From 50c1fdb686705a4ca27a70091c78489b3ceba809 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Thu, 9 Feb 2023 16:05:13 +0100 Subject: [PATCH 001/464] perf: ScalarMulBase with pre-computed points + use in ecdsa --- std/algebra/weierstrass/params.go | 1048 ++++++++++++++++++++++++- std/algebra/weierstrass/point.go | 800 +++++++++++++++++++ std/algebra/weierstrass/point_test.go | 59 ++ std/signature/ecdsa/ecdsa.go | 2 +- std/signature/ecdsa/ecdsa_test.go | 7 + 5 files changed, 1907 insertions(+), 9 deletions(-) diff --git a/std/algebra/weierstrass/params.go b/std/algebra/weierstrass/params.go index aadf2bce6a..afda112f25 100644 --- a/std/algebra/weierstrass/params.go +++ b/std/algebra/weierstrass/params.go @@ -13,10 +13,12 @@ import ( // // The base point is defined by (Gx, Gy). type CurveParams struct { - A *big.Int // a in curve equation - B *big.Int // b in curve equation - Gx *big.Int // base point x - Gy *big.Int // base point y + A *big.Int // a in curve equation + B *big.Int // b in curve equation + Gx *big.Int // base point x + Gy *big.Int // base point y + Gmx [256]*big.Int // m*base point x + Gmy [256]*big.Int // m*base point y } // GetSecp256k1Params returns curve parameters for the curve secp256k1. When @@ -25,11 +27,525 @@ type CurveParams struct { func GetSecp256k1Params() CurveParams { gx, _ := new(big.Int).SetString("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", 16) gy, _ := new(big.Int).SetString("483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", 16) + g2x, _ := new(big.Int).SetString("c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5", 16) + g2y, _ := new(big.Int).SetString("1ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a", 16) + g4x, _ := new(big.Int).SetString("e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13", 16) + g4y, _ := new(big.Int).SetString("51ed993ea0d455b75642e2098ea51448d967ae33bfbdfe40cfe97bdc47739922", 16) + g8x, _ := new(big.Int).SetString("2f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01", 16) + g8y, _ := new(big.Int).SetString("5c4da8a741539949293d082a132d13b4c2e213d6ba5b7617b5da2cb76cbde904", 16) + g16x, _ := new(big.Int).SetString("e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", 16) + g16y, _ := new(big.Int).SetString("f7e3507399e595929db99f34f57937101296891e44d23f0be1f32cce69616821", 16) + g32x, _ := new(big.Int).SetString("d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", 16) + g32y, _ := new(big.Int).SetString("95038d9d0ae3d5c3b3d6dec9e98380651f760cc364ed819605b3ff1f24106ab9", 16) + g64x, _ := new(big.Int).SetString("bf23c1542d16eab70b1051eaf832823cfc4c6f1dcdbafd81e37918e6f874ef8b", 16) + g64y, _ := new(big.Int).SetString("5cb3866fc33003737ad928a0ba5392e4c522fc54811e2f784dc37efe66831d9f", 16) + g128x, _ := new(big.Int).SetString("34ff3be4033f7a06696c3d09f7d1671cbcf55cd700535655647077456769a24e", 16) + g128y, _ := new(big.Int).SetString("5d9d11623a236c553f6619d89832098c55df16c3e8f8b6818491067a73cc2f1a", 16) + g256x, _ := new(big.Int).SetString("8282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508", 16) + g256y, _ := new(big.Int).SetString("11f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf", 16) + g512x, _ := new(big.Int).SetString("465370b287a79ff3905a857a9cf918d50adbc968d9e159d0926e2c00ef34a24d", 16) + g512y, _ := new(big.Int).SetString("35e531b38368c082a4af8bdafdeec2c1588e09b215d37a10a2f8fb20b33887f4", 16) + g1024x, _ := new(big.Int).SetString("241febb8e23cbd77d664a18f66ad6240aaec6ecdc813b088d5b901b2e285131f", 16) + g1024y, _ := new(big.Int).SetString("513378d9ff94f8d3d6c420bd13981df8cd50fd0fbd0cb5afabb3e66f2750026d", 16) + g2048x, _ := new(big.Int).SetString("5d1bdb4ea172fa79fce4cc2983d8f8d9fc318b85f423de0dedcb63069b920471", 16) + g2048y, _ := new(big.Int).SetString("2843826779379e2e794bb99438a2265679eb1e9996c56e7b70330666f7b83103", 16) + g4096x, _ := new(big.Int).SetString("175e159f728b865a72f99cc6c6fc846de0b93833fd2222ed73fce5b551e5b739", 16) + g4096y, _ := new(big.Int).SetString("d3506e0d9e3c79eba4ef97a51ff71f5eacb5955add24345c6efa6ffee9fed695", 16) + g8192x, _ := new(big.Int).SetString("423a013f03ff32d7a5ffbcc8e139c62130fdfeb5c6da121bce78049e46bc47d6", 16) + g8192y, _ := new(big.Int).SetString("b91ae00fe1e1d970a1179f7bbaf6b3c7720d8ec3524f009ed1236e6d8b548a34", 16) + g16384x, _ := new(big.Int).SetString("111d6a45ac1fb90508907a7abcd6877649df662f3b3e2741302df6f78416824a", 16) + g16384y, _ := new(big.Int).SetString("696911c478eaffbb90d48dbff065952f070008996daca4ca9a111d42108e9d0", 16) + g32768x, _ := new(big.Int).SetString("4a4a6dc97ac7c8b8ad795dbebcb9dcff7290b68a5ef74e56ab5edde01bced775", 16) + g32768y, _ := new(big.Int).SetString("529911b016631e72943ef9f739c0f4571de90cdb424742acb2bf8f68a78dd66d", 16) + g65536x, _ := new(big.Int).SetString("363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640", 16) + g65536y, _ := new(big.Int).SetString("4e273adfc732221953b445397f3363145b9a89008199ecb62003c7f3bee9de9", 16) + g131072x, _ := new(big.Int).SetString("4c1b9866ed9a7e9b553973c6c93b02bf0b62fb012edfb59dd2712a5caf92c541", 16) + g131072y, _ := new(big.Int).SetString("c1f792d320be8a0f7fbcb753ce56e69cc652ead7e43eb1ad72c4f3fdc68fe020", 16) + g262144x, _ := new(big.Int).SetString("a4083877ba83b12b529a2f3c0780b54e3233edbc1a28f135e0c8f28cbeaaf3d1", 16) + g262144y, _ := new(big.Int).SetString("40e9f612feefbc79b8bf83d69361b3e22001e7576ed1ef90b12b534df0b254b9", 16) + g524288x, _ := new(big.Int).SetString("a804c641d28cc0b53a4e3e1a2f56c86f6e0d880a454203b98cd3db5a7940d33a", 16) + g524288y, _ := new(big.Int).SetString("95be83252b2fa6d03dec2842c16047e81af18ca89cf736a943ce95fa6d46967a", 16) + g1048576x, _ := new(big.Int).SetString("8b4b5f165df3c2be8c6244b5b745638843e4a781a15bcd1b69f79a55dffdf80c", 16) + g1048576y, _ := new(big.Int).SetString("4aad0a6f68d308b4b3fbd7813ab0da04f9e336546162ee56b3eff0c65fd4fd36", 16) + g2097152x, _ := new(big.Int).SetString("ed0c5ce4e13291718ce17c7ec83c611071af64ee417c997abb3f26714755e4be", 16) + g2097152y, _ := new(big.Int).SetString("221a9fc7bc2345bdbf3dad7f5a7ea68049d93925763ddab163f9fa6ea07bf42f", 16) + g4194304x, _ := new(big.Int).SetString("faecb013c44ce694b3b15c3f83f1fae8e53254566e0552ced4b6e6c807cec8ab", 16) + g4194304y, _ := new(big.Int).SetString("cc09b5e90e9ecb57fc2e02c6ec2fb13d9c32b286b85e2e2e8981dfd9ab155070", 16) + g8388608x, _ := new(big.Int).SetString("9bb8a132dcad2f2c8731a0b37cbcafdb3b2dd824f23cd3e07f64eae9ad1b1f7", 16) + g8388608y, _ := new(big.Int).SetString("945bb2b2afeee3b9b6f9dd284f863e850f54a840f4752d5364130627c3811c80", 16) + g16777216x, _ := new(big.Int).SetString("723cbaa6e5db996d6bf771c00bd548c7b700dbffa6c0e77bcb6115925232fcda", 16) + g16777216y, _ := new(big.Int).SetString("96e867b5595cc498a921137488824d6e2660a0653779494801dc069d9eb39f5f", 16) + g33554432x, _ := new(big.Int).SetString("57efa786437b744d343d7dc45773a3c62d240a43079849071fd383d60ca030d5", 16) + g33554432y, _ := new(big.Int).SetString("d712db0bd1b48518893627c928de03ec689b6d2ae5e9974ab07ab44274b02f9e", 16) + g67108864x, _ := new(big.Int).SetString("264bbd436a28bc42a2df7e9cd5226cb91080577e327b012a7fafc7770c584dd5", 16) + g67108864y, _ := new(big.Int).SetString("d87c6fa94ee093b4d4f75ce24c33be226a118243717b8d8de61227937704ab11", 16) + g134217728x, _ := new(big.Int).SetString("a94c6524bd40d2bbdac85c056236a79da78bc61fd5bdec9d2bf26bd84b2438e8", 16) + g134217728y, _ := new(big.Int).SetString("b5201fd992f96280fd79219505019e3a7e5d3c60a0e39b2bc2e2c8dbf18661f4", 16) + g268435456x, _ := new(big.Int).SetString("eebfa4d493bebf98ba5feec812c2d3b50947961237a919839a533eca0e7dd7fa", 16) + g268435456y, _ := new(big.Int).SetString("5d9a8ca3970ef0f269ee7edaf178089d9ae4cdc3a711f712ddfd4fdae1de8999", 16) + g536870912x, _ := new(big.Int).SetString("381c4ad7a7a97bfda61c6031c118495fc4ea4bc08f6766d676bee90847d297fd", 16) + g536870912y, _ := new(big.Int).SetString("936af53b238eeee48f3e5fa709915eccf0451032db939c0093ace3187d493fc5", 16) + g1073741824x, _ := new(big.Int).SetString("e1efb9cd05adc63bcce10831d9538c479cf1d05fefdd08b2448d70422ede454c", 16) + g1073741824y, _ := new(big.Int).SetString("ecb4530d8af9be7b0154c1ffe477123464e3244a7a2d4c6ad9fd233a8913797", 16) + g2147483648x, _ := new(big.Int).SetString("5318f9b1a2697010c5ac235e9af475a8c7e5419f33d47b18d33feeb329eb99a4", 16) + g2147483648y, _ := new(big.Int).SetString("f44ccfeb4beda4195772d93aebb405e8a41f2b40d1e3ec652c726eeefe91f92d", 16) + g4294967296x, _ := new(big.Int).SetString("100f44da696e71672791d0a09b7bde459f1215a29b3c03bfefd7835b39a48db0", 16) + g4294967296y, _ := new(big.Int).SetString("cdd9e13192a00b772ec8f3300c090666b7ff4a18ff5195ac0fbd5cd62bc65a09", 16) + g8589934592x, _ := new(big.Int).SetString("8c0989f2ceb5c771a8415dff2b4c4199d8d9c8f9237d08084b05284f1e4df706", 16) + g8589934592y, _ := new(big.Int).SetString("fb4dbd044f432034ffd2172cb9dc966c60de6bf5156511aa736ac5a35d72fa98", 16) + g17179869184x, _ := new(big.Int).SetString("fb8f153c5e266704c4a481743262c0259c528539bc95bc1bb1e63c33dc47bffd", 16) + g17179869184y, _ := new(big.Int).SetString("6ca27a9dc5e0621816fa11d9b4bccd531dde1389ac542613090a45ddd949b095", 16) + g34359738368x, _ := new(big.Int).SetString("e747333fd75d51755a0cc9f0a728708465a02c587737a7b8b8fa1b8b4bb2629a", 16) + g34359738368y, _ := new(big.Int).SetString("f2affe0145070c114cc43603804c2581c88376aa6e1a969a9f8d961a6946f6d6", 16) + g68719476736x, _ := new(big.Int).SetString("e1031be262c7ed1b1dc9227a4a04c017a77f8d4464f3b3852c8acde6e534fd2d", 16) + g68719476736y, _ := new(big.Int).SetString("9d7061928940405e6bb6a4176597535af292dd419e1ced79a44f18f29456a00d", 16) + g137438953472x, _ := new(big.Int).SetString("f4b93f224c8089eab9f95dcd0f29b2c9028a6ac5de94d85784e27e36a95c8356", 16) + g137438953472y, _ := new(big.Int).SetString("a67a92ec062962dfb0e5f6a7a40eee90c37ef1344915609abd5861b9be001fd3", 16) + g274877906944x, _ := new(big.Int).SetString("9d1aca1fce55236b19622ea025b08b0d51e8512f97e696c20d62fe17b160e8a", 16) + g274877906944y, _ := new(big.Int).SetString("1153188f5101f0c63e56692ce0d8c27e6fe9e0ee9212b5e534e050c57ca04c44", 16) + g549755813888x, _ := new(big.Int).SetString("c66c59cc454c2b9e18a2ad793821cde7518b3a93bfc39562e97d7d0475ba7fc2", 16) + g549755813888y, _ := new(big.Int).SetString("d9592fe2bfb30fcfbea4f3ceaac10cb2f00a60ddb15955977ec3c69cf75f5956", 16) + g1099511627776x, _ := new(big.Int).SetString("feea6cae46d55b530ac2839f143bd7ec5cf8b266a41d6af52d5e688d9094696d", 16) + g1099511627776y, _ := new(big.Int).SetString("e57c6b6c97dce1bab06e4e12bf3ecd5c981c8957cc41442d3155debf18090088", 16) + g2199023255552x, _ := new(big.Int).SetString("4d000b621adb87e1c53261af9db2e179141ecae0b331a1870aa4040aee752b08", 16) + g2199023255552y, _ := new(big.Int).SetString("6a0d5b8f18e0d255cb6d825582d972cccb7df5f119c7293a3e72851f48302cea", 16) + g4398046511104x, _ := new(big.Int).SetString("71f570ca203da05dd6aa262114717128d657a0403e1f1b77f89962fd475c58ef", 16) + g4398046511104y, _ := new(big.Int).SetString("eb42415b95dc880dd25557345bc95b8df2445d00c3363e7df8649a72d35d420e", 16) + g8796093022208x, _ := new(big.Int).SetString("a2b7b3629f7bd253b7d282b5c21da01446b4821dc65e76516048b06043ff8359", 16) + g8796093022208y, _ := new(big.Int).SetString("693038941695122d57a937a3f71e29c910d10835046f3835a2397fecfe86fec2", 16) + g17592186044416x, _ := new(big.Int).SetString("da67a91d91049cdcb367be4be6ffca3cfeed657d808583de33fa978bc1ec6cb1", 16) + g17592186044416y, _ := new(big.Int).SetString("9bacaa35481642bc41f463f7ec9780e5dec7adc508f740a17e9ea8e27a68be1d", 16) + g35184372088832x, _ := new(big.Int).SetString("4dbacd365fa1ef587c0c0cfaaf00d8718bbd9f35ccea5a835ee3cc821fe741c9", 16) + g35184372088832y, _ := new(big.Int).SetString("16c3540e8a51892e7fdcfd59e838299d0cc384a09fc0535f60be10f8338eb623", 16) + g70368744177664x, _ := new(big.Int).SetString("13d1ffc481509beee68f17d8ff41c2590f4c85f15268605087eda8bab4e218da", 16) + g70368744177664y, _ := new(big.Int).SetString("6008391fa991961dcecb9337b1b758bda4ad01206d5bd127e0db419ddb191c19", 16) + g140737488355328x, _ := new(big.Int).SetString("219b4f9cef6c60007659c79c45b0533b3cc9d916ce29dbff133b40caa2e96db8", 16) + g140737488355328y, _ := new(big.Int).SetString("24d9c605d959efeaf5a44180c0372a6e394f8ac53e90576527df01a78d3b6bc7", 16) + g281474976710656x, _ := new(big.Int).SetString("53904faa0b334cdda6e000935ef22151ec08d0f7bb11069f57545ccc1a37b7c0", 16) + g281474976710656y, _ := new(big.Int).SetString("5bc087d0bc80106d88c9eccac20d3c1c13999981e14434699dcb096b022771c8", 16) + g562949953421312x, _ := new(big.Int).SetString("1a575af9d4146753cf991196316995d2a6ee7aaad0f85ad57cd0f1f38a47ca9", 16) + g562949953421312y, _ := new(big.Int).SetString("3038f1cb8ab20dc3cc55fc52e1bb8698bdb93c5d9f4d7ea667c5df2e77ebcdb7", 16) + g1125899906842624x, _ := new(big.Int).SetString("f5f0e0437621d439ca71f5c1b76155d6d3a61a83d3c20c6ee309d755e315565b", 16) + g1125899906842624y, _ := new(big.Int).SetString("6b9f4e62be5a052bf62189160df7101aa5bf61bf3ed7e40a678430afdd2ecc82", 16) + g2251799813685248x, _ := new(big.Int).SetString("8f506f0b6c0b6e9a57a7f36d970ca4e347cbc92146227642cbe781d9f5362d33", 16) + g2251799813685248y, _ := new(big.Int).SetString("469f955d2afa61719530c5424f1c336848cf925d43bb8eaf30487d0c87fa243f", 16) + g4503599627370496x, _ := new(big.Int).SetString("8e7bcd0bd35983a7719cca7764ca906779b53a043a9b8bcaeff959f43ad86047", 16) + g4503599627370496y, _ := new(big.Int).SetString("10b7770b2a3da4b3940310420ca9514579e88e2e47fd68b3ea10047e8460372a", 16) + g9007199254740992x, _ := new(big.Int).SetString("33b35baa195e729dc350f319996950df3bc15b8d3d0389e777d2808bf13f0351", 16) + g9007199254740992y, _ := new(big.Int).SetString("a58a0185640abf87f9464036248d52bcaa6560efbc889b702bc503cccb8d7418", 16) + g18014398509481984x, _ := new(big.Int).SetString("374deeae22c93f955cb83ad2071f7e2256f6e109cad7bca6d71dc7b24414bb36", 16) + g18014398509481984y, _ := new(big.Int).SetString("171165b64fcd4f9916032c06f806f7293828d66300e543217875bea98daf734a", 16) + g36028797018963968x, _ := new(big.Int).SetString("2380c09c7f3aeae57c46e07395aeb0dc944dbaf2b62a9f0c5e8a64ad6ae7d616", 16) + g36028797018963968y, _ := new(big.Int).SetString("6f8e86193464956af1598aefd509b09a93af92148f8467560099be48161bbc1a", 16) + g72057594037927936x, _ := new(big.Int).SetString("385eed34c1cdff21e6d0818689b81bde71a7f4f18397e6690a841e1599c43862", 16) + g72057594037927936y, _ := new(big.Int).SetString("283bebc3e8ea23f56701de19e9ebf4576b304eec2086dc8cc0458fe5542e5453", 16) + g144115188075855872x, _ := new(big.Int).SetString("f6f622083daf54800456be134d5f67d147c82642befc1ce2dc83a27078f2827c", 16) + g144115188075855872y, _ := new(big.Int).SetString("1bcd4e817de73a0faf2c5715b367cee7e657ca7448321bf6d15b20b520aaa102", 16) + g288230376151711744x, _ := new(big.Int).SetString("fb26e5188f953de2bd70cb3c3d1fc255cd91c3ce7d8c6f369d893209715adcb6", 16) + g288230376151711744y, _ := new(big.Int).SetString("f3e128811012a34d58e846a719d0176916d2cb31b8b7ab5449dbca3b58ba68f3", 16) + g576460752303423488x, _ := new(big.Int).SetString("8991225911b9132d28f5c6bc763ceab7d18c37060e8bd1d7ed44db7560788c1e", 16) + g576460752303423488y, _ := new(big.Int).SetString("da8b4d987cc9ac9b27b8763559b136fa36969c84fdef9e11635c42228e8f0ef1", 16) + g1152921504606846976x, _ := new(big.Int).SetString("6f9d9b803ecf191637c73a4413dfa180fddf84a5947fbc9c606ed86c3fac3a7", 16) + g1152921504606846976y, _ := new(big.Int).SetString("7c80c68e603059ba69b8e2a30e45c4d47ea4dd2f5c281002d86890603a842160", 16) + g2305843009213693952x, _ := new(big.Int).SetString("ae86eeea252b411c1cdc36c284482939da1745e5a7e4da175c9d22744b7fd72d", 16) + g2305843009213693952y, _ := new(big.Int).SetString("19e993c9707302f962ab0ace589ff0e98d9211551472f7282334cb7a4eee38bc", 16) + g4611686018427387904x, _ := new(big.Int).SetString("2248c9f90bbfff55e61d2f8c56dc2c488718be75cf36f2ee7a1474267c169290", 16) + g4611686018427387904y, _ := new(big.Int).SetString("fa0594692d21eed7a506bb55b435ba18e163750235da2be2369d8a12883ea257", 16) + g9223372036854775808x, _ := new(big.Int).SetString("e11a6e16e05c44074ac11b48d94085d0a99f0877dd1c6f76fd0dac4bb50964e3", 16) + g9223372036854775808y, _ := new(big.Int).SetString("87d6065b87a2d430e1ad5e2596f0af2417adc6e138318c6f767fbf8b0682bfc8", 16) + g18446744073709551616x, _ := new(big.Int).SetString("3322d401243c4e2582a2147c104d6ecbf774d163db0f5e5313b7e0e742d0e6bd", 16) + g18446744073709551616y, _ := new(big.Int).SetString("56e70797e9664ef5bfb019bc4ddaf9b72805f63ea2873af624f3a2e96c28b2a0", 16) + g36893488147419103232x, _ := new(big.Int).SetString("8d26200250cebdae120ef31b04c80cd50d4cddc8eadbcf29fc696d32c0ade462", 16) + g36893488147419103232y, _ := new(big.Int).SetString("ebed3bb4715bf437d31f6f2dc3ee36ba1d4afb4e72678b3ad8e0a8b90f26470c", 16) + g73786976294838206464x, _ := new(big.Int).SetString("1238c0766eaebea9ce4068a1f594d03b8ed4930d072d9c8b9164643e1516e633", 16) + g73786976294838206464y, _ := new(big.Int).SetString("8a9db02dbb271359d6c979e2d1c3dc170946252dcc74022805cdb728c77b7805", 16) + g147573952589676412928x, _ := new(big.Int).SetString("271d5b0770cb9c15e7b2ea758a6a11b9cddcd7282b0ec21619b01552788e7a66", 16) + g147573952589676412928y, _ := new(big.Int).SetString("5d3aa45834e7f491e457d09949ac877fe2a065e3508a824e7a8d7258e03c9727", 16) + g295147905179352825856x, _ := new(big.Int).SetString("85672c7d2de0b7da2bd1770d89665868741b3f9af7643397721d74d28134ab83", 16) + g295147905179352825856y, _ := new(big.Int).SetString("7c481b9b5b43b2eb6374049bfa62c2e5e77f17fcc5298f44c8e3094f790313a6", 16) + g590295810358705651712x, _ := new(big.Int).SetString("534ccf6b740f9ec036c1861215c8a61f3b89ea46df2e6d96998b90bc1f17fc25", 16) + g590295810358705651712y, _ := new(big.Int).SetString("d5715cb09c8b2ddb462ae3dd32d543550ae3d277bfdd28ddd71c7f6ecfe86e76", 16) + g1180591620717411303424x, _ := new(big.Int).SetString("a91d1f5cee87b7f3081e142018f8aaed79020d47ecfbc8d2c7170923e8bee8b6", 16) + g1180591620717411303424y, _ := new(big.Int).SetString("748a324ee2df8ee15a7189c8dddad3b2f800569f628cb225003d16aa410644c1", 16) + g2361183241434822606848x, _ := new(big.Int).SetString("c15c8c23d90c8e35c1a214dde2d4383c0735ae45bef61f10aa1a1c255984cf74", 16) + g2361183241434822606848y, _ := new(big.Int).SetString("2ba954d828522235c8dc6f45e25fd7ba47bf772d50b015a2c4a48cd839ccb000", 16) + g4722366482869645213696x, _ := new(big.Int).SetString("948bf809b1988a46b06c9f1919413b10f9226c60f668832ffd959af60c82a0a", 16) + g4722366482869645213696y, _ := new(big.Int).SetString("53a562856dcb6646dc6b74c5d1c3418c6d4dff08c97cd2bed4cb7f88d8c8e589", 16) + g9444732965739290427392x, _ := new(big.Int).SetString("26952c7f372e59360d5ce4c66291f0b6ef16c1331e825e51396eb0457e8b000a", 16) + g9444732965739290427392y, _ := new(big.Int).SetString("f513ea4c5800a68862bc893d2d688422debe398f653d67318c3d401f05ef705a", 16) + g18889465931478580854784x, _ := new(big.Int).SetString("c62e58e6fc23c5bdbef2be8b131ff243f521196572d6b0e9f102588976134f96", 16) + g18889465931478580854784y, _ := new(big.Int).SetString("4397827d45b1a1678c3d676753141fc5bcfb853563731c3e82277ed4d14cf97e", 16) + g37778931862957161709568x, _ := new(big.Int).SetString("107460520eec5c741683329a716622b0b81c03200807de973686f8800b188cbb", 16) + g37778931862957161709568y, _ := new(big.Int).SetString("abe5d4c09a21598c35326b9b9cf54a11242e0d748dce3da601d7b6361f272124", 16) + g75557863725914323419136x, _ := new(big.Int).SetString("6260ce7f461801c34f067ce0f02873a8f1b0e44dfc69752accecd819f38fd8e8", 16) + g75557863725914323419136y, _ := new(big.Int).SetString("bc2da82b6fa5b571a7f09049776a1ef7ecd292238051c198c1a84e95b2b4ae17", 16) + g151115727451828646838272x, _ := new(big.Int).SetString("85d8da4748ad1a73dec8409be84f1a1316e65c5196aad27e0766746f3d477c2d", 16) + g151115727451828646838272y, _ := new(big.Int).SetString("58948b53665c6690586b536531efc7bc94b0a02033c4d5a62079816fc7d1dd70", 16) + g302231454903657293676544x, _ := new(big.Int).SetString("8e2a7166e7ec4b968c0892e9cc3ee3ee4d1e7e100fdc47f04850312d6c0b80d9", 16) + g302231454903657293676544y, _ := new(big.Int).SetString("eadb0ba9ae2cbe592cedd29b716a9d485297b688d706349a49c61f2ad6b29f50", 16) + g604462909807314587353088x, _ := new(big.Int).SetString("769bc75842bff58edc8366ecd78f8950ee4ab2e81359d90f9921fa3d2c4561be", 16) + g604462909807314587353088y, _ := new(big.Int).SetString("4bf817362fe783bac8dce4cef73f5d4741a177767b7873add5920bffb0d9685f", 16) + g1208925819614629174706176x, _ := new(big.Int).SetString("e5037de0afc1d8d43d8348414bbf4103043ec8f575bfdc432953cc8d2037fa2d", 16) + g1208925819614629174706176y, _ := new(big.Int).SetString("4571534baa94d3b5f9f98d09fb990bddbd5f5b03ec481f10e0e5dc841d755bda", 16) + g2417851639229258349412352x, _ := new(big.Int).SetString("a5e00da467fd5494f40b6cf7d2d61b3ec3ab217c792a2ddb8c63c8c79e3d34ef", 16) + g2417851639229258349412352y, _ := new(big.Int).SetString("98fe5f5e5608555421726fe99bf43d25b60dcfe790900acb855c5ce2f7adb4c", 16) + g4835703278458516698824704x, _ := new(big.Int).SetString("a99415f5ef3a2b403519f4bb1c9bfbc46d4afd2e4477572ae6737160d7b91252", 16) + g4835703278458516698824704y, _ := new(big.Int).SetString("82d0e64cae81f84bb9e2f10f24f6f6b6899a16ad590f4ddd73a377ac4bedc264", 16) + g9671406556917033397649408x, _ := new(big.Int).SetString("b56f4e9f9e4fd1fc7d8edde098f935f84c750d705f0c132bd8c465b66a540f17", 16) + g9671406556917033397649408y, _ := new(big.Int).SetString("32e8e53429cca856d3dc11adf0582d1d21d42963cbcca85446a2fcae0200102d", 16) + g19342813113834066795298816x, _ := new(big.Int).SetString("e06372b0f4a207adf5ea905e8f1771b4e7e8dbd1c6a6c5b725866a0ae4fce725", 16) + g19342813113834066795298816y, _ := new(big.Int).SetString("7a908974bce18cfe12a27bb2ad5a488cd7484a7787104870b27034f94eee31dd", 16) + g38685626227668133590597632x, _ := new(big.Int).SetString("eac134ca2046b8f9c8dbd304fad3f3c045ebfdb4ec6ed3cfe09aee43ed2ff3e", 16) + g38685626227668133590597632y, _ := new(big.Int).SetString("49630dbe79359b4245bf103bf2b11799ac19f696b7f21376e17206207d210988", 16) + g77371252455336267181195264x, _ := new(big.Int).SetString("d6788590731fea198392119d7adbb41ff5948a7804c85b17476706e4dfbfa4dc", 16) + g77371252455336267181195264y, _ := new(big.Int).SetString("28eaa8c89d5063c4940ef5c6d21c13aa6206f1c4ddc9a07cca7bcd6bbd3b5406", 16) + g154742504910672534362390528x, _ := new(big.Int).SetString("6930fccbd9a040974abf210f12b71d4bc7b1a6205599b01a7275fb40e48ff9b3", 16) + g154742504910672534362390528y, _ := new(big.Int).SetString("7f02ae94b94701eada30fcdb875f6d78090f9b13e4acc51acfddab5f8ee96a4e", 16) + g309485009821345068724781056x, _ := new(big.Int).SetString("213c7a715cd5d45358d0bbf9dc0ce02204b10bdde2a3f58540ad6908d0559754", 16) + g309485009821345068724781056y, _ := new(big.Int).SetString("4b6dad0b5ae462507013ad06245ba190bb4850f5f36a7eeddff2c27534b458f2", 16) + g618970019642690137449562112x, _ := new(big.Int).SetString("1c5e548132b49a7f66ae9fed8323480e0d1ab974622e7cf08993895e0ec87fac", 16) + g618970019642690137449562112y, _ := new(big.Int).SetString("4ffcf60f837f468f2bb959fa1d4c2ad3a3deaceb26fe324c555d7b3d5fc2d4ef", 16) + g1237940039285380274899124224x, _ := new(big.Int).SetString("46276d0602c5668ddef6e94210bbc7ce1f901c19fed5c970e20fcba1d4531dbc", 16) + g1237940039285380274899124224y, _ := new(big.Int).SetString("e0f7f24d44c75b84a292287570ded99498badfbffe1bc99af8730099686b8e2", 16) + g2475880078570760549798248448x, _ := new(big.Int).SetString("efea68eca7a6c24f4e65eb211c3191636850e0acdc78d8996114ef13522f001d", 16) + g2475880078570760549798248448y, _ := new(big.Int).SetString("aab847869d583c14da150307a3719a17e413959fb3848771c128419f73bc4415", 16) + g4951760157141521099596496896x, _ := new(big.Int).SetString("4e7c272a7af4b34e8dbb9352a5419a87e2838c70adc62cddf0cc3a3b08fbd53c", 16) + g4951760157141521099596496896y, _ := new(big.Int).SetString("17749c766c9d0b18e16fd09f6def681b530b9614bff7dd33e0b3941817dcaae6", 16) + g9903520314283042199192993792x, _ := new(big.Int).SetString("899017b02696888f268a269f4e385d9c9b11f25a1bef8790e2821e6e7c6e1b4d", 16) + g9903520314283042199192993792y, _ := new(big.Int).SetString("43ae2cdab5b334f0bb45798336358bfae4e51bc0f932b212009aebdad814ab2b", 16) + g19807040628566084398385987584x, _ := new(big.Int).SetString("67f644f76e905fd4a8f4728e63227f0e2831f5bf91b583a8af2635a17e5f712f", 16) + g19807040628566084398385987584y, _ := new(big.Int).SetString("b833d68f66445d04f05adeb7b586cf785e0e1488f7d36198d68acb5e707160e5", 16) + g39614081257132168796771975168x, _ := new(big.Int).SetString("327f876c93652555fa80a054968b4712930dc93012ee6b8dc10263ed3b89a762", 16) + g39614081257132168796771975168y, _ := new(big.Int).SetString("b2d404eab3524026b09969255e1997b975535070febd7dfe9c9fd959b9203301", 16) + g79228162514264337593543950336x, _ := new(big.Int).SetString("fea74e3dbe778b1b10f238ad61686aa5c76e3db2be43057632427e2840fb27b6", 16) + g79228162514264337593543950336y, _ := new(big.Int).SetString("6e0568db9b0b13297cf674deccb6af93126b596b973f7b77701d3db7f23cb96f", 16) + g158456325028528675187087900672x, _ := new(big.Int).SetString("ed9441c8304280ff180e03d850e8cd0ebb570ee5de3730488fd97c961f9756e4", 16) + g158456325028528675187087900672y, _ := new(big.Int).SetString("3dbe9e9efe8bfa19afa176128b13911e09f23774fe4de98bff0e09f93f3abfae", 16) + g316912650057057350374175801344x, _ := new(big.Int).SetString("29d9698ee67a7c3fc9fed3f624b487515b10bdd84fab4d3015bad033d51cf119", 16) + g316912650057057350374175801344y, _ := new(big.Int).SetString("7fd02c517dc82b45277a125404f1c96fb89c940e93a7c2963c88740575056339", 16) + g633825300114114700748351602688x, _ := new(big.Int).SetString("126b57d05013936d6f3fb7bd33580a31fd453e4a86060cff467c44537f422491", 16) + g633825300114114700748351602688y, _ := new(big.Int).SetString("c1a7dc13061662c2e3c4a3eba2bf3fb0e148bac30bf39347afa31f199da3ef84", 16) + g1267650600228229401496703205376x, _ := new(big.Int).SetString("76e64113f677cf0e10a2570d599968d31544e179b760432952c02a4417bdde39", 16) + g1267650600228229401496703205376y, _ := new(big.Int).SetString("c90ddf8dee4e95cf577066d70681f0d35e2a33d2b56d2032b4b1752d1901ac01", 16) + g2535301200456458802993406410752x, _ := new(big.Int).SetString("708a530e9e52c73bee87c9d88161c810005d57622c29ae691cf999a83a1187a5", 16) + g2535301200456458802993406410752y, _ := new(big.Int).SetString("9b884811e1f9a897fa9656dcbb6d38283ecda73c6d353e8a58a4f19b473db9c0", 16) + g5070602400912917605986812821504x, _ := new(big.Int).SetString("19cf034fc48b3be219bd648395e462cf9f374b6d86b2b59e2e1b16c6cde4f5be", 16) + g5070602400912917605986812821504y, _ := new(big.Int).SetString("28e32b06a15ab466c3b4be68ab181947ef91d1c93f0f1c0c0a91532b6f321af2", 16) + g10141204801825835211973625643008x, _ := new(big.Int).SetString("af6c44a078cb5f0d7c719c2f8397f576ee93bd034bea2219e3abc209d17cf3e8", 16) + g10141204801825835211973625643008y, _ := new(big.Int).SetString("784096fe85d4b30af9e73153cb246dfec362aea7ca0d435b8add0601751baea", 16) + g20282409603651670423947251286016x, _ := new(big.Int).SetString("c738c56b03b2abe1e8281baa743f8f9a8f7cc643df26cbee3ab150242bcbb891", 16) + g20282409603651670423947251286016y, _ := new(big.Int).SetString("893fb578951ad2537f718f2eacbfbbbb82314eef7880cfe917e735d9699a84c3", 16) + g40564819207303340847894502572032x, _ := new(big.Int).SetString("5578845ecd7c037435b32a6992e7aa94647197ea49b8c9e4ddaab0784662ab1b", 16) + g40564819207303340847894502572032y, _ := new(big.Int).SetString("e61d07978b6de2c3cea6d0a51d2a4053f653a7746a5d64de316d18f3056f3511", 16) + g81129638414606681695789005144064x, _ := new(big.Int).SetString("47f3383888a364cc4abfa3bc1d0ceccd22f12354fce3996094f869b8948b6c29", 16) + g81129638414606681695789005144064y, _ := new(big.Int).SetString("48ca9a8d0f032937190e48675b416c7118bb499588f994a81edee1120e537ef9", 16) + g162259276829213363391578010288128x, _ := new(big.Int).SetString("c0c01f34ae41b8cfe466b4c9c6a5d5f614f570d6fcbef768a81a6c8f05ff4adb", 16) + g162259276829213363391578010288128y, _ := new(big.Int).SetString("b84f5bee4357f5c7c937a0b4075b8cecdbc43d170d15b85fc4eff73ac351065", 16) + g324518553658426726783156020576256x, _ := new(big.Int).SetString("d895626548b65b81e264c7637c972877d1d72e5f3a925014372e9f6588f6c14b", 16) + g324518553658426726783156020576256y, _ := new(big.Int).SetString("febfaa38f2bc7eae728ec60818c340eb03428d632bb067e179363ed75d7d991f", 16) + g649037107316853453566312041152512x, _ := new(big.Int).SetString("fd136eef8971044e8a3a43622003a26703ecaf7a0ec40c3fba5b594b77078424", 16) + g649037107316853453566312041152512y, _ := new(big.Int).SetString("218da834f3c652cc67a1d191b5c5efa57cf2b1f78a2adfa8cd61eeefc671ddf1", 16) + g1298074214633706907132624082305024x, _ := new(big.Int).SetString("d99e8e9dd9638d140e9cca5367519f861b7003a0d43f024a5f1d84ec8db1cb3c", 16) + g1298074214633706907132624082305024y, _ := new(big.Int).SetString("36dc19ad1cc0a3a7a945bb321bceba6e6286fef8ffc8765cd88a29e36b8637a7", 16) + g2596148429267413814265248164610048x, _ := new(big.Int).SetString("3fdf1619a198317a1bd8a54e5b09191d203351e0440e636fd46f68d3c385172", 16) + g2596148429267413814265248164610048y, _ := new(big.Int).SetString("408d02c06e5c12c3fe470c7d3c8573755b9b929e90e7232b79ac67f0fccb9794", 16) + g5192296858534827628530496329220096x, _ := new(big.Int).SetString("b8da94032a957518eb0f6433571e8761ceffc73693e84edd49150a564f676e03", 16) + g5192296858534827628530496329220096y, _ := new(big.Int).SetString("2804dfa44805a1e4d7c99cc9762808b092cc584d95ff3b511488e4e74efdf6e7", 16) + g10384593717069655257060992658440192x, _ := new(big.Int).SetString("6d36d105ed8cc5ce53f2cb698ab620f9469a3e5cb25bf6e6d413f414c5af726a", 16) + g10384593717069655257060992658440192y, _ := new(big.Int).SetString("e4ba5c34e377669e72d8c66c95c50029dcc59936b4108a35c570491a13f9fc7d", 16) + g20769187434139310514121985316880384x, _ := new(big.Int).SetString("3ab6bde10cd3ac0cd06883fa66f0b0e3eb1309c0534b812286e2a30ca540db99", 16) + g20769187434139310514121985316880384y, _ := new(big.Int).SetString("baca62079be871d7fc3117a96a13e99c38d137b0e369c043e6873fe31bda78a3", 16) + g41538374868278621028243970633760768x, _ := new(big.Int).SetString("796634e3f1ad56f0fdba069d9d07bce2ba2fd4f373ddd3ba7777bf279f1048da", 16) + g41538374868278621028243970633760768y, _ := new(big.Int).SetString("4d8ee2b6cfb20b8956de74735a7927f2532576d8cfd74862e8f9be24a106cf01", 16) + g83076749736557242056487941267521536x, _ := new(big.Int).SetString("e80fea14441fb33a7d8adab9475d7fab2019effb5156a792f1a11778e3c0df5d", 16) + g83076749736557242056487941267521536y, _ := new(big.Int).SetString("eed1de7f638e00771e89768ca3ca94472d155e80af322ea9fcb4291b6ac9ec78", 16) + g166153499473114484112975882535043072x, _ := new(big.Int).SetString("440ca1f08ea41265981ac4ed1efe7a37122dcc3877d2f9162db0e78b0f83cd58", 16) + g166153499473114484112975882535043072y, _ := new(big.Int).SetString("a6c8b0d2cd5ee122af8954dc9d4e2f02a21e4d4269c0a260b07bc069b88a3f4b", 16) + g332306998946228968225951765070086144x, _ := new(big.Int).SetString("f694cbaf2b966c1cc5f7f829d3a907819bc70ebcc1b229d9e81bda2712998b10", 16) + g332306998946228968225951765070086144y, _ := new(big.Int).SetString("40a63eba61bef03d633c5ffacc46d82aeb6c64c3183c2a47f6788b1700f05e51", 16) + g664613997892457936451903530140172288x, _ := new(big.Int).SetString("8b6e862a3556684850b6d4f439a2595047abf695c08b6414f95a13358dd553fd", 16) + g664613997892457936451903530140172288y, _ := new(big.Int).SetString("ea5e08910ed11cb40d10bc2df4eb9fa124ac3c5a183383d0d803dad33e9be5ed", 16) + g1329227995784915872903807060280344576x, _ := new(big.Int).SetString("a301697bdfcd704313ba48e51d567543f2a182031efd6915ddc07bbcc4e16070", 16) + g1329227995784915872903807060280344576y, _ := new(big.Int).SetString("7370f91cfb67e4f5081809fa25d40f9b1735dbf7c0a11a130c0d1a041e177ea1", 16) + g2658455991569831745807614120560689152x, _ := new(big.Int).SetString("27e1e59cff79f049f3e8d2419e0bff74b43965004c34b5d811420316f24ba5ae", 16) + g2658455991569831745807614120560689152y, _ := new(big.Int).SetString("310b26a6c804e209ee1b5e3cfc79df05df48a1a69afa63f784a5bfee883a45b3", 16) + g5316911983139663491615228241121378304x, _ := new(big.Int).SetString("c712e7a5f6864aee16588ec3892d7e4f5a39adde84fbfb4f9969175c9caed7ae", 16) + g5316911983139663491615228241121378304y, _ := new(big.Int).SetString("49644107516363b365ed4b82311dd9e5380d8e544b0ce63784d148aa46156294", 16) + g10633823966279326983230456482242756608x, _ := new(big.Int).SetString("bfc0504a4b3235d065c0d426b8675fcb2c85d6f58275d791b43e1fe44a6db03", 16) + g10633823966279326983230456482242756608y, _ := new(big.Int).SetString("1955467a6c34f3453fb8ec7f94a6c99237427197345d4f0558ac8d1a464b8542", 16) + g21267647932558653966460912964485513216x, _ := new(big.Int).SetString("90ad85b389d6b936463f9d0512678de208cc330b11307fffab7ac63e3fb04ed4", 16) + g21267647932558653966460912964485513216y, _ := new(big.Int).SetString("e507a3620a38261affdcbd9427222b839aefabe1582894d991d4d48cb6ef150", 16) + g42535295865117307932921825928971026432x, _ := new(big.Int).SetString("7e2cd40ef8c94077f44b1d1548425e3d7e125be646707bad2818b0eda7dc0151", 16) + g42535295865117307932921825928971026432y, _ := new(big.Int).SetString("905b75082adcfab382a61a8b321ef95d889bee40aeee082c9a3bc53920721ec7", 16) + g85070591730234615865843651857942052864x, _ := new(big.Int).SetString("a146f52195bedace21c975bbd1ef52a79c636bf9db853cf90e103ae41345e597", 16) + g85070591730234615865843651857942052864y, _ := new(big.Int).SetString("a5a99b0ab053feb09ae95dd2dbb31b40ea67a5b221f094b07675676af45a770a", 16) + g170141183460469231731687303715884105728x, _ := new(big.Int).SetString("d24c75a1cf1993b9bcfbf9dab25a8114dbde421efeccc4e20cbb53fc4ce45444", 16) + g170141183460469231731687303715884105728y, _ := new(big.Int).SetString("58fe1d2de84dc1d1cfcb7d1810e5a78abf7593f499f1e524cb93246987dd4a57", 16) + g340282366920938463463374607431768211456x, _ := new(big.Int).SetString("8f68b9d2f63b5f339239c1ad981f162ee88c5678723ea3351b7b444c9ec4c0da", 16) + g340282366920938463463374607431768211456y, _ := new(big.Int).SetString("662a9f2dba063986de1d90c2b6be215dbbea2cfe95510bfdf23cbf79501fff82", 16) + g680564733841876926926749214863536422912x, _ := new(big.Int).SetString("4d49aefd784e8158fcafebe77fd9af59d89858ade7627eaee6847df84cf27076", 16) + g680564733841876926926749214863536422912y, _ := new(big.Int).SetString("cd32fc59a10dd135e723f210359ca6f06e0f2d1a7df4d8466b90b66203aa781e", 16) + g1361129467683753853853498429727072845824x, _ := new(big.Int).SetString("7564539e85d56f8537d6619e1f5c5aa78d2a3de0889d1d4ee8dbcb5729b62026", 16) + g1361129467683753853853498429727072845824y, _ := new(big.Int).SetString("c1d685413749b3c65231df524a722925684aacd954b79f334172c8fadace0cf3", 16) + g2722258935367507707706996859454145691648x, _ := new(big.Int).SetString("210a917ad9df27796746ff301ad9ccc878f61a5f1ff4082b5364dacd57b4a278", 16) + g2722258935367507707706996859454145691648y, _ := new(big.Int).SetString("670e1b5450b5e57b7a39be81f8d6737d3789e61aaff20bfc7f2713fd0c7b2231", 16) + g5444517870735015415413993718908291383296x, _ := new(big.Int).SetString("e4f3fb0176af85d65ff99ff9198c36091f48e86503681e3e6686fd5053231e11", 16) + g5444517870735015415413993718908291383296y, _ := new(big.Int).SetString("1e63633ad0ef4f1c1661a6d0ea02b7286cc7e74ec951d1c9822c38576feb73bc", 16) + g10889035741470030830827987437816582766592x, _ := new(big.Int).SetString("4b30cbb7686773e01ec64110abdb362f88531a825ba172953bfee2233bcdaf2f", 16) + g10889035741470030830827987437816582766592y, _ := new(big.Int).SetString("74c6350265bb629b6f9e2c5777c3c4a91fdf3c81e434857568033d463d26b5b7", 16) + g21778071482940061661655974875633165533184x, _ := new(big.Int).SetString("cbb434aa7ae1700dcd15b20b17464817ec11715050e0fa192ffe9c29a673059f", 16) + g21778071482940061661655974875633165533184y, _ := new(big.Int).SetString("4a1a200ab4dabd17562d492338b5dfad41d45e4f0ad5f845b7da9642227c070c", 16) + g43556142965880123323311949751266331066368x, _ := new(big.Int).SetString("f478056d9c102c1cd06d7b1e7557244c6d9cdac5874610e94d4786e106de12c0", 16) + g43556142965880123323311949751266331066368y, _ := new(big.Int).SetString("7f09e610f33e3946e68095e01068694c26c17ef609ab92d769a76ce6ca5361fe", 16) + g87112285931760246646623899502532662132736x, _ := new(big.Int).SetString("8c00fa9b18ebf331eb961537a45a4266c7034f2f0d4e1d0716fb6eae20eae29e", 16) + g87112285931760246646623899502532662132736y, _ := new(big.Int).SetString("efa47267fea521a1a9dc343a3736c974c2fadafa81e36c54e7d2a4c66702414b", 16) + g174224571863520493293247799005065324265472x, _ := new(big.Int).SetString("24cfc0176da2b46fa8bb5bf9636be1effd7e297f29122fb3e84c9ab0c18ada5f", 16) + g174224571863520493293247799005065324265472y, _ := new(big.Int).SetString("ebff8fbb079c61a69868714d5deda927ed959ca1a4f814f268fa6139978a586b", 16) + g348449143727040986586495598010130648530944x, _ := new(big.Int).SetString("4a7d58d4b9bc82ea2ded72a1292ec616ddd67fc7f057edf103189594679da2", 16) + g348449143727040986586495598010130648530944y, _ := new(big.Int).SetString("b98ac5b76702cb75e6b1d8147ec71b3b71c3b494963fa28a4877f484779ffe26", 16) + g696898287454081973172991196020261297061888x, _ := new(big.Int).SetString("ee7d69c4cbd001c7fc76c5e2c066ce4996f8808a1e07b2a9ccf34eadc87c4b65", 16) + g696898287454081973172991196020261297061888y, _ := new(big.Int).SetString("ecc8626ec1a413821a192abf030f2ee2c33e8999bae942e523e8f44ed136a95a", 16) + g1393796574908163946345982392040522594123776x, _ := new(big.Int).SetString("e7a26ce69dd4829f3e10cec0a9e98ed3143d084f308b92c0997fddfc60cb3e41", 16) + g1393796574908163946345982392040522594123776y, _ := new(big.Int).SetString("2a758e300fa7984b471b006a1aafbb18d0a6b2c0420e83e20e8a9421cf2cfd51", 16) + g2787593149816327892691964784081045188247552x, _ := new(big.Int).SetString("f5cafaba036bf8d00d38bfb6772089f5203c35e4d6e32fa9d97e5b917b4ae861", 16) + g2787593149816327892691964784081045188247552y, _ := new(big.Int).SetString("19e83b8a022a6d817bff9904640839159b3b2a9c552f05f3cc9c239c0d82239c", 16) + g5575186299632655785383929568162090376495104x, _ := new(big.Int).SetString("e9389024ceb63f1f12df5156d7e805428f9e509c494c982084fd4cd7bd2a9651", 16) + g5575186299632655785383929568162090376495104y, _ := new(big.Int).SetString("8648688723726595f9287abaf671aaf18d7110cec6770bfefefde2b75e786824", 16) + g11150372599265311570767859136324180752990208x, _ := new(big.Int).SetString("264559d87829256bed116900d82d0c379f0e4d1253c68e6fcf2d41ae7cddab8b", 16) + g11150372599265311570767859136324180752990208y, _ := new(big.Int).SetString("79e5bd1926d3512cef7bc637034072d77a8631af39caf1e6c9f64b45001de473", 16) + g22300745198530623141535718272648361505980416x, _ := new(big.Int).SetString("b6459e0ee3662ec8d23540c223bcbdc571cbcb967d79424f3cf29eb3de6b80ef", 16) + g22300745198530623141535718272648361505980416y, _ := new(big.Int).SetString("67c876d06f3e06de1dadf16e5661db3c4b3ae6d48e35b2ff30bf0b61a71ba45", 16) + g44601490397061246283071436545296723011960832x, _ := new(big.Int).SetString("e5d8e8f0d9823c88e4d36f7301f41593b6890576be79c211253ef375033eb51f", 16) + g44601490397061246283071436545296723011960832y, _ := new(big.Int).SetString("4dc1e9b7861e3e04abb16a57d8feeef0e509dc46d9f0f54979d5bd965a62a2d9", 16) + g89202980794122492566142873090593446023921664x, _ := new(big.Int).SetString("a9ca27f77dbc8c3dc56b0f7321bae0ddab66be4fa8a3011737a676480f155e64", 16) + g89202980794122492566142873090593446023921664y, _ := new(big.Int).SetString("f4bb335678fb14d4d197d2246c02d004875d41821bcaf0ae1f3f333c561b3297", 16) + g178405961588244985132285746181186892047843328x, _ := new(big.Int).SetString("68fb71800686d7f25eba105611cfe7591f478e847f51cee06d4bc629d6ee247c", 16) + g178405961588244985132285746181186892047843328y, _ := new(big.Int).SetString("cd12d23462dd963673735427501b0c079a8d580b04c73c9dae1f822d1a01865d", 16) + g356811923176489970264571492362373784095686656x, _ := new(big.Int).SetString("d68a80c8280bb840793234aa118f06231d6f1fc67e73c5a5deda0f5b496943e8", 16) + g356811923176489970264571492362373784095686656y, _ := new(big.Int).SetString("db8ba9fff4b586d00c4b1f9177b0e28b5b0e7b8f7845295a294c84266b133120", 16) + g713623846352979940529142984724747568191373312x, _ := new(big.Int).SetString("f16a409c677a40be402f8efb3752373caced053c6f702b828bda222ca412b6fd", 16) + g713623846352979940529142984724747568191373312y, _ := new(big.Int).SetString("2a41311714532799d7a6a75a74e30e4e16540659249ebca4268dae77eca052da", 16) + g1427247692705959881058285969449495136382746624x, _ := new(big.Int).SetString("4154b506ab766f42fbe37f699976f84db89f4f2f6bed98325c1a0b6e326dd4e4", 16) + g1427247692705959881058285969449495136382746624y, _ := new(big.Int).SetString("23ad075043c5988894c6e44d61025ff6414ea9d9d1e22dd46c859295075ded1c", 16) + g2854495385411919762116571938898990272765493248x, _ := new(big.Int).SetString("b73c652769cc95c1080a8d4d0b5956ea93e86e49fc727ddf4c51a7a63f7f0246", 16) + g2854495385411919762116571938898990272765493248y, _ := new(big.Int).SetString("9a67db107174ca9d4b535893c5b6c1ea1a0d72e4c6e554e5597e5164ea2a407b", 16) + g5708990770823839524233143877797980545530986496x, _ := new(big.Int).SetString("324aed7df65c804252dc0270907a30b09612aeb973449cea4095980fc28d3d5d", 16) + g5708990770823839524233143877797980545530986496y, _ := new(big.Int).SetString("648a365774b61f2ff130c0c35aec1f4f19213b0c7e332843967224af96ab7c84", 16) + g11417981541647679048466287755595961091061972992x, _ := new(big.Int).SetString("32c9331ea26f490228d32681880d7203f72b3e4a8de0db1fa8f38381b2919749", 16) + g11417981541647679048466287755595961091061972992y, _ := new(big.Int).SetString("d7cd272b34209cb5695a2f02b6f3dbb8268a4abdae39ab09631e97b0f290b5e3", 16) + g22835963083295358096932575511191922182123945984x, _ := new(big.Int).SetString("eb292f3b3b9837854a02f6a70fec6b1c69c161b6e1846b8e1e1c22527b9795e4", 16) + g22835963083295358096932575511191922182123945984y, _ := new(big.Int).SetString("8c43c25a96eebe801696634af145835b57131d7509111c6f5b7e9d2fae53a0fe", 16) + g45671926166590716193865151022383844364247891968x, _ := new(big.Int).SetString("a65a3a01df3b5ef2e620d4310049fbe14d71457f19d1ed35aea39d5789303fdd", 16) + g45671926166590716193865151022383844364247891968y, _ := new(big.Int).SetString("798ea0940cff5c6fb8f43d8d90ed2c7686861d024faed3cadad44a8d02e68703", 16) + g91343852333181432387730302044767688728495783936x, _ := new(big.Int).SetString("4df9c14919cde61f6d51dfdbe5fee5dceec4143ba8d1ca888e8bd373fd054c96", 16) + g91343852333181432387730302044767688728495783936y, _ := new(big.Int).SetString("35ec51092d8728050974c23a1d85d4b5d506cdc288490192ebac06cad10d5d", 16) + g182687704666362864775460604089535377456991567872x, _ := new(big.Int).SetString("ed32cad8d2cc998cd25317d4e4b87088e9de4554e57a8d70c0c6b0fc1da49e04", 16) + g182687704666362864775460604089535377456991567872y, _ := new(big.Int).SetString("129fef5f1d030204a541ca375859d20b52da9facb49fab7db63120d17c1db9e0", 16) + g365375409332725729550921208179070754913983135744x, _ := new(big.Int).SetString("e821ab724d6360f18049e4111c70366e28c36dcb63c34016cb7418d4e883f855", 16) + g365375409332725729550921208179070754913983135744y, _ := new(big.Int).SetString("adefcbf863f53ce367d0d4115416cf598b3b19c614ec23efed4e0c6a59852ddf", 16) + g730750818665451459101842416358141509827966271488x, _ := new(big.Int).SetString("3f0d8994e51ad212f455452fbc9693a72f14a547af3806e9fbff59eeb441742e", 16) + g730750818665451459101842416358141509827966271488y, _ := new(big.Int).SetString("fbd76c23f28c3dc445e5cb0e847a6e0b1e205e2c3ad13d958c65363bcfecadbe", 16) + g1461501637330902918203684832716283019655932542976x, _ := new(big.Int).SetString("9c3919a84a474870faed8a9c1cc66021523489054d7f0308cbfc99c8ac1f98cd", 16) + g1461501637330902918203684832716283019655932542976y, _ := new(big.Int).SetString("ddb84f0f4a4ddd57584f044bf260e641905326f76c64c8e6be7e5e03d4fc599d", 16) + g2923003274661805836407369665432566039311865085952x, _ := new(big.Int).SetString("2e3c05326255d80f0a42fc69d5c92aa40cd326a53e8535f0435efb7b694a09ec", 16) + g2923003274661805836407369665432566039311865085952y, _ := new(big.Int).SetString("1ff891656c6fb5bddae240b82fc1abe048a53c707b66512534868188c7327e", 16) + g5846006549323611672814739330865132078623730171904x, _ := new(big.Int).SetString("e8e2a24ccfa41587ae15fb7e3e24dda433710316a1908934205f19a2ab9c7ce6", 16) + g5846006549323611672814739330865132078623730171904y, _ := new(big.Int).SetString("46c983ce0c6f5d1b4caf2b2b3bee20596e09e603b5c27a73b2c01eb68836267c", 16) + g11692013098647223345629478661730264157247460343808x, _ := new(big.Int).SetString("a7549aac5d8573c2b2f0a38b170032a212acaf92383d5b5f5b0d39668ac7b3c2", 16) + g11692013098647223345629478661730264157247460343808y, _ := new(big.Int).SetString("bd17d1b90d1c2415335a1d70c1947d2b5d6b5115537116dffa0c91719287eaef", 16) + g23384026197294446691258957323460528314494920687616x, _ := new(big.Int).SetString("6057170b1dd12fdf8de05f281d8e06bb91e1493a8b91d4cc5a21382120a959e5", 16) + g23384026197294446691258957323460528314494920687616y, _ := new(big.Int).SetString("9a1af0b26a6a4807add9a2daf71df262465152bc3ee24c65e899be932385a2a8", 16) + g46768052394588893382517914646921056628989841375232x, _ := new(big.Int).SetString("6773fd677c52e0640394110a46dc85df7c133f8dd4a28e661899ca5d82fd545c", 16) + g46768052394588893382517914646921056628989841375232y, _ := new(big.Int).SetString("444eb6d8cd97652f0f0f25c9dd2b246bead780f5a1c6cf98e8c7f034947eb1ae", 16) + g93536104789177786765035829293842113257979682750464x, _ := new(big.Int).SetString("e0f86d94d17ce565237c79aace0c87c20374e43810468050373c616b0b86f021", 16) + g93536104789177786765035829293842113257979682750464y, _ := new(big.Int).SetString("c571c73730abcf47a91e832f1c89a2c9a80bcc0115fc45b3b6b79ccb5bf325a", 16) + g187072209578355573530071658587684226515959365500928x, _ := new(big.Int).SetString("42ca15ab9f245041ce991e193d696f4f4c277df908cad6038ad0772c02da6e03", 16) + g187072209578355573530071658587684226515959365500928y, _ := new(big.Int).SetString("68d2ef26c81c57c9647ce4d1fcb800eed66e85a68106bea7836889fa8c347793", 16) + g374144419156711147060143317175368453031918731001856x, _ := new(big.Int).SetString("a576df8e23a08411421439a4518da31880cef0fba7d4df12b1a6973eecb94266", 16) + g374144419156711147060143317175368453031918731001856y, _ := new(big.Int).SetString("40a6bf20e76640b2c92b97afe58cd82c432e10a7f514d9f3ee8be11ae1b28ec8", 16) + g748288838313422294120286634350736906063837462003712x, _ := new(big.Int).SetString("9e5dcc62ef3b5a3b546520867be71bae6f3ba063c9acfb8dcec5725bda704896", 16) + g748288838313422294120286634350736906063837462003712y, _ := new(big.Int).SetString("6fedd12ddb925f3ea5fd3a2154c7612279605d186030f51248f2769dca82c835", 16) + g1496577676626844588240573268701473812127674924007424x, _ := new(big.Int).SetString("a7de08375b8745adf8d6e9f976f03b20e33625a05cef5833953ed58744bf7ea0", 16) + g1496577676626844588240573268701473812127674924007424y, _ := new(big.Int).SetString("a63d96b057ada5e52104a0b334888e9a645a47c0febc5aa2e04c05539bbcabaa", 16) + g2993155353253689176481146537402947624255349848014848x, _ := new(big.Int).SetString("c266658e689080c9c13c35ac01cff4cbe68065fde949e4a3a9f8fa104ad916fb", 16) + g2993155353253689176481146537402947624255349848014848y, _ := new(big.Int).SetString("e7e8593854e7daab0f798170b24627ab6b8fecdfeb61138856aef52ba0887814", 16) + g5986310706507378352962293074805895248510699696029696x, _ := new(big.Int).SetString("7778a78c28dec3e30a05fe9629de8c38bb30d1f5cf9a3a208f763889be58ad71", 16) + g5986310706507378352962293074805895248510699696029696y, _ := new(big.Int).SetString("34626d9ab5a5b22ff7098e12f2ff580087b38411ff24ac563b513fc1fd9f43ac", 16) + g11972621413014756705924586149611790497021399392059392x, _ := new(big.Int).SetString("e7b9796b5ca006d1632f482d7f0fe3932cf16a5ae104eea7a7ea1c251073e879", 16) + g11972621413014756705924586149611790497021399392059392y, _ := new(big.Int).SetString("12b8988c19169e2fdf42102a737cc1ca9cb5bf25eda98af338e71089baa89d98", 16) + g23945242826029513411849172299223580994042798784118784x, _ := new(big.Int).SetString("71bf01850876203c2c915a24be09a7365423daaf2aee919865d722bf2628f0f", 16) + g23945242826029513411849172299223580994042798784118784y, _ := new(big.Int).SetString("527aa15d504dcf4ae33600bc1c084ce2098f9c6a231c80bbb57c5cbd45a1c334", 16) + g47890485652059026823698344598447161988085597568237568x, _ := new(big.Int).SetString("218343acb9be56833a32e594c03c39e5b1911c8501213786f6376dfa39620e1", 16) + g47890485652059026823698344598447161988085597568237568y, _ := new(big.Int).SetString("bea81d48970a50beaf3f24fd602fbfc0443299a42f43c9ec5e0199f6506998b5", 16) + g95780971304118053647396689196894323976171195136475136x, _ := new(big.Int).SetString("928955ee637a84463729fd30e7afd2ed5f96274e5ad7e5cb09eda9c06d903ac", 16) + g95780971304118053647396689196894323976171195136475136y, _ := new(big.Int).SetString("c25621003d3f42a827b78a13093a95eeac3d26efa8a8d83fc5180e935bcd091f", 16) + g191561942608236107294793378393788647952342390272950272x, _ := new(big.Int).SetString("4f89bdee3771d350dad163b04cb18ad67ce5e9c55b58f0e7231047a60f59dd9e", 16) + g191561942608236107294793378393788647952342390272950272y, _ := new(big.Int).SetString("ca7952d5227a1f695c4baf4c043bb2471e4882506638df5c1016ae320156b049", 16) + g383123885216472214589586756787577295904684780545900544x, _ := new(big.Int).SetString("cb9e8304cae3c5a80c396baca2c3c4c994b668f079a245bf529c314cfff01197", 16) + g383123885216472214589586756787577295904684780545900544y, _ := new(big.Int).SetString("62c7d2801eb80e6a127258cdff08891741b2d18c015e0a24c334e0763b989c1d", 16) + g766247770432944429179173513575154591809369561091801088x, _ := new(big.Int).SetString("e2f349b0f89c69bd3c8cf2a410730dc58e0beed47048c58c15f9ffc2508d2cc2", 16) + g766247770432944429179173513575154591809369561091801088y, _ := new(big.Int).SetString("1feb2f280f82723781860aec760215ba42344be8e09cbdb37e347bd8e0d4c04f", 16) + g1532495540865888858358347027150309183618739122183602176x, _ := new(big.Int).SetString("85d0fef3ec6db109399064f3a0e3b2855645b4a907ad354527aae75163d82751", 16) + g1532495540865888858358347027150309183618739122183602176y, _ := new(big.Int).SetString("1f03648413a38c0be29d496e582cf5663e8751e96877331582c237a24eb1f962", 16) + g3064991081731777716716694054300618367237478244367204352x, _ := new(big.Int).SetString("6b790f4b19a4c4f4f607a6cfcd11df0468b482e009711ff756356d141d5fcade", 16) + g3064991081731777716716694054300618367237478244367204352y, _ := new(big.Int).SetString("d03a981b2ff9eb3ef296661f9cae09cba83fa5b47be26b0ab6fff86fc338d3ff", 16) + g6129982163463555433433388108601236734474956488734408704x, _ := new(big.Int).SetString("41149b2c2d7ebed3c162c367acc4f8fe3d2479de85978be0bb0ccdabe3a3e0cb", 16) + g6129982163463555433433388108601236734474956488734408704y, _ := new(big.Int).SetString("c90d5b92db7c30542b415c9b9902cf28b3ec7805ef490f2470e92e98339033a8", 16) + g12259964326927110866866776217202473468949912977468817408x, _ := new(big.Int).SetString("d1fad4fa4e7c849dfaec3dfe2872a7ba664a9b8205c29cebf8dddd28e3f3d3fc", 16) + g12259964326927110866866776217202473468949912977468817408y, _ := new(big.Int).SetString("8fe19714a348fdfe5473f70e858b7818bad37131eff37326ed22343c50f3704d", 16) + g24519928653854221733733552434404946937899825954937634816x, _ := new(big.Int).SetString("ff2b0dce97eece97c1c9b6041798b85dfdfb6d8882da20308f5404824526087e", 16) + g24519928653854221733733552434404946937899825954937634816y, _ := new(big.Int).SetString("493d13fef524ba188af4c4dc54d07936c7b7ed6fb90e2ceb2c951e01f0c29907", 16) + g49039857307708443467467104868809893875799651909875269632x, _ := new(big.Int).SetString("2982dbbc5f366c9f78e29ebbecb1bb223deb5c4ee638b4583bd3a9af3149f8ef", 16) + g49039857307708443467467104868809893875799651909875269632y, _ := new(big.Int).SetString("a61b5be9af66220ab9fa5339c7b5bc9d095db99412e3ed8456e726b016c7a248", 16) + g98079714615416886934934209737619787751599303819750539264x, _ := new(big.Int).SetString("1a28e5042af0c0f6b436eb590497db5860011f4580e1765885289f612380441b", 16) + g98079714615416886934934209737619787751599303819750539264y, _ := new(big.Int).SetString("55779a7996c59dab7c78329a8976f0ed04b3e75b46ee67aeb05f606a8452af25", 16) + g196159429230833773869868419475239575503198607639501078528x, _ := new(big.Int).SetString("c8b83e9535f30601d250cc0bd3f20142edd5eb7985d83242eef0e39621e30a7", 16) + g196159429230833773869868419475239575503198607639501078528y, _ := new(big.Int).SetString("dcc7077065fdac7b850e3f17efdc854aacad237b987134dbebf7beb9ff688de", 16) + g392318858461667547739736838950479151006397215279002157056x, _ := new(big.Int).SetString("827fbbe4b1e880ea9ed2b2e6301b212b57f1ee148cd6dd28780e5e2cf856e241", 16) + g392318858461667547739736838950479151006397215279002157056y, _ := new(big.Int).SetString("c60f9c923c727b0b71bef2c67d1d12687ff7a63186903166d605b68baec293ec", 16) + g784637716923335095479473677900958302012794430558004314112x, _ := new(big.Int).SetString("b77f12a7dce56b973e2d7c8d576e6b3660470a9218b87461ef6e44b70cb1815d", 16) + g784637716923335095479473677900958302012794430558004314112y, _ := new(big.Int).SetString("4b6f85b14f86acc43f0cefb373cc2e654c42f0f91a44816d6ba3d2bc8e57dbc5", 16) + g1569275433846670190958947355801916604025588861116008628224x, _ := new(big.Int).SetString("48973b943018bf1247b308b2cb79f956d858d8df4977c5970fe5dad2c45565ec", 16) + g1569275433846670190958947355801916604025588861116008628224y, _ := new(big.Int).SetString("761f75684f3cdc1b6437bb3a01445af1511b3596580477b83b879075faed07e9", 16) + g3138550867693340381917894711603833208051177722232017256448x, _ := new(big.Int).SetString("e931258e8eb5559c6d6972728a704c170b775a265b4527d4a4d4d742bbfd71fa", 16) + g3138550867693340381917894711603833208051177722232017256448y, _ := new(big.Int).SetString("fb1e33364c3fdee0e85eb4169c954b40b3946ce1bb5e35f33d9bd0d3174d3307", 16) + g6277101735386680763835789423207666416102355444464034512896x, _ := new(big.Int).SetString("eaa649f21f51bdbae7be4ae34ce6e5217a58fdce7f47f9aa7f3b58fa2120e2b3", 16) + g6277101735386680763835789423207666416102355444464034512896y, _ := new(big.Int).SetString("be3279ed5bbbb03ac69a80f89879aa5a01a6b965f13f7e59d47a5305ba5ad93d", 16) + g12554203470773361527671578846415332832204710888928069025792x, _ := new(big.Int).SetString("3adb9db3beb997eec2623ea5002279ea9e337b5c705f3db453dbc1cc1fc9b0a8", 16) + g12554203470773361527671578846415332832204710888928069025792y, _ := new(big.Int).SetString("374e2d6daee74e713c774de07c095ff6aad9c8f9870266cc61ae7975f05bbdda", 16) + g25108406941546723055343157692830665664409421777856138051584x, _ := new(big.Int).SetString("129e53ac428e9cbb7e10955e56c5fc69fefdff56963e7caf054e9e0c90ae86f9", 16) + g25108406941546723055343157692830665664409421777856138051584y, _ := new(big.Int).SetString("415ecb958aee9a29b2da2115b712183fb2a232fd16b3e01b822efdcd1e89c85d", 16) + g50216813883093446110686315385661331328818843555712276103168x, _ := new(big.Int).SetString("60144494c8f694485b85ecb6aee10956c756267d12894711922243d5e855b8da", 16) + g50216813883093446110686315385661331328818843555712276103168y, _ := new(big.Int).SetString("8bb5d669f681e6469e8be1fd9132e65b543955c27e3f2a4bad500590f34e4bbd", 16) + g100433627766186892221372630771322662657637687111424552206336x, _ := new(big.Int).SetString("e4a42d43c5cf169d9391df6decf42ee541b6d8f0c9a137401e23632dda34d24f", 16) + g100433627766186892221372630771322662657637687111424552206336y, _ := new(big.Int).SetString("4d9f92e716d1c73526fc99ccfb8ad34ce886eedfa8d8e4f13a7f7131deba9414", 16) + g200867255532373784442745261542645325315275374222849104412672x, _ := new(big.Int).SetString("fd6451fb84cfb18d3ef0acf856c4ef4d0553c562f7ae4d2a303f2ea33e8f62bb", 16) + g200867255532373784442745261542645325315275374222849104412672y, _ := new(big.Int).SetString("e745ceb2b1871578b6fe7a5c1bc344ccfa2ab492d200e83fd0ad9086132c0911", 16) + g401734511064747568885490523085290650630550748445698208825344x, _ := new(big.Int).SetString("1eee207cb24086bc716e81a06f9edbbb0042e2d5dcf3c7a1fa1d1fb9d5fe696b", 16) + g401734511064747568885490523085290650630550748445698208825344y, _ := new(big.Int).SetString("652cbd19aef6269cd2b196d12461c95f7a02062e0afd694ebb45670e7429337b", 16) + g803469022129495137770981046170581301261101496891396417650688x, _ := new(big.Int).SetString("cc0ea33ea8a9eb14d465ab2c346e2111e1c0fc017c57257908d40f19ef94c0d5", 16) + g803469022129495137770981046170581301261101496891396417650688y, _ := new(big.Int).SetString("f9907a3b711c8a2fb23dd203b5fbe663f6074f266113f543deabe597af452fe6", 16) + g1606938044258990275541962092341162602522202993782792835301376x, _ := new(big.Int).SetString("1ec80fef360cbdd954160fadab352b6b92b53576a88fea4947173b9d4300bf19", 16) + g1606938044258990275541962092341162602522202993782792835301376y, _ := new(big.Int).SetString("aeefe93756b5340d2f3a4958a7abbf5e0146e77f6295a07b671cdc1cc107cefd", 16) + g3213876088517980551083924184682325205044405987565585670602752x, _ := new(big.Int).SetString("5be7ea3519f04bc6cbeeaa0344fc90bb8e8462f6ebd890560dae805d414ff9e4", 16) + g3213876088517980551083924184682325205044405987565585670602752y, _ := new(big.Int).SetString("32f32ec3f638e605477f890f655ab7fe0e99c6302119a3094030b07847e0bdbb", 16) + g6427752177035961102167848369364650410088811975131171341205504x, _ := new(big.Int).SetString("58f099116eae4e650813fc8698df7f5cd50028649f853991e3fb545f4ddb7bb8", 16) + g6427752177035961102167848369364650410088811975131171341205504y, _ := new(big.Int).SetString("7e07002aaffe111a0d62ff7614638066507ee4062d174302bdec73582e5b2d6e", 16) + g12855504354071922204335696738729300820177623950262342682411008x, _ := new(big.Int).SetString("b0f9e4b9b29790b633bcc04fd860cb0f823d8d1a4cc1a1c1413c1606cc9a8e2c", 16) + g12855504354071922204335696738729300820177623950262342682411008y, _ := new(big.Int).SetString("49e82bf1843ade6d41cbb0b906fde3f03350cc02c171cee76c2066c4df3d0db4", 16) + g25711008708143844408671393477458601640355247900524685364822016x, _ := new(big.Int).SetString("146a778c04670c2f91b00af4680dfa8bce3490717d58ba889ddb5928366642be", 16) + g25711008708143844408671393477458601640355247900524685364822016y, _ := new(big.Int).SetString("b318e0ec3354028add669827f9d4b2870aaa971d2f7e5ed1d0b297483d83efd0", 16) + g51422017416287688817342786954917203280710495801049370729644032x, _ := new(big.Int).SetString("574ef0ce8a597e24e5670b5c0bcd14cfeefc983c7ecb261911b2365579de5cac", 16) + g51422017416287688817342786954917203280710495801049370729644032y, _ := new(big.Int).SetString("9b99930281f19c73bd6ada0569b78451a260a7bef10008cae59aea6c75a4805", 16) + g102844034832575377634685573909834406561420991602098741459288064x, _ := new(big.Int).SetString("d3d97e799d8bf9f85d909397b98c835d10a770c1aeff8645808c2d74260966d3", 16) + g102844034832575377634685573909834406561420991602098741459288064y, _ := new(big.Int).SetString("8ddbb46376bac95e6aaa89275d403ad3b5e48711be8dc4eebddeb850833c2e52", 16) + g205688069665150755269371147819668813122841983204197482918576128x, _ := new(big.Int).SetString("b1aa653288b318987b974e782cbbee0ab2be78cf8f494c120040fb93968c6d4b", 16) + g205688069665150755269371147819668813122841983204197482918576128y, _ := new(big.Int).SetString("7ed6071c60810d712684aa8e2d63a83b100a1d909d623cc383d9e62ae891ac51", 16) + g411376139330301510538742295639337626245683966408394965837152256x, _ := new(big.Int).SetString("fa50c0f61d22e5f07e3acebb1aa07b128d0012209a28b9776d76a8793180eef9", 16) + g411376139330301510538742295639337626245683966408394965837152256y, _ := new(big.Int).SetString("6b84c6922397eba9b72cd2872281a68a5e683293a57a213b38cd8d7d3f4f2811", 16) + g822752278660603021077484591278675252491367932816789931674304512x, _ := new(big.Int).SetString("63964eee619074e0780140fe02e90836e72328d2448386d459c5be23187f5048", 16) + g822752278660603021077484591278675252491367932816789931674304512y, _ := new(big.Int).SetString("3b6cfb3a6b89cf41a39ff9b1c34bfbc93d580b934dde6c84383a284d89309df8", 16) + g1645504557321206042154969182557350504982735865633579863348609024x, _ := new(big.Int).SetString("5a3ce25b4d15b7e22d1469ddf0fc9f75afd7f12ad3cbda31f814ba1ebadb2a65", 16) + g1645504557321206042154969182557350504982735865633579863348609024y, _ := new(big.Int).SetString("8b34125b92e05f63873a6dbfbf3f99af3ee28bc3d825fe8ed8b170cf1d327f1d", 16) + g3291009114642412084309938365114701009965471731267159726697218048x, _ := new(big.Int).SetString("5ce605af98f93eda6910be34f0de41ff85dbcb6e69a8fa0016a733754a9f44d0", 16) + g3291009114642412084309938365114701009965471731267159726697218048y, _ := new(big.Int).SetString("4cddcf9bec226bfe7ba56bd031c76c58ab3cb1bfa32eccc6c0d05f3489d30105", 16) + g6582018229284824168619876730229402019930943462534319453394436096x, _ := new(big.Int).SetString("da1d61d0ca721a11b1a5bf6b7d88e8421a288ab5d5bba5220e53d32b5f067ec2", 16) + g6582018229284824168619876730229402019930943462534319453394436096y, _ := new(big.Int).SetString("8157f55a7c99306c79c0766161c91e2966a73899d279b48a655fba0f1ad836f1", 16) + g13164036458569648337239753460458804039861886925068638906788872192x, _ := new(big.Int).SetString("9c7be00b4ef4c444df85d5f61dc1283a23605483e1f8e934b3c210d22cd3c369", 16) + g13164036458569648337239753460458804039861886925068638906788872192y, _ := new(big.Int).SetString("9220c0de74b20d2052a26d455ce401483e31153a16769cbd29ee3feba2329515", 16) + g26328072917139296674479506920917608079723773850137277813577744384x, _ := new(big.Int).SetString("fcd83f42825263bb55664b238ccc49174dd06a70541178e76bcd92d7bb8c9e3", 16) + g26328072917139296674479506920917608079723773850137277813577744384y, _ := new(big.Int).SetString("6c0bc1cfeac5fbced1d8232de5fdb683adbeaecdf1627bf4e86d55fbdf4aa9ad", 16) + g52656145834278593348959013841835216159447547700274555627155488768x, _ := new(big.Int).SetString("7175407f1b58f010d4cda4c62511e59db7edcf28f5476d995cf39944b26b64f1", 16) + g52656145834278593348959013841835216159447547700274555627155488768y, _ := new(big.Int).SetString("43b4554344e3d550f36d3401134cc86eb01fe8b774471d2a426e7efab24234d5", 16) + g105312291668557186697918027683670432318895095400549111254310977536x, _ := new(big.Int).SetString("a8e282ff0c9706907215ff98e8fd416615311de0446f1e062a73b0610d064e13", 16) + g105312291668557186697918027683670432318895095400549111254310977536y, _ := new(big.Int).SetString("7f97355b8db81c09abfb7f3c5b2515888b679a3e50dd6bd6cef7c73111f4cc0c", 16) + g210624583337114373395836055367340864637790190801098222508621955072x, _ := new(big.Int).SetString("cac6f2e7e27faecbcb876f805ea66e63efbe9eaa753d67c1c15eb9ea7f7653a1", 16) + g210624583337114373395836055367340864637790190801098222508621955072y, _ := new(big.Int).SetString("f7d416e5e2aa6f194cdb65d9a42a345081e83ae5688103a068c10ad0fec5e556", 16) + g421249166674228746791672110734681729275580381602196445017243910144x, _ := new(big.Int).SetString("e6dfde46ee37d206efbc5932e58e43254ab767294238cb11cc9f4ab08624003d", 16) + g421249166674228746791672110734681729275580381602196445017243910144y, _ := new(big.Int).SetString("8727b3b7be9139498f2f48f7b88f92203b1ce5ea527fd7dd7548650e2216b93b", 16) + g842498333348457493583344221469363458551160763204392890034487820288x, _ := new(big.Int).SetString("3c4e089cd9a6823d66a40cfc7ac96082e250e3149cf211d3b0e1103548dce109", 16) + g842498333348457493583344221469363458551160763204392890034487820288y, _ := new(big.Int).SetString("43fbbe669fe191b480757bca15764d379579e142d97fe697e2bf65923a19aeea", 16) + g1684996666696914987166688442938726917102321526408785780068975640576x, _ := new(big.Int).SetString("174a53b9c9a285872d39e56e6913cab15d59b1fa512508c022f382de8319497c", 16) + g1684996666696914987166688442938726917102321526408785780068975640576y, _ := new(big.Int).SetString("ccc9dc37abfc9c1657b4155f2c47f9e6646b3a1d8cb9854383da13ac079afa73", 16) + g3369993333393829974333376885877453834204643052817571560137951281152x, _ := new(big.Int).SetString("20e6e2e796946bb630c7071ef1b92ea3d53d280e0e4501115f5da36f840dd273", 16) + g3369993333393829974333376885877453834204643052817571560137951281152y, _ := new(big.Int).SetString("d3ad7afe4f1559e44a0ba1ad97874655811ec9793da8693cc07cfd15bb46b593", 16) + g6739986666787659948666753771754907668409286105635143120275902562304x, _ := new(big.Int).SetString("8e0ca824d7a351dba80280a07e71db7035ae68136cc24ca3e7b54f301a077674", 16) + g6739986666787659948666753771754907668409286105635143120275902562304y, _ := new(big.Int).SetString("4ec560759192d41dc569d24da62cf57cff60419d2f910290b84cbec12b7ed98", 16) + g13479973333575319897333507543509815336818572211270286240551805124608x, _ := new(big.Int).SetString("f7bb50da51c982d1c5fa63553e3d66c1afdb5821a321b4afe96afc5ea8192441", 16) + g13479973333575319897333507543509815336818572211270286240551805124608y, _ := new(big.Int).SetString("93cc3be30334a526311bc63bdde6485db1cfdc1fbbc4c74bbc640ea1d45165ae", 16) + g26959946667150639794667015087019630673637144422540572481103610249216x, _ := new(big.Int).SetString("959396981943785c3d3e57edf5018cdbe039e730e4918b3d884fdff09475b7ba", 16) + g26959946667150639794667015087019630673637144422540572481103610249216y, _ := new(big.Int).SetString("2e7e552888c331dd8ba0386a4b9cd6849c653f64c8709385e9b8abf87524f2fd", 16) + g53919893334301279589334030174039261347274288845081144962207220498432x, _ := new(big.Int).SetString("cbee1405ff0da7deafe32ca7dd73d95ed702226b391747c707275a940bc8f53b", 16) + g53919893334301279589334030174039261347274288845081144962207220498432y, _ := new(big.Int).SetString("f6211f4f4e75f902b51f3e689b8294cf0d9ff4f68126f7282922e6b278c87f45", 16) + g107839786668602559178668060348078522694548577690162289924414440996864x, _ := new(big.Int).SetString("add5bad28faaf5acdd580bfa0ba252e03de3beaefbd71b9cf377c88b14b311dd", 16) + g107839786668602559178668060348078522694548577690162289924414440996864y, _ := new(big.Int).SetString("e9c43cf4da3dc3a5974e434f8359814f52d4e1e7669b9b8902f982f349d6c38d", 16) + g215679573337205118357336120696157045389097155380324579848828881993728x, _ := new(big.Int).SetString("53f2432ba81717143fa9df3dff41ced24a29b314bc5a8c96f5f6400a0d7c0979", 16) + g215679573337205118357336120696157045389097155380324579848828881993728y, _ := new(big.Int).SetString("bd52effbc1f079b7ccd4e3e0911b07de4bd5a4f5c9e8b845f9f7e90c537b36a2", 16) + g431359146674410236714672241392314090778194310760649159697657763987456x, _ := new(big.Int).SetString("d2a63a50ae401e56d645a1153b109a8fcca0a43d561fba2dbb51340c9d82b151", 16) + g431359146674410236714672241392314090778194310760649159697657763987456y, _ := new(big.Int).SetString("e82d86fb6443fcb7565aee58b2948220a70f750af484ca52d4142174dcf89405", 16) + g862718293348820473429344482784628181556388621521298319395315527974912x, _ := new(big.Int).SetString("baf183a76100525e23bc7202033725f922b9cd6b36c413497c6c4bacca72da5f", 16) + g862718293348820473429344482784628181556388621521298319395315527974912y, _ := new(big.Int).SetString("deac9fbe9ccb4d335688bd58dd69b1d18e2336c5ca739361377ce628a8f2a0cf", 16) + g1725436586697640946858688965569256363112777243042596638790631055949824x, _ := new(big.Int).SetString("f7aef8a7e38440238f9332906e48f6fd5adbd02d56b76a5ffa5aca58c56c3943", 16) + g1725436586697640946858688965569256363112777243042596638790631055949824y, _ := new(big.Int).SetString("4e3b0b44d5ffda797c442bbdc3ab3fcfeec30184a8dcd003431f627facf442f1", 16) + g3450873173395281893717377931138512726225554486085193277581262111899648x, _ := new(big.Int).SetString("dfb547cb10019036c5a2e29f0dddbb1f7af2fa25a3c7a78c1fac945711924459", 16) + g3450873173395281893717377931138512726225554486085193277581262111899648y, _ := new(big.Int).SetString("9accd2a9ba0f47088b8389ce9dc864cc22af0930e5c031dcfa205e0dcc65fd9e", 16) + g6901746346790563787434755862277025452451108972170386555162524223799296x, _ := new(big.Int).SetString("64587e2335471eb890ee7896d7cfdc866bacbdbd3839317b3436f9b45617e073", 16) + g6901746346790563787434755862277025452451108972170386555162524223799296y, _ := new(big.Int).SetString("d99fcdd5bf6902e2ae96dd6447c299a185b90a39133aeab358299e5e9faf6589", 16) + g13803492693581127574869511724554050904902217944340773110325048447598592x, _ := new(big.Int).SetString("b866d6b142df940f2cf28b54c92f0c1294e0b6a22a91f2ef44bcd88c4384480d", 16) + g13803492693581127574869511724554050904902217944340773110325048447598592y, _ := new(big.Int).SetString("1914b0b3426aeb7089a278d7ea9ad7ac24e522804b1d86d60e659b470c4cafa8", 16) + g27606985387162255149739023449108101809804435888681546220650096895197184x, _ := new(big.Int).SetString("ec2bb89085de819ec4d9d1646102ba87e2d52ae4ed4fe455d229cda81db20d6c", 16) + g27606985387162255149739023449108101809804435888681546220650096895197184y, _ := new(big.Int).SetString("ccecc17661e013a1332f66f0650940c633a2364be87efa98a0e99c4d629cf4a0", 16) + g55213970774324510299478046898216203619608871777363092441300193790394368x, _ := new(big.Int).SetString("71c4a7e389e296ced39d75ef5e545905e50050640f50becf38a60ecb23b09d0f", 16) + g55213970774324510299478046898216203619608871777363092441300193790394368y, _ := new(big.Int).SetString("1313fadb737af3ba0af3e0a292f810aa786f2b084a62ffc7637b1f01720ddb62", 16) + g110427941548649020598956093796432407239217743554726184882600387580788736x, _ := new(big.Int).SetString("8481bde0e4e4d885b3a546d3e549de042f0aa6cea250e7fd358d6c86dd45e458", 16) + g110427941548649020598956093796432407239217743554726184882600387580788736y, _ := new(big.Int).SetString("38ee7b8cba5404dd84a25bf39cecb2ca900a79c42b262e556d64b1b59779057e", 16) + g220855883097298041197912187592864814478435487109452369765200775161577472x, _ := new(big.Int).SetString("9629a450bd383a8b9fd43c6cd1d492bf392ed605299561dde54433526ce9f114", 16) + g220855883097298041197912187592864814478435487109452369765200775161577472y, _ := new(big.Int).SetString("bf439b280c5fb6d7576befd220cef64db925593e5c56af8dca3972c4a24aa391", 16) + g441711766194596082395824375185729628956870974218904739530401550323154944x, _ := new(big.Int).SetString("b73b1c47ef1e4688eb1730da7cc893df1477d747e187e18383d38d9626ca6cc3", 16) + g441711766194596082395824375185729628956870974218904739530401550323154944y, _ := new(big.Int).SetString("584315cb294922a90a57d64bbcc805097322a25209757f5afac35d76a54fdba3", 16) + g883423532389192164791648750371459257913741948437809479060803100646309888x, _ := new(big.Int).SetString("edfe16b2db40180311f9892007a2fef7d05b2a3bb676899f9c6e2192d38f93e0", 16) + g883423532389192164791648750371459257913741948437809479060803100646309888y, _ := new(big.Int).SetString("ee6902f1fca5db3694d74faa4b05d0d25b3d5100c46e227e3d01793de29405ad", 16) + g1766847064778384329583297500742918515827483896875618958121606201292619776x, _ := new(big.Int).SetString("13464a57a78102aa62b6979ae817f4637ffcfed3c4b1ce30bcd6303f6caf666b", 16) + g1766847064778384329583297500742918515827483896875618958121606201292619776y, _ := new(big.Int).SetString("69be159004614580ef7e433453ccb0ca48f300a81d0942e13f495a907f6ecc27", 16) + g3533694129556768659166595001485837031654967793751237916243212402585239552x, _ := new(big.Int).SetString("eb3cf8f532245362ec05c88c85fe12d19182be7dceabe577c75849c6065084ae", 16) + g3533694129556768659166595001485837031654967793751237916243212402585239552y, _ := new(big.Int).SetString("c833c78222d9d70043fe63dcefdca4a1f52b45c5e7dbd2a66f67c1fff96b9480", 16) + g7067388259113537318333190002971674063309935587502475832486424805170479104x, _ := new(big.Int).SetString("bdf1a67d092d99974f7a60f2184519b2a576fcf984a201d9f8e5bcbcc2e9a5d0", 16) + g7067388259113537318333190002971674063309935587502475832486424805170479104y, _ := new(big.Int).SetString("4095902bab65a1aaa80be54a86bf7baaa6280b61e5626461cdb4f7018562ff7b", 16) + g14134776518227074636666380005943348126619871175004951664972849610340958208x, _ := new(big.Int).SetString("68856a6eddc4ec29cd5be267b64483b48c3b4196477da62abde5fc173b27e771", 16) + g14134776518227074636666380005943348126619871175004951664972849610340958208y, _ := new(big.Int).SetString("77a33df14f79a1fb13b6fd49c19f7b4a331d22f293b0733a6118d62a07bbdab6", 16) + g28269553036454149273332760011886696253239742350009903329945699220681916416x, _ := new(big.Int).SetString("bc4a9df5b713fe2e9aef430bcc1dc97a0cd9ccede2f28588cada3a0d2d83f366", 16) + g28269553036454149273332760011886696253239742350009903329945699220681916416y, _ := new(big.Int).SetString("d3a81ca6e785c06383937adf4b798caa6e8a9fbfa547b16d758d666581f33c1", 16) + g56539106072908298546665520023773392506479484700019806659891398441363832832x, _ := new(big.Int).SetString("da433d5e11ceccc0abc5c7626ce7bab42e89b221f785c409282de545f3fceb19", 16) + g56539106072908298546665520023773392506479484700019806659891398441363832832y, _ := new(big.Int).SetString("e498dbd321a810301debbdc4af95e5218e77fc2d9227b277684e7120a6f5cc64", 16) + g113078212145816597093331040047546785012958969400039613319782796882727665664x, _ := new(big.Int).SetString("31e8e1ee9e8c7ec1c1c116981c16efdbcc4838a72207e0654de275c5acf692a", 16) + g113078212145816597093331040047546785012958969400039613319782796882727665664y, _ := new(big.Int).SetString("ad7e7f5b465b353dd9d0970290d6743b70649827c5bf73b09cc2a84eb16f667a", 16) + g226156424291633194186662080095093570025917938800079226639565593765455331328x, _ := new(big.Int).SetString("a9878607a88d61155d3e00d862657f73e9c9bf363fc7a91592bbd7ff81f488b6", 16) + g226156424291633194186662080095093570025917938800079226639565593765455331328y, _ := new(big.Int).SetString("d181a1abd58895d61c063e7c82157c2239d0f01964ad5c6d495a7bbb031dab1d", 16) + g452312848583266388373324160190187140051835877600158453279131187530910662656x, _ := new(big.Int).SetString("8c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa", 16) + g452312848583266388373324160190187140051835877600158453279131187530910662656y, _ := new(big.Int).SetString("40a30463a3305193378fedf31f7cc0eb7ae784f0451cb9459e71dc73cbef9482", 16) + g904625697166532776746648320380374280103671755200316906558262375061821325312x, _ := new(big.Int).SetString("ab1ac1872a38a2f196bed5a6047f0da2c8130fe8de49fc4d5dfb201f7611d8e2", 16) + g904625697166532776746648320380374280103671755200316906558262375061821325312y, _ := new(big.Int).SetString("13f4a37a324d17a1e9aa5f39db6a42b6f7ef93d33e1e545f01a581f3c429d15b", 16) + g1809251394333065553493296640760748560207343510400633813116524750123642650624x, _ := new(big.Int).SetString("2564fe9b5beef82d3703a607253f31ef8ea1b365772df434226aee642651b3fa", 16) + g1809251394333065553493296640760748560207343510400633813116524750123642650624y, _ := new(big.Int).SetString("8ad9f7a60678389095fa14ae1203925f14f37dab6b79816edb82e6a301e5122d", 16) + g3618502788666131106986593281521497120414687020801267626233049500247285301248x, _ := new(big.Int).SetString("ff3d6136ffac5b0cbfc6c5c0c30dc01a7ea3d56c20bd3103b178e3d3ae180068", 16) + g3618502788666131106986593281521497120414687020801267626233049500247285301248y, _ := new(big.Int).SetString("133239be84e4000e40d0372cdd96adc1547676f24001f5e670a6bb6e188c6077", 16) + g7237005577332262213973186563042994240829374041602535252466099000494570602496x, _ := new(big.Int).SetString("8ea9666139527a8c1dd94ce4f071fd23c8b350c5a4bb33748c4ba111faccae0", 16) + g7237005577332262213973186563042994240829374041602535252466099000494570602496y, _ := new(big.Int).SetString("620efabbc8ee2782e24e7c0cfb95c5d735b783be9cf0f8e955af34a30e62b945", 16) + g14474011154664524427946373126085988481658748083205070504932198000989141204992x, _ := new(big.Int).SetString("c25f637176220cd9f3a66df315559d8263cf2a23a4ab5ab9a293131da190b632", 16) + g14474011154664524427946373126085988481658748083205070504932198000989141204992y, _ := new(big.Int).SetString("53154fede94d2873989049903809d7980a9f04ff9e027a1d6eebf3d6fc9590cf", 16) + g28948022309329048855892746252171976963317496166410141009864396001978282409984x, _ := new(big.Int).SetString("2a9e8dfe3cce6bab3e82d82a5688544c0c7b55dc31978b4de2ccb3b7d466d561", 16) + g28948022309329048855892746252171976963317496166410141009864396001978282409984y, _ := new(big.Int).SetString("1dfeda5c16e651fbac7b5ad608b96cf5e01eaec17a02182f96ccf5252e76373", 16) + g57896044618658097711785492504343953926634992332820282019728792003956564819968x, _ := new(big.Int).SetString("b23790a42be63e1b251ad6c94fdef07271ec0aada31db6c3e8bd32043f8be384", 16) + g57896044618658097711785492504343953926634992332820282019728792003956564819968y, _ := new(big.Int).SetString("fc6b694919d55edbe8d50f88aa81f94517f004f4149ecb58d10a473deb19880e", 16) + g115792089237316195423570985008687907853269984665640564039457584007913129639936x, _ := new(big.Int).SetString("dd3625faef5ba06074669716bbd3788d89bdde815959968092f76cc4eb9a9787", 16) + g115792089237316195423570985008687907853269984665640564039457584007913129639936y, _ := new(big.Int).SetString("7a188fa3520e30d461da2501045731ca941461982883395937f68d00c644a573", 16) return CurveParams{ - A: big.NewInt(0), - B: big.NewInt(7), - Gx: gx, - Gy: gy, + A: big.NewInt(0), + B: big.NewInt(7), + Gx: gx, + Gy: gy, + Gmx: [256]*big.Int{g2x, g4x, g8x, g16x, g32x, g64x, g128x, g256x, g512x, g1024x, g2048x, g4096x, g8192x, g16384x, g32768x, g65536x, g131072x, g262144x, g524288x, g1048576x, g2097152x, g4194304x, g8388608x, g16777216x, g33554432x, g67108864x, g134217728x, g268435456x, g536870912x, g1073741824x, g2147483648x, g4294967296x, g8589934592x, g17179869184x, g34359738368x, g68719476736x, g137438953472x, g274877906944x, g549755813888x, g1099511627776x, g2199023255552x, g4398046511104x, g8796093022208x, g17592186044416x, g35184372088832x, g70368744177664x, g140737488355328x, g281474976710656x, g562949953421312x, g1125899906842624x, g2251799813685248x, g4503599627370496x, g9007199254740992x, g18014398509481984x, g36028797018963968x, g72057594037927936x, g144115188075855872x, g288230376151711744x, g576460752303423488x, g1152921504606846976x, g2305843009213693952x, g4611686018427387904x, g9223372036854775808x, g18446744073709551616x, g36893488147419103232x, g73786976294838206464x, g147573952589676412928x, g295147905179352825856x, g590295810358705651712x, g1180591620717411303424x, g2361183241434822606848x, g4722366482869645213696x, g9444732965739290427392x, g18889465931478580854784x, g37778931862957161709568x, g75557863725914323419136x, g151115727451828646838272x, g302231454903657293676544x, g604462909807314587353088x, g1208925819614629174706176x, g2417851639229258349412352x, g4835703278458516698824704x, g9671406556917033397649408x, g19342813113834066795298816x, g38685626227668133590597632x, g77371252455336267181195264x, g154742504910672534362390528x, g309485009821345068724781056x, g618970019642690137449562112x, g1237940039285380274899124224x, g2475880078570760549798248448x, g4951760157141521099596496896x, g9903520314283042199192993792x, g19807040628566084398385987584x, g39614081257132168796771975168x, g79228162514264337593543950336x, g158456325028528675187087900672x, g316912650057057350374175801344x, g633825300114114700748351602688x, g1267650600228229401496703205376x, g2535301200456458802993406410752x, g5070602400912917605986812821504x, g10141204801825835211973625643008x, g20282409603651670423947251286016x, g40564819207303340847894502572032x, g81129638414606681695789005144064x, g162259276829213363391578010288128x, g324518553658426726783156020576256x, g649037107316853453566312041152512x, g1298074214633706907132624082305024x, g2596148429267413814265248164610048x, g5192296858534827628530496329220096x, g10384593717069655257060992658440192x, g20769187434139310514121985316880384x, g41538374868278621028243970633760768x, g83076749736557242056487941267521536x, g166153499473114484112975882535043072x, g332306998946228968225951765070086144x, g664613997892457936451903530140172288x, g1329227995784915872903807060280344576x, g2658455991569831745807614120560689152x, g5316911983139663491615228241121378304x, g10633823966279326983230456482242756608x, g21267647932558653966460912964485513216x, g42535295865117307932921825928971026432x, g85070591730234615865843651857942052864x, g170141183460469231731687303715884105728x, g340282366920938463463374607431768211456x, g680564733841876926926749214863536422912x, g1361129467683753853853498429727072845824x, g2722258935367507707706996859454145691648x, g5444517870735015415413993718908291383296x, g10889035741470030830827987437816582766592x, g21778071482940061661655974875633165533184x, g43556142965880123323311949751266331066368x, g87112285931760246646623899502532662132736x, g174224571863520493293247799005065324265472x, g348449143727040986586495598010130648530944x, g696898287454081973172991196020261297061888x, g1393796574908163946345982392040522594123776x, g2787593149816327892691964784081045188247552x, g5575186299632655785383929568162090376495104x, g11150372599265311570767859136324180752990208x, g22300745198530623141535718272648361505980416x, g44601490397061246283071436545296723011960832x, g89202980794122492566142873090593446023921664x, g178405961588244985132285746181186892047843328x, g356811923176489970264571492362373784095686656x, g713623846352979940529142984724747568191373312x, g1427247692705959881058285969449495136382746624x, g2854495385411919762116571938898990272765493248x, g5708990770823839524233143877797980545530986496x, g11417981541647679048466287755595961091061972992x, g22835963083295358096932575511191922182123945984x, g45671926166590716193865151022383844364247891968x, g91343852333181432387730302044767688728495783936x, g182687704666362864775460604089535377456991567872x, g365375409332725729550921208179070754913983135744x, g730750818665451459101842416358141509827966271488x, g1461501637330902918203684832716283019655932542976x, g2923003274661805836407369665432566039311865085952x, g5846006549323611672814739330865132078623730171904x, g11692013098647223345629478661730264157247460343808x, g23384026197294446691258957323460528314494920687616x, g46768052394588893382517914646921056628989841375232x, g93536104789177786765035829293842113257979682750464x, g187072209578355573530071658587684226515959365500928x, g374144419156711147060143317175368453031918731001856x, g748288838313422294120286634350736906063837462003712x, g1496577676626844588240573268701473812127674924007424x, g2993155353253689176481146537402947624255349848014848x, g5986310706507378352962293074805895248510699696029696x, g11972621413014756705924586149611790497021399392059392x, g23945242826029513411849172299223580994042798784118784x, g47890485652059026823698344598447161988085597568237568x, g95780971304118053647396689196894323976171195136475136x, g191561942608236107294793378393788647952342390272950272x, g383123885216472214589586756787577295904684780545900544x, g766247770432944429179173513575154591809369561091801088x, g1532495540865888858358347027150309183618739122183602176x, g3064991081731777716716694054300618367237478244367204352x, g6129982163463555433433388108601236734474956488734408704x, g12259964326927110866866776217202473468949912977468817408x, g24519928653854221733733552434404946937899825954937634816x, g49039857307708443467467104868809893875799651909875269632x, g98079714615416886934934209737619787751599303819750539264x, g196159429230833773869868419475239575503198607639501078528x, g392318858461667547739736838950479151006397215279002157056x, g784637716923335095479473677900958302012794430558004314112x, g1569275433846670190958947355801916604025588861116008628224x, g3138550867693340381917894711603833208051177722232017256448x, g6277101735386680763835789423207666416102355444464034512896x, g12554203470773361527671578846415332832204710888928069025792x, g25108406941546723055343157692830665664409421777856138051584x, g50216813883093446110686315385661331328818843555712276103168x, g100433627766186892221372630771322662657637687111424552206336x, g200867255532373784442745261542645325315275374222849104412672x, g401734511064747568885490523085290650630550748445698208825344x, g803469022129495137770981046170581301261101496891396417650688x, g1606938044258990275541962092341162602522202993782792835301376x, g3213876088517980551083924184682325205044405987565585670602752x, g6427752177035961102167848369364650410088811975131171341205504x, g12855504354071922204335696738729300820177623950262342682411008x, g25711008708143844408671393477458601640355247900524685364822016x, g51422017416287688817342786954917203280710495801049370729644032x, g102844034832575377634685573909834406561420991602098741459288064x, g205688069665150755269371147819668813122841983204197482918576128x, g411376139330301510538742295639337626245683966408394965837152256x, g822752278660603021077484591278675252491367932816789931674304512x, g1645504557321206042154969182557350504982735865633579863348609024x, g3291009114642412084309938365114701009965471731267159726697218048x, g6582018229284824168619876730229402019930943462534319453394436096x, g13164036458569648337239753460458804039861886925068638906788872192x, g26328072917139296674479506920917608079723773850137277813577744384x, g52656145834278593348959013841835216159447547700274555627155488768x, g105312291668557186697918027683670432318895095400549111254310977536x, g210624583337114373395836055367340864637790190801098222508621955072x, g421249166674228746791672110734681729275580381602196445017243910144x, g842498333348457493583344221469363458551160763204392890034487820288x, g1684996666696914987166688442938726917102321526408785780068975640576x, g3369993333393829974333376885877453834204643052817571560137951281152x, g6739986666787659948666753771754907668409286105635143120275902562304x, g13479973333575319897333507543509815336818572211270286240551805124608x, g26959946667150639794667015087019630673637144422540572481103610249216x, g53919893334301279589334030174039261347274288845081144962207220498432x, g107839786668602559178668060348078522694548577690162289924414440996864x, g215679573337205118357336120696157045389097155380324579848828881993728x, g431359146674410236714672241392314090778194310760649159697657763987456x, g862718293348820473429344482784628181556388621521298319395315527974912x, g1725436586697640946858688965569256363112777243042596638790631055949824x, g3450873173395281893717377931138512726225554486085193277581262111899648x, g6901746346790563787434755862277025452451108972170386555162524223799296x, g13803492693581127574869511724554050904902217944340773110325048447598592x, g27606985387162255149739023449108101809804435888681546220650096895197184x, g55213970774324510299478046898216203619608871777363092441300193790394368x, g110427941548649020598956093796432407239217743554726184882600387580788736x, g220855883097298041197912187592864814478435487109452369765200775161577472x, g441711766194596082395824375185729628956870974218904739530401550323154944x, g883423532389192164791648750371459257913741948437809479060803100646309888x, g1766847064778384329583297500742918515827483896875618958121606201292619776x, g3533694129556768659166595001485837031654967793751237916243212402585239552x, g7067388259113537318333190002971674063309935587502475832486424805170479104x, g14134776518227074636666380005943348126619871175004951664972849610340958208x, g28269553036454149273332760011886696253239742350009903329945699220681916416x, g56539106072908298546665520023773392506479484700019806659891398441363832832x, g113078212145816597093331040047546785012958969400039613319782796882727665664x, g226156424291633194186662080095093570025917938800079226639565593765455331328x, g452312848583266388373324160190187140051835877600158453279131187530910662656x, g904625697166532776746648320380374280103671755200316906558262375061821325312x, g1809251394333065553493296640760748560207343510400633813116524750123642650624x, g3618502788666131106986593281521497120414687020801267626233049500247285301248x, g7237005577332262213973186563042994240829374041602535252466099000494570602496x, g14474011154664524427946373126085988481658748083205070504932198000989141204992x, g28948022309329048855892746252171976963317496166410141009864396001978282409984x, g57896044618658097711785492504343953926634992332820282019728792003956564819968x, g115792089237316195423570985008687907853269984665640564039457584007913129639936x}, + Gmy: [256]*big.Int{g2y, g4y, g8y, g16y, g32y, g64y, g128y, g256y, g512y, g1024y, g2048y, g4096y, g8192y, g16384y, g32768y, g65536y, g131072y, g262144y, g524288y, g1048576y, g2097152y, g4194304y, g8388608y, g16777216y, g33554432y, g67108864y, g134217728y, g268435456y, g536870912y, g1073741824y, g2147483648y, g4294967296y, g8589934592y, g17179869184y, g34359738368y, g68719476736y, g137438953472y, g274877906944y, g549755813888y, g1099511627776y, g2199023255552y, g4398046511104y, g8796093022208y, g17592186044416y, g35184372088832y, g70368744177664y, g140737488355328y, g281474976710656y, g562949953421312y, g1125899906842624y, g2251799813685248y, g4503599627370496y, g9007199254740992y, g18014398509481984y, g36028797018963968y, g72057594037927936y, g144115188075855872y, g288230376151711744y, g576460752303423488y, g1152921504606846976y, g2305843009213693952y, g4611686018427387904y, g9223372036854775808y, g18446744073709551616y, g36893488147419103232y, g73786976294838206464y, g147573952589676412928y, g295147905179352825856y, g590295810358705651712y, g1180591620717411303424y, g2361183241434822606848y, g4722366482869645213696y, g9444732965739290427392y, g18889465931478580854784y, g37778931862957161709568y, g75557863725914323419136y, g151115727451828646838272y, g302231454903657293676544y, g604462909807314587353088y, g1208925819614629174706176y, g2417851639229258349412352y, g4835703278458516698824704y, g9671406556917033397649408y, g19342813113834066795298816y, g38685626227668133590597632y, g77371252455336267181195264y, g154742504910672534362390528y, g309485009821345068724781056y, g618970019642690137449562112y, g1237940039285380274899124224y, g2475880078570760549798248448y, g4951760157141521099596496896y, g9903520314283042199192993792y, g19807040628566084398385987584y, g39614081257132168796771975168y, g79228162514264337593543950336y, g158456325028528675187087900672y, g316912650057057350374175801344y, g633825300114114700748351602688y, g1267650600228229401496703205376y, g2535301200456458802993406410752y, g5070602400912917605986812821504y, g10141204801825835211973625643008y, g20282409603651670423947251286016y, g40564819207303340847894502572032y, g81129638414606681695789005144064y, g162259276829213363391578010288128y, g324518553658426726783156020576256y, g649037107316853453566312041152512y, g1298074214633706907132624082305024y, g2596148429267413814265248164610048y, g5192296858534827628530496329220096y, g10384593717069655257060992658440192y, g20769187434139310514121985316880384y, g41538374868278621028243970633760768y, g83076749736557242056487941267521536y, g166153499473114484112975882535043072y, g332306998946228968225951765070086144y, g664613997892457936451903530140172288y, g1329227995784915872903807060280344576y, g2658455991569831745807614120560689152y, g5316911983139663491615228241121378304y, g10633823966279326983230456482242756608y, g21267647932558653966460912964485513216y, g42535295865117307932921825928971026432y, g85070591730234615865843651857942052864y, g170141183460469231731687303715884105728y, g340282366920938463463374607431768211456y, g680564733841876926926749214863536422912y, g1361129467683753853853498429727072845824y, g2722258935367507707706996859454145691648y, g5444517870735015415413993718908291383296y, g10889035741470030830827987437816582766592y, g21778071482940061661655974875633165533184y, g43556142965880123323311949751266331066368y, g87112285931760246646623899502532662132736y, g174224571863520493293247799005065324265472y, g348449143727040986586495598010130648530944y, g696898287454081973172991196020261297061888y, g1393796574908163946345982392040522594123776y, g2787593149816327892691964784081045188247552y, g5575186299632655785383929568162090376495104y, g11150372599265311570767859136324180752990208y, g22300745198530623141535718272648361505980416y, g44601490397061246283071436545296723011960832y, g89202980794122492566142873090593446023921664y, g178405961588244985132285746181186892047843328y, g356811923176489970264571492362373784095686656y, g713623846352979940529142984724747568191373312y, g1427247692705959881058285969449495136382746624y, g2854495385411919762116571938898990272765493248y, g5708990770823839524233143877797980545530986496y, g11417981541647679048466287755595961091061972992y, g22835963083295358096932575511191922182123945984y, g45671926166590716193865151022383844364247891968y, g91343852333181432387730302044767688728495783936y, g182687704666362864775460604089535377456991567872y, g365375409332725729550921208179070754913983135744y, g730750818665451459101842416358141509827966271488y, g1461501637330902918203684832716283019655932542976y, g2923003274661805836407369665432566039311865085952y, g5846006549323611672814739330865132078623730171904y, g11692013098647223345629478661730264157247460343808y, g23384026197294446691258957323460528314494920687616y, g46768052394588893382517914646921056628989841375232y, g93536104789177786765035829293842113257979682750464y, g187072209578355573530071658587684226515959365500928y, g374144419156711147060143317175368453031918731001856y, g748288838313422294120286634350736906063837462003712y, g1496577676626844588240573268701473812127674924007424y, g2993155353253689176481146537402947624255349848014848y, g5986310706507378352962293074805895248510699696029696y, g11972621413014756705924586149611790497021399392059392y, g23945242826029513411849172299223580994042798784118784y, g47890485652059026823698344598447161988085597568237568y, g95780971304118053647396689196894323976171195136475136y, g191561942608236107294793378393788647952342390272950272y, g383123885216472214589586756787577295904684780545900544y, g766247770432944429179173513575154591809369561091801088y, g1532495540865888858358347027150309183618739122183602176y, g3064991081731777716716694054300618367237478244367204352y, g6129982163463555433433388108601236734474956488734408704y, g12259964326927110866866776217202473468949912977468817408y, g24519928653854221733733552434404946937899825954937634816y, g49039857307708443467467104868809893875799651909875269632y, g98079714615416886934934209737619787751599303819750539264y, g196159429230833773869868419475239575503198607639501078528y, g392318858461667547739736838950479151006397215279002157056y, g784637716923335095479473677900958302012794430558004314112y, g1569275433846670190958947355801916604025588861116008628224y, g3138550867693340381917894711603833208051177722232017256448y, g6277101735386680763835789423207666416102355444464034512896y, g12554203470773361527671578846415332832204710888928069025792y, g25108406941546723055343157692830665664409421777856138051584y, g50216813883093446110686315385661331328818843555712276103168y, g100433627766186892221372630771322662657637687111424552206336y, g200867255532373784442745261542645325315275374222849104412672y, g401734511064747568885490523085290650630550748445698208825344y, g803469022129495137770981046170581301261101496891396417650688y, g1606938044258990275541962092341162602522202993782792835301376y, g3213876088517980551083924184682325205044405987565585670602752y, g6427752177035961102167848369364650410088811975131171341205504y, g12855504354071922204335696738729300820177623950262342682411008y, g25711008708143844408671393477458601640355247900524685364822016y, g51422017416287688817342786954917203280710495801049370729644032y, g102844034832575377634685573909834406561420991602098741459288064y, g205688069665150755269371147819668813122841983204197482918576128y, g411376139330301510538742295639337626245683966408394965837152256y, g822752278660603021077484591278675252491367932816789931674304512y, g1645504557321206042154969182557350504982735865633579863348609024y, g3291009114642412084309938365114701009965471731267159726697218048y, g6582018229284824168619876730229402019930943462534319453394436096y, g13164036458569648337239753460458804039861886925068638906788872192y, g26328072917139296674479506920917608079723773850137277813577744384y, g52656145834278593348959013841835216159447547700274555627155488768y, g105312291668557186697918027683670432318895095400549111254310977536y, g210624583337114373395836055367340864637790190801098222508621955072y, g421249166674228746791672110734681729275580381602196445017243910144y, g842498333348457493583344221469363458551160763204392890034487820288y, g1684996666696914987166688442938726917102321526408785780068975640576y, g3369993333393829974333376885877453834204643052817571560137951281152y, g6739986666787659948666753771754907668409286105635143120275902562304y, g13479973333575319897333507543509815336818572211270286240551805124608y, g26959946667150639794667015087019630673637144422540572481103610249216y, g53919893334301279589334030174039261347274288845081144962207220498432y, g107839786668602559178668060348078522694548577690162289924414440996864y, g215679573337205118357336120696157045389097155380324579848828881993728y, g431359146674410236714672241392314090778194310760649159697657763987456y, g862718293348820473429344482784628181556388621521298319395315527974912y, g1725436586697640946858688965569256363112777243042596638790631055949824y, g3450873173395281893717377931138512726225554486085193277581262111899648y, g6901746346790563787434755862277025452451108972170386555162524223799296y, g13803492693581127574869511724554050904902217944340773110325048447598592y, g27606985387162255149739023449108101809804435888681546220650096895197184y, g55213970774324510299478046898216203619608871777363092441300193790394368y, g110427941548649020598956093796432407239217743554726184882600387580788736y, g220855883097298041197912187592864814478435487109452369765200775161577472y, g441711766194596082395824375185729628956870974218904739530401550323154944y, g883423532389192164791648750371459257913741948437809479060803100646309888y, g1766847064778384329583297500742918515827483896875618958121606201292619776y, g3533694129556768659166595001485837031654967793751237916243212402585239552y, g7067388259113537318333190002971674063309935587502475832486424805170479104y, g14134776518227074636666380005943348126619871175004951664972849610340958208y, g28269553036454149273332760011886696253239742350009903329945699220681916416y, g56539106072908298546665520023773392506479484700019806659891398441363832832y, g113078212145816597093331040047546785012958969400039613319782796882727665664y, g226156424291633194186662080095093570025917938800079226639565593765455331328y, g452312848583266388373324160190187140051835877600158453279131187530910662656y, g904625697166532776746648320380374280103671755200316906558262375061821325312y, g1809251394333065553493296640760748560207343510400633813116524750123642650624y, g3618502788666131106986593281521497120414687020801267626233049500247285301248y, g7237005577332262213973186563042994240829374041602535252466099000494570602496y, g14474011154664524427946373126085988481658748083205070504932198000989141204992y, g28948022309329048855892746252171976963317496166410141009864396001978282409984y, g57896044618658097711785492504343953926634992332820282019728792003956564819968y, g115792089237316195423570985008687907853269984665640564039457584007913129639936y}, } } @@ -39,11 +555,527 @@ func GetSecp256k1Params() CurveParams { func GetBN254Params() CurveParams { gx := big.NewInt(1) gy := big.NewInt(2) + g2x, _ := new(big.Int).SetString("30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd3", 16) + g2y, _ := new(big.Int).SetString("15ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4", 16) + g4x, _ := new(big.Int).SetString("6a7b64af8f414bcbeef455b1da5208c9b592b83ee6599824caa6d2ee9141a76", 16) + g4y, _ := new(big.Int).SetString("8e74e438cee31ac104ce59b94e45fe98a97d8f8a6e75664ce88ef5a41e72fbc", 16) + g8x, _ := new(big.Int).SetString("8b1d51d23480c10f472f5e93b9cfea88238c121fe155af7043937882c306a63", 16) + g8y, _ := new(big.Int).SetString("299836713dad3fa34e337aa412466015c366af8ec50b9d7bd05aa74642822021", 16) + g16x, _ := new(big.Int).SetString("17f485337f6e10fca0e385f7a93d1ac0a977e43995c3e4d9b8f89daa6a183f44", 16) + g16y, _ := new(big.Int).SetString("5ccdc1561db963516da62c66edd39d1bb9c6c4674990c4440403c88025c95ad", 16) + g32x, _ := new(big.Int).SetString("ac610b573e9fb98deaf5aa48feb447536418ddc4cefd17c277c852a2a02a413", 16) + g32y, _ := new(big.Int).SetString("1940e395f5eeaaf3b73a54a9db9910c3b7f907cad7f55137fb0c3847a682d315", 16) + g64x, _ := new(big.Int).SetString("6b7c24035a06c42bcb47d54df4104cd8880f68263afce13250ecc65f7669d1e", 16) + g64y, _ := new(big.Int).SetString("2179e38c6e6341d1c80b4ed2ad6d43188c01c2f70a8093b37fc02f9fd9e5f12f", 16) + g128x, _ := new(big.Int).SetString("2295215c9285bdc4f6beefdeccc5ccb67bbb9959f05f4c2a716a8f442fa69498", 16) + g128y, _ := new(big.Int).SetString("10174283cbb851eaf5f64a278b0fe58fb9b3b0b6a31439012ebe8d731bcdf851", 16) + g256x, _ := new(big.Int).SetString("2b9cd0bae01dfefdb859f3fbacbc897d6174d717103bf3b64dc43276541a2034", 16) + g256y, _ := new(big.Int).SetString("13b64ed1d986a508cbe5b28ca1429210b9c1aff6fb358af406159ff2773181ce", 16) + g512x, _ := new(big.Int).SetString("b0543208dea7cf4a213340ea328fe41297a9adae0d846bdba6a63682164520e", 16) + g512y, _ := new(big.Int).SetString("11fc9d481c85491a1c76370c03abb451edaad8d165909fd8bcef0b0523ea1598", 16) + g1024x, _ := new(big.Int).SetString("24236c8ead13686698f502d88ced24d4a4f4d97d857f7a404dab22a7d7010281", 16) + g1024y, _ := new(big.Int).SetString("14f25da82adf5997cd262a35f883666cd8fb73558e864094f04cafd100d70121", 16) + g2048x, _ := new(big.Int).SetString("42075949fd411801cdb82e636cbaeba5913ee29901d9294e4ec8016fed7de8d", 16) + g2048y, _ := new(big.Int).SetString("18cd5594fbf0daec1813cbbe6752ec1fc46f951b26c19031466364b772f37f47", 16) + g4096x, _ := new(big.Int).SetString("1e55ddfd2bc59eed77164fe02d0232b3d497792ec225376f3c3f5ec2f731fcf9", 16) + g4096y, _ := new(big.Int).SetString("24b3e64690c93b37546abdc4ee90b916e2d3605eb218cf26ef5868d2b666072b", 16) + g8192x, _ := new(big.Int).SetString("133b598ecf07b15b4badc0af8b67d74f574a29c1ef79a426fe1271e235e61e00", 16) + g8192y, _ := new(big.Int).SetString("65bab42b71a49a87ea2b1e39d69612daf58372130af040f503b71b689ac9b8d", 16) + g16384x, _ := new(big.Int).SetString("15dab2550a7d9679f0a528cde54154b2d9ebd399a16691e13f3f28b17f72f7d6", 16) + g16384y, _ := new(big.Int).SetString("178ce9329c1a5914a6561c281c981810a1554be17533bf6e7ce5a03e18f67889", 16) + g32768x, _ := new(big.Int).SetString("145bc328b9b296659851f12d70e35a9ca48cbde2af8a8ad8c9f2b3e0dff32306", 16) + g32768y, _ := new(big.Int).SetString("29556d2e78ac6045e5dd6d555ec184c802c9e0599a8d5173103841caaf829633", 16) + g65536x, _ := new(big.Int).SetString("26e06be6332f9f22b10167247f35f7805a11658a38dbb75d480af28117a525c5", 16) + g65536y, _ := new(big.Int).SetString("5e492d706a927c51e6180228d8be86d15017d61160867d231101e2790e2f451", 16) + g131072x, _ := new(big.Int).SetString("173562ccf10ecd0d4fa859860fda7fbd91089fa60e69dc72fafdd35516ea77af", 16) + g131072y, _ := new(big.Int).SetString("2ecf52567da025409374e147a7e63641b341b7b0e90104d86688d1c244890fce", 16) + g262144x, _ := new(big.Int).SetString("1f2434b943605601a75d294aba1bf13f0ff5db8d7e0a3500b5f4c1bc41e786dc", 16) + g262144y, _ := new(big.Int).SetString("262db6caeadc85809eec6eaec5a25cf46cc7c753a1e28313321fcdbaab1c38", 16) + g524288x, _ := new(big.Int).SetString("3762e07278ae0306a4c00f906f8f2e4d59373bfe860160c0fd9c5e77c46be52", 16) + g524288y, _ := new(big.Int).SetString("25537898872f823d23934c27f897ad4f40773d14b4fd32bc0cde718aa9cb87b9", 16) + g1048576x, _ := new(big.Int).SetString("2cbfb0fe6c22c116187ef88cab54ae9612bca6cc0738379098e3f0c4a4ffe44d", 16) + g1048576y, _ := new(big.Int).SetString("18e367e3d08db17ce4fa3e487e6268c2ba168da6b239a84bf2ea8f2ff0f4c469", 16) + g2097152x, _ := new(big.Int).SetString("55c8d5787694c618d99a4a31e6b68173176fd3ee152aa0bc009e99279a9b348", 16) + g2097152y, _ := new(big.Int).SetString("cb17a49107a9cfbe06478a33ba7e48e279bb9904ee0d6681cc72edea5b984e9", 16) + g4194304x, _ := new(big.Int).SetString("1f4465d62aac0c486d54b87e00f9ea1454aea3f1b0807c471fc172383b0886c8", 16) + g4194304y, _ := new(big.Int).SetString("2fee931883b4bf0d0d2e303bc10317533e6c974d3d884f9315f8d78840e1363c", 16) + g8388608x, _ := new(big.Int).SetString("127b3ab3ee067a5c41553648568b7882ce8ced215bfa190979668b3bc81eb1fc", 16) + g8388608y, _ := new(big.Int).SetString("5e5a09c5ae9de4c0492a8033cf035672a55797cadfc1e6860aab21c32a78112", 16) + g16777216x, _ := new(big.Int).SetString("35b261363afc5e03923315a3dfdfbc2c932d94bc19320f3ab411a203df4b44f", 16) + g16777216y, _ := new(big.Int).SetString("57df51fa44deb6f13412a77fd4325aceec98dfe6036cf74c71a5675f7fe1342", 16) + g33554432x, _ := new(big.Int).SetString("154aceb2bad07cdc9e1e0239e75f74d2b63a297881f9adcb166edb88fe076f4c", 16) + g33554432y, _ := new(big.Int).SetString("2f7568bf2fa097d86b7858e8701480e26d6d42fc819858b2137a427ee5b9a1da", 16) + g67108864x, _ := new(big.Int).SetString("9a6e5836835dd5677aa892580f15382da285a1b1379a67fd54d21664fe5681d", 16) + g67108864y, _ := new(big.Int).SetString("29f5850d45dfc5f3126fd0da3ea2c23ae965655112b9c2771cf2e73a2861ac5d", 16) + g134217728x, _ := new(big.Int).SetString("2566879ca48921f6fe14df4d20d2f9e24024c9d438b131bc30b06efc35dee0f9", 16) + g134217728y, _ := new(big.Int).SetString("2ddf0f6cd3e69d0a018bb01bf69ede7299a90eb9e40ee68dc50fc1b57f42011f", 16) + g268435456x, _ := new(big.Int).SetString("8c4de3bb9284981741584663ff2b08ad9fea7b6fd7f867f558d768cab6683f0", 16) + g268435456y, _ := new(big.Int).SetString("f9c2bd3727428ed114cd7860e28daf81cb9cb7dcdd26bb704dcc13b4314dd6a", 16) + g536870912x, _ := new(big.Int).SetString("a9cfe416626f75b3be8249cbcb7f3732bc7601cf581f774ebea4254dd06a31e", 16) + g536870912y, _ := new(big.Int).SetString("2f37ade304c81412d4ae613bf6d46db48b794a815bffc4413fc4872fd3e54e15", 16) + g1073741824x, _ := new(big.Int).SetString("258872f55cb9b9d5085401f6dfd3ae97c4adf21c3f5a391ee055fbbd9dc4754e", 16) + g1073741824y, _ := new(big.Int).SetString("537cfe016384089d64f027080a6061dc147732e6cd9c5bc1818d20ccf9958cc", 16) + g2147483648x, _ := new(big.Int).SetString("1e46ffd3559b30f6d101a2b49be6d213a9c40979ce8cb6b3c30ac308259bb5f4", 16) + g2147483648y, _ := new(big.Int).SetString("8c2c33416234b10c20e4b8bf0a1c1af83b964df68eda56adf0dae561518f704", 16) + g4294967296x, _ := new(big.Int).SetString("8d1b64842bc402bf13683a6c6f35b5c3d20bc295b2b29547889abb503000938", 16) + g4294967296y, _ := new(big.Int).SetString("8dd9da05595bb2f247f8254c0b5c522610ef4ff6de3397d6a35c2cd57d5ff0a", 16) + g8589934592x, _ := new(big.Int).SetString("17ce741466bfe6b7ddd079fc1b829fc11c670ae647603cc16f07ec4ee9907076", 16) + g8589934592y, _ := new(big.Int).SetString("135c40e7ae971f4f02715e9eacfb0edd48544329e207dcd9e09e3a1d6a7ef9d3", 16) + g17179869184x, _ := new(big.Int).SetString("2560de7ec1fce358673f10c20b44ad547058e357b6abcad273e4de32f8901926", 16) + g17179869184y, _ := new(big.Int).SetString("1ce0ed3c1313830bbf40fe0d7843c66dc5a67680004df9bac115c39ad61a6434", 16) + g34359738368x, _ := new(big.Int).SetString("1d0ab19190a9eea7211606a352bc936d6605a190090ac0843a8beedb54bfcd60", 16) + g34359738368y, _ := new(big.Int).SetString("11013587e7511d4a0d9511b142867820cea6cb9c3d7a8db3ac3230521bfdbb98", 16) + g68719476736x, _ := new(big.Int).SetString("ce765d04f6147d2ec7fd6b47a674fe19734ba8732f9f5b2201fced57eac06d1", 16) + g68719476736y, _ := new(big.Int).SetString("17e32bc3032ce94020638e7d2ab3cb5ccbe6f0b06faf6821fa8e3e4401a5c5f3", 16) + g137438953472x, _ := new(big.Int).SetString("f4dc779722c9006a9c18edb82b48827e1620600ec0d8bf5ea38a9aff00b2fad", 16) + g137438953472y, _ := new(big.Int).SetString("85e58b989c3118da095b0e96fe2b07080d4a7a2c1e68b00de0a673d6ba338c1", 16) + g274877906944x, _ := new(big.Int).SetString("2732bbe06b941c9e2d5b43837d8c5d9c23b7d9e8d5e623427ff3b61f2f5a5a07", 16) + g274877906944y, _ := new(big.Int).SetString("2b591b8a3c2bfe17bd639fc6a77244aa8629abe4bee101a444e4f24f36f1cef4", 16) + g549755813888x, _ := new(big.Int).SetString("27e2e192f061b31a05a77bf2ef3197550a6a3d87137f94166ead6c6bc962dd79", 16) + g549755813888y, _ := new(big.Int).SetString("2d6ed80f66dcba2fa0170b308717dd966f6f290acbf61affd81681234c8c2c06", 16) + g1099511627776x, _ := new(big.Int).SetString("2b74bc4a2f94e7ee3305368999840142e80348e9464caef350c14219abe982ba", 16) + g1099511627776y, _ := new(big.Int).SetString("28ece478e5bef9a805431237214101dd7e42d6619d13344fb5f38cfca35be682", 16) + g2199023255552x, _ := new(big.Int).SetString("22c175e3c8487841f7e95a1448695383526f6b54fa1bd5dc08abc316e31e3517", 16) + g2199023255552y, _ := new(big.Int).SetString("149630c26a8011eff9ef41663b42cb704da419e23b884b7b24414a6561bff9ab", 16) + g4398046511104x, _ := new(big.Int).SetString("1b05155447aaa6fa1ea292a769950cfdbf195dabb8101a25902b5da432322076", 16) + g4398046511104y, _ := new(big.Int).SetString("10575afe16844a09fe4b002623c91f29e52bdebbe29e235f2090c39a930e8c2c", 16) + g8796093022208x, _ := new(big.Int).SetString("2a8577ed48db5ac9e9fa8dfa247f27b3e60d89f1827647685799666c97f1a833", 16) + g8796093022208y, _ := new(big.Int).SetString("902486bd83fd098aa054ffc4cb97ab085cc2f16ac36046994cc30a023107b1d", 16) + g17592186044416x, _ := new(big.Int).SetString("1d9a6be49fb8d2ac15dc3d5c94e14a1503ab0b3ca6a21cad875d6b1a79faa9ae", 16) + g17592186044416y, _ := new(big.Int).SetString("28026c4fe5e3beecfefcfc52d868ec17888e6b9e926ecfebea979f4da743e98c", 16) + g35184372088832x, _ := new(big.Int).SetString("732fab1b46a9d2f5d4e4c0ae76b33d747b97fd120d5a48b403368c0ca59e3e0", 16) + g35184372088832y, _ := new(big.Int).SetString("10ee4d49117fc0c55faee5550615ab0e2020d1cffe21a9138b45be3861386f7", 16) + g70368744177664x, _ := new(big.Int).SetString("1781ee986bd68597bf4d4d208c4288599de61e144c3bdc0400d099816411cd05", 16) + g70368744177664y, _ := new(big.Int).SetString("2ab3082b4ee85457502bfd2c20b89df4181ecd32aba9f00d68a92d8f081c1846", 16) + g140737488355328x, _ := new(big.Int).SetString("2ef769820679d51c8ad33309549d630a069c2e0bedd5f6408bc7932f8bd47fc8", 16) + g140737488355328y, _ := new(big.Int).SetString("6abd56e6a2300623d6945f2f2e965836e0ea9518549579ae5626fbee7a98b01", 16) + g281474976710656x, _ := new(big.Int).SetString("c56565b409d0661559f47150adb952432a186ba0c316d0360db359b32b7b05a", 16) + g281474976710656y, _ := new(big.Int).SetString("1d312504121f5a89e8abc692156492ab42ade35fbeef59b84a720513f9407f51", 16) + g562949953421312x, _ := new(big.Int).SetString("2bd2e4fcc5e329ac6859e2bed1443604639c50181b461499a1ff41d65948615e", 16) + g562949953421312y, _ := new(big.Int).SetString("c6b0aaf39ab436c4d8245cce97c862198c92af61bcfa8e260b78f8b3125609f", 16) + g1125899906842624x, _ := new(big.Int).SetString("111e14c693b4e2f022cd64a6fb0a9a2c30a43eb830af2d536d47d65e31621b35", 16) + g1125899906842624y, _ := new(big.Int).SetString("2556301d79a6b88a9ee4e0c6c7cbf32c998de755f5229cae477b9ae2a688f6ea", 16) + g2251799813685248x, _ := new(big.Int).SetString("61d62988ebd3a3a643e088f5a5117b03e3342eb44aeade5be5e769c8ec5471c", 16) + g2251799813685248y, _ := new(big.Int).SetString("fd8ed00f9e0d1a9b4ce715d06e3a592a38e60e80bc6102764a208f72bab79cb", 16) + g4503599627370496x, _ := new(big.Int).SetString("2bcb97abadf5cc9ebb2146867d6f7451db29fba33dfe8a34ab680dead115e00a", 16) + g4503599627370496y, _ := new(big.Int).SetString("8cf030bdc7a851154cdcd01609d064c93b03ad7808e8f306ab488261db73320", 16) + g9007199254740992x, _ := new(big.Int).SetString("1d174577a9c53cefd85d6bbbdcb5b8f292a884b26f0ea403dd10db43ed6f9a8b", 16) + g9007199254740992y, _ := new(big.Int).SetString("7bb9915573ee3bf341981f4905a2d96167e228b90c8d9dd430530574cf75899", 16) + g18014398509481984x, _ := new(big.Int).SetString("591f4466b7a4ba962d097beaecdb6bd8d17cbea3bd5fb9cc8e166322755869f", 16) + g18014398509481984y, _ := new(big.Int).SetString("1b1808e9fc843a9efe02f7493cecb95c608c316d4ed98f194003ca292a8bbe89", 16) + g36028797018963968x, _ := new(big.Int).SetString("33a47533babbe960c581d996a10c697efeecfcd62b36b6124f5d3c793348962", 16) + g36028797018963968y, _ := new(big.Int).SetString("2f7a4ff5aaa8a0e2cfca3a1401601a52b80aa7cba4991b380f429d26d940924a", 16) + g72057594037927936x, _ := new(big.Int).SetString("1425b11b4fe47a394dbfc0ad3e99dc93c3e1c0980b9bcb68529ba9de33dbf585", 16) + g72057594037927936y, _ := new(big.Int).SetString("168b8cdff7ae7d084fd111608fa03e018b415fd4f0755f7e8f039a2d852bda0e", 16) + g144115188075855872x, _ := new(big.Int).SetString("1281e1b4ae3aa4404c0181f688fecb6c0c4449ee646c0438702eab87f4b7dd1", 16) + g144115188075855872y, _ := new(big.Int).SetString("18d37f7e79d7dfdd82187cc71e706ebe6353499493e23fb8ae536e47db8ce60a", 16) + g288230376151711744x, _ := new(big.Int).SetString("3fd1c6811aba796990bec7a6e1c93456bc73bd41b090d6be589826e49b1ae21", 16) + g288230376151711744y, _ := new(big.Int).SetString("269f5d44435fd8dea26779b7f46c23b4bed44fa1d9863c9880f010959bb4aa88", 16) + g576460752303423488x, _ := new(big.Int).SetString("ec6fc4a5b4e315512f882a012443a460f0ad440410931b3d2f16125b5e08b17", 16) + g576460752303423488y, _ := new(big.Int).SetString("13d2044189630abd18c6a3d7dad67c97b771597be79693a5de68da0ffa2676d3", 16) + g1152921504606846976x, _ := new(big.Int).SetString("1fd5ddc117799eac4054d556ea4dd922ae145542d5524a29a0cad3ec7ec810e8", 16) + g1152921504606846976y, _ := new(big.Int).SetString("27bb413910ef0b9339d3262cde13e189d0b2e64f0c073fc81da5747676ca645e", 16) + g2305843009213693952x, _ := new(big.Int).SetString("2d1b7db11118809263c79240df010a2415abafca8d4248788158bfd6f2141969", 16) + g2305843009213693952y, _ := new(big.Int).SetString("75158f7b9c5890a51d5b46a86e6e3f04f20dc8cafca5e5c3772eb508e2390f1", 16) + g4611686018427387904x, _ := new(big.Int).SetString("2dd2737976a05341def306c8899cf11d24b52f3230f36b6cdbba3fb971cfde1", 16) + g4611686018427387904y, _ := new(big.Int).SetString("1a15e9c72c124e695b6fe0c535bc1c0265ec884cf74b53de358de6d5c956ed73", 16) + g9223372036854775808x, _ := new(big.Int).SetString("1df18f1f725582b96a446cd7fb021d67a357626fbc37e35599ed2d117359d294", 16) + g9223372036854775808y, _ := new(big.Int).SetString("2110263f391b92233267e75ec5641be7385da935a46f8cccd0698a584c70848a", 16) + g18446744073709551616x, _ := new(big.Int).SetString("457cafda1576b6f5fea6125056e6d52c4b01de7b44ae5aae162e83c9fe86928", 16) + g18446744073709551616y, _ := new(big.Int).SetString("16471c8dad2cb3ea4c4645d8b108abfb95fdb1c87485a1d78a3d158e529aaabc", 16) + g36893488147419103232x, _ := new(big.Int).SetString("a431193edb58abf0df45b4bbd6cfc43bf2e39093ec0fd195f3120344b3ac3a0", 16) + g36893488147419103232y, _ := new(big.Int).SetString("b1261fe08f29cc99a084cda6e12f384e7a11f3fa0f75dfcd21005d951fdfc2b", 16) + g73786976294838206464x, _ := new(big.Int).SetString("1542e37f2c64d816c9dde4cdfeff540680cc90b767294ba9937a0de230676b4b", 16) + g73786976294838206464y, _ := new(big.Int).SetString("1717efcb51f08cccdbfe3e4a2da92e000a45a3e3d9eb40f9b9a2041dcbf14d3a", 16) + g147573952589676412928x, _ := new(big.Int).SetString("f39f1ee90eb802366254bf2555173a1bd988e09f8c5ad7bebfdb8d14d88b064", 16) + g147573952589676412928y, _ := new(big.Int).SetString("2cbbd9234ab4f9fd74defb1512b86385b038ea5ae995449b813235e047876986", 16) + g295147905179352825856x, _ := new(big.Int).SetString("250a8a1b9edcecc5f25879262ef2962fdf8499f60e8131c6c33320fd8c98ed15", 16) + g295147905179352825856y, _ := new(big.Int).SetString("1924e2b0b5e2c49449c5ef9b62c2d01207e012a0bc70b219ab44f026ce7e43b8", 16) + g590295810358705651712x, _ := new(big.Int).SetString("239aee62596123c53859dc2937ea9257e52034311bb81519b7f45330c5c883da", 16) + g590295810358705651712y, _ := new(big.Int).SetString("151f09f672db228c74304a2f68f65a7b586f93913b97b6d7dfd638b99571b7f3", 16) + g1180591620717411303424x, _ := new(big.Int).SetString("1ec491fbe90a222adec9c417cd9c39393bf0e9fd4618f8688f20b587e10a92ec", 16) + g1180591620717411303424y, _ := new(big.Int).SetString("2ad8de9952064d982be63f71a172dfddc4daf430bb5c7a0c0d3a53ff776b8474", 16) + g2361183241434822606848x, _ := new(big.Int).SetString("2e5001cee2faa644502bbba6bf6b07e3b7cef0392326b48f300fc56f6982026e", 16) + g2361183241434822606848y, _ := new(big.Int).SetString("180e823c991af5044dde58a9e671fa092d3ba5db98cc7e0376dd079323f80764", 16) + g4722366482869645213696x, _ := new(big.Int).SetString("2715e750e68b52faa68b293da254e1b0049b5825804f4c2700adf08a0214e529", 16) + g4722366482869645213696y, _ := new(big.Int).SetString("3921d1862445f32fb5afe510e7c4e23f41e4bad15c090b1de77447950003fc9", 16) + g9444732965739290427392x, _ := new(big.Int).SetString("b4ae2be8e83c897e6d3aa46f67058f07e0d29edbe4eb1b6c1e325c737af51f7", 16) + g9444732965739290427392y, _ := new(big.Int).SetString("cea4f5b9bc8e843c26cd4e67da727fe9cd09ca8e07b60410602c63c3b0baee6", 16) + g18889465931478580854784x, _ := new(big.Int).SetString("252b5bf255b06eade647646139359221099916d1be9aa6a7edc3f7c9c6b3baa3", 16) + g18889465931478580854784y, _ := new(big.Int).SetString("12f7f9b3871cd66f99e976138eedc4faaec30a67ce3c67d867999ce814f7644d", 16) + g37778931862957161709568x, _ := new(big.Int).SetString("1977739937a75442ba424943233bb2ba55f9d4c62148285873a658581d5114ff", 16) + g37778931862957161709568y, _ := new(big.Int).SetString("178ee53b5e50cc2078544a9cbd11841c47854fe604388a5defeac56ce805bfe6", 16) + g75557863725914323419136x, _ := new(big.Int).SetString("e6581bf922d94d7079fa4b753f3ecedc525f516643a6bc894c5ab191fbf676b", 16) + g75557863725914323419136y, _ := new(big.Int).SetString("160642bdf146cc3f6630cfa5c115629055ab653c0e7f2414391f22b25d6720f6", 16) + g151115727451828646838272x, _ := new(big.Int).SetString("d4da3f9398685005d391d7c328ec8dc2ecab18c7d451901725375b1c373d860", 16) + g151115727451828646838272y, _ := new(big.Int).SetString("1609e3ec29efd4abf1629be26b772ef4b8490bcedfae621851e413e84c513135", 16) + g302231454903657293676544x, _ := new(big.Int).SetString("3a781e0964591a816d07c8d6aa23d23b2ad50ae3acc529f877abf4d13e3f35e", 16) + g302231454903657293676544y, _ := new(big.Int).SetString("20a1f12ea58910335687316cf47761991bad8f11e109095279c05e14b370c876", 16) + g604462909807314587353088x, _ := new(big.Int).SetString("2db5bda50b8b265684bb6e9c7af58513e9aa23abd3fa2a3cfc88dd057f90bef", 16) + g604462909807314587353088y, _ := new(big.Int).SetString("103c36bd9eb69b53205b7fae6224bb36b5a50451261cf87128953b489594b6d8", 16) + g1208925819614629174706176x, _ := new(big.Int).SetString("513dfdf79ca36c0d5e56de067033a42d9e13ce86f261d9081a2dddbdb88127c", 16) + g1208925819614629174706176y, _ := new(big.Int).SetString("2902f0ba36cac9e8a907ae91f2486316258b0b9b3b2c5262ab965004167bfa0", 16) + g2417851639229258349412352x, _ := new(big.Int).SetString("bd86fa4e2f2da10f54c62d2f996d7813d6548785f88386b0286ba719dc973a", 16) + g2417851639229258349412352y, _ := new(big.Int).SetString("2495aed3ff4e37c6d20a260f9847fe15d2bb5c2b788454bbb6e450effafa8bea", 16) + g4835703278458516698824704x, _ := new(big.Int).SetString("18f64e4337ef0a3732be36ca6cf72393b821fe4914ec78b311ca3a343ce7b15c", 16) + g4835703278458516698824704y, _ := new(big.Int).SetString("21c0913ede0f09b5920b629b891a95a30aed5dd6001eda274649363d1877da", 16) + g9671406556917033397649408x, _ := new(big.Int).SetString("46cc874785e387f35fbc3278c63a7d66e89f4642ab9056ec3d0b8d26eb21ec4", 16) + g9671406556917033397649408y, _ := new(big.Int).SetString("1b759ad99b33626516327fbebf9c232e0fca6555b084ee311f62366d7d5f86b7", 16) + g19342813113834066795298816x, _ := new(big.Int).SetString("64fcc679f04e762d783f5b39e9bc9832d06a6809d8c101a216431f1dc792cfd", 16) + g19342813113834066795298816y, _ := new(big.Int).SetString("216690982d703eb77e4ea5a7dd74c7c00fb98033d17ec825ca4950f6c40aeb80", 16) + g38685626227668133590597632x, _ := new(big.Int).SetString("148b2e63d2d3d87f364f35c47d7cf6c006506cf224aac6f208c559a2ed58d834", 16) + g38685626227668133590597632y, _ := new(big.Int).SetString("2727c32af57debc90f6fc9eb1607f72e8180068d6d12c02c38498ddf0a998506", 16) + g77371252455336267181195264x, _ := new(big.Int).SetString("213b9a87905003543236ff3eb6b232083378cd7a9eed91eb78f2c60fa85a3ad2", 16) + g77371252455336267181195264y, _ := new(big.Int).SetString("28e04e92b62096e8d23915d545982855c21be5b3a1193e6e34c43db01192453b", 16) + g154742504910672534362390528x, _ := new(big.Int).SetString("2a4825bea894ae814c1678bbff2fe7c99cd63a77a0c703b2825a5f19b2d98fad", 16) + g154742504910672534362390528y, _ := new(big.Int).SetString("2a127b6261bc7a4f6e76e082d980d0af0bd0f5e0fd9cdb342bf9bbb7694a929d", 16) + g309485009821345068724781056x, _ := new(big.Int).SetString("2257c2e4b41831dd8d36aaca1ab106c26c796f1c8e0a2998431f9d4125d740eb", 16) + g309485009821345068724781056y, _ := new(big.Int).SetString("7b7ed1edbb583f469367ae24bf8e49c1ff6731dfff4abf92e163e595187203c", 16) + g618970019642690137449562112x, _ := new(big.Int).SetString("a8d78ab8a1fb7388787eeca33f3fe251ae93f28ac1fef89dae84057b55436ff", 16) + g618970019642690137449562112y, _ := new(big.Int).SetString("1aef7bd255bab9ae1a74c2b7cb61cb0c22f8c6c0a7da5d9d4753779f9fc3d456", 16) + g1237940039285380274899124224x, _ := new(big.Int).SetString("1bca13199961ec30b02a2e464afef42ab60ef11b26573e11e22a1028afacd288", 16) + g1237940039285380274899124224y, _ := new(big.Int).SetString("ad9ff00a04b9cbebcd54d75a6db4c6042799d29bf0e0d0fae7438c89233850c", 16) + g2475880078570760549798248448x, _ := new(big.Int).SetString("6236320cf783a01e2b8be7816a84671de9e8bebda0e8f957809ee1253565bae", 16) + g2475880078570760549798248448y, _ := new(big.Int).SetString("a4ce1ac405b9974e4eaf9342c2a43bd1fdc4edc2bd18235249bf51ec4328744", 16) + g4951760157141521099596496896x, _ := new(big.Int).SetString("107a0928f1bbd09f3710ba91ea9d69152e2a2de8eb21984ec9caddb69ab37a8a", 16) + g4951760157141521099596496896y, _ := new(big.Int).SetString("28c0d2c1d2b4dd590537fa55a7838a2bbd7aa7f2c0e91b36927b731752c34192", 16) + g9903520314283042199192993792x, _ := new(big.Int).SetString("4c02961cf949cd155f736fdc4c29e4fe409c37994aef1b16cd170cc65b1b2ee", 16) + g9903520314283042199192993792y, _ := new(big.Int).SetString("a92da6a165896cdb685afb42e80bec10097bc2083bc938550706fc5bc355795", 16) + g19807040628566084398385987584x, _ := new(big.Int).SetString("165aabcf0d07544d16f06389ef1d3bd5ae9c4bdbb0f53065b64bc53346c75897", 16) + g19807040628566084398385987584y, _ := new(big.Int).SetString("9dbc96d154f3fb8324230033265a8d5a31c9b88b5104ca5f56c714ac2e6a534", 16) + g39614081257132168796771975168x, _ := new(big.Int).SetString("1bafc8265a8fb16e346e57060848c3ae00b0e2d8520ff8d287cd002705c4c1ab", 16) + g39614081257132168796771975168y, _ := new(big.Int).SetString("3a87183d670bf95439912a7fce6570c957a4d5ecaa722ed50e7d7c55dc55d0a", 16) + g79228162514264337593543950336x, _ := new(big.Int).SetString("1b5b281facfe95fb1144e0f7d0484d119ebe0dca0355e63ec70e5f94cd64e3e9", 16) + g79228162514264337593543950336y, _ := new(big.Int).SetString("10e9c2dfd3e452f067fc71c60a08200402f8f4e5e8dad63e462ba1597a20c615", 16) + g158456325028528675187087900672x, _ := new(big.Int).SetString("18dd61a6d1a9c55b35d048ffb667e7f05ee657481bdb86800e89aa48df541143", 16) + g158456325028528675187087900672y, _ := new(big.Int).SetString("147653157294e50892424edb123ca14f08ae7da80350b6ffdf582aa7a939e371", 16) + g316912650057057350374175801344x, _ := new(big.Int).SetString("24fe3fb77d48ea49e4c1b91c61b634dbd9525b20167226b19d7c603ac36c3d4c", 16) + g316912650057057350374175801344y, _ := new(big.Int).SetString("2a4768c15d9b9c746e253eb271b28afab89da5412565d93c6220a5b14cfba611", 16) + g633825300114114700748351602688x, _ := new(big.Int).SetString("119ba66c94aeb05b2309953c35df696ce195bf7d959770bb9b99ab944db0af91", 16) + g633825300114114700748351602688y, _ := new(big.Int).SetString("29c96c201b71f6540f084e2fb6d4eb8a52b940c0c5585f258aba521311b805d1", 16) + g1267650600228229401496703205376x, _ := new(big.Int).SetString("15856673ff5b68543c671cbe735d53376dcfea3eef0ec5fb3a1ae3c37f5683bc", 16) + g1267650600228229401496703205376y, _ := new(big.Int).SetString("12224ed590244e93f1c6b7abff01b64dac0bb8bf14ae8e3d825322b6623d082", 16) + g2535301200456458802993406410752x, _ := new(big.Int).SetString("253ea43ba2e8c14da0df002c96422fb3234310a5774d8ec6cc9c1796df1789ff", 16) + g2535301200456458802993406410752y, _ := new(big.Int).SetString("234267257e751a5fcebb1e295b774700fcc16b5f270ac8720f4376dbc18281b3", 16) + g5070602400912917605986812821504x, _ := new(big.Int).SetString("2825afe1d583957680db4456ece011c28a7a5e2021a69a1bdb69707d944268e4", 16) + g5070602400912917605986812821504y, _ := new(big.Int).SetString("2870101fe628a0d69a362a7f52d4f57093aceffa7aea51a4544c3033109a05f9", 16) + g10141204801825835211973625643008x, _ := new(big.Int).SetString("f29f472f3b04c24a5ed6675f5ff33720a10826fe53cef56b2c9313b2bd31523", 16) + g10141204801825835211973625643008y, _ := new(big.Int).SetString("2483c78fb7a925e79bf63bb20e9198e12b41429b23fe8e2ce29f91f1112159be", 16) + g20282409603651670423947251286016x, _ := new(big.Int).SetString("28b2e5fdc60e4fa83c1fb52db348434f08b850cc205f98431deea3e8fe209ad8", 16) + g20282409603651670423947251286016y, _ := new(big.Int).SetString("fe1ae72d3f07fef610c96a45cadf362c41f3f902b7b81a735b2a98333f54f47", 16) + g40564819207303340847894502572032x, _ := new(big.Int).SetString("2267c8d0582c04e9568e83bb9155fd9fac11d9c0672455f63fc14112297855da", 16) + g40564819207303340847894502572032y, _ := new(big.Int).SetString("1a13b6e83105beb7164721a03aa0635d2214c68c0ce68c5737ff618f02f62bcc", 16) + g81129638414606681695789005144064x, _ := new(big.Int).SetString("2a3e86af529fb07cadac27f9eb5683abbdacac22e8e55a4b96c61249cb3ce975", 16) + g81129638414606681695789005144064y, _ := new(big.Int).SetString("1eea66c26412cd33e47d7745aa76f7251efdd09bf220e09889675d9896bd1772", 16) + g162259276829213363391578010288128x, _ := new(big.Int).SetString("c5111956406a1ce31b50a0d90fdca236871c353e3f75250304b08cef557b588", 16) + g162259276829213363391578010288128y, _ := new(big.Int).SetString("2b4948845ae79d5803bc258bcd951d476247eb24ebe416a89ad8fd9f465fe8b6", 16) + g324518553658426726783156020576256x, _ := new(big.Int).SetString("2854ffc7b3e8214133feba8d6eb09b263690572a3022b7fcf2871ab9219cdbad", 16) + g324518553658426726783156020576256y, _ := new(big.Int).SetString("106de3acc6519fe5e79d178c2c86abded16f791c8ef4d9335d97862a68f5590", 16) + g649037107316853453566312041152512x, _ := new(big.Int).SetString("24c6a00e705db722a2952db86bbe7f08cac7b6c3b50d023f24a3de1ea736074d", 16) + g649037107316853453566312041152512y, _ := new(big.Int).SetString("dc43ed6b87676e8dd55e167471a55f2eef0968e310767659123e48b357903a4", 16) + g1298074214633706907132624082305024x, _ := new(big.Int).SetString("2644642ad942cfbd4736a0f7f18fc0197e029521ee087615e04a49e5f8fbb66e", 16) + g1298074214633706907132624082305024y, _ := new(big.Int).SetString("22b30468bd6abb89a23a5dce7e57ae96e25e0417937368f6760147af32c7a7ef", 16) + g2596148429267413814265248164610048x, _ := new(big.Int).SetString("139bc1dd75b831294bf28f4030675c0e05ab4f44f87a639b04228814b6cd5531", 16) + g2596148429267413814265248164610048y, _ := new(big.Int).SetString("18c670606f2e48d361c347c0219ae8e678759c0b22c01a1756b6b0e3c679ef33", 16) + g5192296858534827628530496329220096x, _ := new(big.Int).SetString("2699eb06108602cf13980e2b6e4f48c6d90f46de7eae60457e4d1019a4f3b9bd", 16) + g5192296858534827628530496329220096y, _ := new(big.Int).SetString("626c5f10d9f788ba433f2be9ac352b4298ecd2cea3cfff1e15e9d48fbaa113c", 16) + g10384593717069655257060992658440192x, _ := new(big.Int).SetString("1f4479f765ee101dfedcbb07e9033604da94dbbe5b781331484321af5b253dcd", 16) + g10384593717069655257060992658440192y, _ := new(big.Int).SetString("21623c9b390babf2397d31ca4af79148ad304a121ae5edc1723c994d2828f444", 16) + g20769187434139310514121985316880384x, _ := new(big.Int).SetString("2855725b3e68975ebe53642831ae4d5d2d7b4b137b95eb96e8151bc61f1bf053", 16) + g20769187434139310514121985316880384y, _ := new(big.Int).SetString("ca0e44e2fd18ec91840ccfe99c3049de88d1cb70c63633b7aa4416b92b0336d", 16) + g41538374868278621028243970633760768x, _ := new(big.Int).SetString("136dedcff58a79ef53df43747ab531ff7d38d5c7d2f7a6d652f57b415b808c10", 16) + g41538374868278621028243970633760768y, _ := new(big.Int).SetString("108956df051470607a649a39f14ea5cf95a904a406ca3123eebe60a0eb4300fe", 16) + g83076749736557242056487941267521536x, _ := new(big.Int).SetString("d744feede2a6bd63f61403043b33f81f56a61ae58c43e8b771ee0cf5f0dfdea", 16) + g83076749736557242056487941267521536y, _ := new(big.Int).SetString("7edb65778a0aa859b8947ef31e601c311b25aa1bd2a5ccc3225cac13bfc1d18", 16) + g166153499473114484112975882535043072x, _ := new(big.Int).SetString("23ecd41f06eb8051f907d416c36a9a6691dc87cc64de02261c7eacaf70b82beb", 16) + g166153499473114484112975882535043072y, _ := new(big.Int).SetString("caf2de20986119d958e6de7c3f6cd4f8b38645c9e59a12f46003aa5625c1edb", 16) + g332306998946228968225951765070086144x, _ := new(big.Int).SetString("15b08db406565282b6a0d3fc8022eadd2b61a559f3c92cc91521c45c6661a82f", 16) + g332306998946228968225951765070086144y, _ := new(big.Int).SetString("37803c869368190f0443820670330b14439832989f2345a36e5a48b2c59e543", 16) + g664613997892457936451903530140172288x, _ := new(big.Int).SetString("e1eca77e1fdfbc7a151ed32732cbbe093978b5d8724324d73929a30e58be078", 16) + g664613997892457936451903530140172288y, _ := new(big.Int).SetString("2e23a2f478eff00d8f0c0d7ec3c2c76467aeb2ca3d26ef49ed19ef1a8cccf8ff", 16) + g1329227995784915872903807060280344576x, _ := new(big.Int).SetString("e16c46d7f01cd14637900379058cde52352483f90eba6350dea325a183e4c8e", 16) + g1329227995784915872903807060280344576y, _ := new(big.Int).SetString("2bc5983fad220b58189c50be25b200c54e70d0529e3dc96decbe801f0420786f", 16) + g2658455991569831745807614120560689152x, _ := new(big.Int).SetString("1ecf556e4ea1a22b395060ed7c79a79ad9af43103b935caf9d410aaf61ce4e9a", 16) + g2658455991569831745807614120560689152y, _ := new(big.Int).SetString("1ac123a28245de45fd811267a8e343a1b035e77aca8b4614d09722caff12b0eb", 16) + g5316911983139663491615228241121378304x, _ := new(big.Int).SetString("1211f23e5e92c74a454701bf173aaf1ea12f7042e85859c468d94974eaad551c", 16) + g5316911983139663491615228241121378304y, _ := new(big.Int).SetString("165d5f2fff807855a18513ebdb932dee6bfcb8293383f7b7bc5196d737053f73", 16) + g10633823966279326983230456482242756608x, _ := new(big.Int).SetString("2b9fcf34bf541a48ec88d66cf5bfc89700211ae76a79551757dfc50f41288227", 16) + g10633823966279326983230456482242756608y, _ := new(big.Int).SetString("ced96282d5edc9cbc32b1c16e750da8cf3237e07e3625d85bedaecfcd12c9c4", 16) + g21267647932558653966460912964485513216x, _ := new(big.Int).SetString("2f9ea4e44871cf87cfa80f71560253dc13ab58f9728495fddb4b9bdd11628735", 16) + g21267647932558653966460912964485513216y, _ := new(big.Int).SetString("28dadee7c5d2a42cd524d8396f69ee363aa95f85c98c3c836004589b6d73084b", 16) + g42535295865117307932921825928971026432x, _ := new(big.Int).SetString("15530bd41a96a8a225db6640075aecd1884a06bbac5f98c51e5a487bfedc8d70", 16) + g42535295865117307932921825928971026432y, _ := new(big.Int).SetString("1c86da90e9556705a7476bff65b8f53425e3d129db8f179ad6e4b033e0495a20", 16) + g85070591730234615865843651857942052864x, _ := new(big.Int).SetString("da53ef60fd433fe0ee377bedc0e2f7239b514bba5caa80c52991c619a029559", 16) + g85070591730234615865843651857942052864y, _ := new(big.Int).SetString("1e1a37d1bf9f0eb8677bb0fd215c26cecfb350ad226f42d569bb040234da117e", 16) + g170141183460469231731687303715884105728x, _ := new(big.Int).SetString("25d8a9ba3266bd80af59395320e940663ab8c05932a4280b42bfcd0ec4f69d62", 16) + g170141183460469231731687303715884105728y, _ := new(big.Int).SetString("2fc95abfe6be50f1add78a03a9b4e60931ac358a132ad5ef5076c4894fb14aab", 16) + g340282366920938463463374607431768211456x, _ := new(big.Int).SetString("13b8fec4a1eb2c7e3ccc07061ad516277c3bbe57bd4a302012b58a517f6437a4", 16) + g340282366920938463463374607431768211456y, _ := new(big.Int).SetString("224d978b5763831dff16ce9b2c42222684835fedfc70ffec005789bb0c10de36", 16) + g680564733841876926926749214863536422912x, _ := new(big.Int).SetString("2d035cd6cd9ca06a9aecee6826e38a30dd6fa18a9f139179142782803a05e6a4", 16) + g680564733841876926926749214863536422912y, _ := new(big.Int).SetString("bcbe75d48af9e7d4a45ef21e0348411bdf99be154fcc82ecefc6cbab8157291", 16) + g1361129467683753853853498429727072845824x, _ := new(big.Int).SetString("1096e761836e74c5c654df817b4ace41e55cd812e97d2d0af5e2ea6f24dfd392", 16) + g1361129467683753853853498429727072845824y, _ := new(big.Int).SetString("21ff527613e48f4a5e3548af70ec2c1076b85506cf767aceb570ee83983ac6ce", 16) + g2722258935367507707706996859454145691648x, _ := new(big.Int).SetString("292c4a9ebfc080016a973ac9e24fb4b356c69db30308202a31d0bfb2e85443be", 16) + g2722258935367507707706996859454145691648y, _ := new(big.Int).SetString("2d378fef5d7b4b008da52d0c98bb8daa702109aa7d5da477107d9f9559dd6eab", 16) + g5444517870735015415413993718908291383296x, _ := new(big.Int).SetString("1d316fbe5c0ccef4caf35a917244ff619d92d4fbedc80b970205508e4b570595", 16) + g5444517870735015415413993718908291383296y, _ := new(big.Int).SetString("22b85bd410a73800d3610f05dea0bc7d82960d317602cf44bf77ad8f8f254f79", 16) + g10889035741470030830827987437816582766592x, _ := new(big.Int).SetString("2c961c9d2ad66f1049fdd0e8d7337e3449e8774836bb9981b56fc6e7385cd7e8", 16) + g10889035741470030830827987437816582766592y, _ := new(big.Int).SetString("6bd01a16056ed018b2394a0ec6897cfbeb20a18c606b0d78bc78d1d84a6b892", 16) + g21778071482940061661655974875633165533184x, _ := new(big.Int).SetString("2e8a8414affe97ed11410c27ac23b1f54b6a621ba39a9fd7f1685f9db88343a7", 16) + g21778071482940061661655974875633165533184y, _ := new(big.Int).SetString("1efbc6e7cb379b246ad9278606ea10b7c74f52769c615cd67b833c5016ac7db4", 16) + g43556142965880123323311949751266331066368x, _ := new(big.Int).SetString("2ed01ed41ec147ec1eba42d4b3c921568944e9a0d8a498706f99ec15d0ccc511", 16) + g43556142965880123323311949751266331066368y, _ := new(big.Int).SetString("1dcc8b5251aa1008c792ac420bc9be5f1870042d0210ff8ae96804ddffc721ad", 16) + g87112285931760246646623899502532662132736x, _ := new(big.Int).SetString("194c79506a89ea907a1e6777926f317f7231ea49bbde362689477b6ee04e9613", 16) + g87112285931760246646623899502532662132736y, _ := new(big.Int).SetString("26c94fbfb503010b9cac6a4b4e8e5fe29553e60128e05cdbf5546cb7bcb34d7", 16) + g174224571863520493293247799005065324265472x, _ := new(big.Int).SetString("277ac3a2889cea8febfa02110307c50b7d8da14e50adc4e86dc8d0aa73251dd", 16) + g174224571863520493293247799005065324265472y, _ := new(big.Int).SetString("17eb791abc2495f664ffb38442265281a6f9a91c6169ec5a6e7365dcd3c64871", 16) + g348449143727040986586495598010130648530944x, _ := new(big.Int).SetString("d3c84c79e806fda93ee88a7887b9daafa47969dad98217ab2bc82bdff4fbc25", 16) + g348449143727040986586495598010130648530944y, _ := new(big.Int).SetString("213f847ffc2eb33fbb7a5fe6f9e52d792095ffd8c8ebccc3caf9ecfd610cf1b2", 16) + g696898287454081973172991196020261297061888x, _ := new(big.Int).SetString("21d9001150f189e28d9e194e98bc5ac761eda5d600d7ef517983af606c5548b9", 16) + g696898287454081973172991196020261297061888y, _ := new(big.Int).SetString("1e2fff3d9cd1f421a57ff2dade55ab4ce3b4628a60480cce558d3a77b8fd5227", 16) + g1393796574908163946345982392040522594123776x, _ := new(big.Int).SetString("8c4343a41a1dae81a6276852d405acd87e81ff4b1d190482b5718a6e31a761", 16) + g1393796574908163946345982392040522594123776y, _ := new(big.Int).SetString("12b4ca0371b8ee1bd20a1d65277bab81e59f6e5ce60ccc6b82c722cc29d07fa7", 16) + g2787593149816327892691964784081045188247552x, _ := new(big.Int).SetString("2bf8fac78021ac7b2753b1ecb80fb30160b6b3250b5cf0ec9ad46f7801e759b8", 16) + g2787593149816327892691964784081045188247552y, _ := new(big.Int).SetString("2c0016acf87d3833c0fb9709392747265f4202151c050427b3b5913ff39de477", 16) + g5575186299632655785383929568162090376495104x, _ := new(big.Int).SetString("1cf7146b4c1d2ea113417938e790a96fe811cd3dfef48ddf27dcba7cd820f6cf", 16) + g5575186299632655785383929568162090376495104y, _ := new(big.Int).SetString("2a5ed72cbb62ac7046edfdcf9d1b47368fb3e2291e1e85e26c4e8cd35e401ef5", 16) + g11150372599265311570767859136324180752990208x, _ := new(big.Int).SetString("5e61bbcbc655464ba1fd215e04fcf949939de110f05722431cd5084968d6db9", 16) + g11150372599265311570767859136324180752990208y, _ := new(big.Int).SetString("13e15f844fa2767fac2daae3fb818e93cf95082efd681debb31574defacad671", 16) + g22300745198530623141535718272648361505980416x, _ := new(big.Int).SetString("34bf641f495a59e3d28dc3163a1c74aec7f7ef60030c8614c193f7ae2281a96", 16) + g22300745198530623141535718272648361505980416y, _ := new(big.Int).SetString("8b45e915673d26d8c5c5258a951fcf9b439d6833e12d2c301dc2eabe23e3f61", 16) + g44601490397061246283071436545296723011960832x, _ := new(big.Int).SetString("2960a0634103632555b7ed048b833d198c75536bdfce550988dea08d1b2a4b69", 16) + g44601490397061246283071436545296723011960832y, _ := new(big.Int).SetString("1f29d4cddfdbbb9a3aae3c862def08730c9563529b888e065f77604d012c194e", 16) + g89202980794122492566142873090593446023921664x, _ := new(big.Int).SetString("2bed31e2b3ee10fa9cfea431196db0b201587e2e68ee74dc466450053177c5fd", 16) + g89202980794122492566142873090593446023921664y, _ := new(big.Int).SetString("22c3f8fb3346540004df204600e2a60f2b5232a3fcce889962561e1c98a80146", 16) + g178405961588244985132285746181186892047843328x, _ := new(big.Int).SetString("d452f069c9eb613854442c5e9830fff0cccbb7a0c37bb8fa9a81c242933b54e", 16) + g178405961588244985132285746181186892047843328y, _ := new(big.Int).SetString("1c8331a53da629b28d02f6ba74b52caf67c4418e22fd6caf57d627e110451251", 16) + g356811923176489970264571492362373784095686656x, _ := new(big.Int).SetString("f055c21e2d7e8617b71babc6b770fc9a7ef74c3913fcf610d599414096b700d", 16) + g356811923176489970264571492362373784095686656y, _ := new(big.Int).SetString("1ebeb82f257db891825c55b2c909f0210dbe84616c0f5a867aa9f380a9171929", 16) + g713623846352979940529142984724747568191373312x, _ := new(big.Int).SetString("21907afebc2ecfb8c7c376a0db9958b35a6540103391efa541a28b82f472f48a", 16) + g713623846352979940529142984724747568191373312y, _ := new(big.Int).SetString("27c5a8cf6fa01b72d31ac50942838b8362d01e25c82b2d9c4a0f231441de4197", 16) + g1427247692705959881058285969449495136382746624x, _ := new(big.Int).SetString("205ba2fccb49fb5023e5114f84e961b9237b49ca8f5610bebb995b33ee249369", 16) + g1427247692705959881058285969449495136382746624y, _ := new(big.Int).SetString("b388977d2e0a8fc0e63a06375d9fe19fc7b798b8b0f2c8b0885920cb5bae45e", 16) + g2854495385411919762116571938898990272765493248x, _ := new(big.Int).SetString("2bb165ee76d92f26bdcbd9897c6519b8d89eeef2efc0c9521497068c735a54d2", 16) + g2854495385411919762116571938898990272765493248y, _ := new(big.Int).SetString("152704fe7afc78056ee79211313a0b23b71de06863c6102e0f8daefc0f2e85df", 16) + g5708990770823839524233143877797980545530986496x, _ := new(big.Int).SetString("f34d4d950bef2ee3b8e924b0183ca4e00aed6ea9209bc37c4e2202eb5bd7666", 16) + g5708990770823839524233143877797980545530986496y, _ := new(big.Int).SetString("d676a2dac5fcab3731af3283d9c22989889fad53465781a73ea5aa81274798b", 16) + g11417981541647679048466287755595961091061972992x, _ := new(big.Int).SetString("42fdcaca97128fd28b1ca4c90eaf39378d673af8d9f789d33b88c8284c1e4c7", 16) + g11417981541647679048466287755595961091061972992y, _ := new(big.Int).SetString("c5f60e7eaf108af711035a4ca219da7c7926c882d40373d76d9fc5dc05bf2d6", 16) + g22835963083295358096932575511191922182123945984x, _ := new(big.Int).SetString("15f74bf25691e3205d87c4ee7b798f00097551d1a14e732f8ec16be2c2b15424", 16) + g22835963083295358096932575511191922182123945984y, _ := new(big.Int).SetString("e917f31facef054212b2376c65779119a28cf490a506e66d48dd45117ba7cab", 16) + g45671926166590716193865151022383844364247891968x, _ := new(big.Int).SetString("8bd6a57ec62543e02f6fc7d0c3e832c7b7fc579d180a91071faa3d3ee9419d4", 16) + g45671926166590716193865151022383844364247891968y, _ := new(big.Int).SetString("1bc48805b6f1636fbb3fcd6da38aafead46d19c009893b19cbeeeae7937a68b5", 16) + g91343852333181432387730302044767688728495783936x, _ := new(big.Int).SetString("22d27fb14085110cb59094144fc0b73878d88c64957112740a8559878d34fc", 16) + g91343852333181432387730302044767688728495783936y, _ := new(big.Int).SetString("8e1197fb288dbdfc3c45e74c7362e8d24eb51a66e6f601e078713114be490f2", 16) + g182687704666362864775460604089535377456991567872x, _ := new(big.Int).SetString("1b9f573652906bd22ae891e98f72b280aa9f086974561858b06e57325bda14db", 16) + g182687704666362864775460604089535377456991567872y, _ := new(big.Int).SetString("12aec4b8476606d47b077de794be45c888600e94486a93b3560d82c80bc5f8a8", 16) + g365375409332725729550921208179070754913983135744x, _ := new(big.Int).SetString("2548e5ca7207fc244a56030fdee8726891f78b31b786050b01f535872604fef9", 16) + g365375409332725729550921208179070754913983135744y, _ := new(big.Int).SetString("40f0788fad8ef4eca110681d934bc1875cce24d4b79708f50c5c5ade76284e5", 16) + g730750818665451459101842416358141509827966271488x, _ := new(big.Int).SetString("8e2dcb5d0b19b7b0fd7b371bc43c5756f0377132cef98df0db4dd9eb393adca", 16) + g730750818665451459101842416358141509827966271488y, _ := new(big.Int).SetString("2fe5e5ea9fb4e811da5043de233b0b4e971da2dd38941c5033de0afe61e945b5", 16) + g1461501637330902918203684832716283019655932542976x, _ := new(big.Int).SetString("1d4f9e8484dadc0b72b38138caad649253a61a9bf5ad2d9afe7330bf839fcbee", 16) + g1461501637330902918203684832716283019655932542976y, _ := new(big.Int).SetString("9bb9bbafbfbf4038ee64e73ebbb0975db22edcd2d1c1c6e83eca2672fab780b", 16) + g2923003274661805836407369665432566039311865085952x, _ := new(big.Int).SetString("fdbf5656758cf6806e65b7800be3b7c039ed1fe181a0d4b50fabcec79f0df5b", 16) + g2923003274661805836407369665432566039311865085952y, _ := new(big.Int).SetString("173a2bd7eab80c0e2c4cf6abb5b659d289de53889c437ef553167ecfddad034f", 16) + g5846006549323611672814739330865132078623730171904x, _ := new(big.Int).SetString("f1ca7aa3dd35f558481ea63cf19d446200c77835c45c63954770ad12616dade", 16) + g5846006549323611672814739330865132078623730171904y, _ := new(big.Int).SetString("6e0f716d88e8041c0021dd736593a6a3fa501e33faa9a6510b71467d749498e", 16) + g11692013098647223345629478661730264157247460343808x, _ := new(big.Int).SetString("2eb10a9a90309b08dee4cfa8070265358c54b21572d914c9e8fd36a959304d24", 16) + g11692013098647223345629478661730264157247460343808y, _ := new(big.Int).SetString("3b4ec52766ad398c08539c6f8acb2b39874f0e0b994010efa873cfdf680a88c", 16) + g23384026197294446691258957323460528314494920687616x, _ := new(big.Int).SetString("1b94be21f1fb7228d3f3d44204f4f3cac13090d7c5c2af9ac82f0475f5cf39b4", 16) + g23384026197294446691258957323460528314494920687616y, _ := new(big.Int).SetString("27e9d41ef829511094b2af4473637e9375eda5f9e914cf55aac02d9b4a969755", 16) + g46768052394588893382517914646921056628989841375232x, _ := new(big.Int).SetString("25710e3a7246b1e76b8d6fbe6ff44afd9fd30c9585351398c15d050238d3c2d6", 16) + g46768052394588893382517914646921056628989841375232y, _ := new(big.Int).SetString("1c855e42168e00cd947df9d3a268f0db1f8e471f730ca88d84e1c2de7083e4d", 16) + g93536104789177786765035829293842113257979682750464x, _ := new(big.Int).SetString("2b144261f16985c75bff2b9d0796d0bbb63ba9c927669e3839710eea66a8efa5", 16) + g93536104789177786765035829293842113257979682750464y, _ := new(big.Int).SetString("2bb766bc6b62691154fab15cc24ce09d7d0a86f180f7cfc60b459ccfe2bc1842", 16) + g187072209578355573530071658587684226515959365500928x, _ := new(big.Int).SetString("26b93a6de603f0cb5900242713c98a4690d087ee2701f953c81f562a0bcf691a", 16) + g187072209578355573530071658587684226515959365500928y, _ := new(big.Int).SetString("1f275bb2c0d7f2e06d4d3d7718ad405914e62af9dd182c0f3d8cf5bd436ef483", 16) + g374144419156711147060143317175368453031918731001856x, _ := new(big.Int).SetString("f43e8a6e923598ab55483d1cb864aa57273dd9173b898daae6c753e403d80a5", 16) + g374144419156711147060143317175368453031918731001856y, _ := new(big.Int).SetString("14351ad715d016d31bfa656c62512aaeeaf2dcaf8918bb24b379cf035722757c", 16) + g748288838313422294120286634350736906063837462003712x, _ := new(big.Int).SetString("13971d545d04b5639a6bd48a583d0e02bd46b717ae6404589d09ddcf8e0e1664", 16) + g748288838313422294120286634350736906063837462003712y, _ := new(big.Int).SetString("d9e7a36118a844d63b5778975a157e06f444516a730e37ee575079115e1a51a", 16) + g1496577676626844588240573268701473812127674924007424x, _ := new(big.Int).SetString("2b6126f3432d0ab7149133ed284dc4b8f4c690a15d24a2012df8eafd1e584102", 16) + g1496577676626844588240573268701473812127674924007424y, _ := new(big.Int).SetString("2ffed8dfeba141fb9d2ec5f5c4ea602a5dda428b2adbb7fdb83dbfd3cbe3ea36", 16) + g2993155353253689176481146537402947624255349848014848x, _ := new(big.Int).SetString("f8ebff21f4475980919b8bf3a07e2bc3276c32aa8cc9be0d2b9e6ecda1eac62", 16) + g2993155353253689176481146537402947624255349848014848y, _ := new(big.Int).SetString("2d5d4034ffbc3503e76dbfaab4569192bdc22c3297c74cbfc9faa36a1b168a61", 16) + g5986310706507378352962293074805895248510699696029696x, _ := new(big.Int).SetString("f89469183d268e35a4e05882dbe1a6718f5246a18948c8bc421b21e2a1a8f90", 16) + g5986310706507378352962293074805895248510699696029696y, _ := new(big.Int).SetString("c501e43476b33ec702b4a4cb163b64b2077f52e73fa21cf24c1d31e96a88c87", 16) + g11972621413014756705924586149611790497021399392059392x, _ := new(big.Int).SetString("2a49dc5c6e7fe74ff00aaae703c26fe0916b22a76b66f11eb2f1c97a145c2fb9", 16) + g11972621413014756705924586149611790497021399392059392y, _ := new(big.Int).SetString("a3d9acd50d6e2f9032d7708ffcc17a60ba20f887efaf42856b039cbc0a32483", 16) + g23945242826029513411849172299223580994042798784118784x, _ := new(big.Int).SetString("195cdbddb30680997cfb2d5471c87c76f7cb4e61797ef85ec2c6f2d883b018f7", 16) + g23945242826029513411849172299223580994042798784118784y, _ := new(big.Int).SetString("1bf08f1d94d1eeb02f28b7a1ae77f739697de40b672743de45182203b0fa20e0", 16) + g47890485652059026823698344598447161988085597568237568x, _ := new(big.Int).SetString("19d00e5a8576bd737351c55095a19e59a94e4b7ebb3a505c54c194609719ff04", 16) + g47890485652059026823698344598447161988085597568237568y, _ := new(big.Int).SetString("139cd47baae2140ee687714a64063dbcd8ee9c5ba41e8abec89d55eee1018d16", 16) + g95780971304118053647396689196894323976171195136475136x, _ := new(big.Int).SetString("2f9e7f7800c6a9c653f48d4636d9dfad6e122c48c2ed4ad2e59551956563be7a", 16) + g95780971304118053647396689196894323976171195136475136y, _ := new(big.Int).SetString("2414da5e0cd90394bd984c6886c3b7fc7d34a8418cc6898578ec0540d1d3bd48", 16) + g191561942608236107294793378393788647952342390272950272x, _ := new(big.Int).SetString("2b2b8f5e7f644ee1c00937dc227da2e3de69762726d86036f4807b6aaae36c31", 16) + g191561942608236107294793378393788647952342390272950272y, _ := new(big.Int).SetString("47853a419bb6b761e2bf666d6ca8f90e93ec84a6e5b425d5b74daf76ef9ccba", 16) + g383123885216472214589586756787577295904684780545900544x, _ := new(big.Int).SetString("17b3259210a9a0e4339a3fe1caa896e56306745007e783373d47fe37c800b974", 16) + g383123885216472214589586756787577295904684780545900544y, _ := new(big.Int).SetString("1ad16b73e4b32f988f8d9eebbee03224fe7bcbabbceb02973cd2e159c3a58e35", 16) + g766247770432944429179173513575154591809369561091801088x, _ := new(big.Int).SetString("20be897f06fad7a92edf423db7ed12cb2bd2f6cb29c6bb8c6e394ff1aa3b3e9", 16) + g766247770432944429179173513575154591809369561091801088y, _ := new(big.Int).SetString("7958a3fec65b6df34911a018aac0fa72ce89d92ba4bc67dcd06d1b4db184b90", 16) + g1532495540865888858358347027150309183618739122183602176x, _ := new(big.Int).SetString("253eba1d7cf606254ed9cff7613788a6d055495b779d9947a9cf46b9c1da311", 16) + g1532495540865888858358347027150309183618739122183602176y, _ := new(big.Int).SetString("1cabc4e498a23c3f5fcfcb887629459666b7513ac8c70ee43be83a8b4f5c4090", 16) + g3064991081731777716716694054300618367237478244367204352x, _ := new(big.Int).SetString("85fad322fc02ef1cd3e8473c56c6a1a26ecabadccf845a914d79c83beeb318a", 16) + g3064991081731777716716694054300618367237478244367204352y, _ := new(big.Int).SetString("3146780190be66eb78f6d6a2150da305d044739434f4d56ddccd160dafd43b1", 16) + g6129982163463555433433388108601236734474956488734408704x, _ := new(big.Int).SetString("22c33c8c594bf804b9c5a96835ed929dc99711327d5dc3723bb2bcfbb56f7fc4", 16) + g6129982163463555433433388108601236734474956488734408704y, _ := new(big.Int).SetString("2bc57d10207ca4af29f3a0a8eb864d8989e89371936e4544626fb999bf7a4fe2", 16) + g12259964326927110866866776217202473468949912977468817408x, _ := new(big.Int).SetString("225fdab8fe6cd876363d27075cdf0d01c209da61b1634b574a5d811cfae40700", 16) + g12259964326927110866866776217202473468949912977468817408y, _ := new(big.Int).SetString("1216b7c3e2adc07c3bef31771c7bb9e1d02f07ff3a5b74953c4fd5bf9a7a6dff", 16) + g24519928653854221733733552434404946937899825954937634816x, _ := new(big.Int).SetString("2a365a9299da85372ee0455de645cc2330e4c315d6250e3c0c72f10d77ac40e4", 16) + g24519928653854221733733552434404946937899825954937634816y, _ := new(big.Int).SetString("e54618ec8951f6b8be014e3f3bd12802b037ac48c2d0fd983f2343c5759c3db", 16) + g49039857307708443467467104868809893875799651909875269632x, _ := new(big.Int).SetString("2f31ee57ec760885e1e943c7d1602bff848dfde5cea6a4edf03476ad213591cc", 16) + g49039857307708443467467104868809893875799651909875269632y, _ := new(big.Int).SetString("bebf1d735e3aba48854ada67731601a179cd76b2bb690e6aed56a2fd963e9aa", 16) + g98079714615416886934934209737619787751599303819750539264x, _ := new(big.Int).SetString("242a698649332113b115eb3982fa5e454576bc05886f71489a31113fd737feb8", 16) + g98079714615416886934934209737619787751599303819750539264y, _ := new(big.Int).SetString("2e98af3e21c2fb8ecacd092858dc5ea8671f81867d371c9b1a010801ced7ae94", 16) + g196159429230833773869868419475239575503198607639501078528x, _ := new(big.Int).SetString("de2dce497fc378cf9875ea34483653ad21b40050a2be9f32713978fad365b6f", 16) + g196159429230833773869868419475239575503198607639501078528y, _ := new(big.Int).SetString("18818ed119e67e54970494ba4f5c5feb75fb8047779f910713af5793062885b1", 16) + g392318858461667547739736838950479151006397215279002157056x, _ := new(big.Int).SetString("143a5a6a69b89a9baf10bab59c62ddf7a747a8439541febe0964e2ea6e35147f", 16) + g392318858461667547739736838950479151006397215279002157056y, _ := new(big.Int).SetString("ace7c02bcdb98ce30c3b6c4b9d399287ebc911e8d44226bab0c3f06c1e7e717", 16) + g784637716923335095479473677900958302012794430558004314112x, _ := new(big.Int).SetString("18a2a13576df7d0be0daa67eea762a6894fc88a47a4b5d26bf6af3c826c91677", 16) + g784637716923335095479473677900958302012794430558004314112y, _ := new(big.Int).SetString("fc68277f2370379225a32315a25607a6341a371091589edeabda88ecc3d2a18", 16) + g1569275433846670190958947355801916604025588861116008628224x, _ := new(big.Int).SetString("245ca02f753e3dcae81462215695192bb8de0ee8a3c195c1e2f735fb5510c791", 16) + g1569275433846670190958947355801916604025588861116008628224y, _ := new(big.Int).SetString("22dfa007006c664c55102bfd2a79e5e79d89f3947b9f4556dc1ad20b80ff74d6", 16) + g3138550867693340381917894711603833208051177722232017256448x, _ := new(big.Int).SetString("1ae696c232847d27e7b00f3ffeb36076d50514c4ee68bdcb08a892bce08f3ae9", 16) + g3138550867693340381917894711603833208051177722232017256448y, _ := new(big.Int).SetString("1396047d0e2300586624c149388740f5c00e7cf4a7213598d8ca634cb7df215", 16) + g6277101735386680763835789423207666416102355444464034512896x, _ := new(big.Int).SetString("2642b0d7d17b3ae1c6c1ddc1b018ecff936f658d2acc47474a330c8d6cd2d5f7", 16) + g6277101735386680763835789423207666416102355444464034512896y, _ := new(big.Int).SetString("af05ffe2aa2cf4f27db4fc64b9bdc681e15f4fc2bb57f6ce23e2e1f89003c72", 16) + g12554203470773361527671578846415332832204710888928069025792x, _ := new(big.Int).SetString("29d2b27d8d6db3791b3c64b2f61f5b2ab00d7f1ebc252cb97a9896a83c0e5d61", 16) + g12554203470773361527671578846415332832204710888928069025792y, _ := new(big.Int).SetString("12a4333add04e8aad8478e3046268d23ed55292a96d7921460ce3d1f52ce28c6", 16) + g25108406941546723055343157692830665664409421777856138051584x, _ := new(big.Int).SetString("252d6852ed68f5ff4420bf4ae9e5900a65fa7b2993dd3745e8dbceb436c5b94c", 16) + g25108406941546723055343157692830665664409421777856138051584y, _ := new(big.Int).SetString("21df15aafa8dbc395e66f7bbf004139eb5b5bc1bcc071d61b02096cabcdc010e", 16) + g50216813883093446110686315385661331328818843555712276103168x, _ := new(big.Int).SetString("1d115df69be93cf70619b0f005a92968a5ee561161a3dd3cc963c243447f391b", 16) + g50216813883093446110686315385661331328818843555712276103168y, _ := new(big.Int).SetString("1555da4cf093578bc7a49518f3a49a24f57760186fd02a3eec3749ec72cf7ad1", 16) + g100433627766186892221372630771322662657637687111424552206336x, _ := new(big.Int).SetString("2ad97c4b04758df61bf424363bd78665cbd24e20c13125ba2fc618312635a5db", 16) + g100433627766186892221372630771322662657637687111424552206336y, _ := new(big.Int).SetString("f6b80288f228ae9b8cbfdb06a1362c5b4a4fa81cff38dffb36585b871ad747d", 16) + g200867255532373784442745261542645325315275374222849104412672x, _ := new(big.Int).SetString("1385c47fcd92b51986c4ebf480519229ad13bb04255b24ffadf0d64a47c9c56c", 16) + g200867255532373784442745261542645325315275374222849104412672y, _ := new(big.Int).SetString("1b5e107ac4e88ba1f6fe66fd02dffa0211cf505d105647adf3ecbcd475e22840", 16) + g401734511064747568885490523085290650630550748445698208825344x, _ := new(big.Int).SetString("194ed40353d0e3fb0983152b872766ae5f1b4843ccdf294212a22af910755911", 16) + g401734511064747568885490523085290650630550748445698208825344y, _ := new(big.Int).SetString("267aff505f0d68a76ebcb094b24df86ec272309368b812af86fa0bf390d148a9", 16) + g803469022129495137770981046170581301261101496891396417650688x, _ := new(big.Int).SetString("2c87079e8db3eba1a27b14612b8f160b5a9452af0e76b942f61259a4119665cb", 16) + g803469022129495137770981046170581301261101496891396417650688y, _ := new(big.Int).SetString("a26589e75263127c006b16e4c34db58765013d73c48a13c269b75e0fc34dac5", 16) + g1606938044258990275541962092341162602522202993782792835301376x, _ := new(big.Int).SetString("4f1cb752254ce1c92b01b10a5af73b1854c2c62841dc824781caaa56ddb87f1", 16) + g1606938044258990275541962092341162602522202993782792835301376y, _ := new(big.Int).SetString("2511226c45e2074e814befca9728e74afcbe0a2dbb8da9b61497527f7dc16fc7", 16) + g3213876088517980551083924184682325205044405987565585670602752x, _ := new(big.Int).SetString("1726c1df54ad0c394c53dbb2daa6b525d5337201f18ce540686af4310676a873", 16) + g3213876088517980551083924184682325205044405987565585670602752y, _ := new(big.Int).SetString("1ec01458207da40eb3b8483934f1281939e93fcbf8727a81eb45584ed2a3f61c", 16) + g6427752177035961102167848369364650410088811975131171341205504x, _ := new(big.Int).SetString("226c0947127b57567bc20c26508a688b2361f752eafe0072c005e589d8b9ef58", 16) + g6427752177035961102167848369364650410088811975131171341205504y, _ := new(big.Int).SetString("2dcfd6b7a3cb9423a68ca27d4e288f84067d1bca27ab18fa9a7b1c3cdc0876c3", 16) + g12855504354071922204335696738729300820177623950262342682411008x, _ := new(big.Int).SetString("1144eed8752daad82ce8c81c75d13e91c2d8a1368d8b7aece378bdb8f553f7d1", 16) + g12855504354071922204335696738729300820177623950262342682411008y, _ := new(big.Int).SetString("4d8b0b771a46ff8f2e0c18454b643f8908a5b96da44713263eaa0e7609149cb", 16) + g25711008708143844408671393477458601640355247900524685364822016x, _ := new(big.Int).SetString("1e6c7691756045003fd35cf5d449f1bf0c68b45b34905abd5fbf2d944251616", 16) + g25711008708143844408671393477458601640355247900524685364822016y, _ := new(big.Int).SetString("2c808764b3c2d8ba8b949a9f00efb3bac79481195ca7e34a146e913aff89859c", 16) + g51422017416287688817342786954917203280710495801049370729644032x, _ := new(big.Int).SetString("2846b54c3b22668dcbb8cccaae457e53d8b6f5ccac2b48128fc73c254c5e59b0", 16) + g51422017416287688817342786954917203280710495801049370729644032y, _ := new(big.Int).SetString("276f519936be5b3e2f91afc073e810e20473b09e963be92fe55aa82400eb9cfe", 16) + g102844034832575377634685573909834406561420991602098741459288064x, _ := new(big.Int).SetString("9ba7fc0c9257b32d14ef83b0b43ee1b4c875d4ddb70a1f8dff121bb0738d5f", 16) + g102844034832575377634685573909834406561420991602098741459288064y, _ := new(big.Int).SetString("e3b10575559f366d81f1b0076b0f2a8e57c4d11d5daba688a1926e17f22054b", 16) + g205688069665150755269371147819668813122841983204197482918576128x, _ := new(big.Int).SetString("2c8474246fb806dfd385f8358e4fe95f68fae97018d7db1a3fe43b670197d296", 16) + g205688069665150755269371147819668813122841983204197482918576128y, _ := new(big.Int).SetString("2d8ac3b14579252521443a0709069529e88578810f1c6cf4167f595f17c301e4", 16) + g411376139330301510538742295639337626245683966408394965837152256x, _ := new(big.Int).SetString("1ce9e693f0718940f328281f33872bf77e5160c73c0a6068e8855e4716316099", 16) + g411376139330301510538742295639337626245683966408394965837152256y, _ := new(big.Int).SetString("869d2297c13d0e7ed693bb3ef7cf72bade1c34dc9936633b458571bf7231764", 16) + g822752278660603021077484591278675252491367932816789931674304512x, _ := new(big.Int).SetString("25ef45e9014757ee53971d76a5c50e5b57b3daee31af4be46c9cd3d7a382068b", 16) + g822752278660603021077484591278675252491367932816789931674304512y, _ := new(big.Int).SetString("286b42c7d1cfc3387bb75355b59eccccddc593ba7c375c5ac7e8286ae03843e0", 16) + g1645504557321206042154969182557350504982735865633579863348609024x, _ := new(big.Int).SetString("19bab36be51f69ef46db70c779126dadf51c2c4e31ed48a1623cebdce336b5d4", 16) + g1645504557321206042154969182557350504982735865633579863348609024y, _ := new(big.Int).SetString("2854d9e8b595428c2accef0239bd031a4a2f37d751f1a992daf66e653b585686", 16) + g3291009114642412084309938365114701009965471731267159726697218048x, _ := new(big.Int).SetString("1cbc558d34b723ebfa07c9630c96e81c74576d141801165e4710b5b0262c84db", 16) + g3291009114642412084309938365114701009965471731267159726697218048y, _ := new(big.Int).SetString("2d4d9bfe1a7006a4eaf94fd681f467719a68a8231b6b46b496601a34cd8749ee", 16) + g6582018229284824168619876730229402019930943462534319453394436096x, _ := new(big.Int).SetString("22e1b18187f92eab791a18a17bae522f674d76efd8c7188a18c9397350d25421", 16) + g6582018229284824168619876730229402019930943462534319453394436096y, _ := new(big.Int).SetString("ad500831e4522a7fe456bd44967dbb8f56b3a7f36ac51ae95c3cbebd4e0ca7f", 16) + g13164036458569648337239753460458804039861886925068638906788872192x, _ := new(big.Int).SetString("6b3c6bec4d1982470c5f1a033e43fca9cf142639d8d8c1e08e0390a4c5a7da4", 16) + g13164036458569648337239753460458804039861886925068638906788872192y, _ := new(big.Int).SetString("1de78da2ba6a6e08b0b7f5a22bd59fe91abc05909196640e50e1d21741a4286d", 16) + g26328072917139296674479506920917608079723773850137277813577744384x, _ := new(big.Int).SetString("18afa4a6bf750334eac73d2f93349a25819827c4f2e3b42ce8144f0c090e1b12", 16) + g26328072917139296674479506920917608079723773850137277813577744384y, _ := new(big.Int).SetString("2bde7825dce391b931ca81ee1139e6d76760072c81ba53dd2db24ddc28694e92", 16) + g52656145834278593348959013841835216159447547700274555627155488768x, _ := new(big.Int).SetString("28234f55a1ef2d10c29341f59be69a2090c49b57bbc64a58809d4d4b9a050326", 16) + g52656145834278593348959013841835216159447547700274555627155488768y, _ := new(big.Int).SetString("f0d1a871d0f58ae80723f19adf08b8b04a9b11a1f0fb7c38c1dfb3b830939ab", 16) + g105312291668557186697918027683670432318895095400549111254310977536x, _ := new(big.Int).SetString("1f87eb4ecf4979737f4ce5493a5d744349f50675c1e169bbf31689c3e8c04308", 16) + g105312291668557186697918027683670432318895095400549111254310977536y, _ := new(big.Int).SetString("23d45d0cc26f83da885d957417f958f48d15afe583412df36ff2c46b0fae6198", 16) + g210624583337114373395836055367340864637790190801098222508621955072x, _ := new(big.Int).SetString("265fe341276ba4ef03a3e1632e3eacc3c77af43355915017604e3297a2575e0d", 16) + g210624583337114373395836055367340864637790190801098222508621955072y, _ := new(big.Int).SetString("2d96ebc6d29672f1fc80d5f711efc24b099d9e5805d6052db96dc6bfe58e8516", 16) + g421249166674228746791672110734681729275580381602196445017243910144x, _ := new(big.Int).SetString("20adf422bb92e8ebca244338030fff6e5750b73e3b59bef4cf27f9b8b43d86cc", 16) + g421249166674228746791672110734681729275580381602196445017243910144y, _ := new(big.Int).SetString("46d604bb8ba0f91062a910941f8640c12fee8aed73e49f47364de3375b82881", 16) + g842498333348457493583344221469363458551160763204392890034487820288x, _ := new(big.Int).SetString("1b8b0974839d00fcb8ce8411303de0a7c1eb3a4fee51cfc81bc5555cf11e72d1", 16) + g842498333348457493583344221469363458551160763204392890034487820288y, _ := new(big.Int).SetString("10f9785ecc740f71e35ac4bb5667d868c7e0f41d7ac008fe1002b98c74a13550", 16) + g1684996666696914987166688442938726917102321526408785780068975640576x, _ := new(big.Int).SetString("17804f51d82ccacb1f5c235f9229729042bba8586cf4439b4da2bf3ce9e3c6b4", 16) + g1684996666696914987166688442938726917102321526408785780068975640576y, _ := new(big.Int).SetString("4f911ef9571ad0f05275041c06fb56dd3ae9d6ca9faf59a98329140274dd0e3", 16) + g3369993333393829974333376885877453834204643052817571560137951281152x, _ := new(big.Int).SetString("2fcf22a313b481313f27289a45680aaf8805fe788fbdea9964bee963b47bbd6", 16) + g3369993333393829974333376885877453834204643052817571560137951281152y, _ := new(big.Int).SetString("29a1c6fa0c3cc610d930ef1748fecc57aae4d9b73762168af70432d5300acc6c", 16) + g6739986666787659948666753771754907668409286105635143120275902562304x, _ := new(big.Int).SetString("19d7f00e9da0ff3c5e36640d537dc9d8b297918680f8ef92ec5fb5c237e71d94", 16) + g6739986666787659948666753771754907668409286105635143120275902562304y, _ := new(big.Int).SetString("2b1aaab94d44134f97e647d973ec4f5db5627e6fd219f3f3f1e08f487f0b088e", 16) + g13479973333575319897333507543509815336818572211270286240551805124608x, _ := new(big.Int).SetString("1f84c3be21eedc0a6f3a0e8ed81866d2517d1ee09fb86a51601354cbc282c9ae", 16) + g13479973333575319897333507543509815336818572211270286240551805124608y, _ := new(big.Int).SetString("8b172a26e838681d0c4d3cfb013abf392141ee2f871903f94966ab2e7c67995", 16) + g26959946667150639794667015087019630673637144422540572481103610249216x, _ := new(big.Int).SetString("1803f42b6154c73df3776a86da598b72c820e0a39058a6272c97ec432746a253", 16) + g26959946667150639794667015087019630673637144422540572481103610249216y, _ := new(big.Int).SetString("11e4372b105bbbc4ee89496343eddd5f299ca4199190455953e6a4d5d0331172", 16) + g53919893334301279589334030174039261347274288845081144962207220498432x, _ := new(big.Int).SetString("13b103f06dec9eb67eeb1252f52e8ff88c2164c330742569ba6c0c1d79b43d58", 16) + g53919893334301279589334030174039261347274288845081144962207220498432y, _ := new(big.Int).SetString("24983f8c5d29be49c03a61673aa24b73b20f790d821a1832b61276203854ed41", 16) + g107839786668602559178668060348078522694548577690162289924414440996864x, _ := new(big.Int).SetString("2e1389cf976ee7d9ce2992c62c6bbd5268b1096f6e89c6870c25a4737c154fd4", 16) + g107839786668602559178668060348078522694548577690162289924414440996864y, _ := new(big.Int).SetString("2026565add482c9e333bf0f03cc1a0e6de8a45e2fcc79f298f1588852ebc239b", 16) + g215679573337205118357336120696157045389097155380324579848828881993728x, _ := new(big.Int).SetString("27816d71c08ddc593972e5d647880eb1c9fba52ddc130629a4867ec559903e7a", 16) + g215679573337205118357336120696157045389097155380324579848828881993728y, _ := new(big.Int).SetString("2d4342a5b94a716d13ddc4e034263d2526fa8f9dc4672b0490d326a0b2c24104", 16) + g431359146674410236714672241392314090778194310760649159697657763987456x, _ := new(big.Int).SetString("3e8748e8aa834f74f78325f4cade8beb5b2cd987e003dd2e01ca1e507b882ea", 16) + g431359146674410236714672241392314090778194310760649159697657763987456y, _ := new(big.Int).SetString("14e84a9b617bc3bbc51c7580aed6af624f108084aaa51c57c0f6bb42966a06e3", 16) + g862718293348820473429344482784628181556388621521298319395315527974912x, _ := new(big.Int).SetString("2e0333e017005d5580d8f37930910e83a4ec1cbb81513d5c4497e07bb4759ac3", 16) + g862718293348820473429344482784628181556388621521298319395315527974912y, _ := new(big.Int).SetString("2efa0d2056e33484bfd0d28038a697b52071ae3daad55e734c4f1788be4e26e0", 16) + g1725436586697640946858688965569256363112777243042596638790631055949824x, _ := new(big.Int).SetString("66dd4f74bde89af1e484ee7999209deec62204f6fadfe137a007bd1b8a41322", 16) + g1725436586697640946858688965569256363112777243042596638790631055949824y, _ := new(big.Int).SetString("1fafe097739d80d7254bcb0604d47a42a19606e61a5c9464b74c343740615c6d", 16) + g3450873173395281893717377931138512726225554486085193277581262111899648x, _ := new(big.Int).SetString("d3abc9d71dd3d76ec536fdd34c3d535ccd3b2c92e344b04ea63e7a95bf1d40d", 16) + g3450873173395281893717377931138512726225554486085193277581262111899648y, _ := new(big.Int).SetString("4e2d118cd7c19f8b38b28570d982bdf9398ec57fb2bb0d7e8f31e4c8ea3a7e", 16) + g6901746346790563787434755862277025452451108972170386555162524223799296x, _ := new(big.Int).SetString("17a6c2b336d61bf255af78c33a67cf1de2896995df7e83f8241109a184dbbea7", 16) + g6901746346790563787434755862277025452451108972170386555162524223799296y, _ := new(big.Int).SetString("123d241884de16c8078118cf8168546668a7c354c1aadc61505121f1c69318ee", 16) + g13803492693581127574869511724554050904902217944340773110325048447598592x, _ := new(big.Int).SetString("a86bd18c2e2dc328a7fff99345d131988bdb003f53487da1d9affd07dfa4caa", 16) + g13803492693581127574869511724554050904902217944340773110325048447598592y, _ := new(big.Int).SetString("270232b8aa979307cef134be75f5d025d01c3c6ba2f66499e3615e5b2dd00781", 16) + g27606985387162255149739023449108101809804435888681546220650096895197184x, _ := new(big.Int).SetString("1e355fcab47dd4264a85652319a0dddf1ba3889eaaa9e05f21247e4202bda1a5", 16) + g27606985387162255149739023449108101809804435888681546220650096895197184y, _ := new(big.Int).SetString("d60a88eb2f714752b7aecdeb65939828faa6e1e38e8ea1606a7a15e71e7a194", 16) + g55213970774324510299478046898216203619608871777363092441300193790394368x, _ := new(big.Int).SetString("1eb1ba9d3cb37f1e320b57a13707f1b4b40333e1d9893d2d9c6012f5667001c9", 16) + g55213970774324510299478046898216203619608871777363092441300193790394368y, _ := new(big.Int).SetString("c1dea44b0e7ba28967fe607c50f983c3bdec527612e81245029958308f7cbbb", 16) + g110427941548649020598956093796432407239217743554726184882600387580788736x, _ := new(big.Int).SetString("dcd731a87dfac8e27719ecbe1098c415477febd6f06a227fb45f0b8b0b16d9", 16) + g110427941548649020598956093796432407239217743554726184882600387580788736y, _ := new(big.Int).SetString("27218920b62eb55167704aa95c9929a79ead041e57e1f26d5f2b3affa474655b", 16) + g220855883097298041197912187592864814478435487109452369765200775161577472x, _ := new(big.Int).SetString("3058fe52fd5ea77191aba39e84854d7d3f317390b1d869536d81544fad1a7e7f", 16) + g220855883097298041197912187592864814478435487109452369765200775161577472y, _ := new(big.Int).SetString("1f64fd77c47fad6766218a0ca3e9b34b6207ed59f8eb2f902e1548d156584a90", 16) + g441711766194596082395824375185729628956870974218904739530401550323154944x, _ := new(big.Int).SetString("1b5956deed90482c1cc4989e936ca265252d6dd8159a13270b78248b30843363", 16) + g441711766194596082395824375185729628956870974218904739530401550323154944y, _ := new(big.Int).SetString("72ff5f961d1d225dec43bffd5f031562c9087a3a032305b1b716cdd158da5ca", 16) + g883423532389192164791648750371459257913741948437809479060803100646309888x, _ := new(big.Int).SetString("1ee79768b58b0bbebf614d41fcfd9e17a88c38b41d697a2104a931a3cf3106d6", 16) + g883423532389192164791648750371459257913741948437809479060803100646309888y, _ := new(big.Int).SetString("2ac2a26c534a3a84f696dd581ee7063f8910ca58954e436470d1fcc17dbbaad2", 16) + g1766847064778384329583297500742918515827483896875618958121606201292619776x, _ := new(big.Int).SetString("13932be07d7ef64690655fe3541d25b47caa20f0dba7e5843dc309e47fd4036", 16) + g1766847064778384329583297500742918515827483896875618958121606201292619776y, _ := new(big.Int).SetString("68daa9f3433ea9cfe8ab217593263464d3f3796d224d0c837ceb1ba5a388b5c", 16) + g3533694129556768659166595001485837031654967793751237916243212402585239552x, _ := new(big.Int).SetString("28982c2db4c7cc3f0ac38ae0d7a1774e276872fc2fc9be7b97038d1b7deeadad", 16) + g3533694129556768659166595001485837031654967793751237916243212402585239552y, _ := new(big.Int).SetString("fcd19a4ed741eac34e323909b7407f5a612a101c0d5687ea381bd36fd92d2c", 16) + g7067388259113537318333190002971674063309935587502475832486424805170479104x, _ := new(big.Int).SetString("233baee1bae9440f6456b6172b7b08e3b659265362d198e5196ef41d3a2d4b5a", 16) + g7067388259113537318333190002971674063309935587502475832486424805170479104y, _ := new(big.Int).SetString("2eae64ae6c81702e537c49c50c434556a49e9c734bf59580c86f19f2a0fb3374", 16) + g14134776518227074636666380005943348126619871175004951664972849610340958208x, _ := new(big.Int).SetString("2d5968f58c658153ee254d4bded6784e5e057251477b539a6d91f087985338ea", 16) + g14134776518227074636666380005943348126619871175004951664972849610340958208y, _ := new(big.Int).SetString("e0d8224d8090e8f7958bf46ea5f8d2d02370bbab1f4a449e50fee36e3f70773", 16) + g28269553036454149273332760011886696253239742350009903329945699220681916416x, _ := new(big.Int).SetString("282ba63c4d8d5c9d2477af22fa57cbb3618501dd22727c2a3244988179c98d2d", 16) + g28269553036454149273332760011886696253239742350009903329945699220681916416y, _ := new(big.Int).SetString("17957e0d498bd3694c8e62242bc37535cd445bf2a773ad9443cb3771fe113854", 16) + g56539106072908298546665520023773392506479484700019806659891398441363832832x, _ := new(big.Int).SetString("156e5523efb7270e38e80e154849f705a6184365b2261f3db870014428425d83", 16) + g56539106072908298546665520023773392506479484700019806659891398441363832832y, _ := new(big.Int).SetString("2a5e19cd3faf740e1f3ec427897c8da2804b0479bad28ce00ae15b088b04038b", 16) + g113078212145816597093331040047546785012958969400039613319782796882727665664x, _ := new(big.Int).SetString("7edfbd9cb99499052ada8d94e740625888f260adc45fcb5fe9be555b3221d74", 16) + g113078212145816597093331040047546785012958969400039613319782796882727665664y, _ := new(big.Int).SetString("1fd8c3a97911b6eac726e002fd3b84eceaa2b08a57e3df4227067fb5896aaed0", 16) + g226156424291633194186662080095093570025917938800079226639565593765455331328x, _ := new(big.Int).SetString("1725b4a59ea736ec816444dc53dbdf7e78d9194d537fa199c2883a38c60a06ed", 16) + g226156424291633194186662080095093570025917938800079226639565593765455331328y, _ := new(big.Int).SetString("249e0d5a519ef3f2ab6240aba00e912927ad4151be494765e2e31a1566828b06", 16) + g452312848583266388373324160190187140051835877600158453279131187530910662656x, _ := new(big.Int).SetString("5483b9dfbeb5b9fb31fd52b885335da4b23cdf83f2607d37e3fcbe112a85365", 16) + g452312848583266388373324160190187140051835877600158453279131187530910662656y, _ := new(big.Int).SetString("24e0ba9901789eaa6a0dc74bbf22debf9891bc5c03991db95f69df9c25ca6fcf", 16) + g904625697166532776746648320380374280103671755200316906558262375061821325312x, _ := new(big.Int).SetString("65a6b8b56220596ad72f24aea44c1d62f4c1544f23d4e968112d3d57f76c9b5", 16) + g904625697166532776746648320380374280103671755200316906558262375061821325312y, _ := new(big.Int).SetString("2d8d82657d6f9f9d5676cece3b7547be1b2ab34879690cd1d231716891525cf7", 16) + g1809251394333065553493296640760748560207343510400633813116524750123642650624x, _ := new(big.Int).SetString("21f2133247ee84c3bd8c96271b6ad6482744b3367a13f0260535a908caea1d20", 16) + g1809251394333065553493296640760748560207343510400633813116524750123642650624y, _ := new(big.Int).SetString("85b3a99f7d8418907dc897428443fae817137980fe5195974b11d212c6f2171", 16) + g3618502788666131106986593281521497120414687020801267626233049500247285301248x, _ := new(big.Int).SetString("29eed773adae30e41534a519179a5193ace5c32048775a50d6e1a7f998c5636b", 16) + g3618502788666131106986593281521497120414687020801267626233049500247285301248y, _ := new(big.Int).SetString("187868b2ac41a139f3563229e0ee02d65d27e38de3276ad2a4fd503c4f920010", 16) + g7237005577332262213973186563042994240829374041602535252466099000494570602496x, _ := new(big.Int).SetString("ebf18cffd536c5521028aeab7afb898bf91d8abde80f16a70ab404b49dde064", 16) + g7237005577332262213973186563042994240829374041602535252466099000494570602496y, _ := new(big.Int).SetString("2558d4421ddf231cf775888494c86ac8883a92df8b171dbc7e0f26978c2f1533", 16) + g14474011154664524427946373126085988481658748083205070504932198000989141204992x, _ := new(big.Int).SetString("9a5c6756cfc787c9df52f40fa211edfed26f0303bb2e404fa53d486a8ec7963", 16) + g14474011154664524427946373126085988481658748083205070504932198000989141204992y, _ := new(big.Int).SetString("28e47c414278b7f61d2e58077a5d6f12ebcd88950385108a733284e2861b8f81", 16) + g28948022309329048855892746252171976963317496166410141009864396001978282409984x, _ := new(big.Int).SetString("3d541efe3a8777fd5cd6aea697dc2f83706644289adaa9380e68bc150476b0b", 16) + g28948022309329048855892746252171976963317496166410141009864396001978282409984y, _ := new(big.Int).SetString("23fd426daa5672681e63f3c44963a131182ea5f8b9dffc4e4067f321b77648a2", 16) + g57896044618658097711785492504343953926634992332820282019728792003956564819968x, _ := new(big.Int).SetString("18ba548c687cb306f9996e95ebff7530528177141ebd26680d2d994ea1f5b4dd", 16) + g57896044618658097711785492504343953926634992332820282019728792003956564819968y, _ := new(big.Int).SetString("1a34ebd78433b90b62760d37f89ae069a85651a109939e329a4f266ce94c9d64", 16) + g115792089237316195423570985008687907853269984665640564039457584007913129639936x, _ := new(big.Int).SetString("1d78954c630b3895fbbfafac1294f2c0158879fdc70bfe18222890e7bfb66fba", 16) + g115792089237316195423570985008687907853269984665640564039457584007913129639936y, _ := new(big.Int).SetString("20481b2bf7a68cbf47d796f93f038986340f3d19849a3239f93fcc1a1192aff1", 16) + return CurveParams{ A: big.NewInt(0), B: big.NewInt(3), Gx: gx, Gy: gy, + + Gmx: [256]*big.Int{g2x, g4x, g8x, g16x, g32x, g64x, g128x, g256x, g512x, g1024x, g2048x, g4096x, g8192x, g16384x, g32768x, g65536x, g131072x, g262144x, g524288x, g1048576x, g2097152x, g4194304x, g8388608x, g16777216x, g33554432x, g67108864x, g134217728x, g268435456x, g536870912x, g1073741824x, g2147483648x, g4294967296x, g8589934592x, g17179869184x, g34359738368x, g68719476736x, g137438953472x, g274877906944x, g549755813888x, g1099511627776x, g2199023255552x, g4398046511104x, g8796093022208x, g17592186044416x, g35184372088832x, g70368744177664x, g140737488355328x, g281474976710656x, g562949953421312x, g1125899906842624x, g2251799813685248x, g4503599627370496x, g9007199254740992x, g18014398509481984x, g36028797018963968x, g72057594037927936x, g144115188075855872x, g288230376151711744x, g576460752303423488x, g1152921504606846976x, g2305843009213693952x, g4611686018427387904x, g9223372036854775808x, g18446744073709551616x, g36893488147419103232x, g73786976294838206464x, g147573952589676412928x, g295147905179352825856x, g590295810358705651712x, g1180591620717411303424x, g2361183241434822606848x, g4722366482869645213696x, g9444732965739290427392x, g18889465931478580854784x, g37778931862957161709568x, g75557863725914323419136x, g151115727451828646838272x, g302231454903657293676544x, g604462909807314587353088x, g1208925819614629174706176x, g2417851639229258349412352x, g4835703278458516698824704x, g9671406556917033397649408x, g19342813113834066795298816x, g38685626227668133590597632x, g77371252455336267181195264x, g154742504910672534362390528x, g309485009821345068724781056x, g618970019642690137449562112x, g1237940039285380274899124224x, g2475880078570760549798248448x, g4951760157141521099596496896x, g9903520314283042199192993792x, g19807040628566084398385987584x, g39614081257132168796771975168x, g79228162514264337593543950336x, g158456325028528675187087900672x, g316912650057057350374175801344x, g633825300114114700748351602688x, g1267650600228229401496703205376x, g2535301200456458802993406410752x, g5070602400912917605986812821504x, g10141204801825835211973625643008x, g20282409603651670423947251286016x, g40564819207303340847894502572032x, g81129638414606681695789005144064x, g162259276829213363391578010288128x, g324518553658426726783156020576256x, g649037107316853453566312041152512x, g1298074214633706907132624082305024x, g2596148429267413814265248164610048x, g5192296858534827628530496329220096x, g10384593717069655257060992658440192x, g20769187434139310514121985316880384x, g41538374868278621028243970633760768x, g83076749736557242056487941267521536x, g166153499473114484112975882535043072x, g332306998946228968225951765070086144x, g664613997892457936451903530140172288x, g1329227995784915872903807060280344576x, g2658455991569831745807614120560689152x, g5316911983139663491615228241121378304x, g10633823966279326983230456482242756608x, g21267647932558653966460912964485513216x, g42535295865117307932921825928971026432x, g85070591730234615865843651857942052864x, g170141183460469231731687303715884105728x, g340282366920938463463374607431768211456x, g680564733841876926926749214863536422912x, g1361129467683753853853498429727072845824x, g2722258935367507707706996859454145691648x, g5444517870735015415413993718908291383296x, g10889035741470030830827987437816582766592x, g21778071482940061661655974875633165533184x, g43556142965880123323311949751266331066368x, g87112285931760246646623899502532662132736x, g174224571863520493293247799005065324265472x, g348449143727040986586495598010130648530944x, g696898287454081973172991196020261297061888x, g1393796574908163946345982392040522594123776x, g2787593149816327892691964784081045188247552x, g5575186299632655785383929568162090376495104x, g11150372599265311570767859136324180752990208x, g22300745198530623141535718272648361505980416x, g44601490397061246283071436545296723011960832x, g89202980794122492566142873090593446023921664x, g178405961588244985132285746181186892047843328x, g356811923176489970264571492362373784095686656x, g713623846352979940529142984724747568191373312x, g1427247692705959881058285969449495136382746624x, g2854495385411919762116571938898990272765493248x, g5708990770823839524233143877797980545530986496x, g11417981541647679048466287755595961091061972992x, g22835963083295358096932575511191922182123945984x, g45671926166590716193865151022383844364247891968x, g91343852333181432387730302044767688728495783936x, g182687704666362864775460604089535377456991567872x, g365375409332725729550921208179070754913983135744x, g730750818665451459101842416358141509827966271488x, g1461501637330902918203684832716283019655932542976x, g2923003274661805836407369665432566039311865085952x, g5846006549323611672814739330865132078623730171904x, g11692013098647223345629478661730264157247460343808x, g23384026197294446691258957323460528314494920687616x, g46768052394588893382517914646921056628989841375232x, g93536104789177786765035829293842113257979682750464x, g187072209578355573530071658587684226515959365500928x, g374144419156711147060143317175368453031918731001856x, g748288838313422294120286634350736906063837462003712x, g1496577676626844588240573268701473812127674924007424x, g2993155353253689176481146537402947624255349848014848x, g5986310706507378352962293074805895248510699696029696x, g11972621413014756705924586149611790497021399392059392x, g23945242826029513411849172299223580994042798784118784x, g47890485652059026823698344598447161988085597568237568x, g95780971304118053647396689196894323976171195136475136x, g191561942608236107294793378393788647952342390272950272x, g383123885216472214589586756787577295904684780545900544x, g766247770432944429179173513575154591809369561091801088x, g1532495540865888858358347027150309183618739122183602176x, g3064991081731777716716694054300618367237478244367204352x, g6129982163463555433433388108601236734474956488734408704x, g12259964326927110866866776217202473468949912977468817408x, g24519928653854221733733552434404946937899825954937634816x, g49039857307708443467467104868809893875799651909875269632x, g98079714615416886934934209737619787751599303819750539264x, g196159429230833773869868419475239575503198607639501078528x, g392318858461667547739736838950479151006397215279002157056x, g784637716923335095479473677900958302012794430558004314112x, g1569275433846670190958947355801916604025588861116008628224x, g3138550867693340381917894711603833208051177722232017256448x, g6277101735386680763835789423207666416102355444464034512896x, g12554203470773361527671578846415332832204710888928069025792x, g25108406941546723055343157692830665664409421777856138051584x, g50216813883093446110686315385661331328818843555712276103168x, g100433627766186892221372630771322662657637687111424552206336x, g200867255532373784442745261542645325315275374222849104412672x, g401734511064747568885490523085290650630550748445698208825344x, g803469022129495137770981046170581301261101496891396417650688x, g1606938044258990275541962092341162602522202993782792835301376x, g3213876088517980551083924184682325205044405987565585670602752x, g6427752177035961102167848369364650410088811975131171341205504x, g12855504354071922204335696738729300820177623950262342682411008x, g25711008708143844408671393477458601640355247900524685364822016x, g51422017416287688817342786954917203280710495801049370729644032x, g102844034832575377634685573909834406561420991602098741459288064x, g205688069665150755269371147819668813122841983204197482918576128x, g411376139330301510538742295639337626245683966408394965837152256x, g822752278660603021077484591278675252491367932816789931674304512x, g1645504557321206042154969182557350504982735865633579863348609024x, g3291009114642412084309938365114701009965471731267159726697218048x, g6582018229284824168619876730229402019930943462534319453394436096x, g13164036458569648337239753460458804039861886925068638906788872192x, g26328072917139296674479506920917608079723773850137277813577744384x, g52656145834278593348959013841835216159447547700274555627155488768x, g105312291668557186697918027683670432318895095400549111254310977536x, g210624583337114373395836055367340864637790190801098222508621955072x, g421249166674228746791672110734681729275580381602196445017243910144x, g842498333348457493583344221469363458551160763204392890034487820288x, g1684996666696914987166688442938726917102321526408785780068975640576x, g3369993333393829974333376885877453834204643052817571560137951281152x, g6739986666787659948666753771754907668409286105635143120275902562304x, g13479973333575319897333507543509815336818572211270286240551805124608x, g26959946667150639794667015087019630673637144422540572481103610249216x, g53919893334301279589334030174039261347274288845081144962207220498432x, g107839786668602559178668060348078522694548577690162289924414440996864x, g215679573337205118357336120696157045389097155380324579848828881993728x, g431359146674410236714672241392314090778194310760649159697657763987456x, g862718293348820473429344482784628181556388621521298319395315527974912x, g1725436586697640946858688965569256363112777243042596638790631055949824x, g3450873173395281893717377931138512726225554486085193277581262111899648x, g6901746346790563787434755862277025452451108972170386555162524223799296x, g13803492693581127574869511724554050904902217944340773110325048447598592x, g27606985387162255149739023449108101809804435888681546220650096895197184x, g55213970774324510299478046898216203619608871777363092441300193790394368x, g110427941548649020598956093796432407239217743554726184882600387580788736x, g220855883097298041197912187592864814478435487109452369765200775161577472x, g441711766194596082395824375185729628956870974218904739530401550323154944x, g883423532389192164791648750371459257913741948437809479060803100646309888x, g1766847064778384329583297500742918515827483896875618958121606201292619776x, g3533694129556768659166595001485837031654967793751237916243212402585239552x, g7067388259113537318333190002971674063309935587502475832486424805170479104x, g14134776518227074636666380005943348126619871175004951664972849610340958208x, g28269553036454149273332760011886696253239742350009903329945699220681916416x, g56539106072908298546665520023773392506479484700019806659891398441363832832x, g113078212145816597093331040047546785012958969400039613319782796882727665664x, g226156424291633194186662080095093570025917938800079226639565593765455331328x, g452312848583266388373324160190187140051835877600158453279131187530910662656x, g904625697166532776746648320380374280103671755200316906558262375061821325312x, g1809251394333065553493296640760748560207343510400633813116524750123642650624x, g3618502788666131106986593281521497120414687020801267626233049500247285301248x, g7237005577332262213973186563042994240829374041602535252466099000494570602496x, g14474011154664524427946373126085988481658748083205070504932198000989141204992x, g28948022309329048855892746252171976963317496166410141009864396001978282409984x, g57896044618658097711785492504343953926634992332820282019728792003956564819968x, g115792089237316195423570985008687907853269984665640564039457584007913129639936x}, + Gmy: [256]*big.Int{g2y, g4y, g8y, g16y, g32y, g64y, g128y, g256y, g512y, g1024y, g2048y, g4096y, g8192y, g16384y, g32768y, g65536y, g131072y, g262144y, g524288y, g1048576y, g2097152y, g4194304y, g8388608y, g16777216y, g33554432y, g67108864y, g134217728y, g268435456y, g536870912y, g1073741824y, g2147483648y, g4294967296y, g8589934592y, g17179869184y, g34359738368y, g68719476736y, g137438953472y, g274877906944y, g549755813888y, g1099511627776y, g2199023255552y, g4398046511104y, g8796093022208y, g17592186044416y, g35184372088832y, g70368744177664y, g140737488355328y, g281474976710656y, g562949953421312y, g1125899906842624y, g2251799813685248y, g4503599627370496y, g9007199254740992y, g18014398509481984y, g36028797018963968y, g72057594037927936y, g144115188075855872y, g288230376151711744y, g576460752303423488y, g1152921504606846976y, g2305843009213693952y, g4611686018427387904y, g9223372036854775808y, g18446744073709551616y, g36893488147419103232y, g73786976294838206464y, g147573952589676412928y, g295147905179352825856y, g590295810358705651712y, g1180591620717411303424y, g2361183241434822606848y, g4722366482869645213696y, g9444732965739290427392y, g18889465931478580854784y, g37778931862957161709568y, g75557863725914323419136y, g151115727451828646838272y, g302231454903657293676544y, g604462909807314587353088y, g1208925819614629174706176y, g2417851639229258349412352y, g4835703278458516698824704y, g9671406556917033397649408y, g19342813113834066795298816y, g38685626227668133590597632y, g77371252455336267181195264y, g154742504910672534362390528y, g309485009821345068724781056y, g618970019642690137449562112y, g1237940039285380274899124224y, g2475880078570760549798248448y, g4951760157141521099596496896y, g9903520314283042199192993792y, g19807040628566084398385987584y, g39614081257132168796771975168y, g79228162514264337593543950336y, g158456325028528675187087900672y, g316912650057057350374175801344y, g633825300114114700748351602688y, g1267650600228229401496703205376y, g2535301200456458802993406410752y, g5070602400912917605986812821504y, g10141204801825835211973625643008y, g20282409603651670423947251286016y, g40564819207303340847894502572032y, g81129638414606681695789005144064y, g162259276829213363391578010288128y, g324518553658426726783156020576256y, g649037107316853453566312041152512y, g1298074214633706907132624082305024y, g2596148429267413814265248164610048y, g5192296858534827628530496329220096y, g10384593717069655257060992658440192y, g20769187434139310514121985316880384y, g41538374868278621028243970633760768y, g83076749736557242056487941267521536y, g166153499473114484112975882535043072y, g332306998946228968225951765070086144y, g664613997892457936451903530140172288y, g1329227995784915872903807060280344576y, g2658455991569831745807614120560689152y, g5316911983139663491615228241121378304y, g10633823966279326983230456482242756608y, g21267647932558653966460912964485513216y, g42535295865117307932921825928971026432y, g85070591730234615865843651857942052864y, g170141183460469231731687303715884105728y, g340282366920938463463374607431768211456y, g680564733841876926926749214863536422912y, g1361129467683753853853498429727072845824y, g2722258935367507707706996859454145691648y, g5444517870735015415413993718908291383296y, g10889035741470030830827987437816582766592y, g21778071482940061661655974875633165533184y, g43556142965880123323311949751266331066368y, g87112285931760246646623899502532662132736y, g174224571863520493293247799005065324265472y, g348449143727040986586495598010130648530944y, g696898287454081973172991196020261297061888y, g1393796574908163946345982392040522594123776y, g2787593149816327892691964784081045188247552y, g5575186299632655785383929568162090376495104y, g11150372599265311570767859136324180752990208y, g22300745198530623141535718272648361505980416y, g44601490397061246283071436545296723011960832y, g89202980794122492566142873090593446023921664y, g178405961588244985132285746181186892047843328y, g356811923176489970264571492362373784095686656y, g713623846352979940529142984724747568191373312y, g1427247692705959881058285969449495136382746624y, g2854495385411919762116571938898990272765493248y, g5708990770823839524233143877797980545530986496y, g11417981541647679048466287755595961091061972992y, g22835963083295358096932575511191922182123945984y, g45671926166590716193865151022383844364247891968y, g91343852333181432387730302044767688728495783936y, g182687704666362864775460604089535377456991567872y, g365375409332725729550921208179070754913983135744y, g730750818665451459101842416358141509827966271488y, g1461501637330902918203684832716283019655932542976y, g2923003274661805836407369665432566039311865085952y, g5846006549323611672814739330865132078623730171904y, g11692013098647223345629478661730264157247460343808y, g23384026197294446691258957323460528314494920687616y, g46768052394588893382517914646921056628989841375232y, g93536104789177786765035829293842113257979682750464y, g187072209578355573530071658587684226515959365500928y, g374144419156711147060143317175368453031918731001856y, g748288838313422294120286634350736906063837462003712y, g1496577676626844588240573268701473812127674924007424y, g2993155353253689176481146537402947624255349848014848y, g5986310706507378352962293074805895248510699696029696y, g11972621413014756705924586149611790497021399392059392y, g23945242826029513411849172299223580994042798784118784y, g47890485652059026823698344598447161988085597568237568y, g95780971304118053647396689196894323976171195136475136y, g191561942608236107294793378393788647952342390272950272y, g383123885216472214589586756787577295904684780545900544y, g766247770432944429179173513575154591809369561091801088y, g1532495540865888858358347027150309183618739122183602176y, g3064991081731777716716694054300618367237478244367204352y, g6129982163463555433433388108601236734474956488734408704y, g12259964326927110866866776217202473468949912977468817408y, g24519928653854221733733552434404946937899825954937634816y, g49039857307708443467467104868809893875799651909875269632y, g98079714615416886934934209737619787751599303819750539264y, g196159429230833773869868419475239575503198607639501078528y, g392318858461667547739736838950479151006397215279002157056y, g784637716923335095479473677900958302012794430558004314112y, g1569275433846670190958947355801916604025588861116008628224y, g3138550867693340381917894711603833208051177722232017256448y, g6277101735386680763835789423207666416102355444464034512896y, g12554203470773361527671578846415332832204710888928069025792y, g25108406941546723055343157692830665664409421777856138051584y, g50216813883093446110686315385661331328818843555712276103168y, g100433627766186892221372630771322662657637687111424552206336y, g200867255532373784442745261542645325315275374222849104412672y, g401734511064747568885490523085290650630550748445698208825344y, g803469022129495137770981046170581301261101496891396417650688y, g1606938044258990275541962092341162602522202993782792835301376y, g3213876088517980551083924184682325205044405987565585670602752y, g6427752177035961102167848369364650410088811975131171341205504y, g12855504354071922204335696738729300820177623950262342682411008y, g25711008708143844408671393477458601640355247900524685364822016y, g51422017416287688817342786954917203280710495801049370729644032y, g102844034832575377634685573909834406561420991602098741459288064y, g205688069665150755269371147819668813122841983204197482918576128y, g411376139330301510538742295639337626245683966408394965837152256y, g822752278660603021077484591278675252491367932816789931674304512y, g1645504557321206042154969182557350504982735865633579863348609024y, g3291009114642412084309938365114701009965471731267159726697218048y, g6582018229284824168619876730229402019930943462534319453394436096y, g13164036458569648337239753460458804039861886925068638906788872192y, g26328072917139296674479506920917608079723773850137277813577744384y, g52656145834278593348959013841835216159447547700274555627155488768y, g105312291668557186697918027683670432318895095400549111254310977536y, g210624583337114373395836055367340864637790190801098222508621955072y, g421249166674228746791672110734681729275580381602196445017243910144y, g842498333348457493583344221469363458551160763204392890034487820288y, g1684996666696914987166688442938726917102321526408785780068975640576y, g3369993333393829974333376885877453834204643052817571560137951281152y, g6739986666787659948666753771754907668409286105635143120275902562304y, g13479973333575319897333507543509815336818572211270286240551805124608y, g26959946667150639794667015087019630673637144422540572481103610249216y, g53919893334301279589334030174039261347274288845081144962207220498432y, g107839786668602559178668060348078522694548577690162289924414440996864y, g215679573337205118357336120696157045389097155380324579848828881993728y, g431359146674410236714672241392314090778194310760649159697657763987456y, g862718293348820473429344482784628181556388621521298319395315527974912y, g1725436586697640946858688965569256363112777243042596638790631055949824y, g3450873173395281893717377931138512726225554486085193277581262111899648y, g6901746346790563787434755862277025452451108972170386555162524223799296y, g13803492693581127574869511724554050904902217944340773110325048447598592y, g27606985387162255149739023449108101809804435888681546220650096895197184y, g55213970774324510299478046898216203619608871777363092441300193790394368y, g110427941548649020598956093796432407239217743554726184882600387580788736y, g220855883097298041197912187592864814478435487109452369765200775161577472y, g441711766194596082395824375185729628956870974218904739530401550323154944y, g883423532389192164791648750371459257913741948437809479060803100646309888y, g1766847064778384329583297500742918515827483896875618958121606201292619776y, g3533694129556768659166595001485837031654967793751237916243212402585239552y, g7067388259113537318333190002971674063309935587502475832486424805170479104y, g14134776518227074636666380005943348126619871175004951664972849610340958208y, g28269553036454149273332760011886696253239742350009903329945699220681916416y, g56539106072908298546665520023773392506479484700019806659891398441363832832y, g113078212145816597093331040047546785012958969400039613319782796882727665664y, g226156424291633194186662080095093570025917938800079226639565593765455331328y, g452312848583266388373324160190187140051835877600158453279131187530910662656y, g904625697166532776746648320380374280103671755200316906558262375061821325312y, g1809251394333065553493296640760748560207343510400633813116524750123642650624y, g3618502788666131106986593281521497120414687020801267626233049500247285301248y, g7237005577332262213973186563042994240829374041602535252466099000494570602496y, g14474011154664524427946373126085988481658748083205070504932198000989141204992y, g28948022309329048855892746252171976963317496166410141009864396001978282409984y, g57896044618658097711785492504343953926634992332820282019728792003956564819968y, g115792089237316195423570985008687907853269984665640564039457584007913129639936y}, } } diff --git a/std/algebra/weierstrass/point.go b/std/algebra/weierstrass/point.go index 8c91ed2761..1caf665533 100644 --- a/std/algebra/weierstrass/point.go +++ b/std/algebra/weierstrass/point.go @@ -23,6 +23,518 @@ func New[Base, Scalars emulated.FieldParams](api frontend.API, params CurveParam } Gx := emulated.ValueOf[Base](params.Gx) Gy := emulated.ValueOf[Base](params.Gy) + G2x := emulated.ValueOf[Base](params.Gmx[0]) + G2y := emulated.ValueOf[Base](params.Gmy[0]) + G4x := emulated.ValueOf[Base](params.Gmx[1]) + G4y := emulated.ValueOf[Base](params.Gmy[1]) + G8x := emulated.ValueOf[Base](params.Gmx[2]) + G8y := emulated.ValueOf[Base](params.Gmy[2]) + G16x := emulated.ValueOf[Base](params.Gmx[3]) + G16y := emulated.ValueOf[Base](params.Gmy[3]) + G32x := emulated.ValueOf[Base](params.Gmx[4]) + G32y := emulated.ValueOf[Base](params.Gmy[4]) + G64x := emulated.ValueOf[Base](params.Gmx[5]) + G64y := emulated.ValueOf[Base](params.Gmy[5]) + G128x := emulated.ValueOf[Base](params.Gmx[6]) + G128y := emulated.ValueOf[Base](params.Gmy[6]) + G256x := emulated.ValueOf[Base](params.Gmx[7]) + G256y := emulated.ValueOf[Base](params.Gmy[7]) + G512x := emulated.ValueOf[Base](params.Gmx[8]) + G512y := emulated.ValueOf[Base](params.Gmy[8]) + G1024x := emulated.ValueOf[Base](params.Gmx[9]) + G1024y := emulated.ValueOf[Base](params.Gmy[9]) + G2048x := emulated.ValueOf[Base](params.Gmx[10]) + G2048y := emulated.ValueOf[Base](params.Gmy[10]) + G4096x := emulated.ValueOf[Base](params.Gmx[11]) + G4096y := emulated.ValueOf[Base](params.Gmy[11]) + G8192x := emulated.ValueOf[Base](params.Gmx[12]) + G8192y := emulated.ValueOf[Base](params.Gmy[12]) + G16384x := emulated.ValueOf[Base](params.Gmx[13]) + G16384y := emulated.ValueOf[Base](params.Gmy[13]) + G32768x := emulated.ValueOf[Base](params.Gmx[14]) + G32768y := emulated.ValueOf[Base](params.Gmy[14]) + G65536x := emulated.ValueOf[Base](params.Gmx[15]) + G65536y := emulated.ValueOf[Base](params.Gmy[15]) + G131072x := emulated.ValueOf[Base](params.Gmx[16]) + G131072y := emulated.ValueOf[Base](params.Gmy[16]) + G262144x := emulated.ValueOf[Base](params.Gmx[17]) + G262144y := emulated.ValueOf[Base](params.Gmy[17]) + G524288x := emulated.ValueOf[Base](params.Gmx[18]) + G524288y := emulated.ValueOf[Base](params.Gmy[18]) + G1048576x := emulated.ValueOf[Base](params.Gmx[19]) + G1048576y := emulated.ValueOf[Base](params.Gmy[19]) + G2097152x := emulated.ValueOf[Base](params.Gmx[20]) + G2097152y := emulated.ValueOf[Base](params.Gmy[20]) + G4194304x := emulated.ValueOf[Base](params.Gmx[21]) + G4194304y := emulated.ValueOf[Base](params.Gmy[21]) + G8388608x := emulated.ValueOf[Base](params.Gmx[22]) + G8388608y := emulated.ValueOf[Base](params.Gmy[22]) + G16777216x := emulated.ValueOf[Base](params.Gmx[23]) + G16777216y := emulated.ValueOf[Base](params.Gmy[23]) + G33554432x := emulated.ValueOf[Base](params.Gmx[24]) + G33554432y := emulated.ValueOf[Base](params.Gmy[24]) + G67108864x := emulated.ValueOf[Base](params.Gmx[25]) + G67108864y := emulated.ValueOf[Base](params.Gmy[25]) + G134217728x := emulated.ValueOf[Base](params.Gmx[26]) + G134217728y := emulated.ValueOf[Base](params.Gmy[26]) + G268435456x := emulated.ValueOf[Base](params.Gmx[27]) + G268435456y := emulated.ValueOf[Base](params.Gmy[27]) + G536870912x := emulated.ValueOf[Base](params.Gmx[28]) + G536870912y := emulated.ValueOf[Base](params.Gmy[28]) + G1073741824x := emulated.ValueOf[Base](params.Gmx[29]) + G1073741824y := emulated.ValueOf[Base](params.Gmy[29]) + G2147483648x := emulated.ValueOf[Base](params.Gmx[30]) + G2147483648y := emulated.ValueOf[Base](params.Gmy[30]) + G4294967296x := emulated.ValueOf[Base](params.Gmx[31]) + G4294967296y := emulated.ValueOf[Base](params.Gmy[31]) + G8589934592x := emulated.ValueOf[Base](params.Gmx[32]) + G8589934592y := emulated.ValueOf[Base](params.Gmy[32]) + G17179869184x := emulated.ValueOf[Base](params.Gmx[33]) + G17179869184y := emulated.ValueOf[Base](params.Gmy[33]) + G34359738368x := emulated.ValueOf[Base](params.Gmx[34]) + G34359738368y := emulated.ValueOf[Base](params.Gmy[34]) + G68719476736x := emulated.ValueOf[Base](params.Gmx[35]) + G68719476736y := emulated.ValueOf[Base](params.Gmy[35]) + G137438953472x := emulated.ValueOf[Base](params.Gmx[36]) + G137438953472y := emulated.ValueOf[Base](params.Gmy[36]) + G274877906944x := emulated.ValueOf[Base](params.Gmx[37]) + G274877906944y := emulated.ValueOf[Base](params.Gmy[37]) + G549755813888x := emulated.ValueOf[Base](params.Gmx[38]) + G549755813888y := emulated.ValueOf[Base](params.Gmy[38]) + G1099511627776x := emulated.ValueOf[Base](params.Gmx[39]) + G1099511627776y := emulated.ValueOf[Base](params.Gmy[39]) + G2199023255552x := emulated.ValueOf[Base](params.Gmx[40]) + G2199023255552y := emulated.ValueOf[Base](params.Gmy[40]) + G4398046511104x := emulated.ValueOf[Base](params.Gmx[41]) + G4398046511104y := emulated.ValueOf[Base](params.Gmy[41]) + G8796093022208x := emulated.ValueOf[Base](params.Gmx[42]) + G8796093022208y := emulated.ValueOf[Base](params.Gmy[42]) + G17592186044416x := emulated.ValueOf[Base](params.Gmx[43]) + G17592186044416y := emulated.ValueOf[Base](params.Gmy[43]) + G35184372088832x := emulated.ValueOf[Base](params.Gmx[44]) + G35184372088832y := emulated.ValueOf[Base](params.Gmy[44]) + G70368744177664x := emulated.ValueOf[Base](params.Gmx[45]) + G70368744177664y := emulated.ValueOf[Base](params.Gmy[45]) + G140737488355328x := emulated.ValueOf[Base](params.Gmx[46]) + G140737488355328y := emulated.ValueOf[Base](params.Gmy[46]) + G281474976710656x := emulated.ValueOf[Base](params.Gmx[47]) + G281474976710656y := emulated.ValueOf[Base](params.Gmy[47]) + G562949953421312x := emulated.ValueOf[Base](params.Gmx[48]) + G562949953421312y := emulated.ValueOf[Base](params.Gmy[48]) + G1125899906842624x := emulated.ValueOf[Base](params.Gmx[49]) + G1125899906842624y := emulated.ValueOf[Base](params.Gmy[49]) + G2251799813685248x := emulated.ValueOf[Base](params.Gmx[50]) + G2251799813685248y := emulated.ValueOf[Base](params.Gmy[50]) + G4503599627370496x := emulated.ValueOf[Base](params.Gmx[51]) + G4503599627370496y := emulated.ValueOf[Base](params.Gmy[51]) + G9007199254740992x := emulated.ValueOf[Base](params.Gmx[52]) + G9007199254740992y := emulated.ValueOf[Base](params.Gmy[52]) + G18014398509481984x := emulated.ValueOf[Base](params.Gmx[53]) + G18014398509481984y := emulated.ValueOf[Base](params.Gmy[53]) + G36028797018963968x := emulated.ValueOf[Base](params.Gmx[54]) + G36028797018963968y := emulated.ValueOf[Base](params.Gmy[54]) + G72057594037927936x := emulated.ValueOf[Base](params.Gmx[55]) + G72057594037927936y := emulated.ValueOf[Base](params.Gmy[55]) + G144115188075855872x := emulated.ValueOf[Base](params.Gmx[56]) + G144115188075855872y := emulated.ValueOf[Base](params.Gmy[56]) + G288230376151711744x := emulated.ValueOf[Base](params.Gmx[57]) + G288230376151711744y := emulated.ValueOf[Base](params.Gmy[57]) + G576460752303423488x := emulated.ValueOf[Base](params.Gmx[58]) + G576460752303423488y := emulated.ValueOf[Base](params.Gmy[58]) + G1152921504606846976x := emulated.ValueOf[Base](params.Gmx[59]) + G1152921504606846976y := emulated.ValueOf[Base](params.Gmy[59]) + G2305843009213693952x := emulated.ValueOf[Base](params.Gmx[60]) + G2305843009213693952y := emulated.ValueOf[Base](params.Gmy[60]) + G4611686018427387904x := emulated.ValueOf[Base](params.Gmx[61]) + G4611686018427387904y := emulated.ValueOf[Base](params.Gmy[61]) + G9223372036854775808x := emulated.ValueOf[Base](params.Gmx[62]) + G9223372036854775808y := emulated.ValueOf[Base](params.Gmy[62]) + G18446744073709551616x := emulated.ValueOf[Base](params.Gmx[63]) + G18446744073709551616y := emulated.ValueOf[Base](params.Gmy[63]) + G36893488147419103232x := emulated.ValueOf[Base](params.Gmx[64]) + G36893488147419103232y := emulated.ValueOf[Base](params.Gmy[64]) + G73786976294838206464x := emulated.ValueOf[Base](params.Gmx[65]) + G73786976294838206464y := emulated.ValueOf[Base](params.Gmy[65]) + G147573952589676412928x := emulated.ValueOf[Base](params.Gmx[66]) + G147573952589676412928y := emulated.ValueOf[Base](params.Gmy[66]) + G295147905179352825856x := emulated.ValueOf[Base](params.Gmx[67]) + G295147905179352825856y := emulated.ValueOf[Base](params.Gmy[67]) + G590295810358705651712x := emulated.ValueOf[Base](params.Gmx[68]) + G590295810358705651712y := emulated.ValueOf[Base](params.Gmy[68]) + G1180591620717411303424x := emulated.ValueOf[Base](params.Gmx[69]) + G1180591620717411303424y := emulated.ValueOf[Base](params.Gmy[69]) + G2361183241434822606848x := emulated.ValueOf[Base](params.Gmx[70]) + G2361183241434822606848y := emulated.ValueOf[Base](params.Gmy[70]) + G4722366482869645213696x := emulated.ValueOf[Base](params.Gmx[71]) + G4722366482869645213696y := emulated.ValueOf[Base](params.Gmy[71]) + G9444732965739290427392x := emulated.ValueOf[Base](params.Gmx[72]) + G9444732965739290427392y := emulated.ValueOf[Base](params.Gmy[72]) + G18889465931478580854784x := emulated.ValueOf[Base](params.Gmx[73]) + G18889465931478580854784y := emulated.ValueOf[Base](params.Gmy[73]) + G37778931862957161709568x := emulated.ValueOf[Base](params.Gmx[74]) + G37778931862957161709568y := emulated.ValueOf[Base](params.Gmy[74]) + G75557863725914323419136x := emulated.ValueOf[Base](params.Gmx[75]) + G75557863725914323419136y := emulated.ValueOf[Base](params.Gmy[75]) + G151115727451828646838272x := emulated.ValueOf[Base](params.Gmx[76]) + G151115727451828646838272y := emulated.ValueOf[Base](params.Gmy[76]) + G302231454903657293676544x := emulated.ValueOf[Base](params.Gmx[77]) + G302231454903657293676544y := emulated.ValueOf[Base](params.Gmy[77]) + G604462909807314587353088x := emulated.ValueOf[Base](params.Gmx[78]) + G604462909807314587353088y := emulated.ValueOf[Base](params.Gmy[78]) + G1208925819614629174706176x := emulated.ValueOf[Base](params.Gmx[79]) + G1208925819614629174706176y := emulated.ValueOf[Base](params.Gmy[79]) + G2417851639229258349412352x := emulated.ValueOf[Base](params.Gmx[80]) + G2417851639229258349412352y := emulated.ValueOf[Base](params.Gmy[80]) + G4835703278458516698824704x := emulated.ValueOf[Base](params.Gmx[81]) + G4835703278458516698824704y := emulated.ValueOf[Base](params.Gmy[81]) + G9671406556917033397649408x := emulated.ValueOf[Base](params.Gmx[82]) + G9671406556917033397649408y := emulated.ValueOf[Base](params.Gmy[82]) + G19342813113834066795298816x := emulated.ValueOf[Base](params.Gmx[83]) + G19342813113834066795298816y := emulated.ValueOf[Base](params.Gmy[83]) + G38685626227668133590597632x := emulated.ValueOf[Base](params.Gmx[84]) + G38685626227668133590597632y := emulated.ValueOf[Base](params.Gmy[84]) + G77371252455336267181195264x := emulated.ValueOf[Base](params.Gmx[85]) + G77371252455336267181195264y := emulated.ValueOf[Base](params.Gmy[85]) + G154742504910672534362390528x := emulated.ValueOf[Base](params.Gmx[86]) + G154742504910672534362390528y := emulated.ValueOf[Base](params.Gmy[86]) + G309485009821345068724781056x := emulated.ValueOf[Base](params.Gmx[87]) + G309485009821345068724781056y := emulated.ValueOf[Base](params.Gmy[87]) + G618970019642690137449562112x := emulated.ValueOf[Base](params.Gmx[88]) + G618970019642690137449562112y := emulated.ValueOf[Base](params.Gmy[88]) + G1237940039285380274899124224x := emulated.ValueOf[Base](params.Gmx[89]) + G1237940039285380274899124224y := emulated.ValueOf[Base](params.Gmy[89]) + G2475880078570760549798248448x := emulated.ValueOf[Base](params.Gmx[90]) + G2475880078570760549798248448y := emulated.ValueOf[Base](params.Gmy[90]) + G4951760157141521099596496896x := emulated.ValueOf[Base](params.Gmx[91]) + G4951760157141521099596496896y := emulated.ValueOf[Base](params.Gmy[91]) + G9903520314283042199192993792x := emulated.ValueOf[Base](params.Gmx[92]) + G9903520314283042199192993792y := emulated.ValueOf[Base](params.Gmy[92]) + G19807040628566084398385987584x := emulated.ValueOf[Base](params.Gmx[93]) + G19807040628566084398385987584y := emulated.ValueOf[Base](params.Gmy[93]) + G39614081257132168796771975168x := emulated.ValueOf[Base](params.Gmx[94]) + G39614081257132168796771975168y := emulated.ValueOf[Base](params.Gmy[94]) + G79228162514264337593543950336x := emulated.ValueOf[Base](params.Gmx[95]) + G79228162514264337593543950336y := emulated.ValueOf[Base](params.Gmy[95]) + G158456325028528675187087900672x := emulated.ValueOf[Base](params.Gmx[96]) + G158456325028528675187087900672y := emulated.ValueOf[Base](params.Gmy[96]) + G316912650057057350374175801344x := emulated.ValueOf[Base](params.Gmx[97]) + G316912650057057350374175801344y := emulated.ValueOf[Base](params.Gmy[97]) + G633825300114114700748351602688x := emulated.ValueOf[Base](params.Gmx[98]) + G633825300114114700748351602688y := emulated.ValueOf[Base](params.Gmy[98]) + G1267650600228229401496703205376x := emulated.ValueOf[Base](params.Gmx[99]) + G1267650600228229401496703205376y := emulated.ValueOf[Base](params.Gmy[99]) + G2535301200456458802993406410752x := emulated.ValueOf[Base](params.Gmx[100]) + G2535301200456458802993406410752y := emulated.ValueOf[Base](params.Gmy[100]) + G5070602400912917605986812821504x := emulated.ValueOf[Base](params.Gmx[101]) + G5070602400912917605986812821504y := emulated.ValueOf[Base](params.Gmy[101]) + G10141204801825835211973625643008x := emulated.ValueOf[Base](params.Gmx[102]) + G10141204801825835211973625643008y := emulated.ValueOf[Base](params.Gmy[102]) + G20282409603651670423947251286016x := emulated.ValueOf[Base](params.Gmx[103]) + G20282409603651670423947251286016y := emulated.ValueOf[Base](params.Gmy[103]) + G40564819207303340847894502572032x := emulated.ValueOf[Base](params.Gmx[104]) + G40564819207303340847894502572032y := emulated.ValueOf[Base](params.Gmy[104]) + G81129638414606681695789005144064x := emulated.ValueOf[Base](params.Gmx[105]) + G81129638414606681695789005144064y := emulated.ValueOf[Base](params.Gmy[105]) + G162259276829213363391578010288128x := emulated.ValueOf[Base](params.Gmx[106]) + G162259276829213363391578010288128y := emulated.ValueOf[Base](params.Gmy[106]) + G324518553658426726783156020576256x := emulated.ValueOf[Base](params.Gmx[107]) + G324518553658426726783156020576256y := emulated.ValueOf[Base](params.Gmy[107]) + G649037107316853453566312041152512x := emulated.ValueOf[Base](params.Gmx[108]) + G649037107316853453566312041152512y := emulated.ValueOf[Base](params.Gmy[108]) + G1298074214633706907132624082305024x := emulated.ValueOf[Base](params.Gmx[109]) + G1298074214633706907132624082305024y := emulated.ValueOf[Base](params.Gmy[109]) + G2596148429267413814265248164610048x := emulated.ValueOf[Base](params.Gmx[110]) + G2596148429267413814265248164610048y := emulated.ValueOf[Base](params.Gmy[110]) + G5192296858534827628530496329220096x := emulated.ValueOf[Base](params.Gmx[111]) + G5192296858534827628530496329220096y := emulated.ValueOf[Base](params.Gmy[111]) + G10384593717069655257060992658440192x := emulated.ValueOf[Base](params.Gmx[112]) + G10384593717069655257060992658440192y := emulated.ValueOf[Base](params.Gmy[112]) + G20769187434139310514121985316880384x := emulated.ValueOf[Base](params.Gmx[113]) + G20769187434139310514121985316880384y := emulated.ValueOf[Base](params.Gmy[113]) + G41538374868278621028243970633760768x := emulated.ValueOf[Base](params.Gmx[114]) + G41538374868278621028243970633760768y := emulated.ValueOf[Base](params.Gmy[114]) + G83076749736557242056487941267521536x := emulated.ValueOf[Base](params.Gmx[115]) + G83076749736557242056487941267521536y := emulated.ValueOf[Base](params.Gmy[115]) + G166153499473114484112975882535043072x := emulated.ValueOf[Base](params.Gmx[116]) + G166153499473114484112975882535043072y := emulated.ValueOf[Base](params.Gmy[116]) + G332306998946228968225951765070086144x := emulated.ValueOf[Base](params.Gmx[117]) + G332306998946228968225951765070086144y := emulated.ValueOf[Base](params.Gmy[117]) + G664613997892457936451903530140172288x := emulated.ValueOf[Base](params.Gmx[118]) + G664613997892457936451903530140172288y := emulated.ValueOf[Base](params.Gmy[118]) + G1329227995784915872903807060280344576x := emulated.ValueOf[Base](params.Gmx[119]) + G1329227995784915872903807060280344576y := emulated.ValueOf[Base](params.Gmy[119]) + G2658455991569831745807614120560689152x := emulated.ValueOf[Base](params.Gmx[120]) + G2658455991569831745807614120560689152y := emulated.ValueOf[Base](params.Gmy[120]) + G5316911983139663491615228241121378304x := emulated.ValueOf[Base](params.Gmx[121]) + G5316911983139663491615228241121378304y := emulated.ValueOf[Base](params.Gmy[121]) + G10633823966279326983230456482242756608x := emulated.ValueOf[Base](params.Gmx[122]) + G10633823966279326983230456482242756608y := emulated.ValueOf[Base](params.Gmy[122]) + G21267647932558653966460912964485513216x := emulated.ValueOf[Base](params.Gmx[123]) + G21267647932558653966460912964485513216y := emulated.ValueOf[Base](params.Gmy[123]) + G42535295865117307932921825928971026432x := emulated.ValueOf[Base](params.Gmx[124]) + G42535295865117307932921825928971026432y := emulated.ValueOf[Base](params.Gmy[124]) + G85070591730234615865843651857942052864x := emulated.ValueOf[Base](params.Gmx[125]) + G85070591730234615865843651857942052864y := emulated.ValueOf[Base](params.Gmy[125]) + G170141183460469231731687303715884105728x := emulated.ValueOf[Base](params.Gmx[126]) + G170141183460469231731687303715884105728y := emulated.ValueOf[Base](params.Gmy[126]) + G340282366920938463463374607431768211456x := emulated.ValueOf[Base](params.Gmx[127]) + G340282366920938463463374607431768211456y := emulated.ValueOf[Base](params.Gmy[127]) + G680564733841876926926749214863536422912x := emulated.ValueOf[Base](params.Gmx[128]) + G680564733841876926926749214863536422912y := emulated.ValueOf[Base](params.Gmy[128]) + G1361129467683753853853498429727072845824x := emulated.ValueOf[Base](params.Gmx[129]) + G1361129467683753853853498429727072845824y := emulated.ValueOf[Base](params.Gmy[129]) + G2722258935367507707706996859454145691648x := emulated.ValueOf[Base](params.Gmx[130]) + G2722258935367507707706996859454145691648y := emulated.ValueOf[Base](params.Gmy[130]) + G5444517870735015415413993718908291383296x := emulated.ValueOf[Base](params.Gmx[131]) + G5444517870735015415413993718908291383296y := emulated.ValueOf[Base](params.Gmy[131]) + G10889035741470030830827987437816582766592x := emulated.ValueOf[Base](params.Gmx[132]) + G10889035741470030830827987437816582766592y := emulated.ValueOf[Base](params.Gmy[132]) + G21778071482940061661655974875633165533184x := emulated.ValueOf[Base](params.Gmx[133]) + G21778071482940061661655974875633165533184y := emulated.ValueOf[Base](params.Gmy[133]) + G43556142965880123323311949751266331066368x := emulated.ValueOf[Base](params.Gmx[134]) + G43556142965880123323311949751266331066368y := emulated.ValueOf[Base](params.Gmy[134]) + G87112285931760246646623899502532662132736x := emulated.ValueOf[Base](params.Gmx[135]) + G87112285931760246646623899502532662132736y := emulated.ValueOf[Base](params.Gmy[135]) + G174224571863520493293247799005065324265472x := emulated.ValueOf[Base](params.Gmx[136]) + G174224571863520493293247799005065324265472y := emulated.ValueOf[Base](params.Gmy[136]) + G348449143727040986586495598010130648530944x := emulated.ValueOf[Base](params.Gmx[137]) + G348449143727040986586495598010130648530944y := emulated.ValueOf[Base](params.Gmy[137]) + G696898287454081973172991196020261297061888x := emulated.ValueOf[Base](params.Gmx[138]) + G696898287454081973172991196020261297061888y := emulated.ValueOf[Base](params.Gmy[138]) + G1393796574908163946345982392040522594123776x := emulated.ValueOf[Base](params.Gmx[139]) + G1393796574908163946345982392040522594123776y := emulated.ValueOf[Base](params.Gmy[139]) + G2787593149816327892691964784081045188247552x := emulated.ValueOf[Base](params.Gmx[140]) + G2787593149816327892691964784081045188247552y := emulated.ValueOf[Base](params.Gmy[140]) + G5575186299632655785383929568162090376495104x := emulated.ValueOf[Base](params.Gmx[141]) + G5575186299632655785383929568162090376495104y := emulated.ValueOf[Base](params.Gmy[141]) + G11150372599265311570767859136324180752990208x := emulated.ValueOf[Base](params.Gmx[142]) + G11150372599265311570767859136324180752990208y := emulated.ValueOf[Base](params.Gmy[142]) + G22300745198530623141535718272648361505980416x := emulated.ValueOf[Base](params.Gmx[143]) + G22300745198530623141535718272648361505980416y := emulated.ValueOf[Base](params.Gmy[143]) + G44601490397061246283071436545296723011960832x := emulated.ValueOf[Base](params.Gmx[144]) + G44601490397061246283071436545296723011960832y := emulated.ValueOf[Base](params.Gmy[144]) + G89202980794122492566142873090593446023921664x := emulated.ValueOf[Base](params.Gmx[145]) + G89202980794122492566142873090593446023921664y := emulated.ValueOf[Base](params.Gmy[145]) + G178405961588244985132285746181186892047843328x := emulated.ValueOf[Base](params.Gmx[146]) + G178405961588244985132285746181186892047843328y := emulated.ValueOf[Base](params.Gmy[146]) + G356811923176489970264571492362373784095686656x := emulated.ValueOf[Base](params.Gmx[147]) + G356811923176489970264571492362373784095686656y := emulated.ValueOf[Base](params.Gmy[147]) + G713623846352979940529142984724747568191373312x := emulated.ValueOf[Base](params.Gmx[148]) + G713623846352979940529142984724747568191373312y := emulated.ValueOf[Base](params.Gmy[148]) + G1427247692705959881058285969449495136382746624x := emulated.ValueOf[Base](params.Gmx[149]) + G1427247692705959881058285969449495136382746624y := emulated.ValueOf[Base](params.Gmy[149]) + G2854495385411919762116571938898990272765493248x := emulated.ValueOf[Base](params.Gmx[150]) + G2854495385411919762116571938898990272765493248y := emulated.ValueOf[Base](params.Gmy[150]) + G5708990770823839524233143877797980545530986496x := emulated.ValueOf[Base](params.Gmx[151]) + G5708990770823839524233143877797980545530986496y := emulated.ValueOf[Base](params.Gmy[151]) + G11417981541647679048466287755595961091061972992x := emulated.ValueOf[Base](params.Gmx[152]) + G11417981541647679048466287755595961091061972992y := emulated.ValueOf[Base](params.Gmy[152]) + G22835963083295358096932575511191922182123945984x := emulated.ValueOf[Base](params.Gmx[153]) + G22835963083295358096932575511191922182123945984y := emulated.ValueOf[Base](params.Gmy[153]) + G45671926166590716193865151022383844364247891968x := emulated.ValueOf[Base](params.Gmx[154]) + G45671926166590716193865151022383844364247891968y := emulated.ValueOf[Base](params.Gmy[154]) + G91343852333181432387730302044767688728495783936x := emulated.ValueOf[Base](params.Gmx[155]) + G91343852333181432387730302044767688728495783936y := emulated.ValueOf[Base](params.Gmy[155]) + G182687704666362864775460604089535377456991567872x := emulated.ValueOf[Base](params.Gmx[156]) + G182687704666362864775460604089535377456991567872y := emulated.ValueOf[Base](params.Gmy[156]) + G365375409332725729550921208179070754913983135744x := emulated.ValueOf[Base](params.Gmx[157]) + G365375409332725729550921208179070754913983135744y := emulated.ValueOf[Base](params.Gmy[157]) + G730750818665451459101842416358141509827966271488x := emulated.ValueOf[Base](params.Gmx[158]) + G730750818665451459101842416358141509827966271488y := emulated.ValueOf[Base](params.Gmy[158]) + G1461501637330902918203684832716283019655932542976x := emulated.ValueOf[Base](params.Gmx[159]) + G1461501637330902918203684832716283019655932542976y := emulated.ValueOf[Base](params.Gmy[159]) + G2923003274661805836407369665432566039311865085952x := emulated.ValueOf[Base](params.Gmx[160]) + G2923003274661805836407369665432566039311865085952y := emulated.ValueOf[Base](params.Gmy[160]) + G5846006549323611672814739330865132078623730171904x := emulated.ValueOf[Base](params.Gmx[161]) + G5846006549323611672814739330865132078623730171904y := emulated.ValueOf[Base](params.Gmy[161]) + G11692013098647223345629478661730264157247460343808x := emulated.ValueOf[Base](params.Gmx[162]) + G11692013098647223345629478661730264157247460343808y := emulated.ValueOf[Base](params.Gmy[162]) + G23384026197294446691258957323460528314494920687616x := emulated.ValueOf[Base](params.Gmx[163]) + G23384026197294446691258957323460528314494920687616y := emulated.ValueOf[Base](params.Gmy[163]) + G46768052394588893382517914646921056628989841375232x := emulated.ValueOf[Base](params.Gmx[164]) + G46768052394588893382517914646921056628989841375232y := emulated.ValueOf[Base](params.Gmy[164]) + G93536104789177786765035829293842113257979682750464x := emulated.ValueOf[Base](params.Gmx[165]) + G93536104789177786765035829293842113257979682750464y := emulated.ValueOf[Base](params.Gmy[165]) + G187072209578355573530071658587684226515959365500928x := emulated.ValueOf[Base](params.Gmx[166]) + G187072209578355573530071658587684226515959365500928y := emulated.ValueOf[Base](params.Gmy[166]) + G374144419156711147060143317175368453031918731001856x := emulated.ValueOf[Base](params.Gmx[167]) + G374144419156711147060143317175368453031918731001856y := emulated.ValueOf[Base](params.Gmy[167]) + G748288838313422294120286634350736906063837462003712x := emulated.ValueOf[Base](params.Gmx[168]) + G748288838313422294120286634350736906063837462003712y := emulated.ValueOf[Base](params.Gmy[168]) + G1496577676626844588240573268701473812127674924007424x := emulated.ValueOf[Base](params.Gmx[169]) + G1496577676626844588240573268701473812127674924007424y := emulated.ValueOf[Base](params.Gmy[169]) + G2993155353253689176481146537402947624255349848014848x := emulated.ValueOf[Base](params.Gmx[170]) + G2993155353253689176481146537402947624255349848014848y := emulated.ValueOf[Base](params.Gmy[170]) + G5986310706507378352962293074805895248510699696029696x := emulated.ValueOf[Base](params.Gmx[171]) + G5986310706507378352962293074805895248510699696029696y := emulated.ValueOf[Base](params.Gmy[171]) + G11972621413014756705924586149611790497021399392059392x := emulated.ValueOf[Base](params.Gmx[172]) + G11972621413014756705924586149611790497021399392059392y := emulated.ValueOf[Base](params.Gmy[172]) + G23945242826029513411849172299223580994042798784118784x := emulated.ValueOf[Base](params.Gmx[173]) + G23945242826029513411849172299223580994042798784118784y := emulated.ValueOf[Base](params.Gmy[173]) + G47890485652059026823698344598447161988085597568237568x := emulated.ValueOf[Base](params.Gmx[174]) + G47890485652059026823698344598447161988085597568237568y := emulated.ValueOf[Base](params.Gmy[174]) + G95780971304118053647396689196894323976171195136475136x := emulated.ValueOf[Base](params.Gmx[175]) + G95780971304118053647396689196894323976171195136475136y := emulated.ValueOf[Base](params.Gmy[175]) + G191561942608236107294793378393788647952342390272950272x := emulated.ValueOf[Base](params.Gmx[176]) + G191561942608236107294793378393788647952342390272950272y := emulated.ValueOf[Base](params.Gmy[176]) + G383123885216472214589586756787577295904684780545900544x := emulated.ValueOf[Base](params.Gmx[177]) + G383123885216472214589586756787577295904684780545900544y := emulated.ValueOf[Base](params.Gmy[177]) + G766247770432944429179173513575154591809369561091801088x := emulated.ValueOf[Base](params.Gmx[178]) + G766247770432944429179173513575154591809369561091801088y := emulated.ValueOf[Base](params.Gmy[178]) + G1532495540865888858358347027150309183618739122183602176x := emulated.ValueOf[Base](params.Gmx[179]) + G1532495540865888858358347027150309183618739122183602176y := emulated.ValueOf[Base](params.Gmy[179]) + G3064991081731777716716694054300618367237478244367204352x := emulated.ValueOf[Base](params.Gmx[180]) + G3064991081731777716716694054300618367237478244367204352y := emulated.ValueOf[Base](params.Gmy[180]) + G6129982163463555433433388108601236734474956488734408704x := emulated.ValueOf[Base](params.Gmx[181]) + G6129982163463555433433388108601236734474956488734408704y := emulated.ValueOf[Base](params.Gmy[181]) + G12259964326927110866866776217202473468949912977468817408x := emulated.ValueOf[Base](params.Gmx[182]) + G12259964326927110866866776217202473468949912977468817408y := emulated.ValueOf[Base](params.Gmy[182]) + G24519928653854221733733552434404946937899825954937634816x := emulated.ValueOf[Base](params.Gmx[183]) + G24519928653854221733733552434404946937899825954937634816y := emulated.ValueOf[Base](params.Gmy[183]) + G49039857307708443467467104868809893875799651909875269632x := emulated.ValueOf[Base](params.Gmx[184]) + G49039857307708443467467104868809893875799651909875269632y := emulated.ValueOf[Base](params.Gmy[184]) + G98079714615416886934934209737619787751599303819750539264x := emulated.ValueOf[Base](params.Gmx[185]) + G98079714615416886934934209737619787751599303819750539264y := emulated.ValueOf[Base](params.Gmy[185]) + G196159429230833773869868419475239575503198607639501078528x := emulated.ValueOf[Base](params.Gmx[186]) + G196159429230833773869868419475239575503198607639501078528y := emulated.ValueOf[Base](params.Gmy[186]) + G392318858461667547739736838950479151006397215279002157056x := emulated.ValueOf[Base](params.Gmx[187]) + G392318858461667547739736838950479151006397215279002157056y := emulated.ValueOf[Base](params.Gmy[187]) + G784637716923335095479473677900958302012794430558004314112x := emulated.ValueOf[Base](params.Gmx[188]) + G784637716923335095479473677900958302012794430558004314112y := emulated.ValueOf[Base](params.Gmy[188]) + G1569275433846670190958947355801916604025588861116008628224x := emulated.ValueOf[Base](params.Gmx[189]) + G1569275433846670190958947355801916604025588861116008628224y := emulated.ValueOf[Base](params.Gmy[189]) + G3138550867693340381917894711603833208051177722232017256448x := emulated.ValueOf[Base](params.Gmx[190]) + G3138550867693340381917894711603833208051177722232017256448y := emulated.ValueOf[Base](params.Gmy[190]) + G6277101735386680763835789423207666416102355444464034512896x := emulated.ValueOf[Base](params.Gmx[191]) + G6277101735386680763835789423207666416102355444464034512896y := emulated.ValueOf[Base](params.Gmy[191]) + G12554203470773361527671578846415332832204710888928069025792x := emulated.ValueOf[Base](params.Gmx[192]) + G12554203470773361527671578846415332832204710888928069025792y := emulated.ValueOf[Base](params.Gmy[192]) + G25108406941546723055343157692830665664409421777856138051584x := emulated.ValueOf[Base](params.Gmx[193]) + G25108406941546723055343157692830665664409421777856138051584y := emulated.ValueOf[Base](params.Gmy[193]) + G50216813883093446110686315385661331328818843555712276103168x := emulated.ValueOf[Base](params.Gmx[194]) + G50216813883093446110686315385661331328818843555712276103168y := emulated.ValueOf[Base](params.Gmy[194]) + G100433627766186892221372630771322662657637687111424552206336x := emulated.ValueOf[Base](params.Gmx[195]) + G100433627766186892221372630771322662657637687111424552206336y := emulated.ValueOf[Base](params.Gmy[195]) + G200867255532373784442745261542645325315275374222849104412672x := emulated.ValueOf[Base](params.Gmx[196]) + G200867255532373784442745261542645325315275374222849104412672y := emulated.ValueOf[Base](params.Gmy[196]) + G401734511064747568885490523085290650630550748445698208825344x := emulated.ValueOf[Base](params.Gmx[197]) + G401734511064747568885490523085290650630550748445698208825344y := emulated.ValueOf[Base](params.Gmy[197]) + G803469022129495137770981046170581301261101496891396417650688x := emulated.ValueOf[Base](params.Gmx[198]) + G803469022129495137770981046170581301261101496891396417650688y := emulated.ValueOf[Base](params.Gmy[198]) + G1606938044258990275541962092341162602522202993782792835301376x := emulated.ValueOf[Base](params.Gmx[199]) + G1606938044258990275541962092341162602522202993782792835301376y := emulated.ValueOf[Base](params.Gmy[199]) + G3213876088517980551083924184682325205044405987565585670602752x := emulated.ValueOf[Base](params.Gmx[200]) + G3213876088517980551083924184682325205044405987565585670602752y := emulated.ValueOf[Base](params.Gmy[200]) + G6427752177035961102167848369364650410088811975131171341205504x := emulated.ValueOf[Base](params.Gmx[201]) + G6427752177035961102167848369364650410088811975131171341205504y := emulated.ValueOf[Base](params.Gmy[201]) + G12855504354071922204335696738729300820177623950262342682411008x := emulated.ValueOf[Base](params.Gmx[202]) + G12855504354071922204335696738729300820177623950262342682411008y := emulated.ValueOf[Base](params.Gmy[202]) + G25711008708143844408671393477458601640355247900524685364822016x := emulated.ValueOf[Base](params.Gmx[203]) + G25711008708143844408671393477458601640355247900524685364822016y := emulated.ValueOf[Base](params.Gmy[203]) + G51422017416287688817342786954917203280710495801049370729644032x := emulated.ValueOf[Base](params.Gmx[204]) + G51422017416287688817342786954917203280710495801049370729644032y := emulated.ValueOf[Base](params.Gmy[204]) + G102844034832575377634685573909834406561420991602098741459288064x := emulated.ValueOf[Base](params.Gmx[205]) + G102844034832575377634685573909834406561420991602098741459288064y := emulated.ValueOf[Base](params.Gmy[205]) + G205688069665150755269371147819668813122841983204197482918576128x := emulated.ValueOf[Base](params.Gmx[206]) + G205688069665150755269371147819668813122841983204197482918576128y := emulated.ValueOf[Base](params.Gmy[206]) + G411376139330301510538742295639337626245683966408394965837152256x := emulated.ValueOf[Base](params.Gmx[207]) + G411376139330301510538742295639337626245683966408394965837152256y := emulated.ValueOf[Base](params.Gmy[207]) + G822752278660603021077484591278675252491367932816789931674304512x := emulated.ValueOf[Base](params.Gmx[208]) + G822752278660603021077484591278675252491367932816789931674304512y := emulated.ValueOf[Base](params.Gmy[208]) + G1645504557321206042154969182557350504982735865633579863348609024x := emulated.ValueOf[Base](params.Gmx[209]) + G1645504557321206042154969182557350504982735865633579863348609024y := emulated.ValueOf[Base](params.Gmy[209]) + G3291009114642412084309938365114701009965471731267159726697218048x := emulated.ValueOf[Base](params.Gmx[210]) + G3291009114642412084309938365114701009965471731267159726697218048y := emulated.ValueOf[Base](params.Gmy[210]) + G6582018229284824168619876730229402019930943462534319453394436096x := emulated.ValueOf[Base](params.Gmx[211]) + G6582018229284824168619876730229402019930943462534319453394436096y := emulated.ValueOf[Base](params.Gmy[211]) + G13164036458569648337239753460458804039861886925068638906788872192x := emulated.ValueOf[Base](params.Gmx[212]) + G13164036458569648337239753460458804039861886925068638906788872192y := emulated.ValueOf[Base](params.Gmy[212]) + G26328072917139296674479506920917608079723773850137277813577744384x := emulated.ValueOf[Base](params.Gmx[213]) + G26328072917139296674479506920917608079723773850137277813577744384y := emulated.ValueOf[Base](params.Gmy[213]) + G52656145834278593348959013841835216159447547700274555627155488768x := emulated.ValueOf[Base](params.Gmx[214]) + G52656145834278593348959013841835216159447547700274555627155488768y := emulated.ValueOf[Base](params.Gmy[214]) + G105312291668557186697918027683670432318895095400549111254310977536x := emulated.ValueOf[Base](params.Gmx[215]) + G105312291668557186697918027683670432318895095400549111254310977536y := emulated.ValueOf[Base](params.Gmy[215]) + G210624583337114373395836055367340864637790190801098222508621955072x := emulated.ValueOf[Base](params.Gmx[216]) + G210624583337114373395836055367340864637790190801098222508621955072y := emulated.ValueOf[Base](params.Gmy[216]) + G421249166674228746791672110734681729275580381602196445017243910144x := emulated.ValueOf[Base](params.Gmx[217]) + G421249166674228746791672110734681729275580381602196445017243910144y := emulated.ValueOf[Base](params.Gmy[217]) + G842498333348457493583344221469363458551160763204392890034487820288x := emulated.ValueOf[Base](params.Gmx[218]) + G842498333348457493583344221469363458551160763204392890034487820288y := emulated.ValueOf[Base](params.Gmy[218]) + G1684996666696914987166688442938726917102321526408785780068975640576x := emulated.ValueOf[Base](params.Gmx[219]) + G1684996666696914987166688442938726917102321526408785780068975640576y := emulated.ValueOf[Base](params.Gmy[219]) + G3369993333393829974333376885877453834204643052817571560137951281152x := emulated.ValueOf[Base](params.Gmx[220]) + G3369993333393829974333376885877453834204643052817571560137951281152y := emulated.ValueOf[Base](params.Gmy[220]) + G6739986666787659948666753771754907668409286105635143120275902562304x := emulated.ValueOf[Base](params.Gmx[221]) + G6739986666787659948666753771754907668409286105635143120275902562304y := emulated.ValueOf[Base](params.Gmy[221]) + G13479973333575319897333507543509815336818572211270286240551805124608x := emulated.ValueOf[Base](params.Gmx[222]) + G13479973333575319897333507543509815336818572211270286240551805124608y := emulated.ValueOf[Base](params.Gmy[222]) + G26959946667150639794667015087019630673637144422540572481103610249216x := emulated.ValueOf[Base](params.Gmx[223]) + G26959946667150639794667015087019630673637144422540572481103610249216y := emulated.ValueOf[Base](params.Gmy[223]) + G53919893334301279589334030174039261347274288845081144962207220498432x := emulated.ValueOf[Base](params.Gmx[224]) + G53919893334301279589334030174039261347274288845081144962207220498432y := emulated.ValueOf[Base](params.Gmy[224]) + G107839786668602559178668060348078522694548577690162289924414440996864x := emulated.ValueOf[Base](params.Gmx[225]) + G107839786668602559178668060348078522694548577690162289924414440996864y := emulated.ValueOf[Base](params.Gmy[225]) + G215679573337205118357336120696157045389097155380324579848828881993728x := emulated.ValueOf[Base](params.Gmx[226]) + G215679573337205118357336120696157045389097155380324579848828881993728y := emulated.ValueOf[Base](params.Gmy[226]) + G431359146674410236714672241392314090778194310760649159697657763987456x := emulated.ValueOf[Base](params.Gmx[227]) + G431359146674410236714672241392314090778194310760649159697657763987456y := emulated.ValueOf[Base](params.Gmy[227]) + G862718293348820473429344482784628181556388621521298319395315527974912x := emulated.ValueOf[Base](params.Gmx[228]) + G862718293348820473429344482784628181556388621521298319395315527974912y := emulated.ValueOf[Base](params.Gmy[228]) + G1725436586697640946858688965569256363112777243042596638790631055949824x := emulated.ValueOf[Base](params.Gmx[229]) + G1725436586697640946858688965569256363112777243042596638790631055949824y := emulated.ValueOf[Base](params.Gmy[229]) + G3450873173395281893717377931138512726225554486085193277581262111899648x := emulated.ValueOf[Base](params.Gmx[230]) + G3450873173395281893717377931138512726225554486085193277581262111899648y := emulated.ValueOf[Base](params.Gmy[230]) + G6901746346790563787434755862277025452451108972170386555162524223799296x := emulated.ValueOf[Base](params.Gmx[231]) + G6901746346790563787434755862277025452451108972170386555162524223799296y := emulated.ValueOf[Base](params.Gmy[231]) + G13803492693581127574869511724554050904902217944340773110325048447598592x := emulated.ValueOf[Base](params.Gmx[232]) + G13803492693581127574869511724554050904902217944340773110325048447598592y := emulated.ValueOf[Base](params.Gmy[232]) + G27606985387162255149739023449108101809804435888681546220650096895197184x := emulated.ValueOf[Base](params.Gmx[233]) + G27606985387162255149739023449108101809804435888681546220650096895197184y := emulated.ValueOf[Base](params.Gmy[233]) + G55213970774324510299478046898216203619608871777363092441300193790394368x := emulated.ValueOf[Base](params.Gmx[234]) + G55213970774324510299478046898216203619608871777363092441300193790394368y := emulated.ValueOf[Base](params.Gmy[234]) + G110427941548649020598956093796432407239217743554726184882600387580788736x := emulated.ValueOf[Base](params.Gmx[235]) + G110427941548649020598956093796432407239217743554726184882600387580788736y := emulated.ValueOf[Base](params.Gmy[235]) + G220855883097298041197912187592864814478435487109452369765200775161577472x := emulated.ValueOf[Base](params.Gmx[236]) + G220855883097298041197912187592864814478435487109452369765200775161577472y := emulated.ValueOf[Base](params.Gmy[236]) + G441711766194596082395824375185729628956870974218904739530401550323154944x := emulated.ValueOf[Base](params.Gmx[237]) + G441711766194596082395824375185729628956870974218904739530401550323154944y := emulated.ValueOf[Base](params.Gmy[237]) + G883423532389192164791648750371459257913741948437809479060803100646309888x := emulated.ValueOf[Base](params.Gmx[238]) + G883423532389192164791648750371459257913741948437809479060803100646309888y := emulated.ValueOf[Base](params.Gmy[238]) + G1766847064778384329583297500742918515827483896875618958121606201292619776x := emulated.ValueOf[Base](params.Gmx[239]) + G1766847064778384329583297500742918515827483896875618958121606201292619776y := emulated.ValueOf[Base](params.Gmy[239]) + G3533694129556768659166595001485837031654967793751237916243212402585239552x := emulated.ValueOf[Base](params.Gmx[240]) + G3533694129556768659166595001485837031654967793751237916243212402585239552y := emulated.ValueOf[Base](params.Gmy[240]) + G7067388259113537318333190002971674063309935587502475832486424805170479104x := emulated.ValueOf[Base](params.Gmx[241]) + G7067388259113537318333190002971674063309935587502475832486424805170479104y := emulated.ValueOf[Base](params.Gmy[241]) + G14134776518227074636666380005943348126619871175004951664972849610340958208x := emulated.ValueOf[Base](params.Gmx[242]) + G14134776518227074636666380005943348126619871175004951664972849610340958208y := emulated.ValueOf[Base](params.Gmy[242]) + G28269553036454149273332760011886696253239742350009903329945699220681916416x := emulated.ValueOf[Base](params.Gmx[243]) + G28269553036454149273332760011886696253239742350009903329945699220681916416y := emulated.ValueOf[Base](params.Gmy[243]) + G56539106072908298546665520023773392506479484700019806659891398441363832832x := emulated.ValueOf[Base](params.Gmx[244]) + G56539106072908298546665520023773392506479484700019806659891398441363832832y := emulated.ValueOf[Base](params.Gmy[244]) + G113078212145816597093331040047546785012958969400039613319782796882727665664x := emulated.ValueOf[Base](params.Gmx[245]) + G113078212145816597093331040047546785012958969400039613319782796882727665664y := emulated.ValueOf[Base](params.Gmy[245]) + G226156424291633194186662080095093570025917938800079226639565593765455331328x := emulated.ValueOf[Base](params.Gmx[246]) + G226156424291633194186662080095093570025917938800079226639565593765455331328y := emulated.ValueOf[Base](params.Gmy[246]) + G452312848583266388373324160190187140051835877600158453279131187530910662656x := emulated.ValueOf[Base](params.Gmx[247]) + G452312848583266388373324160190187140051835877600158453279131187530910662656y := emulated.ValueOf[Base](params.Gmy[247]) + G904625697166532776746648320380374280103671755200316906558262375061821325312x := emulated.ValueOf[Base](params.Gmx[248]) + G904625697166532776746648320380374280103671755200316906558262375061821325312y := emulated.ValueOf[Base](params.Gmy[248]) + G1809251394333065553493296640760748560207343510400633813116524750123642650624x := emulated.ValueOf[Base](params.Gmx[249]) + G1809251394333065553493296640760748560207343510400633813116524750123642650624y := emulated.ValueOf[Base](params.Gmy[249]) + G3618502788666131106986593281521497120414687020801267626233049500247285301248x := emulated.ValueOf[Base](params.Gmx[250]) + G3618502788666131106986593281521497120414687020801267626233049500247285301248y := emulated.ValueOf[Base](params.Gmy[250]) + G7237005577332262213973186563042994240829374041602535252466099000494570602496x := emulated.ValueOf[Base](params.Gmx[251]) + G7237005577332262213973186563042994240829374041602535252466099000494570602496y := emulated.ValueOf[Base](params.Gmy[251]) + G14474011154664524427946373126085988481658748083205070504932198000989141204992x := emulated.ValueOf[Base](params.Gmx[252]) + G14474011154664524427946373126085988481658748083205070504932198000989141204992y := emulated.ValueOf[Base](params.Gmy[252]) + G28948022309329048855892746252171976963317496166410141009864396001978282409984x := emulated.ValueOf[Base](params.Gmx[253]) + G28948022309329048855892746252171976963317496166410141009864396001978282409984y := emulated.ValueOf[Base](params.Gmy[253]) + G57896044618658097711785492504343953926634992332820282019728792003956564819968x := emulated.ValueOf[Base](params.Gmx[254]) + G57896044618658097711785492504343953926634992332820282019728792003956564819968y := emulated.ValueOf[Base](params.Gmy[254]) + G115792089237316195423570985008687907853269984665640564039457584007913129639936x := emulated.ValueOf[Base](params.Gmx[255]) + G115792089237316195423570985008687907853269984665640564039457584007913129639936y := emulated.ValueOf[Base](params.Gmy[255]) return &Curve[Base, Scalars]{ params: params, api: api, @@ -32,6 +544,265 @@ func New[Base, Scalars emulated.FieldParams](api frontend.API, params CurveParam X: Gx, Y: Gy, }, + gm: [256]AffinePoint[Base]{ + {X: G2x, Y: G2y}, + {X: G4x, Y: G4y}, + {X: G8x, Y: G8y}, + {X: G16x, Y: G16y}, + {X: G32x, Y: G32y}, + {X: G64x, Y: G64y}, + {X: G128x, Y: G128y}, + {X: G256x, Y: G256y}, + {X: G512x, Y: G512y}, + {X: G1024x, Y: G1024y}, + {X: G2048x, Y: G2048y}, + {X: G4096x, Y: G4096y}, + {X: G8192x, Y: G8192y}, + {X: G16384x, Y: G16384y}, + {X: G32768x, Y: G32768y}, + {X: G65536x, Y: G65536y}, + {X: G131072x, Y: G131072y}, + {X: G262144x, Y: G262144y}, + {X: G524288x, Y: G524288y}, + {X: G1048576x, Y: G1048576y}, + {X: G2097152x, Y: G2097152y}, + {X: G4194304x, Y: G4194304y}, + {X: G8388608x, Y: G8388608y}, + {X: G16777216x, Y: G16777216y}, + {X: G33554432x, Y: G33554432y}, + {X: G67108864x, Y: G67108864y}, + {X: G134217728x, Y: G134217728y}, + {X: G268435456x, Y: G268435456y}, + {X: G536870912x, Y: G536870912y}, + {X: G1073741824x, Y: G1073741824y}, + {X: G2147483648x, Y: G2147483648y}, + {X: G4294967296x, Y: G4294967296y}, + {X: G8589934592x, Y: G8589934592y}, + {X: G17179869184x, Y: G17179869184y}, + {X: G34359738368x, Y: G34359738368y}, + {X: G68719476736x, Y: G68719476736y}, + {X: G137438953472x, Y: G137438953472y}, + {X: G274877906944x, Y: G274877906944y}, + {X: G549755813888x, Y: G549755813888y}, + {X: G1099511627776x, Y: G1099511627776y}, + {X: G2199023255552x, Y: G2199023255552y}, + {X: G4398046511104x, Y: G4398046511104y}, + {X: G8796093022208x, Y: G8796093022208y}, + {X: G17592186044416x, Y: G17592186044416y}, + {X: G35184372088832x, Y: G35184372088832y}, + {X: G70368744177664x, Y: G70368744177664y}, + {X: G140737488355328x, Y: G140737488355328y}, + {X: G281474976710656x, Y: G281474976710656y}, + {X: G562949953421312x, Y: G562949953421312y}, + {X: G1125899906842624x, Y: G1125899906842624y}, + {X: G2251799813685248x, Y: G2251799813685248y}, + {X: G4503599627370496x, Y: G4503599627370496y}, + {X: G9007199254740992x, Y: G9007199254740992y}, + {X: G18014398509481984x, Y: G18014398509481984y}, + {X: G36028797018963968x, Y: G36028797018963968y}, + {X: G72057594037927936x, Y: G72057594037927936y}, + {X: G144115188075855872x, Y: G144115188075855872y}, + {X: G288230376151711744x, Y: G288230376151711744y}, + {X: G576460752303423488x, Y: G576460752303423488y}, + {X: G1152921504606846976x, Y: G1152921504606846976y}, + {X: G2305843009213693952x, Y: G2305843009213693952y}, + {X: G4611686018427387904x, Y: G4611686018427387904y}, + {X: G9223372036854775808x, Y: G9223372036854775808y}, + {X: G18446744073709551616x, Y: G18446744073709551616y}, + {X: G36893488147419103232x, Y: G36893488147419103232y}, + {X: G73786976294838206464x, Y: G73786976294838206464y}, + {X: G147573952589676412928x, Y: G147573952589676412928y}, + {X: G295147905179352825856x, Y: G295147905179352825856y}, + {X: G590295810358705651712x, Y: G590295810358705651712y}, + {X: G1180591620717411303424x, Y: G1180591620717411303424y}, + {X: G2361183241434822606848x, Y: G2361183241434822606848y}, + {X: G4722366482869645213696x, Y: G4722366482869645213696y}, + {X: G9444732965739290427392x, Y: G9444732965739290427392y}, + {X: G18889465931478580854784x, Y: G18889465931478580854784y}, + {X: G37778931862957161709568x, Y: G37778931862957161709568y}, + {X: G75557863725914323419136x, Y: G75557863725914323419136y}, + {X: G151115727451828646838272x, Y: G151115727451828646838272y}, + {X: G302231454903657293676544x, Y: G302231454903657293676544y}, + {X: G604462909807314587353088x, Y: G604462909807314587353088y}, + {X: G1208925819614629174706176x, Y: G1208925819614629174706176y}, + {X: G2417851639229258349412352x, Y: G2417851639229258349412352y}, + {X: G4835703278458516698824704x, Y: G4835703278458516698824704y}, + {X: G9671406556917033397649408x, Y: G9671406556917033397649408y}, + {X: G19342813113834066795298816x, Y: G19342813113834066795298816y}, + {X: G38685626227668133590597632x, Y: G38685626227668133590597632y}, + {X: G77371252455336267181195264x, Y: G77371252455336267181195264y}, + {X: G154742504910672534362390528x, Y: G154742504910672534362390528y}, + {X: G309485009821345068724781056x, Y: G309485009821345068724781056y}, + {X: G618970019642690137449562112x, Y: G618970019642690137449562112y}, + {X: G1237940039285380274899124224x, Y: G1237940039285380274899124224y}, + {X: G2475880078570760549798248448x, Y: G2475880078570760549798248448y}, + {X: G4951760157141521099596496896x, Y: G4951760157141521099596496896y}, + {X: G9903520314283042199192993792x, Y: G9903520314283042199192993792y}, + {X: G19807040628566084398385987584x, Y: G19807040628566084398385987584y}, + {X: G39614081257132168796771975168x, Y: G39614081257132168796771975168y}, + {X: G79228162514264337593543950336x, Y: G79228162514264337593543950336y}, + {X: G158456325028528675187087900672x, Y: G158456325028528675187087900672y}, + {X: G316912650057057350374175801344x, Y: G316912650057057350374175801344y}, + {X: G633825300114114700748351602688x, Y: G633825300114114700748351602688y}, + {X: G1267650600228229401496703205376x, Y: G1267650600228229401496703205376y}, + {X: G2535301200456458802993406410752x, Y: G2535301200456458802993406410752y}, + {X: G5070602400912917605986812821504x, Y: G5070602400912917605986812821504y}, + {X: G10141204801825835211973625643008x, Y: G10141204801825835211973625643008y}, + {X: G20282409603651670423947251286016x, Y: G20282409603651670423947251286016y}, + {X: G40564819207303340847894502572032x, Y: G40564819207303340847894502572032y}, + {X: G81129638414606681695789005144064x, Y: G81129638414606681695789005144064y}, + {X: G162259276829213363391578010288128x, Y: G162259276829213363391578010288128y}, + {X: G324518553658426726783156020576256x, Y: G324518553658426726783156020576256y}, + {X: G649037107316853453566312041152512x, Y: G649037107316853453566312041152512y}, + {X: G1298074214633706907132624082305024x, Y: G1298074214633706907132624082305024y}, + {X: G2596148429267413814265248164610048x, Y: G2596148429267413814265248164610048y}, + {X: G5192296858534827628530496329220096x, Y: G5192296858534827628530496329220096y}, + {X: G10384593717069655257060992658440192x, Y: G10384593717069655257060992658440192y}, + {X: G20769187434139310514121985316880384x, Y: G20769187434139310514121985316880384y}, + {X: G41538374868278621028243970633760768x, Y: G41538374868278621028243970633760768y}, + {X: G83076749736557242056487941267521536x, Y: G83076749736557242056487941267521536y}, + {X: G166153499473114484112975882535043072x, Y: G166153499473114484112975882535043072y}, + {X: G332306998946228968225951765070086144x, Y: G332306998946228968225951765070086144y}, + {X: G664613997892457936451903530140172288x, Y: G664613997892457936451903530140172288y}, + {X: G1329227995784915872903807060280344576x, Y: G1329227995784915872903807060280344576y}, + {X: G2658455991569831745807614120560689152x, Y: G2658455991569831745807614120560689152y}, + {X: G5316911983139663491615228241121378304x, Y: G5316911983139663491615228241121378304y}, + {X: G10633823966279326983230456482242756608x, Y: G10633823966279326983230456482242756608y}, + {X: G21267647932558653966460912964485513216x, Y: G21267647932558653966460912964485513216y}, + {X: G42535295865117307932921825928971026432x, Y: G42535295865117307932921825928971026432y}, + {X: G85070591730234615865843651857942052864x, Y: G85070591730234615865843651857942052864y}, + {X: G170141183460469231731687303715884105728x, Y: G170141183460469231731687303715884105728y}, + {X: G340282366920938463463374607431768211456x, Y: G340282366920938463463374607431768211456y}, + {X: G680564733841876926926749214863536422912x, Y: G680564733841876926926749214863536422912y}, + {X: G1361129467683753853853498429727072845824x, Y: G1361129467683753853853498429727072845824y}, + {X: G2722258935367507707706996859454145691648x, Y: G2722258935367507707706996859454145691648y}, + {X: G5444517870735015415413993718908291383296x, Y: G5444517870735015415413993718908291383296y}, + {X: G10889035741470030830827987437816582766592x, Y: G10889035741470030830827987437816582766592y}, + {X: G21778071482940061661655974875633165533184x, Y: G21778071482940061661655974875633165533184y}, + {X: G43556142965880123323311949751266331066368x, Y: G43556142965880123323311949751266331066368y}, + {X: G87112285931760246646623899502532662132736x, Y: G87112285931760246646623899502532662132736y}, + {X: G174224571863520493293247799005065324265472x, Y: G174224571863520493293247799005065324265472y}, + {X: G348449143727040986586495598010130648530944x, Y: G348449143727040986586495598010130648530944y}, + {X: G696898287454081973172991196020261297061888x, Y: G696898287454081973172991196020261297061888y}, + {X: G1393796574908163946345982392040522594123776x, Y: G1393796574908163946345982392040522594123776y}, + {X: G2787593149816327892691964784081045188247552x, Y: G2787593149816327892691964784081045188247552y}, + {X: G5575186299632655785383929568162090376495104x, Y: G5575186299632655785383929568162090376495104y}, + {X: G11150372599265311570767859136324180752990208x, Y: G11150372599265311570767859136324180752990208y}, + {X: G22300745198530623141535718272648361505980416x, Y: G22300745198530623141535718272648361505980416y}, + {X: G44601490397061246283071436545296723011960832x, Y: G44601490397061246283071436545296723011960832y}, + {X: G89202980794122492566142873090593446023921664x, Y: G89202980794122492566142873090593446023921664y}, + {X: G178405961588244985132285746181186892047843328x, Y: G178405961588244985132285746181186892047843328y}, + {X: G356811923176489970264571492362373784095686656x, Y: G356811923176489970264571492362373784095686656y}, + {X: G713623846352979940529142984724747568191373312x, Y: G713623846352979940529142984724747568191373312y}, + {X: G1427247692705959881058285969449495136382746624x, Y: G1427247692705959881058285969449495136382746624y}, + {X: G2854495385411919762116571938898990272765493248x, Y: G2854495385411919762116571938898990272765493248y}, + {X: G5708990770823839524233143877797980545530986496x, Y: G5708990770823839524233143877797980545530986496y}, + {X: G11417981541647679048466287755595961091061972992x, Y: G11417981541647679048466287755595961091061972992y}, + {X: G22835963083295358096932575511191922182123945984x, Y: G22835963083295358096932575511191922182123945984y}, + {X: G45671926166590716193865151022383844364247891968x, Y: G45671926166590716193865151022383844364247891968y}, + {X: G91343852333181432387730302044767688728495783936x, Y: G91343852333181432387730302044767688728495783936y}, + {X: G182687704666362864775460604089535377456991567872x, Y: G182687704666362864775460604089535377456991567872y}, + {X: G365375409332725729550921208179070754913983135744x, Y: G365375409332725729550921208179070754913983135744y}, + {X: G730750818665451459101842416358141509827966271488x, Y: G730750818665451459101842416358141509827966271488y}, + {X: G1461501637330902918203684832716283019655932542976x, Y: G1461501637330902918203684832716283019655932542976y}, + {X: G2923003274661805836407369665432566039311865085952x, Y: G2923003274661805836407369665432566039311865085952y}, + {X: G5846006549323611672814739330865132078623730171904x, Y: G5846006549323611672814739330865132078623730171904y}, + {X: G11692013098647223345629478661730264157247460343808x, Y: G11692013098647223345629478661730264157247460343808y}, + {X: G23384026197294446691258957323460528314494920687616x, Y: G23384026197294446691258957323460528314494920687616y}, + {X: G46768052394588893382517914646921056628989841375232x, Y: G46768052394588893382517914646921056628989841375232y}, + {X: G93536104789177786765035829293842113257979682750464x, Y: G93536104789177786765035829293842113257979682750464y}, + {X: G187072209578355573530071658587684226515959365500928x, Y: G187072209578355573530071658587684226515959365500928y}, + {X: G374144419156711147060143317175368453031918731001856x, Y: G374144419156711147060143317175368453031918731001856y}, + {X: G748288838313422294120286634350736906063837462003712x, Y: G748288838313422294120286634350736906063837462003712y}, + {X: G1496577676626844588240573268701473812127674924007424x, Y: G1496577676626844588240573268701473812127674924007424y}, + {X: G2993155353253689176481146537402947624255349848014848x, Y: G2993155353253689176481146537402947624255349848014848y}, + {X: G5986310706507378352962293074805895248510699696029696x, Y: G5986310706507378352962293074805895248510699696029696y}, + {X: G11972621413014756705924586149611790497021399392059392x, Y: G11972621413014756705924586149611790497021399392059392y}, + {X: G23945242826029513411849172299223580994042798784118784x, Y: G23945242826029513411849172299223580994042798784118784y}, + {X: G47890485652059026823698344598447161988085597568237568x, Y: G47890485652059026823698344598447161988085597568237568y}, + {X: G95780971304118053647396689196894323976171195136475136x, Y: G95780971304118053647396689196894323976171195136475136y}, + {X: G191561942608236107294793378393788647952342390272950272x, Y: G191561942608236107294793378393788647952342390272950272y}, + {X: G383123885216472214589586756787577295904684780545900544x, Y: G383123885216472214589586756787577295904684780545900544y}, + {X: G766247770432944429179173513575154591809369561091801088x, Y: G766247770432944429179173513575154591809369561091801088y}, + {X: G1532495540865888858358347027150309183618739122183602176x, Y: G1532495540865888858358347027150309183618739122183602176y}, + {X: G3064991081731777716716694054300618367237478244367204352x, Y: G3064991081731777716716694054300618367237478244367204352y}, + {X: G6129982163463555433433388108601236734474956488734408704x, Y: G6129982163463555433433388108601236734474956488734408704y}, + {X: G12259964326927110866866776217202473468949912977468817408x, Y: G12259964326927110866866776217202473468949912977468817408y}, + {X: G24519928653854221733733552434404946937899825954937634816x, Y: G24519928653854221733733552434404946937899825954937634816y}, + {X: G49039857307708443467467104868809893875799651909875269632x, Y: G49039857307708443467467104868809893875799651909875269632y}, + {X: G98079714615416886934934209737619787751599303819750539264x, Y: G98079714615416886934934209737619787751599303819750539264y}, + {X: G196159429230833773869868419475239575503198607639501078528x, Y: G196159429230833773869868419475239575503198607639501078528y}, + {X: G392318858461667547739736838950479151006397215279002157056x, Y: G392318858461667547739736838950479151006397215279002157056y}, + {X: G784637716923335095479473677900958302012794430558004314112x, Y: G784637716923335095479473677900958302012794430558004314112y}, + {X: G1569275433846670190958947355801916604025588861116008628224x, Y: G1569275433846670190958947355801916604025588861116008628224y}, + {X: G3138550867693340381917894711603833208051177722232017256448x, Y: G3138550867693340381917894711603833208051177722232017256448y}, + {X: G6277101735386680763835789423207666416102355444464034512896x, Y: G6277101735386680763835789423207666416102355444464034512896y}, + {X: G12554203470773361527671578846415332832204710888928069025792x, Y: G12554203470773361527671578846415332832204710888928069025792y}, + {X: G25108406941546723055343157692830665664409421777856138051584x, Y: G25108406941546723055343157692830665664409421777856138051584y}, + {X: G50216813883093446110686315385661331328818843555712276103168x, Y: G50216813883093446110686315385661331328818843555712276103168y}, + {X: G100433627766186892221372630771322662657637687111424552206336x, Y: G100433627766186892221372630771322662657637687111424552206336y}, + {X: G200867255532373784442745261542645325315275374222849104412672x, Y: G200867255532373784442745261542645325315275374222849104412672y}, + {X: G401734511064747568885490523085290650630550748445698208825344x, Y: G401734511064747568885490523085290650630550748445698208825344y}, + {X: G803469022129495137770981046170581301261101496891396417650688x, Y: G803469022129495137770981046170581301261101496891396417650688y}, + {X: G1606938044258990275541962092341162602522202993782792835301376x, Y: G1606938044258990275541962092341162602522202993782792835301376y}, + {X: G3213876088517980551083924184682325205044405987565585670602752x, Y: G3213876088517980551083924184682325205044405987565585670602752y}, + {X: G6427752177035961102167848369364650410088811975131171341205504x, Y: G6427752177035961102167848369364650410088811975131171341205504y}, + {X: G12855504354071922204335696738729300820177623950262342682411008x, Y: G12855504354071922204335696738729300820177623950262342682411008y}, + {X: G25711008708143844408671393477458601640355247900524685364822016x, Y: G25711008708143844408671393477458601640355247900524685364822016y}, + {X: G51422017416287688817342786954917203280710495801049370729644032x, Y: G51422017416287688817342786954917203280710495801049370729644032y}, + {X: G102844034832575377634685573909834406561420991602098741459288064x, Y: G102844034832575377634685573909834406561420991602098741459288064y}, + {X: G205688069665150755269371147819668813122841983204197482918576128x, Y: G205688069665150755269371147819668813122841983204197482918576128y}, + {X: G411376139330301510538742295639337626245683966408394965837152256x, Y: G411376139330301510538742295639337626245683966408394965837152256y}, + {X: G822752278660603021077484591278675252491367932816789931674304512x, Y: G822752278660603021077484591278675252491367932816789931674304512y}, + {X: G1645504557321206042154969182557350504982735865633579863348609024x, Y: G1645504557321206042154969182557350504982735865633579863348609024y}, + {X: G3291009114642412084309938365114701009965471731267159726697218048x, Y: G3291009114642412084309938365114701009965471731267159726697218048y}, + {X: G6582018229284824168619876730229402019930943462534319453394436096x, Y: G6582018229284824168619876730229402019930943462534319453394436096y}, + {X: G13164036458569648337239753460458804039861886925068638906788872192x, Y: G13164036458569648337239753460458804039861886925068638906788872192y}, + {X: G26328072917139296674479506920917608079723773850137277813577744384x, Y: G26328072917139296674479506920917608079723773850137277813577744384y}, + {X: G52656145834278593348959013841835216159447547700274555627155488768x, Y: G52656145834278593348959013841835216159447547700274555627155488768y}, + {X: G105312291668557186697918027683670432318895095400549111254310977536x, Y: G105312291668557186697918027683670432318895095400549111254310977536y}, + {X: G210624583337114373395836055367340864637790190801098222508621955072x, Y: G210624583337114373395836055367340864637790190801098222508621955072y}, + {X: G421249166674228746791672110734681729275580381602196445017243910144x, Y: G421249166674228746791672110734681729275580381602196445017243910144y}, + {X: G842498333348457493583344221469363458551160763204392890034487820288x, Y: G842498333348457493583344221469363458551160763204392890034487820288y}, + {X: G1684996666696914987166688442938726917102321526408785780068975640576x, Y: G1684996666696914987166688442938726917102321526408785780068975640576y}, + {X: G3369993333393829974333376885877453834204643052817571560137951281152x, Y: G3369993333393829974333376885877453834204643052817571560137951281152y}, + {X: G6739986666787659948666753771754907668409286105635143120275902562304x, Y: G6739986666787659948666753771754907668409286105635143120275902562304y}, + {X: G13479973333575319897333507543509815336818572211270286240551805124608x, Y: G13479973333575319897333507543509815336818572211270286240551805124608y}, + {X: G26959946667150639794667015087019630673637144422540572481103610249216x, Y: G26959946667150639794667015087019630673637144422540572481103610249216y}, + {X: G53919893334301279589334030174039261347274288845081144962207220498432x, Y: G53919893334301279589334030174039261347274288845081144962207220498432y}, + {X: G107839786668602559178668060348078522694548577690162289924414440996864x, Y: G107839786668602559178668060348078522694548577690162289924414440996864y}, + {X: G215679573337205118357336120696157045389097155380324579848828881993728x, Y: G215679573337205118357336120696157045389097155380324579848828881993728y}, + {X: G431359146674410236714672241392314090778194310760649159697657763987456x, Y: G431359146674410236714672241392314090778194310760649159697657763987456y}, + {X: G862718293348820473429344482784628181556388621521298319395315527974912x, Y: G862718293348820473429344482784628181556388621521298319395315527974912y}, + {X: G1725436586697640946858688965569256363112777243042596638790631055949824x, Y: G1725436586697640946858688965569256363112777243042596638790631055949824y}, + {X: G3450873173395281893717377931138512726225554486085193277581262111899648x, Y: G3450873173395281893717377931138512726225554486085193277581262111899648y}, + {X: G6901746346790563787434755862277025452451108972170386555162524223799296x, Y: G6901746346790563787434755862277025452451108972170386555162524223799296y}, + {X: G13803492693581127574869511724554050904902217944340773110325048447598592x, Y: G13803492693581127574869511724554050904902217944340773110325048447598592y}, + {X: G27606985387162255149739023449108101809804435888681546220650096895197184x, Y: G27606985387162255149739023449108101809804435888681546220650096895197184y}, + {X: G55213970774324510299478046898216203619608871777363092441300193790394368x, Y: G55213970774324510299478046898216203619608871777363092441300193790394368y}, + {X: G110427941548649020598956093796432407239217743554726184882600387580788736x, Y: G110427941548649020598956093796432407239217743554726184882600387580788736y}, + {X: G220855883097298041197912187592864814478435487109452369765200775161577472x, Y: G220855883097298041197912187592864814478435487109452369765200775161577472y}, + {X: G441711766194596082395824375185729628956870974218904739530401550323154944x, Y: G441711766194596082395824375185729628956870974218904739530401550323154944y}, + {X: G883423532389192164791648750371459257913741948437809479060803100646309888x, Y: G883423532389192164791648750371459257913741948437809479060803100646309888y}, + {X: G1766847064778384329583297500742918515827483896875618958121606201292619776x, Y: G1766847064778384329583297500742918515827483896875618958121606201292619776y}, + {X: G3533694129556768659166595001485837031654967793751237916243212402585239552x, Y: G3533694129556768659166595001485837031654967793751237916243212402585239552y}, + {X: G7067388259113537318333190002971674063309935587502475832486424805170479104x, Y: G7067388259113537318333190002971674063309935587502475832486424805170479104y}, + {X: G14134776518227074636666380005943348126619871175004951664972849610340958208x, Y: G14134776518227074636666380005943348126619871175004951664972849610340958208y}, + {X: G28269553036454149273332760011886696253239742350009903329945699220681916416x, Y: G28269553036454149273332760011886696253239742350009903329945699220681916416y}, + {X: G56539106072908298546665520023773392506479484700019806659891398441363832832x, Y: G56539106072908298546665520023773392506479484700019806659891398441363832832y}, + {X: G113078212145816597093331040047546785012958969400039613319782796882727665664x, Y: G113078212145816597093331040047546785012958969400039613319782796882727665664y}, + {X: G226156424291633194186662080095093570025917938800079226639565593765455331328x, Y: G226156424291633194186662080095093570025917938800079226639565593765455331328y}, + {X: G452312848583266388373324160190187140051835877600158453279131187530910662656x, Y: G452312848583266388373324160190187140051835877600158453279131187530910662656y}, + {X: G904625697166532776746648320380374280103671755200316906558262375061821325312x, Y: G904625697166532776746648320380374280103671755200316906558262375061821325312y}, + {X: G1809251394333065553493296640760748560207343510400633813116524750123642650624x, Y: G1809251394333065553493296640760748560207343510400633813116524750123642650624y}, + {X: G3618502788666131106986593281521497120414687020801267626233049500247285301248x, Y: G3618502788666131106986593281521497120414687020801267626233049500247285301248y}, + {X: G7237005577332262213973186563042994240829374041602535252466099000494570602496x, Y: G7237005577332262213973186563042994240829374041602535252466099000494570602496y}, + {X: G14474011154664524427946373126085988481658748083205070504932198000989141204992x, Y: G14474011154664524427946373126085988481658748083205070504932198000989141204992y}, + {X: G28948022309329048855892746252171976963317496166410141009864396001978282409984x, Y: G28948022309329048855892746252171976963317496166410141009864396001978282409984y}, + {X: G57896044618658097711785492504343953926634992332820282019728792003956564819968x, Y: G57896044618658097711785492504343953926634992332820282019728792003956564819968y}, + {X: G115792089237316195423570985008687907853269984665640564039457584007913129639936x, Y: G115792089237316195423570985008687907853269984665640564039457584007913129639936y}, + }, + a: emulated.ValueOf[Base](params.A), addA: params.A.Cmp(big.NewInt(0)) != 0, }, nil @@ -51,6 +822,9 @@ type Curve[Base, Scalars emulated.FieldParams] struct { // g is the generator (base point) of the curve. g AffinePoint[Base] + // gm are the pre-computed multiples the generator (base point) of the curve. + gm [256]AffinePoint[Base] + a emulated.Element[Base] addA bool } @@ -61,6 +835,12 @@ func (c *Curve[B, S]) Generator() *AffinePoint[B] { return &c.g } +// GeneratorMultiples returns the pre-computed multiples of the base point of the curve. The method does not copy and +// modifying the returned element leads to undefined behaviour! +func (c *Curve[B, S]) GeneratorMultiples() [256]AffinePoint[B] { + return c.gm +} + // AffinePoint represents a point on the elliptic curve. We do not check that // the point is actually on the curve. type AffinePoint[Base emulated.FieldParams] struct { @@ -161,3 +941,23 @@ func (c *Curve[B, S]) ScalarMul(p *AffinePoint[B], s *emulated.Element[S]) *Affi res = c.Select(sBits[0], res, tmp) return res } + +// ScalarMulBase computes s * g and returns it, where g is the fixed generator. It doesn't modify s. +func (c *Curve[B, S]) ScalarMulBase(s *emulated.Element[S]) *AffinePoint[B] { + g := c.Generator() + gm := c.GeneratorMultiples() + res := g + + var st S + sr := c.scalarApi.Reduce(s) + sBits := c.scalarApi.ToBits(sr) + + for i := 1; i < st.Modulus().BitLen(); i++ { + tmp := c.Add(res, &gm[i-1]) + res = c.Select(sBits[i], tmp, res) + } + + tmp := c.Add(res, c.Neg(g)) + res = c.Select(sBits[0], res, tmp) + return res +} diff --git a/std/algebra/weierstrass/point_test.go b/std/algebra/weierstrass/point_test.go index 28faf42109..4778db0ac0 100644 --- a/std/algebra/weierstrass/point_test.go +++ b/std/algebra/weierstrass/point_test.go @@ -129,6 +129,65 @@ func TestDouble(t *testing.T) { assert.NoError(err) } +type ScalarMulBaseTest[T, S emulated.FieldParams] struct { + Q AffinePoint[T] + S emulated.Element[S] +} + +func (c *ScalarMulBaseTest[T, S]) Define(api frontend.API) error { + cr, err := New[T, S](api, GetCurveParams[T]()) + if err != nil { + return err + } + res := cr.ScalarMulBase(&c.S) + cr.AssertIsEqual(res, &c.Q) + return nil +} + +func TestScalarMulBase(t *testing.T) { + assert := test.NewAssert(t) + _, g := secp256k1.Generators() + s, ok := new(big.Int).SetString("44693544921776318736021182399461740191514036429448770306966433218654680512345", 10) + assert.True(ok) + var S secp256k1.G1Affine + S.ScalarMultiplication(&g, s) + + circuit := ScalarMulBaseTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{} + witness := ScalarMulBaseTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ + S: emulated.ValueOf[emulated.Secp256k1Fr](s), + Q: AffinePoint[emulated.Secp256k1Fp]{ + X: emulated.ValueOf[emulated.Secp256k1Fp](S.X), + Y: emulated.ValueOf[emulated.Secp256k1Fp](S.Y), + }, + } + err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) + assert.NoError(err) + _, err = frontend.Compile(testCurve.ScalarField(), r1cs.NewBuilder, &circuit) + assert.NoError(err) +} + +func TestScalarMulBase2(t *testing.T) { + assert := test.NewAssert(t) + _, _, g, _ := bn254.Generators() + s, ok := new(big.Int).SetString("44693544921776318736021182399461740191514036429448770306966433218654680512345", 10) + assert.True(ok) + var S bn254.G1Affine + S.ScalarMultiplication(&g, s) + + circuit := ScalarMulBaseTest[emulated.BN254Fp, emulated.BN254Fr]{} + witness := ScalarMulBaseTest[emulated.BN254Fp, emulated.BN254Fr]{ + S: emulated.ValueOf[emulated.BN254Fr](s), + Q: AffinePoint[emulated.BN254Fp]{ + X: emulated.ValueOf[emulated.BN254Fp](S.X), + Y: emulated.ValueOf[emulated.BN254Fp](S.Y), + }, + } + err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) + assert.NoError(err) + _, err = frontend.Compile(testCurve.ScalarField(), r1cs.NewBuilder, &circuit) + assert.NoError(err) +} + type ScalarMulTest[T, S emulated.FieldParams] struct { P, Q AffinePoint[T] S emulated.Element[S] diff --git a/std/signature/ecdsa/ecdsa.go b/std/signature/ecdsa/ecdsa.go index 5279f69930..acf7286dcd 100644 --- a/std/signature/ecdsa/ecdsa.go +++ b/std/signature/ecdsa/ecdsa.go @@ -50,7 +50,7 @@ func (pk PublicKey[T, S]) Verify(api frontend.API, params weierstrass.CurveParam msInv := scalarApi.MulMod(msg, sInv) rsInv := scalarApi.MulMod(&sig.R, sInv) - qa := cr.ScalarMul(cr.Generator(), msInv) + qa := cr.ScalarMulBase(msInv) qb := cr.ScalarMul(&pkpt, rsInv) q := cr.Add(qa, qb) qx := baseApi.Reduce(&q.X) diff --git a/std/signature/ecdsa/ecdsa_test.go b/std/signature/ecdsa/ecdsa_test.go index 711ec69554..b1fad60ba0 100644 --- a/std/signature/ecdsa/ecdsa_test.go +++ b/std/signature/ecdsa/ecdsa_test.go @@ -3,12 +3,15 @@ package ecdsa import ( "crypto/rand" "crypto/sha256" + "fmt" "math/big" "testing" "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/secp256k1/ecdsa" "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/profile" "github.com/consensys/gnark/std/algebra/weierstrass" "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/test" @@ -114,6 +117,10 @@ func TestEcdsaSHA256(t *testing.T) { assert := test.NewAssert(t) err := test.IsSolved(&circuit, &witness, ecc.BN254.ScalarField()) assert.NoError(err) + p := profile.Start() + _, _ = frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) + p.Stop() + fmt.Println(p.NbConstraints()) } // Example how to verify the signature inside the circuit. From 50a93480d4a50aea0a2c2afe56695881feb93d43 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Thu, 9 Feb 2023 21:49:23 +0100 Subject: [PATCH 002/464] perf(ecdsa/secp256k1): add instead of dbl in scalarMul (i=1) --- std/algebra/weierstrass/point.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/std/algebra/weierstrass/point.go b/std/algebra/weierstrass/point.go index 1caf665533..d0183712b0 100644 --- a/std/algebra/weierstrass/point.go +++ b/std/algebra/weierstrass/point.go @@ -925,19 +925,22 @@ func (c *Curve[B, S]) Select(b frontend.Variable, p, q *AffinePoint[B]) *AffineP // ScalarMul computes s * p and returns it. It doesn't modify p nor s. func (c *Curve[B, S]) ScalarMul(p *AffinePoint[B], s *emulated.Element[S]) *AffinePoint[B] { - res := p - acc := c.Double(p) - var st S sr := c.scalarApi.Reduce(s) sBits := c.scalarApi.ToBits(sr) - for i := 1; i < st.Modulus().BitLen(); i++ { + + // i = 1 + tmp := c.Add(p, c.Double(p)) + res := c.Select(sBits[1], tmp, p) + acc := c.Add(tmp, p) + + for i := 2; i < st.Modulus().BitLen(); i++ { tmp := c.Add(res, acc) res = c.Select(sBits[i], tmp, res) acc = c.Double(acc) } - tmp := c.Add(res, c.Neg(p)) + tmp = c.Add(res, c.Neg(p)) res = c.Select(sBits[0], res, tmp) return res } From de74b21574416543a6a31255f1da78e106a0482f Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 10 Feb 2023 14:26:51 +0100 Subject: [PATCH 003/464] perf(ecdsa/secp256k1): save 1 mul in triple --- std/algebra/weierstrass/point.go | 41 +++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/std/algebra/weierstrass/point.go b/std/algebra/weierstrass/point.go index d0183712b0..5106658797 100644 --- a/std/algebra/weierstrass/point.go +++ b/std/algebra/weierstrass/point.go @@ -912,6 +912,45 @@ func (c *Curve[B, S]) Double(p *AffinePoint[B]) *AffinePoint[B] { } } +// Triple triples p and return it. It doesn't modify p. +func (c *Curve[B, S]) Triple(p *AffinePoint[B]) *AffinePoint[B] { + + // compute lambda = (3*p1.x**2+a)/2*p1.y, here we assume a=0 (j invariant 0 curve) + xx := c.baseApi.MulMod(&p.X, &p.X) + xx = c.baseApi.MulConst(xx, big.NewInt(3)) + if c.addA { + xx = c.baseApi.Add(xx, &c.a) + } + y2 := c.baseApi.MulConst(&p.Y, big.NewInt(2)) + lambda := c.baseApi.Div(xx, y2) + + // xr = lambda**2-p1.x-p1.x + x2 := c.baseApi.MulConst(&p.X, big.NewInt(2)) + lambdaSq := c.baseApi.MulMod(lambda, lambda) + x2 = c.baseApi.Sub(lambdaSq, x2) + + // compute lambda = (p1.y-p.y)/(p1.x-p.x) + // λ2 = 2y1/(x3 − x1) − λ1. + x1x2 := c.baseApi.Sub(&p.X, x2) + lambda2 := c.baseApi.Div(y2, x1x2) + lambda2 = c.baseApi.Sub(lambda2, lambda) + + // xr = lambda**2-p.x-p1.x + lambdaSq = c.baseApi.MulMod(lambda2, lambda2) + qxrx := c.baseApi.Add(x2, &p.X) + x3 := c.baseApi.Sub(lambdaSq, qxrx) + + // p.y = lambda(p.x-xr) - p.y + pxxr := c.baseApi.Sub(&p.X, x3) + lpxxr := c.baseApi.MulMod(lambda2, pxxr) + y3 := c.baseApi.Sub(lpxxr, &p.Y) + + return &AffinePoint[B]{ + X: *c.baseApi.Reduce(x3), + Y: *c.baseApi.Reduce(y3), + } +} + // Select selects between p and q given the selector b. If b == 0, then returns // p and q otherwise. func (c *Curve[B, S]) Select(b frontend.Variable, p, q *AffinePoint[B]) *AffinePoint[B] { @@ -930,7 +969,7 @@ func (c *Curve[B, S]) ScalarMul(p *AffinePoint[B], s *emulated.Element[S]) *Affi sBits := c.scalarApi.ToBits(sr) // i = 1 - tmp := c.Add(p, c.Double(p)) + tmp := c.Triple(p) res := c.Select(sBits[1], tmp, p) acc := c.Add(tmp, p) From 90417492a7095cdc8b60c35a07afb169a3a761f0 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 10 Feb 2023 16:50:08 +0100 Subject: [PATCH 004/464] perf(scalarMulBase): lookup2 for the first 2 bits --- std/algebra/weierstrass/params.go | 32 ++++---- std/algebra/weierstrass/point.go | 120 +++++++++++++++++------------- 2 files changed, 86 insertions(+), 66 deletions(-) diff --git a/std/algebra/weierstrass/params.go b/std/algebra/weierstrass/params.go index afda112f25..6e7a85c2ad 100644 --- a/std/algebra/weierstrass/params.go +++ b/std/algebra/weierstrass/params.go @@ -17,8 +17,8 @@ type CurveParams struct { B *big.Int // b in curve equation Gx *big.Int // base point x Gy *big.Int // base point y - Gmx [256]*big.Int // m*base point x - Gmy [256]*big.Int // m*base point y + Gmx [257]*big.Int // m*base point x + Gmy [257]*big.Int // m*base point y } // GetSecp256k1Params returns curve parameters for the curve secp256k1. When @@ -27,10 +27,12 @@ type CurveParams struct { func GetSecp256k1Params() CurveParams { gx, _ := new(big.Int).SetString("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", 16) gy, _ := new(big.Int).SetString("483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", 16) - g2x, _ := new(big.Int).SetString("c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5", 16) - g2y, _ := new(big.Int).SetString("1ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a", 16) - g4x, _ := new(big.Int).SetString("e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13", 16) - g4y, _ := new(big.Int).SetString("51ed993ea0d455b75642e2098ea51448d967ae33bfbdfe40cfe97bdc47739922", 16) + g3x, _ := new(big.Int).SetString("f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9", 16) + g3y, _ := new(big.Int).SetString("388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672", 16) + g5x, _ := new(big.Int).SetString("2f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4", 16) + g5y, _ := new(big.Int).SetString("d8ac222636e5e3d6d4dba9dda6c9c426f788271bab0d6840dca87d3aa6ac62d6", 16) + g7x, _ := new(big.Int).SetString("5cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc", 16) + g7y, _ := new(big.Int).SetString("6aebca40ba255960a3178d6d861a54dba813d0b813fde7b5a5082628087264da", 16) g8x, _ := new(big.Int).SetString("2f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01", 16) g8y, _ := new(big.Int).SetString("5c4da8a741539949293d082a132d13b4c2e213d6ba5b7617b5da2cb76cbde904", 16) g16x, _ := new(big.Int).SetString("e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", 16) @@ -544,8 +546,8 @@ func GetSecp256k1Params() CurveParams { B: big.NewInt(7), Gx: gx, Gy: gy, - Gmx: [256]*big.Int{g2x, g4x, g8x, g16x, g32x, g64x, g128x, g256x, g512x, g1024x, g2048x, g4096x, g8192x, g16384x, g32768x, g65536x, g131072x, g262144x, g524288x, g1048576x, g2097152x, g4194304x, g8388608x, g16777216x, g33554432x, g67108864x, g134217728x, g268435456x, g536870912x, g1073741824x, g2147483648x, g4294967296x, g8589934592x, g17179869184x, g34359738368x, g68719476736x, g137438953472x, g274877906944x, g549755813888x, g1099511627776x, g2199023255552x, g4398046511104x, g8796093022208x, g17592186044416x, g35184372088832x, g70368744177664x, g140737488355328x, g281474976710656x, g562949953421312x, g1125899906842624x, g2251799813685248x, g4503599627370496x, g9007199254740992x, g18014398509481984x, g36028797018963968x, g72057594037927936x, g144115188075855872x, g288230376151711744x, g576460752303423488x, g1152921504606846976x, g2305843009213693952x, g4611686018427387904x, g9223372036854775808x, g18446744073709551616x, g36893488147419103232x, g73786976294838206464x, g147573952589676412928x, g295147905179352825856x, g590295810358705651712x, g1180591620717411303424x, g2361183241434822606848x, g4722366482869645213696x, g9444732965739290427392x, g18889465931478580854784x, g37778931862957161709568x, g75557863725914323419136x, g151115727451828646838272x, g302231454903657293676544x, g604462909807314587353088x, g1208925819614629174706176x, g2417851639229258349412352x, g4835703278458516698824704x, g9671406556917033397649408x, g19342813113834066795298816x, g38685626227668133590597632x, g77371252455336267181195264x, g154742504910672534362390528x, g309485009821345068724781056x, g618970019642690137449562112x, g1237940039285380274899124224x, g2475880078570760549798248448x, g4951760157141521099596496896x, g9903520314283042199192993792x, g19807040628566084398385987584x, g39614081257132168796771975168x, g79228162514264337593543950336x, g158456325028528675187087900672x, g316912650057057350374175801344x, g633825300114114700748351602688x, g1267650600228229401496703205376x, g2535301200456458802993406410752x, g5070602400912917605986812821504x, g10141204801825835211973625643008x, g20282409603651670423947251286016x, g40564819207303340847894502572032x, g81129638414606681695789005144064x, g162259276829213363391578010288128x, g324518553658426726783156020576256x, g649037107316853453566312041152512x, g1298074214633706907132624082305024x, g2596148429267413814265248164610048x, g5192296858534827628530496329220096x, g10384593717069655257060992658440192x, g20769187434139310514121985316880384x, g41538374868278621028243970633760768x, g83076749736557242056487941267521536x, g166153499473114484112975882535043072x, g332306998946228968225951765070086144x, g664613997892457936451903530140172288x, g1329227995784915872903807060280344576x, g2658455991569831745807614120560689152x, g5316911983139663491615228241121378304x, g10633823966279326983230456482242756608x, g21267647932558653966460912964485513216x, g42535295865117307932921825928971026432x, g85070591730234615865843651857942052864x, g170141183460469231731687303715884105728x, g340282366920938463463374607431768211456x, g680564733841876926926749214863536422912x, g1361129467683753853853498429727072845824x, g2722258935367507707706996859454145691648x, g5444517870735015415413993718908291383296x, g10889035741470030830827987437816582766592x, g21778071482940061661655974875633165533184x, g43556142965880123323311949751266331066368x, g87112285931760246646623899502532662132736x, g174224571863520493293247799005065324265472x, g348449143727040986586495598010130648530944x, g696898287454081973172991196020261297061888x, g1393796574908163946345982392040522594123776x, g2787593149816327892691964784081045188247552x, g5575186299632655785383929568162090376495104x, g11150372599265311570767859136324180752990208x, g22300745198530623141535718272648361505980416x, g44601490397061246283071436545296723011960832x, g89202980794122492566142873090593446023921664x, g178405961588244985132285746181186892047843328x, g356811923176489970264571492362373784095686656x, g713623846352979940529142984724747568191373312x, g1427247692705959881058285969449495136382746624x, g2854495385411919762116571938898990272765493248x, g5708990770823839524233143877797980545530986496x, g11417981541647679048466287755595961091061972992x, g22835963083295358096932575511191922182123945984x, g45671926166590716193865151022383844364247891968x, g91343852333181432387730302044767688728495783936x, g182687704666362864775460604089535377456991567872x, g365375409332725729550921208179070754913983135744x, g730750818665451459101842416358141509827966271488x, g1461501637330902918203684832716283019655932542976x, g2923003274661805836407369665432566039311865085952x, g5846006549323611672814739330865132078623730171904x, g11692013098647223345629478661730264157247460343808x, g23384026197294446691258957323460528314494920687616x, g46768052394588893382517914646921056628989841375232x, g93536104789177786765035829293842113257979682750464x, g187072209578355573530071658587684226515959365500928x, g374144419156711147060143317175368453031918731001856x, g748288838313422294120286634350736906063837462003712x, g1496577676626844588240573268701473812127674924007424x, g2993155353253689176481146537402947624255349848014848x, g5986310706507378352962293074805895248510699696029696x, g11972621413014756705924586149611790497021399392059392x, g23945242826029513411849172299223580994042798784118784x, g47890485652059026823698344598447161988085597568237568x, g95780971304118053647396689196894323976171195136475136x, g191561942608236107294793378393788647952342390272950272x, g383123885216472214589586756787577295904684780545900544x, g766247770432944429179173513575154591809369561091801088x, g1532495540865888858358347027150309183618739122183602176x, g3064991081731777716716694054300618367237478244367204352x, g6129982163463555433433388108601236734474956488734408704x, g12259964326927110866866776217202473468949912977468817408x, g24519928653854221733733552434404946937899825954937634816x, g49039857307708443467467104868809893875799651909875269632x, g98079714615416886934934209737619787751599303819750539264x, g196159429230833773869868419475239575503198607639501078528x, g392318858461667547739736838950479151006397215279002157056x, g784637716923335095479473677900958302012794430558004314112x, g1569275433846670190958947355801916604025588861116008628224x, g3138550867693340381917894711603833208051177722232017256448x, g6277101735386680763835789423207666416102355444464034512896x, g12554203470773361527671578846415332832204710888928069025792x, g25108406941546723055343157692830665664409421777856138051584x, g50216813883093446110686315385661331328818843555712276103168x, g100433627766186892221372630771322662657637687111424552206336x, g200867255532373784442745261542645325315275374222849104412672x, g401734511064747568885490523085290650630550748445698208825344x, g803469022129495137770981046170581301261101496891396417650688x, g1606938044258990275541962092341162602522202993782792835301376x, g3213876088517980551083924184682325205044405987565585670602752x, g6427752177035961102167848369364650410088811975131171341205504x, g12855504354071922204335696738729300820177623950262342682411008x, g25711008708143844408671393477458601640355247900524685364822016x, g51422017416287688817342786954917203280710495801049370729644032x, g102844034832575377634685573909834406561420991602098741459288064x, g205688069665150755269371147819668813122841983204197482918576128x, g411376139330301510538742295639337626245683966408394965837152256x, g822752278660603021077484591278675252491367932816789931674304512x, g1645504557321206042154969182557350504982735865633579863348609024x, g3291009114642412084309938365114701009965471731267159726697218048x, g6582018229284824168619876730229402019930943462534319453394436096x, g13164036458569648337239753460458804039861886925068638906788872192x, g26328072917139296674479506920917608079723773850137277813577744384x, g52656145834278593348959013841835216159447547700274555627155488768x, g105312291668557186697918027683670432318895095400549111254310977536x, g210624583337114373395836055367340864637790190801098222508621955072x, g421249166674228746791672110734681729275580381602196445017243910144x, g842498333348457493583344221469363458551160763204392890034487820288x, g1684996666696914987166688442938726917102321526408785780068975640576x, g3369993333393829974333376885877453834204643052817571560137951281152x, g6739986666787659948666753771754907668409286105635143120275902562304x, g13479973333575319897333507543509815336818572211270286240551805124608x, g26959946667150639794667015087019630673637144422540572481103610249216x, g53919893334301279589334030174039261347274288845081144962207220498432x, g107839786668602559178668060348078522694548577690162289924414440996864x, g215679573337205118357336120696157045389097155380324579848828881993728x, g431359146674410236714672241392314090778194310760649159697657763987456x, g862718293348820473429344482784628181556388621521298319395315527974912x, g1725436586697640946858688965569256363112777243042596638790631055949824x, g3450873173395281893717377931138512726225554486085193277581262111899648x, g6901746346790563787434755862277025452451108972170386555162524223799296x, g13803492693581127574869511724554050904902217944340773110325048447598592x, g27606985387162255149739023449108101809804435888681546220650096895197184x, g55213970774324510299478046898216203619608871777363092441300193790394368x, g110427941548649020598956093796432407239217743554726184882600387580788736x, g220855883097298041197912187592864814478435487109452369765200775161577472x, g441711766194596082395824375185729628956870974218904739530401550323154944x, g883423532389192164791648750371459257913741948437809479060803100646309888x, g1766847064778384329583297500742918515827483896875618958121606201292619776x, g3533694129556768659166595001485837031654967793751237916243212402585239552x, g7067388259113537318333190002971674063309935587502475832486424805170479104x, g14134776518227074636666380005943348126619871175004951664972849610340958208x, g28269553036454149273332760011886696253239742350009903329945699220681916416x, g56539106072908298546665520023773392506479484700019806659891398441363832832x, g113078212145816597093331040047546785012958969400039613319782796882727665664x, g226156424291633194186662080095093570025917938800079226639565593765455331328x, g452312848583266388373324160190187140051835877600158453279131187530910662656x, g904625697166532776746648320380374280103671755200316906558262375061821325312x, g1809251394333065553493296640760748560207343510400633813116524750123642650624x, g3618502788666131106986593281521497120414687020801267626233049500247285301248x, g7237005577332262213973186563042994240829374041602535252466099000494570602496x, g14474011154664524427946373126085988481658748083205070504932198000989141204992x, g28948022309329048855892746252171976963317496166410141009864396001978282409984x, g57896044618658097711785492504343953926634992332820282019728792003956564819968x, g115792089237316195423570985008687907853269984665640564039457584007913129639936x}, - Gmy: [256]*big.Int{g2y, g4y, g8y, g16y, g32y, g64y, g128y, g256y, g512y, g1024y, g2048y, g4096y, g8192y, g16384y, g32768y, g65536y, g131072y, g262144y, g524288y, g1048576y, g2097152y, g4194304y, g8388608y, g16777216y, g33554432y, g67108864y, g134217728y, g268435456y, g536870912y, g1073741824y, g2147483648y, g4294967296y, g8589934592y, g17179869184y, g34359738368y, g68719476736y, g137438953472y, g274877906944y, g549755813888y, g1099511627776y, g2199023255552y, g4398046511104y, g8796093022208y, g17592186044416y, g35184372088832y, g70368744177664y, g140737488355328y, g281474976710656y, g562949953421312y, g1125899906842624y, g2251799813685248y, g4503599627370496y, g9007199254740992y, g18014398509481984y, g36028797018963968y, g72057594037927936y, g144115188075855872y, g288230376151711744y, g576460752303423488y, g1152921504606846976y, g2305843009213693952y, g4611686018427387904y, g9223372036854775808y, g18446744073709551616y, g36893488147419103232y, g73786976294838206464y, g147573952589676412928y, g295147905179352825856y, g590295810358705651712y, g1180591620717411303424y, g2361183241434822606848y, g4722366482869645213696y, g9444732965739290427392y, g18889465931478580854784y, g37778931862957161709568y, g75557863725914323419136y, g151115727451828646838272y, g302231454903657293676544y, g604462909807314587353088y, g1208925819614629174706176y, g2417851639229258349412352y, g4835703278458516698824704y, g9671406556917033397649408y, g19342813113834066795298816y, g38685626227668133590597632y, g77371252455336267181195264y, g154742504910672534362390528y, g309485009821345068724781056y, g618970019642690137449562112y, g1237940039285380274899124224y, g2475880078570760549798248448y, g4951760157141521099596496896y, g9903520314283042199192993792y, g19807040628566084398385987584y, g39614081257132168796771975168y, g79228162514264337593543950336y, g158456325028528675187087900672y, g316912650057057350374175801344y, g633825300114114700748351602688y, g1267650600228229401496703205376y, g2535301200456458802993406410752y, g5070602400912917605986812821504y, g10141204801825835211973625643008y, g20282409603651670423947251286016y, g40564819207303340847894502572032y, g81129638414606681695789005144064y, g162259276829213363391578010288128y, g324518553658426726783156020576256y, g649037107316853453566312041152512y, g1298074214633706907132624082305024y, g2596148429267413814265248164610048y, g5192296858534827628530496329220096y, g10384593717069655257060992658440192y, g20769187434139310514121985316880384y, g41538374868278621028243970633760768y, g83076749736557242056487941267521536y, g166153499473114484112975882535043072y, g332306998946228968225951765070086144y, g664613997892457936451903530140172288y, g1329227995784915872903807060280344576y, g2658455991569831745807614120560689152y, g5316911983139663491615228241121378304y, g10633823966279326983230456482242756608y, g21267647932558653966460912964485513216y, g42535295865117307932921825928971026432y, g85070591730234615865843651857942052864y, g170141183460469231731687303715884105728y, g340282366920938463463374607431768211456y, g680564733841876926926749214863536422912y, g1361129467683753853853498429727072845824y, g2722258935367507707706996859454145691648y, g5444517870735015415413993718908291383296y, g10889035741470030830827987437816582766592y, g21778071482940061661655974875633165533184y, g43556142965880123323311949751266331066368y, g87112285931760246646623899502532662132736y, g174224571863520493293247799005065324265472y, g348449143727040986586495598010130648530944y, g696898287454081973172991196020261297061888y, g1393796574908163946345982392040522594123776y, g2787593149816327892691964784081045188247552y, g5575186299632655785383929568162090376495104y, g11150372599265311570767859136324180752990208y, g22300745198530623141535718272648361505980416y, g44601490397061246283071436545296723011960832y, g89202980794122492566142873090593446023921664y, g178405961588244985132285746181186892047843328y, g356811923176489970264571492362373784095686656y, g713623846352979940529142984724747568191373312y, g1427247692705959881058285969449495136382746624y, g2854495385411919762116571938898990272765493248y, g5708990770823839524233143877797980545530986496y, g11417981541647679048466287755595961091061972992y, g22835963083295358096932575511191922182123945984y, g45671926166590716193865151022383844364247891968y, g91343852333181432387730302044767688728495783936y, g182687704666362864775460604089535377456991567872y, g365375409332725729550921208179070754913983135744y, g730750818665451459101842416358141509827966271488y, g1461501637330902918203684832716283019655932542976y, g2923003274661805836407369665432566039311865085952y, g5846006549323611672814739330865132078623730171904y, g11692013098647223345629478661730264157247460343808y, g23384026197294446691258957323460528314494920687616y, g46768052394588893382517914646921056628989841375232y, g93536104789177786765035829293842113257979682750464y, g187072209578355573530071658587684226515959365500928y, g374144419156711147060143317175368453031918731001856y, g748288838313422294120286634350736906063837462003712y, g1496577676626844588240573268701473812127674924007424y, g2993155353253689176481146537402947624255349848014848y, g5986310706507378352962293074805895248510699696029696y, g11972621413014756705924586149611790497021399392059392y, g23945242826029513411849172299223580994042798784118784y, g47890485652059026823698344598447161988085597568237568y, g95780971304118053647396689196894323976171195136475136y, g191561942608236107294793378393788647952342390272950272y, g383123885216472214589586756787577295904684780545900544y, g766247770432944429179173513575154591809369561091801088y, g1532495540865888858358347027150309183618739122183602176y, g3064991081731777716716694054300618367237478244367204352y, g6129982163463555433433388108601236734474956488734408704y, g12259964326927110866866776217202473468949912977468817408y, g24519928653854221733733552434404946937899825954937634816y, g49039857307708443467467104868809893875799651909875269632y, g98079714615416886934934209737619787751599303819750539264y, g196159429230833773869868419475239575503198607639501078528y, g392318858461667547739736838950479151006397215279002157056y, g784637716923335095479473677900958302012794430558004314112y, g1569275433846670190958947355801916604025588861116008628224y, g3138550867693340381917894711603833208051177722232017256448y, g6277101735386680763835789423207666416102355444464034512896y, g12554203470773361527671578846415332832204710888928069025792y, g25108406941546723055343157692830665664409421777856138051584y, g50216813883093446110686315385661331328818843555712276103168y, g100433627766186892221372630771322662657637687111424552206336y, g200867255532373784442745261542645325315275374222849104412672y, g401734511064747568885490523085290650630550748445698208825344y, g803469022129495137770981046170581301261101496891396417650688y, g1606938044258990275541962092341162602522202993782792835301376y, g3213876088517980551083924184682325205044405987565585670602752y, g6427752177035961102167848369364650410088811975131171341205504y, g12855504354071922204335696738729300820177623950262342682411008y, g25711008708143844408671393477458601640355247900524685364822016y, g51422017416287688817342786954917203280710495801049370729644032y, g102844034832575377634685573909834406561420991602098741459288064y, g205688069665150755269371147819668813122841983204197482918576128y, g411376139330301510538742295639337626245683966408394965837152256y, g822752278660603021077484591278675252491367932816789931674304512y, g1645504557321206042154969182557350504982735865633579863348609024y, g3291009114642412084309938365114701009965471731267159726697218048y, g6582018229284824168619876730229402019930943462534319453394436096y, g13164036458569648337239753460458804039861886925068638906788872192y, g26328072917139296674479506920917608079723773850137277813577744384y, g52656145834278593348959013841835216159447547700274555627155488768y, g105312291668557186697918027683670432318895095400549111254310977536y, g210624583337114373395836055367340864637790190801098222508621955072y, g421249166674228746791672110734681729275580381602196445017243910144y, g842498333348457493583344221469363458551160763204392890034487820288y, g1684996666696914987166688442938726917102321526408785780068975640576y, g3369993333393829974333376885877453834204643052817571560137951281152y, g6739986666787659948666753771754907668409286105635143120275902562304y, g13479973333575319897333507543509815336818572211270286240551805124608y, g26959946667150639794667015087019630673637144422540572481103610249216y, g53919893334301279589334030174039261347274288845081144962207220498432y, g107839786668602559178668060348078522694548577690162289924414440996864y, g215679573337205118357336120696157045389097155380324579848828881993728y, g431359146674410236714672241392314090778194310760649159697657763987456y, g862718293348820473429344482784628181556388621521298319395315527974912y, g1725436586697640946858688965569256363112777243042596638790631055949824y, g3450873173395281893717377931138512726225554486085193277581262111899648y, g6901746346790563787434755862277025452451108972170386555162524223799296y, g13803492693581127574869511724554050904902217944340773110325048447598592y, g27606985387162255149739023449108101809804435888681546220650096895197184y, g55213970774324510299478046898216203619608871777363092441300193790394368y, g110427941548649020598956093796432407239217743554726184882600387580788736y, g220855883097298041197912187592864814478435487109452369765200775161577472y, g441711766194596082395824375185729628956870974218904739530401550323154944y, g883423532389192164791648750371459257913741948437809479060803100646309888y, g1766847064778384329583297500742918515827483896875618958121606201292619776y, g3533694129556768659166595001485837031654967793751237916243212402585239552y, g7067388259113537318333190002971674063309935587502475832486424805170479104y, g14134776518227074636666380005943348126619871175004951664972849610340958208y, g28269553036454149273332760011886696253239742350009903329945699220681916416y, g56539106072908298546665520023773392506479484700019806659891398441363832832y, g113078212145816597093331040047546785012958969400039613319782796882727665664y, g226156424291633194186662080095093570025917938800079226639565593765455331328y, g452312848583266388373324160190187140051835877600158453279131187530910662656y, g904625697166532776746648320380374280103671755200316906558262375061821325312y, g1809251394333065553493296640760748560207343510400633813116524750123642650624y, g3618502788666131106986593281521497120414687020801267626233049500247285301248y, g7237005577332262213973186563042994240829374041602535252466099000494570602496y, g14474011154664524427946373126085988481658748083205070504932198000989141204992y, g28948022309329048855892746252171976963317496166410141009864396001978282409984y, g57896044618658097711785492504343953926634992332820282019728792003956564819968y, g115792089237316195423570985008687907853269984665640564039457584007913129639936y}, + Gmx: [257]*big.Int{g3x, g5x, g7x, g8x, g16x, g32x, g64x, g128x, g256x, g512x, g1024x, g2048x, g4096x, g8192x, g16384x, g32768x, g65536x, g131072x, g262144x, g524288x, g1048576x, g2097152x, g4194304x, g8388608x, g16777216x, g33554432x, g67108864x, g134217728x, g268435456x, g536870912x, g1073741824x, g2147483648x, g4294967296x, g8589934592x, g17179869184x, g34359738368x, g68719476736x, g137438953472x, g274877906944x, g549755813888x, g1099511627776x, g2199023255552x, g4398046511104x, g8796093022208x, g17592186044416x, g35184372088832x, g70368744177664x, g140737488355328x, g281474976710656x, g562949953421312x, g1125899906842624x, g2251799813685248x, g4503599627370496x, g9007199254740992x, g18014398509481984x, g36028797018963968x, g72057594037927936x, g144115188075855872x, g288230376151711744x, g576460752303423488x, g1152921504606846976x, g2305843009213693952x, g4611686018427387904x, g9223372036854775808x, g18446744073709551616x, g36893488147419103232x, g73786976294838206464x, g147573952589676412928x, g295147905179352825856x, g590295810358705651712x, g1180591620717411303424x, g2361183241434822606848x, g4722366482869645213696x, g9444732965739290427392x, g18889465931478580854784x, g37778931862957161709568x, g75557863725914323419136x, g151115727451828646838272x, g302231454903657293676544x, g604462909807314587353088x, g1208925819614629174706176x, g2417851639229258349412352x, g4835703278458516698824704x, g9671406556917033397649408x, g19342813113834066795298816x, g38685626227668133590597632x, g77371252455336267181195264x, g154742504910672534362390528x, g309485009821345068724781056x, g618970019642690137449562112x, g1237940039285380274899124224x, g2475880078570760549798248448x, g4951760157141521099596496896x, g9903520314283042199192993792x, g19807040628566084398385987584x, g39614081257132168796771975168x, g79228162514264337593543950336x, g158456325028528675187087900672x, g316912650057057350374175801344x, g633825300114114700748351602688x, g1267650600228229401496703205376x, g2535301200456458802993406410752x, g5070602400912917605986812821504x, g10141204801825835211973625643008x, g20282409603651670423947251286016x, g40564819207303340847894502572032x, g81129638414606681695789005144064x, g162259276829213363391578010288128x, g324518553658426726783156020576256x, g649037107316853453566312041152512x, g1298074214633706907132624082305024x, g2596148429267413814265248164610048x, g5192296858534827628530496329220096x, g10384593717069655257060992658440192x, g20769187434139310514121985316880384x, g41538374868278621028243970633760768x, g83076749736557242056487941267521536x, g166153499473114484112975882535043072x, g332306998946228968225951765070086144x, g664613997892457936451903530140172288x, g1329227995784915872903807060280344576x, g2658455991569831745807614120560689152x, g5316911983139663491615228241121378304x, g10633823966279326983230456482242756608x, g21267647932558653966460912964485513216x, g42535295865117307932921825928971026432x, g85070591730234615865843651857942052864x, g170141183460469231731687303715884105728x, g340282366920938463463374607431768211456x, g680564733841876926926749214863536422912x, g1361129467683753853853498429727072845824x, g2722258935367507707706996859454145691648x, g5444517870735015415413993718908291383296x, g10889035741470030830827987437816582766592x, g21778071482940061661655974875633165533184x, g43556142965880123323311949751266331066368x, g87112285931760246646623899502532662132736x, g174224571863520493293247799005065324265472x, g348449143727040986586495598010130648530944x, g696898287454081973172991196020261297061888x, g1393796574908163946345982392040522594123776x, g2787593149816327892691964784081045188247552x, g5575186299632655785383929568162090376495104x, g11150372599265311570767859136324180752990208x, g22300745198530623141535718272648361505980416x, g44601490397061246283071436545296723011960832x, g89202980794122492566142873090593446023921664x, g178405961588244985132285746181186892047843328x, g356811923176489970264571492362373784095686656x, g713623846352979940529142984724747568191373312x, g1427247692705959881058285969449495136382746624x, g2854495385411919762116571938898990272765493248x, g5708990770823839524233143877797980545530986496x, g11417981541647679048466287755595961091061972992x, g22835963083295358096932575511191922182123945984x, g45671926166590716193865151022383844364247891968x, g91343852333181432387730302044767688728495783936x, g182687704666362864775460604089535377456991567872x, g365375409332725729550921208179070754913983135744x, g730750818665451459101842416358141509827966271488x, g1461501637330902918203684832716283019655932542976x, g2923003274661805836407369665432566039311865085952x, g5846006549323611672814739330865132078623730171904x, g11692013098647223345629478661730264157247460343808x, g23384026197294446691258957323460528314494920687616x, g46768052394588893382517914646921056628989841375232x, g93536104789177786765035829293842113257979682750464x, g187072209578355573530071658587684226515959365500928x, g374144419156711147060143317175368453031918731001856x, g748288838313422294120286634350736906063837462003712x, g1496577676626844588240573268701473812127674924007424x, g2993155353253689176481146537402947624255349848014848x, g5986310706507378352962293074805895248510699696029696x, g11972621413014756705924586149611790497021399392059392x, g23945242826029513411849172299223580994042798784118784x, g47890485652059026823698344598447161988085597568237568x, g95780971304118053647396689196894323976171195136475136x, g191561942608236107294793378393788647952342390272950272x, g383123885216472214589586756787577295904684780545900544x, g766247770432944429179173513575154591809369561091801088x, g1532495540865888858358347027150309183618739122183602176x, g3064991081731777716716694054300618367237478244367204352x, g6129982163463555433433388108601236734474956488734408704x, g12259964326927110866866776217202473468949912977468817408x, g24519928653854221733733552434404946937899825954937634816x, g49039857307708443467467104868809893875799651909875269632x, g98079714615416886934934209737619787751599303819750539264x, g196159429230833773869868419475239575503198607639501078528x, g392318858461667547739736838950479151006397215279002157056x, g784637716923335095479473677900958302012794430558004314112x, g1569275433846670190958947355801916604025588861116008628224x, g3138550867693340381917894711603833208051177722232017256448x, g6277101735386680763835789423207666416102355444464034512896x, g12554203470773361527671578846415332832204710888928069025792x, g25108406941546723055343157692830665664409421777856138051584x, g50216813883093446110686315385661331328818843555712276103168x, g100433627766186892221372630771322662657637687111424552206336x, g200867255532373784442745261542645325315275374222849104412672x, g401734511064747568885490523085290650630550748445698208825344x, g803469022129495137770981046170581301261101496891396417650688x, g1606938044258990275541962092341162602522202993782792835301376x, g3213876088517980551083924184682325205044405987565585670602752x, g6427752177035961102167848369364650410088811975131171341205504x, g12855504354071922204335696738729300820177623950262342682411008x, g25711008708143844408671393477458601640355247900524685364822016x, g51422017416287688817342786954917203280710495801049370729644032x, g102844034832575377634685573909834406561420991602098741459288064x, g205688069665150755269371147819668813122841983204197482918576128x, g411376139330301510538742295639337626245683966408394965837152256x, g822752278660603021077484591278675252491367932816789931674304512x, g1645504557321206042154969182557350504982735865633579863348609024x, g3291009114642412084309938365114701009965471731267159726697218048x, g6582018229284824168619876730229402019930943462534319453394436096x, g13164036458569648337239753460458804039861886925068638906788872192x, g26328072917139296674479506920917608079723773850137277813577744384x, g52656145834278593348959013841835216159447547700274555627155488768x, g105312291668557186697918027683670432318895095400549111254310977536x, g210624583337114373395836055367340864637790190801098222508621955072x, g421249166674228746791672110734681729275580381602196445017243910144x, g842498333348457493583344221469363458551160763204392890034487820288x, g1684996666696914987166688442938726917102321526408785780068975640576x, g3369993333393829974333376885877453834204643052817571560137951281152x, g6739986666787659948666753771754907668409286105635143120275902562304x, g13479973333575319897333507543509815336818572211270286240551805124608x, g26959946667150639794667015087019630673637144422540572481103610249216x, g53919893334301279589334030174039261347274288845081144962207220498432x, g107839786668602559178668060348078522694548577690162289924414440996864x, g215679573337205118357336120696157045389097155380324579848828881993728x, g431359146674410236714672241392314090778194310760649159697657763987456x, g862718293348820473429344482784628181556388621521298319395315527974912x, g1725436586697640946858688965569256363112777243042596638790631055949824x, g3450873173395281893717377931138512726225554486085193277581262111899648x, g6901746346790563787434755862277025452451108972170386555162524223799296x, g13803492693581127574869511724554050904902217944340773110325048447598592x, g27606985387162255149739023449108101809804435888681546220650096895197184x, g55213970774324510299478046898216203619608871777363092441300193790394368x, g110427941548649020598956093796432407239217743554726184882600387580788736x, g220855883097298041197912187592864814478435487109452369765200775161577472x, g441711766194596082395824375185729628956870974218904739530401550323154944x, g883423532389192164791648750371459257913741948437809479060803100646309888x, g1766847064778384329583297500742918515827483896875618958121606201292619776x, g3533694129556768659166595001485837031654967793751237916243212402585239552x, g7067388259113537318333190002971674063309935587502475832486424805170479104x, g14134776518227074636666380005943348126619871175004951664972849610340958208x, g28269553036454149273332760011886696253239742350009903329945699220681916416x, g56539106072908298546665520023773392506479484700019806659891398441363832832x, g113078212145816597093331040047546785012958969400039613319782796882727665664x, g226156424291633194186662080095093570025917938800079226639565593765455331328x, g452312848583266388373324160190187140051835877600158453279131187530910662656x, g904625697166532776746648320380374280103671755200316906558262375061821325312x, g1809251394333065553493296640760748560207343510400633813116524750123642650624x, g3618502788666131106986593281521497120414687020801267626233049500247285301248x, g7237005577332262213973186563042994240829374041602535252466099000494570602496x, g14474011154664524427946373126085988481658748083205070504932198000989141204992x, g28948022309329048855892746252171976963317496166410141009864396001978282409984x, g57896044618658097711785492504343953926634992332820282019728792003956564819968x, g115792089237316195423570985008687907853269984665640564039457584007913129639936x}, + Gmy: [257]*big.Int{g3y, g5y, g7y, g8y, g16y, g32y, g64y, g128y, g256y, g512y, g1024y, g2048y, g4096y, g8192y, g16384y, g32768y, g65536y, g131072y, g262144y, g524288y, g1048576y, g2097152y, g4194304y, g8388608y, g16777216y, g33554432y, g67108864y, g134217728y, g268435456y, g536870912y, g1073741824y, g2147483648y, g4294967296y, g8589934592y, g17179869184y, g34359738368y, g68719476736y, g137438953472y, g274877906944y, g549755813888y, g1099511627776y, g2199023255552y, g4398046511104y, g8796093022208y, g17592186044416y, g35184372088832y, g70368744177664y, g140737488355328y, g281474976710656y, g562949953421312y, g1125899906842624y, g2251799813685248y, g4503599627370496y, g9007199254740992y, g18014398509481984y, g36028797018963968y, g72057594037927936y, g144115188075855872y, g288230376151711744y, g576460752303423488y, g1152921504606846976y, g2305843009213693952y, g4611686018427387904y, g9223372036854775808y, g18446744073709551616y, g36893488147419103232y, g73786976294838206464y, g147573952589676412928y, g295147905179352825856y, g590295810358705651712y, g1180591620717411303424y, g2361183241434822606848y, g4722366482869645213696y, g9444732965739290427392y, g18889465931478580854784y, g37778931862957161709568y, g75557863725914323419136y, g151115727451828646838272y, g302231454903657293676544y, g604462909807314587353088y, g1208925819614629174706176y, g2417851639229258349412352y, g4835703278458516698824704y, g9671406556917033397649408y, g19342813113834066795298816y, g38685626227668133590597632y, g77371252455336267181195264y, g154742504910672534362390528y, g309485009821345068724781056y, g618970019642690137449562112y, g1237940039285380274899124224y, g2475880078570760549798248448y, g4951760157141521099596496896y, g9903520314283042199192993792y, g19807040628566084398385987584y, g39614081257132168796771975168y, g79228162514264337593543950336y, g158456325028528675187087900672y, g316912650057057350374175801344y, g633825300114114700748351602688y, g1267650600228229401496703205376y, g2535301200456458802993406410752y, g5070602400912917605986812821504y, g10141204801825835211973625643008y, g20282409603651670423947251286016y, g40564819207303340847894502572032y, g81129638414606681695789005144064y, g162259276829213363391578010288128y, g324518553658426726783156020576256y, g649037107316853453566312041152512y, g1298074214633706907132624082305024y, g2596148429267413814265248164610048y, g5192296858534827628530496329220096y, g10384593717069655257060992658440192y, g20769187434139310514121985316880384y, g41538374868278621028243970633760768y, g83076749736557242056487941267521536y, g166153499473114484112975882535043072y, g332306998946228968225951765070086144y, g664613997892457936451903530140172288y, g1329227995784915872903807060280344576y, g2658455991569831745807614120560689152y, g5316911983139663491615228241121378304y, g10633823966279326983230456482242756608y, g21267647932558653966460912964485513216y, g42535295865117307932921825928971026432y, g85070591730234615865843651857942052864y, g170141183460469231731687303715884105728y, g340282366920938463463374607431768211456y, g680564733841876926926749214863536422912y, g1361129467683753853853498429727072845824y, g2722258935367507707706996859454145691648y, g5444517870735015415413993718908291383296y, g10889035741470030830827987437816582766592y, g21778071482940061661655974875633165533184y, g43556142965880123323311949751266331066368y, g87112285931760246646623899502532662132736y, g174224571863520493293247799005065324265472y, g348449143727040986586495598010130648530944y, g696898287454081973172991196020261297061888y, g1393796574908163946345982392040522594123776y, g2787593149816327892691964784081045188247552y, g5575186299632655785383929568162090376495104y, g11150372599265311570767859136324180752990208y, g22300745198530623141535718272648361505980416y, g44601490397061246283071436545296723011960832y, g89202980794122492566142873090593446023921664y, g178405961588244985132285746181186892047843328y, g356811923176489970264571492362373784095686656y, g713623846352979940529142984724747568191373312y, g1427247692705959881058285969449495136382746624y, g2854495385411919762116571938898990272765493248y, g5708990770823839524233143877797980545530986496y, g11417981541647679048466287755595961091061972992y, g22835963083295358096932575511191922182123945984y, g45671926166590716193865151022383844364247891968y, g91343852333181432387730302044767688728495783936y, g182687704666362864775460604089535377456991567872y, g365375409332725729550921208179070754913983135744y, g730750818665451459101842416358141509827966271488y, g1461501637330902918203684832716283019655932542976y, g2923003274661805836407369665432566039311865085952y, g5846006549323611672814739330865132078623730171904y, g11692013098647223345629478661730264157247460343808y, g23384026197294446691258957323460528314494920687616y, g46768052394588893382517914646921056628989841375232y, g93536104789177786765035829293842113257979682750464y, g187072209578355573530071658587684226515959365500928y, g374144419156711147060143317175368453031918731001856y, g748288838313422294120286634350736906063837462003712y, g1496577676626844588240573268701473812127674924007424y, g2993155353253689176481146537402947624255349848014848y, g5986310706507378352962293074805895248510699696029696y, g11972621413014756705924586149611790497021399392059392y, g23945242826029513411849172299223580994042798784118784y, g47890485652059026823698344598447161988085597568237568y, g95780971304118053647396689196894323976171195136475136y, g191561942608236107294793378393788647952342390272950272y, g383123885216472214589586756787577295904684780545900544y, g766247770432944429179173513575154591809369561091801088y, g1532495540865888858358347027150309183618739122183602176y, g3064991081731777716716694054300618367237478244367204352y, g6129982163463555433433388108601236734474956488734408704y, g12259964326927110866866776217202473468949912977468817408y, g24519928653854221733733552434404946937899825954937634816y, g49039857307708443467467104868809893875799651909875269632y, g98079714615416886934934209737619787751599303819750539264y, g196159429230833773869868419475239575503198607639501078528y, g392318858461667547739736838950479151006397215279002157056y, g784637716923335095479473677900958302012794430558004314112y, g1569275433846670190958947355801916604025588861116008628224y, g3138550867693340381917894711603833208051177722232017256448y, g6277101735386680763835789423207666416102355444464034512896y, g12554203470773361527671578846415332832204710888928069025792y, g25108406941546723055343157692830665664409421777856138051584y, g50216813883093446110686315385661331328818843555712276103168y, g100433627766186892221372630771322662657637687111424552206336y, g200867255532373784442745261542645325315275374222849104412672y, g401734511064747568885490523085290650630550748445698208825344y, g803469022129495137770981046170581301261101496891396417650688y, g1606938044258990275541962092341162602522202993782792835301376y, g3213876088517980551083924184682325205044405987565585670602752y, g6427752177035961102167848369364650410088811975131171341205504y, g12855504354071922204335696738729300820177623950262342682411008y, g25711008708143844408671393477458601640355247900524685364822016y, g51422017416287688817342786954917203280710495801049370729644032y, g102844034832575377634685573909834406561420991602098741459288064y, g205688069665150755269371147819668813122841983204197482918576128y, g411376139330301510538742295639337626245683966408394965837152256y, g822752278660603021077484591278675252491367932816789931674304512y, g1645504557321206042154969182557350504982735865633579863348609024y, g3291009114642412084309938365114701009965471731267159726697218048y, g6582018229284824168619876730229402019930943462534319453394436096y, g13164036458569648337239753460458804039861886925068638906788872192y, g26328072917139296674479506920917608079723773850137277813577744384y, g52656145834278593348959013841835216159447547700274555627155488768y, g105312291668557186697918027683670432318895095400549111254310977536y, g210624583337114373395836055367340864637790190801098222508621955072y, g421249166674228746791672110734681729275580381602196445017243910144y, g842498333348457493583344221469363458551160763204392890034487820288y, g1684996666696914987166688442938726917102321526408785780068975640576y, g3369993333393829974333376885877453834204643052817571560137951281152y, g6739986666787659948666753771754907668409286105635143120275902562304y, g13479973333575319897333507543509815336818572211270286240551805124608y, g26959946667150639794667015087019630673637144422540572481103610249216y, g53919893334301279589334030174039261347274288845081144962207220498432y, g107839786668602559178668060348078522694548577690162289924414440996864y, g215679573337205118357336120696157045389097155380324579848828881993728y, g431359146674410236714672241392314090778194310760649159697657763987456y, g862718293348820473429344482784628181556388621521298319395315527974912y, g1725436586697640946858688965569256363112777243042596638790631055949824y, g3450873173395281893717377931138512726225554486085193277581262111899648y, g6901746346790563787434755862277025452451108972170386555162524223799296y, g13803492693581127574869511724554050904902217944340773110325048447598592y, g27606985387162255149739023449108101809804435888681546220650096895197184y, g55213970774324510299478046898216203619608871777363092441300193790394368y, g110427941548649020598956093796432407239217743554726184882600387580788736y, g220855883097298041197912187592864814478435487109452369765200775161577472y, g441711766194596082395824375185729628956870974218904739530401550323154944y, g883423532389192164791648750371459257913741948437809479060803100646309888y, g1766847064778384329583297500742918515827483896875618958121606201292619776y, g3533694129556768659166595001485837031654967793751237916243212402585239552y, g7067388259113537318333190002971674063309935587502475832486424805170479104y, g14134776518227074636666380005943348126619871175004951664972849610340958208y, g28269553036454149273332760011886696253239742350009903329945699220681916416y, g56539106072908298546665520023773392506479484700019806659891398441363832832y, g113078212145816597093331040047546785012958969400039613319782796882727665664y, g226156424291633194186662080095093570025917938800079226639565593765455331328y, g452312848583266388373324160190187140051835877600158453279131187530910662656y, g904625697166532776746648320380374280103671755200316906558262375061821325312y, g1809251394333065553493296640760748560207343510400633813116524750123642650624y, g3618502788666131106986593281521497120414687020801267626233049500247285301248y, g7237005577332262213973186563042994240829374041602535252466099000494570602496y, g14474011154664524427946373126085988481658748083205070504932198000989141204992y, g28948022309329048855892746252171976963317496166410141009864396001978282409984y, g57896044618658097711785492504343953926634992332820282019728792003956564819968y, g115792089237316195423570985008687907853269984665640564039457584007913129639936y}, } } @@ -555,10 +557,12 @@ func GetSecp256k1Params() CurveParams { func GetBN254Params() CurveParams { gx := big.NewInt(1) gy := big.NewInt(2) - g2x, _ := new(big.Int).SetString("30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd3", 16) - g2y, _ := new(big.Int).SetString("15ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4", 16) - g4x, _ := new(big.Int).SetString("6a7b64af8f414bcbeef455b1da5208c9b592b83ee6599824caa6d2ee9141a76", 16) - g4y, _ := new(big.Int).SetString("8e74e438cee31ac104ce59b94e45fe98a97d8f8a6e75664ce88ef5a41e72fbc", 16) + g3x, _ := new(big.Int).SetString("769bf9ac56bea3ff40232bcb1b6bd159315d84715b8e679f2d355961915abf0", 16) + g3y, _ := new(big.Int).SetString("2ab799bee0489429554fdb7c8d086475319e63b40b9c5b57cdf1ff3dd9fe2261", 16) + g5x, _ := new(big.Int).SetString("17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa9", 16) + g5y, _ := new(big.Int).SetString("1e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c", 16) + g7x, _ := new(big.Int).SetString("17072b2ed3bb8d759a5325f477629386cb6fc6ecb801bd76983a6b86abffe078", 16) + g7y, _ := new(big.Int).SetString("168ada6cd130dd52017bb54bfa19377aadfe3bf05d18f41b77809f7f60d4af9e", 16) g8x, _ := new(big.Int).SetString("8b1d51d23480c10f472f5e93b9cfea88238c121fe155af7043937882c306a63", 16) g8y, _ := new(big.Int).SetString("299836713dad3fa34e337aa412466015c366af8ec50b9d7bd05aa74642822021", 16) g16x, _ := new(big.Int).SetString("17f485337f6e10fca0e385f7a93d1ac0a977e43995c3e4d9b8f89daa6a183f44", 16) @@ -1074,8 +1078,8 @@ func GetBN254Params() CurveParams { Gx: gx, Gy: gy, - Gmx: [256]*big.Int{g2x, g4x, g8x, g16x, g32x, g64x, g128x, g256x, g512x, g1024x, g2048x, g4096x, g8192x, g16384x, g32768x, g65536x, g131072x, g262144x, g524288x, g1048576x, g2097152x, g4194304x, g8388608x, g16777216x, g33554432x, g67108864x, g134217728x, g268435456x, g536870912x, g1073741824x, g2147483648x, g4294967296x, g8589934592x, g17179869184x, g34359738368x, g68719476736x, g137438953472x, g274877906944x, g549755813888x, g1099511627776x, g2199023255552x, g4398046511104x, g8796093022208x, g17592186044416x, g35184372088832x, g70368744177664x, g140737488355328x, g281474976710656x, g562949953421312x, g1125899906842624x, g2251799813685248x, g4503599627370496x, g9007199254740992x, g18014398509481984x, g36028797018963968x, g72057594037927936x, g144115188075855872x, g288230376151711744x, g576460752303423488x, g1152921504606846976x, g2305843009213693952x, g4611686018427387904x, g9223372036854775808x, g18446744073709551616x, g36893488147419103232x, g73786976294838206464x, g147573952589676412928x, g295147905179352825856x, g590295810358705651712x, g1180591620717411303424x, g2361183241434822606848x, g4722366482869645213696x, g9444732965739290427392x, g18889465931478580854784x, g37778931862957161709568x, g75557863725914323419136x, g151115727451828646838272x, g302231454903657293676544x, g604462909807314587353088x, g1208925819614629174706176x, g2417851639229258349412352x, g4835703278458516698824704x, g9671406556917033397649408x, g19342813113834066795298816x, g38685626227668133590597632x, g77371252455336267181195264x, g154742504910672534362390528x, g309485009821345068724781056x, g618970019642690137449562112x, g1237940039285380274899124224x, g2475880078570760549798248448x, g4951760157141521099596496896x, g9903520314283042199192993792x, g19807040628566084398385987584x, g39614081257132168796771975168x, g79228162514264337593543950336x, g158456325028528675187087900672x, g316912650057057350374175801344x, g633825300114114700748351602688x, g1267650600228229401496703205376x, g2535301200456458802993406410752x, g5070602400912917605986812821504x, g10141204801825835211973625643008x, g20282409603651670423947251286016x, g40564819207303340847894502572032x, g81129638414606681695789005144064x, g162259276829213363391578010288128x, g324518553658426726783156020576256x, g649037107316853453566312041152512x, g1298074214633706907132624082305024x, g2596148429267413814265248164610048x, g5192296858534827628530496329220096x, g10384593717069655257060992658440192x, g20769187434139310514121985316880384x, g41538374868278621028243970633760768x, g83076749736557242056487941267521536x, g166153499473114484112975882535043072x, g332306998946228968225951765070086144x, g664613997892457936451903530140172288x, g1329227995784915872903807060280344576x, g2658455991569831745807614120560689152x, g5316911983139663491615228241121378304x, g10633823966279326983230456482242756608x, g21267647932558653966460912964485513216x, g42535295865117307932921825928971026432x, g85070591730234615865843651857942052864x, g170141183460469231731687303715884105728x, g340282366920938463463374607431768211456x, g680564733841876926926749214863536422912x, g1361129467683753853853498429727072845824x, g2722258935367507707706996859454145691648x, g5444517870735015415413993718908291383296x, g10889035741470030830827987437816582766592x, g21778071482940061661655974875633165533184x, g43556142965880123323311949751266331066368x, g87112285931760246646623899502532662132736x, g174224571863520493293247799005065324265472x, g348449143727040986586495598010130648530944x, g696898287454081973172991196020261297061888x, g1393796574908163946345982392040522594123776x, g2787593149816327892691964784081045188247552x, g5575186299632655785383929568162090376495104x, g11150372599265311570767859136324180752990208x, g22300745198530623141535718272648361505980416x, g44601490397061246283071436545296723011960832x, g89202980794122492566142873090593446023921664x, g178405961588244985132285746181186892047843328x, g356811923176489970264571492362373784095686656x, g713623846352979940529142984724747568191373312x, g1427247692705959881058285969449495136382746624x, g2854495385411919762116571938898990272765493248x, g5708990770823839524233143877797980545530986496x, g11417981541647679048466287755595961091061972992x, g22835963083295358096932575511191922182123945984x, g45671926166590716193865151022383844364247891968x, g91343852333181432387730302044767688728495783936x, g182687704666362864775460604089535377456991567872x, g365375409332725729550921208179070754913983135744x, g730750818665451459101842416358141509827966271488x, g1461501637330902918203684832716283019655932542976x, g2923003274661805836407369665432566039311865085952x, g5846006549323611672814739330865132078623730171904x, g11692013098647223345629478661730264157247460343808x, g23384026197294446691258957323460528314494920687616x, g46768052394588893382517914646921056628989841375232x, g93536104789177786765035829293842113257979682750464x, g187072209578355573530071658587684226515959365500928x, g374144419156711147060143317175368453031918731001856x, g748288838313422294120286634350736906063837462003712x, g1496577676626844588240573268701473812127674924007424x, g2993155353253689176481146537402947624255349848014848x, g5986310706507378352962293074805895248510699696029696x, g11972621413014756705924586149611790497021399392059392x, g23945242826029513411849172299223580994042798784118784x, g47890485652059026823698344598447161988085597568237568x, g95780971304118053647396689196894323976171195136475136x, g191561942608236107294793378393788647952342390272950272x, g383123885216472214589586756787577295904684780545900544x, g766247770432944429179173513575154591809369561091801088x, g1532495540865888858358347027150309183618739122183602176x, g3064991081731777716716694054300618367237478244367204352x, g6129982163463555433433388108601236734474956488734408704x, g12259964326927110866866776217202473468949912977468817408x, g24519928653854221733733552434404946937899825954937634816x, g49039857307708443467467104868809893875799651909875269632x, g98079714615416886934934209737619787751599303819750539264x, g196159429230833773869868419475239575503198607639501078528x, g392318858461667547739736838950479151006397215279002157056x, g784637716923335095479473677900958302012794430558004314112x, g1569275433846670190958947355801916604025588861116008628224x, g3138550867693340381917894711603833208051177722232017256448x, g6277101735386680763835789423207666416102355444464034512896x, g12554203470773361527671578846415332832204710888928069025792x, g25108406941546723055343157692830665664409421777856138051584x, g50216813883093446110686315385661331328818843555712276103168x, g100433627766186892221372630771322662657637687111424552206336x, g200867255532373784442745261542645325315275374222849104412672x, g401734511064747568885490523085290650630550748445698208825344x, g803469022129495137770981046170581301261101496891396417650688x, g1606938044258990275541962092341162602522202993782792835301376x, g3213876088517980551083924184682325205044405987565585670602752x, g6427752177035961102167848369364650410088811975131171341205504x, g12855504354071922204335696738729300820177623950262342682411008x, g25711008708143844408671393477458601640355247900524685364822016x, g51422017416287688817342786954917203280710495801049370729644032x, g102844034832575377634685573909834406561420991602098741459288064x, g205688069665150755269371147819668813122841983204197482918576128x, g411376139330301510538742295639337626245683966408394965837152256x, g822752278660603021077484591278675252491367932816789931674304512x, g1645504557321206042154969182557350504982735865633579863348609024x, g3291009114642412084309938365114701009965471731267159726697218048x, g6582018229284824168619876730229402019930943462534319453394436096x, g13164036458569648337239753460458804039861886925068638906788872192x, g26328072917139296674479506920917608079723773850137277813577744384x, g52656145834278593348959013841835216159447547700274555627155488768x, g105312291668557186697918027683670432318895095400549111254310977536x, g210624583337114373395836055367340864637790190801098222508621955072x, g421249166674228746791672110734681729275580381602196445017243910144x, g842498333348457493583344221469363458551160763204392890034487820288x, g1684996666696914987166688442938726917102321526408785780068975640576x, g3369993333393829974333376885877453834204643052817571560137951281152x, g6739986666787659948666753771754907668409286105635143120275902562304x, g13479973333575319897333507543509815336818572211270286240551805124608x, g26959946667150639794667015087019630673637144422540572481103610249216x, g53919893334301279589334030174039261347274288845081144962207220498432x, g107839786668602559178668060348078522694548577690162289924414440996864x, g215679573337205118357336120696157045389097155380324579848828881993728x, g431359146674410236714672241392314090778194310760649159697657763987456x, g862718293348820473429344482784628181556388621521298319395315527974912x, g1725436586697640946858688965569256363112777243042596638790631055949824x, g3450873173395281893717377931138512726225554486085193277581262111899648x, g6901746346790563787434755862277025452451108972170386555162524223799296x, g13803492693581127574869511724554050904902217944340773110325048447598592x, g27606985387162255149739023449108101809804435888681546220650096895197184x, g55213970774324510299478046898216203619608871777363092441300193790394368x, g110427941548649020598956093796432407239217743554726184882600387580788736x, g220855883097298041197912187592864814478435487109452369765200775161577472x, g441711766194596082395824375185729628956870974218904739530401550323154944x, g883423532389192164791648750371459257913741948437809479060803100646309888x, g1766847064778384329583297500742918515827483896875618958121606201292619776x, g3533694129556768659166595001485837031654967793751237916243212402585239552x, g7067388259113537318333190002971674063309935587502475832486424805170479104x, g14134776518227074636666380005943348126619871175004951664972849610340958208x, g28269553036454149273332760011886696253239742350009903329945699220681916416x, g56539106072908298546665520023773392506479484700019806659891398441363832832x, g113078212145816597093331040047546785012958969400039613319782796882727665664x, g226156424291633194186662080095093570025917938800079226639565593765455331328x, g452312848583266388373324160190187140051835877600158453279131187530910662656x, g904625697166532776746648320380374280103671755200316906558262375061821325312x, g1809251394333065553493296640760748560207343510400633813116524750123642650624x, g3618502788666131106986593281521497120414687020801267626233049500247285301248x, g7237005577332262213973186563042994240829374041602535252466099000494570602496x, g14474011154664524427946373126085988481658748083205070504932198000989141204992x, g28948022309329048855892746252171976963317496166410141009864396001978282409984x, g57896044618658097711785492504343953926634992332820282019728792003956564819968x, g115792089237316195423570985008687907853269984665640564039457584007913129639936x}, - Gmy: [256]*big.Int{g2y, g4y, g8y, g16y, g32y, g64y, g128y, g256y, g512y, g1024y, g2048y, g4096y, g8192y, g16384y, g32768y, g65536y, g131072y, g262144y, g524288y, g1048576y, g2097152y, g4194304y, g8388608y, g16777216y, g33554432y, g67108864y, g134217728y, g268435456y, g536870912y, g1073741824y, g2147483648y, g4294967296y, g8589934592y, g17179869184y, g34359738368y, g68719476736y, g137438953472y, g274877906944y, g549755813888y, g1099511627776y, g2199023255552y, g4398046511104y, g8796093022208y, g17592186044416y, g35184372088832y, g70368744177664y, g140737488355328y, g281474976710656y, g562949953421312y, g1125899906842624y, g2251799813685248y, g4503599627370496y, g9007199254740992y, g18014398509481984y, g36028797018963968y, g72057594037927936y, g144115188075855872y, g288230376151711744y, g576460752303423488y, g1152921504606846976y, g2305843009213693952y, g4611686018427387904y, g9223372036854775808y, g18446744073709551616y, g36893488147419103232y, g73786976294838206464y, g147573952589676412928y, g295147905179352825856y, g590295810358705651712y, g1180591620717411303424y, g2361183241434822606848y, g4722366482869645213696y, g9444732965739290427392y, g18889465931478580854784y, g37778931862957161709568y, g75557863725914323419136y, g151115727451828646838272y, g302231454903657293676544y, g604462909807314587353088y, g1208925819614629174706176y, g2417851639229258349412352y, g4835703278458516698824704y, g9671406556917033397649408y, g19342813113834066795298816y, g38685626227668133590597632y, g77371252455336267181195264y, g154742504910672534362390528y, g309485009821345068724781056y, g618970019642690137449562112y, g1237940039285380274899124224y, g2475880078570760549798248448y, g4951760157141521099596496896y, g9903520314283042199192993792y, g19807040628566084398385987584y, g39614081257132168796771975168y, g79228162514264337593543950336y, g158456325028528675187087900672y, g316912650057057350374175801344y, g633825300114114700748351602688y, g1267650600228229401496703205376y, g2535301200456458802993406410752y, g5070602400912917605986812821504y, g10141204801825835211973625643008y, g20282409603651670423947251286016y, g40564819207303340847894502572032y, g81129638414606681695789005144064y, g162259276829213363391578010288128y, g324518553658426726783156020576256y, g649037107316853453566312041152512y, g1298074214633706907132624082305024y, g2596148429267413814265248164610048y, g5192296858534827628530496329220096y, g10384593717069655257060992658440192y, g20769187434139310514121985316880384y, g41538374868278621028243970633760768y, g83076749736557242056487941267521536y, g166153499473114484112975882535043072y, g332306998946228968225951765070086144y, g664613997892457936451903530140172288y, g1329227995784915872903807060280344576y, g2658455991569831745807614120560689152y, g5316911983139663491615228241121378304y, g10633823966279326983230456482242756608y, g21267647932558653966460912964485513216y, g42535295865117307932921825928971026432y, g85070591730234615865843651857942052864y, g170141183460469231731687303715884105728y, g340282366920938463463374607431768211456y, g680564733841876926926749214863536422912y, g1361129467683753853853498429727072845824y, g2722258935367507707706996859454145691648y, g5444517870735015415413993718908291383296y, g10889035741470030830827987437816582766592y, g21778071482940061661655974875633165533184y, g43556142965880123323311949751266331066368y, g87112285931760246646623899502532662132736y, g174224571863520493293247799005065324265472y, g348449143727040986586495598010130648530944y, g696898287454081973172991196020261297061888y, g1393796574908163946345982392040522594123776y, g2787593149816327892691964784081045188247552y, g5575186299632655785383929568162090376495104y, g11150372599265311570767859136324180752990208y, g22300745198530623141535718272648361505980416y, g44601490397061246283071436545296723011960832y, g89202980794122492566142873090593446023921664y, g178405961588244985132285746181186892047843328y, g356811923176489970264571492362373784095686656y, g713623846352979940529142984724747568191373312y, g1427247692705959881058285969449495136382746624y, g2854495385411919762116571938898990272765493248y, g5708990770823839524233143877797980545530986496y, g11417981541647679048466287755595961091061972992y, g22835963083295358096932575511191922182123945984y, g45671926166590716193865151022383844364247891968y, g91343852333181432387730302044767688728495783936y, g182687704666362864775460604089535377456991567872y, g365375409332725729550921208179070754913983135744y, g730750818665451459101842416358141509827966271488y, g1461501637330902918203684832716283019655932542976y, g2923003274661805836407369665432566039311865085952y, g5846006549323611672814739330865132078623730171904y, g11692013098647223345629478661730264157247460343808y, g23384026197294446691258957323460528314494920687616y, g46768052394588893382517914646921056628989841375232y, g93536104789177786765035829293842113257979682750464y, g187072209578355573530071658587684226515959365500928y, g374144419156711147060143317175368453031918731001856y, g748288838313422294120286634350736906063837462003712y, g1496577676626844588240573268701473812127674924007424y, g2993155353253689176481146537402947624255349848014848y, g5986310706507378352962293074805895248510699696029696y, g11972621413014756705924586149611790497021399392059392y, g23945242826029513411849172299223580994042798784118784y, g47890485652059026823698344598447161988085597568237568y, g95780971304118053647396689196894323976171195136475136y, g191561942608236107294793378393788647952342390272950272y, g383123885216472214589586756787577295904684780545900544y, g766247770432944429179173513575154591809369561091801088y, g1532495540865888858358347027150309183618739122183602176y, g3064991081731777716716694054300618367237478244367204352y, g6129982163463555433433388108601236734474956488734408704y, g12259964326927110866866776217202473468949912977468817408y, g24519928653854221733733552434404946937899825954937634816y, g49039857307708443467467104868809893875799651909875269632y, g98079714615416886934934209737619787751599303819750539264y, g196159429230833773869868419475239575503198607639501078528y, g392318858461667547739736838950479151006397215279002157056y, g784637716923335095479473677900958302012794430558004314112y, g1569275433846670190958947355801916604025588861116008628224y, g3138550867693340381917894711603833208051177722232017256448y, g6277101735386680763835789423207666416102355444464034512896y, g12554203470773361527671578846415332832204710888928069025792y, g25108406941546723055343157692830665664409421777856138051584y, g50216813883093446110686315385661331328818843555712276103168y, g100433627766186892221372630771322662657637687111424552206336y, g200867255532373784442745261542645325315275374222849104412672y, g401734511064747568885490523085290650630550748445698208825344y, g803469022129495137770981046170581301261101496891396417650688y, g1606938044258990275541962092341162602522202993782792835301376y, g3213876088517980551083924184682325205044405987565585670602752y, g6427752177035961102167848369364650410088811975131171341205504y, g12855504354071922204335696738729300820177623950262342682411008y, g25711008708143844408671393477458601640355247900524685364822016y, g51422017416287688817342786954917203280710495801049370729644032y, g102844034832575377634685573909834406561420991602098741459288064y, g205688069665150755269371147819668813122841983204197482918576128y, g411376139330301510538742295639337626245683966408394965837152256y, g822752278660603021077484591278675252491367932816789931674304512y, g1645504557321206042154969182557350504982735865633579863348609024y, g3291009114642412084309938365114701009965471731267159726697218048y, g6582018229284824168619876730229402019930943462534319453394436096y, g13164036458569648337239753460458804039861886925068638906788872192y, g26328072917139296674479506920917608079723773850137277813577744384y, g52656145834278593348959013841835216159447547700274555627155488768y, g105312291668557186697918027683670432318895095400549111254310977536y, g210624583337114373395836055367340864637790190801098222508621955072y, g421249166674228746791672110734681729275580381602196445017243910144y, g842498333348457493583344221469363458551160763204392890034487820288y, g1684996666696914987166688442938726917102321526408785780068975640576y, g3369993333393829974333376885877453834204643052817571560137951281152y, g6739986666787659948666753771754907668409286105635143120275902562304y, g13479973333575319897333507543509815336818572211270286240551805124608y, g26959946667150639794667015087019630673637144422540572481103610249216y, g53919893334301279589334030174039261347274288845081144962207220498432y, g107839786668602559178668060348078522694548577690162289924414440996864y, g215679573337205118357336120696157045389097155380324579848828881993728y, g431359146674410236714672241392314090778194310760649159697657763987456y, g862718293348820473429344482784628181556388621521298319395315527974912y, g1725436586697640946858688965569256363112777243042596638790631055949824y, g3450873173395281893717377931138512726225554486085193277581262111899648y, g6901746346790563787434755862277025452451108972170386555162524223799296y, g13803492693581127574869511724554050904902217944340773110325048447598592y, g27606985387162255149739023449108101809804435888681546220650096895197184y, g55213970774324510299478046898216203619608871777363092441300193790394368y, g110427941548649020598956093796432407239217743554726184882600387580788736y, g220855883097298041197912187592864814478435487109452369765200775161577472y, g441711766194596082395824375185729628956870974218904739530401550323154944y, g883423532389192164791648750371459257913741948437809479060803100646309888y, g1766847064778384329583297500742918515827483896875618958121606201292619776y, g3533694129556768659166595001485837031654967793751237916243212402585239552y, g7067388259113537318333190002971674063309935587502475832486424805170479104y, g14134776518227074636666380005943348126619871175004951664972849610340958208y, g28269553036454149273332760011886696253239742350009903329945699220681916416y, g56539106072908298546665520023773392506479484700019806659891398441363832832y, g113078212145816597093331040047546785012958969400039613319782796882727665664y, g226156424291633194186662080095093570025917938800079226639565593765455331328y, g452312848583266388373324160190187140051835877600158453279131187530910662656y, g904625697166532776746648320380374280103671755200316906558262375061821325312y, g1809251394333065553493296640760748560207343510400633813116524750123642650624y, g3618502788666131106986593281521497120414687020801267626233049500247285301248y, g7237005577332262213973186563042994240829374041602535252466099000494570602496y, g14474011154664524427946373126085988481658748083205070504932198000989141204992y, g28948022309329048855892746252171976963317496166410141009864396001978282409984y, g57896044618658097711785492504343953926634992332820282019728792003956564819968y, g115792089237316195423570985008687907853269984665640564039457584007913129639936y}, + Gmx: [257]*big.Int{g3x, g5x, g7x, g8x, g16x, g32x, g64x, g128x, g256x, g512x, g1024x, g2048x, g4096x, g8192x, g16384x, g32768x, g65536x, g131072x, g262144x, g524288x, g1048576x, g2097152x, g4194304x, g8388608x, g16777216x, g33554432x, g67108864x, g134217728x, g268435456x, g536870912x, g1073741824x, g2147483648x, g4294967296x, g8589934592x, g17179869184x, g34359738368x, g68719476736x, g137438953472x, g274877906944x, g549755813888x, g1099511627776x, g2199023255552x, g4398046511104x, g8796093022208x, g17592186044416x, g35184372088832x, g70368744177664x, g140737488355328x, g281474976710656x, g562949953421312x, g1125899906842624x, g2251799813685248x, g4503599627370496x, g9007199254740992x, g18014398509481984x, g36028797018963968x, g72057594037927936x, g144115188075855872x, g288230376151711744x, g576460752303423488x, g1152921504606846976x, g2305843009213693952x, g4611686018427387904x, g9223372036854775808x, g18446744073709551616x, g36893488147419103232x, g73786976294838206464x, g147573952589676412928x, g295147905179352825856x, g590295810358705651712x, g1180591620717411303424x, g2361183241434822606848x, g4722366482869645213696x, g9444732965739290427392x, g18889465931478580854784x, g37778931862957161709568x, g75557863725914323419136x, g151115727451828646838272x, g302231454903657293676544x, g604462909807314587353088x, g1208925819614629174706176x, g2417851639229258349412352x, g4835703278458516698824704x, g9671406556917033397649408x, g19342813113834066795298816x, g38685626227668133590597632x, g77371252455336267181195264x, g154742504910672534362390528x, g309485009821345068724781056x, g618970019642690137449562112x, g1237940039285380274899124224x, g2475880078570760549798248448x, g4951760157141521099596496896x, g9903520314283042199192993792x, g19807040628566084398385987584x, g39614081257132168796771975168x, g79228162514264337593543950336x, g158456325028528675187087900672x, g316912650057057350374175801344x, g633825300114114700748351602688x, g1267650600228229401496703205376x, g2535301200456458802993406410752x, g5070602400912917605986812821504x, g10141204801825835211973625643008x, g20282409603651670423947251286016x, g40564819207303340847894502572032x, g81129638414606681695789005144064x, g162259276829213363391578010288128x, g324518553658426726783156020576256x, g649037107316853453566312041152512x, g1298074214633706907132624082305024x, g2596148429267413814265248164610048x, g5192296858534827628530496329220096x, g10384593717069655257060992658440192x, g20769187434139310514121985316880384x, g41538374868278621028243970633760768x, g83076749736557242056487941267521536x, g166153499473114484112975882535043072x, g332306998946228968225951765070086144x, g664613997892457936451903530140172288x, g1329227995784915872903807060280344576x, g2658455991569831745807614120560689152x, g5316911983139663491615228241121378304x, g10633823966279326983230456482242756608x, g21267647932558653966460912964485513216x, g42535295865117307932921825928971026432x, g85070591730234615865843651857942052864x, g170141183460469231731687303715884105728x, g340282366920938463463374607431768211456x, g680564733841876926926749214863536422912x, g1361129467683753853853498429727072845824x, g2722258935367507707706996859454145691648x, g5444517870735015415413993718908291383296x, g10889035741470030830827987437816582766592x, g21778071482940061661655974875633165533184x, g43556142965880123323311949751266331066368x, g87112285931760246646623899502532662132736x, g174224571863520493293247799005065324265472x, g348449143727040986586495598010130648530944x, g696898287454081973172991196020261297061888x, g1393796574908163946345982392040522594123776x, g2787593149816327892691964784081045188247552x, g5575186299632655785383929568162090376495104x, g11150372599265311570767859136324180752990208x, g22300745198530623141535718272648361505980416x, g44601490397061246283071436545296723011960832x, g89202980794122492566142873090593446023921664x, g178405961588244985132285746181186892047843328x, g356811923176489970264571492362373784095686656x, g713623846352979940529142984724747568191373312x, g1427247692705959881058285969449495136382746624x, g2854495385411919762116571938898990272765493248x, g5708990770823839524233143877797980545530986496x, g11417981541647679048466287755595961091061972992x, g22835963083295358096932575511191922182123945984x, g45671926166590716193865151022383844364247891968x, g91343852333181432387730302044767688728495783936x, g182687704666362864775460604089535377456991567872x, g365375409332725729550921208179070754913983135744x, g730750818665451459101842416358141509827966271488x, g1461501637330902918203684832716283019655932542976x, g2923003274661805836407369665432566039311865085952x, g5846006549323611672814739330865132078623730171904x, g11692013098647223345629478661730264157247460343808x, g23384026197294446691258957323460528314494920687616x, g46768052394588893382517914646921056628989841375232x, g93536104789177786765035829293842113257979682750464x, g187072209578355573530071658587684226515959365500928x, g374144419156711147060143317175368453031918731001856x, g748288838313422294120286634350736906063837462003712x, g1496577676626844588240573268701473812127674924007424x, g2993155353253689176481146537402947624255349848014848x, g5986310706507378352962293074805895248510699696029696x, g11972621413014756705924586149611790497021399392059392x, g23945242826029513411849172299223580994042798784118784x, g47890485652059026823698344598447161988085597568237568x, g95780971304118053647396689196894323976171195136475136x, g191561942608236107294793378393788647952342390272950272x, g383123885216472214589586756787577295904684780545900544x, g766247770432944429179173513575154591809369561091801088x, g1532495540865888858358347027150309183618739122183602176x, g3064991081731777716716694054300618367237478244367204352x, g6129982163463555433433388108601236734474956488734408704x, g12259964326927110866866776217202473468949912977468817408x, g24519928653854221733733552434404946937899825954937634816x, g49039857307708443467467104868809893875799651909875269632x, g98079714615416886934934209737619787751599303819750539264x, g196159429230833773869868419475239575503198607639501078528x, g392318858461667547739736838950479151006397215279002157056x, g784637716923335095479473677900958302012794430558004314112x, g1569275433846670190958947355801916604025588861116008628224x, g3138550867693340381917894711603833208051177722232017256448x, g6277101735386680763835789423207666416102355444464034512896x, g12554203470773361527671578846415332832204710888928069025792x, g25108406941546723055343157692830665664409421777856138051584x, g50216813883093446110686315385661331328818843555712276103168x, g100433627766186892221372630771322662657637687111424552206336x, g200867255532373784442745261542645325315275374222849104412672x, g401734511064747568885490523085290650630550748445698208825344x, g803469022129495137770981046170581301261101496891396417650688x, g1606938044258990275541962092341162602522202993782792835301376x, g3213876088517980551083924184682325205044405987565585670602752x, g6427752177035961102167848369364650410088811975131171341205504x, g12855504354071922204335696738729300820177623950262342682411008x, g25711008708143844408671393477458601640355247900524685364822016x, g51422017416287688817342786954917203280710495801049370729644032x, g102844034832575377634685573909834406561420991602098741459288064x, g205688069665150755269371147819668813122841983204197482918576128x, g411376139330301510538742295639337626245683966408394965837152256x, g822752278660603021077484591278675252491367932816789931674304512x, g1645504557321206042154969182557350504982735865633579863348609024x, g3291009114642412084309938365114701009965471731267159726697218048x, g6582018229284824168619876730229402019930943462534319453394436096x, g13164036458569648337239753460458804039861886925068638906788872192x, g26328072917139296674479506920917608079723773850137277813577744384x, g52656145834278593348959013841835216159447547700274555627155488768x, g105312291668557186697918027683670432318895095400549111254310977536x, g210624583337114373395836055367340864637790190801098222508621955072x, g421249166674228746791672110734681729275580381602196445017243910144x, g842498333348457493583344221469363458551160763204392890034487820288x, g1684996666696914987166688442938726917102321526408785780068975640576x, g3369993333393829974333376885877453834204643052817571560137951281152x, g6739986666787659948666753771754907668409286105635143120275902562304x, g13479973333575319897333507543509815336818572211270286240551805124608x, g26959946667150639794667015087019630673637144422540572481103610249216x, g53919893334301279589334030174039261347274288845081144962207220498432x, g107839786668602559178668060348078522694548577690162289924414440996864x, g215679573337205118357336120696157045389097155380324579848828881993728x, g431359146674410236714672241392314090778194310760649159697657763987456x, g862718293348820473429344482784628181556388621521298319395315527974912x, g1725436586697640946858688965569256363112777243042596638790631055949824x, g3450873173395281893717377931138512726225554486085193277581262111899648x, g6901746346790563787434755862277025452451108972170386555162524223799296x, g13803492693581127574869511724554050904902217944340773110325048447598592x, g27606985387162255149739023449108101809804435888681546220650096895197184x, g55213970774324510299478046898216203619608871777363092441300193790394368x, g110427941548649020598956093796432407239217743554726184882600387580788736x, g220855883097298041197912187592864814478435487109452369765200775161577472x, g441711766194596082395824375185729628956870974218904739530401550323154944x, g883423532389192164791648750371459257913741948437809479060803100646309888x, g1766847064778384329583297500742918515827483896875618958121606201292619776x, g3533694129556768659166595001485837031654967793751237916243212402585239552x, g7067388259113537318333190002971674063309935587502475832486424805170479104x, g14134776518227074636666380005943348126619871175004951664972849610340958208x, g28269553036454149273332760011886696253239742350009903329945699220681916416x, g56539106072908298546665520023773392506479484700019806659891398441363832832x, g113078212145816597093331040047546785012958969400039613319782796882727665664x, g226156424291633194186662080095093570025917938800079226639565593765455331328x, g452312848583266388373324160190187140051835877600158453279131187530910662656x, g904625697166532776746648320380374280103671755200316906558262375061821325312x, g1809251394333065553493296640760748560207343510400633813116524750123642650624x, g3618502788666131106986593281521497120414687020801267626233049500247285301248x, g7237005577332262213973186563042994240829374041602535252466099000494570602496x, g14474011154664524427946373126085988481658748083205070504932198000989141204992x, g28948022309329048855892746252171976963317496166410141009864396001978282409984x, g57896044618658097711785492504343953926634992332820282019728792003956564819968x, g115792089237316195423570985008687907853269984665640564039457584007913129639936x}, + Gmy: [257]*big.Int{g3y, g5y, g7y, g8y, g16y, g32y, g64y, g128y, g256y, g512y, g1024y, g2048y, g4096y, g8192y, g16384y, g32768y, g65536y, g131072y, g262144y, g524288y, g1048576y, g2097152y, g4194304y, g8388608y, g16777216y, g33554432y, g67108864y, g134217728y, g268435456y, g536870912y, g1073741824y, g2147483648y, g4294967296y, g8589934592y, g17179869184y, g34359738368y, g68719476736y, g137438953472y, g274877906944y, g549755813888y, g1099511627776y, g2199023255552y, g4398046511104y, g8796093022208y, g17592186044416y, g35184372088832y, g70368744177664y, g140737488355328y, g281474976710656y, g562949953421312y, g1125899906842624y, g2251799813685248y, g4503599627370496y, g9007199254740992y, g18014398509481984y, g36028797018963968y, g72057594037927936y, g144115188075855872y, g288230376151711744y, g576460752303423488y, g1152921504606846976y, g2305843009213693952y, g4611686018427387904y, g9223372036854775808y, g18446744073709551616y, g36893488147419103232y, g73786976294838206464y, g147573952589676412928y, g295147905179352825856y, g590295810358705651712y, g1180591620717411303424y, g2361183241434822606848y, g4722366482869645213696y, g9444732965739290427392y, g18889465931478580854784y, g37778931862957161709568y, g75557863725914323419136y, g151115727451828646838272y, g302231454903657293676544y, g604462909807314587353088y, g1208925819614629174706176y, g2417851639229258349412352y, g4835703278458516698824704y, g9671406556917033397649408y, g19342813113834066795298816y, g38685626227668133590597632y, g77371252455336267181195264y, g154742504910672534362390528y, g309485009821345068724781056y, g618970019642690137449562112y, g1237940039285380274899124224y, g2475880078570760549798248448y, g4951760157141521099596496896y, g9903520314283042199192993792y, g19807040628566084398385987584y, g39614081257132168796771975168y, g79228162514264337593543950336y, g158456325028528675187087900672y, g316912650057057350374175801344y, g633825300114114700748351602688y, g1267650600228229401496703205376y, g2535301200456458802993406410752y, g5070602400912917605986812821504y, g10141204801825835211973625643008y, g20282409603651670423947251286016y, g40564819207303340847894502572032y, g81129638414606681695789005144064y, g162259276829213363391578010288128y, g324518553658426726783156020576256y, g649037107316853453566312041152512y, g1298074214633706907132624082305024y, g2596148429267413814265248164610048y, g5192296858534827628530496329220096y, g10384593717069655257060992658440192y, g20769187434139310514121985316880384y, g41538374868278621028243970633760768y, g83076749736557242056487941267521536y, g166153499473114484112975882535043072y, g332306998946228968225951765070086144y, g664613997892457936451903530140172288y, g1329227995784915872903807060280344576y, g2658455991569831745807614120560689152y, g5316911983139663491615228241121378304y, g10633823966279326983230456482242756608y, g21267647932558653966460912964485513216y, g42535295865117307932921825928971026432y, g85070591730234615865843651857942052864y, g170141183460469231731687303715884105728y, g340282366920938463463374607431768211456y, g680564733841876926926749214863536422912y, g1361129467683753853853498429727072845824y, g2722258935367507707706996859454145691648y, g5444517870735015415413993718908291383296y, g10889035741470030830827987437816582766592y, g21778071482940061661655974875633165533184y, g43556142965880123323311949751266331066368y, g87112285931760246646623899502532662132736y, g174224571863520493293247799005065324265472y, g348449143727040986586495598010130648530944y, g696898287454081973172991196020261297061888y, g1393796574908163946345982392040522594123776y, g2787593149816327892691964784081045188247552y, g5575186299632655785383929568162090376495104y, g11150372599265311570767859136324180752990208y, g22300745198530623141535718272648361505980416y, g44601490397061246283071436545296723011960832y, g89202980794122492566142873090593446023921664y, g178405961588244985132285746181186892047843328y, g356811923176489970264571492362373784095686656y, g713623846352979940529142984724747568191373312y, g1427247692705959881058285969449495136382746624y, g2854495385411919762116571938898990272765493248y, g5708990770823839524233143877797980545530986496y, g11417981541647679048466287755595961091061972992y, g22835963083295358096932575511191922182123945984y, g45671926166590716193865151022383844364247891968y, g91343852333181432387730302044767688728495783936y, g182687704666362864775460604089535377456991567872y, g365375409332725729550921208179070754913983135744y, g730750818665451459101842416358141509827966271488y, g1461501637330902918203684832716283019655932542976y, g2923003274661805836407369665432566039311865085952y, g5846006549323611672814739330865132078623730171904y, g11692013098647223345629478661730264157247460343808y, g23384026197294446691258957323460528314494920687616y, g46768052394588893382517914646921056628989841375232y, g93536104789177786765035829293842113257979682750464y, g187072209578355573530071658587684226515959365500928y, g374144419156711147060143317175368453031918731001856y, g748288838313422294120286634350736906063837462003712y, g1496577676626844588240573268701473812127674924007424y, g2993155353253689176481146537402947624255349848014848y, g5986310706507378352962293074805895248510699696029696y, g11972621413014756705924586149611790497021399392059392y, g23945242826029513411849172299223580994042798784118784y, g47890485652059026823698344598447161988085597568237568y, g95780971304118053647396689196894323976171195136475136y, g191561942608236107294793378393788647952342390272950272y, g383123885216472214589586756787577295904684780545900544y, g766247770432944429179173513575154591809369561091801088y, g1532495540865888858358347027150309183618739122183602176y, g3064991081731777716716694054300618367237478244367204352y, g6129982163463555433433388108601236734474956488734408704y, g12259964326927110866866776217202473468949912977468817408y, g24519928653854221733733552434404946937899825954937634816y, g49039857307708443467467104868809893875799651909875269632y, g98079714615416886934934209737619787751599303819750539264y, g196159429230833773869868419475239575503198607639501078528y, g392318858461667547739736838950479151006397215279002157056y, g784637716923335095479473677900958302012794430558004314112y, g1569275433846670190958947355801916604025588861116008628224y, g3138550867693340381917894711603833208051177722232017256448y, g6277101735386680763835789423207666416102355444464034512896y, g12554203470773361527671578846415332832204710888928069025792y, g25108406941546723055343157692830665664409421777856138051584y, g50216813883093446110686315385661331328818843555712276103168y, g100433627766186892221372630771322662657637687111424552206336y, g200867255532373784442745261542645325315275374222849104412672y, g401734511064747568885490523085290650630550748445698208825344y, g803469022129495137770981046170581301261101496891396417650688y, g1606938044258990275541962092341162602522202993782792835301376y, g3213876088517980551083924184682325205044405987565585670602752y, g6427752177035961102167848369364650410088811975131171341205504y, g12855504354071922204335696738729300820177623950262342682411008y, g25711008708143844408671393477458601640355247900524685364822016y, g51422017416287688817342786954917203280710495801049370729644032y, g102844034832575377634685573909834406561420991602098741459288064y, g205688069665150755269371147819668813122841983204197482918576128y, g411376139330301510538742295639337626245683966408394965837152256y, g822752278660603021077484591278675252491367932816789931674304512y, g1645504557321206042154969182557350504982735865633579863348609024y, g3291009114642412084309938365114701009965471731267159726697218048y, g6582018229284824168619876730229402019930943462534319453394436096y, g13164036458569648337239753460458804039861886925068638906788872192y, g26328072917139296674479506920917608079723773850137277813577744384y, g52656145834278593348959013841835216159447547700274555627155488768y, g105312291668557186697918027683670432318895095400549111254310977536y, g210624583337114373395836055367340864637790190801098222508621955072y, g421249166674228746791672110734681729275580381602196445017243910144y, g842498333348457493583344221469363458551160763204392890034487820288y, g1684996666696914987166688442938726917102321526408785780068975640576y, g3369993333393829974333376885877453834204643052817571560137951281152y, g6739986666787659948666753771754907668409286105635143120275902562304y, g13479973333575319897333507543509815336818572211270286240551805124608y, g26959946667150639794667015087019630673637144422540572481103610249216y, g53919893334301279589334030174039261347274288845081144962207220498432y, g107839786668602559178668060348078522694548577690162289924414440996864y, g215679573337205118357336120696157045389097155380324579848828881993728y, g431359146674410236714672241392314090778194310760649159697657763987456y, g862718293348820473429344482784628181556388621521298319395315527974912y, g1725436586697640946858688965569256363112777243042596638790631055949824y, g3450873173395281893717377931138512726225554486085193277581262111899648y, g6901746346790563787434755862277025452451108972170386555162524223799296y, g13803492693581127574869511724554050904902217944340773110325048447598592y, g27606985387162255149739023449108101809804435888681546220650096895197184y, g55213970774324510299478046898216203619608871777363092441300193790394368y, g110427941548649020598956093796432407239217743554726184882600387580788736y, g220855883097298041197912187592864814478435487109452369765200775161577472y, g441711766194596082395824375185729628956870974218904739530401550323154944y, g883423532389192164791648750371459257913741948437809479060803100646309888y, g1766847064778384329583297500742918515827483896875618958121606201292619776y, g3533694129556768659166595001485837031654967793751237916243212402585239552y, g7067388259113537318333190002971674063309935587502475832486424805170479104y, g14134776518227074636666380005943348126619871175004951664972849610340958208y, g28269553036454149273332760011886696253239742350009903329945699220681916416y, g56539106072908298546665520023773392506479484700019806659891398441363832832y, g113078212145816597093331040047546785012958969400039613319782796882727665664y, g226156424291633194186662080095093570025917938800079226639565593765455331328y, g452312848583266388373324160190187140051835877600158453279131187530910662656y, g904625697166532776746648320380374280103671755200316906558262375061821325312y, g1809251394333065553493296640760748560207343510400633813116524750123642650624y, g3618502788666131106986593281521497120414687020801267626233049500247285301248y, g7237005577332262213973186563042994240829374041602535252466099000494570602496y, g14474011154664524427946373126085988481658748083205070504932198000989141204992y, g28948022309329048855892746252171976963317496166410141009864396001978282409984y, g57896044618658097711785492504343953926634992332820282019728792003956564819968y, g115792089237316195423570985008687907853269984665640564039457584007913129639936y}, } } diff --git a/std/algebra/weierstrass/point.go b/std/algebra/weierstrass/point.go index 5106658797..c173805600 100644 --- a/std/algebra/weierstrass/point.go +++ b/std/algebra/weierstrass/point.go @@ -23,8 +23,8 @@ func New[Base, Scalars emulated.FieldParams](api frontend.API, params CurveParam } Gx := emulated.ValueOf[Base](params.Gx) Gy := emulated.ValueOf[Base](params.Gy) - G2x := emulated.ValueOf[Base](params.Gmx[0]) - G2y := emulated.ValueOf[Base](params.Gmy[0]) + G3x := emulated.ValueOf[Base](params.Gmx[0]) + G3y := emulated.ValueOf[Base](params.Gmy[0]) G4x := emulated.ValueOf[Base](params.Gmx[1]) G4y := emulated.ValueOf[Base](params.Gmy[1]) G8x := emulated.ValueOf[Base](params.Gmx[2]) @@ -545,7 +545,7 @@ func New[Base, Scalars emulated.FieldParams](api frontend.API, params CurveParam Y: Gy, }, gm: [256]AffinePoint[Base]{ - {X: G2x, Y: G2y}, + {X: G3x, Y: G3y}, {X: G4x, Y: G4y}, {X: G8x, Y: G8y}, {X: G16x, Y: G16y}, @@ -861,93 +861,93 @@ func (c *Curve[B, S]) AssertIsEqual(p, q *AffinePoint[B]) { c.baseApi.AssertIsEqual(&p.Y, &q.Y) } -// Add adds q and r and returns it. -func (c *Curve[B, S]) Add(q, r *AffinePoint[B]) *AffinePoint[B] { - // compute lambda = (p1.y-p.y)/(p1.x-p.x) - p1ypy := c.baseApi.Sub(&r.Y, &q.Y) - p1xpx := c.baseApi.Sub(&r.X, &q.X) - lambda := c.baseApi.Div(p1ypy, p1xpx) +// Add adds p and q and returns it. +func (c *Curve[B, S]) Add(p, q *AffinePoint[B]) *AffinePoint[B] { + // compute λ = (q.y-p.y)/(q.x-p.x) + qypy := c.baseApi.Sub(&q.Y, &p.Y) + qxpx := c.baseApi.Sub(&q.X, &p.X) + λ := c.baseApi.Div(qypy, qxpx) - // xr = lambda**2-p.x-p1.x - lambdaSq := c.baseApi.MulMod(lambda, lambda) - qxrx := c.baseApi.Add(&q.X, &r.X) - xr := c.baseApi.Sub(lambdaSq, qxrx) + // xr = λ²-p.x-q.x + λλ := c.baseApi.MulMod(λ, λ) + qxpx = c.baseApi.Add(&p.X, &q.X) + xr := c.baseApi.Sub(λλ, qxpx) - // p.y = lambda(p.x-xr) - p.y - pxxr := c.baseApi.Sub(&q.X, xr) - lpxxr := c.baseApi.MulMod(lambda, pxxr) - py := c.baseApi.Sub(lpxxr, &q.Y) + // p.y = λ(p.x-r.x) - p.y + pxrx := c.baseApi.Sub(&p.X, xr) + λpxrx := c.baseApi.MulMod(λ, pxrx) + yr := c.baseApi.Sub(λpxrx, &p.Y) return &AffinePoint[B]{ X: *c.baseApi.Reduce(xr), - Y: *c.baseApi.Reduce(py), + Y: *c.baseApi.Reduce(yr), } } // Double doubles p and return it. It doesn't modify p. func (c *Curve[B, S]) Double(p *AffinePoint[B]) *AffinePoint[B] { - // compute lambda = (3*p1.x**2+a)/2*p1.y, here we assume a=0 (j invariant 0 curve) - xSq3a := c.baseApi.MulMod(&p.X, &p.X) - xSq3a = c.baseApi.MulConst(xSq3a, big.NewInt(3)) + // compute λ = (3p.x²+a)/2*p.y, here we assume a=0 (j invariant 0 curve) + xx3a := c.baseApi.MulMod(&p.X, &p.X) + xx3a = c.baseApi.MulConst(xx3a, big.NewInt(3)) if c.addA { - xSq3a = c.baseApi.Add(xSq3a, &c.a) + xx3a = c.baseApi.Add(xx3a, &c.a) } y2 := c.baseApi.MulConst(&p.Y, big.NewInt(2)) - lambda := c.baseApi.Div(xSq3a, y2) + λ := c.baseApi.Div(xx3a, y2) - // xr = lambda**2-p1.x-p1.x + // xr = λ²-2p.x x2 := c.baseApi.MulConst(&p.X, big.NewInt(2)) - lambdaSq := c.baseApi.MulMod(lambda, lambda) - xr := c.baseApi.Sub(lambdaSq, x2) + λλ := c.baseApi.MulMod(λ, λ) + xr := c.baseApi.Sub(λλ, x2) - // p.y = lambda(p.x-xr) - p.y - pxxr := c.baseApi.Sub(&p.X, xr) - lpxxr := c.baseApi.MulMod(lambda, pxxr) - py := c.baseApi.Sub(lpxxr, &p.Y) + // yr = λ(p-xr) - p.y + pxrx := c.baseApi.Sub(&p.X, xr) + λpxrx := c.baseApi.MulMod(λ, pxrx) + yr := c.baseApi.Sub(λpxrx, &p.Y) return &AffinePoint[B]{ X: *c.baseApi.Reduce(xr), - Y: *c.baseApi.Reduce(py), + Y: *c.baseApi.Reduce(yr), } } // Triple triples p and return it. It doesn't modify p. func (c *Curve[B, S]) Triple(p *AffinePoint[B]) *AffinePoint[B] { - // compute lambda = (3*p1.x**2+a)/2*p1.y, here we assume a=0 (j invariant 0 curve) + // compute λ1 = (3p.x²+a)/2p.y, here we assume a=0 (j invariant 0 curve) xx := c.baseApi.MulMod(&p.X, &p.X) xx = c.baseApi.MulConst(xx, big.NewInt(3)) if c.addA { xx = c.baseApi.Add(xx, &c.a) } y2 := c.baseApi.MulConst(&p.Y, big.NewInt(2)) - lambda := c.baseApi.Div(xx, y2) + λ1 := c.baseApi.Div(xx, y2) - // xr = lambda**2-p1.x-p1.x + // xr = λ1²-2p.x x2 := c.baseApi.MulConst(&p.X, big.NewInt(2)) - lambdaSq := c.baseApi.MulMod(lambda, lambda) - x2 = c.baseApi.Sub(lambdaSq, x2) + λ1λ1 := c.baseApi.MulMod(λ1, λ1) + x2 = c.baseApi.Sub(λ1λ1, x2) - // compute lambda = (p1.y-p.y)/(p1.x-p.x) - // λ2 = 2y1/(x3 − x1) − λ1. + // ommit y2 computation, and + // compute λ2 = 2p.y/(x2 − p.x) − λ1. x1x2 := c.baseApi.Sub(&p.X, x2) - lambda2 := c.baseApi.Div(y2, x1x2) - lambda2 = c.baseApi.Sub(lambda2, lambda) + λ2 := c.baseApi.Div(y2, x1x2) + λ2 = c.baseApi.Sub(λ2, λ1) - // xr = lambda**2-p.x-p1.x - lambdaSq = c.baseApi.MulMod(lambda2, lambda2) + // xr = λ²-p.x-x2 + λ2λ2 := c.baseApi.MulMod(λ2, λ2) qxrx := c.baseApi.Add(x2, &p.X) - x3 := c.baseApi.Sub(lambdaSq, qxrx) + xr := c.baseApi.Sub(λ2λ2, qxrx) - // p.y = lambda(p.x-xr) - p.y - pxxr := c.baseApi.Sub(&p.X, x3) - lpxxr := c.baseApi.MulMod(lambda2, pxxr) - y3 := c.baseApi.Sub(lpxxr, &p.Y) + // yr = λ(p.x-xr) - p.y + pxrx := c.baseApi.Sub(&p.X, xr) + λ2pxrx := c.baseApi.MulMod(λ2, pxrx) + yr := c.baseApi.Sub(λ2pxrx, &p.Y) return &AffinePoint[B]{ - X: *c.baseApi.Reduce(x3), - Y: *c.baseApi.Reduce(y3), + X: *c.baseApi.Reduce(xr), + Y: *c.baseApi.Reduce(yr), } } @@ -962,6 +962,18 @@ func (c *Curve[B, S]) Select(b frontend.Variable, p, q *AffinePoint[B]) *AffineP } } +// Lookup2 performs a 2-bit lookup between i0, i1, i2, i3 based on bits b0 +// and b1. Returns i0 if b0=b1=0, i1 if b0=1 and b1=0, i2 if b0=0 and b1=1 +// and i3 if b0=b1=1. +func (c *Curve[B, S]) Lookup2(b0, b1 frontend.Variable, i0, i1, i2, i3 *AffinePoint[B]) *AffinePoint[B] { + x := c.baseApi.Lookup2(b0, b1, &i0.X, &i1.X, &i2.X, &i3.X) + y := c.baseApi.Lookup2(b0, b1, &i0.Y, &i1.Y, &i2.Y, &i3.Y) + return &AffinePoint[B]{ + X: *x, + Y: *y, + } +} + // ScalarMul computes s * p and returns it. It doesn't modify p nor s. func (c *Curve[B, S]) ScalarMul(p *AffinePoint[B], s *emulated.Element[S]) *AffinePoint[B] { var st S @@ -988,14 +1000,18 @@ func (c *Curve[B, S]) ScalarMul(p *AffinePoint[B], s *emulated.Element[S]) *Affi func (c *Curve[B, S]) ScalarMulBase(s *emulated.Element[S]) *AffinePoint[B] { g := c.Generator() gm := c.GeneratorMultiples() - res := g var st S sr := c.scalarApi.Reduce(s) sBits := c.scalarApi.ToBits(sr) - for i := 1; i < st.Modulus().BitLen(); i++ { - tmp := c.Add(res, &gm[i-1]) + // i = 1, 2 + // gm[0] = 3g, gm[0] = 5g, gm[0] = 7g + res := c.Lookup2(sBits[1], sBits[2], g, &gm[0], &gm[1], &gm[2]) + + for i := 3; i < st.Modulus().BitLen(); i++ { + // gm[i] = [2^i]g + tmp := c.Add(res, &gm[i]) res = c.Select(sBits[i], tmp, res) } From 6461e1ef14480336ae901a7baea8495556c48245 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Sun, 12 Feb 2023 14:13:14 +0100 Subject: [PATCH 005/464] perf(scalarMul): saves computation in last two iterations --- std/algebra/weierstrass/point.go | 64 ++++++++++++++++++++- std/algebra/weierstrass/point_test.go | 81 +++++++++++++++++++++++++++ 2 files changed, 142 insertions(+), 3 deletions(-) diff --git a/std/algebra/weierstrass/point.go b/std/algebra/weierstrass/point.go index c173805600..4696f516f8 100644 --- a/std/algebra/weierstrass/point.go +++ b/std/algebra/weierstrass/point.go @@ -861,7 +861,7 @@ func (c *Curve[B, S]) AssertIsEqual(p, q *AffinePoint[B]) { c.baseApi.AssertIsEqual(&p.Y, &q.Y) } -// Add adds p and q and returns it. +// Add adds p and q and returns it. It doesn't modify p nor q. func (c *Curve[B, S]) Add(p, q *AffinePoint[B]) *AffinePoint[B] { // compute λ = (q.y-p.y)/(q.x-p.x) qypy := c.baseApi.Sub(&q.Y, &p.Y) @@ -912,7 +912,11 @@ func (c *Curve[B, S]) Double(p *AffinePoint[B]) *AffinePoint[B] { } } -// Triple triples p and return it. It doesn't modify p. +// Triple triples p and return it. +// It follows [ELM03]: https://arxiv.org/pdf/math/0208038.pdf, 3.1 +// Saves the computation of the y coordinate of 2p as it is used only in the computation of λ2, +// which can be computed as λ2 = -λ1-2*p.y/(x2-p.x) instead. +// It doesn't modify p. func (c *Curve[B, S]) Triple(p *AffinePoint[B]) *AffinePoint[B] { // compute λ1 = (3p.x²+a)/2p.y, here we assume a=0 (j invariant 0 curve) @@ -951,6 +955,47 @@ func (c *Curve[B, S]) Triple(p *AffinePoint[B]) *AffinePoint[B] { } } +// DoubleAndAdd computes 2p+q as (p+q)+p. It follows [ELM03]: https://arxiv.org/pdf/math/0208038.pdf, 3.1 +// Saves the computation of the y coordinate of p+q as it is used only in the computation of λ2, +// which can be computed as λ2 = -λ1-2*p.y/(x2-p.x) instead. +// It doesn't modify p nor q. +func (c *Curve[B, S]) DoubleAndAdd(p, q *AffinePoint[B]) *AffinePoint[B] { + + // compute λ1 = (q.y-p.y)/(q.x-p.x) + yqyp := c.baseApi.Sub(&q.Y, &p.Y) + xqxp := c.baseApi.Sub(&q.X, &p.X) + λ1 := c.baseApi.Div(yqyp, xqxp) + + // compute x2 = λ1²-p.x-q.x + λ1λ1 := c.baseApi.MulMod(λ1, λ1) + xqxp = c.baseApi.Add(&p.X, &q.X) + x2 := c.baseApi.Sub(λ1λ1, xqxp) + + // ommit y2 computation + // compute λ2 = -λ1-2*p.y/(x2-p.x) + ypyp := c.baseApi.Add(&p.Y, &p.Y) + x2xp := c.baseApi.Sub(x2, &p.X) + λ2 := c.baseApi.Div(ypyp, x2xp) + λ2 = c.baseApi.Add(λ1, λ2) + λ2 = c.baseApi.Neg(λ2) + + // compute x3 =λ2²-p.x-x3 + λ2λ2 := c.baseApi.MulMod(λ2, λ2) + x3 := c.baseApi.Sub(λ2λ2, &p.X) + x3 = c.baseApi.Sub(x3, x2) + + // compute y3 = λ2*(p.x - x3)-p.y + y3 := c.baseApi.Sub(&p.X, x3) + y3 = c.baseApi.Mul(λ2, y3) + y3 = c.baseApi.Sub(y3, &p.Y) + + return &AffinePoint[B]{ + X: *c.baseApi.Reduce(x3), + Y: *c.baseApi.Reduce(y3), + } + +} + // Select selects between p and q given the selector b. If b == 0, then returns // p and q otherwise. func (c *Curve[B, S]) Select(b frontend.Variable, p, q *AffinePoint[B]) *AffinePoint[B] { @@ -979,20 +1024,31 @@ func (c *Curve[B, S]) ScalarMul(p *AffinePoint[B], s *emulated.Element[S]) *Affi var st S sr := c.scalarApi.Reduce(s) sBits := c.scalarApi.ToBits(sr) + n := st.Modulus().BitLen() // i = 1 tmp := c.Triple(p) res := c.Select(sBits[1], tmp, p) acc := c.Add(tmp, p) - for i := 2; i < st.Modulus().BitLen(); i++ { + for i := 2; i <= n-3; i++ { tmp := c.Add(res, acc) res = c.Select(sBits[i], tmp, res) acc = c.Double(acc) } + // i = n-2 + tmp = c.Add(res, acc) + res = c.Select(sBits[n-2], tmp, res) + + // i = n-1 + tmp = c.DoubleAndAdd(acc, res) + res = c.Select(sBits[n-1], tmp, res) + + // i = 0 tmp = c.Add(res, c.Neg(p)) res = c.Select(sBits[0], res, tmp) + return res } @@ -1015,7 +1071,9 @@ func (c *Curve[B, S]) ScalarMulBase(s *emulated.Element[S]) *AffinePoint[B] { res = c.Select(sBits[i], tmp, res) } + // i =0 tmp := c.Add(res, c.Neg(g)) res = c.Select(sBits[0], res, tmp) + return res } diff --git a/std/algebra/weierstrass/point_test.go b/std/algebra/weierstrass/point_test.go index 4778db0ac0..bf34b740ce 100644 --- a/std/algebra/weierstrass/point_test.go +++ b/std/algebra/weierstrass/point_test.go @@ -129,6 +129,87 @@ func TestDouble(t *testing.T) { assert.NoError(err) } +type TripleTest[T, S emulated.FieldParams] struct { + P, Q AffinePoint[T] +} + +func (c *TripleTest[T, S]) Define(api frontend.API) error { + cr, err := New[T, S](api, GetCurveParams[T]()) + if err != nil { + return err + } + res := cr.Triple(&c.P) + cr.AssertIsEqual(res, &c.Q) + return nil +} + +func TestTriple(t *testing.T) { + assert := test.NewAssert(t) + g, _ := secp256k1.Generators() + var dJac secp256k1.G1Jac + dJac.Double(&g).AddAssign(&g) + var dAff secp256k1.G1Affine + dAff.FromJacobian(&dJac) + circuit := TripleTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{} + witness := TripleTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ + P: AffinePoint[emulated.Secp256k1Fp]{ + X: emulated.ValueOf[emulated.Secp256k1Fp](g.X), + Y: emulated.ValueOf[emulated.Secp256k1Fp](g.Y), + }, + Q: AffinePoint[emulated.Secp256k1Fp]{ + X: emulated.ValueOf[emulated.Secp256k1Fp](dAff.X), + Y: emulated.ValueOf[emulated.Secp256k1Fp](dAff.Y), + }, + } + err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) + assert.NoError(err) +} + +type DoubleAndAddTest[T, S emulated.FieldParams] struct { + P, Q, R AffinePoint[T] +} + +func (c *DoubleAndAddTest[T, S]) Define(api frontend.API) error { + cr, err := New[T, S](api, GetCurveParams[T]()) + if err != nil { + return err + } + res := cr.DoubleAndAdd(&c.P, &c.Q) + cr.AssertIsEqual(res, &c.R) + return nil +} + +func TestDoubleAndAdd(t *testing.T) { + assert := test.NewAssert(t) + var pJac, qJac, rJac secp256k1.G1Jac + g, _ := secp256k1.Generators() + pJac.Double(&g) + qJac.Set(&g) + rJac.Double(&pJac). + AddAssign(&qJac) + var pAff, qAff, rAff secp256k1.G1Affine + pAff.FromJacobian(&pJac) + qAff.FromJacobian(&qJac) + rAff.FromJacobian(&rJac) + circuit := DoubleAndAddTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{} + witness := DoubleAndAddTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ + P: AffinePoint[emulated.Secp256k1Fp]{ + X: emulated.ValueOf[emulated.Secp256k1Fp](pAff.X), + Y: emulated.ValueOf[emulated.Secp256k1Fp](pAff.Y), + }, + Q: AffinePoint[emulated.Secp256k1Fp]{ + X: emulated.ValueOf[emulated.Secp256k1Fp](qAff.X), + Y: emulated.ValueOf[emulated.Secp256k1Fp](qAff.Y), + }, + R: AffinePoint[emulated.Secp256k1Fp]{ + X: emulated.ValueOf[emulated.Secp256k1Fp](rAff.X), + Y: emulated.ValueOf[emulated.Secp256k1Fp](rAff.Y), + }, + } + err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) + assert.NoError(err) +} + type ScalarMulBaseTest[T, S emulated.FieldParams] struct { Q AffinePoint[T] S emulated.Element[S] From 598414e8e4baf069af5eb6e0e863a8fc59400e1b Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Fri, 17 Feb 2023 19:55:01 +0100 Subject: [PATCH 006/464] fix: update version (#477) --- doc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc.go b/doc.go index 84ae2e9545..b871010f37 100644 --- a/doc.go +++ b/doc.go @@ -22,7 +22,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" ) -var Version = semver.MustParse("0.8.0-alpha") +var Version = semver.MustParse("0.8.1-alpha") // Curves return the curves supported by gnark func Curves() []ecc.ID { From daa9b14e8e0a64f64f80b75ff9cb4d73412b1de9 Mon Sep 17 00:00:00 2001 From: Behrouz Date: Tue, 21 Feb 2023 02:16:43 +0330 Subject: [PATCH 007/464] feat: add n to 1 MUX and MAP (#475) * feat: update gnark version to v0.8.0 * Add an n to 1 multiplexer This commit adds a simple n to 1 multiplexer to the std lib. This multiplexer is based on non-deterministic advice. * Improve tests for `multiplexer.go` Old tests were dependant to outputs and were not able to test invalid inputs correctly. * Refactor multiplexer test * Add a key value lookup table * Change some names A lookup table usually uses indices and not keys, so we renamed `Lookup` to `Map`. We also renamed the `gadgets` package to `selector`. * docs: add examples into documentation * docs: add package documentation * docs: describe hint functions * docs: remove profiling example * refactor: rename 'sel' to 'queryKey' * docs: correct typos --------- Co-authored-by: Gautam Botrel Co-authored-by: Ivo Kubjas --- std/hints.go | 3 + std/selector/doc_map_test.go | 79 ++++++++++++++ std/selector/doc_mux_test.go | 77 ++++++++++++++ std/selector/multiplexer.go | 114 ++++++++++++++++++++ std/selector/multiplexer_test.go | 177 +++++++++++++++++++++++++++++++ 5 files changed, 450 insertions(+) create mode 100644 std/selector/doc_map_test.go create mode 100644 std/selector/doc_mux_test.go create mode 100644 std/selector/multiplexer.go create mode 100644 std/selector/multiplexer_test.go diff --git a/std/hints.go b/std/hints.go index 8fc1222781..b4b16ae52f 100644 --- a/std/hints.go +++ b/std/hints.go @@ -8,6 +8,7 @@ import ( "github.com/consensys/gnark/std/algebra/sw_bls24315" "github.com/consensys/gnark/std/math/bits" "github.com/consensys/gnark/std/math/emulated" + "github.com/consensys/gnark/std/selector" ) var registerOnce sync.Once @@ -30,5 +31,7 @@ func registerHints() { hint.Register(bits.NNAF) hint.Register(bits.IthBit) hint.Register(bits.NBits) + hint.Register(selector.MuxIndicators) + hint.Register(selector.MapIndicators) hint.Register(emulated.GetHints()...) } diff --git a/std/selector/doc_map_test.go b/std/selector/doc_map_test.go new file mode 100644 index 0000000000..f70c353f61 --- /dev/null +++ b/std/selector/doc_map_test.go @@ -0,0 +1,79 @@ +package selector_test + +import ( + "fmt" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/backend/groth16" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/std/selector" +) + +// MapCircuit is a minimal circuit using a selector map. +type MapCircuit struct { + QueryKey frontend.Variable + Keys [10]frontend.Variable // we use array in witness to allocate sufficiently sized vector + Values [10]frontend.Variable // we use array in witness to allocate sufficiently sized vector + ExpectedValue frontend.Variable +} + +// Define defines the arithmetic circuit. +func (c *MapCircuit) Define(api frontend.API) error { + result := selector.Map(api, c.QueryKey, c.Keys[:], c.Values[:]) + api.AssertIsEqual(result, c.ExpectedValue) + return nil +} + +// ExampleMap gives an example on how to use map selector. +func ExampleMap() { + circuit := MapCircuit{} + witness := MapCircuit{ + QueryKey: 55, + Keys: [10]frontend.Variable{0, 11, 22, 33, 44, 55, 66, 77, 88, 99}, + Values: [10]frontend.Variable{0, 2, 4, 6, 8, 10, 12, 14, 16, 18}, + ExpectedValue: 10, // element in values which corresponds to the position of 55 in keys + } + ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) + if err != nil { + panic(err) + } else { + fmt.Println("compiled") + } + pk, vk, err := groth16.Setup(ccs) + if err != nil { + panic(err) + } else { + fmt.Println("setup done") + } + secretWitness, err := frontend.NewWitness(&witness, ecc.BN254.ScalarField()) + if err != nil { + panic(err) + } else { + fmt.Println("secret witness") + } + publicWitness, err := secretWitness.Public() + if err != nil { + panic(err) + } else { + fmt.Println("public witness") + } + proof, err := groth16.Prove(ccs, pk, secretWitness) + if err != nil { + panic(err) + } else { + fmt.Println("proof") + } + err = groth16.Verify(proof, vk, publicWitness) + if err != nil { + panic(err) + } else { + fmt.Println("verify") + } + // Output: compiled + // setup done + // secret witness + // public witness + // proof + // verify +} diff --git a/std/selector/doc_mux_test.go b/std/selector/doc_mux_test.go new file mode 100644 index 0000000000..5a7b75ba36 --- /dev/null +++ b/std/selector/doc_mux_test.go @@ -0,0 +1,77 @@ +package selector_test + +import ( + "fmt" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/backend/groth16" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/std/selector" +) + +// MuxCircuit is a minimal circuit using a selector mux. +type MuxCircuit struct { + Selector frontend.Variable + In [10]frontend.Variable // we use array in witness to allocate sufficiently sized vector + Expected frontend.Variable +} + +// Define defines the arithmetic circuit. +func (c *MuxCircuit) Define(api frontend.API) error { + result := selector.Mux(api, c.Selector, c.In[:]...) // Note Mux takes var-arg input, need to expand the input vector + api.AssertIsEqual(result, c.Expected) + return nil +} + +// ExampleMux gives an example on how to use mux selector. +func ExampleMux() { + circuit := MuxCircuit{} + witness := MuxCircuit{ + Selector: 5, + In: [10]frontend.Variable{0, 2, 4, 6, 8, 10, 12, 14, 16, 18}, + Expected: 10, // 5-th element in vector + } + ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) + if err != nil { + panic(err) + } else { + fmt.Println("compiled") + } + pk, vk, err := groth16.Setup(ccs) + if err != nil { + panic(err) + } else { + fmt.Println("setup done") + } + secretWitness, err := frontend.NewWitness(&witness, ecc.BN254.ScalarField()) + if err != nil { + panic(err) + } else { + fmt.Println("secret witness") + } + publicWitness, err := secretWitness.Public() + if err != nil { + panic(err) + } else { + fmt.Println("public witness") + } + proof, err := groth16.Prove(ccs, pk, secretWitness) + if err != nil { + panic(err) + } else { + fmt.Println("proof") + } + err = groth16.Verify(proof, vk, publicWitness) + if err != nil { + panic(err) + } else { + fmt.Println("verify") + } + // Output: compiled + // setup done + // secret witness + // public witness + // proof + // verify +} diff --git a/std/selector/multiplexer.go b/std/selector/multiplexer.go new file mode 100644 index 0000000000..8e9bec5003 --- /dev/null +++ b/std/selector/multiplexer.go @@ -0,0 +1,114 @@ +// Package selector provides a lookup table and map based on linear scan. +// +// The native [frontend.API] provides 1- and 2-bit lookups through the interface +// methods Select and Lookup2. This package extends the lookups to +// arbitrary-sized vectors. The lookups can be performed using the index of the +// elements (function [Mux]) or using a key, for which the user needs to provide +// the slice of keys (function [Map]). +// +// The implementation uses linear scan over all inputs, so the constraint count +// for every invocation of the function is C*len(values)+1, where: +// - for R1CS, C = 3 +// - for PLONK, C = 5 +package selector + +import ( + "math/big" + + "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/frontend" +) + +func init() { + // register hints + hint.Register(MuxIndicators) + hint.Register(MapIndicators) +} + +// Map is a key value associative array: the output will be values[i] such that keys[i] == queryKey. If keys does not +// contain queryKey, no proofs can be generated. If keys has more than one key that equals to queryKey, the output will +// be undefined, and the output could be a linear combination of all the corresponding values with that queryKey. +// +// In case keys and values do not have the same length, this function will panic. +func Map(api frontend.API, queryKey frontend.Variable, + keys []frontend.Variable, values []frontend.Variable) frontend.Variable { + // we don't need this check, but we added it to produce more informative errors and disallow + // len(keys) < len(values) which is supported by generateSelector. + if len(keys) != len(values) { + panic("The number of keys and values must be equal") + } + return generateSelector(api, false, queryKey, keys, values) +} + +// Mux is an n to 1 multiplexer: out = inputs[sel]. In other words, it selects exactly one of its +// inputs based on sel. The index of inputs starts from zero. +// +// sel needs to be between 0 and n - 1 (inclusive), where n is the number of inputs, otherwise the proof will fail. +func Mux(api frontend.API, sel frontend.Variable, inputs ...frontend.Variable) frontend.Variable { + return generateSelector(api, true, sel, nil, inputs) +} + +// generateSelector generates a circuit for a multiplexer or an associative array (map). If wantMux is true, a +// multiplexer is generated and keys are ignored. If wantMux is false, a map is generated, and we must have +// len(keys) <= len(values), or it panics. +func generateSelector(api frontend.API, wantMux bool, sel frontend.Variable, + keys []frontend.Variable, values []frontend.Variable) (out frontend.Variable) { + + var indicators []frontend.Variable + if wantMux { + indicators, _ = api.Compiler().NewHint(MuxIndicators, len(values), sel) + } else { + indicators, _ = api.Compiler().NewHint(MapIndicators, len(keys), append(keys, sel)...) + } + + out = 0 + indicatorsSum := frontend.Variable(0) + for i := 0; i < len(indicators); i++ { + // Check that all indicators for inputs that are not selected, are zero. + if wantMux { + // indicators[i] * (sel - i) == 0 + api.AssertIsEqual(api.Mul(indicators[i], api.Sub(sel, i)), 0) + } else { + // indicators[i] * (sel - keys[i]) == 0 + api.AssertIsEqual(api.Mul(indicators[i], api.Sub(sel, keys[i])), 0) + } + indicatorsSum = api.Add(indicatorsSum, indicators[i]) + // out += indicators[i] * values[i] + out = api.MulAcc(out, indicators[i], values[i]) + } + // We need to check that the indicator of the selected input is exactly 1. We used a sum constraint, because usually + // it is cheap. + api.AssertIsEqual(indicatorsSum, 1) + return out +} + +// MuxIndicators is a hint function used within [Mux] function. It must be +// provided to the prover when circuit uses it. +func MuxIndicators(_ *big.Int, inputs []*big.Int, results []*big.Int) error { + sel := inputs[0] + for i := 0; i < len(results); i++ { + // i is an int which can be int32 or int64. We convert i to int64 then to bigInt, which is safe. We should + // not convert sel to int64. + if sel.Cmp(big.NewInt(int64(i))) == 0 { + results[i].SetUint64(1) + } else { + results[i].SetUint64(0) + } + } + return nil +} + +// MapIndicators is a hint function used within [Map] function. It must be +// provided to the prover when circuit uses it. +func MapIndicators(_ *big.Int, inputs []*big.Int, results []*big.Int) error { + key := inputs[len(inputs)-1] + // We must make sure that we are initializing all elements of results + for i := 0; i < len(results); i++ { + if key.Cmp(inputs[i]) == 0 { + results[i].SetUint64(1) + } else { + results[i].SetUint64(0) + } + } + return nil +} diff --git a/std/selector/multiplexer_test.go b/std/selector/multiplexer_test.go new file mode 100644 index 0000000000..a0233205d1 --- /dev/null +++ b/std/selector/multiplexer_test.go @@ -0,0 +1,177 @@ +package selector_test + +import ( + "testing" + + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/selector" + "github.com/consensys/gnark/test" +) + +type muxCircuit struct { + SEL frontend.Variable + I0, I1, I2, I3, I4 frontend.Variable + OUT frontend.Variable +} + +func (c *muxCircuit) Define(api frontend.API) error { + + out := selector.Mux(api, c.SEL, c.I0, c.I1, c.I2, c.I3, c.I4) + + api.AssertIsEqual(out, c.OUT) + + return nil +} + +// The output of this circuit is ignored and the only way its proof can fail is by providing invalid inputs. +type ignoredOutputMuxCircuit struct { + SEL frontend.Variable + I0, I1, I2 frontend.Variable +} + +func (c *ignoredOutputMuxCircuit) Define(api frontend.API) error { + // We ignore the output + _ = selector.Mux(api, c.SEL, c.I0, c.I1, c.I2) + + return nil +} + +func TestMux(t *testing.T) { + assert := test.NewAssert(t) + + assert.ProverSucceeded(&muxCircuit{}, &muxCircuit{SEL: 2, I0: 10, I1: 11, I2: 12, I3: 13, I4: 14, OUT: 12}) + + assert.ProverSucceeded(&muxCircuit{}, &muxCircuit{SEL: 0, I0: 10, I1: 11, I2: 12, I3: 13, I4: 14, OUT: 10}) + + assert.ProverSucceeded(&muxCircuit{}, &muxCircuit{SEL: 4, I0: 20, I1: 21, I2: 22, I3: 23, I4: 24, OUT: 24}) + + // Failures + assert.ProverFailed(&muxCircuit{}, &muxCircuit{SEL: 5, I0: 20, I1: 21, I2: 22, I3: 23, I4: 24, OUT: 24}) + + assert.ProverFailed(&muxCircuit{}, &muxCircuit{SEL: 0, I0: 20, I1: 21, I2: 22, I3: 23, I4: 24, OUT: 21}) + + // Ignoring the circuit's output: + assert.ProverSucceeded(&ignoredOutputMuxCircuit{}, &ignoredOutputMuxCircuit{SEL: 0, I0: 0, I1: 1, I2: 2}) + + assert.ProverSucceeded(&ignoredOutputMuxCircuit{}, &ignoredOutputMuxCircuit{SEL: 2, I0: 0, I1: 1, I2: 2}) + + // Failures + assert.ProverFailed(&ignoredOutputMuxCircuit{}, &ignoredOutputMuxCircuit{SEL: 3, I0: 0, I1: 1, I2: 2}) + + assert.ProverFailed(&ignoredOutputMuxCircuit{}, &ignoredOutputMuxCircuit{SEL: -1, I0: 0, I1: 1, I2: 2}) +} + +// Map tests: +type mapCircuit struct { + SEL frontend.Variable + K0, K1, K2, K3 frontend.Variable + V0, V1, V2, V3 frontend.Variable + OUT frontend.Variable +} + +func (c *mapCircuit) Define(api frontend.API) error { + + out := selector.Map(api, c.SEL, + []frontend.Variable{c.K0, c.K1, c.K2, c.K3}, + []frontend.Variable{c.V0, c.V1, c.V2, c.V3}) + + api.AssertIsEqual(out, c.OUT) + + return nil +} + +type ignoredOutputMapCircuit struct { + SEL frontend.Variable + K0, K1 frontend.Variable + V0, V1 frontend.Variable +} + +func (c *ignoredOutputMapCircuit) Define(api frontend.API) error { + + _ = selector.Map(api, c.SEL, + []frontend.Variable{c.K0, c.K1}, + []frontend.Variable{c.V0, c.V1}) + + return nil +} + +func TestMap(t *testing.T) { + assert := test.NewAssert(t) + assert.ProverSucceeded(&mapCircuit{}, + &mapCircuit{ + SEL: 100, + K0: 100, K1: 111, K2: 222, K3: 333, + V0: 0, V1: 1, V2: 2, V3: 3, + OUT: 0, + }) + + assert.ProverSucceeded(&mapCircuit{}, + &mapCircuit{ + SEL: 222, + K0: 100, K1: 111, K2: 222, K3: 333, + V0: 0, V1: 1, V2: 2, V3: 3, + OUT: 2, + }) + + assert.ProverSucceeded(&mapCircuit{}, + &mapCircuit{ + SEL: 333, + K0: 100, K1: 111, K2: 222, K3: 333, + V0: 0, V1: 1, V2: 2, V3: 3, + OUT: 3, + }) + + // Duplicated key, success: + assert.ProverSucceeded(&mapCircuit{}, + &mapCircuit{ + SEL: 333, + K0: 222, K1: 222, K2: 222, K3: 333, + V0: 0, V1: 1, V2: 2, V3: 3, + OUT: 3, + }) + + // Duplicated key, UNDEFINED behavior: (with our hint implementation it fails) + assert.ProverFailed(&mapCircuit{}, + &mapCircuit{ + SEL: 333, + K0: 100, K1: 111, K2: 333, K3: 333, + V0: 0, V1: 1, V2: 2, V3: 3, + OUT: 3, + }) + + assert.ProverFailed(&mapCircuit{}, + &mapCircuit{ + SEL: 77, + K0: 100, K1: 111, K2: 222, K3: 333, + V0: 0, V1: 1, V2: 2, V3: 3, + OUT: 3, + }) + + assert.ProverFailed(&mapCircuit{}, + &mapCircuit{ + SEL: 111, + K0: 100, K1: 111, K2: 222, K3: 333, + V0: 0, V1: 1, V2: 2, V3: 3, + OUT: 2, + }) + + // Ignoring the circuit's output: + assert.ProverSucceeded(&ignoredOutputMapCircuit{}, + &ignoredOutputMapCircuit{SEL: 5, + K0: 5, K1: 7, + V0: 10, V1: 11, + }) + + assert.ProverFailed(&ignoredOutputMapCircuit{}, + &ignoredOutputMapCircuit{SEL: 5, + K0: 5, K1: 5, + V0: 10, V1: 11, + }) + + assert.ProverFailed(&ignoredOutputMapCircuit{}, + &ignoredOutputMapCircuit{SEL: 6, + K0: 5, K1: 7, + V0: 10, V1: 11, + }) + +} From b95a52c46cdf741fc75cf8cc64335e5b4982253b Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 9 Feb 2023 12:30:34 +0100 Subject: [PATCH 008/464] feat: add simple key value storage --- internal/kvstore/kvstore.go | 38 +++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 internal/kvstore/kvstore.go diff --git a/internal/kvstore/kvstore.go b/internal/kvstore/kvstore.go new file mode 100644 index 0000000000..6c580cc2fd --- /dev/null +++ b/internal/kvstore/kvstore.go @@ -0,0 +1,38 @@ +// Package kvstore implements simple key-value store +// +// It is without synchronization and allows any comparable keys. The main use of +// this package is for sharing singletons when building a circuit. +package kvstore + +import ( + "reflect" +) + +type Store interface { + SetKeyValue(key, value any) + GetKeyValue(key any) (value any) +} + +type impl struct { + db map[any]any +} + +func New() Store { + return &impl{ + db: make(map[any]any), + } +} + +func (c *impl) SetKeyValue(key, value any) { + if !reflect.TypeOf(key).Comparable() { + panic("key type not comparable") + } + c.db[key] = value +} + +func (c *impl) GetKeyValue(key any) any { + if !reflect.TypeOf(key).Comparable() { + panic("key type not comparable") + } + return c.db[key] +} From c9ba2ff95ddd2576100e2fabf2f11b4521154b46 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 9 Feb 2023 12:32:08 +0100 Subject: [PATCH 009/464] feat: embed key-value storage in R1CS and SCS --- frontend/cs/r1cs/builder.go | 4 ++++ frontend/cs/scs/builder.go | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/frontend/cs/r1cs/builder.go b/frontend/cs/r1cs/builder.go index d06bd9c3d9..a1800035fc 100644 --- a/frontend/cs/r1cs/builder.go +++ b/frontend/cs/r1cs/builder.go @@ -29,6 +29,7 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/internal/expr" "github.com/consensys/gnark/frontend/schema" + "github.com/consensys/gnark/internal/kvstore" "github.com/consensys/gnark/internal/tinyfield" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" @@ -63,6 +64,8 @@ type builder struct { // buffers used to do in place api.MAC mbuf1 expr.LinearExpression mbuf2 expr.LinearExpression + + kvstore.Store } // initialCapacity has quite some impact on frontend performance, especially on large circuits size @@ -78,6 +81,7 @@ func newBuilder(field *big.Int, config frontend.CompileConfig) *builder { heap: make(minHeap, 0, 100), mbuf1: make(expr.LinearExpression, 0, macCapacity), mbuf2: make(expr.LinearExpression, 0, macCapacity), + Store: kvstore.New(), } // by default the circuit is given a public wire equal to 1 diff --git a/frontend/cs/scs/builder.go b/frontend/cs/scs/builder.go index b5d2881a86..e7e253babd 100644 --- a/frontend/cs/scs/builder.go +++ b/frontend/cs/scs/builder.go @@ -29,6 +29,7 @@ import ( "github.com/consensys/gnark/frontend/cs" "github.com/consensys/gnark/frontend/internal/expr" "github.com/consensys/gnark/frontend/schema" + "github.com/consensys/gnark/internal/kvstore" "github.com/consensys/gnark/internal/tinyfield" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" @@ -57,6 +58,8 @@ type scs struct { mtBooleans map[int]struct{} q *big.Int + + kvstore.Store } // initialCapacity has quite some impact on frontend performance, especially on large circuits size @@ -67,6 +70,7 @@ func newBuilder(field *big.Int, config frontend.CompileConfig) *scs { mtBooleans: make(map[int]struct{}), st: cs.NewCoeffTable(), config: config, + Store: kvstore.New(), } curve := utils.FieldToCurve(field) From 2ca04234177ad77ade3c2eeb3a1a6403af032957 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 9 Feb 2023 12:33:42 +0100 Subject: [PATCH 010/464] feat: embed key-value storage in test engine --- test/engine.go | 3 +++ test/solver_test.go | 2 ++ 2 files changed, 5 insertions(+) diff --git a/test/engine.go b/test/engine.go index ab459573df..ce572f4deb 100644 --- a/test/engine.go +++ b/test/engine.go @@ -34,6 +34,7 @@ import ( "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/internal/kvstore" "github.com/consensys/gnark/internal/utils" ) @@ -50,6 +51,7 @@ type engine struct { // mHintsFunctions map[hint.ID]hintFunction constVars bool apiWrapper ApiWrapper + kvstore.Store } // TestEngineOption defines an option for the test engine. @@ -103,6 +105,7 @@ func IsSolved(circuit, witness frontend.Circuit, field *big.Int, opts ...TestEng q: new(big.Int).Set(field), apiWrapper: func(a frontend.API) frontend.API { return a }, constVars: false, + Store: kvstore.New(), } for _, opt := range opts { if err := opt(e); err != nil { diff --git a/test/solver_test.go b/test/solver_test.go index 0c11baed7b..efda654193 100644 --- a/test/solver_test.go +++ b/test/solver_test.go @@ -18,6 +18,7 @@ import ( "github.com/consensys/gnark/frontend/cs/scs" "github.com/consensys/gnark/frontend/schema" "github.com/consensys/gnark/internal/backend/circuits" + "github.com/consensys/gnark/internal/kvstore" "github.com/consensys/gnark/internal/tinyfield" "github.com/consensys/gnark/internal/utils" ) @@ -155,6 +156,7 @@ func isSolvedEngine(c frontend.Circuit, field *big.Int, opts ...TestEngineOption q: new(big.Int).Set(field), apiWrapper: func(a frontend.API) frontend.API { return a }, constVars: false, + Store: kvstore.New(), } for _, opt := range opts { if err := opt(e); err != nil { From bef225c7142f3c3a98e5e150a57c52948f11bcea Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 9 Feb 2023 18:10:34 +0100 Subject: [PATCH 011/464] refactor: remove Commit from Compiler, make optional interface --- frontend/builder.go | 14 +++++++------- frontend/cs/scs/builder.go | 5 ----- .../bls12-377/groth16/commitment_test.go | 17 +++++++++++++---- .../bls12-381/groth16/commitment_test.go | 17 +++++++++++++---- .../bls24-315/groth16/commitment_test.go | 17 +++++++++++++---- .../bls24-317/groth16/commitment_test.go | 17 +++++++++++++---- .../backend/bn254/groth16/commitment_test.go | 17 +++++++++++++---- .../backend/bw6-633/groth16/commitment_test.go | 17 +++++++++++++---- .../backend/bw6-761/groth16/commitment_test.go | 17 +++++++++++++---- .../groth16/tests/groth16.commitment.go.tmpl | 17 +++++++++++++---- 10 files changed, 111 insertions(+), 44 deletions(-) diff --git a/frontend/builder.go b/frontend/builder.go index c15dc1d334..0b372ef59f 100644 --- a/frontend/builder.go +++ b/frontend/builder.go @@ -48,13 +48,6 @@ type Compiler interface { // FieldBitLen returns the number of bits needed to represent an element in the scalar field FieldBitLen() int - - // Commit returns a commitment to the given variables, to be used as initial randomness in - // Fiat-Shamir when the statement to prove is particularly large. - // TODO cite paper - // ! Experimental - // TENTATIVE: Functions regarding fiat-shamir-ed proofs over enormous statements TODO finalize - Commit(...Variable) (Variable, error) } // Builder represents a constraint system builder @@ -73,3 +66,10 @@ type Builder interface { // called inside circuit.Define() SecretVariable(schema.LeafInfo) Variable } + +// Committer allows to commit to the variables and returns the commitment. The +// commitment can be used as a challenge using Fiat-Shamir heuristic. +type Committer interface { + // Commit commits to the variables and returns the commitment. + Commit(toCommit ...Variable) (commitment Variable, err error) +} diff --git a/frontend/cs/scs/builder.go b/frontend/cs/scs/builder.go index b5d2881a86..d76b229894 100644 --- a/frontend/cs/scs/builder.go +++ b/frontend/cs/scs/builder.go @@ -17,7 +17,6 @@ limitations under the License. package scs import ( - "fmt" "math/big" "reflect" "sort" @@ -357,10 +356,6 @@ func (builder *scs) splitProd(acc expr.TermToRefactor, r expr.LinearExpressionTo return builder.splitProd(o, r[1:]) } -func (builder *scs) Commit(v ...frontend.Variable) (frontend.Variable, error) { - return nil, fmt.Errorf("not implemented") -} - // newDebugInfo this is temporary to restore debug logs // something more like builder.sprintf("my message %le %lv", l0, l1) // to build logs for both debug and println diff --git a/internal/backend/bls12-377/groth16/commitment_test.go b/internal/backend/bls12-377/groth16/commitment_test.go index 18f6f142d1..f18eefb837 100644 --- a/internal/backend/bls12-377/groth16/commitment_test.go +++ b/internal/backend/bls12-377/groth16/commitment_test.go @@ -17,6 +17,9 @@ package groth16_test import ( + "fmt" + "testing" + "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/backend/witness" @@ -24,7 +27,6 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/stretchr/testify/assert" - "testing" ) type singleSecretCommittedCircuit struct { @@ -33,7 +35,11 @@ type singleSecretCommittedCircuit struct { func (c *singleSecretCommittedCircuit) Define(api frontend.API) error { api.AssertIsEqual(c.One, 1) - commit, err := api.Compiler().Commit(c.One) + commitCompiler, ok := api.Compiler().(frontend.Committer) + if !ok { + return fmt.Errorf("compiler does not commit") + } + commit, err := commitCompiler.Commit(c.One) if err != nil { return err } @@ -119,8 +125,11 @@ type oneSecretOnePublicCommittedCircuit struct { } func (c *oneSecretOnePublicCommittedCircuit) Define(api frontend.API) error { - - commit, err := api.Compiler().Commit(c.One, c.Two) + commitCompiler, ok := api.Compiler().(frontend.Committer) + if !ok { + return fmt.Errorf("compiler does not commit") + } + commit, err := commitCompiler.Commit(c.One, c.Two) if err != nil { return err } diff --git a/internal/backend/bls12-381/groth16/commitment_test.go b/internal/backend/bls12-381/groth16/commitment_test.go index 9279f8449e..8f6882aeb1 100644 --- a/internal/backend/bls12-381/groth16/commitment_test.go +++ b/internal/backend/bls12-381/groth16/commitment_test.go @@ -17,6 +17,9 @@ package groth16_test import ( + "fmt" + "testing" + "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/backend/witness" @@ -24,7 +27,6 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/stretchr/testify/assert" - "testing" ) type singleSecretCommittedCircuit struct { @@ -33,7 +35,11 @@ type singleSecretCommittedCircuit struct { func (c *singleSecretCommittedCircuit) Define(api frontend.API) error { api.AssertIsEqual(c.One, 1) - commit, err := api.Compiler().Commit(c.One) + commitCompiler, ok := api.Compiler().(frontend.Committer) + if !ok { + return fmt.Errorf("compiler does not commit") + } + commit, err := commitCompiler.Commit(c.One) if err != nil { return err } @@ -119,8 +125,11 @@ type oneSecretOnePublicCommittedCircuit struct { } func (c *oneSecretOnePublicCommittedCircuit) Define(api frontend.API) error { - - commit, err := api.Compiler().Commit(c.One, c.Two) + commitCompiler, ok := api.Compiler().(frontend.Committer) + if !ok { + return fmt.Errorf("compiler does not commit") + } + commit, err := commitCompiler.Commit(c.One, c.Two) if err != nil { return err } diff --git a/internal/backend/bls24-315/groth16/commitment_test.go b/internal/backend/bls24-315/groth16/commitment_test.go index 236bcda605..0f626448b3 100644 --- a/internal/backend/bls24-315/groth16/commitment_test.go +++ b/internal/backend/bls24-315/groth16/commitment_test.go @@ -17,6 +17,9 @@ package groth16_test import ( + "fmt" + "testing" + "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/backend/witness" @@ -24,7 +27,6 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/stretchr/testify/assert" - "testing" ) type singleSecretCommittedCircuit struct { @@ -33,7 +35,11 @@ type singleSecretCommittedCircuit struct { func (c *singleSecretCommittedCircuit) Define(api frontend.API) error { api.AssertIsEqual(c.One, 1) - commit, err := api.Compiler().Commit(c.One) + commitCompiler, ok := api.Compiler().(frontend.Committer) + if !ok { + return fmt.Errorf("compiler does not commit") + } + commit, err := commitCompiler.Commit(c.One) if err != nil { return err } @@ -119,8 +125,11 @@ type oneSecretOnePublicCommittedCircuit struct { } func (c *oneSecretOnePublicCommittedCircuit) Define(api frontend.API) error { - - commit, err := api.Compiler().Commit(c.One, c.Two) + commitCompiler, ok := api.Compiler().(frontend.Committer) + if !ok { + return fmt.Errorf("compiler does not commit") + } + commit, err := commitCompiler.Commit(c.One, c.Two) if err != nil { return err } diff --git a/internal/backend/bls24-317/groth16/commitment_test.go b/internal/backend/bls24-317/groth16/commitment_test.go index 3963ef349e..bfb2fc578e 100644 --- a/internal/backend/bls24-317/groth16/commitment_test.go +++ b/internal/backend/bls24-317/groth16/commitment_test.go @@ -17,6 +17,9 @@ package groth16_test import ( + "fmt" + "testing" + "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/backend/witness" @@ -24,7 +27,6 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/stretchr/testify/assert" - "testing" ) type singleSecretCommittedCircuit struct { @@ -33,7 +35,11 @@ type singleSecretCommittedCircuit struct { func (c *singleSecretCommittedCircuit) Define(api frontend.API) error { api.AssertIsEqual(c.One, 1) - commit, err := api.Compiler().Commit(c.One) + commitCompiler, ok := api.Compiler().(frontend.Committer) + if !ok { + return fmt.Errorf("compiler does not commit") + } + commit, err := commitCompiler.Commit(c.One) if err != nil { return err } @@ -119,8 +125,11 @@ type oneSecretOnePublicCommittedCircuit struct { } func (c *oneSecretOnePublicCommittedCircuit) Define(api frontend.API) error { - - commit, err := api.Compiler().Commit(c.One, c.Two) + commitCompiler, ok := api.Compiler().(frontend.Committer) + if !ok { + return fmt.Errorf("compiler does not commit") + } + commit, err := commitCompiler.Commit(c.One, c.Two) if err != nil { return err } diff --git a/internal/backend/bn254/groth16/commitment_test.go b/internal/backend/bn254/groth16/commitment_test.go index 4573f9749b..759501ebe2 100644 --- a/internal/backend/bn254/groth16/commitment_test.go +++ b/internal/backend/bn254/groth16/commitment_test.go @@ -17,6 +17,9 @@ package groth16_test import ( + "fmt" + "testing" + "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/backend/witness" @@ -24,7 +27,6 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/stretchr/testify/assert" - "testing" ) type singleSecretCommittedCircuit struct { @@ -33,7 +35,11 @@ type singleSecretCommittedCircuit struct { func (c *singleSecretCommittedCircuit) Define(api frontend.API) error { api.AssertIsEqual(c.One, 1) - commit, err := api.Compiler().Commit(c.One) + commitCompiler, ok := api.Compiler().(frontend.Committer) + if !ok { + return fmt.Errorf("compiler does not commit") + } + commit, err := commitCompiler.Commit(c.One) if err != nil { return err } @@ -119,8 +125,11 @@ type oneSecretOnePublicCommittedCircuit struct { } func (c *oneSecretOnePublicCommittedCircuit) Define(api frontend.API) error { - - commit, err := api.Compiler().Commit(c.One, c.Two) + commitCompiler, ok := api.Compiler().(frontend.Committer) + if !ok { + return fmt.Errorf("compiler does not commit") + } + commit, err := commitCompiler.Commit(c.One, c.Two) if err != nil { return err } diff --git a/internal/backend/bw6-633/groth16/commitment_test.go b/internal/backend/bw6-633/groth16/commitment_test.go index b7f700d2cb..a832752ffd 100644 --- a/internal/backend/bw6-633/groth16/commitment_test.go +++ b/internal/backend/bw6-633/groth16/commitment_test.go @@ -17,6 +17,9 @@ package groth16_test import ( + "fmt" + "testing" + "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/backend/witness" @@ -24,7 +27,6 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/stretchr/testify/assert" - "testing" ) type singleSecretCommittedCircuit struct { @@ -33,7 +35,11 @@ type singleSecretCommittedCircuit struct { func (c *singleSecretCommittedCircuit) Define(api frontend.API) error { api.AssertIsEqual(c.One, 1) - commit, err := api.Compiler().Commit(c.One) + commitCompiler, ok := api.Compiler().(frontend.Committer) + if !ok { + return fmt.Errorf("compiler does not commit") + } + commit, err := commitCompiler.Commit(c.One) if err != nil { return err } @@ -119,8 +125,11 @@ type oneSecretOnePublicCommittedCircuit struct { } func (c *oneSecretOnePublicCommittedCircuit) Define(api frontend.API) error { - - commit, err := api.Compiler().Commit(c.One, c.Two) + commitCompiler, ok := api.Compiler().(frontend.Committer) + if !ok { + return fmt.Errorf("compiler does not commit") + } + commit, err := commitCompiler.Commit(c.One, c.Two) if err != nil { return err } diff --git a/internal/backend/bw6-761/groth16/commitment_test.go b/internal/backend/bw6-761/groth16/commitment_test.go index ccddf6be25..f16cb25786 100644 --- a/internal/backend/bw6-761/groth16/commitment_test.go +++ b/internal/backend/bw6-761/groth16/commitment_test.go @@ -17,6 +17,9 @@ package groth16_test import ( + "fmt" + "testing" + "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/backend/witness" @@ -24,7 +27,6 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/stretchr/testify/assert" - "testing" ) type singleSecretCommittedCircuit struct { @@ -33,7 +35,11 @@ type singleSecretCommittedCircuit struct { func (c *singleSecretCommittedCircuit) Define(api frontend.API) error { api.AssertIsEqual(c.One, 1) - commit, err := api.Compiler().Commit(c.One) + commitCompiler, ok := api.Compiler().(frontend.Committer) + if !ok { + return fmt.Errorf("compiler does not commit") + } + commit, err := commitCompiler.Commit(c.One) if err != nil { return err } @@ -119,8 +125,11 @@ type oneSecretOnePublicCommittedCircuit struct { } func (c *oneSecretOnePublicCommittedCircuit) Define(api frontend.API) error { - - commit, err := api.Compiler().Commit(c.One, c.Two) + commitCompiler, ok := api.Compiler().(frontend.Committer) + if !ok { + return fmt.Errorf("compiler does not commit") + } + commit, err := commitCompiler.Commit(c.One, c.Two) if err != nil { return err } diff --git a/internal/generator/backend/template/zkpschemes/groth16/tests/groth16.commitment.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/tests/groth16.commitment.go.tmpl index 94d202d2b4..cc94c21ef1 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/tests/groth16.commitment.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/tests/groth16.commitment.go.tmpl @@ -1,4 +1,7 @@ import ( + "testing" + "fmt" + "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/backend/witness" @@ -6,7 +9,6 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/stretchr/testify/assert" - "testing" ) type singleSecretCommittedCircuit struct { @@ -15,7 +17,11 @@ type singleSecretCommittedCircuit struct { func (c *singleSecretCommittedCircuit) Define(api frontend.API) error { api.AssertIsEqual(c.One, 1) - commit, err := api.Compiler().Commit(c.One) + commitCompiler, ok := api.Compiler().(frontend.Committer) + if !ok { + return fmt.Errorf("compiler does not commit") + } + commit, err := commitCompiler.Commit(c.One) if err != nil { return err } @@ -101,8 +107,11 @@ type oneSecretOnePublicCommittedCircuit struct { } func (c *oneSecretOnePublicCommittedCircuit) Define(api frontend.API) error { - - commit, err := api.Compiler().Commit(c.One, c.Two) + commitCompiler, ok := api.Compiler().(frontend.Committer) + if !ok { + return fmt.Errorf("compiler does not commit") + } + commit, err := commitCompiler.Commit(c.One, c.Two) if err != nil { return err } From 77285a7b683b448645f799086654cc07ee5febb0 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Fri, 10 Feb 2023 15:33:07 +0100 Subject: [PATCH 012/464] feat: implement commit for test engine --- go.mod | 2 +- test/engine.go | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index f0b879473e..0484bea7ba 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/leanovate/gopter v0.2.9 github.com/rs/zerolog v1.29.0 github.com/stretchr/testify v1.8.1 + golang.org/x/crypto v0.6.0 golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb ) @@ -23,7 +24,6 @@ require ( github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/x448/float16 v0.8.4 // indirect - golang.org/x/crypto v0.6.0 // indirect golang.org/x/sys v0.5.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/test/engine.go b/test/engine.go index ab459573df..f6da07ab2e 100644 --- a/test/engine.go +++ b/test/engine.go @@ -28,6 +28,7 @@ import ( "github.com/consensys/gnark/debug" "github.com/consensys/gnark/frontend/schema" "github.com/consensys/gnark/logger" + "golang.org/x/crypto/sha3" "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/field/pool" @@ -585,5 +586,16 @@ func (e *engine) Compiler() frontend.Compiler { } func (e *engine) Commit(v ...frontend.Variable) (frontend.Variable, error) { - panic("not implemented") + nb := (e.FieldBitLen() + 7) / 8 + buf := make([]byte, nb) + hasher := sha3.NewCShake128(nil, []byte("gnark test engine")) + for i := range v { + vs := e.toBigInt(v[i]) + bs := vs.FillBytes(buf) + hasher.Write(bs) + } + hasher.Read(buf) + res := new(big.Int).SetBytes(buf) + res.Mod(res, e.modulus()) + return res, nil } From 87782ef94d9bdbe8b16d4831da053c82b9ab4b56 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Fri, 10 Feb 2023 15:54:20 +0100 Subject: [PATCH 013/464] docs: explain that r1cs.NewBuilder returns frontend.Committer --- frontend/cs/r1cs/builder.go | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/cs/r1cs/builder.go b/frontend/cs/r1cs/builder.go index d06bd9c3d9..aa9c544558 100644 --- a/frontend/cs/r1cs/builder.go +++ b/frontend/cs/r1cs/builder.go @@ -44,6 +44,7 @@ import ( ) // NewBuilder returns a new R1CS builder which implements frontend.API. +// Additionally, this builder also implements [frontend.Committer]. func NewBuilder(field *big.Int, config frontend.CompileConfig) (frontend.Builder, error) { return newBuilder(field, config), nil } From 40e45b0afa1021e901b6e6c2a312aab3f91d5d8d Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 29 Nov 2022 11:50:45 +0100 Subject: [PATCH 014/464] feat: add BN254 pairing using field emulation --- std/algebra/pairing_bn254/g1.go | 16 + std/algebra/pairing_bn254/g2.go | 31 + std/algebra/pairing_bn254/gt.go | 41 ++ std/algebra/pairing_bn254/pairing.go | 278 ++++++++ std/algebra/pairing_bn254/pairing_test.go | 122 ++++ std/algebra/pairing_bn254/tower.go | 833 ++++++++++++++++++++++ 6 files changed, 1321 insertions(+) create mode 100644 std/algebra/pairing_bn254/g1.go create mode 100644 std/algebra/pairing_bn254/g2.go create mode 100644 std/algebra/pairing_bn254/gt.go create mode 100644 std/algebra/pairing_bn254/pairing.go create mode 100644 std/algebra/pairing_bn254/pairing_test.go create mode 100644 std/algebra/pairing_bn254/tower.go diff --git a/std/algebra/pairing_bn254/g1.go b/std/algebra/pairing_bn254/g1.go new file mode 100644 index 0000000000..4f1fa5d2c4 --- /dev/null +++ b/std/algebra/pairing_bn254/g1.go @@ -0,0 +1,16 @@ +package pairing_bn254 + +import ( + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/std/algebra/weierstrass" + "github.com/consensys/gnark/std/math/emulated" +) + +type G1Affine = weierstrass.AffinePoint[emulated.BN254Fp] + +func NewG1Affine(v bn254.G1Affine) G1Affine { + return G1Affine{ + X: emulated.ValueOf[emulated.BN254Fp](v.X), + Y: emulated.ValueOf[emulated.BN254Fp](v.Y), + } +} diff --git a/std/algebra/pairing_bn254/g2.go b/std/algebra/pairing_bn254/g2.go new file mode 100644 index 0000000000..639dcb9df3 --- /dev/null +++ b/std/algebra/pairing_bn254/g2.go @@ -0,0 +1,31 @@ +package pairing_bn254 + +import ( + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/std/math/emulated" +) + +type G2Affine struct { + X, Y E2 +} + +type G2Jacobian struct { + X, Y, Z E2 +} + +type G2Projective struct { + X, Y, Z E2 +} + +func NewG2Affine(v bn254.G2Affine) G2Affine { + return G2Affine{ + X: E2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.X.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.X.A1), + }, + Y: E2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.Y.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.Y.A1), + }, + } +} diff --git a/std/algebra/pairing_bn254/gt.go b/std/algebra/pairing_bn254/gt.go new file mode 100644 index 0000000000..8cace79739 --- /dev/null +++ b/std/algebra/pairing_bn254/gt.go @@ -0,0 +1,41 @@ +package pairing_bn254 + +import ( + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/std/math/emulated" +) + +type GTEl = E12 + +func NewGTEl(v bn254.GT) GTEl { + return GTEl{ + C0: E6{ + B0: E2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B0.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B0.A1), + }, + B1: E2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B1.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B1.A1), + }, + B2: E2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B2.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B2.A1), + }, + }, + C1: E6{ + B0: E2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B0.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B0.A1), + }, + B1: E2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B1.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B1.A1), + }, + B2: E2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B2.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B2.A1), + }, + }, + } +} diff --git a/std/algebra/pairing_bn254/pairing.go b/std/algebra/pairing_bn254/pairing.go new file mode 100644 index 0000000000..28165b462c --- /dev/null +++ b/std/algebra/pairing_bn254/pairing.go @@ -0,0 +1,278 @@ +package pairing_bn254 + +import ( + "fmt" + + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/math/emulated" +) + +type Pairing struct { + *ext12 +} + +func NewPairing(api frontend.API) (*Pairing, error) { + ba, err := emulated.NewField[emulated.BN254Fp](api) + if err != nil { + return nil, fmt.Errorf("new base api: %w", err) + } + return &Pairing{ + ext12: NewExt12(ba), + }, nil +} + +func (pr Pairing) DoubleStep(p *G2Projective) (*G2Projective, *LineEvaluation) { + // var t1, A, B, C, D, E, EE, F, G, H, I, J, K fptower.E2 + A := pr.ext2.Mul(&p.X, &p.Y) // A.Mul(&p.x, &p.y) + A = pr.ext2.Halve(A) // A.Halve() + B := pr.ext2.Square(&p.Y) // B.Square(&p.y) + C := pr.ext2.Square(&p.Z) // C.Square(&p.z) + D := pr.ext2.Double(C) // D.Double(&C). + D = pr.ext2.Add(D, C) // Add(&D, &C) + E := pr.ext2.MulBybTwistCurveCoeff(D) // E.MulBybTwistCurveCoeff(&D) + F := pr.ext2.Double(E) // F.Double(&E). + F = pr.ext2.Add(F, E) // Add(&F, &E) + G := pr.ext2.Add(B, F) // G.Add(&B, &F) + G = pr.ext2.Halve(G) // G.Halve() + H := pr.ext2.Add(&p.Y, &p.Z) // H.Add(&p.y, &p.z). + H = pr.ext2.Square(H) // Square(&H) + t1 := pr.ext2.Add(B, C) // t1.Add(&B, &C) + H = pr.ext2.Sub(H, t1) // H.Sub(&H, &t1) + I := pr.ext2.Sub(E, B) // I.Sub(&E, &B) + J := pr.ext2.Square(&p.X) // J.Square(&p.x) + EE := pr.ext2.Square(E) // EE.Square(&E) + K := pr.ext2.Double(EE) // K.Double(&EE). + K = pr.ext2.Add(K, EE) // Add(&K, &EE) + px := pr.ext2.Sub(B, F) // p.x.Sub(&B, &F). + px = pr.ext2.Mul(px, A) // Mul(&p.x, &A) + py := pr.ext2.Square(G) // p.y.Square(&G). + py = pr.ext2.Sub(py, K) // Sub(&p.y, &K) + pz := pr.ext2.Mul(B, H) // p.z.Mul(&B, &H) + ev0 := pr.ext2.Neg(H) // evaluations.r0.Neg(&H) + ev1 := pr.ext2.Double(J) // evaluations.r1.Double(&J). + ev1 = pr.ext2.Add(ev1, J) // Add(&evaluations.r1, &J) + ev2 := I // evaluations.r2.Set(&I) + return &G2Projective{ + X: *px, + Y: *py, + Z: *pz, + }, + &LineEvaluation{ + r0: *ev0, + r1: *ev1, + r2: *ev2, + } +} + +func (pr Pairing) AffineToProjective(Q *G2Affine) *G2Projective { + // TODO: check point at infinity? We do not filter them in the Miller Loop neither. + // if Q.X.IsZero() && Q.Y.IsZero() { + // p.z.SetZero() + // p.x.SetOne() + // p.y.SetOne() + // return p + // } + pz := pr.ext2.One() // p.z.SetOne() + px := &Q.X // p.x.Set(&Q.X) + py := &Q.Y // p.y.Set(&Q.Y) + return &G2Projective{ // return p + X: *px, + Y: *py, + Z: *pz, + } +} + +func (pr Pairing) NegAffine(a *G2Affine) *G2Affine { + px := &a.X // p.X = a.X + py := pr.ext2.Neg(&a.Y) // p.Y.Neg(&a.Y) + return &G2Affine{ // return p + X: *px, + Y: *py, + } +} + +func (pr Pairing) AddStep(p *G2Projective, a *G2Affine) (*G2Projective, *LineEvaluation) { + // var Y2Z1, X2Z1, O, L, C, D, E, F, G, H, t0, t1, t2, J fptower.E2 + Y2Z1 := pr.ext2.Mul(&a.Y, &p.Z) // Y2Z1.Mul(&a.Y, &p.z) + O := pr.ext2.Sub(&p.Y, Y2Z1) // O.Sub(&p.y, &Y2Z1) + X2Z1 := pr.ext2.Mul(&a.X, &p.Z) // X2Z1.Mul(&a.X, &p.z) + L := pr.ext2.Sub(&p.X, X2Z1) // L.Sub(&p.x, &X2Z1) + C := pr.ext2.Square(O) // C.Square(&O) + D := pr.ext2.Square(L) // D.Square(&L) + E := pr.ext2.Mul(L, D) // E.Mul(&L, &D) + F := pr.ext2.Mul(&p.Z, C) // F.Mul(&p.z, &C) + G := pr.ext2.Mul(&p.X, D) // G.Mul(&p.x, &D) + t0 := pr.ext2.Double(G) // t0.Double(&G) + H := pr.ext2.Add(E, F) // H.Add(&E, &F). + H = pr.ext2.Sub(H, t0) // Sub(&H, &t0) + t1 := pr.ext2.Mul(&p.Y, E) // t1.Mul(&p.y, &E) + px := pr.ext2.Mul(L, H) // p.x.Mul(&L, &H) + py := pr.ext2.Sub(G, H) // p.y.Sub(&G, &H). + py = pr.ext2.Mul(py, O) // Mul(&p.y, &O). + py = pr.ext2.Sub(py, t1) // Sub(&p.y, &t1) + pz := pr.ext2.Mul(E, &p.Z) // p.z.Mul(&E, &p.z) + t2 := pr.ext2.Mul(L, &a.Y) // t2.Mul(&L, &a.Y) + J := pr.ext2.Mul(&a.X, O) // J.Mul(&a.X, &O). + J = pr.ext2.Sub(J, t2) // Sub(&J, &t2) + ev0 := L // evaluations.r0.Set(&L) + ev1 := pr.ext2.Neg(O) // evaluations.r1.Neg(&O) + ev2 := J // evaluations.r2.Set(&J) + return &G2Projective{ + X: *px, + Y: *py, + Z: *pz, + }, &LineEvaluation{ + r0: *ev0, + r1: *ev1, + r2: *ev2, + } +} + +type LineEvaluation struct { + r0 E2 + r1 E2 + r2 E2 +} + +var loopCounter = [66]int8{ + 0, 0, 0, 1, 0, 1, 0, -1, 0, 0, -1, + 0, 0, 0, 1, 0, 0, -1, 0, -1, 0, 0, + 0, 1, 0, -1, 0, 0, 0, 0, -1, 0, 0, + 1, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, + -1, 0, 0, -1, 0, 1, 0, -1, 0, 0, 0, + -1, 0, -1, 0, 0, 0, 1, 0, -1, 0, 1, +} + +func (pr Pairing) MillerLoop(p []*G1Affine, q []*G2Affine) (*GTEl, error) { + n := len(p) + if n == 0 || n != len(q) { + return nil, fmt.Errorf("invalid inputs sizes") + } + + // TODO: we have omitted filtering for infinity points. + + // projective points for Q + qProj := make([]*G2Projective, n) // qProj := make([]g2Proj, n) + qNeg := make([]*G2Affine, n) // qNeg := make([]G2Affine, n) + for k := 0; k < n; k++ { + qProj[k] = pr.AffineToProjective(q[k]) // qProj[k].FromAffine(&q[k]) + qNeg[k] = pr.NegAffine(q[k]) // qNeg[k].Neg(&q[k]) + } + + var l, l0 *LineEvaluation + result := pr.ext12.One() // var tmp, result GTEl + + // i == len(loopCounter) - 2 + for k := 0; k < n; k++ { + qProj[k], l = pr.DoubleStep(qProj[k]) // qProj[k].DoubleStep(&l) + l.r0 = *pr.ext12.ext2.MulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) + l.r1 = *pr.ext12.ext2.MulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) + result = pr.ext12.MulBy034(result, &l.r0, &l.r1, &l.r2) // result.MulBy034(&l.r0, &l.r1, &l.r2) + } + + for i := len(loopCounter) - 3; i >= 0; i-- { + result = pr.ext12.Square(result) // result.Square(&result) + + for k := 0; k < n; k++ { + qProj[k], l = pr.DoubleStep(qProj[k]) // qProj[k].DoubleStep(&l) + l.r0 = *pr.ext12.ext2.MulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) + l.r1 = *pr.ext12.ext2.MulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) + + if loopCounter[i] == 1 { + qProj[k], l0 = pr.AddStep(qProj[k], q[k]) // qProj[k].AddMixedStep(&l0, &q[k]) + l0.r0 = *pr.ext12.ext2.MulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) + l0.r1 = *pr.ext12.ext2.MulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) + tmp := pr.ext12.MulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result = pr.ext12.Mul(result, tmp) // result.Mul(&result, &tmp) + } else if loopCounter[i] == -1 { + qProj[k], l0 = pr.AddStep(qProj[k], qNeg[k]) // qProj[k].AddMixedStep(&l0, &qNeg[k]) + l0.r0 = *pr.ext12.ext2.MulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) + l0.r1 = *pr.ext12.ext2.MulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) + tmp := pr.ext12.MulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result = pr.ext12.Mul(result, tmp) //result.Mul(&result, &tmp) + } else { + result = pr.ext12.MulBy034(result, &l.r0, &l.r1, &l.r2) // result.MulBy034(&l.r0, &l.r1, &l.r2) + } + } + } + + Q1, Q2 := new(G2Affine), new(G2Affine) // var Q1, Q2 G2Affine + for k := 0; k < n; k++ { + //Q1 = π(Q) + // TODO(ivokub): define phi(Q) in G2 instead of doing manually? + Q1.X = *pr.ext12.ext2.Conjugate(&q[k].X) // Q1.X.Conjugate(&q[k].X).MulByNonResidue1Power2(&Q1.X) + Q1.X = *pr.ext12.ext2.MulByNonResidue1Power2(&Q1.X) // Q1.X.Conjugate(&q[k].X).MulByNonResidue1Power2(&Q1.X) + Q1.Y = *pr.ext12.ext2.Conjugate(&q[k].Y) // Q1.Y.Conjugate(&q[k].Y).MulByNonResidue1Power3(&Q1.Y) + Q1.Y = *pr.ext12.ext2.MulByNonResidue1Power3(&Q1.Y) // Q1.Y.Conjugate(&q[k].Y).MulByNonResidue1Power3(&Q1.Y) + + // Q2 = -π²(Q) + Q2.X = *pr.ext12.ext2.MulByNonResidue2Power2(&q[k].X) // Q2.X.MulByNonResidue2Power2(&q[k].X) + Q2.Y = *pr.ext12.ext2.MulByNonResidue2Power3(&q[k].Y) // Q2.Y.MulByNonResidue2Power3(&q[k].Y).Neg(&Q2.Y) + Q2.Y = *pr.ext12.ext2.Neg(&Q2.Y) // Q2.Y.MulByNonResidue2Power3(&q[k].Y).Neg(&Q2.Y) + + qProj[k], l0 = pr.AddStep(qProj[k], Q1) // qProj[k].AddMixedStep(&l0, &Q1) + l0.r0 = *pr.ext12.ext2.MulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) + l0.r1 = *pr.ext12.ext2.MulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) + + qProj[k], l = pr.AddStep(qProj[k], Q2) // qProj[k].AddMixedStep(&l, &Q2) + l.r0 = *pr.ext12.ext2.MulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) + l.r1 = *pr.ext12.ext2.MulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) + tmp := pr.ext12.MulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result = pr.ext12.Mul(result, tmp) // result.Mul(&result, &tmp) + } + + return result, nil +} + +func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { + // var result GT + // result.Set(z) + var t [4]*GTEl // var t [4]GT + + // easy part + t[0] = pr.ext12.Conjugate(e) // t[0].Conjugate(&result) + result := pr.ext12.Inverse(e) // result.Inverse(&result) + t[0] = pr.ext12.Mul(t[0], result) // t[0].Mul(&t[0], &result) + result = pr.ext12.FrobeniusSquare(t[0]) // result.FrobeniusSquare(&t[0]). + result = pr.ext12.Mul(result, t[0]) // Mul(&result, &t[0]) + + //hard part + t[0] = pr.ext12.Expt(result) // t[0].Expt(&result). + t[0] = pr.ext12.Conjugate(t[0]) // Conjugate(&t[0]) + t[0] = pr.ext12.CyclotomicSquare(t[0]) // t[0].CyclotomicSquare(&t[0]) + t[2] = pr.ext12.Expt(t[0]) // t[2].Expt(&t[0]). + t[2] = pr.ext12.Conjugate(t[2]) // Conjugate(&t[2]) + t[1] = pr.ext12.CyclotomicSquare(t[2]) // t[1].CyclotomicSquare(&t[2]) + t[2] = pr.ext12.Mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) + t[2] = pr.ext12.Mul(t[2], result) // t[2].Mul(&t[2], &result) + t[1] = pr.ext12.Expt(t[2]) // t[1].Expt(&t[2]). + t[1] = pr.ext12.CyclotomicSquare(t[1]) // CyclotomicSquare(&t[1]). + t[1] = pr.ext12.Mul(t[1], t[2]) // Mul(&t[1], &t[2]). + t[1] = pr.ext12.Conjugate(t[1]) // Conjugate(&t[1]) + t[3] = pr.ext12.Conjugate(t[1]) // t[3].Conjugate(&t[1]) + t[1] = pr.ext12.CyclotomicSquare(t[0]) // t[1].CyclotomicSquare(&t[0]) + t[1] = pr.ext12.Mul(t[1], result) // t[1].Mul(&t[1], &result) + t[1] = pr.ext12.Conjugate(t[1]) // t[1].Conjugate(&t[1]) + t[1] = pr.ext12.Mul(t[1], t[3]) // t[1].Mul(&t[1], &t[3]) + t[0] = pr.ext12.Mul(t[0], t[1]) // t[0].Mul(&t[0], &t[1]) + t[2] = pr.ext12.Mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) + t[3] = pr.ext12.FrobeniusSquare(t[1]) // t[3].FrobeniusSquare(&t[1]) + t[2] = pr.ext12.Mul(t[2], t[3]) // t[2].Mul(&t[2], &t[3]) + t[3] = pr.ext12.Conjugate(result) // t[3].Conjugate(&result) + t[3] = pr.ext12.Mul(t[3], t[0]) // t[3].Mul(&t[3], &t[0]) + t[1] = pr.ext12.FrobeniusCube(t[3]) // t[1].FrobeniusCube(&t[3]) + t[2] = pr.ext12.Mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) + t[1] = pr.ext12.Frobenius(t[0]) // t[1].Frobenius(&t[0]) + t[1] = pr.ext12.Mul(t[1], t[2]) // t[1].Mul(&t[1], &t[2]) + // result.Set(&t[1]) + return t[1] // return result +} + +func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { + res, err := pr.MillerLoop(P, Q) + if err != nil { + return nil, fmt.Errorf("miller loop: %w", err) + } + res = pr.FinalExponentiation(res) + return res, nil +} diff --git a/std/algebra/pairing_bn254/pairing_test.go b/std/algebra/pairing_bn254/pairing_test.go new file mode 100644 index 0000000000..ed286c0849 --- /dev/null +++ b/std/algebra/pairing_bn254/pairing_test.go @@ -0,0 +1,122 @@ +package pairing_bn254 + +import ( + "crypto/rand" + "fmt" + "testing" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/algebra/weierstrass" + "github.com/consensys/gnark/std/math/emulated" + "github.com/consensys/gnark/test" +) + +func randomG1G2Affines(assert *test.Assert) (bn254.G1Affine, bn254.G2Affine) { + _, _, G1AffGen, G2AffGen := bn254.Generators() + mod := bn254.ID.ScalarField() + s1, err := rand.Int(rand.Reader, mod) + assert.NoError(err) + s2, err := rand.Int(rand.Reader, mod) + assert.NoError(err) + var p bn254.G1Affine + p.ScalarMultiplication(&G1AffGen, s1) + var q bn254.G2Affine + q.ScalarMultiplication(&G2AffGen, s2) + return p, q +} + +type MillerLoopCircuit struct { + InG1 weierstrass.AffinePoint[emulated.BN254Fp] + InG2 G2Affine + Res GTEl +} + +func (c *MillerLoopCircuit) Define(api frontend.API) error { + pairing, err := NewPairing(api) + if err != nil { + return fmt.Errorf("new pairing: %w", err) + } + res, err := pairing.MillerLoop([]*G1Affine{&c.InG1}, []*G2Affine{&c.InG2}) + if err != nil { + return fmt.Errorf("pair: %w", err) + } + pairing.ext12.AssertIsEqual(res, &c.Res) + return nil +} + +func TestMillerLoopTestSolve(t *testing.T) { + assert := test.NewAssert(t) + p, q := randomG1G2Affines(assert) + res, err := bn254.MillerLoop([]bn254.G1Affine{p}, []bn254.G2Affine{q}) + assert.NoError(err) + witness := MillerLoopCircuit{ + InG1: NewG1Affine(p), + InG2: NewG2Affine(q), + Res: NewGTEl(res), + } + err = test.IsSolved(&MillerLoopCircuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type FinalExponentiationCircuit struct { + InGt GTEl + Res GTEl +} + +func (c *FinalExponentiationCircuit) Define(api frontend.API) error { + pairing, err := NewPairing(api) + if err != nil { + return fmt.Errorf("new pairing: %w", err) + } + res := pairing.FinalExponentiation(&c.InGt) + pairing.ext12.AssertIsEqual(res, &c.Res) + return nil +} + +func TestFinalExponentiationTestSolve(t *testing.T) { + assert := test.NewAssert(t) + var gt bn254.GT + gt.SetRandom() + res := bn254.FinalExponentiation(>) + witness := FinalExponentiationCircuit{ + InGt: NewGTEl(gt), + Res: NewGTEl(res), + } + err := test.IsSolved(&FinalExponentiationCircuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type PairCircuit struct { + InG1 G1Affine + InG2 G2Affine + Res GTEl +} + +func (c *PairCircuit) Define(api frontend.API) error { + pairing, err := NewPairing(api) + if err != nil { + return fmt.Errorf("new pairing: %w", err) + } + res, err := pairing.Pair([]*G1Affine{&c.InG1}, []*G2Affine{&c.InG2}) + if err != nil { + return fmt.Errorf("pair: %w", err) + } + pairing.ext12.AssertIsEqual(res, &c.Res) + return nil +} + +func TestPairTestSolve(t *testing.T) { + assert := test.NewAssert(t) + p, q := randomG1G2Affines(assert) + res, err := bn254.Pair([]bn254.G1Affine{p}, []bn254.G2Affine{q}) + assert.NoError(err) + witness := PairCircuit{ + InG1: NewG1Affine(p), + InG2: NewG2Affine(q), + Res: NewGTEl(res), + } + err = test.IsSolved(&PairCircuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} diff --git a/std/algebra/pairing_bn254/tower.go b/std/algebra/pairing_bn254/tower.go new file mode 100644 index 0000000000..8f457f1f32 --- /dev/null +++ b/std/algebra/pairing_bn254/tower.go @@ -0,0 +1,833 @@ +package pairing_bn254 + +import ( + "math/big" + + "github.com/consensys/gnark/std/math/emulated" +) + +type curveF = emulated.Field[emulated.BN254Fp] +type baseEl = emulated.Element[emulated.BN254Fp] + +type E2 struct { + A0, A1 baseEl +} + +type E6 struct { + B0, B1, B2 E2 +} + +type E12 struct { + C0, C1 E6 +} + +type ext2 struct { + fp *curveF + nonResidues map[int]map[int]*E2 +} + +func NewExt2(baseField *curveF) *ext2 { + pwrs := map[int]map[int]struct { + A0 string + A1 string + }{ + 0: { + -1: {"21087453498479301738505683583845423561061080261299122796980902361914303298513", "14681138511599513868579906292550611339979233093309515871315818100066920017952"}, + 1: {"9", "1"}, + }, + 1: { + 1: {"8376118865763821496583973867626364092589906065868298776909617916018768340080", "16469823323077808223889137241176536799009286646108169935659301613961712198316"}, + 2: {"21575463638280843010398324269430826099269044274347216827212613867836435027261", "10307601595873709700152284273816112264069230130616436755625194854815875713954"}, + 3: {"2821565182194536844548159561693502659359617185244120367078079554186484126554", "3505843767911556378687030309984248845540243509899259641013678093033130930403"}, + 4: {"2581911344467009335267311115468803099551665605076196740867805258568234346338", "19937756971775647987995932169929341994314640652964949448313374472400716661030"}, + 5: {"685108087231508774477564247770172212460312782337200605669322048753928464687", "8447204650696766136447902020341177575205426561248465145919723016860428151883"}, + }, + 2: { + 1: {"21888242871839275220042445260109153167277707414472061641714758635765020556617", "0"}, + 2: {"21888242871839275220042445260109153167277707414472061641714758635765020556616", "0"}, + 3: {"21888242871839275222246405745257275088696311157297823662689037894645226208582", "0"}, + 4: {"2203960485148121921418603742825762020974279258880205651966", "0"}, + 5: {"2203960485148121921418603742825762020974279258880205651967", "0"}, + }, + 3: { + 1: {"11697423496358154304825782922584725312912383441159505038794027105778954184319", "303847389135065887422783454877609941456349188919719272345083954437860409601"}, + 2: {"3772000881919853776433695186713858239009073593817195771773381919316419345261", "2236595495967245188281701248203181795121068902605861227855261137820944008926"}, + 3: {"19066677689644738377698246183563772429336693972053703295610958340458742082029", "18382399103927718843559375435273026243156067647398564021675359801612095278180"}, + 4: {"5324479202449903542726783395506214481928257762400643279780343368557297135718", "16208900380737693084919495127334387981393726419856888799917914180988844123039"}, + 5: {"8941241848238582420466759817324047081148088512956452953208002715982955420483", "10338197737521362862238855242243140895517409139741313354160881284257516364953"}, + }, + } + nonResidues := make(map[int]map[int]*E2) + for pwr, v := range pwrs { + for coeff, v := range v { + el := E2{emulated.ValueOf[emulated.BN254Fp](v.A0), emulated.ValueOf[emulated.BN254Fp](v.A1)} + if nonResidues[pwr] == nil { + nonResidues[pwr] = make(map[int]*E2) + } + nonResidues[pwr][coeff] = &el + } + } + return &ext2{fp: baseField, nonResidues: nonResidues} +} + +type ext6 struct { + *ext2 +} + +func NewExt6(baseField *curveF) *ext6 { + return &ext6{ext2: NewExt2(baseField)} +} + +type ext12 struct { + *ext6 +} + +func NewExt12(baseField *curveF) *ext12 { + return &ext12{ext6: NewExt6(baseField)} +} + +// TODO: check where to use Mod and where ModMul. + +func (e ext2) MulByElement(x *E2, y *baseEl) *E2 { + // var yCopy fp.Element + // yCopy.Set(y) + z0 := e.fp.MulMod(&x.A0, y) // z.A0.Mul(&x.A0, &yCopy) + z1 := e.fp.MulMod(&x.A1, y) // z.A1.Mul(&x.A1, &yCopy) + return &E2{ // return z + A0: *z0, + A1: *z1, + } +} + +func (e ext2) Conjugate(x *E2) *E2 { + z0 := x.A0 // z.A0 = x.A0 + z1 := e.fp.Neg(&x.A1) // z.A1.Neg(&x.A1) + return &E2{ // return z + A0: z0, + A1: *z1, + } +} + +func (e ext2) mulByNonResidue(x *E2, power, coef int) *E2 { + y := e.nonResidues[power][coef] + z := e.Mul(x, y) + return z +} + +func (e ext2) MulByNonResidue(x *E2) *E2 { + /* + // below is the direct transliteration of the gnark-crypto code. Now only, + // for simplicity and debugging purposes, we do the non residue operations + // without optimisations. + + nine := big.NewInt(9) + // var a, b fp.Element + a := e.fp.MulConst(&x.A0, nine) // a.Double(&x.A0).Double(&a).Double(&a).Add(&a, &x.A0). + a = e.fp.Sub(a, &x.A1) // Sub(&a, &x.A1) + b := e.fp.MulConst(&x.A1, nine) // b.Double(&x.A1).Double(&b).Double(&b).Add(&b, &x.A1). + b = e.fp.Add(b, &x.A0) // Add(&b, &x.A0) + return &E2{ + A0: *a, // z.A0.Set(&a) + A1: *b, // z.A1.Set(&b) + } // return z + */ + // TODO: inline non-residue multiplication + return e.mulByNonResidue(x, 0, 1) +} + +func (e ext2) MulByNonResidueInv(x *E2) *E2 { + // TODO: to optimise with constant non-residue inverse + /* + // from gnark-crypto + // z.Mul(x, &nonResInverse) + // return z + */ + return e.mulByNonResidue(x, 0, -1) +} + +func (e ext2) MulByNonResidue1Power1(x *E2) *E2 { + return e.mulByNonResidue(x, 1, 1) +} + +func (e ext2) MulByNonResidue1Power2(x *E2) *E2 { + return e.mulByNonResidue(x, 1, 2) +} + +func (e ext2) MulByNonResidue1Power3(x *E2) *E2 { + return e.mulByNonResidue(x, 1, 3) +} + +func (e ext2) MulByNonResidue1Power4(x *E2) *E2 { + return e.mulByNonResidue(x, 1, 4) +} + +func (e ext2) MulByNonResidue1Power5(x *E2) *E2 { + return e.mulByNonResidue(x, 1, 5) +} + +func (e ext2) MulByNonResidue2Power1(x *E2) *E2 { + // TODO: A1 is 0, we can optimize for it + return e.mulByNonResidue(x, 2, 1) +} +func (e ext2) MulByNonResidue2Power2(x *E2) *E2 { + // TODO: A1 is 0, we can optimize for it + return e.mulByNonResidue(x, 2, 2) +} + +func (e ext2) MulByNonResidue2Power3(x *E2) *E2 { + // TODO: A1 is 0, we can optimize for it + return e.mulByNonResidue(x, 2, 3) +} + +func (e ext2) MulByNonResidue2Power4(x *E2) *E2 { + // TODO: A1 is 0, we can optimize for it + return e.mulByNonResidue(x, 2, 4) +} + +func (e ext2) MulByNonResidue2Power5(x *E2) *E2 { + // TODO: A1 is 0, we can optimize for it + return e.mulByNonResidue(x, 2, 5) +} + +func (e ext2) MulByNonResidue3Power1(x *E2) *E2 { + return e.mulByNonResidue(x, 3, 1) +} + +func (e ext2) MulByNonResidue3Power2(x *E2) *E2 { + return e.mulByNonResidue(x, 3, 2) +} + +func (e ext2) MulByNonResidue3Power3(x *E2) *E2 { + return e.mulByNonResidue(x, 3, 3) +} + +func (e ext2) MulByNonResidue3Power4(x *E2) *E2 { + return e.mulByNonResidue(x, 3, 4) +} + +func (e ext2) MulByNonResidue3Power5(x *E2) *E2 { + return e.mulByNonResidue(x, 3, 5) +} + +func (e ext2) Mul(x, y *E2) *E2 { + // var a, b, c fp.Element + a := e.fp.Add(&x.A0, &x.A1) // a.Add(&x.A0, &x.A1) + b := e.fp.Add(&y.A0, &y.A1) // b.Add(&y.A0, &y.A1) + a = e.fp.MulMod(a, b) // a.Mul(&a, &b) + b = e.fp.MulMod(&x.A0, &y.A0) // b.Mul(&x.A0, &y.A0) + c := e.fp.MulMod(&x.A1, &y.A1) // c.Mul(&x.A1, &y.A1) + z1 := e.fp.Sub(a, b) // z.A1.Sub(&a, &b). + z1 = e.fp.Sub(z1, c) // Sub(&z.A1, &c) + z0 := e.fp.Sub(b, c) // z.A0.Sub(&b, &c) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e ext2) Add(x, y *E2) *E2 { + z0 := e.fp.Add(&x.A0, &y.A0) // z.A0.Add(&x.A0, &y.A0) + z1 := e.fp.Add(&x.A1, &y.A1) // z.A1.Add(&x.A1, &y.A1) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e ext2) Sub(x, y *E2) *E2 { + z0 := e.fp.Sub(&x.A0, &y.A0) // z.A0.Sub(&x.A0, &y.A0) + z1 := e.fp.Sub(&x.A1, &y.A1) // z.A1.Sub(&x.A1, &y.A1) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e ext2) Neg(x *E2) *E2 { + z0 := e.fp.Neg(&x.A0) // z.A0.Neg(&x.A0) + z1 := e.fp.Neg(&x.A1) // z.A1.Neg(&x.A1) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e ext2) One() *E2 { + z0 := e.fp.One() // z.A0.SetOne() + z1 := e.fp.Zero() // z.A1.SetZero() + return &E2{ // return z + A0: *z0, + A1: *z1, + } +} + +func (e ext2) Zero() *E2 { + z0 := e.fp.Zero() + z1 := e.fp.Zero() + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e ext2) Square(x *E2) *E2 { + // var a, b fp.Element + a := e.fp.Add(&x.A0, &x.A1) // a.Add(&x.A0, &x.A1) + b := e.fp.Sub(&x.A0, &x.A1) // b.Sub(&x.A0, &x.A1) + a = e.fp.MulMod(a, b) // a.Mul(&a, &b) + b = e.fp.MulMod(&x.A0, &x.A1) // b.Mul(&x.A0, &x.A1). + b = e.fp.MulConst(b, big.NewInt(2)) // Double(&b) + return &E2{ + A0: *a, // z.A0.Set(&a) + A1: *b, // z.A1.Set(&b) + } +} + +func (e ext2) Double(x *E2) *E2 { + two := big.NewInt(2) + z0 := e.fp.MulConst(&x.A0, two) // z.A0.Double(&x.A0) + z1 := e.fp.MulConst(&x.A1, two) // z.A1.Double(&x.A1) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e ext2) Halve(x *E2) *E2 { + // I'm trying to avoid hard-coding modulus here in case want to make generic + // for different curves. + // TODO: if implemented Half in field emulation, then replace with it. + one := e.fp.One() + two := e.fp.MulConst(one, big.NewInt(2)) + z0 := e.fp.Div(&x.A0, two) + z1 := e.fp.Div(&x.A1, two) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e ext2) MulBybTwistCurveCoeff(x *E2) *E2 { + // var res E2 + res := e.MulByNonResidueInv(x) // res.MulByNonResidueInv(x) + z := e.Double(res) // z.Double(&res). + z = e.Add(z, res) // Add(&res, z) + return z // return z +} + +func (e ext2) Inverse(x *E2) *E2 { + // var t0, t1 fp.Element + t0 := e.fp.MulMod(&x.A0, &x.A0) // t0.Square(&x.A0) + t1 := e.fp.MulMod(&x.A1, &x.A1) // t1.Square(&x.A1) + t0 = e.fp.Add(t0, t1) // t0.Add(&t0, &t1) + t1 = e.fp.Inverse(t0) // t1.Inverse(&t0) + z0 := e.fp.MulMod(&x.A0, t1) // z.A0.Mul(&x.A0, &t1) + z1 := e.fp.MulMod(&x.A1, t1) // z.A1.Mul(&x.A1, &t1). + z1 = e.fp.Neg(z1) // Neg(&z.A1) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e ext2) AssertIsEqual(x, y *E2) { + e.fp.AssertIsEqual(&x.A0, &y.A0) + e.fp.AssertIsEqual(&x.A1, &y.A1) +} + +func (e ext6) Add(x, y *E6) *E6 { + z0 := e.ext2.Add(&x.B0, &y.B0) // z.B0.Add(&x.B0, &y.B0) + z1 := e.ext2.Add(&x.B1, &y.B1) // z.B1.Add(&x.B1, &y.B1) + z2 := e.ext2.Add(&x.B2, &y.B2) // z.B2.Add(&x.B2, &y.B2) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e ext6) Neg(x *E6) *E6 { + z0 := e.ext2.Neg(&x.B0) // z.B0.Neg(&x.B0) + z1 := e.ext2.Neg(&x.B1) // z.B1.Neg(&x.B1) + z2 := e.ext2.Neg(&x.B2) // z.B2.Neg(&x.B2) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e ext6) Sub(x, y *E6) *E6 { + z0 := e.ext2.Sub(&x.B0, &y.B0) // z.B0.Sub(&x.B0, &y.B0) + z1 := e.ext2.Sub(&x.B1, &y.B1) // z.B1.Sub(&x.B1, &y.B1) + z2 := e.ext2.Sub(&x.B2, &y.B2) // z.B2.Sub(&x.B2, &y.B2) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e ext6) Mul(x, y *E6) *E6 { + // var t0, t1, t2, c0, c1, c2, tmp E2 + t0 := e.ext2.Mul(&x.B0, &y.B0) // t0.Mul(&x.B0, &y.B0) + t1 := e.ext2.Mul(&x.B1, &y.B1) // t1.Mul(&x.B1, &y.B1) + t2 := e.ext2.Mul(&x.B2, &y.B2) // t2.Mul(&x.B2, &y.B2) + c0 := e.ext2.Add(&x.B1, &x.B2) // c0.Add(&x.B1, &x.B2) + tmp := e.ext2.Add(&y.B1, &y.B2) // tmp.Add(&y.B1, &y.B2) + c0 = e.ext2.Mul(c0, tmp) // c0.Mul(&c0, &tmp). + c0 = e.ext2.Sub(c0, t1) // Sub(&c0, &t1). + c0 = e.ext2.Sub(c0, t2) // Sub(&c0, &t2). + c0 = e.ext2.MulByNonResidue(c0) // MulByNonResidue(&c0). + c0 = e.ext2.Add(c0, t0) // Add(&c0, &t0) + c1 := e.ext2.Add(&x.B0, &x.B1) // c1.Add(&x.B0, &x.B1) + tmp = e.ext2.Add(&y.B0, &y.B1) // tmp.Add(&y.B0, &y.B1) + c1 = e.ext2.Mul(c1, tmp) // c1.Mul(&c1, &tmp). + c1 = e.ext2.Sub(c1, t0) // Sub(&c1, &t0). + c1 = e.ext2.Sub(c1, t1) // Sub(&c1, &t1) + tmp = e.ext2.MulByNonResidue(t2) // tmp.MulByNonResidue(&t2) + c1 = e.ext2.Add(c1, tmp) // c1.Add(&c1, &tmp) + tmp = e.ext2.Add(&x.B0, &x.B2) // tmp.Add(&x.B0, &x.B2) + c2 := e.ext2.Add(&y.B0, &y.B2) // c2.Add(&y.B0, &y.B2). + c2 = e.ext2.Mul(c2, tmp) // Mul(&c2, &tmp). + c2 = e.ext2.Sub(c2, t0) // Sub(&c2, &t0). + c2 = e.ext2.Sub(c2, t2) // Sub(&c2, &t2). + c2 = e.ext2.Add(c2, t1) // Add(&c2, &t1) + return &E6{ + B0: *c0, // z.B0.Set(&c0) + B1: *c1, // z.B1.Set(&c1) + B2: *c2, // z.B2.Set(&c2) + } // return z +} + +func (e ext6) Double(x *E6) *E6 { + z0 := e.ext2.Double(&x.B0) // z.B0.Double(&x.B0) + z1 := e.ext2.Double(&x.B1) // z.B1.Double(&x.B1) + z2 := e.ext2.Double(&x.B2) // z.B2.Double(&x.B2) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e ext6) Square(x *E6) *E6 { + // var c4, c5, c1, c2, c3, c0 E2 + c4 := e.ext2.Mul(&x.B0, &x.B1) // c4.Mul(&x.B0, &x.B1). + c4 = e.ext2.Double(c4) // Double(&c4) + c5 := e.ext2.Square(&x.B2) // c5.Square(&x.B2) + c1 := e.ext2.MulByNonResidue(c5) // c1.MulByNonResidue(&c5). + c1 = e.ext2.Add(c1, c4) // Add(&c1, &c4) + c2 := e.ext2.Sub(c4, c5) // c2.Sub(&c4, &c5) + c3 := e.ext2.Square(&x.B0) // c3.Square(&x.B0) + c4 = e.ext2.Sub(&x.B0, &x.B1) // c4.Sub(&x.B0, &x.B1). + c4 = e.ext2.Add(c4, &x.B2) // Add(&c4, &x.B2) + c5 = e.ext2.Mul(&x.B1, &x.B2) // c5.Mul(&x.B1, &x.B2). + c5 = e.ext2.Double(c5) // Double(&c5) + c4 = e.ext2.Square(c4) // c4.Square(&c4) + c0 := e.ext2.MulByNonResidue(c5) // c0.MulByNonResidue(&c5). + c0 = e.ext2.Add(c0, c3) // Add(&c0, &c3) + z2 := e.ext2.Add(c2, c4) // z.B2.Add(&c2, &c4). + z2 = e.ext2.Add(z2, c5) // Add(&z.B2, &c5). + z2 = e.ext2.Sub(z2, c3) // Sub(&z.B2, &c3) + z0 := c0 // z.B0.Set(&c0) + z1 := c1 // z.B1.Set(&c1) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e ext6) Inverse(x *E6) *E6 { + // var t0, t1, t2, t3, t4, t5, t6, c0, c1, c2, d1, d2 E2 + t0 := e.ext2.Square(&x.B0) // t0.Square(&x.B0) + t1 := e.ext2.Square(&x.B1) // t1.Square(&x.B1) + t2 := e.ext2.Square(&x.B2) // t2.Square(&x.B2) + t3 := e.ext2.Mul(&x.B0, &x.B1) // t3.Mul(&x.B0, &x.B1) + t4 := e.ext2.Mul(&x.B0, &x.B2) // t4.Mul(&x.B0, &x.B2) + t5 := e.ext2.Mul(&x.B1, &x.B2) // t5.Mul(&x.B1, &x.B2) + c0 := e.ext2.MulByNonResidue(t5) // c0.MulByNonResidue(&t5). + c0 = e.ext2.Neg(c0) // Neg(&c0). + c0 = e.ext2.Add(c0, t0) // Add(&c0, &t0) + c1 := e.ext2.MulByNonResidue(t2) // c1.MulByNonResidue(&t2). + c1 = e.ext2.Sub(c1, t3) // Sub(&c1, &t3) + c2 := e.ext2.Sub(t1, t4) // c2.Sub(&t1, &t4) + t6 := e.ext2.Mul(&x.B0, c0) // t6.Mul(&x.B0, &c0) + d1 := e.ext2.Mul(&x.B2, c1) // d1.Mul(&x.B2, &c1) + d2 := e.ext2.Mul(&x.B1, c2) // d2.Mul(&x.B1, &c2) + d1 = e.ext2.Add(d1, d2) // d1.Add(&d1, &d2). + d1 = e.ext2.MulByNonResidue(d1) // MulByNonResidue(&d1) + t6 = e.ext2.Add(t6, d1) // t6.Add(&t6, &d1) + t6 = e.ext2.Inverse(t6) // t6.Inverse(&t6) + z0 := e.ext2.Mul(c0, t6) // z.B0.Mul(&c0, &t6) + z1 := e.ext2.Mul(c1, t6) // z.B1.Mul(&c1, &t6) + z2 := e.ext2.Mul(c2, t6) // z.B2.Mul(&c2, &t6) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} +func (e ext6) MulByE2(x *E6, y *E2) *E6 { + // var yCopy E2 + // yCopy.Set(y) + z0 := e.ext2.Mul(&x.B0, y) // z.B0.Mul(&x.B0, &yCopy) + z1 := e.ext2.Mul(&x.B1, y) // z.B1.Mul(&x.B1, &yCopy) + z2 := e.ext2.Mul(&x.B2, y) // z.B2.Mul(&x.B2, &yCopy) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e ext6) MulBy01(z *E6, c0, c1 *E2) *E6 { + // var a, b, tmp, t0, t1, t2 E2 + a := e.ext2.Mul(&z.B0, c0) // a.Mul(&z.B0, c0) + b := e.ext2.Mul(&z.B1, c1) // b.Mul(&z.B1, c1) + tmp := e.ext2.Add(&z.B1, &z.B2) // tmp.Add(&z.B1, &z.B2) + t0 := e.ext2.Mul(c1, tmp) // t0.Mul(c1, &tmp) + t0 = e.ext2.Sub(t0, b) // t0.Sub(&t0, &b) + t0 = e.ext2.MulByNonResidue(t0) // t0.MulByNonResidue(&t0) + t0 = e.ext2.Add(t0, a) // t0.Add(&t0, &a) + tmp = e.ext2.Add(&z.B0, &z.B2) // tmp.Add(&z.B0, &z.B2) + t2 := e.ext2.Mul(c0, tmp) // t2.Mul(c0, &tmp) + t2 = e.ext2.Sub(t2, a) // t2.Sub(&t2, &a) + t2 = e.ext2.Add(t2, b) // t2.Add(&t2, &b) + t1 := e.ext2.Add(c0, c1) // t1.Add(c0, c1) + tmp = e.ext2.Add(&z.B0, &z.B1) // tmp.Add(&z.B0, &z.B1) + t1 = e.ext2.Mul(t1, tmp) // t1.Mul(&t1, &tmp) + t1 = e.ext2.Sub(t1, a) // t1.Sub(&t1, &a) + t1 = e.ext2.Sub(t1, b) // t1.Sub(&t1, &b) + return &E6{ + B0: *t0, // z.B0.Set(&t0) + B1: *t1, // z.B1.Set(&t1) + B2: *t2, // z.B2.Set(&t2) + } // return z +} + +func (e ext6) MulByNonResidue(x *E6) *E6 { + z2, z1, z0 := &x.B1, &x.B0, &x.B2 // z.B2, z.B1, z.B0 = x.B1, x.B0, x.B2 + z0 = e.ext2.MulByNonResidue(z0) // z.B0.MulByNonResidue(&z.B0) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e ext6) AssertIsEqual(x, y *E6) { + e.ext2.AssertIsEqual(&x.B0, &y.B0) + e.ext2.AssertIsEqual(&x.B1, &y.B1) + e.ext2.AssertIsEqual(&x.B2, &y.B2) +} + +func (e ext12) Conjugate(x *E12) *E12 { + z1 := e.ext6.Neg(&x.C1) // z.C1.Neg(&z.C1) + return &E12{ // return z + C0: x.C0, + C1: *z1, + } +} + +func (e ext12) Inverse(x *E12) *E12 { + // var t0, t1, tmp E6 + t0 := e.ext6.Square(&x.C0) // t0.Square(&x.C0) + t1 := e.ext6.Square(&x.C1) // t1.Square(&x.C1) + tmp := e.ext6.MulByNonResidue(t1) // tmp.MulByNonResidue(&t1) + t0 = e.ext6.Sub(t0, tmp) // t0.Sub(&t0, &tmp) + t1 = e.ext6.Inverse(t0) // t1.Inverse(&t0) + z0 := e.ext6.Mul(&x.C0, t1) // z.C0.Mul(&x.C0, &t1) + z1 := e.ext6.Mul(&x.C1, t1) // z.C1.Mul(&x.C1, &t1). + z1 = e.ext6.Neg(z1) // Neg(&z.C1) + return &E12{ // return z + C0: *z0, + C1: *z1, + } +} + +func (e ext12) Mul(x, y *E12) *E12 { + // var a, b, c E6 + a := e.ext6.Add(&x.C0, &x.C1) // a.Add(&x.C0, &x.C1) + b := e.ext6.Add(&y.C0, &y.C1) // b.Add(&y.C0, &y.C1) + a = e.ext6.Mul(a, b) // a.Mul(&a, &b) + b = e.ext6.Mul(&x.C0, &y.C0) // b.Mul(&x.C0, &y.C0) + c := e.ext6.Mul(&x.C1, &y.C1) // c.Mul(&x.C1, &y.C1) + z1 := e.ext6.Sub(a, b) // z.C1.Sub(&a, &b). + z1 = e.ext6.Sub(z1, c) // Sub(&z.C1, &c) + z0 := e.ext6.MulByNonResidue(c) // z.C0.MulByNonResidue(&c). + z0 = e.ext6.Add(z0, b) // Add(&z.C0, &b) + return &E12{ // return z + C0: *z0, + C1: *z1, + } +} + +func (e ext12) CyclotomicSquare(x *E12) *E12 { + // var t [9]E2 + t0 := e.ext2.Square(&x.C1.B1) // t[0].Square(&x.C1.B1) + t1 := e.ext2.Square(&x.C0.B0) // t[1].Square(&x.C0.B0) + t6 := e.ext2.Add(&x.C1.B1, &x.C0.B0) // t[6].Add(&x.C1.B1, &x.C0.B0). + t6 = e.ext2.Square(t6) // Square(&t[6]). + t6 = e.ext2.Sub(t6, t0) // Sub(&t[6], &t[0]). + t6 = e.ext2.Sub(t6, t1) // Sub(&t[6], &t[1]) + t2 := e.ext2.Square(&x.C0.B2) // t[2].Square(&x.C0.B2) + t3 := e.ext2.Square(&x.C1.B0) // t[3].Square(&x.C1.B0) + t7 := e.ext2.Add(&x.C0.B2, &x.C1.B0) // t[7].Add(&x.C0.B2, &x.C1.B0). + t7 = e.ext2.Square(t7) // Square(&t[7]). + t7 = e.ext2.Sub(t7, t2) // Sub(&t[7], &t[2]). + t7 = e.ext2.Sub(t7, t3) // Sub(&t[7], &t[3]) + t4 := e.ext2.Square(&x.C1.B2) // t[4].Square(&x.C1.B2) + t5 := e.ext2.Square(&x.C0.B1) // t[5].Square(&x.C0.B1) + t8 := e.ext2.Add(&x.C1.B2, &x.C0.B1) // t[8].Add(&x.C1.B2, &x.C0.B1). + t8 = e.ext2.Square(t8) // Square(&t[8]). + t8 = e.ext2.Sub(t8, t4) // Sub(&t[8], &t[4]). + t8 = e.ext2.Sub(t8, t5) // Sub(&t[8], &t[5]). + t8 = e.ext2.MulByNonResidue(t8) // MulByNonResidue(&t[8]) + t0 = e.ext2.MulByNonResidue(t0) // t[0].MulByNonResidue(&t[0]). + t0 = e.ext2.Add(t0, t1) // Add(&t[0], &t[1]) + t2 = e.ext2.MulByNonResidue(t2) // t[2].MulByNonResidue(&t[2]). + t2 = e.ext2.Add(t2, t3) // Add(&t[2], &t[3]) + t4 = e.ext2.MulByNonResidue(t4) // t[4].MulByNonResidue(&t[4]). + t4 = e.ext2.Add(t4, t5) // Add(&t[4], &t[5]) + z00 := e.ext2.Sub(t0, &x.C0.B0) // z.C0.B0.Sub(&t[0], &x.C0.B0). + z00 = e.ext2.Double(z00) // Double(&z.C0.B0). + z00 = e.ext2.Add(z00, t0) // Add(&z.C0.B0, &t[0]) + z01 := e.ext2.Sub(t2, &x.C0.B1) // z.C0.B1.Sub(&t[2], &x.C0.B1). + z01 = e.ext2.Double(z01) // Double(&z.C0.B1). + z01 = e.ext2.Add(z01, t2) // Add(&z.C0.B1, &t[2]) + z02 := e.ext2.Sub(t4, &x.C0.B2) // z.C0.B2.Sub(&t[4], &x.C0.B2). + z02 = e.ext2.Double(z02) // Double(&z.C0.B2). + z02 = e.ext2.Add(z02, t4) // Add(&z.C0.B2, &t[4]) + z10 := e.ext2.Add(t8, &x.C1.B0) // z.C1.B0.Add(&t[8], &x.C1.B0). + z10 = e.ext2.Double(z10) // Double(&z.C1.B0). + z10 = e.ext2.Add(z10, t8) // Add(&z.C1.B0, &t[8]) + z11 := e.ext2.Add(t6, &x.C1.B1) // z.C1.B1.Add(&t[6], &x.C1.B1). + z11 = e.ext2.Double(z11) // Double(&z.C1.B1). + z11 = e.ext2.Add(z11, t6) // Add(&z.C1.B1, &t[6]) + z12 := e.ext2.Add(t7, &x.C1.B2) // z.C1.B2.Add(&t[7], &x.C1.B2). + z12 = e.ext2.Double(z12) // Double(&z.C1.B2). + z12 = e.ext2.Add(z12, t7) // Add(&z.C1.B2, &t[7]) + return &E12{ // return z + C0: E6{ + B0: *z00, + B1: *z01, + B2: *z02, + }, + C1: E6{ + B0: *z10, + B1: *z11, + B2: *z12, + }, + } +} + +func (e ext12) Frobenius(x *E12) *E12 { + // var t [6]E2 + t0 := e.ext2.Conjugate(&x.C0.B0) // t[0].Conjugate(&x.C0.B0) + t1 := e.ext2.Conjugate(&x.C0.B1) // t[1].Conjugate(&x.C0.B1) + t2 := e.ext2.Conjugate(&x.C0.B2) // t[2].Conjugate(&x.C0.B2) + t3 := e.ext2.Conjugate(&x.C1.B0) // t[3].Conjugate(&x.C1.B0) + t4 := e.ext2.Conjugate(&x.C1.B1) // t[4].Conjugate(&x.C1.B1) + t5 := e.ext2.Conjugate(&x.C1.B2) // t[5].Conjugate(&x.C1.B2) + t1 = e.ext2.MulByNonResidue1Power2(t1) // t[1].MulByNonResidue1Power2(&t[1]) + t2 = e.ext2.MulByNonResidue1Power4(t2) // t[2].MulByNonResidue1Power4(&t[2]) + t3 = e.ext2.MulByNonResidue1Power1(t3) // t[3].MulByNonResidue1Power1(&t[3]) + t4 = e.ext2.MulByNonResidue1Power3(t4) // t[4].MulByNonResidue1Power3(&t[4]) + t5 = e.ext2.MulByNonResidue1Power5(t5) // t[5].MulByNonResidue1Power5(&t[5]) + return &E12{ // return z + C0: E6{ + B0: *t0, // z.C0.B0 = t[0] + B1: *t1, // z.C0.B1 = t[1] + B2: *t2, // z.C0.B2 = t[2] + }, + C1: E6{ + B0: *t3, // z.C1.B0 = t[3] + B1: *t4, // z.C1.B1 = t[4] + B2: *t5, // z.C1.B2 = t[5] + }, + } +} + +func (e ext12) FrobeniusSquare(x *E12) *E12 { + z00 := &x.C0.B0 // z.C0.B0 = x.C0.B0 + z01 := e.ext2.MulByNonResidue2Power2(&x.C0.B1) // z.C0.B1.MulByNonResidue2Power2(&x.C0.B1) + z02 := e.ext2.MulByNonResidue2Power4(&x.C0.B2) // z.C0.B2.MulByNonResidue2Power4(&x.C0.B2) + z10 := e.ext2.MulByNonResidue2Power1(&x.C1.B0) // z.C1.B0.MulByNonResidue2Power1(&x.C1.B0) + z11 := e.ext2.MulByNonResidue2Power3(&x.C1.B1) // z.C1.B1.MulByNonResidue2Power3(&x.C1.B1) + z12 := e.ext2.MulByNonResidue2Power5(&x.C1.B2) // z.C1.B2.MulByNonResidue2Power5(&x.C1.B2) + return &E12{ // return z + C0: E6{B0: *z00, B1: *z01, B2: *z02}, + C1: E6{B0: *z10, B1: *z11, B2: *z12}, + } +} + +func (e ext12) FrobeniusCube(x *E12) *E12 { + // var t [6]E2 + t0 := e.ext2.Conjugate(&x.C0.B0) // t[0].Conjugate(&x.C0.B0) + t1 := e.ext2.Conjugate(&x.C0.B1) // t[1].Conjugate(&x.C0.B1) + t2 := e.ext2.Conjugate(&x.C0.B2) // t[2].Conjugate(&x.C0.B2) + t3 := e.ext2.Conjugate(&x.C1.B0) // t[3].Conjugate(&x.C1.B0) + t4 := e.ext2.Conjugate(&x.C1.B1) // t[4].Conjugate(&x.C1.B1) + t5 := e.ext2.Conjugate(&x.C1.B2) // t[5].Conjugate(&x.C1.B2) + t1 = e.ext2.MulByNonResidue3Power2(t1) // t[1].MulByNonResidue3Power2(&t[1]) + t2 = e.ext2.MulByNonResidue3Power4(t2) // t[2].MulByNonResidue3Power4(&t[2]) + t3 = e.ext2.MulByNonResidue3Power1(t3) // t[3].MulByNonResidue3Power1(&t[3]) + t4 = e.ext2.MulByNonResidue3Power3(t4) // t[4].MulByNonResidue3Power3(&t[4]) + t5 = e.ext2.MulByNonResidue3Power5(t5) // t[5].MulByNonResidue3Power5(&t[5]) + return &E12{ // return z + C0: E6{ + B0: *t0, // z.C0.B0 = t[0] + B1: *t1, // z.C0.B1 = t[1] + B2: *t2, // z.C0.B2 = t[2] + }, + C1: E6{ + B0: *t3, // z.C1.B0 = t[3] + B1: *t4, // z.C1.B1 = t[4] + B2: *t5, // z.C1.B2 = t[5] + }, + } +} + +func (e ext12) Expt(x *E12) *E12 { + // var result, t0, t1, t2, t3, t4, t5, t6 E12 + t3 := e.CyclotomicSquare(x) // t3.CyclotomicSquare(x) + t5 := e.CyclotomicSquare(t3) // t5.CyclotomicSquare(&t3) + result := e.CyclotomicSquare(t5) // result.CyclotomicSquare(&t5) + t0 := e.CyclotomicSquare(result) // t0.CyclotomicSquare(&result) + t2 := e.Mul(x, t0) // t2.Mul(x, &t0) + t0 = e.Mul(t3, t2) // t0.Mul(&t3, &t2) + t1 := e.Mul(x, t0) // t1.Mul(x, &t0) + t4 := e.Mul(result, t2) // t4.Mul(&result, &t2) + t6 := e.CyclotomicSquare(t2) // t6.CyclotomicSquare(&t2) + t1 = e.Mul(t0, t1) // t1.Mul(&t0, &t1) + t0 = e.Mul(t3, t1) // t0.Mul(&t3, &t1) + t6 = e.nSquare(t6, 6) // t6.nSquare(6) + t5 = e.Mul(t5, t6) // t5.Mul(&t5, &t6) + t5 = e.Mul(t4, t5) // t5.Mul(&t4, &t5) + t5 = e.nSquare(t5, 7) // t5.nSquare(7) + t4 = e.Mul(t4, t5) // t4.Mul(&t4, &t5) + t4 = e.nSquare(t4, 8) // t4.nSquare(8) + t4 = e.Mul(t0, t4) // t4.Mul(&t0, &t4) + t3 = e.Mul(t3, t4) // t3.Mul(&t3, &t4) + t3 = e.nSquare(t3, 6) // t3.nSquare(6) + t2 = e.Mul(t2, t3) // t2.Mul(&t2, &t3) + t2 = e.nSquare(t2, 8) // t2.nSquare(8) + t2 = e.Mul(t0, t2) // t2.Mul(&t0, &t2) + t2 = e.nSquare(t2, 6) // t2.nSquare(6) + t2 = e.Mul(t0, t2) // t2.Mul(&t0, &t2) + t2 = e.nSquare(t2, 10) // t2.nSquare(10) + t1 = e.Mul(t1, t2) // t1.Mul(&t1, &t2) + t1 = e.nSquare(t1, 6) // t1.nSquare(6) + t0 = e.Mul(t0, t1) // t0.Mul(&t0, &t1) + z := e.Mul(result, t0) // z.Mul(&result, &t0) + return z // return z +} + +func (e ext12) One() *E12 { + z000 := e.fp.One() + zero := e.fp.Zero() + return &E12{ + C0: E6{ + B0: E2{A0: *z000, A1: *zero}, + B1: E2{A0: *zero, A1: *zero}, + B2: E2{A0: *zero, A1: *zero}, + }, + C1: E6{ + B0: E2{A0: *zero, A1: *zero}, + B1: E2{A0: *zero, A1: *zero}, + B2: E2{A0: *zero, A1: *zero}, + }, + } +} + +func (e ext12) MulBy034(z *E12, c0, c3, c4 *E2) *E12 { + // var a, b, d E6 + a := e.ext6.MulByE2(&z.C0, c0) // a.MulByE2(&z.C0, c0) + // b.Set(&z.C1) + b := e.ext6.MulBy01(&z.C1, c3, c4) // b.MulBy01(c3, c4) + c0 = e.ext2.Add(c0, c3) // c0.Add(c0, c3) + d := e.ext6.Add(&z.C0, &z.C1) // d.Add(&z.C0, &z.C1) + d = e.ext6.MulBy01(d, c0, c4) // d.MulBy01(c0, c4) + z1 := e.Add(a, b) // z.C1.Add(&a, &b). + z1 = e.Neg(z1) // Neg(&z.C1). + z1 = e.Add(z1, d) // Add(&z.C1, &d) + z0 := e.MulByNonResidue(b) // z.C0.MulByNonResidue(&b). + z0 = e.Add(z0, a) // Add(&z.C0, &a) + return &E12{ // return z + C0: *z0, + C1: *z1, + } +} + +func (e ext12) Square(x *E12) *E12 { + // var c0, c2, c3 E6 + c0 := e.ext6.Sub(&x.C0, &x.C1) // c0.Sub(&x.C0, &x.C1) + c3 := e.ext6.MulByNonResidue(&x.C1) // c3.MulByNonResidue(&x.C1). + c3 = e.ext6.Neg(c3) // Neg(&c3). + c3 = e.ext6.Add(&x.C0, c3) // Add(&x.C0, &c3) + c2 := e.ext6.Mul(&x.C0, &x.C1) // c2.Mul(&x.C0, &x.C1) + c0 = e.ext6.Mul(c0, c3) // c0.Mul(&c0, &c3). + c0 = e.ext6.Add(c0, c2) // Add(&c0, &c2) + z1 := e.ext6.Double(c2) // z.C1.Double(&c2) + c2 = e.ext6.MulByNonResidue(c2) // c2.MulByNonResidue(&c2) + z0 := e.ext6.Add(c0, c2) // z.C0.Add(&c0, &c2) + return &E12{ // return z + C0: *z0, + C1: *z1, + } +} + +func (e ext12) MulBy034by034(d0, d3, d4, c0, c3, c4 *E2) *E12 { + // var tmp, x0, x3, x4, x04, x03, x34 E2 + x0 := e.ext2.Mul(c0, d0) // x0.Mul(c0, d0) + x3 := e.ext2.Mul(c3, d3) // x3.Mul(c3, d3) + x4 := e.ext2.Mul(c4, d4) // x4.Mul(c4, d4) + tmp := e.ext2.Add(c0, c4) // tmp.Add(c0, c4) + x04 := e.ext2.Add(d0, d4) // x04.Add(d0, d4). + x04 = e.ext2.Mul(x04, tmp) // Mul(&x04, &tmp). + x04 = e.ext2.Sub(x04, x0) // Sub(&x04, &x0). + x04 = e.ext2.Sub(x04, x4) // Sub(&x04, &x4) + tmp = e.ext2.Add(c0, c3) // tmp.Add(c0, c3) + x03 := e.ext2.Add(d0, d3) // x03.Add(d0, d3). + x03 = e.ext2.Mul(x03, tmp) // Mul(&x03, &tmp). + x03 = e.ext2.Sub(x03, x0) // Sub(&x03, &x0). + x03 = e.ext2.Sub(x03, x3) // Sub(&x03, &x3) + tmp = e.ext2.Add(c3, c4) // tmp.Add(c3, c4) + x34 := e.ext2.Add(d3, d4) // x34.Add(d3, d4). + x34 = e.ext2.Mul(x34, tmp) // Mul(&x34, &tmp). + x34 = e.ext2.Sub(x34, x3) // Sub(&x34, &x3). + x34 = e.ext2.Sub(x34, x4) // Sub(&x34, &x4) + z00 := e.ext2.MulByNonResidue(x4) // z.C0.B0.MulByNonResidue(&x4). + z00 = e.ext2.Add(z00, x0) // Add(&z.C0.B0, &x0) + z01 := x3 // z.C0.B1.Set(&x3) + z02 := x34 // z.C0.B2.Set(&x34) + z10 := x03 // z.C1.B0.Set(&x03) + z11 := x04 // z.C1.B1.Set(&x04) + z12 := e.ext2.Zero() // z.C1.B2.SetZero() + return &E12{ // return z + C0: E6{ + B0: *z00, + B1: *z01, + B2: *z02, + }, + C1: E6{ + B0: *z10, + B1: *z11, + B2: *z12, + }, + } +} + +func (e ext12) AssertIsEqual(x, y *E12) { + e.ext6.AssertIsEqual(&x.C0, &y.C0) + e.ext6.AssertIsEqual(&x.C1, &y.C1) +} + +func (e ext12) nSquare(z *E12, n int) *E12 { + for i := 0; i < n; i++ { + z = e.CyclotomicSquare(z) + } + return z +} From 026133b2b7e1b6de75b92e4a331dd71eace52c29 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Fri, 17 Feb 2023 19:38:14 +0100 Subject: [PATCH 015/464] refactor: make methods private --- std/algebra/pairing_bn254/g2.go | 14 +- std/algebra/pairing_bn254/gt.go | 18 +- std/algebra/pairing_bn254/pairing.go | 274 ++++---- std/algebra/pairing_bn254/pairing_test.go | 6 +- std/algebra/pairing_bn254/tower.go | 788 +++++++++++----------- 5 files changed, 550 insertions(+), 550 deletions(-) diff --git a/std/algebra/pairing_bn254/g2.go b/std/algebra/pairing_bn254/g2.go index 639dcb9df3..ace3b00efe 100644 --- a/std/algebra/pairing_bn254/g2.go +++ b/std/algebra/pairing_bn254/g2.go @@ -6,24 +6,24 @@ import ( ) type G2Affine struct { - X, Y E2 + X, Y e2 } -type G2Jacobian struct { - X, Y, Z E2 +type g2Jacobian struct { + X, Y, Z e2 } -type G2Projective struct { - X, Y, Z E2 +type g2Projective struct { + X, Y, Z e2 } func NewG2Affine(v bn254.G2Affine) G2Affine { return G2Affine{ - X: E2{ + X: e2{ A0: emulated.ValueOf[emulated.BN254Fp](v.X.A0), A1: emulated.ValueOf[emulated.BN254Fp](v.X.A1), }, - Y: E2{ + Y: e2{ A0: emulated.ValueOf[emulated.BN254Fp](v.Y.A0), A1: emulated.ValueOf[emulated.BN254Fp](v.Y.A1), }, diff --git a/std/algebra/pairing_bn254/gt.go b/std/algebra/pairing_bn254/gt.go index 8cace79739..2b84c9f0ed 100644 --- a/std/algebra/pairing_bn254/gt.go +++ b/std/algebra/pairing_bn254/gt.go @@ -5,34 +5,34 @@ import ( "github.com/consensys/gnark/std/math/emulated" ) -type GTEl = E12 +type GTEl = e12 func NewGTEl(v bn254.GT) GTEl { return GTEl{ - C0: E6{ - B0: E2{ + C0: e6{ + B0: e2{ A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B0.A0), A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B0.A1), }, - B1: E2{ + B1: e2{ A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B1.A0), A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B1.A1), }, - B2: E2{ + B2: e2{ A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B2.A0), A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B2.A1), }, }, - C1: E6{ - B0: E2{ + C1: e6{ + B0: e2{ A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B0.A0), A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B0.A1), }, - B1: E2{ + B1: e2{ A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B1.A0), A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B1.A1), }, - B2: E2{ + B2: e2{ A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B2.A0), A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B2.A1), }, diff --git a/std/algebra/pairing_bn254/pairing.go b/std/algebra/pairing_bn254/pairing.go index 28165b462c..8fb1d6f782 100644 --- a/std/algebra/pairing_bn254/pairing.go +++ b/std/algebra/pairing_bn254/pairing.go @@ -17,54 +17,54 @@ func NewPairing(api frontend.API) (*Pairing, error) { return nil, fmt.Errorf("new base api: %w", err) } return &Pairing{ - ext12: NewExt12(ba), + ext12: newExt12(ba), }, nil } -func (pr Pairing) DoubleStep(p *G2Projective) (*G2Projective, *LineEvaluation) { +func (pr Pairing) doubleStep(p *g2Projective) (*g2Projective, *lineEvaluation) { // var t1, A, B, C, D, E, EE, F, G, H, I, J, K fptower.E2 - A := pr.ext2.Mul(&p.X, &p.Y) // A.Mul(&p.x, &p.y) - A = pr.ext2.Halve(A) // A.Halve() - B := pr.ext2.Square(&p.Y) // B.Square(&p.y) - C := pr.ext2.Square(&p.Z) // C.Square(&p.z) - D := pr.ext2.Double(C) // D.Double(&C). - D = pr.ext2.Add(D, C) // Add(&D, &C) - E := pr.ext2.MulBybTwistCurveCoeff(D) // E.MulBybTwistCurveCoeff(&D) - F := pr.ext2.Double(E) // F.Double(&E). - F = pr.ext2.Add(F, E) // Add(&F, &E) - G := pr.ext2.Add(B, F) // G.Add(&B, &F) - G = pr.ext2.Halve(G) // G.Halve() - H := pr.ext2.Add(&p.Y, &p.Z) // H.Add(&p.y, &p.z). - H = pr.ext2.Square(H) // Square(&H) - t1 := pr.ext2.Add(B, C) // t1.Add(&B, &C) - H = pr.ext2.Sub(H, t1) // H.Sub(&H, &t1) - I := pr.ext2.Sub(E, B) // I.Sub(&E, &B) - J := pr.ext2.Square(&p.X) // J.Square(&p.x) - EE := pr.ext2.Square(E) // EE.Square(&E) - K := pr.ext2.Double(EE) // K.Double(&EE). - K = pr.ext2.Add(K, EE) // Add(&K, &EE) - px := pr.ext2.Sub(B, F) // p.x.Sub(&B, &F). - px = pr.ext2.Mul(px, A) // Mul(&p.x, &A) - py := pr.ext2.Square(G) // p.y.Square(&G). - py = pr.ext2.Sub(py, K) // Sub(&p.y, &K) - pz := pr.ext2.Mul(B, H) // p.z.Mul(&B, &H) - ev0 := pr.ext2.Neg(H) // evaluations.r0.Neg(&H) - ev1 := pr.ext2.Double(J) // evaluations.r1.Double(&J). - ev1 = pr.ext2.Add(ev1, J) // Add(&evaluations.r1, &J) + A := pr.ext2.mul(&p.X, &p.Y) // A.Mul(&p.x, &p.y) + A = pr.ext2.halve(A) // A.Halve() + B := pr.ext2.square(&p.Y) // B.Square(&p.y) + C := pr.ext2.square(&p.Z) // C.Square(&p.z) + D := pr.ext2.double(C) // D.Double(&C). + D = pr.ext2.add(D, C) // Add(&D, &C) + E := pr.ext2.mulBybTwistCurveCoeff(D) // E.MulBybTwistCurveCoeff(&D) + F := pr.ext2.double(E) // F.Double(&E). + F = pr.ext2.add(F, E) // Add(&F, &E) + G := pr.ext2.add(B, F) // G.Add(&B, &F) + G = pr.ext2.halve(G) // G.Halve() + H := pr.ext2.add(&p.Y, &p.Z) // H.Add(&p.y, &p.z). + H = pr.ext2.square(H) // Square(&H) + t1 := pr.ext2.add(B, C) // t1.Add(&B, &C) + H = pr.ext2.sub(H, t1) // H.Sub(&H, &t1) + I := pr.ext2.sub(E, B) // I.Sub(&E, &B) + J := pr.ext2.square(&p.X) // J.Square(&p.x) + EE := pr.ext2.square(E) // EE.Square(&E) + K := pr.ext2.double(EE) // K.Double(&EE). + K = pr.ext2.add(K, EE) // Add(&K, &EE) + px := pr.ext2.sub(B, F) // p.x.Sub(&B, &F). + px = pr.ext2.mul(px, A) // Mul(&p.x, &A) + py := pr.ext2.square(G) // p.y.Square(&G). + py = pr.ext2.sub(py, K) // Sub(&p.y, &K) + pz := pr.ext2.mul(B, H) // p.z.Mul(&B, &H) + ev0 := pr.ext2.neg(H) // evaluations.r0.Neg(&H) + ev1 := pr.ext2.double(J) // evaluations.r1.Double(&J). + ev1 = pr.ext2.add(ev1, J) // Add(&evaluations.r1, &J) ev2 := I // evaluations.r2.Set(&I) - return &G2Projective{ + return &g2Projective{ X: *px, Y: *py, Z: *pz, }, - &LineEvaluation{ + &lineEvaluation{ r0: *ev0, r1: *ev1, r2: *ev2, } } -func (pr Pairing) AffineToProjective(Q *G2Affine) *G2Projective { +func (pr Pairing) affineToProjective(Q *G2Affine) *g2Projective { // TODO: check point at infinity? We do not filter them in the Miller Loop neither. // if Q.X.IsZero() && Q.Y.IsZero() { // p.z.SetZero() @@ -72,66 +72,66 @@ func (pr Pairing) AffineToProjective(Q *G2Affine) *G2Projective { // p.y.SetOne() // return p // } - pz := pr.ext2.One() // p.z.SetOne() + pz := pr.ext2.one() // p.z.SetOne() px := &Q.X // p.x.Set(&Q.X) py := &Q.Y // p.y.Set(&Q.Y) - return &G2Projective{ // return p + return &g2Projective{ // return p X: *px, Y: *py, Z: *pz, } } -func (pr Pairing) NegAffine(a *G2Affine) *G2Affine { +func (pr Pairing) negAffine(a *G2Affine) *G2Affine { px := &a.X // p.X = a.X - py := pr.ext2.Neg(&a.Y) // p.Y.Neg(&a.Y) + py := pr.ext2.neg(&a.Y) // p.Y.Neg(&a.Y) return &G2Affine{ // return p X: *px, Y: *py, } } -func (pr Pairing) AddStep(p *G2Projective, a *G2Affine) (*G2Projective, *LineEvaluation) { +func (pr Pairing) addStep(p *g2Projective, a *G2Affine) (*g2Projective, *lineEvaluation) { // var Y2Z1, X2Z1, O, L, C, D, E, F, G, H, t0, t1, t2, J fptower.E2 - Y2Z1 := pr.ext2.Mul(&a.Y, &p.Z) // Y2Z1.Mul(&a.Y, &p.z) - O := pr.ext2.Sub(&p.Y, Y2Z1) // O.Sub(&p.y, &Y2Z1) - X2Z1 := pr.ext2.Mul(&a.X, &p.Z) // X2Z1.Mul(&a.X, &p.z) - L := pr.ext2.Sub(&p.X, X2Z1) // L.Sub(&p.x, &X2Z1) - C := pr.ext2.Square(O) // C.Square(&O) - D := pr.ext2.Square(L) // D.Square(&L) - E := pr.ext2.Mul(L, D) // E.Mul(&L, &D) - F := pr.ext2.Mul(&p.Z, C) // F.Mul(&p.z, &C) - G := pr.ext2.Mul(&p.X, D) // G.Mul(&p.x, &D) - t0 := pr.ext2.Double(G) // t0.Double(&G) - H := pr.ext2.Add(E, F) // H.Add(&E, &F). - H = pr.ext2.Sub(H, t0) // Sub(&H, &t0) - t1 := pr.ext2.Mul(&p.Y, E) // t1.Mul(&p.y, &E) - px := pr.ext2.Mul(L, H) // p.x.Mul(&L, &H) - py := pr.ext2.Sub(G, H) // p.y.Sub(&G, &H). - py = pr.ext2.Mul(py, O) // Mul(&p.y, &O). - py = pr.ext2.Sub(py, t1) // Sub(&p.y, &t1) - pz := pr.ext2.Mul(E, &p.Z) // p.z.Mul(&E, &p.z) - t2 := pr.ext2.Mul(L, &a.Y) // t2.Mul(&L, &a.Y) - J := pr.ext2.Mul(&a.X, O) // J.Mul(&a.X, &O). - J = pr.ext2.Sub(J, t2) // Sub(&J, &t2) + Y2Z1 := pr.ext2.mul(&a.Y, &p.Z) // Y2Z1.Mul(&a.Y, &p.z) + O := pr.ext2.sub(&p.Y, Y2Z1) // O.Sub(&p.y, &Y2Z1) + X2Z1 := pr.ext2.mul(&a.X, &p.Z) // X2Z1.Mul(&a.X, &p.z) + L := pr.ext2.sub(&p.X, X2Z1) // L.Sub(&p.x, &X2Z1) + C := pr.ext2.square(O) // C.Square(&O) + D := pr.ext2.square(L) // D.Square(&L) + E := pr.ext2.mul(L, D) // E.Mul(&L, &D) + F := pr.ext2.mul(&p.Z, C) // F.Mul(&p.z, &C) + G := pr.ext2.mul(&p.X, D) // G.Mul(&p.x, &D) + t0 := pr.ext2.double(G) // t0.Double(&G) + H := pr.ext2.add(E, F) // H.Add(&E, &F). + H = pr.ext2.sub(H, t0) // Sub(&H, &t0) + t1 := pr.ext2.mul(&p.Y, E) // t1.Mul(&p.y, &E) + px := pr.ext2.mul(L, H) // p.x.Mul(&L, &H) + py := pr.ext2.sub(G, H) // p.y.Sub(&G, &H). + py = pr.ext2.mul(py, O) // Mul(&p.y, &O). + py = pr.ext2.sub(py, t1) // Sub(&p.y, &t1) + pz := pr.ext2.mul(E, &p.Z) // p.z.Mul(&E, &p.z) + t2 := pr.ext2.mul(L, &a.Y) // t2.Mul(&L, &a.Y) + J := pr.ext2.mul(&a.X, O) // J.Mul(&a.X, &O). + J = pr.ext2.sub(J, t2) // Sub(&J, &t2) ev0 := L // evaluations.r0.Set(&L) - ev1 := pr.ext2.Neg(O) // evaluations.r1.Neg(&O) + ev1 := pr.ext2.neg(O) // evaluations.r1.Neg(&O) ev2 := J // evaluations.r2.Set(&J) - return &G2Projective{ + return &g2Projective{ X: *px, Y: *py, Z: *pz, - }, &LineEvaluation{ + }, &lineEvaluation{ r0: *ev0, r1: *ev1, r2: *ev2, } } -type LineEvaluation struct { - r0 E2 - r1 E2 - r2 E2 +type lineEvaluation struct { + r0 e2 + r1 e2 + r2 e2 } var loopCounter = [66]int8{ @@ -152,46 +152,46 @@ func (pr Pairing) MillerLoop(p []*G1Affine, q []*G2Affine) (*GTEl, error) { // TODO: we have omitted filtering for infinity points. // projective points for Q - qProj := make([]*G2Projective, n) // qProj := make([]g2Proj, n) + qProj := make([]*g2Projective, n) // qProj := make([]g2Proj, n) qNeg := make([]*G2Affine, n) // qNeg := make([]G2Affine, n) for k := 0; k < n; k++ { - qProj[k] = pr.AffineToProjective(q[k]) // qProj[k].FromAffine(&q[k]) - qNeg[k] = pr.NegAffine(q[k]) // qNeg[k].Neg(&q[k]) + qProj[k] = pr.affineToProjective(q[k]) // qProj[k].FromAffine(&q[k]) + qNeg[k] = pr.negAffine(q[k]) // qNeg[k].Neg(&q[k]) } - var l, l0 *LineEvaluation - result := pr.ext12.One() // var tmp, result GTEl + var l, l0 *lineEvaluation + result := pr.ext12.one() // var tmp, result GTEl // i == len(loopCounter) - 2 for k := 0; k < n; k++ { - qProj[k], l = pr.DoubleStep(qProj[k]) // qProj[k].DoubleStep(&l) - l.r0 = *pr.ext12.ext2.MulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1 = *pr.ext12.ext2.MulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) - result = pr.ext12.MulBy034(result, &l.r0, &l.r1, &l.r2) // result.MulBy034(&l.r0, &l.r1, &l.r2) + qProj[k], l = pr.doubleStep(qProj[k]) // qProj[k].DoubleStep(&l) + l.r0 = *pr.ext12.ext2.mulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) + l.r1 = *pr.ext12.ext2.mulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) + result = pr.ext12.mulBy034(result, &l.r0, &l.r1, &l.r2) // result.MulBy034(&l.r0, &l.r1, &l.r2) } for i := len(loopCounter) - 3; i >= 0; i-- { - result = pr.ext12.Square(result) // result.Square(&result) + result = pr.ext12.square(result) // result.Square(&result) for k := 0; k < n; k++ { - qProj[k], l = pr.DoubleStep(qProj[k]) // qProj[k].DoubleStep(&l) - l.r0 = *pr.ext12.ext2.MulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1 = *pr.ext12.ext2.MulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) + qProj[k], l = pr.doubleStep(qProj[k]) // qProj[k].DoubleStep(&l) + l.r0 = *pr.ext12.ext2.mulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) + l.r1 = *pr.ext12.ext2.mulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) if loopCounter[i] == 1 { - qProj[k], l0 = pr.AddStep(qProj[k], q[k]) // qProj[k].AddMixedStep(&l0, &q[k]) - l0.r0 = *pr.ext12.ext2.MulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) - l0.r1 = *pr.ext12.ext2.MulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) - tmp := pr.ext12.MulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result = pr.ext12.Mul(result, tmp) // result.Mul(&result, &tmp) + qProj[k], l0 = pr.addStep(qProj[k], q[k]) // qProj[k].AddMixedStep(&l0, &q[k]) + l0.r0 = *pr.ext12.ext2.mulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) + l0.r1 = *pr.ext12.ext2.mulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) + tmp := pr.ext12.mulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result = pr.ext12.mul(result, tmp) // result.Mul(&result, &tmp) } else if loopCounter[i] == -1 { - qProj[k], l0 = pr.AddStep(qProj[k], qNeg[k]) // qProj[k].AddMixedStep(&l0, &qNeg[k]) - l0.r0 = *pr.ext12.ext2.MulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) - l0.r1 = *pr.ext12.ext2.MulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) - tmp := pr.ext12.MulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result = pr.ext12.Mul(result, tmp) //result.Mul(&result, &tmp) + qProj[k], l0 = pr.addStep(qProj[k], qNeg[k]) // qProj[k].AddMixedStep(&l0, &qNeg[k]) + l0.r0 = *pr.ext12.ext2.mulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) + l0.r1 = *pr.ext12.ext2.mulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) + tmp := pr.ext12.mulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result = pr.ext12.mul(result, tmp) //result.Mul(&result, &tmp) } else { - result = pr.ext12.MulBy034(result, &l.r0, &l.r1, &l.r2) // result.MulBy034(&l.r0, &l.r1, &l.r2) + result = pr.ext12.mulBy034(result, &l.r0, &l.r1, &l.r2) // result.MulBy034(&l.r0, &l.r1, &l.r2) } } } @@ -200,25 +200,25 @@ func (pr Pairing) MillerLoop(p []*G1Affine, q []*G2Affine) (*GTEl, error) { for k := 0; k < n; k++ { //Q1 = π(Q) // TODO(ivokub): define phi(Q) in G2 instead of doing manually? - Q1.X = *pr.ext12.ext2.Conjugate(&q[k].X) // Q1.X.Conjugate(&q[k].X).MulByNonResidue1Power2(&Q1.X) - Q1.X = *pr.ext12.ext2.MulByNonResidue1Power2(&Q1.X) // Q1.X.Conjugate(&q[k].X).MulByNonResidue1Power2(&Q1.X) - Q1.Y = *pr.ext12.ext2.Conjugate(&q[k].Y) // Q1.Y.Conjugate(&q[k].Y).MulByNonResidue1Power3(&Q1.Y) - Q1.Y = *pr.ext12.ext2.MulByNonResidue1Power3(&Q1.Y) // Q1.Y.Conjugate(&q[k].Y).MulByNonResidue1Power3(&Q1.Y) + Q1.X = *pr.ext12.ext2.conjugate(&q[k].X) // Q1.X.Conjugate(&q[k].X).MulByNonResidue1Power2(&Q1.X) + Q1.X = *pr.ext12.ext2.mulByNonResidue1Power2(&Q1.X) // Q1.X.Conjugate(&q[k].X).MulByNonResidue1Power2(&Q1.X) + Q1.Y = *pr.ext12.ext2.conjugate(&q[k].Y) // Q1.Y.Conjugate(&q[k].Y).MulByNonResidue1Power3(&Q1.Y) + Q1.Y = *pr.ext12.ext2.mulByNonResidue1Power3(&Q1.Y) // Q1.Y.Conjugate(&q[k].Y).MulByNonResidue1Power3(&Q1.Y) // Q2 = -π²(Q) - Q2.X = *pr.ext12.ext2.MulByNonResidue2Power2(&q[k].X) // Q2.X.MulByNonResidue2Power2(&q[k].X) - Q2.Y = *pr.ext12.ext2.MulByNonResidue2Power3(&q[k].Y) // Q2.Y.MulByNonResidue2Power3(&q[k].Y).Neg(&Q2.Y) - Q2.Y = *pr.ext12.ext2.Neg(&Q2.Y) // Q2.Y.MulByNonResidue2Power3(&q[k].Y).Neg(&Q2.Y) + Q2.X = *pr.ext12.ext2.mulByNonResidue2Power2(&q[k].X) // Q2.X.MulByNonResidue2Power2(&q[k].X) + Q2.Y = *pr.ext12.ext2.mulByNonResidue2Power3(&q[k].Y) // Q2.Y.MulByNonResidue2Power3(&q[k].Y).Neg(&Q2.Y) + Q2.Y = *pr.ext12.ext2.neg(&Q2.Y) // Q2.Y.MulByNonResidue2Power3(&q[k].Y).Neg(&Q2.Y) - qProj[k], l0 = pr.AddStep(qProj[k], Q1) // qProj[k].AddMixedStep(&l0, &Q1) - l0.r0 = *pr.ext12.ext2.MulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) - l0.r1 = *pr.ext12.ext2.MulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) + qProj[k], l0 = pr.addStep(qProj[k], Q1) // qProj[k].AddMixedStep(&l0, &Q1) + l0.r0 = *pr.ext12.ext2.mulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) + l0.r1 = *pr.ext12.ext2.mulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) - qProj[k], l = pr.AddStep(qProj[k], Q2) // qProj[k].AddMixedStep(&l, &Q2) - l.r0 = *pr.ext12.ext2.MulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1 = *pr.ext12.ext2.MulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) - tmp := pr.ext12.MulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result = pr.ext12.Mul(result, tmp) // result.Mul(&result, &tmp) + qProj[k], l = pr.addStep(qProj[k], Q2) // qProj[k].AddMixedStep(&l, &Q2) + l.r0 = *pr.ext12.ext2.mulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) + l.r1 = *pr.ext12.ext2.mulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) + tmp := pr.ext12.mulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result = pr.ext12.mul(result, tmp) // result.Mul(&result, &tmp) } return result, nil @@ -230,40 +230,40 @@ func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { var t [4]*GTEl // var t [4]GT // easy part - t[0] = pr.ext12.Conjugate(e) // t[0].Conjugate(&result) - result := pr.ext12.Inverse(e) // result.Inverse(&result) - t[0] = pr.ext12.Mul(t[0], result) // t[0].Mul(&t[0], &result) - result = pr.ext12.FrobeniusSquare(t[0]) // result.FrobeniusSquare(&t[0]). - result = pr.ext12.Mul(result, t[0]) // Mul(&result, &t[0]) + t[0] = pr.ext12.conjugate(e) // t[0].Conjugate(&result) + result := pr.ext12.inverse(e) // result.Inverse(&result) + t[0] = pr.ext12.mul(t[0], result) // t[0].Mul(&t[0], &result) + result = pr.ext12.frobeniusSquare(t[0]) // result.FrobeniusSquare(&t[0]). + result = pr.ext12.mul(result, t[0]) // Mul(&result, &t[0]) //hard part - t[0] = pr.ext12.Expt(result) // t[0].Expt(&result). - t[0] = pr.ext12.Conjugate(t[0]) // Conjugate(&t[0]) - t[0] = pr.ext12.CyclotomicSquare(t[0]) // t[0].CyclotomicSquare(&t[0]) - t[2] = pr.ext12.Expt(t[0]) // t[2].Expt(&t[0]). - t[2] = pr.ext12.Conjugate(t[2]) // Conjugate(&t[2]) - t[1] = pr.ext12.CyclotomicSquare(t[2]) // t[1].CyclotomicSquare(&t[2]) - t[2] = pr.ext12.Mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) - t[2] = pr.ext12.Mul(t[2], result) // t[2].Mul(&t[2], &result) - t[1] = pr.ext12.Expt(t[2]) // t[1].Expt(&t[2]). - t[1] = pr.ext12.CyclotomicSquare(t[1]) // CyclotomicSquare(&t[1]). - t[1] = pr.ext12.Mul(t[1], t[2]) // Mul(&t[1], &t[2]). - t[1] = pr.ext12.Conjugate(t[1]) // Conjugate(&t[1]) - t[3] = pr.ext12.Conjugate(t[1]) // t[3].Conjugate(&t[1]) - t[1] = pr.ext12.CyclotomicSquare(t[0]) // t[1].CyclotomicSquare(&t[0]) - t[1] = pr.ext12.Mul(t[1], result) // t[1].Mul(&t[1], &result) - t[1] = pr.ext12.Conjugate(t[1]) // t[1].Conjugate(&t[1]) - t[1] = pr.ext12.Mul(t[1], t[3]) // t[1].Mul(&t[1], &t[3]) - t[0] = pr.ext12.Mul(t[0], t[1]) // t[0].Mul(&t[0], &t[1]) - t[2] = pr.ext12.Mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) - t[3] = pr.ext12.FrobeniusSquare(t[1]) // t[3].FrobeniusSquare(&t[1]) - t[2] = pr.ext12.Mul(t[2], t[3]) // t[2].Mul(&t[2], &t[3]) - t[3] = pr.ext12.Conjugate(result) // t[3].Conjugate(&result) - t[3] = pr.ext12.Mul(t[3], t[0]) // t[3].Mul(&t[3], &t[0]) - t[1] = pr.ext12.FrobeniusCube(t[3]) // t[1].FrobeniusCube(&t[3]) - t[2] = pr.ext12.Mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) - t[1] = pr.ext12.Frobenius(t[0]) // t[1].Frobenius(&t[0]) - t[1] = pr.ext12.Mul(t[1], t[2]) // t[1].Mul(&t[1], &t[2]) + t[0] = pr.ext12.expt(result) // t[0].Expt(&result). + t[0] = pr.ext12.conjugate(t[0]) // Conjugate(&t[0]) + t[0] = pr.ext12.cyclotomicSquare(t[0]) // t[0].CyclotomicSquare(&t[0]) + t[2] = pr.ext12.expt(t[0]) // t[2].Expt(&t[0]). + t[2] = pr.ext12.conjugate(t[2]) // Conjugate(&t[2]) + t[1] = pr.ext12.cyclotomicSquare(t[2]) // t[1].CyclotomicSquare(&t[2]) + t[2] = pr.ext12.mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) + t[2] = pr.ext12.mul(t[2], result) // t[2].Mul(&t[2], &result) + t[1] = pr.ext12.expt(t[2]) // t[1].Expt(&t[2]). + t[1] = pr.ext12.cyclotomicSquare(t[1]) // CyclotomicSquare(&t[1]). + t[1] = pr.ext12.mul(t[1], t[2]) // Mul(&t[1], &t[2]). + t[1] = pr.ext12.conjugate(t[1]) // Conjugate(&t[1]) + t[3] = pr.ext12.conjugate(t[1]) // t[3].Conjugate(&t[1]) + t[1] = pr.ext12.cyclotomicSquare(t[0]) // t[1].CyclotomicSquare(&t[0]) + t[1] = pr.ext12.mul(t[1], result) // t[1].Mul(&t[1], &result) + t[1] = pr.ext12.conjugate(t[1]) // t[1].Conjugate(&t[1]) + t[1] = pr.ext12.mul(t[1], t[3]) // t[1].Mul(&t[1], &t[3]) + t[0] = pr.ext12.mul(t[0], t[1]) // t[0].Mul(&t[0], &t[1]) + t[2] = pr.ext12.mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) + t[3] = pr.ext12.frobeniusSquare(t[1]) // t[3].FrobeniusSquare(&t[1]) + t[2] = pr.ext12.mul(t[2], t[3]) // t[2].Mul(&t[2], &t[3]) + t[3] = pr.ext12.conjugate(result) // t[3].Conjugate(&result) + t[3] = pr.ext12.mul(t[3], t[0]) // t[3].Mul(&t[3], &t[0]) + t[1] = pr.ext12.frobeniusCube(t[3]) // t[1].FrobeniusCube(&t[3]) + t[2] = pr.ext12.mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) + t[1] = pr.ext12.frobenius(t[0]) // t[1].Frobenius(&t[0]) + t[1] = pr.ext12.mul(t[1], t[2]) // t[1].Mul(&t[1], &t[2]) // result.Set(&t[1]) return t[1] // return result } diff --git a/std/algebra/pairing_bn254/pairing_test.go b/std/algebra/pairing_bn254/pairing_test.go index ed286c0849..30fddc1829 100644 --- a/std/algebra/pairing_bn254/pairing_test.go +++ b/std/algebra/pairing_bn254/pairing_test.go @@ -42,7 +42,7 @@ func (c *MillerLoopCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("pair: %w", err) } - pairing.ext12.AssertIsEqual(res, &c.Res) + pairing.ext12.assertIsEqual(res, &c.Res) return nil } @@ -71,7 +71,7 @@ func (c *FinalExponentiationCircuit) Define(api frontend.API) error { return fmt.Errorf("new pairing: %w", err) } res := pairing.FinalExponentiation(&c.InGt) - pairing.ext12.AssertIsEqual(res, &c.Res) + pairing.ext12.assertIsEqual(res, &c.Res) return nil } @@ -103,7 +103,7 @@ func (c *PairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("pair: %w", err) } - pairing.ext12.AssertIsEqual(res, &c.Res) + pairing.ext12.assertIsEqual(res, &c.Res) return nil } diff --git a/std/algebra/pairing_bn254/tower.go b/std/algebra/pairing_bn254/tower.go index 8f457f1f32..c555680885 100644 --- a/std/algebra/pairing_bn254/tower.go +++ b/std/algebra/pairing_bn254/tower.go @@ -9,24 +9,24 @@ import ( type curveF = emulated.Field[emulated.BN254Fp] type baseEl = emulated.Element[emulated.BN254Fp] -type E2 struct { +type e2 struct { A0, A1 baseEl } -type E6 struct { - B0, B1, B2 E2 +type e6 struct { + B0, B1, B2 e2 } -type E12 struct { - C0, C1 E6 +type e12 struct { + C0, C1 e6 } type ext2 struct { fp *curveF - nonResidues map[int]map[int]*E2 + nonResidues map[int]map[int]*e2 } -func NewExt2(baseField *curveF) *ext2 { +func newExt2(baseField *curveF) *ext2 { pwrs := map[int]map[int]struct { A0 string A1 string @@ -57,12 +57,12 @@ func NewExt2(baseField *curveF) *ext2 { 5: {"8941241848238582420466759817324047081148088512956452953208002715982955420483", "10338197737521362862238855242243140895517409139741313354160881284257516364953"}, }, } - nonResidues := make(map[int]map[int]*E2) + nonResidues := make(map[int]map[int]*e2) for pwr, v := range pwrs { for coeff, v := range v { - el := E2{emulated.ValueOf[emulated.BN254Fp](v.A0), emulated.ValueOf[emulated.BN254Fp](v.A1)} + el := e2{emulated.ValueOf[emulated.BN254Fp](v.A0), emulated.ValueOf[emulated.BN254Fp](v.A1)} if nonResidues[pwr] == nil { - nonResidues[pwr] = make(map[int]*E2) + nonResidues[pwr] = make(map[int]*e2) } nonResidues[pwr][coeff] = &el } @@ -74,47 +74,47 @@ type ext6 struct { *ext2 } -func NewExt6(baseField *curveF) *ext6 { - return &ext6{ext2: NewExt2(baseField)} +func newExt6(baseField *curveF) *ext6 { + return &ext6{ext2: newExt2(baseField)} } type ext12 struct { *ext6 } -func NewExt12(baseField *curveF) *ext12 { - return &ext12{ext6: NewExt6(baseField)} +func newExt12(baseField *curveF) *ext12 { + return &ext12{ext6: newExt6(baseField)} } // TODO: check where to use Mod and where ModMul. -func (e ext2) MulByElement(x *E2, y *baseEl) *E2 { +func (e ext2) mulByElement(x *e2, y *baseEl) *e2 { // var yCopy fp.Element // yCopy.Set(y) z0 := e.fp.MulMod(&x.A0, y) // z.A0.Mul(&x.A0, &yCopy) z1 := e.fp.MulMod(&x.A1, y) // z.A1.Mul(&x.A1, &yCopy) - return &E2{ // return z + return &e2{ // return z A0: *z0, A1: *z1, } } -func (e ext2) Conjugate(x *E2) *E2 { +func (e ext2) conjugate(x *e2) *e2 { z0 := x.A0 // z.A0 = x.A0 z1 := e.fp.Neg(&x.A1) // z.A1.Neg(&x.A1) - return &E2{ // return z + return &e2{ // return z A0: z0, A1: *z1, } } -func (e ext2) mulByNonResidue(x *E2, power, coef int) *E2 { +func (e ext2) mulByNonResidueGeneric(x *e2, power, coef int) *e2 { y := e.nonResidues[power][coef] - z := e.Mul(x, y) + z := e.mul(x, y) return z } -func (e ext2) MulByNonResidue(x *E2) *E2 { +func (e ext2) mulByNonResidue(x *e2) *e2 { /* // below is the direct transliteration of the gnark-crypto code. Now only, // for simplicity and debugging purposes, we do the non residue operations @@ -132,84 +132,84 @@ func (e ext2) MulByNonResidue(x *E2) *E2 { } // return z */ // TODO: inline non-residue multiplication - return e.mulByNonResidue(x, 0, 1) + return e.mulByNonResidueGeneric(x, 0, 1) } -func (e ext2) MulByNonResidueInv(x *E2) *E2 { +func (e ext2) mulByNonResidueInv(x *e2) *e2 { // TODO: to optimise with constant non-residue inverse /* // from gnark-crypto // z.Mul(x, &nonResInverse) // return z */ - return e.mulByNonResidue(x, 0, -1) + return e.mulByNonResidueGeneric(x, 0, -1) } -func (e ext2) MulByNonResidue1Power1(x *E2) *E2 { - return e.mulByNonResidue(x, 1, 1) +func (e ext2) mulByNonResidue1Power1(x *e2) *e2 { + return e.mulByNonResidueGeneric(x, 1, 1) } -func (e ext2) MulByNonResidue1Power2(x *E2) *E2 { - return e.mulByNonResidue(x, 1, 2) +func (e ext2) mulByNonResidue1Power2(x *e2) *e2 { + return e.mulByNonResidueGeneric(x, 1, 2) } -func (e ext2) MulByNonResidue1Power3(x *E2) *E2 { - return e.mulByNonResidue(x, 1, 3) +func (e ext2) mulByNonResidue1Power3(x *e2) *e2 { + return e.mulByNonResidueGeneric(x, 1, 3) } -func (e ext2) MulByNonResidue1Power4(x *E2) *E2 { - return e.mulByNonResidue(x, 1, 4) +func (e ext2) mulByNonResidue1Power4(x *e2) *e2 { + return e.mulByNonResidueGeneric(x, 1, 4) } -func (e ext2) MulByNonResidue1Power5(x *E2) *E2 { - return e.mulByNonResidue(x, 1, 5) +func (e ext2) mulByNonResidue1Power5(x *e2) *e2 { + return e.mulByNonResidueGeneric(x, 1, 5) } -func (e ext2) MulByNonResidue2Power1(x *E2) *E2 { +func (e ext2) mulByNonResidue2Power1(x *e2) *e2 { // TODO: A1 is 0, we can optimize for it - return e.mulByNonResidue(x, 2, 1) + return e.mulByNonResidueGeneric(x, 2, 1) } -func (e ext2) MulByNonResidue2Power2(x *E2) *E2 { +func (e ext2) mulByNonResidue2Power2(x *e2) *e2 { // TODO: A1 is 0, we can optimize for it - return e.mulByNonResidue(x, 2, 2) + return e.mulByNonResidueGeneric(x, 2, 2) } -func (e ext2) MulByNonResidue2Power3(x *E2) *E2 { +func (e ext2) mulByNonResidue2Power3(x *e2) *e2 { // TODO: A1 is 0, we can optimize for it - return e.mulByNonResidue(x, 2, 3) + return e.mulByNonResidueGeneric(x, 2, 3) } -func (e ext2) MulByNonResidue2Power4(x *E2) *E2 { +func (e ext2) mulByNonResidue2Power4(x *e2) *e2 { // TODO: A1 is 0, we can optimize for it - return e.mulByNonResidue(x, 2, 4) + return e.mulByNonResidueGeneric(x, 2, 4) } -func (e ext2) MulByNonResidue2Power5(x *E2) *E2 { +func (e ext2) mulByNonResidue2Power5(x *e2) *e2 { // TODO: A1 is 0, we can optimize for it - return e.mulByNonResidue(x, 2, 5) + return e.mulByNonResidueGeneric(x, 2, 5) } -func (e ext2) MulByNonResidue3Power1(x *E2) *E2 { - return e.mulByNonResidue(x, 3, 1) +func (e ext2) mulByNonResidue3Power1(x *e2) *e2 { + return e.mulByNonResidueGeneric(x, 3, 1) } -func (e ext2) MulByNonResidue3Power2(x *E2) *E2 { - return e.mulByNonResidue(x, 3, 2) +func (e ext2) mulByNonResidue3Power2(x *e2) *e2 { + return e.mulByNonResidueGeneric(x, 3, 2) } -func (e ext2) MulByNonResidue3Power3(x *E2) *E2 { - return e.mulByNonResidue(x, 3, 3) +func (e ext2) mulByNonResidue3Power3(x *e2) *e2 { + return e.mulByNonResidueGeneric(x, 3, 3) } -func (e ext2) MulByNonResidue3Power4(x *E2) *E2 { - return e.mulByNonResidue(x, 3, 4) +func (e ext2) mulByNonResidue3Power4(x *e2) *e2 { + return e.mulByNonResidueGeneric(x, 3, 4) } -func (e ext2) MulByNonResidue3Power5(x *E2) *E2 { - return e.mulByNonResidue(x, 3, 5) +func (e ext2) mulByNonResidue3Power5(x *e2) *e2 { + return e.mulByNonResidueGeneric(x, 3, 5) } -func (e ext2) Mul(x, y *E2) *E2 { +func (e ext2) mul(x, y *e2) *e2 { // var a, b, c fp.Element a := e.fp.Add(&x.A0, &x.A1) // a.Add(&x.A0, &x.A1) b := e.fp.Add(&y.A0, &y.A1) // b.Add(&y.A0, &y.A1) @@ -219,81 +219,81 @@ func (e ext2) Mul(x, y *E2) *E2 { z1 := e.fp.Sub(a, b) // z.A1.Sub(&a, &b). z1 = e.fp.Sub(z1, c) // Sub(&z.A1, &c) z0 := e.fp.Sub(b, c) // z.A0.Sub(&b, &c) - return &E2{ + return &e2{ A0: *z0, A1: *z1, } } -func (e ext2) Add(x, y *E2) *E2 { +func (e ext2) add(x, y *e2) *e2 { z0 := e.fp.Add(&x.A0, &y.A0) // z.A0.Add(&x.A0, &y.A0) z1 := e.fp.Add(&x.A1, &y.A1) // z.A1.Add(&x.A1, &y.A1) - return &E2{ + return &e2{ A0: *z0, A1: *z1, } } -func (e ext2) Sub(x, y *E2) *E2 { +func (e ext2) sub(x, y *e2) *e2 { z0 := e.fp.Sub(&x.A0, &y.A0) // z.A0.Sub(&x.A0, &y.A0) z1 := e.fp.Sub(&x.A1, &y.A1) // z.A1.Sub(&x.A1, &y.A1) - return &E2{ + return &e2{ A0: *z0, A1: *z1, } } -func (e ext2) Neg(x *E2) *E2 { +func (e ext2) neg(x *e2) *e2 { z0 := e.fp.Neg(&x.A0) // z.A0.Neg(&x.A0) z1 := e.fp.Neg(&x.A1) // z.A1.Neg(&x.A1) - return &E2{ + return &e2{ A0: *z0, A1: *z1, } } -func (e ext2) One() *E2 { +func (e ext2) one() *e2 { z0 := e.fp.One() // z.A0.SetOne() z1 := e.fp.Zero() // z.A1.SetZero() - return &E2{ // return z + return &e2{ // return z A0: *z0, A1: *z1, } } -func (e ext2) Zero() *E2 { +func (e ext2) zero() *e2 { z0 := e.fp.Zero() z1 := e.fp.Zero() - return &E2{ + return &e2{ A0: *z0, A1: *z1, } } -func (e ext2) Square(x *E2) *E2 { +func (e ext2) square(x *e2) *e2 { // var a, b fp.Element a := e.fp.Add(&x.A0, &x.A1) // a.Add(&x.A0, &x.A1) b := e.fp.Sub(&x.A0, &x.A1) // b.Sub(&x.A0, &x.A1) a = e.fp.MulMod(a, b) // a.Mul(&a, &b) b = e.fp.MulMod(&x.A0, &x.A1) // b.Mul(&x.A0, &x.A1). b = e.fp.MulConst(b, big.NewInt(2)) // Double(&b) - return &E2{ + return &e2{ A0: *a, // z.A0.Set(&a) A1: *b, // z.A1.Set(&b) } } -func (e ext2) Double(x *E2) *E2 { +func (e ext2) double(x *e2) *e2 { two := big.NewInt(2) z0 := e.fp.MulConst(&x.A0, two) // z.A0.Double(&x.A0) z1 := e.fp.MulConst(&x.A1, two) // z.A1.Double(&x.A1) - return &E2{ + return &e2{ A0: *z0, A1: *z1, } } -func (e ext2) Halve(x *E2) *E2 { +func (e ext2) halve(x *e2) *e2 { // I'm trying to avoid hard-coding modulus here in case want to make generic // for different curves. // TODO: if implemented Half in field emulation, then replace with it. @@ -301,21 +301,21 @@ func (e ext2) Halve(x *E2) *E2 { two := e.fp.MulConst(one, big.NewInt(2)) z0 := e.fp.Div(&x.A0, two) z1 := e.fp.Div(&x.A1, two) - return &E2{ + return &e2{ A0: *z0, A1: *z1, } } -func (e ext2) MulBybTwistCurveCoeff(x *E2) *E2 { +func (e ext2) mulBybTwistCurveCoeff(x *e2) *e2 { // var res E2 - res := e.MulByNonResidueInv(x) // res.MulByNonResidueInv(x) - z := e.Double(res) // z.Double(&res). - z = e.Add(z, res) // Add(&res, z) + res := e.mulByNonResidueInv(x) // res.MulByNonResidueInv(x) + z := e.double(res) // z.Double(&res). + z = e.add(z, res) // Add(&res, z) return z // return z } -func (e ext2) Inverse(x *E2) *E2 { +func (e ext2) inverse(x *e2) *e2 { // var t0, t1 fp.Element t0 := e.fp.MulMod(&x.A0, &x.A0) // t0.Square(&x.A0) t1 := e.fp.MulMod(&x.A1, &x.A1) // t1.Square(&x.A1) @@ -324,298 +324,298 @@ func (e ext2) Inverse(x *E2) *E2 { z0 := e.fp.MulMod(&x.A0, t1) // z.A0.Mul(&x.A0, &t1) z1 := e.fp.MulMod(&x.A1, t1) // z.A1.Mul(&x.A1, &t1). z1 = e.fp.Neg(z1) // Neg(&z.A1) - return &E2{ + return &e2{ A0: *z0, A1: *z1, } } -func (e ext2) AssertIsEqual(x, y *E2) { +func (e ext2) assertIsEqual(x, y *e2) { e.fp.AssertIsEqual(&x.A0, &y.A0) e.fp.AssertIsEqual(&x.A1, &y.A1) } -func (e ext6) Add(x, y *E6) *E6 { - z0 := e.ext2.Add(&x.B0, &y.B0) // z.B0.Add(&x.B0, &y.B0) - z1 := e.ext2.Add(&x.B1, &y.B1) // z.B1.Add(&x.B1, &y.B1) - z2 := e.ext2.Add(&x.B2, &y.B2) // z.B2.Add(&x.B2, &y.B2) - return &E6{ // return z +func (e ext6) add(x, y *e6) *e6 { + z0 := e.ext2.add(&x.B0, &y.B0) // z.B0.Add(&x.B0, &y.B0) + z1 := e.ext2.add(&x.B1, &y.B1) // z.B1.Add(&x.B1, &y.B1) + z2 := e.ext2.add(&x.B2, &y.B2) // z.B2.Add(&x.B2, &y.B2) + return &e6{ // return z B0: *z0, B1: *z1, B2: *z2, } } -func (e ext6) Neg(x *E6) *E6 { - z0 := e.ext2.Neg(&x.B0) // z.B0.Neg(&x.B0) - z1 := e.ext2.Neg(&x.B1) // z.B1.Neg(&x.B1) - z2 := e.ext2.Neg(&x.B2) // z.B2.Neg(&x.B2) - return &E6{ // return z +func (e ext6) neg(x *e6) *e6 { + z0 := e.ext2.neg(&x.B0) // z.B0.Neg(&x.B0) + z1 := e.ext2.neg(&x.B1) // z.B1.Neg(&x.B1) + z2 := e.ext2.neg(&x.B2) // z.B2.Neg(&x.B2) + return &e6{ // return z B0: *z0, B1: *z1, B2: *z2, } } -func (e ext6) Sub(x, y *E6) *E6 { - z0 := e.ext2.Sub(&x.B0, &y.B0) // z.B0.Sub(&x.B0, &y.B0) - z1 := e.ext2.Sub(&x.B1, &y.B1) // z.B1.Sub(&x.B1, &y.B1) - z2 := e.ext2.Sub(&x.B2, &y.B2) // z.B2.Sub(&x.B2, &y.B2) - return &E6{ // return z +func (e ext6) sub(x, y *e6) *e6 { + z0 := e.ext2.sub(&x.B0, &y.B0) // z.B0.Sub(&x.B0, &y.B0) + z1 := e.ext2.sub(&x.B1, &y.B1) // z.B1.Sub(&x.B1, &y.B1) + z2 := e.ext2.sub(&x.B2, &y.B2) // z.B2.Sub(&x.B2, &y.B2) + return &e6{ // return z B0: *z0, B1: *z1, B2: *z2, } } -func (e ext6) Mul(x, y *E6) *E6 { +func (e ext6) mul(x, y *e6) *e6 { // var t0, t1, t2, c0, c1, c2, tmp E2 - t0 := e.ext2.Mul(&x.B0, &y.B0) // t0.Mul(&x.B0, &y.B0) - t1 := e.ext2.Mul(&x.B1, &y.B1) // t1.Mul(&x.B1, &y.B1) - t2 := e.ext2.Mul(&x.B2, &y.B2) // t2.Mul(&x.B2, &y.B2) - c0 := e.ext2.Add(&x.B1, &x.B2) // c0.Add(&x.B1, &x.B2) - tmp := e.ext2.Add(&y.B1, &y.B2) // tmp.Add(&y.B1, &y.B2) - c0 = e.ext2.Mul(c0, tmp) // c0.Mul(&c0, &tmp). - c0 = e.ext2.Sub(c0, t1) // Sub(&c0, &t1). - c0 = e.ext2.Sub(c0, t2) // Sub(&c0, &t2). - c0 = e.ext2.MulByNonResidue(c0) // MulByNonResidue(&c0). - c0 = e.ext2.Add(c0, t0) // Add(&c0, &t0) - c1 := e.ext2.Add(&x.B0, &x.B1) // c1.Add(&x.B0, &x.B1) - tmp = e.ext2.Add(&y.B0, &y.B1) // tmp.Add(&y.B0, &y.B1) - c1 = e.ext2.Mul(c1, tmp) // c1.Mul(&c1, &tmp). - c1 = e.ext2.Sub(c1, t0) // Sub(&c1, &t0). - c1 = e.ext2.Sub(c1, t1) // Sub(&c1, &t1) - tmp = e.ext2.MulByNonResidue(t2) // tmp.MulByNonResidue(&t2) - c1 = e.ext2.Add(c1, tmp) // c1.Add(&c1, &tmp) - tmp = e.ext2.Add(&x.B0, &x.B2) // tmp.Add(&x.B0, &x.B2) - c2 := e.ext2.Add(&y.B0, &y.B2) // c2.Add(&y.B0, &y.B2). - c2 = e.ext2.Mul(c2, tmp) // Mul(&c2, &tmp). - c2 = e.ext2.Sub(c2, t0) // Sub(&c2, &t0). - c2 = e.ext2.Sub(c2, t2) // Sub(&c2, &t2). - c2 = e.ext2.Add(c2, t1) // Add(&c2, &t1) - return &E6{ + t0 := e.ext2.mul(&x.B0, &y.B0) // t0.Mul(&x.B0, &y.B0) + t1 := e.ext2.mul(&x.B1, &y.B1) // t1.Mul(&x.B1, &y.B1) + t2 := e.ext2.mul(&x.B2, &y.B2) // t2.Mul(&x.B2, &y.B2) + c0 := e.ext2.add(&x.B1, &x.B2) // c0.Add(&x.B1, &x.B2) + tmp := e.ext2.add(&y.B1, &y.B2) // tmp.Add(&y.B1, &y.B2) + c0 = e.ext2.mul(c0, tmp) // c0.Mul(&c0, &tmp). + c0 = e.ext2.sub(c0, t1) // Sub(&c0, &t1). + c0 = e.ext2.sub(c0, t2) // Sub(&c0, &t2). + c0 = e.ext2.mulByNonResidue(c0) // MulByNonResidue(&c0). + c0 = e.ext2.add(c0, t0) // Add(&c0, &t0) + c1 := e.ext2.add(&x.B0, &x.B1) // c1.Add(&x.B0, &x.B1) + tmp = e.ext2.add(&y.B0, &y.B1) // tmp.Add(&y.B0, &y.B1) + c1 = e.ext2.mul(c1, tmp) // c1.Mul(&c1, &tmp). + c1 = e.ext2.sub(c1, t0) // Sub(&c1, &t0). + c1 = e.ext2.sub(c1, t1) // Sub(&c1, &t1) + tmp = e.ext2.mulByNonResidue(t2) // tmp.MulByNonResidue(&t2) + c1 = e.ext2.add(c1, tmp) // c1.Add(&c1, &tmp) + tmp = e.ext2.add(&x.B0, &x.B2) // tmp.Add(&x.B0, &x.B2) + c2 := e.ext2.add(&y.B0, &y.B2) // c2.Add(&y.B0, &y.B2). + c2 = e.ext2.mul(c2, tmp) // Mul(&c2, &tmp). + c2 = e.ext2.sub(c2, t0) // Sub(&c2, &t0). + c2 = e.ext2.sub(c2, t2) // Sub(&c2, &t2). + c2 = e.ext2.add(c2, t1) // Add(&c2, &t1) + return &e6{ B0: *c0, // z.B0.Set(&c0) B1: *c1, // z.B1.Set(&c1) B2: *c2, // z.B2.Set(&c2) } // return z } -func (e ext6) Double(x *E6) *E6 { - z0 := e.ext2.Double(&x.B0) // z.B0.Double(&x.B0) - z1 := e.ext2.Double(&x.B1) // z.B1.Double(&x.B1) - z2 := e.ext2.Double(&x.B2) // z.B2.Double(&x.B2) - return &E6{ // return z +func (e ext6) double(x *e6) *e6 { + z0 := e.ext2.double(&x.B0) // z.B0.Double(&x.B0) + z1 := e.ext2.double(&x.B1) // z.B1.Double(&x.B1) + z2 := e.ext2.double(&x.B2) // z.B2.Double(&x.B2) + return &e6{ // return z B0: *z0, B1: *z1, B2: *z2, } } -func (e ext6) Square(x *E6) *E6 { +func (e ext6) square(x *e6) *e6 { // var c4, c5, c1, c2, c3, c0 E2 - c4 := e.ext2.Mul(&x.B0, &x.B1) // c4.Mul(&x.B0, &x.B1). - c4 = e.ext2.Double(c4) // Double(&c4) - c5 := e.ext2.Square(&x.B2) // c5.Square(&x.B2) - c1 := e.ext2.MulByNonResidue(c5) // c1.MulByNonResidue(&c5). - c1 = e.ext2.Add(c1, c4) // Add(&c1, &c4) - c2 := e.ext2.Sub(c4, c5) // c2.Sub(&c4, &c5) - c3 := e.ext2.Square(&x.B0) // c3.Square(&x.B0) - c4 = e.ext2.Sub(&x.B0, &x.B1) // c4.Sub(&x.B0, &x.B1). - c4 = e.ext2.Add(c4, &x.B2) // Add(&c4, &x.B2) - c5 = e.ext2.Mul(&x.B1, &x.B2) // c5.Mul(&x.B1, &x.B2). - c5 = e.ext2.Double(c5) // Double(&c5) - c4 = e.ext2.Square(c4) // c4.Square(&c4) - c0 := e.ext2.MulByNonResidue(c5) // c0.MulByNonResidue(&c5). - c0 = e.ext2.Add(c0, c3) // Add(&c0, &c3) - z2 := e.ext2.Add(c2, c4) // z.B2.Add(&c2, &c4). - z2 = e.ext2.Add(z2, c5) // Add(&z.B2, &c5). - z2 = e.ext2.Sub(z2, c3) // Sub(&z.B2, &c3) + c4 := e.ext2.mul(&x.B0, &x.B1) // c4.Mul(&x.B0, &x.B1). + c4 = e.ext2.double(c4) // Double(&c4) + c5 := e.ext2.square(&x.B2) // c5.Square(&x.B2) + c1 := e.ext2.mulByNonResidue(c5) // c1.MulByNonResidue(&c5). + c1 = e.ext2.add(c1, c4) // Add(&c1, &c4) + c2 := e.ext2.sub(c4, c5) // c2.Sub(&c4, &c5) + c3 := e.ext2.square(&x.B0) // c3.Square(&x.B0) + c4 = e.ext2.sub(&x.B0, &x.B1) // c4.Sub(&x.B0, &x.B1). + c4 = e.ext2.add(c4, &x.B2) // Add(&c4, &x.B2) + c5 = e.ext2.mul(&x.B1, &x.B2) // c5.Mul(&x.B1, &x.B2). + c5 = e.ext2.double(c5) // Double(&c5) + c4 = e.ext2.square(c4) // c4.Square(&c4) + c0 := e.ext2.mulByNonResidue(c5) // c0.MulByNonResidue(&c5). + c0 = e.ext2.add(c0, c3) // Add(&c0, &c3) + z2 := e.ext2.add(c2, c4) // z.B2.Add(&c2, &c4). + z2 = e.ext2.add(z2, c5) // Add(&z.B2, &c5). + z2 = e.ext2.sub(z2, c3) // Sub(&z.B2, &c3) z0 := c0 // z.B0.Set(&c0) z1 := c1 // z.B1.Set(&c1) - return &E6{ // return z + return &e6{ // return z B0: *z0, B1: *z1, B2: *z2, } } -func (e ext6) Inverse(x *E6) *E6 { +func (e ext6) inverse(x *e6) *e6 { // var t0, t1, t2, t3, t4, t5, t6, c0, c1, c2, d1, d2 E2 - t0 := e.ext2.Square(&x.B0) // t0.Square(&x.B0) - t1 := e.ext2.Square(&x.B1) // t1.Square(&x.B1) - t2 := e.ext2.Square(&x.B2) // t2.Square(&x.B2) - t3 := e.ext2.Mul(&x.B0, &x.B1) // t3.Mul(&x.B0, &x.B1) - t4 := e.ext2.Mul(&x.B0, &x.B2) // t4.Mul(&x.B0, &x.B2) - t5 := e.ext2.Mul(&x.B1, &x.B2) // t5.Mul(&x.B1, &x.B2) - c0 := e.ext2.MulByNonResidue(t5) // c0.MulByNonResidue(&t5). - c0 = e.ext2.Neg(c0) // Neg(&c0). - c0 = e.ext2.Add(c0, t0) // Add(&c0, &t0) - c1 := e.ext2.MulByNonResidue(t2) // c1.MulByNonResidue(&t2). - c1 = e.ext2.Sub(c1, t3) // Sub(&c1, &t3) - c2 := e.ext2.Sub(t1, t4) // c2.Sub(&t1, &t4) - t6 := e.ext2.Mul(&x.B0, c0) // t6.Mul(&x.B0, &c0) - d1 := e.ext2.Mul(&x.B2, c1) // d1.Mul(&x.B2, &c1) - d2 := e.ext2.Mul(&x.B1, c2) // d2.Mul(&x.B1, &c2) - d1 = e.ext2.Add(d1, d2) // d1.Add(&d1, &d2). - d1 = e.ext2.MulByNonResidue(d1) // MulByNonResidue(&d1) - t6 = e.ext2.Add(t6, d1) // t6.Add(&t6, &d1) - t6 = e.ext2.Inverse(t6) // t6.Inverse(&t6) - z0 := e.ext2.Mul(c0, t6) // z.B0.Mul(&c0, &t6) - z1 := e.ext2.Mul(c1, t6) // z.B1.Mul(&c1, &t6) - z2 := e.ext2.Mul(c2, t6) // z.B2.Mul(&c2, &t6) - return &E6{ // return z + t0 := e.ext2.square(&x.B0) // t0.Square(&x.B0) + t1 := e.ext2.square(&x.B1) // t1.Square(&x.B1) + t2 := e.ext2.square(&x.B2) // t2.Square(&x.B2) + t3 := e.ext2.mul(&x.B0, &x.B1) // t3.Mul(&x.B0, &x.B1) + t4 := e.ext2.mul(&x.B0, &x.B2) // t4.Mul(&x.B0, &x.B2) + t5 := e.ext2.mul(&x.B1, &x.B2) // t5.Mul(&x.B1, &x.B2) + c0 := e.ext2.mulByNonResidue(t5) // c0.MulByNonResidue(&t5). + c0 = e.ext2.neg(c0) // Neg(&c0). + c0 = e.ext2.add(c0, t0) // Add(&c0, &t0) + c1 := e.ext2.mulByNonResidue(t2) // c1.MulByNonResidue(&t2). + c1 = e.ext2.sub(c1, t3) // Sub(&c1, &t3) + c2 := e.ext2.sub(t1, t4) // c2.Sub(&t1, &t4) + t6 := e.ext2.mul(&x.B0, c0) // t6.Mul(&x.B0, &c0) + d1 := e.ext2.mul(&x.B2, c1) // d1.Mul(&x.B2, &c1) + d2 := e.ext2.mul(&x.B1, c2) // d2.Mul(&x.B1, &c2) + d1 = e.ext2.add(d1, d2) // d1.Add(&d1, &d2). + d1 = e.ext2.mulByNonResidue(d1) // MulByNonResidue(&d1) + t6 = e.ext2.add(t6, d1) // t6.Add(&t6, &d1) + t6 = e.ext2.inverse(t6) // t6.Inverse(&t6) + z0 := e.ext2.mul(c0, t6) // z.B0.Mul(&c0, &t6) + z1 := e.ext2.mul(c1, t6) // z.B1.Mul(&c1, &t6) + z2 := e.ext2.mul(c2, t6) // z.B2.Mul(&c2, &t6) + return &e6{ // return z B0: *z0, B1: *z1, B2: *z2, } } -func (e ext6) MulByE2(x *E6, y *E2) *E6 { +func (e ext6) mulByE2(x *e6, y *e2) *e6 { // var yCopy E2 // yCopy.Set(y) - z0 := e.ext2.Mul(&x.B0, y) // z.B0.Mul(&x.B0, &yCopy) - z1 := e.ext2.Mul(&x.B1, y) // z.B1.Mul(&x.B1, &yCopy) - z2 := e.ext2.Mul(&x.B2, y) // z.B2.Mul(&x.B2, &yCopy) - return &E6{ // return z + z0 := e.ext2.mul(&x.B0, y) // z.B0.Mul(&x.B0, &yCopy) + z1 := e.ext2.mul(&x.B1, y) // z.B1.Mul(&x.B1, &yCopy) + z2 := e.ext2.mul(&x.B2, y) // z.B2.Mul(&x.B2, &yCopy) + return &e6{ // return z B0: *z0, B1: *z1, B2: *z2, } } -func (e ext6) MulBy01(z *E6, c0, c1 *E2) *E6 { +func (e ext6) mulBy01(z *e6, c0, c1 *e2) *e6 { // var a, b, tmp, t0, t1, t2 E2 - a := e.ext2.Mul(&z.B0, c0) // a.Mul(&z.B0, c0) - b := e.ext2.Mul(&z.B1, c1) // b.Mul(&z.B1, c1) - tmp := e.ext2.Add(&z.B1, &z.B2) // tmp.Add(&z.B1, &z.B2) - t0 := e.ext2.Mul(c1, tmp) // t0.Mul(c1, &tmp) - t0 = e.ext2.Sub(t0, b) // t0.Sub(&t0, &b) - t0 = e.ext2.MulByNonResidue(t0) // t0.MulByNonResidue(&t0) - t0 = e.ext2.Add(t0, a) // t0.Add(&t0, &a) - tmp = e.ext2.Add(&z.B0, &z.B2) // tmp.Add(&z.B0, &z.B2) - t2 := e.ext2.Mul(c0, tmp) // t2.Mul(c0, &tmp) - t2 = e.ext2.Sub(t2, a) // t2.Sub(&t2, &a) - t2 = e.ext2.Add(t2, b) // t2.Add(&t2, &b) - t1 := e.ext2.Add(c0, c1) // t1.Add(c0, c1) - tmp = e.ext2.Add(&z.B0, &z.B1) // tmp.Add(&z.B0, &z.B1) - t1 = e.ext2.Mul(t1, tmp) // t1.Mul(&t1, &tmp) - t1 = e.ext2.Sub(t1, a) // t1.Sub(&t1, &a) - t1 = e.ext2.Sub(t1, b) // t1.Sub(&t1, &b) - return &E6{ + a := e.ext2.mul(&z.B0, c0) // a.Mul(&z.B0, c0) + b := e.ext2.mul(&z.B1, c1) // b.Mul(&z.B1, c1) + tmp := e.ext2.add(&z.B1, &z.B2) // tmp.Add(&z.B1, &z.B2) + t0 := e.ext2.mul(c1, tmp) // t0.Mul(c1, &tmp) + t0 = e.ext2.sub(t0, b) // t0.Sub(&t0, &b) + t0 = e.ext2.mulByNonResidue(t0) // t0.MulByNonResidue(&t0) + t0 = e.ext2.add(t0, a) // t0.Add(&t0, &a) + tmp = e.ext2.add(&z.B0, &z.B2) // tmp.Add(&z.B0, &z.B2) + t2 := e.ext2.mul(c0, tmp) // t2.Mul(c0, &tmp) + t2 = e.ext2.sub(t2, a) // t2.Sub(&t2, &a) + t2 = e.ext2.add(t2, b) // t2.Add(&t2, &b) + t1 := e.ext2.add(c0, c1) // t1.Add(c0, c1) + tmp = e.ext2.add(&z.B0, &z.B1) // tmp.Add(&z.B0, &z.B1) + t1 = e.ext2.mul(t1, tmp) // t1.Mul(&t1, &tmp) + t1 = e.ext2.sub(t1, a) // t1.Sub(&t1, &a) + t1 = e.ext2.sub(t1, b) // t1.Sub(&t1, &b) + return &e6{ B0: *t0, // z.B0.Set(&t0) B1: *t1, // z.B1.Set(&t1) B2: *t2, // z.B2.Set(&t2) } // return z } -func (e ext6) MulByNonResidue(x *E6) *E6 { +func (e ext6) mulByNonResidue(x *e6) *e6 { z2, z1, z0 := &x.B1, &x.B0, &x.B2 // z.B2, z.B1, z.B0 = x.B1, x.B0, x.B2 - z0 = e.ext2.MulByNonResidue(z0) // z.B0.MulByNonResidue(&z.B0) - return &E6{ // return z + z0 = e.ext2.mulByNonResidue(z0) // z.B0.MulByNonResidue(&z.B0) + return &e6{ // return z B0: *z0, B1: *z1, B2: *z2, } } -func (e ext6) AssertIsEqual(x, y *E6) { - e.ext2.AssertIsEqual(&x.B0, &y.B0) - e.ext2.AssertIsEqual(&x.B1, &y.B1) - e.ext2.AssertIsEqual(&x.B2, &y.B2) +func (e ext6) assertIsEqual(x, y *e6) { + e.ext2.assertIsEqual(&x.B0, &y.B0) + e.ext2.assertIsEqual(&x.B1, &y.B1) + e.ext2.assertIsEqual(&x.B2, &y.B2) } -func (e ext12) Conjugate(x *E12) *E12 { - z1 := e.ext6.Neg(&x.C1) // z.C1.Neg(&z.C1) - return &E12{ // return z +func (e ext12) conjugate(x *e12) *e12 { + z1 := e.ext6.neg(&x.C1) // z.C1.Neg(&z.C1) + return &e12{ // return z C0: x.C0, C1: *z1, } } -func (e ext12) Inverse(x *E12) *E12 { +func (e ext12) inverse(x *e12) *e12 { // var t0, t1, tmp E6 - t0 := e.ext6.Square(&x.C0) // t0.Square(&x.C0) - t1 := e.ext6.Square(&x.C1) // t1.Square(&x.C1) - tmp := e.ext6.MulByNonResidue(t1) // tmp.MulByNonResidue(&t1) - t0 = e.ext6.Sub(t0, tmp) // t0.Sub(&t0, &tmp) - t1 = e.ext6.Inverse(t0) // t1.Inverse(&t0) - z0 := e.ext6.Mul(&x.C0, t1) // z.C0.Mul(&x.C0, &t1) - z1 := e.ext6.Mul(&x.C1, t1) // z.C1.Mul(&x.C1, &t1). - z1 = e.ext6.Neg(z1) // Neg(&z.C1) - return &E12{ // return z + t0 := e.ext6.square(&x.C0) // t0.Square(&x.C0) + t1 := e.ext6.square(&x.C1) // t1.Square(&x.C1) + tmp := e.ext6.mulByNonResidue(t1) // tmp.MulByNonResidue(&t1) + t0 = e.ext6.sub(t0, tmp) // t0.Sub(&t0, &tmp) + t1 = e.ext6.inverse(t0) // t1.Inverse(&t0) + z0 := e.ext6.mul(&x.C0, t1) // z.C0.Mul(&x.C0, &t1) + z1 := e.ext6.mul(&x.C1, t1) // z.C1.Mul(&x.C1, &t1). + z1 = e.ext6.neg(z1) // Neg(&z.C1) + return &e12{ // return z C0: *z0, C1: *z1, } } -func (e ext12) Mul(x, y *E12) *E12 { +func (e ext12) mul(x, y *e12) *e12 { // var a, b, c E6 - a := e.ext6.Add(&x.C0, &x.C1) // a.Add(&x.C0, &x.C1) - b := e.ext6.Add(&y.C0, &y.C1) // b.Add(&y.C0, &y.C1) - a = e.ext6.Mul(a, b) // a.Mul(&a, &b) - b = e.ext6.Mul(&x.C0, &y.C0) // b.Mul(&x.C0, &y.C0) - c := e.ext6.Mul(&x.C1, &y.C1) // c.Mul(&x.C1, &y.C1) - z1 := e.ext6.Sub(a, b) // z.C1.Sub(&a, &b). - z1 = e.ext6.Sub(z1, c) // Sub(&z.C1, &c) - z0 := e.ext6.MulByNonResidue(c) // z.C0.MulByNonResidue(&c). - z0 = e.ext6.Add(z0, b) // Add(&z.C0, &b) - return &E12{ // return z + a := e.ext6.add(&x.C0, &x.C1) // a.Add(&x.C0, &x.C1) + b := e.ext6.add(&y.C0, &y.C1) // b.Add(&y.C0, &y.C1) + a = e.ext6.mul(a, b) // a.Mul(&a, &b) + b = e.ext6.mul(&x.C0, &y.C0) // b.Mul(&x.C0, &y.C0) + c := e.ext6.mul(&x.C1, &y.C1) // c.Mul(&x.C1, &y.C1) + z1 := e.ext6.sub(a, b) // z.C1.Sub(&a, &b). + z1 = e.ext6.sub(z1, c) // Sub(&z.C1, &c) + z0 := e.ext6.mulByNonResidue(c) // z.C0.MulByNonResidue(&c). + z0 = e.ext6.add(z0, b) // Add(&z.C0, &b) + return &e12{ // return z C0: *z0, C1: *z1, } } -func (e ext12) CyclotomicSquare(x *E12) *E12 { +func (e ext12) cyclotomicSquare(x *e12) *e12 { // var t [9]E2 - t0 := e.ext2.Square(&x.C1.B1) // t[0].Square(&x.C1.B1) - t1 := e.ext2.Square(&x.C0.B0) // t[1].Square(&x.C0.B0) - t6 := e.ext2.Add(&x.C1.B1, &x.C0.B0) // t[6].Add(&x.C1.B1, &x.C0.B0). - t6 = e.ext2.Square(t6) // Square(&t[6]). - t6 = e.ext2.Sub(t6, t0) // Sub(&t[6], &t[0]). - t6 = e.ext2.Sub(t6, t1) // Sub(&t[6], &t[1]) - t2 := e.ext2.Square(&x.C0.B2) // t[2].Square(&x.C0.B2) - t3 := e.ext2.Square(&x.C1.B0) // t[3].Square(&x.C1.B0) - t7 := e.ext2.Add(&x.C0.B2, &x.C1.B0) // t[7].Add(&x.C0.B2, &x.C1.B0). - t7 = e.ext2.Square(t7) // Square(&t[7]). - t7 = e.ext2.Sub(t7, t2) // Sub(&t[7], &t[2]). - t7 = e.ext2.Sub(t7, t3) // Sub(&t[7], &t[3]) - t4 := e.ext2.Square(&x.C1.B2) // t[4].Square(&x.C1.B2) - t5 := e.ext2.Square(&x.C0.B1) // t[5].Square(&x.C0.B1) - t8 := e.ext2.Add(&x.C1.B2, &x.C0.B1) // t[8].Add(&x.C1.B2, &x.C0.B1). - t8 = e.ext2.Square(t8) // Square(&t[8]). - t8 = e.ext2.Sub(t8, t4) // Sub(&t[8], &t[4]). - t8 = e.ext2.Sub(t8, t5) // Sub(&t[8], &t[5]). - t8 = e.ext2.MulByNonResidue(t8) // MulByNonResidue(&t[8]) - t0 = e.ext2.MulByNonResidue(t0) // t[0].MulByNonResidue(&t[0]). - t0 = e.ext2.Add(t0, t1) // Add(&t[0], &t[1]) - t2 = e.ext2.MulByNonResidue(t2) // t[2].MulByNonResidue(&t[2]). - t2 = e.ext2.Add(t2, t3) // Add(&t[2], &t[3]) - t4 = e.ext2.MulByNonResidue(t4) // t[4].MulByNonResidue(&t[4]). - t4 = e.ext2.Add(t4, t5) // Add(&t[4], &t[5]) - z00 := e.ext2.Sub(t0, &x.C0.B0) // z.C0.B0.Sub(&t[0], &x.C0.B0). - z00 = e.ext2.Double(z00) // Double(&z.C0.B0). - z00 = e.ext2.Add(z00, t0) // Add(&z.C0.B0, &t[0]) - z01 := e.ext2.Sub(t2, &x.C0.B1) // z.C0.B1.Sub(&t[2], &x.C0.B1). - z01 = e.ext2.Double(z01) // Double(&z.C0.B1). - z01 = e.ext2.Add(z01, t2) // Add(&z.C0.B1, &t[2]) - z02 := e.ext2.Sub(t4, &x.C0.B2) // z.C0.B2.Sub(&t[4], &x.C0.B2). - z02 = e.ext2.Double(z02) // Double(&z.C0.B2). - z02 = e.ext2.Add(z02, t4) // Add(&z.C0.B2, &t[4]) - z10 := e.ext2.Add(t8, &x.C1.B0) // z.C1.B0.Add(&t[8], &x.C1.B0). - z10 = e.ext2.Double(z10) // Double(&z.C1.B0). - z10 = e.ext2.Add(z10, t8) // Add(&z.C1.B0, &t[8]) - z11 := e.ext2.Add(t6, &x.C1.B1) // z.C1.B1.Add(&t[6], &x.C1.B1). - z11 = e.ext2.Double(z11) // Double(&z.C1.B1). - z11 = e.ext2.Add(z11, t6) // Add(&z.C1.B1, &t[6]) - z12 := e.ext2.Add(t7, &x.C1.B2) // z.C1.B2.Add(&t[7], &x.C1.B2). - z12 = e.ext2.Double(z12) // Double(&z.C1.B2). - z12 = e.ext2.Add(z12, t7) // Add(&z.C1.B2, &t[7]) - return &E12{ // return z - C0: E6{ + t0 := e.ext2.square(&x.C1.B1) // t[0].Square(&x.C1.B1) + t1 := e.ext2.square(&x.C0.B0) // t[1].Square(&x.C0.B0) + t6 := e.ext2.add(&x.C1.B1, &x.C0.B0) // t[6].Add(&x.C1.B1, &x.C0.B0). + t6 = e.ext2.square(t6) // Square(&t[6]). + t6 = e.ext2.sub(t6, t0) // Sub(&t[6], &t[0]). + t6 = e.ext2.sub(t6, t1) // Sub(&t[6], &t[1]) + t2 := e.ext2.square(&x.C0.B2) // t[2].Square(&x.C0.B2) + t3 := e.ext2.square(&x.C1.B0) // t[3].Square(&x.C1.B0) + t7 := e.ext2.add(&x.C0.B2, &x.C1.B0) // t[7].Add(&x.C0.B2, &x.C1.B0). + t7 = e.ext2.square(t7) // Square(&t[7]). + t7 = e.ext2.sub(t7, t2) // Sub(&t[7], &t[2]). + t7 = e.ext2.sub(t7, t3) // Sub(&t[7], &t[3]) + t4 := e.ext2.square(&x.C1.B2) // t[4].Square(&x.C1.B2) + t5 := e.ext2.square(&x.C0.B1) // t[5].Square(&x.C0.B1) + t8 := e.ext2.add(&x.C1.B2, &x.C0.B1) // t[8].Add(&x.C1.B2, &x.C0.B1). + t8 = e.ext2.square(t8) // Square(&t[8]). + t8 = e.ext2.sub(t8, t4) // Sub(&t[8], &t[4]). + t8 = e.ext2.sub(t8, t5) // Sub(&t[8], &t[5]). + t8 = e.ext2.mulByNonResidue(t8) // MulByNonResidue(&t[8]) + t0 = e.ext2.mulByNonResidue(t0) // t[0].MulByNonResidue(&t[0]). + t0 = e.ext2.add(t0, t1) // Add(&t[0], &t[1]) + t2 = e.ext2.mulByNonResidue(t2) // t[2].MulByNonResidue(&t[2]). + t2 = e.ext2.add(t2, t3) // Add(&t[2], &t[3]) + t4 = e.ext2.mulByNonResidue(t4) // t[4].MulByNonResidue(&t[4]). + t4 = e.ext2.add(t4, t5) // Add(&t[4], &t[5]) + z00 := e.ext2.sub(t0, &x.C0.B0) // z.C0.B0.Sub(&t[0], &x.C0.B0). + z00 = e.ext2.double(z00) // Double(&z.C0.B0). + z00 = e.ext2.add(z00, t0) // Add(&z.C0.B0, &t[0]) + z01 := e.ext2.sub(t2, &x.C0.B1) // z.C0.B1.Sub(&t[2], &x.C0.B1). + z01 = e.ext2.double(z01) // Double(&z.C0.B1). + z01 = e.ext2.add(z01, t2) // Add(&z.C0.B1, &t[2]) + z02 := e.ext2.sub(t4, &x.C0.B2) // z.C0.B2.Sub(&t[4], &x.C0.B2). + z02 = e.ext2.double(z02) // Double(&z.C0.B2). + z02 = e.ext2.add(z02, t4) // Add(&z.C0.B2, &t[4]) + z10 := e.ext2.add(t8, &x.C1.B0) // z.C1.B0.Add(&t[8], &x.C1.B0). + z10 = e.ext2.double(z10) // Double(&z.C1.B0). + z10 = e.ext2.add(z10, t8) // Add(&z.C1.B0, &t[8]) + z11 := e.ext2.add(t6, &x.C1.B1) // z.C1.B1.Add(&t[6], &x.C1.B1). + z11 = e.ext2.double(z11) // Double(&z.C1.B1). + z11 = e.ext2.add(z11, t6) // Add(&z.C1.B1, &t[6]) + z12 := e.ext2.add(t7, &x.C1.B2) // z.C1.B2.Add(&t[7], &x.C1.B2). + z12 = e.ext2.double(z12) // Double(&z.C1.B2). + z12 = e.ext2.add(z12, t7) // Add(&z.C1.B2, &t[7]) + return &e12{ // return z + C0: e6{ B0: *z00, B1: *z01, B2: *z02, }, - C1: E6{ + C1: e6{ B0: *z10, B1: *z11, B2: *z12, @@ -623,26 +623,26 @@ func (e ext12) CyclotomicSquare(x *E12) *E12 { } } -func (e ext12) Frobenius(x *E12) *E12 { +func (e ext12) frobenius(x *e12) *e12 { // var t [6]E2 - t0 := e.ext2.Conjugate(&x.C0.B0) // t[0].Conjugate(&x.C0.B0) - t1 := e.ext2.Conjugate(&x.C0.B1) // t[1].Conjugate(&x.C0.B1) - t2 := e.ext2.Conjugate(&x.C0.B2) // t[2].Conjugate(&x.C0.B2) - t3 := e.ext2.Conjugate(&x.C1.B0) // t[3].Conjugate(&x.C1.B0) - t4 := e.ext2.Conjugate(&x.C1.B1) // t[4].Conjugate(&x.C1.B1) - t5 := e.ext2.Conjugate(&x.C1.B2) // t[5].Conjugate(&x.C1.B2) - t1 = e.ext2.MulByNonResidue1Power2(t1) // t[1].MulByNonResidue1Power2(&t[1]) - t2 = e.ext2.MulByNonResidue1Power4(t2) // t[2].MulByNonResidue1Power4(&t[2]) - t3 = e.ext2.MulByNonResidue1Power1(t3) // t[3].MulByNonResidue1Power1(&t[3]) - t4 = e.ext2.MulByNonResidue1Power3(t4) // t[4].MulByNonResidue1Power3(&t[4]) - t5 = e.ext2.MulByNonResidue1Power5(t5) // t[5].MulByNonResidue1Power5(&t[5]) - return &E12{ // return z - C0: E6{ + t0 := e.ext2.conjugate(&x.C0.B0) // t[0].Conjugate(&x.C0.B0) + t1 := e.ext2.conjugate(&x.C0.B1) // t[1].Conjugate(&x.C0.B1) + t2 := e.ext2.conjugate(&x.C0.B2) // t[2].Conjugate(&x.C0.B2) + t3 := e.ext2.conjugate(&x.C1.B0) // t[3].Conjugate(&x.C1.B0) + t4 := e.ext2.conjugate(&x.C1.B1) // t[4].Conjugate(&x.C1.B1) + t5 := e.ext2.conjugate(&x.C1.B2) // t[5].Conjugate(&x.C1.B2) + t1 = e.ext2.mulByNonResidue1Power2(t1) // t[1].MulByNonResidue1Power2(&t[1]) + t2 = e.ext2.mulByNonResidue1Power4(t2) // t[2].MulByNonResidue1Power4(&t[2]) + t3 = e.ext2.mulByNonResidue1Power1(t3) // t[3].MulByNonResidue1Power1(&t[3]) + t4 = e.ext2.mulByNonResidue1Power3(t4) // t[4].MulByNonResidue1Power3(&t[4]) + t5 = e.ext2.mulByNonResidue1Power5(t5) // t[5].MulByNonResidue1Power5(&t[5]) + return &e12{ // return z + C0: e6{ B0: *t0, // z.C0.B0 = t[0] B1: *t1, // z.C0.B1 = t[1] B2: *t2, // z.C0.B2 = t[2] }, - C1: E6{ + C1: e6{ B0: *t3, // z.C1.B0 = t[3] B1: *t4, // z.C1.B1 = t[4] B2: *t5, // z.C1.B2 = t[5] @@ -650,39 +650,39 @@ func (e ext12) Frobenius(x *E12) *E12 { } } -func (e ext12) FrobeniusSquare(x *E12) *E12 { +func (e ext12) frobeniusSquare(x *e12) *e12 { z00 := &x.C0.B0 // z.C0.B0 = x.C0.B0 - z01 := e.ext2.MulByNonResidue2Power2(&x.C0.B1) // z.C0.B1.MulByNonResidue2Power2(&x.C0.B1) - z02 := e.ext2.MulByNonResidue2Power4(&x.C0.B2) // z.C0.B2.MulByNonResidue2Power4(&x.C0.B2) - z10 := e.ext2.MulByNonResidue2Power1(&x.C1.B0) // z.C1.B0.MulByNonResidue2Power1(&x.C1.B0) - z11 := e.ext2.MulByNonResidue2Power3(&x.C1.B1) // z.C1.B1.MulByNonResidue2Power3(&x.C1.B1) - z12 := e.ext2.MulByNonResidue2Power5(&x.C1.B2) // z.C1.B2.MulByNonResidue2Power5(&x.C1.B2) - return &E12{ // return z - C0: E6{B0: *z00, B1: *z01, B2: *z02}, - C1: E6{B0: *z10, B1: *z11, B2: *z12}, + z01 := e.ext2.mulByNonResidue2Power2(&x.C0.B1) // z.C0.B1.MulByNonResidue2Power2(&x.C0.B1) + z02 := e.ext2.mulByNonResidue2Power4(&x.C0.B2) // z.C0.B2.MulByNonResidue2Power4(&x.C0.B2) + z10 := e.ext2.mulByNonResidue2Power1(&x.C1.B0) // z.C1.B0.MulByNonResidue2Power1(&x.C1.B0) + z11 := e.ext2.mulByNonResidue2Power3(&x.C1.B1) // z.C1.B1.MulByNonResidue2Power3(&x.C1.B1) + z12 := e.ext2.mulByNonResidue2Power5(&x.C1.B2) // z.C1.B2.MulByNonResidue2Power5(&x.C1.B2) + return &e12{ // return z + C0: e6{B0: *z00, B1: *z01, B2: *z02}, + C1: e6{B0: *z10, B1: *z11, B2: *z12}, } } -func (e ext12) FrobeniusCube(x *E12) *E12 { +func (e ext12) frobeniusCube(x *e12) *e12 { // var t [6]E2 - t0 := e.ext2.Conjugate(&x.C0.B0) // t[0].Conjugate(&x.C0.B0) - t1 := e.ext2.Conjugate(&x.C0.B1) // t[1].Conjugate(&x.C0.B1) - t2 := e.ext2.Conjugate(&x.C0.B2) // t[2].Conjugate(&x.C0.B2) - t3 := e.ext2.Conjugate(&x.C1.B0) // t[3].Conjugate(&x.C1.B0) - t4 := e.ext2.Conjugate(&x.C1.B1) // t[4].Conjugate(&x.C1.B1) - t5 := e.ext2.Conjugate(&x.C1.B2) // t[5].Conjugate(&x.C1.B2) - t1 = e.ext2.MulByNonResidue3Power2(t1) // t[1].MulByNonResidue3Power2(&t[1]) - t2 = e.ext2.MulByNonResidue3Power4(t2) // t[2].MulByNonResidue3Power4(&t[2]) - t3 = e.ext2.MulByNonResidue3Power1(t3) // t[3].MulByNonResidue3Power1(&t[3]) - t4 = e.ext2.MulByNonResidue3Power3(t4) // t[4].MulByNonResidue3Power3(&t[4]) - t5 = e.ext2.MulByNonResidue3Power5(t5) // t[5].MulByNonResidue3Power5(&t[5]) - return &E12{ // return z - C0: E6{ + t0 := e.ext2.conjugate(&x.C0.B0) // t[0].Conjugate(&x.C0.B0) + t1 := e.ext2.conjugate(&x.C0.B1) // t[1].Conjugate(&x.C0.B1) + t2 := e.ext2.conjugate(&x.C0.B2) // t[2].Conjugate(&x.C0.B2) + t3 := e.ext2.conjugate(&x.C1.B0) // t[3].Conjugate(&x.C1.B0) + t4 := e.ext2.conjugate(&x.C1.B1) // t[4].Conjugate(&x.C1.B1) + t5 := e.ext2.conjugate(&x.C1.B2) // t[5].Conjugate(&x.C1.B2) + t1 = e.ext2.mulByNonResidue3Power2(t1) // t[1].MulByNonResidue3Power2(&t[1]) + t2 = e.ext2.mulByNonResidue3Power4(t2) // t[2].MulByNonResidue3Power4(&t[2]) + t3 = e.ext2.mulByNonResidue3Power1(t3) // t[3].MulByNonResidue3Power1(&t[3]) + t4 = e.ext2.mulByNonResidue3Power3(t4) // t[4].MulByNonResidue3Power3(&t[4]) + t5 = e.ext2.mulByNonResidue3Power5(t5) // t[5].MulByNonResidue3Power5(&t[5]) + return &e12{ // return z + C0: e6{ B0: *t0, // z.C0.B0 = t[0] B1: *t1, // z.C0.B1 = t[1] B2: *t2, // z.C0.B2 = t[2] }, - C1: E6{ + C1: e6{ B0: *t3, // z.C1.B0 = t[3] B1: *t4, // z.C1.B1 = t[4] B2: *t5, // z.C1.B2 = t[5] @@ -690,129 +690,129 @@ func (e ext12) FrobeniusCube(x *E12) *E12 { } } -func (e ext12) Expt(x *E12) *E12 { +func (e ext12) expt(x *e12) *e12 { // var result, t0, t1, t2, t3, t4, t5, t6 E12 - t3 := e.CyclotomicSquare(x) // t3.CyclotomicSquare(x) - t5 := e.CyclotomicSquare(t3) // t5.CyclotomicSquare(&t3) - result := e.CyclotomicSquare(t5) // result.CyclotomicSquare(&t5) - t0 := e.CyclotomicSquare(result) // t0.CyclotomicSquare(&result) - t2 := e.Mul(x, t0) // t2.Mul(x, &t0) - t0 = e.Mul(t3, t2) // t0.Mul(&t3, &t2) - t1 := e.Mul(x, t0) // t1.Mul(x, &t0) - t4 := e.Mul(result, t2) // t4.Mul(&result, &t2) - t6 := e.CyclotomicSquare(t2) // t6.CyclotomicSquare(&t2) - t1 = e.Mul(t0, t1) // t1.Mul(&t0, &t1) - t0 = e.Mul(t3, t1) // t0.Mul(&t3, &t1) + t3 := e.cyclotomicSquare(x) // t3.CyclotomicSquare(x) + t5 := e.cyclotomicSquare(t3) // t5.CyclotomicSquare(&t3) + result := e.cyclotomicSquare(t5) // result.CyclotomicSquare(&t5) + t0 := e.cyclotomicSquare(result) // t0.CyclotomicSquare(&result) + t2 := e.mul(x, t0) // t2.Mul(x, &t0) + t0 = e.mul(t3, t2) // t0.Mul(&t3, &t2) + t1 := e.mul(x, t0) // t1.Mul(x, &t0) + t4 := e.mul(result, t2) // t4.Mul(&result, &t2) + t6 := e.cyclotomicSquare(t2) // t6.CyclotomicSquare(&t2) + t1 = e.mul(t0, t1) // t1.Mul(&t0, &t1) + t0 = e.mul(t3, t1) // t0.Mul(&t3, &t1) t6 = e.nSquare(t6, 6) // t6.nSquare(6) - t5 = e.Mul(t5, t6) // t5.Mul(&t5, &t6) - t5 = e.Mul(t4, t5) // t5.Mul(&t4, &t5) + t5 = e.mul(t5, t6) // t5.Mul(&t5, &t6) + t5 = e.mul(t4, t5) // t5.Mul(&t4, &t5) t5 = e.nSquare(t5, 7) // t5.nSquare(7) - t4 = e.Mul(t4, t5) // t4.Mul(&t4, &t5) + t4 = e.mul(t4, t5) // t4.Mul(&t4, &t5) t4 = e.nSquare(t4, 8) // t4.nSquare(8) - t4 = e.Mul(t0, t4) // t4.Mul(&t0, &t4) - t3 = e.Mul(t3, t4) // t3.Mul(&t3, &t4) + t4 = e.mul(t0, t4) // t4.Mul(&t0, &t4) + t3 = e.mul(t3, t4) // t3.Mul(&t3, &t4) t3 = e.nSquare(t3, 6) // t3.nSquare(6) - t2 = e.Mul(t2, t3) // t2.Mul(&t2, &t3) + t2 = e.mul(t2, t3) // t2.Mul(&t2, &t3) t2 = e.nSquare(t2, 8) // t2.nSquare(8) - t2 = e.Mul(t0, t2) // t2.Mul(&t0, &t2) + t2 = e.mul(t0, t2) // t2.Mul(&t0, &t2) t2 = e.nSquare(t2, 6) // t2.nSquare(6) - t2 = e.Mul(t0, t2) // t2.Mul(&t0, &t2) + t2 = e.mul(t0, t2) // t2.Mul(&t0, &t2) t2 = e.nSquare(t2, 10) // t2.nSquare(10) - t1 = e.Mul(t1, t2) // t1.Mul(&t1, &t2) + t1 = e.mul(t1, t2) // t1.Mul(&t1, &t2) t1 = e.nSquare(t1, 6) // t1.nSquare(6) - t0 = e.Mul(t0, t1) // t0.Mul(&t0, &t1) - z := e.Mul(result, t0) // z.Mul(&result, &t0) + t0 = e.mul(t0, t1) // t0.Mul(&t0, &t1) + z := e.mul(result, t0) // z.Mul(&result, &t0) return z // return z } -func (e ext12) One() *E12 { +func (e ext12) one() *e12 { z000 := e.fp.One() zero := e.fp.Zero() - return &E12{ - C0: E6{ - B0: E2{A0: *z000, A1: *zero}, - B1: E2{A0: *zero, A1: *zero}, - B2: E2{A0: *zero, A1: *zero}, + return &e12{ + C0: e6{ + B0: e2{A0: *z000, A1: *zero}, + B1: e2{A0: *zero, A1: *zero}, + B2: e2{A0: *zero, A1: *zero}, }, - C1: E6{ - B0: E2{A0: *zero, A1: *zero}, - B1: E2{A0: *zero, A1: *zero}, - B2: E2{A0: *zero, A1: *zero}, + C1: e6{ + B0: e2{A0: *zero, A1: *zero}, + B1: e2{A0: *zero, A1: *zero}, + B2: e2{A0: *zero, A1: *zero}, }, } } -func (e ext12) MulBy034(z *E12, c0, c3, c4 *E2) *E12 { +func (e ext12) mulBy034(z *e12, c0, c3, c4 *e2) *e12 { // var a, b, d E6 - a := e.ext6.MulByE2(&z.C0, c0) // a.MulByE2(&z.C0, c0) + a := e.ext6.mulByE2(&z.C0, c0) // a.MulByE2(&z.C0, c0) // b.Set(&z.C1) - b := e.ext6.MulBy01(&z.C1, c3, c4) // b.MulBy01(c3, c4) - c0 = e.ext2.Add(c0, c3) // c0.Add(c0, c3) - d := e.ext6.Add(&z.C0, &z.C1) // d.Add(&z.C0, &z.C1) - d = e.ext6.MulBy01(d, c0, c4) // d.MulBy01(c0, c4) - z1 := e.Add(a, b) // z.C1.Add(&a, &b). - z1 = e.Neg(z1) // Neg(&z.C1). - z1 = e.Add(z1, d) // Add(&z.C1, &d) - z0 := e.MulByNonResidue(b) // z.C0.MulByNonResidue(&b). - z0 = e.Add(z0, a) // Add(&z.C0, &a) - return &E12{ // return z + b := e.ext6.mulBy01(&z.C1, c3, c4) // b.MulBy01(c3, c4) + c0 = e.ext2.add(c0, c3) // c0.Add(c0, c3) + d := e.ext6.add(&z.C0, &z.C1) // d.Add(&z.C0, &z.C1) + d = e.ext6.mulBy01(d, c0, c4) // d.MulBy01(c0, c4) + z1 := e.add(a, b) // z.C1.Add(&a, &b). + z1 = e.neg(z1) // Neg(&z.C1). + z1 = e.add(z1, d) // Add(&z.C1, &d) + z0 := e.mulByNonResidue(b) // z.C0.MulByNonResidue(&b). + z0 = e.add(z0, a) // Add(&z.C0, &a) + return &e12{ // return z C0: *z0, C1: *z1, } } -func (e ext12) Square(x *E12) *E12 { +func (e ext12) square(x *e12) *e12 { // var c0, c2, c3 E6 - c0 := e.ext6.Sub(&x.C0, &x.C1) // c0.Sub(&x.C0, &x.C1) - c3 := e.ext6.MulByNonResidue(&x.C1) // c3.MulByNonResidue(&x.C1). - c3 = e.ext6.Neg(c3) // Neg(&c3). - c3 = e.ext6.Add(&x.C0, c3) // Add(&x.C0, &c3) - c2 := e.ext6.Mul(&x.C0, &x.C1) // c2.Mul(&x.C0, &x.C1) - c0 = e.ext6.Mul(c0, c3) // c0.Mul(&c0, &c3). - c0 = e.ext6.Add(c0, c2) // Add(&c0, &c2) - z1 := e.ext6.Double(c2) // z.C1.Double(&c2) - c2 = e.ext6.MulByNonResidue(c2) // c2.MulByNonResidue(&c2) - z0 := e.ext6.Add(c0, c2) // z.C0.Add(&c0, &c2) - return &E12{ // return z + c0 := e.ext6.sub(&x.C0, &x.C1) // c0.Sub(&x.C0, &x.C1) + c3 := e.ext6.mulByNonResidue(&x.C1) // c3.MulByNonResidue(&x.C1). + c3 = e.ext6.neg(c3) // Neg(&c3). + c3 = e.ext6.add(&x.C0, c3) // Add(&x.C0, &c3) + c2 := e.ext6.mul(&x.C0, &x.C1) // c2.Mul(&x.C0, &x.C1) + c0 = e.ext6.mul(c0, c3) // c0.Mul(&c0, &c3). + c0 = e.ext6.add(c0, c2) // Add(&c0, &c2) + z1 := e.ext6.double(c2) // z.C1.Double(&c2) + c2 = e.ext6.mulByNonResidue(c2) // c2.MulByNonResidue(&c2) + z0 := e.ext6.add(c0, c2) // z.C0.Add(&c0, &c2) + return &e12{ // return z C0: *z0, C1: *z1, } } -func (e ext12) MulBy034by034(d0, d3, d4, c0, c3, c4 *E2) *E12 { +func (e ext12) mulBy034by034(d0, d3, d4, c0, c3, c4 *e2) *e12 { // var tmp, x0, x3, x4, x04, x03, x34 E2 - x0 := e.ext2.Mul(c0, d0) // x0.Mul(c0, d0) - x3 := e.ext2.Mul(c3, d3) // x3.Mul(c3, d3) - x4 := e.ext2.Mul(c4, d4) // x4.Mul(c4, d4) - tmp := e.ext2.Add(c0, c4) // tmp.Add(c0, c4) - x04 := e.ext2.Add(d0, d4) // x04.Add(d0, d4). - x04 = e.ext2.Mul(x04, tmp) // Mul(&x04, &tmp). - x04 = e.ext2.Sub(x04, x0) // Sub(&x04, &x0). - x04 = e.ext2.Sub(x04, x4) // Sub(&x04, &x4) - tmp = e.ext2.Add(c0, c3) // tmp.Add(c0, c3) - x03 := e.ext2.Add(d0, d3) // x03.Add(d0, d3). - x03 = e.ext2.Mul(x03, tmp) // Mul(&x03, &tmp). - x03 = e.ext2.Sub(x03, x0) // Sub(&x03, &x0). - x03 = e.ext2.Sub(x03, x3) // Sub(&x03, &x3) - tmp = e.ext2.Add(c3, c4) // tmp.Add(c3, c4) - x34 := e.ext2.Add(d3, d4) // x34.Add(d3, d4). - x34 = e.ext2.Mul(x34, tmp) // Mul(&x34, &tmp). - x34 = e.ext2.Sub(x34, x3) // Sub(&x34, &x3). - x34 = e.ext2.Sub(x34, x4) // Sub(&x34, &x4) - z00 := e.ext2.MulByNonResidue(x4) // z.C0.B0.MulByNonResidue(&x4). - z00 = e.ext2.Add(z00, x0) // Add(&z.C0.B0, &x0) + x0 := e.ext2.mul(c0, d0) // x0.Mul(c0, d0) + x3 := e.ext2.mul(c3, d3) // x3.Mul(c3, d3) + x4 := e.ext2.mul(c4, d4) // x4.Mul(c4, d4) + tmp := e.ext2.add(c0, c4) // tmp.Add(c0, c4) + x04 := e.ext2.add(d0, d4) // x04.Add(d0, d4). + x04 = e.ext2.mul(x04, tmp) // Mul(&x04, &tmp). + x04 = e.ext2.sub(x04, x0) // Sub(&x04, &x0). + x04 = e.ext2.sub(x04, x4) // Sub(&x04, &x4) + tmp = e.ext2.add(c0, c3) // tmp.Add(c0, c3) + x03 := e.ext2.add(d0, d3) // x03.Add(d0, d3). + x03 = e.ext2.mul(x03, tmp) // Mul(&x03, &tmp). + x03 = e.ext2.sub(x03, x0) // Sub(&x03, &x0). + x03 = e.ext2.sub(x03, x3) // Sub(&x03, &x3) + tmp = e.ext2.add(c3, c4) // tmp.Add(c3, c4) + x34 := e.ext2.add(d3, d4) // x34.Add(d3, d4). + x34 = e.ext2.mul(x34, tmp) // Mul(&x34, &tmp). + x34 = e.ext2.sub(x34, x3) // Sub(&x34, &x3). + x34 = e.ext2.sub(x34, x4) // Sub(&x34, &x4) + z00 := e.ext2.mulByNonResidue(x4) // z.C0.B0.MulByNonResidue(&x4). + z00 = e.ext2.add(z00, x0) // Add(&z.C0.B0, &x0) z01 := x3 // z.C0.B1.Set(&x3) z02 := x34 // z.C0.B2.Set(&x34) z10 := x03 // z.C1.B0.Set(&x03) z11 := x04 // z.C1.B1.Set(&x04) - z12 := e.ext2.Zero() // z.C1.B2.SetZero() - return &E12{ // return z - C0: E6{ + z12 := e.ext2.zero() // z.C1.B2.SetZero() + return &e12{ // return z + C0: e6{ B0: *z00, B1: *z01, B2: *z02, }, - C1: E6{ + C1: e6{ B0: *z10, B1: *z11, B2: *z12, @@ -820,14 +820,14 @@ func (e ext12) MulBy034by034(d0, d3, d4, c0, c3, c4 *E2) *E12 { } } -func (e ext12) AssertIsEqual(x, y *E12) { - e.ext6.AssertIsEqual(&x.C0, &y.C0) - e.ext6.AssertIsEqual(&x.C1, &y.C1) +func (e ext12) assertIsEqual(x, y *e12) { + e.ext6.assertIsEqual(&x.C0, &y.C0) + e.ext6.assertIsEqual(&x.C1, &y.C1) } -func (e ext12) nSquare(z *E12, n int) *E12 { +func (e ext12) nSquare(z *e12, n int) *e12 { for i := 0; i < n; i++ { - z = e.CyclotomicSquare(z) + z = e.cyclotomicSquare(z) } return z } From 41d98e28e527a33a3dfd5ced0123cbe6afe17aec Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Fri, 17 Feb 2023 19:38:35 +0100 Subject: [PATCH 016/464] feat: add equality assertion for GT elements --- std/algebra/pairing_bn254/pairing.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/std/algebra/pairing_bn254/pairing.go b/std/algebra/pairing_bn254/pairing.go index 8fb1d6f782..ec0baa633b 100644 --- a/std/algebra/pairing_bn254/pairing.go +++ b/std/algebra/pairing_bn254/pairing.go @@ -276,3 +276,7 @@ func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { res = pr.FinalExponentiation(res) return res, nil } + +func (pr Pairing) AssertIsEqual(x, y *GTEl) { + pr.ext12.assertIsEqual(x, y) +} From c2f401d0421877d0e15535367b761737f4f207b1 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Fri, 17 Feb 2023 19:39:01 +0100 Subject: [PATCH 017/464] docs: add package documentation and example --- std/algebra/pairing_bn254/doc.go | 7 ++ std/algebra/pairing_bn254/doc_test.go | 101 ++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 std/algebra/pairing_bn254/doc.go create mode 100644 std/algebra/pairing_bn254/doc_test.go diff --git a/std/algebra/pairing_bn254/doc.go b/std/algebra/pairing_bn254/doc.go new file mode 100644 index 0000000000..5f04a7dd72 --- /dev/null +++ b/std/algebra/pairing_bn254/doc.go @@ -0,0 +1,7 @@ +// Package pairing_bn254 implements pairing over BN254 curve. +// +// The implementation follows very closely the implementation of its out-circuit +// counterpart in [gnark-crypto]. +// +// [gnark-crypto]: https://github.com/ConsenSys/gnark-crypto/tree/master/ecc/bn254 +package pairing_bn254 diff --git a/std/algebra/pairing_bn254/doc_test.go b/std/algebra/pairing_bn254/doc_test.go new file mode 100644 index 0000000000..8481c45361 --- /dev/null +++ b/std/algebra/pairing_bn254/doc_test.go @@ -0,0 +1,101 @@ +package pairing_bn254_test + +import ( + "crypto/rand" + "fmt" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/backend/groth16" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/std/algebra/pairing_bn254" +) + +type PairCircuit struct { + InG1 pairing_bn254.G1Affine + InG2 pairing_bn254.G2Affine + Res pairing_bn254.GTEl +} + +func (c *PairCircuit) Define(api frontend.API) error { + pairing, err := pairing_bn254.NewPairing(api) + if err != nil { + return fmt.Errorf("new pairing: %w", err) + } + res, err := pairing.Pair([]*pairing_bn254.G1Affine{&c.InG1}, []*pairing_bn254.G2Affine{&c.InG2}) + if err != nil { + return fmt.Errorf("pair: %w", err) + } + pairing.AssertIsEqual(res, &c.Res) + return nil +} + +func ExamplePairing() { + p, q, err := randomG1G2Affines() + if err != nil { + panic(err) + } + res, err := bn254.Pair([]bn254.G1Affine{p}, []bn254.G2Affine{q}) + if err != nil { + panic(err) + } + circuit := PairCircuit{} + witness := PairCircuit{ + InG1: pairing_bn254.NewG1Affine(p), + InG2: pairing_bn254.NewG2Affine(q), + Res: pairing_bn254.NewGTEl(res), + } + ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) + if err != nil { + panic(err) + } else { + fmt.Println("compiled") + } + pk, vk, err := groth16.Setup(ccs) + if err != nil { + panic(err) + } else { + fmt.Println("setup done") + } + secretWitness, err := frontend.NewWitness(&witness, ecc.BN254.ScalarField()) + if err != nil { + panic(err) + } else { + fmt.Println("secret witness") + } + publicWitness, err := secretWitness.Public() + if err != nil { + panic(err) + } else { + fmt.Println("public witness") + } + proof, err := groth16.Prove(ccs, pk, secretWitness) + if err != nil { + panic(err) + } else { + fmt.Println("proof") + } + err = groth16.Verify(proof, vk, publicWitness) + if err != nil { + panic(err) + } else { + fmt.Println("verify") + } +} + +func randomG1G2Affines() (p bn254.G1Affine, q bn254.G2Affine, err error) { + _, _, G1AffGen, G2AffGen := bn254.Generators() + mod := bn254.ID.ScalarField() + s1, err := rand.Int(rand.Reader, mod) + if err != nil { + return p, q, err + } + s2, err := rand.Int(rand.Reader, mod) + if err != nil { + return p, q, err + } + p.ScalarMultiplication(&G1AffGen, s1) + q.ScalarMultiplication(&G2AffGen, s2) + return +} From 3e4133b58013e2e77178353117575453f1c91e3c Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 21 Feb 2023 20:07:29 +0100 Subject: [PATCH 018/464] style: rename variables --- std/algebra/weierstrass/params.go | 2040 ++++++++++++++--------------- std/algebra/weierstrass/point.go | 1534 +++++++++++----------- 2 files changed, 1785 insertions(+), 1789 deletions(-) diff --git a/std/algebra/weierstrass/params.go b/std/algebra/weierstrass/params.go index 6e7a85c2ad..ad6699f28d 100644 --- a/std/algebra/weierstrass/params.go +++ b/std/algebra/weierstrass/params.go @@ -17,8 +17,8 @@ type CurveParams struct { B *big.Int // b in curve equation Gx *big.Int // base point x Gy *big.Int // base point y - Gmx [257]*big.Int // m*base point x - Gmy [257]*big.Int // m*base point y + Gmx [256]*big.Int // m*base point x + Gmy [256]*big.Int // m*base point y } // GetSecp256k1Params returns curve parameters for the curve secp256k1. When @@ -33,521 +33,519 @@ func GetSecp256k1Params() CurveParams { g5y, _ := new(big.Int).SetString("d8ac222636e5e3d6d4dba9dda6c9c426f788271bab0d6840dca87d3aa6ac62d6", 16) g7x, _ := new(big.Int).SetString("5cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc", 16) g7y, _ := new(big.Int).SetString("6aebca40ba255960a3178d6d861a54dba813d0b813fde7b5a5082628087264da", 16) - g8x, _ := new(big.Int).SetString("2f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01", 16) - g8y, _ := new(big.Int).SetString("5c4da8a741539949293d082a132d13b4c2e213d6ba5b7617b5da2cb76cbde904", 16) - g16x, _ := new(big.Int).SetString("e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", 16) - g16y, _ := new(big.Int).SetString("f7e3507399e595929db99f34f57937101296891e44d23f0be1f32cce69616821", 16) - g32x, _ := new(big.Int).SetString("d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", 16) - g32y, _ := new(big.Int).SetString("95038d9d0ae3d5c3b3d6dec9e98380651f760cc364ed819605b3ff1f24106ab9", 16) - g64x, _ := new(big.Int).SetString("bf23c1542d16eab70b1051eaf832823cfc4c6f1dcdbafd81e37918e6f874ef8b", 16) - g64y, _ := new(big.Int).SetString("5cb3866fc33003737ad928a0ba5392e4c522fc54811e2f784dc37efe66831d9f", 16) - g128x, _ := new(big.Int).SetString("34ff3be4033f7a06696c3d09f7d1671cbcf55cd700535655647077456769a24e", 16) - g128y, _ := new(big.Int).SetString("5d9d11623a236c553f6619d89832098c55df16c3e8f8b6818491067a73cc2f1a", 16) - g256x, _ := new(big.Int).SetString("8282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508", 16) - g256y, _ := new(big.Int).SetString("11f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf", 16) - g512x, _ := new(big.Int).SetString("465370b287a79ff3905a857a9cf918d50adbc968d9e159d0926e2c00ef34a24d", 16) - g512y, _ := new(big.Int).SetString("35e531b38368c082a4af8bdafdeec2c1588e09b215d37a10a2f8fb20b33887f4", 16) - g1024x, _ := new(big.Int).SetString("241febb8e23cbd77d664a18f66ad6240aaec6ecdc813b088d5b901b2e285131f", 16) - g1024y, _ := new(big.Int).SetString("513378d9ff94f8d3d6c420bd13981df8cd50fd0fbd0cb5afabb3e66f2750026d", 16) - g2048x, _ := new(big.Int).SetString("5d1bdb4ea172fa79fce4cc2983d8f8d9fc318b85f423de0dedcb63069b920471", 16) - g2048y, _ := new(big.Int).SetString("2843826779379e2e794bb99438a2265679eb1e9996c56e7b70330666f7b83103", 16) - g4096x, _ := new(big.Int).SetString("175e159f728b865a72f99cc6c6fc846de0b93833fd2222ed73fce5b551e5b739", 16) - g4096y, _ := new(big.Int).SetString("d3506e0d9e3c79eba4ef97a51ff71f5eacb5955add24345c6efa6ffee9fed695", 16) - g8192x, _ := new(big.Int).SetString("423a013f03ff32d7a5ffbcc8e139c62130fdfeb5c6da121bce78049e46bc47d6", 16) - g8192y, _ := new(big.Int).SetString("b91ae00fe1e1d970a1179f7bbaf6b3c7720d8ec3524f009ed1236e6d8b548a34", 16) - g16384x, _ := new(big.Int).SetString("111d6a45ac1fb90508907a7abcd6877649df662f3b3e2741302df6f78416824a", 16) - g16384y, _ := new(big.Int).SetString("696911c478eaffbb90d48dbff065952f070008996daca4ca9a111d42108e9d0", 16) - g32768x, _ := new(big.Int).SetString("4a4a6dc97ac7c8b8ad795dbebcb9dcff7290b68a5ef74e56ab5edde01bced775", 16) - g32768y, _ := new(big.Int).SetString("529911b016631e72943ef9f739c0f4571de90cdb424742acb2bf8f68a78dd66d", 16) - g65536x, _ := new(big.Int).SetString("363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640", 16) - g65536y, _ := new(big.Int).SetString("4e273adfc732221953b445397f3363145b9a89008199ecb62003c7f3bee9de9", 16) - g131072x, _ := new(big.Int).SetString("4c1b9866ed9a7e9b553973c6c93b02bf0b62fb012edfb59dd2712a5caf92c541", 16) - g131072y, _ := new(big.Int).SetString("c1f792d320be8a0f7fbcb753ce56e69cc652ead7e43eb1ad72c4f3fdc68fe020", 16) - g262144x, _ := new(big.Int).SetString("a4083877ba83b12b529a2f3c0780b54e3233edbc1a28f135e0c8f28cbeaaf3d1", 16) - g262144y, _ := new(big.Int).SetString("40e9f612feefbc79b8bf83d69361b3e22001e7576ed1ef90b12b534df0b254b9", 16) - g524288x, _ := new(big.Int).SetString("a804c641d28cc0b53a4e3e1a2f56c86f6e0d880a454203b98cd3db5a7940d33a", 16) - g524288y, _ := new(big.Int).SetString("95be83252b2fa6d03dec2842c16047e81af18ca89cf736a943ce95fa6d46967a", 16) - g1048576x, _ := new(big.Int).SetString("8b4b5f165df3c2be8c6244b5b745638843e4a781a15bcd1b69f79a55dffdf80c", 16) - g1048576y, _ := new(big.Int).SetString("4aad0a6f68d308b4b3fbd7813ab0da04f9e336546162ee56b3eff0c65fd4fd36", 16) - g2097152x, _ := new(big.Int).SetString("ed0c5ce4e13291718ce17c7ec83c611071af64ee417c997abb3f26714755e4be", 16) - g2097152y, _ := new(big.Int).SetString("221a9fc7bc2345bdbf3dad7f5a7ea68049d93925763ddab163f9fa6ea07bf42f", 16) - g4194304x, _ := new(big.Int).SetString("faecb013c44ce694b3b15c3f83f1fae8e53254566e0552ced4b6e6c807cec8ab", 16) - g4194304y, _ := new(big.Int).SetString("cc09b5e90e9ecb57fc2e02c6ec2fb13d9c32b286b85e2e2e8981dfd9ab155070", 16) - g8388608x, _ := new(big.Int).SetString("9bb8a132dcad2f2c8731a0b37cbcafdb3b2dd824f23cd3e07f64eae9ad1b1f7", 16) - g8388608y, _ := new(big.Int).SetString("945bb2b2afeee3b9b6f9dd284f863e850f54a840f4752d5364130627c3811c80", 16) - g16777216x, _ := new(big.Int).SetString("723cbaa6e5db996d6bf771c00bd548c7b700dbffa6c0e77bcb6115925232fcda", 16) - g16777216y, _ := new(big.Int).SetString("96e867b5595cc498a921137488824d6e2660a0653779494801dc069d9eb39f5f", 16) - g33554432x, _ := new(big.Int).SetString("57efa786437b744d343d7dc45773a3c62d240a43079849071fd383d60ca030d5", 16) - g33554432y, _ := new(big.Int).SetString("d712db0bd1b48518893627c928de03ec689b6d2ae5e9974ab07ab44274b02f9e", 16) - g67108864x, _ := new(big.Int).SetString("264bbd436a28bc42a2df7e9cd5226cb91080577e327b012a7fafc7770c584dd5", 16) - g67108864y, _ := new(big.Int).SetString("d87c6fa94ee093b4d4f75ce24c33be226a118243717b8d8de61227937704ab11", 16) - g134217728x, _ := new(big.Int).SetString("a94c6524bd40d2bbdac85c056236a79da78bc61fd5bdec9d2bf26bd84b2438e8", 16) - g134217728y, _ := new(big.Int).SetString("b5201fd992f96280fd79219505019e3a7e5d3c60a0e39b2bc2e2c8dbf18661f4", 16) - g268435456x, _ := new(big.Int).SetString("eebfa4d493bebf98ba5feec812c2d3b50947961237a919839a533eca0e7dd7fa", 16) - g268435456y, _ := new(big.Int).SetString("5d9a8ca3970ef0f269ee7edaf178089d9ae4cdc3a711f712ddfd4fdae1de8999", 16) - g536870912x, _ := new(big.Int).SetString("381c4ad7a7a97bfda61c6031c118495fc4ea4bc08f6766d676bee90847d297fd", 16) - g536870912y, _ := new(big.Int).SetString("936af53b238eeee48f3e5fa709915eccf0451032db939c0093ace3187d493fc5", 16) - g1073741824x, _ := new(big.Int).SetString("e1efb9cd05adc63bcce10831d9538c479cf1d05fefdd08b2448d70422ede454c", 16) - g1073741824y, _ := new(big.Int).SetString("ecb4530d8af9be7b0154c1ffe477123464e3244a7a2d4c6ad9fd233a8913797", 16) - g2147483648x, _ := new(big.Int).SetString("5318f9b1a2697010c5ac235e9af475a8c7e5419f33d47b18d33feeb329eb99a4", 16) - g2147483648y, _ := new(big.Int).SetString("f44ccfeb4beda4195772d93aebb405e8a41f2b40d1e3ec652c726eeefe91f92d", 16) - g4294967296x, _ := new(big.Int).SetString("100f44da696e71672791d0a09b7bde459f1215a29b3c03bfefd7835b39a48db0", 16) - g4294967296y, _ := new(big.Int).SetString("cdd9e13192a00b772ec8f3300c090666b7ff4a18ff5195ac0fbd5cd62bc65a09", 16) - g8589934592x, _ := new(big.Int).SetString("8c0989f2ceb5c771a8415dff2b4c4199d8d9c8f9237d08084b05284f1e4df706", 16) - g8589934592y, _ := new(big.Int).SetString("fb4dbd044f432034ffd2172cb9dc966c60de6bf5156511aa736ac5a35d72fa98", 16) - g17179869184x, _ := new(big.Int).SetString("fb8f153c5e266704c4a481743262c0259c528539bc95bc1bb1e63c33dc47bffd", 16) - g17179869184y, _ := new(big.Int).SetString("6ca27a9dc5e0621816fa11d9b4bccd531dde1389ac542613090a45ddd949b095", 16) - g34359738368x, _ := new(big.Int).SetString("e747333fd75d51755a0cc9f0a728708465a02c587737a7b8b8fa1b8b4bb2629a", 16) - g34359738368y, _ := new(big.Int).SetString("f2affe0145070c114cc43603804c2581c88376aa6e1a969a9f8d961a6946f6d6", 16) - g68719476736x, _ := new(big.Int).SetString("e1031be262c7ed1b1dc9227a4a04c017a77f8d4464f3b3852c8acde6e534fd2d", 16) - g68719476736y, _ := new(big.Int).SetString("9d7061928940405e6bb6a4176597535af292dd419e1ced79a44f18f29456a00d", 16) - g137438953472x, _ := new(big.Int).SetString("f4b93f224c8089eab9f95dcd0f29b2c9028a6ac5de94d85784e27e36a95c8356", 16) - g137438953472y, _ := new(big.Int).SetString("a67a92ec062962dfb0e5f6a7a40eee90c37ef1344915609abd5861b9be001fd3", 16) - g274877906944x, _ := new(big.Int).SetString("9d1aca1fce55236b19622ea025b08b0d51e8512f97e696c20d62fe17b160e8a", 16) - g274877906944y, _ := new(big.Int).SetString("1153188f5101f0c63e56692ce0d8c27e6fe9e0ee9212b5e534e050c57ca04c44", 16) - g549755813888x, _ := new(big.Int).SetString("c66c59cc454c2b9e18a2ad793821cde7518b3a93bfc39562e97d7d0475ba7fc2", 16) - g549755813888y, _ := new(big.Int).SetString("d9592fe2bfb30fcfbea4f3ceaac10cb2f00a60ddb15955977ec3c69cf75f5956", 16) - g1099511627776x, _ := new(big.Int).SetString("feea6cae46d55b530ac2839f143bd7ec5cf8b266a41d6af52d5e688d9094696d", 16) - g1099511627776y, _ := new(big.Int).SetString("e57c6b6c97dce1bab06e4e12bf3ecd5c981c8957cc41442d3155debf18090088", 16) - g2199023255552x, _ := new(big.Int).SetString("4d000b621adb87e1c53261af9db2e179141ecae0b331a1870aa4040aee752b08", 16) - g2199023255552y, _ := new(big.Int).SetString("6a0d5b8f18e0d255cb6d825582d972cccb7df5f119c7293a3e72851f48302cea", 16) - g4398046511104x, _ := new(big.Int).SetString("71f570ca203da05dd6aa262114717128d657a0403e1f1b77f89962fd475c58ef", 16) - g4398046511104y, _ := new(big.Int).SetString("eb42415b95dc880dd25557345bc95b8df2445d00c3363e7df8649a72d35d420e", 16) - g8796093022208x, _ := new(big.Int).SetString("a2b7b3629f7bd253b7d282b5c21da01446b4821dc65e76516048b06043ff8359", 16) - g8796093022208y, _ := new(big.Int).SetString("693038941695122d57a937a3f71e29c910d10835046f3835a2397fecfe86fec2", 16) - g17592186044416x, _ := new(big.Int).SetString("da67a91d91049cdcb367be4be6ffca3cfeed657d808583de33fa978bc1ec6cb1", 16) - g17592186044416y, _ := new(big.Int).SetString("9bacaa35481642bc41f463f7ec9780e5dec7adc508f740a17e9ea8e27a68be1d", 16) - g35184372088832x, _ := new(big.Int).SetString("4dbacd365fa1ef587c0c0cfaaf00d8718bbd9f35ccea5a835ee3cc821fe741c9", 16) - g35184372088832y, _ := new(big.Int).SetString("16c3540e8a51892e7fdcfd59e838299d0cc384a09fc0535f60be10f8338eb623", 16) - g70368744177664x, _ := new(big.Int).SetString("13d1ffc481509beee68f17d8ff41c2590f4c85f15268605087eda8bab4e218da", 16) - g70368744177664y, _ := new(big.Int).SetString("6008391fa991961dcecb9337b1b758bda4ad01206d5bd127e0db419ddb191c19", 16) - g140737488355328x, _ := new(big.Int).SetString("219b4f9cef6c60007659c79c45b0533b3cc9d916ce29dbff133b40caa2e96db8", 16) - g140737488355328y, _ := new(big.Int).SetString("24d9c605d959efeaf5a44180c0372a6e394f8ac53e90576527df01a78d3b6bc7", 16) - g281474976710656x, _ := new(big.Int).SetString("53904faa0b334cdda6e000935ef22151ec08d0f7bb11069f57545ccc1a37b7c0", 16) - g281474976710656y, _ := new(big.Int).SetString("5bc087d0bc80106d88c9eccac20d3c1c13999981e14434699dcb096b022771c8", 16) - g562949953421312x, _ := new(big.Int).SetString("1a575af9d4146753cf991196316995d2a6ee7aaad0f85ad57cd0f1f38a47ca9", 16) - g562949953421312y, _ := new(big.Int).SetString("3038f1cb8ab20dc3cc55fc52e1bb8698bdb93c5d9f4d7ea667c5df2e77ebcdb7", 16) - g1125899906842624x, _ := new(big.Int).SetString("f5f0e0437621d439ca71f5c1b76155d6d3a61a83d3c20c6ee309d755e315565b", 16) - g1125899906842624y, _ := new(big.Int).SetString("6b9f4e62be5a052bf62189160df7101aa5bf61bf3ed7e40a678430afdd2ecc82", 16) - g2251799813685248x, _ := new(big.Int).SetString("8f506f0b6c0b6e9a57a7f36d970ca4e347cbc92146227642cbe781d9f5362d33", 16) - g2251799813685248y, _ := new(big.Int).SetString("469f955d2afa61719530c5424f1c336848cf925d43bb8eaf30487d0c87fa243f", 16) - g4503599627370496x, _ := new(big.Int).SetString("8e7bcd0bd35983a7719cca7764ca906779b53a043a9b8bcaeff959f43ad86047", 16) - g4503599627370496y, _ := new(big.Int).SetString("10b7770b2a3da4b3940310420ca9514579e88e2e47fd68b3ea10047e8460372a", 16) - g9007199254740992x, _ := new(big.Int).SetString("33b35baa195e729dc350f319996950df3bc15b8d3d0389e777d2808bf13f0351", 16) - g9007199254740992y, _ := new(big.Int).SetString("a58a0185640abf87f9464036248d52bcaa6560efbc889b702bc503cccb8d7418", 16) - g18014398509481984x, _ := new(big.Int).SetString("374deeae22c93f955cb83ad2071f7e2256f6e109cad7bca6d71dc7b24414bb36", 16) - g18014398509481984y, _ := new(big.Int).SetString("171165b64fcd4f9916032c06f806f7293828d66300e543217875bea98daf734a", 16) - g36028797018963968x, _ := new(big.Int).SetString("2380c09c7f3aeae57c46e07395aeb0dc944dbaf2b62a9f0c5e8a64ad6ae7d616", 16) - g36028797018963968y, _ := new(big.Int).SetString("6f8e86193464956af1598aefd509b09a93af92148f8467560099be48161bbc1a", 16) - g72057594037927936x, _ := new(big.Int).SetString("385eed34c1cdff21e6d0818689b81bde71a7f4f18397e6690a841e1599c43862", 16) - g72057594037927936y, _ := new(big.Int).SetString("283bebc3e8ea23f56701de19e9ebf4576b304eec2086dc8cc0458fe5542e5453", 16) - g144115188075855872x, _ := new(big.Int).SetString("f6f622083daf54800456be134d5f67d147c82642befc1ce2dc83a27078f2827c", 16) - g144115188075855872y, _ := new(big.Int).SetString("1bcd4e817de73a0faf2c5715b367cee7e657ca7448321bf6d15b20b520aaa102", 16) - g288230376151711744x, _ := new(big.Int).SetString("fb26e5188f953de2bd70cb3c3d1fc255cd91c3ce7d8c6f369d893209715adcb6", 16) - g288230376151711744y, _ := new(big.Int).SetString("f3e128811012a34d58e846a719d0176916d2cb31b8b7ab5449dbca3b58ba68f3", 16) - g576460752303423488x, _ := new(big.Int).SetString("8991225911b9132d28f5c6bc763ceab7d18c37060e8bd1d7ed44db7560788c1e", 16) - g576460752303423488y, _ := new(big.Int).SetString("da8b4d987cc9ac9b27b8763559b136fa36969c84fdef9e11635c42228e8f0ef1", 16) - g1152921504606846976x, _ := new(big.Int).SetString("6f9d9b803ecf191637c73a4413dfa180fddf84a5947fbc9c606ed86c3fac3a7", 16) - g1152921504606846976y, _ := new(big.Int).SetString("7c80c68e603059ba69b8e2a30e45c4d47ea4dd2f5c281002d86890603a842160", 16) - g2305843009213693952x, _ := new(big.Int).SetString("ae86eeea252b411c1cdc36c284482939da1745e5a7e4da175c9d22744b7fd72d", 16) - g2305843009213693952y, _ := new(big.Int).SetString("19e993c9707302f962ab0ace589ff0e98d9211551472f7282334cb7a4eee38bc", 16) - g4611686018427387904x, _ := new(big.Int).SetString("2248c9f90bbfff55e61d2f8c56dc2c488718be75cf36f2ee7a1474267c169290", 16) - g4611686018427387904y, _ := new(big.Int).SetString("fa0594692d21eed7a506bb55b435ba18e163750235da2be2369d8a12883ea257", 16) - g9223372036854775808x, _ := new(big.Int).SetString("e11a6e16e05c44074ac11b48d94085d0a99f0877dd1c6f76fd0dac4bb50964e3", 16) - g9223372036854775808y, _ := new(big.Int).SetString("87d6065b87a2d430e1ad5e2596f0af2417adc6e138318c6f767fbf8b0682bfc8", 16) - g18446744073709551616x, _ := new(big.Int).SetString("3322d401243c4e2582a2147c104d6ecbf774d163db0f5e5313b7e0e742d0e6bd", 16) - g18446744073709551616y, _ := new(big.Int).SetString("56e70797e9664ef5bfb019bc4ddaf9b72805f63ea2873af624f3a2e96c28b2a0", 16) - g36893488147419103232x, _ := new(big.Int).SetString("8d26200250cebdae120ef31b04c80cd50d4cddc8eadbcf29fc696d32c0ade462", 16) - g36893488147419103232y, _ := new(big.Int).SetString("ebed3bb4715bf437d31f6f2dc3ee36ba1d4afb4e72678b3ad8e0a8b90f26470c", 16) - g73786976294838206464x, _ := new(big.Int).SetString("1238c0766eaebea9ce4068a1f594d03b8ed4930d072d9c8b9164643e1516e633", 16) - g73786976294838206464y, _ := new(big.Int).SetString("8a9db02dbb271359d6c979e2d1c3dc170946252dcc74022805cdb728c77b7805", 16) - g147573952589676412928x, _ := new(big.Int).SetString("271d5b0770cb9c15e7b2ea758a6a11b9cddcd7282b0ec21619b01552788e7a66", 16) - g147573952589676412928y, _ := new(big.Int).SetString("5d3aa45834e7f491e457d09949ac877fe2a065e3508a824e7a8d7258e03c9727", 16) - g295147905179352825856x, _ := new(big.Int).SetString("85672c7d2de0b7da2bd1770d89665868741b3f9af7643397721d74d28134ab83", 16) - g295147905179352825856y, _ := new(big.Int).SetString("7c481b9b5b43b2eb6374049bfa62c2e5e77f17fcc5298f44c8e3094f790313a6", 16) - g590295810358705651712x, _ := new(big.Int).SetString("534ccf6b740f9ec036c1861215c8a61f3b89ea46df2e6d96998b90bc1f17fc25", 16) - g590295810358705651712y, _ := new(big.Int).SetString("d5715cb09c8b2ddb462ae3dd32d543550ae3d277bfdd28ddd71c7f6ecfe86e76", 16) - g1180591620717411303424x, _ := new(big.Int).SetString("a91d1f5cee87b7f3081e142018f8aaed79020d47ecfbc8d2c7170923e8bee8b6", 16) - g1180591620717411303424y, _ := new(big.Int).SetString("748a324ee2df8ee15a7189c8dddad3b2f800569f628cb225003d16aa410644c1", 16) - g2361183241434822606848x, _ := new(big.Int).SetString("c15c8c23d90c8e35c1a214dde2d4383c0735ae45bef61f10aa1a1c255984cf74", 16) - g2361183241434822606848y, _ := new(big.Int).SetString("2ba954d828522235c8dc6f45e25fd7ba47bf772d50b015a2c4a48cd839ccb000", 16) - g4722366482869645213696x, _ := new(big.Int).SetString("948bf809b1988a46b06c9f1919413b10f9226c60f668832ffd959af60c82a0a", 16) - g4722366482869645213696y, _ := new(big.Int).SetString("53a562856dcb6646dc6b74c5d1c3418c6d4dff08c97cd2bed4cb7f88d8c8e589", 16) - g9444732965739290427392x, _ := new(big.Int).SetString("26952c7f372e59360d5ce4c66291f0b6ef16c1331e825e51396eb0457e8b000a", 16) - g9444732965739290427392y, _ := new(big.Int).SetString("f513ea4c5800a68862bc893d2d688422debe398f653d67318c3d401f05ef705a", 16) - g18889465931478580854784x, _ := new(big.Int).SetString("c62e58e6fc23c5bdbef2be8b131ff243f521196572d6b0e9f102588976134f96", 16) - g18889465931478580854784y, _ := new(big.Int).SetString("4397827d45b1a1678c3d676753141fc5bcfb853563731c3e82277ed4d14cf97e", 16) - g37778931862957161709568x, _ := new(big.Int).SetString("107460520eec5c741683329a716622b0b81c03200807de973686f8800b188cbb", 16) - g37778931862957161709568y, _ := new(big.Int).SetString("abe5d4c09a21598c35326b9b9cf54a11242e0d748dce3da601d7b6361f272124", 16) - g75557863725914323419136x, _ := new(big.Int).SetString("6260ce7f461801c34f067ce0f02873a8f1b0e44dfc69752accecd819f38fd8e8", 16) - g75557863725914323419136y, _ := new(big.Int).SetString("bc2da82b6fa5b571a7f09049776a1ef7ecd292238051c198c1a84e95b2b4ae17", 16) - g151115727451828646838272x, _ := new(big.Int).SetString("85d8da4748ad1a73dec8409be84f1a1316e65c5196aad27e0766746f3d477c2d", 16) - g151115727451828646838272y, _ := new(big.Int).SetString("58948b53665c6690586b536531efc7bc94b0a02033c4d5a62079816fc7d1dd70", 16) - g302231454903657293676544x, _ := new(big.Int).SetString("8e2a7166e7ec4b968c0892e9cc3ee3ee4d1e7e100fdc47f04850312d6c0b80d9", 16) - g302231454903657293676544y, _ := new(big.Int).SetString("eadb0ba9ae2cbe592cedd29b716a9d485297b688d706349a49c61f2ad6b29f50", 16) - g604462909807314587353088x, _ := new(big.Int).SetString("769bc75842bff58edc8366ecd78f8950ee4ab2e81359d90f9921fa3d2c4561be", 16) - g604462909807314587353088y, _ := new(big.Int).SetString("4bf817362fe783bac8dce4cef73f5d4741a177767b7873add5920bffb0d9685f", 16) - g1208925819614629174706176x, _ := new(big.Int).SetString("e5037de0afc1d8d43d8348414bbf4103043ec8f575bfdc432953cc8d2037fa2d", 16) - g1208925819614629174706176y, _ := new(big.Int).SetString("4571534baa94d3b5f9f98d09fb990bddbd5f5b03ec481f10e0e5dc841d755bda", 16) - g2417851639229258349412352x, _ := new(big.Int).SetString("a5e00da467fd5494f40b6cf7d2d61b3ec3ab217c792a2ddb8c63c8c79e3d34ef", 16) - g2417851639229258349412352y, _ := new(big.Int).SetString("98fe5f5e5608555421726fe99bf43d25b60dcfe790900acb855c5ce2f7adb4c", 16) - g4835703278458516698824704x, _ := new(big.Int).SetString("a99415f5ef3a2b403519f4bb1c9bfbc46d4afd2e4477572ae6737160d7b91252", 16) - g4835703278458516698824704y, _ := new(big.Int).SetString("82d0e64cae81f84bb9e2f10f24f6f6b6899a16ad590f4ddd73a377ac4bedc264", 16) - g9671406556917033397649408x, _ := new(big.Int).SetString("b56f4e9f9e4fd1fc7d8edde098f935f84c750d705f0c132bd8c465b66a540f17", 16) - g9671406556917033397649408y, _ := new(big.Int).SetString("32e8e53429cca856d3dc11adf0582d1d21d42963cbcca85446a2fcae0200102d", 16) - g19342813113834066795298816x, _ := new(big.Int).SetString("e06372b0f4a207adf5ea905e8f1771b4e7e8dbd1c6a6c5b725866a0ae4fce725", 16) - g19342813113834066795298816y, _ := new(big.Int).SetString("7a908974bce18cfe12a27bb2ad5a488cd7484a7787104870b27034f94eee31dd", 16) - g38685626227668133590597632x, _ := new(big.Int).SetString("eac134ca2046b8f9c8dbd304fad3f3c045ebfdb4ec6ed3cfe09aee43ed2ff3e", 16) - g38685626227668133590597632y, _ := new(big.Int).SetString("49630dbe79359b4245bf103bf2b11799ac19f696b7f21376e17206207d210988", 16) - g77371252455336267181195264x, _ := new(big.Int).SetString("d6788590731fea198392119d7adbb41ff5948a7804c85b17476706e4dfbfa4dc", 16) - g77371252455336267181195264y, _ := new(big.Int).SetString("28eaa8c89d5063c4940ef5c6d21c13aa6206f1c4ddc9a07cca7bcd6bbd3b5406", 16) - g154742504910672534362390528x, _ := new(big.Int).SetString("6930fccbd9a040974abf210f12b71d4bc7b1a6205599b01a7275fb40e48ff9b3", 16) - g154742504910672534362390528y, _ := new(big.Int).SetString("7f02ae94b94701eada30fcdb875f6d78090f9b13e4acc51acfddab5f8ee96a4e", 16) - g309485009821345068724781056x, _ := new(big.Int).SetString("213c7a715cd5d45358d0bbf9dc0ce02204b10bdde2a3f58540ad6908d0559754", 16) - g309485009821345068724781056y, _ := new(big.Int).SetString("4b6dad0b5ae462507013ad06245ba190bb4850f5f36a7eeddff2c27534b458f2", 16) - g618970019642690137449562112x, _ := new(big.Int).SetString("1c5e548132b49a7f66ae9fed8323480e0d1ab974622e7cf08993895e0ec87fac", 16) - g618970019642690137449562112y, _ := new(big.Int).SetString("4ffcf60f837f468f2bb959fa1d4c2ad3a3deaceb26fe324c555d7b3d5fc2d4ef", 16) - g1237940039285380274899124224x, _ := new(big.Int).SetString("46276d0602c5668ddef6e94210bbc7ce1f901c19fed5c970e20fcba1d4531dbc", 16) - g1237940039285380274899124224y, _ := new(big.Int).SetString("e0f7f24d44c75b84a292287570ded99498badfbffe1bc99af8730099686b8e2", 16) - g2475880078570760549798248448x, _ := new(big.Int).SetString("efea68eca7a6c24f4e65eb211c3191636850e0acdc78d8996114ef13522f001d", 16) - g2475880078570760549798248448y, _ := new(big.Int).SetString("aab847869d583c14da150307a3719a17e413959fb3848771c128419f73bc4415", 16) - g4951760157141521099596496896x, _ := new(big.Int).SetString("4e7c272a7af4b34e8dbb9352a5419a87e2838c70adc62cddf0cc3a3b08fbd53c", 16) - g4951760157141521099596496896y, _ := new(big.Int).SetString("17749c766c9d0b18e16fd09f6def681b530b9614bff7dd33e0b3941817dcaae6", 16) - g9903520314283042199192993792x, _ := new(big.Int).SetString("899017b02696888f268a269f4e385d9c9b11f25a1bef8790e2821e6e7c6e1b4d", 16) - g9903520314283042199192993792y, _ := new(big.Int).SetString("43ae2cdab5b334f0bb45798336358bfae4e51bc0f932b212009aebdad814ab2b", 16) - g19807040628566084398385987584x, _ := new(big.Int).SetString("67f644f76e905fd4a8f4728e63227f0e2831f5bf91b583a8af2635a17e5f712f", 16) - g19807040628566084398385987584y, _ := new(big.Int).SetString("b833d68f66445d04f05adeb7b586cf785e0e1488f7d36198d68acb5e707160e5", 16) - g39614081257132168796771975168x, _ := new(big.Int).SetString("327f876c93652555fa80a054968b4712930dc93012ee6b8dc10263ed3b89a762", 16) - g39614081257132168796771975168y, _ := new(big.Int).SetString("b2d404eab3524026b09969255e1997b975535070febd7dfe9c9fd959b9203301", 16) - g79228162514264337593543950336x, _ := new(big.Int).SetString("fea74e3dbe778b1b10f238ad61686aa5c76e3db2be43057632427e2840fb27b6", 16) - g79228162514264337593543950336y, _ := new(big.Int).SetString("6e0568db9b0b13297cf674deccb6af93126b596b973f7b77701d3db7f23cb96f", 16) - g158456325028528675187087900672x, _ := new(big.Int).SetString("ed9441c8304280ff180e03d850e8cd0ebb570ee5de3730488fd97c961f9756e4", 16) - g158456325028528675187087900672y, _ := new(big.Int).SetString("3dbe9e9efe8bfa19afa176128b13911e09f23774fe4de98bff0e09f93f3abfae", 16) - g316912650057057350374175801344x, _ := new(big.Int).SetString("29d9698ee67a7c3fc9fed3f624b487515b10bdd84fab4d3015bad033d51cf119", 16) - g316912650057057350374175801344y, _ := new(big.Int).SetString("7fd02c517dc82b45277a125404f1c96fb89c940e93a7c2963c88740575056339", 16) - g633825300114114700748351602688x, _ := new(big.Int).SetString("126b57d05013936d6f3fb7bd33580a31fd453e4a86060cff467c44537f422491", 16) - g633825300114114700748351602688y, _ := new(big.Int).SetString("c1a7dc13061662c2e3c4a3eba2bf3fb0e148bac30bf39347afa31f199da3ef84", 16) - g1267650600228229401496703205376x, _ := new(big.Int).SetString("76e64113f677cf0e10a2570d599968d31544e179b760432952c02a4417bdde39", 16) - g1267650600228229401496703205376y, _ := new(big.Int).SetString("c90ddf8dee4e95cf577066d70681f0d35e2a33d2b56d2032b4b1752d1901ac01", 16) - g2535301200456458802993406410752x, _ := new(big.Int).SetString("708a530e9e52c73bee87c9d88161c810005d57622c29ae691cf999a83a1187a5", 16) - g2535301200456458802993406410752y, _ := new(big.Int).SetString("9b884811e1f9a897fa9656dcbb6d38283ecda73c6d353e8a58a4f19b473db9c0", 16) - g5070602400912917605986812821504x, _ := new(big.Int).SetString("19cf034fc48b3be219bd648395e462cf9f374b6d86b2b59e2e1b16c6cde4f5be", 16) - g5070602400912917605986812821504y, _ := new(big.Int).SetString("28e32b06a15ab466c3b4be68ab181947ef91d1c93f0f1c0c0a91532b6f321af2", 16) - g10141204801825835211973625643008x, _ := new(big.Int).SetString("af6c44a078cb5f0d7c719c2f8397f576ee93bd034bea2219e3abc209d17cf3e8", 16) - g10141204801825835211973625643008y, _ := new(big.Int).SetString("784096fe85d4b30af9e73153cb246dfec362aea7ca0d435b8add0601751baea", 16) - g20282409603651670423947251286016x, _ := new(big.Int).SetString("c738c56b03b2abe1e8281baa743f8f9a8f7cc643df26cbee3ab150242bcbb891", 16) - g20282409603651670423947251286016y, _ := new(big.Int).SetString("893fb578951ad2537f718f2eacbfbbbb82314eef7880cfe917e735d9699a84c3", 16) - g40564819207303340847894502572032x, _ := new(big.Int).SetString("5578845ecd7c037435b32a6992e7aa94647197ea49b8c9e4ddaab0784662ab1b", 16) - g40564819207303340847894502572032y, _ := new(big.Int).SetString("e61d07978b6de2c3cea6d0a51d2a4053f653a7746a5d64de316d18f3056f3511", 16) - g81129638414606681695789005144064x, _ := new(big.Int).SetString("47f3383888a364cc4abfa3bc1d0ceccd22f12354fce3996094f869b8948b6c29", 16) - g81129638414606681695789005144064y, _ := new(big.Int).SetString("48ca9a8d0f032937190e48675b416c7118bb499588f994a81edee1120e537ef9", 16) - g162259276829213363391578010288128x, _ := new(big.Int).SetString("c0c01f34ae41b8cfe466b4c9c6a5d5f614f570d6fcbef768a81a6c8f05ff4adb", 16) - g162259276829213363391578010288128y, _ := new(big.Int).SetString("b84f5bee4357f5c7c937a0b4075b8cecdbc43d170d15b85fc4eff73ac351065", 16) - g324518553658426726783156020576256x, _ := new(big.Int).SetString("d895626548b65b81e264c7637c972877d1d72e5f3a925014372e9f6588f6c14b", 16) - g324518553658426726783156020576256y, _ := new(big.Int).SetString("febfaa38f2bc7eae728ec60818c340eb03428d632bb067e179363ed75d7d991f", 16) - g649037107316853453566312041152512x, _ := new(big.Int).SetString("fd136eef8971044e8a3a43622003a26703ecaf7a0ec40c3fba5b594b77078424", 16) - g649037107316853453566312041152512y, _ := new(big.Int).SetString("218da834f3c652cc67a1d191b5c5efa57cf2b1f78a2adfa8cd61eeefc671ddf1", 16) - g1298074214633706907132624082305024x, _ := new(big.Int).SetString("d99e8e9dd9638d140e9cca5367519f861b7003a0d43f024a5f1d84ec8db1cb3c", 16) - g1298074214633706907132624082305024y, _ := new(big.Int).SetString("36dc19ad1cc0a3a7a945bb321bceba6e6286fef8ffc8765cd88a29e36b8637a7", 16) - g2596148429267413814265248164610048x, _ := new(big.Int).SetString("3fdf1619a198317a1bd8a54e5b09191d203351e0440e636fd46f68d3c385172", 16) - g2596148429267413814265248164610048y, _ := new(big.Int).SetString("408d02c06e5c12c3fe470c7d3c8573755b9b929e90e7232b79ac67f0fccb9794", 16) - g5192296858534827628530496329220096x, _ := new(big.Int).SetString("b8da94032a957518eb0f6433571e8761ceffc73693e84edd49150a564f676e03", 16) - g5192296858534827628530496329220096y, _ := new(big.Int).SetString("2804dfa44805a1e4d7c99cc9762808b092cc584d95ff3b511488e4e74efdf6e7", 16) - g10384593717069655257060992658440192x, _ := new(big.Int).SetString("6d36d105ed8cc5ce53f2cb698ab620f9469a3e5cb25bf6e6d413f414c5af726a", 16) - g10384593717069655257060992658440192y, _ := new(big.Int).SetString("e4ba5c34e377669e72d8c66c95c50029dcc59936b4108a35c570491a13f9fc7d", 16) - g20769187434139310514121985316880384x, _ := new(big.Int).SetString("3ab6bde10cd3ac0cd06883fa66f0b0e3eb1309c0534b812286e2a30ca540db99", 16) - g20769187434139310514121985316880384y, _ := new(big.Int).SetString("baca62079be871d7fc3117a96a13e99c38d137b0e369c043e6873fe31bda78a3", 16) - g41538374868278621028243970633760768x, _ := new(big.Int).SetString("796634e3f1ad56f0fdba069d9d07bce2ba2fd4f373ddd3ba7777bf279f1048da", 16) - g41538374868278621028243970633760768y, _ := new(big.Int).SetString("4d8ee2b6cfb20b8956de74735a7927f2532576d8cfd74862e8f9be24a106cf01", 16) - g83076749736557242056487941267521536x, _ := new(big.Int).SetString("e80fea14441fb33a7d8adab9475d7fab2019effb5156a792f1a11778e3c0df5d", 16) - g83076749736557242056487941267521536y, _ := new(big.Int).SetString("eed1de7f638e00771e89768ca3ca94472d155e80af322ea9fcb4291b6ac9ec78", 16) - g166153499473114484112975882535043072x, _ := new(big.Int).SetString("440ca1f08ea41265981ac4ed1efe7a37122dcc3877d2f9162db0e78b0f83cd58", 16) - g166153499473114484112975882535043072y, _ := new(big.Int).SetString("a6c8b0d2cd5ee122af8954dc9d4e2f02a21e4d4269c0a260b07bc069b88a3f4b", 16) - g332306998946228968225951765070086144x, _ := new(big.Int).SetString("f694cbaf2b966c1cc5f7f829d3a907819bc70ebcc1b229d9e81bda2712998b10", 16) - g332306998946228968225951765070086144y, _ := new(big.Int).SetString("40a63eba61bef03d633c5ffacc46d82aeb6c64c3183c2a47f6788b1700f05e51", 16) - g664613997892457936451903530140172288x, _ := new(big.Int).SetString("8b6e862a3556684850b6d4f439a2595047abf695c08b6414f95a13358dd553fd", 16) - g664613997892457936451903530140172288y, _ := new(big.Int).SetString("ea5e08910ed11cb40d10bc2df4eb9fa124ac3c5a183383d0d803dad33e9be5ed", 16) - g1329227995784915872903807060280344576x, _ := new(big.Int).SetString("a301697bdfcd704313ba48e51d567543f2a182031efd6915ddc07bbcc4e16070", 16) - g1329227995784915872903807060280344576y, _ := new(big.Int).SetString("7370f91cfb67e4f5081809fa25d40f9b1735dbf7c0a11a130c0d1a041e177ea1", 16) - g2658455991569831745807614120560689152x, _ := new(big.Int).SetString("27e1e59cff79f049f3e8d2419e0bff74b43965004c34b5d811420316f24ba5ae", 16) - g2658455991569831745807614120560689152y, _ := new(big.Int).SetString("310b26a6c804e209ee1b5e3cfc79df05df48a1a69afa63f784a5bfee883a45b3", 16) - g5316911983139663491615228241121378304x, _ := new(big.Int).SetString("c712e7a5f6864aee16588ec3892d7e4f5a39adde84fbfb4f9969175c9caed7ae", 16) - g5316911983139663491615228241121378304y, _ := new(big.Int).SetString("49644107516363b365ed4b82311dd9e5380d8e544b0ce63784d148aa46156294", 16) - g10633823966279326983230456482242756608x, _ := new(big.Int).SetString("bfc0504a4b3235d065c0d426b8675fcb2c85d6f58275d791b43e1fe44a6db03", 16) - g10633823966279326983230456482242756608y, _ := new(big.Int).SetString("1955467a6c34f3453fb8ec7f94a6c99237427197345d4f0558ac8d1a464b8542", 16) - g21267647932558653966460912964485513216x, _ := new(big.Int).SetString("90ad85b389d6b936463f9d0512678de208cc330b11307fffab7ac63e3fb04ed4", 16) - g21267647932558653966460912964485513216y, _ := new(big.Int).SetString("e507a3620a38261affdcbd9427222b839aefabe1582894d991d4d48cb6ef150", 16) - g42535295865117307932921825928971026432x, _ := new(big.Int).SetString("7e2cd40ef8c94077f44b1d1548425e3d7e125be646707bad2818b0eda7dc0151", 16) - g42535295865117307932921825928971026432y, _ := new(big.Int).SetString("905b75082adcfab382a61a8b321ef95d889bee40aeee082c9a3bc53920721ec7", 16) - g85070591730234615865843651857942052864x, _ := new(big.Int).SetString("a146f52195bedace21c975bbd1ef52a79c636bf9db853cf90e103ae41345e597", 16) - g85070591730234615865843651857942052864y, _ := new(big.Int).SetString("a5a99b0ab053feb09ae95dd2dbb31b40ea67a5b221f094b07675676af45a770a", 16) - g170141183460469231731687303715884105728x, _ := new(big.Int).SetString("d24c75a1cf1993b9bcfbf9dab25a8114dbde421efeccc4e20cbb53fc4ce45444", 16) - g170141183460469231731687303715884105728y, _ := new(big.Int).SetString("58fe1d2de84dc1d1cfcb7d1810e5a78abf7593f499f1e524cb93246987dd4a57", 16) - g340282366920938463463374607431768211456x, _ := new(big.Int).SetString("8f68b9d2f63b5f339239c1ad981f162ee88c5678723ea3351b7b444c9ec4c0da", 16) - g340282366920938463463374607431768211456y, _ := new(big.Int).SetString("662a9f2dba063986de1d90c2b6be215dbbea2cfe95510bfdf23cbf79501fff82", 16) - g680564733841876926926749214863536422912x, _ := new(big.Int).SetString("4d49aefd784e8158fcafebe77fd9af59d89858ade7627eaee6847df84cf27076", 16) - g680564733841876926926749214863536422912y, _ := new(big.Int).SetString("cd32fc59a10dd135e723f210359ca6f06e0f2d1a7df4d8466b90b66203aa781e", 16) - g1361129467683753853853498429727072845824x, _ := new(big.Int).SetString("7564539e85d56f8537d6619e1f5c5aa78d2a3de0889d1d4ee8dbcb5729b62026", 16) - g1361129467683753853853498429727072845824y, _ := new(big.Int).SetString("c1d685413749b3c65231df524a722925684aacd954b79f334172c8fadace0cf3", 16) - g2722258935367507707706996859454145691648x, _ := new(big.Int).SetString("210a917ad9df27796746ff301ad9ccc878f61a5f1ff4082b5364dacd57b4a278", 16) - g2722258935367507707706996859454145691648y, _ := new(big.Int).SetString("670e1b5450b5e57b7a39be81f8d6737d3789e61aaff20bfc7f2713fd0c7b2231", 16) - g5444517870735015415413993718908291383296x, _ := new(big.Int).SetString("e4f3fb0176af85d65ff99ff9198c36091f48e86503681e3e6686fd5053231e11", 16) - g5444517870735015415413993718908291383296y, _ := new(big.Int).SetString("1e63633ad0ef4f1c1661a6d0ea02b7286cc7e74ec951d1c9822c38576feb73bc", 16) - g10889035741470030830827987437816582766592x, _ := new(big.Int).SetString("4b30cbb7686773e01ec64110abdb362f88531a825ba172953bfee2233bcdaf2f", 16) - g10889035741470030830827987437816582766592y, _ := new(big.Int).SetString("74c6350265bb629b6f9e2c5777c3c4a91fdf3c81e434857568033d463d26b5b7", 16) - g21778071482940061661655974875633165533184x, _ := new(big.Int).SetString("cbb434aa7ae1700dcd15b20b17464817ec11715050e0fa192ffe9c29a673059f", 16) - g21778071482940061661655974875633165533184y, _ := new(big.Int).SetString("4a1a200ab4dabd17562d492338b5dfad41d45e4f0ad5f845b7da9642227c070c", 16) - g43556142965880123323311949751266331066368x, _ := new(big.Int).SetString("f478056d9c102c1cd06d7b1e7557244c6d9cdac5874610e94d4786e106de12c0", 16) - g43556142965880123323311949751266331066368y, _ := new(big.Int).SetString("7f09e610f33e3946e68095e01068694c26c17ef609ab92d769a76ce6ca5361fe", 16) - g87112285931760246646623899502532662132736x, _ := new(big.Int).SetString("8c00fa9b18ebf331eb961537a45a4266c7034f2f0d4e1d0716fb6eae20eae29e", 16) - g87112285931760246646623899502532662132736y, _ := new(big.Int).SetString("efa47267fea521a1a9dc343a3736c974c2fadafa81e36c54e7d2a4c66702414b", 16) - g174224571863520493293247799005065324265472x, _ := new(big.Int).SetString("24cfc0176da2b46fa8bb5bf9636be1effd7e297f29122fb3e84c9ab0c18ada5f", 16) - g174224571863520493293247799005065324265472y, _ := new(big.Int).SetString("ebff8fbb079c61a69868714d5deda927ed959ca1a4f814f268fa6139978a586b", 16) - g348449143727040986586495598010130648530944x, _ := new(big.Int).SetString("4a7d58d4b9bc82ea2ded72a1292ec616ddd67fc7f057edf103189594679da2", 16) - g348449143727040986586495598010130648530944y, _ := new(big.Int).SetString("b98ac5b76702cb75e6b1d8147ec71b3b71c3b494963fa28a4877f484779ffe26", 16) - g696898287454081973172991196020261297061888x, _ := new(big.Int).SetString("ee7d69c4cbd001c7fc76c5e2c066ce4996f8808a1e07b2a9ccf34eadc87c4b65", 16) - g696898287454081973172991196020261297061888y, _ := new(big.Int).SetString("ecc8626ec1a413821a192abf030f2ee2c33e8999bae942e523e8f44ed136a95a", 16) - g1393796574908163946345982392040522594123776x, _ := new(big.Int).SetString("e7a26ce69dd4829f3e10cec0a9e98ed3143d084f308b92c0997fddfc60cb3e41", 16) - g1393796574908163946345982392040522594123776y, _ := new(big.Int).SetString("2a758e300fa7984b471b006a1aafbb18d0a6b2c0420e83e20e8a9421cf2cfd51", 16) - g2787593149816327892691964784081045188247552x, _ := new(big.Int).SetString("f5cafaba036bf8d00d38bfb6772089f5203c35e4d6e32fa9d97e5b917b4ae861", 16) - g2787593149816327892691964784081045188247552y, _ := new(big.Int).SetString("19e83b8a022a6d817bff9904640839159b3b2a9c552f05f3cc9c239c0d82239c", 16) - g5575186299632655785383929568162090376495104x, _ := new(big.Int).SetString("e9389024ceb63f1f12df5156d7e805428f9e509c494c982084fd4cd7bd2a9651", 16) - g5575186299632655785383929568162090376495104y, _ := new(big.Int).SetString("8648688723726595f9287abaf671aaf18d7110cec6770bfefefde2b75e786824", 16) - g11150372599265311570767859136324180752990208x, _ := new(big.Int).SetString("264559d87829256bed116900d82d0c379f0e4d1253c68e6fcf2d41ae7cddab8b", 16) - g11150372599265311570767859136324180752990208y, _ := new(big.Int).SetString("79e5bd1926d3512cef7bc637034072d77a8631af39caf1e6c9f64b45001de473", 16) - g22300745198530623141535718272648361505980416x, _ := new(big.Int).SetString("b6459e0ee3662ec8d23540c223bcbdc571cbcb967d79424f3cf29eb3de6b80ef", 16) - g22300745198530623141535718272648361505980416y, _ := new(big.Int).SetString("67c876d06f3e06de1dadf16e5661db3c4b3ae6d48e35b2ff30bf0b61a71ba45", 16) - g44601490397061246283071436545296723011960832x, _ := new(big.Int).SetString("e5d8e8f0d9823c88e4d36f7301f41593b6890576be79c211253ef375033eb51f", 16) - g44601490397061246283071436545296723011960832y, _ := new(big.Int).SetString("4dc1e9b7861e3e04abb16a57d8feeef0e509dc46d9f0f54979d5bd965a62a2d9", 16) - g89202980794122492566142873090593446023921664x, _ := new(big.Int).SetString("a9ca27f77dbc8c3dc56b0f7321bae0ddab66be4fa8a3011737a676480f155e64", 16) - g89202980794122492566142873090593446023921664y, _ := new(big.Int).SetString("f4bb335678fb14d4d197d2246c02d004875d41821bcaf0ae1f3f333c561b3297", 16) - g178405961588244985132285746181186892047843328x, _ := new(big.Int).SetString("68fb71800686d7f25eba105611cfe7591f478e847f51cee06d4bc629d6ee247c", 16) - g178405961588244985132285746181186892047843328y, _ := new(big.Int).SetString("cd12d23462dd963673735427501b0c079a8d580b04c73c9dae1f822d1a01865d", 16) - g356811923176489970264571492362373784095686656x, _ := new(big.Int).SetString("d68a80c8280bb840793234aa118f06231d6f1fc67e73c5a5deda0f5b496943e8", 16) - g356811923176489970264571492362373784095686656y, _ := new(big.Int).SetString("db8ba9fff4b586d00c4b1f9177b0e28b5b0e7b8f7845295a294c84266b133120", 16) - g713623846352979940529142984724747568191373312x, _ := new(big.Int).SetString("f16a409c677a40be402f8efb3752373caced053c6f702b828bda222ca412b6fd", 16) - g713623846352979940529142984724747568191373312y, _ := new(big.Int).SetString("2a41311714532799d7a6a75a74e30e4e16540659249ebca4268dae77eca052da", 16) - g1427247692705959881058285969449495136382746624x, _ := new(big.Int).SetString("4154b506ab766f42fbe37f699976f84db89f4f2f6bed98325c1a0b6e326dd4e4", 16) - g1427247692705959881058285969449495136382746624y, _ := new(big.Int).SetString("23ad075043c5988894c6e44d61025ff6414ea9d9d1e22dd46c859295075ded1c", 16) - g2854495385411919762116571938898990272765493248x, _ := new(big.Int).SetString("b73c652769cc95c1080a8d4d0b5956ea93e86e49fc727ddf4c51a7a63f7f0246", 16) - g2854495385411919762116571938898990272765493248y, _ := new(big.Int).SetString("9a67db107174ca9d4b535893c5b6c1ea1a0d72e4c6e554e5597e5164ea2a407b", 16) - g5708990770823839524233143877797980545530986496x, _ := new(big.Int).SetString("324aed7df65c804252dc0270907a30b09612aeb973449cea4095980fc28d3d5d", 16) - g5708990770823839524233143877797980545530986496y, _ := new(big.Int).SetString("648a365774b61f2ff130c0c35aec1f4f19213b0c7e332843967224af96ab7c84", 16) - g11417981541647679048466287755595961091061972992x, _ := new(big.Int).SetString("32c9331ea26f490228d32681880d7203f72b3e4a8de0db1fa8f38381b2919749", 16) - g11417981541647679048466287755595961091061972992y, _ := new(big.Int).SetString("d7cd272b34209cb5695a2f02b6f3dbb8268a4abdae39ab09631e97b0f290b5e3", 16) - g22835963083295358096932575511191922182123945984x, _ := new(big.Int).SetString("eb292f3b3b9837854a02f6a70fec6b1c69c161b6e1846b8e1e1c22527b9795e4", 16) - g22835963083295358096932575511191922182123945984y, _ := new(big.Int).SetString("8c43c25a96eebe801696634af145835b57131d7509111c6f5b7e9d2fae53a0fe", 16) - g45671926166590716193865151022383844364247891968x, _ := new(big.Int).SetString("a65a3a01df3b5ef2e620d4310049fbe14d71457f19d1ed35aea39d5789303fdd", 16) - g45671926166590716193865151022383844364247891968y, _ := new(big.Int).SetString("798ea0940cff5c6fb8f43d8d90ed2c7686861d024faed3cadad44a8d02e68703", 16) - g91343852333181432387730302044767688728495783936x, _ := new(big.Int).SetString("4df9c14919cde61f6d51dfdbe5fee5dceec4143ba8d1ca888e8bd373fd054c96", 16) - g91343852333181432387730302044767688728495783936y, _ := new(big.Int).SetString("35ec51092d8728050974c23a1d85d4b5d506cdc288490192ebac06cad10d5d", 16) - g182687704666362864775460604089535377456991567872x, _ := new(big.Int).SetString("ed32cad8d2cc998cd25317d4e4b87088e9de4554e57a8d70c0c6b0fc1da49e04", 16) - g182687704666362864775460604089535377456991567872y, _ := new(big.Int).SetString("129fef5f1d030204a541ca375859d20b52da9facb49fab7db63120d17c1db9e0", 16) - g365375409332725729550921208179070754913983135744x, _ := new(big.Int).SetString("e821ab724d6360f18049e4111c70366e28c36dcb63c34016cb7418d4e883f855", 16) - g365375409332725729550921208179070754913983135744y, _ := new(big.Int).SetString("adefcbf863f53ce367d0d4115416cf598b3b19c614ec23efed4e0c6a59852ddf", 16) - g730750818665451459101842416358141509827966271488x, _ := new(big.Int).SetString("3f0d8994e51ad212f455452fbc9693a72f14a547af3806e9fbff59eeb441742e", 16) - g730750818665451459101842416358141509827966271488y, _ := new(big.Int).SetString("fbd76c23f28c3dc445e5cb0e847a6e0b1e205e2c3ad13d958c65363bcfecadbe", 16) - g1461501637330902918203684832716283019655932542976x, _ := new(big.Int).SetString("9c3919a84a474870faed8a9c1cc66021523489054d7f0308cbfc99c8ac1f98cd", 16) - g1461501637330902918203684832716283019655932542976y, _ := new(big.Int).SetString("ddb84f0f4a4ddd57584f044bf260e641905326f76c64c8e6be7e5e03d4fc599d", 16) - g2923003274661805836407369665432566039311865085952x, _ := new(big.Int).SetString("2e3c05326255d80f0a42fc69d5c92aa40cd326a53e8535f0435efb7b694a09ec", 16) - g2923003274661805836407369665432566039311865085952y, _ := new(big.Int).SetString("1ff891656c6fb5bddae240b82fc1abe048a53c707b66512534868188c7327e", 16) - g5846006549323611672814739330865132078623730171904x, _ := new(big.Int).SetString("e8e2a24ccfa41587ae15fb7e3e24dda433710316a1908934205f19a2ab9c7ce6", 16) - g5846006549323611672814739330865132078623730171904y, _ := new(big.Int).SetString("46c983ce0c6f5d1b4caf2b2b3bee20596e09e603b5c27a73b2c01eb68836267c", 16) - g11692013098647223345629478661730264157247460343808x, _ := new(big.Int).SetString("a7549aac5d8573c2b2f0a38b170032a212acaf92383d5b5f5b0d39668ac7b3c2", 16) - g11692013098647223345629478661730264157247460343808y, _ := new(big.Int).SetString("bd17d1b90d1c2415335a1d70c1947d2b5d6b5115537116dffa0c91719287eaef", 16) - g23384026197294446691258957323460528314494920687616x, _ := new(big.Int).SetString("6057170b1dd12fdf8de05f281d8e06bb91e1493a8b91d4cc5a21382120a959e5", 16) - g23384026197294446691258957323460528314494920687616y, _ := new(big.Int).SetString("9a1af0b26a6a4807add9a2daf71df262465152bc3ee24c65e899be932385a2a8", 16) - g46768052394588893382517914646921056628989841375232x, _ := new(big.Int).SetString("6773fd677c52e0640394110a46dc85df7c133f8dd4a28e661899ca5d82fd545c", 16) - g46768052394588893382517914646921056628989841375232y, _ := new(big.Int).SetString("444eb6d8cd97652f0f0f25c9dd2b246bead780f5a1c6cf98e8c7f034947eb1ae", 16) - g93536104789177786765035829293842113257979682750464x, _ := new(big.Int).SetString("e0f86d94d17ce565237c79aace0c87c20374e43810468050373c616b0b86f021", 16) - g93536104789177786765035829293842113257979682750464y, _ := new(big.Int).SetString("c571c73730abcf47a91e832f1c89a2c9a80bcc0115fc45b3b6b79ccb5bf325a", 16) - g187072209578355573530071658587684226515959365500928x, _ := new(big.Int).SetString("42ca15ab9f245041ce991e193d696f4f4c277df908cad6038ad0772c02da6e03", 16) - g187072209578355573530071658587684226515959365500928y, _ := new(big.Int).SetString("68d2ef26c81c57c9647ce4d1fcb800eed66e85a68106bea7836889fa8c347793", 16) - g374144419156711147060143317175368453031918731001856x, _ := new(big.Int).SetString("a576df8e23a08411421439a4518da31880cef0fba7d4df12b1a6973eecb94266", 16) - g374144419156711147060143317175368453031918731001856y, _ := new(big.Int).SetString("40a6bf20e76640b2c92b97afe58cd82c432e10a7f514d9f3ee8be11ae1b28ec8", 16) - g748288838313422294120286634350736906063837462003712x, _ := new(big.Int).SetString("9e5dcc62ef3b5a3b546520867be71bae6f3ba063c9acfb8dcec5725bda704896", 16) - g748288838313422294120286634350736906063837462003712y, _ := new(big.Int).SetString("6fedd12ddb925f3ea5fd3a2154c7612279605d186030f51248f2769dca82c835", 16) - g1496577676626844588240573268701473812127674924007424x, _ := new(big.Int).SetString("a7de08375b8745adf8d6e9f976f03b20e33625a05cef5833953ed58744bf7ea0", 16) - g1496577676626844588240573268701473812127674924007424y, _ := new(big.Int).SetString("a63d96b057ada5e52104a0b334888e9a645a47c0febc5aa2e04c05539bbcabaa", 16) - g2993155353253689176481146537402947624255349848014848x, _ := new(big.Int).SetString("c266658e689080c9c13c35ac01cff4cbe68065fde949e4a3a9f8fa104ad916fb", 16) - g2993155353253689176481146537402947624255349848014848y, _ := new(big.Int).SetString("e7e8593854e7daab0f798170b24627ab6b8fecdfeb61138856aef52ba0887814", 16) - g5986310706507378352962293074805895248510699696029696x, _ := new(big.Int).SetString("7778a78c28dec3e30a05fe9629de8c38bb30d1f5cf9a3a208f763889be58ad71", 16) - g5986310706507378352962293074805895248510699696029696y, _ := new(big.Int).SetString("34626d9ab5a5b22ff7098e12f2ff580087b38411ff24ac563b513fc1fd9f43ac", 16) - g11972621413014756705924586149611790497021399392059392x, _ := new(big.Int).SetString("e7b9796b5ca006d1632f482d7f0fe3932cf16a5ae104eea7a7ea1c251073e879", 16) - g11972621413014756705924586149611790497021399392059392y, _ := new(big.Int).SetString("12b8988c19169e2fdf42102a737cc1ca9cb5bf25eda98af338e71089baa89d98", 16) - g23945242826029513411849172299223580994042798784118784x, _ := new(big.Int).SetString("71bf01850876203c2c915a24be09a7365423daaf2aee919865d722bf2628f0f", 16) - g23945242826029513411849172299223580994042798784118784y, _ := new(big.Int).SetString("527aa15d504dcf4ae33600bc1c084ce2098f9c6a231c80bbb57c5cbd45a1c334", 16) - g47890485652059026823698344598447161988085597568237568x, _ := new(big.Int).SetString("218343acb9be56833a32e594c03c39e5b1911c8501213786f6376dfa39620e1", 16) - g47890485652059026823698344598447161988085597568237568y, _ := new(big.Int).SetString("bea81d48970a50beaf3f24fd602fbfc0443299a42f43c9ec5e0199f6506998b5", 16) - g95780971304118053647396689196894323976171195136475136x, _ := new(big.Int).SetString("928955ee637a84463729fd30e7afd2ed5f96274e5ad7e5cb09eda9c06d903ac", 16) - g95780971304118053647396689196894323976171195136475136y, _ := new(big.Int).SetString("c25621003d3f42a827b78a13093a95eeac3d26efa8a8d83fc5180e935bcd091f", 16) - g191561942608236107294793378393788647952342390272950272x, _ := new(big.Int).SetString("4f89bdee3771d350dad163b04cb18ad67ce5e9c55b58f0e7231047a60f59dd9e", 16) - g191561942608236107294793378393788647952342390272950272y, _ := new(big.Int).SetString("ca7952d5227a1f695c4baf4c043bb2471e4882506638df5c1016ae320156b049", 16) - g383123885216472214589586756787577295904684780545900544x, _ := new(big.Int).SetString("cb9e8304cae3c5a80c396baca2c3c4c994b668f079a245bf529c314cfff01197", 16) - g383123885216472214589586756787577295904684780545900544y, _ := new(big.Int).SetString("62c7d2801eb80e6a127258cdff08891741b2d18c015e0a24c334e0763b989c1d", 16) - g766247770432944429179173513575154591809369561091801088x, _ := new(big.Int).SetString("e2f349b0f89c69bd3c8cf2a410730dc58e0beed47048c58c15f9ffc2508d2cc2", 16) - g766247770432944429179173513575154591809369561091801088y, _ := new(big.Int).SetString("1feb2f280f82723781860aec760215ba42344be8e09cbdb37e347bd8e0d4c04f", 16) - g1532495540865888858358347027150309183618739122183602176x, _ := new(big.Int).SetString("85d0fef3ec6db109399064f3a0e3b2855645b4a907ad354527aae75163d82751", 16) - g1532495540865888858358347027150309183618739122183602176y, _ := new(big.Int).SetString("1f03648413a38c0be29d496e582cf5663e8751e96877331582c237a24eb1f962", 16) - g3064991081731777716716694054300618367237478244367204352x, _ := new(big.Int).SetString("6b790f4b19a4c4f4f607a6cfcd11df0468b482e009711ff756356d141d5fcade", 16) - g3064991081731777716716694054300618367237478244367204352y, _ := new(big.Int).SetString("d03a981b2ff9eb3ef296661f9cae09cba83fa5b47be26b0ab6fff86fc338d3ff", 16) - g6129982163463555433433388108601236734474956488734408704x, _ := new(big.Int).SetString("41149b2c2d7ebed3c162c367acc4f8fe3d2479de85978be0bb0ccdabe3a3e0cb", 16) - g6129982163463555433433388108601236734474956488734408704y, _ := new(big.Int).SetString("c90d5b92db7c30542b415c9b9902cf28b3ec7805ef490f2470e92e98339033a8", 16) - g12259964326927110866866776217202473468949912977468817408x, _ := new(big.Int).SetString("d1fad4fa4e7c849dfaec3dfe2872a7ba664a9b8205c29cebf8dddd28e3f3d3fc", 16) - g12259964326927110866866776217202473468949912977468817408y, _ := new(big.Int).SetString("8fe19714a348fdfe5473f70e858b7818bad37131eff37326ed22343c50f3704d", 16) - g24519928653854221733733552434404946937899825954937634816x, _ := new(big.Int).SetString("ff2b0dce97eece97c1c9b6041798b85dfdfb6d8882da20308f5404824526087e", 16) - g24519928653854221733733552434404946937899825954937634816y, _ := new(big.Int).SetString("493d13fef524ba188af4c4dc54d07936c7b7ed6fb90e2ceb2c951e01f0c29907", 16) - g49039857307708443467467104868809893875799651909875269632x, _ := new(big.Int).SetString("2982dbbc5f366c9f78e29ebbecb1bb223deb5c4ee638b4583bd3a9af3149f8ef", 16) - g49039857307708443467467104868809893875799651909875269632y, _ := new(big.Int).SetString("a61b5be9af66220ab9fa5339c7b5bc9d095db99412e3ed8456e726b016c7a248", 16) - g98079714615416886934934209737619787751599303819750539264x, _ := new(big.Int).SetString("1a28e5042af0c0f6b436eb590497db5860011f4580e1765885289f612380441b", 16) - g98079714615416886934934209737619787751599303819750539264y, _ := new(big.Int).SetString("55779a7996c59dab7c78329a8976f0ed04b3e75b46ee67aeb05f606a8452af25", 16) - g196159429230833773869868419475239575503198607639501078528x, _ := new(big.Int).SetString("c8b83e9535f30601d250cc0bd3f20142edd5eb7985d83242eef0e39621e30a7", 16) - g196159429230833773869868419475239575503198607639501078528y, _ := new(big.Int).SetString("dcc7077065fdac7b850e3f17efdc854aacad237b987134dbebf7beb9ff688de", 16) - g392318858461667547739736838950479151006397215279002157056x, _ := new(big.Int).SetString("827fbbe4b1e880ea9ed2b2e6301b212b57f1ee148cd6dd28780e5e2cf856e241", 16) - g392318858461667547739736838950479151006397215279002157056y, _ := new(big.Int).SetString("c60f9c923c727b0b71bef2c67d1d12687ff7a63186903166d605b68baec293ec", 16) - g784637716923335095479473677900958302012794430558004314112x, _ := new(big.Int).SetString("b77f12a7dce56b973e2d7c8d576e6b3660470a9218b87461ef6e44b70cb1815d", 16) - g784637716923335095479473677900958302012794430558004314112y, _ := new(big.Int).SetString("4b6f85b14f86acc43f0cefb373cc2e654c42f0f91a44816d6ba3d2bc8e57dbc5", 16) - g1569275433846670190958947355801916604025588861116008628224x, _ := new(big.Int).SetString("48973b943018bf1247b308b2cb79f956d858d8df4977c5970fe5dad2c45565ec", 16) - g1569275433846670190958947355801916604025588861116008628224y, _ := new(big.Int).SetString("761f75684f3cdc1b6437bb3a01445af1511b3596580477b83b879075faed07e9", 16) - g3138550867693340381917894711603833208051177722232017256448x, _ := new(big.Int).SetString("e931258e8eb5559c6d6972728a704c170b775a265b4527d4a4d4d742bbfd71fa", 16) - g3138550867693340381917894711603833208051177722232017256448y, _ := new(big.Int).SetString("fb1e33364c3fdee0e85eb4169c954b40b3946ce1bb5e35f33d9bd0d3174d3307", 16) - g6277101735386680763835789423207666416102355444464034512896x, _ := new(big.Int).SetString("eaa649f21f51bdbae7be4ae34ce6e5217a58fdce7f47f9aa7f3b58fa2120e2b3", 16) - g6277101735386680763835789423207666416102355444464034512896y, _ := new(big.Int).SetString("be3279ed5bbbb03ac69a80f89879aa5a01a6b965f13f7e59d47a5305ba5ad93d", 16) - g12554203470773361527671578846415332832204710888928069025792x, _ := new(big.Int).SetString("3adb9db3beb997eec2623ea5002279ea9e337b5c705f3db453dbc1cc1fc9b0a8", 16) - g12554203470773361527671578846415332832204710888928069025792y, _ := new(big.Int).SetString("374e2d6daee74e713c774de07c095ff6aad9c8f9870266cc61ae7975f05bbdda", 16) - g25108406941546723055343157692830665664409421777856138051584x, _ := new(big.Int).SetString("129e53ac428e9cbb7e10955e56c5fc69fefdff56963e7caf054e9e0c90ae86f9", 16) - g25108406941546723055343157692830665664409421777856138051584y, _ := new(big.Int).SetString("415ecb958aee9a29b2da2115b712183fb2a232fd16b3e01b822efdcd1e89c85d", 16) - g50216813883093446110686315385661331328818843555712276103168x, _ := new(big.Int).SetString("60144494c8f694485b85ecb6aee10956c756267d12894711922243d5e855b8da", 16) - g50216813883093446110686315385661331328818843555712276103168y, _ := new(big.Int).SetString("8bb5d669f681e6469e8be1fd9132e65b543955c27e3f2a4bad500590f34e4bbd", 16) - g100433627766186892221372630771322662657637687111424552206336x, _ := new(big.Int).SetString("e4a42d43c5cf169d9391df6decf42ee541b6d8f0c9a137401e23632dda34d24f", 16) - g100433627766186892221372630771322662657637687111424552206336y, _ := new(big.Int).SetString("4d9f92e716d1c73526fc99ccfb8ad34ce886eedfa8d8e4f13a7f7131deba9414", 16) - g200867255532373784442745261542645325315275374222849104412672x, _ := new(big.Int).SetString("fd6451fb84cfb18d3ef0acf856c4ef4d0553c562f7ae4d2a303f2ea33e8f62bb", 16) - g200867255532373784442745261542645325315275374222849104412672y, _ := new(big.Int).SetString("e745ceb2b1871578b6fe7a5c1bc344ccfa2ab492d200e83fd0ad9086132c0911", 16) - g401734511064747568885490523085290650630550748445698208825344x, _ := new(big.Int).SetString("1eee207cb24086bc716e81a06f9edbbb0042e2d5dcf3c7a1fa1d1fb9d5fe696b", 16) - g401734511064747568885490523085290650630550748445698208825344y, _ := new(big.Int).SetString("652cbd19aef6269cd2b196d12461c95f7a02062e0afd694ebb45670e7429337b", 16) - g803469022129495137770981046170581301261101496891396417650688x, _ := new(big.Int).SetString("cc0ea33ea8a9eb14d465ab2c346e2111e1c0fc017c57257908d40f19ef94c0d5", 16) - g803469022129495137770981046170581301261101496891396417650688y, _ := new(big.Int).SetString("f9907a3b711c8a2fb23dd203b5fbe663f6074f266113f543deabe597af452fe6", 16) - g1606938044258990275541962092341162602522202993782792835301376x, _ := new(big.Int).SetString("1ec80fef360cbdd954160fadab352b6b92b53576a88fea4947173b9d4300bf19", 16) - g1606938044258990275541962092341162602522202993782792835301376y, _ := new(big.Int).SetString("aeefe93756b5340d2f3a4958a7abbf5e0146e77f6295a07b671cdc1cc107cefd", 16) - g3213876088517980551083924184682325205044405987565585670602752x, _ := new(big.Int).SetString("5be7ea3519f04bc6cbeeaa0344fc90bb8e8462f6ebd890560dae805d414ff9e4", 16) - g3213876088517980551083924184682325205044405987565585670602752y, _ := new(big.Int).SetString("32f32ec3f638e605477f890f655ab7fe0e99c6302119a3094030b07847e0bdbb", 16) - g6427752177035961102167848369364650410088811975131171341205504x, _ := new(big.Int).SetString("58f099116eae4e650813fc8698df7f5cd50028649f853991e3fb545f4ddb7bb8", 16) - g6427752177035961102167848369364650410088811975131171341205504y, _ := new(big.Int).SetString("7e07002aaffe111a0d62ff7614638066507ee4062d174302bdec73582e5b2d6e", 16) - g12855504354071922204335696738729300820177623950262342682411008x, _ := new(big.Int).SetString("b0f9e4b9b29790b633bcc04fd860cb0f823d8d1a4cc1a1c1413c1606cc9a8e2c", 16) - g12855504354071922204335696738729300820177623950262342682411008y, _ := new(big.Int).SetString("49e82bf1843ade6d41cbb0b906fde3f03350cc02c171cee76c2066c4df3d0db4", 16) - g25711008708143844408671393477458601640355247900524685364822016x, _ := new(big.Int).SetString("146a778c04670c2f91b00af4680dfa8bce3490717d58ba889ddb5928366642be", 16) - g25711008708143844408671393477458601640355247900524685364822016y, _ := new(big.Int).SetString("b318e0ec3354028add669827f9d4b2870aaa971d2f7e5ed1d0b297483d83efd0", 16) - g51422017416287688817342786954917203280710495801049370729644032x, _ := new(big.Int).SetString("574ef0ce8a597e24e5670b5c0bcd14cfeefc983c7ecb261911b2365579de5cac", 16) - g51422017416287688817342786954917203280710495801049370729644032y, _ := new(big.Int).SetString("9b99930281f19c73bd6ada0569b78451a260a7bef10008cae59aea6c75a4805", 16) - g102844034832575377634685573909834406561420991602098741459288064x, _ := new(big.Int).SetString("d3d97e799d8bf9f85d909397b98c835d10a770c1aeff8645808c2d74260966d3", 16) - g102844034832575377634685573909834406561420991602098741459288064y, _ := new(big.Int).SetString("8ddbb46376bac95e6aaa89275d403ad3b5e48711be8dc4eebddeb850833c2e52", 16) - g205688069665150755269371147819668813122841983204197482918576128x, _ := new(big.Int).SetString("b1aa653288b318987b974e782cbbee0ab2be78cf8f494c120040fb93968c6d4b", 16) - g205688069665150755269371147819668813122841983204197482918576128y, _ := new(big.Int).SetString("7ed6071c60810d712684aa8e2d63a83b100a1d909d623cc383d9e62ae891ac51", 16) - g411376139330301510538742295639337626245683966408394965837152256x, _ := new(big.Int).SetString("fa50c0f61d22e5f07e3acebb1aa07b128d0012209a28b9776d76a8793180eef9", 16) - g411376139330301510538742295639337626245683966408394965837152256y, _ := new(big.Int).SetString("6b84c6922397eba9b72cd2872281a68a5e683293a57a213b38cd8d7d3f4f2811", 16) - g822752278660603021077484591278675252491367932816789931674304512x, _ := new(big.Int).SetString("63964eee619074e0780140fe02e90836e72328d2448386d459c5be23187f5048", 16) - g822752278660603021077484591278675252491367932816789931674304512y, _ := new(big.Int).SetString("3b6cfb3a6b89cf41a39ff9b1c34bfbc93d580b934dde6c84383a284d89309df8", 16) - g1645504557321206042154969182557350504982735865633579863348609024x, _ := new(big.Int).SetString("5a3ce25b4d15b7e22d1469ddf0fc9f75afd7f12ad3cbda31f814ba1ebadb2a65", 16) - g1645504557321206042154969182557350504982735865633579863348609024y, _ := new(big.Int).SetString("8b34125b92e05f63873a6dbfbf3f99af3ee28bc3d825fe8ed8b170cf1d327f1d", 16) - g3291009114642412084309938365114701009965471731267159726697218048x, _ := new(big.Int).SetString("5ce605af98f93eda6910be34f0de41ff85dbcb6e69a8fa0016a733754a9f44d0", 16) - g3291009114642412084309938365114701009965471731267159726697218048y, _ := new(big.Int).SetString("4cddcf9bec226bfe7ba56bd031c76c58ab3cb1bfa32eccc6c0d05f3489d30105", 16) - g6582018229284824168619876730229402019930943462534319453394436096x, _ := new(big.Int).SetString("da1d61d0ca721a11b1a5bf6b7d88e8421a288ab5d5bba5220e53d32b5f067ec2", 16) - g6582018229284824168619876730229402019930943462534319453394436096y, _ := new(big.Int).SetString("8157f55a7c99306c79c0766161c91e2966a73899d279b48a655fba0f1ad836f1", 16) - g13164036458569648337239753460458804039861886925068638906788872192x, _ := new(big.Int).SetString("9c7be00b4ef4c444df85d5f61dc1283a23605483e1f8e934b3c210d22cd3c369", 16) - g13164036458569648337239753460458804039861886925068638906788872192y, _ := new(big.Int).SetString("9220c0de74b20d2052a26d455ce401483e31153a16769cbd29ee3feba2329515", 16) - g26328072917139296674479506920917608079723773850137277813577744384x, _ := new(big.Int).SetString("fcd83f42825263bb55664b238ccc49174dd06a70541178e76bcd92d7bb8c9e3", 16) - g26328072917139296674479506920917608079723773850137277813577744384y, _ := new(big.Int).SetString("6c0bc1cfeac5fbced1d8232de5fdb683adbeaecdf1627bf4e86d55fbdf4aa9ad", 16) - g52656145834278593348959013841835216159447547700274555627155488768x, _ := new(big.Int).SetString("7175407f1b58f010d4cda4c62511e59db7edcf28f5476d995cf39944b26b64f1", 16) - g52656145834278593348959013841835216159447547700274555627155488768y, _ := new(big.Int).SetString("43b4554344e3d550f36d3401134cc86eb01fe8b774471d2a426e7efab24234d5", 16) - g105312291668557186697918027683670432318895095400549111254310977536x, _ := new(big.Int).SetString("a8e282ff0c9706907215ff98e8fd416615311de0446f1e062a73b0610d064e13", 16) - g105312291668557186697918027683670432318895095400549111254310977536y, _ := new(big.Int).SetString("7f97355b8db81c09abfb7f3c5b2515888b679a3e50dd6bd6cef7c73111f4cc0c", 16) - g210624583337114373395836055367340864637790190801098222508621955072x, _ := new(big.Int).SetString("cac6f2e7e27faecbcb876f805ea66e63efbe9eaa753d67c1c15eb9ea7f7653a1", 16) - g210624583337114373395836055367340864637790190801098222508621955072y, _ := new(big.Int).SetString("f7d416e5e2aa6f194cdb65d9a42a345081e83ae5688103a068c10ad0fec5e556", 16) - g421249166674228746791672110734681729275580381602196445017243910144x, _ := new(big.Int).SetString("e6dfde46ee37d206efbc5932e58e43254ab767294238cb11cc9f4ab08624003d", 16) - g421249166674228746791672110734681729275580381602196445017243910144y, _ := new(big.Int).SetString("8727b3b7be9139498f2f48f7b88f92203b1ce5ea527fd7dd7548650e2216b93b", 16) - g842498333348457493583344221469363458551160763204392890034487820288x, _ := new(big.Int).SetString("3c4e089cd9a6823d66a40cfc7ac96082e250e3149cf211d3b0e1103548dce109", 16) - g842498333348457493583344221469363458551160763204392890034487820288y, _ := new(big.Int).SetString("43fbbe669fe191b480757bca15764d379579e142d97fe697e2bf65923a19aeea", 16) - g1684996666696914987166688442938726917102321526408785780068975640576x, _ := new(big.Int).SetString("174a53b9c9a285872d39e56e6913cab15d59b1fa512508c022f382de8319497c", 16) - g1684996666696914987166688442938726917102321526408785780068975640576y, _ := new(big.Int).SetString("ccc9dc37abfc9c1657b4155f2c47f9e6646b3a1d8cb9854383da13ac079afa73", 16) - g3369993333393829974333376885877453834204643052817571560137951281152x, _ := new(big.Int).SetString("20e6e2e796946bb630c7071ef1b92ea3d53d280e0e4501115f5da36f840dd273", 16) - g3369993333393829974333376885877453834204643052817571560137951281152y, _ := new(big.Int).SetString("d3ad7afe4f1559e44a0ba1ad97874655811ec9793da8693cc07cfd15bb46b593", 16) - g6739986666787659948666753771754907668409286105635143120275902562304x, _ := new(big.Int).SetString("8e0ca824d7a351dba80280a07e71db7035ae68136cc24ca3e7b54f301a077674", 16) - g6739986666787659948666753771754907668409286105635143120275902562304y, _ := new(big.Int).SetString("4ec560759192d41dc569d24da62cf57cff60419d2f910290b84cbec12b7ed98", 16) - g13479973333575319897333507543509815336818572211270286240551805124608x, _ := new(big.Int).SetString("f7bb50da51c982d1c5fa63553e3d66c1afdb5821a321b4afe96afc5ea8192441", 16) - g13479973333575319897333507543509815336818572211270286240551805124608y, _ := new(big.Int).SetString("93cc3be30334a526311bc63bdde6485db1cfdc1fbbc4c74bbc640ea1d45165ae", 16) - g26959946667150639794667015087019630673637144422540572481103610249216x, _ := new(big.Int).SetString("959396981943785c3d3e57edf5018cdbe039e730e4918b3d884fdff09475b7ba", 16) - g26959946667150639794667015087019630673637144422540572481103610249216y, _ := new(big.Int).SetString("2e7e552888c331dd8ba0386a4b9cd6849c653f64c8709385e9b8abf87524f2fd", 16) - g53919893334301279589334030174039261347274288845081144962207220498432x, _ := new(big.Int).SetString("cbee1405ff0da7deafe32ca7dd73d95ed702226b391747c707275a940bc8f53b", 16) - g53919893334301279589334030174039261347274288845081144962207220498432y, _ := new(big.Int).SetString("f6211f4f4e75f902b51f3e689b8294cf0d9ff4f68126f7282922e6b278c87f45", 16) - g107839786668602559178668060348078522694548577690162289924414440996864x, _ := new(big.Int).SetString("add5bad28faaf5acdd580bfa0ba252e03de3beaefbd71b9cf377c88b14b311dd", 16) - g107839786668602559178668060348078522694548577690162289924414440996864y, _ := new(big.Int).SetString("e9c43cf4da3dc3a5974e434f8359814f52d4e1e7669b9b8902f982f349d6c38d", 16) - g215679573337205118357336120696157045389097155380324579848828881993728x, _ := new(big.Int).SetString("53f2432ba81717143fa9df3dff41ced24a29b314bc5a8c96f5f6400a0d7c0979", 16) - g215679573337205118357336120696157045389097155380324579848828881993728y, _ := new(big.Int).SetString("bd52effbc1f079b7ccd4e3e0911b07de4bd5a4f5c9e8b845f9f7e90c537b36a2", 16) - g431359146674410236714672241392314090778194310760649159697657763987456x, _ := new(big.Int).SetString("d2a63a50ae401e56d645a1153b109a8fcca0a43d561fba2dbb51340c9d82b151", 16) - g431359146674410236714672241392314090778194310760649159697657763987456y, _ := new(big.Int).SetString("e82d86fb6443fcb7565aee58b2948220a70f750af484ca52d4142174dcf89405", 16) - g862718293348820473429344482784628181556388621521298319395315527974912x, _ := new(big.Int).SetString("baf183a76100525e23bc7202033725f922b9cd6b36c413497c6c4bacca72da5f", 16) - g862718293348820473429344482784628181556388621521298319395315527974912y, _ := new(big.Int).SetString("deac9fbe9ccb4d335688bd58dd69b1d18e2336c5ca739361377ce628a8f2a0cf", 16) - g1725436586697640946858688965569256363112777243042596638790631055949824x, _ := new(big.Int).SetString("f7aef8a7e38440238f9332906e48f6fd5adbd02d56b76a5ffa5aca58c56c3943", 16) - g1725436586697640946858688965569256363112777243042596638790631055949824y, _ := new(big.Int).SetString("4e3b0b44d5ffda797c442bbdc3ab3fcfeec30184a8dcd003431f627facf442f1", 16) - g3450873173395281893717377931138512726225554486085193277581262111899648x, _ := new(big.Int).SetString("dfb547cb10019036c5a2e29f0dddbb1f7af2fa25a3c7a78c1fac945711924459", 16) - g3450873173395281893717377931138512726225554486085193277581262111899648y, _ := new(big.Int).SetString("9accd2a9ba0f47088b8389ce9dc864cc22af0930e5c031dcfa205e0dcc65fd9e", 16) - g6901746346790563787434755862277025452451108972170386555162524223799296x, _ := new(big.Int).SetString("64587e2335471eb890ee7896d7cfdc866bacbdbd3839317b3436f9b45617e073", 16) - g6901746346790563787434755862277025452451108972170386555162524223799296y, _ := new(big.Int).SetString("d99fcdd5bf6902e2ae96dd6447c299a185b90a39133aeab358299e5e9faf6589", 16) - g13803492693581127574869511724554050904902217944340773110325048447598592x, _ := new(big.Int).SetString("b866d6b142df940f2cf28b54c92f0c1294e0b6a22a91f2ef44bcd88c4384480d", 16) - g13803492693581127574869511724554050904902217944340773110325048447598592y, _ := new(big.Int).SetString("1914b0b3426aeb7089a278d7ea9ad7ac24e522804b1d86d60e659b470c4cafa8", 16) - g27606985387162255149739023449108101809804435888681546220650096895197184x, _ := new(big.Int).SetString("ec2bb89085de819ec4d9d1646102ba87e2d52ae4ed4fe455d229cda81db20d6c", 16) - g27606985387162255149739023449108101809804435888681546220650096895197184y, _ := new(big.Int).SetString("ccecc17661e013a1332f66f0650940c633a2364be87efa98a0e99c4d629cf4a0", 16) - g55213970774324510299478046898216203619608871777363092441300193790394368x, _ := new(big.Int).SetString("71c4a7e389e296ced39d75ef5e545905e50050640f50becf38a60ecb23b09d0f", 16) - g55213970774324510299478046898216203619608871777363092441300193790394368y, _ := new(big.Int).SetString("1313fadb737af3ba0af3e0a292f810aa786f2b084a62ffc7637b1f01720ddb62", 16) - g110427941548649020598956093796432407239217743554726184882600387580788736x, _ := new(big.Int).SetString("8481bde0e4e4d885b3a546d3e549de042f0aa6cea250e7fd358d6c86dd45e458", 16) - g110427941548649020598956093796432407239217743554726184882600387580788736y, _ := new(big.Int).SetString("38ee7b8cba5404dd84a25bf39cecb2ca900a79c42b262e556d64b1b59779057e", 16) - g220855883097298041197912187592864814478435487109452369765200775161577472x, _ := new(big.Int).SetString("9629a450bd383a8b9fd43c6cd1d492bf392ed605299561dde54433526ce9f114", 16) - g220855883097298041197912187592864814478435487109452369765200775161577472y, _ := new(big.Int).SetString("bf439b280c5fb6d7576befd220cef64db925593e5c56af8dca3972c4a24aa391", 16) - g441711766194596082395824375185729628956870974218904739530401550323154944x, _ := new(big.Int).SetString("b73b1c47ef1e4688eb1730da7cc893df1477d747e187e18383d38d9626ca6cc3", 16) - g441711766194596082395824375185729628956870974218904739530401550323154944y, _ := new(big.Int).SetString("584315cb294922a90a57d64bbcc805097322a25209757f5afac35d76a54fdba3", 16) - g883423532389192164791648750371459257913741948437809479060803100646309888x, _ := new(big.Int).SetString("edfe16b2db40180311f9892007a2fef7d05b2a3bb676899f9c6e2192d38f93e0", 16) - g883423532389192164791648750371459257913741948437809479060803100646309888y, _ := new(big.Int).SetString("ee6902f1fca5db3694d74faa4b05d0d25b3d5100c46e227e3d01793de29405ad", 16) - g1766847064778384329583297500742918515827483896875618958121606201292619776x, _ := new(big.Int).SetString("13464a57a78102aa62b6979ae817f4637ffcfed3c4b1ce30bcd6303f6caf666b", 16) - g1766847064778384329583297500742918515827483896875618958121606201292619776y, _ := new(big.Int).SetString("69be159004614580ef7e433453ccb0ca48f300a81d0942e13f495a907f6ecc27", 16) - g3533694129556768659166595001485837031654967793751237916243212402585239552x, _ := new(big.Int).SetString("eb3cf8f532245362ec05c88c85fe12d19182be7dceabe577c75849c6065084ae", 16) - g3533694129556768659166595001485837031654967793751237916243212402585239552y, _ := new(big.Int).SetString("c833c78222d9d70043fe63dcefdca4a1f52b45c5e7dbd2a66f67c1fff96b9480", 16) - g7067388259113537318333190002971674063309935587502475832486424805170479104x, _ := new(big.Int).SetString("bdf1a67d092d99974f7a60f2184519b2a576fcf984a201d9f8e5bcbcc2e9a5d0", 16) - g7067388259113537318333190002971674063309935587502475832486424805170479104y, _ := new(big.Int).SetString("4095902bab65a1aaa80be54a86bf7baaa6280b61e5626461cdb4f7018562ff7b", 16) - g14134776518227074636666380005943348126619871175004951664972849610340958208x, _ := new(big.Int).SetString("68856a6eddc4ec29cd5be267b64483b48c3b4196477da62abde5fc173b27e771", 16) - g14134776518227074636666380005943348126619871175004951664972849610340958208y, _ := new(big.Int).SetString("77a33df14f79a1fb13b6fd49c19f7b4a331d22f293b0733a6118d62a07bbdab6", 16) - g28269553036454149273332760011886696253239742350009903329945699220681916416x, _ := new(big.Int).SetString("bc4a9df5b713fe2e9aef430bcc1dc97a0cd9ccede2f28588cada3a0d2d83f366", 16) - g28269553036454149273332760011886696253239742350009903329945699220681916416y, _ := new(big.Int).SetString("d3a81ca6e785c06383937adf4b798caa6e8a9fbfa547b16d758d666581f33c1", 16) - g56539106072908298546665520023773392506479484700019806659891398441363832832x, _ := new(big.Int).SetString("da433d5e11ceccc0abc5c7626ce7bab42e89b221f785c409282de545f3fceb19", 16) - g56539106072908298546665520023773392506479484700019806659891398441363832832y, _ := new(big.Int).SetString("e498dbd321a810301debbdc4af95e5218e77fc2d9227b277684e7120a6f5cc64", 16) - g113078212145816597093331040047546785012958969400039613319782796882727665664x, _ := new(big.Int).SetString("31e8e1ee9e8c7ec1c1c116981c16efdbcc4838a72207e0654de275c5acf692a", 16) - g113078212145816597093331040047546785012958969400039613319782796882727665664y, _ := new(big.Int).SetString("ad7e7f5b465b353dd9d0970290d6743b70649827c5bf73b09cc2a84eb16f667a", 16) - g226156424291633194186662080095093570025917938800079226639565593765455331328x, _ := new(big.Int).SetString("a9878607a88d61155d3e00d862657f73e9c9bf363fc7a91592bbd7ff81f488b6", 16) - g226156424291633194186662080095093570025917938800079226639565593765455331328y, _ := new(big.Int).SetString("d181a1abd58895d61c063e7c82157c2239d0f01964ad5c6d495a7bbb031dab1d", 16) - g452312848583266388373324160190187140051835877600158453279131187530910662656x, _ := new(big.Int).SetString("8c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa", 16) - g452312848583266388373324160190187140051835877600158453279131187530910662656y, _ := new(big.Int).SetString("40a30463a3305193378fedf31f7cc0eb7ae784f0451cb9459e71dc73cbef9482", 16) - g904625697166532776746648320380374280103671755200316906558262375061821325312x, _ := new(big.Int).SetString("ab1ac1872a38a2f196bed5a6047f0da2c8130fe8de49fc4d5dfb201f7611d8e2", 16) - g904625697166532776746648320380374280103671755200316906558262375061821325312y, _ := new(big.Int).SetString("13f4a37a324d17a1e9aa5f39db6a42b6f7ef93d33e1e545f01a581f3c429d15b", 16) - g1809251394333065553493296640760748560207343510400633813116524750123642650624x, _ := new(big.Int).SetString("2564fe9b5beef82d3703a607253f31ef8ea1b365772df434226aee642651b3fa", 16) - g1809251394333065553493296640760748560207343510400633813116524750123642650624y, _ := new(big.Int).SetString("8ad9f7a60678389095fa14ae1203925f14f37dab6b79816edb82e6a301e5122d", 16) - g3618502788666131106986593281521497120414687020801267626233049500247285301248x, _ := new(big.Int).SetString("ff3d6136ffac5b0cbfc6c5c0c30dc01a7ea3d56c20bd3103b178e3d3ae180068", 16) - g3618502788666131106986593281521497120414687020801267626233049500247285301248y, _ := new(big.Int).SetString("133239be84e4000e40d0372cdd96adc1547676f24001f5e670a6bb6e188c6077", 16) - g7237005577332262213973186563042994240829374041602535252466099000494570602496x, _ := new(big.Int).SetString("8ea9666139527a8c1dd94ce4f071fd23c8b350c5a4bb33748c4ba111faccae0", 16) - g7237005577332262213973186563042994240829374041602535252466099000494570602496y, _ := new(big.Int).SetString("620efabbc8ee2782e24e7c0cfb95c5d735b783be9cf0f8e955af34a30e62b945", 16) - g14474011154664524427946373126085988481658748083205070504932198000989141204992x, _ := new(big.Int).SetString("c25f637176220cd9f3a66df315559d8263cf2a23a4ab5ab9a293131da190b632", 16) - g14474011154664524427946373126085988481658748083205070504932198000989141204992y, _ := new(big.Int).SetString("53154fede94d2873989049903809d7980a9f04ff9e027a1d6eebf3d6fc9590cf", 16) - g28948022309329048855892746252171976963317496166410141009864396001978282409984x, _ := new(big.Int).SetString("2a9e8dfe3cce6bab3e82d82a5688544c0c7b55dc31978b4de2ccb3b7d466d561", 16) - g28948022309329048855892746252171976963317496166410141009864396001978282409984y, _ := new(big.Int).SetString("1dfeda5c16e651fbac7b5ad608b96cf5e01eaec17a02182f96ccf5252e76373", 16) - g57896044618658097711785492504343953926634992332820282019728792003956564819968x, _ := new(big.Int).SetString("b23790a42be63e1b251ad6c94fdef07271ec0aada31db6c3e8bd32043f8be384", 16) - g57896044618658097711785492504343953926634992332820282019728792003956564819968y, _ := new(big.Int).SetString("fc6b694919d55edbe8d50f88aa81f94517f004f4149ecb58d10a473deb19880e", 16) - g115792089237316195423570985008687907853269984665640564039457584007913129639936x, _ := new(big.Int).SetString("dd3625faef5ba06074669716bbd3788d89bdde815959968092f76cc4eb9a9787", 16) - g115792089237316195423570985008687907853269984665640564039457584007913129639936y, _ := new(big.Int).SetString("7a188fa3520e30d461da2501045731ca941461982883395937f68d00c644a573", 16) + g2To3x, _ := new(big.Int).SetString("2f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01", 16) + g2To3y, _ := new(big.Int).SetString("5c4da8a741539949293d082a132d13b4c2e213d6ba5b7617b5da2cb76cbde904", 16) + g2To4x, _ := new(big.Int).SetString("e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", 16) + g2To4y, _ := new(big.Int).SetString("f7e3507399e595929db99f34f57937101296891e44d23f0be1f32cce69616821", 16) + g2To5x, _ := new(big.Int).SetString("d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", 16) + g2To5y, _ := new(big.Int).SetString("95038d9d0ae3d5c3b3d6dec9e98380651f760cc364ed819605b3ff1f24106ab9", 16) + g2To6x, _ := new(big.Int).SetString("bf23c1542d16eab70b1051eaf832823cfc4c6f1dcdbafd81e37918e6f874ef8b", 16) + g2To6y, _ := new(big.Int).SetString("5cb3866fc33003737ad928a0ba5392e4c522fc54811e2f784dc37efe66831d9f", 16) + g2To7x, _ := new(big.Int).SetString("34ff3be4033f7a06696c3d09f7d1671cbcf55cd700535655647077456769a24e", 16) + g2To7y, _ := new(big.Int).SetString("5d9d11623a236c553f6619d89832098c55df16c3e8f8b6818491067a73cc2f1a", 16) + g2To8x, _ := new(big.Int).SetString("8282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508", 16) + g2To8y, _ := new(big.Int).SetString("11f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf", 16) + g2To9x, _ := new(big.Int).SetString("465370b287a79ff3905a857a9cf918d50adbc968d9e159d0926e2c00ef34a24d", 16) + g2To9y, _ := new(big.Int).SetString("35e531b38368c082a4af8bdafdeec2c1588e09b215d37a10a2f8fb20b33887f4", 16) + g2To10x, _ := new(big.Int).SetString("241febb8e23cbd77d664a18f66ad6240aaec6ecdc813b088d5b901b2e285131f", 16) + g2To10y, _ := new(big.Int).SetString("513378d9ff94f8d3d6c420bd13981df8cd50fd0fbd0cb5afabb3e66f2750026d", 16) + g2To11x, _ := new(big.Int).SetString("5d1bdb4ea172fa79fce4cc2983d8f8d9fc318b85f423de0dedcb63069b920471", 16) + g2To11y, _ := new(big.Int).SetString("2843826779379e2e794bb99438a2265679eb1e9996c56e7b70330666f7b83103", 16) + g2To12x, _ := new(big.Int).SetString("175e159f728b865a72f99cc6c6fc846de0b93833fd2222ed73fce5b551e5b739", 16) + g2To12y, _ := new(big.Int).SetString("d3506e0d9e3c79eba4ef97a51ff71f5eacb5955add24345c6efa6ffee9fed695", 16) + g2To13x, _ := new(big.Int).SetString("423a013f03ff32d7a5ffbcc8e139c62130fdfeb5c6da121bce78049e46bc47d6", 16) + g2To13y, _ := new(big.Int).SetString("b91ae00fe1e1d970a1179f7bbaf6b3c7720d8ec3524f009ed1236e6d8b548a34", 16) + g2To14x, _ := new(big.Int).SetString("111d6a45ac1fb90508907a7abcd6877649df662f3b3e2741302df6f78416824a", 16) + g2To14y, _ := new(big.Int).SetString("696911c478eaffbb90d48dbff065952f070008996daca4ca9a111d42108e9d0", 16) + g2To15x, _ := new(big.Int).SetString("4a4a6dc97ac7c8b8ad795dbebcb9dcff7290b68a5ef74e56ab5edde01bced775", 16) + g2To15y, _ := new(big.Int).SetString("529911b016631e72943ef9f739c0f4571de90cdb424742acb2bf8f68a78dd66d", 16) + g2To16x, _ := new(big.Int).SetString("363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640", 16) + g2To16y, _ := new(big.Int).SetString("4e273adfc732221953b445397f3363145b9a89008199ecb62003c7f3bee9de9", 16) + g2To17x, _ := new(big.Int).SetString("4c1b9866ed9a7e9b553973c6c93b02bf0b62fb012edfb59dd2712a5caf92c541", 16) + g2To17y, _ := new(big.Int).SetString("c1f792d320be8a0f7fbcb753ce56e69cc652ead7e43eb1ad72c4f3fdc68fe020", 16) + g2To18x, _ := new(big.Int).SetString("a4083877ba83b12b529a2f3c0780b54e3233edbc1a28f135e0c8f28cbeaaf3d1", 16) + g2To18y, _ := new(big.Int).SetString("40e9f612feefbc79b8bf83d69361b3e22001e7576ed1ef90b12b534df0b254b9", 16) + g2To19x, _ := new(big.Int).SetString("a804c641d28cc0b53a4e3e1a2f56c86f6e0d880a454203b98cd3db5a7940d33a", 16) + g2To19y, _ := new(big.Int).SetString("95be83252b2fa6d03dec2842c16047e81af18ca89cf736a943ce95fa6d46967a", 16) + g2To20x, _ := new(big.Int).SetString("8b4b5f165df3c2be8c6244b5b745638843e4a781a15bcd1b69f79a55dffdf80c", 16) + g2To20y, _ := new(big.Int).SetString("4aad0a6f68d308b4b3fbd7813ab0da04f9e336546162ee56b3eff0c65fd4fd36", 16) + g2To21x, _ := new(big.Int).SetString("ed0c5ce4e13291718ce17c7ec83c611071af64ee417c997abb3f26714755e4be", 16) + g2To21y, _ := new(big.Int).SetString("221a9fc7bc2345bdbf3dad7f5a7ea68049d93925763ddab163f9fa6ea07bf42f", 16) + g2To22x, _ := new(big.Int).SetString("faecb013c44ce694b3b15c3f83f1fae8e53254566e0552ced4b6e6c807cec8ab", 16) + g2To22y, _ := new(big.Int).SetString("cc09b5e90e9ecb57fc2e02c6ec2fb13d9c32b286b85e2e2e8981dfd9ab155070", 16) + g2To23x, _ := new(big.Int).SetString("9bb8a132dcad2f2c8731a0b37cbcafdb3b2dd824f23cd3e07f64eae9ad1b1f7", 16) + g2To23y, _ := new(big.Int).SetString("945bb2b2afeee3b9b6f9dd284f863e850f54a840f4752d5364130627c3811c80", 16) + g2To24x, _ := new(big.Int).SetString("723cbaa6e5db996d6bf771c00bd548c7b700dbffa6c0e77bcb6115925232fcda", 16) + g2To24y, _ := new(big.Int).SetString("96e867b5595cc498a921137488824d6e2660a0653779494801dc069d9eb39f5f", 16) + g2To25x, _ := new(big.Int).SetString("57efa786437b744d343d7dc45773a3c62d240a43079849071fd383d60ca030d5", 16) + g2To25y, _ := new(big.Int).SetString("d712db0bd1b48518893627c928de03ec689b6d2ae5e9974ab07ab44274b02f9e", 16) + g2To26x, _ := new(big.Int).SetString("264bbd436a28bc42a2df7e9cd5226cb91080577e327b012a7fafc7770c584dd5", 16) + g2To26y, _ := new(big.Int).SetString("d87c6fa94ee093b4d4f75ce24c33be226a118243717b8d8de61227937704ab11", 16) + g2To27x, _ := new(big.Int).SetString("a94c6524bd40d2bbdac85c056236a79da78bc61fd5bdec9d2bf26bd84b2438e8", 16) + g2To27y, _ := new(big.Int).SetString("b5201fd992f96280fd79219505019e3a7e5d3c60a0e39b2bc2e2c8dbf18661f4", 16) + g2To28x, _ := new(big.Int).SetString("eebfa4d493bebf98ba5feec812c2d3b50947961237a919839a533eca0e7dd7fa", 16) + g2To28y, _ := new(big.Int).SetString("5d9a8ca3970ef0f269ee7edaf178089d9ae4cdc3a711f712ddfd4fdae1de8999", 16) + g2To29x, _ := new(big.Int).SetString("381c4ad7a7a97bfda61c6031c118495fc4ea4bc08f6766d676bee90847d297fd", 16) + g2To29y, _ := new(big.Int).SetString("936af53b238eeee48f3e5fa709915eccf0451032db939c0093ace3187d493fc5", 16) + g2To30x, _ := new(big.Int).SetString("e1efb9cd05adc63bcce10831d9538c479cf1d05fefdd08b2448d70422ede454c", 16) + g2To30y, _ := new(big.Int).SetString("ecb4530d8af9be7b0154c1ffe477123464e3244a7a2d4c6ad9fd233a8913797", 16) + g2To31x, _ := new(big.Int).SetString("5318f9b1a2697010c5ac235e9af475a8c7e5419f33d47b18d33feeb329eb99a4", 16) + g2To31y, _ := new(big.Int).SetString("f44ccfeb4beda4195772d93aebb405e8a41f2b40d1e3ec652c726eeefe91f92d", 16) + g2To32x, _ := new(big.Int).SetString("100f44da696e71672791d0a09b7bde459f1215a29b3c03bfefd7835b39a48db0", 16) + g2To32y, _ := new(big.Int).SetString("cdd9e13192a00b772ec8f3300c090666b7ff4a18ff5195ac0fbd5cd62bc65a09", 16) + g2To33x, _ := new(big.Int).SetString("8c0989f2ceb5c771a8415dff2b4c4199d8d9c8f9237d08084b05284f1e4df706", 16) + g2To33y, _ := new(big.Int).SetString("fb4dbd044f432034ffd2172cb9dc966c60de6bf5156511aa736ac5a35d72fa98", 16) + g2To34x, _ := new(big.Int).SetString("fb8f153c5e266704c4a481743262c0259c528539bc95bc1bb1e63c33dc47bffd", 16) + g2To34y, _ := new(big.Int).SetString("6ca27a9dc5e0621816fa11d9b4bccd531dde1389ac542613090a45ddd949b095", 16) + g2To35x, _ := new(big.Int).SetString("e747333fd75d51755a0cc9f0a728708465a02c587737a7b8b8fa1b8b4bb2629a", 16) + g2To35y, _ := new(big.Int).SetString("f2affe0145070c114cc43603804c2581c88376aa6e1a969a9f8d961a6946f6d6", 16) + g2To36x, _ := new(big.Int).SetString("e1031be262c7ed1b1dc9227a4a04c017a77f8d4464f3b3852c8acde6e534fd2d", 16) + g2To36y, _ := new(big.Int).SetString("9d7061928940405e6bb6a4176597535af292dd419e1ced79a44f18f29456a00d", 16) + g2To37x, _ := new(big.Int).SetString("f4b93f224c8089eab9f95dcd0f29b2c9028a6ac5de94d85784e27e36a95c8356", 16) + g2To37y, _ := new(big.Int).SetString("a67a92ec062962dfb0e5f6a7a40eee90c37ef1344915609abd5861b9be001fd3", 16) + g2To38x, _ := new(big.Int).SetString("9d1aca1fce55236b19622ea025b08b0d51e8512f97e696c20d62fe17b160e8a", 16) + g2To38y, _ := new(big.Int).SetString("1153188f5101f0c63e56692ce0d8c27e6fe9e0ee9212b5e534e050c57ca04c44", 16) + g2To39x, _ := new(big.Int).SetString("c66c59cc454c2b9e18a2ad793821cde7518b3a93bfc39562e97d7d0475ba7fc2", 16) + g2To39y, _ := new(big.Int).SetString("d9592fe2bfb30fcfbea4f3ceaac10cb2f00a60ddb15955977ec3c69cf75f5956", 16) + g2To40x, _ := new(big.Int).SetString("feea6cae46d55b530ac2839f143bd7ec5cf8b266a41d6af52d5e688d9094696d", 16) + g2To40y, _ := new(big.Int).SetString("e57c6b6c97dce1bab06e4e12bf3ecd5c981c8957cc41442d3155debf18090088", 16) + g2To41x, _ := new(big.Int).SetString("4d000b621adb87e1c53261af9db2e179141ecae0b331a1870aa4040aee752b08", 16) + g2To41y, _ := new(big.Int).SetString("6a0d5b8f18e0d255cb6d825582d972cccb7df5f119c7293a3e72851f48302cea", 16) + g2To42x, _ := new(big.Int).SetString("71f570ca203da05dd6aa262114717128d657a0403e1f1b77f89962fd475c58ef", 16) + g2To42y, _ := new(big.Int).SetString("eb42415b95dc880dd25557345bc95b8df2445d00c3363e7df8649a72d35d420e", 16) + g2To43x, _ := new(big.Int).SetString("a2b7b3629f7bd253b7d282b5c21da01446b4821dc65e76516048b06043ff8359", 16) + g2To43y, _ := new(big.Int).SetString("693038941695122d57a937a3f71e29c910d10835046f3835a2397fecfe86fec2", 16) + g2To44x, _ := new(big.Int).SetString("da67a91d91049cdcb367be4be6ffca3cfeed657d808583de33fa978bc1ec6cb1", 16) + g2To44y, _ := new(big.Int).SetString("9bacaa35481642bc41f463f7ec9780e5dec7adc508f740a17e9ea8e27a68be1d", 16) + g2To45x, _ := new(big.Int).SetString("4dbacd365fa1ef587c0c0cfaaf00d8718bbd9f35ccea5a835ee3cc821fe741c9", 16) + g2To45y, _ := new(big.Int).SetString("16c3540e8a51892e7fdcfd59e838299d0cc384a09fc0535f60be10f8338eb623", 16) + g2To46x, _ := new(big.Int).SetString("13d1ffc481509beee68f17d8ff41c2590f4c85f15268605087eda8bab4e218da", 16) + g2To46y, _ := new(big.Int).SetString("6008391fa991961dcecb9337b1b758bda4ad01206d5bd127e0db419ddb191c19", 16) + g2To47x, _ := new(big.Int).SetString("219b4f9cef6c60007659c79c45b0533b3cc9d916ce29dbff133b40caa2e96db8", 16) + g2To47y, _ := new(big.Int).SetString("24d9c605d959efeaf5a44180c0372a6e394f8ac53e90576527df01a78d3b6bc7", 16) + g2To48x, _ := new(big.Int).SetString("53904faa0b334cdda6e000935ef22151ec08d0f7bb11069f57545ccc1a37b7c0", 16) + g2To48y, _ := new(big.Int).SetString("5bc087d0bc80106d88c9eccac20d3c1c13999981e14434699dcb096b022771c8", 16) + g2To49x, _ := new(big.Int).SetString("1a575af9d4146753cf991196316995d2a6ee7aaad0f85ad57cd0f1f38a47ca9", 16) + g2To49y, _ := new(big.Int).SetString("3038f1cb8ab20dc3cc55fc52e1bb8698bdb93c5d9f4d7ea667c5df2e77ebcdb7", 16) + g2To50x, _ := new(big.Int).SetString("f5f0e0437621d439ca71f5c1b76155d6d3a61a83d3c20c6ee309d755e315565b", 16) + g2To50y, _ := new(big.Int).SetString("6b9f4e62be5a052bf62189160df7101aa5bf61bf3ed7e40a678430afdd2ecc82", 16) + g2To51x, _ := new(big.Int).SetString("8f506f0b6c0b6e9a57a7f36d970ca4e347cbc92146227642cbe781d9f5362d33", 16) + g2To51y, _ := new(big.Int).SetString("469f955d2afa61719530c5424f1c336848cf925d43bb8eaf30487d0c87fa243f", 16) + g2To52x, _ := new(big.Int).SetString("8e7bcd0bd35983a7719cca7764ca906779b53a043a9b8bcaeff959f43ad86047", 16) + g2To52y, _ := new(big.Int).SetString("10b7770b2a3da4b3940310420ca9514579e88e2e47fd68b3ea10047e8460372a", 16) + g2To53x, _ := new(big.Int).SetString("33b35baa195e729dc350f319996950df3bc15b8d3d0389e777d2808bf13f0351", 16) + g2To53y, _ := new(big.Int).SetString("a58a0185640abf87f9464036248d52bcaa6560efbc889b702bc503cccb8d7418", 16) + g2To54x, _ := new(big.Int).SetString("374deeae22c93f955cb83ad2071f7e2256f6e109cad7bca6d71dc7b24414bb36", 16) + g2To54y, _ := new(big.Int).SetString("171165b64fcd4f9916032c06f806f7293828d66300e543217875bea98daf734a", 16) + g2To55x, _ := new(big.Int).SetString("2380c09c7f3aeae57c46e07395aeb0dc944dbaf2b62a9f0c5e8a64ad6ae7d616", 16) + g2To55y, _ := new(big.Int).SetString("6f8e86193464956af1598aefd509b09a93af92148f8467560099be48161bbc1a", 16) + g2To56x, _ := new(big.Int).SetString("385eed34c1cdff21e6d0818689b81bde71a7f4f18397e6690a841e1599c43862", 16) + g2To56y, _ := new(big.Int).SetString("283bebc3e8ea23f56701de19e9ebf4576b304eec2086dc8cc0458fe5542e5453", 16) + g2To57x, _ := new(big.Int).SetString("f6f622083daf54800456be134d5f67d147c82642befc1ce2dc83a27078f2827c", 16) + g2To57y, _ := new(big.Int).SetString("1bcd4e817de73a0faf2c5715b367cee7e657ca7448321bf6d15b20b520aaa102", 16) + g2To58x, _ := new(big.Int).SetString("fb26e5188f953de2bd70cb3c3d1fc255cd91c3ce7d8c6f369d893209715adcb6", 16) + g2To58y, _ := new(big.Int).SetString("f3e128811012a34d58e846a719d0176916d2cb31b8b7ab5449dbca3b58ba68f3", 16) + g2To59x, _ := new(big.Int).SetString("8991225911b9132d28f5c6bc763ceab7d18c37060e8bd1d7ed44db7560788c1e", 16) + g2To59y, _ := new(big.Int).SetString("da8b4d987cc9ac9b27b8763559b136fa36969c84fdef9e11635c42228e8f0ef1", 16) + g2To60x, _ := new(big.Int).SetString("6f9d9b803ecf191637c73a4413dfa180fddf84a5947fbc9c606ed86c3fac3a7", 16) + g2To60y, _ := new(big.Int).SetString("7c80c68e603059ba69b8e2a30e45c4d47ea4dd2f5c281002d86890603a842160", 16) + g2To61x, _ := new(big.Int).SetString("ae86eeea252b411c1cdc36c284482939da1745e5a7e4da175c9d22744b7fd72d", 16) + g2To61y, _ := new(big.Int).SetString("19e993c9707302f962ab0ace589ff0e98d9211551472f7282334cb7a4eee38bc", 16) + g2To62x, _ := new(big.Int).SetString("2248c9f90bbfff55e61d2f8c56dc2c488718be75cf36f2ee7a1474267c169290", 16) + g2To62y, _ := new(big.Int).SetString("fa0594692d21eed7a506bb55b435ba18e163750235da2be2369d8a12883ea257", 16) + g2To63x, _ := new(big.Int).SetString("e11a6e16e05c44074ac11b48d94085d0a99f0877dd1c6f76fd0dac4bb50964e3", 16) + g2To63y, _ := new(big.Int).SetString("87d6065b87a2d430e1ad5e2596f0af2417adc6e138318c6f767fbf8b0682bfc8", 16) + g2To64x, _ := new(big.Int).SetString("3322d401243c4e2582a2147c104d6ecbf774d163db0f5e5313b7e0e742d0e6bd", 16) + g2To64y, _ := new(big.Int).SetString("56e70797e9664ef5bfb019bc4ddaf9b72805f63ea2873af624f3a2e96c28b2a0", 16) + g2To65x, _ := new(big.Int).SetString("8d26200250cebdae120ef31b04c80cd50d4cddc8eadbcf29fc696d32c0ade462", 16) + g2To65y, _ := new(big.Int).SetString("ebed3bb4715bf437d31f6f2dc3ee36ba1d4afb4e72678b3ad8e0a8b90f26470c", 16) + g2To66x, _ := new(big.Int).SetString("1238c0766eaebea9ce4068a1f594d03b8ed4930d072d9c8b9164643e1516e633", 16) + g2To66y, _ := new(big.Int).SetString("8a9db02dbb271359d6c979e2d1c3dc170946252dcc74022805cdb728c77b7805", 16) + g2To67x, _ := new(big.Int).SetString("271d5b0770cb9c15e7b2ea758a6a11b9cddcd7282b0ec21619b01552788e7a66", 16) + g2To67y, _ := new(big.Int).SetString("5d3aa45834e7f491e457d09949ac877fe2a065e3508a824e7a8d7258e03c9727", 16) + g2To68x, _ := new(big.Int).SetString("85672c7d2de0b7da2bd1770d89665868741b3f9af7643397721d74d28134ab83", 16) + g2To68y, _ := new(big.Int).SetString("7c481b9b5b43b2eb6374049bfa62c2e5e77f17fcc5298f44c8e3094f790313a6", 16) + g2To69x, _ := new(big.Int).SetString("534ccf6b740f9ec036c1861215c8a61f3b89ea46df2e6d96998b90bc1f17fc25", 16) + g2To69y, _ := new(big.Int).SetString("d5715cb09c8b2ddb462ae3dd32d543550ae3d277bfdd28ddd71c7f6ecfe86e76", 16) + g2To70x, _ := new(big.Int).SetString("a91d1f5cee87b7f3081e142018f8aaed79020d47ecfbc8d2c7170923e8bee8b6", 16) + g2To70y, _ := new(big.Int).SetString("748a324ee2df8ee15a7189c8dddad3b2f800569f628cb225003d16aa410644c1", 16) + g2To71x, _ := new(big.Int).SetString("c15c8c23d90c8e35c1a214dde2d4383c0735ae45bef61f10aa1a1c255984cf74", 16) + g2To71y, _ := new(big.Int).SetString("2ba954d828522235c8dc6f45e25fd7ba47bf772d50b015a2c4a48cd839ccb000", 16) + g2To72x, _ := new(big.Int).SetString("948bf809b1988a46b06c9f1919413b10f9226c60f668832ffd959af60c82a0a", 16) + g2To72y, _ := new(big.Int).SetString("53a562856dcb6646dc6b74c5d1c3418c6d4dff08c97cd2bed4cb7f88d8c8e589", 16) + g2To73x, _ := new(big.Int).SetString("26952c7f372e59360d5ce4c66291f0b6ef16c1331e825e51396eb0457e8b000a", 16) + g2To73y, _ := new(big.Int).SetString("f513ea4c5800a68862bc893d2d688422debe398f653d67318c3d401f05ef705a", 16) + g2To74x, _ := new(big.Int).SetString("c62e58e6fc23c5bdbef2be8b131ff243f521196572d6b0e9f102588976134f96", 16) + g2To74y, _ := new(big.Int).SetString("4397827d45b1a1678c3d676753141fc5bcfb853563731c3e82277ed4d14cf97e", 16) + g2To75x, _ := new(big.Int).SetString("107460520eec5c741683329a716622b0b81c03200807de973686f8800b188cbb", 16) + g2To75y, _ := new(big.Int).SetString("abe5d4c09a21598c35326b9b9cf54a11242e0d748dce3da601d7b6361f272124", 16) + g2To76x, _ := new(big.Int).SetString("6260ce7f461801c34f067ce0f02873a8f1b0e44dfc69752accecd819f38fd8e8", 16) + g2To76y, _ := new(big.Int).SetString("bc2da82b6fa5b571a7f09049776a1ef7ecd292238051c198c1a84e95b2b4ae17", 16) + g2To77x, _ := new(big.Int).SetString("85d8da4748ad1a73dec8409be84f1a1316e65c5196aad27e0766746f3d477c2d", 16) + g2To77y, _ := new(big.Int).SetString("58948b53665c6690586b536531efc7bc94b0a02033c4d5a62079816fc7d1dd70", 16) + g2To78x, _ := new(big.Int).SetString("8e2a7166e7ec4b968c0892e9cc3ee3ee4d1e7e100fdc47f04850312d6c0b80d9", 16) + g2To78y, _ := new(big.Int).SetString("eadb0ba9ae2cbe592cedd29b716a9d485297b688d706349a49c61f2ad6b29f50", 16) + g2To79x, _ := new(big.Int).SetString("769bc75842bff58edc8366ecd78f8950ee4ab2e81359d90f9921fa3d2c4561be", 16) + g2To79y, _ := new(big.Int).SetString("4bf817362fe783bac8dce4cef73f5d4741a177767b7873add5920bffb0d9685f", 16) + g2To80x, _ := new(big.Int).SetString("e5037de0afc1d8d43d8348414bbf4103043ec8f575bfdc432953cc8d2037fa2d", 16) + g2To80y, _ := new(big.Int).SetString("4571534baa94d3b5f9f98d09fb990bddbd5f5b03ec481f10e0e5dc841d755bda", 16) + g2To81x, _ := new(big.Int).SetString("a5e00da467fd5494f40b6cf7d2d61b3ec3ab217c792a2ddb8c63c8c79e3d34ef", 16) + g2To81y, _ := new(big.Int).SetString("98fe5f5e5608555421726fe99bf43d25b60dcfe790900acb855c5ce2f7adb4c", 16) + g2To82x, _ := new(big.Int).SetString("a99415f5ef3a2b403519f4bb1c9bfbc46d4afd2e4477572ae6737160d7b91252", 16) + g2To82y, _ := new(big.Int).SetString("82d0e64cae81f84bb9e2f10f24f6f6b6899a16ad590f4ddd73a377ac4bedc264", 16) + g2To83x, _ := new(big.Int).SetString("b56f4e9f9e4fd1fc7d8edde098f935f84c750d705f0c132bd8c465b66a540f17", 16) + g2To83y, _ := new(big.Int).SetString("32e8e53429cca856d3dc11adf0582d1d21d42963cbcca85446a2fcae0200102d", 16) + g2To84x, _ := new(big.Int).SetString("e06372b0f4a207adf5ea905e8f1771b4e7e8dbd1c6a6c5b725866a0ae4fce725", 16) + g2To84y, _ := new(big.Int).SetString("7a908974bce18cfe12a27bb2ad5a488cd7484a7787104870b27034f94eee31dd", 16) + g2To85x, _ := new(big.Int).SetString("eac134ca2046b8f9c8dbd304fad3f3c045ebfdb4ec6ed3cfe09aee43ed2ff3e", 16) + g2To85y, _ := new(big.Int).SetString("49630dbe79359b4245bf103bf2b11799ac19f696b7f21376e17206207d210988", 16) + g2To86x, _ := new(big.Int).SetString("d6788590731fea198392119d7adbb41ff5948a7804c85b17476706e4dfbfa4dc", 16) + g2To86y, _ := new(big.Int).SetString("28eaa8c89d5063c4940ef5c6d21c13aa6206f1c4ddc9a07cca7bcd6bbd3b5406", 16) + g2To87x, _ := new(big.Int).SetString("6930fccbd9a040974abf210f12b71d4bc7b1a6205599b01a7275fb40e48ff9b3", 16) + g2To87y, _ := new(big.Int).SetString("7f02ae94b94701eada30fcdb875f6d78090f9b13e4acc51acfddab5f8ee96a4e", 16) + g2To88x, _ := new(big.Int).SetString("213c7a715cd5d45358d0bbf9dc0ce02204b10bdde2a3f58540ad6908d0559754", 16) + g2To88y, _ := new(big.Int).SetString("4b6dad0b5ae462507013ad06245ba190bb4850f5f36a7eeddff2c27534b458f2", 16) + g2To89x, _ := new(big.Int).SetString("1c5e548132b49a7f66ae9fed8323480e0d1ab974622e7cf08993895e0ec87fac", 16) + g2To89y, _ := new(big.Int).SetString("4ffcf60f837f468f2bb959fa1d4c2ad3a3deaceb26fe324c555d7b3d5fc2d4ef", 16) + g2To90x, _ := new(big.Int).SetString("46276d0602c5668ddef6e94210bbc7ce1f901c19fed5c970e20fcba1d4531dbc", 16) + g2To90y, _ := new(big.Int).SetString("e0f7f24d44c75b84a292287570ded99498badfbffe1bc99af8730099686b8e2", 16) + g2To91x, _ := new(big.Int).SetString("efea68eca7a6c24f4e65eb211c3191636850e0acdc78d8996114ef13522f001d", 16) + g2To91y, _ := new(big.Int).SetString("aab847869d583c14da150307a3719a17e413959fb3848771c128419f73bc4415", 16) + g2To92x, _ := new(big.Int).SetString("4e7c272a7af4b34e8dbb9352a5419a87e2838c70adc62cddf0cc3a3b08fbd53c", 16) + g2To92y, _ := new(big.Int).SetString("17749c766c9d0b18e16fd09f6def681b530b9614bff7dd33e0b3941817dcaae6", 16) + g2To93x, _ := new(big.Int).SetString("899017b02696888f268a269f4e385d9c9b11f25a1bef8790e2821e6e7c6e1b4d", 16) + g2To93y, _ := new(big.Int).SetString("43ae2cdab5b334f0bb45798336358bfae4e51bc0f932b212009aebdad814ab2b", 16) + g2To94x, _ := new(big.Int).SetString("67f644f76e905fd4a8f4728e63227f0e2831f5bf91b583a8af2635a17e5f712f", 16) + g2To94y, _ := new(big.Int).SetString("b833d68f66445d04f05adeb7b586cf785e0e1488f7d36198d68acb5e707160e5", 16) + g2To95x, _ := new(big.Int).SetString("327f876c93652555fa80a054968b4712930dc93012ee6b8dc10263ed3b89a762", 16) + g2To95y, _ := new(big.Int).SetString("b2d404eab3524026b09969255e1997b975535070febd7dfe9c9fd959b9203301", 16) + g2To96x, _ := new(big.Int).SetString("fea74e3dbe778b1b10f238ad61686aa5c76e3db2be43057632427e2840fb27b6", 16) + g2To96y, _ := new(big.Int).SetString("6e0568db9b0b13297cf674deccb6af93126b596b973f7b77701d3db7f23cb96f", 16) + g2To97x, _ := new(big.Int).SetString("ed9441c8304280ff180e03d850e8cd0ebb570ee5de3730488fd97c961f9756e4", 16) + g2To97y, _ := new(big.Int).SetString("3dbe9e9efe8bfa19afa176128b13911e09f23774fe4de98bff0e09f93f3abfae", 16) + g2To98x, _ := new(big.Int).SetString("29d9698ee67a7c3fc9fed3f624b487515b10bdd84fab4d3015bad033d51cf119", 16) + g2To98y, _ := new(big.Int).SetString("7fd02c517dc82b45277a125404f1c96fb89c940e93a7c2963c88740575056339", 16) + g2To99x, _ := new(big.Int).SetString("126b57d05013936d6f3fb7bd33580a31fd453e4a86060cff467c44537f422491", 16) + g2To99y, _ := new(big.Int).SetString("c1a7dc13061662c2e3c4a3eba2bf3fb0e148bac30bf39347afa31f199da3ef84", 16) + g2To100x, _ := new(big.Int).SetString("76e64113f677cf0e10a2570d599968d31544e179b760432952c02a4417bdde39", 16) + g2To100y, _ := new(big.Int).SetString("c90ddf8dee4e95cf577066d70681f0d35e2a33d2b56d2032b4b1752d1901ac01", 16) + g2To101x, _ := new(big.Int).SetString("708a530e9e52c73bee87c9d88161c810005d57622c29ae691cf999a83a1187a5", 16) + g2To101y, _ := new(big.Int).SetString("9b884811e1f9a897fa9656dcbb6d38283ecda73c6d353e8a58a4f19b473db9c0", 16) + g2To102x, _ := new(big.Int).SetString("19cf034fc48b3be219bd648395e462cf9f374b6d86b2b59e2e1b16c6cde4f5be", 16) + g2To102y, _ := new(big.Int).SetString("28e32b06a15ab466c3b4be68ab181947ef91d1c93f0f1c0c0a91532b6f321af2", 16) + g2To103x, _ := new(big.Int).SetString("af6c44a078cb5f0d7c719c2f8397f576ee93bd034bea2219e3abc209d17cf3e8", 16) + g2To103y, _ := new(big.Int).SetString("784096fe85d4b30af9e73153cb246dfec362aea7ca0d435b8add0601751baea", 16) + g2To104x, _ := new(big.Int).SetString("c738c56b03b2abe1e8281baa743f8f9a8f7cc643df26cbee3ab150242bcbb891", 16) + g2To104y, _ := new(big.Int).SetString("893fb578951ad2537f718f2eacbfbbbb82314eef7880cfe917e735d9699a84c3", 16) + g2To105x, _ := new(big.Int).SetString("5578845ecd7c037435b32a6992e7aa94647197ea49b8c9e4ddaab0784662ab1b", 16) + g2To105y, _ := new(big.Int).SetString("e61d07978b6de2c3cea6d0a51d2a4053f653a7746a5d64de316d18f3056f3511", 16) + g2To106x, _ := new(big.Int).SetString("47f3383888a364cc4abfa3bc1d0ceccd22f12354fce3996094f869b8948b6c29", 16) + g2To106y, _ := new(big.Int).SetString("48ca9a8d0f032937190e48675b416c7118bb499588f994a81edee1120e537ef9", 16) + g2To107x, _ := new(big.Int).SetString("c0c01f34ae41b8cfe466b4c9c6a5d5f614f570d6fcbef768a81a6c8f05ff4adb", 16) + g2To107y, _ := new(big.Int).SetString("b84f5bee4357f5c7c937a0b4075b8cecdbc43d170d15b85fc4eff73ac351065", 16) + g2To108x, _ := new(big.Int).SetString("d895626548b65b81e264c7637c972877d1d72e5f3a925014372e9f6588f6c14b", 16) + g2To108y, _ := new(big.Int).SetString("febfaa38f2bc7eae728ec60818c340eb03428d632bb067e179363ed75d7d991f", 16) + g2To109x, _ := new(big.Int).SetString("fd136eef8971044e8a3a43622003a26703ecaf7a0ec40c3fba5b594b77078424", 16) + g2To109y, _ := new(big.Int).SetString("218da834f3c652cc67a1d191b5c5efa57cf2b1f78a2adfa8cd61eeefc671ddf1", 16) + g2To110x, _ := new(big.Int).SetString("d99e8e9dd9638d140e9cca5367519f861b7003a0d43f024a5f1d84ec8db1cb3c", 16) + g2To110y, _ := new(big.Int).SetString("36dc19ad1cc0a3a7a945bb321bceba6e6286fef8ffc8765cd88a29e36b8637a7", 16) + g2To111x, _ := new(big.Int).SetString("3fdf1619a198317a1bd8a54e5b09191d203351e0440e636fd46f68d3c385172", 16) + g2To111y, _ := new(big.Int).SetString("408d02c06e5c12c3fe470c7d3c8573755b9b929e90e7232b79ac67f0fccb9794", 16) + g2To112x, _ := new(big.Int).SetString("b8da94032a957518eb0f6433571e8761ceffc73693e84edd49150a564f676e03", 16) + g2To112y, _ := new(big.Int).SetString("2804dfa44805a1e4d7c99cc9762808b092cc584d95ff3b511488e4e74efdf6e7", 16) + g2To113x, _ := new(big.Int).SetString("6d36d105ed8cc5ce53f2cb698ab620f9469a3e5cb25bf6e6d413f414c5af726a", 16) + g2To113y, _ := new(big.Int).SetString("e4ba5c34e377669e72d8c66c95c50029dcc59936b4108a35c570491a13f9fc7d", 16) + g2To114x, _ := new(big.Int).SetString("3ab6bde10cd3ac0cd06883fa66f0b0e3eb1309c0534b812286e2a30ca540db99", 16) + g2To114y, _ := new(big.Int).SetString("baca62079be871d7fc3117a96a13e99c38d137b0e369c043e6873fe31bda78a3", 16) + g2To115x, _ := new(big.Int).SetString("796634e3f1ad56f0fdba069d9d07bce2ba2fd4f373ddd3ba7777bf279f1048da", 16) + g2To115y, _ := new(big.Int).SetString("4d8ee2b6cfb20b8956de74735a7927f2532576d8cfd74862e8f9be24a106cf01", 16) + g2To116x, _ := new(big.Int).SetString("e80fea14441fb33a7d8adab9475d7fab2019effb5156a792f1a11778e3c0df5d", 16) + g2To116y, _ := new(big.Int).SetString("eed1de7f638e00771e89768ca3ca94472d155e80af322ea9fcb4291b6ac9ec78", 16) + g2To117x, _ := new(big.Int).SetString("440ca1f08ea41265981ac4ed1efe7a37122dcc3877d2f9162db0e78b0f83cd58", 16) + g2To117y, _ := new(big.Int).SetString("a6c8b0d2cd5ee122af8954dc9d4e2f02a21e4d4269c0a260b07bc069b88a3f4b", 16) + g2To118x, _ := new(big.Int).SetString("f694cbaf2b966c1cc5f7f829d3a907819bc70ebcc1b229d9e81bda2712998b10", 16) + g2To118y, _ := new(big.Int).SetString("40a63eba61bef03d633c5ffacc46d82aeb6c64c3183c2a47f6788b1700f05e51", 16) + g2To119x, _ := new(big.Int).SetString("8b6e862a3556684850b6d4f439a2595047abf695c08b6414f95a13358dd553fd", 16) + g2To119y, _ := new(big.Int).SetString("ea5e08910ed11cb40d10bc2df4eb9fa124ac3c5a183383d0d803dad33e9be5ed", 16) + g2To120x, _ := new(big.Int).SetString("a301697bdfcd704313ba48e51d567543f2a182031efd6915ddc07bbcc4e16070", 16) + g2To120y, _ := new(big.Int).SetString("7370f91cfb67e4f5081809fa25d40f9b1735dbf7c0a11a130c0d1a041e177ea1", 16) + g2To121x, _ := new(big.Int).SetString("27e1e59cff79f049f3e8d2419e0bff74b43965004c34b5d811420316f24ba5ae", 16) + g2To121y, _ := new(big.Int).SetString("310b26a6c804e209ee1b5e3cfc79df05df48a1a69afa63f784a5bfee883a45b3", 16) + g2To122x, _ := new(big.Int).SetString("c712e7a5f6864aee16588ec3892d7e4f5a39adde84fbfb4f9969175c9caed7ae", 16) + g2To122y, _ := new(big.Int).SetString("49644107516363b365ed4b82311dd9e5380d8e544b0ce63784d148aa46156294", 16) + g2To123x, _ := new(big.Int).SetString("bfc0504a4b3235d065c0d426b8675fcb2c85d6f58275d791b43e1fe44a6db03", 16) + g2To123y, _ := new(big.Int).SetString("1955467a6c34f3453fb8ec7f94a6c99237427197345d4f0558ac8d1a464b8542", 16) + g2To124x, _ := new(big.Int).SetString("90ad85b389d6b936463f9d0512678de208cc330b11307fffab7ac63e3fb04ed4", 16) + g2To124y, _ := new(big.Int).SetString("e507a3620a38261affdcbd9427222b839aefabe1582894d991d4d48cb6ef150", 16) + g2To125x, _ := new(big.Int).SetString("7e2cd40ef8c94077f44b1d1548425e3d7e125be646707bad2818b0eda7dc0151", 16) + g2To125y, _ := new(big.Int).SetString("905b75082adcfab382a61a8b321ef95d889bee40aeee082c9a3bc53920721ec7", 16) + g2To126x, _ := new(big.Int).SetString("a146f52195bedace21c975bbd1ef52a79c636bf9db853cf90e103ae41345e597", 16) + g2To126y, _ := new(big.Int).SetString("a5a99b0ab053feb09ae95dd2dbb31b40ea67a5b221f094b07675676af45a770a", 16) + g2To127x, _ := new(big.Int).SetString("d24c75a1cf1993b9bcfbf9dab25a8114dbde421efeccc4e20cbb53fc4ce45444", 16) + g2To127y, _ := new(big.Int).SetString("58fe1d2de84dc1d1cfcb7d1810e5a78abf7593f499f1e524cb93246987dd4a57", 16) + g2To128x, _ := new(big.Int).SetString("8f68b9d2f63b5f339239c1ad981f162ee88c5678723ea3351b7b444c9ec4c0da", 16) + g2To128y, _ := new(big.Int).SetString("662a9f2dba063986de1d90c2b6be215dbbea2cfe95510bfdf23cbf79501fff82", 16) + g2To129x, _ := new(big.Int).SetString("4d49aefd784e8158fcafebe77fd9af59d89858ade7627eaee6847df84cf27076", 16) + g2To129y, _ := new(big.Int).SetString("cd32fc59a10dd135e723f210359ca6f06e0f2d1a7df4d8466b90b66203aa781e", 16) + g2To130x, _ := new(big.Int).SetString("7564539e85d56f8537d6619e1f5c5aa78d2a3de0889d1d4ee8dbcb5729b62026", 16) + g2To130y, _ := new(big.Int).SetString("c1d685413749b3c65231df524a722925684aacd954b79f334172c8fadace0cf3", 16) + g2To131x, _ := new(big.Int).SetString("210a917ad9df27796746ff301ad9ccc878f61a5f1ff4082b5364dacd57b4a278", 16) + g2To131y, _ := new(big.Int).SetString("670e1b5450b5e57b7a39be81f8d6737d3789e61aaff20bfc7f2713fd0c7b2231", 16) + g2To132x, _ := new(big.Int).SetString("e4f3fb0176af85d65ff99ff9198c36091f48e86503681e3e6686fd5053231e11", 16) + g2To132y, _ := new(big.Int).SetString("1e63633ad0ef4f1c1661a6d0ea02b7286cc7e74ec951d1c9822c38576feb73bc", 16) + g2To133x, _ := new(big.Int).SetString("4b30cbb7686773e01ec64110abdb362f88531a825ba172953bfee2233bcdaf2f", 16) + g2To133y, _ := new(big.Int).SetString("74c6350265bb629b6f9e2c5777c3c4a91fdf3c81e434857568033d463d26b5b7", 16) + g2To134x, _ := new(big.Int).SetString("cbb434aa7ae1700dcd15b20b17464817ec11715050e0fa192ffe9c29a673059f", 16) + g2To134y, _ := new(big.Int).SetString("4a1a200ab4dabd17562d492338b5dfad41d45e4f0ad5f845b7da9642227c070c", 16) + g2To135x, _ := new(big.Int).SetString("f478056d9c102c1cd06d7b1e7557244c6d9cdac5874610e94d4786e106de12c0", 16) + g2To135y, _ := new(big.Int).SetString("7f09e610f33e3946e68095e01068694c26c17ef609ab92d769a76ce6ca5361fe", 16) + g2To136x, _ := new(big.Int).SetString("8c00fa9b18ebf331eb961537a45a4266c7034f2f0d4e1d0716fb6eae20eae29e", 16) + g2To136y, _ := new(big.Int).SetString("efa47267fea521a1a9dc343a3736c974c2fadafa81e36c54e7d2a4c66702414b", 16) + g2To137x, _ := new(big.Int).SetString("24cfc0176da2b46fa8bb5bf9636be1effd7e297f29122fb3e84c9ab0c18ada5f", 16) + g2To137y, _ := new(big.Int).SetString("ebff8fbb079c61a69868714d5deda927ed959ca1a4f814f268fa6139978a586b", 16) + g2To138x, _ := new(big.Int).SetString("4a7d58d4b9bc82ea2ded72a1292ec616ddd67fc7f057edf103189594679da2", 16) + g2To138y, _ := new(big.Int).SetString("b98ac5b76702cb75e6b1d8147ec71b3b71c3b494963fa28a4877f484779ffe26", 16) + g2To139x, _ := new(big.Int).SetString("ee7d69c4cbd001c7fc76c5e2c066ce4996f8808a1e07b2a9ccf34eadc87c4b65", 16) + g2To139y, _ := new(big.Int).SetString("ecc8626ec1a413821a192abf030f2ee2c33e8999bae942e523e8f44ed136a95a", 16) + g2To140x, _ := new(big.Int).SetString("e7a26ce69dd4829f3e10cec0a9e98ed3143d084f308b92c0997fddfc60cb3e41", 16) + g2To140y, _ := new(big.Int).SetString("2a758e300fa7984b471b006a1aafbb18d0a6b2c0420e83e20e8a9421cf2cfd51", 16) + g2To141x, _ := new(big.Int).SetString("f5cafaba036bf8d00d38bfb6772089f5203c35e4d6e32fa9d97e5b917b4ae861", 16) + g2To141y, _ := new(big.Int).SetString("19e83b8a022a6d817bff9904640839159b3b2a9c552f05f3cc9c239c0d82239c", 16) + g2To142x, _ := new(big.Int).SetString("e9389024ceb63f1f12df5156d7e805428f9e509c494c982084fd4cd7bd2a9651", 16) + g2To142y, _ := new(big.Int).SetString("8648688723726595f9287abaf671aaf18d7110cec6770bfefefde2b75e786824", 16) + g2To143x, _ := new(big.Int).SetString("264559d87829256bed116900d82d0c379f0e4d1253c68e6fcf2d41ae7cddab8b", 16) + g2To143y, _ := new(big.Int).SetString("79e5bd1926d3512cef7bc637034072d77a8631af39caf1e6c9f64b45001de473", 16) + g2To144x, _ := new(big.Int).SetString("b6459e0ee3662ec8d23540c223bcbdc571cbcb967d79424f3cf29eb3de6b80ef", 16) + g2To144y, _ := new(big.Int).SetString("67c876d06f3e06de1dadf16e5661db3c4b3ae6d48e35b2ff30bf0b61a71ba45", 16) + g2To145x, _ := new(big.Int).SetString("e5d8e8f0d9823c88e4d36f7301f41593b6890576be79c211253ef375033eb51f", 16) + g2To145y, _ := new(big.Int).SetString("4dc1e9b7861e3e04abb16a57d8feeef0e509dc46d9f0f54979d5bd965a62a2d9", 16) + g2To146x, _ := new(big.Int).SetString("a9ca27f77dbc8c3dc56b0f7321bae0ddab66be4fa8a3011737a676480f155e64", 16) + g2To146y, _ := new(big.Int).SetString("f4bb335678fb14d4d197d2246c02d004875d41821bcaf0ae1f3f333c561b3297", 16) + g2To147x, _ := new(big.Int).SetString("68fb71800686d7f25eba105611cfe7591f478e847f51cee06d4bc629d6ee247c", 16) + g2To147y, _ := new(big.Int).SetString("cd12d23462dd963673735427501b0c079a8d580b04c73c9dae1f822d1a01865d", 16) + g2To148x, _ := new(big.Int).SetString("d68a80c8280bb840793234aa118f06231d6f1fc67e73c5a5deda0f5b496943e8", 16) + g2To148y, _ := new(big.Int).SetString("db8ba9fff4b586d00c4b1f9177b0e28b5b0e7b8f7845295a294c84266b133120", 16) + g2To149x, _ := new(big.Int).SetString("f16a409c677a40be402f8efb3752373caced053c6f702b828bda222ca412b6fd", 16) + g2To149y, _ := new(big.Int).SetString("2a41311714532799d7a6a75a74e30e4e16540659249ebca4268dae77eca052da", 16) + g2To150x, _ := new(big.Int).SetString("4154b506ab766f42fbe37f699976f84db89f4f2f6bed98325c1a0b6e326dd4e4", 16) + g2To150y, _ := new(big.Int).SetString("23ad075043c5988894c6e44d61025ff6414ea9d9d1e22dd46c859295075ded1c", 16) + g2To151x, _ := new(big.Int).SetString("b73c652769cc95c1080a8d4d0b5956ea93e86e49fc727ddf4c51a7a63f7f0246", 16) + g2To151y, _ := new(big.Int).SetString("9a67db107174ca9d4b535893c5b6c1ea1a0d72e4c6e554e5597e5164ea2a407b", 16) + g2To152x, _ := new(big.Int).SetString("324aed7df65c804252dc0270907a30b09612aeb973449cea4095980fc28d3d5d", 16) + g2To152y, _ := new(big.Int).SetString("648a365774b61f2ff130c0c35aec1f4f19213b0c7e332843967224af96ab7c84", 16) + g2To153x, _ := new(big.Int).SetString("32c9331ea26f490228d32681880d7203f72b3e4a8de0db1fa8f38381b2919749", 16) + g2To153y, _ := new(big.Int).SetString("d7cd272b34209cb5695a2f02b6f3dbb8268a4abdae39ab09631e97b0f290b5e3", 16) + g2To154x, _ := new(big.Int).SetString("eb292f3b3b9837854a02f6a70fec6b1c69c161b6e1846b8e1e1c22527b9795e4", 16) + g2To154y, _ := new(big.Int).SetString("8c43c25a96eebe801696634af145835b57131d7509111c6f5b7e9d2fae53a0fe", 16) + g2To155x, _ := new(big.Int).SetString("a65a3a01df3b5ef2e620d4310049fbe14d71457f19d1ed35aea39d5789303fdd", 16) + g2To155y, _ := new(big.Int).SetString("798ea0940cff5c6fb8f43d8d90ed2c7686861d024faed3cadad44a8d02e68703", 16) + g2To156x, _ := new(big.Int).SetString("4df9c14919cde61f6d51dfdbe5fee5dceec4143ba8d1ca888e8bd373fd054c96", 16) + g2To156y, _ := new(big.Int).SetString("35ec51092d8728050974c23a1d85d4b5d506cdc288490192ebac06cad10d5d", 16) + g2To157x, _ := new(big.Int).SetString("ed32cad8d2cc998cd25317d4e4b87088e9de4554e57a8d70c0c6b0fc1da49e04", 16) + g2To157y, _ := new(big.Int).SetString("129fef5f1d030204a541ca375859d20b52da9facb49fab7db63120d17c1db9e0", 16) + g2To158x, _ := new(big.Int).SetString("e821ab724d6360f18049e4111c70366e28c36dcb63c34016cb7418d4e883f855", 16) + g2To158y, _ := new(big.Int).SetString("adefcbf863f53ce367d0d4115416cf598b3b19c614ec23efed4e0c6a59852ddf", 16) + g2To159x, _ := new(big.Int).SetString("3f0d8994e51ad212f455452fbc9693a72f14a547af3806e9fbff59eeb441742e", 16) + g2To159y, _ := new(big.Int).SetString("fbd76c23f28c3dc445e5cb0e847a6e0b1e205e2c3ad13d958c65363bcfecadbe", 16) + g2To160x, _ := new(big.Int).SetString("9c3919a84a474870faed8a9c1cc66021523489054d7f0308cbfc99c8ac1f98cd", 16) + g2To160y, _ := new(big.Int).SetString("ddb84f0f4a4ddd57584f044bf260e641905326f76c64c8e6be7e5e03d4fc599d", 16) + g2To161x, _ := new(big.Int).SetString("2e3c05326255d80f0a42fc69d5c92aa40cd326a53e8535f0435efb7b694a09ec", 16) + g2To161y, _ := new(big.Int).SetString("1ff891656c6fb5bddae240b82fc1abe048a53c707b66512534868188c7327e", 16) + g2To162x, _ := new(big.Int).SetString("e8e2a24ccfa41587ae15fb7e3e24dda433710316a1908934205f19a2ab9c7ce6", 16) + g2To162y, _ := new(big.Int).SetString("46c983ce0c6f5d1b4caf2b2b3bee20596e09e603b5c27a73b2c01eb68836267c", 16) + g2To163x, _ := new(big.Int).SetString("a7549aac5d8573c2b2f0a38b170032a212acaf92383d5b5f5b0d39668ac7b3c2", 16) + g2To163y, _ := new(big.Int).SetString("bd17d1b90d1c2415335a1d70c1947d2b5d6b5115537116dffa0c91719287eaef", 16) + g2To164x, _ := new(big.Int).SetString("6057170b1dd12fdf8de05f281d8e06bb91e1493a8b91d4cc5a21382120a959e5", 16) + g2To164y, _ := new(big.Int).SetString("9a1af0b26a6a4807add9a2daf71df262465152bc3ee24c65e899be932385a2a8", 16) + g2To165x, _ := new(big.Int).SetString("6773fd677c52e0640394110a46dc85df7c133f8dd4a28e661899ca5d82fd545c", 16) + g2To165y, _ := new(big.Int).SetString("444eb6d8cd97652f0f0f25c9dd2b246bead780f5a1c6cf98e8c7f034947eb1ae", 16) + g2To166x, _ := new(big.Int).SetString("e0f86d94d17ce565237c79aace0c87c20374e43810468050373c616b0b86f021", 16) + g2To166y, _ := new(big.Int).SetString("c571c73730abcf47a91e832f1c89a2c9a80bcc0115fc45b3b6b79ccb5bf325a", 16) + g2To167x, _ := new(big.Int).SetString("42ca15ab9f245041ce991e193d696f4f4c277df908cad6038ad0772c02da6e03", 16) + g2To167y, _ := new(big.Int).SetString("68d2ef26c81c57c9647ce4d1fcb800eed66e85a68106bea7836889fa8c347793", 16) + g2To168x, _ := new(big.Int).SetString("a576df8e23a08411421439a4518da31880cef0fba7d4df12b1a6973eecb94266", 16) + g2To168y, _ := new(big.Int).SetString("40a6bf20e76640b2c92b97afe58cd82c432e10a7f514d9f3ee8be11ae1b28ec8", 16) + g2To169x, _ := new(big.Int).SetString("9e5dcc62ef3b5a3b546520867be71bae6f3ba063c9acfb8dcec5725bda704896", 16) + g2To169y, _ := new(big.Int).SetString("6fedd12ddb925f3ea5fd3a2154c7612279605d186030f51248f2769dca82c835", 16) + g2To170x, _ := new(big.Int).SetString("a7de08375b8745adf8d6e9f976f03b20e33625a05cef5833953ed58744bf7ea0", 16) + g2To170y, _ := new(big.Int).SetString("a63d96b057ada5e52104a0b334888e9a645a47c0febc5aa2e04c05539bbcabaa", 16) + g2To171x, _ := new(big.Int).SetString("c266658e689080c9c13c35ac01cff4cbe68065fde949e4a3a9f8fa104ad916fb", 16) + g2To171y, _ := new(big.Int).SetString("e7e8593854e7daab0f798170b24627ab6b8fecdfeb61138856aef52ba0887814", 16) + g2To172x, _ := new(big.Int).SetString("7778a78c28dec3e30a05fe9629de8c38bb30d1f5cf9a3a208f763889be58ad71", 16) + g2To172y, _ := new(big.Int).SetString("34626d9ab5a5b22ff7098e12f2ff580087b38411ff24ac563b513fc1fd9f43ac", 16) + g2To173x, _ := new(big.Int).SetString("e7b9796b5ca006d1632f482d7f0fe3932cf16a5ae104eea7a7ea1c251073e879", 16) + g2To173y, _ := new(big.Int).SetString("12b8988c19169e2fdf42102a737cc1ca9cb5bf25eda98af338e71089baa89d98", 16) + g2To174x, _ := new(big.Int).SetString("71bf01850876203c2c915a24be09a7365423daaf2aee919865d722bf2628f0f", 16) + g2To174y, _ := new(big.Int).SetString("527aa15d504dcf4ae33600bc1c084ce2098f9c6a231c80bbb57c5cbd45a1c334", 16) + g2To175x, _ := new(big.Int).SetString("218343acb9be56833a32e594c03c39e5b1911c8501213786f6376dfa39620e1", 16) + g2To175y, _ := new(big.Int).SetString("bea81d48970a50beaf3f24fd602fbfc0443299a42f43c9ec5e0199f6506998b5", 16) + g2To176x, _ := new(big.Int).SetString("928955ee637a84463729fd30e7afd2ed5f96274e5ad7e5cb09eda9c06d903ac", 16) + g2To176y, _ := new(big.Int).SetString("c25621003d3f42a827b78a13093a95eeac3d26efa8a8d83fc5180e935bcd091f", 16) + g2To177x, _ := new(big.Int).SetString("4f89bdee3771d350dad163b04cb18ad67ce5e9c55b58f0e7231047a60f59dd9e", 16) + g2To177y, _ := new(big.Int).SetString("ca7952d5227a1f695c4baf4c043bb2471e4882506638df5c1016ae320156b049", 16) + g2To178x, _ := new(big.Int).SetString("cb9e8304cae3c5a80c396baca2c3c4c994b668f079a245bf529c314cfff01197", 16) + g2To178y, _ := new(big.Int).SetString("62c7d2801eb80e6a127258cdff08891741b2d18c015e0a24c334e0763b989c1d", 16) + g2To179x, _ := new(big.Int).SetString("e2f349b0f89c69bd3c8cf2a410730dc58e0beed47048c58c15f9ffc2508d2cc2", 16) + g2To179y, _ := new(big.Int).SetString("1feb2f280f82723781860aec760215ba42344be8e09cbdb37e347bd8e0d4c04f", 16) + g2To180x, _ := new(big.Int).SetString("85d0fef3ec6db109399064f3a0e3b2855645b4a907ad354527aae75163d82751", 16) + g2To180y, _ := new(big.Int).SetString("1f03648413a38c0be29d496e582cf5663e8751e96877331582c237a24eb1f962", 16) + g2To181x, _ := new(big.Int).SetString("6b790f4b19a4c4f4f607a6cfcd11df0468b482e009711ff756356d141d5fcade", 16) + g2To181y, _ := new(big.Int).SetString("d03a981b2ff9eb3ef296661f9cae09cba83fa5b47be26b0ab6fff86fc338d3ff", 16) + g2To182x, _ := new(big.Int).SetString("41149b2c2d7ebed3c162c367acc4f8fe3d2479de85978be0bb0ccdabe3a3e0cb", 16) + g2To182y, _ := new(big.Int).SetString("c90d5b92db7c30542b415c9b9902cf28b3ec7805ef490f2470e92e98339033a8", 16) + g2To183x, _ := new(big.Int).SetString("d1fad4fa4e7c849dfaec3dfe2872a7ba664a9b8205c29cebf8dddd28e3f3d3fc", 16) + g2To183y, _ := new(big.Int).SetString("8fe19714a348fdfe5473f70e858b7818bad37131eff37326ed22343c50f3704d", 16) + g2To184x, _ := new(big.Int).SetString("ff2b0dce97eece97c1c9b6041798b85dfdfb6d8882da20308f5404824526087e", 16) + g2To184y, _ := new(big.Int).SetString("493d13fef524ba188af4c4dc54d07936c7b7ed6fb90e2ceb2c951e01f0c29907", 16) + g2To185x, _ := new(big.Int).SetString("2982dbbc5f366c9f78e29ebbecb1bb223deb5c4ee638b4583bd3a9af3149f8ef", 16) + g2To185y, _ := new(big.Int).SetString("a61b5be9af66220ab9fa5339c7b5bc9d095db99412e3ed8456e726b016c7a248", 16) + g2To186x, _ := new(big.Int).SetString("1a28e5042af0c0f6b436eb590497db5860011f4580e1765885289f612380441b", 16) + g2To186y, _ := new(big.Int).SetString("55779a7996c59dab7c78329a8976f0ed04b3e75b46ee67aeb05f606a8452af25", 16) + g2To187x, _ := new(big.Int).SetString("c8b83e9535f30601d250cc0bd3f20142edd5eb7985d83242eef0e39621e30a7", 16) + g2To187y, _ := new(big.Int).SetString("dcc7077065fdac7b850e3f17efdc854aacad237b987134dbebf7beb9ff688de", 16) + g2To188x, _ := new(big.Int).SetString("827fbbe4b1e880ea9ed2b2e6301b212b57f1ee148cd6dd28780e5e2cf856e241", 16) + g2To188y, _ := new(big.Int).SetString("c60f9c923c727b0b71bef2c67d1d12687ff7a63186903166d605b68baec293ec", 16) + g2To189x, _ := new(big.Int).SetString("b77f12a7dce56b973e2d7c8d576e6b3660470a9218b87461ef6e44b70cb1815d", 16) + g2To189y, _ := new(big.Int).SetString("4b6f85b14f86acc43f0cefb373cc2e654c42f0f91a44816d6ba3d2bc8e57dbc5", 16) + g2To190x, _ := new(big.Int).SetString("48973b943018bf1247b308b2cb79f956d858d8df4977c5970fe5dad2c45565ec", 16) + g2To190y, _ := new(big.Int).SetString("761f75684f3cdc1b6437bb3a01445af1511b3596580477b83b879075faed07e9", 16) + g2To191x, _ := new(big.Int).SetString("e931258e8eb5559c6d6972728a704c170b775a265b4527d4a4d4d742bbfd71fa", 16) + g2To191y, _ := new(big.Int).SetString("fb1e33364c3fdee0e85eb4169c954b40b3946ce1bb5e35f33d9bd0d3174d3307", 16) + g2To192x, _ := new(big.Int).SetString("eaa649f21f51bdbae7be4ae34ce6e5217a58fdce7f47f9aa7f3b58fa2120e2b3", 16) + g2To192y, _ := new(big.Int).SetString("be3279ed5bbbb03ac69a80f89879aa5a01a6b965f13f7e59d47a5305ba5ad93d", 16) + g2To193x, _ := new(big.Int).SetString("3adb9db3beb997eec2623ea5002279ea9e337b5c705f3db453dbc1cc1fc9b0a8", 16) + g2To193y, _ := new(big.Int).SetString("374e2d6daee74e713c774de07c095ff6aad9c8f9870266cc61ae7975f05bbdda", 16) + g2To194x, _ := new(big.Int).SetString("129e53ac428e9cbb7e10955e56c5fc69fefdff56963e7caf054e9e0c90ae86f9", 16) + g2To194y, _ := new(big.Int).SetString("415ecb958aee9a29b2da2115b712183fb2a232fd16b3e01b822efdcd1e89c85d", 16) + g2To195x, _ := new(big.Int).SetString("60144494c8f694485b85ecb6aee10956c756267d12894711922243d5e855b8da", 16) + g2To195y, _ := new(big.Int).SetString("8bb5d669f681e6469e8be1fd9132e65b543955c27e3f2a4bad500590f34e4bbd", 16) + g2To196x, _ := new(big.Int).SetString("e4a42d43c5cf169d9391df6decf42ee541b6d8f0c9a137401e23632dda34d24f", 16) + g2To196y, _ := new(big.Int).SetString("4d9f92e716d1c73526fc99ccfb8ad34ce886eedfa8d8e4f13a7f7131deba9414", 16) + g2To197x, _ := new(big.Int).SetString("fd6451fb84cfb18d3ef0acf856c4ef4d0553c562f7ae4d2a303f2ea33e8f62bb", 16) + g2To197y, _ := new(big.Int).SetString("e745ceb2b1871578b6fe7a5c1bc344ccfa2ab492d200e83fd0ad9086132c0911", 16) + g2To198x, _ := new(big.Int).SetString("1eee207cb24086bc716e81a06f9edbbb0042e2d5dcf3c7a1fa1d1fb9d5fe696b", 16) + g2To198y, _ := new(big.Int).SetString("652cbd19aef6269cd2b196d12461c95f7a02062e0afd694ebb45670e7429337b", 16) + g2To199x, _ := new(big.Int).SetString("cc0ea33ea8a9eb14d465ab2c346e2111e1c0fc017c57257908d40f19ef94c0d5", 16) + g2To199y, _ := new(big.Int).SetString("f9907a3b711c8a2fb23dd203b5fbe663f6074f266113f543deabe597af452fe6", 16) + g2To200x, _ := new(big.Int).SetString("1ec80fef360cbdd954160fadab352b6b92b53576a88fea4947173b9d4300bf19", 16) + g2To200y, _ := new(big.Int).SetString("aeefe93756b5340d2f3a4958a7abbf5e0146e77f6295a07b671cdc1cc107cefd", 16) + g2To201x, _ := new(big.Int).SetString("5be7ea3519f04bc6cbeeaa0344fc90bb8e8462f6ebd890560dae805d414ff9e4", 16) + g2To201y, _ := new(big.Int).SetString("32f32ec3f638e605477f890f655ab7fe0e99c6302119a3094030b07847e0bdbb", 16) + g2To202x, _ := new(big.Int).SetString("58f099116eae4e650813fc8698df7f5cd50028649f853991e3fb545f4ddb7bb8", 16) + g2To202y, _ := new(big.Int).SetString("7e07002aaffe111a0d62ff7614638066507ee4062d174302bdec73582e5b2d6e", 16) + g2To203x, _ := new(big.Int).SetString("b0f9e4b9b29790b633bcc04fd860cb0f823d8d1a4cc1a1c1413c1606cc9a8e2c", 16) + g2To203y, _ := new(big.Int).SetString("49e82bf1843ade6d41cbb0b906fde3f03350cc02c171cee76c2066c4df3d0db4", 16) + g2To204x, _ := new(big.Int).SetString("146a778c04670c2f91b00af4680dfa8bce3490717d58ba889ddb5928366642be", 16) + g2To204y, _ := new(big.Int).SetString("b318e0ec3354028add669827f9d4b2870aaa971d2f7e5ed1d0b297483d83efd0", 16) + g2To205x, _ := new(big.Int).SetString("574ef0ce8a597e24e5670b5c0bcd14cfeefc983c7ecb261911b2365579de5cac", 16) + g2To205y, _ := new(big.Int).SetString("9b99930281f19c73bd6ada0569b78451a260a7bef10008cae59aea6c75a4805", 16) + g2To206x, _ := new(big.Int).SetString("d3d97e799d8bf9f85d909397b98c835d10a770c1aeff8645808c2d74260966d3", 16) + g2To206y, _ := new(big.Int).SetString("8ddbb46376bac95e6aaa89275d403ad3b5e48711be8dc4eebddeb850833c2e52", 16) + g2To207x, _ := new(big.Int).SetString("b1aa653288b318987b974e782cbbee0ab2be78cf8f494c120040fb93968c6d4b", 16) + g2To207y, _ := new(big.Int).SetString("7ed6071c60810d712684aa8e2d63a83b100a1d909d623cc383d9e62ae891ac51", 16) + g2To208x, _ := new(big.Int).SetString("fa50c0f61d22e5f07e3acebb1aa07b128d0012209a28b9776d76a8793180eef9", 16) + g2To208y, _ := new(big.Int).SetString("6b84c6922397eba9b72cd2872281a68a5e683293a57a213b38cd8d7d3f4f2811", 16) + g2To209x, _ := new(big.Int).SetString("63964eee619074e0780140fe02e90836e72328d2448386d459c5be23187f5048", 16) + g2To209y, _ := new(big.Int).SetString("3b6cfb3a6b89cf41a39ff9b1c34bfbc93d580b934dde6c84383a284d89309df8", 16) + g2To210x, _ := new(big.Int).SetString("5a3ce25b4d15b7e22d1469ddf0fc9f75afd7f12ad3cbda31f814ba1ebadb2a65", 16) + g2To210y, _ := new(big.Int).SetString("8b34125b92e05f63873a6dbfbf3f99af3ee28bc3d825fe8ed8b170cf1d327f1d", 16) + g2To211x, _ := new(big.Int).SetString("5ce605af98f93eda6910be34f0de41ff85dbcb6e69a8fa0016a733754a9f44d0", 16) + g2To211y, _ := new(big.Int).SetString("4cddcf9bec226bfe7ba56bd031c76c58ab3cb1bfa32eccc6c0d05f3489d30105", 16) + g2To212x, _ := new(big.Int).SetString("da1d61d0ca721a11b1a5bf6b7d88e8421a288ab5d5bba5220e53d32b5f067ec2", 16) + g2To212y, _ := new(big.Int).SetString("8157f55a7c99306c79c0766161c91e2966a73899d279b48a655fba0f1ad836f1", 16) + g2To213x, _ := new(big.Int).SetString("9c7be00b4ef4c444df85d5f61dc1283a23605483e1f8e934b3c210d22cd3c369", 16) + g2To213y, _ := new(big.Int).SetString("9220c0de74b20d2052a26d455ce401483e31153a16769cbd29ee3feba2329515", 16) + g2To214x, _ := new(big.Int).SetString("fcd83f42825263bb55664b238ccc49174dd06a70541178e76bcd92d7bb8c9e3", 16) + g2To214y, _ := new(big.Int).SetString("6c0bc1cfeac5fbced1d8232de5fdb683adbeaecdf1627bf4e86d55fbdf4aa9ad", 16) + g2To215x, _ := new(big.Int).SetString("7175407f1b58f010d4cda4c62511e59db7edcf28f5476d995cf39944b26b64f1", 16) + g2To215y, _ := new(big.Int).SetString("43b4554344e3d550f36d3401134cc86eb01fe8b774471d2a426e7efab24234d5", 16) + g2To216x, _ := new(big.Int).SetString("a8e282ff0c9706907215ff98e8fd416615311de0446f1e062a73b0610d064e13", 16) + g2To216y, _ := new(big.Int).SetString("7f97355b8db81c09abfb7f3c5b2515888b679a3e50dd6bd6cef7c73111f4cc0c", 16) + g2To217x, _ := new(big.Int).SetString("cac6f2e7e27faecbcb876f805ea66e63efbe9eaa753d67c1c15eb9ea7f7653a1", 16) + g2To217y, _ := new(big.Int).SetString("f7d416e5e2aa6f194cdb65d9a42a345081e83ae5688103a068c10ad0fec5e556", 16) + g2To218x, _ := new(big.Int).SetString("e6dfde46ee37d206efbc5932e58e43254ab767294238cb11cc9f4ab08624003d", 16) + g2To218y, _ := new(big.Int).SetString("8727b3b7be9139498f2f48f7b88f92203b1ce5ea527fd7dd7548650e2216b93b", 16) + g2To219x, _ := new(big.Int).SetString("3c4e089cd9a6823d66a40cfc7ac96082e250e3149cf211d3b0e1103548dce109", 16) + g2To219y, _ := new(big.Int).SetString("43fbbe669fe191b480757bca15764d379579e142d97fe697e2bf65923a19aeea", 16) + g2To220x, _ := new(big.Int).SetString("174a53b9c9a285872d39e56e6913cab15d59b1fa512508c022f382de8319497c", 16) + g2To220y, _ := new(big.Int).SetString("ccc9dc37abfc9c1657b4155f2c47f9e6646b3a1d8cb9854383da13ac079afa73", 16) + g2To221x, _ := new(big.Int).SetString("20e6e2e796946bb630c7071ef1b92ea3d53d280e0e4501115f5da36f840dd273", 16) + g2To221y, _ := new(big.Int).SetString("d3ad7afe4f1559e44a0ba1ad97874655811ec9793da8693cc07cfd15bb46b593", 16) + g2To222x, _ := new(big.Int).SetString("8e0ca824d7a351dba80280a07e71db7035ae68136cc24ca3e7b54f301a077674", 16) + g2To222y, _ := new(big.Int).SetString("4ec560759192d41dc569d24da62cf57cff60419d2f910290b84cbec12b7ed98", 16) + g2To223x, _ := new(big.Int).SetString("f7bb50da51c982d1c5fa63553e3d66c1afdb5821a321b4afe96afc5ea8192441", 16) + g2To223y, _ := new(big.Int).SetString("93cc3be30334a526311bc63bdde6485db1cfdc1fbbc4c74bbc640ea1d45165ae", 16) + g2To224x, _ := new(big.Int).SetString("959396981943785c3d3e57edf5018cdbe039e730e4918b3d884fdff09475b7ba", 16) + g2To224y, _ := new(big.Int).SetString("2e7e552888c331dd8ba0386a4b9cd6849c653f64c8709385e9b8abf87524f2fd", 16) + g2To225x, _ := new(big.Int).SetString("cbee1405ff0da7deafe32ca7dd73d95ed702226b391747c707275a940bc8f53b", 16) + g2To225y, _ := new(big.Int).SetString("f6211f4f4e75f902b51f3e689b8294cf0d9ff4f68126f7282922e6b278c87f45", 16) + g2To226x, _ := new(big.Int).SetString("add5bad28faaf5acdd580bfa0ba252e03de3beaefbd71b9cf377c88b14b311dd", 16) + g2To226y, _ := new(big.Int).SetString("e9c43cf4da3dc3a5974e434f8359814f52d4e1e7669b9b8902f982f349d6c38d", 16) + g2To227x, _ := new(big.Int).SetString("53f2432ba81717143fa9df3dff41ced24a29b314bc5a8c96f5f6400a0d7c0979", 16) + g2To227y, _ := new(big.Int).SetString("bd52effbc1f079b7ccd4e3e0911b07de4bd5a4f5c9e8b845f9f7e90c537b36a2", 16) + g2To228x, _ := new(big.Int).SetString("d2a63a50ae401e56d645a1153b109a8fcca0a43d561fba2dbb51340c9d82b151", 16) + g2To228y, _ := new(big.Int).SetString("e82d86fb6443fcb7565aee58b2948220a70f750af484ca52d4142174dcf89405", 16) + g2To229x, _ := new(big.Int).SetString("baf183a76100525e23bc7202033725f922b9cd6b36c413497c6c4bacca72da5f", 16) + g2To229y, _ := new(big.Int).SetString("deac9fbe9ccb4d335688bd58dd69b1d18e2336c5ca739361377ce628a8f2a0cf", 16) + g2To230x, _ := new(big.Int).SetString("f7aef8a7e38440238f9332906e48f6fd5adbd02d56b76a5ffa5aca58c56c3943", 16) + g2To230y, _ := new(big.Int).SetString("4e3b0b44d5ffda797c442bbdc3ab3fcfeec30184a8dcd003431f627facf442f1", 16) + g2To231x, _ := new(big.Int).SetString("dfb547cb10019036c5a2e29f0dddbb1f7af2fa25a3c7a78c1fac945711924459", 16) + g2To231y, _ := new(big.Int).SetString("9accd2a9ba0f47088b8389ce9dc864cc22af0930e5c031dcfa205e0dcc65fd9e", 16) + g2To232x, _ := new(big.Int).SetString("64587e2335471eb890ee7896d7cfdc866bacbdbd3839317b3436f9b45617e073", 16) + g2To232y, _ := new(big.Int).SetString("d99fcdd5bf6902e2ae96dd6447c299a185b90a39133aeab358299e5e9faf6589", 16) + g2To233x, _ := new(big.Int).SetString("b866d6b142df940f2cf28b54c92f0c1294e0b6a22a91f2ef44bcd88c4384480d", 16) + g2To233y, _ := new(big.Int).SetString("1914b0b3426aeb7089a278d7ea9ad7ac24e522804b1d86d60e659b470c4cafa8", 16) + g2To234x, _ := new(big.Int).SetString("ec2bb89085de819ec4d9d1646102ba87e2d52ae4ed4fe455d229cda81db20d6c", 16) + g2To234y, _ := new(big.Int).SetString("ccecc17661e013a1332f66f0650940c633a2364be87efa98a0e99c4d629cf4a0", 16) + g2To235x, _ := new(big.Int).SetString("71c4a7e389e296ced39d75ef5e545905e50050640f50becf38a60ecb23b09d0f", 16) + g2To235y, _ := new(big.Int).SetString("1313fadb737af3ba0af3e0a292f810aa786f2b084a62ffc7637b1f01720ddb62", 16) + g2To236x, _ := new(big.Int).SetString("8481bde0e4e4d885b3a546d3e549de042f0aa6cea250e7fd358d6c86dd45e458", 16) + g2To236y, _ := new(big.Int).SetString("38ee7b8cba5404dd84a25bf39cecb2ca900a79c42b262e556d64b1b59779057e", 16) + g2To237x, _ := new(big.Int).SetString("9629a450bd383a8b9fd43c6cd1d492bf392ed605299561dde54433526ce9f114", 16) + g2To237y, _ := new(big.Int).SetString("bf439b280c5fb6d7576befd220cef64db925593e5c56af8dca3972c4a24aa391", 16) + g2To238x, _ := new(big.Int).SetString("b73b1c47ef1e4688eb1730da7cc893df1477d747e187e18383d38d9626ca6cc3", 16) + g2To238y, _ := new(big.Int).SetString("584315cb294922a90a57d64bbcc805097322a25209757f5afac35d76a54fdba3", 16) + g2To239x, _ := new(big.Int).SetString("edfe16b2db40180311f9892007a2fef7d05b2a3bb676899f9c6e2192d38f93e0", 16) + g2To239y, _ := new(big.Int).SetString("ee6902f1fca5db3694d74faa4b05d0d25b3d5100c46e227e3d01793de29405ad", 16) + g2To240x, _ := new(big.Int).SetString("13464a57a78102aa62b6979ae817f4637ffcfed3c4b1ce30bcd6303f6caf666b", 16) + g2To240y, _ := new(big.Int).SetString("69be159004614580ef7e433453ccb0ca48f300a81d0942e13f495a907f6ecc27", 16) + g2To241x, _ := new(big.Int).SetString("eb3cf8f532245362ec05c88c85fe12d19182be7dceabe577c75849c6065084ae", 16) + g2To241y, _ := new(big.Int).SetString("c833c78222d9d70043fe63dcefdca4a1f52b45c5e7dbd2a66f67c1fff96b9480", 16) + g2To242x, _ := new(big.Int).SetString("bdf1a67d092d99974f7a60f2184519b2a576fcf984a201d9f8e5bcbcc2e9a5d0", 16) + g2To242y, _ := new(big.Int).SetString("4095902bab65a1aaa80be54a86bf7baaa6280b61e5626461cdb4f7018562ff7b", 16) + g2To243x, _ := new(big.Int).SetString("68856a6eddc4ec29cd5be267b64483b48c3b4196477da62abde5fc173b27e771", 16) + g2To243y, _ := new(big.Int).SetString("77a33df14f79a1fb13b6fd49c19f7b4a331d22f293b0733a6118d62a07bbdab6", 16) + g2To244x, _ := new(big.Int).SetString("bc4a9df5b713fe2e9aef430bcc1dc97a0cd9ccede2f28588cada3a0d2d83f366", 16) + g2To244y, _ := new(big.Int).SetString("d3a81ca6e785c06383937adf4b798caa6e8a9fbfa547b16d758d666581f33c1", 16) + g2To245x, _ := new(big.Int).SetString("da433d5e11ceccc0abc5c7626ce7bab42e89b221f785c409282de545f3fceb19", 16) + g2To245y, _ := new(big.Int).SetString("e498dbd321a810301debbdc4af95e5218e77fc2d9227b277684e7120a6f5cc64", 16) + g2To246x, _ := new(big.Int).SetString("31e8e1ee9e8c7ec1c1c116981c16efdbcc4838a72207e0654de275c5acf692a", 16) + g2To246y, _ := new(big.Int).SetString("ad7e7f5b465b353dd9d0970290d6743b70649827c5bf73b09cc2a84eb16f667a", 16) + g2To247x, _ := new(big.Int).SetString("a9878607a88d61155d3e00d862657f73e9c9bf363fc7a91592bbd7ff81f488b6", 16) + g2To247y, _ := new(big.Int).SetString("d181a1abd58895d61c063e7c82157c2239d0f01964ad5c6d495a7bbb031dab1d", 16) + g2To248x, _ := new(big.Int).SetString("8c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa", 16) + g2To248y, _ := new(big.Int).SetString("40a30463a3305193378fedf31f7cc0eb7ae784f0451cb9459e71dc73cbef9482", 16) + g2To249x, _ := new(big.Int).SetString("ab1ac1872a38a2f196bed5a6047f0da2c8130fe8de49fc4d5dfb201f7611d8e2", 16) + g2To249y, _ := new(big.Int).SetString("13f4a37a324d17a1e9aa5f39db6a42b6f7ef93d33e1e545f01a581f3c429d15b", 16) + g2To250x, _ := new(big.Int).SetString("2564fe9b5beef82d3703a607253f31ef8ea1b365772df434226aee642651b3fa", 16) + g2To250y, _ := new(big.Int).SetString("8ad9f7a60678389095fa14ae1203925f14f37dab6b79816edb82e6a301e5122d", 16) + g2To251x, _ := new(big.Int).SetString("ff3d6136ffac5b0cbfc6c5c0c30dc01a7ea3d56c20bd3103b178e3d3ae180068", 16) + g2To251y, _ := new(big.Int).SetString("133239be84e4000e40d0372cdd96adc1547676f24001f5e670a6bb6e188c6077", 16) + g2To252x, _ := new(big.Int).SetString("8ea9666139527a8c1dd94ce4f071fd23c8b350c5a4bb33748c4ba111faccae0", 16) + g2To252y, _ := new(big.Int).SetString("620efabbc8ee2782e24e7c0cfb95c5d735b783be9cf0f8e955af34a30e62b945", 16) + g2To253x, _ := new(big.Int).SetString("c25f637176220cd9f3a66df315559d8263cf2a23a4ab5ab9a293131da190b632", 16) + g2To253y, _ := new(big.Int).SetString("53154fede94d2873989049903809d7980a9f04ff9e027a1d6eebf3d6fc9590cf", 16) + g2To254x, _ := new(big.Int).SetString("2a9e8dfe3cce6bab3e82d82a5688544c0c7b55dc31978b4de2ccb3b7d466d561", 16) + g2To254y, _ := new(big.Int).SetString("1dfeda5c16e651fbac7b5ad608b96cf5e01eaec17a02182f96ccf5252e76373", 16) + g2To255x, _ := new(big.Int).SetString("b23790a42be63e1b251ad6c94fdef07271ec0aada31db6c3e8bd32043f8be384", 16) + g2To255y, _ := new(big.Int).SetString("fc6b694919d55edbe8d50f88aa81f94517f004f4149ecb58d10a473deb19880e", 16) return CurveParams{ A: big.NewInt(0), B: big.NewInt(7), Gx: gx, Gy: gy, - Gmx: [257]*big.Int{g3x, g5x, g7x, g8x, g16x, g32x, g64x, g128x, g256x, g512x, g1024x, g2048x, g4096x, g8192x, g16384x, g32768x, g65536x, g131072x, g262144x, g524288x, g1048576x, g2097152x, g4194304x, g8388608x, g16777216x, g33554432x, g67108864x, g134217728x, g268435456x, g536870912x, g1073741824x, g2147483648x, g4294967296x, g8589934592x, g17179869184x, g34359738368x, g68719476736x, g137438953472x, g274877906944x, g549755813888x, g1099511627776x, g2199023255552x, g4398046511104x, g8796093022208x, g17592186044416x, g35184372088832x, g70368744177664x, g140737488355328x, g281474976710656x, g562949953421312x, g1125899906842624x, g2251799813685248x, g4503599627370496x, g9007199254740992x, g18014398509481984x, g36028797018963968x, g72057594037927936x, g144115188075855872x, g288230376151711744x, g576460752303423488x, g1152921504606846976x, g2305843009213693952x, g4611686018427387904x, g9223372036854775808x, g18446744073709551616x, g36893488147419103232x, g73786976294838206464x, g147573952589676412928x, g295147905179352825856x, g590295810358705651712x, g1180591620717411303424x, g2361183241434822606848x, g4722366482869645213696x, g9444732965739290427392x, g18889465931478580854784x, g37778931862957161709568x, g75557863725914323419136x, g151115727451828646838272x, g302231454903657293676544x, g604462909807314587353088x, g1208925819614629174706176x, g2417851639229258349412352x, g4835703278458516698824704x, g9671406556917033397649408x, g19342813113834066795298816x, g38685626227668133590597632x, g77371252455336267181195264x, g154742504910672534362390528x, g309485009821345068724781056x, g618970019642690137449562112x, g1237940039285380274899124224x, g2475880078570760549798248448x, g4951760157141521099596496896x, g9903520314283042199192993792x, g19807040628566084398385987584x, g39614081257132168796771975168x, g79228162514264337593543950336x, g158456325028528675187087900672x, g316912650057057350374175801344x, g633825300114114700748351602688x, g1267650600228229401496703205376x, g2535301200456458802993406410752x, g5070602400912917605986812821504x, g10141204801825835211973625643008x, g20282409603651670423947251286016x, g40564819207303340847894502572032x, g81129638414606681695789005144064x, g162259276829213363391578010288128x, g324518553658426726783156020576256x, g649037107316853453566312041152512x, g1298074214633706907132624082305024x, g2596148429267413814265248164610048x, g5192296858534827628530496329220096x, g10384593717069655257060992658440192x, g20769187434139310514121985316880384x, g41538374868278621028243970633760768x, g83076749736557242056487941267521536x, g166153499473114484112975882535043072x, g332306998946228968225951765070086144x, g664613997892457936451903530140172288x, g1329227995784915872903807060280344576x, g2658455991569831745807614120560689152x, g5316911983139663491615228241121378304x, g10633823966279326983230456482242756608x, g21267647932558653966460912964485513216x, g42535295865117307932921825928971026432x, g85070591730234615865843651857942052864x, g170141183460469231731687303715884105728x, g340282366920938463463374607431768211456x, g680564733841876926926749214863536422912x, g1361129467683753853853498429727072845824x, g2722258935367507707706996859454145691648x, g5444517870735015415413993718908291383296x, g10889035741470030830827987437816582766592x, g21778071482940061661655974875633165533184x, g43556142965880123323311949751266331066368x, g87112285931760246646623899502532662132736x, g174224571863520493293247799005065324265472x, g348449143727040986586495598010130648530944x, g696898287454081973172991196020261297061888x, g1393796574908163946345982392040522594123776x, g2787593149816327892691964784081045188247552x, g5575186299632655785383929568162090376495104x, g11150372599265311570767859136324180752990208x, g22300745198530623141535718272648361505980416x, g44601490397061246283071436545296723011960832x, g89202980794122492566142873090593446023921664x, g178405961588244985132285746181186892047843328x, g356811923176489970264571492362373784095686656x, g713623846352979940529142984724747568191373312x, g1427247692705959881058285969449495136382746624x, g2854495385411919762116571938898990272765493248x, g5708990770823839524233143877797980545530986496x, g11417981541647679048466287755595961091061972992x, g22835963083295358096932575511191922182123945984x, g45671926166590716193865151022383844364247891968x, g91343852333181432387730302044767688728495783936x, g182687704666362864775460604089535377456991567872x, g365375409332725729550921208179070754913983135744x, g730750818665451459101842416358141509827966271488x, g1461501637330902918203684832716283019655932542976x, g2923003274661805836407369665432566039311865085952x, g5846006549323611672814739330865132078623730171904x, g11692013098647223345629478661730264157247460343808x, g23384026197294446691258957323460528314494920687616x, g46768052394588893382517914646921056628989841375232x, g93536104789177786765035829293842113257979682750464x, g187072209578355573530071658587684226515959365500928x, g374144419156711147060143317175368453031918731001856x, g748288838313422294120286634350736906063837462003712x, g1496577676626844588240573268701473812127674924007424x, g2993155353253689176481146537402947624255349848014848x, g5986310706507378352962293074805895248510699696029696x, g11972621413014756705924586149611790497021399392059392x, g23945242826029513411849172299223580994042798784118784x, g47890485652059026823698344598447161988085597568237568x, g95780971304118053647396689196894323976171195136475136x, g191561942608236107294793378393788647952342390272950272x, g383123885216472214589586756787577295904684780545900544x, g766247770432944429179173513575154591809369561091801088x, g1532495540865888858358347027150309183618739122183602176x, g3064991081731777716716694054300618367237478244367204352x, g6129982163463555433433388108601236734474956488734408704x, g12259964326927110866866776217202473468949912977468817408x, g24519928653854221733733552434404946937899825954937634816x, g49039857307708443467467104868809893875799651909875269632x, g98079714615416886934934209737619787751599303819750539264x, g196159429230833773869868419475239575503198607639501078528x, g392318858461667547739736838950479151006397215279002157056x, g784637716923335095479473677900958302012794430558004314112x, g1569275433846670190958947355801916604025588861116008628224x, g3138550867693340381917894711603833208051177722232017256448x, g6277101735386680763835789423207666416102355444464034512896x, g12554203470773361527671578846415332832204710888928069025792x, g25108406941546723055343157692830665664409421777856138051584x, g50216813883093446110686315385661331328818843555712276103168x, g100433627766186892221372630771322662657637687111424552206336x, g200867255532373784442745261542645325315275374222849104412672x, g401734511064747568885490523085290650630550748445698208825344x, g803469022129495137770981046170581301261101496891396417650688x, g1606938044258990275541962092341162602522202993782792835301376x, g3213876088517980551083924184682325205044405987565585670602752x, g6427752177035961102167848369364650410088811975131171341205504x, g12855504354071922204335696738729300820177623950262342682411008x, g25711008708143844408671393477458601640355247900524685364822016x, g51422017416287688817342786954917203280710495801049370729644032x, g102844034832575377634685573909834406561420991602098741459288064x, g205688069665150755269371147819668813122841983204197482918576128x, g411376139330301510538742295639337626245683966408394965837152256x, g822752278660603021077484591278675252491367932816789931674304512x, g1645504557321206042154969182557350504982735865633579863348609024x, g3291009114642412084309938365114701009965471731267159726697218048x, g6582018229284824168619876730229402019930943462534319453394436096x, g13164036458569648337239753460458804039861886925068638906788872192x, g26328072917139296674479506920917608079723773850137277813577744384x, g52656145834278593348959013841835216159447547700274555627155488768x, g105312291668557186697918027683670432318895095400549111254310977536x, g210624583337114373395836055367340864637790190801098222508621955072x, g421249166674228746791672110734681729275580381602196445017243910144x, g842498333348457493583344221469363458551160763204392890034487820288x, g1684996666696914987166688442938726917102321526408785780068975640576x, g3369993333393829974333376885877453834204643052817571560137951281152x, g6739986666787659948666753771754907668409286105635143120275902562304x, g13479973333575319897333507543509815336818572211270286240551805124608x, g26959946667150639794667015087019630673637144422540572481103610249216x, g53919893334301279589334030174039261347274288845081144962207220498432x, g107839786668602559178668060348078522694548577690162289924414440996864x, g215679573337205118357336120696157045389097155380324579848828881993728x, g431359146674410236714672241392314090778194310760649159697657763987456x, g862718293348820473429344482784628181556388621521298319395315527974912x, g1725436586697640946858688965569256363112777243042596638790631055949824x, g3450873173395281893717377931138512726225554486085193277581262111899648x, g6901746346790563787434755862277025452451108972170386555162524223799296x, g13803492693581127574869511724554050904902217944340773110325048447598592x, g27606985387162255149739023449108101809804435888681546220650096895197184x, g55213970774324510299478046898216203619608871777363092441300193790394368x, g110427941548649020598956093796432407239217743554726184882600387580788736x, g220855883097298041197912187592864814478435487109452369765200775161577472x, g441711766194596082395824375185729628956870974218904739530401550323154944x, g883423532389192164791648750371459257913741948437809479060803100646309888x, g1766847064778384329583297500742918515827483896875618958121606201292619776x, g3533694129556768659166595001485837031654967793751237916243212402585239552x, g7067388259113537318333190002971674063309935587502475832486424805170479104x, g14134776518227074636666380005943348126619871175004951664972849610340958208x, g28269553036454149273332760011886696253239742350009903329945699220681916416x, g56539106072908298546665520023773392506479484700019806659891398441363832832x, g113078212145816597093331040047546785012958969400039613319782796882727665664x, g226156424291633194186662080095093570025917938800079226639565593765455331328x, g452312848583266388373324160190187140051835877600158453279131187530910662656x, g904625697166532776746648320380374280103671755200316906558262375061821325312x, g1809251394333065553493296640760748560207343510400633813116524750123642650624x, g3618502788666131106986593281521497120414687020801267626233049500247285301248x, g7237005577332262213973186563042994240829374041602535252466099000494570602496x, g14474011154664524427946373126085988481658748083205070504932198000989141204992x, g28948022309329048855892746252171976963317496166410141009864396001978282409984x, g57896044618658097711785492504343953926634992332820282019728792003956564819968x, g115792089237316195423570985008687907853269984665640564039457584007913129639936x}, - Gmy: [257]*big.Int{g3y, g5y, g7y, g8y, g16y, g32y, g64y, g128y, g256y, g512y, g1024y, g2048y, g4096y, g8192y, g16384y, g32768y, g65536y, g131072y, g262144y, g524288y, g1048576y, g2097152y, g4194304y, g8388608y, g16777216y, g33554432y, g67108864y, g134217728y, g268435456y, g536870912y, g1073741824y, g2147483648y, g4294967296y, g8589934592y, g17179869184y, g34359738368y, g68719476736y, g137438953472y, g274877906944y, g549755813888y, g1099511627776y, g2199023255552y, g4398046511104y, g8796093022208y, g17592186044416y, g35184372088832y, g70368744177664y, g140737488355328y, g281474976710656y, g562949953421312y, g1125899906842624y, g2251799813685248y, g4503599627370496y, g9007199254740992y, g18014398509481984y, g36028797018963968y, g72057594037927936y, g144115188075855872y, g288230376151711744y, g576460752303423488y, g1152921504606846976y, g2305843009213693952y, g4611686018427387904y, g9223372036854775808y, g18446744073709551616y, g36893488147419103232y, g73786976294838206464y, g147573952589676412928y, g295147905179352825856y, g590295810358705651712y, g1180591620717411303424y, g2361183241434822606848y, g4722366482869645213696y, g9444732965739290427392y, g18889465931478580854784y, g37778931862957161709568y, g75557863725914323419136y, g151115727451828646838272y, g302231454903657293676544y, g604462909807314587353088y, g1208925819614629174706176y, g2417851639229258349412352y, g4835703278458516698824704y, g9671406556917033397649408y, g19342813113834066795298816y, g38685626227668133590597632y, g77371252455336267181195264y, g154742504910672534362390528y, g309485009821345068724781056y, g618970019642690137449562112y, g1237940039285380274899124224y, g2475880078570760549798248448y, g4951760157141521099596496896y, g9903520314283042199192993792y, g19807040628566084398385987584y, g39614081257132168796771975168y, g79228162514264337593543950336y, g158456325028528675187087900672y, g316912650057057350374175801344y, g633825300114114700748351602688y, g1267650600228229401496703205376y, g2535301200456458802993406410752y, g5070602400912917605986812821504y, g10141204801825835211973625643008y, g20282409603651670423947251286016y, g40564819207303340847894502572032y, g81129638414606681695789005144064y, g162259276829213363391578010288128y, g324518553658426726783156020576256y, g649037107316853453566312041152512y, g1298074214633706907132624082305024y, g2596148429267413814265248164610048y, g5192296858534827628530496329220096y, g10384593717069655257060992658440192y, g20769187434139310514121985316880384y, g41538374868278621028243970633760768y, g83076749736557242056487941267521536y, g166153499473114484112975882535043072y, g332306998946228968225951765070086144y, g664613997892457936451903530140172288y, g1329227995784915872903807060280344576y, g2658455991569831745807614120560689152y, g5316911983139663491615228241121378304y, g10633823966279326983230456482242756608y, g21267647932558653966460912964485513216y, g42535295865117307932921825928971026432y, g85070591730234615865843651857942052864y, g170141183460469231731687303715884105728y, g340282366920938463463374607431768211456y, g680564733841876926926749214863536422912y, g1361129467683753853853498429727072845824y, g2722258935367507707706996859454145691648y, g5444517870735015415413993718908291383296y, g10889035741470030830827987437816582766592y, g21778071482940061661655974875633165533184y, g43556142965880123323311949751266331066368y, g87112285931760246646623899502532662132736y, g174224571863520493293247799005065324265472y, g348449143727040986586495598010130648530944y, g696898287454081973172991196020261297061888y, g1393796574908163946345982392040522594123776y, g2787593149816327892691964784081045188247552y, g5575186299632655785383929568162090376495104y, g11150372599265311570767859136324180752990208y, g22300745198530623141535718272648361505980416y, g44601490397061246283071436545296723011960832y, g89202980794122492566142873090593446023921664y, g178405961588244985132285746181186892047843328y, g356811923176489970264571492362373784095686656y, g713623846352979940529142984724747568191373312y, g1427247692705959881058285969449495136382746624y, g2854495385411919762116571938898990272765493248y, g5708990770823839524233143877797980545530986496y, g11417981541647679048466287755595961091061972992y, g22835963083295358096932575511191922182123945984y, g45671926166590716193865151022383844364247891968y, g91343852333181432387730302044767688728495783936y, g182687704666362864775460604089535377456991567872y, g365375409332725729550921208179070754913983135744y, g730750818665451459101842416358141509827966271488y, g1461501637330902918203684832716283019655932542976y, g2923003274661805836407369665432566039311865085952y, g5846006549323611672814739330865132078623730171904y, g11692013098647223345629478661730264157247460343808y, g23384026197294446691258957323460528314494920687616y, g46768052394588893382517914646921056628989841375232y, g93536104789177786765035829293842113257979682750464y, g187072209578355573530071658587684226515959365500928y, g374144419156711147060143317175368453031918731001856y, g748288838313422294120286634350736906063837462003712y, g1496577676626844588240573268701473812127674924007424y, g2993155353253689176481146537402947624255349848014848y, g5986310706507378352962293074805895248510699696029696y, g11972621413014756705924586149611790497021399392059392y, g23945242826029513411849172299223580994042798784118784y, g47890485652059026823698344598447161988085597568237568y, g95780971304118053647396689196894323976171195136475136y, g191561942608236107294793378393788647952342390272950272y, g383123885216472214589586756787577295904684780545900544y, g766247770432944429179173513575154591809369561091801088y, g1532495540865888858358347027150309183618739122183602176y, g3064991081731777716716694054300618367237478244367204352y, g6129982163463555433433388108601236734474956488734408704y, g12259964326927110866866776217202473468949912977468817408y, g24519928653854221733733552434404946937899825954937634816y, g49039857307708443467467104868809893875799651909875269632y, g98079714615416886934934209737619787751599303819750539264y, g196159429230833773869868419475239575503198607639501078528y, g392318858461667547739736838950479151006397215279002157056y, g784637716923335095479473677900958302012794430558004314112y, g1569275433846670190958947355801916604025588861116008628224y, g3138550867693340381917894711603833208051177722232017256448y, g6277101735386680763835789423207666416102355444464034512896y, g12554203470773361527671578846415332832204710888928069025792y, g25108406941546723055343157692830665664409421777856138051584y, g50216813883093446110686315385661331328818843555712276103168y, g100433627766186892221372630771322662657637687111424552206336y, g200867255532373784442745261542645325315275374222849104412672y, g401734511064747568885490523085290650630550748445698208825344y, g803469022129495137770981046170581301261101496891396417650688y, g1606938044258990275541962092341162602522202993782792835301376y, g3213876088517980551083924184682325205044405987565585670602752y, g6427752177035961102167848369364650410088811975131171341205504y, g12855504354071922204335696738729300820177623950262342682411008y, g25711008708143844408671393477458601640355247900524685364822016y, g51422017416287688817342786954917203280710495801049370729644032y, g102844034832575377634685573909834406561420991602098741459288064y, g205688069665150755269371147819668813122841983204197482918576128y, g411376139330301510538742295639337626245683966408394965837152256y, g822752278660603021077484591278675252491367932816789931674304512y, g1645504557321206042154969182557350504982735865633579863348609024y, g3291009114642412084309938365114701009965471731267159726697218048y, g6582018229284824168619876730229402019930943462534319453394436096y, g13164036458569648337239753460458804039861886925068638906788872192y, g26328072917139296674479506920917608079723773850137277813577744384y, g52656145834278593348959013841835216159447547700274555627155488768y, g105312291668557186697918027683670432318895095400549111254310977536y, g210624583337114373395836055367340864637790190801098222508621955072y, g421249166674228746791672110734681729275580381602196445017243910144y, g842498333348457493583344221469363458551160763204392890034487820288y, g1684996666696914987166688442938726917102321526408785780068975640576y, g3369993333393829974333376885877453834204643052817571560137951281152y, g6739986666787659948666753771754907668409286105635143120275902562304y, g13479973333575319897333507543509815336818572211270286240551805124608y, g26959946667150639794667015087019630673637144422540572481103610249216y, g53919893334301279589334030174039261347274288845081144962207220498432y, g107839786668602559178668060348078522694548577690162289924414440996864y, g215679573337205118357336120696157045389097155380324579848828881993728y, g431359146674410236714672241392314090778194310760649159697657763987456y, g862718293348820473429344482784628181556388621521298319395315527974912y, g1725436586697640946858688965569256363112777243042596638790631055949824y, g3450873173395281893717377931138512726225554486085193277581262111899648y, g6901746346790563787434755862277025452451108972170386555162524223799296y, g13803492693581127574869511724554050904902217944340773110325048447598592y, g27606985387162255149739023449108101809804435888681546220650096895197184y, g55213970774324510299478046898216203619608871777363092441300193790394368y, g110427941548649020598956093796432407239217743554726184882600387580788736y, g220855883097298041197912187592864814478435487109452369765200775161577472y, g441711766194596082395824375185729628956870974218904739530401550323154944y, g883423532389192164791648750371459257913741948437809479060803100646309888y, g1766847064778384329583297500742918515827483896875618958121606201292619776y, g3533694129556768659166595001485837031654967793751237916243212402585239552y, g7067388259113537318333190002971674063309935587502475832486424805170479104y, g14134776518227074636666380005943348126619871175004951664972849610340958208y, g28269553036454149273332760011886696253239742350009903329945699220681916416y, g56539106072908298546665520023773392506479484700019806659891398441363832832y, g113078212145816597093331040047546785012958969400039613319782796882727665664y, g226156424291633194186662080095093570025917938800079226639565593765455331328y, g452312848583266388373324160190187140051835877600158453279131187530910662656y, g904625697166532776746648320380374280103671755200316906558262375061821325312y, g1809251394333065553493296640760748560207343510400633813116524750123642650624y, g3618502788666131106986593281521497120414687020801267626233049500247285301248y, g7237005577332262213973186563042994240829374041602535252466099000494570602496y, g14474011154664524427946373126085988481658748083205070504932198000989141204992y, g28948022309329048855892746252171976963317496166410141009864396001978282409984y, g57896044618658097711785492504343953926634992332820282019728792003956564819968y, g115792089237316195423570985008687907853269984665640564039457584007913129639936y}, + Gmx: [256]*big.Int{g3x, g5x, g7x, g2To3x, g2To4x, g2To5x, g2To6x, g2To7x, g2To8x, g2To9x, g2To10x, g2To11x, g2To12x, g2To13x, g2To14x, g2To15x, g2To16x, g2To17x, g2To18x, g2To19x, g2To20x, g2To21x, g2To22x, g2To23x, g2To24x, g2To25x, g2To26x, g2To27x, g2To28x, g2To29x, g2To30x, g2To31x, g2To32x, g2To33x, g2To34x, g2To35x, g2To36x, g2To37x, g2To38x, g2To39x, g2To40x, g2To41x, g2To42x, g2To43x, g2To44x, g2To45x, g2To46x, g2To47x, g2To48x, g2To49x, g2To50x, g2To51x, g2To52x, g2To53x, g2To54x, g2To55x, g2To56x, g2To57x, g2To58x, g2To59x, g2To60x, g2To61x, g2To62x, g2To63x, g2To64x, g2To65x, g2To66x, g2To67x, g2To68x, g2To69x, g2To70x, g2To71x, g2To72x, g2To73x, g2To74x, g2To75x, g2To76x, g2To77x, g2To78x, g2To79x, g2To80x, g2To81x, g2To82x, g2To83x, g2To84x, g2To85x, g2To86x, g2To87x, g2To88x, g2To89x, g2To90x, g2To91x, g2To92x, g2To93x, g2To94x, g2To95x, g2To96x, g2To97x, g2To98x, g2To99x, g2To100x, g2To101x, g2To102x, g2To103x, g2To104x, g2To105x, g2To106x, g2To107x, g2To108x, g2To109x, g2To110x, g2To111x, g2To112x, g2To113x, g2To114x, g2To115x, g2To116x, g2To117x, g2To118x, g2To119x, g2To120x, g2To121x, g2To122x, g2To123x, g2To124x, g2To125x, g2To126x, g2To127x, g2To128x, g2To129x, g2To130x, g2To131x, g2To132x, g2To133x, g2To134x, g2To135x, g2To136x, g2To137x, g2To138x, g2To139x, g2To140x, g2To141x, g2To142x, g2To143x, g2To144x, g2To145x, g2To146x, g2To147x, g2To148x, g2To149x, g2To150x, g2To151x, g2To152x, g2To153x, g2To154x, g2To155x, g2To156x, g2To157x, g2To158x, g2To159x, g2To160x, g2To161x, g2To162x, g2To163x, g2To164x, g2To165x, g2To166x, g2To167x, g2To168x, g2To169x, g2To170x, g2To171x, g2To172x, g2To173x, g2To174x, g2To175x, g2To176x, g2To177x, g2To178x, g2To179x, g2To180x, g2To181x, g2To182x, g2To183x, g2To184x, g2To185x, g2To186x, g2To187x, g2To188x, g2To189x, g2To190x, g2To191x, g2To192x, g2To193x, g2To194x, g2To195x, g2To196x, g2To197x, g2To198x, g2To199x, g2To200x, g2To201x, g2To202x, g2To203x, g2To204x, g2To205x, g2To206x, g2To207x, g2To208x, g2To209x, g2To210x, g2To211x, g2To212x, g2To213x, g2To214x, g2To215x, g2To216x, g2To217x, g2To218x, g2To219x, g2To220x, g2To221x, g2To222x, g2To223x, g2To224x, g2To225x, g2To226x, g2To227x, g2To228x, g2To229x, g2To230x, g2To231x, g2To232x, g2To233x, g2To234x, g2To235x, g2To236x, g2To237x, g2To238x, g2To239x, g2To240x, g2To241x, g2To242x, g2To243x, g2To244x, g2To245x, g2To246x, g2To247x, g2To248x, g2To249x, g2To250x, g2To251x, g2To252x, g2To253x, g2To254x, g2To255x}, + Gmy: [256]*big.Int{g3y, g5y, g7y, g2To3y, g2To4y, g2To5y, g2To6y, g2To7y, g2To8y, g2To9y, g2To10y, g2To11y, g2To12y, g2To13y, g2To14y, g2To15y, g2To16y, g2To17y, g2To18y, g2To19y, g2To20y, g2To21y, g2To22y, g2To23y, g2To24y, g2To25y, g2To26y, g2To27y, g2To28y, g2To29y, g2To30y, g2To31y, g2To32y, g2To33y, g2To34y, g2To35y, g2To36y, g2To37y, g2To38y, g2To39y, g2To40y, g2To41y, g2To42y, g2To43y, g2To44y, g2To45y, g2To46y, g2To47y, g2To48y, g2To49y, g2To50y, g2To51y, g2To52y, g2To53y, g2To54y, g2To55y, g2To56y, g2To57y, g2To58y, g2To59y, g2To60y, g2To61y, g2To62y, g2To63y, g2To64y, g2To65y, g2To66y, g2To67y, g2To68y, g2To69y, g2To70y, g2To71y, g2To72y, g2To73y, g2To74y, g2To75y, g2To76y, g2To77y, g2To78y, g2To79y, g2To80y, g2To81y, g2To82y, g2To83y, g2To84y, g2To85y, g2To86y, g2To87y, g2To88y, g2To89y, g2To90y, g2To91y, g2To92y, g2To93y, g2To94y, g2To95y, g2To96y, g2To97y, g2To98y, g2To99y, g2To100y, g2To101y, g2To102y, g2To103y, g2To104y, g2To105y, g2To106y, g2To107y, g2To108y, g2To109y, g2To110y, g2To111y, g2To112y, g2To113y, g2To114y, g2To115y, g2To116y, g2To117y, g2To118y, g2To119y, g2To120y, g2To121y, g2To122y, g2To123y, g2To124y, g2To125y, g2To126y, g2To127y, g2To128y, g2To129y, g2To130y, g2To131y, g2To132y, g2To133y, g2To134y, g2To135y, g2To136y, g2To137y, g2To138y, g2To139y, g2To140y, g2To141y, g2To142y, g2To143y, g2To144y, g2To145y, g2To146y, g2To147y, g2To148y, g2To149y, g2To150y, g2To151y, g2To152y, g2To153y, g2To154y, g2To155y, g2To156y, g2To157y, g2To158y, g2To159y, g2To160y, g2To161y, g2To162y, g2To163y, g2To164y, g2To165y, g2To166y, g2To167y, g2To168y, g2To169y, g2To170y, g2To171y, g2To172y, g2To173y, g2To174y, g2To175y, g2To176y, g2To177y, g2To178y, g2To179y, g2To180y, g2To181y, g2To182y, g2To183y, g2To184y, g2To185y, g2To186y, g2To187y, g2To188y, g2To189y, g2To190y, g2To191y, g2To192y, g2To193y, g2To194y, g2To195y, g2To196y, g2To197y, g2To198y, g2To199y, g2To200y, g2To201y, g2To202y, g2To203y, g2To204y, g2To205y, g2To206y, g2To207y, g2To208y, g2To209y, g2To210y, g2To211y, g2To212y, g2To213y, g2To214y, g2To215y, g2To216y, g2To217y, g2To218y, g2To219y, g2To220y, g2To221y, g2To222y, g2To223y, g2To224y, g2To225y, g2To226y, g2To227y, g2To228y, g2To229y, g2To230y, g2To231y, g2To232y, g2To233y, g2To234y, g2To235y, g2To236y, g2To237y, g2To238y, g2To239y, g2To240y, g2To241y, g2To242y, g2To243y, g2To244y, g2To245y, g2To246y, g2To247y, g2To248y, g2To249y, g2To250y, g2To251y, g2To252y, g2To253y, g2To254y, g2To255y}, } } @@ -563,514 +561,512 @@ func GetBN254Params() CurveParams { g5y, _ := new(big.Int).SetString("1e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c", 16) g7x, _ := new(big.Int).SetString("17072b2ed3bb8d759a5325f477629386cb6fc6ecb801bd76983a6b86abffe078", 16) g7y, _ := new(big.Int).SetString("168ada6cd130dd52017bb54bfa19377aadfe3bf05d18f41b77809f7f60d4af9e", 16) - g8x, _ := new(big.Int).SetString("8b1d51d23480c10f472f5e93b9cfea88238c121fe155af7043937882c306a63", 16) - g8y, _ := new(big.Int).SetString("299836713dad3fa34e337aa412466015c366af8ec50b9d7bd05aa74642822021", 16) - g16x, _ := new(big.Int).SetString("17f485337f6e10fca0e385f7a93d1ac0a977e43995c3e4d9b8f89daa6a183f44", 16) - g16y, _ := new(big.Int).SetString("5ccdc1561db963516da62c66edd39d1bb9c6c4674990c4440403c88025c95ad", 16) - g32x, _ := new(big.Int).SetString("ac610b573e9fb98deaf5aa48feb447536418ddc4cefd17c277c852a2a02a413", 16) - g32y, _ := new(big.Int).SetString("1940e395f5eeaaf3b73a54a9db9910c3b7f907cad7f55137fb0c3847a682d315", 16) - g64x, _ := new(big.Int).SetString("6b7c24035a06c42bcb47d54df4104cd8880f68263afce13250ecc65f7669d1e", 16) - g64y, _ := new(big.Int).SetString("2179e38c6e6341d1c80b4ed2ad6d43188c01c2f70a8093b37fc02f9fd9e5f12f", 16) - g128x, _ := new(big.Int).SetString("2295215c9285bdc4f6beefdeccc5ccb67bbb9959f05f4c2a716a8f442fa69498", 16) - g128y, _ := new(big.Int).SetString("10174283cbb851eaf5f64a278b0fe58fb9b3b0b6a31439012ebe8d731bcdf851", 16) - g256x, _ := new(big.Int).SetString("2b9cd0bae01dfefdb859f3fbacbc897d6174d717103bf3b64dc43276541a2034", 16) - g256y, _ := new(big.Int).SetString("13b64ed1d986a508cbe5b28ca1429210b9c1aff6fb358af406159ff2773181ce", 16) - g512x, _ := new(big.Int).SetString("b0543208dea7cf4a213340ea328fe41297a9adae0d846bdba6a63682164520e", 16) - g512y, _ := new(big.Int).SetString("11fc9d481c85491a1c76370c03abb451edaad8d165909fd8bcef0b0523ea1598", 16) - g1024x, _ := new(big.Int).SetString("24236c8ead13686698f502d88ced24d4a4f4d97d857f7a404dab22a7d7010281", 16) - g1024y, _ := new(big.Int).SetString("14f25da82adf5997cd262a35f883666cd8fb73558e864094f04cafd100d70121", 16) - g2048x, _ := new(big.Int).SetString("42075949fd411801cdb82e636cbaeba5913ee29901d9294e4ec8016fed7de8d", 16) - g2048y, _ := new(big.Int).SetString("18cd5594fbf0daec1813cbbe6752ec1fc46f951b26c19031466364b772f37f47", 16) - g4096x, _ := new(big.Int).SetString("1e55ddfd2bc59eed77164fe02d0232b3d497792ec225376f3c3f5ec2f731fcf9", 16) - g4096y, _ := new(big.Int).SetString("24b3e64690c93b37546abdc4ee90b916e2d3605eb218cf26ef5868d2b666072b", 16) - g8192x, _ := new(big.Int).SetString("133b598ecf07b15b4badc0af8b67d74f574a29c1ef79a426fe1271e235e61e00", 16) - g8192y, _ := new(big.Int).SetString("65bab42b71a49a87ea2b1e39d69612daf58372130af040f503b71b689ac9b8d", 16) - g16384x, _ := new(big.Int).SetString("15dab2550a7d9679f0a528cde54154b2d9ebd399a16691e13f3f28b17f72f7d6", 16) - g16384y, _ := new(big.Int).SetString("178ce9329c1a5914a6561c281c981810a1554be17533bf6e7ce5a03e18f67889", 16) - g32768x, _ := new(big.Int).SetString("145bc328b9b296659851f12d70e35a9ca48cbde2af8a8ad8c9f2b3e0dff32306", 16) - g32768y, _ := new(big.Int).SetString("29556d2e78ac6045e5dd6d555ec184c802c9e0599a8d5173103841caaf829633", 16) - g65536x, _ := new(big.Int).SetString("26e06be6332f9f22b10167247f35f7805a11658a38dbb75d480af28117a525c5", 16) - g65536y, _ := new(big.Int).SetString("5e492d706a927c51e6180228d8be86d15017d61160867d231101e2790e2f451", 16) - g131072x, _ := new(big.Int).SetString("173562ccf10ecd0d4fa859860fda7fbd91089fa60e69dc72fafdd35516ea77af", 16) - g131072y, _ := new(big.Int).SetString("2ecf52567da025409374e147a7e63641b341b7b0e90104d86688d1c244890fce", 16) - g262144x, _ := new(big.Int).SetString("1f2434b943605601a75d294aba1bf13f0ff5db8d7e0a3500b5f4c1bc41e786dc", 16) - g262144y, _ := new(big.Int).SetString("262db6caeadc85809eec6eaec5a25cf46cc7c753a1e28313321fcdbaab1c38", 16) - g524288x, _ := new(big.Int).SetString("3762e07278ae0306a4c00f906f8f2e4d59373bfe860160c0fd9c5e77c46be52", 16) - g524288y, _ := new(big.Int).SetString("25537898872f823d23934c27f897ad4f40773d14b4fd32bc0cde718aa9cb87b9", 16) - g1048576x, _ := new(big.Int).SetString("2cbfb0fe6c22c116187ef88cab54ae9612bca6cc0738379098e3f0c4a4ffe44d", 16) - g1048576y, _ := new(big.Int).SetString("18e367e3d08db17ce4fa3e487e6268c2ba168da6b239a84bf2ea8f2ff0f4c469", 16) - g2097152x, _ := new(big.Int).SetString("55c8d5787694c618d99a4a31e6b68173176fd3ee152aa0bc009e99279a9b348", 16) - g2097152y, _ := new(big.Int).SetString("cb17a49107a9cfbe06478a33ba7e48e279bb9904ee0d6681cc72edea5b984e9", 16) - g4194304x, _ := new(big.Int).SetString("1f4465d62aac0c486d54b87e00f9ea1454aea3f1b0807c471fc172383b0886c8", 16) - g4194304y, _ := new(big.Int).SetString("2fee931883b4bf0d0d2e303bc10317533e6c974d3d884f9315f8d78840e1363c", 16) - g8388608x, _ := new(big.Int).SetString("127b3ab3ee067a5c41553648568b7882ce8ced215bfa190979668b3bc81eb1fc", 16) - g8388608y, _ := new(big.Int).SetString("5e5a09c5ae9de4c0492a8033cf035672a55797cadfc1e6860aab21c32a78112", 16) - g16777216x, _ := new(big.Int).SetString("35b261363afc5e03923315a3dfdfbc2c932d94bc19320f3ab411a203df4b44f", 16) - g16777216y, _ := new(big.Int).SetString("57df51fa44deb6f13412a77fd4325aceec98dfe6036cf74c71a5675f7fe1342", 16) - g33554432x, _ := new(big.Int).SetString("154aceb2bad07cdc9e1e0239e75f74d2b63a297881f9adcb166edb88fe076f4c", 16) - g33554432y, _ := new(big.Int).SetString("2f7568bf2fa097d86b7858e8701480e26d6d42fc819858b2137a427ee5b9a1da", 16) - g67108864x, _ := new(big.Int).SetString("9a6e5836835dd5677aa892580f15382da285a1b1379a67fd54d21664fe5681d", 16) - g67108864y, _ := new(big.Int).SetString("29f5850d45dfc5f3126fd0da3ea2c23ae965655112b9c2771cf2e73a2861ac5d", 16) - g134217728x, _ := new(big.Int).SetString("2566879ca48921f6fe14df4d20d2f9e24024c9d438b131bc30b06efc35dee0f9", 16) - g134217728y, _ := new(big.Int).SetString("2ddf0f6cd3e69d0a018bb01bf69ede7299a90eb9e40ee68dc50fc1b57f42011f", 16) - g268435456x, _ := new(big.Int).SetString("8c4de3bb9284981741584663ff2b08ad9fea7b6fd7f867f558d768cab6683f0", 16) - g268435456y, _ := new(big.Int).SetString("f9c2bd3727428ed114cd7860e28daf81cb9cb7dcdd26bb704dcc13b4314dd6a", 16) - g536870912x, _ := new(big.Int).SetString("a9cfe416626f75b3be8249cbcb7f3732bc7601cf581f774ebea4254dd06a31e", 16) - g536870912y, _ := new(big.Int).SetString("2f37ade304c81412d4ae613bf6d46db48b794a815bffc4413fc4872fd3e54e15", 16) - g1073741824x, _ := new(big.Int).SetString("258872f55cb9b9d5085401f6dfd3ae97c4adf21c3f5a391ee055fbbd9dc4754e", 16) - g1073741824y, _ := new(big.Int).SetString("537cfe016384089d64f027080a6061dc147732e6cd9c5bc1818d20ccf9958cc", 16) - g2147483648x, _ := new(big.Int).SetString("1e46ffd3559b30f6d101a2b49be6d213a9c40979ce8cb6b3c30ac308259bb5f4", 16) - g2147483648y, _ := new(big.Int).SetString("8c2c33416234b10c20e4b8bf0a1c1af83b964df68eda56adf0dae561518f704", 16) - g4294967296x, _ := new(big.Int).SetString("8d1b64842bc402bf13683a6c6f35b5c3d20bc295b2b29547889abb503000938", 16) - g4294967296y, _ := new(big.Int).SetString("8dd9da05595bb2f247f8254c0b5c522610ef4ff6de3397d6a35c2cd57d5ff0a", 16) - g8589934592x, _ := new(big.Int).SetString("17ce741466bfe6b7ddd079fc1b829fc11c670ae647603cc16f07ec4ee9907076", 16) - g8589934592y, _ := new(big.Int).SetString("135c40e7ae971f4f02715e9eacfb0edd48544329e207dcd9e09e3a1d6a7ef9d3", 16) - g17179869184x, _ := new(big.Int).SetString("2560de7ec1fce358673f10c20b44ad547058e357b6abcad273e4de32f8901926", 16) - g17179869184y, _ := new(big.Int).SetString("1ce0ed3c1313830bbf40fe0d7843c66dc5a67680004df9bac115c39ad61a6434", 16) - g34359738368x, _ := new(big.Int).SetString("1d0ab19190a9eea7211606a352bc936d6605a190090ac0843a8beedb54bfcd60", 16) - g34359738368y, _ := new(big.Int).SetString("11013587e7511d4a0d9511b142867820cea6cb9c3d7a8db3ac3230521bfdbb98", 16) - g68719476736x, _ := new(big.Int).SetString("ce765d04f6147d2ec7fd6b47a674fe19734ba8732f9f5b2201fced57eac06d1", 16) - g68719476736y, _ := new(big.Int).SetString("17e32bc3032ce94020638e7d2ab3cb5ccbe6f0b06faf6821fa8e3e4401a5c5f3", 16) - g137438953472x, _ := new(big.Int).SetString("f4dc779722c9006a9c18edb82b48827e1620600ec0d8bf5ea38a9aff00b2fad", 16) - g137438953472y, _ := new(big.Int).SetString("85e58b989c3118da095b0e96fe2b07080d4a7a2c1e68b00de0a673d6ba338c1", 16) - g274877906944x, _ := new(big.Int).SetString("2732bbe06b941c9e2d5b43837d8c5d9c23b7d9e8d5e623427ff3b61f2f5a5a07", 16) - g274877906944y, _ := new(big.Int).SetString("2b591b8a3c2bfe17bd639fc6a77244aa8629abe4bee101a444e4f24f36f1cef4", 16) - g549755813888x, _ := new(big.Int).SetString("27e2e192f061b31a05a77bf2ef3197550a6a3d87137f94166ead6c6bc962dd79", 16) - g549755813888y, _ := new(big.Int).SetString("2d6ed80f66dcba2fa0170b308717dd966f6f290acbf61affd81681234c8c2c06", 16) - g1099511627776x, _ := new(big.Int).SetString("2b74bc4a2f94e7ee3305368999840142e80348e9464caef350c14219abe982ba", 16) - g1099511627776y, _ := new(big.Int).SetString("28ece478e5bef9a805431237214101dd7e42d6619d13344fb5f38cfca35be682", 16) - g2199023255552x, _ := new(big.Int).SetString("22c175e3c8487841f7e95a1448695383526f6b54fa1bd5dc08abc316e31e3517", 16) - g2199023255552y, _ := new(big.Int).SetString("149630c26a8011eff9ef41663b42cb704da419e23b884b7b24414a6561bff9ab", 16) - g4398046511104x, _ := new(big.Int).SetString("1b05155447aaa6fa1ea292a769950cfdbf195dabb8101a25902b5da432322076", 16) - g4398046511104y, _ := new(big.Int).SetString("10575afe16844a09fe4b002623c91f29e52bdebbe29e235f2090c39a930e8c2c", 16) - g8796093022208x, _ := new(big.Int).SetString("2a8577ed48db5ac9e9fa8dfa247f27b3e60d89f1827647685799666c97f1a833", 16) - g8796093022208y, _ := new(big.Int).SetString("902486bd83fd098aa054ffc4cb97ab085cc2f16ac36046994cc30a023107b1d", 16) - g17592186044416x, _ := new(big.Int).SetString("1d9a6be49fb8d2ac15dc3d5c94e14a1503ab0b3ca6a21cad875d6b1a79faa9ae", 16) - g17592186044416y, _ := new(big.Int).SetString("28026c4fe5e3beecfefcfc52d868ec17888e6b9e926ecfebea979f4da743e98c", 16) - g35184372088832x, _ := new(big.Int).SetString("732fab1b46a9d2f5d4e4c0ae76b33d747b97fd120d5a48b403368c0ca59e3e0", 16) - g35184372088832y, _ := new(big.Int).SetString("10ee4d49117fc0c55faee5550615ab0e2020d1cffe21a9138b45be3861386f7", 16) - g70368744177664x, _ := new(big.Int).SetString("1781ee986bd68597bf4d4d208c4288599de61e144c3bdc0400d099816411cd05", 16) - g70368744177664y, _ := new(big.Int).SetString("2ab3082b4ee85457502bfd2c20b89df4181ecd32aba9f00d68a92d8f081c1846", 16) - g140737488355328x, _ := new(big.Int).SetString("2ef769820679d51c8ad33309549d630a069c2e0bedd5f6408bc7932f8bd47fc8", 16) - g140737488355328y, _ := new(big.Int).SetString("6abd56e6a2300623d6945f2f2e965836e0ea9518549579ae5626fbee7a98b01", 16) - g281474976710656x, _ := new(big.Int).SetString("c56565b409d0661559f47150adb952432a186ba0c316d0360db359b32b7b05a", 16) - g281474976710656y, _ := new(big.Int).SetString("1d312504121f5a89e8abc692156492ab42ade35fbeef59b84a720513f9407f51", 16) - g562949953421312x, _ := new(big.Int).SetString("2bd2e4fcc5e329ac6859e2bed1443604639c50181b461499a1ff41d65948615e", 16) - g562949953421312y, _ := new(big.Int).SetString("c6b0aaf39ab436c4d8245cce97c862198c92af61bcfa8e260b78f8b3125609f", 16) - g1125899906842624x, _ := new(big.Int).SetString("111e14c693b4e2f022cd64a6fb0a9a2c30a43eb830af2d536d47d65e31621b35", 16) - g1125899906842624y, _ := new(big.Int).SetString("2556301d79a6b88a9ee4e0c6c7cbf32c998de755f5229cae477b9ae2a688f6ea", 16) - g2251799813685248x, _ := new(big.Int).SetString("61d62988ebd3a3a643e088f5a5117b03e3342eb44aeade5be5e769c8ec5471c", 16) - g2251799813685248y, _ := new(big.Int).SetString("fd8ed00f9e0d1a9b4ce715d06e3a592a38e60e80bc6102764a208f72bab79cb", 16) - g4503599627370496x, _ := new(big.Int).SetString("2bcb97abadf5cc9ebb2146867d6f7451db29fba33dfe8a34ab680dead115e00a", 16) - g4503599627370496y, _ := new(big.Int).SetString("8cf030bdc7a851154cdcd01609d064c93b03ad7808e8f306ab488261db73320", 16) - g9007199254740992x, _ := new(big.Int).SetString("1d174577a9c53cefd85d6bbbdcb5b8f292a884b26f0ea403dd10db43ed6f9a8b", 16) - g9007199254740992y, _ := new(big.Int).SetString("7bb9915573ee3bf341981f4905a2d96167e228b90c8d9dd430530574cf75899", 16) - g18014398509481984x, _ := new(big.Int).SetString("591f4466b7a4ba962d097beaecdb6bd8d17cbea3bd5fb9cc8e166322755869f", 16) - g18014398509481984y, _ := new(big.Int).SetString("1b1808e9fc843a9efe02f7493cecb95c608c316d4ed98f194003ca292a8bbe89", 16) - g36028797018963968x, _ := new(big.Int).SetString("33a47533babbe960c581d996a10c697efeecfcd62b36b6124f5d3c793348962", 16) - g36028797018963968y, _ := new(big.Int).SetString("2f7a4ff5aaa8a0e2cfca3a1401601a52b80aa7cba4991b380f429d26d940924a", 16) - g72057594037927936x, _ := new(big.Int).SetString("1425b11b4fe47a394dbfc0ad3e99dc93c3e1c0980b9bcb68529ba9de33dbf585", 16) - g72057594037927936y, _ := new(big.Int).SetString("168b8cdff7ae7d084fd111608fa03e018b415fd4f0755f7e8f039a2d852bda0e", 16) - g144115188075855872x, _ := new(big.Int).SetString("1281e1b4ae3aa4404c0181f688fecb6c0c4449ee646c0438702eab87f4b7dd1", 16) - g144115188075855872y, _ := new(big.Int).SetString("18d37f7e79d7dfdd82187cc71e706ebe6353499493e23fb8ae536e47db8ce60a", 16) - g288230376151711744x, _ := new(big.Int).SetString("3fd1c6811aba796990bec7a6e1c93456bc73bd41b090d6be589826e49b1ae21", 16) - g288230376151711744y, _ := new(big.Int).SetString("269f5d44435fd8dea26779b7f46c23b4bed44fa1d9863c9880f010959bb4aa88", 16) - g576460752303423488x, _ := new(big.Int).SetString("ec6fc4a5b4e315512f882a012443a460f0ad440410931b3d2f16125b5e08b17", 16) - g576460752303423488y, _ := new(big.Int).SetString("13d2044189630abd18c6a3d7dad67c97b771597be79693a5de68da0ffa2676d3", 16) - g1152921504606846976x, _ := new(big.Int).SetString("1fd5ddc117799eac4054d556ea4dd922ae145542d5524a29a0cad3ec7ec810e8", 16) - g1152921504606846976y, _ := new(big.Int).SetString("27bb413910ef0b9339d3262cde13e189d0b2e64f0c073fc81da5747676ca645e", 16) - g2305843009213693952x, _ := new(big.Int).SetString("2d1b7db11118809263c79240df010a2415abafca8d4248788158bfd6f2141969", 16) - g2305843009213693952y, _ := new(big.Int).SetString("75158f7b9c5890a51d5b46a86e6e3f04f20dc8cafca5e5c3772eb508e2390f1", 16) - g4611686018427387904x, _ := new(big.Int).SetString("2dd2737976a05341def306c8899cf11d24b52f3230f36b6cdbba3fb971cfde1", 16) - g4611686018427387904y, _ := new(big.Int).SetString("1a15e9c72c124e695b6fe0c535bc1c0265ec884cf74b53de358de6d5c956ed73", 16) - g9223372036854775808x, _ := new(big.Int).SetString("1df18f1f725582b96a446cd7fb021d67a357626fbc37e35599ed2d117359d294", 16) - g9223372036854775808y, _ := new(big.Int).SetString("2110263f391b92233267e75ec5641be7385da935a46f8cccd0698a584c70848a", 16) - g18446744073709551616x, _ := new(big.Int).SetString("457cafda1576b6f5fea6125056e6d52c4b01de7b44ae5aae162e83c9fe86928", 16) - g18446744073709551616y, _ := new(big.Int).SetString("16471c8dad2cb3ea4c4645d8b108abfb95fdb1c87485a1d78a3d158e529aaabc", 16) - g36893488147419103232x, _ := new(big.Int).SetString("a431193edb58abf0df45b4bbd6cfc43bf2e39093ec0fd195f3120344b3ac3a0", 16) - g36893488147419103232y, _ := new(big.Int).SetString("b1261fe08f29cc99a084cda6e12f384e7a11f3fa0f75dfcd21005d951fdfc2b", 16) - g73786976294838206464x, _ := new(big.Int).SetString("1542e37f2c64d816c9dde4cdfeff540680cc90b767294ba9937a0de230676b4b", 16) - g73786976294838206464y, _ := new(big.Int).SetString("1717efcb51f08cccdbfe3e4a2da92e000a45a3e3d9eb40f9b9a2041dcbf14d3a", 16) - g147573952589676412928x, _ := new(big.Int).SetString("f39f1ee90eb802366254bf2555173a1bd988e09f8c5ad7bebfdb8d14d88b064", 16) - g147573952589676412928y, _ := new(big.Int).SetString("2cbbd9234ab4f9fd74defb1512b86385b038ea5ae995449b813235e047876986", 16) - g295147905179352825856x, _ := new(big.Int).SetString("250a8a1b9edcecc5f25879262ef2962fdf8499f60e8131c6c33320fd8c98ed15", 16) - g295147905179352825856y, _ := new(big.Int).SetString("1924e2b0b5e2c49449c5ef9b62c2d01207e012a0bc70b219ab44f026ce7e43b8", 16) - g590295810358705651712x, _ := new(big.Int).SetString("239aee62596123c53859dc2937ea9257e52034311bb81519b7f45330c5c883da", 16) - g590295810358705651712y, _ := new(big.Int).SetString("151f09f672db228c74304a2f68f65a7b586f93913b97b6d7dfd638b99571b7f3", 16) - g1180591620717411303424x, _ := new(big.Int).SetString("1ec491fbe90a222adec9c417cd9c39393bf0e9fd4618f8688f20b587e10a92ec", 16) - g1180591620717411303424y, _ := new(big.Int).SetString("2ad8de9952064d982be63f71a172dfddc4daf430bb5c7a0c0d3a53ff776b8474", 16) - g2361183241434822606848x, _ := new(big.Int).SetString("2e5001cee2faa644502bbba6bf6b07e3b7cef0392326b48f300fc56f6982026e", 16) - g2361183241434822606848y, _ := new(big.Int).SetString("180e823c991af5044dde58a9e671fa092d3ba5db98cc7e0376dd079323f80764", 16) - g4722366482869645213696x, _ := new(big.Int).SetString("2715e750e68b52faa68b293da254e1b0049b5825804f4c2700adf08a0214e529", 16) - g4722366482869645213696y, _ := new(big.Int).SetString("3921d1862445f32fb5afe510e7c4e23f41e4bad15c090b1de77447950003fc9", 16) - g9444732965739290427392x, _ := new(big.Int).SetString("b4ae2be8e83c897e6d3aa46f67058f07e0d29edbe4eb1b6c1e325c737af51f7", 16) - g9444732965739290427392y, _ := new(big.Int).SetString("cea4f5b9bc8e843c26cd4e67da727fe9cd09ca8e07b60410602c63c3b0baee6", 16) - g18889465931478580854784x, _ := new(big.Int).SetString("252b5bf255b06eade647646139359221099916d1be9aa6a7edc3f7c9c6b3baa3", 16) - g18889465931478580854784y, _ := new(big.Int).SetString("12f7f9b3871cd66f99e976138eedc4faaec30a67ce3c67d867999ce814f7644d", 16) - g37778931862957161709568x, _ := new(big.Int).SetString("1977739937a75442ba424943233bb2ba55f9d4c62148285873a658581d5114ff", 16) - g37778931862957161709568y, _ := new(big.Int).SetString("178ee53b5e50cc2078544a9cbd11841c47854fe604388a5defeac56ce805bfe6", 16) - g75557863725914323419136x, _ := new(big.Int).SetString("e6581bf922d94d7079fa4b753f3ecedc525f516643a6bc894c5ab191fbf676b", 16) - g75557863725914323419136y, _ := new(big.Int).SetString("160642bdf146cc3f6630cfa5c115629055ab653c0e7f2414391f22b25d6720f6", 16) - g151115727451828646838272x, _ := new(big.Int).SetString("d4da3f9398685005d391d7c328ec8dc2ecab18c7d451901725375b1c373d860", 16) - g151115727451828646838272y, _ := new(big.Int).SetString("1609e3ec29efd4abf1629be26b772ef4b8490bcedfae621851e413e84c513135", 16) - g302231454903657293676544x, _ := new(big.Int).SetString("3a781e0964591a816d07c8d6aa23d23b2ad50ae3acc529f877abf4d13e3f35e", 16) - g302231454903657293676544y, _ := new(big.Int).SetString("20a1f12ea58910335687316cf47761991bad8f11e109095279c05e14b370c876", 16) - g604462909807314587353088x, _ := new(big.Int).SetString("2db5bda50b8b265684bb6e9c7af58513e9aa23abd3fa2a3cfc88dd057f90bef", 16) - g604462909807314587353088y, _ := new(big.Int).SetString("103c36bd9eb69b53205b7fae6224bb36b5a50451261cf87128953b489594b6d8", 16) - g1208925819614629174706176x, _ := new(big.Int).SetString("513dfdf79ca36c0d5e56de067033a42d9e13ce86f261d9081a2dddbdb88127c", 16) - g1208925819614629174706176y, _ := new(big.Int).SetString("2902f0ba36cac9e8a907ae91f2486316258b0b9b3b2c5262ab965004167bfa0", 16) - g2417851639229258349412352x, _ := new(big.Int).SetString("bd86fa4e2f2da10f54c62d2f996d7813d6548785f88386b0286ba719dc973a", 16) - g2417851639229258349412352y, _ := new(big.Int).SetString("2495aed3ff4e37c6d20a260f9847fe15d2bb5c2b788454bbb6e450effafa8bea", 16) - g4835703278458516698824704x, _ := new(big.Int).SetString("18f64e4337ef0a3732be36ca6cf72393b821fe4914ec78b311ca3a343ce7b15c", 16) - g4835703278458516698824704y, _ := new(big.Int).SetString("21c0913ede0f09b5920b629b891a95a30aed5dd6001eda274649363d1877da", 16) - g9671406556917033397649408x, _ := new(big.Int).SetString("46cc874785e387f35fbc3278c63a7d66e89f4642ab9056ec3d0b8d26eb21ec4", 16) - g9671406556917033397649408y, _ := new(big.Int).SetString("1b759ad99b33626516327fbebf9c232e0fca6555b084ee311f62366d7d5f86b7", 16) - g19342813113834066795298816x, _ := new(big.Int).SetString("64fcc679f04e762d783f5b39e9bc9832d06a6809d8c101a216431f1dc792cfd", 16) - g19342813113834066795298816y, _ := new(big.Int).SetString("216690982d703eb77e4ea5a7dd74c7c00fb98033d17ec825ca4950f6c40aeb80", 16) - g38685626227668133590597632x, _ := new(big.Int).SetString("148b2e63d2d3d87f364f35c47d7cf6c006506cf224aac6f208c559a2ed58d834", 16) - g38685626227668133590597632y, _ := new(big.Int).SetString("2727c32af57debc90f6fc9eb1607f72e8180068d6d12c02c38498ddf0a998506", 16) - g77371252455336267181195264x, _ := new(big.Int).SetString("213b9a87905003543236ff3eb6b232083378cd7a9eed91eb78f2c60fa85a3ad2", 16) - g77371252455336267181195264y, _ := new(big.Int).SetString("28e04e92b62096e8d23915d545982855c21be5b3a1193e6e34c43db01192453b", 16) - g154742504910672534362390528x, _ := new(big.Int).SetString("2a4825bea894ae814c1678bbff2fe7c99cd63a77a0c703b2825a5f19b2d98fad", 16) - g154742504910672534362390528y, _ := new(big.Int).SetString("2a127b6261bc7a4f6e76e082d980d0af0bd0f5e0fd9cdb342bf9bbb7694a929d", 16) - g309485009821345068724781056x, _ := new(big.Int).SetString("2257c2e4b41831dd8d36aaca1ab106c26c796f1c8e0a2998431f9d4125d740eb", 16) - g309485009821345068724781056y, _ := new(big.Int).SetString("7b7ed1edbb583f469367ae24bf8e49c1ff6731dfff4abf92e163e595187203c", 16) - g618970019642690137449562112x, _ := new(big.Int).SetString("a8d78ab8a1fb7388787eeca33f3fe251ae93f28ac1fef89dae84057b55436ff", 16) - g618970019642690137449562112y, _ := new(big.Int).SetString("1aef7bd255bab9ae1a74c2b7cb61cb0c22f8c6c0a7da5d9d4753779f9fc3d456", 16) - g1237940039285380274899124224x, _ := new(big.Int).SetString("1bca13199961ec30b02a2e464afef42ab60ef11b26573e11e22a1028afacd288", 16) - g1237940039285380274899124224y, _ := new(big.Int).SetString("ad9ff00a04b9cbebcd54d75a6db4c6042799d29bf0e0d0fae7438c89233850c", 16) - g2475880078570760549798248448x, _ := new(big.Int).SetString("6236320cf783a01e2b8be7816a84671de9e8bebda0e8f957809ee1253565bae", 16) - g2475880078570760549798248448y, _ := new(big.Int).SetString("a4ce1ac405b9974e4eaf9342c2a43bd1fdc4edc2bd18235249bf51ec4328744", 16) - g4951760157141521099596496896x, _ := new(big.Int).SetString("107a0928f1bbd09f3710ba91ea9d69152e2a2de8eb21984ec9caddb69ab37a8a", 16) - g4951760157141521099596496896y, _ := new(big.Int).SetString("28c0d2c1d2b4dd590537fa55a7838a2bbd7aa7f2c0e91b36927b731752c34192", 16) - g9903520314283042199192993792x, _ := new(big.Int).SetString("4c02961cf949cd155f736fdc4c29e4fe409c37994aef1b16cd170cc65b1b2ee", 16) - g9903520314283042199192993792y, _ := new(big.Int).SetString("a92da6a165896cdb685afb42e80bec10097bc2083bc938550706fc5bc355795", 16) - g19807040628566084398385987584x, _ := new(big.Int).SetString("165aabcf0d07544d16f06389ef1d3bd5ae9c4bdbb0f53065b64bc53346c75897", 16) - g19807040628566084398385987584y, _ := new(big.Int).SetString("9dbc96d154f3fb8324230033265a8d5a31c9b88b5104ca5f56c714ac2e6a534", 16) - g39614081257132168796771975168x, _ := new(big.Int).SetString("1bafc8265a8fb16e346e57060848c3ae00b0e2d8520ff8d287cd002705c4c1ab", 16) - g39614081257132168796771975168y, _ := new(big.Int).SetString("3a87183d670bf95439912a7fce6570c957a4d5ecaa722ed50e7d7c55dc55d0a", 16) - g79228162514264337593543950336x, _ := new(big.Int).SetString("1b5b281facfe95fb1144e0f7d0484d119ebe0dca0355e63ec70e5f94cd64e3e9", 16) - g79228162514264337593543950336y, _ := new(big.Int).SetString("10e9c2dfd3e452f067fc71c60a08200402f8f4e5e8dad63e462ba1597a20c615", 16) - g158456325028528675187087900672x, _ := new(big.Int).SetString("18dd61a6d1a9c55b35d048ffb667e7f05ee657481bdb86800e89aa48df541143", 16) - g158456325028528675187087900672y, _ := new(big.Int).SetString("147653157294e50892424edb123ca14f08ae7da80350b6ffdf582aa7a939e371", 16) - g316912650057057350374175801344x, _ := new(big.Int).SetString("24fe3fb77d48ea49e4c1b91c61b634dbd9525b20167226b19d7c603ac36c3d4c", 16) - g316912650057057350374175801344y, _ := new(big.Int).SetString("2a4768c15d9b9c746e253eb271b28afab89da5412565d93c6220a5b14cfba611", 16) - g633825300114114700748351602688x, _ := new(big.Int).SetString("119ba66c94aeb05b2309953c35df696ce195bf7d959770bb9b99ab944db0af91", 16) - g633825300114114700748351602688y, _ := new(big.Int).SetString("29c96c201b71f6540f084e2fb6d4eb8a52b940c0c5585f258aba521311b805d1", 16) - g1267650600228229401496703205376x, _ := new(big.Int).SetString("15856673ff5b68543c671cbe735d53376dcfea3eef0ec5fb3a1ae3c37f5683bc", 16) - g1267650600228229401496703205376y, _ := new(big.Int).SetString("12224ed590244e93f1c6b7abff01b64dac0bb8bf14ae8e3d825322b6623d082", 16) - g2535301200456458802993406410752x, _ := new(big.Int).SetString("253ea43ba2e8c14da0df002c96422fb3234310a5774d8ec6cc9c1796df1789ff", 16) - g2535301200456458802993406410752y, _ := new(big.Int).SetString("234267257e751a5fcebb1e295b774700fcc16b5f270ac8720f4376dbc18281b3", 16) - g5070602400912917605986812821504x, _ := new(big.Int).SetString("2825afe1d583957680db4456ece011c28a7a5e2021a69a1bdb69707d944268e4", 16) - g5070602400912917605986812821504y, _ := new(big.Int).SetString("2870101fe628a0d69a362a7f52d4f57093aceffa7aea51a4544c3033109a05f9", 16) - g10141204801825835211973625643008x, _ := new(big.Int).SetString("f29f472f3b04c24a5ed6675f5ff33720a10826fe53cef56b2c9313b2bd31523", 16) - g10141204801825835211973625643008y, _ := new(big.Int).SetString("2483c78fb7a925e79bf63bb20e9198e12b41429b23fe8e2ce29f91f1112159be", 16) - g20282409603651670423947251286016x, _ := new(big.Int).SetString("28b2e5fdc60e4fa83c1fb52db348434f08b850cc205f98431deea3e8fe209ad8", 16) - g20282409603651670423947251286016y, _ := new(big.Int).SetString("fe1ae72d3f07fef610c96a45cadf362c41f3f902b7b81a735b2a98333f54f47", 16) - g40564819207303340847894502572032x, _ := new(big.Int).SetString("2267c8d0582c04e9568e83bb9155fd9fac11d9c0672455f63fc14112297855da", 16) - g40564819207303340847894502572032y, _ := new(big.Int).SetString("1a13b6e83105beb7164721a03aa0635d2214c68c0ce68c5737ff618f02f62bcc", 16) - g81129638414606681695789005144064x, _ := new(big.Int).SetString("2a3e86af529fb07cadac27f9eb5683abbdacac22e8e55a4b96c61249cb3ce975", 16) - g81129638414606681695789005144064y, _ := new(big.Int).SetString("1eea66c26412cd33e47d7745aa76f7251efdd09bf220e09889675d9896bd1772", 16) - g162259276829213363391578010288128x, _ := new(big.Int).SetString("c5111956406a1ce31b50a0d90fdca236871c353e3f75250304b08cef557b588", 16) - g162259276829213363391578010288128y, _ := new(big.Int).SetString("2b4948845ae79d5803bc258bcd951d476247eb24ebe416a89ad8fd9f465fe8b6", 16) - g324518553658426726783156020576256x, _ := new(big.Int).SetString("2854ffc7b3e8214133feba8d6eb09b263690572a3022b7fcf2871ab9219cdbad", 16) - g324518553658426726783156020576256y, _ := new(big.Int).SetString("106de3acc6519fe5e79d178c2c86abded16f791c8ef4d9335d97862a68f5590", 16) - g649037107316853453566312041152512x, _ := new(big.Int).SetString("24c6a00e705db722a2952db86bbe7f08cac7b6c3b50d023f24a3de1ea736074d", 16) - g649037107316853453566312041152512y, _ := new(big.Int).SetString("dc43ed6b87676e8dd55e167471a55f2eef0968e310767659123e48b357903a4", 16) - g1298074214633706907132624082305024x, _ := new(big.Int).SetString("2644642ad942cfbd4736a0f7f18fc0197e029521ee087615e04a49e5f8fbb66e", 16) - g1298074214633706907132624082305024y, _ := new(big.Int).SetString("22b30468bd6abb89a23a5dce7e57ae96e25e0417937368f6760147af32c7a7ef", 16) - g2596148429267413814265248164610048x, _ := new(big.Int).SetString("139bc1dd75b831294bf28f4030675c0e05ab4f44f87a639b04228814b6cd5531", 16) - g2596148429267413814265248164610048y, _ := new(big.Int).SetString("18c670606f2e48d361c347c0219ae8e678759c0b22c01a1756b6b0e3c679ef33", 16) - g5192296858534827628530496329220096x, _ := new(big.Int).SetString("2699eb06108602cf13980e2b6e4f48c6d90f46de7eae60457e4d1019a4f3b9bd", 16) - g5192296858534827628530496329220096y, _ := new(big.Int).SetString("626c5f10d9f788ba433f2be9ac352b4298ecd2cea3cfff1e15e9d48fbaa113c", 16) - g10384593717069655257060992658440192x, _ := new(big.Int).SetString("1f4479f765ee101dfedcbb07e9033604da94dbbe5b781331484321af5b253dcd", 16) - g10384593717069655257060992658440192y, _ := new(big.Int).SetString("21623c9b390babf2397d31ca4af79148ad304a121ae5edc1723c994d2828f444", 16) - g20769187434139310514121985316880384x, _ := new(big.Int).SetString("2855725b3e68975ebe53642831ae4d5d2d7b4b137b95eb96e8151bc61f1bf053", 16) - g20769187434139310514121985316880384y, _ := new(big.Int).SetString("ca0e44e2fd18ec91840ccfe99c3049de88d1cb70c63633b7aa4416b92b0336d", 16) - g41538374868278621028243970633760768x, _ := new(big.Int).SetString("136dedcff58a79ef53df43747ab531ff7d38d5c7d2f7a6d652f57b415b808c10", 16) - g41538374868278621028243970633760768y, _ := new(big.Int).SetString("108956df051470607a649a39f14ea5cf95a904a406ca3123eebe60a0eb4300fe", 16) - g83076749736557242056487941267521536x, _ := new(big.Int).SetString("d744feede2a6bd63f61403043b33f81f56a61ae58c43e8b771ee0cf5f0dfdea", 16) - g83076749736557242056487941267521536y, _ := new(big.Int).SetString("7edb65778a0aa859b8947ef31e601c311b25aa1bd2a5ccc3225cac13bfc1d18", 16) - g166153499473114484112975882535043072x, _ := new(big.Int).SetString("23ecd41f06eb8051f907d416c36a9a6691dc87cc64de02261c7eacaf70b82beb", 16) - g166153499473114484112975882535043072y, _ := new(big.Int).SetString("caf2de20986119d958e6de7c3f6cd4f8b38645c9e59a12f46003aa5625c1edb", 16) - g332306998946228968225951765070086144x, _ := new(big.Int).SetString("15b08db406565282b6a0d3fc8022eadd2b61a559f3c92cc91521c45c6661a82f", 16) - g332306998946228968225951765070086144y, _ := new(big.Int).SetString("37803c869368190f0443820670330b14439832989f2345a36e5a48b2c59e543", 16) - g664613997892457936451903530140172288x, _ := new(big.Int).SetString("e1eca77e1fdfbc7a151ed32732cbbe093978b5d8724324d73929a30e58be078", 16) - g664613997892457936451903530140172288y, _ := new(big.Int).SetString("2e23a2f478eff00d8f0c0d7ec3c2c76467aeb2ca3d26ef49ed19ef1a8cccf8ff", 16) - g1329227995784915872903807060280344576x, _ := new(big.Int).SetString("e16c46d7f01cd14637900379058cde52352483f90eba6350dea325a183e4c8e", 16) - g1329227995784915872903807060280344576y, _ := new(big.Int).SetString("2bc5983fad220b58189c50be25b200c54e70d0529e3dc96decbe801f0420786f", 16) - g2658455991569831745807614120560689152x, _ := new(big.Int).SetString("1ecf556e4ea1a22b395060ed7c79a79ad9af43103b935caf9d410aaf61ce4e9a", 16) - g2658455991569831745807614120560689152y, _ := new(big.Int).SetString("1ac123a28245de45fd811267a8e343a1b035e77aca8b4614d09722caff12b0eb", 16) - g5316911983139663491615228241121378304x, _ := new(big.Int).SetString("1211f23e5e92c74a454701bf173aaf1ea12f7042e85859c468d94974eaad551c", 16) - g5316911983139663491615228241121378304y, _ := new(big.Int).SetString("165d5f2fff807855a18513ebdb932dee6bfcb8293383f7b7bc5196d737053f73", 16) - g10633823966279326983230456482242756608x, _ := new(big.Int).SetString("2b9fcf34bf541a48ec88d66cf5bfc89700211ae76a79551757dfc50f41288227", 16) - g10633823966279326983230456482242756608y, _ := new(big.Int).SetString("ced96282d5edc9cbc32b1c16e750da8cf3237e07e3625d85bedaecfcd12c9c4", 16) - g21267647932558653966460912964485513216x, _ := new(big.Int).SetString("2f9ea4e44871cf87cfa80f71560253dc13ab58f9728495fddb4b9bdd11628735", 16) - g21267647932558653966460912964485513216y, _ := new(big.Int).SetString("28dadee7c5d2a42cd524d8396f69ee363aa95f85c98c3c836004589b6d73084b", 16) - g42535295865117307932921825928971026432x, _ := new(big.Int).SetString("15530bd41a96a8a225db6640075aecd1884a06bbac5f98c51e5a487bfedc8d70", 16) - g42535295865117307932921825928971026432y, _ := new(big.Int).SetString("1c86da90e9556705a7476bff65b8f53425e3d129db8f179ad6e4b033e0495a20", 16) - g85070591730234615865843651857942052864x, _ := new(big.Int).SetString("da53ef60fd433fe0ee377bedc0e2f7239b514bba5caa80c52991c619a029559", 16) - g85070591730234615865843651857942052864y, _ := new(big.Int).SetString("1e1a37d1bf9f0eb8677bb0fd215c26cecfb350ad226f42d569bb040234da117e", 16) - g170141183460469231731687303715884105728x, _ := new(big.Int).SetString("25d8a9ba3266bd80af59395320e940663ab8c05932a4280b42bfcd0ec4f69d62", 16) - g170141183460469231731687303715884105728y, _ := new(big.Int).SetString("2fc95abfe6be50f1add78a03a9b4e60931ac358a132ad5ef5076c4894fb14aab", 16) - g340282366920938463463374607431768211456x, _ := new(big.Int).SetString("13b8fec4a1eb2c7e3ccc07061ad516277c3bbe57bd4a302012b58a517f6437a4", 16) - g340282366920938463463374607431768211456y, _ := new(big.Int).SetString("224d978b5763831dff16ce9b2c42222684835fedfc70ffec005789bb0c10de36", 16) - g680564733841876926926749214863536422912x, _ := new(big.Int).SetString("2d035cd6cd9ca06a9aecee6826e38a30dd6fa18a9f139179142782803a05e6a4", 16) - g680564733841876926926749214863536422912y, _ := new(big.Int).SetString("bcbe75d48af9e7d4a45ef21e0348411bdf99be154fcc82ecefc6cbab8157291", 16) - g1361129467683753853853498429727072845824x, _ := new(big.Int).SetString("1096e761836e74c5c654df817b4ace41e55cd812e97d2d0af5e2ea6f24dfd392", 16) - g1361129467683753853853498429727072845824y, _ := new(big.Int).SetString("21ff527613e48f4a5e3548af70ec2c1076b85506cf767aceb570ee83983ac6ce", 16) - g2722258935367507707706996859454145691648x, _ := new(big.Int).SetString("292c4a9ebfc080016a973ac9e24fb4b356c69db30308202a31d0bfb2e85443be", 16) - g2722258935367507707706996859454145691648y, _ := new(big.Int).SetString("2d378fef5d7b4b008da52d0c98bb8daa702109aa7d5da477107d9f9559dd6eab", 16) - g5444517870735015415413993718908291383296x, _ := new(big.Int).SetString("1d316fbe5c0ccef4caf35a917244ff619d92d4fbedc80b970205508e4b570595", 16) - g5444517870735015415413993718908291383296y, _ := new(big.Int).SetString("22b85bd410a73800d3610f05dea0bc7d82960d317602cf44bf77ad8f8f254f79", 16) - g10889035741470030830827987437816582766592x, _ := new(big.Int).SetString("2c961c9d2ad66f1049fdd0e8d7337e3449e8774836bb9981b56fc6e7385cd7e8", 16) - g10889035741470030830827987437816582766592y, _ := new(big.Int).SetString("6bd01a16056ed018b2394a0ec6897cfbeb20a18c606b0d78bc78d1d84a6b892", 16) - g21778071482940061661655974875633165533184x, _ := new(big.Int).SetString("2e8a8414affe97ed11410c27ac23b1f54b6a621ba39a9fd7f1685f9db88343a7", 16) - g21778071482940061661655974875633165533184y, _ := new(big.Int).SetString("1efbc6e7cb379b246ad9278606ea10b7c74f52769c615cd67b833c5016ac7db4", 16) - g43556142965880123323311949751266331066368x, _ := new(big.Int).SetString("2ed01ed41ec147ec1eba42d4b3c921568944e9a0d8a498706f99ec15d0ccc511", 16) - g43556142965880123323311949751266331066368y, _ := new(big.Int).SetString("1dcc8b5251aa1008c792ac420bc9be5f1870042d0210ff8ae96804ddffc721ad", 16) - g87112285931760246646623899502532662132736x, _ := new(big.Int).SetString("194c79506a89ea907a1e6777926f317f7231ea49bbde362689477b6ee04e9613", 16) - g87112285931760246646623899502532662132736y, _ := new(big.Int).SetString("26c94fbfb503010b9cac6a4b4e8e5fe29553e60128e05cdbf5546cb7bcb34d7", 16) - g174224571863520493293247799005065324265472x, _ := new(big.Int).SetString("277ac3a2889cea8febfa02110307c50b7d8da14e50adc4e86dc8d0aa73251dd", 16) - g174224571863520493293247799005065324265472y, _ := new(big.Int).SetString("17eb791abc2495f664ffb38442265281a6f9a91c6169ec5a6e7365dcd3c64871", 16) - g348449143727040986586495598010130648530944x, _ := new(big.Int).SetString("d3c84c79e806fda93ee88a7887b9daafa47969dad98217ab2bc82bdff4fbc25", 16) - g348449143727040986586495598010130648530944y, _ := new(big.Int).SetString("213f847ffc2eb33fbb7a5fe6f9e52d792095ffd8c8ebccc3caf9ecfd610cf1b2", 16) - g696898287454081973172991196020261297061888x, _ := new(big.Int).SetString("21d9001150f189e28d9e194e98bc5ac761eda5d600d7ef517983af606c5548b9", 16) - g696898287454081973172991196020261297061888y, _ := new(big.Int).SetString("1e2fff3d9cd1f421a57ff2dade55ab4ce3b4628a60480cce558d3a77b8fd5227", 16) - g1393796574908163946345982392040522594123776x, _ := new(big.Int).SetString("8c4343a41a1dae81a6276852d405acd87e81ff4b1d190482b5718a6e31a761", 16) - g1393796574908163946345982392040522594123776y, _ := new(big.Int).SetString("12b4ca0371b8ee1bd20a1d65277bab81e59f6e5ce60ccc6b82c722cc29d07fa7", 16) - g2787593149816327892691964784081045188247552x, _ := new(big.Int).SetString("2bf8fac78021ac7b2753b1ecb80fb30160b6b3250b5cf0ec9ad46f7801e759b8", 16) - g2787593149816327892691964784081045188247552y, _ := new(big.Int).SetString("2c0016acf87d3833c0fb9709392747265f4202151c050427b3b5913ff39de477", 16) - g5575186299632655785383929568162090376495104x, _ := new(big.Int).SetString("1cf7146b4c1d2ea113417938e790a96fe811cd3dfef48ddf27dcba7cd820f6cf", 16) - g5575186299632655785383929568162090376495104y, _ := new(big.Int).SetString("2a5ed72cbb62ac7046edfdcf9d1b47368fb3e2291e1e85e26c4e8cd35e401ef5", 16) - g11150372599265311570767859136324180752990208x, _ := new(big.Int).SetString("5e61bbcbc655464ba1fd215e04fcf949939de110f05722431cd5084968d6db9", 16) - g11150372599265311570767859136324180752990208y, _ := new(big.Int).SetString("13e15f844fa2767fac2daae3fb818e93cf95082efd681debb31574defacad671", 16) - g22300745198530623141535718272648361505980416x, _ := new(big.Int).SetString("34bf641f495a59e3d28dc3163a1c74aec7f7ef60030c8614c193f7ae2281a96", 16) - g22300745198530623141535718272648361505980416y, _ := new(big.Int).SetString("8b45e915673d26d8c5c5258a951fcf9b439d6833e12d2c301dc2eabe23e3f61", 16) - g44601490397061246283071436545296723011960832x, _ := new(big.Int).SetString("2960a0634103632555b7ed048b833d198c75536bdfce550988dea08d1b2a4b69", 16) - g44601490397061246283071436545296723011960832y, _ := new(big.Int).SetString("1f29d4cddfdbbb9a3aae3c862def08730c9563529b888e065f77604d012c194e", 16) - g89202980794122492566142873090593446023921664x, _ := new(big.Int).SetString("2bed31e2b3ee10fa9cfea431196db0b201587e2e68ee74dc466450053177c5fd", 16) - g89202980794122492566142873090593446023921664y, _ := new(big.Int).SetString("22c3f8fb3346540004df204600e2a60f2b5232a3fcce889962561e1c98a80146", 16) - g178405961588244985132285746181186892047843328x, _ := new(big.Int).SetString("d452f069c9eb613854442c5e9830fff0cccbb7a0c37bb8fa9a81c242933b54e", 16) - g178405961588244985132285746181186892047843328y, _ := new(big.Int).SetString("1c8331a53da629b28d02f6ba74b52caf67c4418e22fd6caf57d627e110451251", 16) - g356811923176489970264571492362373784095686656x, _ := new(big.Int).SetString("f055c21e2d7e8617b71babc6b770fc9a7ef74c3913fcf610d599414096b700d", 16) - g356811923176489970264571492362373784095686656y, _ := new(big.Int).SetString("1ebeb82f257db891825c55b2c909f0210dbe84616c0f5a867aa9f380a9171929", 16) - g713623846352979940529142984724747568191373312x, _ := new(big.Int).SetString("21907afebc2ecfb8c7c376a0db9958b35a6540103391efa541a28b82f472f48a", 16) - g713623846352979940529142984724747568191373312y, _ := new(big.Int).SetString("27c5a8cf6fa01b72d31ac50942838b8362d01e25c82b2d9c4a0f231441de4197", 16) - g1427247692705959881058285969449495136382746624x, _ := new(big.Int).SetString("205ba2fccb49fb5023e5114f84e961b9237b49ca8f5610bebb995b33ee249369", 16) - g1427247692705959881058285969449495136382746624y, _ := new(big.Int).SetString("b388977d2e0a8fc0e63a06375d9fe19fc7b798b8b0f2c8b0885920cb5bae45e", 16) - g2854495385411919762116571938898990272765493248x, _ := new(big.Int).SetString("2bb165ee76d92f26bdcbd9897c6519b8d89eeef2efc0c9521497068c735a54d2", 16) - g2854495385411919762116571938898990272765493248y, _ := new(big.Int).SetString("152704fe7afc78056ee79211313a0b23b71de06863c6102e0f8daefc0f2e85df", 16) - g5708990770823839524233143877797980545530986496x, _ := new(big.Int).SetString("f34d4d950bef2ee3b8e924b0183ca4e00aed6ea9209bc37c4e2202eb5bd7666", 16) - g5708990770823839524233143877797980545530986496y, _ := new(big.Int).SetString("d676a2dac5fcab3731af3283d9c22989889fad53465781a73ea5aa81274798b", 16) - g11417981541647679048466287755595961091061972992x, _ := new(big.Int).SetString("42fdcaca97128fd28b1ca4c90eaf39378d673af8d9f789d33b88c8284c1e4c7", 16) - g11417981541647679048466287755595961091061972992y, _ := new(big.Int).SetString("c5f60e7eaf108af711035a4ca219da7c7926c882d40373d76d9fc5dc05bf2d6", 16) - g22835963083295358096932575511191922182123945984x, _ := new(big.Int).SetString("15f74bf25691e3205d87c4ee7b798f00097551d1a14e732f8ec16be2c2b15424", 16) - g22835963083295358096932575511191922182123945984y, _ := new(big.Int).SetString("e917f31facef054212b2376c65779119a28cf490a506e66d48dd45117ba7cab", 16) - g45671926166590716193865151022383844364247891968x, _ := new(big.Int).SetString("8bd6a57ec62543e02f6fc7d0c3e832c7b7fc579d180a91071faa3d3ee9419d4", 16) - g45671926166590716193865151022383844364247891968y, _ := new(big.Int).SetString("1bc48805b6f1636fbb3fcd6da38aafead46d19c009893b19cbeeeae7937a68b5", 16) - g91343852333181432387730302044767688728495783936x, _ := new(big.Int).SetString("22d27fb14085110cb59094144fc0b73878d88c64957112740a8559878d34fc", 16) - g91343852333181432387730302044767688728495783936y, _ := new(big.Int).SetString("8e1197fb288dbdfc3c45e74c7362e8d24eb51a66e6f601e078713114be490f2", 16) - g182687704666362864775460604089535377456991567872x, _ := new(big.Int).SetString("1b9f573652906bd22ae891e98f72b280aa9f086974561858b06e57325bda14db", 16) - g182687704666362864775460604089535377456991567872y, _ := new(big.Int).SetString("12aec4b8476606d47b077de794be45c888600e94486a93b3560d82c80bc5f8a8", 16) - g365375409332725729550921208179070754913983135744x, _ := new(big.Int).SetString("2548e5ca7207fc244a56030fdee8726891f78b31b786050b01f535872604fef9", 16) - g365375409332725729550921208179070754913983135744y, _ := new(big.Int).SetString("40f0788fad8ef4eca110681d934bc1875cce24d4b79708f50c5c5ade76284e5", 16) - g730750818665451459101842416358141509827966271488x, _ := new(big.Int).SetString("8e2dcb5d0b19b7b0fd7b371bc43c5756f0377132cef98df0db4dd9eb393adca", 16) - g730750818665451459101842416358141509827966271488y, _ := new(big.Int).SetString("2fe5e5ea9fb4e811da5043de233b0b4e971da2dd38941c5033de0afe61e945b5", 16) - g1461501637330902918203684832716283019655932542976x, _ := new(big.Int).SetString("1d4f9e8484dadc0b72b38138caad649253a61a9bf5ad2d9afe7330bf839fcbee", 16) - g1461501637330902918203684832716283019655932542976y, _ := new(big.Int).SetString("9bb9bbafbfbf4038ee64e73ebbb0975db22edcd2d1c1c6e83eca2672fab780b", 16) - g2923003274661805836407369665432566039311865085952x, _ := new(big.Int).SetString("fdbf5656758cf6806e65b7800be3b7c039ed1fe181a0d4b50fabcec79f0df5b", 16) - g2923003274661805836407369665432566039311865085952y, _ := new(big.Int).SetString("173a2bd7eab80c0e2c4cf6abb5b659d289de53889c437ef553167ecfddad034f", 16) - g5846006549323611672814739330865132078623730171904x, _ := new(big.Int).SetString("f1ca7aa3dd35f558481ea63cf19d446200c77835c45c63954770ad12616dade", 16) - g5846006549323611672814739330865132078623730171904y, _ := new(big.Int).SetString("6e0f716d88e8041c0021dd736593a6a3fa501e33faa9a6510b71467d749498e", 16) - g11692013098647223345629478661730264157247460343808x, _ := new(big.Int).SetString("2eb10a9a90309b08dee4cfa8070265358c54b21572d914c9e8fd36a959304d24", 16) - g11692013098647223345629478661730264157247460343808y, _ := new(big.Int).SetString("3b4ec52766ad398c08539c6f8acb2b39874f0e0b994010efa873cfdf680a88c", 16) - g23384026197294446691258957323460528314494920687616x, _ := new(big.Int).SetString("1b94be21f1fb7228d3f3d44204f4f3cac13090d7c5c2af9ac82f0475f5cf39b4", 16) - g23384026197294446691258957323460528314494920687616y, _ := new(big.Int).SetString("27e9d41ef829511094b2af4473637e9375eda5f9e914cf55aac02d9b4a969755", 16) - g46768052394588893382517914646921056628989841375232x, _ := new(big.Int).SetString("25710e3a7246b1e76b8d6fbe6ff44afd9fd30c9585351398c15d050238d3c2d6", 16) - g46768052394588893382517914646921056628989841375232y, _ := new(big.Int).SetString("1c855e42168e00cd947df9d3a268f0db1f8e471f730ca88d84e1c2de7083e4d", 16) - g93536104789177786765035829293842113257979682750464x, _ := new(big.Int).SetString("2b144261f16985c75bff2b9d0796d0bbb63ba9c927669e3839710eea66a8efa5", 16) - g93536104789177786765035829293842113257979682750464y, _ := new(big.Int).SetString("2bb766bc6b62691154fab15cc24ce09d7d0a86f180f7cfc60b459ccfe2bc1842", 16) - g187072209578355573530071658587684226515959365500928x, _ := new(big.Int).SetString("26b93a6de603f0cb5900242713c98a4690d087ee2701f953c81f562a0bcf691a", 16) - g187072209578355573530071658587684226515959365500928y, _ := new(big.Int).SetString("1f275bb2c0d7f2e06d4d3d7718ad405914e62af9dd182c0f3d8cf5bd436ef483", 16) - g374144419156711147060143317175368453031918731001856x, _ := new(big.Int).SetString("f43e8a6e923598ab55483d1cb864aa57273dd9173b898daae6c753e403d80a5", 16) - g374144419156711147060143317175368453031918731001856y, _ := new(big.Int).SetString("14351ad715d016d31bfa656c62512aaeeaf2dcaf8918bb24b379cf035722757c", 16) - g748288838313422294120286634350736906063837462003712x, _ := new(big.Int).SetString("13971d545d04b5639a6bd48a583d0e02bd46b717ae6404589d09ddcf8e0e1664", 16) - g748288838313422294120286634350736906063837462003712y, _ := new(big.Int).SetString("d9e7a36118a844d63b5778975a157e06f444516a730e37ee575079115e1a51a", 16) - g1496577676626844588240573268701473812127674924007424x, _ := new(big.Int).SetString("2b6126f3432d0ab7149133ed284dc4b8f4c690a15d24a2012df8eafd1e584102", 16) - g1496577676626844588240573268701473812127674924007424y, _ := new(big.Int).SetString("2ffed8dfeba141fb9d2ec5f5c4ea602a5dda428b2adbb7fdb83dbfd3cbe3ea36", 16) - g2993155353253689176481146537402947624255349848014848x, _ := new(big.Int).SetString("f8ebff21f4475980919b8bf3a07e2bc3276c32aa8cc9be0d2b9e6ecda1eac62", 16) - g2993155353253689176481146537402947624255349848014848y, _ := new(big.Int).SetString("2d5d4034ffbc3503e76dbfaab4569192bdc22c3297c74cbfc9faa36a1b168a61", 16) - g5986310706507378352962293074805895248510699696029696x, _ := new(big.Int).SetString("f89469183d268e35a4e05882dbe1a6718f5246a18948c8bc421b21e2a1a8f90", 16) - g5986310706507378352962293074805895248510699696029696y, _ := new(big.Int).SetString("c501e43476b33ec702b4a4cb163b64b2077f52e73fa21cf24c1d31e96a88c87", 16) - g11972621413014756705924586149611790497021399392059392x, _ := new(big.Int).SetString("2a49dc5c6e7fe74ff00aaae703c26fe0916b22a76b66f11eb2f1c97a145c2fb9", 16) - g11972621413014756705924586149611790497021399392059392y, _ := new(big.Int).SetString("a3d9acd50d6e2f9032d7708ffcc17a60ba20f887efaf42856b039cbc0a32483", 16) - g23945242826029513411849172299223580994042798784118784x, _ := new(big.Int).SetString("195cdbddb30680997cfb2d5471c87c76f7cb4e61797ef85ec2c6f2d883b018f7", 16) - g23945242826029513411849172299223580994042798784118784y, _ := new(big.Int).SetString("1bf08f1d94d1eeb02f28b7a1ae77f739697de40b672743de45182203b0fa20e0", 16) - g47890485652059026823698344598447161988085597568237568x, _ := new(big.Int).SetString("19d00e5a8576bd737351c55095a19e59a94e4b7ebb3a505c54c194609719ff04", 16) - g47890485652059026823698344598447161988085597568237568y, _ := new(big.Int).SetString("139cd47baae2140ee687714a64063dbcd8ee9c5ba41e8abec89d55eee1018d16", 16) - g95780971304118053647396689196894323976171195136475136x, _ := new(big.Int).SetString("2f9e7f7800c6a9c653f48d4636d9dfad6e122c48c2ed4ad2e59551956563be7a", 16) - g95780971304118053647396689196894323976171195136475136y, _ := new(big.Int).SetString("2414da5e0cd90394bd984c6886c3b7fc7d34a8418cc6898578ec0540d1d3bd48", 16) - g191561942608236107294793378393788647952342390272950272x, _ := new(big.Int).SetString("2b2b8f5e7f644ee1c00937dc227da2e3de69762726d86036f4807b6aaae36c31", 16) - g191561942608236107294793378393788647952342390272950272y, _ := new(big.Int).SetString("47853a419bb6b761e2bf666d6ca8f90e93ec84a6e5b425d5b74daf76ef9ccba", 16) - g383123885216472214589586756787577295904684780545900544x, _ := new(big.Int).SetString("17b3259210a9a0e4339a3fe1caa896e56306745007e783373d47fe37c800b974", 16) - g383123885216472214589586756787577295904684780545900544y, _ := new(big.Int).SetString("1ad16b73e4b32f988f8d9eebbee03224fe7bcbabbceb02973cd2e159c3a58e35", 16) - g766247770432944429179173513575154591809369561091801088x, _ := new(big.Int).SetString("20be897f06fad7a92edf423db7ed12cb2bd2f6cb29c6bb8c6e394ff1aa3b3e9", 16) - g766247770432944429179173513575154591809369561091801088y, _ := new(big.Int).SetString("7958a3fec65b6df34911a018aac0fa72ce89d92ba4bc67dcd06d1b4db184b90", 16) - g1532495540865888858358347027150309183618739122183602176x, _ := new(big.Int).SetString("253eba1d7cf606254ed9cff7613788a6d055495b779d9947a9cf46b9c1da311", 16) - g1532495540865888858358347027150309183618739122183602176y, _ := new(big.Int).SetString("1cabc4e498a23c3f5fcfcb887629459666b7513ac8c70ee43be83a8b4f5c4090", 16) - g3064991081731777716716694054300618367237478244367204352x, _ := new(big.Int).SetString("85fad322fc02ef1cd3e8473c56c6a1a26ecabadccf845a914d79c83beeb318a", 16) - g3064991081731777716716694054300618367237478244367204352y, _ := new(big.Int).SetString("3146780190be66eb78f6d6a2150da305d044739434f4d56ddccd160dafd43b1", 16) - g6129982163463555433433388108601236734474956488734408704x, _ := new(big.Int).SetString("22c33c8c594bf804b9c5a96835ed929dc99711327d5dc3723bb2bcfbb56f7fc4", 16) - g6129982163463555433433388108601236734474956488734408704y, _ := new(big.Int).SetString("2bc57d10207ca4af29f3a0a8eb864d8989e89371936e4544626fb999bf7a4fe2", 16) - g12259964326927110866866776217202473468949912977468817408x, _ := new(big.Int).SetString("225fdab8fe6cd876363d27075cdf0d01c209da61b1634b574a5d811cfae40700", 16) - g12259964326927110866866776217202473468949912977468817408y, _ := new(big.Int).SetString("1216b7c3e2adc07c3bef31771c7bb9e1d02f07ff3a5b74953c4fd5bf9a7a6dff", 16) - g24519928653854221733733552434404946937899825954937634816x, _ := new(big.Int).SetString("2a365a9299da85372ee0455de645cc2330e4c315d6250e3c0c72f10d77ac40e4", 16) - g24519928653854221733733552434404946937899825954937634816y, _ := new(big.Int).SetString("e54618ec8951f6b8be014e3f3bd12802b037ac48c2d0fd983f2343c5759c3db", 16) - g49039857307708443467467104868809893875799651909875269632x, _ := new(big.Int).SetString("2f31ee57ec760885e1e943c7d1602bff848dfde5cea6a4edf03476ad213591cc", 16) - g49039857307708443467467104868809893875799651909875269632y, _ := new(big.Int).SetString("bebf1d735e3aba48854ada67731601a179cd76b2bb690e6aed56a2fd963e9aa", 16) - g98079714615416886934934209737619787751599303819750539264x, _ := new(big.Int).SetString("242a698649332113b115eb3982fa5e454576bc05886f71489a31113fd737feb8", 16) - g98079714615416886934934209737619787751599303819750539264y, _ := new(big.Int).SetString("2e98af3e21c2fb8ecacd092858dc5ea8671f81867d371c9b1a010801ced7ae94", 16) - g196159429230833773869868419475239575503198607639501078528x, _ := new(big.Int).SetString("de2dce497fc378cf9875ea34483653ad21b40050a2be9f32713978fad365b6f", 16) - g196159429230833773869868419475239575503198607639501078528y, _ := new(big.Int).SetString("18818ed119e67e54970494ba4f5c5feb75fb8047779f910713af5793062885b1", 16) - g392318858461667547739736838950479151006397215279002157056x, _ := new(big.Int).SetString("143a5a6a69b89a9baf10bab59c62ddf7a747a8439541febe0964e2ea6e35147f", 16) - g392318858461667547739736838950479151006397215279002157056y, _ := new(big.Int).SetString("ace7c02bcdb98ce30c3b6c4b9d399287ebc911e8d44226bab0c3f06c1e7e717", 16) - g784637716923335095479473677900958302012794430558004314112x, _ := new(big.Int).SetString("18a2a13576df7d0be0daa67eea762a6894fc88a47a4b5d26bf6af3c826c91677", 16) - g784637716923335095479473677900958302012794430558004314112y, _ := new(big.Int).SetString("fc68277f2370379225a32315a25607a6341a371091589edeabda88ecc3d2a18", 16) - g1569275433846670190958947355801916604025588861116008628224x, _ := new(big.Int).SetString("245ca02f753e3dcae81462215695192bb8de0ee8a3c195c1e2f735fb5510c791", 16) - g1569275433846670190958947355801916604025588861116008628224y, _ := new(big.Int).SetString("22dfa007006c664c55102bfd2a79e5e79d89f3947b9f4556dc1ad20b80ff74d6", 16) - g3138550867693340381917894711603833208051177722232017256448x, _ := new(big.Int).SetString("1ae696c232847d27e7b00f3ffeb36076d50514c4ee68bdcb08a892bce08f3ae9", 16) - g3138550867693340381917894711603833208051177722232017256448y, _ := new(big.Int).SetString("1396047d0e2300586624c149388740f5c00e7cf4a7213598d8ca634cb7df215", 16) - g6277101735386680763835789423207666416102355444464034512896x, _ := new(big.Int).SetString("2642b0d7d17b3ae1c6c1ddc1b018ecff936f658d2acc47474a330c8d6cd2d5f7", 16) - g6277101735386680763835789423207666416102355444464034512896y, _ := new(big.Int).SetString("af05ffe2aa2cf4f27db4fc64b9bdc681e15f4fc2bb57f6ce23e2e1f89003c72", 16) - g12554203470773361527671578846415332832204710888928069025792x, _ := new(big.Int).SetString("29d2b27d8d6db3791b3c64b2f61f5b2ab00d7f1ebc252cb97a9896a83c0e5d61", 16) - g12554203470773361527671578846415332832204710888928069025792y, _ := new(big.Int).SetString("12a4333add04e8aad8478e3046268d23ed55292a96d7921460ce3d1f52ce28c6", 16) - g25108406941546723055343157692830665664409421777856138051584x, _ := new(big.Int).SetString("252d6852ed68f5ff4420bf4ae9e5900a65fa7b2993dd3745e8dbceb436c5b94c", 16) - g25108406941546723055343157692830665664409421777856138051584y, _ := new(big.Int).SetString("21df15aafa8dbc395e66f7bbf004139eb5b5bc1bcc071d61b02096cabcdc010e", 16) - g50216813883093446110686315385661331328818843555712276103168x, _ := new(big.Int).SetString("1d115df69be93cf70619b0f005a92968a5ee561161a3dd3cc963c243447f391b", 16) - g50216813883093446110686315385661331328818843555712276103168y, _ := new(big.Int).SetString("1555da4cf093578bc7a49518f3a49a24f57760186fd02a3eec3749ec72cf7ad1", 16) - g100433627766186892221372630771322662657637687111424552206336x, _ := new(big.Int).SetString("2ad97c4b04758df61bf424363bd78665cbd24e20c13125ba2fc618312635a5db", 16) - g100433627766186892221372630771322662657637687111424552206336y, _ := new(big.Int).SetString("f6b80288f228ae9b8cbfdb06a1362c5b4a4fa81cff38dffb36585b871ad747d", 16) - g200867255532373784442745261542645325315275374222849104412672x, _ := new(big.Int).SetString("1385c47fcd92b51986c4ebf480519229ad13bb04255b24ffadf0d64a47c9c56c", 16) - g200867255532373784442745261542645325315275374222849104412672y, _ := new(big.Int).SetString("1b5e107ac4e88ba1f6fe66fd02dffa0211cf505d105647adf3ecbcd475e22840", 16) - g401734511064747568885490523085290650630550748445698208825344x, _ := new(big.Int).SetString("194ed40353d0e3fb0983152b872766ae5f1b4843ccdf294212a22af910755911", 16) - g401734511064747568885490523085290650630550748445698208825344y, _ := new(big.Int).SetString("267aff505f0d68a76ebcb094b24df86ec272309368b812af86fa0bf390d148a9", 16) - g803469022129495137770981046170581301261101496891396417650688x, _ := new(big.Int).SetString("2c87079e8db3eba1a27b14612b8f160b5a9452af0e76b942f61259a4119665cb", 16) - g803469022129495137770981046170581301261101496891396417650688y, _ := new(big.Int).SetString("a26589e75263127c006b16e4c34db58765013d73c48a13c269b75e0fc34dac5", 16) - g1606938044258990275541962092341162602522202993782792835301376x, _ := new(big.Int).SetString("4f1cb752254ce1c92b01b10a5af73b1854c2c62841dc824781caaa56ddb87f1", 16) - g1606938044258990275541962092341162602522202993782792835301376y, _ := new(big.Int).SetString("2511226c45e2074e814befca9728e74afcbe0a2dbb8da9b61497527f7dc16fc7", 16) - g3213876088517980551083924184682325205044405987565585670602752x, _ := new(big.Int).SetString("1726c1df54ad0c394c53dbb2daa6b525d5337201f18ce540686af4310676a873", 16) - g3213876088517980551083924184682325205044405987565585670602752y, _ := new(big.Int).SetString("1ec01458207da40eb3b8483934f1281939e93fcbf8727a81eb45584ed2a3f61c", 16) - g6427752177035961102167848369364650410088811975131171341205504x, _ := new(big.Int).SetString("226c0947127b57567bc20c26508a688b2361f752eafe0072c005e589d8b9ef58", 16) - g6427752177035961102167848369364650410088811975131171341205504y, _ := new(big.Int).SetString("2dcfd6b7a3cb9423a68ca27d4e288f84067d1bca27ab18fa9a7b1c3cdc0876c3", 16) - g12855504354071922204335696738729300820177623950262342682411008x, _ := new(big.Int).SetString("1144eed8752daad82ce8c81c75d13e91c2d8a1368d8b7aece378bdb8f553f7d1", 16) - g12855504354071922204335696738729300820177623950262342682411008y, _ := new(big.Int).SetString("4d8b0b771a46ff8f2e0c18454b643f8908a5b96da44713263eaa0e7609149cb", 16) - g25711008708143844408671393477458601640355247900524685364822016x, _ := new(big.Int).SetString("1e6c7691756045003fd35cf5d449f1bf0c68b45b34905abd5fbf2d944251616", 16) - g25711008708143844408671393477458601640355247900524685364822016y, _ := new(big.Int).SetString("2c808764b3c2d8ba8b949a9f00efb3bac79481195ca7e34a146e913aff89859c", 16) - g51422017416287688817342786954917203280710495801049370729644032x, _ := new(big.Int).SetString("2846b54c3b22668dcbb8cccaae457e53d8b6f5ccac2b48128fc73c254c5e59b0", 16) - g51422017416287688817342786954917203280710495801049370729644032y, _ := new(big.Int).SetString("276f519936be5b3e2f91afc073e810e20473b09e963be92fe55aa82400eb9cfe", 16) - g102844034832575377634685573909834406561420991602098741459288064x, _ := new(big.Int).SetString("9ba7fc0c9257b32d14ef83b0b43ee1b4c875d4ddb70a1f8dff121bb0738d5f", 16) - g102844034832575377634685573909834406561420991602098741459288064y, _ := new(big.Int).SetString("e3b10575559f366d81f1b0076b0f2a8e57c4d11d5daba688a1926e17f22054b", 16) - g205688069665150755269371147819668813122841983204197482918576128x, _ := new(big.Int).SetString("2c8474246fb806dfd385f8358e4fe95f68fae97018d7db1a3fe43b670197d296", 16) - g205688069665150755269371147819668813122841983204197482918576128y, _ := new(big.Int).SetString("2d8ac3b14579252521443a0709069529e88578810f1c6cf4167f595f17c301e4", 16) - g411376139330301510538742295639337626245683966408394965837152256x, _ := new(big.Int).SetString("1ce9e693f0718940f328281f33872bf77e5160c73c0a6068e8855e4716316099", 16) - g411376139330301510538742295639337626245683966408394965837152256y, _ := new(big.Int).SetString("869d2297c13d0e7ed693bb3ef7cf72bade1c34dc9936633b458571bf7231764", 16) - g822752278660603021077484591278675252491367932816789931674304512x, _ := new(big.Int).SetString("25ef45e9014757ee53971d76a5c50e5b57b3daee31af4be46c9cd3d7a382068b", 16) - g822752278660603021077484591278675252491367932816789931674304512y, _ := new(big.Int).SetString("286b42c7d1cfc3387bb75355b59eccccddc593ba7c375c5ac7e8286ae03843e0", 16) - g1645504557321206042154969182557350504982735865633579863348609024x, _ := new(big.Int).SetString("19bab36be51f69ef46db70c779126dadf51c2c4e31ed48a1623cebdce336b5d4", 16) - g1645504557321206042154969182557350504982735865633579863348609024y, _ := new(big.Int).SetString("2854d9e8b595428c2accef0239bd031a4a2f37d751f1a992daf66e653b585686", 16) - g3291009114642412084309938365114701009965471731267159726697218048x, _ := new(big.Int).SetString("1cbc558d34b723ebfa07c9630c96e81c74576d141801165e4710b5b0262c84db", 16) - g3291009114642412084309938365114701009965471731267159726697218048y, _ := new(big.Int).SetString("2d4d9bfe1a7006a4eaf94fd681f467719a68a8231b6b46b496601a34cd8749ee", 16) - g6582018229284824168619876730229402019930943462534319453394436096x, _ := new(big.Int).SetString("22e1b18187f92eab791a18a17bae522f674d76efd8c7188a18c9397350d25421", 16) - g6582018229284824168619876730229402019930943462534319453394436096y, _ := new(big.Int).SetString("ad500831e4522a7fe456bd44967dbb8f56b3a7f36ac51ae95c3cbebd4e0ca7f", 16) - g13164036458569648337239753460458804039861886925068638906788872192x, _ := new(big.Int).SetString("6b3c6bec4d1982470c5f1a033e43fca9cf142639d8d8c1e08e0390a4c5a7da4", 16) - g13164036458569648337239753460458804039861886925068638906788872192y, _ := new(big.Int).SetString("1de78da2ba6a6e08b0b7f5a22bd59fe91abc05909196640e50e1d21741a4286d", 16) - g26328072917139296674479506920917608079723773850137277813577744384x, _ := new(big.Int).SetString("18afa4a6bf750334eac73d2f93349a25819827c4f2e3b42ce8144f0c090e1b12", 16) - g26328072917139296674479506920917608079723773850137277813577744384y, _ := new(big.Int).SetString("2bde7825dce391b931ca81ee1139e6d76760072c81ba53dd2db24ddc28694e92", 16) - g52656145834278593348959013841835216159447547700274555627155488768x, _ := new(big.Int).SetString("28234f55a1ef2d10c29341f59be69a2090c49b57bbc64a58809d4d4b9a050326", 16) - g52656145834278593348959013841835216159447547700274555627155488768y, _ := new(big.Int).SetString("f0d1a871d0f58ae80723f19adf08b8b04a9b11a1f0fb7c38c1dfb3b830939ab", 16) - g105312291668557186697918027683670432318895095400549111254310977536x, _ := new(big.Int).SetString("1f87eb4ecf4979737f4ce5493a5d744349f50675c1e169bbf31689c3e8c04308", 16) - g105312291668557186697918027683670432318895095400549111254310977536y, _ := new(big.Int).SetString("23d45d0cc26f83da885d957417f958f48d15afe583412df36ff2c46b0fae6198", 16) - g210624583337114373395836055367340864637790190801098222508621955072x, _ := new(big.Int).SetString("265fe341276ba4ef03a3e1632e3eacc3c77af43355915017604e3297a2575e0d", 16) - g210624583337114373395836055367340864637790190801098222508621955072y, _ := new(big.Int).SetString("2d96ebc6d29672f1fc80d5f711efc24b099d9e5805d6052db96dc6bfe58e8516", 16) - g421249166674228746791672110734681729275580381602196445017243910144x, _ := new(big.Int).SetString("20adf422bb92e8ebca244338030fff6e5750b73e3b59bef4cf27f9b8b43d86cc", 16) - g421249166674228746791672110734681729275580381602196445017243910144y, _ := new(big.Int).SetString("46d604bb8ba0f91062a910941f8640c12fee8aed73e49f47364de3375b82881", 16) - g842498333348457493583344221469363458551160763204392890034487820288x, _ := new(big.Int).SetString("1b8b0974839d00fcb8ce8411303de0a7c1eb3a4fee51cfc81bc5555cf11e72d1", 16) - g842498333348457493583344221469363458551160763204392890034487820288y, _ := new(big.Int).SetString("10f9785ecc740f71e35ac4bb5667d868c7e0f41d7ac008fe1002b98c74a13550", 16) - g1684996666696914987166688442938726917102321526408785780068975640576x, _ := new(big.Int).SetString("17804f51d82ccacb1f5c235f9229729042bba8586cf4439b4da2bf3ce9e3c6b4", 16) - g1684996666696914987166688442938726917102321526408785780068975640576y, _ := new(big.Int).SetString("4f911ef9571ad0f05275041c06fb56dd3ae9d6ca9faf59a98329140274dd0e3", 16) - g3369993333393829974333376885877453834204643052817571560137951281152x, _ := new(big.Int).SetString("2fcf22a313b481313f27289a45680aaf8805fe788fbdea9964bee963b47bbd6", 16) - g3369993333393829974333376885877453834204643052817571560137951281152y, _ := new(big.Int).SetString("29a1c6fa0c3cc610d930ef1748fecc57aae4d9b73762168af70432d5300acc6c", 16) - g6739986666787659948666753771754907668409286105635143120275902562304x, _ := new(big.Int).SetString("19d7f00e9da0ff3c5e36640d537dc9d8b297918680f8ef92ec5fb5c237e71d94", 16) - g6739986666787659948666753771754907668409286105635143120275902562304y, _ := new(big.Int).SetString("2b1aaab94d44134f97e647d973ec4f5db5627e6fd219f3f3f1e08f487f0b088e", 16) - g13479973333575319897333507543509815336818572211270286240551805124608x, _ := new(big.Int).SetString("1f84c3be21eedc0a6f3a0e8ed81866d2517d1ee09fb86a51601354cbc282c9ae", 16) - g13479973333575319897333507543509815336818572211270286240551805124608y, _ := new(big.Int).SetString("8b172a26e838681d0c4d3cfb013abf392141ee2f871903f94966ab2e7c67995", 16) - g26959946667150639794667015087019630673637144422540572481103610249216x, _ := new(big.Int).SetString("1803f42b6154c73df3776a86da598b72c820e0a39058a6272c97ec432746a253", 16) - g26959946667150639794667015087019630673637144422540572481103610249216y, _ := new(big.Int).SetString("11e4372b105bbbc4ee89496343eddd5f299ca4199190455953e6a4d5d0331172", 16) - g53919893334301279589334030174039261347274288845081144962207220498432x, _ := new(big.Int).SetString("13b103f06dec9eb67eeb1252f52e8ff88c2164c330742569ba6c0c1d79b43d58", 16) - g53919893334301279589334030174039261347274288845081144962207220498432y, _ := new(big.Int).SetString("24983f8c5d29be49c03a61673aa24b73b20f790d821a1832b61276203854ed41", 16) - g107839786668602559178668060348078522694548577690162289924414440996864x, _ := new(big.Int).SetString("2e1389cf976ee7d9ce2992c62c6bbd5268b1096f6e89c6870c25a4737c154fd4", 16) - g107839786668602559178668060348078522694548577690162289924414440996864y, _ := new(big.Int).SetString("2026565add482c9e333bf0f03cc1a0e6de8a45e2fcc79f298f1588852ebc239b", 16) - g215679573337205118357336120696157045389097155380324579848828881993728x, _ := new(big.Int).SetString("27816d71c08ddc593972e5d647880eb1c9fba52ddc130629a4867ec559903e7a", 16) - g215679573337205118357336120696157045389097155380324579848828881993728y, _ := new(big.Int).SetString("2d4342a5b94a716d13ddc4e034263d2526fa8f9dc4672b0490d326a0b2c24104", 16) - g431359146674410236714672241392314090778194310760649159697657763987456x, _ := new(big.Int).SetString("3e8748e8aa834f74f78325f4cade8beb5b2cd987e003dd2e01ca1e507b882ea", 16) - g431359146674410236714672241392314090778194310760649159697657763987456y, _ := new(big.Int).SetString("14e84a9b617bc3bbc51c7580aed6af624f108084aaa51c57c0f6bb42966a06e3", 16) - g862718293348820473429344482784628181556388621521298319395315527974912x, _ := new(big.Int).SetString("2e0333e017005d5580d8f37930910e83a4ec1cbb81513d5c4497e07bb4759ac3", 16) - g862718293348820473429344482784628181556388621521298319395315527974912y, _ := new(big.Int).SetString("2efa0d2056e33484bfd0d28038a697b52071ae3daad55e734c4f1788be4e26e0", 16) - g1725436586697640946858688965569256363112777243042596638790631055949824x, _ := new(big.Int).SetString("66dd4f74bde89af1e484ee7999209deec62204f6fadfe137a007bd1b8a41322", 16) - g1725436586697640946858688965569256363112777243042596638790631055949824y, _ := new(big.Int).SetString("1fafe097739d80d7254bcb0604d47a42a19606e61a5c9464b74c343740615c6d", 16) - g3450873173395281893717377931138512726225554486085193277581262111899648x, _ := new(big.Int).SetString("d3abc9d71dd3d76ec536fdd34c3d535ccd3b2c92e344b04ea63e7a95bf1d40d", 16) - g3450873173395281893717377931138512726225554486085193277581262111899648y, _ := new(big.Int).SetString("4e2d118cd7c19f8b38b28570d982bdf9398ec57fb2bb0d7e8f31e4c8ea3a7e", 16) - g6901746346790563787434755862277025452451108972170386555162524223799296x, _ := new(big.Int).SetString("17a6c2b336d61bf255af78c33a67cf1de2896995df7e83f8241109a184dbbea7", 16) - g6901746346790563787434755862277025452451108972170386555162524223799296y, _ := new(big.Int).SetString("123d241884de16c8078118cf8168546668a7c354c1aadc61505121f1c69318ee", 16) - g13803492693581127574869511724554050904902217944340773110325048447598592x, _ := new(big.Int).SetString("a86bd18c2e2dc328a7fff99345d131988bdb003f53487da1d9affd07dfa4caa", 16) - g13803492693581127574869511724554050904902217944340773110325048447598592y, _ := new(big.Int).SetString("270232b8aa979307cef134be75f5d025d01c3c6ba2f66499e3615e5b2dd00781", 16) - g27606985387162255149739023449108101809804435888681546220650096895197184x, _ := new(big.Int).SetString("1e355fcab47dd4264a85652319a0dddf1ba3889eaaa9e05f21247e4202bda1a5", 16) - g27606985387162255149739023449108101809804435888681546220650096895197184y, _ := new(big.Int).SetString("d60a88eb2f714752b7aecdeb65939828faa6e1e38e8ea1606a7a15e71e7a194", 16) - g55213970774324510299478046898216203619608871777363092441300193790394368x, _ := new(big.Int).SetString("1eb1ba9d3cb37f1e320b57a13707f1b4b40333e1d9893d2d9c6012f5667001c9", 16) - g55213970774324510299478046898216203619608871777363092441300193790394368y, _ := new(big.Int).SetString("c1dea44b0e7ba28967fe607c50f983c3bdec527612e81245029958308f7cbbb", 16) - g110427941548649020598956093796432407239217743554726184882600387580788736x, _ := new(big.Int).SetString("dcd731a87dfac8e27719ecbe1098c415477febd6f06a227fb45f0b8b0b16d9", 16) - g110427941548649020598956093796432407239217743554726184882600387580788736y, _ := new(big.Int).SetString("27218920b62eb55167704aa95c9929a79ead041e57e1f26d5f2b3affa474655b", 16) - g220855883097298041197912187592864814478435487109452369765200775161577472x, _ := new(big.Int).SetString("3058fe52fd5ea77191aba39e84854d7d3f317390b1d869536d81544fad1a7e7f", 16) - g220855883097298041197912187592864814478435487109452369765200775161577472y, _ := new(big.Int).SetString("1f64fd77c47fad6766218a0ca3e9b34b6207ed59f8eb2f902e1548d156584a90", 16) - g441711766194596082395824375185729628956870974218904739530401550323154944x, _ := new(big.Int).SetString("1b5956deed90482c1cc4989e936ca265252d6dd8159a13270b78248b30843363", 16) - g441711766194596082395824375185729628956870974218904739530401550323154944y, _ := new(big.Int).SetString("72ff5f961d1d225dec43bffd5f031562c9087a3a032305b1b716cdd158da5ca", 16) - g883423532389192164791648750371459257913741948437809479060803100646309888x, _ := new(big.Int).SetString("1ee79768b58b0bbebf614d41fcfd9e17a88c38b41d697a2104a931a3cf3106d6", 16) - g883423532389192164791648750371459257913741948437809479060803100646309888y, _ := new(big.Int).SetString("2ac2a26c534a3a84f696dd581ee7063f8910ca58954e436470d1fcc17dbbaad2", 16) - g1766847064778384329583297500742918515827483896875618958121606201292619776x, _ := new(big.Int).SetString("13932be07d7ef64690655fe3541d25b47caa20f0dba7e5843dc309e47fd4036", 16) - g1766847064778384329583297500742918515827483896875618958121606201292619776y, _ := new(big.Int).SetString("68daa9f3433ea9cfe8ab217593263464d3f3796d224d0c837ceb1ba5a388b5c", 16) - g3533694129556768659166595001485837031654967793751237916243212402585239552x, _ := new(big.Int).SetString("28982c2db4c7cc3f0ac38ae0d7a1774e276872fc2fc9be7b97038d1b7deeadad", 16) - g3533694129556768659166595001485837031654967793751237916243212402585239552y, _ := new(big.Int).SetString("fcd19a4ed741eac34e323909b7407f5a612a101c0d5687ea381bd36fd92d2c", 16) - g7067388259113537318333190002971674063309935587502475832486424805170479104x, _ := new(big.Int).SetString("233baee1bae9440f6456b6172b7b08e3b659265362d198e5196ef41d3a2d4b5a", 16) - g7067388259113537318333190002971674063309935587502475832486424805170479104y, _ := new(big.Int).SetString("2eae64ae6c81702e537c49c50c434556a49e9c734bf59580c86f19f2a0fb3374", 16) - g14134776518227074636666380005943348126619871175004951664972849610340958208x, _ := new(big.Int).SetString("2d5968f58c658153ee254d4bded6784e5e057251477b539a6d91f087985338ea", 16) - g14134776518227074636666380005943348126619871175004951664972849610340958208y, _ := new(big.Int).SetString("e0d8224d8090e8f7958bf46ea5f8d2d02370bbab1f4a449e50fee36e3f70773", 16) - g28269553036454149273332760011886696253239742350009903329945699220681916416x, _ := new(big.Int).SetString("282ba63c4d8d5c9d2477af22fa57cbb3618501dd22727c2a3244988179c98d2d", 16) - g28269553036454149273332760011886696253239742350009903329945699220681916416y, _ := new(big.Int).SetString("17957e0d498bd3694c8e62242bc37535cd445bf2a773ad9443cb3771fe113854", 16) - g56539106072908298546665520023773392506479484700019806659891398441363832832x, _ := new(big.Int).SetString("156e5523efb7270e38e80e154849f705a6184365b2261f3db870014428425d83", 16) - g56539106072908298546665520023773392506479484700019806659891398441363832832y, _ := new(big.Int).SetString("2a5e19cd3faf740e1f3ec427897c8da2804b0479bad28ce00ae15b088b04038b", 16) - g113078212145816597093331040047546785012958969400039613319782796882727665664x, _ := new(big.Int).SetString("7edfbd9cb99499052ada8d94e740625888f260adc45fcb5fe9be555b3221d74", 16) - g113078212145816597093331040047546785012958969400039613319782796882727665664y, _ := new(big.Int).SetString("1fd8c3a97911b6eac726e002fd3b84eceaa2b08a57e3df4227067fb5896aaed0", 16) - g226156424291633194186662080095093570025917938800079226639565593765455331328x, _ := new(big.Int).SetString("1725b4a59ea736ec816444dc53dbdf7e78d9194d537fa199c2883a38c60a06ed", 16) - g226156424291633194186662080095093570025917938800079226639565593765455331328y, _ := new(big.Int).SetString("249e0d5a519ef3f2ab6240aba00e912927ad4151be494765e2e31a1566828b06", 16) - g452312848583266388373324160190187140051835877600158453279131187530910662656x, _ := new(big.Int).SetString("5483b9dfbeb5b9fb31fd52b885335da4b23cdf83f2607d37e3fcbe112a85365", 16) - g452312848583266388373324160190187140051835877600158453279131187530910662656y, _ := new(big.Int).SetString("24e0ba9901789eaa6a0dc74bbf22debf9891bc5c03991db95f69df9c25ca6fcf", 16) - g904625697166532776746648320380374280103671755200316906558262375061821325312x, _ := new(big.Int).SetString("65a6b8b56220596ad72f24aea44c1d62f4c1544f23d4e968112d3d57f76c9b5", 16) - g904625697166532776746648320380374280103671755200316906558262375061821325312y, _ := new(big.Int).SetString("2d8d82657d6f9f9d5676cece3b7547be1b2ab34879690cd1d231716891525cf7", 16) - g1809251394333065553493296640760748560207343510400633813116524750123642650624x, _ := new(big.Int).SetString("21f2133247ee84c3bd8c96271b6ad6482744b3367a13f0260535a908caea1d20", 16) - g1809251394333065553493296640760748560207343510400633813116524750123642650624y, _ := new(big.Int).SetString("85b3a99f7d8418907dc897428443fae817137980fe5195974b11d212c6f2171", 16) - g3618502788666131106986593281521497120414687020801267626233049500247285301248x, _ := new(big.Int).SetString("29eed773adae30e41534a519179a5193ace5c32048775a50d6e1a7f998c5636b", 16) - g3618502788666131106986593281521497120414687020801267626233049500247285301248y, _ := new(big.Int).SetString("187868b2ac41a139f3563229e0ee02d65d27e38de3276ad2a4fd503c4f920010", 16) - g7237005577332262213973186563042994240829374041602535252466099000494570602496x, _ := new(big.Int).SetString("ebf18cffd536c5521028aeab7afb898bf91d8abde80f16a70ab404b49dde064", 16) - g7237005577332262213973186563042994240829374041602535252466099000494570602496y, _ := new(big.Int).SetString("2558d4421ddf231cf775888494c86ac8883a92df8b171dbc7e0f26978c2f1533", 16) - g14474011154664524427946373126085988481658748083205070504932198000989141204992x, _ := new(big.Int).SetString("9a5c6756cfc787c9df52f40fa211edfed26f0303bb2e404fa53d486a8ec7963", 16) - g14474011154664524427946373126085988481658748083205070504932198000989141204992y, _ := new(big.Int).SetString("28e47c414278b7f61d2e58077a5d6f12ebcd88950385108a733284e2861b8f81", 16) - g28948022309329048855892746252171976963317496166410141009864396001978282409984x, _ := new(big.Int).SetString("3d541efe3a8777fd5cd6aea697dc2f83706644289adaa9380e68bc150476b0b", 16) - g28948022309329048855892746252171976963317496166410141009864396001978282409984y, _ := new(big.Int).SetString("23fd426daa5672681e63f3c44963a131182ea5f8b9dffc4e4067f321b77648a2", 16) - g57896044618658097711785492504343953926634992332820282019728792003956564819968x, _ := new(big.Int).SetString("18ba548c687cb306f9996e95ebff7530528177141ebd26680d2d994ea1f5b4dd", 16) - g57896044618658097711785492504343953926634992332820282019728792003956564819968y, _ := new(big.Int).SetString("1a34ebd78433b90b62760d37f89ae069a85651a109939e329a4f266ce94c9d64", 16) - g115792089237316195423570985008687907853269984665640564039457584007913129639936x, _ := new(big.Int).SetString("1d78954c630b3895fbbfafac1294f2c0158879fdc70bfe18222890e7bfb66fba", 16) - g115792089237316195423570985008687907853269984665640564039457584007913129639936y, _ := new(big.Int).SetString("20481b2bf7a68cbf47d796f93f038986340f3d19849a3239f93fcc1a1192aff1", 16) + g2To3x, _ := new(big.Int).SetString("8b1d51d23480c10f472f5e93b9cfea88238c121fe155af7043937882c306a63", 16) + g2To3y, _ := new(big.Int).SetString("299836713dad3fa34e337aa412466015c366af8ec50b9d7bd05aa74642822021", 16) + g2To4x, _ := new(big.Int).SetString("17f485337f6e10fca0e385f7a93d1ac0a977e43995c3e4d9b8f89daa6a183f44", 16) + g2To4y, _ := new(big.Int).SetString("5ccdc1561db963516da62c66edd39d1bb9c6c4674990c4440403c88025c95ad", 16) + g2To5x, _ := new(big.Int).SetString("ac610b573e9fb98deaf5aa48feb447536418ddc4cefd17c277c852a2a02a413", 16) + g2To5y, _ := new(big.Int).SetString("1940e395f5eeaaf3b73a54a9db9910c3b7f907cad7f55137fb0c3847a682d315", 16) + g2To6x, _ := new(big.Int).SetString("6b7c24035a06c42bcb47d54df4104cd8880f68263afce13250ecc65f7669d1e", 16) + g2To6y, _ := new(big.Int).SetString("2179e38c6e6341d1c80b4ed2ad6d43188c01c2f70a8093b37fc02f9fd9e5f12f", 16) + g2To7x, _ := new(big.Int).SetString("2295215c9285bdc4f6beefdeccc5ccb67bbb9959f05f4c2a716a8f442fa69498", 16) + g2To7y, _ := new(big.Int).SetString("10174283cbb851eaf5f64a278b0fe58fb9b3b0b6a31439012ebe8d731bcdf851", 16) + g2To8x, _ := new(big.Int).SetString("2b9cd0bae01dfefdb859f3fbacbc897d6174d717103bf3b64dc43276541a2034", 16) + g2To8y, _ := new(big.Int).SetString("13b64ed1d986a508cbe5b28ca1429210b9c1aff6fb358af406159ff2773181ce", 16) + g2To9x, _ := new(big.Int).SetString("b0543208dea7cf4a213340ea328fe41297a9adae0d846bdba6a63682164520e", 16) + g2To9y, _ := new(big.Int).SetString("11fc9d481c85491a1c76370c03abb451edaad8d165909fd8bcef0b0523ea1598", 16) + g2To10x, _ := new(big.Int).SetString("24236c8ead13686698f502d88ced24d4a4f4d97d857f7a404dab22a7d7010281", 16) + g2To10y, _ := new(big.Int).SetString("14f25da82adf5997cd262a35f883666cd8fb73558e864094f04cafd100d70121", 16) + g2To11x, _ := new(big.Int).SetString("42075949fd411801cdb82e636cbaeba5913ee29901d9294e4ec8016fed7de8d", 16) + g2To11y, _ := new(big.Int).SetString("18cd5594fbf0daec1813cbbe6752ec1fc46f951b26c19031466364b772f37f47", 16) + g2To12x, _ := new(big.Int).SetString("1e55ddfd2bc59eed77164fe02d0232b3d497792ec225376f3c3f5ec2f731fcf9", 16) + g2To12y, _ := new(big.Int).SetString("24b3e64690c93b37546abdc4ee90b916e2d3605eb218cf26ef5868d2b666072b", 16) + g2To13x, _ := new(big.Int).SetString("133b598ecf07b15b4badc0af8b67d74f574a29c1ef79a426fe1271e235e61e00", 16) + g2To13y, _ := new(big.Int).SetString("65bab42b71a49a87ea2b1e39d69612daf58372130af040f503b71b689ac9b8d", 16) + g2To14x, _ := new(big.Int).SetString("15dab2550a7d9679f0a528cde54154b2d9ebd399a16691e13f3f28b17f72f7d6", 16) + g2To14y, _ := new(big.Int).SetString("178ce9329c1a5914a6561c281c981810a1554be17533bf6e7ce5a03e18f67889", 16) + g2To15x, _ := new(big.Int).SetString("145bc328b9b296659851f12d70e35a9ca48cbde2af8a8ad8c9f2b3e0dff32306", 16) + g2To15y, _ := new(big.Int).SetString("29556d2e78ac6045e5dd6d555ec184c802c9e0599a8d5173103841caaf829633", 16) + g2To16x, _ := new(big.Int).SetString("26e06be6332f9f22b10167247f35f7805a11658a38dbb75d480af28117a525c5", 16) + g2To16y, _ := new(big.Int).SetString("5e492d706a927c51e6180228d8be86d15017d61160867d231101e2790e2f451", 16) + g2To17x, _ := new(big.Int).SetString("173562ccf10ecd0d4fa859860fda7fbd91089fa60e69dc72fafdd35516ea77af", 16) + g2To17y, _ := new(big.Int).SetString("2ecf52567da025409374e147a7e63641b341b7b0e90104d86688d1c244890fce", 16) + g2To18x, _ := new(big.Int).SetString("1f2434b943605601a75d294aba1bf13f0ff5db8d7e0a3500b5f4c1bc41e786dc", 16) + g2To18y, _ := new(big.Int).SetString("262db6caeadc85809eec6eaec5a25cf46cc7c753a1e28313321fcdbaab1c38", 16) + g2To19x, _ := new(big.Int).SetString("3762e07278ae0306a4c00f906f8f2e4d59373bfe860160c0fd9c5e77c46be52", 16) + g2To19y, _ := new(big.Int).SetString("25537898872f823d23934c27f897ad4f40773d14b4fd32bc0cde718aa9cb87b9", 16) + g2To20x, _ := new(big.Int).SetString("2cbfb0fe6c22c116187ef88cab54ae9612bca6cc0738379098e3f0c4a4ffe44d", 16) + g2To20y, _ := new(big.Int).SetString("18e367e3d08db17ce4fa3e487e6268c2ba168da6b239a84bf2ea8f2ff0f4c469", 16) + g2To21x, _ := new(big.Int).SetString("55c8d5787694c618d99a4a31e6b68173176fd3ee152aa0bc009e99279a9b348", 16) + g2To21y, _ := new(big.Int).SetString("cb17a49107a9cfbe06478a33ba7e48e279bb9904ee0d6681cc72edea5b984e9", 16) + g2To22x, _ := new(big.Int).SetString("1f4465d62aac0c486d54b87e00f9ea1454aea3f1b0807c471fc172383b0886c8", 16) + g2To22y, _ := new(big.Int).SetString("2fee931883b4bf0d0d2e303bc10317533e6c974d3d884f9315f8d78840e1363c", 16) + g2To23x, _ := new(big.Int).SetString("127b3ab3ee067a5c41553648568b7882ce8ced215bfa190979668b3bc81eb1fc", 16) + g2To23y, _ := new(big.Int).SetString("5e5a09c5ae9de4c0492a8033cf035672a55797cadfc1e6860aab21c32a78112", 16) + g2To24x, _ := new(big.Int).SetString("35b261363afc5e03923315a3dfdfbc2c932d94bc19320f3ab411a203df4b44f", 16) + g2To24y, _ := new(big.Int).SetString("57df51fa44deb6f13412a77fd4325aceec98dfe6036cf74c71a5675f7fe1342", 16) + g2To25x, _ := new(big.Int).SetString("154aceb2bad07cdc9e1e0239e75f74d2b63a297881f9adcb166edb88fe076f4c", 16) + g2To25y, _ := new(big.Int).SetString("2f7568bf2fa097d86b7858e8701480e26d6d42fc819858b2137a427ee5b9a1da", 16) + g2To26x, _ := new(big.Int).SetString("9a6e5836835dd5677aa892580f15382da285a1b1379a67fd54d21664fe5681d", 16) + g2To26y, _ := new(big.Int).SetString("29f5850d45dfc5f3126fd0da3ea2c23ae965655112b9c2771cf2e73a2861ac5d", 16) + g2To27x, _ := new(big.Int).SetString("2566879ca48921f6fe14df4d20d2f9e24024c9d438b131bc30b06efc35dee0f9", 16) + g2To27y, _ := new(big.Int).SetString("2ddf0f6cd3e69d0a018bb01bf69ede7299a90eb9e40ee68dc50fc1b57f42011f", 16) + g2To28x, _ := new(big.Int).SetString("8c4de3bb9284981741584663ff2b08ad9fea7b6fd7f867f558d768cab6683f0", 16) + g2To28y, _ := new(big.Int).SetString("f9c2bd3727428ed114cd7860e28daf81cb9cb7dcdd26bb704dcc13b4314dd6a", 16) + g2To29x, _ := new(big.Int).SetString("a9cfe416626f75b3be8249cbcb7f3732bc7601cf581f774ebea4254dd06a31e", 16) + g2To29y, _ := new(big.Int).SetString("2f37ade304c81412d4ae613bf6d46db48b794a815bffc4413fc4872fd3e54e15", 16) + g2To30x, _ := new(big.Int).SetString("258872f55cb9b9d5085401f6dfd3ae97c4adf21c3f5a391ee055fbbd9dc4754e", 16) + g2To30y, _ := new(big.Int).SetString("537cfe016384089d64f027080a6061dc147732e6cd9c5bc1818d20ccf9958cc", 16) + g2To31x, _ := new(big.Int).SetString("1e46ffd3559b30f6d101a2b49be6d213a9c40979ce8cb6b3c30ac308259bb5f4", 16) + g2To31y, _ := new(big.Int).SetString("8c2c33416234b10c20e4b8bf0a1c1af83b964df68eda56adf0dae561518f704", 16) + g2To32x, _ := new(big.Int).SetString("8d1b64842bc402bf13683a6c6f35b5c3d20bc295b2b29547889abb503000938", 16) + g2To32y, _ := new(big.Int).SetString("8dd9da05595bb2f247f8254c0b5c522610ef4ff6de3397d6a35c2cd57d5ff0a", 16) + g2To33x, _ := new(big.Int).SetString("17ce741466bfe6b7ddd079fc1b829fc11c670ae647603cc16f07ec4ee9907076", 16) + g2To33y, _ := new(big.Int).SetString("135c40e7ae971f4f02715e9eacfb0edd48544329e207dcd9e09e3a1d6a7ef9d3", 16) + g2To34x, _ := new(big.Int).SetString("2560de7ec1fce358673f10c20b44ad547058e357b6abcad273e4de32f8901926", 16) + g2To34y, _ := new(big.Int).SetString("1ce0ed3c1313830bbf40fe0d7843c66dc5a67680004df9bac115c39ad61a6434", 16) + g2To35x, _ := new(big.Int).SetString("1d0ab19190a9eea7211606a352bc936d6605a190090ac0843a8beedb54bfcd60", 16) + g2To35y, _ := new(big.Int).SetString("11013587e7511d4a0d9511b142867820cea6cb9c3d7a8db3ac3230521bfdbb98", 16) + g2To36x, _ := new(big.Int).SetString("ce765d04f6147d2ec7fd6b47a674fe19734ba8732f9f5b2201fced57eac06d1", 16) + g2To36y, _ := new(big.Int).SetString("17e32bc3032ce94020638e7d2ab3cb5ccbe6f0b06faf6821fa8e3e4401a5c5f3", 16) + g2To37x, _ := new(big.Int).SetString("f4dc779722c9006a9c18edb82b48827e1620600ec0d8bf5ea38a9aff00b2fad", 16) + g2To37y, _ := new(big.Int).SetString("85e58b989c3118da095b0e96fe2b07080d4a7a2c1e68b00de0a673d6ba338c1", 16) + g2To38x, _ := new(big.Int).SetString("2732bbe06b941c9e2d5b43837d8c5d9c23b7d9e8d5e623427ff3b61f2f5a5a07", 16) + g2To38y, _ := new(big.Int).SetString("2b591b8a3c2bfe17bd639fc6a77244aa8629abe4bee101a444e4f24f36f1cef4", 16) + g2To39x, _ := new(big.Int).SetString("27e2e192f061b31a05a77bf2ef3197550a6a3d87137f94166ead6c6bc962dd79", 16) + g2To39y, _ := new(big.Int).SetString("2d6ed80f66dcba2fa0170b308717dd966f6f290acbf61affd81681234c8c2c06", 16) + g2To40x, _ := new(big.Int).SetString("2b74bc4a2f94e7ee3305368999840142e80348e9464caef350c14219abe982ba", 16) + g2To40y, _ := new(big.Int).SetString("28ece478e5bef9a805431237214101dd7e42d6619d13344fb5f38cfca35be682", 16) + g2To41x, _ := new(big.Int).SetString("22c175e3c8487841f7e95a1448695383526f6b54fa1bd5dc08abc316e31e3517", 16) + g2To41y, _ := new(big.Int).SetString("149630c26a8011eff9ef41663b42cb704da419e23b884b7b24414a6561bff9ab", 16) + g2To42x, _ := new(big.Int).SetString("1b05155447aaa6fa1ea292a769950cfdbf195dabb8101a25902b5da432322076", 16) + g2To42y, _ := new(big.Int).SetString("10575afe16844a09fe4b002623c91f29e52bdebbe29e235f2090c39a930e8c2c", 16) + g2To43x, _ := new(big.Int).SetString("2a8577ed48db5ac9e9fa8dfa247f27b3e60d89f1827647685799666c97f1a833", 16) + g2To43y, _ := new(big.Int).SetString("902486bd83fd098aa054ffc4cb97ab085cc2f16ac36046994cc30a023107b1d", 16) + g2To44x, _ := new(big.Int).SetString("1d9a6be49fb8d2ac15dc3d5c94e14a1503ab0b3ca6a21cad875d6b1a79faa9ae", 16) + g2To44y, _ := new(big.Int).SetString("28026c4fe5e3beecfefcfc52d868ec17888e6b9e926ecfebea979f4da743e98c", 16) + g2To45x, _ := new(big.Int).SetString("732fab1b46a9d2f5d4e4c0ae76b33d747b97fd120d5a48b403368c0ca59e3e0", 16) + g2To45y, _ := new(big.Int).SetString("10ee4d49117fc0c55faee5550615ab0e2020d1cffe21a9138b45be3861386f7", 16) + g2To46x, _ := new(big.Int).SetString("1781ee986bd68597bf4d4d208c4288599de61e144c3bdc0400d099816411cd05", 16) + g2To46y, _ := new(big.Int).SetString("2ab3082b4ee85457502bfd2c20b89df4181ecd32aba9f00d68a92d8f081c1846", 16) + g2To47x, _ := new(big.Int).SetString("2ef769820679d51c8ad33309549d630a069c2e0bedd5f6408bc7932f8bd47fc8", 16) + g2To47y, _ := new(big.Int).SetString("6abd56e6a2300623d6945f2f2e965836e0ea9518549579ae5626fbee7a98b01", 16) + g2To48x, _ := new(big.Int).SetString("c56565b409d0661559f47150adb952432a186ba0c316d0360db359b32b7b05a", 16) + g2To48y, _ := new(big.Int).SetString("1d312504121f5a89e8abc692156492ab42ade35fbeef59b84a720513f9407f51", 16) + g2To49x, _ := new(big.Int).SetString("2bd2e4fcc5e329ac6859e2bed1443604639c50181b461499a1ff41d65948615e", 16) + g2To49y, _ := new(big.Int).SetString("c6b0aaf39ab436c4d8245cce97c862198c92af61bcfa8e260b78f8b3125609f", 16) + g2To50x, _ := new(big.Int).SetString("111e14c693b4e2f022cd64a6fb0a9a2c30a43eb830af2d536d47d65e31621b35", 16) + g2To50y, _ := new(big.Int).SetString("2556301d79a6b88a9ee4e0c6c7cbf32c998de755f5229cae477b9ae2a688f6ea", 16) + g2To51x, _ := new(big.Int).SetString("61d62988ebd3a3a643e088f5a5117b03e3342eb44aeade5be5e769c8ec5471c", 16) + g2To51y, _ := new(big.Int).SetString("fd8ed00f9e0d1a9b4ce715d06e3a592a38e60e80bc6102764a208f72bab79cb", 16) + g2To52x, _ := new(big.Int).SetString("2bcb97abadf5cc9ebb2146867d6f7451db29fba33dfe8a34ab680dead115e00a", 16) + g2To52y, _ := new(big.Int).SetString("8cf030bdc7a851154cdcd01609d064c93b03ad7808e8f306ab488261db73320", 16) + g2To53x, _ := new(big.Int).SetString("1d174577a9c53cefd85d6bbbdcb5b8f292a884b26f0ea403dd10db43ed6f9a8b", 16) + g2To53y, _ := new(big.Int).SetString("7bb9915573ee3bf341981f4905a2d96167e228b90c8d9dd430530574cf75899", 16) + g2To54x, _ := new(big.Int).SetString("591f4466b7a4ba962d097beaecdb6bd8d17cbea3bd5fb9cc8e166322755869f", 16) + g2To54y, _ := new(big.Int).SetString("1b1808e9fc843a9efe02f7493cecb95c608c316d4ed98f194003ca292a8bbe89", 16) + g2To55x, _ := new(big.Int).SetString("33a47533babbe960c581d996a10c697efeecfcd62b36b6124f5d3c793348962", 16) + g2To55y, _ := new(big.Int).SetString("2f7a4ff5aaa8a0e2cfca3a1401601a52b80aa7cba4991b380f429d26d940924a", 16) + g2To56x, _ := new(big.Int).SetString("1425b11b4fe47a394dbfc0ad3e99dc93c3e1c0980b9bcb68529ba9de33dbf585", 16) + g2To56y, _ := new(big.Int).SetString("168b8cdff7ae7d084fd111608fa03e018b415fd4f0755f7e8f039a2d852bda0e", 16) + g2To57x, _ := new(big.Int).SetString("1281e1b4ae3aa4404c0181f688fecb6c0c4449ee646c0438702eab87f4b7dd1", 16) + g2To57y, _ := new(big.Int).SetString("18d37f7e79d7dfdd82187cc71e706ebe6353499493e23fb8ae536e47db8ce60a", 16) + g2To58x, _ := new(big.Int).SetString("3fd1c6811aba796990bec7a6e1c93456bc73bd41b090d6be589826e49b1ae21", 16) + g2To58y, _ := new(big.Int).SetString("269f5d44435fd8dea26779b7f46c23b4bed44fa1d9863c9880f010959bb4aa88", 16) + g2To59x, _ := new(big.Int).SetString("ec6fc4a5b4e315512f882a012443a460f0ad440410931b3d2f16125b5e08b17", 16) + g2To59y, _ := new(big.Int).SetString("13d2044189630abd18c6a3d7dad67c97b771597be79693a5de68da0ffa2676d3", 16) + g2To60x, _ := new(big.Int).SetString("1fd5ddc117799eac4054d556ea4dd922ae145542d5524a29a0cad3ec7ec810e8", 16) + g2To60y, _ := new(big.Int).SetString("27bb413910ef0b9339d3262cde13e189d0b2e64f0c073fc81da5747676ca645e", 16) + g2To61x, _ := new(big.Int).SetString("2d1b7db11118809263c79240df010a2415abafca8d4248788158bfd6f2141969", 16) + g2To61y, _ := new(big.Int).SetString("75158f7b9c5890a51d5b46a86e6e3f04f20dc8cafca5e5c3772eb508e2390f1", 16) + g2To62x, _ := new(big.Int).SetString("2dd2737976a05341def306c8899cf11d24b52f3230f36b6cdbba3fb971cfde1", 16) + g2To62y, _ := new(big.Int).SetString("1a15e9c72c124e695b6fe0c535bc1c0265ec884cf74b53de358de6d5c956ed73", 16) + g2To63x, _ := new(big.Int).SetString("1df18f1f725582b96a446cd7fb021d67a357626fbc37e35599ed2d117359d294", 16) + g2To63y, _ := new(big.Int).SetString("2110263f391b92233267e75ec5641be7385da935a46f8cccd0698a584c70848a", 16) + g2To64x, _ := new(big.Int).SetString("457cafda1576b6f5fea6125056e6d52c4b01de7b44ae5aae162e83c9fe86928", 16) + g2To64y, _ := new(big.Int).SetString("16471c8dad2cb3ea4c4645d8b108abfb95fdb1c87485a1d78a3d158e529aaabc", 16) + g2To65x, _ := new(big.Int).SetString("a431193edb58abf0df45b4bbd6cfc43bf2e39093ec0fd195f3120344b3ac3a0", 16) + g2To65y, _ := new(big.Int).SetString("b1261fe08f29cc99a084cda6e12f384e7a11f3fa0f75dfcd21005d951fdfc2b", 16) + g2To66x, _ := new(big.Int).SetString("1542e37f2c64d816c9dde4cdfeff540680cc90b767294ba9937a0de230676b4b", 16) + g2To66y, _ := new(big.Int).SetString("1717efcb51f08cccdbfe3e4a2da92e000a45a3e3d9eb40f9b9a2041dcbf14d3a", 16) + g2To67x, _ := new(big.Int).SetString("f39f1ee90eb802366254bf2555173a1bd988e09f8c5ad7bebfdb8d14d88b064", 16) + g2To67y, _ := new(big.Int).SetString("2cbbd9234ab4f9fd74defb1512b86385b038ea5ae995449b813235e047876986", 16) + g2To68x, _ := new(big.Int).SetString("250a8a1b9edcecc5f25879262ef2962fdf8499f60e8131c6c33320fd8c98ed15", 16) + g2To68y, _ := new(big.Int).SetString("1924e2b0b5e2c49449c5ef9b62c2d01207e012a0bc70b219ab44f026ce7e43b8", 16) + g2To69x, _ := new(big.Int).SetString("239aee62596123c53859dc2937ea9257e52034311bb81519b7f45330c5c883da", 16) + g2To69y, _ := new(big.Int).SetString("151f09f672db228c74304a2f68f65a7b586f93913b97b6d7dfd638b99571b7f3", 16) + g2To70x, _ := new(big.Int).SetString("1ec491fbe90a222adec9c417cd9c39393bf0e9fd4618f8688f20b587e10a92ec", 16) + g2To70y, _ := new(big.Int).SetString("2ad8de9952064d982be63f71a172dfddc4daf430bb5c7a0c0d3a53ff776b8474", 16) + g2To71x, _ := new(big.Int).SetString("2e5001cee2faa644502bbba6bf6b07e3b7cef0392326b48f300fc56f6982026e", 16) + g2To71y, _ := new(big.Int).SetString("180e823c991af5044dde58a9e671fa092d3ba5db98cc7e0376dd079323f80764", 16) + g2To72x, _ := new(big.Int).SetString("2715e750e68b52faa68b293da254e1b0049b5825804f4c2700adf08a0214e529", 16) + g2To72y, _ := new(big.Int).SetString("3921d1862445f32fb5afe510e7c4e23f41e4bad15c090b1de77447950003fc9", 16) + g2To73x, _ := new(big.Int).SetString("b4ae2be8e83c897e6d3aa46f67058f07e0d29edbe4eb1b6c1e325c737af51f7", 16) + g2To73y, _ := new(big.Int).SetString("cea4f5b9bc8e843c26cd4e67da727fe9cd09ca8e07b60410602c63c3b0baee6", 16) + g2To74x, _ := new(big.Int).SetString("252b5bf255b06eade647646139359221099916d1be9aa6a7edc3f7c9c6b3baa3", 16) + g2To74y, _ := new(big.Int).SetString("12f7f9b3871cd66f99e976138eedc4faaec30a67ce3c67d867999ce814f7644d", 16) + g2To75x, _ := new(big.Int).SetString("1977739937a75442ba424943233bb2ba55f9d4c62148285873a658581d5114ff", 16) + g2To75y, _ := new(big.Int).SetString("178ee53b5e50cc2078544a9cbd11841c47854fe604388a5defeac56ce805bfe6", 16) + g2To76x, _ := new(big.Int).SetString("e6581bf922d94d7079fa4b753f3ecedc525f516643a6bc894c5ab191fbf676b", 16) + g2To76y, _ := new(big.Int).SetString("160642bdf146cc3f6630cfa5c115629055ab653c0e7f2414391f22b25d6720f6", 16) + g2To77x, _ := new(big.Int).SetString("d4da3f9398685005d391d7c328ec8dc2ecab18c7d451901725375b1c373d860", 16) + g2To77y, _ := new(big.Int).SetString("1609e3ec29efd4abf1629be26b772ef4b8490bcedfae621851e413e84c513135", 16) + g2To78x, _ := new(big.Int).SetString("3a781e0964591a816d07c8d6aa23d23b2ad50ae3acc529f877abf4d13e3f35e", 16) + g2To78y, _ := new(big.Int).SetString("20a1f12ea58910335687316cf47761991bad8f11e109095279c05e14b370c876", 16) + g2To79x, _ := new(big.Int).SetString("2db5bda50b8b265684bb6e9c7af58513e9aa23abd3fa2a3cfc88dd057f90bef", 16) + g2To79y, _ := new(big.Int).SetString("103c36bd9eb69b53205b7fae6224bb36b5a50451261cf87128953b489594b6d8", 16) + g2To80x, _ := new(big.Int).SetString("513dfdf79ca36c0d5e56de067033a42d9e13ce86f261d9081a2dddbdb88127c", 16) + g2To80y, _ := new(big.Int).SetString("2902f0ba36cac9e8a907ae91f2486316258b0b9b3b2c5262ab965004167bfa0", 16) + g2To81x, _ := new(big.Int).SetString("bd86fa4e2f2da10f54c62d2f996d7813d6548785f88386b0286ba719dc973a", 16) + g2To81y, _ := new(big.Int).SetString("2495aed3ff4e37c6d20a260f9847fe15d2bb5c2b788454bbb6e450effafa8bea", 16) + g2To82x, _ := new(big.Int).SetString("18f64e4337ef0a3732be36ca6cf72393b821fe4914ec78b311ca3a343ce7b15c", 16) + g2To82y, _ := new(big.Int).SetString("21c0913ede0f09b5920b629b891a95a30aed5dd6001eda274649363d1877da", 16) + g2To83x, _ := new(big.Int).SetString("46cc874785e387f35fbc3278c63a7d66e89f4642ab9056ec3d0b8d26eb21ec4", 16) + g2To83y, _ := new(big.Int).SetString("1b759ad99b33626516327fbebf9c232e0fca6555b084ee311f62366d7d5f86b7", 16) + g2To84x, _ := new(big.Int).SetString("64fcc679f04e762d783f5b39e9bc9832d06a6809d8c101a216431f1dc792cfd", 16) + g2To84y, _ := new(big.Int).SetString("216690982d703eb77e4ea5a7dd74c7c00fb98033d17ec825ca4950f6c40aeb80", 16) + g2To85x, _ := new(big.Int).SetString("148b2e63d2d3d87f364f35c47d7cf6c006506cf224aac6f208c559a2ed58d834", 16) + g2To85y, _ := new(big.Int).SetString("2727c32af57debc90f6fc9eb1607f72e8180068d6d12c02c38498ddf0a998506", 16) + g2To86x, _ := new(big.Int).SetString("213b9a87905003543236ff3eb6b232083378cd7a9eed91eb78f2c60fa85a3ad2", 16) + g2To86y, _ := new(big.Int).SetString("28e04e92b62096e8d23915d545982855c21be5b3a1193e6e34c43db01192453b", 16) + g2To87x, _ := new(big.Int).SetString("2a4825bea894ae814c1678bbff2fe7c99cd63a77a0c703b2825a5f19b2d98fad", 16) + g2To87y, _ := new(big.Int).SetString("2a127b6261bc7a4f6e76e082d980d0af0bd0f5e0fd9cdb342bf9bbb7694a929d", 16) + g2To88x, _ := new(big.Int).SetString("2257c2e4b41831dd8d36aaca1ab106c26c796f1c8e0a2998431f9d4125d740eb", 16) + g2To88y, _ := new(big.Int).SetString("7b7ed1edbb583f469367ae24bf8e49c1ff6731dfff4abf92e163e595187203c", 16) + g2To89x, _ := new(big.Int).SetString("a8d78ab8a1fb7388787eeca33f3fe251ae93f28ac1fef89dae84057b55436ff", 16) + g2To89y, _ := new(big.Int).SetString("1aef7bd255bab9ae1a74c2b7cb61cb0c22f8c6c0a7da5d9d4753779f9fc3d456", 16) + g2To90x, _ := new(big.Int).SetString("1bca13199961ec30b02a2e464afef42ab60ef11b26573e11e22a1028afacd288", 16) + g2To90y, _ := new(big.Int).SetString("ad9ff00a04b9cbebcd54d75a6db4c6042799d29bf0e0d0fae7438c89233850c", 16) + g2To91x, _ := new(big.Int).SetString("6236320cf783a01e2b8be7816a84671de9e8bebda0e8f957809ee1253565bae", 16) + g2To91y, _ := new(big.Int).SetString("a4ce1ac405b9974e4eaf9342c2a43bd1fdc4edc2bd18235249bf51ec4328744", 16) + g2To92x, _ := new(big.Int).SetString("107a0928f1bbd09f3710ba91ea9d69152e2a2de8eb21984ec9caddb69ab37a8a", 16) + g2To92y, _ := new(big.Int).SetString("28c0d2c1d2b4dd590537fa55a7838a2bbd7aa7f2c0e91b36927b731752c34192", 16) + g2To93x, _ := new(big.Int).SetString("4c02961cf949cd155f736fdc4c29e4fe409c37994aef1b16cd170cc65b1b2ee", 16) + g2To93y, _ := new(big.Int).SetString("a92da6a165896cdb685afb42e80bec10097bc2083bc938550706fc5bc355795", 16) + g2To94x, _ := new(big.Int).SetString("165aabcf0d07544d16f06389ef1d3bd5ae9c4bdbb0f53065b64bc53346c75897", 16) + g2To94y, _ := new(big.Int).SetString("9dbc96d154f3fb8324230033265a8d5a31c9b88b5104ca5f56c714ac2e6a534", 16) + g2To95x, _ := new(big.Int).SetString("1bafc8265a8fb16e346e57060848c3ae00b0e2d8520ff8d287cd002705c4c1ab", 16) + g2To95y, _ := new(big.Int).SetString("3a87183d670bf95439912a7fce6570c957a4d5ecaa722ed50e7d7c55dc55d0a", 16) + g2To96x, _ := new(big.Int).SetString("1b5b281facfe95fb1144e0f7d0484d119ebe0dca0355e63ec70e5f94cd64e3e9", 16) + g2To96y, _ := new(big.Int).SetString("10e9c2dfd3e452f067fc71c60a08200402f8f4e5e8dad63e462ba1597a20c615", 16) + g2To97x, _ := new(big.Int).SetString("18dd61a6d1a9c55b35d048ffb667e7f05ee657481bdb86800e89aa48df541143", 16) + g2To97y, _ := new(big.Int).SetString("147653157294e50892424edb123ca14f08ae7da80350b6ffdf582aa7a939e371", 16) + g2To98x, _ := new(big.Int).SetString("24fe3fb77d48ea49e4c1b91c61b634dbd9525b20167226b19d7c603ac36c3d4c", 16) + g2To98y, _ := new(big.Int).SetString("2a4768c15d9b9c746e253eb271b28afab89da5412565d93c6220a5b14cfba611", 16) + g2To99x, _ := new(big.Int).SetString("119ba66c94aeb05b2309953c35df696ce195bf7d959770bb9b99ab944db0af91", 16) + g2To99y, _ := new(big.Int).SetString("29c96c201b71f6540f084e2fb6d4eb8a52b940c0c5585f258aba521311b805d1", 16) + g2To100x, _ := new(big.Int).SetString("15856673ff5b68543c671cbe735d53376dcfea3eef0ec5fb3a1ae3c37f5683bc", 16) + g2To100y, _ := new(big.Int).SetString("12224ed590244e93f1c6b7abff01b64dac0bb8bf14ae8e3d825322b6623d082", 16) + g2To101x, _ := new(big.Int).SetString("253ea43ba2e8c14da0df002c96422fb3234310a5774d8ec6cc9c1796df1789ff", 16) + g2To101y, _ := new(big.Int).SetString("234267257e751a5fcebb1e295b774700fcc16b5f270ac8720f4376dbc18281b3", 16) + g2To102x, _ := new(big.Int).SetString("2825afe1d583957680db4456ece011c28a7a5e2021a69a1bdb69707d944268e4", 16) + g2To102y, _ := new(big.Int).SetString("2870101fe628a0d69a362a7f52d4f57093aceffa7aea51a4544c3033109a05f9", 16) + g2To103x, _ := new(big.Int).SetString("f29f472f3b04c24a5ed6675f5ff33720a10826fe53cef56b2c9313b2bd31523", 16) + g2To103y, _ := new(big.Int).SetString("2483c78fb7a925e79bf63bb20e9198e12b41429b23fe8e2ce29f91f1112159be", 16) + g2To104x, _ := new(big.Int).SetString("28b2e5fdc60e4fa83c1fb52db348434f08b850cc205f98431deea3e8fe209ad8", 16) + g2To104y, _ := new(big.Int).SetString("fe1ae72d3f07fef610c96a45cadf362c41f3f902b7b81a735b2a98333f54f47", 16) + g2To105x, _ := new(big.Int).SetString("2267c8d0582c04e9568e83bb9155fd9fac11d9c0672455f63fc14112297855da", 16) + g2To105y, _ := new(big.Int).SetString("1a13b6e83105beb7164721a03aa0635d2214c68c0ce68c5737ff618f02f62bcc", 16) + g2To106x, _ := new(big.Int).SetString("2a3e86af529fb07cadac27f9eb5683abbdacac22e8e55a4b96c61249cb3ce975", 16) + g2To106y, _ := new(big.Int).SetString("1eea66c26412cd33e47d7745aa76f7251efdd09bf220e09889675d9896bd1772", 16) + g2To107x, _ := new(big.Int).SetString("c5111956406a1ce31b50a0d90fdca236871c353e3f75250304b08cef557b588", 16) + g2To107y, _ := new(big.Int).SetString("2b4948845ae79d5803bc258bcd951d476247eb24ebe416a89ad8fd9f465fe8b6", 16) + g2To108x, _ := new(big.Int).SetString("2854ffc7b3e8214133feba8d6eb09b263690572a3022b7fcf2871ab9219cdbad", 16) + g2To108y, _ := new(big.Int).SetString("106de3acc6519fe5e79d178c2c86abded16f791c8ef4d9335d97862a68f5590", 16) + g2To109x, _ := new(big.Int).SetString("24c6a00e705db722a2952db86bbe7f08cac7b6c3b50d023f24a3de1ea736074d", 16) + g2To109y, _ := new(big.Int).SetString("dc43ed6b87676e8dd55e167471a55f2eef0968e310767659123e48b357903a4", 16) + g2To110x, _ := new(big.Int).SetString("2644642ad942cfbd4736a0f7f18fc0197e029521ee087615e04a49e5f8fbb66e", 16) + g2To110y, _ := new(big.Int).SetString("22b30468bd6abb89a23a5dce7e57ae96e25e0417937368f6760147af32c7a7ef", 16) + g2To111x, _ := new(big.Int).SetString("139bc1dd75b831294bf28f4030675c0e05ab4f44f87a639b04228814b6cd5531", 16) + g2To111y, _ := new(big.Int).SetString("18c670606f2e48d361c347c0219ae8e678759c0b22c01a1756b6b0e3c679ef33", 16) + g2To112x, _ := new(big.Int).SetString("2699eb06108602cf13980e2b6e4f48c6d90f46de7eae60457e4d1019a4f3b9bd", 16) + g2To112y, _ := new(big.Int).SetString("626c5f10d9f788ba433f2be9ac352b4298ecd2cea3cfff1e15e9d48fbaa113c", 16) + g2To113x, _ := new(big.Int).SetString("1f4479f765ee101dfedcbb07e9033604da94dbbe5b781331484321af5b253dcd", 16) + g2To113y, _ := new(big.Int).SetString("21623c9b390babf2397d31ca4af79148ad304a121ae5edc1723c994d2828f444", 16) + g2To114x, _ := new(big.Int).SetString("2855725b3e68975ebe53642831ae4d5d2d7b4b137b95eb96e8151bc61f1bf053", 16) + g2To114y, _ := new(big.Int).SetString("ca0e44e2fd18ec91840ccfe99c3049de88d1cb70c63633b7aa4416b92b0336d", 16) + g2To115x, _ := new(big.Int).SetString("136dedcff58a79ef53df43747ab531ff7d38d5c7d2f7a6d652f57b415b808c10", 16) + g2To115y, _ := new(big.Int).SetString("108956df051470607a649a39f14ea5cf95a904a406ca3123eebe60a0eb4300fe", 16) + g2To116x, _ := new(big.Int).SetString("d744feede2a6bd63f61403043b33f81f56a61ae58c43e8b771ee0cf5f0dfdea", 16) + g2To116y, _ := new(big.Int).SetString("7edb65778a0aa859b8947ef31e601c311b25aa1bd2a5ccc3225cac13bfc1d18", 16) + g2To117x, _ := new(big.Int).SetString("23ecd41f06eb8051f907d416c36a9a6691dc87cc64de02261c7eacaf70b82beb", 16) + g2To117y, _ := new(big.Int).SetString("caf2de20986119d958e6de7c3f6cd4f8b38645c9e59a12f46003aa5625c1edb", 16) + g2To118x, _ := new(big.Int).SetString("15b08db406565282b6a0d3fc8022eadd2b61a559f3c92cc91521c45c6661a82f", 16) + g2To118y, _ := new(big.Int).SetString("37803c869368190f0443820670330b14439832989f2345a36e5a48b2c59e543", 16) + g2To119x, _ := new(big.Int).SetString("e1eca77e1fdfbc7a151ed32732cbbe093978b5d8724324d73929a30e58be078", 16) + g2To119y, _ := new(big.Int).SetString("2e23a2f478eff00d8f0c0d7ec3c2c76467aeb2ca3d26ef49ed19ef1a8cccf8ff", 16) + g2To120x, _ := new(big.Int).SetString("e16c46d7f01cd14637900379058cde52352483f90eba6350dea325a183e4c8e", 16) + g2To120y, _ := new(big.Int).SetString("2bc5983fad220b58189c50be25b200c54e70d0529e3dc96decbe801f0420786f", 16) + g2To121x, _ := new(big.Int).SetString("1ecf556e4ea1a22b395060ed7c79a79ad9af43103b935caf9d410aaf61ce4e9a", 16) + g2To121y, _ := new(big.Int).SetString("1ac123a28245de45fd811267a8e343a1b035e77aca8b4614d09722caff12b0eb", 16) + g2To122x, _ := new(big.Int).SetString("1211f23e5e92c74a454701bf173aaf1ea12f7042e85859c468d94974eaad551c", 16) + g2To122y, _ := new(big.Int).SetString("165d5f2fff807855a18513ebdb932dee6bfcb8293383f7b7bc5196d737053f73", 16) + g2To123x, _ := new(big.Int).SetString("2b9fcf34bf541a48ec88d66cf5bfc89700211ae76a79551757dfc50f41288227", 16) + g2To123y, _ := new(big.Int).SetString("ced96282d5edc9cbc32b1c16e750da8cf3237e07e3625d85bedaecfcd12c9c4", 16) + g2To124x, _ := new(big.Int).SetString("2f9ea4e44871cf87cfa80f71560253dc13ab58f9728495fddb4b9bdd11628735", 16) + g2To124y, _ := new(big.Int).SetString("28dadee7c5d2a42cd524d8396f69ee363aa95f85c98c3c836004589b6d73084b", 16) + g2To125x, _ := new(big.Int).SetString("15530bd41a96a8a225db6640075aecd1884a06bbac5f98c51e5a487bfedc8d70", 16) + g2To125y, _ := new(big.Int).SetString("1c86da90e9556705a7476bff65b8f53425e3d129db8f179ad6e4b033e0495a20", 16) + g2To126x, _ := new(big.Int).SetString("da53ef60fd433fe0ee377bedc0e2f7239b514bba5caa80c52991c619a029559", 16) + g2To126y, _ := new(big.Int).SetString("1e1a37d1bf9f0eb8677bb0fd215c26cecfb350ad226f42d569bb040234da117e", 16) + g2To127x, _ := new(big.Int).SetString("25d8a9ba3266bd80af59395320e940663ab8c05932a4280b42bfcd0ec4f69d62", 16) + g2To127y, _ := new(big.Int).SetString("2fc95abfe6be50f1add78a03a9b4e60931ac358a132ad5ef5076c4894fb14aab", 16) + g2To128x, _ := new(big.Int).SetString("13b8fec4a1eb2c7e3ccc07061ad516277c3bbe57bd4a302012b58a517f6437a4", 16) + g2To128y, _ := new(big.Int).SetString("224d978b5763831dff16ce9b2c42222684835fedfc70ffec005789bb0c10de36", 16) + g2To129x, _ := new(big.Int).SetString("2d035cd6cd9ca06a9aecee6826e38a30dd6fa18a9f139179142782803a05e6a4", 16) + g2To129y, _ := new(big.Int).SetString("bcbe75d48af9e7d4a45ef21e0348411bdf99be154fcc82ecefc6cbab8157291", 16) + g2To130x, _ := new(big.Int).SetString("1096e761836e74c5c654df817b4ace41e55cd812e97d2d0af5e2ea6f24dfd392", 16) + g2To130y, _ := new(big.Int).SetString("21ff527613e48f4a5e3548af70ec2c1076b85506cf767aceb570ee83983ac6ce", 16) + g2To131x, _ := new(big.Int).SetString("292c4a9ebfc080016a973ac9e24fb4b356c69db30308202a31d0bfb2e85443be", 16) + g2To131y, _ := new(big.Int).SetString("2d378fef5d7b4b008da52d0c98bb8daa702109aa7d5da477107d9f9559dd6eab", 16) + g2To132x, _ := new(big.Int).SetString("1d316fbe5c0ccef4caf35a917244ff619d92d4fbedc80b970205508e4b570595", 16) + g2To132y, _ := new(big.Int).SetString("22b85bd410a73800d3610f05dea0bc7d82960d317602cf44bf77ad8f8f254f79", 16) + g2To133x, _ := new(big.Int).SetString("2c961c9d2ad66f1049fdd0e8d7337e3449e8774836bb9981b56fc6e7385cd7e8", 16) + g2To133y, _ := new(big.Int).SetString("6bd01a16056ed018b2394a0ec6897cfbeb20a18c606b0d78bc78d1d84a6b892", 16) + g2To134x, _ := new(big.Int).SetString("2e8a8414affe97ed11410c27ac23b1f54b6a621ba39a9fd7f1685f9db88343a7", 16) + g2To134y, _ := new(big.Int).SetString("1efbc6e7cb379b246ad9278606ea10b7c74f52769c615cd67b833c5016ac7db4", 16) + g2To135x, _ := new(big.Int).SetString("2ed01ed41ec147ec1eba42d4b3c921568944e9a0d8a498706f99ec15d0ccc511", 16) + g2To135y, _ := new(big.Int).SetString("1dcc8b5251aa1008c792ac420bc9be5f1870042d0210ff8ae96804ddffc721ad", 16) + g2To136x, _ := new(big.Int).SetString("194c79506a89ea907a1e6777926f317f7231ea49bbde362689477b6ee04e9613", 16) + g2To136y, _ := new(big.Int).SetString("26c94fbfb503010b9cac6a4b4e8e5fe29553e60128e05cdbf5546cb7bcb34d7", 16) + g2To137x, _ := new(big.Int).SetString("277ac3a2889cea8febfa02110307c50b7d8da14e50adc4e86dc8d0aa73251dd", 16) + g2To137y, _ := new(big.Int).SetString("17eb791abc2495f664ffb38442265281a6f9a91c6169ec5a6e7365dcd3c64871", 16) + g2To138x, _ := new(big.Int).SetString("d3c84c79e806fda93ee88a7887b9daafa47969dad98217ab2bc82bdff4fbc25", 16) + g2To138y, _ := new(big.Int).SetString("213f847ffc2eb33fbb7a5fe6f9e52d792095ffd8c8ebccc3caf9ecfd610cf1b2", 16) + g2To139x, _ := new(big.Int).SetString("21d9001150f189e28d9e194e98bc5ac761eda5d600d7ef517983af606c5548b9", 16) + g2To139y, _ := new(big.Int).SetString("1e2fff3d9cd1f421a57ff2dade55ab4ce3b4628a60480cce558d3a77b8fd5227", 16) + g2To140x, _ := new(big.Int).SetString("8c4343a41a1dae81a6276852d405acd87e81ff4b1d190482b5718a6e31a761", 16) + g2To140y, _ := new(big.Int).SetString("12b4ca0371b8ee1bd20a1d65277bab81e59f6e5ce60ccc6b82c722cc29d07fa7", 16) + g2To141x, _ := new(big.Int).SetString("2bf8fac78021ac7b2753b1ecb80fb30160b6b3250b5cf0ec9ad46f7801e759b8", 16) + g2To141y, _ := new(big.Int).SetString("2c0016acf87d3833c0fb9709392747265f4202151c050427b3b5913ff39de477", 16) + g2To142x, _ := new(big.Int).SetString("1cf7146b4c1d2ea113417938e790a96fe811cd3dfef48ddf27dcba7cd820f6cf", 16) + g2To142y, _ := new(big.Int).SetString("2a5ed72cbb62ac7046edfdcf9d1b47368fb3e2291e1e85e26c4e8cd35e401ef5", 16) + g2To143x, _ := new(big.Int).SetString("5e61bbcbc655464ba1fd215e04fcf949939de110f05722431cd5084968d6db9", 16) + g2To143y, _ := new(big.Int).SetString("13e15f844fa2767fac2daae3fb818e93cf95082efd681debb31574defacad671", 16) + g2To144x, _ := new(big.Int).SetString("34bf641f495a59e3d28dc3163a1c74aec7f7ef60030c8614c193f7ae2281a96", 16) + g2To144y, _ := new(big.Int).SetString("8b45e915673d26d8c5c5258a951fcf9b439d6833e12d2c301dc2eabe23e3f61", 16) + g2To145x, _ := new(big.Int).SetString("2960a0634103632555b7ed048b833d198c75536bdfce550988dea08d1b2a4b69", 16) + g2To145y, _ := new(big.Int).SetString("1f29d4cddfdbbb9a3aae3c862def08730c9563529b888e065f77604d012c194e", 16) + g2To146x, _ := new(big.Int).SetString("2bed31e2b3ee10fa9cfea431196db0b201587e2e68ee74dc466450053177c5fd", 16) + g2To146y, _ := new(big.Int).SetString("22c3f8fb3346540004df204600e2a60f2b5232a3fcce889962561e1c98a80146", 16) + g2To147x, _ := new(big.Int).SetString("d452f069c9eb613854442c5e9830fff0cccbb7a0c37bb8fa9a81c242933b54e", 16) + g2To147y, _ := new(big.Int).SetString("1c8331a53da629b28d02f6ba74b52caf67c4418e22fd6caf57d627e110451251", 16) + g2To148x, _ := new(big.Int).SetString("f055c21e2d7e8617b71babc6b770fc9a7ef74c3913fcf610d599414096b700d", 16) + g2To148y, _ := new(big.Int).SetString("1ebeb82f257db891825c55b2c909f0210dbe84616c0f5a867aa9f380a9171929", 16) + g2To149x, _ := new(big.Int).SetString("21907afebc2ecfb8c7c376a0db9958b35a6540103391efa541a28b82f472f48a", 16) + g2To149y, _ := new(big.Int).SetString("27c5a8cf6fa01b72d31ac50942838b8362d01e25c82b2d9c4a0f231441de4197", 16) + g2To150x, _ := new(big.Int).SetString("205ba2fccb49fb5023e5114f84e961b9237b49ca8f5610bebb995b33ee249369", 16) + g2To150y, _ := new(big.Int).SetString("b388977d2e0a8fc0e63a06375d9fe19fc7b798b8b0f2c8b0885920cb5bae45e", 16) + g2To151x, _ := new(big.Int).SetString("2bb165ee76d92f26bdcbd9897c6519b8d89eeef2efc0c9521497068c735a54d2", 16) + g2To151y, _ := new(big.Int).SetString("152704fe7afc78056ee79211313a0b23b71de06863c6102e0f8daefc0f2e85df", 16) + g2To152x, _ := new(big.Int).SetString("f34d4d950bef2ee3b8e924b0183ca4e00aed6ea9209bc37c4e2202eb5bd7666", 16) + g2To152y, _ := new(big.Int).SetString("d676a2dac5fcab3731af3283d9c22989889fad53465781a73ea5aa81274798b", 16) + g2To153x, _ := new(big.Int).SetString("42fdcaca97128fd28b1ca4c90eaf39378d673af8d9f789d33b88c8284c1e4c7", 16) + g2To153y, _ := new(big.Int).SetString("c5f60e7eaf108af711035a4ca219da7c7926c882d40373d76d9fc5dc05bf2d6", 16) + g2To154x, _ := new(big.Int).SetString("15f74bf25691e3205d87c4ee7b798f00097551d1a14e732f8ec16be2c2b15424", 16) + g2To154y, _ := new(big.Int).SetString("e917f31facef054212b2376c65779119a28cf490a506e66d48dd45117ba7cab", 16) + g2To155x, _ := new(big.Int).SetString("8bd6a57ec62543e02f6fc7d0c3e832c7b7fc579d180a91071faa3d3ee9419d4", 16) + g2To155y, _ := new(big.Int).SetString("1bc48805b6f1636fbb3fcd6da38aafead46d19c009893b19cbeeeae7937a68b5", 16) + g2To156x, _ := new(big.Int).SetString("22d27fb14085110cb59094144fc0b73878d88c64957112740a8559878d34fc", 16) + g2To156y, _ := new(big.Int).SetString("8e1197fb288dbdfc3c45e74c7362e8d24eb51a66e6f601e078713114be490f2", 16) + g2To157x, _ := new(big.Int).SetString("1b9f573652906bd22ae891e98f72b280aa9f086974561858b06e57325bda14db", 16) + g2To157y, _ := new(big.Int).SetString("12aec4b8476606d47b077de794be45c888600e94486a93b3560d82c80bc5f8a8", 16) + g2To158x, _ := new(big.Int).SetString("2548e5ca7207fc244a56030fdee8726891f78b31b786050b01f535872604fef9", 16) + g2To158y, _ := new(big.Int).SetString("40f0788fad8ef4eca110681d934bc1875cce24d4b79708f50c5c5ade76284e5", 16) + g2To159x, _ := new(big.Int).SetString("8e2dcb5d0b19b7b0fd7b371bc43c5756f0377132cef98df0db4dd9eb393adca", 16) + g2To159y, _ := new(big.Int).SetString("2fe5e5ea9fb4e811da5043de233b0b4e971da2dd38941c5033de0afe61e945b5", 16) + g2To160x, _ := new(big.Int).SetString("1d4f9e8484dadc0b72b38138caad649253a61a9bf5ad2d9afe7330bf839fcbee", 16) + g2To160y, _ := new(big.Int).SetString("9bb9bbafbfbf4038ee64e73ebbb0975db22edcd2d1c1c6e83eca2672fab780b", 16) + g2To161x, _ := new(big.Int).SetString("fdbf5656758cf6806e65b7800be3b7c039ed1fe181a0d4b50fabcec79f0df5b", 16) + g2To161y, _ := new(big.Int).SetString("173a2bd7eab80c0e2c4cf6abb5b659d289de53889c437ef553167ecfddad034f", 16) + g2To162x, _ := new(big.Int).SetString("f1ca7aa3dd35f558481ea63cf19d446200c77835c45c63954770ad12616dade", 16) + g2To162y, _ := new(big.Int).SetString("6e0f716d88e8041c0021dd736593a6a3fa501e33faa9a6510b71467d749498e", 16) + g2To163x, _ := new(big.Int).SetString("2eb10a9a90309b08dee4cfa8070265358c54b21572d914c9e8fd36a959304d24", 16) + g2To163y, _ := new(big.Int).SetString("3b4ec52766ad398c08539c6f8acb2b39874f0e0b994010efa873cfdf680a88c", 16) + g2To164x, _ := new(big.Int).SetString("1b94be21f1fb7228d3f3d44204f4f3cac13090d7c5c2af9ac82f0475f5cf39b4", 16) + g2To164y, _ := new(big.Int).SetString("27e9d41ef829511094b2af4473637e9375eda5f9e914cf55aac02d9b4a969755", 16) + g2To165x, _ := new(big.Int).SetString("25710e3a7246b1e76b8d6fbe6ff44afd9fd30c9585351398c15d050238d3c2d6", 16) + g2To165y, _ := new(big.Int).SetString("1c855e42168e00cd947df9d3a268f0db1f8e471f730ca88d84e1c2de7083e4d", 16) + g2To166x, _ := new(big.Int).SetString("2b144261f16985c75bff2b9d0796d0bbb63ba9c927669e3839710eea66a8efa5", 16) + g2To166y, _ := new(big.Int).SetString("2bb766bc6b62691154fab15cc24ce09d7d0a86f180f7cfc60b459ccfe2bc1842", 16) + g2To167x, _ := new(big.Int).SetString("26b93a6de603f0cb5900242713c98a4690d087ee2701f953c81f562a0bcf691a", 16) + g2To167y, _ := new(big.Int).SetString("1f275bb2c0d7f2e06d4d3d7718ad405914e62af9dd182c0f3d8cf5bd436ef483", 16) + g2To168x, _ := new(big.Int).SetString("f43e8a6e923598ab55483d1cb864aa57273dd9173b898daae6c753e403d80a5", 16) + g2To168y, _ := new(big.Int).SetString("14351ad715d016d31bfa656c62512aaeeaf2dcaf8918bb24b379cf035722757c", 16) + g2To169x, _ := new(big.Int).SetString("13971d545d04b5639a6bd48a583d0e02bd46b717ae6404589d09ddcf8e0e1664", 16) + g2To169y, _ := new(big.Int).SetString("d9e7a36118a844d63b5778975a157e06f444516a730e37ee575079115e1a51a", 16) + g2To170x, _ := new(big.Int).SetString("2b6126f3432d0ab7149133ed284dc4b8f4c690a15d24a2012df8eafd1e584102", 16) + g2To170y, _ := new(big.Int).SetString("2ffed8dfeba141fb9d2ec5f5c4ea602a5dda428b2adbb7fdb83dbfd3cbe3ea36", 16) + g2To171x, _ := new(big.Int).SetString("f8ebff21f4475980919b8bf3a07e2bc3276c32aa8cc9be0d2b9e6ecda1eac62", 16) + g2To171y, _ := new(big.Int).SetString("2d5d4034ffbc3503e76dbfaab4569192bdc22c3297c74cbfc9faa36a1b168a61", 16) + g2To172x, _ := new(big.Int).SetString("f89469183d268e35a4e05882dbe1a6718f5246a18948c8bc421b21e2a1a8f90", 16) + g2To172y, _ := new(big.Int).SetString("c501e43476b33ec702b4a4cb163b64b2077f52e73fa21cf24c1d31e96a88c87", 16) + g2To173x, _ := new(big.Int).SetString("2a49dc5c6e7fe74ff00aaae703c26fe0916b22a76b66f11eb2f1c97a145c2fb9", 16) + g2To173y, _ := new(big.Int).SetString("a3d9acd50d6e2f9032d7708ffcc17a60ba20f887efaf42856b039cbc0a32483", 16) + g2To174x, _ := new(big.Int).SetString("195cdbddb30680997cfb2d5471c87c76f7cb4e61797ef85ec2c6f2d883b018f7", 16) + g2To174y, _ := new(big.Int).SetString("1bf08f1d94d1eeb02f28b7a1ae77f739697de40b672743de45182203b0fa20e0", 16) + g2To175x, _ := new(big.Int).SetString("19d00e5a8576bd737351c55095a19e59a94e4b7ebb3a505c54c194609719ff04", 16) + g2To175y, _ := new(big.Int).SetString("139cd47baae2140ee687714a64063dbcd8ee9c5ba41e8abec89d55eee1018d16", 16) + g2To176x, _ := new(big.Int).SetString("2f9e7f7800c6a9c653f48d4636d9dfad6e122c48c2ed4ad2e59551956563be7a", 16) + g2To176y, _ := new(big.Int).SetString("2414da5e0cd90394bd984c6886c3b7fc7d34a8418cc6898578ec0540d1d3bd48", 16) + g2To177x, _ := new(big.Int).SetString("2b2b8f5e7f644ee1c00937dc227da2e3de69762726d86036f4807b6aaae36c31", 16) + g2To177y, _ := new(big.Int).SetString("47853a419bb6b761e2bf666d6ca8f90e93ec84a6e5b425d5b74daf76ef9ccba", 16) + g2To178x, _ := new(big.Int).SetString("17b3259210a9a0e4339a3fe1caa896e56306745007e783373d47fe37c800b974", 16) + g2To178y, _ := new(big.Int).SetString("1ad16b73e4b32f988f8d9eebbee03224fe7bcbabbceb02973cd2e159c3a58e35", 16) + g2To179x, _ := new(big.Int).SetString("20be897f06fad7a92edf423db7ed12cb2bd2f6cb29c6bb8c6e394ff1aa3b3e9", 16) + g2To179y, _ := new(big.Int).SetString("7958a3fec65b6df34911a018aac0fa72ce89d92ba4bc67dcd06d1b4db184b90", 16) + g2To180x, _ := new(big.Int).SetString("253eba1d7cf606254ed9cff7613788a6d055495b779d9947a9cf46b9c1da311", 16) + g2To180y, _ := new(big.Int).SetString("1cabc4e498a23c3f5fcfcb887629459666b7513ac8c70ee43be83a8b4f5c4090", 16) + g2To181x, _ := new(big.Int).SetString("85fad322fc02ef1cd3e8473c56c6a1a26ecabadccf845a914d79c83beeb318a", 16) + g2To181y, _ := new(big.Int).SetString("3146780190be66eb78f6d6a2150da305d044739434f4d56ddccd160dafd43b1", 16) + g2To182x, _ := new(big.Int).SetString("22c33c8c594bf804b9c5a96835ed929dc99711327d5dc3723bb2bcfbb56f7fc4", 16) + g2To182y, _ := new(big.Int).SetString("2bc57d10207ca4af29f3a0a8eb864d8989e89371936e4544626fb999bf7a4fe2", 16) + g2To183x, _ := new(big.Int).SetString("225fdab8fe6cd876363d27075cdf0d01c209da61b1634b574a5d811cfae40700", 16) + g2To183y, _ := new(big.Int).SetString("1216b7c3e2adc07c3bef31771c7bb9e1d02f07ff3a5b74953c4fd5bf9a7a6dff", 16) + g2To184x, _ := new(big.Int).SetString("2a365a9299da85372ee0455de645cc2330e4c315d6250e3c0c72f10d77ac40e4", 16) + g2To184y, _ := new(big.Int).SetString("e54618ec8951f6b8be014e3f3bd12802b037ac48c2d0fd983f2343c5759c3db", 16) + g2To185x, _ := new(big.Int).SetString("2f31ee57ec760885e1e943c7d1602bff848dfde5cea6a4edf03476ad213591cc", 16) + g2To185y, _ := new(big.Int).SetString("bebf1d735e3aba48854ada67731601a179cd76b2bb690e6aed56a2fd963e9aa", 16) + g2To186x, _ := new(big.Int).SetString("242a698649332113b115eb3982fa5e454576bc05886f71489a31113fd737feb8", 16) + g2To186y, _ := new(big.Int).SetString("2e98af3e21c2fb8ecacd092858dc5ea8671f81867d371c9b1a010801ced7ae94", 16) + g2To187x, _ := new(big.Int).SetString("de2dce497fc378cf9875ea34483653ad21b40050a2be9f32713978fad365b6f", 16) + g2To187y, _ := new(big.Int).SetString("18818ed119e67e54970494ba4f5c5feb75fb8047779f910713af5793062885b1", 16) + g2To188x, _ := new(big.Int).SetString("143a5a6a69b89a9baf10bab59c62ddf7a747a8439541febe0964e2ea6e35147f", 16) + g2To188y, _ := new(big.Int).SetString("ace7c02bcdb98ce30c3b6c4b9d399287ebc911e8d44226bab0c3f06c1e7e717", 16) + g2To189x, _ := new(big.Int).SetString("18a2a13576df7d0be0daa67eea762a6894fc88a47a4b5d26bf6af3c826c91677", 16) + g2To189y, _ := new(big.Int).SetString("fc68277f2370379225a32315a25607a6341a371091589edeabda88ecc3d2a18", 16) + g2To190x, _ := new(big.Int).SetString("245ca02f753e3dcae81462215695192bb8de0ee8a3c195c1e2f735fb5510c791", 16) + g2To190y, _ := new(big.Int).SetString("22dfa007006c664c55102bfd2a79e5e79d89f3947b9f4556dc1ad20b80ff74d6", 16) + g2To191x, _ := new(big.Int).SetString("1ae696c232847d27e7b00f3ffeb36076d50514c4ee68bdcb08a892bce08f3ae9", 16) + g2To191y, _ := new(big.Int).SetString("1396047d0e2300586624c149388740f5c00e7cf4a7213598d8ca634cb7df215", 16) + g2To192x, _ := new(big.Int).SetString("2642b0d7d17b3ae1c6c1ddc1b018ecff936f658d2acc47474a330c8d6cd2d5f7", 16) + g2To192y, _ := new(big.Int).SetString("af05ffe2aa2cf4f27db4fc64b9bdc681e15f4fc2bb57f6ce23e2e1f89003c72", 16) + g2To193x, _ := new(big.Int).SetString("29d2b27d8d6db3791b3c64b2f61f5b2ab00d7f1ebc252cb97a9896a83c0e5d61", 16) + g2To193y, _ := new(big.Int).SetString("12a4333add04e8aad8478e3046268d23ed55292a96d7921460ce3d1f52ce28c6", 16) + g2To194x, _ := new(big.Int).SetString("252d6852ed68f5ff4420bf4ae9e5900a65fa7b2993dd3745e8dbceb436c5b94c", 16) + g2To194y, _ := new(big.Int).SetString("21df15aafa8dbc395e66f7bbf004139eb5b5bc1bcc071d61b02096cabcdc010e", 16) + g2To195x, _ := new(big.Int).SetString("1d115df69be93cf70619b0f005a92968a5ee561161a3dd3cc963c243447f391b", 16) + g2To195y, _ := new(big.Int).SetString("1555da4cf093578bc7a49518f3a49a24f57760186fd02a3eec3749ec72cf7ad1", 16) + g2To196x, _ := new(big.Int).SetString("2ad97c4b04758df61bf424363bd78665cbd24e20c13125ba2fc618312635a5db", 16) + g2To196y, _ := new(big.Int).SetString("f6b80288f228ae9b8cbfdb06a1362c5b4a4fa81cff38dffb36585b871ad747d", 16) + g2To197x, _ := new(big.Int).SetString("1385c47fcd92b51986c4ebf480519229ad13bb04255b24ffadf0d64a47c9c56c", 16) + g2To197y, _ := new(big.Int).SetString("1b5e107ac4e88ba1f6fe66fd02dffa0211cf505d105647adf3ecbcd475e22840", 16) + g2To198x, _ := new(big.Int).SetString("194ed40353d0e3fb0983152b872766ae5f1b4843ccdf294212a22af910755911", 16) + g2To198y, _ := new(big.Int).SetString("267aff505f0d68a76ebcb094b24df86ec272309368b812af86fa0bf390d148a9", 16) + g2To199x, _ := new(big.Int).SetString("2c87079e8db3eba1a27b14612b8f160b5a9452af0e76b942f61259a4119665cb", 16) + g2To199y, _ := new(big.Int).SetString("a26589e75263127c006b16e4c34db58765013d73c48a13c269b75e0fc34dac5", 16) + g2To200x, _ := new(big.Int).SetString("4f1cb752254ce1c92b01b10a5af73b1854c2c62841dc824781caaa56ddb87f1", 16) + g2To200y, _ := new(big.Int).SetString("2511226c45e2074e814befca9728e74afcbe0a2dbb8da9b61497527f7dc16fc7", 16) + g2To201x, _ := new(big.Int).SetString("1726c1df54ad0c394c53dbb2daa6b525d5337201f18ce540686af4310676a873", 16) + g2To201y, _ := new(big.Int).SetString("1ec01458207da40eb3b8483934f1281939e93fcbf8727a81eb45584ed2a3f61c", 16) + g2To202x, _ := new(big.Int).SetString("226c0947127b57567bc20c26508a688b2361f752eafe0072c005e589d8b9ef58", 16) + g2To202y, _ := new(big.Int).SetString("2dcfd6b7a3cb9423a68ca27d4e288f84067d1bca27ab18fa9a7b1c3cdc0876c3", 16) + g2To203x, _ := new(big.Int).SetString("1144eed8752daad82ce8c81c75d13e91c2d8a1368d8b7aece378bdb8f553f7d1", 16) + g2To203y, _ := new(big.Int).SetString("4d8b0b771a46ff8f2e0c18454b643f8908a5b96da44713263eaa0e7609149cb", 16) + g2To204x, _ := new(big.Int).SetString("1e6c7691756045003fd35cf5d449f1bf0c68b45b34905abd5fbf2d944251616", 16) + g2To204y, _ := new(big.Int).SetString("2c808764b3c2d8ba8b949a9f00efb3bac79481195ca7e34a146e913aff89859c", 16) + g2To205x, _ := new(big.Int).SetString("2846b54c3b22668dcbb8cccaae457e53d8b6f5ccac2b48128fc73c254c5e59b0", 16) + g2To205y, _ := new(big.Int).SetString("276f519936be5b3e2f91afc073e810e20473b09e963be92fe55aa82400eb9cfe", 16) + g2To206x, _ := new(big.Int).SetString("9ba7fc0c9257b32d14ef83b0b43ee1b4c875d4ddb70a1f8dff121bb0738d5f", 16) + g2To206y, _ := new(big.Int).SetString("e3b10575559f366d81f1b0076b0f2a8e57c4d11d5daba688a1926e17f22054b", 16) + g2To207x, _ := new(big.Int).SetString("2c8474246fb806dfd385f8358e4fe95f68fae97018d7db1a3fe43b670197d296", 16) + g2To207y, _ := new(big.Int).SetString("2d8ac3b14579252521443a0709069529e88578810f1c6cf4167f595f17c301e4", 16) + g2To208x, _ := new(big.Int).SetString("1ce9e693f0718940f328281f33872bf77e5160c73c0a6068e8855e4716316099", 16) + g2To208y, _ := new(big.Int).SetString("869d2297c13d0e7ed693bb3ef7cf72bade1c34dc9936633b458571bf7231764", 16) + g2To209x, _ := new(big.Int).SetString("25ef45e9014757ee53971d76a5c50e5b57b3daee31af4be46c9cd3d7a382068b", 16) + g2To209y, _ := new(big.Int).SetString("286b42c7d1cfc3387bb75355b59eccccddc593ba7c375c5ac7e8286ae03843e0", 16) + g2To210x, _ := new(big.Int).SetString("19bab36be51f69ef46db70c779126dadf51c2c4e31ed48a1623cebdce336b5d4", 16) + g2To210y, _ := new(big.Int).SetString("2854d9e8b595428c2accef0239bd031a4a2f37d751f1a992daf66e653b585686", 16) + g2To211x, _ := new(big.Int).SetString("1cbc558d34b723ebfa07c9630c96e81c74576d141801165e4710b5b0262c84db", 16) + g2To211y, _ := new(big.Int).SetString("2d4d9bfe1a7006a4eaf94fd681f467719a68a8231b6b46b496601a34cd8749ee", 16) + g2To212x, _ := new(big.Int).SetString("22e1b18187f92eab791a18a17bae522f674d76efd8c7188a18c9397350d25421", 16) + g2To212y, _ := new(big.Int).SetString("ad500831e4522a7fe456bd44967dbb8f56b3a7f36ac51ae95c3cbebd4e0ca7f", 16) + g2To213x, _ := new(big.Int).SetString("6b3c6bec4d1982470c5f1a033e43fca9cf142639d8d8c1e08e0390a4c5a7da4", 16) + g2To213y, _ := new(big.Int).SetString("1de78da2ba6a6e08b0b7f5a22bd59fe91abc05909196640e50e1d21741a4286d", 16) + g2To214x, _ := new(big.Int).SetString("18afa4a6bf750334eac73d2f93349a25819827c4f2e3b42ce8144f0c090e1b12", 16) + g2To214y, _ := new(big.Int).SetString("2bde7825dce391b931ca81ee1139e6d76760072c81ba53dd2db24ddc28694e92", 16) + g2To215x, _ := new(big.Int).SetString("28234f55a1ef2d10c29341f59be69a2090c49b57bbc64a58809d4d4b9a050326", 16) + g2To215y, _ := new(big.Int).SetString("f0d1a871d0f58ae80723f19adf08b8b04a9b11a1f0fb7c38c1dfb3b830939ab", 16) + g2To216x, _ := new(big.Int).SetString("1f87eb4ecf4979737f4ce5493a5d744349f50675c1e169bbf31689c3e8c04308", 16) + g2To216y, _ := new(big.Int).SetString("23d45d0cc26f83da885d957417f958f48d15afe583412df36ff2c46b0fae6198", 16) + g2To217x, _ := new(big.Int).SetString("265fe341276ba4ef03a3e1632e3eacc3c77af43355915017604e3297a2575e0d", 16) + g2To217y, _ := new(big.Int).SetString("2d96ebc6d29672f1fc80d5f711efc24b099d9e5805d6052db96dc6bfe58e8516", 16) + g2To218x, _ := new(big.Int).SetString("20adf422bb92e8ebca244338030fff6e5750b73e3b59bef4cf27f9b8b43d86cc", 16) + g2To218y, _ := new(big.Int).SetString("46d604bb8ba0f91062a910941f8640c12fee8aed73e49f47364de3375b82881", 16) + g2To219x, _ := new(big.Int).SetString("1b8b0974839d00fcb8ce8411303de0a7c1eb3a4fee51cfc81bc5555cf11e72d1", 16) + g2To219y, _ := new(big.Int).SetString("10f9785ecc740f71e35ac4bb5667d868c7e0f41d7ac008fe1002b98c74a13550", 16) + g2To220x, _ := new(big.Int).SetString("17804f51d82ccacb1f5c235f9229729042bba8586cf4439b4da2bf3ce9e3c6b4", 16) + g2To220y, _ := new(big.Int).SetString("4f911ef9571ad0f05275041c06fb56dd3ae9d6ca9faf59a98329140274dd0e3", 16) + g2To221x, _ := new(big.Int).SetString("2fcf22a313b481313f27289a45680aaf8805fe788fbdea9964bee963b47bbd6", 16) + g2To221y, _ := new(big.Int).SetString("29a1c6fa0c3cc610d930ef1748fecc57aae4d9b73762168af70432d5300acc6c", 16) + g2To222x, _ := new(big.Int).SetString("19d7f00e9da0ff3c5e36640d537dc9d8b297918680f8ef92ec5fb5c237e71d94", 16) + g2To222y, _ := new(big.Int).SetString("2b1aaab94d44134f97e647d973ec4f5db5627e6fd219f3f3f1e08f487f0b088e", 16) + g2To223x, _ := new(big.Int).SetString("1f84c3be21eedc0a6f3a0e8ed81866d2517d1ee09fb86a51601354cbc282c9ae", 16) + g2To223y, _ := new(big.Int).SetString("8b172a26e838681d0c4d3cfb013abf392141ee2f871903f94966ab2e7c67995", 16) + g2To224x, _ := new(big.Int).SetString("1803f42b6154c73df3776a86da598b72c820e0a39058a6272c97ec432746a253", 16) + g2To224y, _ := new(big.Int).SetString("11e4372b105bbbc4ee89496343eddd5f299ca4199190455953e6a4d5d0331172", 16) + g2To225x, _ := new(big.Int).SetString("13b103f06dec9eb67eeb1252f52e8ff88c2164c330742569ba6c0c1d79b43d58", 16) + g2To225y, _ := new(big.Int).SetString("24983f8c5d29be49c03a61673aa24b73b20f790d821a1832b61276203854ed41", 16) + g2To226x, _ := new(big.Int).SetString("2e1389cf976ee7d9ce2992c62c6bbd5268b1096f6e89c6870c25a4737c154fd4", 16) + g2To226y, _ := new(big.Int).SetString("2026565add482c9e333bf0f03cc1a0e6de8a45e2fcc79f298f1588852ebc239b", 16) + g2To227x, _ := new(big.Int).SetString("27816d71c08ddc593972e5d647880eb1c9fba52ddc130629a4867ec559903e7a", 16) + g2To227y, _ := new(big.Int).SetString("2d4342a5b94a716d13ddc4e034263d2526fa8f9dc4672b0490d326a0b2c24104", 16) + g2To228x, _ := new(big.Int).SetString("3e8748e8aa834f74f78325f4cade8beb5b2cd987e003dd2e01ca1e507b882ea", 16) + g2To228y, _ := new(big.Int).SetString("14e84a9b617bc3bbc51c7580aed6af624f108084aaa51c57c0f6bb42966a06e3", 16) + g2To229x, _ := new(big.Int).SetString("2e0333e017005d5580d8f37930910e83a4ec1cbb81513d5c4497e07bb4759ac3", 16) + g2To229y, _ := new(big.Int).SetString("2efa0d2056e33484bfd0d28038a697b52071ae3daad55e734c4f1788be4e26e0", 16) + g2To230x, _ := new(big.Int).SetString("66dd4f74bde89af1e484ee7999209deec62204f6fadfe137a007bd1b8a41322", 16) + g2To230y, _ := new(big.Int).SetString("1fafe097739d80d7254bcb0604d47a42a19606e61a5c9464b74c343740615c6d", 16) + g2To231x, _ := new(big.Int).SetString("d3abc9d71dd3d76ec536fdd34c3d535ccd3b2c92e344b04ea63e7a95bf1d40d", 16) + g2To231y, _ := new(big.Int).SetString("4e2d118cd7c19f8b38b28570d982bdf9398ec57fb2bb0d7e8f31e4c8ea3a7e", 16) + g2To232x, _ := new(big.Int).SetString("17a6c2b336d61bf255af78c33a67cf1de2896995df7e83f8241109a184dbbea7", 16) + g2To232y, _ := new(big.Int).SetString("123d241884de16c8078118cf8168546668a7c354c1aadc61505121f1c69318ee", 16) + g2To233x, _ := new(big.Int).SetString("a86bd18c2e2dc328a7fff99345d131988bdb003f53487da1d9affd07dfa4caa", 16) + g2To233y, _ := new(big.Int).SetString("270232b8aa979307cef134be75f5d025d01c3c6ba2f66499e3615e5b2dd00781", 16) + g2To234x, _ := new(big.Int).SetString("1e355fcab47dd4264a85652319a0dddf1ba3889eaaa9e05f21247e4202bda1a5", 16) + g2To234y, _ := new(big.Int).SetString("d60a88eb2f714752b7aecdeb65939828faa6e1e38e8ea1606a7a15e71e7a194", 16) + g2To235x, _ := new(big.Int).SetString("1eb1ba9d3cb37f1e320b57a13707f1b4b40333e1d9893d2d9c6012f5667001c9", 16) + g2To235y, _ := new(big.Int).SetString("c1dea44b0e7ba28967fe607c50f983c3bdec527612e81245029958308f7cbbb", 16) + g2To236x, _ := new(big.Int).SetString("dcd731a87dfac8e27719ecbe1098c415477febd6f06a227fb45f0b8b0b16d9", 16) + g2To236y, _ := new(big.Int).SetString("27218920b62eb55167704aa95c9929a79ead041e57e1f26d5f2b3affa474655b", 16) + g2To237x, _ := new(big.Int).SetString("3058fe52fd5ea77191aba39e84854d7d3f317390b1d869536d81544fad1a7e7f", 16) + g2To237y, _ := new(big.Int).SetString("1f64fd77c47fad6766218a0ca3e9b34b6207ed59f8eb2f902e1548d156584a90", 16) + g2To238x, _ := new(big.Int).SetString("1b5956deed90482c1cc4989e936ca265252d6dd8159a13270b78248b30843363", 16) + g2To238y, _ := new(big.Int).SetString("72ff5f961d1d225dec43bffd5f031562c9087a3a032305b1b716cdd158da5ca", 16) + g2To239x, _ := new(big.Int).SetString("1ee79768b58b0bbebf614d41fcfd9e17a88c38b41d697a2104a931a3cf3106d6", 16) + g2To239y, _ := new(big.Int).SetString("2ac2a26c534a3a84f696dd581ee7063f8910ca58954e436470d1fcc17dbbaad2", 16) + g2To240x, _ := new(big.Int).SetString("13932be07d7ef64690655fe3541d25b47caa20f0dba7e5843dc309e47fd4036", 16) + g2To240y, _ := new(big.Int).SetString("68daa9f3433ea9cfe8ab217593263464d3f3796d224d0c837ceb1ba5a388b5c", 16) + g2To241x, _ := new(big.Int).SetString("28982c2db4c7cc3f0ac38ae0d7a1774e276872fc2fc9be7b97038d1b7deeadad", 16) + g2To241y, _ := new(big.Int).SetString("fcd19a4ed741eac34e323909b7407f5a612a101c0d5687ea381bd36fd92d2c", 16) + g2To242x, _ := new(big.Int).SetString("233baee1bae9440f6456b6172b7b08e3b659265362d198e5196ef41d3a2d4b5a", 16) + g2To242y, _ := new(big.Int).SetString("2eae64ae6c81702e537c49c50c434556a49e9c734bf59580c86f19f2a0fb3374", 16) + g2To243x, _ := new(big.Int).SetString("2d5968f58c658153ee254d4bded6784e5e057251477b539a6d91f087985338ea", 16) + g2To243y, _ := new(big.Int).SetString("e0d8224d8090e8f7958bf46ea5f8d2d02370bbab1f4a449e50fee36e3f70773", 16) + g2To244x, _ := new(big.Int).SetString("282ba63c4d8d5c9d2477af22fa57cbb3618501dd22727c2a3244988179c98d2d", 16) + g2To244y, _ := new(big.Int).SetString("17957e0d498bd3694c8e62242bc37535cd445bf2a773ad9443cb3771fe113854", 16) + g2To245x, _ := new(big.Int).SetString("156e5523efb7270e38e80e154849f705a6184365b2261f3db870014428425d83", 16) + g2To245y, _ := new(big.Int).SetString("2a5e19cd3faf740e1f3ec427897c8da2804b0479bad28ce00ae15b088b04038b", 16) + g2To246x, _ := new(big.Int).SetString("7edfbd9cb99499052ada8d94e740625888f260adc45fcb5fe9be555b3221d74", 16) + g2To246y, _ := new(big.Int).SetString("1fd8c3a97911b6eac726e002fd3b84eceaa2b08a57e3df4227067fb5896aaed0", 16) + g2To247x, _ := new(big.Int).SetString("1725b4a59ea736ec816444dc53dbdf7e78d9194d537fa199c2883a38c60a06ed", 16) + g2To247y, _ := new(big.Int).SetString("249e0d5a519ef3f2ab6240aba00e912927ad4151be494765e2e31a1566828b06", 16) + g2To248x, _ := new(big.Int).SetString("5483b9dfbeb5b9fb31fd52b885335da4b23cdf83f2607d37e3fcbe112a85365", 16) + g2To248y, _ := new(big.Int).SetString("24e0ba9901789eaa6a0dc74bbf22debf9891bc5c03991db95f69df9c25ca6fcf", 16) + g2To249x, _ := new(big.Int).SetString("65a6b8b56220596ad72f24aea44c1d62f4c1544f23d4e968112d3d57f76c9b5", 16) + g2To249y, _ := new(big.Int).SetString("2d8d82657d6f9f9d5676cece3b7547be1b2ab34879690cd1d231716891525cf7", 16) + g2To250x, _ := new(big.Int).SetString("21f2133247ee84c3bd8c96271b6ad6482744b3367a13f0260535a908caea1d20", 16) + g2To250y, _ := new(big.Int).SetString("85b3a99f7d8418907dc897428443fae817137980fe5195974b11d212c6f2171", 16) + g2To251x, _ := new(big.Int).SetString("29eed773adae30e41534a519179a5193ace5c32048775a50d6e1a7f998c5636b", 16) + g2To251y, _ := new(big.Int).SetString("187868b2ac41a139f3563229e0ee02d65d27e38de3276ad2a4fd503c4f920010", 16) + g2To252x, _ := new(big.Int).SetString("ebf18cffd536c5521028aeab7afb898bf91d8abde80f16a70ab404b49dde064", 16) + g2To252y, _ := new(big.Int).SetString("2558d4421ddf231cf775888494c86ac8883a92df8b171dbc7e0f26978c2f1533", 16) + g2To253x, _ := new(big.Int).SetString("9a5c6756cfc787c9df52f40fa211edfed26f0303bb2e404fa53d486a8ec7963", 16) + g2To253y, _ := new(big.Int).SetString("28e47c414278b7f61d2e58077a5d6f12ebcd88950385108a733284e2861b8f81", 16) + g2To254x, _ := new(big.Int).SetString("3d541efe3a8777fd5cd6aea697dc2f83706644289adaa9380e68bc150476b0b", 16) + g2To254y, _ := new(big.Int).SetString("23fd426daa5672681e63f3c44963a131182ea5f8b9dffc4e4067f321b77648a2", 16) + g2To255x, _ := new(big.Int).SetString("18ba548c687cb306f9996e95ebff7530528177141ebd26680d2d994ea1f5b4dd", 16) + g2To255y, _ := new(big.Int).SetString("1a34ebd78433b90b62760d37f89ae069a85651a109939e329a4f266ce94c9d64", 16) return CurveParams{ A: big.NewInt(0), @@ -1078,8 +1074,8 @@ func GetBN254Params() CurveParams { Gx: gx, Gy: gy, - Gmx: [257]*big.Int{g3x, g5x, g7x, g8x, g16x, g32x, g64x, g128x, g256x, g512x, g1024x, g2048x, g4096x, g8192x, g16384x, g32768x, g65536x, g131072x, g262144x, g524288x, g1048576x, g2097152x, g4194304x, g8388608x, g16777216x, g33554432x, g67108864x, g134217728x, g268435456x, g536870912x, g1073741824x, g2147483648x, g4294967296x, g8589934592x, g17179869184x, g34359738368x, g68719476736x, g137438953472x, g274877906944x, g549755813888x, g1099511627776x, g2199023255552x, g4398046511104x, g8796093022208x, g17592186044416x, g35184372088832x, g70368744177664x, g140737488355328x, g281474976710656x, g562949953421312x, g1125899906842624x, g2251799813685248x, g4503599627370496x, g9007199254740992x, g18014398509481984x, g36028797018963968x, g72057594037927936x, g144115188075855872x, g288230376151711744x, g576460752303423488x, g1152921504606846976x, g2305843009213693952x, g4611686018427387904x, g9223372036854775808x, g18446744073709551616x, g36893488147419103232x, g73786976294838206464x, g147573952589676412928x, g295147905179352825856x, g590295810358705651712x, g1180591620717411303424x, g2361183241434822606848x, g4722366482869645213696x, g9444732965739290427392x, g18889465931478580854784x, g37778931862957161709568x, g75557863725914323419136x, g151115727451828646838272x, g302231454903657293676544x, g604462909807314587353088x, g1208925819614629174706176x, g2417851639229258349412352x, g4835703278458516698824704x, g9671406556917033397649408x, g19342813113834066795298816x, g38685626227668133590597632x, g77371252455336267181195264x, g154742504910672534362390528x, g309485009821345068724781056x, g618970019642690137449562112x, g1237940039285380274899124224x, g2475880078570760549798248448x, g4951760157141521099596496896x, g9903520314283042199192993792x, g19807040628566084398385987584x, g39614081257132168796771975168x, g79228162514264337593543950336x, g158456325028528675187087900672x, g316912650057057350374175801344x, g633825300114114700748351602688x, g1267650600228229401496703205376x, g2535301200456458802993406410752x, g5070602400912917605986812821504x, g10141204801825835211973625643008x, g20282409603651670423947251286016x, g40564819207303340847894502572032x, g81129638414606681695789005144064x, g162259276829213363391578010288128x, g324518553658426726783156020576256x, g649037107316853453566312041152512x, g1298074214633706907132624082305024x, g2596148429267413814265248164610048x, g5192296858534827628530496329220096x, g10384593717069655257060992658440192x, g20769187434139310514121985316880384x, g41538374868278621028243970633760768x, g83076749736557242056487941267521536x, g166153499473114484112975882535043072x, g332306998946228968225951765070086144x, g664613997892457936451903530140172288x, g1329227995784915872903807060280344576x, g2658455991569831745807614120560689152x, g5316911983139663491615228241121378304x, g10633823966279326983230456482242756608x, g21267647932558653966460912964485513216x, g42535295865117307932921825928971026432x, g85070591730234615865843651857942052864x, g170141183460469231731687303715884105728x, g340282366920938463463374607431768211456x, g680564733841876926926749214863536422912x, g1361129467683753853853498429727072845824x, g2722258935367507707706996859454145691648x, g5444517870735015415413993718908291383296x, g10889035741470030830827987437816582766592x, g21778071482940061661655974875633165533184x, g43556142965880123323311949751266331066368x, g87112285931760246646623899502532662132736x, g174224571863520493293247799005065324265472x, g348449143727040986586495598010130648530944x, g696898287454081973172991196020261297061888x, g1393796574908163946345982392040522594123776x, g2787593149816327892691964784081045188247552x, g5575186299632655785383929568162090376495104x, g11150372599265311570767859136324180752990208x, g22300745198530623141535718272648361505980416x, g44601490397061246283071436545296723011960832x, g89202980794122492566142873090593446023921664x, g178405961588244985132285746181186892047843328x, g356811923176489970264571492362373784095686656x, g713623846352979940529142984724747568191373312x, g1427247692705959881058285969449495136382746624x, g2854495385411919762116571938898990272765493248x, g5708990770823839524233143877797980545530986496x, g11417981541647679048466287755595961091061972992x, g22835963083295358096932575511191922182123945984x, g45671926166590716193865151022383844364247891968x, g91343852333181432387730302044767688728495783936x, g182687704666362864775460604089535377456991567872x, g365375409332725729550921208179070754913983135744x, g730750818665451459101842416358141509827966271488x, g1461501637330902918203684832716283019655932542976x, g2923003274661805836407369665432566039311865085952x, g5846006549323611672814739330865132078623730171904x, g11692013098647223345629478661730264157247460343808x, g23384026197294446691258957323460528314494920687616x, g46768052394588893382517914646921056628989841375232x, g93536104789177786765035829293842113257979682750464x, g187072209578355573530071658587684226515959365500928x, g374144419156711147060143317175368453031918731001856x, g748288838313422294120286634350736906063837462003712x, g1496577676626844588240573268701473812127674924007424x, g2993155353253689176481146537402947624255349848014848x, g5986310706507378352962293074805895248510699696029696x, g11972621413014756705924586149611790497021399392059392x, g23945242826029513411849172299223580994042798784118784x, g47890485652059026823698344598447161988085597568237568x, g95780971304118053647396689196894323976171195136475136x, g191561942608236107294793378393788647952342390272950272x, g383123885216472214589586756787577295904684780545900544x, g766247770432944429179173513575154591809369561091801088x, g1532495540865888858358347027150309183618739122183602176x, g3064991081731777716716694054300618367237478244367204352x, g6129982163463555433433388108601236734474956488734408704x, g12259964326927110866866776217202473468949912977468817408x, g24519928653854221733733552434404946937899825954937634816x, g49039857307708443467467104868809893875799651909875269632x, g98079714615416886934934209737619787751599303819750539264x, g196159429230833773869868419475239575503198607639501078528x, g392318858461667547739736838950479151006397215279002157056x, g784637716923335095479473677900958302012794430558004314112x, g1569275433846670190958947355801916604025588861116008628224x, g3138550867693340381917894711603833208051177722232017256448x, g6277101735386680763835789423207666416102355444464034512896x, g12554203470773361527671578846415332832204710888928069025792x, g25108406941546723055343157692830665664409421777856138051584x, g50216813883093446110686315385661331328818843555712276103168x, g100433627766186892221372630771322662657637687111424552206336x, g200867255532373784442745261542645325315275374222849104412672x, g401734511064747568885490523085290650630550748445698208825344x, g803469022129495137770981046170581301261101496891396417650688x, g1606938044258990275541962092341162602522202993782792835301376x, g3213876088517980551083924184682325205044405987565585670602752x, g6427752177035961102167848369364650410088811975131171341205504x, g12855504354071922204335696738729300820177623950262342682411008x, g25711008708143844408671393477458601640355247900524685364822016x, g51422017416287688817342786954917203280710495801049370729644032x, g102844034832575377634685573909834406561420991602098741459288064x, g205688069665150755269371147819668813122841983204197482918576128x, g411376139330301510538742295639337626245683966408394965837152256x, g822752278660603021077484591278675252491367932816789931674304512x, g1645504557321206042154969182557350504982735865633579863348609024x, g3291009114642412084309938365114701009965471731267159726697218048x, g6582018229284824168619876730229402019930943462534319453394436096x, g13164036458569648337239753460458804039861886925068638906788872192x, g26328072917139296674479506920917608079723773850137277813577744384x, g52656145834278593348959013841835216159447547700274555627155488768x, g105312291668557186697918027683670432318895095400549111254310977536x, g210624583337114373395836055367340864637790190801098222508621955072x, g421249166674228746791672110734681729275580381602196445017243910144x, g842498333348457493583344221469363458551160763204392890034487820288x, g1684996666696914987166688442938726917102321526408785780068975640576x, g3369993333393829974333376885877453834204643052817571560137951281152x, g6739986666787659948666753771754907668409286105635143120275902562304x, g13479973333575319897333507543509815336818572211270286240551805124608x, g26959946667150639794667015087019630673637144422540572481103610249216x, g53919893334301279589334030174039261347274288845081144962207220498432x, g107839786668602559178668060348078522694548577690162289924414440996864x, g215679573337205118357336120696157045389097155380324579848828881993728x, g431359146674410236714672241392314090778194310760649159697657763987456x, g862718293348820473429344482784628181556388621521298319395315527974912x, g1725436586697640946858688965569256363112777243042596638790631055949824x, g3450873173395281893717377931138512726225554486085193277581262111899648x, g6901746346790563787434755862277025452451108972170386555162524223799296x, g13803492693581127574869511724554050904902217944340773110325048447598592x, g27606985387162255149739023449108101809804435888681546220650096895197184x, g55213970774324510299478046898216203619608871777363092441300193790394368x, g110427941548649020598956093796432407239217743554726184882600387580788736x, g220855883097298041197912187592864814478435487109452369765200775161577472x, g441711766194596082395824375185729628956870974218904739530401550323154944x, g883423532389192164791648750371459257913741948437809479060803100646309888x, g1766847064778384329583297500742918515827483896875618958121606201292619776x, g3533694129556768659166595001485837031654967793751237916243212402585239552x, g7067388259113537318333190002971674063309935587502475832486424805170479104x, g14134776518227074636666380005943348126619871175004951664972849610340958208x, g28269553036454149273332760011886696253239742350009903329945699220681916416x, g56539106072908298546665520023773392506479484700019806659891398441363832832x, g113078212145816597093331040047546785012958969400039613319782796882727665664x, g226156424291633194186662080095093570025917938800079226639565593765455331328x, g452312848583266388373324160190187140051835877600158453279131187530910662656x, g904625697166532776746648320380374280103671755200316906558262375061821325312x, g1809251394333065553493296640760748560207343510400633813116524750123642650624x, g3618502788666131106986593281521497120414687020801267626233049500247285301248x, g7237005577332262213973186563042994240829374041602535252466099000494570602496x, g14474011154664524427946373126085988481658748083205070504932198000989141204992x, g28948022309329048855892746252171976963317496166410141009864396001978282409984x, g57896044618658097711785492504343953926634992332820282019728792003956564819968x, g115792089237316195423570985008687907853269984665640564039457584007913129639936x}, - Gmy: [257]*big.Int{g3y, g5y, g7y, g8y, g16y, g32y, g64y, g128y, g256y, g512y, g1024y, g2048y, g4096y, g8192y, g16384y, g32768y, g65536y, g131072y, g262144y, g524288y, g1048576y, g2097152y, g4194304y, g8388608y, g16777216y, g33554432y, g67108864y, g134217728y, g268435456y, g536870912y, g1073741824y, g2147483648y, g4294967296y, g8589934592y, g17179869184y, g34359738368y, g68719476736y, g137438953472y, g274877906944y, g549755813888y, g1099511627776y, g2199023255552y, g4398046511104y, g8796093022208y, g17592186044416y, g35184372088832y, g70368744177664y, g140737488355328y, g281474976710656y, g562949953421312y, g1125899906842624y, g2251799813685248y, g4503599627370496y, g9007199254740992y, g18014398509481984y, g36028797018963968y, g72057594037927936y, g144115188075855872y, g288230376151711744y, g576460752303423488y, g1152921504606846976y, g2305843009213693952y, g4611686018427387904y, g9223372036854775808y, g18446744073709551616y, g36893488147419103232y, g73786976294838206464y, g147573952589676412928y, g295147905179352825856y, g590295810358705651712y, g1180591620717411303424y, g2361183241434822606848y, g4722366482869645213696y, g9444732965739290427392y, g18889465931478580854784y, g37778931862957161709568y, g75557863725914323419136y, g151115727451828646838272y, g302231454903657293676544y, g604462909807314587353088y, g1208925819614629174706176y, g2417851639229258349412352y, g4835703278458516698824704y, g9671406556917033397649408y, g19342813113834066795298816y, g38685626227668133590597632y, g77371252455336267181195264y, g154742504910672534362390528y, g309485009821345068724781056y, g618970019642690137449562112y, g1237940039285380274899124224y, g2475880078570760549798248448y, g4951760157141521099596496896y, g9903520314283042199192993792y, g19807040628566084398385987584y, g39614081257132168796771975168y, g79228162514264337593543950336y, g158456325028528675187087900672y, g316912650057057350374175801344y, g633825300114114700748351602688y, g1267650600228229401496703205376y, g2535301200456458802993406410752y, g5070602400912917605986812821504y, g10141204801825835211973625643008y, g20282409603651670423947251286016y, g40564819207303340847894502572032y, g81129638414606681695789005144064y, g162259276829213363391578010288128y, g324518553658426726783156020576256y, g649037107316853453566312041152512y, g1298074214633706907132624082305024y, g2596148429267413814265248164610048y, g5192296858534827628530496329220096y, g10384593717069655257060992658440192y, g20769187434139310514121985316880384y, g41538374868278621028243970633760768y, g83076749736557242056487941267521536y, g166153499473114484112975882535043072y, g332306998946228968225951765070086144y, g664613997892457936451903530140172288y, g1329227995784915872903807060280344576y, g2658455991569831745807614120560689152y, g5316911983139663491615228241121378304y, g10633823966279326983230456482242756608y, g21267647932558653966460912964485513216y, g42535295865117307932921825928971026432y, g85070591730234615865843651857942052864y, g170141183460469231731687303715884105728y, g340282366920938463463374607431768211456y, g680564733841876926926749214863536422912y, g1361129467683753853853498429727072845824y, g2722258935367507707706996859454145691648y, g5444517870735015415413993718908291383296y, g10889035741470030830827987437816582766592y, g21778071482940061661655974875633165533184y, g43556142965880123323311949751266331066368y, g87112285931760246646623899502532662132736y, g174224571863520493293247799005065324265472y, g348449143727040986586495598010130648530944y, g696898287454081973172991196020261297061888y, g1393796574908163946345982392040522594123776y, g2787593149816327892691964784081045188247552y, g5575186299632655785383929568162090376495104y, g11150372599265311570767859136324180752990208y, g22300745198530623141535718272648361505980416y, g44601490397061246283071436545296723011960832y, g89202980794122492566142873090593446023921664y, g178405961588244985132285746181186892047843328y, g356811923176489970264571492362373784095686656y, g713623846352979940529142984724747568191373312y, g1427247692705959881058285969449495136382746624y, g2854495385411919762116571938898990272765493248y, g5708990770823839524233143877797980545530986496y, g11417981541647679048466287755595961091061972992y, g22835963083295358096932575511191922182123945984y, g45671926166590716193865151022383844364247891968y, g91343852333181432387730302044767688728495783936y, g182687704666362864775460604089535377456991567872y, g365375409332725729550921208179070754913983135744y, g730750818665451459101842416358141509827966271488y, g1461501637330902918203684832716283019655932542976y, g2923003274661805836407369665432566039311865085952y, g5846006549323611672814739330865132078623730171904y, g11692013098647223345629478661730264157247460343808y, g23384026197294446691258957323460528314494920687616y, g46768052394588893382517914646921056628989841375232y, g93536104789177786765035829293842113257979682750464y, g187072209578355573530071658587684226515959365500928y, g374144419156711147060143317175368453031918731001856y, g748288838313422294120286634350736906063837462003712y, g1496577676626844588240573268701473812127674924007424y, g2993155353253689176481146537402947624255349848014848y, g5986310706507378352962293074805895248510699696029696y, g11972621413014756705924586149611790497021399392059392y, g23945242826029513411849172299223580994042798784118784y, g47890485652059026823698344598447161988085597568237568y, g95780971304118053647396689196894323976171195136475136y, g191561942608236107294793378393788647952342390272950272y, g383123885216472214589586756787577295904684780545900544y, g766247770432944429179173513575154591809369561091801088y, g1532495540865888858358347027150309183618739122183602176y, g3064991081731777716716694054300618367237478244367204352y, g6129982163463555433433388108601236734474956488734408704y, g12259964326927110866866776217202473468949912977468817408y, g24519928653854221733733552434404946937899825954937634816y, g49039857307708443467467104868809893875799651909875269632y, g98079714615416886934934209737619787751599303819750539264y, g196159429230833773869868419475239575503198607639501078528y, g392318858461667547739736838950479151006397215279002157056y, g784637716923335095479473677900958302012794430558004314112y, g1569275433846670190958947355801916604025588861116008628224y, g3138550867693340381917894711603833208051177722232017256448y, g6277101735386680763835789423207666416102355444464034512896y, g12554203470773361527671578846415332832204710888928069025792y, g25108406941546723055343157692830665664409421777856138051584y, g50216813883093446110686315385661331328818843555712276103168y, g100433627766186892221372630771322662657637687111424552206336y, g200867255532373784442745261542645325315275374222849104412672y, g401734511064747568885490523085290650630550748445698208825344y, g803469022129495137770981046170581301261101496891396417650688y, g1606938044258990275541962092341162602522202993782792835301376y, g3213876088517980551083924184682325205044405987565585670602752y, g6427752177035961102167848369364650410088811975131171341205504y, g12855504354071922204335696738729300820177623950262342682411008y, g25711008708143844408671393477458601640355247900524685364822016y, g51422017416287688817342786954917203280710495801049370729644032y, g102844034832575377634685573909834406561420991602098741459288064y, g205688069665150755269371147819668813122841983204197482918576128y, g411376139330301510538742295639337626245683966408394965837152256y, g822752278660603021077484591278675252491367932816789931674304512y, g1645504557321206042154969182557350504982735865633579863348609024y, g3291009114642412084309938365114701009965471731267159726697218048y, g6582018229284824168619876730229402019930943462534319453394436096y, g13164036458569648337239753460458804039861886925068638906788872192y, g26328072917139296674479506920917608079723773850137277813577744384y, g52656145834278593348959013841835216159447547700274555627155488768y, g105312291668557186697918027683670432318895095400549111254310977536y, g210624583337114373395836055367340864637790190801098222508621955072y, g421249166674228746791672110734681729275580381602196445017243910144y, g842498333348457493583344221469363458551160763204392890034487820288y, g1684996666696914987166688442938726917102321526408785780068975640576y, g3369993333393829974333376885877453834204643052817571560137951281152y, g6739986666787659948666753771754907668409286105635143120275902562304y, g13479973333575319897333507543509815336818572211270286240551805124608y, g26959946667150639794667015087019630673637144422540572481103610249216y, g53919893334301279589334030174039261347274288845081144962207220498432y, g107839786668602559178668060348078522694548577690162289924414440996864y, g215679573337205118357336120696157045389097155380324579848828881993728y, g431359146674410236714672241392314090778194310760649159697657763987456y, g862718293348820473429344482784628181556388621521298319395315527974912y, g1725436586697640946858688965569256363112777243042596638790631055949824y, g3450873173395281893717377931138512726225554486085193277581262111899648y, g6901746346790563787434755862277025452451108972170386555162524223799296y, g13803492693581127574869511724554050904902217944340773110325048447598592y, g27606985387162255149739023449108101809804435888681546220650096895197184y, g55213970774324510299478046898216203619608871777363092441300193790394368y, g110427941548649020598956093796432407239217743554726184882600387580788736y, g220855883097298041197912187592864814478435487109452369765200775161577472y, g441711766194596082395824375185729628956870974218904739530401550323154944y, g883423532389192164791648750371459257913741948437809479060803100646309888y, g1766847064778384329583297500742918515827483896875618958121606201292619776y, g3533694129556768659166595001485837031654967793751237916243212402585239552y, g7067388259113537318333190002971674063309935587502475832486424805170479104y, g14134776518227074636666380005943348126619871175004951664972849610340958208y, g28269553036454149273332760011886696253239742350009903329945699220681916416y, g56539106072908298546665520023773392506479484700019806659891398441363832832y, g113078212145816597093331040047546785012958969400039613319782796882727665664y, g226156424291633194186662080095093570025917938800079226639565593765455331328y, g452312848583266388373324160190187140051835877600158453279131187530910662656y, g904625697166532776746648320380374280103671755200316906558262375061821325312y, g1809251394333065553493296640760748560207343510400633813116524750123642650624y, g3618502788666131106986593281521497120414687020801267626233049500247285301248y, g7237005577332262213973186563042994240829374041602535252466099000494570602496y, g14474011154664524427946373126085988481658748083205070504932198000989141204992y, g28948022309329048855892746252171976963317496166410141009864396001978282409984y, g57896044618658097711785492504343953926634992332820282019728792003956564819968y, g115792089237316195423570985008687907853269984665640564039457584007913129639936y}, + Gmx: [256]*big.Int{g3x, g5x, g7x, g2To3x, g2To4x, g2To5x, g2To6x, g2To7x, g2To8x, g2To9x, g2To10x, g2To11x, g2To12x, g2To13x, g2To14x, g2To15x, g2To16x, g2To17x, g2To18x, g2To19x, g2To20x, g2To21x, g2To22x, g2To23x, g2To24x, g2To25x, g2To26x, g2To27x, g2To28x, g2To29x, g2To30x, g2To31x, g2To32x, g2To33x, g2To34x, g2To35x, g2To36x, g2To37x, g2To38x, g2To39x, g2To40x, g2To41x, g2To42x, g2To43x, g2To44x, g2To45x, g2To46x, g2To47x, g2To48x, g2To49x, g2To50x, g2To51x, g2To52x, g2To53x, g2To54x, g2To55x, g2To56x, g2To57x, g2To58x, g2To59x, g2To60x, g2To61x, g2To62x, g2To63x, g2To64x, g2To65x, g2To66x, g2To67x, g2To68x, g2To69x, g2To70x, g2To71x, g2To72x, g2To73x, g2To74x, g2To75x, g2To76x, g2To77x, g2To78x, g2To79x, g2To80x, g2To81x, g2To82x, g2To83x, g2To84x, g2To85x, g2To86x, g2To87x, g2To88x, g2To89x, g2To90x, g2To91x, g2To92x, g2To93x, g2To94x, g2To95x, g2To96x, g2To97x, g2To98x, g2To99x, g2To100x, g2To101x, g2To102x, g2To103x, g2To104x, g2To105x, g2To106x, g2To107x, g2To108x, g2To109x, g2To110x, g2To111x, g2To112x, g2To113x, g2To114x, g2To115x, g2To116x, g2To117x, g2To118x, g2To119x, g2To120x, g2To121x, g2To122x, g2To123x, g2To124x, g2To125x, g2To126x, g2To127x, g2To128x, g2To129x, g2To130x, g2To131x, g2To132x, g2To133x, g2To134x, g2To135x, g2To136x, g2To137x, g2To138x, g2To139x, g2To140x, g2To141x, g2To142x, g2To143x, g2To144x, g2To145x, g2To146x, g2To147x, g2To148x, g2To149x, g2To150x, g2To151x, g2To152x, g2To153x, g2To154x, g2To155x, g2To156x, g2To157x, g2To158x, g2To159x, g2To160x, g2To161x, g2To162x, g2To163x, g2To164x, g2To165x, g2To166x, g2To167x, g2To168x, g2To169x, g2To170x, g2To171x, g2To172x, g2To173x, g2To174x, g2To175x, g2To176x, g2To177x, g2To178x, g2To179x, g2To180x, g2To181x, g2To182x, g2To183x, g2To184x, g2To185x, g2To186x, g2To187x, g2To188x, g2To189x, g2To190x, g2To191x, g2To192x, g2To193x, g2To194x, g2To195x, g2To196x, g2To197x, g2To198x, g2To199x, g2To200x, g2To201x, g2To202x, g2To203x, g2To204x, g2To205x, g2To206x, g2To207x, g2To208x, g2To209x, g2To210x, g2To211x, g2To212x, g2To213x, g2To214x, g2To215x, g2To216x, g2To217x, g2To218x, g2To219x, g2To220x, g2To221x, g2To222x, g2To223x, g2To224x, g2To225x, g2To226x, g2To227x, g2To228x, g2To229x, g2To230x, g2To231x, g2To232x, g2To233x, g2To234x, g2To235x, g2To236x, g2To237x, g2To238x, g2To239x, g2To240x, g2To241x, g2To242x, g2To243x, g2To244x, g2To245x, g2To246x, g2To247x, g2To248x, g2To249x, g2To250x, g2To251x, g2To252x, g2To253x, g2To254x, g2To255x}, + Gmy: [256]*big.Int{g3y, g5y, g7y, g2To3y, g2To4y, g2To5y, g2To6y, g2To7y, g2To8y, g2To9y, g2To10y, g2To11y, g2To12y, g2To13y, g2To14y, g2To15y, g2To16y, g2To17y, g2To18y, g2To19y, g2To20y, g2To21y, g2To22y, g2To23y, g2To24y, g2To25y, g2To26y, g2To27y, g2To28y, g2To29y, g2To30y, g2To31y, g2To32y, g2To33y, g2To34y, g2To35y, g2To36y, g2To37y, g2To38y, g2To39y, g2To40y, g2To41y, g2To42y, g2To43y, g2To44y, g2To45y, g2To46y, g2To47y, g2To48y, g2To49y, g2To50y, g2To51y, g2To52y, g2To53y, g2To54y, g2To55y, g2To56y, g2To57y, g2To58y, g2To59y, g2To60y, g2To61y, g2To62y, g2To63y, g2To64y, g2To65y, g2To66y, g2To67y, g2To68y, g2To69y, g2To70y, g2To71y, g2To72y, g2To73y, g2To74y, g2To75y, g2To76y, g2To77y, g2To78y, g2To79y, g2To80y, g2To81y, g2To82y, g2To83y, g2To84y, g2To85y, g2To86y, g2To87y, g2To88y, g2To89y, g2To90y, g2To91y, g2To92y, g2To93y, g2To94y, g2To95y, g2To96y, g2To97y, g2To98y, g2To99y, g2To100y, g2To101y, g2To102y, g2To103y, g2To104y, g2To105y, g2To106y, g2To107y, g2To108y, g2To109y, g2To110y, g2To111y, g2To112y, g2To113y, g2To114y, g2To115y, g2To116y, g2To117y, g2To118y, g2To119y, g2To120y, g2To121y, g2To122y, g2To123y, g2To124y, g2To125y, g2To126y, g2To127y, g2To128y, g2To129y, g2To130y, g2To131y, g2To132y, g2To133y, g2To134y, g2To135y, g2To136y, g2To137y, g2To138y, g2To139y, g2To140y, g2To141y, g2To142y, g2To143y, g2To144y, g2To145y, g2To146y, g2To147y, g2To148y, g2To149y, g2To150y, g2To151y, g2To152y, g2To153y, g2To154y, g2To155y, g2To156y, g2To157y, g2To158y, g2To159y, g2To160y, g2To161y, g2To162y, g2To163y, g2To164y, g2To165y, g2To166y, g2To167y, g2To168y, g2To169y, g2To170y, g2To171y, g2To172y, g2To173y, g2To174y, g2To175y, g2To176y, g2To177y, g2To178y, g2To179y, g2To180y, g2To181y, g2To182y, g2To183y, g2To184y, g2To185y, g2To186y, g2To187y, g2To188y, g2To189y, g2To190y, g2To191y, g2To192y, g2To193y, g2To194y, g2To195y, g2To196y, g2To197y, g2To198y, g2To199y, g2To200y, g2To201y, g2To202y, g2To203y, g2To204y, g2To205y, g2To206y, g2To207y, g2To208y, g2To209y, g2To210y, g2To211y, g2To212y, g2To213y, g2To214y, g2To215y, g2To216y, g2To217y, g2To218y, g2To219y, g2To220y, g2To221y, g2To222y, g2To223y, g2To224y, g2To225y, g2To226y, g2To227y, g2To228y, g2To229y, g2To230y, g2To231y, g2To232y, g2To233y, g2To234y, g2To235y, g2To236y, g2To237y, g2To238y, g2To239y, g2To240y, g2To241y, g2To242y, g2To243y, g2To244y, g2To245y, g2To246y, g2To247y, g2To248y, g2To249y, g2To250y, g2To251y, g2To252y, g2To253y, g2To254y, g2To255y}, } } diff --git a/std/algebra/weierstrass/point.go b/std/algebra/weierstrass/point.go index 4696f516f8..c32932d419 100644 --- a/std/algebra/weierstrass/point.go +++ b/std/algebra/weierstrass/point.go @@ -25,516 +25,516 @@ func New[Base, Scalars emulated.FieldParams](api frontend.API, params CurveParam Gy := emulated.ValueOf[Base](params.Gy) G3x := emulated.ValueOf[Base](params.Gmx[0]) G3y := emulated.ValueOf[Base](params.Gmy[0]) - G4x := emulated.ValueOf[Base](params.Gmx[1]) - G4y := emulated.ValueOf[Base](params.Gmy[1]) - G8x := emulated.ValueOf[Base](params.Gmx[2]) - G8y := emulated.ValueOf[Base](params.Gmy[2]) - G16x := emulated.ValueOf[Base](params.Gmx[3]) - G16y := emulated.ValueOf[Base](params.Gmy[3]) - G32x := emulated.ValueOf[Base](params.Gmx[4]) - G32y := emulated.ValueOf[Base](params.Gmy[4]) - G64x := emulated.ValueOf[Base](params.Gmx[5]) - G64y := emulated.ValueOf[Base](params.Gmy[5]) - G128x := emulated.ValueOf[Base](params.Gmx[6]) - G128y := emulated.ValueOf[Base](params.Gmy[6]) - G256x := emulated.ValueOf[Base](params.Gmx[7]) - G256y := emulated.ValueOf[Base](params.Gmy[7]) - G512x := emulated.ValueOf[Base](params.Gmx[8]) - G512y := emulated.ValueOf[Base](params.Gmy[8]) - G1024x := emulated.ValueOf[Base](params.Gmx[9]) - G1024y := emulated.ValueOf[Base](params.Gmy[9]) - G2048x := emulated.ValueOf[Base](params.Gmx[10]) - G2048y := emulated.ValueOf[Base](params.Gmy[10]) - G4096x := emulated.ValueOf[Base](params.Gmx[11]) - G4096y := emulated.ValueOf[Base](params.Gmy[11]) - G8192x := emulated.ValueOf[Base](params.Gmx[12]) - G8192y := emulated.ValueOf[Base](params.Gmy[12]) - G16384x := emulated.ValueOf[Base](params.Gmx[13]) - G16384y := emulated.ValueOf[Base](params.Gmy[13]) - G32768x := emulated.ValueOf[Base](params.Gmx[14]) - G32768y := emulated.ValueOf[Base](params.Gmy[14]) - G65536x := emulated.ValueOf[Base](params.Gmx[15]) - G65536y := emulated.ValueOf[Base](params.Gmy[15]) - G131072x := emulated.ValueOf[Base](params.Gmx[16]) - G131072y := emulated.ValueOf[Base](params.Gmy[16]) - G262144x := emulated.ValueOf[Base](params.Gmx[17]) - G262144y := emulated.ValueOf[Base](params.Gmy[17]) - G524288x := emulated.ValueOf[Base](params.Gmx[18]) - G524288y := emulated.ValueOf[Base](params.Gmy[18]) - G1048576x := emulated.ValueOf[Base](params.Gmx[19]) - G1048576y := emulated.ValueOf[Base](params.Gmy[19]) - G2097152x := emulated.ValueOf[Base](params.Gmx[20]) - G2097152y := emulated.ValueOf[Base](params.Gmy[20]) - G4194304x := emulated.ValueOf[Base](params.Gmx[21]) - G4194304y := emulated.ValueOf[Base](params.Gmy[21]) - G8388608x := emulated.ValueOf[Base](params.Gmx[22]) - G8388608y := emulated.ValueOf[Base](params.Gmy[22]) - G16777216x := emulated.ValueOf[Base](params.Gmx[23]) - G16777216y := emulated.ValueOf[Base](params.Gmy[23]) - G33554432x := emulated.ValueOf[Base](params.Gmx[24]) - G33554432y := emulated.ValueOf[Base](params.Gmy[24]) - G67108864x := emulated.ValueOf[Base](params.Gmx[25]) - G67108864y := emulated.ValueOf[Base](params.Gmy[25]) - G134217728x := emulated.ValueOf[Base](params.Gmx[26]) - G134217728y := emulated.ValueOf[Base](params.Gmy[26]) - G268435456x := emulated.ValueOf[Base](params.Gmx[27]) - G268435456y := emulated.ValueOf[Base](params.Gmy[27]) - G536870912x := emulated.ValueOf[Base](params.Gmx[28]) - G536870912y := emulated.ValueOf[Base](params.Gmy[28]) - G1073741824x := emulated.ValueOf[Base](params.Gmx[29]) - G1073741824y := emulated.ValueOf[Base](params.Gmy[29]) - G2147483648x := emulated.ValueOf[Base](params.Gmx[30]) - G2147483648y := emulated.ValueOf[Base](params.Gmy[30]) - G4294967296x := emulated.ValueOf[Base](params.Gmx[31]) - G4294967296y := emulated.ValueOf[Base](params.Gmy[31]) - G8589934592x := emulated.ValueOf[Base](params.Gmx[32]) - G8589934592y := emulated.ValueOf[Base](params.Gmy[32]) - G17179869184x := emulated.ValueOf[Base](params.Gmx[33]) - G17179869184y := emulated.ValueOf[Base](params.Gmy[33]) - G34359738368x := emulated.ValueOf[Base](params.Gmx[34]) - G34359738368y := emulated.ValueOf[Base](params.Gmy[34]) - G68719476736x := emulated.ValueOf[Base](params.Gmx[35]) - G68719476736y := emulated.ValueOf[Base](params.Gmy[35]) - G137438953472x := emulated.ValueOf[Base](params.Gmx[36]) - G137438953472y := emulated.ValueOf[Base](params.Gmy[36]) - G274877906944x := emulated.ValueOf[Base](params.Gmx[37]) - G274877906944y := emulated.ValueOf[Base](params.Gmy[37]) - G549755813888x := emulated.ValueOf[Base](params.Gmx[38]) - G549755813888y := emulated.ValueOf[Base](params.Gmy[38]) - G1099511627776x := emulated.ValueOf[Base](params.Gmx[39]) - G1099511627776y := emulated.ValueOf[Base](params.Gmy[39]) - G2199023255552x := emulated.ValueOf[Base](params.Gmx[40]) - G2199023255552y := emulated.ValueOf[Base](params.Gmy[40]) - G4398046511104x := emulated.ValueOf[Base](params.Gmx[41]) - G4398046511104y := emulated.ValueOf[Base](params.Gmy[41]) - G8796093022208x := emulated.ValueOf[Base](params.Gmx[42]) - G8796093022208y := emulated.ValueOf[Base](params.Gmy[42]) - G17592186044416x := emulated.ValueOf[Base](params.Gmx[43]) - G17592186044416y := emulated.ValueOf[Base](params.Gmy[43]) - G35184372088832x := emulated.ValueOf[Base](params.Gmx[44]) - G35184372088832y := emulated.ValueOf[Base](params.Gmy[44]) - G70368744177664x := emulated.ValueOf[Base](params.Gmx[45]) - G70368744177664y := emulated.ValueOf[Base](params.Gmy[45]) - G140737488355328x := emulated.ValueOf[Base](params.Gmx[46]) - G140737488355328y := emulated.ValueOf[Base](params.Gmy[46]) - G281474976710656x := emulated.ValueOf[Base](params.Gmx[47]) - G281474976710656y := emulated.ValueOf[Base](params.Gmy[47]) - G562949953421312x := emulated.ValueOf[Base](params.Gmx[48]) - G562949953421312y := emulated.ValueOf[Base](params.Gmy[48]) - G1125899906842624x := emulated.ValueOf[Base](params.Gmx[49]) - G1125899906842624y := emulated.ValueOf[Base](params.Gmy[49]) - G2251799813685248x := emulated.ValueOf[Base](params.Gmx[50]) - G2251799813685248y := emulated.ValueOf[Base](params.Gmy[50]) - G4503599627370496x := emulated.ValueOf[Base](params.Gmx[51]) - G4503599627370496y := emulated.ValueOf[Base](params.Gmy[51]) - G9007199254740992x := emulated.ValueOf[Base](params.Gmx[52]) - G9007199254740992y := emulated.ValueOf[Base](params.Gmy[52]) - G18014398509481984x := emulated.ValueOf[Base](params.Gmx[53]) - G18014398509481984y := emulated.ValueOf[Base](params.Gmy[53]) - G36028797018963968x := emulated.ValueOf[Base](params.Gmx[54]) - G36028797018963968y := emulated.ValueOf[Base](params.Gmy[54]) - G72057594037927936x := emulated.ValueOf[Base](params.Gmx[55]) - G72057594037927936y := emulated.ValueOf[Base](params.Gmy[55]) - G144115188075855872x := emulated.ValueOf[Base](params.Gmx[56]) - G144115188075855872y := emulated.ValueOf[Base](params.Gmy[56]) - G288230376151711744x := emulated.ValueOf[Base](params.Gmx[57]) - G288230376151711744y := emulated.ValueOf[Base](params.Gmy[57]) - G576460752303423488x := emulated.ValueOf[Base](params.Gmx[58]) - G576460752303423488y := emulated.ValueOf[Base](params.Gmy[58]) - G1152921504606846976x := emulated.ValueOf[Base](params.Gmx[59]) - G1152921504606846976y := emulated.ValueOf[Base](params.Gmy[59]) - G2305843009213693952x := emulated.ValueOf[Base](params.Gmx[60]) - G2305843009213693952y := emulated.ValueOf[Base](params.Gmy[60]) - G4611686018427387904x := emulated.ValueOf[Base](params.Gmx[61]) - G4611686018427387904y := emulated.ValueOf[Base](params.Gmy[61]) - G9223372036854775808x := emulated.ValueOf[Base](params.Gmx[62]) - G9223372036854775808y := emulated.ValueOf[Base](params.Gmy[62]) - G18446744073709551616x := emulated.ValueOf[Base](params.Gmx[63]) - G18446744073709551616y := emulated.ValueOf[Base](params.Gmy[63]) - G36893488147419103232x := emulated.ValueOf[Base](params.Gmx[64]) - G36893488147419103232y := emulated.ValueOf[Base](params.Gmy[64]) - G73786976294838206464x := emulated.ValueOf[Base](params.Gmx[65]) - G73786976294838206464y := emulated.ValueOf[Base](params.Gmy[65]) - G147573952589676412928x := emulated.ValueOf[Base](params.Gmx[66]) - G147573952589676412928y := emulated.ValueOf[Base](params.Gmy[66]) - G295147905179352825856x := emulated.ValueOf[Base](params.Gmx[67]) - G295147905179352825856y := emulated.ValueOf[Base](params.Gmy[67]) - G590295810358705651712x := emulated.ValueOf[Base](params.Gmx[68]) - G590295810358705651712y := emulated.ValueOf[Base](params.Gmy[68]) - G1180591620717411303424x := emulated.ValueOf[Base](params.Gmx[69]) - G1180591620717411303424y := emulated.ValueOf[Base](params.Gmy[69]) - G2361183241434822606848x := emulated.ValueOf[Base](params.Gmx[70]) - G2361183241434822606848y := emulated.ValueOf[Base](params.Gmy[70]) - G4722366482869645213696x := emulated.ValueOf[Base](params.Gmx[71]) - G4722366482869645213696y := emulated.ValueOf[Base](params.Gmy[71]) - G9444732965739290427392x := emulated.ValueOf[Base](params.Gmx[72]) - G9444732965739290427392y := emulated.ValueOf[Base](params.Gmy[72]) - G18889465931478580854784x := emulated.ValueOf[Base](params.Gmx[73]) - G18889465931478580854784y := emulated.ValueOf[Base](params.Gmy[73]) - G37778931862957161709568x := emulated.ValueOf[Base](params.Gmx[74]) - G37778931862957161709568y := emulated.ValueOf[Base](params.Gmy[74]) - G75557863725914323419136x := emulated.ValueOf[Base](params.Gmx[75]) - G75557863725914323419136y := emulated.ValueOf[Base](params.Gmy[75]) - G151115727451828646838272x := emulated.ValueOf[Base](params.Gmx[76]) - G151115727451828646838272y := emulated.ValueOf[Base](params.Gmy[76]) - G302231454903657293676544x := emulated.ValueOf[Base](params.Gmx[77]) - G302231454903657293676544y := emulated.ValueOf[Base](params.Gmy[77]) - G604462909807314587353088x := emulated.ValueOf[Base](params.Gmx[78]) - G604462909807314587353088y := emulated.ValueOf[Base](params.Gmy[78]) - G1208925819614629174706176x := emulated.ValueOf[Base](params.Gmx[79]) - G1208925819614629174706176y := emulated.ValueOf[Base](params.Gmy[79]) - G2417851639229258349412352x := emulated.ValueOf[Base](params.Gmx[80]) - G2417851639229258349412352y := emulated.ValueOf[Base](params.Gmy[80]) - G4835703278458516698824704x := emulated.ValueOf[Base](params.Gmx[81]) - G4835703278458516698824704y := emulated.ValueOf[Base](params.Gmy[81]) - G9671406556917033397649408x := emulated.ValueOf[Base](params.Gmx[82]) - G9671406556917033397649408y := emulated.ValueOf[Base](params.Gmy[82]) - G19342813113834066795298816x := emulated.ValueOf[Base](params.Gmx[83]) - G19342813113834066795298816y := emulated.ValueOf[Base](params.Gmy[83]) - G38685626227668133590597632x := emulated.ValueOf[Base](params.Gmx[84]) - G38685626227668133590597632y := emulated.ValueOf[Base](params.Gmy[84]) - G77371252455336267181195264x := emulated.ValueOf[Base](params.Gmx[85]) - G77371252455336267181195264y := emulated.ValueOf[Base](params.Gmy[85]) - G154742504910672534362390528x := emulated.ValueOf[Base](params.Gmx[86]) - G154742504910672534362390528y := emulated.ValueOf[Base](params.Gmy[86]) - G309485009821345068724781056x := emulated.ValueOf[Base](params.Gmx[87]) - G309485009821345068724781056y := emulated.ValueOf[Base](params.Gmy[87]) - G618970019642690137449562112x := emulated.ValueOf[Base](params.Gmx[88]) - G618970019642690137449562112y := emulated.ValueOf[Base](params.Gmy[88]) - G1237940039285380274899124224x := emulated.ValueOf[Base](params.Gmx[89]) - G1237940039285380274899124224y := emulated.ValueOf[Base](params.Gmy[89]) - G2475880078570760549798248448x := emulated.ValueOf[Base](params.Gmx[90]) - G2475880078570760549798248448y := emulated.ValueOf[Base](params.Gmy[90]) - G4951760157141521099596496896x := emulated.ValueOf[Base](params.Gmx[91]) - G4951760157141521099596496896y := emulated.ValueOf[Base](params.Gmy[91]) - G9903520314283042199192993792x := emulated.ValueOf[Base](params.Gmx[92]) - G9903520314283042199192993792y := emulated.ValueOf[Base](params.Gmy[92]) - G19807040628566084398385987584x := emulated.ValueOf[Base](params.Gmx[93]) - G19807040628566084398385987584y := emulated.ValueOf[Base](params.Gmy[93]) - G39614081257132168796771975168x := emulated.ValueOf[Base](params.Gmx[94]) - G39614081257132168796771975168y := emulated.ValueOf[Base](params.Gmy[94]) - G79228162514264337593543950336x := emulated.ValueOf[Base](params.Gmx[95]) - G79228162514264337593543950336y := emulated.ValueOf[Base](params.Gmy[95]) - G158456325028528675187087900672x := emulated.ValueOf[Base](params.Gmx[96]) - G158456325028528675187087900672y := emulated.ValueOf[Base](params.Gmy[96]) - G316912650057057350374175801344x := emulated.ValueOf[Base](params.Gmx[97]) - G316912650057057350374175801344y := emulated.ValueOf[Base](params.Gmy[97]) - G633825300114114700748351602688x := emulated.ValueOf[Base](params.Gmx[98]) - G633825300114114700748351602688y := emulated.ValueOf[Base](params.Gmy[98]) - G1267650600228229401496703205376x := emulated.ValueOf[Base](params.Gmx[99]) - G1267650600228229401496703205376y := emulated.ValueOf[Base](params.Gmy[99]) - G2535301200456458802993406410752x := emulated.ValueOf[Base](params.Gmx[100]) - G2535301200456458802993406410752y := emulated.ValueOf[Base](params.Gmy[100]) - G5070602400912917605986812821504x := emulated.ValueOf[Base](params.Gmx[101]) - G5070602400912917605986812821504y := emulated.ValueOf[Base](params.Gmy[101]) - G10141204801825835211973625643008x := emulated.ValueOf[Base](params.Gmx[102]) - G10141204801825835211973625643008y := emulated.ValueOf[Base](params.Gmy[102]) - G20282409603651670423947251286016x := emulated.ValueOf[Base](params.Gmx[103]) - G20282409603651670423947251286016y := emulated.ValueOf[Base](params.Gmy[103]) - G40564819207303340847894502572032x := emulated.ValueOf[Base](params.Gmx[104]) - G40564819207303340847894502572032y := emulated.ValueOf[Base](params.Gmy[104]) - G81129638414606681695789005144064x := emulated.ValueOf[Base](params.Gmx[105]) - G81129638414606681695789005144064y := emulated.ValueOf[Base](params.Gmy[105]) - G162259276829213363391578010288128x := emulated.ValueOf[Base](params.Gmx[106]) - G162259276829213363391578010288128y := emulated.ValueOf[Base](params.Gmy[106]) - G324518553658426726783156020576256x := emulated.ValueOf[Base](params.Gmx[107]) - G324518553658426726783156020576256y := emulated.ValueOf[Base](params.Gmy[107]) - G649037107316853453566312041152512x := emulated.ValueOf[Base](params.Gmx[108]) - G649037107316853453566312041152512y := emulated.ValueOf[Base](params.Gmy[108]) - G1298074214633706907132624082305024x := emulated.ValueOf[Base](params.Gmx[109]) - G1298074214633706907132624082305024y := emulated.ValueOf[Base](params.Gmy[109]) - G2596148429267413814265248164610048x := emulated.ValueOf[Base](params.Gmx[110]) - G2596148429267413814265248164610048y := emulated.ValueOf[Base](params.Gmy[110]) - G5192296858534827628530496329220096x := emulated.ValueOf[Base](params.Gmx[111]) - G5192296858534827628530496329220096y := emulated.ValueOf[Base](params.Gmy[111]) - G10384593717069655257060992658440192x := emulated.ValueOf[Base](params.Gmx[112]) - G10384593717069655257060992658440192y := emulated.ValueOf[Base](params.Gmy[112]) - G20769187434139310514121985316880384x := emulated.ValueOf[Base](params.Gmx[113]) - G20769187434139310514121985316880384y := emulated.ValueOf[Base](params.Gmy[113]) - G41538374868278621028243970633760768x := emulated.ValueOf[Base](params.Gmx[114]) - G41538374868278621028243970633760768y := emulated.ValueOf[Base](params.Gmy[114]) - G83076749736557242056487941267521536x := emulated.ValueOf[Base](params.Gmx[115]) - G83076749736557242056487941267521536y := emulated.ValueOf[Base](params.Gmy[115]) - G166153499473114484112975882535043072x := emulated.ValueOf[Base](params.Gmx[116]) - G166153499473114484112975882535043072y := emulated.ValueOf[Base](params.Gmy[116]) - G332306998946228968225951765070086144x := emulated.ValueOf[Base](params.Gmx[117]) - G332306998946228968225951765070086144y := emulated.ValueOf[Base](params.Gmy[117]) - G664613997892457936451903530140172288x := emulated.ValueOf[Base](params.Gmx[118]) - G664613997892457936451903530140172288y := emulated.ValueOf[Base](params.Gmy[118]) - G1329227995784915872903807060280344576x := emulated.ValueOf[Base](params.Gmx[119]) - G1329227995784915872903807060280344576y := emulated.ValueOf[Base](params.Gmy[119]) - G2658455991569831745807614120560689152x := emulated.ValueOf[Base](params.Gmx[120]) - G2658455991569831745807614120560689152y := emulated.ValueOf[Base](params.Gmy[120]) - G5316911983139663491615228241121378304x := emulated.ValueOf[Base](params.Gmx[121]) - G5316911983139663491615228241121378304y := emulated.ValueOf[Base](params.Gmy[121]) - G10633823966279326983230456482242756608x := emulated.ValueOf[Base](params.Gmx[122]) - G10633823966279326983230456482242756608y := emulated.ValueOf[Base](params.Gmy[122]) - G21267647932558653966460912964485513216x := emulated.ValueOf[Base](params.Gmx[123]) - G21267647932558653966460912964485513216y := emulated.ValueOf[Base](params.Gmy[123]) - G42535295865117307932921825928971026432x := emulated.ValueOf[Base](params.Gmx[124]) - G42535295865117307932921825928971026432y := emulated.ValueOf[Base](params.Gmy[124]) - G85070591730234615865843651857942052864x := emulated.ValueOf[Base](params.Gmx[125]) - G85070591730234615865843651857942052864y := emulated.ValueOf[Base](params.Gmy[125]) - G170141183460469231731687303715884105728x := emulated.ValueOf[Base](params.Gmx[126]) - G170141183460469231731687303715884105728y := emulated.ValueOf[Base](params.Gmy[126]) - G340282366920938463463374607431768211456x := emulated.ValueOf[Base](params.Gmx[127]) - G340282366920938463463374607431768211456y := emulated.ValueOf[Base](params.Gmy[127]) - G680564733841876926926749214863536422912x := emulated.ValueOf[Base](params.Gmx[128]) - G680564733841876926926749214863536422912y := emulated.ValueOf[Base](params.Gmy[128]) - G1361129467683753853853498429727072845824x := emulated.ValueOf[Base](params.Gmx[129]) - G1361129467683753853853498429727072845824y := emulated.ValueOf[Base](params.Gmy[129]) - G2722258935367507707706996859454145691648x := emulated.ValueOf[Base](params.Gmx[130]) - G2722258935367507707706996859454145691648y := emulated.ValueOf[Base](params.Gmy[130]) - G5444517870735015415413993718908291383296x := emulated.ValueOf[Base](params.Gmx[131]) - G5444517870735015415413993718908291383296y := emulated.ValueOf[Base](params.Gmy[131]) - G10889035741470030830827987437816582766592x := emulated.ValueOf[Base](params.Gmx[132]) - G10889035741470030830827987437816582766592y := emulated.ValueOf[Base](params.Gmy[132]) - G21778071482940061661655974875633165533184x := emulated.ValueOf[Base](params.Gmx[133]) - G21778071482940061661655974875633165533184y := emulated.ValueOf[Base](params.Gmy[133]) - G43556142965880123323311949751266331066368x := emulated.ValueOf[Base](params.Gmx[134]) - G43556142965880123323311949751266331066368y := emulated.ValueOf[Base](params.Gmy[134]) - G87112285931760246646623899502532662132736x := emulated.ValueOf[Base](params.Gmx[135]) - G87112285931760246646623899502532662132736y := emulated.ValueOf[Base](params.Gmy[135]) - G174224571863520493293247799005065324265472x := emulated.ValueOf[Base](params.Gmx[136]) - G174224571863520493293247799005065324265472y := emulated.ValueOf[Base](params.Gmy[136]) - G348449143727040986586495598010130648530944x := emulated.ValueOf[Base](params.Gmx[137]) - G348449143727040986586495598010130648530944y := emulated.ValueOf[Base](params.Gmy[137]) - G696898287454081973172991196020261297061888x := emulated.ValueOf[Base](params.Gmx[138]) - G696898287454081973172991196020261297061888y := emulated.ValueOf[Base](params.Gmy[138]) - G1393796574908163946345982392040522594123776x := emulated.ValueOf[Base](params.Gmx[139]) - G1393796574908163946345982392040522594123776y := emulated.ValueOf[Base](params.Gmy[139]) - G2787593149816327892691964784081045188247552x := emulated.ValueOf[Base](params.Gmx[140]) - G2787593149816327892691964784081045188247552y := emulated.ValueOf[Base](params.Gmy[140]) - G5575186299632655785383929568162090376495104x := emulated.ValueOf[Base](params.Gmx[141]) - G5575186299632655785383929568162090376495104y := emulated.ValueOf[Base](params.Gmy[141]) - G11150372599265311570767859136324180752990208x := emulated.ValueOf[Base](params.Gmx[142]) - G11150372599265311570767859136324180752990208y := emulated.ValueOf[Base](params.Gmy[142]) - G22300745198530623141535718272648361505980416x := emulated.ValueOf[Base](params.Gmx[143]) - G22300745198530623141535718272648361505980416y := emulated.ValueOf[Base](params.Gmy[143]) - G44601490397061246283071436545296723011960832x := emulated.ValueOf[Base](params.Gmx[144]) - G44601490397061246283071436545296723011960832y := emulated.ValueOf[Base](params.Gmy[144]) - G89202980794122492566142873090593446023921664x := emulated.ValueOf[Base](params.Gmx[145]) - G89202980794122492566142873090593446023921664y := emulated.ValueOf[Base](params.Gmy[145]) - G178405961588244985132285746181186892047843328x := emulated.ValueOf[Base](params.Gmx[146]) - G178405961588244985132285746181186892047843328y := emulated.ValueOf[Base](params.Gmy[146]) - G356811923176489970264571492362373784095686656x := emulated.ValueOf[Base](params.Gmx[147]) - G356811923176489970264571492362373784095686656y := emulated.ValueOf[Base](params.Gmy[147]) - G713623846352979940529142984724747568191373312x := emulated.ValueOf[Base](params.Gmx[148]) - G713623846352979940529142984724747568191373312y := emulated.ValueOf[Base](params.Gmy[148]) - G1427247692705959881058285969449495136382746624x := emulated.ValueOf[Base](params.Gmx[149]) - G1427247692705959881058285969449495136382746624y := emulated.ValueOf[Base](params.Gmy[149]) - G2854495385411919762116571938898990272765493248x := emulated.ValueOf[Base](params.Gmx[150]) - G2854495385411919762116571938898990272765493248y := emulated.ValueOf[Base](params.Gmy[150]) - G5708990770823839524233143877797980545530986496x := emulated.ValueOf[Base](params.Gmx[151]) - G5708990770823839524233143877797980545530986496y := emulated.ValueOf[Base](params.Gmy[151]) - G11417981541647679048466287755595961091061972992x := emulated.ValueOf[Base](params.Gmx[152]) - G11417981541647679048466287755595961091061972992y := emulated.ValueOf[Base](params.Gmy[152]) - G22835963083295358096932575511191922182123945984x := emulated.ValueOf[Base](params.Gmx[153]) - G22835963083295358096932575511191922182123945984y := emulated.ValueOf[Base](params.Gmy[153]) - G45671926166590716193865151022383844364247891968x := emulated.ValueOf[Base](params.Gmx[154]) - G45671926166590716193865151022383844364247891968y := emulated.ValueOf[Base](params.Gmy[154]) - G91343852333181432387730302044767688728495783936x := emulated.ValueOf[Base](params.Gmx[155]) - G91343852333181432387730302044767688728495783936y := emulated.ValueOf[Base](params.Gmy[155]) - G182687704666362864775460604089535377456991567872x := emulated.ValueOf[Base](params.Gmx[156]) - G182687704666362864775460604089535377456991567872y := emulated.ValueOf[Base](params.Gmy[156]) - G365375409332725729550921208179070754913983135744x := emulated.ValueOf[Base](params.Gmx[157]) - G365375409332725729550921208179070754913983135744y := emulated.ValueOf[Base](params.Gmy[157]) - G730750818665451459101842416358141509827966271488x := emulated.ValueOf[Base](params.Gmx[158]) - G730750818665451459101842416358141509827966271488y := emulated.ValueOf[Base](params.Gmy[158]) - G1461501637330902918203684832716283019655932542976x := emulated.ValueOf[Base](params.Gmx[159]) - G1461501637330902918203684832716283019655932542976y := emulated.ValueOf[Base](params.Gmy[159]) - G2923003274661805836407369665432566039311865085952x := emulated.ValueOf[Base](params.Gmx[160]) - G2923003274661805836407369665432566039311865085952y := emulated.ValueOf[Base](params.Gmy[160]) - G5846006549323611672814739330865132078623730171904x := emulated.ValueOf[Base](params.Gmx[161]) - G5846006549323611672814739330865132078623730171904y := emulated.ValueOf[Base](params.Gmy[161]) - G11692013098647223345629478661730264157247460343808x := emulated.ValueOf[Base](params.Gmx[162]) - G11692013098647223345629478661730264157247460343808y := emulated.ValueOf[Base](params.Gmy[162]) - G23384026197294446691258957323460528314494920687616x := emulated.ValueOf[Base](params.Gmx[163]) - G23384026197294446691258957323460528314494920687616y := emulated.ValueOf[Base](params.Gmy[163]) - G46768052394588893382517914646921056628989841375232x := emulated.ValueOf[Base](params.Gmx[164]) - G46768052394588893382517914646921056628989841375232y := emulated.ValueOf[Base](params.Gmy[164]) - G93536104789177786765035829293842113257979682750464x := emulated.ValueOf[Base](params.Gmx[165]) - G93536104789177786765035829293842113257979682750464y := emulated.ValueOf[Base](params.Gmy[165]) - G187072209578355573530071658587684226515959365500928x := emulated.ValueOf[Base](params.Gmx[166]) - G187072209578355573530071658587684226515959365500928y := emulated.ValueOf[Base](params.Gmy[166]) - G374144419156711147060143317175368453031918731001856x := emulated.ValueOf[Base](params.Gmx[167]) - G374144419156711147060143317175368453031918731001856y := emulated.ValueOf[Base](params.Gmy[167]) - G748288838313422294120286634350736906063837462003712x := emulated.ValueOf[Base](params.Gmx[168]) - G748288838313422294120286634350736906063837462003712y := emulated.ValueOf[Base](params.Gmy[168]) - G1496577676626844588240573268701473812127674924007424x := emulated.ValueOf[Base](params.Gmx[169]) - G1496577676626844588240573268701473812127674924007424y := emulated.ValueOf[Base](params.Gmy[169]) - G2993155353253689176481146537402947624255349848014848x := emulated.ValueOf[Base](params.Gmx[170]) - G2993155353253689176481146537402947624255349848014848y := emulated.ValueOf[Base](params.Gmy[170]) - G5986310706507378352962293074805895248510699696029696x := emulated.ValueOf[Base](params.Gmx[171]) - G5986310706507378352962293074805895248510699696029696y := emulated.ValueOf[Base](params.Gmy[171]) - G11972621413014756705924586149611790497021399392059392x := emulated.ValueOf[Base](params.Gmx[172]) - G11972621413014756705924586149611790497021399392059392y := emulated.ValueOf[Base](params.Gmy[172]) - G23945242826029513411849172299223580994042798784118784x := emulated.ValueOf[Base](params.Gmx[173]) - G23945242826029513411849172299223580994042798784118784y := emulated.ValueOf[Base](params.Gmy[173]) - G47890485652059026823698344598447161988085597568237568x := emulated.ValueOf[Base](params.Gmx[174]) - G47890485652059026823698344598447161988085597568237568y := emulated.ValueOf[Base](params.Gmy[174]) - G95780971304118053647396689196894323976171195136475136x := emulated.ValueOf[Base](params.Gmx[175]) - G95780971304118053647396689196894323976171195136475136y := emulated.ValueOf[Base](params.Gmy[175]) - G191561942608236107294793378393788647952342390272950272x := emulated.ValueOf[Base](params.Gmx[176]) - G191561942608236107294793378393788647952342390272950272y := emulated.ValueOf[Base](params.Gmy[176]) - G383123885216472214589586756787577295904684780545900544x := emulated.ValueOf[Base](params.Gmx[177]) - G383123885216472214589586756787577295904684780545900544y := emulated.ValueOf[Base](params.Gmy[177]) - G766247770432944429179173513575154591809369561091801088x := emulated.ValueOf[Base](params.Gmx[178]) - G766247770432944429179173513575154591809369561091801088y := emulated.ValueOf[Base](params.Gmy[178]) - G1532495540865888858358347027150309183618739122183602176x := emulated.ValueOf[Base](params.Gmx[179]) - G1532495540865888858358347027150309183618739122183602176y := emulated.ValueOf[Base](params.Gmy[179]) - G3064991081731777716716694054300618367237478244367204352x := emulated.ValueOf[Base](params.Gmx[180]) - G3064991081731777716716694054300618367237478244367204352y := emulated.ValueOf[Base](params.Gmy[180]) - G6129982163463555433433388108601236734474956488734408704x := emulated.ValueOf[Base](params.Gmx[181]) - G6129982163463555433433388108601236734474956488734408704y := emulated.ValueOf[Base](params.Gmy[181]) - G12259964326927110866866776217202473468949912977468817408x := emulated.ValueOf[Base](params.Gmx[182]) - G12259964326927110866866776217202473468949912977468817408y := emulated.ValueOf[Base](params.Gmy[182]) - G24519928653854221733733552434404946937899825954937634816x := emulated.ValueOf[Base](params.Gmx[183]) - G24519928653854221733733552434404946937899825954937634816y := emulated.ValueOf[Base](params.Gmy[183]) - G49039857307708443467467104868809893875799651909875269632x := emulated.ValueOf[Base](params.Gmx[184]) - G49039857307708443467467104868809893875799651909875269632y := emulated.ValueOf[Base](params.Gmy[184]) - G98079714615416886934934209737619787751599303819750539264x := emulated.ValueOf[Base](params.Gmx[185]) - G98079714615416886934934209737619787751599303819750539264y := emulated.ValueOf[Base](params.Gmy[185]) - G196159429230833773869868419475239575503198607639501078528x := emulated.ValueOf[Base](params.Gmx[186]) - G196159429230833773869868419475239575503198607639501078528y := emulated.ValueOf[Base](params.Gmy[186]) - G392318858461667547739736838950479151006397215279002157056x := emulated.ValueOf[Base](params.Gmx[187]) - G392318858461667547739736838950479151006397215279002157056y := emulated.ValueOf[Base](params.Gmy[187]) - G784637716923335095479473677900958302012794430558004314112x := emulated.ValueOf[Base](params.Gmx[188]) - G784637716923335095479473677900958302012794430558004314112y := emulated.ValueOf[Base](params.Gmy[188]) - G1569275433846670190958947355801916604025588861116008628224x := emulated.ValueOf[Base](params.Gmx[189]) - G1569275433846670190958947355801916604025588861116008628224y := emulated.ValueOf[Base](params.Gmy[189]) - G3138550867693340381917894711603833208051177722232017256448x := emulated.ValueOf[Base](params.Gmx[190]) - G3138550867693340381917894711603833208051177722232017256448y := emulated.ValueOf[Base](params.Gmy[190]) - G6277101735386680763835789423207666416102355444464034512896x := emulated.ValueOf[Base](params.Gmx[191]) - G6277101735386680763835789423207666416102355444464034512896y := emulated.ValueOf[Base](params.Gmy[191]) - G12554203470773361527671578846415332832204710888928069025792x := emulated.ValueOf[Base](params.Gmx[192]) - G12554203470773361527671578846415332832204710888928069025792y := emulated.ValueOf[Base](params.Gmy[192]) - G25108406941546723055343157692830665664409421777856138051584x := emulated.ValueOf[Base](params.Gmx[193]) - G25108406941546723055343157692830665664409421777856138051584y := emulated.ValueOf[Base](params.Gmy[193]) - G50216813883093446110686315385661331328818843555712276103168x := emulated.ValueOf[Base](params.Gmx[194]) - G50216813883093446110686315385661331328818843555712276103168y := emulated.ValueOf[Base](params.Gmy[194]) - G100433627766186892221372630771322662657637687111424552206336x := emulated.ValueOf[Base](params.Gmx[195]) - G100433627766186892221372630771322662657637687111424552206336y := emulated.ValueOf[Base](params.Gmy[195]) - G200867255532373784442745261542645325315275374222849104412672x := emulated.ValueOf[Base](params.Gmx[196]) - G200867255532373784442745261542645325315275374222849104412672y := emulated.ValueOf[Base](params.Gmy[196]) - G401734511064747568885490523085290650630550748445698208825344x := emulated.ValueOf[Base](params.Gmx[197]) - G401734511064747568885490523085290650630550748445698208825344y := emulated.ValueOf[Base](params.Gmy[197]) - G803469022129495137770981046170581301261101496891396417650688x := emulated.ValueOf[Base](params.Gmx[198]) - G803469022129495137770981046170581301261101496891396417650688y := emulated.ValueOf[Base](params.Gmy[198]) - G1606938044258990275541962092341162602522202993782792835301376x := emulated.ValueOf[Base](params.Gmx[199]) - G1606938044258990275541962092341162602522202993782792835301376y := emulated.ValueOf[Base](params.Gmy[199]) - G3213876088517980551083924184682325205044405987565585670602752x := emulated.ValueOf[Base](params.Gmx[200]) - G3213876088517980551083924184682325205044405987565585670602752y := emulated.ValueOf[Base](params.Gmy[200]) - G6427752177035961102167848369364650410088811975131171341205504x := emulated.ValueOf[Base](params.Gmx[201]) - G6427752177035961102167848369364650410088811975131171341205504y := emulated.ValueOf[Base](params.Gmy[201]) - G12855504354071922204335696738729300820177623950262342682411008x := emulated.ValueOf[Base](params.Gmx[202]) - G12855504354071922204335696738729300820177623950262342682411008y := emulated.ValueOf[Base](params.Gmy[202]) - G25711008708143844408671393477458601640355247900524685364822016x := emulated.ValueOf[Base](params.Gmx[203]) - G25711008708143844408671393477458601640355247900524685364822016y := emulated.ValueOf[Base](params.Gmy[203]) - G51422017416287688817342786954917203280710495801049370729644032x := emulated.ValueOf[Base](params.Gmx[204]) - G51422017416287688817342786954917203280710495801049370729644032y := emulated.ValueOf[Base](params.Gmy[204]) - G102844034832575377634685573909834406561420991602098741459288064x := emulated.ValueOf[Base](params.Gmx[205]) - G102844034832575377634685573909834406561420991602098741459288064y := emulated.ValueOf[Base](params.Gmy[205]) - G205688069665150755269371147819668813122841983204197482918576128x := emulated.ValueOf[Base](params.Gmx[206]) - G205688069665150755269371147819668813122841983204197482918576128y := emulated.ValueOf[Base](params.Gmy[206]) - G411376139330301510538742295639337626245683966408394965837152256x := emulated.ValueOf[Base](params.Gmx[207]) - G411376139330301510538742295639337626245683966408394965837152256y := emulated.ValueOf[Base](params.Gmy[207]) - G822752278660603021077484591278675252491367932816789931674304512x := emulated.ValueOf[Base](params.Gmx[208]) - G822752278660603021077484591278675252491367932816789931674304512y := emulated.ValueOf[Base](params.Gmy[208]) - G1645504557321206042154969182557350504982735865633579863348609024x := emulated.ValueOf[Base](params.Gmx[209]) - G1645504557321206042154969182557350504982735865633579863348609024y := emulated.ValueOf[Base](params.Gmy[209]) - G3291009114642412084309938365114701009965471731267159726697218048x := emulated.ValueOf[Base](params.Gmx[210]) - G3291009114642412084309938365114701009965471731267159726697218048y := emulated.ValueOf[Base](params.Gmy[210]) - G6582018229284824168619876730229402019930943462534319453394436096x := emulated.ValueOf[Base](params.Gmx[211]) - G6582018229284824168619876730229402019930943462534319453394436096y := emulated.ValueOf[Base](params.Gmy[211]) - G13164036458569648337239753460458804039861886925068638906788872192x := emulated.ValueOf[Base](params.Gmx[212]) - G13164036458569648337239753460458804039861886925068638906788872192y := emulated.ValueOf[Base](params.Gmy[212]) - G26328072917139296674479506920917608079723773850137277813577744384x := emulated.ValueOf[Base](params.Gmx[213]) - G26328072917139296674479506920917608079723773850137277813577744384y := emulated.ValueOf[Base](params.Gmy[213]) - G52656145834278593348959013841835216159447547700274555627155488768x := emulated.ValueOf[Base](params.Gmx[214]) - G52656145834278593348959013841835216159447547700274555627155488768y := emulated.ValueOf[Base](params.Gmy[214]) - G105312291668557186697918027683670432318895095400549111254310977536x := emulated.ValueOf[Base](params.Gmx[215]) - G105312291668557186697918027683670432318895095400549111254310977536y := emulated.ValueOf[Base](params.Gmy[215]) - G210624583337114373395836055367340864637790190801098222508621955072x := emulated.ValueOf[Base](params.Gmx[216]) - G210624583337114373395836055367340864637790190801098222508621955072y := emulated.ValueOf[Base](params.Gmy[216]) - G421249166674228746791672110734681729275580381602196445017243910144x := emulated.ValueOf[Base](params.Gmx[217]) - G421249166674228746791672110734681729275580381602196445017243910144y := emulated.ValueOf[Base](params.Gmy[217]) - G842498333348457493583344221469363458551160763204392890034487820288x := emulated.ValueOf[Base](params.Gmx[218]) - G842498333348457493583344221469363458551160763204392890034487820288y := emulated.ValueOf[Base](params.Gmy[218]) - G1684996666696914987166688442938726917102321526408785780068975640576x := emulated.ValueOf[Base](params.Gmx[219]) - G1684996666696914987166688442938726917102321526408785780068975640576y := emulated.ValueOf[Base](params.Gmy[219]) - G3369993333393829974333376885877453834204643052817571560137951281152x := emulated.ValueOf[Base](params.Gmx[220]) - G3369993333393829974333376885877453834204643052817571560137951281152y := emulated.ValueOf[Base](params.Gmy[220]) - G6739986666787659948666753771754907668409286105635143120275902562304x := emulated.ValueOf[Base](params.Gmx[221]) - G6739986666787659948666753771754907668409286105635143120275902562304y := emulated.ValueOf[Base](params.Gmy[221]) - G13479973333575319897333507543509815336818572211270286240551805124608x := emulated.ValueOf[Base](params.Gmx[222]) - G13479973333575319897333507543509815336818572211270286240551805124608y := emulated.ValueOf[Base](params.Gmy[222]) - G26959946667150639794667015087019630673637144422540572481103610249216x := emulated.ValueOf[Base](params.Gmx[223]) - G26959946667150639794667015087019630673637144422540572481103610249216y := emulated.ValueOf[Base](params.Gmy[223]) - G53919893334301279589334030174039261347274288845081144962207220498432x := emulated.ValueOf[Base](params.Gmx[224]) - G53919893334301279589334030174039261347274288845081144962207220498432y := emulated.ValueOf[Base](params.Gmy[224]) - G107839786668602559178668060348078522694548577690162289924414440996864x := emulated.ValueOf[Base](params.Gmx[225]) - G107839786668602559178668060348078522694548577690162289924414440996864y := emulated.ValueOf[Base](params.Gmy[225]) - G215679573337205118357336120696157045389097155380324579848828881993728x := emulated.ValueOf[Base](params.Gmx[226]) - G215679573337205118357336120696157045389097155380324579848828881993728y := emulated.ValueOf[Base](params.Gmy[226]) - G431359146674410236714672241392314090778194310760649159697657763987456x := emulated.ValueOf[Base](params.Gmx[227]) - G431359146674410236714672241392314090778194310760649159697657763987456y := emulated.ValueOf[Base](params.Gmy[227]) - G862718293348820473429344482784628181556388621521298319395315527974912x := emulated.ValueOf[Base](params.Gmx[228]) - G862718293348820473429344482784628181556388621521298319395315527974912y := emulated.ValueOf[Base](params.Gmy[228]) - G1725436586697640946858688965569256363112777243042596638790631055949824x := emulated.ValueOf[Base](params.Gmx[229]) - G1725436586697640946858688965569256363112777243042596638790631055949824y := emulated.ValueOf[Base](params.Gmy[229]) - G3450873173395281893717377931138512726225554486085193277581262111899648x := emulated.ValueOf[Base](params.Gmx[230]) - G3450873173395281893717377931138512726225554486085193277581262111899648y := emulated.ValueOf[Base](params.Gmy[230]) - G6901746346790563787434755862277025452451108972170386555162524223799296x := emulated.ValueOf[Base](params.Gmx[231]) - G6901746346790563787434755862277025452451108972170386555162524223799296y := emulated.ValueOf[Base](params.Gmy[231]) - G13803492693581127574869511724554050904902217944340773110325048447598592x := emulated.ValueOf[Base](params.Gmx[232]) - G13803492693581127574869511724554050904902217944340773110325048447598592y := emulated.ValueOf[Base](params.Gmy[232]) - G27606985387162255149739023449108101809804435888681546220650096895197184x := emulated.ValueOf[Base](params.Gmx[233]) - G27606985387162255149739023449108101809804435888681546220650096895197184y := emulated.ValueOf[Base](params.Gmy[233]) - G55213970774324510299478046898216203619608871777363092441300193790394368x := emulated.ValueOf[Base](params.Gmx[234]) - G55213970774324510299478046898216203619608871777363092441300193790394368y := emulated.ValueOf[Base](params.Gmy[234]) - G110427941548649020598956093796432407239217743554726184882600387580788736x := emulated.ValueOf[Base](params.Gmx[235]) - G110427941548649020598956093796432407239217743554726184882600387580788736y := emulated.ValueOf[Base](params.Gmy[235]) - G220855883097298041197912187592864814478435487109452369765200775161577472x := emulated.ValueOf[Base](params.Gmx[236]) - G220855883097298041197912187592864814478435487109452369765200775161577472y := emulated.ValueOf[Base](params.Gmy[236]) - G441711766194596082395824375185729628956870974218904739530401550323154944x := emulated.ValueOf[Base](params.Gmx[237]) - G441711766194596082395824375185729628956870974218904739530401550323154944y := emulated.ValueOf[Base](params.Gmy[237]) - G883423532389192164791648750371459257913741948437809479060803100646309888x := emulated.ValueOf[Base](params.Gmx[238]) - G883423532389192164791648750371459257913741948437809479060803100646309888y := emulated.ValueOf[Base](params.Gmy[238]) - G1766847064778384329583297500742918515827483896875618958121606201292619776x := emulated.ValueOf[Base](params.Gmx[239]) - G1766847064778384329583297500742918515827483896875618958121606201292619776y := emulated.ValueOf[Base](params.Gmy[239]) - G3533694129556768659166595001485837031654967793751237916243212402585239552x := emulated.ValueOf[Base](params.Gmx[240]) - G3533694129556768659166595001485837031654967793751237916243212402585239552y := emulated.ValueOf[Base](params.Gmy[240]) - G7067388259113537318333190002971674063309935587502475832486424805170479104x := emulated.ValueOf[Base](params.Gmx[241]) - G7067388259113537318333190002971674063309935587502475832486424805170479104y := emulated.ValueOf[Base](params.Gmy[241]) - G14134776518227074636666380005943348126619871175004951664972849610340958208x := emulated.ValueOf[Base](params.Gmx[242]) - G14134776518227074636666380005943348126619871175004951664972849610340958208y := emulated.ValueOf[Base](params.Gmy[242]) - G28269553036454149273332760011886696253239742350009903329945699220681916416x := emulated.ValueOf[Base](params.Gmx[243]) - G28269553036454149273332760011886696253239742350009903329945699220681916416y := emulated.ValueOf[Base](params.Gmy[243]) - G56539106072908298546665520023773392506479484700019806659891398441363832832x := emulated.ValueOf[Base](params.Gmx[244]) - G56539106072908298546665520023773392506479484700019806659891398441363832832y := emulated.ValueOf[Base](params.Gmy[244]) - G113078212145816597093331040047546785012958969400039613319782796882727665664x := emulated.ValueOf[Base](params.Gmx[245]) - G113078212145816597093331040047546785012958969400039613319782796882727665664y := emulated.ValueOf[Base](params.Gmy[245]) - G226156424291633194186662080095093570025917938800079226639565593765455331328x := emulated.ValueOf[Base](params.Gmx[246]) - G226156424291633194186662080095093570025917938800079226639565593765455331328y := emulated.ValueOf[Base](params.Gmy[246]) - G452312848583266388373324160190187140051835877600158453279131187530910662656x := emulated.ValueOf[Base](params.Gmx[247]) - G452312848583266388373324160190187140051835877600158453279131187530910662656y := emulated.ValueOf[Base](params.Gmy[247]) - G904625697166532776746648320380374280103671755200316906558262375061821325312x := emulated.ValueOf[Base](params.Gmx[248]) - G904625697166532776746648320380374280103671755200316906558262375061821325312y := emulated.ValueOf[Base](params.Gmy[248]) - G1809251394333065553493296640760748560207343510400633813116524750123642650624x := emulated.ValueOf[Base](params.Gmx[249]) - G1809251394333065553493296640760748560207343510400633813116524750123642650624y := emulated.ValueOf[Base](params.Gmy[249]) - G3618502788666131106986593281521497120414687020801267626233049500247285301248x := emulated.ValueOf[Base](params.Gmx[250]) - G3618502788666131106986593281521497120414687020801267626233049500247285301248y := emulated.ValueOf[Base](params.Gmy[250]) - G7237005577332262213973186563042994240829374041602535252466099000494570602496x := emulated.ValueOf[Base](params.Gmx[251]) - G7237005577332262213973186563042994240829374041602535252466099000494570602496y := emulated.ValueOf[Base](params.Gmy[251]) - G14474011154664524427946373126085988481658748083205070504932198000989141204992x := emulated.ValueOf[Base](params.Gmx[252]) - G14474011154664524427946373126085988481658748083205070504932198000989141204992y := emulated.ValueOf[Base](params.Gmy[252]) - G28948022309329048855892746252171976963317496166410141009864396001978282409984x := emulated.ValueOf[Base](params.Gmx[253]) - G28948022309329048855892746252171976963317496166410141009864396001978282409984y := emulated.ValueOf[Base](params.Gmy[253]) - G57896044618658097711785492504343953926634992332820282019728792003956564819968x := emulated.ValueOf[Base](params.Gmx[254]) - G57896044618658097711785492504343953926634992332820282019728792003956564819968y := emulated.ValueOf[Base](params.Gmy[254]) - G115792089237316195423570985008687907853269984665640564039457584007913129639936x := emulated.ValueOf[Base](params.Gmx[255]) - G115792089237316195423570985008687907853269984665640564039457584007913129639936y := emulated.ValueOf[Base](params.Gmy[255]) + G5x := emulated.ValueOf[Base](params.Gmx[1]) + G5y := emulated.ValueOf[Base](params.Gmy[1]) + G7x := emulated.ValueOf[Base](params.Gmx[2]) + G7y := emulated.ValueOf[Base](params.Gmy[2]) + G2To3x := emulated.ValueOf[Base](params.Gmx[3]) + G2To3y := emulated.ValueOf[Base](params.Gmy[3]) + G2To4x := emulated.ValueOf[Base](params.Gmx[4]) + G2To4y := emulated.ValueOf[Base](params.Gmy[4]) + G2To5x := emulated.ValueOf[Base](params.Gmx[5]) + G2To5y := emulated.ValueOf[Base](params.Gmy[5]) + G2To6x := emulated.ValueOf[Base](params.Gmx[6]) + G2To6y := emulated.ValueOf[Base](params.Gmy[6]) + G2To7x := emulated.ValueOf[Base](params.Gmx[7]) + G2To7y := emulated.ValueOf[Base](params.Gmy[7]) + G2To8x := emulated.ValueOf[Base](params.Gmx[8]) + G2To8y := emulated.ValueOf[Base](params.Gmy[8]) + G2To9x := emulated.ValueOf[Base](params.Gmx[9]) + G2To9y := emulated.ValueOf[Base](params.Gmy[9]) + G2To10x := emulated.ValueOf[Base](params.Gmx[10]) + G2To10y := emulated.ValueOf[Base](params.Gmy[10]) + G2To11x := emulated.ValueOf[Base](params.Gmx[11]) + G2To11y := emulated.ValueOf[Base](params.Gmy[11]) + G2To12x := emulated.ValueOf[Base](params.Gmx[12]) + G2To12y := emulated.ValueOf[Base](params.Gmy[12]) + G2To13x := emulated.ValueOf[Base](params.Gmx[13]) + G2To13y := emulated.ValueOf[Base](params.Gmy[13]) + G2To14x := emulated.ValueOf[Base](params.Gmx[14]) + G2To14y := emulated.ValueOf[Base](params.Gmy[14]) + G2To15x := emulated.ValueOf[Base](params.Gmx[15]) + G2To15y := emulated.ValueOf[Base](params.Gmy[15]) + G2To16x := emulated.ValueOf[Base](params.Gmx[16]) + G2To16y := emulated.ValueOf[Base](params.Gmy[16]) + G2To17x := emulated.ValueOf[Base](params.Gmx[17]) + G2To17y := emulated.ValueOf[Base](params.Gmy[17]) + G2To18x := emulated.ValueOf[Base](params.Gmx[18]) + G2To18y := emulated.ValueOf[Base](params.Gmy[18]) + G2To19x := emulated.ValueOf[Base](params.Gmx[19]) + G2To19y := emulated.ValueOf[Base](params.Gmy[19]) + G2To20x := emulated.ValueOf[Base](params.Gmx[20]) + G2To20y := emulated.ValueOf[Base](params.Gmy[20]) + G2To21x := emulated.ValueOf[Base](params.Gmx[21]) + G2To21y := emulated.ValueOf[Base](params.Gmy[21]) + G2To22x := emulated.ValueOf[Base](params.Gmx[22]) + G2To22y := emulated.ValueOf[Base](params.Gmy[22]) + G2To23x := emulated.ValueOf[Base](params.Gmx[23]) + G2To23y := emulated.ValueOf[Base](params.Gmy[23]) + G2To24x := emulated.ValueOf[Base](params.Gmx[24]) + G2To24y := emulated.ValueOf[Base](params.Gmy[24]) + G2To25x := emulated.ValueOf[Base](params.Gmx[25]) + G2To25y := emulated.ValueOf[Base](params.Gmy[25]) + G2To26x := emulated.ValueOf[Base](params.Gmx[26]) + G2To26y := emulated.ValueOf[Base](params.Gmy[26]) + G2To27x := emulated.ValueOf[Base](params.Gmx[27]) + G2To27y := emulated.ValueOf[Base](params.Gmy[27]) + G2To28x := emulated.ValueOf[Base](params.Gmx[28]) + G2To28y := emulated.ValueOf[Base](params.Gmy[28]) + G2To29x := emulated.ValueOf[Base](params.Gmx[29]) + G2To29y := emulated.ValueOf[Base](params.Gmy[29]) + G2To30x := emulated.ValueOf[Base](params.Gmx[30]) + G2To30y := emulated.ValueOf[Base](params.Gmy[30]) + G2To31x := emulated.ValueOf[Base](params.Gmx[31]) + G2To31y := emulated.ValueOf[Base](params.Gmy[31]) + G2To32x := emulated.ValueOf[Base](params.Gmx[32]) + G2To32y := emulated.ValueOf[Base](params.Gmy[32]) + G2To33x := emulated.ValueOf[Base](params.Gmx[33]) + G2To33y := emulated.ValueOf[Base](params.Gmy[33]) + G2To34x := emulated.ValueOf[Base](params.Gmx[34]) + G2To34y := emulated.ValueOf[Base](params.Gmy[34]) + G2To35x := emulated.ValueOf[Base](params.Gmx[35]) + G2To35y := emulated.ValueOf[Base](params.Gmy[35]) + G2To36x := emulated.ValueOf[Base](params.Gmx[36]) + G2To36y := emulated.ValueOf[Base](params.Gmy[36]) + G2To37x := emulated.ValueOf[Base](params.Gmx[37]) + G2To37y := emulated.ValueOf[Base](params.Gmy[37]) + G2To38x := emulated.ValueOf[Base](params.Gmx[38]) + G2To38y := emulated.ValueOf[Base](params.Gmy[38]) + G2To39x := emulated.ValueOf[Base](params.Gmx[39]) + G2To39y := emulated.ValueOf[Base](params.Gmy[39]) + G2To40x := emulated.ValueOf[Base](params.Gmx[40]) + G2To40y := emulated.ValueOf[Base](params.Gmy[40]) + G2To41x := emulated.ValueOf[Base](params.Gmx[41]) + G2To41y := emulated.ValueOf[Base](params.Gmy[41]) + G2To42x := emulated.ValueOf[Base](params.Gmx[42]) + G2To42y := emulated.ValueOf[Base](params.Gmy[42]) + G2To43x := emulated.ValueOf[Base](params.Gmx[43]) + G2To43y := emulated.ValueOf[Base](params.Gmy[43]) + G2To44x := emulated.ValueOf[Base](params.Gmx[44]) + G2To44y := emulated.ValueOf[Base](params.Gmy[44]) + G2To45x := emulated.ValueOf[Base](params.Gmx[45]) + G2To45y := emulated.ValueOf[Base](params.Gmy[45]) + G2To46x := emulated.ValueOf[Base](params.Gmx[46]) + G2To46y := emulated.ValueOf[Base](params.Gmy[46]) + G2To47x := emulated.ValueOf[Base](params.Gmx[47]) + G2To47y := emulated.ValueOf[Base](params.Gmy[47]) + G2To48x := emulated.ValueOf[Base](params.Gmx[48]) + G2To48y := emulated.ValueOf[Base](params.Gmy[48]) + G2To49x := emulated.ValueOf[Base](params.Gmx[49]) + G2To49y := emulated.ValueOf[Base](params.Gmy[49]) + G2To50x := emulated.ValueOf[Base](params.Gmx[50]) + G2To50y := emulated.ValueOf[Base](params.Gmy[50]) + G2To51x := emulated.ValueOf[Base](params.Gmx[51]) + G2To51y := emulated.ValueOf[Base](params.Gmy[51]) + G2To52x := emulated.ValueOf[Base](params.Gmx[52]) + G2To52y := emulated.ValueOf[Base](params.Gmy[52]) + G2To53x := emulated.ValueOf[Base](params.Gmx[53]) + G2To53y := emulated.ValueOf[Base](params.Gmy[53]) + G2To54x := emulated.ValueOf[Base](params.Gmx[54]) + G2To54y := emulated.ValueOf[Base](params.Gmy[54]) + G2To55x := emulated.ValueOf[Base](params.Gmx[55]) + G2To55y := emulated.ValueOf[Base](params.Gmy[55]) + G2To56x := emulated.ValueOf[Base](params.Gmx[56]) + G2To56y := emulated.ValueOf[Base](params.Gmy[56]) + G2To57x := emulated.ValueOf[Base](params.Gmx[57]) + G2To57y := emulated.ValueOf[Base](params.Gmy[57]) + G2To58x := emulated.ValueOf[Base](params.Gmx[58]) + G2To58y := emulated.ValueOf[Base](params.Gmy[58]) + G2To59x := emulated.ValueOf[Base](params.Gmx[59]) + G2To59y := emulated.ValueOf[Base](params.Gmy[59]) + G2To60x := emulated.ValueOf[Base](params.Gmx[60]) + G2To60y := emulated.ValueOf[Base](params.Gmy[60]) + G2To61x := emulated.ValueOf[Base](params.Gmx[61]) + G2To61y := emulated.ValueOf[Base](params.Gmy[61]) + G2To62x := emulated.ValueOf[Base](params.Gmx[62]) + G2To62y := emulated.ValueOf[Base](params.Gmy[62]) + G2To63x := emulated.ValueOf[Base](params.Gmx[63]) + G2To63y := emulated.ValueOf[Base](params.Gmy[63]) + G2To64x := emulated.ValueOf[Base](params.Gmx[64]) + G2To64y := emulated.ValueOf[Base](params.Gmy[64]) + G2To65x := emulated.ValueOf[Base](params.Gmx[65]) + G2To65y := emulated.ValueOf[Base](params.Gmy[65]) + G2To66x := emulated.ValueOf[Base](params.Gmx[66]) + G2To66y := emulated.ValueOf[Base](params.Gmy[66]) + G2To67x := emulated.ValueOf[Base](params.Gmx[67]) + G2To67y := emulated.ValueOf[Base](params.Gmy[67]) + G2To68x := emulated.ValueOf[Base](params.Gmx[68]) + G2To68y := emulated.ValueOf[Base](params.Gmy[68]) + G2To69x := emulated.ValueOf[Base](params.Gmx[69]) + G2To69y := emulated.ValueOf[Base](params.Gmy[69]) + G2To70x := emulated.ValueOf[Base](params.Gmx[70]) + G2To70y := emulated.ValueOf[Base](params.Gmy[70]) + G2To71x := emulated.ValueOf[Base](params.Gmx[71]) + G2To71y := emulated.ValueOf[Base](params.Gmy[71]) + G2To72x := emulated.ValueOf[Base](params.Gmx[72]) + G2To72y := emulated.ValueOf[Base](params.Gmy[72]) + G2To73x := emulated.ValueOf[Base](params.Gmx[73]) + G2To73y := emulated.ValueOf[Base](params.Gmy[73]) + G2To74x := emulated.ValueOf[Base](params.Gmx[74]) + G2To74y := emulated.ValueOf[Base](params.Gmy[74]) + G2To75x := emulated.ValueOf[Base](params.Gmx[75]) + G2To75y := emulated.ValueOf[Base](params.Gmy[75]) + G2To76x := emulated.ValueOf[Base](params.Gmx[76]) + G2To76y := emulated.ValueOf[Base](params.Gmy[76]) + G2To77x := emulated.ValueOf[Base](params.Gmx[77]) + G2To77y := emulated.ValueOf[Base](params.Gmy[77]) + G2To78x := emulated.ValueOf[Base](params.Gmx[78]) + G2To78y := emulated.ValueOf[Base](params.Gmy[78]) + G2To79x := emulated.ValueOf[Base](params.Gmx[79]) + G2To79y := emulated.ValueOf[Base](params.Gmy[79]) + G2To80x := emulated.ValueOf[Base](params.Gmx[80]) + G2To80y := emulated.ValueOf[Base](params.Gmy[80]) + G2To81x := emulated.ValueOf[Base](params.Gmx[81]) + G2To81y := emulated.ValueOf[Base](params.Gmy[81]) + G2To82x := emulated.ValueOf[Base](params.Gmx[82]) + G2To82y := emulated.ValueOf[Base](params.Gmy[82]) + G2To83x := emulated.ValueOf[Base](params.Gmx[83]) + G2To83y := emulated.ValueOf[Base](params.Gmy[83]) + G2To84x := emulated.ValueOf[Base](params.Gmx[84]) + G2To84y := emulated.ValueOf[Base](params.Gmy[84]) + G2To85x := emulated.ValueOf[Base](params.Gmx[85]) + G2To85y := emulated.ValueOf[Base](params.Gmy[85]) + G2To86x := emulated.ValueOf[Base](params.Gmx[86]) + G2To86y := emulated.ValueOf[Base](params.Gmy[86]) + G2To87x := emulated.ValueOf[Base](params.Gmx[87]) + G2To87y := emulated.ValueOf[Base](params.Gmy[87]) + G2To88x := emulated.ValueOf[Base](params.Gmx[88]) + G2To88y := emulated.ValueOf[Base](params.Gmy[88]) + G2To89x := emulated.ValueOf[Base](params.Gmx[89]) + G2To89y := emulated.ValueOf[Base](params.Gmy[89]) + G2To90x := emulated.ValueOf[Base](params.Gmx[90]) + G2To90y := emulated.ValueOf[Base](params.Gmy[90]) + G2To91x := emulated.ValueOf[Base](params.Gmx[91]) + G2To91y := emulated.ValueOf[Base](params.Gmy[91]) + G2To92x := emulated.ValueOf[Base](params.Gmx[92]) + G2To92y := emulated.ValueOf[Base](params.Gmy[92]) + G2To93x := emulated.ValueOf[Base](params.Gmx[93]) + G2To93y := emulated.ValueOf[Base](params.Gmy[93]) + G2To94x := emulated.ValueOf[Base](params.Gmx[94]) + G2To94y := emulated.ValueOf[Base](params.Gmy[94]) + G2To95x := emulated.ValueOf[Base](params.Gmx[95]) + G2To95y := emulated.ValueOf[Base](params.Gmy[95]) + G2To96x := emulated.ValueOf[Base](params.Gmx[96]) + G2To96y := emulated.ValueOf[Base](params.Gmy[96]) + G2To97x := emulated.ValueOf[Base](params.Gmx[97]) + G2To97y := emulated.ValueOf[Base](params.Gmy[97]) + G2To98x := emulated.ValueOf[Base](params.Gmx[98]) + G2To98y := emulated.ValueOf[Base](params.Gmy[98]) + G2To99x := emulated.ValueOf[Base](params.Gmx[99]) + G2To99y := emulated.ValueOf[Base](params.Gmy[99]) + G2To100x := emulated.ValueOf[Base](params.Gmx[100]) + G2To100y := emulated.ValueOf[Base](params.Gmy[100]) + G2To101x := emulated.ValueOf[Base](params.Gmx[101]) + G2To101y := emulated.ValueOf[Base](params.Gmy[101]) + G2To102x := emulated.ValueOf[Base](params.Gmx[102]) + G2To102y := emulated.ValueOf[Base](params.Gmy[102]) + G2To103x := emulated.ValueOf[Base](params.Gmx[103]) + G2To103y := emulated.ValueOf[Base](params.Gmy[103]) + G2To104x := emulated.ValueOf[Base](params.Gmx[104]) + G2To104y := emulated.ValueOf[Base](params.Gmy[104]) + G2To105x := emulated.ValueOf[Base](params.Gmx[105]) + G2To105y := emulated.ValueOf[Base](params.Gmy[105]) + G2To106x := emulated.ValueOf[Base](params.Gmx[106]) + G2To106y := emulated.ValueOf[Base](params.Gmy[106]) + G2To107x := emulated.ValueOf[Base](params.Gmx[107]) + G2To107y := emulated.ValueOf[Base](params.Gmy[107]) + G2To108x := emulated.ValueOf[Base](params.Gmx[108]) + G2To108y := emulated.ValueOf[Base](params.Gmy[108]) + G2To109x := emulated.ValueOf[Base](params.Gmx[109]) + G2To109y := emulated.ValueOf[Base](params.Gmy[109]) + G2To110x := emulated.ValueOf[Base](params.Gmx[110]) + G2To110y := emulated.ValueOf[Base](params.Gmy[110]) + G2To111x := emulated.ValueOf[Base](params.Gmx[111]) + G2To111y := emulated.ValueOf[Base](params.Gmy[111]) + G2To112x := emulated.ValueOf[Base](params.Gmx[112]) + G2To112y := emulated.ValueOf[Base](params.Gmy[112]) + G2To113x := emulated.ValueOf[Base](params.Gmx[113]) + G2To113y := emulated.ValueOf[Base](params.Gmy[113]) + G2To114x := emulated.ValueOf[Base](params.Gmx[114]) + G2To114y := emulated.ValueOf[Base](params.Gmy[114]) + G2To115x := emulated.ValueOf[Base](params.Gmx[115]) + G2To115y := emulated.ValueOf[Base](params.Gmy[115]) + G2To116x := emulated.ValueOf[Base](params.Gmx[116]) + G2To116y := emulated.ValueOf[Base](params.Gmy[116]) + G2To117x := emulated.ValueOf[Base](params.Gmx[117]) + G2To117y := emulated.ValueOf[Base](params.Gmy[117]) + G2To118x := emulated.ValueOf[Base](params.Gmx[118]) + G2To118y := emulated.ValueOf[Base](params.Gmy[118]) + G2To119x := emulated.ValueOf[Base](params.Gmx[119]) + G2To119y := emulated.ValueOf[Base](params.Gmy[119]) + G2To120x := emulated.ValueOf[Base](params.Gmx[120]) + G2To120y := emulated.ValueOf[Base](params.Gmy[120]) + G2To121x := emulated.ValueOf[Base](params.Gmx[121]) + G2To121y := emulated.ValueOf[Base](params.Gmy[121]) + G2To122x := emulated.ValueOf[Base](params.Gmx[122]) + G2To122y := emulated.ValueOf[Base](params.Gmy[122]) + G2To123x := emulated.ValueOf[Base](params.Gmx[123]) + G2To123y := emulated.ValueOf[Base](params.Gmy[123]) + G2To124x := emulated.ValueOf[Base](params.Gmx[124]) + G2To124y := emulated.ValueOf[Base](params.Gmy[124]) + G2To125x := emulated.ValueOf[Base](params.Gmx[125]) + G2To125y := emulated.ValueOf[Base](params.Gmy[125]) + G2To126x := emulated.ValueOf[Base](params.Gmx[126]) + G2To126y := emulated.ValueOf[Base](params.Gmy[126]) + G2To127x := emulated.ValueOf[Base](params.Gmx[127]) + G2To127y := emulated.ValueOf[Base](params.Gmy[127]) + G2To128x := emulated.ValueOf[Base](params.Gmx[128]) + G2To128y := emulated.ValueOf[Base](params.Gmy[128]) + G2To129x := emulated.ValueOf[Base](params.Gmx[129]) + G2To129y := emulated.ValueOf[Base](params.Gmy[129]) + G2To130x := emulated.ValueOf[Base](params.Gmx[130]) + G2To130y := emulated.ValueOf[Base](params.Gmy[130]) + G2To131x := emulated.ValueOf[Base](params.Gmx[131]) + G2To131y := emulated.ValueOf[Base](params.Gmy[131]) + G2To132x := emulated.ValueOf[Base](params.Gmx[132]) + G2To132y := emulated.ValueOf[Base](params.Gmy[132]) + G2To133x := emulated.ValueOf[Base](params.Gmx[133]) + G2To133y := emulated.ValueOf[Base](params.Gmy[133]) + G2To134x := emulated.ValueOf[Base](params.Gmx[134]) + G2To134y := emulated.ValueOf[Base](params.Gmy[134]) + G2To135x := emulated.ValueOf[Base](params.Gmx[135]) + G2To135y := emulated.ValueOf[Base](params.Gmy[135]) + G2To136x := emulated.ValueOf[Base](params.Gmx[136]) + G2To136y := emulated.ValueOf[Base](params.Gmy[136]) + G2To137x := emulated.ValueOf[Base](params.Gmx[137]) + G2To137y := emulated.ValueOf[Base](params.Gmy[137]) + G2To138x := emulated.ValueOf[Base](params.Gmx[138]) + G2To138y := emulated.ValueOf[Base](params.Gmy[138]) + G2To139x := emulated.ValueOf[Base](params.Gmx[139]) + G2To139y := emulated.ValueOf[Base](params.Gmy[139]) + G2To140x := emulated.ValueOf[Base](params.Gmx[140]) + G2To140y := emulated.ValueOf[Base](params.Gmy[140]) + G2To141x := emulated.ValueOf[Base](params.Gmx[141]) + G2To141y := emulated.ValueOf[Base](params.Gmy[141]) + G2To142x := emulated.ValueOf[Base](params.Gmx[142]) + G2To142y := emulated.ValueOf[Base](params.Gmy[142]) + G2To143x := emulated.ValueOf[Base](params.Gmx[143]) + G2To143y := emulated.ValueOf[Base](params.Gmy[143]) + G2To144x := emulated.ValueOf[Base](params.Gmx[144]) + G2To144y := emulated.ValueOf[Base](params.Gmy[144]) + G2To145x := emulated.ValueOf[Base](params.Gmx[145]) + G2To145y := emulated.ValueOf[Base](params.Gmy[145]) + G2To146x := emulated.ValueOf[Base](params.Gmx[146]) + G2To146y := emulated.ValueOf[Base](params.Gmy[146]) + G2To147x := emulated.ValueOf[Base](params.Gmx[147]) + G2To147y := emulated.ValueOf[Base](params.Gmy[147]) + G2To148x := emulated.ValueOf[Base](params.Gmx[148]) + G2To148y := emulated.ValueOf[Base](params.Gmy[148]) + G2To149x := emulated.ValueOf[Base](params.Gmx[149]) + G2To149y := emulated.ValueOf[Base](params.Gmy[149]) + G2To150x := emulated.ValueOf[Base](params.Gmx[150]) + G2To150y := emulated.ValueOf[Base](params.Gmy[150]) + G2To151x := emulated.ValueOf[Base](params.Gmx[151]) + G2To151y := emulated.ValueOf[Base](params.Gmy[151]) + G2To152x := emulated.ValueOf[Base](params.Gmx[152]) + G2To152y := emulated.ValueOf[Base](params.Gmy[152]) + G2To153x := emulated.ValueOf[Base](params.Gmx[153]) + G2To153y := emulated.ValueOf[Base](params.Gmy[153]) + G2To154x := emulated.ValueOf[Base](params.Gmx[154]) + G2To154y := emulated.ValueOf[Base](params.Gmy[154]) + G2To155x := emulated.ValueOf[Base](params.Gmx[155]) + G2To155y := emulated.ValueOf[Base](params.Gmy[155]) + G2To156x := emulated.ValueOf[Base](params.Gmx[156]) + G2To156y := emulated.ValueOf[Base](params.Gmy[156]) + G2To157x := emulated.ValueOf[Base](params.Gmx[157]) + G2To157y := emulated.ValueOf[Base](params.Gmy[157]) + G2To158x := emulated.ValueOf[Base](params.Gmx[158]) + G2To158y := emulated.ValueOf[Base](params.Gmy[158]) + G2To159x := emulated.ValueOf[Base](params.Gmx[159]) + G2To159y := emulated.ValueOf[Base](params.Gmy[159]) + G2To160x := emulated.ValueOf[Base](params.Gmx[160]) + G2To160y := emulated.ValueOf[Base](params.Gmy[160]) + G2To161x := emulated.ValueOf[Base](params.Gmx[161]) + G2To161y := emulated.ValueOf[Base](params.Gmy[161]) + G2To162x := emulated.ValueOf[Base](params.Gmx[162]) + G2To162y := emulated.ValueOf[Base](params.Gmy[162]) + G2To163x := emulated.ValueOf[Base](params.Gmx[163]) + G2To163y := emulated.ValueOf[Base](params.Gmy[163]) + G2To164x := emulated.ValueOf[Base](params.Gmx[164]) + G2To164y := emulated.ValueOf[Base](params.Gmy[164]) + G2To165x := emulated.ValueOf[Base](params.Gmx[165]) + G2To165y := emulated.ValueOf[Base](params.Gmy[165]) + G2To166x := emulated.ValueOf[Base](params.Gmx[166]) + G2To166y := emulated.ValueOf[Base](params.Gmy[166]) + G2To167x := emulated.ValueOf[Base](params.Gmx[167]) + G2To167y := emulated.ValueOf[Base](params.Gmy[167]) + G2To168x := emulated.ValueOf[Base](params.Gmx[168]) + G2To168y := emulated.ValueOf[Base](params.Gmy[168]) + G2To169x := emulated.ValueOf[Base](params.Gmx[169]) + G2To169y := emulated.ValueOf[Base](params.Gmy[169]) + G2To170x := emulated.ValueOf[Base](params.Gmx[170]) + G2To170y := emulated.ValueOf[Base](params.Gmy[170]) + G2To171x := emulated.ValueOf[Base](params.Gmx[171]) + G2To171y := emulated.ValueOf[Base](params.Gmy[171]) + G2To172x := emulated.ValueOf[Base](params.Gmx[172]) + G2To172y := emulated.ValueOf[Base](params.Gmy[172]) + G2To173x := emulated.ValueOf[Base](params.Gmx[173]) + G2To173y := emulated.ValueOf[Base](params.Gmy[173]) + G2To174x := emulated.ValueOf[Base](params.Gmx[174]) + G2To174y := emulated.ValueOf[Base](params.Gmy[174]) + G2To175x := emulated.ValueOf[Base](params.Gmx[175]) + G2To175y := emulated.ValueOf[Base](params.Gmy[175]) + G2To176x := emulated.ValueOf[Base](params.Gmx[176]) + G2To176y := emulated.ValueOf[Base](params.Gmy[176]) + G2To177x := emulated.ValueOf[Base](params.Gmx[177]) + G2To177y := emulated.ValueOf[Base](params.Gmy[177]) + G2To178x := emulated.ValueOf[Base](params.Gmx[178]) + G2To178y := emulated.ValueOf[Base](params.Gmy[178]) + G2To179x := emulated.ValueOf[Base](params.Gmx[179]) + G2To179y := emulated.ValueOf[Base](params.Gmy[179]) + G2To180x := emulated.ValueOf[Base](params.Gmx[180]) + G2To180y := emulated.ValueOf[Base](params.Gmy[180]) + G2To181x := emulated.ValueOf[Base](params.Gmx[181]) + G2To181y := emulated.ValueOf[Base](params.Gmy[181]) + G2To182x := emulated.ValueOf[Base](params.Gmx[182]) + G2To182y := emulated.ValueOf[Base](params.Gmy[182]) + G2To183x := emulated.ValueOf[Base](params.Gmx[183]) + G2To183y := emulated.ValueOf[Base](params.Gmy[183]) + G2To184x := emulated.ValueOf[Base](params.Gmx[184]) + G2To184y := emulated.ValueOf[Base](params.Gmy[184]) + G2To185x := emulated.ValueOf[Base](params.Gmx[185]) + G2To185y := emulated.ValueOf[Base](params.Gmy[185]) + G2To186x := emulated.ValueOf[Base](params.Gmx[186]) + G2To186y := emulated.ValueOf[Base](params.Gmy[186]) + G2To187x := emulated.ValueOf[Base](params.Gmx[187]) + G2To187y := emulated.ValueOf[Base](params.Gmy[187]) + G2To188x := emulated.ValueOf[Base](params.Gmx[188]) + G2To188y := emulated.ValueOf[Base](params.Gmy[188]) + G2To189x := emulated.ValueOf[Base](params.Gmx[189]) + G2To189y := emulated.ValueOf[Base](params.Gmy[189]) + G2To190x := emulated.ValueOf[Base](params.Gmx[190]) + G2To190y := emulated.ValueOf[Base](params.Gmy[190]) + G2To191x := emulated.ValueOf[Base](params.Gmx[191]) + G2To191y := emulated.ValueOf[Base](params.Gmy[191]) + G2To192x := emulated.ValueOf[Base](params.Gmx[192]) + G2To192y := emulated.ValueOf[Base](params.Gmy[192]) + G2To193x := emulated.ValueOf[Base](params.Gmx[193]) + G2To193y := emulated.ValueOf[Base](params.Gmy[193]) + G2To194x := emulated.ValueOf[Base](params.Gmx[194]) + G2To194y := emulated.ValueOf[Base](params.Gmy[194]) + G2To195x := emulated.ValueOf[Base](params.Gmx[195]) + G2To195y := emulated.ValueOf[Base](params.Gmy[195]) + G2To196x := emulated.ValueOf[Base](params.Gmx[196]) + G2To196y := emulated.ValueOf[Base](params.Gmy[196]) + G2To197x := emulated.ValueOf[Base](params.Gmx[197]) + G2To197y := emulated.ValueOf[Base](params.Gmy[197]) + G2To198x := emulated.ValueOf[Base](params.Gmx[198]) + G2To198y := emulated.ValueOf[Base](params.Gmy[198]) + G2To199x := emulated.ValueOf[Base](params.Gmx[199]) + G2To199y := emulated.ValueOf[Base](params.Gmy[199]) + G2To200x := emulated.ValueOf[Base](params.Gmx[200]) + G2To200y := emulated.ValueOf[Base](params.Gmy[200]) + G2To201x := emulated.ValueOf[Base](params.Gmx[201]) + G2To201y := emulated.ValueOf[Base](params.Gmy[201]) + G2To202x := emulated.ValueOf[Base](params.Gmx[202]) + G2To202y := emulated.ValueOf[Base](params.Gmy[202]) + G2To203x := emulated.ValueOf[Base](params.Gmx[203]) + G2To203y := emulated.ValueOf[Base](params.Gmy[203]) + G2To204x := emulated.ValueOf[Base](params.Gmx[204]) + G2To204y := emulated.ValueOf[Base](params.Gmy[204]) + G2To205x := emulated.ValueOf[Base](params.Gmx[205]) + G2To205y := emulated.ValueOf[Base](params.Gmy[205]) + G2To206x := emulated.ValueOf[Base](params.Gmx[206]) + G2To206y := emulated.ValueOf[Base](params.Gmy[206]) + G2To207x := emulated.ValueOf[Base](params.Gmx[207]) + G2To207y := emulated.ValueOf[Base](params.Gmy[207]) + G2To208x := emulated.ValueOf[Base](params.Gmx[208]) + G2To208y := emulated.ValueOf[Base](params.Gmy[208]) + G2To209x := emulated.ValueOf[Base](params.Gmx[209]) + G2To209y := emulated.ValueOf[Base](params.Gmy[209]) + G2To210x := emulated.ValueOf[Base](params.Gmx[210]) + G2To210y := emulated.ValueOf[Base](params.Gmy[210]) + G2To211x := emulated.ValueOf[Base](params.Gmx[211]) + G2To211y := emulated.ValueOf[Base](params.Gmy[211]) + G2To212x := emulated.ValueOf[Base](params.Gmx[212]) + G2To212y := emulated.ValueOf[Base](params.Gmy[212]) + G2To213x := emulated.ValueOf[Base](params.Gmx[213]) + G2To213y := emulated.ValueOf[Base](params.Gmy[213]) + G2To214x := emulated.ValueOf[Base](params.Gmx[214]) + G2To214y := emulated.ValueOf[Base](params.Gmy[214]) + G2To215x := emulated.ValueOf[Base](params.Gmx[215]) + G2To215y := emulated.ValueOf[Base](params.Gmy[215]) + G2To216x := emulated.ValueOf[Base](params.Gmx[216]) + G2To216y := emulated.ValueOf[Base](params.Gmy[216]) + G2To217x := emulated.ValueOf[Base](params.Gmx[217]) + G2To217y := emulated.ValueOf[Base](params.Gmy[217]) + G2To218x := emulated.ValueOf[Base](params.Gmx[218]) + G2To218y := emulated.ValueOf[Base](params.Gmy[218]) + G2To219x := emulated.ValueOf[Base](params.Gmx[219]) + G2To219y := emulated.ValueOf[Base](params.Gmy[219]) + G2To220x := emulated.ValueOf[Base](params.Gmx[220]) + G2To220y := emulated.ValueOf[Base](params.Gmy[220]) + G2To221x := emulated.ValueOf[Base](params.Gmx[221]) + G2To221y := emulated.ValueOf[Base](params.Gmy[221]) + G2To222x := emulated.ValueOf[Base](params.Gmx[222]) + G2To222y := emulated.ValueOf[Base](params.Gmy[222]) + G2To223x := emulated.ValueOf[Base](params.Gmx[223]) + G2To223y := emulated.ValueOf[Base](params.Gmy[223]) + G2To224x := emulated.ValueOf[Base](params.Gmx[224]) + G2To224y := emulated.ValueOf[Base](params.Gmy[224]) + G2To225x := emulated.ValueOf[Base](params.Gmx[225]) + G2To225y := emulated.ValueOf[Base](params.Gmy[225]) + G2To226x := emulated.ValueOf[Base](params.Gmx[226]) + G2To226y := emulated.ValueOf[Base](params.Gmy[226]) + G2To227x := emulated.ValueOf[Base](params.Gmx[227]) + G2To227y := emulated.ValueOf[Base](params.Gmy[227]) + G2To228x := emulated.ValueOf[Base](params.Gmx[228]) + G2To228y := emulated.ValueOf[Base](params.Gmy[228]) + G2To229x := emulated.ValueOf[Base](params.Gmx[229]) + G2To229y := emulated.ValueOf[Base](params.Gmy[229]) + G2To230x := emulated.ValueOf[Base](params.Gmx[230]) + G2To230y := emulated.ValueOf[Base](params.Gmy[230]) + G2To231x := emulated.ValueOf[Base](params.Gmx[231]) + G2To231y := emulated.ValueOf[Base](params.Gmy[231]) + G2To232x := emulated.ValueOf[Base](params.Gmx[232]) + G2To232y := emulated.ValueOf[Base](params.Gmy[232]) + G2To233x := emulated.ValueOf[Base](params.Gmx[233]) + G2To233y := emulated.ValueOf[Base](params.Gmy[233]) + G2To234x := emulated.ValueOf[Base](params.Gmx[234]) + G2To234y := emulated.ValueOf[Base](params.Gmy[234]) + G2To235x := emulated.ValueOf[Base](params.Gmx[235]) + G2To235y := emulated.ValueOf[Base](params.Gmy[235]) + G2To236x := emulated.ValueOf[Base](params.Gmx[236]) + G2To236y := emulated.ValueOf[Base](params.Gmy[236]) + G2To237x := emulated.ValueOf[Base](params.Gmx[237]) + G2To237y := emulated.ValueOf[Base](params.Gmy[237]) + G2To238x := emulated.ValueOf[Base](params.Gmx[238]) + G2To238y := emulated.ValueOf[Base](params.Gmy[238]) + G2To239x := emulated.ValueOf[Base](params.Gmx[239]) + G2To239y := emulated.ValueOf[Base](params.Gmy[239]) + G2To240x := emulated.ValueOf[Base](params.Gmx[240]) + G2To240y := emulated.ValueOf[Base](params.Gmy[240]) + G2To241x := emulated.ValueOf[Base](params.Gmx[241]) + G2To241y := emulated.ValueOf[Base](params.Gmy[241]) + G2To242x := emulated.ValueOf[Base](params.Gmx[242]) + G2To242y := emulated.ValueOf[Base](params.Gmy[242]) + G2To243x := emulated.ValueOf[Base](params.Gmx[243]) + G2To243y := emulated.ValueOf[Base](params.Gmy[243]) + G2To244x := emulated.ValueOf[Base](params.Gmx[244]) + G2To244y := emulated.ValueOf[Base](params.Gmy[244]) + G2To245x := emulated.ValueOf[Base](params.Gmx[245]) + G2To245y := emulated.ValueOf[Base](params.Gmy[245]) + G2To246x := emulated.ValueOf[Base](params.Gmx[246]) + G2To246y := emulated.ValueOf[Base](params.Gmy[246]) + G2To247x := emulated.ValueOf[Base](params.Gmx[247]) + G2To247y := emulated.ValueOf[Base](params.Gmy[247]) + G2To248x := emulated.ValueOf[Base](params.Gmx[248]) + G2To248y := emulated.ValueOf[Base](params.Gmy[248]) + G2To249x := emulated.ValueOf[Base](params.Gmx[249]) + G2To249y := emulated.ValueOf[Base](params.Gmy[249]) + G2To250x := emulated.ValueOf[Base](params.Gmx[250]) + G2To250y := emulated.ValueOf[Base](params.Gmy[250]) + G2To251x := emulated.ValueOf[Base](params.Gmx[251]) + G2To251y := emulated.ValueOf[Base](params.Gmy[251]) + G2To252x := emulated.ValueOf[Base](params.Gmx[252]) + G2To252y := emulated.ValueOf[Base](params.Gmy[252]) + G2To253x := emulated.ValueOf[Base](params.Gmx[253]) + G2To253y := emulated.ValueOf[Base](params.Gmy[253]) + G2To254x := emulated.ValueOf[Base](params.Gmx[254]) + G2To254y := emulated.ValueOf[Base](params.Gmy[254]) + G2To255x := emulated.ValueOf[Base](params.Gmx[255]) + G2To255y := emulated.ValueOf[Base](params.Gmy[255]) return &Curve[Base, Scalars]{ params: params, api: api, @@ -546,261 +546,261 @@ func New[Base, Scalars emulated.FieldParams](api frontend.API, params CurveParam }, gm: [256]AffinePoint[Base]{ {X: G3x, Y: G3y}, - {X: G4x, Y: G4y}, - {X: G8x, Y: G8y}, - {X: G16x, Y: G16y}, - {X: G32x, Y: G32y}, - {X: G64x, Y: G64y}, - {X: G128x, Y: G128y}, - {X: G256x, Y: G256y}, - {X: G512x, Y: G512y}, - {X: G1024x, Y: G1024y}, - {X: G2048x, Y: G2048y}, - {X: G4096x, Y: G4096y}, - {X: G8192x, Y: G8192y}, - {X: G16384x, Y: G16384y}, - {X: G32768x, Y: G32768y}, - {X: G65536x, Y: G65536y}, - {X: G131072x, Y: G131072y}, - {X: G262144x, Y: G262144y}, - {X: G524288x, Y: G524288y}, - {X: G1048576x, Y: G1048576y}, - {X: G2097152x, Y: G2097152y}, - {X: G4194304x, Y: G4194304y}, - {X: G8388608x, Y: G8388608y}, - {X: G16777216x, Y: G16777216y}, - {X: G33554432x, Y: G33554432y}, - {X: G67108864x, Y: G67108864y}, - {X: G134217728x, Y: G134217728y}, - {X: G268435456x, Y: G268435456y}, - {X: G536870912x, Y: G536870912y}, - {X: G1073741824x, Y: G1073741824y}, - {X: G2147483648x, Y: G2147483648y}, - {X: G4294967296x, Y: G4294967296y}, - {X: G8589934592x, Y: G8589934592y}, - {X: G17179869184x, Y: G17179869184y}, - {X: G34359738368x, Y: G34359738368y}, - {X: G68719476736x, Y: G68719476736y}, - {X: G137438953472x, Y: G137438953472y}, - {X: G274877906944x, Y: G274877906944y}, - {X: G549755813888x, Y: G549755813888y}, - {X: G1099511627776x, Y: G1099511627776y}, - {X: G2199023255552x, Y: G2199023255552y}, - {X: G4398046511104x, Y: G4398046511104y}, - {X: G8796093022208x, Y: G8796093022208y}, - {X: G17592186044416x, Y: G17592186044416y}, - {X: G35184372088832x, Y: G35184372088832y}, - {X: G70368744177664x, Y: G70368744177664y}, - {X: G140737488355328x, Y: G140737488355328y}, - {X: G281474976710656x, Y: G281474976710656y}, - {X: G562949953421312x, Y: G562949953421312y}, - {X: G1125899906842624x, Y: G1125899906842624y}, - {X: G2251799813685248x, Y: G2251799813685248y}, - {X: G4503599627370496x, Y: G4503599627370496y}, - {X: G9007199254740992x, Y: G9007199254740992y}, - {X: G18014398509481984x, Y: G18014398509481984y}, - {X: G36028797018963968x, Y: G36028797018963968y}, - {X: G72057594037927936x, Y: G72057594037927936y}, - {X: G144115188075855872x, Y: G144115188075855872y}, - {X: G288230376151711744x, Y: G288230376151711744y}, - {X: G576460752303423488x, Y: G576460752303423488y}, - {X: G1152921504606846976x, Y: G1152921504606846976y}, - {X: G2305843009213693952x, Y: G2305843009213693952y}, - {X: G4611686018427387904x, Y: G4611686018427387904y}, - {X: G9223372036854775808x, Y: G9223372036854775808y}, - {X: G18446744073709551616x, Y: G18446744073709551616y}, - {X: G36893488147419103232x, Y: G36893488147419103232y}, - {X: G73786976294838206464x, Y: G73786976294838206464y}, - {X: G147573952589676412928x, Y: G147573952589676412928y}, - {X: G295147905179352825856x, Y: G295147905179352825856y}, - {X: G590295810358705651712x, Y: G590295810358705651712y}, - {X: G1180591620717411303424x, Y: G1180591620717411303424y}, - {X: G2361183241434822606848x, Y: G2361183241434822606848y}, - {X: G4722366482869645213696x, Y: G4722366482869645213696y}, - {X: G9444732965739290427392x, Y: G9444732965739290427392y}, - {X: G18889465931478580854784x, Y: G18889465931478580854784y}, - {X: G37778931862957161709568x, Y: G37778931862957161709568y}, - {X: G75557863725914323419136x, Y: G75557863725914323419136y}, - {X: G151115727451828646838272x, Y: G151115727451828646838272y}, - {X: G302231454903657293676544x, Y: G302231454903657293676544y}, - {X: G604462909807314587353088x, Y: G604462909807314587353088y}, - {X: G1208925819614629174706176x, Y: G1208925819614629174706176y}, - {X: G2417851639229258349412352x, Y: G2417851639229258349412352y}, - {X: G4835703278458516698824704x, Y: G4835703278458516698824704y}, - {X: G9671406556917033397649408x, Y: G9671406556917033397649408y}, - {X: G19342813113834066795298816x, Y: G19342813113834066795298816y}, - {X: G38685626227668133590597632x, Y: G38685626227668133590597632y}, - {X: G77371252455336267181195264x, Y: G77371252455336267181195264y}, - {X: G154742504910672534362390528x, Y: G154742504910672534362390528y}, - {X: G309485009821345068724781056x, Y: G309485009821345068724781056y}, - {X: G618970019642690137449562112x, Y: G618970019642690137449562112y}, - {X: G1237940039285380274899124224x, Y: G1237940039285380274899124224y}, - {X: G2475880078570760549798248448x, Y: G2475880078570760549798248448y}, - {X: G4951760157141521099596496896x, Y: G4951760157141521099596496896y}, - {X: G9903520314283042199192993792x, Y: G9903520314283042199192993792y}, - {X: G19807040628566084398385987584x, Y: G19807040628566084398385987584y}, - {X: G39614081257132168796771975168x, Y: G39614081257132168796771975168y}, - {X: G79228162514264337593543950336x, Y: G79228162514264337593543950336y}, - {X: G158456325028528675187087900672x, Y: G158456325028528675187087900672y}, - {X: G316912650057057350374175801344x, Y: G316912650057057350374175801344y}, - {X: G633825300114114700748351602688x, Y: G633825300114114700748351602688y}, - {X: G1267650600228229401496703205376x, Y: G1267650600228229401496703205376y}, - {X: G2535301200456458802993406410752x, Y: G2535301200456458802993406410752y}, - {X: G5070602400912917605986812821504x, Y: G5070602400912917605986812821504y}, - {X: G10141204801825835211973625643008x, Y: G10141204801825835211973625643008y}, - {X: G20282409603651670423947251286016x, Y: G20282409603651670423947251286016y}, - {X: G40564819207303340847894502572032x, Y: G40564819207303340847894502572032y}, - {X: G81129638414606681695789005144064x, Y: G81129638414606681695789005144064y}, - {X: G162259276829213363391578010288128x, Y: G162259276829213363391578010288128y}, - {X: G324518553658426726783156020576256x, Y: G324518553658426726783156020576256y}, - {X: G649037107316853453566312041152512x, Y: G649037107316853453566312041152512y}, - {X: G1298074214633706907132624082305024x, Y: G1298074214633706907132624082305024y}, - {X: G2596148429267413814265248164610048x, Y: G2596148429267413814265248164610048y}, - {X: G5192296858534827628530496329220096x, Y: G5192296858534827628530496329220096y}, - {X: G10384593717069655257060992658440192x, Y: G10384593717069655257060992658440192y}, - {X: G20769187434139310514121985316880384x, Y: G20769187434139310514121985316880384y}, - {X: G41538374868278621028243970633760768x, Y: G41538374868278621028243970633760768y}, - {X: G83076749736557242056487941267521536x, Y: G83076749736557242056487941267521536y}, - {X: G166153499473114484112975882535043072x, Y: G166153499473114484112975882535043072y}, - {X: G332306998946228968225951765070086144x, Y: G332306998946228968225951765070086144y}, - {X: G664613997892457936451903530140172288x, Y: G664613997892457936451903530140172288y}, - {X: G1329227995784915872903807060280344576x, Y: G1329227995784915872903807060280344576y}, - {X: G2658455991569831745807614120560689152x, Y: G2658455991569831745807614120560689152y}, - {X: G5316911983139663491615228241121378304x, Y: G5316911983139663491615228241121378304y}, - {X: G10633823966279326983230456482242756608x, Y: G10633823966279326983230456482242756608y}, - {X: G21267647932558653966460912964485513216x, Y: G21267647932558653966460912964485513216y}, - {X: G42535295865117307932921825928971026432x, Y: G42535295865117307932921825928971026432y}, - {X: G85070591730234615865843651857942052864x, Y: G85070591730234615865843651857942052864y}, - {X: G170141183460469231731687303715884105728x, Y: G170141183460469231731687303715884105728y}, - {X: G340282366920938463463374607431768211456x, Y: G340282366920938463463374607431768211456y}, - {X: G680564733841876926926749214863536422912x, Y: G680564733841876926926749214863536422912y}, - {X: G1361129467683753853853498429727072845824x, Y: G1361129467683753853853498429727072845824y}, - {X: G2722258935367507707706996859454145691648x, Y: G2722258935367507707706996859454145691648y}, - {X: G5444517870735015415413993718908291383296x, Y: G5444517870735015415413993718908291383296y}, - {X: G10889035741470030830827987437816582766592x, Y: G10889035741470030830827987437816582766592y}, - {X: G21778071482940061661655974875633165533184x, Y: G21778071482940061661655974875633165533184y}, - {X: G43556142965880123323311949751266331066368x, Y: G43556142965880123323311949751266331066368y}, - {X: G87112285931760246646623899502532662132736x, Y: G87112285931760246646623899502532662132736y}, - {X: G174224571863520493293247799005065324265472x, Y: G174224571863520493293247799005065324265472y}, - {X: G348449143727040986586495598010130648530944x, Y: G348449143727040986586495598010130648530944y}, - {X: G696898287454081973172991196020261297061888x, Y: G696898287454081973172991196020261297061888y}, - {X: G1393796574908163946345982392040522594123776x, Y: G1393796574908163946345982392040522594123776y}, - {X: G2787593149816327892691964784081045188247552x, Y: G2787593149816327892691964784081045188247552y}, - {X: G5575186299632655785383929568162090376495104x, Y: G5575186299632655785383929568162090376495104y}, - {X: G11150372599265311570767859136324180752990208x, Y: G11150372599265311570767859136324180752990208y}, - {X: G22300745198530623141535718272648361505980416x, Y: G22300745198530623141535718272648361505980416y}, - {X: G44601490397061246283071436545296723011960832x, Y: G44601490397061246283071436545296723011960832y}, - {X: G89202980794122492566142873090593446023921664x, Y: G89202980794122492566142873090593446023921664y}, - {X: G178405961588244985132285746181186892047843328x, Y: G178405961588244985132285746181186892047843328y}, - {X: G356811923176489970264571492362373784095686656x, Y: G356811923176489970264571492362373784095686656y}, - {X: G713623846352979940529142984724747568191373312x, Y: G713623846352979940529142984724747568191373312y}, - {X: G1427247692705959881058285969449495136382746624x, Y: G1427247692705959881058285969449495136382746624y}, - {X: G2854495385411919762116571938898990272765493248x, Y: G2854495385411919762116571938898990272765493248y}, - {X: G5708990770823839524233143877797980545530986496x, Y: G5708990770823839524233143877797980545530986496y}, - {X: G11417981541647679048466287755595961091061972992x, Y: G11417981541647679048466287755595961091061972992y}, - {X: G22835963083295358096932575511191922182123945984x, Y: G22835963083295358096932575511191922182123945984y}, - {X: G45671926166590716193865151022383844364247891968x, Y: G45671926166590716193865151022383844364247891968y}, - {X: G91343852333181432387730302044767688728495783936x, Y: G91343852333181432387730302044767688728495783936y}, - {X: G182687704666362864775460604089535377456991567872x, Y: G182687704666362864775460604089535377456991567872y}, - {X: G365375409332725729550921208179070754913983135744x, Y: G365375409332725729550921208179070754913983135744y}, - {X: G730750818665451459101842416358141509827966271488x, Y: G730750818665451459101842416358141509827966271488y}, - {X: G1461501637330902918203684832716283019655932542976x, Y: G1461501637330902918203684832716283019655932542976y}, - {X: G2923003274661805836407369665432566039311865085952x, Y: G2923003274661805836407369665432566039311865085952y}, - {X: G5846006549323611672814739330865132078623730171904x, Y: G5846006549323611672814739330865132078623730171904y}, - {X: G11692013098647223345629478661730264157247460343808x, Y: G11692013098647223345629478661730264157247460343808y}, - {X: G23384026197294446691258957323460528314494920687616x, Y: G23384026197294446691258957323460528314494920687616y}, - {X: G46768052394588893382517914646921056628989841375232x, Y: G46768052394588893382517914646921056628989841375232y}, - {X: G93536104789177786765035829293842113257979682750464x, Y: G93536104789177786765035829293842113257979682750464y}, - {X: G187072209578355573530071658587684226515959365500928x, Y: G187072209578355573530071658587684226515959365500928y}, - {X: G374144419156711147060143317175368453031918731001856x, Y: G374144419156711147060143317175368453031918731001856y}, - {X: G748288838313422294120286634350736906063837462003712x, Y: G748288838313422294120286634350736906063837462003712y}, - {X: G1496577676626844588240573268701473812127674924007424x, Y: G1496577676626844588240573268701473812127674924007424y}, - {X: G2993155353253689176481146537402947624255349848014848x, Y: G2993155353253689176481146537402947624255349848014848y}, - {X: G5986310706507378352962293074805895248510699696029696x, Y: G5986310706507378352962293074805895248510699696029696y}, - {X: G11972621413014756705924586149611790497021399392059392x, Y: G11972621413014756705924586149611790497021399392059392y}, - {X: G23945242826029513411849172299223580994042798784118784x, Y: G23945242826029513411849172299223580994042798784118784y}, - {X: G47890485652059026823698344598447161988085597568237568x, Y: G47890485652059026823698344598447161988085597568237568y}, - {X: G95780971304118053647396689196894323976171195136475136x, Y: G95780971304118053647396689196894323976171195136475136y}, - {X: G191561942608236107294793378393788647952342390272950272x, Y: G191561942608236107294793378393788647952342390272950272y}, - {X: G383123885216472214589586756787577295904684780545900544x, Y: G383123885216472214589586756787577295904684780545900544y}, - {X: G766247770432944429179173513575154591809369561091801088x, Y: G766247770432944429179173513575154591809369561091801088y}, - {X: G1532495540865888858358347027150309183618739122183602176x, Y: G1532495540865888858358347027150309183618739122183602176y}, - {X: G3064991081731777716716694054300618367237478244367204352x, Y: G3064991081731777716716694054300618367237478244367204352y}, - {X: G6129982163463555433433388108601236734474956488734408704x, Y: G6129982163463555433433388108601236734474956488734408704y}, - {X: G12259964326927110866866776217202473468949912977468817408x, Y: G12259964326927110866866776217202473468949912977468817408y}, - {X: G24519928653854221733733552434404946937899825954937634816x, Y: G24519928653854221733733552434404946937899825954937634816y}, - {X: G49039857307708443467467104868809893875799651909875269632x, Y: G49039857307708443467467104868809893875799651909875269632y}, - {X: G98079714615416886934934209737619787751599303819750539264x, Y: G98079714615416886934934209737619787751599303819750539264y}, - {X: G196159429230833773869868419475239575503198607639501078528x, Y: G196159429230833773869868419475239575503198607639501078528y}, - {X: G392318858461667547739736838950479151006397215279002157056x, Y: G392318858461667547739736838950479151006397215279002157056y}, - {X: G784637716923335095479473677900958302012794430558004314112x, Y: G784637716923335095479473677900958302012794430558004314112y}, - {X: G1569275433846670190958947355801916604025588861116008628224x, Y: G1569275433846670190958947355801916604025588861116008628224y}, - {X: G3138550867693340381917894711603833208051177722232017256448x, Y: G3138550867693340381917894711603833208051177722232017256448y}, - {X: G6277101735386680763835789423207666416102355444464034512896x, Y: G6277101735386680763835789423207666416102355444464034512896y}, - {X: G12554203470773361527671578846415332832204710888928069025792x, Y: G12554203470773361527671578846415332832204710888928069025792y}, - {X: G25108406941546723055343157692830665664409421777856138051584x, Y: G25108406941546723055343157692830665664409421777856138051584y}, - {X: G50216813883093446110686315385661331328818843555712276103168x, Y: G50216813883093446110686315385661331328818843555712276103168y}, - {X: G100433627766186892221372630771322662657637687111424552206336x, Y: G100433627766186892221372630771322662657637687111424552206336y}, - {X: G200867255532373784442745261542645325315275374222849104412672x, Y: G200867255532373784442745261542645325315275374222849104412672y}, - {X: G401734511064747568885490523085290650630550748445698208825344x, Y: G401734511064747568885490523085290650630550748445698208825344y}, - {X: G803469022129495137770981046170581301261101496891396417650688x, Y: G803469022129495137770981046170581301261101496891396417650688y}, - {X: G1606938044258990275541962092341162602522202993782792835301376x, Y: G1606938044258990275541962092341162602522202993782792835301376y}, - {X: G3213876088517980551083924184682325205044405987565585670602752x, Y: G3213876088517980551083924184682325205044405987565585670602752y}, - {X: G6427752177035961102167848369364650410088811975131171341205504x, Y: G6427752177035961102167848369364650410088811975131171341205504y}, - {X: G12855504354071922204335696738729300820177623950262342682411008x, Y: G12855504354071922204335696738729300820177623950262342682411008y}, - {X: G25711008708143844408671393477458601640355247900524685364822016x, Y: G25711008708143844408671393477458601640355247900524685364822016y}, - {X: G51422017416287688817342786954917203280710495801049370729644032x, Y: G51422017416287688817342786954917203280710495801049370729644032y}, - {X: G102844034832575377634685573909834406561420991602098741459288064x, Y: G102844034832575377634685573909834406561420991602098741459288064y}, - {X: G205688069665150755269371147819668813122841983204197482918576128x, Y: G205688069665150755269371147819668813122841983204197482918576128y}, - {X: G411376139330301510538742295639337626245683966408394965837152256x, Y: G411376139330301510538742295639337626245683966408394965837152256y}, - {X: G822752278660603021077484591278675252491367932816789931674304512x, Y: G822752278660603021077484591278675252491367932816789931674304512y}, - {X: G1645504557321206042154969182557350504982735865633579863348609024x, Y: G1645504557321206042154969182557350504982735865633579863348609024y}, - {X: G3291009114642412084309938365114701009965471731267159726697218048x, Y: G3291009114642412084309938365114701009965471731267159726697218048y}, - {X: G6582018229284824168619876730229402019930943462534319453394436096x, Y: G6582018229284824168619876730229402019930943462534319453394436096y}, - {X: G13164036458569648337239753460458804039861886925068638906788872192x, Y: G13164036458569648337239753460458804039861886925068638906788872192y}, - {X: G26328072917139296674479506920917608079723773850137277813577744384x, Y: G26328072917139296674479506920917608079723773850137277813577744384y}, - {X: G52656145834278593348959013841835216159447547700274555627155488768x, Y: G52656145834278593348959013841835216159447547700274555627155488768y}, - {X: G105312291668557186697918027683670432318895095400549111254310977536x, Y: G105312291668557186697918027683670432318895095400549111254310977536y}, - {X: G210624583337114373395836055367340864637790190801098222508621955072x, Y: G210624583337114373395836055367340864637790190801098222508621955072y}, - {X: G421249166674228746791672110734681729275580381602196445017243910144x, Y: G421249166674228746791672110734681729275580381602196445017243910144y}, - {X: G842498333348457493583344221469363458551160763204392890034487820288x, Y: G842498333348457493583344221469363458551160763204392890034487820288y}, - {X: G1684996666696914987166688442938726917102321526408785780068975640576x, Y: G1684996666696914987166688442938726917102321526408785780068975640576y}, - {X: G3369993333393829974333376885877453834204643052817571560137951281152x, Y: G3369993333393829974333376885877453834204643052817571560137951281152y}, - {X: G6739986666787659948666753771754907668409286105635143120275902562304x, Y: G6739986666787659948666753771754907668409286105635143120275902562304y}, - {X: G13479973333575319897333507543509815336818572211270286240551805124608x, Y: G13479973333575319897333507543509815336818572211270286240551805124608y}, - {X: G26959946667150639794667015087019630673637144422540572481103610249216x, Y: G26959946667150639794667015087019630673637144422540572481103610249216y}, - {X: G53919893334301279589334030174039261347274288845081144962207220498432x, Y: G53919893334301279589334030174039261347274288845081144962207220498432y}, - {X: G107839786668602559178668060348078522694548577690162289924414440996864x, Y: G107839786668602559178668060348078522694548577690162289924414440996864y}, - {X: G215679573337205118357336120696157045389097155380324579848828881993728x, Y: G215679573337205118357336120696157045389097155380324579848828881993728y}, - {X: G431359146674410236714672241392314090778194310760649159697657763987456x, Y: G431359146674410236714672241392314090778194310760649159697657763987456y}, - {X: G862718293348820473429344482784628181556388621521298319395315527974912x, Y: G862718293348820473429344482784628181556388621521298319395315527974912y}, - {X: G1725436586697640946858688965569256363112777243042596638790631055949824x, Y: G1725436586697640946858688965569256363112777243042596638790631055949824y}, - {X: G3450873173395281893717377931138512726225554486085193277581262111899648x, Y: G3450873173395281893717377931138512726225554486085193277581262111899648y}, - {X: G6901746346790563787434755862277025452451108972170386555162524223799296x, Y: G6901746346790563787434755862277025452451108972170386555162524223799296y}, - {X: G13803492693581127574869511724554050904902217944340773110325048447598592x, Y: G13803492693581127574869511724554050904902217944340773110325048447598592y}, - {X: G27606985387162255149739023449108101809804435888681546220650096895197184x, Y: G27606985387162255149739023449108101809804435888681546220650096895197184y}, - {X: G55213970774324510299478046898216203619608871777363092441300193790394368x, Y: G55213970774324510299478046898216203619608871777363092441300193790394368y}, - {X: G110427941548649020598956093796432407239217743554726184882600387580788736x, Y: G110427941548649020598956093796432407239217743554726184882600387580788736y}, - {X: G220855883097298041197912187592864814478435487109452369765200775161577472x, Y: G220855883097298041197912187592864814478435487109452369765200775161577472y}, - {X: G441711766194596082395824375185729628956870974218904739530401550323154944x, Y: G441711766194596082395824375185729628956870974218904739530401550323154944y}, - {X: G883423532389192164791648750371459257913741948437809479060803100646309888x, Y: G883423532389192164791648750371459257913741948437809479060803100646309888y}, - {X: G1766847064778384329583297500742918515827483896875618958121606201292619776x, Y: G1766847064778384329583297500742918515827483896875618958121606201292619776y}, - {X: G3533694129556768659166595001485837031654967793751237916243212402585239552x, Y: G3533694129556768659166595001485837031654967793751237916243212402585239552y}, - {X: G7067388259113537318333190002971674063309935587502475832486424805170479104x, Y: G7067388259113537318333190002971674063309935587502475832486424805170479104y}, - {X: G14134776518227074636666380005943348126619871175004951664972849610340958208x, Y: G14134776518227074636666380005943348126619871175004951664972849610340958208y}, - {X: G28269553036454149273332760011886696253239742350009903329945699220681916416x, Y: G28269553036454149273332760011886696253239742350009903329945699220681916416y}, - {X: G56539106072908298546665520023773392506479484700019806659891398441363832832x, Y: G56539106072908298546665520023773392506479484700019806659891398441363832832y}, - {X: G113078212145816597093331040047546785012958969400039613319782796882727665664x, Y: G113078212145816597093331040047546785012958969400039613319782796882727665664y}, - {X: G226156424291633194186662080095093570025917938800079226639565593765455331328x, Y: G226156424291633194186662080095093570025917938800079226639565593765455331328y}, - {X: G452312848583266388373324160190187140051835877600158453279131187530910662656x, Y: G452312848583266388373324160190187140051835877600158453279131187530910662656y}, - {X: G904625697166532776746648320380374280103671755200316906558262375061821325312x, Y: G904625697166532776746648320380374280103671755200316906558262375061821325312y}, - {X: G1809251394333065553493296640760748560207343510400633813116524750123642650624x, Y: G1809251394333065553493296640760748560207343510400633813116524750123642650624y}, - {X: G3618502788666131106986593281521497120414687020801267626233049500247285301248x, Y: G3618502788666131106986593281521497120414687020801267626233049500247285301248y}, - {X: G7237005577332262213973186563042994240829374041602535252466099000494570602496x, Y: G7237005577332262213973186563042994240829374041602535252466099000494570602496y}, - {X: G14474011154664524427946373126085988481658748083205070504932198000989141204992x, Y: G14474011154664524427946373126085988481658748083205070504932198000989141204992y}, - {X: G28948022309329048855892746252171976963317496166410141009864396001978282409984x, Y: G28948022309329048855892746252171976963317496166410141009864396001978282409984y}, - {X: G57896044618658097711785492504343953926634992332820282019728792003956564819968x, Y: G57896044618658097711785492504343953926634992332820282019728792003956564819968y}, - {X: G115792089237316195423570985008687907853269984665640564039457584007913129639936x, Y: G115792089237316195423570985008687907853269984665640564039457584007913129639936y}, + {X: G5x, Y: G5y}, + {X: G7x, Y: G7y}, + {X: G2To3x, Y: G2To3y}, + {X: G2To4x, Y: G2To4y}, + {X: G2To5x, Y: G2To5y}, + {X: G2To6x, Y: G2To6y}, + {X: G2To7x, Y: G2To7y}, + {X: G2To8x, Y: G2To8y}, + {X: G2To9x, Y: G2To9y}, + {X: G2To10x, Y: G2To10y}, + {X: G2To11x, Y: G2To11y}, + {X: G2To12x, Y: G2To12y}, + {X: G2To13x, Y: G2To13y}, + {X: G2To14x, Y: G2To14y}, + {X: G2To15x, Y: G2To15y}, + {X: G2To16x, Y: G2To16y}, + {X: G2To17x, Y: G2To17y}, + {X: G2To18x, Y: G2To18y}, + {X: G2To19x, Y: G2To19y}, + {X: G2To20x, Y: G2To20y}, + {X: G2To21x, Y: G2To21y}, + {X: G2To22x, Y: G2To22y}, + {X: G2To23x, Y: G2To23y}, + {X: G2To24x, Y: G2To24y}, + {X: G2To25x, Y: G2To25y}, + {X: G2To26x, Y: G2To26y}, + {X: G2To27x, Y: G2To27y}, + {X: G2To28x, Y: G2To28y}, + {X: G2To29x, Y: G2To29y}, + {X: G2To30x, Y: G2To30y}, + {X: G2To31x, Y: G2To31y}, + {X: G2To32x, Y: G2To32y}, + {X: G2To33x, Y: G2To33y}, + {X: G2To34x, Y: G2To34y}, + {X: G2To35x, Y: G2To35y}, + {X: G2To36x, Y: G2To36y}, + {X: G2To37x, Y: G2To37y}, + {X: G2To38x, Y: G2To38y}, + {X: G2To39x, Y: G2To39y}, + {X: G2To40x, Y: G2To40y}, + {X: G2To41x, Y: G2To41y}, + {X: G2To42x, Y: G2To42y}, + {X: G2To43x, Y: G2To43y}, + {X: G2To44x, Y: G2To44y}, + {X: G2To45x, Y: G2To45y}, + {X: G2To46x, Y: G2To46y}, + {X: G2To47x, Y: G2To47y}, + {X: G2To48x, Y: G2To48y}, + {X: G2To49x, Y: G2To49y}, + {X: G2To50x, Y: G2To50y}, + {X: G2To51x, Y: G2To51y}, + {X: G2To52x, Y: G2To52y}, + {X: G2To53x, Y: G2To53y}, + {X: G2To54x, Y: G2To54y}, + {X: G2To55x, Y: G2To55y}, + {X: G2To56x, Y: G2To56y}, + {X: G2To57x, Y: G2To57y}, + {X: G2To58x, Y: G2To58y}, + {X: G2To59x, Y: G2To59y}, + {X: G2To60x, Y: G2To60y}, + {X: G2To61x, Y: G2To61y}, + {X: G2To62x, Y: G2To62y}, + {X: G2To63x, Y: G2To63y}, + {X: G2To64x, Y: G2To64y}, + {X: G2To65x, Y: G2To65y}, + {X: G2To66x, Y: G2To66y}, + {X: G2To67x, Y: G2To67y}, + {X: G2To68x, Y: G2To68y}, + {X: G2To69x, Y: G2To69y}, + {X: G2To70x, Y: G2To70y}, + {X: G2To71x, Y: G2To71y}, + {X: G2To72x, Y: G2To72y}, + {X: G2To73x, Y: G2To73y}, + {X: G2To74x, Y: G2To74y}, + {X: G2To75x, Y: G2To75y}, + {X: G2To76x, Y: G2To76y}, + {X: G2To77x, Y: G2To77y}, + {X: G2To78x, Y: G2To78y}, + {X: G2To79x, Y: G2To79y}, + {X: G2To80x, Y: G2To80y}, + {X: G2To81x, Y: G2To81y}, + {X: G2To82x, Y: G2To82y}, + {X: G2To83x, Y: G2To83y}, + {X: G2To84x, Y: G2To84y}, + {X: G2To85x, Y: G2To85y}, + {X: G2To86x, Y: G2To86y}, + {X: G2To87x, Y: G2To87y}, + {X: G2To88x, Y: G2To88y}, + {X: G2To89x, Y: G2To89y}, + {X: G2To90x, Y: G2To90y}, + {X: G2To91x, Y: G2To91y}, + {X: G2To92x, Y: G2To92y}, + {X: G2To93x, Y: G2To93y}, + {X: G2To94x, Y: G2To94y}, + {X: G2To95x, Y: G2To95y}, + {X: G2To96x, Y: G2To96y}, + {X: G2To97x, Y: G2To97y}, + {X: G2To98x, Y: G2To98y}, + {X: G2To99x, Y: G2To99y}, + {X: G2To100x, Y: G2To100y}, + {X: G2To101x, Y: G2To101y}, + {X: G2To102x, Y: G2To102y}, + {X: G2To103x, Y: G2To103y}, + {X: G2To104x, Y: G2To104y}, + {X: G2To105x, Y: G2To105y}, + {X: G2To106x, Y: G2To106y}, + {X: G2To107x, Y: G2To107y}, + {X: G2To108x, Y: G2To108y}, + {X: G2To109x, Y: G2To109y}, + {X: G2To110x, Y: G2To110y}, + {X: G2To111x, Y: G2To111y}, + {X: G2To112x, Y: G2To112y}, + {X: G2To113x, Y: G2To113y}, + {X: G2To114x, Y: G2To114y}, + {X: G2To115x, Y: G2To115y}, + {X: G2To116x, Y: G2To116y}, + {X: G2To117x, Y: G2To117y}, + {X: G2To118x, Y: G2To118y}, + {X: G2To119x, Y: G2To119y}, + {X: G2To120x, Y: G2To120y}, + {X: G2To121x, Y: G2To121y}, + {X: G2To122x, Y: G2To122y}, + {X: G2To123x, Y: G2To123y}, + {X: G2To124x, Y: G2To124y}, + {X: G2To125x, Y: G2To125y}, + {X: G2To126x, Y: G2To126y}, + {X: G2To127x, Y: G2To127y}, + {X: G2To128x, Y: G2To128y}, + {X: G2To129x, Y: G2To129y}, + {X: G2To130x, Y: G2To130y}, + {X: G2To131x, Y: G2To131y}, + {X: G2To132x, Y: G2To132y}, + {X: G2To133x, Y: G2To133y}, + {X: G2To134x, Y: G2To134y}, + {X: G2To135x, Y: G2To135y}, + {X: G2To136x, Y: G2To136y}, + {X: G2To137x, Y: G2To137y}, + {X: G2To138x, Y: G2To138y}, + {X: G2To139x, Y: G2To139y}, + {X: G2To140x, Y: G2To140y}, + {X: G2To141x, Y: G2To141y}, + {X: G2To142x, Y: G2To142y}, + {X: G2To143x, Y: G2To143y}, + {X: G2To144x, Y: G2To144y}, + {X: G2To145x, Y: G2To145y}, + {X: G2To146x, Y: G2To146y}, + {X: G2To147x, Y: G2To147y}, + {X: G2To148x, Y: G2To148y}, + {X: G2To149x, Y: G2To149y}, + {X: G2To150x, Y: G2To150y}, + {X: G2To151x, Y: G2To151y}, + {X: G2To152x, Y: G2To152y}, + {X: G2To153x, Y: G2To153y}, + {X: G2To154x, Y: G2To154y}, + {X: G2To155x, Y: G2To155y}, + {X: G2To156x, Y: G2To156y}, + {X: G2To157x, Y: G2To157y}, + {X: G2To158x, Y: G2To158y}, + {X: G2To159x, Y: G2To159y}, + {X: G2To160x, Y: G2To160y}, + {X: G2To161x, Y: G2To161y}, + {X: G2To162x, Y: G2To162y}, + {X: G2To163x, Y: G2To163y}, + {X: G2To164x, Y: G2To164y}, + {X: G2To165x, Y: G2To165y}, + {X: G2To166x, Y: G2To166y}, + {X: G2To167x, Y: G2To167y}, + {X: G2To168x, Y: G2To168y}, + {X: G2To169x, Y: G2To169y}, + {X: G2To170x, Y: G2To170y}, + {X: G2To171x, Y: G2To171y}, + {X: G2To172x, Y: G2To172y}, + {X: G2To173x, Y: G2To173y}, + {X: G2To174x, Y: G2To174y}, + {X: G2To175x, Y: G2To175y}, + {X: G2To176x, Y: G2To176y}, + {X: G2To177x, Y: G2To177y}, + {X: G2To178x, Y: G2To178y}, + {X: G2To179x, Y: G2To179y}, + {X: G2To180x, Y: G2To180y}, + {X: G2To181x, Y: G2To181y}, + {X: G2To182x, Y: G2To182y}, + {X: G2To183x, Y: G2To183y}, + {X: G2To184x, Y: G2To184y}, + {X: G2To185x, Y: G2To185y}, + {X: G2To186x, Y: G2To186y}, + {X: G2To187x, Y: G2To187y}, + {X: G2To188x, Y: G2To188y}, + {X: G2To189x, Y: G2To189y}, + {X: G2To190x, Y: G2To190y}, + {X: G2To191x, Y: G2To191y}, + {X: G2To192x, Y: G2To192y}, + {X: G2To193x, Y: G2To193y}, + {X: G2To194x, Y: G2To194y}, + {X: G2To195x, Y: G2To195y}, + {X: G2To196x, Y: G2To196y}, + {X: G2To197x, Y: G2To197y}, + {X: G2To198x, Y: G2To198y}, + {X: G2To199x, Y: G2To199y}, + {X: G2To200x, Y: G2To200y}, + {X: G2To201x, Y: G2To201y}, + {X: G2To202x, Y: G2To202y}, + {X: G2To203x, Y: G2To203y}, + {X: G2To204x, Y: G2To204y}, + {X: G2To205x, Y: G2To205y}, + {X: G2To206x, Y: G2To206y}, + {X: G2To207x, Y: G2To207y}, + {X: G2To208x, Y: G2To208y}, + {X: G2To209x, Y: G2To209y}, + {X: G2To210x, Y: G2To210y}, + {X: G2To211x, Y: G2To211y}, + {X: G2To212x, Y: G2To212y}, + {X: G2To213x, Y: G2To213y}, + {X: G2To214x, Y: G2To214y}, + {X: G2To215x, Y: G2To215y}, + {X: G2To216x, Y: G2To216y}, + {X: G2To217x, Y: G2To217y}, + {X: G2To218x, Y: G2To218y}, + {X: G2To219x, Y: G2To219y}, + {X: G2To220x, Y: G2To220y}, + {X: G2To221x, Y: G2To221y}, + {X: G2To222x, Y: G2To222y}, + {X: G2To223x, Y: G2To223y}, + {X: G2To224x, Y: G2To224y}, + {X: G2To225x, Y: G2To225y}, + {X: G2To226x, Y: G2To226y}, + {X: G2To227x, Y: G2To227y}, + {X: G2To228x, Y: G2To228y}, + {X: G2To229x, Y: G2To229y}, + {X: G2To230x, Y: G2To230y}, + {X: G2To231x, Y: G2To231y}, + {X: G2To232x, Y: G2To232y}, + {X: G2To233x, Y: G2To233y}, + {X: G2To234x, Y: G2To234y}, + {X: G2To235x, Y: G2To235y}, + {X: G2To236x, Y: G2To236y}, + {X: G2To237x, Y: G2To237y}, + {X: G2To238x, Y: G2To238y}, + {X: G2To239x, Y: G2To239y}, + {X: G2To240x, Y: G2To240y}, + {X: G2To241x, Y: G2To241y}, + {X: G2To242x, Y: G2To242y}, + {X: G2To243x, Y: G2To243y}, + {X: G2To244x, Y: G2To244y}, + {X: G2To245x, Y: G2To245y}, + {X: G2To246x, Y: G2To246y}, + {X: G2To247x, Y: G2To247y}, + {X: G2To248x, Y: G2To248y}, + {X: G2To249x, Y: G2To249y}, + {X: G2To250x, Y: G2To250y}, + {X: G2To251x, Y: G2To251y}, + {X: G2To252x, Y: G2To252y}, + {X: G2To253x, Y: G2To253y}, + {X: G2To254x, Y: G2To254y}, + {X: G2To255x, Y: G2To255y}, }, a: emulated.ValueOf[Base](params.A), @@ -1062,7 +1062,7 @@ func (c *Curve[B, S]) ScalarMulBase(s *emulated.Element[S]) *AffinePoint[B] { sBits := c.scalarApi.ToBits(sr) // i = 1, 2 - // gm[0] = 3g, gm[0] = 5g, gm[0] = 7g + // gm[0] = 3g, gm[1] = 5g, gm[2] = 7g res := c.Lookup2(sBits[1], sBits[2], g, &gm[0], &gm[1], &gm[2]) for i := 3; i < st.Modulus().BitLen(); i++ { @@ -1071,7 +1071,7 @@ func (c *Curve[B, S]) ScalarMulBase(s *emulated.Element[S]) *AffinePoint[B] { res = c.Select(sBits[i], tmp, res) } - // i =0 + // i = 0 tmp := c.Add(res, c.Neg(g)) res = c.Select(sBits[0], res, tmp) From ead63c3f72203a413590c19262dd75115b2ca975 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 22 Feb 2023 12:29:57 +0100 Subject: [PATCH 019/464] test(emulated): ScalarMul with random scalars --- std/algebra/weierstrass/point_test.go | 30 ++++++++++++++++++--------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/std/algebra/weierstrass/point_test.go b/std/algebra/weierstrass/point_test.go index bf34b740ce..86a9295e7c 100644 --- a/std/algebra/weierstrass/point_test.go +++ b/std/algebra/weierstrass/point_test.go @@ -6,8 +6,10 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bn254" + fr_bn "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark-crypto/ecc/secp256k1" - "github.com/consensys/gnark-crypto/ecc/secp256k1/fp" + fp_secp "github.com/consensys/gnark-crypto/ecc/secp256k1/fp" + fr_secp "github.com/consensys/gnark-crypto/ecc/secp256k1/fr" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/consensys/gnark/std/math/emulated" @@ -33,7 +35,7 @@ func (c *NegTest[T, S]) Define(api frontend.API) error { func TestNeg(t *testing.T) { assert := test.NewAssert(t) _, g := secp256k1.Generators() - var yn fp.Element + var yn fp_secp.Element yn.Neg(&g.Y) circuit := NegTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{} witness := NegTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ @@ -228,8 +230,10 @@ func (c *ScalarMulBaseTest[T, S]) Define(api frontend.API) error { func TestScalarMulBase(t *testing.T) { assert := test.NewAssert(t) _, g := secp256k1.Generators() - s, ok := new(big.Int).SetString("44693544921776318736021182399461740191514036429448770306966433218654680512345", 10) - assert.True(ok) + var r fr_secp.Element + _, _ = r.SetRandom() + s := new(big.Int) + r.BigInt(s) var S secp256k1.G1Affine S.ScalarMultiplication(&g, s) @@ -250,8 +254,10 @@ func TestScalarMulBase(t *testing.T) { func TestScalarMulBase2(t *testing.T) { assert := test.NewAssert(t) _, _, g, _ := bn254.Generators() - s, ok := new(big.Int).SetString("44693544921776318736021182399461740191514036429448770306966433218654680512345", 10) - assert.True(ok) + var r fr_bn.Element + _, _ = r.SetRandom() + s := new(big.Int) + r.BigInt(s) var S bn254.G1Affine S.ScalarMultiplication(&g, s) @@ -287,8 +293,10 @@ func (c *ScalarMulTest[T, S]) Define(api frontend.API) error { func TestScalarMul(t *testing.T) { assert := test.NewAssert(t) _, g := secp256k1.Generators() - s, ok := new(big.Int).SetString("44693544921776318736021182399461740191514036429448770306966433218654680512345", 10) - assert.True(ok) + var r fr_secp.Element + _, _ = r.SetRandom() + s := new(big.Int) + r.BigInt(s) var S secp256k1.G1Affine S.ScalarMultiplication(&g, s) @@ -312,8 +320,10 @@ func TestScalarMul(t *testing.T) { func TestScalarMul2(t *testing.T) { assert := test.NewAssert(t) - s, ok := new(big.Int).SetString("14108069686105661647148607545884343550368786660735262576656400957535521042679", 10) - assert.True(ok) + var r fr_bn.Element + _, _ = r.SetRandom() + s := new(big.Int) + r.BigInt(s) var res bn254.G1Affine _, _, gen, _ := bn254.Generators() res.ScalarMultiplication(&gen, s) From f2beb15b1f36b4631f591f3378dfce7b0bc9ae53 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Wed, 22 Feb 2023 09:58:39 -0600 Subject: [PATCH 020/464] refactor: latest gnark-crypto, use FFT signature change with opts (#485) --- go.mod | 2 +- go.sum | 2 ++ internal/backend/bls12-377/groth16/prove.go | 8 ++++---- internal/backend/bls12-377/plonkfri/prove.go | 4 ++-- internal/backend/bls12-377/plonkfri/setup.go | 20 +++++++++---------- internal/backend/bls12-381/groth16/prove.go | 8 ++++---- internal/backend/bls12-381/plonkfri/prove.go | 4 ++-- internal/backend/bls12-381/plonkfri/setup.go | 20 +++++++++---------- internal/backend/bls24-315/groth16/prove.go | 8 ++++---- internal/backend/bls24-315/plonkfri/prove.go | 4 ++-- internal/backend/bls24-315/plonkfri/setup.go | 20 +++++++++---------- internal/backend/bls24-317/groth16/prove.go | 8 ++++---- internal/backend/bls24-317/plonkfri/prove.go | 4 ++-- internal/backend/bls24-317/plonkfri/setup.go | 20 +++++++++---------- internal/backend/bn254/groth16/prove.go | 8 ++++---- internal/backend/bn254/plonkfri/prove.go | 4 ++-- internal/backend/bn254/plonkfri/setup.go | 20 +++++++++---------- internal/backend/bw6-633/groth16/prove.go | 8 ++++---- internal/backend/bw6-633/plonkfri/prove.go | 4 ++-- internal/backend/bw6-633/plonkfri/setup.go | 20 +++++++++---------- internal/backend/bw6-761/groth16/prove.go | 8 ++++---- internal/backend/bw6-761/plonkfri/prove.go | 4 ++-- internal/backend/bw6-761/plonkfri/setup.go | 20 +++++++++---------- .../zkpschemes/groth16/groth16.prove.go.tmpl | 8 ++++---- .../zkpschemes/plonkfri/plonk.prove.go.tmpl | 4 ++-- .../zkpschemes/plonkfri/plonk.setup.go.tmpl | 20 +++++++++---------- 26 files changed, 131 insertions(+), 129 deletions(-) diff --git a/go.mod b/go.mod index f0b879473e..d2a30330f8 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 - github.com/consensys/gnark-crypto v0.9.1 + github.com/consensys/gnark-crypto v0.9.2-0.20230222154459-49b5c6cfd875 github.com/fxamacker/cbor/v2 v2.4.0 github.com/google/go-cmp v0.5.9 github.com/google/pprof v0.0.0-20230207041349-798e818bf904 diff --git a/go.sum b/go.sum index 8749f1a378..83552db257 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/Yj github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= github.com/consensys/gnark-crypto v0.9.1 h1:mru55qKdWl3E035hAoh1jj9d7hVnYY5pfb6tmovSmII= github.com/consensys/gnark-crypto v0.9.1/go.mod h1:a2DQL4+5ywF6safEeZFEPGRiiGbjzGFRUN2sg06VuU4= +github.com/consensys/gnark-crypto v0.9.2-0.20230222154459-49b5c6cfd875 h1:FTOvlE+90hvp+XHi8i89xCejJ0627wfbP0RSWzmVFks= +github.com/consensys/gnark-crypto v0.9.2-0.20230222154459-49b5c6cfd875/go.mod h1:a2DQL4+5ywF6safEeZFEPGRiiGbjzGFRUN2sg06VuU4= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/internal/backend/bls12-377/groth16/prove.go b/internal/backend/bls12-377/groth16/prove.go index 4590530c00..79eab8cbef 100644 --- a/internal/backend/bls12-377/groth16/prove.go +++ b/internal/backend/bls12-377/groth16/prove.go @@ -334,9 +334,9 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { domain.FFTInverse(b, fft.DIF) domain.FFTInverse(c, fft.DIF) - domain.FFT(a, fft.DIT, true) - domain.FFT(b, fft.DIT, true) - domain.FFT(c, fft.DIT, true) + domain.FFT(a, fft.DIT, fft.OnCoset()) + domain.FFT(b, fft.DIT, fft.OnCoset()) + domain.FFT(c, fft.DIT, fft.OnCoset()) var den, one fr.Element one.SetOne() @@ -354,7 +354,7 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { }) // ifft_coset - domain.FFTInverse(a, fft.DIF, true) + domain.FFTInverse(a, fft.DIF, fft.OnCoset()) return a } diff --git a/internal/backend/bls12-377/plonkfri/prove.go b/internal/backend/bls12-377/plonkfri/prove.go index f3c15d78f9..6fda5f6a49 100644 --- a/internal/backend/bls12-377/plonkfri/prove.go +++ b/internal/backend/bls12-377/plonkfri/prove.go @@ -487,7 +487,7 @@ func computeQuotientCanonical(pk *ProvingKey, evaluationConstraintsIndBitReverse for i := 0; i < int(pk.Domain[0].Cardinality); i++ { startsAtOne[i].Set(&pk.Domain[0].CardinalityInv) } - pk.Domain[1].FFT(startsAtOne, fft.DIF, true) + pk.Domain[1].FFT(startsAtOne, fft.DIF, fft.OnCoset()) // ql(X)L(X)+qr(X)R(X)+qm(X)L(X)R(X)+qo(X)O(X)+k(X) + α.(z(μX)*g₁(X)*g₂(X)*g₃(X)-z(X)*f₁(X)*f₂(X)*f₃(X)) + α**2*L₁(X)(Z(X)-1) // on a coset of the big domain @@ -515,7 +515,7 @@ func computeQuotientCanonical(pk *ProvingKey, evaluationConstraintsIndBitReverse // put h in canonical form. h is of degree 3*(n+1)+2. // using fft.DIT put h revert bit reverse - pk.Domain[1].FFTInverse(h, fft.DIT, true) + pk.Domain[1].FFTInverse(h, fft.DIT, fft.OnCoset()) // degree of hi is n+2 because of the blinding h1 := h[:pk.Domain[0].Cardinality+2] diff --git a/internal/backend/bls12-377/plonkfri/setup.go b/internal/backend/bls12-377/plonkfri/setup.go index 6e9083bb18..91e561f8ed 100644 --- a/internal/backend/bls12-377/plonkfri/setup.go +++ b/internal/backend/bls12-377/plonkfri/setup.go @@ -209,10 +209,10 @@ func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { return &pk, &vk, err } - pk.Domain[1].FFT(pk.EvaluationQlDomainBigBitReversed, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationQrDomainBigBitReversed, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationQmDomainBigBitReversed, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationQoDomainBigBitReversed, fft.DIF, true) + pk.Domain[1].FFT(pk.EvaluationQlDomainBigBitReversed, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationQrDomainBigBitReversed, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationQmDomainBigBitReversed, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationQoDomainBigBitReversed, fft.DIF, fft.OnCoset()) // build permutation. Note: at this stage, the permutation takes in account the placeholders buildPermutation(spr, &pk) @@ -349,9 +349,9 @@ func computePermutationPolynomials(pk *ProvingKey, vk *VerifyingKey) error { if err != nil { return err } - pk.Domain[1].FFT(pk.EvaluationId1BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationId2BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationId3BigDomain, fft.DIF, true) + pk.Domain[1].FFT(pk.EvaluationId1BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationId2BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationId3BigDomain, fft.DIF, fft.OnCoset()) pk.Domain[0].FFTInverse(pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality], fft.DIF) pk.Domain[0].FFTInverse(pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality], fft.DIF) @@ -379,9 +379,9 @@ func computePermutationPolynomials(pk *ProvingKey, vk *VerifyingKey) error { if err != nil { return err } - pk.Domain[1].FFT(pk.EvaluationS1BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationS2BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationS3BigDomain, fft.DIF, true) + pk.Domain[1].FFT(pk.EvaluationS1BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationS2BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationS3BigDomain, fft.DIF, fft.OnCoset()) return nil diff --git a/internal/backend/bls12-381/groth16/prove.go b/internal/backend/bls12-381/groth16/prove.go index 9afd4240c1..775bd83af9 100644 --- a/internal/backend/bls12-381/groth16/prove.go +++ b/internal/backend/bls12-381/groth16/prove.go @@ -334,9 +334,9 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { domain.FFTInverse(b, fft.DIF) domain.FFTInverse(c, fft.DIF) - domain.FFT(a, fft.DIT, true) - domain.FFT(b, fft.DIT, true) - domain.FFT(c, fft.DIT, true) + domain.FFT(a, fft.DIT, fft.OnCoset()) + domain.FFT(b, fft.DIT, fft.OnCoset()) + domain.FFT(c, fft.DIT, fft.OnCoset()) var den, one fr.Element one.SetOne() @@ -354,7 +354,7 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { }) // ifft_coset - domain.FFTInverse(a, fft.DIF, true) + domain.FFTInverse(a, fft.DIF, fft.OnCoset()) return a } diff --git a/internal/backend/bls12-381/plonkfri/prove.go b/internal/backend/bls12-381/plonkfri/prove.go index 8909988986..f0b7a2414a 100644 --- a/internal/backend/bls12-381/plonkfri/prove.go +++ b/internal/backend/bls12-381/plonkfri/prove.go @@ -487,7 +487,7 @@ func computeQuotientCanonical(pk *ProvingKey, evaluationConstraintsIndBitReverse for i := 0; i < int(pk.Domain[0].Cardinality); i++ { startsAtOne[i].Set(&pk.Domain[0].CardinalityInv) } - pk.Domain[1].FFT(startsAtOne, fft.DIF, true) + pk.Domain[1].FFT(startsAtOne, fft.DIF, fft.OnCoset()) // ql(X)L(X)+qr(X)R(X)+qm(X)L(X)R(X)+qo(X)O(X)+k(X) + α.(z(μX)*g₁(X)*g₂(X)*g₃(X)-z(X)*f₁(X)*f₂(X)*f₃(X)) + α**2*L₁(X)(Z(X)-1) // on a coset of the big domain @@ -515,7 +515,7 @@ func computeQuotientCanonical(pk *ProvingKey, evaluationConstraintsIndBitReverse // put h in canonical form. h is of degree 3*(n+1)+2. // using fft.DIT put h revert bit reverse - pk.Domain[1].FFTInverse(h, fft.DIT, true) + pk.Domain[1].FFTInverse(h, fft.DIT, fft.OnCoset()) // degree of hi is n+2 because of the blinding h1 := h[:pk.Domain[0].Cardinality+2] diff --git a/internal/backend/bls12-381/plonkfri/setup.go b/internal/backend/bls12-381/plonkfri/setup.go index da30df7b0f..7be1c02042 100644 --- a/internal/backend/bls12-381/plonkfri/setup.go +++ b/internal/backend/bls12-381/plonkfri/setup.go @@ -209,10 +209,10 @@ func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { return &pk, &vk, err } - pk.Domain[1].FFT(pk.EvaluationQlDomainBigBitReversed, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationQrDomainBigBitReversed, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationQmDomainBigBitReversed, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationQoDomainBigBitReversed, fft.DIF, true) + pk.Domain[1].FFT(pk.EvaluationQlDomainBigBitReversed, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationQrDomainBigBitReversed, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationQmDomainBigBitReversed, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationQoDomainBigBitReversed, fft.DIF, fft.OnCoset()) // build permutation. Note: at this stage, the permutation takes in account the placeholders buildPermutation(spr, &pk) @@ -349,9 +349,9 @@ func computePermutationPolynomials(pk *ProvingKey, vk *VerifyingKey) error { if err != nil { return err } - pk.Domain[1].FFT(pk.EvaluationId1BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationId2BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationId3BigDomain, fft.DIF, true) + pk.Domain[1].FFT(pk.EvaluationId1BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationId2BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationId3BigDomain, fft.DIF, fft.OnCoset()) pk.Domain[0].FFTInverse(pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality], fft.DIF) pk.Domain[0].FFTInverse(pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality], fft.DIF) @@ -379,9 +379,9 @@ func computePermutationPolynomials(pk *ProvingKey, vk *VerifyingKey) error { if err != nil { return err } - pk.Domain[1].FFT(pk.EvaluationS1BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationS2BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationS3BigDomain, fft.DIF, true) + pk.Domain[1].FFT(pk.EvaluationS1BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationS2BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationS3BigDomain, fft.DIF, fft.OnCoset()) return nil diff --git a/internal/backend/bls24-315/groth16/prove.go b/internal/backend/bls24-315/groth16/prove.go index cd2fa623e5..d822d3780c 100644 --- a/internal/backend/bls24-315/groth16/prove.go +++ b/internal/backend/bls24-315/groth16/prove.go @@ -334,9 +334,9 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { domain.FFTInverse(b, fft.DIF) domain.FFTInverse(c, fft.DIF) - domain.FFT(a, fft.DIT, true) - domain.FFT(b, fft.DIT, true) - domain.FFT(c, fft.DIT, true) + domain.FFT(a, fft.DIT, fft.OnCoset()) + domain.FFT(b, fft.DIT, fft.OnCoset()) + domain.FFT(c, fft.DIT, fft.OnCoset()) var den, one fr.Element one.SetOne() @@ -354,7 +354,7 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { }) // ifft_coset - domain.FFTInverse(a, fft.DIF, true) + domain.FFTInverse(a, fft.DIF, fft.OnCoset()) return a } diff --git a/internal/backend/bls24-315/plonkfri/prove.go b/internal/backend/bls24-315/plonkfri/prove.go index a440c5953f..a73d5afac3 100644 --- a/internal/backend/bls24-315/plonkfri/prove.go +++ b/internal/backend/bls24-315/plonkfri/prove.go @@ -487,7 +487,7 @@ func computeQuotientCanonical(pk *ProvingKey, evaluationConstraintsIndBitReverse for i := 0; i < int(pk.Domain[0].Cardinality); i++ { startsAtOne[i].Set(&pk.Domain[0].CardinalityInv) } - pk.Domain[1].FFT(startsAtOne, fft.DIF, true) + pk.Domain[1].FFT(startsAtOne, fft.DIF, fft.OnCoset()) // ql(X)L(X)+qr(X)R(X)+qm(X)L(X)R(X)+qo(X)O(X)+k(X) + α.(z(μX)*g₁(X)*g₂(X)*g₃(X)-z(X)*f₁(X)*f₂(X)*f₃(X)) + α**2*L₁(X)(Z(X)-1) // on a coset of the big domain @@ -515,7 +515,7 @@ func computeQuotientCanonical(pk *ProvingKey, evaluationConstraintsIndBitReverse // put h in canonical form. h is of degree 3*(n+1)+2. // using fft.DIT put h revert bit reverse - pk.Domain[1].FFTInverse(h, fft.DIT, true) + pk.Domain[1].FFTInverse(h, fft.DIT, fft.OnCoset()) // degree of hi is n+2 because of the blinding h1 := h[:pk.Domain[0].Cardinality+2] diff --git a/internal/backend/bls24-315/plonkfri/setup.go b/internal/backend/bls24-315/plonkfri/setup.go index d02f7f504f..32315bb39f 100644 --- a/internal/backend/bls24-315/plonkfri/setup.go +++ b/internal/backend/bls24-315/plonkfri/setup.go @@ -209,10 +209,10 @@ func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { return &pk, &vk, err } - pk.Domain[1].FFT(pk.EvaluationQlDomainBigBitReversed, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationQrDomainBigBitReversed, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationQmDomainBigBitReversed, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationQoDomainBigBitReversed, fft.DIF, true) + pk.Domain[1].FFT(pk.EvaluationQlDomainBigBitReversed, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationQrDomainBigBitReversed, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationQmDomainBigBitReversed, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationQoDomainBigBitReversed, fft.DIF, fft.OnCoset()) // build permutation. Note: at this stage, the permutation takes in account the placeholders buildPermutation(spr, &pk) @@ -349,9 +349,9 @@ func computePermutationPolynomials(pk *ProvingKey, vk *VerifyingKey) error { if err != nil { return err } - pk.Domain[1].FFT(pk.EvaluationId1BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationId2BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationId3BigDomain, fft.DIF, true) + pk.Domain[1].FFT(pk.EvaluationId1BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationId2BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationId3BigDomain, fft.DIF, fft.OnCoset()) pk.Domain[0].FFTInverse(pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality], fft.DIF) pk.Domain[0].FFTInverse(pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality], fft.DIF) @@ -379,9 +379,9 @@ func computePermutationPolynomials(pk *ProvingKey, vk *VerifyingKey) error { if err != nil { return err } - pk.Domain[1].FFT(pk.EvaluationS1BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationS2BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationS3BigDomain, fft.DIF, true) + pk.Domain[1].FFT(pk.EvaluationS1BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationS2BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationS3BigDomain, fft.DIF, fft.OnCoset()) return nil diff --git a/internal/backend/bls24-317/groth16/prove.go b/internal/backend/bls24-317/groth16/prove.go index 5dfeaf9228..d80167098d 100644 --- a/internal/backend/bls24-317/groth16/prove.go +++ b/internal/backend/bls24-317/groth16/prove.go @@ -334,9 +334,9 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { domain.FFTInverse(b, fft.DIF) domain.FFTInverse(c, fft.DIF) - domain.FFT(a, fft.DIT, true) - domain.FFT(b, fft.DIT, true) - domain.FFT(c, fft.DIT, true) + domain.FFT(a, fft.DIT, fft.OnCoset()) + domain.FFT(b, fft.DIT, fft.OnCoset()) + domain.FFT(c, fft.DIT, fft.OnCoset()) var den, one fr.Element one.SetOne() @@ -354,7 +354,7 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { }) // ifft_coset - domain.FFTInverse(a, fft.DIF, true) + domain.FFTInverse(a, fft.DIF, fft.OnCoset()) return a } diff --git a/internal/backend/bls24-317/plonkfri/prove.go b/internal/backend/bls24-317/plonkfri/prove.go index 752c825069..5dfebe9c2f 100644 --- a/internal/backend/bls24-317/plonkfri/prove.go +++ b/internal/backend/bls24-317/plonkfri/prove.go @@ -487,7 +487,7 @@ func computeQuotientCanonical(pk *ProvingKey, evaluationConstraintsIndBitReverse for i := 0; i < int(pk.Domain[0].Cardinality); i++ { startsAtOne[i].Set(&pk.Domain[0].CardinalityInv) } - pk.Domain[1].FFT(startsAtOne, fft.DIF, true) + pk.Domain[1].FFT(startsAtOne, fft.DIF, fft.OnCoset()) // ql(X)L(X)+qr(X)R(X)+qm(X)L(X)R(X)+qo(X)O(X)+k(X) + α.(z(μX)*g₁(X)*g₂(X)*g₃(X)-z(X)*f₁(X)*f₂(X)*f₃(X)) + α**2*L₁(X)(Z(X)-1) // on a coset of the big domain @@ -515,7 +515,7 @@ func computeQuotientCanonical(pk *ProvingKey, evaluationConstraintsIndBitReverse // put h in canonical form. h is of degree 3*(n+1)+2. // using fft.DIT put h revert bit reverse - pk.Domain[1].FFTInverse(h, fft.DIT, true) + pk.Domain[1].FFTInverse(h, fft.DIT, fft.OnCoset()) // degree of hi is n+2 because of the blinding h1 := h[:pk.Domain[0].Cardinality+2] diff --git a/internal/backend/bls24-317/plonkfri/setup.go b/internal/backend/bls24-317/plonkfri/setup.go index 7cd1fb80ff..266a8d0107 100644 --- a/internal/backend/bls24-317/plonkfri/setup.go +++ b/internal/backend/bls24-317/plonkfri/setup.go @@ -209,10 +209,10 @@ func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { return &pk, &vk, err } - pk.Domain[1].FFT(pk.EvaluationQlDomainBigBitReversed, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationQrDomainBigBitReversed, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationQmDomainBigBitReversed, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationQoDomainBigBitReversed, fft.DIF, true) + pk.Domain[1].FFT(pk.EvaluationQlDomainBigBitReversed, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationQrDomainBigBitReversed, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationQmDomainBigBitReversed, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationQoDomainBigBitReversed, fft.DIF, fft.OnCoset()) // build permutation. Note: at this stage, the permutation takes in account the placeholders buildPermutation(spr, &pk) @@ -349,9 +349,9 @@ func computePermutationPolynomials(pk *ProvingKey, vk *VerifyingKey) error { if err != nil { return err } - pk.Domain[1].FFT(pk.EvaluationId1BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationId2BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationId3BigDomain, fft.DIF, true) + pk.Domain[1].FFT(pk.EvaluationId1BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationId2BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationId3BigDomain, fft.DIF, fft.OnCoset()) pk.Domain[0].FFTInverse(pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality], fft.DIF) pk.Domain[0].FFTInverse(pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality], fft.DIF) @@ -379,9 +379,9 @@ func computePermutationPolynomials(pk *ProvingKey, vk *VerifyingKey) error { if err != nil { return err } - pk.Domain[1].FFT(pk.EvaluationS1BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationS2BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationS3BigDomain, fft.DIF, true) + pk.Domain[1].FFT(pk.EvaluationS1BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationS2BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationS3BigDomain, fft.DIF, fft.OnCoset()) return nil diff --git a/internal/backend/bn254/groth16/prove.go b/internal/backend/bn254/groth16/prove.go index 8ca7d568d8..d3dcc1ba5a 100644 --- a/internal/backend/bn254/groth16/prove.go +++ b/internal/backend/bn254/groth16/prove.go @@ -334,9 +334,9 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { domain.FFTInverse(b, fft.DIF) domain.FFTInverse(c, fft.DIF) - domain.FFT(a, fft.DIT, true) - domain.FFT(b, fft.DIT, true) - domain.FFT(c, fft.DIT, true) + domain.FFT(a, fft.DIT, fft.OnCoset()) + domain.FFT(b, fft.DIT, fft.OnCoset()) + domain.FFT(c, fft.DIT, fft.OnCoset()) var den, one fr.Element one.SetOne() @@ -354,7 +354,7 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { }) // ifft_coset - domain.FFTInverse(a, fft.DIF, true) + domain.FFTInverse(a, fft.DIF, fft.OnCoset()) return a } diff --git a/internal/backend/bn254/plonkfri/prove.go b/internal/backend/bn254/plonkfri/prove.go index 1166b5cc30..c4465d7ab4 100644 --- a/internal/backend/bn254/plonkfri/prove.go +++ b/internal/backend/bn254/plonkfri/prove.go @@ -487,7 +487,7 @@ func computeQuotientCanonical(pk *ProvingKey, evaluationConstraintsIndBitReverse for i := 0; i < int(pk.Domain[0].Cardinality); i++ { startsAtOne[i].Set(&pk.Domain[0].CardinalityInv) } - pk.Domain[1].FFT(startsAtOne, fft.DIF, true) + pk.Domain[1].FFT(startsAtOne, fft.DIF, fft.OnCoset()) // ql(X)L(X)+qr(X)R(X)+qm(X)L(X)R(X)+qo(X)O(X)+k(X) + α.(z(μX)*g₁(X)*g₂(X)*g₃(X)-z(X)*f₁(X)*f₂(X)*f₃(X)) + α**2*L₁(X)(Z(X)-1) // on a coset of the big domain @@ -515,7 +515,7 @@ func computeQuotientCanonical(pk *ProvingKey, evaluationConstraintsIndBitReverse // put h in canonical form. h is of degree 3*(n+1)+2. // using fft.DIT put h revert bit reverse - pk.Domain[1].FFTInverse(h, fft.DIT, true) + pk.Domain[1].FFTInverse(h, fft.DIT, fft.OnCoset()) // degree of hi is n+2 because of the blinding h1 := h[:pk.Domain[0].Cardinality+2] diff --git a/internal/backend/bn254/plonkfri/setup.go b/internal/backend/bn254/plonkfri/setup.go index 4a47a70839..a2e5b2023d 100644 --- a/internal/backend/bn254/plonkfri/setup.go +++ b/internal/backend/bn254/plonkfri/setup.go @@ -209,10 +209,10 @@ func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { return &pk, &vk, err } - pk.Domain[1].FFT(pk.EvaluationQlDomainBigBitReversed, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationQrDomainBigBitReversed, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationQmDomainBigBitReversed, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationQoDomainBigBitReversed, fft.DIF, true) + pk.Domain[1].FFT(pk.EvaluationQlDomainBigBitReversed, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationQrDomainBigBitReversed, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationQmDomainBigBitReversed, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationQoDomainBigBitReversed, fft.DIF, fft.OnCoset()) // build permutation. Note: at this stage, the permutation takes in account the placeholders buildPermutation(spr, &pk) @@ -349,9 +349,9 @@ func computePermutationPolynomials(pk *ProvingKey, vk *VerifyingKey) error { if err != nil { return err } - pk.Domain[1].FFT(pk.EvaluationId1BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationId2BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationId3BigDomain, fft.DIF, true) + pk.Domain[1].FFT(pk.EvaluationId1BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationId2BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationId3BigDomain, fft.DIF, fft.OnCoset()) pk.Domain[0].FFTInverse(pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality], fft.DIF) pk.Domain[0].FFTInverse(pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality], fft.DIF) @@ -379,9 +379,9 @@ func computePermutationPolynomials(pk *ProvingKey, vk *VerifyingKey) error { if err != nil { return err } - pk.Domain[1].FFT(pk.EvaluationS1BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationS2BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationS3BigDomain, fft.DIF, true) + pk.Domain[1].FFT(pk.EvaluationS1BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationS2BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationS3BigDomain, fft.DIF, fft.OnCoset()) return nil diff --git a/internal/backend/bw6-633/groth16/prove.go b/internal/backend/bw6-633/groth16/prove.go index 335a9f0ccb..e22ef4e7a0 100644 --- a/internal/backend/bw6-633/groth16/prove.go +++ b/internal/backend/bw6-633/groth16/prove.go @@ -334,9 +334,9 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { domain.FFTInverse(b, fft.DIF) domain.FFTInverse(c, fft.DIF) - domain.FFT(a, fft.DIT, true) - domain.FFT(b, fft.DIT, true) - domain.FFT(c, fft.DIT, true) + domain.FFT(a, fft.DIT, fft.OnCoset()) + domain.FFT(b, fft.DIT, fft.OnCoset()) + domain.FFT(c, fft.DIT, fft.OnCoset()) var den, one fr.Element one.SetOne() @@ -354,7 +354,7 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { }) // ifft_coset - domain.FFTInverse(a, fft.DIF, true) + domain.FFTInverse(a, fft.DIF, fft.OnCoset()) return a } diff --git a/internal/backend/bw6-633/plonkfri/prove.go b/internal/backend/bw6-633/plonkfri/prove.go index aa02bc934b..27e42784a5 100644 --- a/internal/backend/bw6-633/plonkfri/prove.go +++ b/internal/backend/bw6-633/plonkfri/prove.go @@ -487,7 +487,7 @@ func computeQuotientCanonical(pk *ProvingKey, evaluationConstraintsIndBitReverse for i := 0; i < int(pk.Domain[0].Cardinality); i++ { startsAtOne[i].Set(&pk.Domain[0].CardinalityInv) } - pk.Domain[1].FFT(startsAtOne, fft.DIF, true) + pk.Domain[1].FFT(startsAtOne, fft.DIF, fft.OnCoset()) // ql(X)L(X)+qr(X)R(X)+qm(X)L(X)R(X)+qo(X)O(X)+k(X) + α.(z(μX)*g₁(X)*g₂(X)*g₃(X)-z(X)*f₁(X)*f₂(X)*f₃(X)) + α**2*L₁(X)(Z(X)-1) // on a coset of the big domain @@ -515,7 +515,7 @@ func computeQuotientCanonical(pk *ProvingKey, evaluationConstraintsIndBitReverse // put h in canonical form. h is of degree 3*(n+1)+2. // using fft.DIT put h revert bit reverse - pk.Domain[1].FFTInverse(h, fft.DIT, true) + pk.Domain[1].FFTInverse(h, fft.DIT, fft.OnCoset()) // degree of hi is n+2 because of the blinding h1 := h[:pk.Domain[0].Cardinality+2] diff --git a/internal/backend/bw6-633/plonkfri/setup.go b/internal/backend/bw6-633/plonkfri/setup.go index 04d0062321..afad348574 100644 --- a/internal/backend/bw6-633/plonkfri/setup.go +++ b/internal/backend/bw6-633/plonkfri/setup.go @@ -209,10 +209,10 @@ func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { return &pk, &vk, err } - pk.Domain[1].FFT(pk.EvaluationQlDomainBigBitReversed, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationQrDomainBigBitReversed, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationQmDomainBigBitReversed, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationQoDomainBigBitReversed, fft.DIF, true) + pk.Domain[1].FFT(pk.EvaluationQlDomainBigBitReversed, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationQrDomainBigBitReversed, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationQmDomainBigBitReversed, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationQoDomainBigBitReversed, fft.DIF, fft.OnCoset()) // build permutation. Note: at this stage, the permutation takes in account the placeholders buildPermutation(spr, &pk) @@ -349,9 +349,9 @@ func computePermutationPolynomials(pk *ProvingKey, vk *VerifyingKey) error { if err != nil { return err } - pk.Domain[1].FFT(pk.EvaluationId1BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationId2BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationId3BigDomain, fft.DIF, true) + pk.Domain[1].FFT(pk.EvaluationId1BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationId2BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationId3BigDomain, fft.DIF, fft.OnCoset()) pk.Domain[0].FFTInverse(pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality], fft.DIF) pk.Domain[0].FFTInverse(pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality], fft.DIF) @@ -379,9 +379,9 @@ func computePermutationPolynomials(pk *ProvingKey, vk *VerifyingKey) error { if err != nil { return err } - pk.Domain[1].FFT(pk.EvaluationS1BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationS2BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationS3BigDomain, fft.DIF, true) + pk.Domain[1].FFT(pk.EvaluationS1BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationS2BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationS3BigDomain, fft.DIF, fft.OnCoset()) return nil diff --git a/internal/backend/bw6-761/groth16/prove.go b/internal/backend/bw6-761/groth16/prove.go index 950932327f..80b4df34fd 100644 --- a/internal/backend/bw6-761/groth16/prove.go +++ b/internal/backend/bw6-761/groth16/prove.go @@ -334,9 +334,9 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { domain.FFTInverse(b, fft.DIF) domain.FFTInverse(c, fft.DIF) - domain.FFT(a, fft.DIT, true) - domain.FFT(b, fft.DIT, true) - domain.FFT(c, fft.DIT, true) + domain.FFT(a, fft.DIT, fft.OnCoset()) + domain.FFT(b, fft.DIT, fft.OnCoset()) + domain.FFT(c, fft.DIT, fft.OnCoset()) var den, one fr.Element one.SetOne() @@ -354,7 +354,7 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { }) // ifft_coset - domain.FFTInverse(a, fft.DIF, true) + domain.FFTInverse(a, fft.DIF, fft.OnCoset()) return a } diff --git a/internal/backend/bw6-761/plonkfri/prove.go b/internal/backend/bw6-761/plonkfri/prove.go index e5f9cb5b78..41ab07bf26 100644 --- a/internal/backend/bw6-761/plonkfri/prove.go +++ b/internal/backend/bw6-761/plonkfri/prove.go @@ -487,7 +487,7 @@ func computeQuotientCanonical(pk *ProvingKey, evaluationConstraintsIndBitReverse for i := 0; i < int(pk.Domain[0].Cardinality); i++ { startsAtOne[i].Set(&pk.Domain[0].CardinalityInv) } - pk.Domain[1].FFT(startsAtOne, fft.DIF, true) + pk.Domain[1].FFT(startsAtOne, fft.DIF, fft.OnCoset()) // ql(X)L(X)+qr(X)R(X)+qm(X)L(X)R(X)+qo(X)O(X)+k(X) + α.(z(μX)*g₁(X)*g₂(X)*g₃(X)-z(X)*f₁(X)*f₂(X)*f₃(X)) + α**2*L₁(X)(Z(X)-1) // on a coset of the big domain @@ -515,7 +515,7 @@ func computeQuotientCanonical(pk *ProvingKey, evaluationConstraintsIndBitReverse // put h in canonical form. h is of degree 3*(n+1)+2. // using fft.DIT put h revert bit reverse - pk.Domain[1].FFTInverse(h, fft.DIT, true) + pk.Domain[1].FFTInverse(h, fft.DIT, fft.OnCoset()) // degree of hi is n+2 because of the blinding h1 := h[:pk.Domain[0].Cardinality+2] diff --git a/internal/backend/bw6-761/plonkfri/setup.go b/internal/backend/bw6-761/plonkfri/setup.go index 32be4d26fe..3570409af5 100644 --- a/internal/backend/bw6-761/plonkfri/setup.go +++ b/internal/backend/bw6-761/plonkfri/setup.go @@ -209,10 +209,10 @@ func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { return &pk, &vk, err } - pk.Domain[1].FFT(pk.EvaluationQlDomainBigBitReversed, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationQrDomainBigBitReversed, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationQmDomainBigBitReversed, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationQoDomainBigBitReversed, fft.DIF, true) + pk.Domain[1].FFT(pk.EvaluationQlDomainBigBitReversed, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationQrDomainBigBitReversed, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationQmDomainBigBitReversed, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationQoDomainBigBitReversed, fft.DIF, fft.OnCoset()) // build permutation. Note: at this stage, the permutation takes in account the placeholders buildPermutation(spr, &pk) @@ -349,9 +349,9 @@ func computePermutationPolynomials(pk *ProvingKey, vk *VerifyingKey) error { if err != nil { return err } - pk.Domain[1].FFT(pk.EvaluationId1BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationId2BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationId3BigDomain, fft.DIF, true) + pk.Domain[1].FFT(pk.EvaluationId1BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationId2BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationId3BigDomain, fft.DIF, fft.OnCoset()) pk.Domain[0].FFTInverse(pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality], fft.DIF) pk.Domain[0].FFTInverse(pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality], fft.DIF) @@ -379,9 +379,9 @@ func computePermutationPolynomials(pk *ProvingKey, vk *VerifyingKey) error { if err != nil { return err } - pk.Domain[1].FFT(pk.EvaluationS1BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationS2BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationS3BigDomain, fft.DIF, true) + pk.Domain[1].FFT(pk.EvaluationS1BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationS2BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationS3BigDomain, fft.DIF, fft.OnCoset()) return nil diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl index 64987ebd1b..dec4db8338 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl @@ -317,9 +317,9 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { domain.FFTInverse(b, fft.DIF) domain.FFTInverse(c, fft.DIF) - domain.FFT(a, fft.DIT, true) - domain.FFT(b, fft.DIT, true) - domain.FFT(c, fft.DIT, true) + domain.FFT(a, fft.DIT, fft.OnCoset()) + domain.FFT(b, fft.DIT, fft.OnCoset()) + domain.FFT(c, fft.DIT, fft.OnCoset()) var den, one fr.Element one.SetOne() @@ -337,7 +337,7 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { }) // ifft_coset - domain.FFTInverse(a, fft.DIF, true) + domain.FFTInverse(a, fft.DIF, fft.OnCoset()) return a } \ No newline at end of file diff --git a/internal/generator/backend/template/zkpschemes/plonkfri/plonk.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/plonkfri/plonk.prove.go.tmpl index b9b8a839a9..20ee52c909 100644 --- a/internal/generator/backend/template/zkpschemes/plonkfri/plonk.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonkfri/plonk.prove.go.tmpl @@ -465,7 +465,7 @@ func computeQuotientCanonical(pk *ProvingKey, evaluationConstraintsIndBitReverse for i := 0; i < int(pk.Domain[0].Cardinality); i++ { startsAtOne[i].Set(&pk.Domain[0].CardinalityInv) } - pk.Domain[1].FFT(startsAtOne, fft.DIF, true) + pk.Domain[1].FFT(startsAtOne, fft.DIF, fft.OnCoset()) // ql(X)L(X)+qr(X)R(X)+qm(X)L(X)R(X)+qo(X)O(X)+k(X) + α.(z(μX)*g₁(X)*g₂(X)*g₃(X)-z(X)*f₁(X)*f₂(X)*f₃(X)) + α**2*L₁(X)(Z(X)-1) // on a coset of the big domain @@ -493,7 +493,7 @@ func computeQuotientCanonical(pk *ProvingKey, evaluationConstraintsIndBitReverse // put h in canonical form. h is of degree 3*(n+1)+2. // using fft.DIT put h revert bit reverse - pk.Domain[1].FFTInverse(h, fft.DIT, true) + pk.Domain[1].FFTInverse(h, fft.DIT, fft.OnCoset()) // degree of hi is n+2 because of the blinding h1 := h[:pk.Domain[0].Cardinality+2] diff --git a/internal/generator/backend/template/zkpschemes/plonkfri/plonk.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/plonkfri/plonk.setup.go.tmpl index 43079ccb62..f07ad840ba 100644 --- a/internal/generator/backend/template/zkpschemes/plonkfri/plonk.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonkfri/plonk.setup.go.tmpl @@ -192,10 +192,10 @@ func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { return &pk, &vk, err } - pk.Domain[1].FFT(pk.EvaluationQlDomainBigBitReversed, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationQrDomainBigBitReversed, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationQmDomainBigBitReversed, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationQoDomainBigBitReversed, fft.DIF, true) + pk.Domain[1].FFT(pk.EvaluationQlDomainBigBitReversed, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationQrDomainBigBitReversed, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationQmDomainBigBitReversed, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationQoDomainBigBitReversed, fft.DIF, fft.OnCoset()) // build permutation. Note: at this stage, the permutation takes in account the placeholders buildPermutation(spr, &pk) @@ -329,9 +329,9 @@ func computePermutationPolynomials(pk *ProvingKey, vk *VerifyingKey) error { if err != nil { return err } - pk.Domain[1].FFT(pk.EvaluationId1BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationId2BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationId3BigDomain, fft.DIF, true) + pk.Domain[1].FFT(pk.EvaluationId1BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationId2BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationId3BigDomain, fft.DIF, fft.OnCoset()) pk.Domain[0].FFTInverse(pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality], fft.DIF) pk.Domain[0].FFTInverse(pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality], fft.DIF) @@ -359,9 +359,9 @@ func computePermutationPolynomials(pk *ProvingKey, vk *VerifyingKey) error { if err != nil { return err } - pk.Domain[1].FFT(pk.EvaluationS1BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationS2BigDomain, fft.DIF, true) - pk.Domain[1].FFT(pk.EvaluationS3BigDomain, fft.DIF, true) + pk.Domain[1].FFT(pk.EvaluationS1BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationS2BigDomain, fft.DIF, fft.OnCoset()) + pk.Domain[1].FFT(pk.EvaluationS3BigDomain, fft.DIF, fft.OnCoset()) return nil From 7493fa2d6d8e913fc32b95cead04c39c335a9bcf Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 23 Feb 2023 02:20:53 +0100 Subject: [PATCH 021/464] fix: allocate new variable in engine.MulAcc (#482) * fix: allocate new variable in engine.MulAcc We previously modified the result inline, but the behaviour may be inconsistent with actual frontend/compiler. When variable is a Term or LinearExpression, then b := a copies value of a into b and after that these variables are independent. For example, with MulAcc(b, x, y) we won't modify the variable a. But, as test engine modified variable inline, then doing MulAcc(b, x, y) also changed value of a (as they are just *big.Int). This lead to inconsistent results. * perf: use mulacc in emulated mul * fix: return newly allocated value --- std/math/emulated/field_ops.go | 6 +++--- test/engine.go | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/std/math/emulated/field_ops.go b/std/math/emulated/field_ops.go index baa7154f5d..0b1d6f5e7f 100644 --- a/std/math/emulated/field_ops.go +++ b/std/math/emulated/field_ops.go @@ -185,12 +185,12 @@ func (f *Field[T]) mul(a, b *Element[T], nextOverflow uint) *Element[T] { for i := 1; i < len(mulResult); i++ { w.Lsh(w, uint(c)) if i < len(a.Limbs) { - l = f.api.Add(l, f.api.Mul(a.Limbs[i], w)) + l = f.api.MulAcc(l, a.Limbs[i], w) } if i < len(b.Limbs) { - r = f.api.Add(r, f.api.Mul(b.Limbs[i], w)) + r = f.api.MulAcc(r, b.Limbs[i], w) } - o = f.api.Add(o, f.api.Mul(mulResult[i], w)) + o = f.api.MulAcc(o, mulResult[i], w) } f.api.AssertIsEqual(f.api.Mul(l, r), o) } diff --git a/test/engine.go b/test/engine.go index ab459573df..2651cc8ad5 100644 --- a/test/engine.go +++ b/test/engine.go @@ -161,11 +161,12 @@ func (e *engine) MulAcc(a, b, c frontend.Variable) frontend.Variable { bc := pool.BigInt.Get() bc.Mul(e.toBigInt(b), e.toBigInt(c)) + res := new(big.Int) _a := e.toBigInt(a) - _a.Add(_a, bc).Mod(_a, e.modulus()) + res.Add(_a, bc).Mod(res, e.modulus()) pool.BigInt.Put(bc) - return _a + return res } func (e *engine) Sub(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { From 913ff628ae38a4ee2e180d5c2580a2358b8a376d Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Thu, 23 Feb 2023 15:51:56 -0600 Subject: [PATCH 022/464] fix: scs.MarkBoolean missing return w/ constant (#491) --- frontend/cs/scs/builder.go | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/cs/scs/builder.go b/frontend/cs/scs/builder.go index b5d2881a86..1c791b1716 100644 --- a/frontend/cs/scs/builder.go +++ b/frontend/cs/scs/builder.go @@ -208,6 +208,7 @@ func (builder *scs) MarkBoolean(v frontend.Variable) { if !(b.IsUint64() && b.Uint64() <= 1) { panic("MarkBoolean called a non-boolean constant") } + return } builder.mtBooleans[int(v.(expr.TermToRefactor).CID|(int(v.(expr.TermToRefactor).VID)<<32))] = struct{}{} // TODO @gbotrel fixme this is sketchy } From 83a3b096dcb60e44c39515ca9e29f850be3a3887 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Tue, 14 Feb 2023 14:33:34 -0600 Subject: [PATCH 023/464] feat: update gnark version to v0.8.0 --- doc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc.go b/doc.go index b871010f37..697944b7d7 100644 --- a/doc.go +++ b/doc.go @@ -22,7 +22,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" ) -var Version = semver.MustParse("0.8.1-alpha") +var Version = semver.MustParse("0.8.0") // Curves return the curves supported by gnark func Curves() []ecc.ID { From a51987e95284175b8e2ce34102c0d13a3e35e321 Mon Sep 17 00:00:00 2001 From: Behrouz Date: Tue, 21 Feb 2023 18:40:52 +0330 Subject: [PATCH 024/464] Fix the example in `README.md` (#478) The example in `README.md` (still) does not compile. `BN254` has a `ScalarField()` method now, and should not be passed directly. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 143ca2814a..91e014ab2c 100644 --- a/README.md +++ b/README.md @@ -99,14 +99,14 @@ func (circuit *CubicCircuit) Define(api frontend.API) error { func main() { // compiles our circuit into a R1CS var circuit CubicCircuit - ccs, _ := frontend.Compile(ecc.BN254, r1cs.NewBuilder, &circuit) + ccs, _ := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) // groth16 zkSNARK: Setup pk, vk, _ := groth16.Setup(ccs) // witness definition assignment := CubicCircuit{X: 3, Y: 35} - witness, _ := frontend.NewWitness(&assignment, ecc.BN254) + witness, _ := frontend.NewWitness(&assignment, ecc.BN254.ScalarField()) publicWitness, _ := witness.Public() // groth16: Prove & Verify From 83889dcdf39175cad51dc895dc600d6a3c83deaf Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Mon, 27 Feb 2023 23:40:59 -0500 Subject: [PATCH 025/464] feat: compilation, setup and commitment done; proof and verification next --- backend/plonk/plonk.go | 2 +- constraint/bn254/r1cs_sparse.go | 2 +- constraint/r1cs_sparse.go | 1 + examples/plonk/main.go | 2 +- frontend/cs/scs/api.go | 19 +++++---- frontend/cs/scs/api_assertions.go | 10 ++--- frontend/cs/scs/builder.go | 26 +++++++++--- internal/backend/bn254/plonk/prove.go | 29 +++++++++++++ internal/backend/bn254/plonk/setup.go | 21 ++++++++-- test/commitments_test.go | 60 +++++++++++++++++++++++++++ 10 files changed, 146 insertions(+), 26 deletions(-) create mode 100644 test/commitments_test.go diff --git a/backend/plonk/plonk.go b/backend/plonk/plonk.go index 0a6fbc4330..a0ca1be331 100644 --- a/backend/plonk/plonk.go +++ b/backend/plonk/plonk.go @@ -120,7 +120,7 @@ func Setup(ccs constraint.ConstraintSystem, kzgSRS kzg.SRS) (ProvingKey, Verifyi // Prove generates PLONK proof from a circuit, associated preprocessed public data, and the witness // if the force flag is set: // -// will executes all the prover computations, even if the witness is invalid +// will execute all the prover computations, even if the witness is invalid // will produce an invalid proof // internally, the solution vector to the SparseR1CS will be filled with random values which may impact benchmarking func Prove(ccs constraint.ConstraintSystem, pk ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (Proof, error) { diff --git a/constraint/bn254/r1cs_sparse.go b/constraint/bn254/r1cs_sparse.go index 4a9df0856e..50eab07a86 100644 --- a/constraint/bn254/r1cs_sparse.go +++ b/constraint/bn254/r1cs_sparse.go @@ -82,7 +82,7 @@ func (cs *SparseR1CS) Solve(witness fr.Vector, opt backend.ProverConfig) (fr.Vec start := time.Now() - expectedWitnessSize := int(len(cs.Public) + len(cs.Secret)) + expectedWitnessSize := len(cs.Public) + len(cs.Secret) if len(witness) != expectedWitnessSize { return make(fr.Vector, nbVariables), fmt.Errorf( "invalid witness size, got %d, expected %d = %d (public) + %d (secret)", diff --git a/constraint/r1cs_sparse.go b/constraint/r1cs_sparse.go index 4d99c82857..c65485cc03 100644 --- a/constraint/r1cs_sparse.go +++ b/constraint/r1cs_sparse.go @@ -136,6 +136,7 @@ type SparseR1C struct { L, R, O Term M [2]Term K int // stores only the ID of the constant term that is used + C int // index among commitment constraints. -1 if not a commitment. } // WireIterator implements constraint.Iterable diff --git a/examples/plonk/main.go b/examples/plonk/main.go index 36e355ccde..80aeea5eaf 100644 --- a/examples/plonk/main.go +++ b/examples/plonk/main.go @@ -80,7 +80,7 @@ func main() { // create the necessary data for KZG. // This is a toy example, normally the trusted setup to build ZKG - // has been ran before. + // has been run before. // The size of the data in KZG should be the closest power of 2 bounding // // above max(nbConstraints, nbVariables). _r1cs := ccs.(*cs.SparseR1CS) diff --git a/frontend/cs/scs/api.go b/frontend/cs/scs/api.go index 0971715911..945c746a6d 100644 --- a/frontend/cs/scs/api.go +++ b/frontend/cs/scs/api.go @@ -47,7 +47,7 @@ func (builder *scs) Add(i1, i2 frontend.Variable, in ...frontend.Variable) front cl, _ := vars[0].Unpack() kID := builder.st.CoeffID(&k) o := builder.newInternalVariable() - builder.addPlonkConstraint(vars[0], builder.zero(), o, cl, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdMinusOne, kID) + builder.addPlonkConstraint(vars[0], builder.zero(), o, cl, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdMinusOne, kID, -1) return builder.splitSum(o, vars[1:]) } @@ -144,7 +144,7 @@ func (builder *scs) DivUnchecked(i1, i2 frontend.Variable) frontend.Variable { o := builder.Neg(i1).(expr.TermToRefactor) cr, _ := r.Unpack() co, _ := o.Unpack() - builder.addPlonkConstraint(res, r, o, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdOne, cr, co, constraint.CoeffIdZero) + builder.addPlonkConstraint(res, r, o, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdOne, cr, co, constraint.CoeffIdZero, -1) return res } @@ -167,7 +167,7 @@ func (builder *scs) Inverse(i1 frontend.Variable) frontend.Variable { cr, _ := t.Unpack() debug := builder.newDebugInfo("inverse", "1/", i1, " < ∞") res := builder.newInternalVariable() - builder.addPlonkConstraint(res, t, builder.zero(), constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdOne, cr, constraint.CoeffIdZero, constraint.CoeffIdMinusOne, debug) + builder.addPlonkConstraint(res, t, builder.zero(), constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdOne, cr, constraint.CoeffIdZero, constraint.CoeffIdMinusOne, -1, debug) return res } @@ -223,12 +223,12 @@ func (builder *scs) Xor(a, b frontend.Variable) frontend.Variable { r := l oneMinusTwoB := big.NewInt(1) oneMinusTwoB.Sub(oneMinusTwoB, _b).Sub(oneMinusTwoB, _b) - builder.addPlonkConstraint(l, r, res, builder.st.CoeffID(oneMinusTwoB), constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdMinusOne, builder.st.CoeffID(_b)) + builder.addPlonkConstraint(l, r, res, builder.st.CoeffID(oneMinusTwoB), constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdMinusOne, builder.st.CoeffID(_b), -1) return res } l := a.(expr.TermToRefactor) r := b.(expr.TermToRefactor) - builder.addPlonkConstraint(l, r, res, constraint.CoeffIdMinusOne, constraint.CoeffIdMinusOne, constraint.CoeffIdTwo, constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdZero) + builder.addPlonkConstraint(l, r, res, constraint.CoeffIdMinusOne, constraint.CoeffIdMinusOne, constraint.CoeffIdTwo, constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdZero, -1) return res } @@ -260,12 +260,12 @@ func (builder *scs) Or(a, b frontend.Variable) frontend.Variable { one := big.NewInt(1) _b.Sub(_b, one) idl := builder.st.CoeffID(_b) - builder.addPlonkConstraint(l, r, res, idl, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdOne, constraint.CoeffIdZero) + builder.addPlonkConstraint(l, r, res, idl, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdOne, constraint.CoeffIdZero, -1) return res } l := a.(expr.TermToRefactor) r := b.(expr.TermToRefactor) - builder.addPlonkConstraint(l, r, res, constraint.CoeffIdMinusOne, constraint.CoeffIdMinusOne, constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdZero) + builder.addPlonkConstraint(l, r, res, constraint.CoeffIdMinusOne, constraint.CoeffIdMinusOne, constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdZero, -1) return res } @@ -391,10 +391,11 @@ func (builder *scs) IsZero(i1 frontend.Variable) frontend.Variable { constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdOne, - constraint.CoeffIdMinusOne) + constraint.CoeffIdMinusOne, + -1) // a * m = 0 // constrain m to be 0 if a != 0 - builder.addPlonkConstraint(a, m, builder.zero(), constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdZero, constraint.CoeffIdZero) + builder.addPlonkConstraint(a, m, builder.zero(), constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdZero, constraint.CoeffIdZero, -1) return m } diff --git a/frontend/cs/scs/api_assertions.go b/frontend/cs/scs/api_assertions.go index f30b177666..381d5bafb5 100644 --- a/frontend/cs/scs/api_assertions.go +++ b/frontend/cs/scs/api_assertions.go @@ -51,7 +51,7 @@ func (builder *scs) AssertIsEqual(i1, i2 frontend.Variable) { debug := builder.newDebugInfo("assertIsEqual", l, "+", i2, " == 0") k.Neg(k) _k := builder.st.CoeffID(k) - builder.addPlonkConstraint(l, builder.zero(), builder.zero(), lc, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, _k, debug) + builder.addPlonkConstraint(l, builder.zero(), builder.zero(), lc, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, _k, -1, debug) return } l := i1.(expr.TermToRefactor) @@ -60,7 +60,7 @@ func (builder *scs) AssertIsEqual(i1, i2 frontend.Variable) { rc, _ := r.Unpack() debug := builder.newDebugInfo("assertIsEqual", l, " + ", r, " == 0") - builder.addPlonkConstraint(l, r, builder.zero(), lc, rc, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, debug) + builder.addPlonkConstraint(l, r, builder.zero(), lc, rc, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, -1, debug) } // AssertIsDifferent fails if i1 == i2 @@ -87,7 +87,7 @@ func (builder *scs) AssertIsBoolean(i1 frontend.Variable) { var mCoef big.Int mCoef.Neg(&builder.st.Coeffs[cID]) mcID := builder.st.CoeffID(&mCoef) - builder.addPlonkConstraint(t, t, builder.zero(), cID, constraint.CoeffIdZero, mcID, cID, constraint.CoeffIdZero, constraint.CoeffIdZero, debug) + builder.addPlonkConstraint(t, t, builder.zero(), cID, constraint.CoeffIdZero, mcID, cID, constraint.CoeffIdZero, constraint.CoeffIdZero, -1, debug) } // AssertIsLessOrEqual fails if v > bound @@ -142,7 +142,7 @@ func (builder *scs) mustBeLessOrEqVar(a expr.TermToRefactor, bound expr.TermToRe constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdZero, - constraint.CoeffIdZero, debug) + constraint.CoeffIdZero, -1, debug) } } @@ -204,7 +204,7 @@ func (builder *scs) mustBeLessOrEqCst(a expr.TermToRefactor, bound big.Int) { constraint.CoeffIdOne, constraint.CoeffIdZero, constraint.CoeffIdZero, - debug) + -1, debug) // builder.markBoolean(aBits[i].(term)) } else { builder.AssertIsBoolean(aBits[i]) diff --git a/frontend/cs/scs/builder.go b/frontend/cs/scs/builder.go index 58d75bc03b..92f7878d64 100644 --- a/frontend/cs/scs/builder.go +++ b/frontend/cs/scs/builder.go @@ -17,6 +17,7 @@ limitations under the License. package scs import ( + "errors" "math/big" "reflect" "sort" @@ -115,7 +116,7 @@ func (builder *scs) FieldBitLen() int { // addPlonkConstraint creates a constraint of the for al+br+clr+k=0 // qL⋅xa + qR⋅xb + qO⋅xc + qM⋅(xaxb) + qC == 0 -func (builder *scs) addPlonkConstraint(xa, xb, xc expr.TermToRefactor, qL, qR, qM1, qM2, qO, qC int, debug ...constraint.DebugInfo) { +func (builder *scs) addPlonkConstraint(xa, xb, xc expr.TermToRefactor, qL, qR, qM1, qM2, qO, qC int, cIndex int, debug ...constraint.DebugInfo) { // TODO @gbotrel the signature of this function is odd.. and confusing. need refactor. // TODO @gbotrel restore debug info // if len(debugID) > 0 { @@ -139,7 +140,7 @@ func (builder *scs) addPlonkConstraint(xa, xb, xc expr.TermToRefactor, qL, qR, q V := builder.TOREFACTORMakeTerm(&builder.st.Coeffs[v.CID], v.VID) K := builder.TOREFACTORMakeTerm(&builder.st.Coeffs[qC], 0) K.MarkConstant() - builder.cs.AddConstraint(constraint.SparseR1C{L: L, R: R, O: O, M: [2]constraint.Term{U, V}, K: K.CoeffID()}, debug...) + builder.cs.AddConstraint(constraint.SparseR1C{L: L, R: R, O: O, M: [2]constraint.Term{U, V}, K: K.CoeffID(), C: cIndex}, debug...) } // newInternalVariable creates a new wire, appends it on the list of wires of the circuit, sets @@ -300,7 +301,7 @@ func (builder *scs) NewHint(f hint.Function, nbOutputs int, inputs ...frontend.V } -// returns in split into a slice of compiledTerm and the sum of all constants in in as a bigInt +// returns in split into a slice of compiledTerm and the sum of all constants in as a bigInt func (builder *scs) filterConstantSum(in []frontend.Variable) (expr.LinearExpressionToRefactor, big.Int) { res := make(expr.LinearExpressionToRefactor, 0, len(in)) var b big.Int @@ -343,7 +344,7 @@ func (builder *scs) splitSum(acc expr.TermToRefactor, r expr.LinearExpressionToR cl, _ := acc.Unpack() cr, _ := r[0].Unpack() o := builder.newInternalVariable() - builder.addPlonkConstraint(acc, r[0], o, cl, cr, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdMinusOne, constraint.CoeffIdZero) + builder.addPlonkConstraint(acc, r[0], o, cl, cr, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdMinusOne, constraint.CoeffIdZero, -1) return builder.splitSum(o, r[1:]) } @@ -357,10 +358,25 @@ func (builder *scs) splitProd(acc expr.TermToRefactor, r expr.LinearExpressionTo cl, _ := acc.Unpack() cr, _ := r[0].Unpack() o := builder.newInternalVariable() - builder.addPlonkConstraint(acc, r[0], o, constraint.CoeffIdZero, constraint.CoeffIdZero, cl, cr, constraint.CoeffIdMinusOne, constraint.CoeffIdZero) + builder.addPlonkConstraint(acc, r[0], o, constraint.CoeffIdZero, constraint.CoeffIdZero, cl, cr, constraint.CoeffIdMinusOne, constraint.CoeffIdZero, -1) return builder.splitProd(o, r[1:]) } +func scsBsb22CommitmentHintPlaceholder(*big.Int, []*big.Int, []*big.Int) error { + return errors.New("placeholder - should never be called") +} + +func (builder *scs) Commit(v ...frontend.Variable) (frontend.Variable, error) { + for i, vI := range v { // Perf-TODO: If public, hash it + builder.addPlonkConstraint(vI.(expr.TermToRefactor), builder.zero(), builder.zero(), constraint.CoeffIdOne, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, i) + } + outs, err := builder.NewHint(scsBsb22CommitmentHintPlaceholder, 1, v...) + if err != nil { + return nil, err + } + return outs[0], builder.cs.AddCommitment(constraint.Commitment{HintID: hint.UUID(scsBsb22CommitmentHintPlaceholder)}) +} + // newDebugInfo this is temporary to restore debug logs // something more like builder.sprintf("my message %le %lv", l0, l1) // to build logs for both debug and println diff --git a/internal/backend/bn254/plonk/prove.go b/internal/backend/bn254/plonk/prove.go index 0f5042889d..04e961ed04 100644 --- a/internal/backend/bn254/plonk/prove.go +++ b/internal/backend/bn254/plonk/prove.go @@ -51,6 +51,9 @@ type Proof struct { // Commitments to h1, h2, h3 such that h = h1 + Xh2 + X**2h3 is the quotient polynomial H [3]kzg.Digest + // PI2, the BSB22 commitment + PI2 kzg.Digest + // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2 BatchedProof kzg.BatchOpeningProof @@ -71,6 +74,32 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen // result proof := &Proof{} + var pi2 fr.Vector + + if id := spr.CommitmentInfo.HintID; id != 0 { + opt.HintFunctions[id] = func(_ *big.Int, ins, outs []*big.Int) error { + pi2 = make(fr.Vector, len(spr.Constraints)) //TODO: Correct? Or fft.DomainSize etc? + for i, cI := range spr.Constraints { + if cI.C != -1 { + pi2[i].SetBigInt(ins[cI.C]) + } + } + var ( + err error + hashRes []fr.Element + ) + if proof.PI2, err = kzg.Commit(pi2, pk.Vk.KZGSRS); err != nil { + return err + } + + if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + return err + } + + hashRes[0].BigInt(outs[0]) + return nil + } + } // compute the constraint system solution var solution []fr.Element diff --git a/internal/backend/bn254/plonk/setup.go b/internal/backend/bn254/plonk/setup.go index 1cefa3c469..43b6754c24 100644 --- a/internal/backend/bn254/plonk/setup.go +++ b/internal/backend/bn254/plonk/setup.go @@ -42,7 +42,8 @@ type ProvingKey struct { // TODO store iop.Polynomial here, not []fr.Element for more "type safety" // qr,ql,qm,qo (in canonical basis). - Ql, Qr, Qm, Qo []fr.Element + // QcPrime denotes the constraints defining committed variables + Ql, Qr, Qm, Qo, QcPrime []fr.Element // qr,ql,qm,qo (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. lQl, lQr, lQm, lQo []fr.Element @@ -90,7 +91,7 @@ type VerifyingKey struct { // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk kzg.Digest + Ql, Qr, Qm, Qo, Qk, QcPrime kzg.Digest } // Setup sets proving and verifying keys @@ -126,15 +127,16 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } - // public polynomials corresponding to constraints: [ placholders | constraints | assertions ] + // public polynomials corresponding to constraints: [ placeholders | constraints | assertions ] pk.Ql = make([]fr.Element, pk.Domain[0].Cardinality) pk.Qr = make([]fr.Element, pk.Domain[0].Cardinality) pk.Qm = make([]fr.Element, pk.Domain[0].Cardinality) + pk.QcPrime = make([]fr.Element, pk.Domain[0].Cardinality) pk.Qo = make([]fr.Element, pk.Domain[0].Cardinality) pk.CQk = make([]fr.Element, pk.Domain[0].Cardinality) pk.LQk = make([]fr.Element, pk.Domain[0].Cardinality) - for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistant + for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent pk.Ql[i].SetOne().Neg(&pk.Ql[i]) pk.Qr[i].SetZero() pk.Qm[i].SetZero() @@ -152,6 +154,12 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) pk.Qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) pk.CQk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) pk.LQk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) + + if spr.Constraints[i].C == -1 { + pk.QcPrime[i].SetZero() + } else { + pk.QcPrime[i].SetInt64(-1) + } } pk.Domain[0].FFTInverse(pk.Ql, fft.DIF) @@ -159,11 +167,13 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) pk.Domain[0].FFTInverse(pk.Qm, fft.DIF) pk.Domain[0].FFTInverse(pk.Qo, fft.DIF) pk.Domain[0].FFTInverse(pk.CQk, fft.DIF) + pk.Domain[0].FFTInverse(pk.QcPrime, fft.DIF) fft.BitReverse(pk.Ql) fft.BitReverse(pk.Qr) fft.BitReverse(pk.Qm) fft.BitReverse(pk.Qo) fft.BitReverse(pk.CQk) + fft.BitReverse(pk.QcPrime) // build permutation. Note: at this stage, the permutation takes in account the placeholders buildPermutation(spr, &pk) @@ -185,6 +195,9 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) if vk.Qm, err = kzg.Commit(pk.Qm, vk.KZGSRS); err != nil { return nil, nil, err } + if vk.QcPrime, err = kzg.Commit(pk.QcPrime, vk.KZGSRS); err != nil { + return nil, nil, err + } if vk.Qo, err = kzg.Commit(pk.Qo, vk.KZGSRS); err != nil { return nil, nil, err } diff --git a/test/commitments_test.go b/test/commitments_test.go new file mode 100644 index 0000000000..a1407caffc --- /dev/null +++ b/test/commitments_test.go @@ -0,0 +1,60 @@ +package test + +import ( + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/scs" + "github.com/stretchr/testify/assert" + "testing" + + "github.com/consensys/gnark/backend/plonk" + cs "github.com/consensys/gnark/constraint/bn254" +) + +type commitmentCircuit struct { + X []frontend.Variable +} + +func (c *commitmentCircuit) Define(api frontend.API) error { + commitment, err := api.Compiler().Commit(c.X...) + if err == nil { + api.AssertIsDifferent(commitment, 0) + } + return err +} + +func TestSingleCommitmentPlonkBn254(t *testing.T) { + + assignment := commitmentCircuit{[]frontend.Variable{1}} + + // // building the circuit... + ccs, err := frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, &commitmentCircuit{make([]frontend.Variable, 1)}) + assert.NoError(t, err) + + _r1cs := ccs.(*cs.SparseR1CS) + srs, err := NewKZGSRS(_r1cs) + assert.NoError(t, err) + + // Witnesses instantiation. Witness is known only by the prover, + // while public w is a public data known by the verifier. + + witnessFull, err := frontend.NewWitness(&assignment, ecc.BN254.ScalarField()) + assert.NoError(t, err) + + witnessPublic, err := frontend.NewWitness(&assignment, ecc.BN254.ScalarField(), frontend.PublicOnly()) + assert.NoError(t, err) + + // public data consists the polynomials describing the constants involved + // in the constraints, the polynomial describing the permutation ("grand + // product argument"), and the FFT domains. + pk, vk, err := plonk.Setup(ccs, srs) + //_, err := plonk.Setup(r1cs, kate, &publicWitness) + assert.NoError(t, err) + + proof, err := plonk.Prove(ccs, pk, witnessFull) + assert.NoError(t, err) + + err = plonk.Verify(proof, vk, witnessPublic) + assert.NoError(t, err) + +} From 458e39716297b58710e39dbd1b22dfba24782be6 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 28 Feb 2023 21:11:24 +0100 Subject: [PATCH 026/464] feat: add defer to the Compiler interface (#483) * refactor: remove API wrapper in test engine This was used to create API for field emulation. But we removed the fake-API interface in favor of dedicated emulated field type. * feat: add defer to compiler * fix: stop collecting traces on deferred fns * fix: make internal key type private --------- Co-authored-by: Gautam Botrel --- debug/debug.go | 3 +++ debug/symbol_table.go | 3 +++ frontend/builder.go | 5 ++++ frontend/compile.go | 13 ++++++++++ frontend/cs/r1cs/builder.go | 5 ++++ frontend/cs/r1cs/r1cs_test.go | 25 +++++++++++++++++++ frontend/cs/scs/builder.go | 5 ++++ internal/circuitdefer/defer.go | 45 ++++++++++++++++++++++++++++++++++ test/engine.go | 40 ++++++++++++++---------------- test/engine_test.go | 31 +++++++++++++++++++++++ test/solver_test.go | 20 +++++++++------ 11 files changed, 167 insertions(+), 28 deletions(-) create mode 100644 internal/circuitdefer/defer.go diff --git a/debug/debug.go b/debug/debug.go index f41bac9e83..95e1079768 100644 --- a/debug/debug.go +++ b/debug/debug.go @@ -75,5 +75,8 @@ func writeStack(sbb *strings.Builder, forceClean ...bool) { if strings.HasSuffix(function, "Define") { break } + if strings.HasSuffix(function, "callDeferred") { + break + } } } diff --git a/debug/symbol_table.go b/debug/symbol_table.go index a840aeb7ae..6ce2f68bb3 100644 --- a/debug/symbol_table.go +++ b/debug/symbol_table.go @@ -76,6 +76,9 @@ func (st *SymbolTable) CollectStack() []int { if strings.HasSuffix(function, "Define") { break } + if strings.HasSuffix(function, "callDeferred") { + break + } } return r } diff --git a/frontend/builder.go b/frontend/builder.go index 0b372ef59f..372752cf5f 100644 --- a/frontend/builder.go +++ b/frontend/builder.go @@ -48,6 +48,11 @@ type Compiler interface { // FieldBitLen returns the number of bits needed to represent an element in the scalar field FieldBitLen() int + + // Defer is called after circuit.Define() and before Compile(). This method + // allows for the circuits to register callbacks which finalize batching + // operations etc. Unlike Go defer, it is not locally scoped. + Defer(cb func(api API) error) } // Builder represents a constraint system builder diff --git a/frontend/compile.go b/frontend/compile.go index d39ff5dd7b..439b5802a5 100644 --- a/frontend/compile.go +++ b/frontend/compile.go @@ -9,6 +9,7 @@ import ( "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/debug" "github.com/consensys/gnark/frontend/schema" + "github.com/consensys/gnark/internal/circuitdefer" "github.com/consensys/gnark/logger" ) @@ -122,10 +123,22 @@ func parseCircuit(builder Builder, circuit Circuit) (err error) { if err = circuit.Define(builder); err != nil { return fmt.Errorf("define circuit: %w", err) } + if err = callDeferred(builder); err != nil { + return fmt.Errorf("") + } return } +func callDeferred(builder Builder) error { + for i, cb := range circuitdefer.GetAll[func(API) error](builder) { + if err := cb(builder); err != nil { + return fmt.Errorf("defer fn %d: %w", i, err) + } + } + return nil +} + // CompileOption defines option for altering the behaviour of the Compile // method. See the descriptions of the functions returning instances of this // type for available options. diff --git a/frontend/cs/r1cs/builder.go b/frontend/cs/r1cs/builder.go index a26b65ed0f..0165df815d 100644 --- a/frontend/cs/r1cs/builder.go +++ b/frontend/cs/r1cs/builder.go @@ -29,6 +29,7 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/internal/expr" "github.com/consensys/gnark/frontend/schema" + "github.com/consensys/gnark/internal/circuitdefer" "github.com/consensys/gnark/internal/kvstore" "github.com/consensys/gnark/internal/tinyfield" "github.com/consensys/gnark/internal/utils" @@ -453,3 +454,7 @@ func (builder *builder) compress(le expr.LinearExpression) expr.LinearExpression builder.cs.AddConstraint(builder.newR1C(le, one, t)) return t } + +func (builder *builder) Defer(cb func(frontend.API) error) { + circuitdefer.Put(builder, cb) +} diff --git a/frontend/cs/r1cs/r1cs_test.go b/frontend/cs/r1cs/r1cs_test.go index 51370f9802..b7519e8f3a 100644 --- a/frontend/cs/r1cs/r1cs_test.go +++ b/frontend/cs/r1cs/r1cs_test.go @@ -135,3 +135,28 @@ func BenchmarkReduce(b *testing.B) { } }) } + +type EmptyCircuit struct { + X frontend.Variable + cb func(frontend.API) error +} + +func (c *EmptyCircuit) Define(api frontend.API) error { + api.AssertIsEqual(c.X, 0) + api.Compiler().Defer(c.cb) + return nil +} + +func TestPreCompileHook(t *testing.T) { + var called bool + c := &EmptyCircuit{ + cb: func(a frontend.API) error { called = true; return nil }, + } + _, err := frontend.Compile(ecc.BN254.ScalarField(), NewBuilder, c) + if err != nil { + t.Fatal(err) + } + if !called { + t.Error("callback not called") + } +} diff --git a/frontend/cs/scs/builder.go b/frontend/cs/scs/builder.go index 58d75bc03b..f73452143e 100644 --- a/frontend/cs/scs/builder.go +++ b/frontend/cs/scs/builder.go @@ -28,6 +28,7 @@ import ( "github.com/consensys/gnark/frontend/cs" "github.com/consensys/gnark/frontend/internal/expr" "github.com/consensys/gnark/frontend/schema" + "github.com/consensys/gnark/internal/circuitdefer" "github.com/consensys/gnark/internal/kvstore" "github.com/consensys/gnark/internal/tinyfield" "github.com/consensys/gnark/internal/utils" @@ -387,3 +388,7 @@ func (builder *scs) newDebugInfo(errName string, in ...interface{}) constraint.D return builder.cs.NewDebugInfo(errName, in...) } + +func (builder *scs) Defer(cb func(frontend.API) error) { + circuitdefer.Put(builder, cb) +} diff --git a/internal/circuitdefer/defer.go b/internal/circuitdefer/defer.go new file mode 100644 index 0000000000..f21ac65d5e --- /dev/null +++ b/internal/circuitdefer/defer.go @@ -0,0 +1,45 @@ +package circuitdefer + +import ( + "github.com/consensys/gnark/internal/kvstore" +) + +type deferKey struct{} + +func Put[T any](builder any, cb T) { + // we use generics for type safety but to avoid import cycles. + // TODO: compare with using any and type asserting at caller + kv, ok := builder.(kvstore.Store) + if !ok { + panic("builder does not implement kvstore.Store") + } + val := kv.GetKeyValue(deferKey{}) + var deferred []T + if val == nil { + deferred = []T{cb} + } else { + var ok bool + deferred, ok = val.([]T) + if !ok { + panic("stored deferred functions not []func(frontend.API) error") + } + } + deferred = append(deferred, cb) + kv.SetKeyValue(deferKey{}, deferred) +} + +func GetAll[T any](builder any) []T { + kv, ok := builder.(kvstore.Store) + if !ok { + panic("builder does not implement kvstore.Store") + } + val := kv.GetKeyValue(deferKey{}) + if val == nil { + return nil + } + deferred, ok := val.([]T) + if !ok { + panic("stored deferred functions not []func(frontend.API) error") + } + return deferred +} diff --git a/test/engine.go b/test/engine.go index 6a515d789d..d8e5f36389 100644 --- a/test/engine.go +++ b/test/engine.go @@ -35,6 +35,7 @@ import ( "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/internal/circuitdefer" "github.com/consensys/gnark/internal/kvstore" "github.com/consensys/gnark/internal/utils" ) @@ -50,26 +51,13 @@ type engine struct { q *big.Int opt backend.ProverConfig // mHintsFunctions map[hint.ID]hintFunction - constVars bool - apiWrapper ApiWrapper + constVars bool kvstore.Store } // TestEngineOption defines an option for the test engine. type TestEngineOption func(e *engine) error -// ApiWrapper defines a function which wraps the API given to the circuit. -type ApiWrapper func(frontend.API) frontend.API - -// WithApiWrapper is a test engine option which which wraps the API before -// calling the Define method in circuit. If not set, then API is not wrapped. -func WithApiWrapper(wrapper ApiWrapper) TestEngineOption { - return func(e *engine) error { - e.apiWrapper = wrapper - return nil - } -} - // SetAllVariablesAsConstants is a test engine option which makes the calls to // IsConstant() and ConstantValue() always return true. If this test engine // option is not set, then all variables are considered as non-constant, @@ -102,11 +90,10 @@ func WithBackendProverOptions(opts ...backend.ProverOption) TestEngineOption { // This is an experimental feature. func IsSolved(circuit, witness frontend.Circuit, field *big.Int, opts ...TestEngineOption) (err error) { e := &engine{ - curveID: utils.FieldToCurve(field), - q: new(big.Int).Set(field), - apiWrapper: func(a frontend.API) frontend.API { return a }, - constVars: false, - Store: kvstore.New(), + curveID: utils.FieldToCurve(field), + q: new(big.Int).Set(field), + constVars: false, + Store: kvstore.New(), } for _, opt := range opts { if err := opt(e); err != nil { @@ -135,8 +122,15 @@ func IsSolved(circuit, witness frontend.Circuit, field *big.Int, opts ...TestEng log := logger.Logger() log.Debug().Msg("running circuit in test engine") cptAdd, cptMul, cptSub, cptToBinary, cptFromBinary, cptAssertIsEqual = 0, 0, 0, 0, 0, 0 - api := e.apiWrapper(e) - err = c.Define(api) + if err = c.Define(e); err != nil { + return fmt.Errorf("define: %w", err) + } + for i, cb := range circuitdefer.GetAll[func(frontend.API) error](e) { + if err = cb(e); err != nil { + return fmt.Errorf("defer %d: %w", i, err) + } + } + log.Debug().Uint64("add", cptAdd). Uint64("sub", cptSub). Uint64("mul", cptMul). @@ -603,3 +597,7 @@ func (e *engine) Commit(v ...frontend.Variable) (frontend.Variable, error) { res.Mod(res, e.modulus()) return res, nil } + +func (e *engine) Defer(cb func(frontend.API) error) { + circuitdefer.Put(e, cb) +} diff --git a/test/engine_test.go b/test/engine_test.go index 26b232b46e..fe91f550cf 100644 --- a/test/engine_test.go +++ b/test/engine_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/consensys/gnark" + "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/math/bits" @@ -69,3 +70,33 @@ func TestBuiltinHints(t *testing.T) { } } + +var isDeferCalled bool + +type EmptyCircuit struct { + X frontend.Variable +} + +func (c *EmptyCircuit) Define(api frontend.API) error { + api.AssertIsEqual(c.X, 0) + api.Compiler().Defer(func(api frontend.API) error { + isDeferCalled = true + return nil + }) + return nil +} + +func TestPreCompileHook(t *testing.T) { + c := &EmptyCircuit{} + w := &EmptyCircuit{ + X: 0, + } + isDeferCalled = false + err := IsSolved(c, w, ecc.BN254.ScalarField()) + if err != nil { + t.Fatal(err) + } + if !isDeferCalled { + t.Error("callback not called") + } +} diff --git a/test/solver_test.go b/test/solver_test.go index efda654193..2b9ec9de9d 100644 --- a/test/solver_test.go +++ b/test/solver_test.go @@ -18,6 +18,7 @@ import ( "github.com/consensys/gnark/frontend/cs/scs" "github.com/consensys/gnark/frontend/schema" "github.com/consensys/gnark/internal/backend/circuits" + "github.com/consensys/gnark/internal/circuitdefer" "github.com/consensys/gnark/internal/kvstore" "github.com/consensys/gnark/internal/tinyfield" "github.com/consensys/gnark/internal/utils" @@ -152,11 +153,10 @@ func (p *permutter) solveR1CS() error { // isSolvedEngine behaves like test.IsSolved except it doesn't clone the circuit func isSolvedEngine(c frontend.Circuit, field *big.Int, opts ...TestEngineOption) (err error) { e := &engine{ - curveID: utils.FieldToCurve(field), - q: new(big.Int).Set(field), - apiWrapper: func(a frontend.API) frontend.API { return a }, - constVars: false, - Store: kvstore.New(), + curveID: utils.FieldToCurve(field), + q: new(big.Int).Set(field), + constVars: false, + Store: kvstore.New(), } for _, opt := range opts { if err := opt(e); err != nil { @@ -170,8 +170,14 @@ func isSolvedEngine(c frontend.Circuit, field *big.Int, opts ...TestEngineOption } }() - api := e.apiWrapper(e) - err = c.Define(api) + if err = c.Define(e); err != nil { + return fmt.Errorf("define: %w", err) + } + for i, cb := range circuitdefer.GetAll[func(frontend.API) error](e) { + if err = cb(e); err != nil { + return fmt.Errorf("defer %d: %w", i, err) + } + } return } From 4f9bfba7bcdf753dda2c48c8148665b6455ba955 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Tue, 28 Feb 2023 14:37:50 -0600 Subject: [PATCH 027/464] refactor: plonk uses constraint/ and couple of fixes closes #467 (#493) * refactor: remove API wrapper in test engine This was used to create API for field emulation. But we removed the fake-API interface in favor of dedicated emulated field type. * feat: add defer to compiler * fix: stop collecting traces on deferred fns * fix: make internal key type private * refactor: step 1 use constraint/ simplify addPlonkConstraint a bit * refactor,perf: scs.Add(v,v,c) is better * fix: fix some scs API that incorrectly discarded boolean coeffs * style: code cleaning * fix: missing return * fix: panic when inverse by constant 0 in plonk --------- Co-authored-by: Ivo Kubjas --- debug_test.go | 2 +- frontend/cs/r1cs/builder.go | 16 +- frontend/cs/scs/api.go | 347 ++++++++++-------- frontend/cs/scs/api_assertions.go | 136 +++---- frontend/cs/scs/builder.go | 286 ++++++++------- frontend/internal/expr/linear_expression.go | 4 +- .../expr/linear_expression_scs_torefactor.go | 78 ---- frontend/variable.go | 2 - internal/stats/latest.stats | Bin 2803 -> 2803 bytes 9 files changed, 428 insertions(+), 443 deletions(-) delete mode 100644 frontend/internal/expr/linear_expression_scs_torefactor.go diff --git a/debug_test.go b/debug_test.go index d3efb39e1e..bd5b538325 100644 --- a/debug_test.go +++ b/debug_test.go @@ -131,7 +131,7 @@ func TestTraceNotEqual(t *testing.T) { { _, err := getPlonkTrace(&circuit, &witness) assert.Error(err) - assert.Contains(err.Error(), "constraint #1 is not satisfied: [assertIsEqual] 1 + -66 == 0") + assert.Contains(err.Error(), "constraint #1 is not satisfied: [assertIsEqual] 1 == 66") assert.Contains(err.Error(), "(*notEqualTrace).Define") assert.Contains(err.Error(), "debug_test.go:") } diff --git a/frontend/cs/r1cs/builder.go b/frontend/cs/r1cs/builder.go index 0165df815d..8cd5883d5d 100644 --- a/frontend/cs/r1cs/builder.go +++ b/frontend/cs/r1cs/builder.go @@ -52,22 +52,21 @@ func NewBuilder(field *big.Int, config frontend.CompileConfig) (frontend.Builder } type builder struct { - cs constraint.R1CS - + cs constraint.R1CS config frontend.CompileConfig + kvstore.Store // map for recording boolean constrained variables (to not constrain them twice) mtBooleans map[uint64][]expr.LinearExpression - q *big.Int tOne constraint.Coeff - heap minHeap // helps merge k sorted linear expressions + + // helps merge k sorted linear expressions + heap minHeap // buffers used to do in place api.MAC mbuf1 expr.LinearExpression mbuf2 expr.LinearExpression - - kvstore.Store } // initialCapacity has quite some impact on frontend performance, especially on large circuits size @@ -116,11 +115,6 @@ func newBuilder(field *big.Int, config frontend.CompileConfig) *builder { builder.tOne = builder.cs.One() builder.cs.AddPublicVariable("1") - builder.q = builder.cs.Field() - if builder.q.Cmp(field) != 0 { - panic("invalid modulus on cs impl") // sanity check - } - return &builder } diff --git a/frontend/cs/scs/api.go b/frontend/cs/scs/api.go index 0971715911..db721158a4 100644 --- a/frontend/cs/scs/api.go +++ b/frontend/cs/scs/api.go @@ -18,7 +18,6 @@ package scs import ( "fmt" - "math/big" "path/filepath" "reflect" "runtime" @@ -33,34 +32,30 @@ import ( ) // Add returns res = i1+i2+...in -func (builder *scs) Add(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { - zero := big.NewInt(0) +func (builder *builder) Add(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { + // separate the constant part from the variables vars, k := builder.filterConstantSum(append([]frontend.Variable{i1, i2}, in...)) if len(vars) == 0 { - return k + // no variables, we return the constant. + return builder.cs.ToBigInt(&k) } + vars = builder.reduce(vars) - if k.Cmp(zero) == 0 { - return builder.splitSum(vars[0], vars[1:]) + if k.IsZero() { + return builder.splitSum(vars[0], vars[1:], nil) } - cl, _ := vars[0].Unpack() - kID := builder.st.CoeffID(&k) - o := builder.newInternalVariable() - builder.addPlonkConstraint(vars[0], builder.zero(), o, cl, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdMinusOne, kID) - return builder.splitSum(o, vars[1:]) - + // no constant we decompose the linear expressions in additions of 2 terms + return builder.splitSum(vars[0], vars[1:], &k) } -func (builder *scs) MulAcc(a, b, c frontend.Variable) frontend.Variable { +func (builder *builder) MulAcc(a, b, c frontend.Variable) frontend.Variable { // TODO can we do better here to limit allocations? - // technically we could do that in one PlonK constraint (against 2 for separate Add & Mul) return builder.Add(a, builder.Mul(b, c)) } // neg returns -in -func (builder *scs) neg(in []frontend.Variable) []frontend.Variable { - +func (builder *builder) neg(in []frontend.Variable) []frontend.Variable { res := make([]frontend.Variable, len(in)) for i := 0; i < len(in); i++ { @@ -70,87 +65,72 @@ func (builder *scs) neg(in []frontend.Variable) []frontend.Variable { } // Sub returns res = i1 - i2 - ...in -func (builder *scs) Sub(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { +func (builder *builder) Sub(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { r := builder.neg(append([]frontend.Variable{i2}, in...)) return builder.Add(i1, r[0], r[1:]...) } // Neg returns -i -func (builder *scs) Neg(i1 frontend.Variable) frontend.Variable { - if n, ok := builder.ConstantValue(i1); ok { - n.Neg(n) - return *n - } else { - v := i1.(expr.TermToRefactor) - c, _ := v.Unpack() - var coef big.Int - coef.Set(&builder.st.Coeffs[c]) - coef.Neg(&coef) - c = builder.st.CoeffID(&coef) - v.SetCoeffID(c) - return v +func (builder *builder) Neg(i1 frontend.Variable) frontend.Variable { + if n, ok := builder.constantValue(i1); ok { + builder.cs.Neg(&n) + return builder.cs.ToBigInt(&n) } + v := i1.(expr.Term) + builder.cs.Neg(&v.Coeff) + return v } // Mul returns res = i1 * i2 * ... in -func (builder *scs) Mul(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { - +func (builder *builder) Mul(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { vars, k := builder.filterConstantProd(append([]frontend.Variable{i1, i2}, in...)) if len(vars) == 0 { - return k + return builder.cs.ToBigInt(&k) } l := builder.mulConstant(vars[0], &k) - return builder.splitProd(l, vars[1:]) + return builder.splitProd(l, vars[1:]) } // returns t*m -func (builder *scs) mulConstant(t expr.TermToRefactor, m *big.Int) expr.TermToRefactor { - var coef big.Int - cid, _ := t.Unpack() - coef.Set(&builder.st.Coeffs[cid]) - coef.Mul(m, &coef).Mod(&coef, builder.q) - cid = builder.st.CoeffID(&coef) - t.SetCoeffID(cid) +func (builder *builder) mulConstant(t expr.Term, m *constraint.Coeff) expr.Term { + builder.cs.Mul(&t.Coeff, m) return t } // DivUnchecked returns i1 / i2 . if i1 == i2 == 0, returns 0 -func (builder *scs) DivUnchecked(i1, i2 frontend.Variable) frontend.Variable { - c1, i1Constant := builder.ConstantValue(i1) - c2, i2Constant := builder.ConstantValue(i2) +func (builder *builder) DivUnchecked(i1, i2 frontend.Variable) frontend.Variable { + c1, i1Constant := builder.constantValue(i1) + c2, i2Constant := builder.constantValue(i2) if i1Constant && i2Constant { - l := c1 - r := c2 - q := builder.q - return r.ModInverse(r, q). - Mul(l, r). - Mod(r, q) + if c2.IsZero() { + panic("inverse by constant(0)") + } + builder.cs.Inverse(&c2) + builder.cs.Mul(&c2, &c1) + return builder.cs.ToBigInt(&c2) } if i2Constant { - c := c2 - q := builder.q - c.ModInverse(c, q) - return builder.mulConstant(i1.(expr.TermToRefactor), c) + if c2.IsZero() { + panic("inverse by constant(0)") + } + builder.cs.Inverse(&c2) + return builder.mulConstant(i1.(expr.Term), &c2) } if i1Constant { res := builder.Inverse(i2) - return builder.mulConstant(res.(expr.TermToRefactor), c1) + return builder.mulConstant(res.(expr.Term), &c1) } + // res * i2 == i1 res := builder.newInternalVariable() - r := i2.(expr.TermToRefactor) - o := builder.Neg(i1).(expr.TermToRefactor) - cr, _ := r.Unpack() - co, _ := o.Unpack() - builder.addPlonkConstraint(res, r, o, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdOne, cr, co, constraint.CoeffIdZero) + builder.addMulGate(res, i2.(expr.Term), i1.(expr.Term)) return res } // Div returns i1 / i2 -func (builder *scs) Div(i1, i2 frontend.Variable) frontend.Variable { - +func (builder *builder) Div(i1, i2 frontend.Variable) frontend.Variable { // note that here we ensure that v2 can't be 0, but it costs us one extra constraint builder.Inverse(i2) @@ -158,16 +138,25 @@ func (builder *scs) Div(i1, i2 frontend.Variable) frontend.Variable { } // Inverse returns res = 1 / i1 -func (builder *scs) Inverse(i1 frontend.Variable) frontend.Variable { - if c, ok := builder.ConstantValue(i1); ok { - c.ModInverse(c, builder.q) - return c +func (builder *builder) Inverse(i1 frontend.Variable) frontend.Variable { + if c, ok := builder.constantValue(i1); ok { + if c.IsZero() { + panic("inverse by constant(0)") + } + builder.cs.Inverse(&c) + return builder.cs.ToBigInt(&c) } - t := i1.(expr.TermToRefactor) - cr, _ := t.Unpack() + t := i1.(expr.Term) debug := builder.newDebugInfo("inverse", "1/", i1, " < ∞") res := builder.newInternalVariable() - builder.addPlonkConstraint(res, t, builder.zero(), constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdOne, cr, constraint.CoeffIdZero, constraint.CoeffIdMinusOne, debug) + + // res * i1 - 1 == 0 + builder.addPlonkConstraint(sparseR1C{ + xa: res.VID, + xb: t.VID, + qM: t.Coeff, + qC: builder.tMinusOne, + }, debug) return res } @@ -179,7 +168,7 @@ func (builder *scs) Inverse(i1 frontend.Variable) frontend.Variable { // n default value is fr.Bits the number of bits needed to represent a field element // // The result in in little endian (first bit= lsb) -func (builder *scs) ToBinary(i1 frontend.Variable, n ...int) []frontend.Variable { +func (builder *builder) ToBinary(i1 frontend.Variable, n ...int) []frontend.Variable { // nbBits nbBits := builder.cs.FieldBitLen() if len(n) == 1 { @@ -193,85 +182,158 @@ func (builder *scs) ToBinary(i1 frontend.Variable, n ...int) []frontend.Variable } // FromBinary packs b, seen as a fr.Element in little endian -func (builder *scs) FromBinary(b ...frontend.Variable) frontend.Variable { +func (builder *builder) FromBinary(b ...frontend.Variable) frontend.Variable { return bits.FromBinary(builder, b) } // Xor returns a ^ b // a and b must be 0 or 1 -func (builder *scs) Xor(a, b frontend.Variable) frontend.Variable { - +func (builder *builder) Xor(a, b frontend.Variable) frontend.Variable { + // pre condition: a, b must be booleans builder.AssertIsBoolean(a) builder.AssertIsBoolean(b) - _a, aConstant := builder.ConstantValue(a) - _b, bConstant := builder.ConstantValue(b) + _a, aConstant := builder.constantValue(a) + _b, bConstant := builder.constantValue(b) + + // if both inputs are constants if aConstant && bConstant { - _a.Xor(_a, _b) - return _a + b0 := 0 + b1 := 0 + if builder.cs.IsOne(&_a) { + b0 = 1 + } + if builder.cs.IsOne(&_b) { + b1 = 1 + } + return b0 ^ b1 } res := builder.newInternalVariable() builder.MarkBoolean(res) + + // if one input is constant, ensure we put it in b. if aConstant { a, b = b, a bConstant = aConstant _b = _a } if bConstant { - l := a.(expr.TermToRefactor) - r := l - oneMinusTwoB := big.NewInt(1) - oneMinusTwoB.Sub(oneMinusTwoB, _b).Sub(oneMinusTwoB, _b) - builder.addPlonkConstraint(l, r, res, builder.st.CoeffID(oneMinusTwoB), constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdMinusOne, builder.st.CoeffID(_b)) + xa := a.(expr.Term) + // 1 - 2b + qL := builder.tOne + builder.cs.Sub(&qL, &_b) + builder.cs.Sub(&qL, &_b) + builder.cs.Mul(&qL, &xa.Coeff) + + // (1-2b)a + b == res + builder.addPlonkConstraint(sparseR1C{ + xa: xa.VID, + xc: res.VID, + qL: qL, + qO: builder.tMinusOne, + qC: _b, + }) + // builder.addPlonkConstraint(xa, xb, res, builder.st.CoeffID(oneMinusTwoB), constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdMinusOne, builder.st.CoeffID(_b)) return res } - l := a.(expr.TermToRefactor) - r := b.(expr.TermToRefactor) - builder.addPlonkConstraint(l, r, res, constraint.CoeffIdMinusOne, constraint.CoeffIdMinusOne, constraint.CoeffIdTwo, constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdZero) + xa := a.(expr.Term) + xb := b.(expr.Term) + + // -a - b + 2ab + res == 0 + qM := builder.tOne + builder.cs.Add(&qM, &qM) + builder.cs.Mul(&qM, &xa.Coeff) + builder.cs.Mul(&qM, &xb.Coeff) + + qL := xa.Coeff + qR := xb.Coeff + + builder.cs.Neg(&qL) + builder.cs.Neg(&qR) + + builder.addPlonkConstraint(sparseR1C{ + xa: xa.VID, + xb: xb.VID, + xc: res.VID, + qL: qL, + qR: qR, + qO: builder.tOne, + qM: qM, + }) + // builder.addPlonkConstraint(xa, xb, res, constraint.CoeffIdMinusOne, constraint.CoeffIdMinusOne, constraint.CoeffIdTwo, constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdZero) return res } // Or returns a | b // a and b must be 0 or 1 -func (builder *scs) Or(a, b frontend.Variable) frontend.Variable { - +func (builder *builder) Or(a, b frontend.Variable) frontend.Variable { builder.AssertIsBoolean(a) builder.AssertIsBoolean(b) - _a, aConstant := builder.ConstantValue(a) - _b, bConstant := builder.ConstantValue(b) + _a, aConstant := builder.constantValue(a) + _b, bConstant := builder.constantValue(b) if aConstant && bConstant { - _a.Or(_a, _b) - return _a + if builder.cs.IsOne(&_a) || builder.cs.IsOne(&_b) { + return 1 + } + return 0 } + res := builder.newInternalVariable() builder.MarkBoolean(res) + + // if one input is constant, ensure we put it in b if aConstant { a, b = b, a _b = _a bConstant = aConstant } - if bConstant { - l := a.(expr.TermToRefactor) - r := l - one := big.NewInt(1) - _b.Sub(_b, one) - idl := builder.st.CoeffID(_b) - builder.addPlonkConstraint(l, r, res, idl, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdOne, constraint.CoeffIdZero) + if bConstant { + xa := a.(expr.Term) + // b = b - 1 + qL := _b + builder.cs.Sub(&qL, &builder.tOne) + builder.cs.Mul(&qL, &xa.Coeff) + // a * (b-1) + res == 0 + builder.addPlonkConstraint(sparseR1C{ + xa: xa.VID, + xc: res.VID, + qL: qL, + qO: builder.tOne, + }) return res } - l := a.(expr.TermToRefactor) - r := b.(expr.TermToRefactor) - builder.addPlonkConstraint(l, r, res, constraint.CoeffIdMinusOne, constraint.CoeffIdMinusOne, constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdZero) + xa := a.(expr.Term) + xb := b.(expr.Term) + // -a - b + ab + res == 0 + + qM := xa.Coeff + builder.cs.Mul(&qM, &xb.Coeff) + + qL := xa.Coeff + qR := xb.Coeff + + builder.cs.Neg(&qL) + builder.cs.Neg(&qR) + + builder.addPlonkConstraint(sparseR1C{ + xa: xa.VID, + xb: xb.VID, + xc: res.VID, + qL: qL, + qR: qR, + qM: qM, + qO: builder.tOne, + }) return res } // Or returns a & b // a and b must be 0 or 1 -func (builder *scs) And(a, b frontend.Variable) frontend.Variable { +func (builder *builder) And(a, b frontend.Variable) frontend.Variable { builder.AssertIsBoolean(a) builder.AssertIsBoolean(b) res := builder.Mul(a, b) @@ -283,14 +345,14 @@ func (builder *scs) And(a, b frontend.Variable) frontend.Variable { // Conditionals // Select if b is true, yields i1 else yields i2 -func (builder *scs) Select(b frontend.Variable, i1, i2 frontend.Variable) frontend.Variable { - _b, bConstant := builder.ConstantValue(b) +func (builder *builder) Select(b frontend.Variable, i1, i2 frontend.Variable) frontend.Variable { + _b, bConstant := builder.constantValue(b) if bConstant { - if !(_b.IsUint64() && (_b.Uint64() <= 1)) { - panic(fmt.Sprintf("%s should be 0 or 1", _b.String())) + if !builder.IsBoolean(b) { + panic(fmt.Sprintf("%s should be 0 or 1", builder.cs.String(&_b))) } - if _b.Uint64() == 0 { + if _b.IsZero() { return i2 } return i1 @@ -305,23 +367,18 @@ func (builder *scs) Select(b frontend.Variable, i1, i2 frontend.Variable) fronte // Lookup2 performs a 2-bit lookup between i1, i2, i3, i4 based on bits b0 // and b1. Returns i0 if b0=b1=0, i1 if b0=1 and b1=0, i2 if b0=0 and b1=1 // and i3 if b0=b1=1. -func (builder *scs) Lookup2(b0, b1 frontend.Variable, i0, i1, i2, i3 frontend.Variable) frontend.Variable { - - // vars, _ := builder.toVariables(b0, b1, i0, i1, i2, i3) - // s0, s1 := vars[0], vars[1] - // in0, in1, in2, in3 := vars[2], vars[3], vars[4], vars[5] - +func (builder *builder) Lookup2(b0, b1 frontend.Variable, i0, i1, i2, i3 frontend.Variable) frontend.Variable { // ensure that bits are actually bits. Adds no constraints if the variables // are already constrained. builder.AssertIsBoolean(b0) builder.AssertIsBoolean(b1) - c0, b0IsConstant := builder.ConstantValue(b0) - c1, b1IsConstant := builder.ConstantValue(b1) + c0, b0IsConstant := builder.constantValue(b0) + c1, b1IsConstant := builder.constantValue(b1) if b0IsConstant && b1IsConstant { - b0 := c0.Uint64() == 1 - b1 := c1.Uint64() == 1 + b0 := builder.cs.IsOne(&c0) + b1 := builder.cs.IsOne(&c1) if !b0 && !b1 { return i0 @@ -360,18 +417,18 @@ func (builder *scs) Lookup2(b0, b1 frontend.Variable, i0, i1, i2, i3 frontend.Va } // IsZero returns 1 if a is zero, 0 otherwise -func (builder *scs) IsZero(i1 frontend.Variable) frontend.Variable { - if a, ok := builder.ConstantValue(i1); ok { - if !(a.IsUint64() && a.Uint64() == 0) { - return 0 +func (builder *builder) IsZero(i1 frontend.Variable) frontend.Variable { + if a, ok := builder.constantValue(i1); ok { + if a.IsZero() { + return 1 } - return 1 + return 0 } // x = 1/a // in a hint (x == 0 if a == 0) // m = -a*x + 1 // constrain m to be 1 if a == 0 // a * m = 0 // constrain m to be 0 if a != 0 - a := i1.(expr.TermToRefactor) + a := i1.(expr.Term) m := builder.newInternalVariable() // x = 1/a // in a hint (x == 0 if a == 0) @@ -383,24 +440,28 @@ func (builder *scs) IsZero(i1 frontend.Variable) frontend.Variable { // m = -a*x + 1 // constrain m to be 1 if a == 0 // a*x + m - 1 == 0 - builder.addPlonkConstraint(a, - x[0].(expr.TermToRefactor), - m, - constraint.CoeffIdZero, - constraint.CoeffIdZero, - constraint.CoeffIdOne, - constraint.CoeffIdOne, - constraint.CoeffIdOne, - constraint.CoeffIdMinusOne) + X := x[0].(expr.Term) + builder.addPlonkConstraint(sparseR1C{ + xa: a.VID, + xb: X.VID, + xc: m.VID, + qM: a.Coeff, + qO: builder.tOne, + qC: builder.tMinusOne, + }) // a * m = 0 // constrain m to be 0 if a != 0 - builder.addPlonkConstraint(a, m, builder.zero(), constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdZero, constraint.CoeffIdZero) + builder.addPlonkConstraint(sparseR1C{ + xa: a.VID, + xb: m.VID, + qM: a.Coeff, + }) return m } // Cmp returns 1 if i1>i2, 0 if i1=i2, -1 if i1= 0; i-- { - iszeroi1 := builder.IsZero(bi1[i]) iszeroi2 := builder.IsZero(bi2[i]) @@ -420,7 +480,6 @@ func (builder *scs) Cmp(i1, i2 frontend.Variable) frontend.Variable { m := builder.Select(i1i2, 1, n) res = builder.Select(builder.IsZero(res), m, res) - } return res } @@ -431,8 +490,8 @@ func (builder *scs) Cmp(i1, i2 frontend.Variable) frontend.Variable { // // the print will be done once the R1CS.Solve() method is executed // -// if one of the input is a variable, its value will be resolved avec R1CS.Solve() method is called -func (builder *scs) Println(a ...frontend.Variable) { +// if one of the input is a variable, its value will be resolved when R1CS.Solve() method is called +func (builder *builder) Println(a ...frontend.Variable) { var log constraint.LogEntry // prefix log line with file.go:line @@ -446,12 +505,12 @@ func (builder *scs) Println(a ...frontend.Variable) { if i > 0 { sbb.WriteByte(' ') } - if v, ok := arg.(expr.TermToRefactor); ok { + if v, ok := arg.(expr.Term); ok { sbb.WriteString("%s") // we set limits to the linear expression, so that the log printer // can evaluate it before printing it - log.ToResolve = append(log.ToResolve, constraint.LinearExpression{builder.TOREFACTORMakeTerm(&builder.st.Coeffs[v.CID], v.VID)}) + log.ToResolve = append(log.ToResolve, constraint.LinearExpression{builder.cs.MakeTerm(&v.Coeff, v.VID)}) } else { builder.printArg(&log, &sbb, arg) } @@ -463,7 +522,7 @@ func (builder *scs) Println(a ...frontend.Variable) { builder.cs.AddLog(log) } -func (builder *scs) printArg(log *constraint.LogEntry, sbb *strings.Builder, a frontend.Variable) { +func (builder *builder) printArg(log *constraint.LogEntry, sbb *strings.Builder, a frontend.Variable) { leafCount, err := schema.Walk(a, tVariable, nil) count := leafCount.Public + leafCount.Secret @@ -484,10 +543,10 @@ func (builder *scs) printArg(log *constraint.LogEntry, sbb *strings.Builder, a f sbb.WriteString(", ") } - v := tValue.Interface().(expr.TermToRefactor) + v := tValue.Interface().(expr.Term) // we set limits to the linear expression, so that the log printer // can evaluate it before printing it - log.ToResolve = append(log.ToResolve, constraint.LinearExpression{builder.TOREFACTORMakeTerm(&builder.st.Coeffs[v.CID], v.VID)}) + log.ToResolve = append(log.ToResolve, constraint.LinearExpression{builder.cs.MakeTerm(&v.Coeff, v.VID)}) return nil } // ignoring error, printer() doesn't return errors @@ -495,6 +554,6 @@ func (builder *scs) printArg(log *constraint.LogEntry, sbb *strings.Builder, a f sbb.WriteByte('}') } -func (builder *scs) Compiler() frontend.Compiler { +func (builder *builder) Compiler() frontend.Compiler { return builder } diff --git a/frontend/cs/scs/api_assertions.go b/frontend/cs/scs/api_assertions.go index f30b177666..976a60f1ab 100644 --- a/frontend/cs/scs/api_assertions.go +++ b/frontend/cs/scs/api_assertions.go @@ -20,7 +20,6 @@ import ( "fmt" "math/big" - "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/internal/expr" "github.com/consensys/gnark/internal/utils" @@ -28,13 +27,13 @@ import ( ) // AssertIsEqual fails if i1 != i2 -func (builder *scs) AssertIsEqual(i1, i2 frontend.Variable) { +func (builder *builder) AssertIsEqual(i1, i2 frontend.Variable) { - c1, i1Constant := builder.ConstantValue(i1) - c2, i2Constant := builder.ConstantValue(i2) + c1, i1Constant := builder.constantValue(i1) + c2, i2Constant := builder.constantValue(i2) if i1Constant && i2Constant { - if c1.Cmp(c2) != 0 { + if c1 != c2 { panic("i1, i2 should be equal") } return @@ -45,62 +44,79 @@ func (builder *scs) AssertIsEqual(i1, i2 frontend.Variable) { c2 = c1 } if i2Constant { - l := i1.(expr.TermToRefactor) - lc, _ := l.Unpack() - k := c2 - debug := builder.newDebugInfo("assertIsEqual", l, "+", i2, " == 0") - k.Neg(k) - _k := builder.st.CoeffID(k) - builder.addPlonkConstraint(l, builder.zero(), builder.zero(), lc, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, _k, debug) + xa := i1.(expr.Term) + builder.cs.Neg(&c2) + debug := builder.newDebugInfo("assertIsEqual", xa, "==", i2) + + // xa - i2 == 0 + builder.addPlonkConstraint(sparseR1C{ + xa: xa.VID, + qL: xa.Coeff, + qC: c2, + }, debug) return } - l := i1.(expr.TermToRefactor) - r := builder.Neg(i2).(expr.TermToRefactor) - lc, _ := l.Unpack() - rc, _ := r.Unpack() - - debug := builder.newDebugInfo("assertIsEqual", l, " + ", r, " == 0") - builder.addPlonkConstraint(l, r, builder.zero(), lc, rc, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, debug) + xa := i1.(expr.Term) + xb := i2.(expr.Term) + + debug := builder.newDebugInfo("assertIsEqual", xa, " == ", xb) + + builder.cs.Neg(&xb.Coeff) + // xa - xb == 0 + builder.addPlonkConstraint(sparseR1C{ + xa: xa.VID, + xb: xb.VID, + qL: xa.Coeff, + qR: xb.Coeff, + }, debug) } // AssertIsDifferent fails if i1 == i2 -func (builder *scs) AssertIsDifferent(i1, i2 frontend.Variable) { +func (builder *builder) AssertIsDifferent(i1, i2 frontend.Variable) { builder.Inverse(builder.Sub(i1, i2)) } // AssertIsBoolean fails if v != 0 ∥ v != 1 -func (builder *scs) AssertIsBoolean(i1 frontend.Variable) { - if c, ok := builder.ConstantValue(i1); ok { - if !(c.IsUint64() && (c.Uint64() == 0 || c.Uint64() == 1)) { - panic(fmt.Sprintf("assertIsBoolean failed: constant(%s)", c.String())) +func (builder *builder) AssertIsBoolean(i1 frontend.Variable) { + if c, ok := builder.constantValue(i1); ok { + if !(c.IsZero() || builder.cs.IsOne(&c)) { + panic(fmt.Sprintf("assertIsBoolean failed: constant(%s)", builder.cs.String(&c))) } return } - t := i1.(expr.TermToRefactor) - if builder.IsBoolean(t) { + + v := i1.(expr.Term) + if builder.IsBoolean(v) { return } - builder.MarkBoolean(t) - builder.mtBooleans[int(t.CID)|t.VID<<32] = struct{}{} // TODO @gbotrel smelly fix me - debug := builder.newDebugInfo("assertIsBoolean", t, " == (0|1)") - cID, _ := t.Unpack() - var mCoef big.Int - mCoef.Neg(&builder.st.Coeffs[cID]) - mcID := builder.st.CoeffID(&mCoef) - builder.addPlonkConstraint(t, t, builder.zero(), cID, constraint.CoeffIdZero, mcID, cID, constraint.CoeffIdZero, constraint.CoeffIdZero, debug) + builder.MarkBoolean(v) + debug := builder.newDebugInfo("assertIsBoolean", v, " == (0|1)") + + // ensure v * (1 - v) == 0 + // that is v + -v*v == 0 + // qM = -v.Coeff*v.Coeff + qM := v.Coeff + builder.cs.Neg(&qM) + builder.cs.Mul(&qM, &v.Coeff) + builder.addPlonkConstraint(sparseR1C{ + xa: v.VID, + xb: v.VID, + qL: v.Coeff, + qM: qM, + }, debug) } // AssertIsLessOrEqual fails if v > bound -func (builder *scs) AssertIsLessOrEqual(v frontend.Variable, bound frontend.Variable) { +func (builder *builder) AssertIsLessOrEqual(v frontend.Variable, bound frontend.Variable) { switch b := bound.(type) { - case expr.TermToRefactor: - builder.mustBeLessOrEqVar(v.(expr.TermToRefactor), b) + case expr.Term: + builder.mustBeLessOrEqVar(v.(expr.Term), b) default: - builder.mustBeLessOrEqCst(v.(expr.TermToRefactor), utils.FromInterface(b)) + builder.mustBeLessOrEqCst(v.(expr.Term), utils.FromInterface(b)) } } -func (builder *scs) mustBeLessOrEqVar(a expr.TermToRefactor, bound expr.TermToRefactor) { +func (builder *builder) mustBeLessOrEqVar(a expr.Term, bound expr.Term) { debug := builder.newDebugInfo("mustBeLessOrEq", a, " <= ", bound) @@ -126,28 +142,23 @@ func (builder *scs) mustBeLessOrEqVar(a expr.TermToRefactor, bound expr.TermToRe t := builder.Select(boundBits[i], 0, p[i+1]) // (1 - t - ai) * ai == 0 - l := builder.Sub(1, t, aBits[i]) + l := builder.Sub(1, t, aBits[i]).(expr.Term) // note if bound[i] == 1, this constraint is (1 - ai) * ai == 0 // → this is a boolean constraint // if bound[i] == 0, t must be 0 or 1, thus ai must be 0 or 1 too - builder.MarkBoolean(aBits[i].(expr.TermToRefactor)) // this does not create a constraint - - builder.addPlonkConstraint( - l.(expr.TermToRefactor), - aBits[i].(expr.TermToRefactor), - builder.zero(), - constraint.CoeffIdZero, - constraint.CoeffIdZero, - constraint.CoeffIdOne, - constraint.CoeffIdOne, - constraint.CoeffIdZero, - constraint.CoeffIdZero, debug) + builder.MarkBoolean(aBits[i].(expr.Term)) // this does not create a constraint + + builder.addPlonkConstraint(sparseR1C{ + xa: l.VID, + xb: aBits[i].(expr.Term).VID, + qM: l.Coeff, + }, debug) } } -func (builder *scs) mustBeLessOrEqCst(a expr.TermToRefactor, bound big.Int) { +func (builder *builder) mustBeLessOrEqCst(a expr.Term, bound big.Int) { nbBits := builder.cs.FieldBitLen() @@ -191,21 +202,14 @@ func (builder *scs) mustBeLessOrEqCst(a expr.TermToRefactor, bound big.Int) { if bound.Bit(i) == 0 { // (1 - p(i+1) - ai) * ai == 0 - l := builder.Sub(1, p[i+1], aBits[i]).(expr.TermToRefactor) + l := builder.Sub(1, p[i+1], aBits[i]).(expr.Term) //l = builder.Sub(l, ).(term) - builder.addPlonkConstraint( - l, - aBits[i].(expr.TermToRefactor), - builder.zero(), - constraint.CoeffIdZero, - constraint.CoeffIdZero, - constraint.CoeffIdOne, - constraint.CoeffIdOne, - constraint.CoeffIdZero, - constraint.CoeffIdZero, - debug) - // builder.markBoolean(aBits[i].(term)) + builder.addPlonkConstraint(sparseR1C{ + xa: l.VID, + xb: aBits[i].(expr.Term).VID, + qM: builder.tOne, + }, debug) } else { builder.AssertIsBoolean(aBits[i]) } diff --git a/frontend/cs/scs/builder.go b/frontend/cs/scs/builder.go index f73452143e..5a9159ce24 100644 --- a/frontend/cs/scs/builder.go +++ b/frontend/cs/scs/builder.go @@ -25,7 +25,6 @@ import ( "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/frontend/cs" "github.com/consensys/gnark/frontend/internal/expr" "github.com/consensys/gnark/frontend/schema" "github.com/consensys/gnark/internal/circuitdefer" @@ -48,27 +47,23 @@ func NewBuilder(field *big.Int, config frontend.CompileConfig) (frontend.Builder return newBuilder(field, config), nil } -type scs struct { - cs constraint.SparseR1CS - - st cs.CoeffTable +type builder struct { + cs constraint.SparseR1CS config frontend.CompileConfig + kvstore.Store // map for recording boolean constrained variables (to not constrain them twice) - mtBooleans map[int]struct{} - - q *big.Int + mtBooleans map[expr.Term]struct{} - kvstore.Store + // frequently used coefficients + tOne, tMinusOne constraint.Coeff } // initialCapacity has quite some impact on frontend performance, especially on large circuits size // we may want to add build tags to tune that -// TODO @gbotrel restore capacity option! -func newBuilder(field *big.Int, config frontend.CompileConfig) *scs { - builder := scs{ - mtBooleans: make(map[int]struct{}), - st: cs.NewCoeffTable(), +func newBuilder(field *big.Int, config frontend.CompileConfig) *builder { + b := builder{ + mtBooleans: make(map[expr.Term]struct{}), config: config, Store: kvstore.New(), } @@ -77,109 +72,112 @@ func newBuilder(field *big.Int, config frontend.CompileConfig) *scs { switch curve { case ecc.BLS12_377: - builder.cs = bls12377r1cs.NewSparseR1CS(config.Capacity) + b.cs = bls12377r1cs.NewSparseR1CS(config.Capacity) case ecc.BLS12_381: - builder.cs = bls12381r1cs.NewSparseR1CS(config.Capacity) + b.cs = bls12381r1cs.NewSparseR1CS(config.Capacity) case ecc.BN254: - builder.cs = bn254r1cs.NewSparseR1CS(config.Capacity) + b.cs = bn254r1cs.NewSparseR1CS(config.Capacity) case ecc.BW6_761: - builder.cs = bw6761r1cs.NewSparseR1CS(config.Capacity) + b.cs = bw6761r1cs.NewSparseR1CS(config.Capacity) case ecc.BW6_633: - builder.cs = bw6633r1cs.NewSparseR1CS(config.Capacity) + b.cs = bw6633r1cs.NewSparseR1CS(config.Capacity) case ecc.BLS24_315: - builder.cs = bls24315r1cs.NewSparseR1CS(config.Capacity) + b.cs = bls24315r1cs.NewSparseR1CS(config.Capacity) case ecc.BLS24_317: - builder.cs = bls24317r1cs.NewSparseR1CS(config.Capacity) + b.cs = bls24317r1cs.NewSparseR1CS(config.Capacity) default: if field.Cmp(tinyfield.Modulus()) == 0 { - builder.cs = tinyfieldr1cs.NewSparseR1CS(config.Capacity) + b.cs = tinyfieldr1cs.NewSparseR1CS(config.Capacity) break } - panic("not implemtented") + panic("not implemented") } - builder.q = builder.cs.Field() - if builder.q.Cmp(field) != 0 { - panic("invalid modulus on cs impl") // sanity check - } + b.tOne = b.cs.One() + b.tMinusOne = b.cs.FromInterface(-1) - return &builder + return &b } -func (builder *scs) Field() *big.Int { +func (builder *builder) Field() *big.Int { return builder.cs.Field() } -func (builder *scs) FieldBitLen() int { +func (builder *builder) FieldBitLen() int { return builder.cs.FieldBitLen() } -// addPlonkConstraint creates a constraint of the for al+br+clr+k=0 +// TODO @gbotrel doing a 2-step refactoring for now, frontend only. need to update constraint/SparseR1C. // qL⋅xa + qR⋅xb + qO⋅xc + qM⋅(xaxb) + qC == 0 -func (builder *scs) addPlonkConstraint(xa, xb, xc expr.TermToRefactor, qL, qR, qM1, qM2, qO, qC int, debug ...constraint.DebugInfo) { - // TODO @gbotrel the signature of this function is odd.. and confusing. need refactor. - // TODO @gbotrel restore debug info - // if len(debugID) > 0 { - // builder.MDebug[len(builder.Constraints)] = debugID[0] - // } else if debug.Debug { - // builder.MDebug[len(builder.Constraints)] = constraint.NewDebugInfo("") - // } - - xa.SetCoeffID(qL) - xb.SetCoeffID(qR) - xc.SetCoeffID(qO) - - u := xa - v := xb - u.SetCoeffID(qM1) - v.SetCoeffID(qM2) - L := builder.TOREFACTORMakeTerm(&builder.st.Coeffs[xa.CID], xa.VID) - R := builder.TOREFACTORMakeTerm(&builder.st.Coeffs[xb.CID], xb.VID) - O := builder.TOREFACTORMakeTerm(&builder.st.Coeffs[xc.CID], xc.VID) - U := builder.TOREFACTORMakeTerm(&builder.st.Coeffs[u.CID], u.VID) - V := builder.TOREFACTORMakeTerm(&builder.st.Coeffs[v.CID], v.VID) - K := builder.TOREFACTORMakeTerm(&builder.st.Coeffs[qC], 0) +type sparseR1C struct { + xa, xb, xc int // wires + qL, qR, qO, qM, qC constraint.Coeff // coefficients +} + +// a * b == c +func (builder *builder) addMulGate(a, b, c expr.Term, debug ...constraint.DebugInfo) { + qO := builder.tMinusOne + if c.Coeff != builder.tOne { + // slow path + t := c.Coeff + builder.cs.Neg(&t) + qO = t + } + qM := a.Coeff + builder.cs.Mul(&qM, &b.Coeff) + builder.addPlonkConstraint(sparseR1C{ + xa: a.VID, + xb: b.VID, + xc: c.VID, + qM: qM, + qO: qO, + }, debug...) +} + +// addPlonkConstraint adds a sparseR1C to the underlying constraint system +func (builder *builder) addPlonkConstraint(c sparseR1C, debug ...constraint.DebugInfo) { + L := builder.cs.MakeTerm(&c.qL, c.xa) + R := builder.cs.MakeTerm(&c.qR, c.xb) + O := builder.cs.MakeTerm(&c.qO, c.xc) + U := builder.cs.MakeTerm(&c.qM, c.xa) + V := builder.cs.MakeTerm(&builder.tOne, c.xb) + K := builder.cs.MakeTerm(&c.qC, 0) K.MarkConstant() builder.cs.AddConstraint(constraint.SparseR1C{L: L, R: R, O: O, M: [2]constraint.Term{U, V}, K: K.CoeffID()}, debug...) } // newInternalVariable creates a new wire, appends it on the list of wires of the circuit, sets // the wire's id to the number of wires, and returns it -func (builder *scs) newInternalVariable() expr.TermToRefactor { +func (builder *builder) newInternalVariable() expr.Term { idx := builder.cs.AddInternalVariable() - return expr.NewTermToRefactor(idx, constraint.CoeffIdOne) + return expr.NewTerm(idx, builder.tOne) } // PublicVariable creates a new Public Variable -func (builder *scs) PublicVariable(f schema.LeafInfo) frontend.Variable { +func (builder *builder) PublicVariable(f schema.LeafInfo) frontend.Variable { idx := builder.cs.AddPublicVariable(f.FullName()) - return expr.NewTermToRefactor(idx, constraint.CoeffIdOne) + return expr.NewTerm(idx, builder.tOne) } // SecretVariable creates a new Secret Variable -func (builder *scs) SecretVariable(f schema.LeafInfo) frontend.Variable { +func (builder *builder) SecretVariable(f schema.LeafInfo) frontend.Variable { idx := builder.cs.AddSecretVariable(f.FullName()) - return expr.NewTermToRefactor(idx, constraint.CoeffIdOne) + return expr.NewTerm(idx, builder.tOne) } // reduces redundancy in linear expression // It factorizes Variable that appears multiple times with != coeff Ids // To ensure the determinism in the compile process, Variables are stored as public∥secret∥internal∥unset // for each visibility, the Variables are sorted from lowest ID to highest ID -func (builder *scs) reduce(l expr.LinearExpressionToRefactor) expr.LinearExpressionToRefactor { +func (builder *builder) reduce(l expr.LinearExpression) expr.LinearExpression { // ensure our linear expression is sorted, by visibility and by Variable ID sort.Sort(l) - c := new(big.Int) for i := 1; i < len(l); i++ { - pcID, pvID := l[i-1].Unpack() - ccID, cvID := l[i].Unpack() - if pvID == cvID { + if l[i-1].VID == l[i].VID { // we have redundancy - c.Add(&builder.st.Coeffs[pcID], &builder.st.Coeffs[ccID]) - c.Mod(c, builder.q) - l[i-1].SetCoeffID(builder.st.CoeffID(c)) + builder.cs.Add(&l[i-1].Coeff, &l[i].Coeff) l = append(l[:i], l[i+1:]...) i-- } @@ -187,34 +185,28 @@ func (builder *scs) reduce(l expr.LinearExpressionToRefactor) expr.LinearExpress return l } -// to handle wires that don't exist (=coef 0) in a sparse constraint -func (builder *scs) zero() expr.TermToRefactor { - var a expr.TermToRefactor - return a -} - // IsBoolean returns true if given variable was marked as boolean in the compiler (see MarkBoolean) // Use with care; variable may not have been **constrained** to be boolean // This returns true if the v is a constant and v == 0 || v == 1. -func (builder *scs) IsBoolean(v frontend.Variable) bool { - if b, ok := builder.ConstantValue(v); ok { - return b.IsUint64() && b.Uint64() <= 1 +func (builder *builder) IsBoolean(v frontend.Variable) bool { + if b, ok := builder.constantValue(v); ok { + return (b.IsZero() || builder.cs.IsOne(&b)) } - _, ok := builder.mtBooleans[int(v.(expr.TermToRefactor).CID|(int(v.(expr.TermToRefactor).VID)<<32))] // TODO @gbotrel fixme this is sketchy + _, ok := builder.mtBooleans[v.(expr.Term)] return ok } // MarkBoolean sets (but do not constraint!) v to be boolean // This is useful in scenarios where a variable is known to be boolean through a constraint // that is not api.AssertIsBoolean. If v is a constant, this is a no-op. -func (builder *scs) MarkBoolean(v frontend.Variable) { - if b, ok := builder.ConstantValue(v); ok { - if !(b.IsUint64() && b.Uint64() <= 1) { +func (builder *builder) MarkBoolean(v frontend.Variable) { + if _, ok := builder.constantValue(v); ok { + if !builder.IsBoolean(v) { panic("MarkBoolean called a non-boolean constant") } return } - builder.mtBooleans[int(v.(expr.TermToRefactor).CID|(int(v.(expr.TermToRefactor).VID)<<32))] = struct{}{} // TODO @gbotrel fixme this is sketchy + builder.mtBooleans[v.(expr.Term)] = struct{}{} } var tVariable reflect.Type @@ -223,7 +215,7 @@ func init() { tVariable = reflect.ValueOf(struct{ A frontend.Variable }{}).FieldByName("A").Type() } -func (builder *scs) Compile() (constraint.ConstraintSystem, error) { +func (builder *builder) Compile() (constraint.ConstraintSystem, error) { log := logger.Logger() log.Info(). Int("nbConstraints", builder.cs.GetNbConstraints()). @@ -241,21 +233,21 @@ func (builder *scs) Compile() (constraint.ConstraintSystem, error) { return builder.cs, nil } -// ConstantValue returns the big.Int value of v. It -// panics if v.IsConstant() == false -func (builder *scs) ConstantValue(v frontend.Variable) (*big.Int, bool) { - switch t := v.(type) { - case expr.TermToRefactor: +// ConstantValue returns the big.Int value of v. +// Will panic if v.IsConstant() == false +func (builder *builder) ConstantValue(v frontend.Variable) (*big.Int, bool) { + coeff, ok := builder.constantValue(v) + if !ok { return nil, false - default: - res := utils.FromInterface(t) - return &res, true } + return builder.cs.ToBigInt(&coeff), true } -func (builder *scs) TOREFACTORMakeTerm(c *big.Int, vID int) constraint.Term { - cc := builder.cs.FromInterface(c) - return builder.cs.MakeTerm(&cc, vID) +func (builder *builder) constantValue(v frontend.Variable) (constraint.Coeff, bool) { + if _, ok := v.(expr.Term); ok { + return constraint.Coeff{}, false + } + return builder.cs.FromInterface(v), true } // NewHint initializes internal variables whose value will be evaluated using @@ -270,18 +262,17 @@ func (builder *scs) TOREFACTORMakeTerm(c *big.Int, vID int) constraint.Term { // // No new constraints are added to the newly created wire and must be added // manually in the circuit. Failing to do so leads to solver failure. -func (builder *scs) NewHint(f hint.Function, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { - +func (builder *builder) NewHint(f hint.Function, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { hintInputs := make([]constraint.LinearExpression, len(inputs)) // ensure inputs are set and pack them in a []uint64 for i, in := range inputs { switch t := in.(type) { - case expr.TermToRefactor: - hintInputs[i] = constraint.LinearExpression{builder.TOREFACTORMakeTerm(&builder.st.Coeffs[t.CID], t.VID)} + case expr.Term: + hintInputs[i] = constraint.LinearExpression{builder.cs.MakeTerm(&t.Coeff, t.VID)} default: - c := utils.FromInterface(in) - term := builder.TOREFACTORMakeTerm(&c, 0) + c := builder.cs.FromInterface(in) + term := builder.cs.MakeTerm(&c, 0) term.MarkConstant() hintInputs[i] = constraint.LinearExpression{term} } @@ -295,70 +286,87 @@ func (builder *scs) NewHint(f hint.Function, nbOutputs int, inputs ...frontend.V // make the variables res := make([]frontend.Variable, len(internalVariables)) for i, idx := range internalVariables { - res[i] = expr.NewTermToRefactor(idx, constraint.CoeffIdOne) + res[i] = expr.NewTerm(idx, builder.tOne) } return res, nil } // returns in split into a slice of compiledTerm and the sum of all constants in in as a bigInt -func (builder *scs) filterConstantSum(in []frontend.Variable) (expr.LinearExpressionToRefactor, big.Int) { - res := make(expr.LinearExpressionToRefactor, 0, len(in)) - var b big.Int +func (builder *builder) filterConstantSum(in []frontend.Variable) (expr.LinearExpression, constraint.Coeff) { + res := make(expr.LinearExpression, 0, len(in)) + b := constraint.Coeff{} for i := 0; i < len(in); i++ { - switch t := in[i].(type) { - case expr.TermToRefactor: - res = append(res, t) - default: - n := utils.FromInterface(t) - b.Add(&b, &n) + if c, ok := builder.constantValue(in[i]); ok { + builder.cs.Add(&b, &c) + } else { + res = append(res, in[i].(expr.Term)) } } return res, b } -// returns in split into a slice of compiledTerm and the product of all constants in in as a bigInt -func (builder *scs) filterConstantProd(in []frontend.Variable) (expr.LinearExpressionToRefactor, big.Int) { - res := make(expr.LinearExpressionToRefactor, 0, len(in)) - var b big.Int - b.SetInt64(1) +// returns in split into a slice of compiledTerm and the product of all constants in in as a coeff +func (builder *builder) filterConstantProd(in []frontend.Variable) (expr.LinearExpression, constraint.Coeff) { + res := make(expr.LinearExpression, 0, len(in)) + b := builder.tOne for i := 0; i < len(in); i++ { - switch t := in[i].(type) { - case expr.TermToRefactor: - res = append(res, t) - default: - n := utils.FromInterface(t) - b.Mul(&b, &n).Mod(&b, builder.q) + if c, ok := builder.constantValue(in[i]); ok { + builder.cs.Mul(&b, &c) + } else { + res = append(res, in[i].(expr.Term)) } } return res, b } -func (builder *scs) splitSum(acc expr.TermToRefactor, r expr.LinearExpressionToRefactor) expr.TermToRefactor { - +func (builder *builder) splitSum(acc expr.Term, r expr.LinearExpression, k *constraint.Coeff) expr.Term { // floor case if len(r) == 0 { + if k != nil { + // we need to return acc + k + o := builder.newInternalVariable() + builder.addPlonkConstraint(sparseR1C{ + xa: acc.VID, + xc: o.VID, + qL: acc.Coeff, + qO: builder.tMinusOne, + qC: *k, + }) + return o + } return acc } - cl, _ := acc.Unpack() - cr, _ := r[0].Unpack() + // constraint to add: acc + r[0] (+ k) == o o := builder.newInternalVariable() - builder.addPlonkConstraint(acc, r[0], o, cl, cr, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdMinusOne, constraint.CoeffIdZero) - return builder.splitSum(o, r[1:]) -} -func (builder *scs) splitProd(acc expr.TermToRefactor, r expr.LinearExpressionToRefactor) expr.TermToRefactor { + qC := constraint.Coeff{} + if k != nil { + qC = *k + } + builder.addPlonkConstraint(sparseR1C{ + xa: acc.VID, + xb: r[0].VID, + xc: o.VID, + qL: acc.Coeff, + qR: r[0].Coeff, + qO: builder.tMinusOne, + qC: qC, + }) + + return builder.splitSum(o, r[1:], nil) +} +func (builder *builder) splitProd(acc expr.Term, r expr.LinearExpression) expr.Term { // floor case if len(r) == 0 { return acc } - cl, _ := acc.Unpack() - cr, _ := r[0].Unpack() + // constraint to add: acc * r[0] == o o := builder.newInternalVariable() - builder.addPlonkConstraint(acc, r[0], o, constraint.CoeffIdZero, constraint.CoeffIdZero, cl, cr, constraint.CoeffIdMinusOne, constraint.CoeffIdZero) + builder.addMulGate(acc, r[0], o) return builder.splitProd(o, r[1:]) } @@ -366,18 +374,18 @@ func (builder *scs) splitProd(acc expr.TermToRefactor, r expr.LinearExpressionTo // something more like builder.sprintf("my message %le %lv", l0, l1) // to build logs for both debug and println // and append some program location.. (see other todo in debug_info.go) -func (builder *scs) newDebugInfo(errName string, in ...interface{}) constraint.DebugInfo { +func (builder *builder) newDebugInfo(errName string, in ...interface{}) constraint.DebugInfo { for i := 0; i < len(in); i++ { // for inputs that are LinearExpressions or Term, we need to "Make" them in the backend. // TODO @gbotrel this is a duplicate effort with adding a constraint and should be taken care off switch t := in[i].(type) { - case *expr.LinearExpressionToRefactor, expr.LinearExpressionToRefactor: + case *expr.LinearExpression, expr.LinearExpression: // shouldn't happen - case expr.TermToRefactor: - in[i] = builder.TOREFACTORMakeTerm(&builder.st.Coeffs[t.CID], t.VID) - case *expr.TermToRefactor: - in[i] = builder.TOREFACTORMakeTerm(&builder.st.Coeffs[t.CID], t.VID) + case expr.Term: + in[i] = builder.cs.MakeTerm(&t.Coeff, t.VID) + case *expr.Term: + in[i] = builder.cs.MakeTerm(&t.Coeff, t.VID) case constraint.Coeff: in[i] = builder.cs.String(&t) case *constraint.Coeff: @@ -389,6 +397,6 @@ func (builder *scs) newDebugInfo(errName string, in ...interface{}) constraint.D } -func (builder *scs) Defer(cb func(frontend.API) error) { +func (builder *builder) Defer(cb func(frontend.API) error) { circuitdefer.Put(builder, cb) } diff --git a/frontend/internal/expr/linear_expression.go b/frontend/internal/expr/linear_expression.go index 23efcbc146..21b3b8f17b 100644 --- a/frontend/internal/expr/linear_expression.go +++ b/frontend/internal/expr/linear_expression.go @@ -5,7 +5,7 @@ import ( ) // TODO @gbotrel --> storing a UUID in the linear expressions would enable better perf -// in the frontends -> check a linear expression is boolean, or has been converted to a +// in the frontend -> check a linear expression is boolean, or has been converted to a // "backend" constraint.LinearExpresion ... and avoid duplicating work would be interesting. type LinearExpression []Term @@ -41,7 +41,7 @@ func (t Term) HashCode() uint64 { return t.Coeff[0]*29 + uint64(t.VID<<12) } -// Len return the lenght of the Variable (implements Sort interface) +// Len return the length of the Variable (implements Sort interface) func (l LinearExpression) Len() int { return len(l) } diff --git a/frontend/internal/expr/linear_expression_scs_torefactor.go b/frontend/internal/expr/linear_expression_scs_torefactor.go deleted file mode 100644 index 6547c63bb5..0000000000 --- a/frontend/internal/expr/linear_expression_scs_torefactor.go +++ /dev/null @@ -1,78 +0,0 @@ -package expr - -type LinearExpressionToRefactor []TermToRefactor - -func (l LinearExpressionToRefactor) Clone() LinearExpressionToRefactor { - res := make(LinearExpressionToRefactor, len(l)) - copy(res, l) - return res -} - -func NewTermToRefactor(vID, cID int) TermToRefactor { - return TermToRefactor{CID: cID, VID: vID} -} - -type TermToRefactor struct { - CID int - VID int -} - -func (t TermToRefactor) Unpack() (cID, vID int) { - return t.CID, t.VID -} - -func (t *TermToRefactor) SetCoeffID(cID int) { - t.CID = cID -} -func (t TermToRefactor) WireID() int { - return t.VID -} - -func (t TermToRefactor) HashCode() uint64 { - return uint64(t.CID) + uint64(t.VID<<32) -} - -// Len return the lenght of the Variable (implements Sort interface) -func (l LinearExpressionToRefactor) Len() int { - return len(l) -} - -// Equals returns true if both SORTED expressions are the same -// -// pre conditions: l and o are sorted -func (l LinearExpressionToRefactor) Equal(o LinearExpressionToRefactor) bool { - if len(l) != len(o) { - return false - } - if (l == nil) != (o == nil) { - return false - } - for i := 0; i < len(l); i++ { - if l[i] != o[i] { - return false - } - } - return true -} - -// Swap swaps terms in the Variable (implements Sort interface) -func (l LinearExpressionToRefactor) Swap(i, j int) { - l[i], l[j] = l[j], l[i] -} - -// Less returns true if variableID for term at i is less than variableID for term at j (implements Sort interface) -func (l LinearExpressionToRefactor) Less(i, j int) bool { - iID := l[i].WireID() - jID := l[j].WireID() - return iID < jID -} - -// HashCode returns a fast-to-compute but NOT collision resistant hash code identifier for the linear -// expression -func (l LinearExpressionToRefactor) HashCode() uint64 { - h := uint64(17) - for _, val := range l { - h = h*23 + val.HashCode() // TODO @gbotrel revisit - } - return h -} diff --git a/frontend/variable.go b/frontend/variable.go index 9f00ba5167..82d33fbc90 100644 --- a/frontend/variable.go +++ b/frontend/variable.go @@ -32,8 +32,6 @@ func IsCanonical(v Variable) bool { switch v.(type) { case expr.LinearExpression, *expr.LinearExpression, expr.Term, *expr.Term: return true - case expr.LinearExpressionToRefactor, *expr.LinearExpressionToRefactor, expr.TermToRefactor, *expr.TermToRefactor: - return true } return false } diff --git a/internal/stats/latest.stats b/internal/stats/latest.stats index be2ff23c987ac84a1cd466308e97c9f046513b88..c846090f0ae1d77d0d5e4ac2e9b1f20ae4acc0f7 100644 GIT binary patch delta 182 zcmew?`dM^B)?_872a}`OTPJ%nUY~rNA__^2{}keYBGP<7%!N?HzyVZBkpYtzas^H1WDlDBiuvxutcL&> Cfk#gO delta 182 zcmew?`dM^B)?^{Bhm+4UUZ0rtU~&q}i^-;(cPB4nx;xp2wPkWM^TWxHIf5p8F}7~L z!0N Date: Wed, 1 Mar 2023 00:53:06 +0100 Subject: [PATCH 028/464] docs: fix select description in field emulation --- std/math/emulated/field_ops.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/math/emulated/field_ops.go b/std/math/emulated/field_ops.go index 0b1d6f5e7f..c64b6a24d7 100644 --- a/std/math/emulated/field_ops.go +++ b/std/math/emulated/field_ops.go @@ -263,7 +263,7 @@ func (f *Field[T]) Neg(a *Element[T]) *Element[T] { return f.Sub(f.Zero(), a) } -// Select sets e to a if selector == 0 and to b otherwise. Sets the number of +// Select sets e to a if selector == 1 and to b otherwise. Sets the number of // limbs and overflow of the result to be the maximum of the limb lengths and // overflows. If the inputs are strongly unbalanced, then it would better to // reduce the result after the operation. From faa66e03d716acfe2ceb83708d48957003933faf Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 1 Mar 2023 11:21:51 +0100 Subject: [PATCH 029/464] docs: make documentation of weierstrass/ better --- std/algebra/weierstrass/doc.go | 5 +-- std/algebra/weierstrass/point.go | 57 ++++++++++++++++++++++++++------ 2 files changed, 48 insertions(+), 14 deletions(-) diff --git a/std/algebra/weierstrass/doc.go b/std/algebra/weierstrass/doc.go index 72ff229dad..dfcb647fe5 100644 --- a/std/algebra/weierstrass/doc.go +++ b/std/algebra/weierstrass/doc.go @@ -25,9 +25,6 @@ This package uses field emulation (unlike packages [github.com/consensys/gnark/std/algebra/sw_bls12377] and [github.com/consensys/gnark/std/algebra/sw_bls24315], which use 2-chains). This allows to use any curve over any native (SNARK) field. The drawback of this -approach is the extreme cost of the operations. In R1CS, point addition on -256-bit fields is approximately 3500 constraints and doubling is approximately -4300 constraints. A full scalar multiplication is approximately 2M constraints. -It is several times more in PLONKish aritmetisation. +approach is the extreme cost of the operations. */ package weierstrass diff --git a/std/algebra/weierstrass/point.go b/std/algebra/weierstrass/point.go index c32932d419..fcb648c20d 100644 --- a/std/algebra/weierstrass/point.go +++ b/std/algebra/weierstrass/point.go @@ -862,6 +862,8 @@ func (c *Curve[B, S]) AssertIsEqual(p, q *AffinePoint[B]) { } // Add adds p and q and returns it. It doesn't modify p nor q. +// It uses incomplete formulas in affine coordinates. +// The points p and q should be different and nonzero (neutral element). func (c *Curve[B, S]) Add(p, q *AffinePoint[B]) *AffinePoint[B] { // compute λ = (q.y-p.y)/(q.x-p.x) qypy := c.baseApi.Sub(&q.Y, &p.Y) @@ -885,6 +887,7 @@ func (c *Curve[B, S]) Add(p, q *AffinePoint[B]) *AffinePoint[B] { } // Double doubles p and return it. It doesn't modify p. +// It uses affine coordinates. func (c *Curve[B, S]) Double(p *AffinePoint[B]) *AffinePoint[B] { // compute λ = (3p.x²+a)/2*p.y, here we assume a=0 (j invariant 0 curve) @@ -912,11 +915,15 @@ func (c *Curve[B, S]) Double(p *AffinePoint[B]) *AffinePoint[B] { } } -// Triple triples p and return it. -// It follows [ELM03]: https://arxiv.org/pdf/math/0208038.pdf, 3.1 +// Triple triples p and return it. It follows [ELM03] (Section 3.1). // Saves the computation of the y coordinate of 2p as it is used only in the computation of λ2, -// which can be computed as λ2 = -λ1-2*p.y/(x2-p.x) instead. +// which can be computed as +// +// diffλ2 = -λ1-2*p.y/(x2-p.x) instead. +// // It doesn't modify p. +// +// [ELM03]: https://arxiv.org/pdf/math/0208038.pdf func (c *Curve[B, S]) Triple(p *AffinePoint[B]) *AffinePoint[B] { // compute λ1 = (3p.x²+a)/2p.y, here we assume a=0 (j invariant 0 curve) @@ -955,10 +962,15 @@ func (c *Curve[B, S]) Triple(p *AffinePoint[B]) *AffinePoint[B] { } } -// DoubleAndAdd computes 2p+q as (p+q)+p. It follows [ELM03]: https://arxiv.org/pdf/math/0208038.pdf, 3.1 +// DoubleAndAdd computes 2p+q as (p+q)+p. It follows [ELM03] (Section 3.1) // Saves the computation of the y coordinate of p+q as it is used only in the computation of λ2, -// which can be computed as λ2 = -λ1-2*p.y/(x2-p.x) instead. -// It doesn't modify p nor q. +// which can be computed as +// +// diffλ2 = -λ1-2*p.y/(x2-p.x) +// +// instead. It doesn't modify p nor q. +// +// [ELM03]: https://arxiv.org/pdf/math/0208038.pdf func (c *Curve[B, S]) DoubleAndAdd(p, q *AffinePoint[B]) *AffinePoint[B] { // compute λ1 = (q.y-p.y)/(q.x-p.x) @@ -996,7 +1008,7 @@ func (c *Curve[B, S]) DoubleAndAdd(p, q *AffinePoint[B]) *AffinePoint[B] { } -// Select selects between p and q given the selector b. If b == 0, then returns +// Select selects between p and q given the selector b. If b == 1, then returns // p and q otherwise. func (c *Curve[B, S]) Select(b frontend.Variable, p, q *AffinePoint[B]) *AffinePoint[B] { x := c.baseApi.Select(b, &p.X, &q.X) @@ -1008,8 +1020,11 @@ func (c *Curve[B, S]) Select(b frontend.Variable, p, q *AffinePoint[B]) *AffineP } // Lookup2 performs a 2-bit lookup between i0, i1, i2, i3 based on bits b0 -// and b1. Returns i0 if b0=b1=0, i1 if b0=1 and b1=0, i2 if b0=0 and b1=1 -// and i3 if b0=b1=1. +// and b1. Returns: +// - i0 if b0=0 and b1=0, +// - i1 if b0=1 and b1=0, +// - i2 if b0=0 and b1=1, +// - i3 if b0=1 and b1=1. func (c *Curve[B, S]) Lookup2(b0, b1 frontend.Variable, i0, i1, i2, i3 *AffinePoint[B]) *AffinePoint[B] { x := c.baseApi.Lookup2(b0, b1, &i0.X, &i1.X, &i2.X, &i3.X) y := c.baseApi.Lookup2(b0, b1, &i0.Y, &i1.Y, &i2.Y, &i3.Y) @@ -1020,6 +1035,19 @@ func (c *Curve[B, S]) Lookup2(b0, b1 frontend.Variable, i0, i1, i2, i3 *AffinePo } // ScalarMul computes s * p and returns it. It doesn't modify p nor s. +// +// It computes the standard little-endian variable-base double-and-add algorithm +// [HMV04] (Algorithm 3.26). +// +// Since we use incomplete formulas for the addition law, we need to start with +// a non-zero accumulator point (res). To do this, we skip the LSB (bit at +// position 0) and proceed assuming it was 1. At the end, we conditionally +// subtract the initial value (p) if LSB is 1. We also handle the bits at +// positions 1, n-2 and n-1 outside of the loop to optimize the number of +// constraints using [ELM03] (Section 3.1) +// +// [ELM03]: https://arxiv.org/pdf/math/0208038.pdf +// [HMV04]: Guide to Elliptic Curve Cryptography func (c *Curve[B, S]) ScalarMul(p *AffinePoint[B], s *emulated.Element[S]) *AffinePoint[B] { var st S sr := c.scalarApi.Reduce(s) @@ -1052,7 +1080,16 @@ func (c *Curve[B, S]) ScalarMul(p *AffinePoint[B], s *emulated.Element[S]) *Affi return res } -// ScalarMulBase computes s * g and returns it, where g is the fixed generator. It doesn't modify s. +// ScalarMulBase computes s * g and returns it, where g is the fixed generator. +// It doesn't modify s. +// +// It computes the standard little-endian fixed-base double-and-add algorithm +// [HMV04] (Algorithm 3.26). +// +// The method proceeds similarly to ScalarMul but with the points [2^i]g +// precomputed. The bits at positions 1 and 2 are handled outside of the loop +// to optimize the number of constraints using a Lookup2 with pre-computed +// [3]g, [5]g and [7]g points. func (c *Curve[B, S]) ScalarMulBase(s *emulated.Element[S]) *AffinePoint[B] { g := c.Generator() gm := c.GeneratorMultiples() From 766b1f6cfe32989fffb9f93cc64a51410f8b901e Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 1 Mar 2023 11:42:22 +0100 Subject: [PATCH 030/464] perf: ScalarMulBase for sw_bls12377 --- std/algebra/sw_bls12377/g1.go | 33 + std/algebra/sw_bls12377/g1_test.go | 31 + std/algebra/sw_bls12377/inner.go | 774 ++++++++++++++++++ std/commitments/kzg_bls12377/verifier.go | 3 +- std/commitments/kzg_bls12377/verifier_test.go | 8 +- 5 files changed, 842 insertions(+), 7 deletions(-) diff --git a/std/algebra/sw_bls12377/g1.go b/std/algebra/sw_bls12377/g1.go index 303315a833..ac8ea4a746 100644 --- a/std/algebra/sw_bls12377/g1.go +++ b/std/algebra/sw_bls12377/g1.go @@ -451,3 +451,36 @@ func (p *G1Affine) DoubleAndAdd(api frontend.API, p1, p2 *G1Affine) *G1Affine { return p } + +// ScalarMulBase computes s * g and returns it, where g is the fixed generator. It doesn't modify s. +func (P *G1Affine) ScalarMulBase(api frontend.API, s frontend.Variable) *G1Affine { + + points := GetBLS12377Points() + + sBits := api.ToBinary(s) + + var res, tmp G1Affine + + // i = 1, 2 + // gm[0] = 3g, gm[1] = 5g, gm[2] = 7g + res.X = api.Lookup2(sBits[1], sBits[2], points.Gx, points.Gmx[0], points.Gmx[1], points.Gmx[2]) + res.Y = api.Lookup2(sBits[1], sBits[2], points.Gy, points.Gmy[0], points.Gmy[1], points.Gmy[2]) + + for i := 3; i < len(sBits); i++ { + // gm[i] = [2^i]g + tmp.X = res.X + tmp.Y = res.Y + tmp.AddAssign(api, G1Affine{points.Gmx[i], points.Gmy[i]}) + res.Select(api, sBits[i], tmp, res) + } + + // i = 0 + tmp.Neg(api, G1Affine{points.Gx, points.Gy}) + tmp.AddAssign(api, res) + res.Select(api, sBits[0], res, tmp) + + P.X = res.X + P.Y = res.Y + + return P +} diff --git a/std/algebra/sw_bls12377/g1_test.go b/std/algebra/sw_bls12377/g1_test.go index 2a0a83a1a5..55e5c524bc 100644 --- a/std/algebra/sw_bls12377/g1_test.go +++ b/std/algebra/sw_bls12377/g1_test.go @@ -369,6 +369,37 @@ func TestScalarMulG1(t *testing.T) { assert.SolvingSucceeded(&circuit, &witness, test.WithCurves(ecc.BW6_761)) } +type g1varScalarMulBase struct { + C G1Affine `gnark:",public"` + R frontend.Variable +} + +func (circuit *g1varScalarMulBase) Define(api frontend.API) error { + expected := G1Affine{} + expected.ScalarMulBase(api, circuit.R) + expected.AssertIsEqual(api, circuit.C) + return nil +} + +func TestVarScalarMulBaseG1(t *testing.T) { + var c bls12377.G1Affine + gJac, _, _, _ := bls12377.Generators() + + // create the cs + var circuit, witness g1varScalarMulBase + var r fr.Element + _, _ = r.SetRandom() + witness.R = r.String() + // compute the result + var br big.Int + gJac.ScalarMultiplication(&gJac, r.BigInt(&br)) + c.FromJacobian(&gJac) + witness.C.Assign(&c) + + assert := test.NewAssert(t) + assert.SolvingSucceeded(&circuit, &witness, test.WithCurves(ecc.BW6_761)) +} + func randomPointG1() bls12377.G1Jac { p1, _, _, _ := bls12377.Generators() diff --git a/std/algebra/sw_bls12377/inner.go b/std/algebra/sw_bls12377/inner.go index 7843ac8f17..bef2cc9eca 100644 --- a/std/algebra/sw_bls12377/inner.go +++ b/std/algebra/sw_bls12377/inner.go @@ -62,3 +62,777 @@ func getInnerCurveConfig(outerCurveScalarField *big.Int) *innerConfig { return &innerConfigBW6_761 } + +type CurvePoints struct { + Gx *big.Int // base point x + Gy *big.Int // base point y + Gmx [377]*big.Int // m*base point x + Gmy [377]*big.Int // m*base point y +} + +func GetBLS12377Points() CurvePoints { + gx, _ := new(big.Int).SetString("8848defe740a67c8fc6225bf87ff5485951e2caa9d41bb188282c8bd37cb5cd5481512ffcd394eeab9b16eb21be9ef", 16) + gy, _ := new(big.Int).SetString("1914a69c5102eff1f674f5d30afeec4bd7fb348ca3e52d96d182ad44fb82305c2fe3d3634a9591afd82de55559c8ea6", 16) + g3x, _ := new(big.Int).SetString("1252b781171f507db36291b433a1f911a46543890a20ca9712e11f66a5d216e63d817bd8d96cef715abc604dcf6ec2e", 16) + g3y, _ := new(big.Int).SetString("14a00fa77c727e8987cc438b51bbe012c823a19955ae692c54ce572a61f0ea1fe5cd981533df419fd1330d1f6e6d802", 16) + g5x, _ := new(big.Int).SetString("17052d4e3eb642d32ef4989af253cc2a30ad376ce8f0b23c92b987e95cc718d02072bb78d37c09fd76f7014eecf797", 16) + g5y, _ := new(big.Int).SetString("16c206be738bf4644faff10bb82b19f6f07779903a6ad2524809ce29f94683be32bbdd072ec0be66ae0ed0d8781f277", 16) + g7x, _ := new(big.Int).SetString("916932fceb94ad7b80fcf492aa5ee0e120410017cc6d17c8962ba2eb799260d022c3de5a103e6edbb5ee9135c7f0fa", 16) + g7y, _ := new(big.Int).SetString("18efb7c0b6e083030a858e3e8b4d1db5857a3f6c60f01691eb9783f6a1f1064069da2e220952121c771f276888d5137", 16) + g2To3x, _ := new(big.Int).SetString("18aff632c0048f5afb5c07fd197a44a127c829be3ff6170c6cebc1154bc72633b45de2ac855e0da30cebfa33672e7f3", 16) + g2To3y, _ := new(big.Int).SetString("efb82d5f13565755df1445db9ed4c4969f09bb31cc610f83eb1490be76ab3817808c52d98074f1a98ff896012a78ab", 16) + g2To4x, _ := new(big.Int).SetString("107db75ab97dcb352b7e3e0596950ec2793cb394f821b1a2e7d5f54d11da8215a998cc84736ddffed74f549052a9df4", 16) + g2To4y, _ := new(big.Int).SetString("7d8459036fefe53ffd95028a2be4f8588b07cd359b0955e1cbe986d4b1ee854e452d7c14f05c41b861266522e3e887", 16) + g2To5x, _ := new(big.Int).SetString("680fb4caec4a06f92a7f4f1e20624b4eaf74001df5ab3ca6f4b3fd9c2d49f257d3021400f5844e227d9763090d8cb", 16) + g2To5y, _ := new(big.Int).SetString("1a9a941bd20effaea30f547d27e433ddf0e29bad201877d54995e73586e8847aaadc0b521762db07fc7906d3c39ee80", 16) + g2To6x, _ := new(big.Int).SetString("56827fbf50c974fda74996e7415fb0fa6c653d0279ae5e0726c124b222837c6ff5fb12682ba380984981f2442100cd", 16) + g2To6y, _ := new(big.Int).SetString("962aa4e39307e00d9934914a1ae85e57513ac9f7b7dbd11003d67d62f288d92f5bd2aedad3a9686ce807efe6f8fba4", 16) + g2To7x, _ := new(big.Int).SetString("880497aa4f51a84c24fb4d92ef46819156918734858556807059b6f6d3e62d2e3f589f33d7f8c5f6af63a0f072629a", 16) + g2To7y, _ := new(big.Int).SetString("111c794e9d2397062f763482bec5584abb31f5b73090174dc22c8dce191c94362ed75492067209bd63044d40f694ad1", 16) + g2To8x, _ := new(big.Int).SetString("e5ddb0da4a5b32e245f78e95760c03227b976ed310ef3922624473d3ca4ea85429797e145692f87d5cb39b4e9a807c", 16) + g2To8y, _ := new(big.Int).SetString("ee67ff3335bffe5cba6953e23e9a1953ee9c1f37371c01a0ceca424f98566df7c353e1eead76435e7854af3fe89c3e", 16) + g2To9x, _ := new(big.Int).SetString("13c910dadc716133218967c098a8f2889817ea5688f68c1878cf6b97e903f728b65dd7b7a6ad65226ee2089a3317b4a", 16) + g2To9y, _ := new(big.Int).SetString("13324bef362a2a30fef824ea32e78c5c1e628842afd2fe67baae1e80fe7eabdbe97ef70a9606fe8db5359a607750b8c", 16) + g2To10x, _ := new(big.Int).SetString("134fb9a0098e3581953df24b0cb4a16306a4eea26bdb08b92b5fe28c35c178873e7a3b813e3579b417f780a7585a027", 16) + g2To10y, _ := new(big.Int).SetString("11e922e78cc7bbf317f9e3013d3c4d35a134d8ff2b94cd33450331a67f3585dd6c548b494f4eaa21f325e45d5d01912", 16) + g2To11x, _ := new(big.Int).SetString("14fe16f6fbc301389a2ce1cf4380af5eace02eb0be172c174e0e6e59f22259b861eefe33fcd031bf94d23d3622b19dc", 16) + g2To11y, _ := new(big.Int).SetString("aeb36e0a5f8b155febe62a45c6d318fae2a035999d0c309e163721431c4e2d2185db90329a3a644cbe7c07d5042c05", 16) + g2To12x, _ := new(big.Int).SetString("ab8d63c61ea2a57f78951d45eca6a177a7dd1c7b753587d1d7348c6f158fea835c5a2c9b4b39be911a900d9d71753e", 16) + g2To12y, _ := new(big.Int).SetString("10b05d822a9665013d90ad837b75171e8b491636943329c997822f58577adac847d95b7f188b11ca33d14fd5d3acec8", 16) + g2To13x, _ := new(big.Int).SetString("add361f77572a949e411d6435d8121daecb31402c58a7cc6ebb737c26a11d6bfb60ef1eb0e1226b8e4ff4d7a1f19a1", 16) + g2To13y, _ := new(big.Int).SetString("ad05daef21794dd0d33692eb4743bfe28c6c85090622926a547e5122ef41a1dddad4cba10b798f89579cb2348e9d57", 16) + g2To14x, _ := new(big.Int).SetString("63929f07e03764ea4b3b4baa6e504c2bc7588a2c7f3e2b1029e94caf03e5f20d41bb644edcdb8f6869527047984d6b", 16) + g2To14y, _ := new(big.Int).SetString("6a51e86ce05f6f4bf7761db5143323f36250a620a3c5132ec24fe0a0ccce5375eea48bf39a27141acd8a6339587186", 16) + g2To15x, _ := new(big.Int).SetString("9d656058092638a500e7febd7c820798ec2e7139b02a10083ab6593d915a4ec4293d023ba59192b49845c0512a6686", 16) + g2To15y, _ := new(big.Int).SetString("191cac9f967d935ab360a6f6e58381956a7f9497e2c67175c7710ccf4c2db22bfbc390090fdb568f0e182b30df1a280", 16) + g2To16x, _ := new(big.Int).SetString("1371622e52c4790930c0dc81051c5d922318a05a5dddf4035838f88368cae1178db6ddafef464a9bd035fbe22311be9", 16) + g2To16y, _ := new(big.Int).SetString("5a6cf187acfb8a91dd2130b0d8f4f617b1bb0f9beb1a29ea908cb24254e4e2a3e8c14c3c5cc20bc714a1bcdfed1535", 16) + g2To17x, _ := new(big.Int).SetString("127f9cd4d32d5b68839ad50475180b572cf5a64a298bef23b2ed972dbe8f65e33056e5476e8716252635b980cecd7c5", 16) + g2To17y, _ := new(big.Int).SetString("1738a6dd32253efa3621c81b81eb1d109a35a1d182a04be293b75bbdeabf7f3090d32b0bae41fb0bb317f5c7b669f8b", 16) + g2To18x, _ := new(big.Int).SetString("7a60c7c738fb264482fe46a69c514cc4cbbc83370890dc1cbf39567e8b34bf5c388313c82804d1c7261dc99b2801ab", 16) + g2To18y, _ := new(big.Int).SetString("d0ab238b768b54b095db2aca7acfa16ae26264066fe7be9547b76c855188a07d287d0031fdc40d57dab98c7d073bca", 16) + g2To19x, _ := new(big.Int).SetString("6042f781b85a81d10048c15da22c5069b880f6d1f6f5c54bd327760bc1b4daa247aca6c96bee7d20c8578220981ef", 16) + g2To19y, _ := new(big.Int).SetString("c20df594f36b4a18be4c2e759c55a1c08d08fdd8e7f0d228e282727518eba66383cd667811c0d5e4baf03455e46f99", 16) + g2To20x, _ := new(big.Int).SetString("141937e53eb28e9328d805dec48045a9f258c632aa4e4f360fea78d16850921b636fc52df323fcae8051385364cff58", 16) + g2To20y, _ := new(big.Int).SetString("f82e14368390d59c28fcfb130566a936b446e783877578d7e27e15c14614be38a5927329189abda212bd4576ae6421", 16) + g2To21x, _ := new(big.Int).SetString("94e187a31d02354de6787d1abffc8b9fdb62f8dd91a01fe0af6265736966d8ec181bd65863c2b0c3020c1c7c26a9ee", 16) + g2To21y, _ := new(big.Int).SetString("77cb65bade2f40dd98b6ee8d84aff95295647f5f2744e9691ee8013537f714df467010007b8479a018dce66ecf011", 16) + g2To22x, _ := new(big.Int).SetString("f574cd8336eb82714f7cfe446d239ee89bafbe52b6cb5e7dc839fba89cfb78187f1aacbf92dc4d772519e500d3faae", 16) + g2To22y, _ := new(big.Int).SetString("4e3073dfae73051d165648b65a1910c82d22e2344db0a906e98485883d11f12e061c84e99905fa09c3a73c1a0dff86", 16) + g2To23x, _ := new(big.Int).SetString("879b817a80faf83a690e7d4cc5c7f802bae36cc397bb4fc5210a48b23227821ffe5b5fd90f34b37aee8bea5b143a1e", 16) + g2To23y, _ := new(big.Int).SetString("1387d2b720763e114e58702c269ff61007ab33c1e6e7d5834f010b970fb70ed7bc469b2129e613ac2fd2d3a6a6e34d1", 16) + g2To24x, _ := new(big.Int).SetString("f1e52f2ceb352869eac2a752dd6bc47b84724b3f4e74df4b72db06d9000456571cd58b4a1332f0c99f40eb4893e5c9", 16) + g2To24y, _ := new(big.Int).SetString("60e7d9eb062783ba26ec00ed46179386b4225a129fd044f84f9d7984147879c80f6b8d70eb6d55e160d7bc2a5c1684", 16) + g2To25x, _ := new(big.Int).SetString("133f8d1a44d868b95891a82ab4cd2343ce38e370e48a256f232b0077b411a12922bb919c599e6c5a1f9a81395d7d054", 16) + g2To25y, _ := new(big.Int).SetString("1414246490ffe596f7c8db806833128a661e98dc52b62a694caca1df3644c135bd8946d933275f2642f81e03f645daf", 16) + g2To26x, _ := new(big.Int).SetString("12982253bcdcfc660df538b5d004eb6bf283dbaf7788eec8d958bf77f10067e1f62ccc3194a65b0120fe15e92695667", 16) + g2To26y, _ := new(big.Int).SetString("97ec4a1c3de3030096011e1cce00814d216b19659fe3cb5eac04df4a12cf5e1f36ee47cd8acc02e51d031a65a17114", 16) + g2To27x, _ := new(big.Int).SetString("bafb585867ed534280a3a898ab8e7b8d6d0b393add86ba307b150dfaee25eea932e3a744d01b9d18950cc3f5670e4b", 16) + g2To27y, _ := new(big.Int).SetString("ba377e08bcc57ed719d82ffde026ea1c0fa3f3ec44e5e587507531731eb815ca6712e9eb92dfa63864b570e10e735", 16) + g2To28x, _ := new(big.Int).SetString("43ddf8732e7a29888831d1923985991bf6a9dc2fbe7916b12c8d676fafb96025023eeba8e208ff582fafefbd2af2bc", 16) + g2To28y, _ := new(big.Int).SetString("156dc34ce172d5dcdde35e9f77e0f23a3410f164b4ca2fdded4ffef71cd6c8be6605bbb2eb66522c15c7db50be316c4", 16) + g2To29x, _ := new(big.Int).SetString("13d7c2e8c14d861444f01eb7137520d1fc91ffd61c1c798710af6be926acc53921523d48708f41edb321ec779a2a92e", 16) + g2To29y, _ := new(big.Int).SetString("1108bb151007ff0b724046c4d5a641fbfe6e6a3bd71d3e1284cacc8e416a5fdedb4ed2693aded3d457d8ac72906070a", 16) + g2To30x, _ := new(big.Int).SetString("d2716f627351a4863060ab6777b148610d94e1b48b1607350f0098cc1289939097e4c3968506d152627350593d11a5", 16) + g2To30y, _ := new(big.Int).SetString("e64f79eb0f4d2fe93594259c1bc28f418a7ebd0a60769042315cac1fd6a1131e69ac868568526c3107c9176bab0c05", 16) + g2To31x, _ := new(big.Int).SetString("16c405bdc35a13c07c1157145face8ee9d13e41bb9e243d9a02c1900f26c7c062570cf56e1e992aab2b3bfbb61d387e", 16) + g2To31y, _ := new(big.Int).SetString("9c4f95f7c2c3fe1a4ac36d90ef98612c0691f3ed2ca212e9e1d38345606c2416652f5d8531bffbfbe1437f133b4e12", 16) + g2To32x, _ := new(big.Int).SetString("969e8eb9ce543735eb543a770a40903c3755d2e28c6c8ea9318440f2ea087f458f4b6f071aac44906b2a887d1a69a4", 16) + g2To32y, _ := new(big.Int).SetString("19f9bc3859f6781918a79e836d745c8787ba8b11c355e49e66b64e54428817e9fbbba06333e26d6b5dbd5fa6d7ea2f2", 16) + g2To33x, _ := new(big.Int).SetString("f14b7e7af6fa1d295f7b6ac8b1badf1fa3d65de31e79e94e69f02f21589642505a00ae1868525566cecce45fd62e44", 16) + g2To33y, _ := new(big.Int).SetString("1a115f0aa272d645be22ee308865c893e575c01aa55ace3410fd3e751a4e610655884c0a97427f37c9dcd90338b1626", 16) + g2To34x, _ := new(big.Int).SetString("148e97cb2504eb135a392a36e995694e281e727919ac5736e3f5dc45bd857e1a2b1fd48984147f762ff5a08e9eff340", 16) + g2To34y, _ := new(big.Int).SetString("18818155deaebb73bb615991f4aa7eb7750b2186f12d0aca0f56ecc22e7fb1cc4086d7fbf5da6cb8d12dfea5047975a", 16) + g2To35x, _ := new(big.Int).SetString("1826fdb3058eed244014b2cc2e84a61cfd4f4ec0e502e81ad5279246a8df015171bb35d70b4d21f0778b2bd46bba947", 16) + g2To35y, _ := new(big.Int).SetString("1511d311e43642cfa8ddc23dada8d387c5ebedbf1f96e22fea67c841550227148533e983b310f8287e50ef5462aef4d", 16) + g2To36x, _ := new(big.Int).SetString("1afe7f02e75acba6bb817bf762fddb0c50ed73ee7ad2abd3eb648a624dbb3649a70f8a0bed77b364dc64d5670e12c9", 16) + g2To36y, _ := new(big.Int).SetString("1141907296b72c2969a79f29523d5378b7c2323e87b93a667ccc0ece9f62a3bf7448dd8b2222a077de60f5245b0ab26", 16) + g2To37x, _ := new(big.Int).SetString("eaab1bcb93f8e64dd8dd822119af39e6db14b06a0dfda84a8948038412ce5f5e2e3d89492eec2242e2730c81e8651f", 16) + g2To37y, _ := new(big.Int).SetString("17f4f5be515e6bf8037faec8f667ee63a786a59688ea502ef4da6131ce63aaf4355b55e7dfa52f16c374105fb8bf924", 16) + g2To38x, _ := new(big.Int).SetString("1a5b9caa4a74b679c4186aadfcc8d05408728e9caf463724e9a9e8468d13f4e2895f0d0eb386a749009b7d6e5b2e75f", 16) + g2To38y, _ := new(big.Int).SetString("47e7ef7de6058e4ab1b2655164ae9df1cb3865dd5049f604b68cf77ea65a079ada29e524ed864792f7bf22283634a", 16) + g2To39x, _ := new(big.Int).SetString("14fcd5c9fda9b70d081e0b955145e5f5f7a15b4ca4f22e284a8c13bd7add0c67eec7bbd901e33991d94a8838638a9e7", 16) + g2To39y, _ := new(big.Int).SetString("ddfdb26ac57951cebfe2394dd4dd4d27c6efec24b70b1208b2dc5ca1f867974f3e8eec4050eb21af8497860af54d", 16) + g2To40x, _ := new(big.Int).SetString("252bee9b6ef8f22112ed489d3f56f08cc662d26783e4dfb44c65e5effe63e35e7df58894ff7c3e861dae155d0a021f", 16) + g2To40y, _ := new(big.Int).SetString("2bb53e9d3d1b2d87b5d1e237d39c3920dd4fbf9c34ca9b526b82472681c4c316e93a705dc28f2b6a262f21bf4138ce", 16) + g2To41x, _ := new(big.Int).SetString("174acac12c03f292f9c8c9ef1be3a1127fd64726cb9a3da1c37d18a0474830c5bdd294671a31e09670a0a9a357f640f", 16) + g2To41y, _ := new(big.Int).SetString("15cafb6ce83da980dbbbe486269ce721e9ae2d32b33773705904a74ab223df23e26b7655ff55d0c1ace86a72b4f6cfc", 16) + g2To42x, _ := new(big.Int).SetString("aa5ae22e7da20eb760d8be899a537d78c7f76aef985f6afa881020e7169a6960284c42bb5bf3301029b7ea78ddbab2", 16) + g2To42y, _ := new(big.Int).SetString("3cb9cf41a120b481b419ceda853a508337f74a91500f881629c0cb16c9be10b352929006ae300b93263ba01b378517", 16) + g2To43x, _ := new(big.Int).SetString("182b1745e5f859974d7ecbcec4da576a01cb5883ba5bae584709bd2e45d8eef002e4b093d8324372143460b4d0e4d5", 16) + g2To43y, _ := new(big.Int).SetString("187934573dca1cabc7a250d3e53091e9269009e3edfd0dc0ca2bc4843c1db9c0d7582c55dcc9a113728a37b4c7957b6", 16) + g2To44x, _ := new(big.Int).SetString("9008e86f9a7abb2b70044f3ea1565f3fe7df01bf46778f3a216a3605292382614dd4e807501c514760495f1fbad362", 16) + g2To44y, _ := new(big.Int).SetString("fe0c7b627908402489f139e577d86c527f9022a81cf6d4b20839b2886aeb4ade6cda54ddedab603a331acda5dc9997", 16) + g2To45x, _ := new(big.Int).SetString("db1db669a0f65547c0ef181afddcd6af4ebaae9a0b0977ac99aca37286bd94d9d14ee0a67de9f64d647ed58620aa46", 16) + g2To45y, _ := new(big.Int).SetString("1604ae03716ae90daa4711695fd86138eaaa4d03d3bf85217586783c77acad34497b1e89bab3c26036cc780b95cf98e", 16) + g2To46x, _ := new(big.Int).SetString("a961a93d8d69857b45972c45e7da4cc98fa11a28ef93b391bce2b4d7bb7472cf8dad04b0833443717085fbb14b8a0c", 16) + g2To46y, _ := new(big.Int).SetString("1222d52c8fb984fb00c1ebae3b66f52144b030bb2c28a304cbaa8a5335cd797cdb519cbcb6df298ff7ef426c80d53d6", 16) + g2To47x, _ := new(big.Int).SetString("605fbf7d4a4865e18a349f6af474d04c53ccd15aef07dc5c63d0aeaa9e35c732d5c25dce539d1018a8eb5ba1a1e703", 16) + g2To47y, _ := new(big.Int).SetString("1673edb028fae78421ab69bbf1d4c2116d0977a486f911a30354a6c6c74341c0a081dc604fdd130f1dbea16158a14c0", 16) + g2To48x, _ := new(big.Int).SetString("16b32d15667fbf3b37d2fd42b9648b8d12c1e8380df504dd6d1bb74387e615190aa158e31557e26710bddd3f62c448", 16) + g2To48y, _ := new(big.Int).SetString("1a96b7fb2441a65a1507e7b63bed23aa162ed2cc002553292d5b9009b1ccccebb7c597b12e1303afe406cad47d14b76", 16) + g2To49x, _ := new(big.Int).SetString("1ac0e778e13331dc87c9ec5c9eb608894f5ccb3448b6e537ef0481cd6534873c65c3b90265eeb87aefe7e0b6719df47", 16) + g2To49y, _ := new(big.Int).SetString("1374cc9941ddc21bf5d7fe0d3f6863d55084da5d3270756b2239d03dc0fe22ea67127f7eb04900e676d687f1479c4f", 16) + g2To50x, _ := new(big.Int).SetString("f2a9a16712080ab0597457b86c31c890fa22f1c512a9dda284f4d5b307742092ed7cf6e17e09a02e405bcb285aba7d", 16) + g2To50y, _ := new(big.Int).SetString("e6e13736ec424657d9f75e2e4817786a58c432f021b61c8a448af8b8f4d861dc0fe23cfde02b655fe8394d27b40ec9", 16) + g2To51x, _ := new(big.Int).SetString("2677277410ccf8b96bdd183733368cae50e14b757616979ee0975aa9e4201fdd12b86256c9f9a143653e1cc620a85", 16) + g2To51y, _ := new(big.Int).SetString("cd1b38e1e3b2e1067822422ba488a83c851a4f6d29680947fcac986ef07fa3148817a3840894b82daa4da2e274e94a", 16) + g2To52x, _ := new(big.Int).SetString("281b180d9e4aae07f4d6c11e679744d92592c26a6fb90692fe12f10eb16b58916ca87e74c9c0bd03887de8e2e45d0f", 16) + g2To52y, _ := new(big.Int).SetString("11101677eb41c6ca2c60d14456cfc148b4758a7dc86bb3f596d0afbf9677e403d9e8cbb9ad3afb08499e58ae295e9df", 16) + g2To53x, _ := new(big.Int).SetString("f1cc005ed80694095b1a61ba7e9700676450f5693e403aa9bba34b10be09111151dd9f4448d6bb287aabe37365d1c0", 16) + g2To53y, _ := new(big.Int).SetString("1a3e52c9f74db8b43d80c20e054c3a4849a441bebc44d444f4e7460036c46a1743320d75af77e11bb43ff521663aa29", 16) + g2To54x, _ := new(big.Int).SetString("7617573decd671474599623dd69aa96fe82794763eb49d2443f182428c6227145b7b6389cff20f9f46832fd2dbfcae", 16) + g2To54y, _ := new(big.Int).SetString("1a92a1f480f7d985d4e1abe80af96adf0e475571b80e99456d75b4218ee0c1e363afdd161789756f618f78cba51dd03", 16) + g2To55x, _ := new(big.Int).SetString("adff1ee838fd0e69694d32df4364308fec2313cd57c641367615c74f069f343a0c4888235308f22901084d9bcea913", 16) + g2To55y, _ := new(big.Int).SetString("9301a7eee38fe353161f286347647d566f8949fea78942d854a9b5c1639daeb83242ef6424caaba2095532f66b2e5b", 16) + g2To56x, _ := new(big.Int).SetString("2fd8f21f20fa1e949001314366e933d619b6e421c67c0bee21da9ef0d0318cec8fef099803b8e5629accd6d6b78e1c", 16) + g2To56y, _ := new(big.Int).SetString("ced044196c59388c333e8a0b17f9b9ee3c38ebee8c9c22b5be43c40737c6c9de7984b14c8f39127bc1c073ee60e25d", 16) + g2To57x, _ := new(big.Int).SetString("12d8246a5064c33a3b6e9be28e650715f2c62b696c90acc014ef9a2700bc1c7012f777b6af6d59949b3e0d87c1e88fe", 16) + g2To57y, _ := new(big.Int).SetString("19dbac773f76ba1a8c485090b6b10f9bc3110fe48e380da71a6b7f0336c4c818a3803126caadd7d3effecccf667097c", 16) + g2To58x, _ := new(big.Int).SetString("381bab5aa65d2b159bb82883559754e5fe26003013389761496d63eea249701c1b1eb742a28f529d6fea8c1b0aa726", 16) + g2To58y, _ := new(big.Int).SetString("7a43f15f319df3d07beadbe688619ac1ca80c76e472ea0d76555d200cc8f2c4e0b9a77065dbd41542d3dc7f0099622", 16) + g2To59x, _ := new(big.Int).SetString("eb3ba48bcae37c9ca7d0c66d42cd4f7a66640f14da2f439b7b1c27a05af916e818ba28eab92bf632f458eb02b962fb", 16) + g2To59y, _ := new(big.Int).SetString("fe6a0dddf3767c9f743eb544204739ddc4f9171c85cedf5f45f94d2fc2124df60c37ea0757ee4fdc98d1289f615b79", 16) + g2To60x, _ := new(big.Int).SetString("f64fccc7b7e1170569fa4ea7de6a25952252fdf82c1de13a3884a3384780d310d2ab52f42a15b46ef642f368b46f5d", 16) + g2To60y, _ := new(big.Int).SetString("a871d03f47a1889ce201513c353519e0cae34edea28f150f76b682c9b361feded8357d3bfdf5fff761ad18350fecad", 16) + g2To61x, _ := new(big.Int).SetString("138b8b61f53ba70e7b76545b01cf7ad7741eccb5ec524efd9d9a40d098c26c5fe99aff1565f5e66c331825dcd2c6f89", 16) + g2To61y, _ := new(big.Int).SetString("11360c12c63ce8faf10c63922afafb010bc325df0ae89fa87b8219dcac998e1add68d301475d12a483c85b48ae67068", 16) + g2To62x, _ := new(big.Int).SetString("18ec134222d187af5a8ede9ce9d4ab16c0a8e6c2113c92d6410e592b84c8df883cc6c05ae301e1f2e3c025eacc52b7a", 16) + g2To62y, _ := new(big.Int).SetString("1294ae9fe885df3c37931412484804feee91610b48fdd111baf15b5196ae8f5b7b16169ddac187c0447eb800127aa12", 16) + g2To63x, _ := new(big.Int).SetString("65813a9ec5492e7d799bafaf677f69d4630e24e47fe86ec0223181acc6ce0100e2de4a09db66616a01b48f7ab8b357", 16) + g2To63y, _ := new(big.Int).SetString("104147600c7118a89a55b524b254c8e14b17487b056f8a25cf793a7e6e4b44e137105a694d5421609fc5fa1d84edfbc", 16) + g2To64x, _ := new(big.Int).SetString("16ca0fa8a6de67c61d26f4263fe963c97726c7cd420b971b60fa3d8f19eeac52a059967f721c3f2f5cfd291eff79f95", 16) + g2To64y, _ := new(big.Int).SetString("1024b7a78a4be6db33eed9b9b0d6281408c344a3b7d7e50abb37b2766d3b6ec53321a398bc4abfb39589d73763fe4ad", 16) + g2To65x, _ := new(big.Int).SetString("ef930907a7c98f8ff74b03a671cf3e9f1ede0cc83fb570ef632f8c1808e03c623eebd12aeb80cab653ef808bfdaadf", 16) + g2To65y, _ := new(big.Int).SetString("163eaed12715d8b4e6669ed4d436ebf5a6e88d194081460ac58c43226c75b07e4d2d46f2afd5d092c5061ed5ada80fb", 16) + g2To66x, _ := new(big.Int).SetString("e55f91871935265fc666add9109b85a295b92dd1275e210e6752b88103551bb4a5054a820a8a7bea707b8152642d0f", 16) + g2To66y, _ := new(big.Int).SetString("3217a82630c2b2dcec5561f1af239b10612bd41f78cd69b109b90107d31c7bf25b7d822c629864c2b9ae95ddd9c6d4", 16) + g2To67x, _ := new(big.Int).SetString("32b0d40116e34b3c7001c348d371556b91b72af41555188ea23d442cf1748e80343e73af832f8ddd660b478aef3a82", 16) + g2To67y, _ := new(big.Int).SetString("190793652b804b0744c796f9c28b4ca77ae6c2c896c0b6420ca4802b270d322120313e4db6baddb5526b91479a69ef2", 16) + g2To68x, _ := new(big.Int).SetString("14db8a6116888ad28268bea38946ba5ddf9fdfec15250a3618f013233b12b2599934f639caa52e14ce78e65e4aca34c", 16) + g2To68y, _ := new(big.Int).SetString("11a146093cd40fdaa65c6ff93b3197cad47192f0645b8a5982a8abd9a15cae80167daf818ee820b02c31e42c10e9a98", 16) + g2To69x, _ := new(big.Int).SetString("721597f56b47a9b81055cbb92f68bd0f856d3314097b5008e255402093cecef95e10f34c66e9cf2c4636a5955f0401", 16) + g2To69y, _ := new(big.Int).SetString("9df9b789e238433aedccdb8996b9013095a5c72debc3d4161dc5517e3139352016137ebe5f1b88c7bccb464ae5932c", 16) + g2To70x, _ := new(big.Int).SetString("542bac3be82ab5260e405a2e37ce13ea57ec69523d412e640d6d44538c32b963d3536abb12d0796508013060181ab1", 16) + g2To70y, _ := new(big.Int).SetString("178910c28886167aaf6a3d2057951e5a046c2a2c90a621eda94c097b1b4b126f1dfe67f5efd496b244b9ebe02aff90a", 16) + g2To71x, _ := new(big.Int).SetString("c86c8ddd50b04e5bb33b5af20301eba97254ffb0f7f2190c2e4dc61fbda6560a4c6508813a74b2268b40af89b15a6", 16) + g2To71y, _ := new(big.Int).SetString("118d6c0fccd01732e48bb29539a0eaa8e7319d29a12cb9b87d76f4cfb0bf3a0a60250e8a3366bdeaafeda261ca834da", 16) + g2To72x, _ := new(big.Int).SetString("10b8803ef93d4428058963d394f1599bfd06ac2e8424ca8e33522f640bfb1f422263f9b3899cd6e857b78dc72d84835", 16) + g2To72y, _ := new(big.Int).SetString("16312e5482b4a4a69868094147c12514d3cd1e35a8e8e8a8fb67a6fbda08280b86352ba638314b0b731325d21928184", 16) + g2To73x, _ := new(big.Int).SetString("c1aa68b66a71e0925208c387cd45504c67c4c75e941d1c575385cb8595c24a24df762e9ff871f491254d8eca147de2", 16) + g2To73y, _ := new(big.Int).SetString("1a1ef925e585988f896c197af7a6b460f379b6eb5afa0b656702c3825b8ddbbc5384aaee6b61a1fea889c908f1b876e", 16) + g2To74x, _ := new(big.Int).SetString("1988799b72da095b8cd09fa266565ea14ac2bbdc8ce0d40c5cfc539d15d09f43bc6b540c598e8e2cd2e480df7f37979", 16) + g2To74y, _ := new(big.Int).SetString("d6f09872112bb080205ba42682dbb7127929850d7040458fb69ada42aa9c493f109a8eed018fb7bf731bb94870c666", 16) + g2To75x, _ := new(big.Int).SetString("985b8f67cd5043f0b04927caced7101f2e2416e1a3e54d9ef503b9f63258b8266e96280fed0ec57a020c9f871fa7e6", 16) + g2To75y, _ := new(big.Int).SetString("10dbd43d1277b59abcd4d63f4faa2abb22cd0630d44ae038b20596dcd5d9be2766621345db48f46d2602784a8874b33", 16) + g2To76x, _ := new(big.Int).SetString("128d9b00c2387f8b958a5e69235d7bc3c6566ffdaf6bf6baf9bf407501a905307b3db4fc93444ce9efefd717e6e704c", 16) + g2To76y, _ := new(big.Int).SetString("7e6df79c1ad8b8c57d71f284a1e9356a67c2211461c84eb277873500ad5f5600416c8ea67a0cb95b6395ede29080fb", 16) + g2To77x, _ := new(big.Int).SetString("19a8c6bec19d125a97a4636e38a9c71c482d1fd2c063bd4ab791fb84b508b2511c0c57832b0631d259b51524b3ac61c", 16) + g2To77y, _ := new(big.Int).SetString("beb651001b47818276d32281cebcacfb23ad81f9af4982bd94e936ef31c0a2165eb2f14ef545d735e04decf9c1efab", 16) + g2To78x, _ := new(big.Int).SetString("c0c3281519d3a66eeef710d61aa05a648c02108d193a0f60d69e4341f3d916eafdb4ff66559e365f44d5c1375a8c4f", 16) + g2To78y, _ := new(big.Int).SetString("1321f3814e3da08308073186aa0bd0e0c4fdac4effd332b58cc91b71d02f9c621b943c3d5d0796def3767afb7b67f8a", 16) + g2To79x, _ := new(big.Int).SetString("90830b4e3531c735e3842b3fb1bde63a7f73b380f9193bbe8ab7dea4af48f08d8cd085130fbcf1b328a3c9dcbe6a76", 16) + g2To79y, _ := new(big.Int).SetString("f509e10a3207e10696ccfa1abe78b556f532d6f5d8803a35186286466d65aabce571dfc3c644a8c448ee6014705cec", 16) + g2To80x, _ := new(big.Int).SetString("10531f514b920d4051719e3341c279e8e5892b73a6d03d7805f81d08cfac7367b3377f575cda8fc69ccb268f99937a", 16) + g2To80y, _ := new(big.Int).SetString("5a8aace529af52e6842a6dd12ef0d34a841a87edd0351f959a3fdf05316a40894b8424f5c8bc48896708a49c04a136", 16) + g2To81x, _ := new(big.Int).SetString("12a8f78469b6185103baf43ccb81fe98768366766da34efbea5ee12eaffe6f4b72dbbf615bddadf184c59326de5940c", 16) + g2To81y, _ := new(big.Int).SetString("60fe8174c79a00c14b389ef1bc853700b4fa990c34ffa2ca1c681c1decedbf9ba688dca5010fe8b7e5bbfe1b021b29", 16) + g2To82x, _ := new(big.Int).SetString("96a56b5bca31bb6f97724d57f7b80380e1f0a2fa32d2226d92c9335971d8a5dcfd765a75cbd2be6b5932b886eca12c", 16) + g2To82y, _ := new(big.Int).SetString("9f33be6bc8bea9511acf18ec9fd8b71025f75150a2ef9fe83b724c0acfe07a6faa7e96e4cd53bde14ae4b96a53ab2f", 16) + g2To83x, _ := new(big.Int).SetString("17862b6d524f16e02a084e9fb0654973aa92da25a0f118ba93df9a105d2c00c740d2169545e7494a1636a7ac086edda", 16) + g2To83y, _ := new(big.Int).SetString("10c1e04620e95976bfdf742bdb03533b7b55046a9aa5a8517e42db7b71aaf00ebb236eee62a1959b96bdad8ccc914bf", 16) + g2To84x, _ := new(big.Int).SetString("2b44930db60c5e62fda1ee9936201d3115c63e40894a354fedaffda074b07c6c54d3035cc69ba2622af4a1127d523a", 16) + g2To84y, _ := new(big.Int).SetString("afda5460f7fc032597d3fc38834540acd3037d394dd7aa3133d0d1082d6758e87c8422f7addfaa885a5d551132b275", 16) + g2To85x, _ := new(big.Int).SetString("7d20b0283582f3e2efb8ef9561e69f645ff108db1a9a94694783649acdaabb957ca2bd76c84714da306f36cf95b416", 16) + g2To85y, _ := new(big.Int).SetString("70a720b8f2f5aa5e9307245d554b599372203318b5ca241656bb133e38cadd215f0d46eac4dcfd144d27d9b1d8fcb8", 16) + g2To86x, _ := new(big.Int).SetString("19c3ef7b33932b842f91ecbee1b588277fdb1a8bb1dfdda304f94ea33b9a07420a1f54dfc6da8ed2865d3132c85fc1b", 16) + g2To86y, _ := new(big.Int).SetString("c5a8a15999fb9021ea63c9141795080d4ef705cb988c4a1c97bba7070584890c6ff6fb78422004bbc86fbb5910274", 16) + g2To87x, _ := new(big.Int).SetString("160475f653c938043ee3949cec0fbde6737e67a4153c900ca8e7c08f17c42c1065b9304f46753dad2c35eb29be942af", 16) + g2To87y, _ := new(big.Int).SetString("d11cb6b0c5394dd2cad261f7846de206762fbde37b91eca7421fde35763f0454277baeae33525668e619e5a2d025e6", 16) + g2To88x, _ := new(big.Int).SetString("17841df9133f6a38903b90a0a67b2f0374207566992a3312dd0f6a1df2213c788a5e716ca0aa49245d8321b094f3cda", 16) + g2To88y, _ := new(big.Int).SetString("4d13e575ddc348796fffc4eac9f510ffe1f079d531c2b524d462cd49384373be208e7903bd8e5c574085355a33d113", 16) + g2To89x, _ := new(big.Int).SetString("13c0591a0f059e36f943d0e24f1c27a7ec66d12057c958a22bdb3583e1d9a50a4a60e4aec16dd586e45275ba543cf1f", 16) + g2To89y, _ := new(big.Int).SetString("4a529fe7cc3a88767be9720803cc8c3ea908bd8b79ec3a635dc6d4a2ff526fa378f5e94f23fc462f67fe66f0727d03", 16) + g2To90x, _ := new(big.Int).SetString("c59e4fae1f057573b420ec1bd61f8be08bc040689990a9ee866b4803d4dc50a9ad832c470a6e10ebaa3c738afa1523", 16) + g2To90y, _ := new(big.Int).SetString("110ca4c030099d03f733ea9de3f674464b4b8ccb2385945a148414a9f95fd4579c630320e27baca3dc7fb2141bf2f5b", 16) + g2To91x, _ := new(big.Int).SetString("763925b8f5ef62d240d76aca100de7dfea130bf34a09f7e70fa74a0978137699840f7242086761595db4b5c844c872", 16) + g2To91y, _ := new(big.Int).SetString("1a7b4929003f677f9194349f5e72ea5fc2594a146405bb917a23b232991da2663763df8eb866603c11025ba823e13c8", 16) + g2To92x, _ := new(big.Int).SetString("773e594f149dd63a3b6180bc3ecd958a142c249a2c554d20a6ae08c4b8218dcfafba746100f395fba248d05cbedb56", 16) + g2To92y, _ := new(big.Int).SetString("170f97f41c75a7bdd7f45885847fb0e9c77482b345d8cdc212e43dcfe3172c4c2ef4f7bf0a85c35833eb0f07404a460", 16) + g2To93x, _ := new(big.Int).SetString("72f4cdc52c410c573a6b6877f123ce328312321d118a743d640a62208fd96ceecf94f5105d216628f327c131cd57f2", 16) + g2To93y, _ := new(big.Int).SetString("d979e10ef5e4bf4b079db8f4b92535d3163cfe65f4cf780f2f588a9ff15a17c2fd99abea87d947b3eba898e275189", 16) + g2To94x, _ := new(big.Int).SetString("1500f73c1580e754583a10830b68534664a92011ecb99fc49a6b8ff8e16403dec02ffc5025283f9daf89afded75aa4d", 16) + g2To94y, _ := new(big.Int).SetString("1123e023b823cb49e34b883254a55c6830213fae288a12638a3c4858db3324a780590a26eca1ab0bfeebe1231c64fc0", 16) + g2To95x, _ := new(big.Int).SetString("138dcd92af7921b62bd16966f89907ae6cf447bff72129cb94b945324fff201ed119837e4c789f7daf5d1348ccb3f4e", 16) + g2To95y, _ := new(big.Int).SetString("b316c8be8dc0963cf075e8ae59b4d8589dfc07e41b22351c5e77fa3ab75fd11bc0a7f16857609bd196725896f5492a", 16) + g2To96x, _ := new(big.Int).SetString("101ea5fdb817941a117aabea37c5409a815c527b3d2aeca08ebdc6888749da51efcc57e0f9413b38ff38937b5d75cef", 16) + g2To96y, _ := new(big.Int).SetString("16c70419efb5ee583789653307a3ad9ef5cc4e92cb36e050fe02d6ab5771c24059ed9042b32d2e3b80dabc9e76dbec0", 16) + g2To97x, _ := new(big.Int).SetString("6b196d937da669209d3180b6e0d1840c79ed567ff337c823075e3fcc0bcefc24be337af22e9a37bd282a4f73b39de", 16) + g2To97y, _ := new(big.Int).SetString("25c43a9d0e59c35eff1e825b2111e1e90b364b8a930a2d3745137a05b054242f377582b02e527a33bf2cb95b6ad919", 16) + g2To98x, _ := new(big.Int).SetString("3496658a2ecc3a834db0fc9d84fae1aa75e0f78f126423216ff6b66880755152b21c046e8c34b13f8a1d62e477b5b9", 16) + g2To98y, _ := new(big.Int).SetString("d479674629f00313a607397c5c90bdf27eb487ec9f04fff1e56a61b92240fdd93ef876dd14c4734311e876ac49f6ab", 16) + g2To99x, _ := new(big.Int).SetString("19a0aa4853b07b1cb768e74c4f7c628f734856a90f598ffd1441f11b1384477a4a05bf25f2d17e152a2417bfb0ae87d", 16) + g2To99y, _ := new(big.Int).SetString("14ce74b65fd7001822b0778c113cde10cb11b6cbd5014f766fb6bc1c2b72a4e9f7d72407c8a47e3427595ad0bacad9c", 16) + g2To100x, _ := new(big.Int).SetString("2044ddbbf0dec33e557caf3f2b88173c44bc9a26bcca970852f46cd3202c28a254fd14d2b44ef1343724691441e055", 16) + g2To100y, _ := new(big.Int).SetString("134e03d8d8900fde4f640624dd05c5f0120559df6bc9dae7dcee6e6a483ad7b749e00d97ba8b81df8cde07b16ad097d", 16) + g2To101x, _ := new(big.Int).SetString("320ddc8cec816f4f1b9d5cbc9782f28457e5034436f318b8bfc4ff5cea2426ca402b2cef332e5d1fd88c215f747e72", 16) + g2To101y, _ := new(big.Int).SetString("12a211c464b89f00c61302c790230e80ff8a3616bce1acffaaef0a40cda2ff68a2657ed5b7dc5025d3c2b0435bd0077", 16) + g2To102x, _ := new(big.Int).SetString("fb79ae0ecd6f1b3f46f5a1f67188388e3292ed3b2222b32d631ac8d6683a10724b9642b255cc3c233b18f8e44666cc", 16) + g2To102y, _ := new(big.Int).SetString("50d1ffc9d8a2e03d7054c716a9bc66d023ab40fe7f460538b27c3c55c24a4459bbad18340f3cea2021df64f0f842dd", 16) + g2To103x, _ := new(big.Int).SetString("1129ea0748cdb9b845b5bc40ed9e0be0ffb8cf89445ae3389d99c6ec446759a58d6c8d27b0576918bae0a58f8f0a029", 16) + g2To103y, _ := new(big.Int).SetString("11546c1a2cded1c9437a93e59dc9cc5101e3464af5c7270ac2b2336130bbbcdf2655b4465428377b805fcb059669410", 16) + g2To104x, _ := new(big.Int).SetString("18c8d9e58d0197ede9759ecd91b67d6b5015d325c7583946865b5d2de5a05adc3203172c3f7411374186ac4b453674b", 16) + g2To104y, _ := new(big.Int).SetString("19dd01ebcd952016ed6385a5394627c9298898908e73750fe55d3a23d84b8287dc2f9f3d9fb7c6648b0f8593eaece2d", 16) + g2To105x, _ := new(big.Int).SetString("d21dbcdc3d7262275f9350c31b675c22d06ab047ae8fbd181fd0753128bf0c8989f0cfcc73100b16a630eb07c99310", 16) + g2To105y, _ := new(big.Int).SetString("19f1f79a45e3f8c0e7052850671a64d6bdc7f98261bb81cd99b7cd802754b47870acfc7e12decee0a08bb89bdf27fac", 16) + g2To106x, _ := new(big.Int).SetString("393a7383d765c36e360dd01d29abdf0715d7168c59cce0efeea765c0b03f29c3a2ff76022a0ae3cfe44f94e7c47127", 16) + g2To106y, _ := new(big.Int).SetString("f4f07b787a555b1d7615ee63ec118f890ba99f98f470f88dfc5cff57fb3f01c077fb13c8703fa538a357b7837ccc19", 16) + g2To107x, _ := new(big.Int).SetString("80122ac51038d1ddef4ac8494a52920e89f63bcb7cd198192da5311acb3fe847017509fb9290f7bf262e786461b9fd", 16) + g2To107y, _ := new(big.Int).SetString("17e39ca2ee4a8eb9f89a4ac907a54209ea8a0b75a9ff6829c4cf98452891166bbd573b2a537cd740f620bab4fcc32cf", 16) + g2To108x, _ := new(big.Int).SetString("9b7138398d7017dab8c04b23364f37d17a61a44d50bff2e05ab096ad0ac5067d30889802dbe92f57b330e8752a8721", 16) + g2To108y, _ := new(big.Int).SetString("b0df5aabf78731bd4990843eb1f349c95670c6b67d2fcdc0fb170736b93b608de24aec60db88813e5c6ec199aa94fd", 16) + g2To109x, _ := new(big.Int).SetString("e091d99dc6037d1f4c24b74d4c4565da3af54c75fd095283cdfafce856e46844d450fb3488d3ba4598ebebb8327c2b", 16) + g2To109y, _ := new(big.Int).SetString("729e298310ea46c8038352f4af4e5ee9b33634f91b2fc252df262c6c39b54496f3b6894ed641bab49b0da26450b985", 16) + g2To110x, _ := new(big.Int).SetString("e3eed427c6a5017599b40f73cdb22e1d40fa9376f301fcf32f64b75fecde7a782320544b9cf3a59df3de15d1cd2275", 16) + g2To110y, _ := new(big.Int).SetString("72598a238bfdc22f2e5791853c64ba305d96051afb1367d57dec6191945c4ad39992dfed2f526f660235470e22d676", 16) + g2To111x, _ := new(big.Int).SetString("4ecb8e157e3531ab8f9018f6b205812ea61410c058a8cdc9a8f74b3dde14ea3255ca1771eb1fb38377cb4a45f5ac97", 16) + g2To111y, _ := new(big.Int).SetString("3ff73af8c95bca6d67fa2d006b8e737a3839b159179abfbbf851e549fb2eb134e6dd1d6bdda529079be3ee37d52366", 16) + g2To112x, _ := new(big.Int).SetString("af7a0c0e2c15f9f0fc230bf9e8dd54ce6e623c6e5e050c7784ce3274fdf2c68615b7b536f1fbd93a6c65d200f0dd2b", 16) + g2To112y, _ := new(big.Int).SetString("11c21280451bc798e2849a37eeaffdb8070b44812fcc1a42216e8261170e6faee5eb2e99a70479885481f868f7ffdab", 16) + g2To113x, _ := new(big.Int).SetString("467bb117e14f72ed478889189b78614ce929e0a11dc4c9fe5f4b3c94460845fc1a93a7e84f2d017ffcd8e766153108", 16) + g2To113y, _ := new(big.Int).SetString("11f478fc0b3d40880188a104fd6db94db06a96a11446b8204c5047f08361dd20b1c6d3b9e8c7683bc93a7e3f9b48009", 16) + g2To114x, _ := new(big.Int).SetString("21040890dbe4d60a532435850be5e3b85be4efa8d3e4b53f6e9b86435fd5b584707082f3f2013137bf7e83e6a6be87", 16) + g2To114y, _ := new(big.Int).SetString("3a46738a14f592e5f25cdb3687f23b572bdccf6e1bf3cf3c087573ddc2ddf56acb0f2f7c024b8f22e7fe215ffd569b", 16) + g2To115x, _ := new(big.Int).SetString("19d00592cb821b60089fdc0963e4d40c1d427a41bd99249b9209e79b15e53b5671f1f002f97b0a3a1a1d87799a065df", 16) + g2To115y, _ := new(big.Int).SetString("13cba57cdc23a8c650025500cbafd661cad5dd269f8569ced5c190ed94d1c97468e54472bdb19d8533c3efc24620283", 16) + g2To116x, _ := new(big.Int).SetString("5bcc22bdd1b8f6bd3697c48899f3c3c66d3ed95bde450507175df4e99bdfee8b5140b2113d09172309e7f92b1997cd", 16) + g2To116y, _ := new(big.Int).SetString("607ba58c3109aba00b398acdb1210b877194e6b658c85d99905af6b762c3a5d0290dd555af824cc6dd58221a8dc072", 16) + g2To117x, _ := new(big.Int).SetString("1fc7f19047611351202a7f5332c1fc97b359a1c521f20afa9b334963467485600b6f8016438e9c51af8442b86c1314", 16) + g2To117y, _ := new(big.Int).SetString("a72af1b9824439482958fd9e3f8fe750cd8409e2d527bcc3542a5e03e46378e7fb745f064ffd357e168234e8477687", 16) + g2To118x, _ := new(big.Int).SetString("7ae261965d9fe9cd01ede8ebdec85bcfd51970aa009425f795b27a625129c51fc4f209d21a43db6cb0f64b3c828c90", 16) + g2To118y, _ := new(big.Int).SetString("e1f9b9bc743372d94c063abf6ba56008f0d07472b7c0ba96362fcebcd267bba72133d5dd9d4e422a2cca2ee2e1a0f1", 16) + g2To119x, _ := new(big.Int).SetString("55838e6a68c9e022b657bf2cbb728021fabe867767bf84da222d2314f94d78cd7fc555fbb2384914daf68aa044fa10", 16) + g2To119y, _ := new(big.Int).SetString("1540e4114abff824399c889d0e259166858a8f950766b071267e7747ea9580ffb5d3b03d41ca558233eed812e920af3", 16) + g2To120x, _ := new(big.Int).SetString("944b4fc0ca112cfa7ac887aa61167fea6d2be550b52c31daf2b43c732bc3cca9a23bc7b7b9767eb59f2c15d3f53ecc", 16) + g2To120y, _ := new(big.Int).SetString("e10c7dcbdd84002e7da14bfd1337da7c1acd68c7604292020ea4756bab5dc9c29be790f59e9f19c6ddf2063c3b9ddf", 16) + g2To121x, _ := new(big.Int).SetString("1814aa8084352ca9646edc03f3a666a49d6c8c6b397c75a3f2db4e7367c961eec704d60b2f056ca622eba5e7d5aed17", 16) + g2To121y, _ := new(big.Int).SetString("1091aa493ba3e157ca796bbbda78c2a6173b353b98bfdf64cad515be0633dda924b04ec769a95a7b9907677210f4eca", 16) + g2To122x, _ := new(big.Int).SetString("4c79be993599aa6f2cc588c9a17729e07fd443b5d0be7d71e6374bc1b6cd7853a8d5cdd2fd1f355512cff3abd6847e", 16) + g2To122y, _ := new(big.Int).SetString("17969fb3d5c1520400aa5f89bc13dc5553bb16fbec5dc3d3b05719c593201b2384c81a3e52b72273ff4a7e10d17ec66", 16) + g2To123x, _ := new(big.Int).SetString("56e4cd225404894800e1a17d0a9b01b6210ed3e42d8df1912c77772ac47cab49b52054a7c3f6ebf8f77c00ccfcb888", 16) + g2To123y, _ := new(big.Int).SetString("48996d22cb69b2d6a9f29ce0c1d8bcb75725b77caa0f1dcefb6523d5f2056399c9c19c3eead6480dba0928cc691c8e", 16) + g2To124x, _ := new(big.Int).SetString("1795d38c0f3168e622a236ae402e9f1ae6b13fde7b65429b03453066489e147213b8ee6745ddfed915ff10fe780742c", 16) + g2To124y, _ := new(big.Int).SetString("5873e3cbcd5dcb0ece242388d565088fd2181264fad06534c9416a887f7eb115fe259b97987bd8bd794fe1bff88187", 16) + g2To125x, _ := new(big.Int).SetString("117f497140d0e102b9612a0c0760c5fae1bf451a40501debe6ff6a0c6bf0be1b0957dbc274f4a2c3d5b0db48ee39ca0", 16) + g2To125y, _ := new(big.Int).SetString("380dae20e3f1e6b897371384a44e757a2d7a84df6666e32cb6c8fbc5e06e762d27f9cfd6ba1459b45fb327432e49ce", 16) + g2To126x, _ := new(big.Int).SetString("bb69b209c8d3382211895e4f0c0f69efbbaac9b51bb76793fa50acc1254105433e8afad7511c492e6e864480fafd61", 16) + g2To126y, _ := new(big.Int).SetString("85f238d05a21136f7f88114e7cc8cb2e7ed0be3e4b73dfd1be654577ff75db8baffd94f1746044efbba8cbe219521d", 16) + g2To127x, _ := new(big.Int).SetString("19f732e83c5801519c11076d13d81be227279802aca85d79a7c70ab68df622942e496f46e175b88c4c3fc5fde7bfe31", 16) + g2To127y, _ := new(big.Int).SetString("66d4699239e91cf083b474b9e2eadda2754630528a209d7fdde9018dec26fc93c039c9315922abe377f6b2739d2a8a", 16) + g2To128x, _ := new(big.Int).SetString("e4792c45ea0374775d9005fcfca11a9cf28cef25cb45c4ce3a4fcf88fa648378d0473f07ff1a56a9f3b7a593fe5002", 16) + g2To128y, _ := new(big.Int).SetString("1acb4c048149b23c021e9df25fe5b3fc54b77d3f2295926565b6179955af9dcc41d53713878d285916f2e01c6fa6e31", 16) + g2To129x, _ := new(big.Int).SetString("18af57cc0cba6db0d3c81025895bb6c552297a1ff24f5fb93e01270405c3ca1a010f3cf3463f03893e45d68bc8a2f62", 16) + g2To129y, _ := new(big.Int).SetString("1fd7cfe2078a0e1e79ee9fb7877872c382fe387ccb8797007654656774e15bef83c3f55928d5454e620fe073de20ee", 16) + g2To130x, _ := new(big.Int).SetString("12cc5b7441a487be214269e527ec1176f2f6dde1bd1fe02a08fdc92410c91d8d883fe9f7151c19c235e9dde01f5d9d0", 16) + g2To130y, _ := new(big.Int).SetString("67dbd3814cdcd0c12ff13eff08e790faac9b3c9895a233d71ecb5399c16983ea1623fc1b7422c061d9c7338e82108e", 16) + g2To131x, _ := new(big.Int).SetString("15318da6e7435d4194e5253f4bfff8adec4aab7304e49182c5d3a1ee498d800cef3e3a5762d8d6e7029a8b396e5df96", 16) + g2To131y, _ := new(big.Int).SetString("557ecd16ceb9695e6909571f371b659738fb6e61e69b73fb7b932a88e6c064cc73191053606716df7747aa07ebd47b", 16) + g2To132x, _ := new(big.Int).SetString("320b3b8315d2f24baed0ead61c7ef235b7dab1b76a3120c99cf15ff76af149aaa37cfaf7751ed74d541aba79f7485d", 16) + g2To132y, _ := new(big.Int).SetString("1580b7920ee4b3407677ef153239024119a12cbd13e9811e6a1736dbb03a873b4bfd2c8bc897f94e94a01eecd6dd3fd", 16) + g2To133x, _ := new(big.Int).SetString("9c942c27e37b0eea666d85dc58a566e900f88451e4cd3dc5133a62f6dde3a5c93307f3c86e7d336573a95f38c86448", 16) + g2To133y, _ := new(big.Int).SetString("48250ddc92820ecd6fcadcca3d6bf73dd4d6bfa66f5b49bc59001574b09f05f99e74d3ea9f91c8579d7f38fb2c8763", 16) + g2To134x, _ := new(big.Int).SetString("15ebc88aac7bcbc57c2b057692e1b99cfc9ad13972d89eea008239c015b74ecaf80c889f65ddb8129f321b214f7e599", 16) + g2To134y, _ := new(big.Int).SetString("80e4b8b7ba1a7c5f1de2b62f64ba4693652a307dd9b1a92252c4291c69335cf0b8c6f8561a15462916c24a78141823", 16) + g2To135x, _ := new(big.Int).SetString("18b3a334505d4c7cc8b4f906dc3496316d8d02c128fcd88ca1139f09e0957a3d7360aa03f19d9aa9e1ca509ed0a7287", 16) + g2To135y, _ := new(big.Int).SetString("50899b31fb24615a49ab0f49bc38371ddf1ca7982cf30b43c929041bd16444ed13d4a851943d195275c55315a6bc4c", 16) + g2To136x, _ := new(big.Int).SetString("324957c3564d435c9e28916ce384b568bad35e8da0416becf4dcb8d47a5f9b99b59ff84e2f3d01306e32faf4ec1b1e", 16) + g2To136y, _ := new(big.Int).SetString("180b670ab4b14f4af15fad06c063199c831f15c730fe1ef169f2a24ee3c87ea18f9e8ea393b3ab693de860a3c3b19e3", 16) + g2To137x, _ := new(big.Int).SetString("55bcc692af3a8ed7313777f1085effcee98ddf6bdfd0a4cbab5e805c313b15a637bbe3097fd4328bb37c922e8e8d0", 16) + g2To137y, _ := new(big.Int).SetString("14ef17878c43aadf2bee219d4d4ac616ffe2bb2ca85c5add0e091ba5e4471a2e9a4324a02f5aad8c497d19a339fd64b", 16) + g2To138x, _ := new(big.Int).SetString("1d282049941b376a7bdb9b0e81c5d5fc6d3df7c4dd9059d02bee35ffe56481afd1911ce2efc80384f2221145747f84", 16) + g2To138y, _ := new(big.Int).SetString("12d5989e164bf32bc49ce538bc2185f3ba43d10e5bc5865cd523ff3681c14cc4c77a159dc77e909dc4ae17fb16c207a", 16) + g2To139x, _ := new(big.Int).SetString("cabdd2d555e7fdbf15eea8d9e879dae763b74813ca8e7e7201222d0163f7819dabb4e9a177d0215c8ee0209f818e3a", 16) + g2To139y, _ := new(big.Int).SetString("b5e9b30c2bee3862bcf355e0ae8402ceb6e595557d1d89799f9dac25e857690d6ab274d64f395b2e1875ad09a5f7c4", 16) + g2To140x, _ := new(big.Int).SetString("3756b96f44a0b8d81e869f8105fe226a1dc0c422b372ef16bf1c960151838075fc1d0be337631b42bd7a17ef158c20", 16) + g2To140y, _ := new(big.Int).SetString("185eff03736ded483448d28e5e609429609ff67094f880a79f9884a77ae121cef32aed642a1664ae5a0934e80e0a791", 16) + g2To141x, _ := new(big.Int).SetString("83abdf9576124e1579a07d704dfd0eb68b3eaef853a00d9ed7ce519bffd0f016b22053d2eea2478f69a668a26ec6cd", 16) + g2To141y, _ := new(big.Int).SetString("1a23389ceda0fae24bc826d9cad8cb0791f933d6d5fb549c08cb6a6fb420a9b2925a221b7a0d3c7e2078d728ac03bfd", 16) + g2To142x, _ := new(big.Int).SetString("1025af987dc0aa4594bf71b342b71dfa9be8ea9440f6cb940288c14fc53926062169a28fc6f968f5a06cdffc4c2f3bc", 16) + g2To142y, _ := new(big.Int).SetString("124266250eda81a840f60b00c5332d52404e97c4dab39fc2737fe972bd800ec451dcb55aba8f5c8a9bed1e4ed9e2f3f", 16) + g2To143x, _ := new(big.Int).SetString("f95cfdcb19aff123335c9294fa46f7df5585001076640f0306c04c5b7f826e314776ab7f8428e8e24d44cbff92b135", 16) + g2To143y, _ := new(big.Int).SetString("157fc1ecb3d469a07b6319864e2b0cdaf20b9ac53a34f2af7f960d6feaaa2c1c063e2b5f39256612f8517f6a1e8488c", 16) + g2To144x, _ := new(big.Int).SetString("d3f7e41e0d6dca357b0eb5ff58ad3edc9eb4cc825d96fb2db4c13bbc26d85cedd3d0bc1fc2259dff6493b150e7018d", 16) + g2To144y, _ := new(big.Int).SetString("14cf7eb25efc61049a02975c507595406a02915c85a361e72aeadfc65f647c576d87a28822880684b9e6f486d9341ac", 16) + g2To145x, _ := new(big.Int).SetString("d76126e3b8f6c41767722603e99dacdc2c07a20710e51da646d473fa0afebd76c30c230b6ab66539ad5813e7207f1", 16) + g2To145y, _ := new(big.Int).SetString("8ec28dd0b2eb92af66344e8beddf6b47962bf3564c4ec460261683910f35a996e48b0aedd1b4b204600638d935c85", 16) + g2To146x, _ := new(big.Int).SetString("1501b1cb3bad5faa01786c85390ea937130f8045f0c10c9dc2bc81a5a8f3dfdc6c44c38386a18c6aeaf32ae615628fb", 16) + g2To146y, _ := new(big.Int).SetString("483f53ba6eb054817101d01fd4b93c84dfbfcb4a003df00344798866f70c52bb53f6c1344f3727116b3eaea6191fcb", 16) + g2To147x, _ := new(big.Int).SetString("10086ea020c2276607abd7656c03d5ed96fde894a409d9a409fd363298da9741231e8d3ac02baac482431b157ace447", 16) + g2To147y, _ := new(big.Int).SetString("3fc52b9384c8a28f37cf21ad02c24a39f0c52d6c2bcba1b2ee2b0d0bf0093b7185445241f3dae009709d8c82fae8a7", 16) + g2To148x, _ := new(big.Int).SetString("42241569f4225c2ab29b43c20f2f91646397db50d2d48bc19c13a98b72c3cebd8b09ab7cd1e6d82a9f427b0dd6138a", 16) + g2To148y, _ := new(big.Int).SetString("f945aad154d8008cc453a734e92166572a3b0e2ec1dbfed5444990999849908c709383f23fa31f436bdfcedf11b75f", 16) + g2To149x, _ := new(big.Int).SetString("c9f67f6dbc91e05e5ddf0503a62858c29d86a0d183dac66a834a38c7351152f4a391864afee16226a94ab3c1a7c42e", 16) + g2To149y, _ := new(big.Int).SetString("a6609b594fcc8075bb3a73ce66bbf3b7665abafe4017d176067af46f52f5a9116644bfc0e5bca6ee1b8ac8158d4e12", 16) + g2To150x, _ := new(big.Int).SetString("1153c5af141928d2fc95e766c33dab8feef4b9130700659e5d8f5efebfb043d73ee4337c5f0fc733edc4539698a4a15", 16) + g2To150y, _ := new(big.Int).SetString("e12d0a44494b847726c36b27f89e9ad39e6550ccc1e4829f792a8ceb51eac58b8bd434c09111dd81beca462de88c2b", 16) + g2To151x, _ := new(big.Int).SetString("3c5aaf47dbcd0dd23a0fa0c2051ba8c3d0fe6ac1eaf40188bab2f9de5927217944a7c102ab828718ac8e7661b10d11", 16) + g2To151y, _ := new(big.Int).SetString("1776473aff44785cfa49c3c90d715081e987acc7652039db8a3df404b0804c124319dcebeed7da580ee9082e96cd671", 16) + g2To152x, _ := new(big.Int).SetString("14e85d6dd8e43ae3579caf05c4f60311bbef732d30a4adabb4718b14651f7cf649a1b211425e46a462cfc774aebfceb", 16) + g2To152y, _ := new(big.Int).SetString("12a314ef9a9376289103bce265dc11be2a3cf93080568d3b2a67e7c78e78950ce35338169501930e5e59c162e489c31", 16) + g2To153x, _ := new(big.Int).SetString("3bd85a843e5f7cb348c19ae3219a3ea7493b615acfdc2df784a5b386e520b0eb1b2e9b91431d24917a822bf779796", 16) + g2To153y, _ := new(big.Int).SetString("cb11b6ad47b64ddc1968ccdcc60f91159879bb11ac7b035111a622e805b33d81189e8f695df8e7f181f1751fe6f7a0", 16) + g2To154x, _ := new(big.Int).SetString("10e41425e5297f70eb296aaa09c5f2ba87f8d22fd05cb0b8a984441b4b9998bd896af921f19f8b5a2a9698e24fa764e", 16) + g2To154y, _ := new(big.Int).SetString("281547615a1a34525b0910a27a705f36b1fbf2629284007c1842ab8259d9c7fed09ce955d4923710275cacfdbbfc42", 16) + g2To155x, _ := new(big.Int).SetString("24dfaca436700b2a28321fbbb35a8a8710f0b53506da3444d25d7258c3557a7f04ff4066c3577a382b78cfeffb1fb9", 16) + g2To155y, _ := new(big.Int).SetString("17cce223736ad9349c8ba8e85fc84473331f94573d220051df7654a37ad183c0ee66cc65f21870945ccf2b3cb5a4a3a", 16) + g2To156x, _ := new(big.Int).SetString("108ffd6cd88e29e760c221a6a8630eea55741e4d69cf25bb18d27b48c142ae6bc909578a243af518fc431ce17632763", 16) + g2To156y, _ := new(big.Int).SetString("7a4007cbf16132fff1cc4672297bbac19491404299836b6f0462ca11b230f6a170a353bad9bd6cccca1e84e76104d4", 16) + g2To157x, _ := new(big.Int).SetString("127465b15bbe5570434356ab8b9a4288f764b9777d9be89b52d93af6ace9f18d79ef8d26fe686e935583bb1b35f2662", 16) + g2To157y, _ := new(big.Int).SetString("135739c799b7b80f38d3973e2c1a96519d0daf16e384c2a6e988bc9c512feeb36025dcc0bafbb4029a0baed39d08977", 16) + g2To158x, _ := new(big.Int).SetString("a47d778a09e9b91e8a66e1b7ff48855de7c086c22e97e2a33d78cd6ac0f03789ef65ad6c42bd7469d79e8a771b3014", 16) + g2To158y, _ := new(big.Int).SetString("19807686de5ade7f78c1e92df43e146f59458f7a7ed3632917bcee346a09b17c771c0c30ebfa30eb574db51825ff2ff", 16) + g2To159x, _ := new(big.Int).SetString("553bbe29a93925cacc8f63a35bf3111930ac49d6cf6c4748690697385b9beaff873f9d50e737a67035cc4630d304cd", 16) + g2To159y, _ := new(big.Int).SetString("7ae6ac5a15a6904163bd3f4231aecb2a3ff35ac04dcc88dcea26054957fee459b1d655210c82492a91d21e9c62eb86", 16) + g2To160x, _ := new(big.Int).SetString("15f77fdc47ab14c2101f763260f537f2350f2fd32bf1b2f27451524a2559baf8e683aa0362294c1e8c3f50e72f9142f", 16) + g2To160y, _ := new(big.Int).SetString("9d4009700bcd44218332952b3d1d7f2265e8e554bb6e991929b1e96d9fdca23b05acf0b70c7af4b5840f90c11371b", 16) + g2To161x, _ := new(big.Int).SetString("155082f9a8c24a6cf3200452141640bec8fae3a269872e4f535f5f58ecb3ae9789133dc3707cf1936be2461c942c1ac", 16) + g2To161y, _ := new(big.Int).SetString("16fab5585ec39985e7372355d7911eb1d3ab1fca71e920504172278c1a61ddb3d9959e0d4a61aac70d322f5c145dee2", 16) + g2To162x, _ := new(big.Int).SetString("3fb08dc59a282d83866eecc906b694f1d92b24e87658814ad685cb6b110b749db7a1d7c0185be7b4c8a325fb7bb6dc", 16) + g2To162y, _ := new(big.Int).SetString("3e98c7707613366535514c7bda8a9d20f4102fd81f3fcebe6734aae4e231c937b46b23d823b960cb8040a8287dd5bd", 16) + g2To163x, _ := new(big.Int).SetString("133c8d89b872593cf25925ba8d7f240a85029eea7006a58388a6f7549efff747a9f5f7a44f7016854ca345e8620e7f5", 16) + g2To163y, _ := new(big.Int).SetString("1028b91b8e2f13769a0190c0e9fed0d842f0c3efd531e5df212cecccfd314e189d56d54565cbe206c2ae326b882dac3", 16) + g2To164x, _ := new(big.Int).SetString("6422c61104e62eee280da427bdd2e91fde9e9a1f9df8d77b1b0e91ee5db2d2ade3c6986c5e8c0ec21035ccc35f93d4", 16) + g2To164y, _ := new(big.Int).SetString("18cf5bf95c516e422ff72afb2df3d1f99b08fcdd69657f5ce7ab8bcf6a8f3eb717dc69a32ffd79e048b7d45bd353f7f", 16) + g2To165x, _ := new(big.Int).SetString("bb49069be1114cd86fb632d7e3dfb7ba79bb3aa8e842298169ba74a53f61e182f27cad88e6c8b243b9e068120e6cc8", 16) + g2To165y, _ := new(big.Int).SetString("b50b69c4b23b3e07123aadd4119784e70c32735424b88094b08c75a456daa4f7626bff7daa51f2c73d30ddc5318570", 16) + g2To166x, _ := new(big.Int).SetString("12a19d3de6d72caac8d34bbd6e90546ec0a4009e574be029a66f339500bbe021b34383e410617fb0a526591286e0643", 16) + g2To166y, _ := new(big.Int).SetString("9b406052873481fafdb61a8adfc9019e48faac87c9e44121af21f0a4cff2774798e28fb783bb8e7e31dc4a313d7a91", 16) + g2To167x, _ := new(big.Int).SetString("10906d84db20b228bb0388b23ce4488e21775454205d723df5a075c51e4dd153774343fc43b58075de945f24bfebb67", 16) + g2To167y, _ := new(big.Int).SetString("7cfe72c84ca6b9dabb5c139ba427cc47e87b4ba07d24d410c430a2b9b5c6b7f9237bdd5fe199be039d8181b2d4649f", 16) + g2To168x, _ := new(big.Int).SetString("910bc0e25094b13d6e04b32302f247d99cb4a71d9a1d8cdc75a467bdce8160d8af85beccb93dabb2cf1e15cd359ea8", 16) + g2To168y, _ := new(big.Int).SetString("c3d5f0eecd86b5f0dbfa46038cf379197d0112e674dd50f6071eb9b787d000ecf2b4ad8717af94fdfc8bc162d91345", 16) + g2To169x, _ := new(big.Int).SetString("170f6e8c17ee0f447e7c56000ec81b125743fc7a71c61e099d368c89d7e9bdd6f91b9828865d1c21bcd01f1101e13b0", 16) + g2To169y, _ := new(big.Int).SetString("b4179cea51ddb18b7f53b44f96c32d409a5170ab59624bf81562545d451ed3a77e82287d8331b6077b76c920a79de7", 16) + g2To170x, _ := new(big.Int).SetString("5f3a211c40201fc17f6aac6f9ca51bf34e2adfe0c385fe9434db7e711b1c442fe8342da2f3ae012b26b932c3fec0cc", 16) + g2To170y, _ := new(big.Int).SetString("16173a4992b83b3a498bbade3c171fd251a1877fca293db16f50fb73cfb410c67c98a21c8e39c6f2ca22547a0096cbc", 16) + g2To171x, _ := new(big.Int).SetString("c4eb3ee27f8b8d47854a14084f3165ef885d4ef7aa848263e8e08326eb8ff10931e72237a46735f5b1abaf11850dad", 16) + g2To171y, _ := new(big.Int).SetString("ca881eb1904d3980dc3ad9e49dea9feb0333bb8f61b3ade8020a7108379fa9289e17f86ee0ff5ebd009dbb873bfdd7", 16) + g2To172x, _ := new(big.Int).SetString("bcace195e9b15a115edd0bc6cb21722ad3556a8945470c1a556bc83e45a913f9155febf07ec47769b47b8d5d6b2a40", 16) + g2To172y, _ := new(big.Int).SetString("14c699aa9adfe467f3977c6a1bdcc34029160b789d11d5e71980d044fc23666678cc2cb79738b6baa607ee733b3c8da", 16) + g2To173x, _ := new(big.Int).SetString("57e20231567347a7749584f82ad2ffc059698f0c4b702b9324414bcf5aa6f46a4462429172ae83f72512d1d8fb9f69", 16) + g2To173y, _ := new(big.Int).SetString("14581ba8e6fdb0222ddd92a5e87bf666ab7ca5cb86ca699bd16cc5daa67d6ac01afb81f266f06f4ea1f38b0aab90c61", 16) + g2To174x, _ := new(big.Int).SetString("143afae29780766b112a5952f024ae3145eab24719ec21babc615d8547634c5d4636389de5b5d11cce1143016efcfeb", 16) + g2To174y, _ := new(big.Int).SetString("de662f6be83569140af7ba194adc87b5bcb4aba0adcb4403884b64e7e89625d04f0028a80c2f2c9f8dc9dddf23b181", 16) + g2To175x, _ := new(big.Int).SetString("3bce098b21d2e1f1296592746475919ebf66ff784482579e32c9118ed276f978dffedf3ef07a77947b7d36f1ea93e3", 16) + g2To175y, _ := new(big.Int).SetString("9c76e0c83204761988945d5430ab3389502b8778103529176ef2ea285fee97c40946d4ef43f105f91dbf1222bffe0", 16) + g2To176x, _ := new(big.Int).SetString("e4bcab05cf3ecfa042fda48bda025cd28ae2e8b121c82cb8c35986605d6f2240eb17c9b9c27169095736d0198765f9", 16) + g2To176y, _ := new(big.Int).SetString("18555a4c275a57b24968df3885cec2c8feb1cf1ccbbc2a1dc5ff419b71a49abacc6a0167773590ab998bf5c2a5fc653", 16) + g2To177x, _ := new(big.Int).SetString("497522e3537513af8ab51673eafa636250d1ea15f90b2028bee227749c817db9d7094ff36ee24057d0b68b4b019523", 16) + g2To177y, _ := new(big.Int).SetString("c7735117d127fb022a8a3a6365faa220271467a986daeee92cfb913d584aec1eb93ab57e98c6108b225a83af8ab69f", 16) + g2To178x, _ := new(big.Int).SetString("1076cfe5560f5d378308b02b4b23efdf3f6f268b885340ffc6f3aaae8bf5b301aebc22939c012e0616bc519a34f318e", 16) + g2To178y, _ := new(big.Int).SetString("985107e1e9d76c2608d6784589ad58f744f7b8ccbf591e969758100af81f6c6cc751b35433af724e4aacaf48fdce39", 16) + g2To179x, _ := new(big.Int).SetString("e41cf5effab3711d615699c7a1aab2cf8aa8daf691b96b52449ceebc1b57cf29c74f782bd7500894e49ab1ce06e8a5", 16) + g2To179y, _ := new(big.Int).SetString("a8d52e34491822c0de9ed308007713d32ad8559f3ef8bff3d856f99ea1babc568f0b2a86d7c68a70f4dcad5a50631c", 16) + g2To180x, _ := new(big.Int).SetString("cc71f17e685ad819201a2a96b89fa2f0badb410fff58e2155407e08a0ce68f6e8fa26e083efd8233c6ee5517d095dd", 16) + g2To180y, _ := new(big.Int).SetString("a9381762747bb275934bcfd6c4023a3a2a140e498e16cc66ebc8460b218d590287f3eab54d885dbfac38ddaae6acdd", 16) + g2To181x, _ := new(big.Int).SetString("2d13c1f441c3a5f19d42c26699ab14fdf28a6b8dcd508e5f543a2ac444a5b0acf4228cb19f9e8e306f22dc3d6baa26", 16) + g2To181y, _ := new(big.Int).SetString("13b1d26048011fe25c9a47331ce9367876e2d9265eaa1d99135b942fa8312e7e57d7520bc7df9d6312e4c3835c2f174", 16) + g2To182x, _ := new(big.Int).SetString("19b39844d9593c8e4487ce996a33cb3dbb12c719750dbfaaaf0b43014dd8a48bca668bdb223741ec35c3f7579e8f930", 16) + g2To182y, _ := new(big.Int).SetString("d3e8168b65f3e54fcc0a390f176fb4e44845640a59deebfc5a27df65ff45b630d5b266a579d514794540000aae7d3b", 16) + g2To183x, _ := new(big.Int).SetString("b21d5c905a554590574da9b27c20b139ecc9ce777c62c35843f917a5f74dd0804e2035cb55262897d02f755ea7b68b", 16) + g2To183y, _ := new(big.Int).SetString("13364bb242ca69a09ab5433e0265a6d987539f6741bb66d393c6d1bb1e4a0378bb51c976783b25c5afc189de3a5e5ea", 16) + g2To184x, _ := new(big.Int).SetString("19e679044a9eca80829f98d71bf8ca98b1cdc60d0cd7cc8957e7865479ba79fa7608ecd608392f9293739f4d17aac3e", 16) + g2To184y, _ := new(big.Int).SetString("18c81a9bdd6d8e094e5192f7e4cfc90644260c334c489db57bf530185021e96ac4af6fd528337dd07e298db4a7de0b2", 16) + g2To185x, _ := new(big.Int).SetString("369dfd6ab7bf26a8d4e5d64dcfb3b63d455cf2ee4db02f7c7683b6bca035ed1100832f60313db7deaecb8251078873", 16) + g2To185y, _ := new(big.Int).SetString("44bafdb818f8499bb51328d51eb1632e8d14ad7152353f9a9b2d9f2fff57d3e994a923c843a4ffdfdadc46132e7d26", 16) + g2To186x, _ := new(big.Int).SetString("15ebc18f89a2b6fd6ed009fb65888d39a071e3fda69dd9bcea7578ea66689c08d0126947da592298137ddf6dfa6ec1f", 16) + g2To186y, _ := new(big.Int).SetString("127b260a21eb7668c14bc43e4235f7479af7043c32872b60e1038b37bfe1315aa7205fd1a8cf65f2836e6e8e374bf28", 16) + g2To187x, _ := new(big.Int).SetString("bcfc9e711ad2a3a8b6990a3df74642db48922f04dcb1a26bd88ce4c8ccb6d79914a5a29d33334b0636338fc2a8047d", 16) + g2To187y, _ := new(big.Int).SetString("9da171650b66c067d1c41602761278a215fd2987eab435b3d0882737189cedfc1972e9199f58a6d6c1c1d70bd393fe", 16) + g2To188x, _ := new(big.Int).SetString("d898ee857af4fafaf02b327345d90e824b964b954bd7366ad05b6a1c5d14acbbd011214b55440f87786de2a330c131", 16) + g2To188y, _ := new(big.Int).SetString("ceb2ff631bd5b2eebb78bc9bf5ed6ca1fa088baa3608bd202fc8ba88d88baeb6d2410fe89f2ac2cdc4fe615150cd0f", 16) + g2To189x, _ := new(big.Int).SetString("1047172b741e1bb646e4b98defcf554691d16d7de036d0cade3f72387a0ef2175206a55f5000afaf1fd5fdd143fad0a", 16) + g2To189y, _ := new(big.Int).SetString("f5b5d94ebe0e7fce2ccb9cf9c396f8a83367f4c80c45428222560d0c28f14153f1d302812cbb939c06e2e8f60f6dd2", 16) + g2To190x, _ := new(big.Int).SetString("abc14aec8a9cf6d7b1344f4a4e65164e1abcf369de4de55d20c91e966d4aeb11ed24cf663c60b7bd7a88c79cf5c623", 16) + g2To190y, _ := new(big.Int).SetString("7cc4b196c7dfef20b1ebc9e5b03385311bd591da7fbdd89c05ada304c99ae780eac02895fb6a5f01235208b71b4298", 16) + g2To191x, _ := new(big.Int).SetString("13f43125659111895ca3e60c4bfcdf74ed7c261581b2b077730a4ee2a50ae5fe948e4a597403b3368ddf58bfbdfa00a", 16) + g2To191y, _ := new(big.Int).SetString("d3bf81b2e73d05debda0abdd73ce206b8262a5ba42374cd350b6e7f67190d2a59214edc1df2aaa4f5a4a53f2a5dd37", 16) + g2To192x, _ := new(big.Int).SetString("12d30265ab77bb06db58babf408679b92e26fd367391b38a926b91bb6ec2ab6df0c3f4efb10f89a99474010a949b27e", 16) + g2To192y, _ := new(big.Int).SetString("18d1d446266830b4c625c3ccab5b5ef7c51bb10f15ba024ab9c7978996ab7620332b020e941e0f80d69d0a056af7937", 16) + g2To193x, _ := new(big.Int).SetString("6966169e2a61337377ccb7ecaeb7942adc5b170f0a1c1c5df11aa259b41587d9febafb4a901c8b005b5a0faa2baea", 16) + g2To193y, _ := new(big.Int).SetString("11ab8a505040f271f4fb7a90ff298e64dda579761ffc9ee299f01aed1ebecb034f541388d84f8bac4a7d2a72986864c", 16) + g2To194x, _ := new(big.Int).SetString("c55aeab8b28d83fd4804f4bdd1cdb1e5516015ce22af1e110808eb6796f62a48fe8eea251d514e887650dcadc39def", 16) + g2To194y, _ := new(big.Int).SetString("177c839def54a86f879deeb5f15c5dddb1c6adf3a3c1bd9e4e79b4d8b26bc43ede744075562d10b81a240138e8455e1", 16) + g2To195x, _ := new(big.Int).SetString("1105c20f194e40e47ddfc67d3c2847ed841f63e0e1af6546f73af72f260b11fe3fafe46b3a41686d110cb07be24ab33", 16) + g2To195y, _ := new(big.Int).SetString("714b782b7923dcbbb584eeb469ad872536aca104ce9bd473428e567af9b55a7ccf5a5fa9d56185b3ffe354b4298a01", 16) + g2To196x, _ := new(big.Int).SetString("1116c55421ef7370fd3656007023683a9b495478c870adfa074313df8187342031cdff474041f1651a73f4c9ff709d6", 16) + g2To196y, _ := new(big.Int).SetString("80791ddb2418bb4685fc9f4377b63b92f3c66d120b7c97d857f78886a501e1dd83f047a49f420b83b6957d2120b71", 16) + g2To197x, _ := new(big.Int).SetString("3df18d8a4dbc6781742de2628cc12170472db073be5804eb3606e0cd713f55536c35b20a060c48c0f51c2cb1f9af3d", 16) + g2To197y, _ := new(big.Int).SetString("3cd17e0a2f9bc57321467dae7f43b78b1c902c576558ff1fe389b5d5d570f13c0802e29b07e198c6b0ae18be8d39c2", 16) + g2To198x, _ := new(big.Int).SetString("3f21786ce8f4fc420a75fcbef2f60e48715f80da3429d88289d7d5d1366c76b3786d6541f281913d0847c6f4ce84a2", 16) + g2To198y, _ := new(big.Int).SetString("1419f8e19f28ae0d6bf54763dadc5861b16affa1c7e240f7ab7e6ec22b06edc07fc36912953af41850c2726bc8d79c1", 16) + g2To199x, _ := new(big.Int).SetString("118eacd4f99a7d65ea1a055bb139ddff1024284c1227afd27cebdf2a44ffd5272a998b390aa73b4f54f19898d460976", 16) + g2To199y, _ := new(big.Int).SetString("47e50aed98571fb91415d84c3417b6a0d17d990046112fae29005faa6d2ae98b1b9464b59829c0ae715a65d33525b2", 16) + g2To200x, _ := new(big.Int).SetString("cf4908fda94aa06c04d26e30491ac30ddce9a6a3266555b5686c1720120cdecc3ef91e7427f622727e79b1b86f8797", 16) + g2To200y, _ := new(big.Int).SetString("16e19b5fc4ebe0bb8abdb30aa933b8cef3c87c09a0f23ca356fe55314dddb83bafbaa7531641dc5cb8021f4ad5f6c4b", 16) + g2To201x, _ := new(big.Int).SetString("380a1af45213129ae237fc6da75d4982eb6636e2268c81379412961651ceb218a73290294dc28a44c38d6c9584a3bc", 16) + g2To201y, _ := new(big.Int).SetString("69fd537c980b67e523b0b3f3fde7d8538f96207be299b6752ffced4e8f11d7e0a325d8c86671cf00b91829c9bcd5e6", 16) + g2To202x, _ := new(big.Int).SetString("5fe086b1c4b10505db63f342fb415f6d6861d07ee468d3349e163092ab5e030033a7fdc2107a93747905a44cfaad95", 16) + g2To202y, _ := new(big.Int).SetString("41a6b3dd31fe367f16863e68f319627c8a3acf4bb80248f5abc4401afcfb333fe97ab35da581cf251d0991e9b57e49", 16) + g2To203x, _ := new(big.Int).SetString("136776a77fc774c7786b3ab805bd8497fd6c8e798865a250854863a5f05efa4c8c6c1cad56b74d5a8de2009b9de5847", 16) + g2To203y, _ := new(big.Int).SetString("1960e3ca3276ce29fbfd5e61985740c9e94baeaafa3c6ea8648d502e76c4771d91610806cf7db1845721425594fa105", 16) + g2To204x, _ := new(big.Int).SetString("51774de396e0456c71dd80a60f12d21cd8d394f444f8ec11cc1241172b823e5a2da0e4026f0463f6938507a28f61fd", 16) + g2To204y, _ := new(big.Int).SetString("70f63c6e5f10ca36d4f66cf255f49d38d272887072471f04e301922318eb176ee7fdbe5d37e730853dc70b2c97106d", 16) + g2To205x, _ := new(big.Int).SetString("114e44441bab56585d1f00e4698303b8ae52925ed22ff608f3f346d0c1796f00f954e240a5965aa50f6f684a2739c73", 16) + g2To205y, _ := new(big.Int).SetString("1add868b94031d9254694dc163765c071de69620dd7198b9e980407a82f2b5bad8c9ed3c151f965bb735754162776ad", 16) + g2To206x, _ := new(big.Int).SetString("94c916a63bafc36d0ff51f36dbf5abe60c974ccde1f2945e3f482a996e15063f9334ab874ae00d7d4baeeece68a76a", 16) + g2To206y, _ := new(big.Int).SetString("c5b8c12e8b085309c2218ab936a9f8486242ba4abe16605fcf53e2fa59b8b4f2f0d8fce0866a63ecc2b1d9559c887a", 16) + g2To207x, _ := new(big.Int).SetString("118440e9ea5d0ca6a4d593eadf149988b376ae79deba462c11b9c4146cbca71d93710184cddba8bf57e9bdf0f4fd5b3", 16) + g2To207y, _ := new(big.Int).SetString("9817389a50fe85127287e1c25d5c40a7c793e787f048bf02a69ff2492e898227d9d5d40ec3fd29f86d7cc912e4ad06", 16) + g2To208x, _ := new(big.Int).SetString("44e02fe124b5a7754ce07713a818b661a88e5b59609c2fb866fa26023d0499ea8ecf96ce2cfd661c67b2a7bbee76e8", 16) + g2To208y, _ := new(big.Int).SetString("d3ba51a10bbed75f98f791cb225080b3087e4668935e2d8200d2a42c0aa5ba28c1711c841a835882e2669c19e04fa7", 16) + g2To209x, _ := new(big.Int).SetString("ae715b1dd065c4e8b9df8d27c6f40868fdf5f5da8c17474258e2d7df84e69654d4fa23f574343c7746e4cedb04da5a", 16) + g2To209y, _ := new(big.Int).SetString("980127fbe1ac3176c4c3494a8f11b4d6f07b65aaa4c37a133007601111f8167cbd58cc4b755cfec8877b440618734a", 16) + g2To210x, _ := new(big.Int).SetString("d4e72f646af729fc96a5b6619ec898808a8bd12f9a0e2b60a54e844c04ae5a00dd215424a869037219d426f839d651", 16) + g2To210y, _ := new(big.Int).SetString("41ecfaf326ee4b88c5f81811ea8c338e943516ba7da547b0bafcd484de23e208b39dddf2ca0add4f420a9c2722bdbd", 16) + g2To211x, _ := new(big.Int).SetString("4bcbfa770bd4aeb8b160709c8a69fb22cdc4e58ca9a58763b99c53617358671e8c20d8ec33cb06a75d4da3a3982a1e", 16) + g2To211y, _ := new(big.Int).SetString("3d7b253a592e3fc11ca9d6b143348f88232abe363a699726bda6f9a61f4e84cd5bcf08f6f8278306de297060476df", 16) + g2To212x, _ := new(big.Int).SetString("f19dc610f4449da5420a5d5e6406bcb006b62faea414868d2e38eed978596cff8e86a4e47676101cb98259e082146b", 16) + g2To212y, _ := new(big.Int).SetString("830e4e2e50bfefce0bc558c9e74c9714a71a5a471ccbd3d9d7ac534c009f399e15f85c324a7d5dc2585d74946c6500", 16) + g2To213x, _ := new(big.Int).SetString("197885701bd9af118177ec0f6f791ef4251959a3f59b80a05e1653a1f633432c3a4018555ffd215db7f9d5084390b9f", 16) + g2To213y, _ := new(big.Int).SetString("608112aa435d04a0f05bd432e13b67ab7bda184ad23763a858a35aef57d59da082e1e842f75ee524f8de79ee794d8a", 16) + g2To214x, _ := new(big.Int).SetString("16bd8a55e3b1695699dea5763a5fe6418a55899f3c768a68ab1e04e676a7052446c609bc0e5506d7972397f6392910c", 16) + g2To214y, _ := new(big.Int).SetString("16feab32309d89d44a8b2868a130d3007b69b1ed83d601d1acdf9f6f8b2331ef9926fb47e0436802b064aae773d646d", 16) + g2To215x, _ := new(big.Int).SetString("192a288de4334ce746bf19aa8e26e736a51be264d605ebf93991272741aac00736aaa1db44f3e565c365a03304d4671", 16) + g2To215y, _ := new(big.Int).SetString("7f44babc07ca8bcf82dbc9ffc304e0e44a05005d9918850f89cf0e653073f8ce343cfa307e52156657ecafcb1d52ff", 16) + g2To216x, _ := new(big.Int).SetString("3bd781aa9a31d5ca87a7e692e86eec5b6229cc0199d804a1b8db429adea932c92788fbba31297cee74147a5e861395", 16) + g2To216y, _ := new(big.Int).SetString("1a3bf79a61de7f92887ed75e0fcba22522df68818ea86d86dfac86bf60ec06f77f058f06980b03fdff28d0fd57f2e0b", 16) + g2To217x, _ := new(big.Int).SetString("2402d983298af793f637561b68b08f470992fbda0ec4da86d7179ccc4b979a0f9164ceedc9c6a29a2cc54ee0ecf1bc", 16) + g2To217y, _ := new(big.Int).SetString("144e6b94177252db037f6a84f6d16d40758ada97caf5d7d9387a7928be61828c0459d7317a24bdb42caabc0966dc716", 16) + g2To218x, _ := new(big.Int).SetString("e0fcb99476c675900c955298c1df338e33e23b28a74ad9a27b4ffd47ea8bd67b9de3b5add072c8a1b072b9fb78066", 16) + g2To218y, _ := new(big.Int).SetString("6f388a7db5cbb124de08a246b079f628e61b1cd7c0e5edc65fb19cb21938071a56ccd33ca116f5a2397713c63048db", 16) + g2To219x, _ := new(big.Int).SetString("11498993939102f5740d8858f5ee70a087ae0d52b2cdb801e279e42ff150975019a92576cc14fd2b8e07efa76b2589b", 16) + g2To219y, _ := new(big.Int).SetString("9977f5d8f10e23098bdba68a286f25fb2b6db0aef7ee845934934f4268789a2c042f44a6c80f0162ed5b2bfe537d30", 16) + g2To220x, _ := new(big.Int).SetString("9ebce7cceb0314e1994f20d7a716ad5ef32c3cdd8171950dcef910261445412d9a5682dc2e0500370e2d6317c384d7", 16) + g2To220y, _ := new(big.Int).SetString("10d543e1a05b9c11d5a24ace56f05d04799b48c6f86a4df612fbea5ad2e2954ee8a041ecb5b765ac6a32392242903f0", 16) + g2To221x, _ := new(big.Int).SetString("82bbc0277954ba90241cc800aa18b05f2826378db66d59da11ec6a9fcda310415f8385f68f2eb25f2ed3abb21581c0", 16) + g2To221y, _ := new(big.Int).SetString("1258c7929372aef1be2ba403af16d1fe24d500c81499a17adae4fb94775cd7b593911ea2e04d7d4e7946d68ac301373", 16) + g2To222x, _ := new(big.Int).SetString("1130ab0736b48f526e01bc5fc4cf9164ac4704047e54f9d8e9f861dc9cae10a884b5b16423f344d86de58d1f0c8aa61", 16) + g2To222y, _ := new(big.Int).SetString("68b14390cb893f5e775837141eff37bf894c75899591a3e67779cd16d89567db5c69539bb486f57a24b6c4892b1b88", 16) + g2To223x, _ := new(big.Int).SetString("5e04b1e370b58aa76aa0071ab2e6586501eabf3d80c2b8967eab61f56dbc6a3943c1e9e6000729ffce3811f4478d2b", 16) + g2To223y, _ := new(big.Int).SetString("1374b8d7eb70c4cb81df2bb50e894791d5ab853520480e89c198c96ab7158993000b895e21b618d33f30e9f3dbd4930", 16) + g2To224x, _ := new(big.Int).SetString("174a97d44f91430e497ae21c793730e8b5441ee8708021e73637a9f8c30066e641794ffb913b92fbe64566879f9a194", 16) + g2To224y, _ := new(big.Int).SetString("151ce7878fa02ec8966f73c48125743a771018b3dc5743a2bd836b90ed38444df88aecff1dbbce14e0ee2888e1ef708", 16) + g2To225x, _ := new(big.Int).SetString("16a2d22751e0faeeef7844c4427269e26009b756ec7a4fbe5a727df769bdb9ef441142ce22daab727482ab2673435b7", 16) + g2To225y, _ := new(big.Int).SetString("1224d9344ee5398193bad09c691f4ea3067802c789714ebda5e62c2eef5c524b7ab9a73afbbcc3d3866b94b1e838f33", 16) + g2To226x, _ := new(big.Int).SetString("14de3ccef2af8ee23cf6b04f610838aa53cf823dc104d975f19db702bc56d5d25bea164369267dfe22d9feb60902e3f", 16) + g2To226y, _ := new(big.Int).SetString("58d7a014b6c3abb260b6569c61e74425a97fa90dc588966aff854c0fb682ce41d779079962b88a4425c29f06a6753c", 16) + g2To227x, _ := new(big.Int).SetString("6c19a89057fb87bfc179bf4062ab6459526bdc11146304f311f647ea5957e12244418386c0fe09da476630835add77", 16) + g2To227y, _ := new(big.Int).SetString("bbe679f18d53cd4df93bd02f6f5511050647d160c59514673f1e86e3891053b8445f45df4a3b373861503c71d58de9", 16) + g2To228x, _ := new(big.Int).SetString("ecf150e129cd512a141df58f95f8c38512fb2af1bd320a94842569f434fed7a0604cbf1b1528eb1118c11c32a692aa", 16) + g2To228y, _ := new(big.Int).SetString("122d71c7c5115b38a0f2aa28e8e21b649db953bbac9aeea82e7e14c02c8c1cf1cde06eb8914ceb29d2979533d0a8a1f", 16) + g2To229x, _ := new(big.Int).SetString("19a4e9478707019b033794bf784f3c37777efa971f51003a37b460479fcc05910dba5c852f534a299b9e2404288bc86", 16) + g2To229y, _ := new(big.Int).SetString("398ff16dcc00614b1e2257987ee2c339a53a29e67a2d6b4687089d36fc5d432e6c4d0bcf1609db45dc2f3f11fecc53", 16) + g2To230x, _ := new(big.Int).SetString("d4483fdce59dfd84042f5be7f8458962a8867c4ea38445f809abe00cf3286979a93ed8690630783455c17e06e37647", 16) + g2To230y, _ := new(big.Int).SetString("7bf259c13a02f5117d6e1f1b4a0899c1082c6ee6b71ca1511833e312c0a7c81732cec58d4fb8b5ca0c62a7c2e07807", 16) + g2To231x, _ := new(big.Int).SetString("7f0589fa75f0f5cc007a62fe6cc3e368adb2bb08de7eefc8821a031935ea2c98ffe212e6c15f031f2ed23aa58311", 16) + g2To231y, _ := new(big.Int).SetString("1612984f2bb0a5fe9f3c941a4cd2bb1946a3a4d1f605faa84161c6340cc1b1890cc6821fcb23f9111975839883d1792", 16) + g2To232x, _ := new(big.Int).SetString("f74be9f2e89f7fc9d63e1a380117e4ed633b936ae43735e6ff3f28056d1362725c791ebccd776fe43fd9436277c0", 16) + g2To232y, _ := new(big.Int).SetString("101552b0bc58c07276643717fea8a73853c5194ef7e4a39f72ae9d87f79402c42d18a67517760721113eb4efb6a6b72", 16) + g2To233x, _ := new(big.Int).SetString("15789f64a8d6d7d1ccd4501e25f29ef551f2a020b11948464b56943c8d893ad47241325be82cd684a12d8a94d178b50", 16) + g2To233y, _ := new(big.Int).SetString("16a632a4df6dea33665ac380117f717b7d38a0072d6a531e131f1fa3aa4db46b01339cc7b2c9f03f78acdd37982ddda", 16) + g2To234x, _ := new(big.Int).SetString("5eee70541f00b428410a9f0b6112ab6c14c01c3af8c6831709ba9baf84ce9dc1ba948251e603279474ebbd9dd432cb", 16) + g2To234y, _ := new(big.Int).SetString("1c026b8f77584b85ef151e4454cfe9ca90ab047b3e012ae5273a8c10a6c28584c14fa6855e21b6ff88dd3bd73a0125", 16) + g2To235x, _ := new(big.Int).SetString("98a5fb33dde33395886a093e83b6e681fa4ffc07ec561bd840281a6c464509203dcdf7ee209d109600907e6bf257dd", 16) + g2To235y, _ := new(big.Int).SetString("788c41665350ffaa411f7f87eb1841dc9c55a2a2d9eee4d53074d259ff8212be1412b24ade48b6659d73a2aeef2893", 16) + g2To236x, _ := new(big.Int).SetString("f11dccf426e9213ade8c9ee90b06f3bea1e6457601318092afdb2845873962a9ebdf44d6a52517e30e2fb59d47937d", 16) + g2To236y, _ := new(big.Int).SetString("11a2c73b55ae8b0418e23694e988a586a00e7d167972e66def5b18b80f5822e0386be601d0eb553a33e2dcea9d2f304", 16) + g2To237x, _ := new(big.Int).SetString("54733fda527c1d2c1967947da26074e803c5143b267a3661439bf3f773a42a754ef55d56dbb624d2daa933656b26ca", 16) + g2To237y, _ := new(big.Int).SetString("18f358aa4576692f77586da3ea26d5fa85516181e6838a7bf7b52b586c06d9f7074c5e90e7ba1ac4a925d368d8cb981", 16) + g2To238x, _ := new(big.Int).SetString("184c780c3114f29206d1533772298961a70b6fdaeccc642335a824909cdb6f906e957dce89627d1e7716d95a2cfb46d", 16) + g2To238y, _ := new(big.Int).SetString("12d98e699809d4e11aa2e0b33a6fbfef9e22336bdd90fffa323b7e3bb30ae239089b2be9ff8058ac6c15597788af01d", 16) + g2To239x, _ := new(big.Int).SetString("1585afaee8b5f5508cae51b92a6c44c8d49cb8dbe9673c33eb981efea193d06ccc524de0dfe21c4dc0981ae129d80d", 16) + g2To239y, _ := new(big.Int).SetString("13f2a75ebdb771622fc9ced0989babf38f67dfd65a083a692514dabe83b3a97eac4e42bdb47cf6d51b8f3d5c963565f", 16) + g2To240x, _ := new(big.Int).SetString("14355642d7750cbbba97db165768632badccfb6af700fff0805d22834e97eefcf84defb444cf0273b1a9944f7e5b91", 16) + g2To240y, _ := new(big.Int).SetString("1197f01614054d77e687096e7538f6a2545b860dac56f1891056c358e42ead9a2bb48b10afac6df3fce655328a5e818", 16) + g2To241x, _ := new(big.Int).SetString("13b73e44f2659f9e3107e77dfbdf6a1ef7f9bb9f50d1edef96f72a35233da9405700d898d93db5507d52dc52889823a", 16) + g2To241y, _ := new(big.Int).SetString("16b68db42349d35537fac003e9f2bb42031b338c12f4913997c4884ffd26990afd463d337dfbb5d29eeb5fe2385e77", 16) + g2To242x, _ := new(big.Int).SetString("89a89ab5b237b3cccd3fe1dcaa534fc6568ee9d460b3ca0df9c84f9ad0af74e11d99a258d42e2fdf90c87ffb008fda", 16) + g2To242y, _ := new(big.Int).SetString("116466cbf9bc5f5cf137f3b917fb95025546af24874a181f09a3798ffc6214dd8c60ee3dc473ba4693ca0c272dd993d", 16) + g2To243x, _ := new(big.Int).SetString("1955d0dba9ad4e82d07b90e40a406188df46abdc803974b4104fff90ad95f1ae7c278690cc349c3a35dd36e67eaedd5", 16) + g2To243y, _ := new(big.Int).SetString("17f6f0f43e95cce0f3091b701119eedb0631f018c3ee3adf30e011fadb07a460c18d08db250bae2d071fef1a92a1f79", 16) + g2To244x, _ := new(big.Int).SetString("1ac41b9b7179d3b109edaae37533c2eda16f2ef82ad3b6116001e33ca216786d72d5df4eaddc275a349be1f221ef018", 16) + g2To244y, _ := new(big.Int).SetString("17007d8c32333765265165962b19a98122d21d224d1529e10776c574997401b32af137363701401acd4f8b28337da6d", 16) + g2To245x, _ := new(big.Int).SetString("1173c60965d349c342b3423e4fdd4bd8e2d9321895e2e5131e4434094a918415e8ef88daa57f29e507345caec040621", 16) + g2To245y, _ := new(big.Int).SetString("175d01ed6f7e2a7cb9866762d30756dee408e5ebc1c34a2c84b795db33f09a89ef455ba08e99d8bb2a28b9e86616c4", 16) + g2To246x, _ := new(big.Int).SetString("5c1bc8f91e383e69293368e1b57038c922347f71ea365a4db593f71074875ef0e6d432ca81c4b80ee579965cf17c93", 16) + g2To246y, _ := new(big.Int).SetString("189e095fc94cb2e838ead34306a32b40924cccc78b4a0cf28af85fbe0b54538cf8a772b75095f356a1c0ef3296f5561", 16) + g2To247x, _ := new(big.Int).SetString("8a9efcf927af9dbe6e2d4c77d29df093ef459afced7a9f097f017091ff06e4bf4d6b640966c68c10b75f1e7149a85", 16) + g2To247y, _ := new(big.Int).SetString("70805ec8649c9a7c25d21736edb523b4790d3747f1a368d21293243c6dc11c5fe79daaf07c4d63fc9d187df46fd510", 16) + g2To248x, _ := new(big.Int).SetString("16e52b1a5b5ec2b3fe5af7e76b966000583cf9670843094480b65d13a592603e9cde594a02e2415372d36d238673d8d", 16) + g2To248y, _ := new(big.Int).SetString("d5022a2983f3d3fb721884c0af2829680a18dbbd005394c5065c498ae2c6826831da4f412db24ce93ab82ade2b9000", 16) + g2To249x, _ := new(big.Int).SetString("133fcd0d44b5e9b4101193f9d001faa4f8d888b85643e479c8e6e541a9270caaa8d54d5f0bb87a1f8ec5a25cf4be6cc", 16) + g2To249y, _ := new(big.Int).SetString("19c9d609e590e4b4eaf3f48c1a7c52c5a019da645e7411ea105ef0bc3ccf4682f0ff73522747157d7468f84c7cecebc", 16) + g2To250x, _ := new(big.Int).SetString("fee78dced3f99645d6043ff6106a2427a646ce40ef8bac3664c76edbb88b6e5106ee4cfaaf5858118ed3290b75621a", 16) + g2To250y, _ := new(big.Int).SetString("3e93b344b8faf9ac5549ed35296a660bac621823591228bb54e6d19b0c7985482f37e76d3d5e4744c568529023ba9b", 16) + g2To251x, _ := new(big.Int).SetString("1190d295e06f2de4269762adc2c605d3c767055ab628933f1a3a184b691ab73b7724beb9c126974b8f4553308c6c2bb", 16) + g2To251y, _ := new(big.Int).SetString("6895ecd12c1cfcc15a05cde2e775d7387754b5e3fc43b1961f370dc28fc9b6a5602389685b7251dd0f6ee1490e99ce", 16) + g2To252x, _ := new(big.Int).SetString("13a0c4f35b617ea8aa399aac8b1c977320c28204236dc32ada1b64e7a8c79165f34ba75baef06d41918e24984c8ddfc", 16) + g2To252y, _ := new(big.Int).SetString("8f6802c76d44e816b66d17f7be4e845edf2c12caae31d9223f8b9b40dcf782b222218ca0c725116b18986661f9068c", 16) + g2To253x, _ := new(big.Int).SetString("129727af35616521d6ae25809aa137ab2449ff07117bda3cede303cf37a5836e9fe3163dbbec2e479f6d731960816f1", 16) + g2To253y, _ := new(big.Int).SetString("1ab7e34c28459a4b0ddc48f5824c99d0fc99bf037164ff4bc414f76ef9d60df14133055056dbcbfa1913091cce44fcf", 16) + g2To254x, _ := new(big.Int).SetString("197845ed8f04a6b851f909820152cc21841e6ace5830d9c67d8f64209b05e4487e0cbc2096dffb85f86286b10c6e662", 16) + g2To254y, _ := new(big.Int).SetString("5d09de5b809843819627a98be83a8384edc0dec8794f0b7014d411cd1e0260e4113f55ca5557491f5a2f9de64441f2", 16) + g2To255x, _ := new(big.Int).SetString("400ecf2f17e142d9852c1998a771c52129869a7ce40e1003d83398f6628e3a0021dd3309424d92c3d3f6e3bde5d70d", 16) + g2To255y, _ := new(big.Int).SetString("132d749e90bc289de1447e5c4234333311f49db68ee5b58950adb26f7dec18db3d79fc75644ce2651adfc483b01ab24", 16) + g2To256x, _ := new(big.Int).SetString("198ad93d9ba5054eed66c1745995e7ba6672c99ee4179c2f02793ff6a495e6fa7e879e3b54cca408499fee19eb2045a", 16) + g2To256y, _ := new(big.Int).SetString("ac8bff7efe46a32015801a50c1699fa4d6db622fc4f9bbbe0a96b930633c64a11aa2ad9055d54098f29c742f05d8b1", 16) + g2To257x, _ := new(big.Int).SetString("419b587dbbc9aa407b2457fc95c4c0cccb6e635eab74694f90181ba4b78500181d91689f9548bb983d061550db352f", 16) + g2To257y, _ := new(big.Int).SetString("838937ff5e909ae25c2bdb5eca27f919fd94cb035efa30d578cae3599d8b987f7780b27c943641a91fd1659de7583c", 16) + g2To258x, _ := new(big.Int).SetString("17cb59b9056bbcbbd2845178a93c57602b138aacc93fe2a6f8cfccb4819349eb4a66b88689f9db95874dc6db1247eb9", 16) + g2To258y, _ := new(big.Int).SetString("2e8c8691a68b105570acaf31637176ead8cfe6bb53c8708431483d1e8f8f3e24fbd8c33c9b448224d91bcd717d7edc", 16) + g2To259x, _ := new(big.Int).SetString("4749dda7b83f7f538e98bb688780b430eb22f7b3a9c30461c354334a5773585868334bf1b99d5df328c5e7c3e1661b", 16) + g2To259y, _ := new(big.Int).SetString("66356809bd4b23dbd70fb1c7869a1cc7a3aa71d8620883a4626feadca45ebe435031cb135c71e3fabfda6cd8ddf6b8", 16) + g2To260x, _ := new(big.Int).SetString("8ef3c6b70c4cb43b4d9b04e361c35d94ecf6026cca5ac3c7969feb7c5f340f35fd70bba29aaf1dc4796a989f0f3f7", 16) + g2To260y, _ := new(big.Int).SetString("91166e9fc5c9c93e346d479b7423ef9c427c1bc6deae02668d14a7aac9e5b602c95ea34f415cdf9df8d2354dbb47ba", 16) + g2To261x, _ := new(big.Int).SetString("4a1b0dd0bde5642499ebbb58e0e7864cccb19db85c202d7c2cfd365ae10ccbfa94235659f6d8f3b13f7406e1f2130f", 16) + g2To261y, _ := new(big.Int).SetString("18874ff430cd57f22ef1e9eb200fd9179e25ebdeff4deec94b1ea47383f67efa5b5d28cf44431434801ae6006dcb152", 16) + g2To262x, _ := new(big.Int).SetString("7330b2e525bb4a8b1873430a816350f55362e9d5a02b54888fc371234d7fa0a6b1c819eec90877a22d2f01c9577f49", 16) + g2To262y, _ := new(big.Int).SetString("2eac84091b4c2d07ef816af65ccab3557767faafed961fc26bdeb185356ce67acd605f848cb64c1b25075d50368731", 16) + g2To263x, _ := new(big.Int).SetString("12865ece19ac21dddd28e54ca2315c04612fdff240d7e6eb1ccdd7e53b0647b6f6d701c0f12df73b909b30a8793ca", 16) + g2To263y, _ := new(big.Int).SetString("628a236c09ebf3da0eb8a32b632a536af927faaecc26e0e62083e241b96bcebeaf70c070770b45d368fd3a3c15c05f", 16) + g2To264x, _ := new(big.Int).SetString("11c2b8dcf027f232fefc8b1f7364794b61325690bc49bfa393ce1a5c205c9fa845f51f82266a9f9fcce5a8ddc5ba8ec", 16) + g2To264y, _ := new(big.Int).SetString("10c9be29c224fe56bdb9cd71577876e25f18bb80c1f1169072f14d82d1a685309fa53569db022b1ba3b419cc408ed65", 16) + g2To265x, _ := new(big.Int).SetString("190e07f485371d9df7ca8076030dac2c988271a38582223db0a99a917c4a7ef60f7ab934bd7a9495045a01174a04efb", 16) + g2To265y, _ := new(big.Int).SetString("de4b4db4a1e8a4786319172ef206b782042f3808ddebef6698548b903289cbf13f9895185823181aae0507745883b4", 16) + g2To266x, _ := new(big.Int).SetString("1129d1c009f73dad3ed13ce78b98c3938c4f2978521a281a8cf98806b466071338b1b6b00e90d66bb4e6fe34d85dc01", 16) + g2To266y, _ := new(big.Int).SetString("26428deb622885a32f6a93f445f98eb23d0b31e613f0beeea361b5550b1da5c64f4285f710c1a8877bf1deefc7ac6a", 16) + g2To267x, _ := new(big.Int).SetString("3e2a4ce3e21d1415389de270dc6b64930f04220c0ea201c478356a86d2a2988785b78e5de59bca4f656343e3c49a6b", 16) + g2To267y, _ := new(big.Int).SetString("491d6b62b5ad50de349916125744205a2f3d8f9afc259fbbd844073f26f5922426da3218444bcecc183ff852aa2d80", 16) + g2To268x, _ := new(big.Int).SetString("93562e285dd4f2535ce60f41e0a0d5797fe30dee311719378882be71ee2a4217492da7e1e82189909e3cb1d4e11b36", 16) + g2To268y, _ := new(big.Int).SetString("f30d3eae5ff8c1d4d90444f13751403e77c339e6398616ddadae1fefb974a36694fbdcd1d437b0bc5620971d4b5dd9", 16) + g2To269x, _ := new(big.Int).SetString("110f35fd5e1f3e5f31e1b10ed4bd954cc415ec17a02481072eba284d8c85a54024adf64e6ff161113a09d5c1fdd3c13", 16) + g2To269y, _ := new(big.Int).SetString("c3a5f3d706fa77b9555211cf396acd58adde710836873d0fd426c9c0048aae9b54b04392e8f679abdba1c0927da64d", 16) + g2To270x, _ := new(big.Int).SetString("7d5629ea38e80696049f6054fab076f750986cbcb8795401df61552dd66c3fa2eca45a94fb73aea59161317d58dc52", 16) + g2To270y, _ := new(big.Int).SetString("19b0327cacdd519ac0b418d30133d8614ea2bc0e6653e361b5aa395f223a9f7539fb153624dbb359f14fdab18362236", 16) + g2To271x, _ := new(big.Int).SetString("76375a9ed297d7179a658bda7a75f096fb55d4b5f8d9f2702d5f305f709f237e5542ac681d314882ece877445e9052", 16) + g2To271y, _ := new(big.Int).SetString("85a6cec94909c5c81528dca80917bab1dd40fff8ff6a2dca5131d44f7267bec37af3a583f2bda2f8d14bdc366ba8bd", 16) + g2To272x, _ := new(big.Int).SetString("5307db362da35cd9e3042ff39dfe4d6e32814680ba2c15ec5248b98e00bca43398402df00135210c3a288afd700b58", 16) + g2To272y, _ := new(big.Int).SetString("18b19f017bbb62694f9a020fa59cd9a4619103128ea9e4c8eec2ad34807db2c291c8ca699c241450e80957bdadb7621", 16) + g2To273x, _ := new(big.Int).SetString("cc0c3dcca2a2ba0faf9d86cfb1bce4852a857a3223b9961a2d267251682fbd5d901e580ab8c458a9d03e9a9311ac3f", 16) + g2To273y, _ := new(big.Int).SetString("4cdc419d53ebd91ea1ef2b31ea52002a642d6936f2635276765b90f18e3ea2e928fb8d7f021541a2b816f9b98e4b32", 16) + g2To274x, _ := new(big.Int).SetString("1373889bb768f7b8818a86cdb37f357ca1df4c315df29f730749e04cc984768b607109fcded27561b16392a15f6a62b", 16) + g2To274y, _ := new(big.Int).SetString("42e6c6adc559d0b600596b1da26b47fb0024ae1ff58f9ac81edf903470ed6bbc25940cab656fbe63f52245e7d6c40c", 16) + g2To275x, _ := new(big.Int).SetString("4425b4bc590d3a0deb95b9ae2f4170622369380cf8a79f23e13b63b514676a75ac0e3016bcef3199d9a359b10abe77", 16) + g2To275y, _ := new(big.Int).SetString("d369391aa9385e690273b20581f2025870107e0aa093053b783ea0bdfc95612e8b60fcd07bbaab4d5949b49488a0d4", 16) + g2To276x, _ := new(big.Int).SetString("697be33fb1ef863339c0c6ea0d35a6c232afed052eb8c60501727806c022a00161afc888777407e279130cacdadec5", 16) + g2To276y, _ := new(big.Int).SetString("c101ddf5a50059841baef4e6a71cb2053167c2467137beed7058b55891b0a121e782c927878039ada00bec4a75dcb2", 16) + g2To277x, _ := new(big.Int).SetString("4d741376cb452dc79b375e493b92b7cc103461c46ba083aecfc4717a51991b22d0b224f4b48ca610ee4272ee4ba57c", 16) + g2To277y, _ := new(big.Int).SetString("16272eff87c487ee35461f9e2cf855e2459f428e8e10f6530306d521963fefadcc2998420d4301e96e8c4a1b58ff751", 16) + g2To278x, _ := new(big.Int).SetString("19a2da9695527c7443f6d9923eb614eae02a2920b687c888ec16a92d833fa4540354c023d94f0fa7ae23ce4f3218e6c", 16) + g2To278y, _ := new(big.Int).SetString("8d2ab5506225b4e3deaf064de43f41ebf96ab2b220d9cc0743ee441bbfca43f1d6626adb0e15f169d5b68a196d75c9", 16) + g2To279x, _ := new(big.Int).SetString("6a18c433f0ef0a57b8a7b892345440be445b2b23530e8310041c13e2a8ca0e83f86c4e0bc027caae701edd2a39b0b4", 16) + g2To279y, _ := new(big.Int).SetString("d1029ec23058096bae1cf886f80946dbb30264a5e54703a369af9d9317abc29fae41c7519d9277ad021434d98bac32", 16) + g2To280x, _ := new(big.Int).SetString("53755aa60d2e9a364a799ad0d2b533a84b7ce41bc2096b1b49dc93b158bdb4c4ef43b8d6f88c36a1db7a2ac7d602f0", 16) + g2To280y, _ := new(big.Int).SetString("9326fb36e432fdd400f2a88d3efb1982c3fb6a6f7c1d92d9f319681c30fd1a0e456ba85be7cd767e7bcbbfe153dce2", 16) + g2To281x, _ := new(big.Int).SetString("14814f25cbb4be1ed4cf806517bf8462047a16bec2c9510b3dcdbc4bfaa44dcf5a7efb78ca7e516027830d0403bcc1d", 16) + g2To281y, _ := new(big.Int).SetString("d561f4f28b926f36ab06ae2836997fad42544522ae85cf6333ccada055ef86e27d2e4f46bf2af2cbb13acc5e05c50f", 16) + g2To282x, _ := new(big.Int).SetString("158a2a93668fcf4a1e58f85ac7da6f8524cf792d7f3522ce55493de98b6268b4a1391dab00fa011250a0af293f00f4a", 16) + g2To282y, _ := new(big.Int).SetString("17d5fed5520155e357fd49b080d860adbd52d3c84a17706d7bb63ce828150e7b7df16948de00aae7389b762e2e23fee", 16) + g2To283x, _ := new(big.Int).SetString("a5a27cb4c2d061bf5b78873640d0cd551c7428ceab00beac8d65298399cef7361472637b2bdf1fe62dbd96480e0648", 16) + g2To283y, _ := new(big.Int).SetString("3702567d32d73c08eb9c8359fd36ffc7647dec3329246074a0b67b3c84a143f0b528686648a2b34376390f26cf02f7", 16) + g2To284x, _ := new(big.Int).SetString("11871bb4fe777e21f5ca4c776f6f5370eba971601cdd75dfce98d2f1b2e254dad527b4c1ad7ddb3c7e737498d9edda2", 16) + g2To284y, _ := new(big.Int).SetString("6cce724cbfda855df7d9af40c16e5756c0bec0acef775105c12215ee5922d870fe686ea4e4cf442915223bb6ee8a65", 16) + g2To285x, _ := new(big.Int).SetString("3c80b6c78481505c73073249a1716fbeaf7bb4b12069c5fdac37d39546c5d24b8caf0a18800cfed0a365aabde8bf4", 16) + g2To285y, _ := new(big.Int).SetString("15b8df4ca5f4268dfcffe37019d7cb3a5cec43fc822a5e310f676dc29678dc1e7f96846f1f3d64623e198afd53f124c", 16) + g2To286x, _ := new(big.Int).SetString("40162febfa4d3f42f0e47e4452b2b51086747f93a1fc9156aebc026f740dfd914849f5caee5c67c63586f941497ebf", 16) + g2To286y, _ := new(big.Int).SetString("e03eb269e1468ed3ef29bcf24d1f0e04b9a5958c9003ff78845d37a5deb225d6891fb92f7c215525c3e4b1062a109d", 16) + g2To287x, _ := new(big.Int).SetString("1493b9d57cf6acbd0808ac663544393d2f515b2f838898891e04989c68790be371a6086fc1aee17eb9cbc7348aa0671", 16) + g2To287y, _ := new(big.Int).SetString("a0d29a1faaa1ddd7bce363126895b08876c70a937c089c8fbbf7a618284ff40c6951ccd8af8b8519ec29f4d8a9fc7e", 16) + g2To288x, _ := new(big.Int).SetString("72b2d1533620d90b4a4e1b782438b2538c89801379085dc166388c928d38836bc7b387878799847a83ef86226d318c", 16) + g2To288y, _ := new(big.Int).SetString("9ab6b3871c45de21de41ad3b42bf7cd58249202e3ba72b3bee9ee81074d1126e92820216223c54533cc9873e1d5b6a", 16) + g2To289x, _ := new(big.Int).SetString("61dc382951627452c3211e0be9a2a9f04231cdd7f08e315cee00f811aa53a13e8c1fc67292058446b87b8402ae9983", 16) + g2To289y, _ := new(big.Int).SetString("dfa82dedb32092192d7797f092b448ee90a692e07e0f1f7b5acc89869dc347cfcb7d1e1c1794f36735318ca8504041", 16) + g2To290x, _ := new(big.Int).SetString("f10991af9ea2ff3e19ba38dcf151ef80883dc10c5b407504f1b0e4e339d268314333113faca5de2be89734c83664f4", 16) + g2To290y, _ := new(big.Int).SetString("1456b8faaf48224f6f331ed52f8217a0a568a8529f5b146f9770bd1bbd28e2a19cad175dd84965d11dae4fcf4a42ccb", 16) + g2To291x, _ := new(big.Int).SetString("1a56b7a87e64076383351c99c9d8d73a4127d15a56512ae0b13930389bb244c3ab78f6c2c80c00bbdaf39353ba41b03", 16) + g2To291y, _ := new(big.Int).SetString("b507a6299e0372b53d374dc1463b12f1252c22e77c7bba8164ccc37d853bfe0248b51d92c01b8f55882c749a577895", 16) + g2To292x, _ := new(big.Int).SetString("11a339dc3f4fd8fb63b4f073155796a3807eadddea8ac3896a042ca2c872753f36037d9d0e07a7fa1eac723605245a5", 16) + g2To292y, _ := new(big.Int).SetString("1222dbd930ddb39f80dffe1ca06e8017f3114f6094d85e6627483b3a640582f40f830af0204b62e2a78493f4ba3f23b", 16) + g2To293x, _ := new(big.Int).SetString("459173a706efdf94c37379c6944ac48ed75f7da2dd1be11ca616cfdddc2d958174869752916699f5dc176ee0c157fc", 16) + g2To293y, _ := new(big.Int).SetString("fce2b1d0d8bbdc00c279384a9c641003e2b5658db3f998b4856e25cf9a8595585f054f1093d89fc57e148ee9ab91c8", 16) + g2To294x, _ := new(big.Int).SetString("1546b9a6ba2faff24981b8216977dd0a38d2fd3f37f4053d85fc94a3fc716cdab79e3dab7a3c1206e28cb20c444bf4c", 16) + g2To294y, _ := new(big.Int).SetString("cc581666d2ee87f6d70c73ad809581e7e0e254198f5a798b92a310cfdc4822d6722ac887ee89d06fea469e11e25682", 16) + g2To295x, _ := new(big.Int).SetString("2df3c0aaf31a895018c2d0dda7455c4a5680ac0b06abfedefa3f014a96538546d42bb2265357fdee9a9bacc5e7fed0", 16) + g2To295y, _ := new(big.Int).SetString("19f1ca4f3dd67988869f506cc3a8956c31436801590664a3273ac8fd44bdee7fa4f169fb37fed250d19b37505c51e53", 16) + g2To296x, _ := new(big.Int).SetString("10d85f49ceabd73b9b34811cbe9a864005884a030cc44b528fbc3fd8591f7c2827fc5c8d3bc0f2c2a677c5f126e0c0f", 16) + g2To296y, _ := new(big.Int).SetString("1722c2b06c19defb2ee8538a77c0eccc29d3f60bd20772dae3e171897cd4a08362dc9b5dcd2076474c54c6db36f2852", 16) + g2To297x, _ := new(big.Int).SetString("162bb0f2b229c9f3e7163aba9d76ad9490a4031233755f2296bcc54e399bd3fa7b1b5f4f804c873a423442e7d9d379c", 16) + g2To297y, _ := new(big.Int).SetString("4749127524f982ee4571f1273796da2da71a4a682377c1ceee2a63211f1217f22cd8a7aa3f45ed8935345e85a10388", 16) + g2To298x, _ := new(big.Int).SetString("1366bf14679623b87120475fd016efb61f9f3e58694e061f041f5033f6ca425904ca49bdc45dedf969da27a152aa6b6", 16) + g2To298y, _ := new(big.Int).SetString("1a6202ab1f165f8bcb5e626d2ad47c44154e0f561fc0b87bd0914cb1ed789c69ddbb29c6c26704bfe5c3bd129bd5f1a", 16) + g2To299x, _ := new(big.Int).SetString("1d16b104d8f9a8322af8283a7eb7a4dfbc35d36f20572a963e24ec07978ca71260f8477407ac359e8823c67d3296c9", 16) + g2To299y, _ := new(big.Int).SetString("56bef9b5f17871bc287e1e448f871c6782f9a3ef9c2f1cca5aec18da0b87e46e7cc71fb039030e88043522864a9a90", 16) + g2To300x, _ := new(big.Int).SetString("165e04e9ca95dff7448a502f661ddc1d75999ef8e90c1a1bbb075131dcfd6910b5af199e22b45120d5c9ad8725a278", 16) + g2To300y, _ := new(big.Int).SetString("179c2e9122eecbf8545eb3e95aa6037e1966f40d617a1dc43f87ab50fc854d0c7b42683ecc10f086eb9e360034dcd3", 16) + g2To301x, _ := new(big.Int).SetString("d932f96c4db384a2bdea3a992c7935f8d3fd66f464d8cbb42ce64403bc9ce4517214f9a801b7b8b02b67981ffaa5a", 16) + g2To301y, _ := new(big.Int).SetString("d8ae0d2c8a1ff3518592407a7785f2e81aef26fd41afa3ecf242769d11f0572c95b296f90ad262727730cd5efc7639", 16) + g2To302x, _ := new(big.Int).SetString("184264c42dc98876a91810be0ee55108e99a85449d9038206fea705e78f55d498ac677dabeab6d7184bac6eb761436f", 16) + g2To302y, _ := new(big.Int).SetString("17436ea5d26738fc1224bc3a1fbe7d18846c0c0b69971fe9b8ad59f899386bf0721b97a42631c5813b3b40c86cdab23", 16) + g2To303x, _ := new(big.Int).SetString("13b5cc9794bd532ac83a9cdce9d019125d82a5ecc7d08dde9f00561821344b1097842a6f81ac05ecdc095d87924632d", 16) + g2To303y, _ := new(big.Int).SetString("12554e14e652790ebef1c5bd600800d30183acbf5c15b2e56f5f61499d86ff86214aaaf2946b9ae8bb5cddde56c6ab6", 16) + g2To304x, _ := new(big.Int).SetString("efe32413206283e7e1803cb4369634b96f63a7e10909faeab03f4ed34fc0f78598d7d0a0f0893b08dac9bfb076af78", 16) + g2To304y, _ := new(big.Int).SetString("f7f330b8edf6f4e93093cec6531718843decaac91c4181bedab0da3f267ad434b931f92f0c09221fef185c1d7a917c", 16) + g2To305x, _ := new(big.Int).SetString("12d54e5952c785c28baa8bd33dff36001f8e0c97bf6fa147ed761a6de24bc0362ebf91a759c3359eb9d625a2fd5dfd0", 16) + g2To305y, _ := new(big.Int).SetString("c9365e30e6a13e765d8e741c2c5029bcdc794fa1aa262e5dff9b14274e3b86bd2962e61b19e1aaf5cc6b807d3ed9b4", 16) + g2To306x, _ := new(big.Int).SetString("11955da58ef800b656ecc0b048f7973d8133274661cacab5f2a58688b3c0d57ee73402f00cf0336eca5f8a9c9a7f6ec", 16) + g2To306y, _ := new(big.Int).SetString("71435f1e97fcf65cdef87416fc0177b78a24ecf443641ac4801c2df0ae324cb1fdfcf428ffb646ed95bfc896f583c8", 16) + g2To307x, _ := new(big.Int).SetString("127d3735aa726ce6add291566fedcdebbcf4343d7868449d61562fcb06939765995ece8f0376e2b68d597622e0f64d9", 16) + g2To307y, _ := new(big.Int).SetString("294ee27536ac834061d9110ecd5d354a6f5bfac51dd362ede04675a7438ae867f90e6d638fb212756c8627bc77e7c3", 16) + g2To308x, _ := new(big.Int).SetString("615e1bddd4b42f50f9afbe26d2fbaec50f74ffd60ddfff4468b600f5d1535573aae261502d8b32d45fa474314b8b7d", 16) + g2To308y, _ := new(big.Int).SetString("23099fe1fb8cf9cb193c9bfb00f5b68f473a823e0a259bfd47d074dc09689a43f779cc754d2846a43550b645477eef", 16) + g2To309x, _ := new(big.Int).SetString("1abbbac6285d7f3847071534ed6332de2474930df760b46dce6b15a4ff82f5b9f71bea82fa8265899579051b4c64c2e", 16) + g2To309y, _ := new(big.Int).SetString("106ce0daa6992db96dba92216f6e2da51b934c00d1be063364321e26ccea7e8b178904135907ba8b3a86329a137973b", 16) + g2To310x, _ := new(big.Int).SetString("2f9b903ecf3f5682fffa7154e49767e5a4055c23b69efbfb69bb89a06ab38c1891c84b6e3ccfe4ff634444b726a53c", 16) + g2To310y, _ := new(big.Int).SetString("191dbd0d0a0cc587817efe6094a041d73c673866dea62a3f0106374ccbe09787604b010652342c83ddaef264dbd26ba", 16) + g2To311x, _ := new(big.Int).SetString("111866c35c690e56fbff009771f6027011ceb738dcd0742ab1194ba73098cd3f51cbdecc5b2e0ca1c2d0abaa706e8cf", 16) + g2To311y, _ := new(big.Int).SetString("b2427fa56f2ab073523673d047fd542419b4e2e15fee9974323bcbf274868ca64a1176db454d86aa542b5befe1fb39", 16) + g2To312x, _ := new(big.Int).SetString("c2a36a44347a86ab1c2c2cf4926f5789adface133d5feaa10c9f702fd91441222c0ea57328ee192969f2696f5535fb", 16) + g2To312y, _ := new(big.Int).SetString("c509e32a3045eb2b49b25526726fdc4cc978b42ac2fe98265a948e126624a6b3298ee2384b7e013e737615f5463e1d", 16) + g2To313x, _ := new(big.Int).SetString("451fd03aab9a1d983649dfff27d3589a5684cf5d245c579222d11938b2b7b56a62483d00333e4a656607972d5f14c9", 16) + g2To313y, _ := new(big.Int).SetString("9aaa7d11318a8a4c3b71b3f6f7a79f5241ad81069870ed4d8311075f68049c5785aa6f76a7278d411599070fe4bcf6", 16) + g2To314x, _ := new(big.Int).SetString("32b128fe475a8d7b53143cf89fe4348158394d2b569c167a3c293e7afc363c91bdcd99481fbe74410707edf332d2a1", 16) + g2To314y, _ := new(big.Int).SetString("df407ba4a659cc1f6bd6714fe68b1fd5901acf4645c4221f7bf253cbf0c1badca035e078942eba78c9c6ec4bb6f217", 16) + g2To315x, _ := new(big.Int).SetString("15bdeda5e3fd541d263e2266ab5b76a4e20efb18e90a8190d8fd54ad92c3845f31099876837f8859d04a7fe9f370027", 16) + g2To315y, _ := new(big.Int).SetString("144164adbe2d5229a4c204f2f938714b93517839aab086493b780dfe9c986c9da0fab1c4a045d359dde543a8a471fb0", 16) + g2To316x, _ := new(big.Int).SetString("82c442c6adca56f6b5be8452f115b4d69e8ba931045aa47ad54f8006b24b5e0a66041de5aeaf610c52c0be7ebcf200", 16) + g2To316y, _ := new(big.Int).SetString("ae7c68a565e4827edf354673f0a0a76314d25d3788eda91476e0e9d150f27443e173dbab370fab3fb9fd7b96ca236c", 16) + g2To317x, _ := new(big.Int).SetString("143cab22afb72880a35d47e88c99d2ed4fae97b99ff299edb739f878818c7626af633f0788c63b617976d8c392496da", 16) + g2To317y, _ := new(big.Int).SetString("7db206208bfa5559cd69d832217b877344036d54e14e1f246de34c4232ab6f08cb31557a309caef00e6a4c13432446", 16) + g2To318x, _ := new(big.Int).SetString("980d9374b06f3c317cae2aa4bf4ece2f2d0e44ad82d7eefa9cea1f63c741d511aaa1504fa66126b8172eaa38e3bb4e", 16) + g2To318y, _ := new(big.Int).SetString("9201ecdadfe89bafd482e1f6eac13772d9acf746f4ba506e7bb1bcfcbd4a97aa853fcc2eddd1889dbfbc430485b795", 16) + g2To319x, _ := new(big.Int).SetString("16fd8df33ef7e2a350ee5d70fedfab65782f05bcbc8620c83287c37deb2dc7930207cbc56f5f7d259194febdaa567c1", 16) + g2To319y, _ := new(big.Int).SetString("226a7e20aadf5126f5141cf9d9a6fd5e91ec65ca9b88637f4fac7bd5fab74254463610b32b15d80f04be778071c082", 16) + g2To320x, _ := new(big.Int).SetString("33837b8fc7cddef08f70d78f3d798391ec1204648e27188b85cc17094cafd2de397269de5d02ba1b3fa4d3fd87d2f0", 16) + g2To320y, _ := new(big.Int).SetString("2694ed2299005aeb35a8a71fd31024220ccbbd23fb76d386a99260750944076eb77f9111e9a23c01b513f264f7a6ee", 16) + g2To321x, _ := new(big.Int).SetString("eda41e19b1f5b3bbc7c9008cba4600ba826d414bcc9dd02c4481362de9f0f05b0355c475620dbbee7c9a5a7aa22067", 16) + g2To321y, _ := new(big.Int).SetString("218803f222f91b7cbb2f0b62fa1ff99454b01e185ce1fba26513f147017174ce38e9a89788ad589d693e47308dd150", 16) + g2To322x, _ := new(big.Int).SetString("12f5b8e90a9d36ed7eb153d9073db8c9e09c51a02b632a8c5d3aad4d77f86c4591f5dad192f7ca6c0fea7c5f41403c4", 16) + g2To322y, _ := new(big.Int).SetString("17a7ec92a2cb8478686184659615714d8d345c40eb495f2ab38333964935284678a97319c2a2bfc6c9ca61566884138", 16) + g2To323x, _ := new(big.Int).SetString("1221152369fca5412411c565c79f044b546984f01918b4d97edec6528a3980f03cf7e63e9ef8f55b3d5293d16badb86", 16) + g2To323y, _ := new(big.Int).SetString("118d45d7bc5088b03f1f8708e743e60a22707ee6f32a673d1414ba936fd683d81768293cdf1485e3f7de9eebbcbbeaa", 16) + g2To324x, _ := new(big.Int).SetString("82ff20a6292915f974708036a2fe6aa8bff9822e984cbcc4e704c32a74f0aca29eb44c23ea3f41be9d78b5d1363d52", 16) + g2To324y, _ := new(big.Int).SetString("15476de58380f6fc3e81212fbfa104b75e6b95173e2e7465606d00e90a01cb979c2dc5228c29857f118e8c75ae8d867", 16) + g2To325x, _ := new(big.Int).SetString("13cd07d37734b85917134e31e0da01cafbd7ec12840f470fa5bbf063a9f7c25138ecae4965deb9395571ac91af70e80", 16) + g2To325y, _ := new(big.Int).SetString("19376f39503358ddd7b0d0c89c161df3105aaca6d8b77311fc46a0ee0ea600ed0b041a50abef940daab7efb96b0a3a0", 16) + g2To326x, _ := new(big.Int).SetString("138bda3d6b146c30abde357a81f4c92ec0de1987e0cafedf62c3a718e5a76468376bb2a4b6c35d549969d43f224ca9e", 16) + g2To326y, _ := new(big.Int).SetString("5c01f9f48e8cabfc0801b89b21ce997a9dc3deb4575bf718214cb33fd1d3059f96c7f50aca93449511ffec2326b596", 16) + g2To327x, _ := new(big.Int).SetString("176806d5a6d8da954a719505987a0c239e0f4cc3644b88c1879cf2111287b98271beeb5cc3a05131f17fbb3a9100221", 16) + g2To327y, _ := new(big.Int).SetString("169cdeecf2bd8fac26bd789fbd00fc9c239b3a26576803e4c4a783ebed40f43a2175f05ed2e625dba29e3577b56d64b", 16) + g2To328x, _ := new(big.Int).SetString("1670583ed7e2ac2564fb7286a15c367d649bcb4f27329022480065e027e814f0b43f85172fa49fc4d2b5b3b4a150c85", 16) + g2To328y, _ := new(big.Int).SetString("108f1c8cdfa1efb8f73986a2c146c981572e562fb76d47d63f82e91cbed357c47cdbc89fea66ce6e7e7b629f0833604", 16) + g2To329x, _ := new(big.Int).SetString("62a9813d5e2a2ed755bd83dfc0338206560167a692e5e6d1b6a53fd6026b47635d3012c65a8b9388b95c34a8d91dc4", 16) + g2To329y, _ := new(big.Int).SetString("2cac82b8856f73359deb5a67e6d09db38e6c8156f25aa0f9b8ba411352ea3bbad397432b08b0d8511e5c539a824263", 16) + g2To330x, _ := new(big.Int).SetString("126b0bb0f258eaf2b8fb6c8cfe87e7abe6180fb4f43bbf28162efa08e12a7b52ee5a997ccf51656290fd424dfbc1393", 16) + g2To330y, _ := new(big.Int).SetString("188be748144fc5e24e2a226e4e9b4b24a8c29ba1e61506283b9b861f203613b91fac1d7fae101953ada6f6ba1bdaa93", 16) + g2To331x, _ := new(big.Int).SetString("a805b4d91d259dfd08defd52139260f6a563a579be1b9be167096af4a8735e00e7650a99a0058f6135ebd917e37ffe", 16) + g2To331y, _ := new(big.Int).SetString("96806965f68ddfca7ca8f8aef933405daa264b8d4afc7ab43b06ecd25741c08117b9f90fa1c11fd8a6d9ee59f5e5c8", 16) + g2To332x, _ := new(big.Int).SetString("bef13fb286d1ad6bda19c54484c5dc542e68fcfe65a873c9949b696a293fe3c364f614deb37cb2307e1b696d4ea1a7", 16) + g2To332y, _ := new(big.Int).SetString("1175b199f071ebbadb29d886a08f55ca12756d63e6df5d6b23b6cffccab067de8289cdecd4968b55361a1c788b464e0", 16) + g2To333x, _ := new(big.Int).SetString("88e3529cb1e090483a76d71a4b5db43fd2eedfe817562fec9038fa5627625aa4aa1a5e3b258696371dc09cd67d27c9", 16) + g2To333y, _ := new(big.Int).SetString("1425f4d3159dcffb3ad846b06232581ef8a27727e737647414e95bf40b3451298dc8731331ff5970cd43017a962029b", 16) + g2To334x, _ := new(big.Int).SetString("5a744af441dea697e5248c9b47bdef9ff684c124670ff3bc8a4ca23e7bf8939e9e6d58fd332cbdc2b49e13ffe1f2ba", 16) + g2To334y, _ := new(big.Int).SetString("19c54057a884c10109bdb88960e8f8a71133a6e140de962b60ebdad30ce84cc3da90843b0293580130027aebb98652", 16) + g2To335x, _ := new(big.Int).SetString("6b915a27f2e96efb69d11b7d8d19b4149f03a1d2cbd949b416f79271cbdb90eacd2732b194c7bf4f8ef824933f61ff", 16) + g2To335y, _ := new(big.Int).SetString("116e95fd3fe94c1ee784f72ac93f44e94c406745e0c5a8d97c0ced8a2eefb7bfe9ee2161242225f6ab857c020e03c84", 16) + g2To336x, _ := new(big.Int).SetString("cdc33c8ad030b1e15488ec5f7e054adf5d8e535830a1e5e285a0b2aa73d7f32c0eac2b74ec47c075b427fb6a5a8ff3", 16) + g2To336y, _ := new(big.Int).SetString("cd4bb0efb6541ebcff0748db7de50ab96f5c69e7c262ba36b129d96f601c887ec5b909d9634b571f46dc6f036b5ede", 16) + g2To337x, _ := new(big.Int).SetString("1722482e9c7f5cd289843e43e198b2e6be1e27fe833b490b002b579326ec33744b858b2324c9dd2baa1e34ba3129e77", 16) + g2To337y, _ := new(big.Int).SetString("68551cf7075c382f49bed3447b84ddfdb5ca24c60c207d2bc8924e296179ee70014dc0445885bfee0641beef32a64d", 16) + g2To338x, _ := new(big.Int).SetString("11e8cca326ae7cee7d8f4609f6247ea0d8b25d16d394f4db3804cf6741cd2d6f6de8b10a0e01fd281c0aebe7b981d5a", 16) + g2To338y, _ := new(big.Int).SetString("176bc4bd1cdb56bb86db6f84aa624c3c7c9561e8ce38e69f3baafc21b283c296731c53b051214c7cf621ba6b40bafff", 16) + g2To339x, _ := new(big.Int).SetString("a0f07342e976c6b9812218a40b21fec9cad87af9efff3c34cac73afcf6bcb94b5aa10b8c7f38b5e82b36a9815b0d8a", 16) + g2To339y, _ := new(big.Int).SetString("168626ba856267787b6673be864b83bef18e385ec280226612c59598662473b83d99938e37624f4691c791e0763f5c8", 16) + g2To340x, _ := new(big.Int).SetString("1a5aa4338efb66c5a530b41ffc1da3cadb49a9f25e03eb02f8bcaa2552769b1978955f1c6443c650eb81a8d09694caa", 16) + g2To340y, _ := new(big.Int).SetString("18ac9582657dae82090f0ca96a9dbc7c16cfb04719a598201bc1b8fa895f4b01270d5f285fac71fb9f9f26ea67734d3", 16) + g2To341x, _ := new(big.Int).SetString("806b32d3880209dc8872094e7dbba158dba9fe8353c83247f72cdc195b15821ea91c452b4cb46b005f0afb1ad8bc3a", 16) + g2To341y, _ := new(big.Int).SetString("10d2ff0f2ce0c8add5ba759e5918d503f1cda09ef263ed41ccb35a58dc1cd471920b45faea399e50fc9029584085e6c", 16) + g2To342x, _ := new(big.Int).SetString("e6bec1a058a818caee7d3c5b891519e1fc300a65fbd048110be85a3d19b746782217f8ad7e4af1ab4377b5dd0a8460", 16) + g2To342y, _ := new(big.Int).SetString("132a9a730bb3d7d9631aae4f528177fcfe647f6370931e8c45262c9f816002d8c062127126874dd5a83954588659c19", 16) + g2To343x, _ := new(big.Int).SetString("24a5836b629b9d6dc24d81b542a4159476ed0c57ce0341eaaec7d95b36b96194ccce02db106124808fa26b9a5e899d", 16) + g2To343y, _ := new(big.Int).SetString("129e34d641ad5cdd582e4ac4404ca9adb288f12cfd18721212574ae46a036c6377b9543a829b9fc09f2083c22f2ae57", 16) + g2To344x, _ := new(big.Int).SetString("ae46732d5bdb333be059365e374c5d261344c0febae49ffbd26e6f96bdc1710a9eb962ebfc96100d8d1d94fc73ea2c", 16) + g2To344y, _ := new(big.Int).SetString("fb39a612a7b2e70efcb2a01771a6a85460639158f6ab2514d0864b81a61881426a634301f43b807b41573bf83f48ef", 16) + g2To345x, _ := new(big.Int).SetString("320bc9ebef0f9b0a01e79b6e38b1baea6f794e263b2808dbfe1ce08a3662cf6d10d8d282c1f30b07e1f178ac8bb88e", 16) + g2To345y, _ := new(big.Int).SetString("6bb7685664b9941642a8a614a467715d6e60492551bfb68c4eedaada7e1b4d3bd872fca56d5877765f91051f742376", 16) + g2To346x, _ := new(big.Int).SetString("8b337d3a0778738aad74b30e3482278f4b962f3b7bc9950c7d01e3e9fb9bba5529a61e50703387f6d2b4c2e273f3f3", 16) + g2To346y, _ := new(big.Int).SetString("153b19f1162ba2f1a3a2e8f0449a1f88975f7b69f495c07c6e2af826137e805b1a9694e373dd7ed05de2ce7ac062b72", 16) + g2To347x, _ := new(big.Int).SetString("194cc05f1f9b917c0d334824a93eb77e4ddf1577051b31d7f656ae9bd9345dc71fbd7a499e50d1ba016315508932336", 16) + g2To347y, _ := new(big.Int).SetString("a228455476c0c2e19fb6bf3e302c7efb4c52b3cef3b15983769b290f20a59d7581fb589aa2aaf12d917231b3fe9842", 16) + g2To348x, _ := new(big.Int).SetString("25fde08a25e27ebabb5bca6e8adbbaa2ed0ddb932fe50cae36d6941a761e907ec1b72e28ad037b2b49b8e12f075128", 16) + g2To348y, _ := new(big.Int).SetString("5a67365d4975b7774e01a25f66a40e989282d72c71baa7baebd02e7400b9592bc9eae1d7270b25dc5d6dd5fb2e63ae", 16) + g2To349x, _ := new(big.Int).SetString("c3412332dd8e5c03f33eafd042b8e7612a4cabde5861e149d95d8362458d572c0a54de9b2f8d84bbb6b345272ba610", 16) + g2To349y, _ := new(big.Int).SetString("47d9ff462724810b2dbc73a0ae9504785a0640879bcd628bb87b8ec229528eda3887463ecfc3fa4000a3f64bbaaeb9", 16) + g2To350x, _ := new(big.Int).SetString("30804bcc5cfdfe6501db5ef22b1494f892aba6f14bedec86096ddc5d67086ba43e54dee7d50e3b50c5800c29509ad7", 16) + g2To350y, _ := new(big.Int).SetString("6c2bc85976ce447723a6af9cdb2b02cb6efaa1ca591d19b16307379671dc10deb9e8bb49f8f5cd67f1c9c77427ef70", 16) + g2To351x, _ := new(big.Int).SetString("eaa19d82315ec52ae5dd8cd819f2acd01d4c1e2419cdb79c494b61067729fee2daa46997d92f9ec4edd676ee6b3cd5", 16) + g2To351y, _ := new(big.Int).SetString("197da9de1b9bc8f70003380e71c84f116686c06ceb741b63c9c44db2c828c71b7bf0820dbbf8b54a124b72d426b5276", 16) + g2To352x, _ := new(big.Int).SetString("936df9581109ac18c66358d7e5a1e93a2c6a09ba3e481fdd878398eb74ad271fcf7d6b4b613e155c3b70504f86adc3", 16) + g2To352y, _ := new(big.Int).SetString("36e5d6c54d1e75498622b48a46a7f30cc18b9b1d7e16e9121367290cf1aa0c0132976f3bc3c241630c02aca66e070e", 16) + g2To353x, _ := new(big.Int).SetString("e03b5a733511b241dded70bb27a45540c2f932fb3ca7093b32d35a7bdad276da8a36336fd0c7947dc606ebc8d65216", 16) + g2To353y, _ := new(big.Int).SetString("131fa796d16299d6fd3435528183ab598a2564471521892e6880a1bd196aadb78e7010afb790caff9392901c2142dd8", 16) + g2To354x, _ := new(big.Int).SetString("b299f44dcdf3c05c1183a875ff598888b9b1fc3d0565d8f411273b365d5b9791136679a97c9900fdeba3b6ead8a2b5", 16) + g2To354y, _ := new(big.Int).SetString("1aba7ac86a133146939c472e0ab51669da7fa4cd2973db95e0c91f5b1ebcca0f596925c80b4c061d8973d4eee20644e", 16) + g2To355x, _ := new(big.Int).SetString("2f079339f94ee4f57dcad806186a5b18ef9c406dd3b39b6322e3a234307a16625005e489b6431e953c41092ac91314", 16) + g2To355y, _ := new(big.Int).SetString("a8af71578ea94452c3c80b68c85756e1cfe6cc78c84e44596aa980cce9ba39371f767b3b7f0cf31c9824b148d5364d", 16) + g2To356x, _ := new(big.Int).SetString("bc5e3ec2bf84bcacb8b541c331184dea078277cf72664ae98b33da575f897183137bcf8451f7e5518c5a01a90ba073", 16) + g2To356y, _ := new(big.Int).SetString("478b3ba1c586db5a56e40209e282eb1d4a67bdad5eab8248fd79c93613d64b2f19c7733e5b05fabab6782afa1f6c20", 16) + g2To357x, _ := new(big.Int).SetString("c4fd8f8b91dbc4e2cc656c051055d88e8c1423cb57590b9c6def1507decc0264dca04e6b89846baa298167767a6687", 16) + g2To357y, _ := new(big.Int).SetString("a069aefc91fcd2bd934cc982e00cf2b09826ecb9391f64dc73b234f389c8edbd873cf60d5f3967661e18d62e0608c8", 16) + g2To358x, _ := new(big.Int).SetString("1590a01aab74236cfde06b181b47760428d14e72ff8bebd1be6a37219ddf352bd0acbe88cca6cf4a369ff273e7b348d", 16) + g2To358y, _ := new(big.Int).SetString("9df16198abf966f2fb0aa9321dda2bd12d45e90622c8464724ad3c5250b7bc720316443a6b1fc9c157a8c8e6117a45", 16) + g2To359x, _ := new(big.Int).SetString("191e44a4da422531287ff23becc8ab142fde217c3103f94c2a06241a65db5e8bcdf7fd5ea89797c08edf75a975acd85", 16) + g2To359y, _ := new(big.Int).SetString("181760764282c3ef0b608fc6ee204e35ae7b39e20c9610422c3da09f299c90b65e11acce099722c8f69a226a3b0e6d9", 16) + g2To360x, _ := new(big.Int).SetString("16640d9e5b56aa5678e7e43ad8b2a0baeebe908b8ce34a0c8bccf175d58d42e9c80e8e3881f11bc2bf3dc4edced9ebc", 16) + g2To360y, _ := new(big.Int).SetString("fed41f72081c7e09f2804940ebd758e8fb071f816d60ec24a26e63db1eaae3eaf892757693f8b91a9e691a77cb95de", 16) + g2To361x, _ := new(big.Int).SetString("12e4ae1e316b7d7be879a12c20ae0635679517f8405fe1749c0e7ea38d41ac52840076f70256a1df6e449df7fc3ff1c", 16) + g2To361y, _ := new(big.Int).SetString("950b53c101af32c6c2ca7db1eef29e8a4fe7cd459b35212936d93cb25273bfedfda4e40beec676deab937fbc2a9e2", 16) + g2To362x, _ := new(big.Int).SetString("d51ab083eb7c89aaf1f7195594c8fe038d8b5cca680bea3ea7d544ab3a468c695c528c07458d0a48dd314d3beae518", 16) + g2To362y, _ := new(big.Int).SetString("15cc9b5b004da0b4fab661f07d924cf6161624c7727df1576a53ac829e941df55b163dbb573a566340ef0371a25c7c1", 16) + g2To363x, _ := new(big.Int).SetString("e3230c3a0b2f354660488e204837810c9b850985ed2c2b10dffc04c68e937aded281090a6ab1a2143c1506273986ca", 16) + g2To363y, _ := new(big.Int).SetString("ac37d93717549dc0e7363fa5f0a8b01a09db130af6df1a9ac67eec29fef2479315ea0f82cc234ce1c41960cbafbede", 16) + g2To364x, _ := new(big.Int).SetString("8205a824a6f304d3b052487c9ed6ed29ef78c0ebbccd5773fdd4f1c14124add69a3c8b9502e929af3c902be375f58d", 16) + g2To364y, _ := new(big.Int).SetString("18c7078631c53fd552c41290c111e91824d4470792c1ae04c37d646a63c5bfebc161f57159294447233b89c957d24e", 16) + g2To365x, _ := new(big.Int).SetString("18f7915fdce96217ad18241e2a4567ececdba645030d66e256defcf5a73497a34abdb95258ab412626209b9d726e2e6", 16) + g2To365y, _ := new(big.Int).SetString("423ba66324a2cb13932ffc1d86ade0010e836ea8a641daf1c8efd264f7d6a9e64d8db1aba79f0cee040f66fda36f12", 16) + g2To366x, _ := new(big.Int).SetString("29d424b613b9b29b24decbb39120345413a6c565a07944162f3b71e3f7e4a02f25596a1f228d85cf9e4dd0fd3acc2a", 16) + g2To366y, _ := new(big.Int).SetString("b0589296e7dd04a447cb7739eb249541b5ae9de2a451aba3c14f3572aec6baffd6f3deff1d75e0a48519785bbc4f09", 16) + g2To367x, _ := new(big.Int).SetString("b29891662f6a6ff52209bdd893751488eb5e29ead206e4d3b3b3274b2f1dd2558f7ead4b5a854c0411164e3f431cae", 16) + g2To367y, _ := new(big.Int).SetString("119fc3ab0bbf1d0c0ead2e84897795e30d85707a85feff8f3ace65b6db714cd0985a1e8c71b7da97bf67d1f030865c3", 16) + g2To368x, _ := new(big.Int).SetString("ed23a3f54b439c5c15bd5d87c7b2bbba3e8b7ba7c112ba043aff04a2184a8525ac47c399ebb7900d41e35d9c2aa6fd", 16) + g2To368y, _ := new(big.Int).SetString("977779960cbba06bcc4b231f2012767172ca59d0ce154759c734694d3cb8c6913e5b48626c2d22d018e6d805649de3", 16) + g2To369x, _ := new(big.Int).SetString("154d2fba6e5862dc6cea1154dd33bba1b0179b85baef1417dd807a65627ad173fb3a16d078ca2c698dc59a6d646524b", 16) + g2To369y, _ := new(big.Int).SetString("829e52abb7d38f0b7b41676faa78c3ebc48b5744dd2428277d82d05ecfbab5de0cb2b4c09d6d38659bb2744e532899", 16) + g2To370x, _ := new(big.Int).SetString("14b4837188c5142d9a0203cb7cae32f0490835335ca494fb64c041574fe220950d4753b5c1da02c945c7946ba27d86a", 16) + g2To370y, _ := new(big.Int).SetString("b35694fe7b4f14515b7dcfbbdcdb305941ddb39e1fc757d7ada794f137b6051d2b8992dffab9b2f00c330a62712870", 16) + g2To371x, _ := new(big.Int).SetString("1e8aa5ad207848e44eb7fe073e9c2bc98d0832bef8c7ff1fccc9d671bd9c8771e4794c9d5eb5335ef0b86c42031a51", 16) + g2To371y, _ := new(big.Int).SetString("d239e83948c7bde5159eaf6ce6cf4f40f71be69330fcd2f1b41ce36afa0a568813f3e1c10a194b8f086b28d01cf834", 16) + g2To372x, _ := new(big.Int).SetString("8e11f1f3e7cb99daae5ce7061e34a798af7ff23b13d56f6395edf45d4be4ea59c65f5d2d898638fc7b4537dca41170", 16) + g2To372y, _ := new(big.Int).SetString("68a9ff131c2916f4ab183a422feaa5442900683d6176bf7c36e816a45b1f5f9df394ca7117f7780e2c6e5e5dfff73", 16) + g2To373x, _ := new(big.Int).SetString("84d5af6e2f4b2b9babba22f9f3a9bb978972b1ef4548eb48dd81ebd06afb8e1b03d061ed8607daf2464b7e7155464a", 16) + g2To373y, _ := new(big.Int).SetString("13e7dd0b4a5dcd9114011529bd13d8a1bfef91a8e65a9ee3db45b4038dcb04fef8fe24c633615e4b8cdecaf63093cb7", 16) + g2To374x, _ := new(big.Int).SetString("1ab7ae756cb1a4ce535b1476fde782b558345b35abe41b8fa9d72ce745ff3484e9492b2ed2dd2124471b51475ee9488", 16) + g2To374y, _ := new(big.Int).SetString("14b3558a24d7eb383096d1963efc1fb865a6a02e995a6b0b8b2fccb13160cfd665a9e4a24dcfabb9ba4003f08c53c86", 16) + g2To375x, _ := new(big.Int).SetString("dc760af5c11d31450e588152a4022dcaf567fd647b1db15f8870aacd8eacacc0f46631ce851a569579601f5715e2cd", 16) + g2To375y, _ := new(big.Int).SetString("179db42c900b0bfb6f0a8a1dc2394016663ad79a7a338c01030eb1f3852a962c2195f47fdda5b3c658d9ca5bdf09281", 16) + g2To376x, _ := new(big.Int).SetString("16490e82ddc6080d4fdfc6b156351793a0b8b1152eba0b9f210342871ff9a5305348518e9baa6aa2aa81a7ad88815e0", 16) + g2To376y, _ := new(big.Int).SetString("18e204412e7ebdf645fa94d53609bf7d1c11b81cedb787a1d5dff84712b7284edd329a83986c196c3c9891fbdf75b88", 16) + + return CurvePoints{ + Gx: gx, + Gy: gy, + + Gmx: [377]*big.Int{g3x, g5x, g7x, g2To3x, g2To4x, g2To5x, g2To6x, g2To7x, g2To8x, g2To9x, g2To10x, g2To11x, g2To12x, g2To13x, g2To14x, g2To15x, g2To16x, g2To17x, g2To18x, g2To19x, g2To20x, g2To21x, g2To22x, g2To23x, g2To24x, g2To25x, g2To26x, g2To27x, g2To28x, g2To29x, g2To30x, g2To31x, g2To32x, g2To33x, g2To34x, g2To35x, g2To36x, g2To37x, g2To38x, g2To39x, g2To40x, g2To41x, g2To42x, g2To43x, g2To44x, g2To45x, g2To46x, g2To47x, g2To48x, g2To49x, g2To50x, g2To51x, g2To52x, g2To53x, g2To54x, g2To55x, g2To56x, g2To57x, g2To58x, g2To59x, g2To60x, g2To61x, g2To62x, g2To63x, g2To64x, g2To65x, g2To66x, g2To67x, g2To68x, g2To69x, g2To70x, g2To71x, g2To72x, g2To73x, g2To74x, g2To75x, g2To76x, g2To77x, g2To78x, g2To79x, g2To80x, g2To81x, g2To82x, g2To83x, g2To84x, g2To85x, g2To86x, g2To87x, g2To88x, g2To89x, g2To90x, g2To91x, g2To92x, g2To93x, g2To94x, g2To95x, g2To96x, g2To97x, g2To98x, g2To99x, g2To100x, g2To101x, g2To102x, g2To103x, g2To104x, g2To105x, g2To106x, g2To107x, g2To108x, g2To109x, g2To110x, g2To111x, g2To112x, g2To113x, g2To114x, g2To115x, g2To116x, g2To117x, g2To118x, g2To119x, g2To120x, g2To121x, g2To122x, g2To123x, g2To124x, g2To125x, g2To126x, g2To127x, g2To128x, g2To129x, g2To130x, g2To131x, g2To132x, g2To133x, g2To134x, g2To135x, g2To136x, g2To137x, g2To138x, g2To139x, g2To140x, g2To141x, g2To142x, g2To143x, g2To144x, g2To145x, g2To146x, g2To147x, g2To148x, g2To149x, g2To150x, g2To151x, g2To152x, g2To153x, g2To154x, g2To155x, g2To156x, g2To157x, g2To158x, g2To159x, g2To160x, g2To161x, g2To162x, g2To163x, g2To164x, g2To165x, g2To166x, g2To167x, g2To168x, g2To169x, g2To170x, g2To171x, g2To172x, g2To173x, g2To174x, g2To175x, g2To176x, g2To177x, g2To178x, g2To179x, g2To180x, g2To181x, g2To182x, g2To183x, g2To184x, g2To185x, g2To186x, g2To187x, g2To188x, g2To189x, g2To190x, g2To191x, g2To192x, g2To193x, g2To194x, g2To195x, g2To196x, g2To197x, g2To198x, g2To199x, g2To200x, g2To201x, g2To202x, g2To203x, g2To204x, g2To205x, g2To206x, g2To207x, g2To208x, g2To209x, g2To210x, g2To211x, g2To212x, g2To213x, g2To214x, g2To215x, g2To216x, g2To217x, g2To218x, g2To219x, g2To220x, g2To221x, g2To222x, g2To223x, g2To224x, g2To225x, g2To226x, g2To227x, g2To228x, g2To229x, g2To230x, g2To231x, g2To232x, g2To233x, g2To234x, g2To235x, g2To236x, g2To237x, g2To238x, g2To239x, g2To240x, g2To241x, g2To242x, g2To243x, g2To244x, g2To245x, g2To246x, g2To247x, g2To248x, g2To249x, g2To250x, g2To251x, g2To252x, g2To253x, g2To254x, g2To255x, g2To256x, g2To257x, g2To258x, g2To259x, g2To260x, g2To261x, g2To262x, g2To263x, g2To264x, g2To265x, g2To266x, g2To267x, g2To268x, g2To269x, g2To270x, g2To271x, g2To272x, g2To273x, g2To274x, g2To275x, g2To276x, g2To277x, g2To278x, g2To279x, g2To280x, g2To281x, g2To282x, g2To283x, g2To284x, g2To285x, g2To286x, g2To287x, g2To288x, g2To289x, g2To290x, g2To291x, g2To292x, g2To293x, g2To294x, g2To295x, g2To296x, g2To297x, g2To298x, g2To299x, g2To300x, g2To301x, g2To302x, g2To303x, g2To304x, g2To305x, g2To306x, g2To307x, g2To308x, g2To309x, g2To310x, g2To311x, g2To312x, g2To313x, g2To314x, g2To315x, g2To316x, g2To317x, g2To318x, g2To319x, g2To320x, g2To321x, g2To322x, g2To323x, g2To324x, g2To325x, g2To326x, g2To327x, g2To328x, g2To329x, g2To330x, g2To331x, g2To332x, g2To333x, g2To334x, g2To335x, g2To336x, g2To337x, g2To338x, g2To339x, g2To340x, g2To341x, g2To342x, g2To343x, g2To344x, g2To345x, g2To346x, g2To347x, g2To348x, g2To349x, g2To350x, g2To351x, g2To352x, g2To353x, g2To354x, g2To355x, g2To356x, g2To357x, g2To358x, g2To359x, g2To360x, g2To361x, g2To362x, g2To363x, g2To364x, g2To365x, g2To366x, g2To367x, g2To368x, g2To369x, g2To370x, g2To371x, g2To372x, g2To373x, g2To374x, g2To375x, g2To376x}, + Gmy: [377]*big.Int{g3y, g5y, g7y, g2To3y, g2To4y, g2To5y, g2To6y, g2To7y, g2To8y, g2To9y, g2To10y, g2To11y, g2To12y, g2To13y, g2To14y, g2To15y, g2To16y, g2To17y, g2To18y, g2To19y, g2To20y, g2To21y, g2To22y, g2To23y, g2To24y, g2To25y, g2To26y, g2To27y, g2To28y, g2To29y, g2To30y, g2To31y, g2To32y, g2To33y, g2To34y, g2To35y, g2To36y, g2To37y, g2To38y, g2To39y, g2To40y, g2To41y, g2To42y, g2To43y, g2To44y, g2To45y, g2To46y, g2To47y, g2To48y, g2To49y, g2To50y, g2To51y, g2To52y, g2To53y, g2To54y, g2To55y, g2To56y, g2To57y, g2To58y, g2To59y, g2To60y, g2To61y, g2To62y, g2To63y, g2To64y, g2To65y, g2To66y, g2To67y, g2To68y, g2To69y, g2To70y, g2To71y, g2To72y, g2To73y, g2To74y, g2To75y, g2To76y, g2To77y, g2To78y, g2To79y, g2To80y, g2To81y, g2To82y, g2To83y, g2To84y, g2To85y, g2To86y, g2To87y, g2To88y, g2To89y, g2To90y, g2To91y, g2To92y, g2To93y, g2To94y, g2To95y, g2To96y, g2To97y, g2To98y, g2To99y, g2To100y, g2To101y, g2To102y, g2To103y, g2To104y, g2To105y, g2To106y, g2To107y, g2To108y, g2To109y, g2To110y, g2To111y, g2To112y, g2To113y, g2To114y, g2To115y, g2To116y, g2To117y, g2To118y, g2To119y, g2To120y, g2To121y, g2To122y, g2To123y, g2To124y, g2To125y, g2To126y, g2To127y, g2To128y, g2To129y, g2To130y, g2To131y, g2To132y, g2To133y, g2To134y, g2To135y, g2To136y, g2To137y, g2To138y, g2To139y, g2To140y, g2To141y, g2To142y, g2To143y, g2To144y, g2To145y, g2To146y, g2To147y, g2To148y, g2To149y, g2To150y, g2To151y, g2To152y, g2To153y, g2To154y, g2To155y, g2To156y, g2To157y, g2To158y, g2To159y, g2To160y, g2To161y, g2To162y, g2To163y, g2To164y, g2To165y, g2To166y, g2To167y, g2To168y, g2To169y, g2To170y, g2To171y, g2To172y, g2To173y, g2To174y, g2To175y, g2To176y, g2To177y, g2To178y, g2To179y, g2To180y, g2To181y, g2To182y, g2To183y, g2To184y, g2To185y, g2To186y, g2To187y, g2To188y, g2To189y, g2To190y, g2To191y, g2To192y, g2To193y, g2To194y, g2To195y, g2To196y, g2To197y, g2To198y, g2To199y, g2To200y, g2To201y, g2To202y, g2To203y, g2To204y, g2To205y, g2To206y, g2To207y, g2To208y, g2To209y, g2To210y, g2To211y, g2To212y, g2To213y, g2To214y, g2To215y, g2To216y, g2To217y, g2To218y, g2To219y, g2To220y, g2To221y, g2To222y, g2To223y, g2To224y, g2To225y, g2To226y, g2To227y, g2To228y, g2To229y, g2To230y, g2To231y, g2To232y, g2To233y, g2To234y, g2To235y, g2To236y, g2To237y, g2To238y, g2To239y, g2To240y, g2To241y, g2To242y, g2To243y, g2To244y, g2To245y, g2To246y, g2To247y, g2To248y, g2To249y, g2To250y, g2To251y, g2To252y, g2To253y, g2To254y, g2To255y, g2To256y, g2To257y, g2To258y, g2To259y, g2To260y, g2To261y, g2To262y, g2To263y, g2To264y, g2To265y, g2To266y, g2To267y, g2To268y, g2To269y, g2To270y, g2To271y, g2To272y, g2To273y, g2To274y, g2To275y, g2To276y, g2To277y, g2To278y, g2To279y, g2To280y, g2To281y, g2To282y, g2To283y, g2To284y, g2To285y, g2To286y, g2To287y, g2To288y, g2To289y, g2To290y, g2To291y, g2To292y, g2To293y, g2To294y, g2To295y, g2To296y, g2To297y, g2To298y, g2To299y, g2To300y, g2To301y, g2To302y, g2To303y, g2To304y, g2To305y, g2To306y, g2To307y, g2To308y, g2To309y, g2To310y, g2To311y, g2To312y, g2To313y, g2To314y, g2To315y, g2To316y, g2To317y, g2To318y, g2To319y, g2To320y, g2To321y, g2To322y, g2To323y, g2To324y, g2To325y, g2To326y, g2To327y, g2To328y, g2To329y, g2To330y, g2To331y, g2To332y, g2To333y, g2To334y, g2To335y, g2To336y, g2To337y, g2To338y, g2To339y, g2To340y, g2To341y, g2To342y, g2To343y, g2To344y, g2To345y, g2To346y, g2To347y, g2To348y, g2To349y, g2To350y, g2To351y, g2To352y, g2To353y, g2To354y, g2To355y, g2To356y, g2To357y, g2To358y, g2To359y, g2To360y, g2To361y, g2To362y, g2To363y, g2To364y, g2To365y, g2To366y, g2To367y, g2To368y, g2To369y, g2To370y, g2To371y, g2To372y, g2To373y, g2To374y, g2To375y, g2To376y}, + } +} diff --git a/std/commitments/kzg_bls12377/verifier.go b/std/commitments/kzg_bls12377/verifier.go index 49f9ed5b19..264f76dc70 100644 --- a/std/commitments/kzg_bls12377/verifier.go +++ b/std/commitments/kzg_bls12377/verifier.go @@ -28,7 +28,6 @@ type Digest = sw_bls12377.G1Affine // VK verification key (G2 part of SRS) type VK struct { - G1 sw_bls12377.G1Affine // G₁ G2 [2]sw_bls12377.G2Affine // [G₂, [α]G₂] } @@ -53,7 +52,7 @@ func Verify(api frontend.API, commitment Digest, proof OpeningProof, point front // [f(a)]G₁ var claimedValueG1Aff sw_bls12377.G1Affine - claimedValueG1Aff.ScalarMul(api, srs.G1, proof.ClaimedValue) + claimedValueG1Aff.ScalarMulBase(api, proof.ClaimedValue) // [f(α) - f(a)]G₁ var fminusfaG1 sw_bls12377.G1Affine diff --git a/std/commitments/kzg_bls12377/verifier_test.go b/std/commitments/kzg_bls12377/verifier_test.go index 55f9c9453a..7acd1e55aa 100644 --- a/std/commitments/kzg_bls12377/verifier_test.go +++ b/std/commitments/kzg_bls12377/verifier_test.go @@ -27,6 +27,7 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/consensys/gnark/frontend/cs/scs" + "github.com/consensys/gnark/profile" "github.com/consensys/gnark/test" ) @@ -98,9 +99,6 @@ func TestVerifierDynamic(t *testing.T) { witness.S = point.String() - witness.VerifKey.G1.X = srs.G1[0].X.String() - witness.VerifKey.G1.Y = srs.G1[0].Y.String() - witness.VerifKey.G2[0].X.A0 = srs.G2[0].X.A0.String() witness.VerifKey.G2[0].X.A1 = srs.G2[0].X.A1.String() witness.VerifKey.G2[0].Y.A0 = srs.G2[0].Y.A0.String() @@ -132,8 +130,6 @@ func TestVerifier(t *testing.T) { witness.Proof.ClaimedValue = "7211341386127354417397285211336133449231039596179023429378585109196698597268" witness.S = "4321" - witness.VerifKey.G1.X = "81937999373150964239938255573465948239988671502647976594219695644855304257327692006745978603320413799295628339695" - witness.VerifKey.G1.Y = "241266749859715473739788878240585681733927191168601896383759122102112907357779751001206799952863815012735208165030" witness.VerifKey.G2[0].X.A0 = "233578398248691099356572568220835526895379068987715365179118596935057653620464273615301663571204657964920925606294" witness.VerifKey.G2[0].X.A1 = "140913150380207355837477652521042157274541796891053068589147167627541651775299824604154852141315666357241556069118" witness.VerifKey.G2[0].Y.A0 = "63160294768292073209381361943935198908131692476676907196754037919244929611450776219210369229519898517858833747423" @@ -157,7 +153,9 @@ func BenchmarkVerifyKZG(b *testing.B) { b.ResetTimer() b.Run("groth16", func(b *testing.B) { for i := 0; i < b.N; i++ { + p := profile.Start() ccsBench, _ = frontend.Compile(ecc.BW6_761.ScalarField(), r1cs.NewBuilder, &c) + p.Stop() } }) b.Log("groth16", ccsBench.GetNbConstraints()) From 29b49866ef7fb8f10ddb60ca807198715c95e71f Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 1 Mar 2023 11:55:21 +0100 Subject: [PATCH 031/464] fix(sw_bls12377/ScalarMulBase): limit loop size to fr.BitLen --- std/algebra/sw_bls12377/g1.go | 4 +- std/algebra/sw_bls12377/inner.go | 256 +------------------------------ 2 files changed, 6 insertions(+), 254 deletions(-) diff --git a/std/algebra/sw_bls12377/g1.go b/std/algebra/sw_bls12377/g1.go index ac8ea4a746..134199e4ed 100644 --- a/std/algebra/sw_bls12377/g1.go +++ b/std/algebra/sw_bls12377/g1.go @@ -457,7 +457,7 @@ func (P *G1Affine) ScalarMulBase(api frontend.API, s frontend.Variable) *G1Affin points := GetBLS12377Points() - sBits := api.ToBinary(s) + sBits := api.ToBinary(s, 253) var res, tmp G1Affine @@ -466,7 +466,7 @@ func (P *G1Affine) ScalarMulBase(api frontend.API, s frontend.Variable) *G1Affin res.X = api.Lookup2(sBits[1], sBits[2], points.Gx, points.Gmx[0], points.Gmx[1], points.Gmx[2]) res.Y = api.Lookup2(sBits[1], sBits[2], points.Gy, points.Gmy[0], points.Gmy[1], points.Gmy[2]) - for i := 3; i < len(sBits); i++ { + for i := 3; i < 253; i++ { // gm[i] = [2^i]g tmp.X = res.X tmp.Y = res.Y diff --git a/std/algebra/sw_bls12377/inner.go b/std/algebra/sw_bls12377/inner.go index bef2cc9eca..f71f6f1523 100644 --- a/std/algebra/sw_bls12377/inner.go +++ b/std/algebra/sw_bls12377/inner.go @@ -66,8 +66,8 @@ func getInnerCurveConfig(outerCurveScalarField *big.Int) *innerConfig { type CurvePoints struct { Gx *big.Int // base point x Gy *big.Int // base point y - Gmx [377]*big.Int // m*base point x - Gmy [377]*big.Int // m*base point y + Gmx [253]*big.Int // m*base point x + Gmy [253]*big.Int // m*base point y } func GetBLS12377Points() CurvePoints { @@ -579,260 +579,12 @@ func GetBLS12377Points() CurvePoints { g2To251y, _ := new(big.Int).SetString("6895ecd12c1cfcc15a05cde2e775d7387754b5e3fc43b1961f370dc28fc9b6a5602389685b7251dd0f6ee1490e99ce", 16) g2To252x, _ := new(big.Int).SetString("13a0c4f35b617ea8aa399aac8b1c977320c28204236dc32ada1b64e7a8c79165f34ba75baef06d41918e24984c8ddfc", 16) g2To252y, _ := new(big.Int).SetString("8f6802c76d44e816b66d17f7be4e845edf2c12caae31d9223f8b9b40dcf782b222218ca0c725116b18986661f9068c", 16) - g2To253x, _ := new(big.Int).SetString("129727af35616521d6ae25809aa137ab2449ff07117bda3cede303cf37a5836e9fe3163dbbec2e479f6d731960816f1", 16) - g2To253y, _ := new(big.Int).SetString("1ab7e34c28459a4b0ddc48f5824c99d0fc99bf037164ff4bc414f76ef9d60df14133055056dbcbfa1913091cce44fcf", 16) - g2To254x, _ := new(big.Int).SetString("197845ed8f04a6b851f909820152cc21841e6ace5830d9c67d8f64209b05e4487e0cbc2096dffb85f86286b10c6e662", 16) - g2To254y, _ := new(big.Int).SetString("5d09de5b809843819627a98be83a8384edc0dec8794f0b7014d411cd1e0260e4113f55ca5557491f5a2f9de64441f2", 16) - g2To255x, _ := new(big.Int).SetString("400ecf2f17e142d9852c1998a771c52129869a7ce40e1003d83398f6628e3a0021dd3309424d92c3d3f6e3bde5d70d", 16) - g2To255y, _ := new(big.Int).SetString("132d749e90bc289de1447e5c4234333311f49db68ee5b58950adb26f7dec18db3d79fc75644ce2651adfc483b01ab24", 16) - g2To256x, _ := new(big.Int).SetString("198ad93d9ba5054eed66c1745995e7ba6672c99ee4179c2f02793ff6a495e6fa7e879e3b54cca408499fee19eb2045a", 16) - g2To256y, _ := new(big.Int).SetString("ac8bff7efe46a32015801a50c1699fa4d6db622fc4f9bbbe0a96b930633c64a11aa2ad9055d54098f29c742f05d8b1", 16) - g2To257x, _ := new(big.Int).SetString("419b587dbbc9aa407b2457fc95c4c0cccb6e635eab74694f90181ba4b78500181d91689f9548bb983d061550db352f", 16) - g2To257y, _ := new(big.Int).SetString("838937ff5e909ae25c2bdb5eca27f919fd94cb035efa30d578cae3599d8b987f7780b27c943641a91fd1659de7583c", 16) - g2To258x, _ := new(big.Int).SetString("17cb59b9056bbcbbd2845178a93c57602b138aacc93fe2a6f8cfccb4819349eb4a66b88689f9db95874dc6db1247eb9", 16) - g2To258y, _ := new(big.Int).SetString("2e8c8691a68b105570acaf31637176ead8cfe6bb53c8708431483d1e8f8f3e24fbd8c33c9b448224d91bcd717d7edc", 16) - g2To259x, _ := new(big.Int).SetString("4749dda7b83f7f538e98bb688780b430eb22f7b3a9c30461c354334a5773585868334bf1b99d5df328c5e7c3e1661b", 16) - g2To259y, _ := new(big.Int).SetString("66356809bd4b23dbd70fb1c7869a1cc7a3aa71d8620883a4626feadca45ebe435031cb135c71e3fabfda6cd8ddf6b8", 16) - g2To260x, _ := new(big.Int).SetString("8ef3c6b70c4cb43b4d9b04e361c35d94ecf6026cca5ac3c7969feb7c5f340f35fd70bba29aaf1dc4796a989f0f3f7", 16) - g2To260y, _ := new(big.Int).SetString("91166e9fc5c9c93e346d479b7423ef9c427c1bc6deae02668d14a7aac9e5b602c95ea34f415cdf9df8d2354dbb47ba", 16) - g2To261x, _ := new(big.Int).SetString("4a1b0dd0bde5642499ebbb58e0e7864cccb19db85c202d7c2cfd365ae10ccbfa94235659f6d8f3b13f7406e1f2130f", 16) - g2To261y, _ := new(big.Int).SetString("18874ff430cd57f22ef1e9eb200fd9179e25ebdeff4deec94b1ea47383f67efa5b5d28cf44431434801ae6006dcb152", 16) - g2To262x, _ := new(big.Int).SetString("7330b2e525bb4a8b1873430a816350f55362e9d5a02b54888fc371234d7fa0a6b1c819eec90877a22d2f01c9577f49", 16) - g2To262y, _ := new(big.Int).SetString("2eac84091b4c2d07ef816af65ccab3557767faafed961fc26bdeb185356ce67acd605f848cb64c1b25075d50368731", 16) - g2To263x, _ := new(big.Int).SetString("12865ece19ac21dddd28e54ca2315c04612fdff240d7e6eb1ccdd7e53b0647b6f6d701c0f12df73b909b30a8793ca", 16) - g2To263y, _ := new(big.Int).SetString("628a236c09ebf3da0eb8a32b632a536af927faaecc26e0e62083e241b96bcebeaf70c070770b45d368fd3a3c15c05f", 16) - g2To264x, _ := new(big.Int).SetString("11c2b8dcf027f232fefc8b1f7364794b61325690bc49bfa393ce1a5c205c9fa845f51f82266a9f9fcce5a8ddc5ba8ec", 16) - g2To264y, _ := new(big.Int).SetString("10c9be29c224fe56bdb9cd71577876e25f18bb80c1f1169072f14d82d1a685309fa53569db022b1ba3b419cc408ed65", 16) - g2To265x, _ := new(big.Int).SetString("190e07f485371d9df7ca8076030dac2c988271a38582223db0a99a917c4a7ef60f7ab934bd7a9495045a01174a04efb", 16) - g2To265y, _ := new(big.Int).SetString("de4b4db4a1e8a4786319172ef206b782042f3808ddebef6698548b903289cbf13f9895185823181aae0507745883b4", 16) - g2To266x, _ := new(big.Int).SetString("1129d1c009f73dad3ed13ce78b98c3938c4f2978521a281a8cf98806b466071338b1b6b00e90d66bb4e6fe34d85dc01", 16) - g2To266y, _ := new(big.Int).SetString("26428deb622885a32f6a93f445f98eb23d0b31e613f0beeea361b5550b1da5c64f4285f710c1a8877bf1deefc7ac6a", 16) - g2To267x, _ := new(big.Int).SetString("3e2a4ce3e21d1415389de270dc6b64930f04220c0ea201c478356a86d2a2988785b78e5de59bca4f656343e3c49a6b", 16) - g2To267y, _ := new(big.Int).SetString("491d6b62b5ad50de349916125744205a2f3d8f9afc259fbbd844073f26f5922426da3218444bcecc183ff852aa2d80", 16) - g2To268x, _ := new(big.Int).SetString("93562e285dd4f2535ce60f41e0a0d5797fe30dee311719378882be71ee2a4217492da7e1e82189909e3cb1d4e11b36", 16) - g2To268y, _ := new(big.Int).SetString("f30d3eae5ff8c1d4d90444f13751403e77c339e6398616ddadae1fefb974a36694fbdcd1d437b0bc5620971d4b5dd9", 16) - g2To269x, _ := new(big.Int).SetString("110f35fd5e1f3e5f31e1b10ed4bd954cc415ec17a02481072eba284d8c85a54024adf64e6ff161113a09d5c1fdd3c13", 16) - g2To269y, _ := new(big.Int).SetString("c3a5f3d706fa77b9555211cf396acd58adde710836873d0fd426c9c0048aae9b54b04392e8f679abdba1c0927da64d", 16) - g2To270x, _ := new(big.Int).SetString("7d5629ea38e80696049f6054fab076f750986cbcb8795401df61552dd66c3fa2eca45a94fb73aea59161317d58dc52", 16) - g2To270y, _ := new(big.Int).SetString("19b0327cacdd519ac0b418d30133d8614ea2bc0e6653e361b5aa395f223a9f7539fb153624dbb359f14fdab18362236", 16) - g2To271x, _ := new(big.Int).SetString("76375a9ed297d7179a658bda7a75f096fb55d4b5f8d9f2702d5f305f709f237e5542ac681d314882ece877445e9052", 16) - g2To271y, _ := new(big.Int).SetString("85a6cec94909c5c81528dca80917bab1dd40fff8ff6a2dca5131d44f7267bec37af3a583f2bda2f8d14bdc366ba8bd", 16) - g2To272x, _ := new(big.Int).SetString("5307db362da35cd9e3042ff39dfe4d6e32814680ba2c15ec5248b98e00bca43398402df00135210c3a288afd700b58", 16) - g2To272y, _ := new(big.Int).SetString("18b19f017bbb62694f9a020fa59cd9a4619103128ea9e4c8eec2ad34807db2c291c8ca699c241450e80957bdadb7621", 16) - g2To273x, _ := new(big.Int).SetString("cc0c3dcca2a2ba0faf9d86cfb1bce4852a857a3223b9961a2d267251682fbd5d901e580ab8c458a9d03e9a9311ac3f", 16) - g2To273y, _ := new(big.Int).SetString("4cdc419d53ebd91ea1ef2b31ea52002a642d6936f2635276765b90f18e3ea2e928fb8d7f021541a2b816f9b98e4b32", 16) - g2To274x, _ := new(big.Int).SetString("1373889bb768f7b8818a86cdb37f357ca1df4c315df29f730749e04cc984768b607109fcded27561b16392a15f6a62b", 16) - g2To274y, _ := new(big.Int).SetString("42e6c6adc559d0b600596b1da26b47fb0024ae1ff58f9ac81edf903470ed6bbc25940cab656fbe63f52245e7d6c40c", 16) - g2To275x, _ := new(big.Int).SetString("4425b4bc590d3a0deb95b9ae2f4170622369380cf8a79f23e13b63b514676a75ac0e3016bcef3199d9a359b10abe77", 16) - g2To275y, _ := new(big.Int).SetString("d369391aa9385e690273b20581f2025870107e0aa093053b783ea0bdfc95612e8b60fcd07bbaab4d5949b49488a0d4", 16) - g2To276x, _ := new(big.Int).SetString("697be33fb1ef863339c0c6ea0d35a6c232afed052eb8c60501727806c022a00161afc888777407e279130cacdadec5", 16) - g2To276y, _ := new(big.Int).SetString("c101ddf5a50059841baef4e6a71cb2053167c2467137beed7058b55891b0a121e782c927878039ada00bec4a75dcb2", 16) - g2To277x, _ := new(big.Int).SetString("4d741376cb452dc79b375e493b92b7cc103461c46ba083aecfc4717a51991b22d0b224f4b48ca610ee4272ee4ba57c", 16) - g2To277y, _ := new(big.Int).SetString("16272eff87c487ee35461f9e2cf855e2459f428e8e10f6530306d521963fefadcc2998420d4301e96e8c4a1b58ff751", 16) - g2To278x, _ := new(big.Int).SetString("19a2da9695527c7443f6d9923eb614eae02a2920b687c888ec16a92d833fa4540354c023d94f0fa7ae23ce4f3218e6c", 16) - g2To278y, _ := new(big.Int).SetString("8d2ab5506225b4e3deaf064de43f41ebf96ab2b220d9cc0743ee441bbfca43f1d6626adb0e15f169d5b68a196d75c9", 16) - g2To279x, _ := new(big.Int).SetString("6a18c433f0ef0a57b8a7b892345440be445b2b23530e8310041c13e2a8ca0e83f86c4e0bc027caae701edd2a39b0b4", 16) - g2To279y, _ := new(big.Int).SetString("d1029ec23058096bae1cf886f80946dbb30264a5e54703a369af9d9317abc29fae41c7519d9277ad021434d98bac32", 16) - g2To280x, _ := new(big.Int).SetString("53755aa60d2e9a364a799ad0d2b533a84b7ce41bc2096b1b49dc93b158bdb4c4ef43b8d6f88c36a1db7a2ac7d602f0", 16) - g2To280y, _ := new(big.Int).SetString("9326fb36e432fdd400f2a88d3efb1982c3fb6a6f7c1d92d9f319681c30fd1a0e456ba85be7cd767e7bcbbfe153dce2", 16) - g2To281x, _ := new(big.Int).SetString("14814f25cbb4be1ed4cf806517bf8462047a16bec2c9510b3dcdbc4bfaa44dcf5a7efb78ca7e516027830d0403bcc1d", 16) - g2To281y, _ := new(big.Int).SetString("d561f4f28b926f36ab06ae2836997fad42544522ae85cf6333ccada055ef86e27d2e4f46bf2af2cbb13acc5e05c50f", 16) - g2To282x, _ := new(big.Int).SetString("158a2a93668fcf4a1e58f85ac7da6f8524cf792d7f3522ce55493de98b6268b4a1391dab00fa011250a0af293f00f4a", 16) - g2To282y, _ := new(big.Int).SetString("17d5fed5520155e357fd49b080d860adbd52d3c84a17706d7bb63ce828150e7b7df16948de00aae7389b762e2e23fee", 16) - g2To283x, _ := new(big.Int).SetString("a5a27cb4c2d061bf5b78873640d0cd551c7428ceab00beac8d65298399cef7361472637b2bdf1fe62dbd96480e0648", 16) - g2To283y, _ := new(big.Int).SetString("3702567d32d73c08eb9c8359fd36ffc7647dec3329246074a0b67b3c84a143f0b528686648a2b34376390f26cf02f7", 16) - g2To284x, _ := new(big.Int).SetString("11871bb4fe777e21f5ca4c776f6f5370eba971601cdd75dfce98d2f1b2e254dad527b4c1ad7ddb3c7e737498d9edda2", 16) - g2To284y, _ := new(big.Int).SetString("6cce724cbfda855df7d9af40c16e5756c0bec0acef775105c12215ee5922d870fe686ea4e4cf442915223bb6ee8a65", 16) - g2To285x, _ := new(big.Int).SetString("3c80b6c78481505c73073249a1716fbeaf7bb4b12069c5fdac37d39546c5d24b8caf0a18800cfed0a365aabde8bf4", 16) - g2To285y, _ := new(big.Int).SetString("15b8df4ca5f4268dfcffe37019d7cb3a5cec43fc822a5e310f676dc29678dc1e7f96846f1f3d64623e198afd53f124c", 16) - g2To286x, _ := new(big.Int).SetString("40162febfa4d3f42f0e47e4452b2b51086747f93a1fc9156aebc026f740dfd914849f5caee5c67c63586f941497ebf", 16) - g2To286y, _ := new(big.Int).SetString("e03eb269e1468ed3ef29bcf24d1f0e04b9a5958c9003ff78845d37a5deb225d6891fb92f7c215525c3e4b1062a109d", 16) - g2To287x, _ := new(big.Int).SetString("1493b9d57cf6acbd0808ac663544393d2f515b2f838898891e04989c68790be371a6086fc1aee17eb9cbc7348aa0671", 16) - g2To287y, _ := new(big.Int).SetString("a0d29a1faaa1ddd7bce363126895b08876c70a937c089c8fbbf7a618284ff40c6951ccd8af8b8519ec29f4d8a9fc7e", 16) - g2To288x, _ := new(big.Int).SetString("72b2d1533620d90b4a4e1b782438b2538c89801379085dc166388c928d38836bc7b387878799847a83ef86226d318c", 16) - g2To288y, _ := new(big.Int).SetString("9ab6b3871c45de21de41ad3b42bf7cd58249202e3ba72b3bee9ee81074d1126e92820216223c54533cc9873e1d5b6a", 16) - g2To289x, _ := new(big.Int).SetString("61dc382951627452c3211e0be9a2a9f04231cdd7f08e315cee00f811aa53a13e8c1fc67292058446b87b8402ae9983", 16) - g2To289y, _ := new(big.Int).SetString("dfa82dedb32092192d7797f092b448ee90a692e07e0f1f7b5acc89869dc347cfcb7d1e1c1794f36735318ca8504041", 16) - g2To290x, _ := new(big.Int).SetString("f10991af9ea2ff3e19ba38dcf151ef80883dc10c5b407504f1b0e4e339d268314333113faca5de2be89734c83664f4", 16) - g2To290y, _ := new(big.Int).SetString("1456b8faaf48224f6f331ed52f8217a0a568a8529f5b146f9770bd1bbd28e2a19cad175dd84965d11dae4fcf4a42ccb", 16) - g2To291x, _ := new(big.Int).SetString("1a56b7a87e64076383351c99c9d8d73a4127d15a56512ae0b13930389bb244c3ab78f6c2c80c00bbdaf39353ba41b03", 16) - g2To291y, _ := new(big.Int).SetString("b507a6299e0372b53d374dc1463b12f1252c22e77c7bba8164ccc37d853bfe0248b51d92c01b8f55882c749a577895", 16) - g2To292x, _ := new(big.Int).SetString("11a339dc3f4fd8fb63b4f073155796a3807eadddea8ac3896a042ca2c872753f36037d9d0e07a7fa1eac723605245a5", 16) - g2To292y, _ := new(big.Int).SetString("1222dbd930ddb39f80dffe1ca06e8017f3114f6094d85e6627483b3a640582f40f830af0204b62e2a78493f4ba3f23b", 16) - g2To293x, _ := new(big.Int).SetString("459173a706efdf94c37379c6944ac48ed75f7da2dd1be11ca616cfdddc2d958174869752916699f5dc176ee0c157fc", 16) - g2To293y, _ := new(big.Int).SetString("fce2b1d0d8bbdc00c279384a9c641003e2b5658db3f998b4856e25cf9a8595585f054f1093d89fc57e148ee9ab91c8", 16) - g2To294x, _ := new(big.Int).SetString("1546b9a6ba2faff24981b8216977dd0a38d2fd3f37f4053d85fc94a3fc716cdab79e3dab7a3c1206e28cb20c444bf4c", 16) - g2To294y, _ := new(big.Int).SetString("cc581666d2ee87f6d70c73ad809581e7e0e254198f5a798b92a310cfdc4822d6722ac887ee89d06fea469e11e25682", 16) - g2To295x, _ := new(big.Int).SetString("2df3c0aaf31a895018c2d0dda7455c4a5680ac0b06abfedefa3f014a96538546d42bb2265357fdee9a9bacc5e7fed0", 16) - g2To295y, _ := new(big.Int).SetString("19f1ca4f3dd67988869f506cc3a8956c31436801590664a3273ac8fd44bdee7fa4f169fb37fed250d19b37505c51e53", 16) - g2To296x, _ := new(big.Int).SetString("10d85f49ceabd73b9b34811cbe9a864005884a030cc44b528fbc3fd8591f7c2827fc5c8d3bc0f2c2a677c5f126e0c0f", 16) - g2To296y, _ := new(big.Int).SetString("1722c2b06c19defb2ee8538a77c0eccc29d3f60bd20772dae3e171897cd4a08362dc9b5dcd2076474c54c6db36f2852", 16) - g2To297x, _ := new(big.Int).SetString("162bb0f2b229c9f3e7163aba9d76ad9490a4031233755f2296bcc54e399bd3fa7b1b5f4f804c873a423442e7d9d379c", 16) - g2To297y, _ := new(big.Int).SetString("4749127524f982ee4571f1273796da2da71a4a682377c1ceee2a63211f1217f22cd8a7aa3f45ed8935345e85a10388", 16) - g2To298x, _ := new(big.Int).SetString("1366bf14679623b87120475fd016efb61f9f3e58694e061f041f5033f6ca425904ca49bdc45dedf969da27a152aa6b6", 16) - g2To298y, _ := new(big.Int).SetString("1a6202ab1f165f8bcb5e626d2ad47c44154e0f561fc0b87bd0914cb1ed789c69ddbb29c6c26704bfe5c3bd129bd5f1a", 16) - g2To299x, _ := new(big.Int).SetString("1d16b104d8f9a8322af8283a7eb7a4dfbc35d36f20572a963e24ec07978ca71260f8477407ac359e8823c67d3296c9", 16) - g2To299y, _ := new(big.Int).SetString("56bef9b5f17871bc287e1e448f871c6782f9a3ef9c2f1cca5aec18da0b87e46e7cc71fb039030e88043522864a9a90", 16) - g2To300x, _ := new(big.Int).SetString("165e04e9ca95dff7448a502f661ddc1d75999ef8e90c1a1bbb075131dcfd6910b5af199e22b45120d5c9ad8725a278", 16) - g2To300y, _ := new(big.Int).SetString("179c2e9122eecbf8545eb3e95aa6037e1966f40d617a1dc43f87ab50fc854d0c7b42683ecc10f086eb9e360034dcd3", 16) - g2To301x, _ := new(big.Int).SetString("d932f96c4db384a2bdea3a992c7935f8d3fd66f464d8cbb42ce64403bc9ce4517214f9a801b7b8b02b67981ffaa5a", 16) - g2To301y, _ := new(big.Int).SetString("d8ae0d2c8a1ff3518592407a7785f2e81aef26fd41afa3ecf242769d11f0572c95b296f90ad262727730cd5efc7639", 16) - g2To302x, _ := new(big.Int).SetString("184264c42dc98876a91810be0ee55108e99a85449d9038206fea705e78f55d498ac677dabeab6d7184bac6eb761436f", 16) - g2To302y, _ := new(big.Int).SetString("17436ea5d26738fc1224bc3a1fbe7d18846c0c0b69971fe9b8ad59f899386bf0721b97a42631c5813b3b40c86cdab23", 16) - g2To303x, _ := new(big.Int).SetString("13b5cc9794bd532ac83a9cdce9d019125d82a5ecc7d08dde9f00561821344b1097842a6f81ac05ecdc095d87924632d", 16) - g2To303y, _ := new(big.Int).SetString("12554e14e652790ebef1c5bd600800d30183acbf5c15b2e56f5f61499d86ff86214aaaf2946b9ae8bb5cddde56c6ab6", 16) - g2To304x, _ := new(big.Int).SetString("efe32413206283e7e1803cb4369634b96f63a7e10909faeab03f4ed34fc0f78598d7d0a0f0893b08dac9bfb076af78", 16) - g2To304y, _ := new(big.Int).SetString("f7f330b8edf6f4e93093cec6531718843decaac91c4181bedab0da3f267ad434b931f92f0c09221fef185c1d7a917c", 16) - g2To305x, _ := new(big.Int).SetString("12d54e5952c785c28baa8bd33dff36001f8e0c97bf6fa147ed761a6de24bc0362ebf91a759c3359eb9d625a2fd5dfd0", 16) - g2To305y, _ := new(big.Int).SetString("c9365e30e6a13e765d8e741c2c5029bcdc794fa1aa262e5dff9b14274e3b86bd2962e61b19e1aaf5cc6b807d3ed9b4", 16) - g2To306x, _ := new(big.Int).SetString("11955da58ef800b656ecc0b048f7973d8133274661cacab5f2a58688b3c0d57ee73402f00cf0336eca5f8a9c9a7f6ec", 16) - g2To306y, _ := new(big.Int).SetString("71435f1e97fcf65cdef87416fc0177b78a24ecf443641ac4801c2df0ae324cb1fdfcf428ffb646ed95bfc896f583c8", 16) - g2To307x, _ := new(big.Int).SetString("127d3735aa726ce6add291566fedcdebbcf4343d7868449d61562fcb06939765995ece8f0376e2b68d597622e0f64d9", 16) - g2To307y, _ := new(big.Int).SetString("294ee27536ac834061d9110ecd5d354a6f5bfac51dd362ede04675a7438ae867f90e6d638fb212756c8627bc77e7c3", 16) - g2To308x, _ := new(big.Int).SetString("615e1bddd4b42f50f9afbe26d2fbaec50f74ffd60ddfff4468b600f5d1535573aae261502d8b32d45fa474314b8b7d", 16) - g2To308y, _ := new(big.Int).SetString("23099fe1fb8cf9cb193c9bfb00f5b68f473a823e0a259bfd47d074dc09689a43f779cc754d2846a43550b645477eef", 16) - g2To309x, _ := new(big.Int).SetString("1abbbac6285d7f3847071534ed6332de2474930df760b46dce6b15a4ff82f5b9f71bea82fa8265899579051b4c64c2e", 16) - g2To309y, _ := new(big.Int).SetString("106ce0daa6992db96dba92216f6e2da51b934c00d1be063364321e26ccea7e8b178904135907ba8b3a86329a137973b", 16) - g2To310x, _ := new(big.Int).SetString("2f9b903ecf3f5682fffa7154e49767e5a4055c23b69efbfb69bb89a06ab38c1891c84b6e3ccfe4ff634444b726a53c", 16) - g2To310y, _ := new(big.Int).SetString("191dbd0d0a0cc587817efe6094a041d73c673866dea62a3f0106374ccbe09787604b010652342c83ddaef264dbd26ba", 16) - g2To311x, _ := new(big.Int).SetString("111866c35c690e56fbff009771f6027011ceb738dcd0742ab1194ba73098cd3f51cbdecc5b2e0ca1c2d0abaa706e8cf", 16) - g2To311y, _ := new(big.Int).SetString("b2427fa56f2ab073523673d047fd542419b4e2e15fee9974323bcbf274868ca64a1176db454d86aa542b5befe1fb39", 16) - g2To312x, _ := new(big.Int).SetString("c2a36a44347a86ab1c2c2cf4926f5789adface133d5feaa10c9f702fd91441222c0ea57328ee192969f2696f5535fb", 16) - g2To312y, _ := new(big.Int).SetString("c509e32a3045eb2b49b25526726fdc4cc978b42ac2fe98265a948e126624a6b3298ee2384b7e013e737615f5463e1d", 16) - g2To313x, _ := new(big.Int).SetString("451fd03aab9a1d983649dfff27d3589a5684cf5d245c579222d11938b2b7b56a62483d00333e4a656607972d5f14c9", 16) - g2To313y, _ := new(big.Int).SetString("9aaa7d11318a8a4c3b71b3f6f7a79f5241ad81069870ed4d8311075f68049c5785aa6f76a7278d411599070fe4bcf6", 16) - g2To314x, _ := new(big.Int).SetString("32b128fe475a8d7b53143cf89fe4348158394d2b569c167a3c293e7afc363c91bdcd99481fbe74410707edf332d2a1", 16) - g2To314y, _ := new(big.Int).SetString("df407ba4a659cc1f6bd6714fe68b1fd5901acf4645c4221f7bf253cbf0c1badca035e078942eba78c9c6ec4bb6f217", 16) - g2To315x, _ := new(big.Int).SetString("15bdeda5e3fd541d263e2266ab5b76a4e20efb18e90a8190d8fd54ad92c3845f31099876837f8859d04a7fe9f370027", 16) - g2To315y, _ := new(big.Int).SetString("144164adbe2d5229a4c204f2f938714b93517839aab086493b780dfe9c986c9da0fab1c4a045d359dde543a8a471fb0", 16) - g2To316x, _ := new(big.Int).SetString("82c442c6adca56f6b5be8452f115b4d69e8ba931045aa47ad54f8006b24b5e0a66041de5aeaf610c52c0be7ebcf200", 16) - g2To316y, _ := new(big.Int).SetString("ae7c68a565e4827edf354673f0a0a76314d25d3788eda91476e0e9d150f27443e173dbab370fab3fb9fd7b96ca236c", 16) - g2To317x, _ := new(big.Int).SetString("143cab22afb72880a35d47e88c99d2ed4fae97b99ff299edb739f878818c7626af633f0788c63b617976d8c392496da", 16) - g2To317y, _ := new(big.Int).SetString("7db206208bfa5559cd69d832217b877344036d54e14e1f246de34c4232ab6f08cb31557a309caef00e6a4c13432446", 16) - g2To318x, _ := new(big.Int).SetString("980d9374b06f3c317cae2aa4bf4ece2f2d0e44ad82d7eefa9cea1f63c741d511aaa1504fa66126b8172eaa38e3bb4e", 16) - g2To318y, _ := new(big.Int).SetString("9201ecdadfe89bafd482e1f6eac13772d9acf746f4ba506e7bb1bcfcbd4a97aa853fcc2eddd1889dbfbc430485b795", 16) - g2To319x, _ := new(big.Int).SetString("16fd8df33ef7e2a350ee5d70fedfab65782f05bcbc8620c83287c37deb2dc7930207cbc56f5f7d259194febdaa567c1", 16) - g2To319y, _ := new(big.Int).SetString("226a7e20aadf5126f5141cf9d9a6fd5e91ec65ca9b88637f4fac7bd5fab74254463610b32b15d80f04be778071c082", 16) - g2To320x, _ := new(big.Int).SetString("33837b8fc7cddef08f70d78f3d798391ec1204648e27188b85cc17094cafd2de397269de5d02ba1b3fa4d3fd87d2f0", 16) - g2To320y, _ := new(big.Int).SetString("2694ed2299005aeb35a8a71fd31024220ccbbd23fb76d386a99260750944076eb77f9111e9a23c01b513f264f7a6ee", 16) - g2To321x, _ := new(big.Int).SetString("eda41e19b1f5b3bbc7c9008cba4600ba826d414bcc9dd02c4481362de9f0f05b0355c475620dbbee7c9a5a7aa22067", 16) - g2To321y, _ := new(big.Int).SetString("218803f222f91b7cbb2f0b62fa1ff99454b01e185ce1fba26513f147017174ce38e9a89788ad589d693e47308dd150", 16) - g2To322x, _ := new(big.Int).SetString("12f5b8e90a9d36ed7eb153d9073db8c9e09c51a02b632a8c5d3aad4d77f86c4591f5dad192f7ca6c0fea7c5f41403c4", 16) - g2To322y, _ := new(big.Int).SetString("17a7ec92a2cb8478686184659615714d8d345c40eb495f2ab38333964935284678a97319c2a2bfc6c9ca61566884138", 16) - g2To323x, _ := new(big.Int).SetString("1221152369fca5412411c565c79f044b546984f01918b4d97edec6528a3980f03cf7e63e9ef8f55b3d5293d16badb86", 16) - g2To323y, _ := new(big.Int).SetString("118d45d7bc5088b03f1f8708e743e60a22707ee6f32a673d1414ba936fd683d81768293cdf1485e3f7de9eebbcbbeaa", 16) - g2To324x, _ := new(big.Int).SetString("82ff20a6292915f974708036a2fe6aa8bff9822e984cbcc4e704c32a74f0aca29eb44c23ea3f41be9d78b5d1363d52", 16) - g2To324y, _ := new(big.Int).SetString("15476de58380f6fc3e81212fbfa104b75e6b95173e2e7465606d00e90a01cb979c2dc5228c29857f118e8c75ae8d867", 16) - g2To325x, _ := new(big.Int).SetString("13cd07d37734b85917134e31e0da01cafbd7ec12840f470fa5bbf063a9f7c25138ecae4965deb9395571ac91af70e80", 16) - g2To325y, _ := new(big.Int).SetString("19376f39503358ddd7b0d0c89c161df3105aaca6d8b77311fc46a0ee0ea600ed0b041a50abef940daab7efb96b0a3a0", 16) - g2To326x, _ := new(big.Int).SetString("138bda3d6b146c30abde357a81f4c92ec0de1987e0cafedf62c3a718e5a76468376bb2a4b6c35d549969d43f224ca9e", 16) - g2To326y, _ := new(big.Int).SetString("5c01f9f48e8cabfc0801b89b21ce997a9dc3deb4575bf718214cb33fd1d3059f96c7f50aca93449511ffec2326b596", 16) - g2To327x, _ := new(big.Int).SetString("176806d5a6d8da954a719505987a0c239e0f4cc3644b88c1879cf2111287b98271beeb5cc3a05131f17fbb3a9100221", 16) - g2To327y, _ := new(big.Int).SetString("169cdeecf2bd8fac26bd789fbd00fc9c239b3a26576803e4c4a783ebed40f43a2175f05ed2e625dba29e3577b56d64b", 16) - g2To328x, _ := new(big.Int).SetString("1670583ed7e2ac2564fb7286a15c367d649bcb4f27329022480065e027e814f0b43f85172fa49fc4d2b5b3b4a150c85", 16) - g2To328y, _ := new(big.Int).SetString("108f1c8cdfa1efb8f73986a2c146c981572e562fb76d47d63f82e91cbed357c47cdbc89fea66ce6e7e7b629f0833604", 16) - g2To329x, _ := new(big.Int).SetString("62a9813d5e2a2ed755bd83dfc0338206560167a692e5e6d1b6a53fd6026b47635d3012c65a8b9388b95c34a8d91dc4", 16) - g2To329y, _ := new(big.Int).SetString("2cac82b8856f73359deb5a67e6d09db38e6c8156f25aa0f9b8ba411352ea3bbad397432b08b0d8511e5c539a824263", 16) - g2To330x, _ := new(big.Int).SetString("126b0bb0f258eaf2b8fb6c8cfe87e7abe6180fb4f43bbf28162efa08e12a7b52ee5a997ccf51656290fd424dfbc1393", 16) - g2To330y, _ := new(big.Int).SetString("188be748144fc5e24e2a226e4e9b4b24a8c29ba1e61506283b9b861f203613b91fac1d7fae101953ada6f6ba1bdaa93", 16) - g2To331x, _ := new(big.Int).SetString("a805b4d91d259dfd08defd52139260f6a563a579be1b9be167096af4a8735e00e7650a99a0058f6135ebd917e37ffe", 16) - g2To331y, _ := new(big.Int).SetString("96806965f68ddfca7ca8f8aef933405daa264b8d4afc7ab43b06ecd25741c08117b9f90fa1c11fd8a6d9ee59f5e5c8", 16) - g2To332x, _ := new(big.Int).SetString("bef13fb286d1ad6bda19c54484c5dc542e68fcfe65a873c9949b696a293fe3c364f614deb37cb2307e1b696d4ea1a7", 16) - g2To332y, _ := new(big.Int).SetString("1175b199f071ebbadb29d886a08f55ca12756d63e6df5d6b23b6cffccab067de8289cdecd4968b55361a1c788b464e0", 16) - g2To333x, _ := new(big.Int).SetString("88e3529cb1e090483a76d71a4b5db43fd2eedfe817562fec9038fa5627625aa4aa1a5e3b258696371dc09cd67d27c9", 16) - g2To333y, _ := new(big.Int).SetString("1425f4d3159dcffb3ad846b06232581ef8a27727e737647414e95bf40b3451298dc8731331ff5970cd43017a962029b", 16) - g2To334x, _ := new(big.Int).SetString("5a744af441dea697e5248c9b47bdef9ff684c124670ff3bc8a4ca23e7bf8939e9e6d58fd332cbdc2b49e13ffe1f2ba", 16) - g2To334y, _ := new(big.Int).SetString("19c54057a884c10109bdb88960e8f8a71133a6e140de962b60ebdad30ce84cc3da90843b0293580130027aebb98652", 16) - g2To335x, _ := new(big.Int).SetString("6b915a27f2e96efb69d11b7d8d19b4149f03a1d2cbd949b416f79271cbdb90eacd2732b194c7bf4f8ef824933f61ff", 16) - g2To335y, _ := new(big.Int).SetString("116e95fd3fe94c1ee784f72ac93f44e94c406745e0c5a8d97c0ced8a2eefb7bfe9ee2161242225f6ab857c020e03c84", 16) - g2To336x, _ := new(big.Int).SetString("cdc33c8ad030b1e15488ec5f7e054adf5d8e535830a1e5e285a0b2aa73d7f32c0eac2b74ec47c075b427fb6a5a8ff3", 16) - g2To336y, _ := new(big.Int).SetString("cd4bb0efb6541ebcff0748db7de50ab96f5c69e7c262ba36b129d96f601c887ec5b909d9634b571f46dc6f036b5ede", 16) - g2To337x, _ := new(big.Int).SetString("1722482e9c7f5cd289843e43e198b2e6be1e27fe833b490b002b579326ec33744b858b2324c9dd2baa1e34ba3129e77", 16) - g2To337y, _ := new(big.Int).SetString("68551cf7075c382f49bed3447b84ddfdb5ca24c60c207d2bc8924e296179ee70014dc0445885bfee0641beef32a64d", 16) - g2To338x, _ := new(big.Int).SetString("11e8cca326ae7cee7d8f4609f6247ea0d8b25d16d394f4db3804cf6741cd2d6f6de8b10a0e01fd281c0aebe7b981d5a", 16) - g2To338y, _ := new(big.Int).SetString("176bc4bd1cdb56bb86db6f84aa624c3c7c9561e8ce38e69f3baafc21b283c296731c53b051214c7cf621ba6b40bafff", 16) - g2To339x, _ := new(big.Int).SetString("a0f07342e976c6b9812218a40b21fec9cad87af9efff3c34cac73afcf6bcb94b5aa10b8c7f38b5e82b36a9815b0d8a", 16) - g2To339y, _ := new(big.Int).SetString("168626ba856267787b6673be864b83bef18e385ec280226612c59598662473b83d99938e37624f4691c791e0763f5c8", 16) - g2To340x, _ := new(big.Int).SetString("1a5aa4338efb66c5a530b41ffc1da3cadb49a9f25e03eb02f8bcaa2552769b1978955f1c6443c650eb81a8d09694caa", 16) - g2To340y, _ := new(big.Int).SetString("18ac9582657dae82090f0ca96a9dbc7c16cfb04719a598201bc1b8fa895f4b01270d5f285fac71fb9f9f26ea67734d3", 16) - g2To341x, _ := new(big.Int).SetString("806b32d3880209dc8872094e7dbba158dba9fe8353c83247f72cdc195b15821ea91c452b4cb46b005f0afb1ad8bc3a", 16) - g2To341y, _ := new(big.Int).SetString("10d2ff0f2ce0c8add5ba759e5918d503f1cda09ef263ed41ccb35a58dc1cd471920b45faea399e50fc9029584085e6c", 16) - g2To342x, _ := new(big.Int).SetString("e6bec1a058a818caee7d3c5b891519e1fc300a65fbd048110be85a3d19b746782217f8ad7e4af1ab4377b5dd0a8460", 16) - g2To342y, _ := new(big.Int).SetString("132a9a730bb3d7d9631aae4f528177fcfe647f6370931e8c45262c9f816002d8c062127126874dd5a83954588659c19", 16) - g2To343x, _ := new(big.Int).SetString("24a5836b629b9d6dc24d81b542a4159476ed0c57ce0341eaaec7d95b36b96194ccce02db106124808fa26b9a5e899d", 16) - g2To343y, _ := new(big.Int).SetString("129e34d641ad5cdd582e4ac4404ca9adb288f12cfd18721212574ae46a036c6377b9543a829b9fc09f2083c22f2ae57", 16) - g2To344x, _ := new(big.Int).SetString("ae46732d5bdb333be059365e374c5d261344c0febae49ffbd26e6f96bdc1710a9eb962ebfc96100d8d1d94fc73ea2c", 16) - g2To344y, _ := new(big.Int).SetString("fb39a612a7b2e70efcb2a01771a6a85460639158f6ab2514d0864b81a61881426a634301f43b807b41573bf83f48ef", 16) - g2To345x, _ := new(big.Int).SetString("320bc9ebef0f9b0a01e79b6e38b1baea6f794e263b2808dbfe1ce08a3662cf6d10d8d282c1f30b07e1f178ac8bb88e", 16) - g2To345y, _ := new(big.Int).SetString("6bb7685664b9941642a8a614a467715d6e60492551bfb68c4eedaada7e1b4d3bd872fca56d5877765f91051f742376", 16) - g2To346x, _ := new(big.Int).SetString("8b337d3a0778738aad74b30e3482278f4b962f3b7bc9950c7d01e3e9fb9bba5529a61e50703387f6d2b4c2e273f3f3", 16) - g2To346y, _ := new(big.Int).SetString("153b19f1162ba2f1a3a2e8f0449a1f88975f7b69f495c07c6e2af826137e805b1a9694e373dd7ed05de2ce7ac062b72", 16) - g2To347x, _ := new(big.Int).SetString("194cc05f1f9b917c0d334824a93eb77e4ddf1577051b31d7f656ae9bd9345dc71fbd7a499e50d1ba016315508932336", 16) - g2To347y, _ := new(big.Int).SetString("a228455476c0c2e19fb6bf3e302c7efb4c52b3cef3b15983769b290f20a59d7581fb589aa2aaf12d917231b3fe9842", 16) - g2To348x, _ := new(big.Int).SetString("25fde08a25e27ebabb5bca6e8adbbaa2ed0ddb932fe50cae36d6941a761e907ec1b72e28ad037b2b49b8e12f075128", 16) - g2To348y, _ := new(big.Int).SetString("5a67365d4975b7774e01a25f66a40e989282d72c71baa7baebd02e7400b9592bc9eae1d7270b25dc5d6dd5fb2e63ae", 16) - g2To349x, _ := new(big.Int).SetString("c3412332dd8e5c03f33eafd042b8e7612a4cabde5861e149d95d8362458d572c0a54de9b2f8d84bbb6b345272ba610", 16) - g2To349y, _ := new(big.Int).SetString("47d9ff462724810b2dbc73a0ae9504785a0640879bcd628bb87b8ec229528eda3887463ecfc3fa4000a3f64bbaaeb9", 16) - g2To350x, _ := new(big.Int).SetString("30804bcc5cfdfe6501db5ef22b1494f892aba6f14bedec86096ddc5d67086ba43e54dee7d50e3b50c5800c29509ad7", 16) - g2To350y, _ := new(big.Int).SetString("6c2bc85976ce447723a6af9cdb2b02cb6efaa1ca591d19b16307379671dc10deb9e8bb49f8f5cd67f1c9c77427ef70", 16) - g2To351x, _ := new(big.Int).SetString("eaa19d82315ec52ae5dd8cd819f2acd01d4c1e2419cdb79c494b61067729fee2daa46997d92f9ec4edd676ee6b3cd5", 16) - g2To351y, _ := new(big.Int).SetString("197da9de1b9bc8f70003380e71c84f116686c06ceb741b63c9c44db2c828c71b7bf0820dbbf8b54a124b72d426b5276", 16) - g2To352x, _ := new(big.Int).SetString("936df9581109ac18c66358d7e5a1e93a2c6a09ba3e481fdd878398eb74ad271fcf7d6b4b613e155c3b70504f86adc3", 16) - g2To352y, _ := new(big.Int).SetString("36e5d6c54d1e75498622b48a46a7f30cc18b9b1d7e16e9121367290cf1aa0c0132976f3bc3c241630c02aca66e070e", 16) - g2To353x, _ := new(big.Int).SetString("e03b5a733511b241dded70bb27a45540c2f932fb3ca7093b32d35a7bdad276da8a36336fd0c7947dc606ebc8d65216", 16) - g2To353y, _ := new(big.Int).SetString("131fa796d16299d6fd3435528183ab598a2564471521892e6880a1bd196aadb78e7010afb790caff9392901c2142dd8", 16) - g2To354x, _ := new(big.Int).SetString("b299f44dcdf3c05c1183a875ff598888b9b1fc3d0565d8f411273b365d5b9791136679a97c9900fdeba3b6ead8a2b5", 16) - g2To354y, _ := new(big.Int).SetString("1aba7ac86a133146939c472e0ab51669da7fa4cd2973db95e0c91f5b1ebcca0f596925c80b4c061d8973d4eee20644e", 16) - g2To355x, _ := new(big.Int).SetString("2f079339f94ee4f57dcad806186a5b18ef9c406dd3b39b6322e3a234307a16625005e489b6431e953c41092ac91314", 16) - g2To355y, _ := new(big.Int).SetString("a8af71578ea94452c3c80b68c85756e1cfe6cc78c84e44596aa980cce9ba39371f767b3b7f0cf31c9824b148d5364d", 16) - g2To356x, _ := new(big.Int).SetString("bc5e3ec2bf84bcacb8b541c331184dea078277cf72664ae98b33da575f897183137bcf8451f7e5518c5a01a90ba073", 16) - g2To356y, _ := new(big.Int).SetString("478b3ba1c586db5a56e40209e282eb1d4a67bdad5eab8248fd79c93613d64b2f19c7733e5b05fabab6782afa1f6c20", 16) - g2To357x, _ := new(big.Int).SetString("c4fd8f8b91dbc4e2cc656c051055d88e8c1423cb57590b9c6def1507decc0264dca04e6b89846baa298167767a6687", 16) - g2To357y, _ := new(big.Int).SetString("a069aefc91fcd2bd934cc982e00cf2b09826ecb9391f64dc73b234f389c8edbd873cf60d5f3967661e18d62e0608c8", 16) - g2To358x, _ := new(big.Int).SetString("1590a01aab74236cfde06b181b47760428d14e72ff8bebd1be6a37219ddf352bd0acbe88cca6cf4a369ff273e7b348d", 16) - g2To358y, _ := new(big.Int).SetString("9df16198abf966f2fb0aa9321dda2bd12d45e90622c8464724ad3c5250b7bc720316443a6b1fc9c157a8c8e6117a45", 16) - g2To359x, _ := new(big.Int).SetString("191e44a4da422531287ff23becc8ab142fde217c3103f94c2a06241a65db5e8bcdf7fd5ea89797c08edf75a975acd85", 16) - g2To359y, _ := new(big.Int).SetString("181760764282c3ef0b608fc6ee204e35ae7b39e20c9610422c3da09f299c90b65e11acce099722c8f69a226a3b0e6d9", 16) - g2To360x, _ := new(big.Int).SetString("16640d9e5b56aa5678e7e43ad8b2a0baeebe908b8ce34a0c8bccf175d58d42e9c80e8e3881f11bc2bf3dc4edced9ebc", 16) - g2To360y, _ := new(big.Int).SetString("fed41f72081c7e09f2804940ebd758e8fb071f816d60ec24a26e63db1eaae3eaf892757693f8b91a9e691a77cb95de", 16) - g2To361x, _ := new(big.Int).SetString("12e4ae1e316b7d7be879a12c20ae0635679517f8405fe1749c0e7ea38d41ac52840076f70256a1df6e449df7fc3ff1c", 16) - g2To361y, _ := new(big.Int).SetString("950b53c101af32c6c2ca7db1eef29e8a4fe7cd459b35212936d93cb25273bfedfda4e40beec676deab937fbc2a9e2", 16) - g2To362x, _ := new(big.Int).SetString("d51ab083eb7c89aaf1f7195594c8fe038d8b5cca680bea3ea7d544ab3a468c695c528c07458d0a48dd314d3beae518", 16) - g2To362y, _ := new(big.Int).SetString("15cc9b5b004da0b4fab661f07d924cf6161624c7727df1576a53ac829e941df55b163dbb573a566340ef0371a25c7c1", 16) - g2To363x, _ := new(big.Int).SetString("e3230c3a0b2f354660488e204837810c9b850985ed2c2b10dffc04c68e937aded281090a6ab1a2143c1506273986ca", 16) - g2To363y, _ := new(big.Int).SetString("ac37d93717549dc0e7363fa5f0a8b01a09db130af6df1a9ac67eec29fef2479315ea0f82cc234ce1c41960cbafbede", 16) - g2To364x, _ := new(big.Int).SetString("8205a824a6f304d3b052487c9ed6ed29ef78c0ebbccd5773fdd4f1c14124add69a3c8b9502e929af3c902be375f58d", 16) - g2To364y, _ := new(big.Int).SetString("18c7078631c53fd552c41290c111e91824d4470792c1ae04c37d646a63c5bfebc161f57159294447233b89c957d24e", 16) - g2To365x, _ := new(big.Int).SetString("18f7915fdce96217ad18241e2a4567ececdba645030d66e256defcf5a73497a34abdb95258ab412626209b9d726e2e6", 16) - g2To365y, _ := new(big.Int).SetString("423ba66324a2cb13932ffc1d86ade0010e836ea8a641daf1c8efd264f7d6a9e64d8db1aba79f0cee040f66fda36f12", 16) - g2To366x, _ := new(big.Int).SetString("29d424b613b9b29b24decbb39120345413a6c565a07944162f3b71e3f7e4a02f25596a1f228d85cf9e4dd0fd3acc2a", 16) - g2To366y, _ := new(big.Int).SetString("b0589296e7dd04a447cb7739eb249541b5ae9de2a451aba3c14f3572aec6baffd6f3deff1d75e0a48519785bbc4f09", 16) - g2To367x, _ := new(big.Int).SetString("b29891662f6a6ff52209bdd893751488eb5e29ead206e4d3b3b3274b2f1dd2558f7ead4b5a854c0411164e3f431cae", 16) - g2To367y, _ := new(big.Int).SetString("119fc3ab0bbf1d0c0ead2e84897795e30d85707a85feff8f3ace65b6db714cd0985a1e8c71b7da97bf67d1f030865c3", 16) - g2To368x, _ := new(big.Int).SetString("ed23a3f54b439c5c15bd5d87c7b2bbba3e8b7ba7c112ba043aff04a2184a8525ac47c399ebb7900d41e35d9c2aa6fd", 16) - g2To368y, _ := new(big.Int).SetString("977779960cbba06bcc4b231f2012767172ca59d0ce154759c734694d3cb8c6913e5b48626c2d22d018e6d805649de3", 16) - g2To369x, _ := new(big.Int).SetString("154d2fba6e5862dc6cea1154dd33bba1b0179b85baef1417dd807a65627ad173fb3a16d078ca2c698dc59a6d646524b", 16) - g2To369y, _ := new(big.Int).SetString("829e52abb7d38f0b7b41676faa78c3ebc48b5744dd2428277d82d05ecfbab5de0cb2b4c09d6d38659bb2744e532899", 16) - g2To370x, _ := new(big.Int).SetString("14b4837188c5142d9a0203cb7cae32f0490835335ca494fb64c041574fe220950d4753b5c1da02c945c7946ba27d86a", 16) - g2To370y, _ := new(big.Int).SetString("b35694fe7b4f14515b7dcfbbdcdb305941ddb39e1fc757d7ada794f137b6051d2b8992dffab9b2f00c330a62712870", 16) - g2To371x, _ := new(big.Int).SetString("1e8aa5ad207848e44eb7fe073e9c2bc98d0832bef8c7ff1fccc9d671bd9c8771e4794c9d5eb5335ef0b86c42031a51", 16) - g2To371y, _ := new(big.Int).SetString("d239e83948c7bde5159eaf6ce6cf4f40f71be69330fcd2f1b41ce36afa0a568813f3e1c10a194b8f086b28d01cf834", 16) - g2To372x, _ := new(big.Int).SetString("8e11f1f3e7cb99daae5ce7061e34a798af7ff23b13d56f6395edf45d4be4ea59c65f5d2d898638fc7b4537dca41170", 16) - g2To372y, _ := new(big.Int).SetString("68a9ff131c2916f4ab183a422feaa5442900683d6176bf7c36e816a45b1f5f9df394ca7117f7780e2c6e5e5dfff73", 16) - g2To373x, _ := new(big.Int).SetString("84d5af6e2f4b2b9babba22f9f3a9bb978972b1ef4548eb48dd81ebd06afb8e1b03d061ed8607daf2464b7e7155464a", 16) - g2To373y, _ := new(big.Int).SetString("13e7dd0b4a5dcd9114011529bd13d8a1bfef91a8e65a9ee3db45b4038dcb04fef8fe24c633615e4b8cdecaf63093cb7", 16) - g2To374x, _ := new(big.Int).SetString("1ab7ae756cb1a4ce535b1476fde782b558345b35abe41b8fa9d72ce745ff3484e9492b2ed2dd2124471b51475ee9488", 16) - g2To374y, _ := new(big.Int).SetString("14b3558a24d7eb383096d1963efc1fb865a6a02e995a6b0b8b2fccb13160cfd665a9e4a24dcfabb9ba4003f08c53c86", 16) - g2To375x, _ := new(big.Int).SetString("dc760af5c11d31450e588152a4022dcaf567fd647b1db15f8870aacd8eacacc0f46631ce851a569579601f5715e2cd", 16) - g2To375y, _ := new(big.Int).SetString("179db42c900b0bfb6f0a8a1dc2394016663ad79a7a338c01030eb1f3852a962c2195f47fdda5b3c658d9ca5bdf09281", 16) - g2To376x, _ := new(big.Int).SetString("16490e82ddc6080d4fdfc6b156351793a0b8b1152eba0b9f210342871ff9a5305348518e9baa6aa2aa81a7ad88815e0", 16) - g2To376y, _ := new(big.Int).SetString("18e204412e7ebdf645fa94d53609bf7d1c11b81cedb787a1d5dff84712b7284edd329a83986c196c3c9891fbdf75b88", 16) return CurvePoints{ Gx: gx, Gy: gy, - Gmx: [377]*big.Int{g3x, g5x, g7x, g2To3x, g2To4x, g2To5x, g2To6x, g2To7x, g2To8x, g2To9x, g2To10x, g2To11x, g2To12x, g2To13x, g2To14x, g2To15x, g2To16x, g2To17x, g2To18x, g2To19x, g2To20x, g2To21x, g2To22x, g2To23x, g2To24x, g2To25x, g2To26x, g2To27x, g2To28x, g2To29x, g2To30x, g2To31x, g2To32x, g2To33x, g2To34x, g2To35x, g2To36x, g2To37x, g2To38x, g2To39x, g2To40x, g2To41x, g2To42x, g2To43x, g2To44x, g2To45x, g2To46x, g2To47x, g2To48x, g2To49x, g2To50x, g2To51x, g2To52x, g2To53x, g2To54x, g2To55x, g2To56x, g2To57x, g2To58x, g2To59x, g2To60x, g2To61x, g2To62x, g2To63x, g2To64x, g2To65x, g2To66x, g2To67x, g2To68x, g2To69x, g2To70x, g2To71x, g2To72x, g2To73x, g2To74x, g2To75x, g2To76x, g2To77x, g2To78x, g2To79x, g2To80x, g2To81x, g2To82x, g2To83x, g2To84x, g2To85x, g2To86x, g2To87x, g2To88x, g2To89x, g2To90x, g2To91x, g2To92x, g2To93x, g2To94x, g2To95x, g2To96x, g2To97x, g2To98x, g2To99x, g2To100x, g2To101x, g2To102x, g2To103x, g2To104x, g2To105x, g2To106x, g2To107x, g2To108x, g2To109x, g2To110x, g2To111x, g2To112x, g2To113x, g2To114x, g2To115x, g2To116x, g2To117x, g2To118x, g2To119x, g2To120x, g2To121x, g2To122x, g2To123x, g2To124x, g2To125x, g2To126x, g2To127x, g2To128x, g2To129x, g2To130x, g2To131x, g2To132x, g2To133x, g2To134x, g2To135x, g2To136x, g2To137x, g2To138x, g2To139x, g2To140x, g2To141x, g2To142x, g2To143x, g2To144x, g2To145x, g2To146x, g2To147x, g2To148x, g2To149x, g2To150x, g2To151x, g2To152x, g2To153x, g2To154x, g2To155x, g2To156x, g2To157x, g2To158x, g2To159x, g2To160x, g2To161x, g2To162x, g2To163x, g2To164x, g2To165x, g2To166x, g2To167x, g2To168x, g2To169x, g2To170x, g2To171x, g2To172x, g2To173x, g2To174x, g2To175x, g2To176x, g2To177x, g2To178x, g2To179x, g2To180x, g2To181x, g2To182x, g2To183x, g2To184x, g2To185x, g2To186x, g2To187x, g2To188x, g2To189x, g2To190x, g2To191x, g2To192x, g2To193x, g2To194x, g2To195x, g2To196x, g2To197x, g2To198x, g2To199x, g2To200x, g2To201x, g2To202x, g2To203x, g2To204x, g2To205x, g2To206x, g2To207x, g2To208x, g2To209x, g2To210x, g2To211x, g2To212x, g2To213x, g2To214x, g2To215x, g2To216x, g2To217x, g2To218x, g2To219x, g2To220x, g2To221x, g2To222x, g2To223x, g2To224x, g2To225x, g2To226x, g2To227x, g2To228x, g2To229x, g2To230x, g2To231x, g2To232x, g2To233x, g2To234x, g2To235x, g2To236x, g2To237x, g2To238x, g2To239x, g2To240x, g2To241x, g2To242x, g2To243x, g2To244x, g2To245x, g2To246x, g2To247x, g2To248x, g2To249x, g2To250x, g2To251x, g2To252x, g2To253x, g2To254x, g2To255x, g2To256x, g2To257x, g2To258x, g2To259x, g2To260x, g2To261x, g2To262x, g2To263x, g2To264x, g2To265x, g2To266x, g2To267x, g2To268x, g2To269x, g2To270x, g2To271x, g2To272x, g2To273x, g2To274x, g2To275x, g2To276x, g2To277x, g2To278x, g2To279x, g2To280x, g2To281x, g2To282x, g2To283x, g2To284x, g2To285x, g2To286x, g2To287x, g2To288x, g2To289x, g2To290x, g2To291x, g2To292x, g2To293x, g2To294x, g2To295x, g2To296x, g2To297x, g2To298x, g2To299x, g2To300x, g2To301x, g2To302x, g2To303x, g2To304x, g2To305x, g2To306x, g2To307x, g2To308x, g2To309x, g2To310x, g2To311x, g2To312x, g2To313x, g2To314x, g2To315x, g2To316x, g2To317x, g2To318x, g2To319x, g2To320x, g2To321x, g2To322x, g2To323x, g2To324x, g2To325x, g2To326x, g2To327x, g2To328x, g2To329x, g2To330x, g2To331x, g2To332x, g2To333x, g2To334x, g2To335x, g2To336x, g2To337x, g2To338x, g2To339x, g2To340x, g2To341x, g2To342x, g2To343x, g2To344x, g2To345x, g2To346x, g2To347x, g2To348x, g2To349x, g2To350x, g2To351x, g2To352x, g2To353x, g2To354x, g2To355x, g2To356x, g2To357x, g2To358x, g2To359x, g2To360x, g2To361x, g2To362x, g2To363x, g2To364x, g2To365x, g2To366x, g2To367x, g2To368x, g2To369x, g2To370x, g2To371x, g2To372x, g2To373x, g2To374x, g2To375x, g2To376x}, - Gmy: [377]*big.Int{g3y, g5y, g7y, g2To3y, g2To4y, g2To5y, g2To6y, g2To7y, g2To8y, g2To9y, g2To10y, g2To11y, g2To12y, g2To13y, g2To14y, g2To15y, g2To16y, g2To17y, g2To18y, g2To19y, g2To20y, g2To21y, g2To22y, g2To23y, g2To24y, g2To25y, g2To26y, g2To27y, g2To28y, g2To29y, g2To30y, g2To31y, g2To32y, g2To33y, g2To34y, g2To35y, g2To36y, g2To37y, g2To38y, g2To39y, g2To40y, g2To41y, g2To42y, g2To43y, g2To44y, g2To45y, g2To46y, g2To47y, g2To48y, g2To49y, g2To50y, g2To51y, g2To52y, g2To53y, g2To54y, g2To55y, g2To56y, g2To57y, g2To58y, g2To59y, g2To60y, g2To61y, g2To62y, g2To63y, g2To64y, g2To65y, g2To66y, g2To67y, g2To68y, g2To69y, g2To70y, g2To71y, g2To72y, g2To73y, g2To74y, g2To75y, g2To76y, g2To77y, g2To78y, g2To79y, g2To80y, g2To81y, g2To82y, g2To83y, g2To84y, g2To85y, g2To86y, g2To87y, g2To88y, g2To89y, g2To90y, g2To91y, g2To92y, g2To93y, g2To94y, g2To95y, g2To96y, g2To97y, g2To98y, g2To99y, g2To100y, g2To101y, g2To102y, g2To103y, g2To104y, g2To105y, g2To106y, g2To107y, g2To108y, g2To109y, g2To110y, g2To111y, g2To112y, g2To113y, g2To114y, g2To115y, g2To116y, g2To117y, g2To118y, g2To119y, g2To120y, g2To121y, g2To122y, g2To123y, g2To124y, g2To125y, g2To126y, g2To127y, g2To128y, g2To129y, g2To130y, g2To131y, g2To132y, g2To133y, g2To134y, g2To135y, g2To136y, g2To137y, g2To138y, g2To139y, g2To140y, g2To141y, g2To142y, g2To143y, g2To144y, g2To145y, g2To146y, g2To147y, g2To148y, g2To149y, g2To150y, g2To151y, g2To152y, g2To153y, g2To154y, g2To155y, g2To156y, g2To157y, g2To158y, g2To159y, g2To160y, g2To161y, g2To162y, g2To163y, g2To164y, g2To165y, g2To166y, g2To167y, g2To168y, g2To169y, g2To170y, g2To171y, g2To172y, g2To173y, g2To174y, g2To175y, g2To176y, g2To177y, g2To178y, g2To179y, g2To180y, g2To181y, g2To182y, g2To183y, g2To184y, g2To185y, g2To186y, g2To187y, g2To188y, g2To189y, g2To190y, g2To191y, g2To192y, g2To193y, g2To194y, g2To195y, g2To196y, g2To197y, g2To198y, g2To199y, g2To200y, g2To201y, g2To202y, g2To203y, g2To204y, g2To205y, g2To206y, g2To207y, g2To208y, g2To209y, g2To210y, g2To211y, g2To212y, g2To213y, g2To214y, g2To215y, g2To216y, g2To217y, g2To218y, g2To219y, g2To220y, g2To221y, g2To222y, g2To223y, g2To224y, g2To225y, g2To226y, g2To227y, g2To228y, g2To229y, g2To230y, g2To231y, g2To232y, g2To233y, g2To234y, g2To235y, g2To236y, g2To237y, g2To238y, g2To239y, g2To240y, g2To241y, g2To242y, g2To243y, g2To244y, g2To245y, g2To246y, g2To247y, g2To248y, g2To249y, g2To250y, g2To251y, g2To252y, g2To253y, g2To254y, g2To255y, g2To256y, g2To257y, g2To258y, g2To259y, g2To260y, g2To261y, g2To262y, g2To263y, g2To264y, g2To265y, g2To266y, g2To267y, g2To268y, g2To269y, g2To270y, g2To271y, g2To272y, g2To273y, g2To274y, g2To275y, g2To276y, g2To277y, g2To278y, g2To279y, g2To280y, g2To281y, g2To282y, g2To283y, g2To284y, g2To285y, g2To286y, g2To287y, g2To288y, g2To289y, g2To290y, g2To291y, g2To292y, g2To293y, g2To294y, g2To295y, g2To296y, g2To297y, g2To298y, g2To299y, g2To300y, g2To301y, g2To302y, g2To303y, g2To304y, g2To305y, g2To306y, g2To307y, g2To308y, g2To309y, g2To310y, g2To311y, g2To312y, g2To313y, g2To314y, g2To315y, g2To316y, g2To317y, g2To318y, g2To319y, g2To320y, g2To321y, g2To322y, g2To323y, g2To324y, g2To325y, g2To326y, g2To327y, g2To328y, g2To329y, g2To330y, g2To331y, g2To332y, g2To333y, g2To334y, g2To335y, g2To336y, g2To337y, g2To338y, g2To339y, g2To340y, g2To341y, g2To342y, g2To343y, g2To344y, g2To345y, g2To346y, g2To347y, g2To348y, g2To349y, g2To350y, g2To351y, g2To352y, g2To353y, g2To354y, g2To355y, g2To356y, g2To357y, g2To358y, g2To359y, g2To360y, g2To361y, g2To362y, g2To363y, g2To364y, g2To365y, g2To366y, g2To367y, g2To368y, g2To369y, g2To370y, g2To371y, g2To372y, g2To373y, g2To374y, g2To375y, g2To376y}, + Gmx: [253]*big.Int{g3x, g5x, g7x, g2To3x, g2To4x, g2To5x, g2To6x, g2To7x, g2To8x, g2To9x, g2To10x, g2To11x, g2To12x, g2To13x, g2To14x, g2To15x, g2To16x, g2To17x, g2To18x, g2To19x, g2To20x, g2To21x, g2To22x, g2To23x, g2To24x, g2To25x, g2To26x, g2To27x, g2To28x, g2To29x, g2To30x, g2To31x, g2To32x, g2To33x, g2To34x, g2To35x, g2To36x, g2To37x, g2To38x, g2To39x, g2To40x, g2To41x, g2To42x, g2To43x, g2To44x, g2To45x, g2To46x, g2To47x, g2To48x, g2To49x, g2To50x, g2To51x, g2To52x, g2To53x, g2To54x, g2To55x, g2To56x, g2To57x, g2To58x, g2To59x, g2To60x, g2To61x, g2To62x, g2To63x, g2To64x, g2To65x, g2To66x, g2To67x, g2To68x, g2To69x, g2To70x, g2To71x, g2To72x, g2To73x, g2To74x, g2To75x, g2To76x, g2To77x, g2To78x, g2To79x, g2To80x, g2To81x, g2To82x, g2To83x, g2To84x, g2To85x, g2To86x, g2To87x, g2To88x, g2To89x, g2To90x, g2To91x, g2To92x, g2To93x, g2To94x, g2To95x, g2To96x, g2To97x, g2To98x, g2To99x, g2To100x, g2To101x, g2To102x, g2To103x, g2To104x, g2To105x, g2To106x, g2To107x, g2To108x, g2To109x, g2To110x, g2To111x, g2To112x, g2To113x, g2To114x, g2To115x, g2To116x, g2To117x, g2To118x, g2To119x, g2To120x, g2To121x, g2To122x, g2To123x, g2To124x, g2To125x, g2To126x, g2To127x, g2To128x, g2To129x, g2To130x, g2To131x, g2To132x, g2To133x, g2To134x, g2To135x, g2To136x, g2To137x, g2To138x, g2To139x, g2To140x, g2To141x, g2To142x, g2To143x, g2To144x, g2To145x, g2To146x, g2To147x, g2To148x, g2To149x, g2To150x, g2To151x, g2To152x, g2To153x, g2To154x, g2To155x, g2To156x, g2To157x, g2To158x, g2To159x, g2To160x, g2To161x, g2To162x, g2To163x, g2To164x, g2To165x, g2To166x, g2To167x, g2To168x, g2To169x, g2To170x, g2To171x, g2To172x, g2To173x, g2To174x, g2To175x, g2To176x, g2To177x, g2To178x, g2To179x, g2To180x, g2To181x, g2To182x, g2To183x, g2To184x, g2To185x, g2To186x, g2To187x, g2To188x, g2To189x, g2To190x, g2To191x, g2To192x, g2To193x, g2To194x, g2To195x, g2To196x, g2To197x, g2To198x, g2To199x, g2To200x, g2To201x, g2To202x, g2To203x, g2To204x, g2To205x, g2To206x, g2To207x, g2To208x, g2To209x, g2To210x, g2To211x, g2To212x, g2To213x, g2To214x, g2To215x, g2To216x, g2To217x, g2To218x, g2To219x, g2To220x, g2To221x, g2To222x, g2To223x, g2To224x, g2To225x, g2To226x, g2To227x, g2To228x, g2To229x, g2To230x, g2To231x, g2To232x, g2To233x, g2To234x, g2To235x, g2To236x, g2To237x, g2To238x, g2To239x, g2To240x, g2To241x, g2To242x, g2To243x, g2To244x, g2To245x, g2To246x, g2To247x, g2To248x, g2To249x, g2To250x, g2To251x, g2To252x}, + Gmy: [253]*big.Int{g3y, g5y, g7y, g2To3y, g2To4y, g2To5y, g2To6y, g2To7y, g2To8y, g2To9y, g2To10y, g2To11y, g2To12y, g2To13y, g2To14y, g2To15y, g2To16y, g2To17y, g2To18y, g2To19y, g2To20y, g2To21y, g2To22y, g2To23y, g2To24y, g2To25y, g2To26y, g2To27y, g2To28y, g2To29y, g2To30y, g2To31y, g2To32y, g2To33y, g2To34y, g2To35y, g2To36y, g2To37y, g2To38y, g2To39y, g2To40y, g2To41y, g2To42y, g2To43y, g2To44y, g2To45y, g2To46y, g2To47y, g2To48y, g2To49y, g2To50y, g2To51y, g2To52y, g2To53y, g2To54y, g2To55y, g2To56y, g2To57y, g2To58y, g2To59y, g2To60y, g2To61y, g2To62y, g2To63y, g2To64y, g2To65y, g2To66y, g2To67y, g2To68y, g2To69y, g2To70y, g2To71y, g2To72y, g2To73y, g2To74y, g2To75y, g2To76y, g2To77y, g2To78y, g2To79y, g2To80y, g2To81y, g2To82y, g2To83y, g2To84y, g2To85y, g2To86y, g2To87y, g2To88y, g2To89y, g2To90y, g2To91y, g2To92y, g2To93y, g2To94y, g2To95y, g2To96y, g2To97y, g2To98y, g2To99y, g2To100y, g2To101y, g2To102y, g2To103y, g2To104y, g2To105y, g2To106y, g2To107y, g2To108y, g2To109y, g2To110y, g2To111y, g2To112y, g2To113y, g2To114y, g2To115y, g2To116y, g2To117y, g2To118y, g2To119y, g2To120y, g2To121y, g2To122y, g2To123y, g2To124y, g2To125y, g2To126y, g2To127y, g2To128y, g2To129y, g2To130y, g2To131y, g2To132y, g2To133y, g2To134y, g2To135y, g2To136y, g2To137y, g2To138y, g2To139y, g2To140y, g2To141y, g2To142y, g2To143y, g2To144y, g2To145y, g2To146y, g2To147y, g2To148y, g2To149y, g2To150y, g2To151y, g2To152y, g2To153y, g2To154y, g2To155y, g2To156y, g2To157y, g2To158y, g2To159y, g2To160y, g2To161y, g2To162y, g2To163y, g2To164y, g2To165y, g2To166y, g2To167y, g2To168y, g2To169y, g2To170y, g2To171y, g2To172y, g2To173y, g2To174y, g2To175y, g2To176y, g2To177y, g2To178y, g2To179y, g2To180y, g2To181y, g2To182y, g2To183y, g2To184y, g2To185y, g2To186y, g2To187y, g2To188y, g2To189y, g2To190y, g2To191y, g2To192y, g2To193y, g2To194y, g2To195y, g2To196y, g2To197y, g2To198y, g2To199y, g2To200y, g2To201y, g2To202y, g2To203y, g2To204y, g2To205y, g2To206y, g2To207y, g2To208y, g2To209y, g2To210y, g2To211y, g2To212y, g2To213y, g2To214y, g2To215y, g2To216y, g2To217y, g2To218y, g2To219y, g2To220y, g2To221y, g2To222y, g2To223y, g2To224y, g2To225y, g2To226y, g2To227y, g2To228y, g2To229y, g2To230y, g2To231y, g2To232y, g2To233y, g2To234y, g2To235y, g2To236y, g2To237y, g2To238y, g2To239y, g2To240y, g2To241y, g2To242y, g2To243y, g2To244y, g2To245y, g2To246y, g2To247y, g2To248y, g2To249y, g2To250y, g2To251y, g2To252y}, } } From 325d08c94baf7aeae4a6890af12bdfb5a03815ed Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Wed, 1 Mar 2023 12:52:02 +0100 Subject: [PATCH 032/464] refactor: lazy compute the base tables on init --- std/algebra/weierstrass/params.go | 1050 +-------------------- std/algebra/weierstrass/params_compute.go | 60 ++ std/algebra/weierstrass/point.go | 780 +-------------- 3 files changed, 78 insertions(+), 1812 deletions(-) create mode 100644 std/algebra/weierstrass/params_compute.go diff --git a/std/algebra/weierstrass/params.go b/std/algebra/weierstrass/params.go index ad6699f28d..348b212008 100644 --- a/std/algebra/weierstrass/params.go +++ b/std/algebra/weierstrass/params.go @@ -13,12 +13,11 @@ import ( // // The base point is defined by (Gx, Gy). type CurveParams struct { - A *big.Int // a in curve equation - B *big.Int // b in curve equation - Gx *big.Int // base point x - Gy *big.Int // base point y - Gmx [256]*big.Int // m*base point x - Gmy [256]*big.Int // m*base point y + A *big.Int // a in curve equation + B *big.Int // b in curve equation + Gx *big.Int // base point x + Gy *big.Int // base point y + Gm [][2]*big.Int // m*base point coords } // GetSecp256k1Params returns curve parameters for the curve secp256k1. When @@ -27,525 +26,12 @@ type CurveParams struct { func GetSecp256k1Params() CurveParams { gx, _ := new(big.Int).SetString("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", 16) gy, _ := new(big.Int).SetString("483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", 16) - g3x, _ := new(big.Int).SetString("f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9", 16) - g3y, _ := new(big.Int).SetString("388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672", 16) - g5x, _ := new(big.Int).SetString("2f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4", 16) - g5y, _ := new(big.Int).SetString("d8ac222636e5e3d6d4dba9dda6c9c426f788271bab0d6840dca87d3aa6ac62d6", 16) - g7x, _ := new(big.Int).SetString("5cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc", 16) - g7y, _ := new(big.Int).SetString("6aebca40ba255960a3178d6d861a54dba813d0b813fde7b5a5082628087264da", 16) - g2To3x, _ := new(big.Int).SetString("2f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01", 16) - g2To3y, _ := new(big.Int).SetString("5c4da8a741539949293d082a132d13b4c2e213d6ba5b7617b5da2cb76cbde904", 16) - g2To4x, _ := new(big.Int).SetString("e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a", 16) - g2To4y, _ := new(big.Int).SetString("f7e3507399e595929db99f34f57937101296891e44d23f0be1f32cce69616821", 16) - g2To5x, _ := new(big.Int).SetString("d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65", 16) - g2To5y, _ := new(big.Int).SetString("95038d9d0ae3d5c3b3d6dec9e98380651f760cc364ed819605b3ff1f24106ab9", 16) - g2To6x, _ := new(big.Int).SetString("bf23c1542d16eab70b1051eaf832823cfc4c6f1dcdbafd81e37918e6f874ef8b", 16) - g2To6y, _ := new(big.Int).SetString("5cb3866fc33003737ad928a0ba5392e4c522fc54811e2f784dc37efe66831d9f", 16) - g2To7x, _ := new(big.Int).SetString("34ff3be4033f7a06696c3d09f7d1671cbcf55cd700535655647077456769a24e", 16) - g2To7y, _ := new(big.Int).SetString("5d9d11623a236c553f6619d89832098c55df16c3e8f8b6818491067a73cc2f1a", 16) - g2To8x, _ := new(big.Int).SetString("8282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508", 16) - g2To8y, _ := new(big.Int).SetString("11f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf", 16) - g2To9x, _ := new(big.Int).SetString("465370b287a79ff3905a857a9cf918d50adbc968d9e159d0926e2c00ef34a24d", 16) - g2To9y, _ := new(big.Int).SetString("35e531b38368c082a4af8bdafdeec2c1588e09b215d37a10a2f8fb20b33887f4", 16) - g2To10x, _ := new(big.Int).SetString("241febb8e23cbd77d664a18f66ad6240aaec6ecdc813b088d5b901b2e285131f", 16) - g2To10y, _ := new(big.Int).SetString("513378d9ff94f8d3d6c420bd13981df8cd50fd0fbd0cb5afabb3e66f2750026d", 16) - g2To11x, _ := new(big.Int).SetString("5d1bdb4ea172fa79fce4cc2983d8f8d9fc318b85f423de0dedcb63069b920471", 16) - g2To11y, _ := new(big.Int).SetString("2843826779379e2e794bb99438a2265679eb1e9996c56e7b70330666f7b83103", 16) - g2To12x, _ := new(big.Int).SetString("175e159f728b865a72f99cc6c6fc846de0b93833fd2222ed73fce5b551e5b739", 16) - g2To12y, _ := new(big.Int).SetString("d3506e0d9e3c79eba4ef97a51ff71f5eacb5955add24345c6efa6ffee9fed695", 16) - g2To13x, _ := new(big.Int).SetString("423a013f03ff32d7a5ffbcc8e139c62130fdfeb5c6da121bce78049e46bc47d6", 16) - g2To13y, _ := new(big.Int).SetString("b91ae00fe1e1d970a1179f7bbaf6b3c7720d8ec3524f009ed1236e6d8b548a34", 16) - g2To14x, _ := new(big.Int).SetString("111d6a45ac1fb90508907a7abcd6877649df662f3b3e2741302df6f78416824a", 16) - g2To14y, _ := new(big.Int).SetString("696911c478eaffbb90d48dbff065952f070008996daca4ca9a111d42108e9d0", 16) - g2To15x, _ := new(big.Int).SetString("4a4a6dc97ac7c8b8ad795dbebcb9dcff7290b68a5ef74e56ab5edde01bced775", 16) - g2To15y, _ := new(big.Int).SetString("529911b016631e72943ef9f739c0f4571de90cdb424742acb2bf8f68a78dd66d", 16) - g2To16x, _ := new(big.Int).SetString("363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640", 16) - g2To16y, _ := new(big.Int).SetString("4e273adfc732221953b445397f3363145b9a89008199ecb62003c7f3bee9de9", 16) - g2To17x, _ := new(big.Int).SetString("4c1b9866ed9a7e9b553973c6c93b02bf0b62fb012edfb59dd2712a5caf92c541", 16) - g2To17y, _ := new(big.Int).SetString("c1f792d320be8a0f7fbcb753ce56e69cc652ead7e43eb1ad72c4f3fdc68fe020", 16) - g2To18x, _ := new(big.Int).SetString("a4083877ba83b12b529a2f3c0780b54e3233edbc1a28f135e0c8f28cbeaaf3d1", 16) - g2To18y, _ := new(big.Int).SetString("40e9f612feefbc79b8bf83d69361b3e22001e7576ed1ef90b12b534df0b254b9", 16) - g2To19x, _ := new(big.Int).SetString("a804c641d28cc0b53a4e3e1a2f56c86f6e0d880a454203b98cd3db5a7940d33a", 16) - g2To19y, _ := new(big.Int).SetString("95be83252b2fa6d03dec2842c16047e81af18ca89cf736a943ce95fa6d46967a", 16) - g2To20x, _ := new(big.Int).SetString("8b4b5f165df3c2be8c6244b5b745638843e4a781a15bcd1b69f79a55dffdf80c", 16) - g2To20y, _ := new(big.Int).SetString("4aad0a6f68d308b4b3fbd7813ab0da04f9e336546162ee56b3eff0c65fd4fd36", 16) - g2To21x, _ := new(big.Int).SetString("ed0c5ce4e13291718ce17c7ec83c611071af64ee417c997abb3f26714755e4be", 16) - g2To21y, _ := new(big.Int).SetString("221a9fc7bc2345bdbf3dad7f5a7ea68049d93925763ddab163f9fa6ea07bf42f", 16) - g2To22x, _ := new(big.Int).SetString("faecb013c44ce694b3b15c3f83f1fae8e53254566e0552ced4b6e6c807cec8ab", 16) - g2To22y, _ := new(big.Int).SetString("cc09b5e90e9ecb57fc2e02c6ec2fb13d9c32b286b85e2e2e8981dfd9ab155070", 16) - g2To23x, _ := new(big.Int).SetString("9bb8a132dcad2f2c8731a0b37cbcafdb3b2dd824f23cd3e07f64eae9ad1b1f7", 16) - g2To23y, _ := new(big.Int).SetString("945bb2b2afeee3b9b6f9dd284f863e850f54a840f4752d5364130627c3811c80", 16) - g2To24x, _ := new(big.Int).SetString("723cbaa6e5db996d6bf771c00bd548c7b700dbffa6c0e77bcb6115925232fcda", 16) - g2To24y, _ := new(big.Int).SetString("96e867b5595cc498a921137488824d6e2660a0653779494801dc069d9eb39f5f", 16) - g2To25x, _ := new(big.Int).SetString("57efa786437b744d343d7dc45773a3c62d240a43079849071fd383d60ca030d5", 16) - g2To25y, _ := new(big.Int).SetString("d712db0bd1b48518893627c928de03ec689b6d2ae5e9974ab07ab44274b02f9e", 16) - g2To26x, _ := new(big.Int).SetString("264bbd436a28bc42a2df7e9cd5226cb91080577e327b012a7fafc7770c584dd5", 16) - g2To26y, _ := new(big.Int).SetString("d87c6fa94ee093b4d4f75ce24c33be226a118243717b8d8de61227937704ab11", 16) - g2To27x, _ := new(big.Int).SetString("a94c6524bd40d2bbdac85c056236a79da78bc61fd5bdec9d2bf26bd84b2438e8", 16) - g2To27y, _ := new(big.Int).SetString("b5201fd992f96280fd79219505019e3a7e5d3c60a0e39b2bc2e2c8dbf18661f4", 16) - g2To28x, _ := new(big.Int).SetString("eebfa4d493bebf98ba5feec812c2d3b50947961237a919839a533eca0e7dd7fa", 16) - g2To28y, _ := new(big.Int).SetString("5d9a8ca3970ef0f269ee7edaf178089d9ae4cdc3a711f712ddfd4fdae1de8999", 16) - g2To29x, _ := new(big.Int).SetString("381c4ad7a7a97bfda61c6031c118495fc4ea4bc08f6766d676bee90847d297fd", 16) - g2To29y, _ := new(big.Int).SetString("936af53b238eeee48f3e5fa709915eccf0451032db939c0093ace3187d493fc5", 16) - g2To30x, _ := new(big.Int).SetString("e1efb9cd05adc63bcce10831d9538c479cf1d05fefdd08b2448d70422ede454c", 16) - g2To30y, _ := new(big.Int).SetString("ecb4530d8af9be7b0154c1ffe477123464e3244a7a2d4c6ad9fd233a8913797", 16) - g2To31x, _ := new(big.Int).SetString("5318f9b1a2697010c5ac235e9af475a8c7e5419f33d47b18d33feeb329eb99a4", 16) - g2To31y, _ := new(big.Int).SetString("f44ccfeb4beda4195772d93aebb405e8a41f2b40d1e3ec652c726eeefe91f92d", 16) - g2To32x, _ := new(big.Int).SetString("100f44da696e71672791d0a09b7bde459f1215a29b3c03bfefd7835b39a48db0", 16) - g2To32y, _ := new(big.Int).SetString("cdd9e13192a00b772ec8f3300c090666b7ff4a18ff5195ac0fbd5cd62bc65a09", 16) - g2To33x, _ := new(big.Int).SetString("8c0989f2ceb5c771a8415dff2b4c4199d8d9c8f9237d08084b05284f1e4df706", 16) - g2To33y, _ := new(big.Int).SetString("fb4dbd044f432034ffd2172cb9dc966c60de6bf5156511aa736ac5a35d72fa98", 16) - g2To34x, _ := new(big.Int).SetString("fb8f153c5e266704c4a481743262c0259c528539bc95bc1bb1e63c33dc47bffd", 16) - g2To34y, _ := new(big.Int).SetString("6ca27a9dc5e0621816fa11d9b4bccd531dde1389ac542613090a45ddd949b095", 16) - g2To35x, _ := new(big.Int).SetString("e747333fd75d51755a0cc9f0a728708465a02c587737a7b8b8fa1b8b4bb2629a", 16) - g2To35y, _ := new(big.Int).SetString("f2affe0145070c114cc43603804c2581c88376aa6e1a969a9f8d961a6946f6d6", 16) - g2To36x, _ := new(big.Int).SetString("e1031be262c7ed1b1dc9227a4a04c017a77f8d4464f3b3852c8acde6e534fd2d", 16) - g2To36y, _ := new(big.Int).SetString("9d7061928940405e6bb6a4176597535af292dd419e1ced79a44f18f29456a00d", 16) - g2To37x, _ := new(big.Int).SetString("f4b93f224c8089eab9f95dcd0f29b2c9028a6ac5de94d85784e27e36a95c8356", 16) - g2To37y, _ := new(big.Int).SetString("a67a92ec062962dfb0e5f6a7a40eee90c37ef1344915609abd5861b9be001fd3", 16) - g2To38x, _ := new(big.Int).SetString("9d1aca1fce55236b19622ea025b08b0d51e8512f97e696c20d62fe17b160e8a", 16) - g2To38y, _ := new(big.Int).SetString("1153188f5101f0c63e56692ce0d8c27e6fe9e0ee9212b5e534e050c57ca04c44", 16) - g2To39x, _ := new(big.Int).SetString("c66c59cc454c2b9e18a2ad793821cde7518b3a93bfc39562e97d7d0475ba7fc2", 16) - g2To39y, _ := new(big.Int).SetString("d9592fe2bfb30fcfbea4f3ceaac10cb2f00a60ddb15955977ec3c69cf75f5956", 16) - g2To40x, _ := new(big.Int).SetString("feea6cae46d55b530ac2839f143bd7ec5cf8b266a41d6af52d5e688d9094696d", 16) - g2To40y, _ := new(big.Int).SetString("e57c6b6c97dce1bab06e4e12bf3ecd5c981c8957cc41442d3155debf18090088", 16) - g2To41x, _ := new(big.Int).SetString("4d000b621adb87e1c53261af9db2e179141ecae0b331a1870aa4040aee752b08", 16) - g2To41y, _ := new(big.Int).SetString("6a0d5b8f18e0d255cb6d825582d972cccb7df5f119c7293a3e72851f48302cea", 16) - g2To42x, _ := new(big.Int).SetString("71f570ca203da05dd6aa262114717128d657a0403e1f1b77f89962fd475c58ef", 16) - g2To42y, _ := new(big.Int).SetString("eb42415b95dc880dd25557345bc95b8df2445d00c3363e7df8649a72d35d420e", 16) - g2To43x, _ := new(big.Int).SetString("a2b7b3629f7bd253b7d282b5c21da01446b4821dc65e76516048b06043ff8359", 16) - g2To43y, _ := new(big.Int).SetString("693038941695122d57a937a3f71e29c910d10835046f3835a2397fecfe86fec2", 16) - g2To44x, _ := new(big.Int).SetString("da67a91d91049cdcb367be4be6ffca3cfeed657d808583de33fa978bc1ec6cb1", 16) - g2To44y, _ := new(big.Int).SetString("9bacaa35481642bc41f463f7ec9780e5dec7adc508f740a17e9ea8e27a68be1d", 16) - g2To45x, _ := new(big.Int).SetString("4dbacd365fa1ef587c0c0cfaaf00d8718bbd9f35ccea5a835ee3cc821fe741c9", 16) - g2To45y, _ := new(big.Int).SetString("16c3540e8a51892e7fdcfd59e838299d0cc384a09fc0535f60be10f8338eb623", 16) - g2To46x, _ := new(big.Int).SetString("13d1ffc481509beee68f17d8ff41c2590f4c85f15268605087eda8bab4e218da", 16) - g2To46y, _ := new(big.Int).SetString("6008391fa991961dcecb9337b1b758bda4ad01206d5bd127e0db419ddb191c19", 16) - g2To47x, _ := new(big.Int).SetString("219b4f9cef6c60007659c79c45b0533b3cc9d916ce29dbff133b40caa2e96db8", 16) - g2To47y, _ := new(big.Int).SetString("24d9c605d959efeaf5a44180c0372a6e394f8ac53e90576527df01a78d3b6bc7", 16) - g2To48x, _ := new(big.Int).SetString("53904faa0b334cdda6e000935ef22151ec08d0f7bb11069f57545ccc1a37b7c0", 16) - g2To48y, _ := new(big.Int).SetString("5bc087d0bc80106d88c9eccac20d3c1c13999981e14434699dcb096b022771c8", 16) - g2To49x, _ := new(big.Int).SetString("1a575af9d4146753cf991196316995d2a6ee7aaad0f85ad57cd0f1f38a47ca9", 16) - g2To49y, _ := new(big.Int).SetString("3038f1cb8ab20dc3cc55fc52e1bb8698bdb93c5d9f4d7ea667c5df2e77ebcdb7", 16) - g2To50x, _ := new(big.Int).SetString("f5f0e0437621d439ca71f5c1b76155d6d3a61a83d3c20c6ee309d755e315565b", 16) - g2To50y, _ := new(big.Int).SetString("6b9f4e62be5a052bf62189160df7101aa5bf61bf3ed7e40a678430afdd2ecc82", 16) - g2To51x, _ := new(big.Int).SetString("8f506f0b6c0b6e9a57a7f36d970ca4e347cbc92146227642cbe781d9f5362d33", 16) - g2To51y, _ := new(big.Int).SetString("469f955d2afa61719530c5424f1c336848cf925d43bb8eaf30487d0c87fa243f", 16) - g2To52x, _ := new(big.Int).SetString("8e7bcd0bd35983a7719cca7764ca906779b53a043a9b8bcaeff959f43ad86047", 16) - g2To52y, _ := new(big.Int).SetString("10b7770b2a3da4b3940310420ca9514579e88e2e47fd68b3ea10047e8460372a", 16) - g2To53x, _ := new(big.Int).SetString("33b35baa195e729dc350f319996950df3bc15b8d3d0389e777d2808bf13f0351", 16) - g2To53y, _ := new(big.Int).SetString("a58a0185640abf87f9464036248d52bcaa6560efbc889b702bc503cccb8d7418", 16) - g2To54x, _ := new(big.Int).SetString("374deeae22c93f955cb83ad2071f7e2256f6e109cad7bca6d71dc7b24414bb36", 16) - g2To54y, _ := new(big.Int).SetString("171165b64fcd4f9916032c06f806f7293828d66300e543217875bea98daf734a", 16) - g2To55x, _ := new(big.Int).SetString("2380c09c7f3aeae57c46e07395aeb0dc944dbaf2b62a9f0c5e8a64ad6ae7d616", 16) - g2To55y, _ := new(big.Int).SetString("6f8e86193464956af1598aefd509b09a93af92148f8467560099be48161bbc1a", 16) - g2To56x, _ := new(big.Int).SetString("385eed34c1cdff21e6d0818689b81bde71a7f4f18397e6690a841e1599c43862", 16) - g2To56y, _ := new(big.Int).SetString("283bebc3e8ea23f56701de19e9ebf4576b304eec2086dc8cc0458fe5542e5453", 16) - g2To57x, _ := new(big.Int).SetString("f6f622083daf54800456be134d5f67d147c82642befc1ce2dc83a27078f2827c", 16) - g2To57y, _ := new(big.Int).SetString("1bcd4e817de73a0faf2c5715b367cee7e657ca7448321bf6d15b20b520aaa102", 16) - g2To58x, _ := new(big.Int).SetString("fb26e5188f953de2bd70cb3c3d1fc255cd91c3ce7d8c6f369d893209715adcb6", 16) - g2To58y, _ := new(big.Int).SetString("f3e128811012a34d58e846a719d0176916d2cb31b8b7ab5449dbca3b58ba68f3", 16) - g2To59x, _ := new(big.Int).SetString("8991225911b9132d28f5c6bc763ceab7d18c37060e8bd1d7ed44db7560788c1e", 16) - g2To59y, _ := new(big.Int).SetString("da8b4d987cc9ac9b27b8763559b136fa36969c84fdef9e11635c42228e8f0ef1", 16) - g2To60x, _ := new(big.Int).SetString("6f9d9b803ecf191637c73a4413dfa180fddf84a5947fbc9c606ed86c3fac3a7", 16) - g2To60y, _ := new(big.Int).SetString("7c80c68e603059ba69b8e2a30e45c4d47ea4dd2f5c281002d86890603a842160", 16) - g2To61x, _ := new(big.Int).SetString("ae86eeea252b411c1cdc36c284482939da1745e5a7e4da175c9d22744b7fd72d", 16) - g2To61y, _ := new(big.Int).SetString("19e993c9707302f962ab0ace589ff0e98d9211551472f7282334cb7a4eee38bc", 16) - g2To62x, _ := new(big.Int).SetString("2248c9f90bbfff55e61d2f8c56dc2c488718be75cf36f2ee7a1474267c169290", 16) - g2To62y, _ := new(big.Int).SetString("fa0594692d21eed7a506bb55b435ba18e163750235da2be2369d8a12883ea257", 16) - g2To63x, _ := new(big.Int).SetString("e11a6e16e05c44074ac11b48d94085d0a99f0877dd1c6f76fd0dac4bb50964e3", 16) - g2To63y, _ := new(big.Int).SetString("87d6065b87a2d430e1ad5e2596f0af2417adc6e138318c6f767fbf8b0682bfc8", 16) - g2To64x, _ := new(big.Int).SetString("3322d401243c4e2582a2147c104d6ecbf774d163db0f5e5313b7e0e742d0e6bd", 16) - g2To64y, _ := new(big.Int).SetString("56e70797e9664ef5bfb019bc4ddaf9b72805f63ea2873af624f3a2e96c28b2a0", 16) - g2To65x, _ := new(big.Int).SetString("8d26200250cebdae120ef31b04c80cd50d4cddc8eadbcf29fc696d32c0ade462", 16) - g2To65y, _ := new(big.Int).SetString("ebed3bb4715bf437d31f6f2dc3ee36ba1d4afb4e72678b3ad8e0a8b90f26470c", 16) - g2To66x, _ := new(big.Int).SetString("1238c0766eaebea9ce4068a1f594d03b8ed4930d072d9c8b9164643e1516e633", 16) - g2To66y, _ := new(big.Int).SetString("8a9db02dbb271359d6c979e2d1c3dc170946252dcc74022805cdb728c77b7805", 16) - g2To67x, _ := new(big.Int).SetString("271d5b0770cb9c15e7b2ea758a6a11b9cddcd7282b0ec21619b01552788e7a66", 16) - g2To67y, _ := new(big.Int).SetString("5d3aa45834e7f491e457d09949ac877fe2a065e3508a824e7a8d7258e03c9727", 16) - g2To68x, _ := new(big.Int).SetString("85672c7d2de0b7da2bd1770d89665868741b3f9af7643397721d74d28134ab83", 16) - g2To68y, _ := new(big.Int).SetString("7c481b9b5b43b2eb6374049bfa62c2e5e77f17fcc5298f44c8e3094f790313a6", 16) - g2To69x, _ := new(big.Int).SetString("534ccf6b740f9ec036c1861215c8a61f3b89ea46df2e6d96998b90bc1f17fc25", 16) - g2To69y, _ := new(big.Int).SetString("d5715cb09c8b2ddb462ae3dd32d543550ae3d277bfdd28ddd71c7f6ecfe86e76", 16) - g2To70x, _ := new(big.Int).SetString("a91d1f5cee87b7f3081e142018f8aaed79020d47ecfbc8d2c7170923e8bee8b6", 16) - g2To70y, _ := new(big.Int).SetString("748a324ee2df8ee15a7189c8dddad3b2f800569f628cb225003d16aa410644c1", 16) - g2To71x, _ := new(big.Int).SetString("c15c8c23d90c8e35c1a214dde2d4383c0735ae45bef61f10aa1a1c255984cf74", 16) - g2To71y, _ := new(big.Int).SetString("2ba954d828522235c8dc6f45e25fd7ba47bf772d50b015a2c4a48cd839ccb000", 16) - g2To72x, _ := new(big.Int).SetString("948bf809b1988a46b06c9f1919413b10f9226c60f668832ffd959af60c82a0a", 16) - g2To72y, _ := new(big.Int).SetString("53a562856dcb6646dc6b74c5d1c3418c6d4dff08c97cd2bed4cb7f88d8c8e589", 16) - g2To73x, _ := new(big.Int).SetString("26952c7f372e59360d5ce4c66291f0b6ef16c1331e825e51396eb0457e8b000a", 16) - g2To73y, _ := new(big.Int).SetString("f513ea4c5800a68862bc893d2d688422debe398f653d67318c3d401f05ef705a", 16) - g2To74x, _ := new(big.Int).SetString("c62e58e6fc23c5bdbef2be8b131ff243f521196572d6b0e9f102588976134f96", 16) - g2To74y, _ := new(big.Int).SetString("4397827d45b1a1678c3d676753141fc5bcfb853563731c3e82277ed4d14cf97e", 16) - g2To75x, _ := new(big.Int).SetString("107460520eec5c741683329a716622b0b81c03200807de973686f8800b188cbb", 16) - g2To75y, _ := new(big.Int).SetString("abe5d4c09a21598c35326b9b9cf54a11242e0d748dce3da601d7b6361f272124", 16) - g2To76x, _ := new(big.Int).SetString("6260ce7f461801c34f067ce0f02873a8f1b0e44dfc69752accecd819f38fd8e8", 16) - g2To76y, _ := new(big.Int).SetString("bc2da82b6fa5b571a7f09049776a1ef7ecd292238051c198c1a84e95b2b4ae17", 16) - g2To77x, _ := new(big.Int).SetString("85d8da4748ad1a73dec8409be84f1a1316e65c5196aad27e0766746f3d477c2d", 16) - g2To77y, _ := new(big.Int).SetString("58948b53665c6690586b536531efc7bc94b0a02033c4d5a62079816fc7d1dd70", 16) - g2To78x, _ := new(big.Int).SetString("8e2a7166e7ec4b968c0892e9cc3ee3ee4d1e7e100fdc47f04850312d6c0b80d9", 16) - g2To78y, _ := new(big.Int).SetString("eadb0ba9ae2cbe592cedd29b716a9d485297b688d706349a49c61f2ad6b29f50", 16) - g2To79x, _ := new(big.Int).SetString("769bc75842bff58edc8366ecd78f8950ee4ab2e81359d90f9921fa3d2c4561be", 16) - g2To79y, _ := new(big.Int).SetString("4bf817362fe783bac8dce4cef73f5d4741a177767b7873add5920bffb0d9685f", 16) - g2To80x, _ := new(big.Int).SetString("e5037de0afc1d8d43d8348414bbf4103043ec8f575bfdc432953cc8d2037fa2d", 16) - g2To80y, _ := new(big.Int).SetString("4571534baa94d3b5f9f98d09fb990bddbd5f5b03ec481f10e0e5dc841d755bda", 16) - g2To81x, _ := new(big.Int).SetString("a5e00da467fd5494f40b6cf7d2d61b3ec3ab217c792a2ddb8c63c8c79e3d34ef", 16) - g2To81y, _ := new(big.Int).SetString("98fe5f5e5608555421726fe99bf43d25b60dcfe790900acb855c5ce2f7adb4c", 16) - g2To82x, _ := new(big.Int).SetString("a99415f5ef3a2b403519f4bb1c9bfbc46d4afd2e4477572ae6737160d7b91252", 16) - g2To82y, _ := new(big.Int).SetString("82d0e64cae81f84bb9e2f10f24f6f6b6899a16ad590f4ddd73a377ac4bedc264", 16) - g2To83x, _ := new(big.Int).SetString("b56f4e9f9e4fd1fc7d8edde098f935f84c750d705f0c132bd8c465b66a540f17", 16) - g2To83y, _ := new(big.Int).SetString("32e8e53429cca856d3dc11adf0582d1d21d42963cbcca85446a2fcae0200102d", 16) - g2To84x, _ := new(big.Int).SetString("e06372b0f4a207adf5ea905e8f1771b4e7e8dbd1c6a6c5b725866a0ae4fce725", 16) - g2To84y, _ := new(big.Int).SetString("7a908974bce18cfe12a27bb2ad5a488cd7484a7787104870b27034f94eee31dd", 16) - g2To85x, _ := new(big.Int).SetString("eac134ca2046b8f9c8dbd304fad3f3c045ebfdb4ec6ed3cfe09aee43ed2ff3e", 16) - g2To85y, _ := new(big.Int).SetString("49630dbe79359b4245bf103bf2b11799ac19f696b7f21376e17206207d210988", 16) - g2To86x, _ := new(big.Int).SetString("d6788590731fea198392119d7adbb41ff5948a7804c85b17476706e4dfbfa4dc", 16) - g2To86y, _ := new(big.Int).SetString("28eaa8c89d5063c4940ef5c6d21c13aa6206f1c4ddc9a07cca7bcd6bbd3b5406", 16) - g2To87x, _ := new(big.Int).SetString("6930fccbd9a040974abf210f12b71d4bc7b1a6205599b01a7275fb40e48ff9b3", 16) - g2To87y, _ := new(big.Int).SetString("7f02ae94b94701eada30fcdb875f6d78090f9b13e4acc51acfddab5f8ee96a4e", 16) - g2To88x, _ := new(big.Int).SetString("213c7a715cd5d45358d0bbf9dc0ce02204b10bdde2a3f58540ad6908d0559754", 16) - g2To88y, _ := new(big.Int).SetString("4b6dad0b5ae462507013ad06245ba190bb4850f5f36a7eeddff2c27534b458f2", 16) - g2To89x, _ := new(big.Int).SetString("1c5e548132b49a7f66ae9fed8323480e0d1ab974622e7cf08993895e0ec87fac", 16) - g2To89y, _ := new(big.Int).SetString("4ffcf60f837f468f2bb959fa1d4c2ad3a3deaceb26fe324c555d7b3d5fc2d4ef", 16) - g2To90x, _ := new(big.Int).SetString("46276d0602c5668ddef6e94210bbc7ce1f901c19fed5c970e20fcba1d4531dbc", 16) - g2To90y, _ := new(big.Int).SetString("e0f7f24d44c75b84a292287570ded99498badfbffe1bc99af8730099686b8e2", 16) - g2To91x, _ := new(big.Int).SetString("efea68eca7a6c24f4e65eb211c3191636850e0acdc78d8996114ef13522f001d", 16) - g2To91y, _ := new(big.Int).SetString("aab847869d583c14da150307a3719a17e413959fb3848771c128419f73bc4415", 16) - g2To92x, _ := new(big.Int).SetString("4e7c272a7af4b34e8dbb9352a5419a87e2838c70adc62cddf0cc3a3b08fbd53c", 16) - g2To92y, _ := new(big.Int).SetString("17749c766c9d0b18e16fd09f6def681b530b9614bff7dd33e0b3941817dcaae6", 16) - g2To93x, _ := new(big.Int).SetString("899017b02696888f268a269f4e385d9c9b11f25a1bef8790e2821e6e7c6e1b4d", 16) - g2To93y, _ := new(big.Int).SetString("43ae2cdab5b334f0bb45798336358bfae4e51bc0f932b212009aebdad814ab2b", 16) - g2To94x, _ := new(big.Int).SetString("67f644f76e905fd4a8f4728e63227f0e2831f5bf91b583a8af2635a17e5f712f", 16) - g2To94y, _ := new(big.Int).SetString("b833d68f66445d04f05adeb7b586cf785e0e1488f7d36198d68acb5e707160e5", 16) - g2To95x, _ := new(big.Int).SetString("327f876c93652555fa80a054968b4712930dc93012ee6b8dc10263ed3b89a762", 16) - g2To95y, _ := new(big.Int).SetString("b2d404eab3524026b09969255e1997b975535070febd7dfe9c9fd959b9203301", 16) - g2To96x, _ := new(big.Int).SetString("fea74e3dbe778b1b10f238ad61686aa5c76e3db2be43057632427e2840fb27b6", 16) - g2To96y, _ := new(big.Int).SetString("6e0568db9b0b13297cf674deccb6af93126b596b973f7b77701d3db7f23cb96f", 16) - g2To97x, _ := new(big.Int).SetString("ed9441c8304280ff180e03d850e8cd0ebb570ee5de3730488fd97c961f9756e4", 16) - g2To97y, _ := new(big.Int).SetString("3dbe9e9efe8bfa19afa176128b13911e09f23774fe4de98bff0e09f93f3abfae", 16) - g2To98x, _ := new(big.Int).SetString("29d9698ee67a7c3fc9fed3f624b487515b10bdd84fab4d3015bad033d51cf119", 16) - g2To98y, _ := new(big.Int).SetString("7fd02c517dc82b45277a125404f1c96fb89c940e93a7c2963c88740575056339", 16) - g2To99x, _ := new(big.Int).SetString("126b57d05013936d6f3fb7bd33580a31fd453e4a86060cff467c44537f422491", 16) - g2To99y, _ := new(big.Int).SetString("c1a7dc13061662c2e3c4a3eba2bf3fb0e148bac30bf39347afa31f199da3ef84", 16) - g2To100x, _ := new(big.Int).SetString("76e64113f677cf0e10a2570d599968d31544e179b760432952c02a4417bdde39", 16) - g2To100y, _ := new(big.Int).SetString("c90ddf8dee4e95cf577066d70681f0d35e2a33d2b56d2032b4b1752d1901ac01", 16) - g2To101x, _ := new(big.Int).SetString("708a530e9e52c73bee87c9d88161c810005d57622c29ae691cf999a83a1187a5", 16) - g2To101y, _ := new(big.Int).SetString("9b884811e1f9a897fa9656dcbb6d38283ecda73c6d353e8a58a4f19b473db9c0", 16) - g2To102x, _ := new(big.Int).SetString("19cf034fc48b3be219bd648395e462cf9f374b6d86b2b59e2e1b16c6cde4f5be", 16) - g2To102y, _ := new(big.Int).SetString("28e32b06a15ab466c3b4be68ab181947ef91d1c93f0f1c0c0a91532b6f321af2", 16) - g2To103x, _ := new(big.Int).SetString("af6c44a078cb5f0d7c719c2f8397f576ee93bd034bea2219e3abc209d17cf3e8", 16) - g2To103y, _ := new(big.Int).SetString("784096fe85d4b30af9e73153cb246dfec362aea7ca0d435b8add0601751baea", 16) - g2To104x, _ := new(big.Int).SetString("c738c56b03b2abe1e8281baa743f8f9a8f7cc643df26cbee3ab150242bcbb891", 16) - g2To104y, _ := new(big.Int).SetString("893fb578951ad2537f718f2eacbfbbbb82314eef7880cfe917e735d9699a84c3", 16) - g2To105x, _ := new(big.Int).SetString("5578845ecd7c037435b32a6992e7aa94647197ea49b8c9e4ddaab0784662ab1b", 16) - g2To105y, _ := new(big.Int).SetString("e61d07978b6de2c3cea6d0a51d2a4053f653a7746a5d64de316d18f3056f3511", 16) - g2To106x, _ := new(big.Int).SetString("47f3383888a364cc4abfa3bc1d0ceccd22f12354fce3996094f869b8948b6c29", 16) - g2To106y, _ := new(big.Int).SetString("48ca9a8d0f032937190e48675b416c7118bb499588f994a81edee1120e537ef9", 16) - g2To107x, _ := new(big.Int).SetString("c0c01f34ae41b8cfe466b4c9c6a5d5f614f570d6fcbef768a81a6c8f05ff4adb", 16) - g2To107y, _ := new(big.Int).SetString("b84f5bee4357f5c7c937a0b4075b8cecdbc43d170d15b85fc4eff73ac351065", 16) - g2To108x, _ := new(big.Int).SetString("d895626548b65b81e264c7637c972877d1d72e5f3a925014372e9f6588f6c14b", 16) - g2To108y, _ := new(big.Int).SetString("febfaa38f2bc7eae728ec60818c340eb03428d632bb067e179363ed75d7d991f", 16) - g2To109x, _ := new(big.Int).SetString("fd136eef8971044e8a3a43622003a26703ecaf7a0ec40c3fba5b594b77078424", 16) - g2To109y, _ := new(big.Int).SetString("218da834f3c652cc67a1d191b5c5efa57cf2b1f78a2adfa8cd61eeefc671ddf1", 16) - g2To110x, _ := new(big.Int).SetString("d99e8e9dd9638d140e9cca5367519f861b7003a0d43f024a5f1d84ec8db1cb3c", 16) - g2To110y, _ := new(big.Int).SetString("36dc19ad1cc0a3a7a945bb321bceba6e6286fef8ffc8765cd88a29e36b8637a7", 16) - g2To111x, _ := new(big.Int).SetString("3fdf1619a198317a1bd8a54e5b09191d203351e0440e636fd46f68d3c385172", 16) - g2To111y, _ := new(big.Int).SetString("408d02c06e5c12c3fe470c7d3c8573755b9b929e90e7232b79ac67f0fccb9794", 16) - g2To112x, _ := new(big.Int).SetString("b8da94032a957518eb0f6433571e8761ceffc73693e84edd49150a564f676e03", 16) - g2To112y, _ := new(big.Int).SetString("2804dfa44805a1e4d7c99cc9762808b092cc584d95ff3b511488e4e74efdf6e7", 16) - g2To113x, _ := new(big.Int).SetString("6d36d105ed8cc5ce53f2cb698ab620f9469a3e5cb25bf6e6d413f414c5af726a", 16) - g2To113y, _ := new(big.Int).SetString("e4ba5c34e377669e72d8c66c95c50029dcc59936b4108a35c570491a13f9fc7d", 16) - g2To114x, _ := new(big.Int).SetString("3ab6bde10cd3ac0cd06883fa66f0b0e3eb1309c0534b812286e2a30ca540db99", 16) - g2To114y, _ := new(big.Int).SetString("baca62079be871d7fc3117a96a13e99c38d137b0e369c043e6873fe31bda78a3", 16) - g2To115x, _ := new(big.Int).SetString("796634e3f1ad56f0fdba069d9d07bce2ba2fd4f373ddd3ba7777bf279f1048da", 16) - g2To115y, _ := new(big.Int).SetString("4d8ee2b6cfb20b8956de74735a7927f2532576d8cfd74862e8f9be24a106cf01", 16) - g2To116x, _ := new(big.Int).SetString("e80fea14441fb33a7d8adab9475d7fab2019effb5156a792f1a11778e3c0df5d", 16) - g2To116y, _ := new(big.Int).SetString("eed1de7f638e00771e89768ca3ca94472d155e80af322ea9fcb4291b6ac9ec78", 16) - g2To117x, _ := new(big.Int).SetString("440ca1f08ea41265981ac4ed1efe7a37122dcc3877d2f9162db0e78b0f83cd58", 16) - g2To117y, _ := new(big.Int).SetString("a6c8b0d2cd5ee122af8954dc9d4e2f02a21e4d4269c0a260b07bc069b88a3f4b", 16) - g2To118x, _ := new(big.Int).SetString("f694cbaf2b966c1cc5f7f829d3a907819bc70ebcc1b229d9e81bda2712998b10", 16) - g2To118y, _ := new(big.Int).SetString("40a63eba61bef03d633c5ffacc46d82aeb6c64c3183c2a47f6788b1700f05e51", 16) - g2To119x, _ := new(big.Int).SetString("8b6e862a3556684850b6d4f439a2595047abf695c08b6414f95a13358dd553fd", 16) - g2To119y, _ := new(big.Int).SetString("ea5e08910ed11cb40d10bc2df4eb9fa124ac3c5a183383d0d803dad33e9be5ed", 16) - g2To120x, _ := new(big.Int).SetString("a301697bdfcd704313ba48e51d567543f2a182031efd6915ddc07bbcc4e16070", 16) - g2To120y, _ := new(big.Int).SetString("7370f91cfb67e4f5081809fa25d40f9b1735dbf7c0a11a130c0d1a041e177ea1", 16) - g2To121x, _ := new(big.Int).SetString("27e1e59cff79f049f3e8d2419e0bff74b43965004c34b5d811420316f24ba5ae", 16) - g2To121y, _ := new(big.Int).SetString("310b26a6c804e209ee1b5e3cfc79df05df48a1a69afa63f784a5bfee883a45b3", 16) - g2To122x, _ := new(big.Int).SetString("c712e7a5f6864aee16588ec3892d7e4f5a39adde84fbfb4f9969175c9caed7ae", 16) - g2To122y, _ := new(big.Int).SetString("49644107516363b365ed4b82311dd9e5380d8e544b0ce63784d148aa46156294", 16) - g2To123x, _ := new(big.Int).SetString("bfc0504a4b3235d065c0d426b8675fcb2c85d6f58275d791b43e1fe44a6db03", 16) - g2To123y, _ := new(big.Int).SetString("1955467a6c34f3453fb8ec7f94a6c99237427197345d4f0558ac8d1a464b8542", 16) - g2To124x, _ := new(big.Int).SetString("90ad85b389d6b936463f9d0512678de208cc330b11307fffab7ac63e3fb04ed4", 16) - g2To124y, _ := new(big.Int).SetString("e507a3620a38261affdcbd9427222b839aefabe1582894d991d4d48cb6ef150", 16) - g2To125x, _ := new(big.Int).SetString("7e2cd40ef8c94077f44b1d1548425e3d7e125be646707bad2818b0eda7dc0151", 16) - g2To125y, _ := new(big.Int).SetString("905b75082adcfab382a61a8b321ef95d889bee40aeee082c9a3bc53920721ec7", 16) - g2To126x, _ := new(big.Int).SetString("a146f52195bedace21c975bbd1ef52a79c636bf9db853cf90e103ae41345e597", 16) - g2To126y, _ := new(big.Int).SetString("a5a99b0ab053feb09ae95dd2dbb31b40ea67a5b221f094b07675676af45a770a", 16) - g2To127x, _ := new(big.Int).SetString("d24c75a1cf1993b9bcfbf9dab25a8114dbde421efeccc4e20cbb53fc4ce45444", 16) - g2To127y, _ := new(big.Int).SetString("58fe1d2de84dc1d1cfcb7d1810e5a78abf7593f499f1e524cb93246987dd4a57", 16) - g2To128x, _ := new(big.Int).SetString("8f68b9d2f63b5f339239c1ad981f162ee88c5678723ea3351b7b444c9ec4c0da", 16) - g2To128y, _ := new(big.Int).SetString("662a9f2dba063986de1d90c2b6be215dbbea2cfe95510bfdf23cbf79501fff82", 16) - g2To129x, _ := new(big.Int).SetString("4d49aefd784e8158fcafebe77fd9af59d89858ade7627eaee6847df84cf27076", 16) - g2To129y, _ := new(big.Int).SetString("cd32fc59a10dd135e723f210359ca6f06e0f2d1a7df4d8466b90b66203aa781e", 16) - g2To130x, _ := new(big.Int).SetString("7564539e85d56f8537d6619e1f5c5aa78d2a3de0889d1d4ee8dbcb5729b62026", 16) - g2To130y, _ := new(big.Int).SetString("c1d685413749b3c65231df524a722925684aacd954b79f334172c8fadace0cf3", 16) - g2To131x, _ := new(big.Int).SetString("210a917ad9df27796746ff301ad9ccc878f61a5f1ff4082b5364dacd57b4a278", 16) - g2To131y, _ := new(big.Int).SetString("670e1b5450b5e57b7a39be81f8d6737d3789e61aaff20bfc7f2713fd0c7b2231", 16) - g2To132x, _ := new(big.Int).SetString("e4f3fb0176af85d65ff99ff9198c36091f48e86503681e3e6686fd5053231e11", 16) - g2To132y, _ := new(big.Int).SetString("1e63633ad0ef4f1c1661a6d0ea02b7286cc7e74ec951d1c9822c38576feb73bc", 16) - g2To133x, _ := new(big.Int).SetString("4b30cbb7686773e01ec64110abdb362f88531a825ba172953bfee2233bcdaf2f", 16) - g2To133y, _ := new(big.Int).SetString("74c6350265bb629b6f9e2c5777c3c4a91fdf3c81e434857568033d463d26b5b7", 16) - g2To134x, _ := new(big.Int).SetString("cbb434aa7ae1700dcd15b20b17464817ec11715050e0fa192ffe9c29a673059f", 16) - g2To134y, _ := new(big.Int).SetString("4a1a200ab4dabd17562d492338b5dfad41d45e4f0ad5f845b7da9642227c070c", 16) - g2To135x, _ := new(big.Int).SetString("f478056d9c102c1cd06d7b1e7557244c6d9cdac5874610e94d4786e106de12c0", 16) - g2To135y, _ := new(big.Int).SetString("7f09e610f33e3946e68095e01068694c26c17ef609ab92d769a76ce6ca5361fe", 16) - g2To136x, _ := new(big.Int).SetString("8c00fa9b18ebf331eb961537a45a4266c7034f2f0d4e1d0716fb6eae20eae29e", 16) - g2To136y, _ := new(big.Int).SetString("efa47267fea521a1a9dc343a3736c974c2fadafa81e36c54e7d2a4c66702414b", 16) - g2To137x, _ := new(big.Int).SetString("24cfc0176da2b46fa8bb5bf9636be1effd7e297f29122fb3e84c9ab0c18ada5f", 16) - g2To137y, _ := new(big.Int).SetString("ebff8fbb079c61a69868714d5deda927ed959ca1a4f814f268fa6139978a586b", 16) - g2To138x, _ := new(big.Int).SetString("4a7d58d4b9bc82ea2ded72a1292ec616ddd67fc7f057edf103189594679da2", 16) - g2To138y, _ := new(big.Int).SetString("b98ac5b76702cb75e6b1d8147ec71b3b71c3b494963fa28a4877f484779ffe26", 16) - g2To139x, _ := new(big.Int).SetString("ee7d69c4cbd001c7fc76c5e2c066ce4996f8808a1e07b2a9ccf34eadc87c4b65", 16) - g2To139y, _ := new(big.Int).SetString("ecc8626ec1a413821a192abf030f2ee2c33e8999bae942e523e8f44ed136a95a", 16) - g2To140x, _ := new(big.Int).SetString("e7a26ce69dd4829f3e10cec0a9e98ed3143d084f308b92c0997fddfc60cb3e41", 16) - g2To140y, _ := new(big.Int).SetString("2a758e300fa7984b471b006a1aafbb18d0a6b2c0420e83e20e8a9421cf2cfd51", 16) - g2To141x, _ := new(big.Int).SetString("f5cafaba036bf8d00d38bfb6772089f5203c35e4d6e32fa9d97e5b917b4ae861", 16) - g2To141y, _ := new(big.Int).SetString("19e83b8a022a6d817bff9904640839159b3b2a9c552f05f3cc9c239c0d82239c", 16) - g2To142x, _ := new(big.Int).SetString("e9389024ceb63f1f12df5156d7e805428f9e509c494c982084fd4cd7bd2a9651", 16) - g2To142y, _ := new(big.Int).SetString("8648688723726595f9287abaf671aaf18d7110cec6770bfefefde2b75e786824", 16) - g2To143x, _ := new(big.Int).SetString("264559d87829256bed116900d82d0c379f0e4d1253c68e6fcf2d41ae7cddab8b", 16) - g2To143y, _ := new(big.Int).SetString("79e5bd1926d3512cef7bc637034072d77a8631af39caf1e6c9f64b45001de473", 16) - g2To144x, _ := new(big.Int).SetString("b6459e0ee3662ec8d23540c223bcbdc571cbcb967d79424f3cf29eb3de6b80ef", 16) - g2To144y, _ := new(big.Int).SetString("67c876d06f3e06de1dadf16e5661db3c4b3ae6d48e35b2ff30bf0b61a71ba45", 16) - g2To145x, _ := new(big.Int).SetString("e5d8e8f0d9823c88e4d36f7301f41593b6890576be79c211253ef375033eb51f", 16) - g2To145y, _ := new(big.Int).SetString("4dc1e9b7861e3e04abb16a57d8feeef0e509dc46d9f0f54979d5bd965a62a2d9", 16) - g2To146x, _ := new(big.Int).SetString("a9ca27f77dbc8c3dc56b0f7321bae0ddab66be4fa8a3011737a676480f155e64", 16) - g2To146y, _ := new(big.Int).SetString("f4bb335678fb14d4d197d2246c02d004875d41821bcaf0ae1f3f333c561b3297", 16) - g2To147x, _ := new(big.Int).SetString("68fb71800686d7f25eba105611cfe7591f478e847f51cee06d4bc629d6ee247c", 16) - g2To147y, _ := new(big.Int).SetString("cd12d23462dd963673735427501b0c079a8d580b04c73c9dae1f822d1a01865d", 16) - g2To148x, _ := new(big.Int).SetString("d68a80c8280bb840793234aa118f06231d6f1fc67e73c5a5deda0f5b496943e8", 16) - g2To148y, _ := new(big.Int).SetString("db8ba9fff4b586d00c4b1f9177b0e28b5b0e7b8f7845295a294c84266b133120", 16) - g2To149x, _ := new(big.Int).SetString("f16a409c677a40be402f8efb3752373caced053c6f702b828bda222ca412b6fd", 16) - g2To149y, _ := new(big.Int).SetString("2a41311714532799d7a6a75a74e30e4e16540659249ebca4268dae77eca052da", 16) - g2To150x, _ := new(big.Int).SetString("4154b506ab766f42fbe37f699976f84db89f4f2f6bed98325c1a0b6e326dd4e4", 16) - g2To150y, _ := new(big.Int).SetString("23ad075043c5988894c6e44d61025ff6414ea9d9d1e22dd46c859295075ded1c", 16) - g2To151x, _ := new(big.Int).SetString("b73c652769cc95c1080a8d4d0b5956ea93e86e49fc727ddf4c51a7a63f7f0246", 16) - g2To151y, _ := new(big.Int).SetString("9a67db107174ca9d4b535893c5b6c1ea1a0d72e4c6e554e5597e5164ea2a407b", 16) - g2To152x, _ := new(big.Int).SetString("324aed7df65c804252dc0270907a30b09612aeb973449cea4095980fc28d3d5d", 16) - g2To152y, _ := new(big.Int).SetString("648a365774b61f2ff130c0c35aec1f4f19213b0c7e332843967224af96ab7c84", 16) - g2To153x, _ := new(big.Int).SetString("32c9331ea26f490228d32681880d7203f72b3e4a8de0db1fa8f38381b2919749", 16) - g2To153y, _ := new(big.Int).SetString("d7cd272b34209cb5695a2f02b6f3dbb8268a4abdae39ab09631e97b0f290b5e3", 16) - g2To154x, _ := new(big.Int).SetString("eb292f3b3b9837854a02f6a70fec6b1c69c161b6e1846b8e1e1c22527b9795e4", 16) - g2To154y, _ := new(big.Int).SetString("8c43c25a96eebe801696634af145835b57131d7509111c6f5b7e9d2fae53a0fe", 16) - g2To155x, _ := new(big.Int).SetString("a65a3a01df3b5ef2e620d4310049fbe14d71457f19d1ed35aea39d5789303fdd", 16) - g2To155y, _ := new(big.Int).SetString("798ea0940cff5c6fb8f43d8d90ed2c7686861d024faed3cadad44a8d02e68703", 16) - g2To156x, _ := new(big.Int).SetString("4df9c14919cde61f6d51dfdbe5fee5dceec4143ba8d1ca888e8bd373fd054c96", 16) - g2To156y, _ := new(big.Int).SetString("35ec51092d8728050974c23a1d85d4b5d506cdc288490192ebac06cad10d5d", 16) - g2To157x, _ := new(big.Int).SetString("ed32cad8d2cc998cd25317d4e4b87088e9de4554e57a8d70c0c6b0fc1da49e04", 16) - g2To157y, _ := new(big.Int).SetString("129fef5f1d030204a541ca375859d20b52da9facb49fab7db63120d17c1db9e0", 16) - g2To158x, _ := new(big.Int).SetString("e821ab724d6360f18049e4111c70366e28c36dcb63c34016cb7418d4e883f855", 16) - g2To158y, _ := new(big.Int).SetString("adefcbf863f53ce367d0d4115416cf598b3b19c614ec23efed4e0c6a59852ddf", 16) - g2To159x, _ := new(big.Int).SetString("3f0d8994e51ad212f455452fbc9693a72f14a547af3806e9fbff59eeb441742e", 16) - g2To159y, _ := new(big.Int).SetString("fbd76c23f28c3dc445e5cb0e847a6e0b1e205e2c3ad13d958c65363bcfecadbe", 16) - g2To160x, _ := new(big.Int).SetString("9c3919a84a474870faed8a9c1cc66021523489054d7f0308cbfc99c8ac1f98cd", 16) - g2To160y, _ := new(big.Int).SetString("ddb84f0f4a4ddd57584f044bf260e641905326f76c64c8e6be7e5e03d4fc599d", 16) - g2To161x, _ := new(big.Int).SetString("2e3c05326255d80f0a42fc69d5c92aa40cd326a53e8535f0435efb7b694a09ec", 16) - g2To161y, _ := new(big.Int).SetString("1ff891656c6fb5bddae240b82fc1abe048a53c707b66512534868188c7327e", 16) - g2To162x, _ := new(big.Int).SetString("e8e2a24ccfa41587ae15fb7e3e24dda433710316a1908934205f19a2ab9c7ce6", 16) - g2To162y, _ := new(big.Int).SetString("46c983ce0c6f5d1b4caf2b2b3bee20596e09e603b5c27a73b2c01eb68836267c", 16) - g2To163x, _ := new(big.Int).SetString("a7549aac5d8573c2b2f0a38b170032a212acaf92383d5b5f5b0d39668ac7b3c2", 16) - g2To163y, _ := new(big.Int).SetString("bd17d1b90d1c2415335a1d70c1947d2b5d6b5115537116dffa0c91719287eaef", 16) - g2To164x, _ := new(big.Int).SetString("6057170b1dd12fdf8de05f281d8e06bb91e1493a8b91d4cc5a21382120a959e5", 16) - g2To164y, _ := new(big.Int).SetString("9a1af0b26a6a4807add9a2daf71df262465152bc3ee24c65e899be932385a2a8", 16) - g2To165x, _ := new(big.Int).SetString("6773fd677c52e0640394110a46dc85df7c133f8dd4a28e661899ca5d82fd545c", 16) - g2To165y, _ := new(big.Int).SetString("444eb6d8cd97652f0f0f25c9dd2b246bead780f5a1c6cf98e8c7f034947eb1ae", 16) - g2To166x, _ := new(big.Int).SetString("e0f86d94d17ce565237c79aace0c87c20374e43810468050373c616b0b86f021", 16) - g2To166y, _ := new(big.Int).SetString("c571c73730abcf47a91e832f1c89a2c9a80bcc0115fc45b3b6b79ccb5bf325a", 16) - g2To167x, _ := new(big.Int).SetString("42ca15ab9f245041ce991e193d696f4f4c277df908cad6038ad0772c02da6e03", 16) - g2To167y, _ := new(big.Int).SetString("68d2ef26c81c57c9647ce4d1fcb800eed66e85a68106bea7836889fa8c347793", 16) - g2To168x, _ := new(big.Int).SetString("a576df8e23a08411421439a4518da31880cef0fba7d4df12b1a6973eecb94266", 16) - g2To168y, _ := new(big.Int).SetString("40a6bf20e76640b2c92b97afe58cd82c432e10a7f514d9f3ee8be11ae1b28ec8", 16) - g2To169x, _ := new(big.Int).SetString("9e5dcc62ef3b5a3b546520867be71bae6f3ba063c9acfb8dcec5725bda704896", 16) - g2To169y, _ := new(big.Int).SetString("6fedd12ddb925f3ea5fd3a2154c7612279605d186030f51248f2769dca82c835", 16) - g2To170x, _ := new(big.Int).SetString("a7de08375b8745adf8d6e9f976f03b20e33625a05cef5833953ed58744bf7ea0", 16) - g2To170y, _ := new(big.Int).SetString("a63d96b057ada5e52104a0b334888e9a645a47c0febc5aa2e04c05539bbcabaa", 16) - g2To171x, _ := new(big.Int).SetString("c266658e689080c9c13c35ac01cff4cbe68065fde949e4a3a9f8fa104ad916fb", 16) - g2To171y, _ := new(big.Int).SetString("e7e8593854e7daab0f798170b24627ab6b8fecdfeb61138856aef52ba0887814", 16) - g2To172x, _ := new(big.Int).SetString("7778a78c28dec3e30a05fe9629de8c38bb30d1f5cf9a3a208f763889be58ad71", 16) - g2To172y, _ := new(big.Int).SetString("34626d9ab5a5b22ff7098e12f2ff580087b38411ff24ac563b513fc1fd9f43ac", 16) - g2To173x, _ := new(big.Int).SetString("e7b9796b5ca006d1632f482d7f0fe3932cf16a5ae104eea7a7ea1c251073e879", 16) - g2To173y, _ := new(big.Int).SetString("12b8988c19169e2fdf42102a737cc1ca9cb5bf25eda98af338e71089baa89d98", 16) - g2To174x, _ := new(big.Int).SetString("71bf01850876203c2c915a24be09a7365423daaf2aee919865d722bf2628f0f", 16) - g2To174y, _ := new(big.Int).SetString("527aa15d504dcf4ae33600bc1c084ce2098f9c6a231c80bbb57c5cbd45a1c334", 16) - g2To175x, _ := new(big.Int).SetString("218343acb9be56833a32e594c03c39e5b1911c8501213786f6376dfa39620e1", 16) - g2To175y, _ := new(big.Int).SetString("bea81d48970a50beaf3f24fd602fbfc0443299a42f43c9ec5e0199f6506998b5", 16) - g2To176x, _ := new(big.Int).SetString("928955ee637a84463729fd30e7afd2ed5f96274e5ad7e5cb09eda9c06d903ac", 16) - g2To176y, _ := new(big.Int).SetString("c25621003d3f42a827b78a13093a95eeac3d26efa8a8d83fc5180e935bcd091f", 16) - g2To177x, _ := new(big.Int).SetString("4f89bdee3771d350dad163b04cb18ad67ce5e9c55b58f0e7231047a60f59dd9e", 16) - g2To177y, _ := new(big.Int).SetString("ca7952d5227a1f695c4baf4c043bb2471e4882506638df5c1016ae320156b049", 16) - g2To178x, _ := new(big.Int).SetString("cb9e8304cae3c5a80c396baca2c3c4c994b668f079a245bf529c314cfff01197", 16) - g2To178y, _ := new(big.Int).SetString("62c7d2801eb80e6a127258cdff08891741b2d18c015e0a24c334e0763b989c1d", 16) - g2To179x, _ := new(big.Int).SetString("e2f349b0f89c69bd3c8cf2a410730dc58e0beed47048c58c15f9ffc2508d2cc2", 16) - g2To179y, _ := new(big.Int).SetString("1feb2f280f82723781860aec760215ba42344be8e09cbdb37e347bd8e0d4c04f", 16) - g2To180x, _ := new(big.Int).SetString("85d0fef3ec6db109399064f3a0e3b2855645b4a907ad354527aae75163d82751", 16) - g2To180y, _ := new(big.Int).SetString("1f03648413a38c0be29d496e582cf5663e8751e96877331582c237a24eb1f962", 16) - g2To181x, _ := new(big.Int).SetString("6b790f4b19a4c4f4f607a6cfcd11df0468b482e009711ff756356d141d5fcade", 16) - g2To181y, _ := new(big.Int).SetString("d03a981b2ff9eb3ef296661f9cae09cba83fa5b47be26b0ab6fff86fc338d3ff", 16) - g2To182x, _ := new(big.Int).SetString("41149b2c2d7ebed3c162c367acc4f8fe3d2479de85978be0bb0ccdabe3a3e0cb", 16) - g2To182y, _ := new(big.Int).SetString("c90d5b92db7c30542b415c9b9902cf28b3ec7805ef490f2470e92e98339033a8", 16) - g2To183x, _ := new(big.Int).SetString("d1fad4fa4e7c849dfaec3dfe2872a7ba664a9b8205c29cebf8dddd28e3f3d3fc", 16) - g2To183y, _ := new(big.Int).SetString("8fe19714a348fdfe5473f70e858b7818bad37131eff37326ed22343c50f3704d", 16) - g2To184x, _ := new(big.Int).SetString("ff2b0dce97eece97c1c9b6041798b85dfdfb6d8882da20308f5404824526087e", 16) - g2To184y, _ := new(big.Int).SetString("493d13fef524ba188af4c4dc54d07936c7b7ed6fb90e2ceb2c951e01f0c29907", 16) - g2To185x, _ := new(big.Int).SetString("2982dbbc5f366c9f78e29ebbecb1bb223deb5c4ee638b4583bd3a9af3149f8ef", 16) - g2To185y, _ := new(big.Int).SetString("a61b5be9af66220ab9fa5339c7b5bc9d095db99412e3ed8456e726b016c7a248", 16) - g2To186x, _ := new(big.Int).SetString("1a28e5042af0c0f6b436eb590497db5860011f4580e1765885289f612380441b", 16) - g2To186y, _ := new(big.Int).SetString("55779a7996c59dab7c78329a8976f0ed04b3e75b46ee67aeb05f606a8452af25", 16) - g2To187x, _ := new(big.Int).SetString("c8b83e9535f30601d250cc0bd3f20142edd5eb7985d83242eef0e39621e30a7", 16) - g2To187y, _ := new(big.Int).SetString("dcc7077065fdac7b850e3f17efdc854aacad237b987134dbebf7beb9ff688de", 16) - g2To188x, _ := new(big.Int).SetString("827fbbe4b1e880ea9ed2b2e6301b212b57f1ee148cd6dd28780e5e2cf856e241", 16) - g2To188y, _ := new(big.Int).SetString("c60f9c923c727b0b71bef2c67d1d12687ff7a63186903166d605b68baec293ec", 16) - g2To189x, _ := new(big.Int).SetString("b77f12a7dce56b973e2d7c8d576e6b3660470a9218b87461ef6e44b70cb1815d", 16) - g2To189y, _ := new(big.Int).SetString("4b6f85b14f86acc43f0cefb373cc2e654c42f0f91a44816d6ba3d2bc8e57dbc5", 16) - g2To190x, _ := new(big.Int).SetString("48973b943018bf1247b308b2cb79f956d858d8df4977c5970fe5dad2c45565ec", 16) - g2To190y, _ := new(big.Int).SetString("761f75684f3cdc1b6437bb3a01445af1511b3596580477b83b879075faed07e9", 16) - g2To191x, _ := new(big.Int).SetString("e931258e8eb5559c6d6972728a704c170b775a265b4527d4a4d4d742bbfd71fa", 16) - g2To191y, _ := new(big.Int).SetString("fb1e33364c3fdee0e85eb4169c954b40b3946ce1bb5e35f33d9bd0d3174d3307", 16) - g2To192x, _ := new(big.Int).SetString("eaa649f21f51bdbae7be4ae34ce6e5217a58fdce7f47f9aa7f3b58fa2120e2b3", 16) - g2To192y, _ := new(big.Int).SetString("be3279ed5bbbb03ac69a80f89879aa5a01a6b965f13f7e59d47a5305ba5ad93d", 16) - g2To193x, _ := new(big.Int).SetString("3adb9db3beb997eec2623ea5002279ea9e337b5c705f3db453dbc1cc1fc9b0a8", 16) - g2To193y, _ := new(big.Int).SetString("374e2d6daee74e713c774de07c095ff6aad9c8f9870266cc61ae7975f05bbdda", 16) - g2To194x, _ := new(big.Int).SetString("129e53ac428e9cbb7e10955e56c5fc69fefdff56963e7caf054e9e0c90ae86f9", 16) - g2To194y, _ := new(big.Int).SetString("415ecb958aee9a29b2da2115b712183fb2a232fd16b3e01b822efdcd1e89c85d", 16) - g2To195x, _ := new(big.Int).SetString("60144494c8f694485b85ecb6aee10956c756267d12894711922243d5e855b8da", 16) - g2To195y, _ := new(big.Int).SetString("8bb5d669f681e6469e8be1fd9132e65b543955c27e3f2a4bad500590f34e4bbd", 16) - g2To196x, _ := new(big.Int).SetString("e4a42d43c5cf169d9391df6decf42ee541b6d8f0c9a137401e23632dda34d24f", 16) - g2To196y, _ := new(big.Int).SetString("4d9f92e716d1c73526fc99ccfb8ad34ce886eedfa8d8e4f13a7f7131deba9414", 16) - g2To197x, _ := new(big.Int).SetString("fd6451fb84cfb18d3ef0acf856c4ef4d0553c562f7ae4d2a303f2ea33e8f62bb", 16) - g2To197y, _ := new(big.Int).SetString("e745ceb2b1871578b6fe7a5c1bc344ccfa2ab492d200e83fd0ad9086132c0911", 16) - g2To198x, _ := new(big.Int).SetString("1eee207cb24086bc716e81a06f9edbbb0042e2d5dcf3c7a1fa1d1fb9d5fe696b", 16) - g2To198y, _ := new(big.Int).SetString("652cbd19aef6269cd2b196d12461c95f7a02062e0afd694ebb45670e7429337b", 16) - g2To199x, _ := new(big.Int).SetString("cc0ea33ea8a9eb14d465ab2c346e2111e1c0fc017c57257908d40f19ef94c0d5", 16) - g2To199y, _ := new(big.Int).SetString("f9907a3b711c8a2fb23dd203b5fbe663f6074f266113f543deabe597af452fe6", 16) - g2To200x, _ := new(big.Int).SetString("1ec80fef360cbdd954160fadab352b6b92b53576a88fea4947173b9d4300bf19", 16) - g2To200y, _ := new(big.Int).SetString("aeefe93756b5340d2f3a4958a7abbf5e0146e77f6295a07b671cdc1cc107cefd", 16) - g2To201x, _ := new(big.Int).SetString("5be7ea3519f04bc6cbeeaa0344fc90bb8e8462f6ebd890560dae805d414ff9e4", 16) - g2To201y, _ := new(big.Int).SetString("32f32ec3f638e605477f890f655ab7fe0e99c6302119a3094030b07847e0bdbb", 16) - g2To202x, _ := new(big.Int).SetString("58f099116eae4e650813fc8698df7f5cd50028649f853991e3fb545f4ddb7bb8", 16) - g2To202y, _ := new(big.Int).SetString("7e07002aaffe111a0d62ff7614638066507ee4062d174302bdec73582e5b2d6e", 16) - g2To203x, _ := new(big.Int).SetString("b0f9e4b9b29790b633bcc04fd860cb0f823d8d1a4cc1a1c1413c1606cc9a8e2c", 16) - g2To203y, _ := new(big.Int).SetString("49e82bf1843ade6d41cbb0b906fde3f03350cc02c171cee76c2066c4df3d0db4", 16) - g2To204x, _ := new(big.Int).SetString("146a778c04670c2f91b00af4680dfa8bce3490717d58ba889ddb5928366642be", 16) - g2To204y, _ := new(big.Int).SetString("b318e0ec3354028add669827f9d4b2870aaa971d2f7e5ed1d0b297483d83efd0", 16) - g2To205x, _ := new(big.Int).SetString("574ef0ce8a597e24e5670b5c0bcd14cfeefc983c7ecb261911b2365579de5cac", 16) - g2To205y, _ := new(big.Int).SetString("9b99930281f19c73bd6ada0569b78451a260a7bef10008cae59aea6c75a4805", 16) - g2To206x, _ := new(big.Int).SetString("d3d97e799d8bf9f85d909397b98c835d10a770c1aeff8645808c2d74260966d3", 16) - g2To206y, _ := new(big.Int).SetString("8ddbb46376bac95e6aaa89275d403ad3b5e48711be8dc4eebddeb850833c2e52", 16) - g2To207x, _ := new(big.Int).SetString("b1aa653288b318987b974e782cbbee0ab2be78cf8f494c120040fb93968c6d4b", 16) - g2To207y, _ := new(big.Int).SetString("7ed6071c60810d712684aa8e2d63a83b100a1d909d623cc383d9e62ae891ac51", 16) - g2To208x, _ := new(big.Int).SetString("fa50c0f61d22e5f07e3acebb1aa07b128d0012209a28b9776d76a8793180eef9", 16) - g2To208y, _ := new(big.Int).SetString("6b84c6922397eba9b72cd2872281a68a5e683293a57a213b38cd8d7d3f4f2811", 16) - g2To209x, _ := new(big.Int).SetString("63964eee619074e0780140fe02e90836e72328d2448386d459c5be23187f5048", 16) - g2To209y, _ := new(big.Int).SetString("3b6cfb3a6b89cf41a39ff9b1c34bfbc93d580b934dde6c84383a284d89309df8", 16) - g2To210x, _ := new(big.Int).SetString("5a3ce25b4d15b7e22d1469ddf0fc9f75afd7f12ad3cbda31f814ba1ebadb2a65", 16) - g2To210y, _ := new(big.Int).SetString("8b34125b92e05f63873a6dbfbf3f99af3ee28bc3d825fe8ed8b170cf1d327f1d", 16) - g2To211x, _ := new(big.Int).SetString("5ce605af98f93eda6910be34f0de41ff85dbcb6e69a8fa0016a733754a9f44d0", 16) - g2To211y, _ := new(big.Int).SetString("4cddcf9bec226bfe7ba56bd031c76c58ab3cb1bfa32eccc6c0d05f3489d30105", 16) - g2To212x, _ := new(big.Int).SetString("da1d61d0ca721a11b1a5bf6b7d88e8421a288ab5d5bba5220e53d32b5f067ec2", 16) - g2To212y, _ := new(big.Int).SetString("8157f55a7c99306c79c0766161c91e2966a73899d279b48a655fba0f1ad836f1", 16) - g2To213x, _ := new(big.Int).SetString("9c7be00b4ef4c444df85d5f61dc1283a23605483e1f8e934b3c210d22cd3c369", 16) - g2To213y, _ := new(big.Int).SetString("9220c0de74b20d2052a26d455ce401483e31153a16769cbd29ee3feba2329515", 16) - g2To214x, _ := new(big.Int).SetString("fcd83f42825263bb55664b238ccc49174dd06a70541178e76bcd92d7bb8c9e3", 16) - g2To214y, _ := new(big.Int).SetString("6c0bc1cfeac5fbced1d8232de5fdb683adbeaecdf1627bf4e86d55fbdf4aa9ad", 16) - g2To215x, _ := new(big.Int).SetString("7175407f1b58f010d4cda4c62511e59db7edcf28f5476d995cf39944b26b64f1", 16) - g2To215y, _ := new(big.Int).SetString("43b4554344e3d550f36d3401134cc86eb01fe8b774471d2a426e7efab24234d5", 16) - g2To216x, _ := new(big.Int).SetString("a8e282ff0c9706907215ff98e8fd416615311de0446f1e062a73b0610d064e13", 16) - g2To216y, _ := new(big.Int).SetString("7f97355b8db81c09abfb7f3c5b2515888b679a3e50dd6bd6cef7c73111f4cc0c", 16) - g2To217x, _ := new(big.Int).SetString("cac6f2e7e27faecbcb876f805ea66e63efbe9eaa753d67c1c15eb9ea7f7653a1", 16) - g2To217y, _ := new(big.Int).SetString("f7d416e5e2aa6f194cdb65d9a42a345081e83ae5688103a068c10ad0fec5e556", 16) - g2To218x, _ := new(big.Int).SetString("e6dfde46ee37d206efbc5932e58e43254ab767294238cb11cc9f4ab08624003d", 16) - g2To218y, _ := new(big.Int).SetString("8727b3b7be9139498f2f48f7b88f92203b1ce5ea527fd7dd7548650e2216b93b", 16) - g2To219x, _ := new(big.Int).SetString("3c4e089cd9a6823d66a40cfc7ac96082e250e3149cf211d3b0e1103548dce109", 16) - g2To219y, _ := new(big.Int).SetString("43fbbe669fe191b480757bca15764d379579e142d97fe697e2bf65923a19aeea", 16) - g2To220x, _ := new(big.Int).SetString("174a53b9c9a285872d39e56e6913cab15d59b1fa512508c022f382de8319497c", 16) - g2To220y, _ := new(big.Int).SetString("ccc9dc37abfc9c1657b4155f2c47f9e6646b3a1d8cb9854383da13ac079afa73", 16) - g2To221x, _ := new(big.Int).SetString("20e6e2e796946bb630c7071ef1b92ea3d53d280e0e4501115f5da36f840dd273", 16) - g2To221y, _ := new(big.Int).SetString("d3ad7afe4f1559e44a0ba1ad97874655811ec9793da8693cc07cfd15bb46b593", 16) - g2To222x, _ := new(big.Int).SetString("8e0ca824d7a351dba80280a07e71db7035ae68136cc24ca3e7b54f301a077674", 16) - g2To222y, _ := new(big.Int).SetString("4ec560759192d41dc569d24da62cf57cff60419d2f910290b84cbec12b7ed98", 16) - g2To223x, _ := new(big.Int).SetString("f7bb50da51c982d1c5fa63553e3d66c1afdb5821a321b4afe96afc5ea8192441", 16) - g2To223y, _ := new(big.Int).SetString("93cc3be30334a526311bc63bdde6485db1cfdc1fbbc4c74bbc640ea1d45165ae", 16) - g2To224x, _ := new(big.Int).SetString("959396981943785c3d3e57edf5018cdbe039e730e4918b3d884fdff09475b7ba", 16) - g2To224y, _ := new(big.Int).SetString("2e7e552888c331dd8ba0386a4b9cd6849c653f64c8709385e9b8abf87524f2fd", 16) - g2To225x, _ := new(big.Int).SetString("cbee1405ff0da7deafe32ca7dd73d95ed702226b391747c707275a940bc8f53b", 16) - g2To225y, _ := new(big.Int).SetString("f6211f4f4e75f902b51f3e689b8294cf0d9ff4f68126f7282922e6b278c87f45", 16) - g2To226x, _ := new(big.Int).SetString("add5bad28faaf5acdd580bfa0ba252e03de3beaefbd71b9cf377c88b14b311dd", 16) - g2To226y, _ := new(big.Int).SetString("e9c43cf4da3dc3a5974e434f8359814f52d4e1e7669b9b8902f982f349d6c38d", 16) - g2To227x, _ := new(big.Int).SetString("53f2432ba81717143fa9df3dff41ced24a29b314bc5a8c96f5f6400a0d7c0979", 16) - g2To227y, _ := new(big.Int).SetString("bd52effbc1f079b7ccd4e3e0911b07de4bd5a4f5c9e8b845f9f7e90c537b36a2", 16) - g2To228x, _ := new(big.Int).SetString("d2a63a50ae401e56d645a1153b109a8fcca0a43d561fba2dbb51340c9d82b151", 16) - g2To228y, _ := new(big.Int).SetString("e82d86fb6443fcb7565aee58b2948220a70f750af484ca52d4142174dcf89405", 16) - g2To229x, _ := new(big.Int).SetString("baf183a76100525e23bc7202033725f922b9cd6b36c413497c6c4bacca72da5f", 16) - g2To229y, _ := new(big.Int).SetString("deac9fbe9ccb4d335688bd58dd69b1d18e2336c5ca739361377ce628a8f2a0cf", 16) - g2To230x, _ := new(big.Int).SetString("f7aef8a7e38440238f9332906e48f6fd5adbd02d56b76a5ffa5aca58c56c3943", 16) - g2To230y, _ := new(big.Int).SetString("4e3b0b44d5ffda797c442bbdc3ab3fcfeec30184a8dcd003431f627facf442f1", 16) - g2To231x, _ := new(big.Int).SetString("dfb547cb10019036c5a2e29f0dddbb1f7af2fa25a3c7a78c1fac945711924459", 16) - g2To231y, _ := new(big.Int).SetString("9accd2a9ba0f47088b8389ce9dc864cc22af0930e5c031dcfa205e0dcc65fd9e", 16) - g2To232x, _ := new(big.Int).SetString("64587e2335471eb890ee7896d7cfdc866bacbdbd3839317b3436f9b45617e073", 16) - g2To232y, _ := new(big.Int).SetString("d99fcdd5bf6902e2ae96dd6447c299a185b90a39133aeab358299e5e9faf6589", 16) - g2To233x, _ := new(big.Int).SetString("b866d6b142df940f2cf28b54c92f0c1294e0b6a22a91f2ef44bcd88c4384480d", 16) - g2To233y, _ := new(big.Int).SetString("1914b0b3426aeb7089a278d7ea9ad7ac24e522804b1d86d60e659b470c4cafa8", 16) - g2To234x, _ := new(big.Int).SetString("ec2bb89085de819ec4d9d1646102ba87e2d52ae4ed4fe455d229cda81db20d6c", 16) - g2To234y, _ := new(big.Int).SetString("ccecc17661e013a1332f66f0650940c633a2364be87efa98a0e99c4d629cf4a0", 16) - g2To235x, _ := new(big.Int).SetString("71c4a7e389e296ced39d75ef5e545905e50050640f50becf38a60ecb23b09d0f", 16) - g2To235y, _ := new(big.Int).SetString("1313fadb737af3ba0af3e0a292f810aa786f2b084a62ffc7637b1f01720ddb62", 16) - g2To236x, _ := new(big.Int).SetString("8481bde0e4e4d885b3a546d3e549de042f0aa6cea250e7fd358d6c86dd45e458", 16) - g2To236y, _ := new(big.Int).SetString("38ee7b8cba5404dd84a25bf39cecb2ca900a79c42b262e556d64b1b59779057e", 16) - g2To237x, _ := new(big.Int).SetString("9629a450bd383a8b9fd43c6cd1d492bf392ed605299561dde54433526ce9f114", 16) - g2To237y, _ := new(big.Int).SetString("bf439b280c5fb6d7576befd220cef64db925593e5c56af8dca3972c4a24aa391", 16) - g2To238x, _ := new(big.Int).SetString("b73b1c47ef1e4688eb1730da7cc893df1477d747e187e18383d38d9626ca6cc3", 16) - g2To238y, _ := new(big.Int).SetString("584315cb294922a90a57d64bbcc805097322a25209757f5afac35d76a54fdba3", 16) - g2To239x, _ := new(big.Int).SetString("edfe16b2db40180311f9892007a2fef7d05b2a3bb676899f9c6e2192d38f93e0", 16) - g2To239y, _ := new(big.Int).SetString("ee6902f1fca5db3694d74faa4b05d0d25b3d5100c46e227e3d01793de29405ad", 16) - g2To240x, _ := new(big.Int).SetString("13464a57a78102aa62b6979ae817f4637ffcfed3c4b1ce30bcd6303f6caf666b", 16) - g2To240y, _ := new(big.Int).SetString("69be159004614580ef7e433453ccb0ca48f300a81d0942e13f495a907f6ecc27", 16) - g2To241x, _ := new(big.Int).SetString("eb3cf8f532245362ec05c88c85fe12d19182be7dceabe577c75849c6065084ae", 16) - g2To241y, _ := new(big.Int).SetString("c833c78222d9d70043fe63dcefdca4a1f52b45c5e7dbd2a66f67c1fff96b9480", 16) - g2To242x, _ := new(big.Int).SetString("bdf1a67d092d99974f7a60f2184519b2a576fcf984a201d9f8e5bcbcc2e9a5d0", 16) - g2To242y, _ := new(big.Int).SetString("4095902bab65a1aaa80be54a86bf7baaa6280b61e5626461cdb4f7018562ff7b", 16) - g2To243x, _ := new(big.Int).SetString("68856a6eddc4ec29cd5be267b64483b48c3b4196477da62abde5fc173b27e771", 16) - g2To243y, _ := new(big.Int).SetString("77a33df14f79a1fb13b6fd49c19f7b4a331d22f293b0733a6118d62a07bbdab6", 16) - g2To244x, _ := new(big.Int).SetString("bc4a9df5b713fe2e9aef430bcc1dc97a0cd9ccede2f28588cada3a0d2d83f366", 16) - g2To244y, _ := new(big.Int).SetString("d3a81ca6e785c06383937adf4b798caa6e8a9fbfa547b16d758d666581f33c1", 16) - g2To245x, _ := new(big.Int).SetString("da433d5e11ceccc0abc5c7626ce7bab42e89b221f785c409282de545f3fceb19", 16) - g2To245y, _ := new(big.Int).SetString("e498dbd321a810301debbdc4af95e5218e77fc2d9227b277684e7120a6f5cc64", 16) - g2To246x, _ := new(big.Int).SetString("31e8e1ee9e8c7ec1c1c116981c16efdbcc4838a72207e0654de275c5acf692a", 16) - g2To246y, _ := new(big.Int).SetString("ad7e7f5b465b353dd9d0970290d6743b70649827c5bf73b09cc2a84eb16f667a", 16) - g2To247x, _ := new(big.Int).SetString("a9878607a88d61155d3e00d862657f73e9c9bf363fc7a91592bbd7ff81f488b6", 16) - g2To247y, _ := new(big.Int).SetString("d181a1abd58895d61c063e7c82157c2239d0f01964ad5c6d495a7bbb031dab1d", 16) - g2To248x, _ := new(big.Int).SetString("8c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa", 16) - g2To248y, _ := new(big.Int).SetString("40a30463a3305193378fedf31f7cc0eb7ae784f0451cb9459e71dc73cbef9482", 16) - g2To249x, _ := new(big.Int).SetString("ab1ac1872a38a2f196bed5a6047f0da2c8130fe8de49fc4d5dfb201f7611d8e2", 16) - g2To249y, _ := new(big.Int).SetString("13f4a37a324d17a1e9aa5f39db6a42b6f7ef93d33e1e545f01a581f3c429d15b", 16) - g2To250x, _ := new(big.Int).SetString("2564fe9b5beef82d3703a607253f31ef8ea1b365772df434226aee642651b3fa", 16) - g2To250y, _ := new(big.Int).SetString("8ad9f7a60678389095fa14ae1203925f14f37dab6b79816edb82e6a301e5122d", 16) - g2To251x, _ := new(big.Int).SetString("ff3d6136ffac5b0cbfc6c5c0c30dc01a7ea3d56c20bd3103b178e3d3ae180068", 16) - g2To251y, _ := new(big.Int).SetString("133239be84e4000e40d0372cdd96adc1547676f24001f5e670a6bb6e188c6077", 16) - g2To252x, _ := new(big.Int).SetString("8ea9666139527a8c1dd94ce4f071fd23c8b350c5a4bb33748c4ba111faccae0", 16) - g2To252y, _ := new(big.Int).SetString("620efabbc8ee2782e24e7c0cfb95c5d735b783be9cf0f8e955af34a30e62b945", 16) - g2To253x, _ := new(big.Int).SetString("c25f637176220cd9f3a66df315559d8263cf2a23a4ab5ab9a293131da190b632", 16) - g2To253y, _ := new(big.Int).SetString("53154fede94d2873989049903809d7980a9f04ff9e027a1d6eebf3d6fc9590cf", 16) - g2To254x, _ := new(big.Int).SetString("2a9e8dfe3cce6bab3e82d82a5688544c0c7b55dc31978b4de2ccb3b7d466d561", 16) - g2To254y, _ := new(big.Int).SetString("1dfeda5c16e651fbac7b5ad608b96cf5e01eaec17a02182f96ccf5252e76373", 16) - g2To255x, _ := new(big.Int).SetString("b23790a42be63e1b251ad6c94fdef07271ec0aada31db6c3e8bd32043f8be384", 16) - g2To255y, _ := new(big.Int).SetString("fc6b694919d55edbe8d50f88aa81f94517f004f4149ecb58d10a473deb19880e", 16) return CurveParams{ - A: big.NewInt(0), - B: big.NewInt(7), - Gx: gx, - Gy: gy, - Gmx: [256]*big.Int{g3x, g5x, g7x, g2To3x, g2To4x, g2To5x, g2To6x, g2To7x, g2To8x, g2To9x, g2To10x, g2To11x, g2To12x, g2To13x, g2To14x, g2To15x, g2To16x, g2To17x, g2To18x, g2To19x, g2To20x, g2To21x, g2To22x, g2To23x, g2To24x, g2To25x, g2To26x, g2To27x, g2To28x, g2To29x, g2To30x, g2To31x, g2To32x, g2To33x, g2To34x, g2To35x, g2To36x, g2To37x, g2To38x, g2To39x, g2To40x, g2To41x, g2To42x, g2To43x, g2To44x, g2To45x, g2To46x, g2To47x, g2To48x, g2To49x, g2To50x, g2To51x, g2To52x, g2To53x, g2To54x, g2To55x, g2To56x, g2To57x, g2To58x, g2To59x, g2To60x, g2To61x, g2To62x, g2To63x, g2To64x, g2To65x, g2To66x, g2To67x, g2To68x, g2To69x, g2To70x, g2To71x, g2To72x, g2To73x, g2To74x, g2To75x, g2To76x, g2To77x, g2To78x, g2To79x, g2To80x, g2To81x, g2To82x, g2To83x, g2To84x, g2To85x, g2To86x, g2To87x, g2To88x, g2To89x, g2To90x, g2To91x, g2To92x, g2To93x, g2To94x, g2To95x, g2To96x, g2To97x, g2To98x, g2To99x, g2To100x, g2To101x, g2To102x, g2To103x, g2To104x, g2To105x, g2To106x, g2To107x, g2To108x, g2To109x, g2To110x, g2To111x, g2To112x, g2To113x, g2To114x, g2To115x, g2To116x, g2To117x, g2To118x, g2To119x, g2To120x, g2To121x, g2To122x, g2To123x, g2To124x, g2To125x, g2To126x, g2To127x, g2To128x, g2To129x, g2To130x, g2To131x, g2To132x, g2To133x, g2To134x, g2To135x, g2To136x, g2To137x, g2To138x, g2To139x, g2To140x, g2To141x, g2To142x, g2To143x, g2To144x, g2To145x, g2To146x, g2To147x, g2To148x, g2To149x, g2To150x, g2To151x, g2To152x, g2To153x, g2To154x, g2To155x, g2To156x, g2To157x, g2To158x, g2To159x, g2To160x, g2To161x, g2To162x, g2To163x, g2To164x, g2To165x, g2To166x, g2To167x, g2To168x, g2To169x, g2To170x, g2To171x, g2To172x, g2To173x, g2To174x, g2To175x, g2To176x, g2To177x, g2To178x, g2To179x, g2To180x, g2To181x, g2To182x, g2To183x, g2To184x, g2To185x, g2To186x, g2To187x, g2To188x, g2To189x, g2To190x, g2To191x, g2To192x, g2To193x, g2To194x, g2To195x, g2To196x, g2To197x, g2To198x, g2To199x, g2To200x, g2To201x, g2To202x, g2To203x, g2To204x, g2To205x, g2To206x, g2To207x, g2To208x, g2To209x, g2To210x, g2To211x, g2To212x, g2To213x, g2To214x, g2To215x, g2To216x, g2To217x, g2To218x, g2To219x, g2To220x, g2To221x, g2To222x, g2To223x, g2To224x, g2To225x, g2To226x, g2To227x, g2To228x, g2To229x, g2To230x, g2To231x, g2To232x, g2To233x, g2To234x, g2To235x, g2To236x, g2To237x, g2To238x, g2To239x, g2To240x, g2To241x, g2To242x, g2To243x, g2To244x, g2To245x, g2To246x, g2To247x, g2To248x, g2To249x, g2To250x, g2To251x, g2To252x, g2To253x, g2To254x, g2To255x}, - Gmy: [256]*big.Int{g3y, g5y, g7y, g2To3y, g2To4y, g2To5y, g2To6y, g2To7y, g2To8y, g2To9y, g2To10y, g2To11y, g2To12y, g2To13y, g2To14y, g2To15y, g2To16y, g2To17y, g2To18y, g2To19y, g2To20y, g2To21y, g2To22y, g2To23y, g2To24y, g2To25y, g2To26y, g2To27y, g2To28y, g2To29y, g2To30y, g2To31y, g2To32y, g2To33y, g2To34y, g2To35y, g2To36y, g2To37y, g2To38y, g2To39y, g2To40y, g2To41y, g2To42y, g2To43y, g2To44y, g2To45y, g2To46y, g2To47y, g2To48y, g2To49y, g2To50y, g2To51y, g2To52y, g2To53y, g2To54y, g2To55y, g2To56y, g2To57y, g2To58y, g2To59y, g2To60y, g2To61y, g2To62y, g2To63y, g2To64y, g2To65y, g2To66y, g2To67y, g2To68y, g2To69y, g2To70y, g2To71y, g2To72y, g2To73y, g2To74y, g2To75y, g2To76y, g2To77y, g2To78y, g2To79y, g2To80y, g2To81y, g2To82y, g2To83y, g2To84y, g2To85y, g2To86y, g2To87y, g2To88y, g2To89y, g2To90y, g2To91y, g2To92y, g2To93y, g2To94y, g2To95y, g2To96y, g2To97y, g2To98y, g2To99y, g2To100y, g2To101y, g2To102y, g2To103y, g2To104y, g2To105y, g2To106y, g2To107y, g2To108y, g2To109y, g2To110y, g2To111y, g2To112y, g2To113y, g2To114y, g2To115y, g2To116y, g2To117y, g2To118y, g2To119y, g2To120y, g2To121y, g2To122y, g2To123y, g2To124y, g2To125y, g2To126y, g2To127y, g2To128y, g2To129y, g2To130y, g2To131y, g2To132y, g2To133y, g2To134y, g2To135y, g2To136y, g2To137y, g2To138y, g2To139y, g2To140y, g2To141y, g2To142y, g2To143y, g2To144y, g2To145y, g2To146y, g2To147y, g2To148y, g2To149y, g2To150y, g2To151y, g2To152y, g2To153y, g2To154y, g2To155y, g2To156y, g2To157y, g2To158y, g2To159y, g2To160y, g2To161y, g2To162y, g2To163y, g2To164y, g2To165y, g2To166y, g2To167y, g2To168y, g2To169y, g2To170y, g2To171y, g2To172y, g2To173y, g2To174y, g2To175y, g2To176y, g2To177y, g2To178y, g2To179y, g2To180y, g2To181y, g2To182y, g2To183y, g2To184y, g2To185y, g2To186y, g2To187y, g2To188y, g2To189y, g2To190y, g2To191y, g2To192y, g2To193y, g2To194y, g2To195y, g2To196y, g2To197y, g2To198y, g2To199y, g2To200y, g2To201y, g2To202y, g2To203y, g2To204y, g2To205y, g2To206y, g2To207y, g2To208y, g2To209y, g2To210y, g2To211y, g2To212y, g2To213y, g2To214y, g2To215y, g2To216y, g2To217y, g2To218y, g2To219y, g2To220y, g2To221y, g2To222y, g2To223y, g2To224y, g2To225y, g2To226y, g2To227y, g2To228y, g2To229y, g2To230y, g2To231y, g2To232y, g2To233y, g2To234y, g2To235y, g2To236y, g2To237y, g2To238y, g2To239y, g2To240y, g2To241y, g2To242y, g2To243y, g2To244y, g2To245y, g2To246y, g2To247y, g2To248y, g2To249y, g2To250y, g2To251y, g2To252y, g2To253y, g2To254y, g2To255y}, + A: big.NewInt(0), + B: big.NewInt(7), + Gx: gx, + Gy: gy, + Gm: computeSecp256k1Table(), } } @@ -555,527 +41,13 @@ func GetSecp256k1Params() CurveParams { func GetBN254Params() CurveParams { gx := big.NewInt(1) gy := big.NewInt(2) - g3x, _ := new(big.Int).SetString("769bf9ac56bea3ff40232bcb1b6bd159315d84715b8e679f2d355961915abf0", 16) - g3y, _ := new(big.Int).SetString("2ab799bee0489429554fdb7c8d086475319e63b40b9c5b57cdf1ff3dd9fe2261", 16) - g5x, _ := new(big.Int).SetString("17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa9", 16) - g5y, _ := new(big.Int).SetString("1e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c", 16) - g7x, _ := new(big.Int).SetString("17072b2ed3bb8d759a5325f477629386cb6fc6ecb801bd76983a6b86abffe078", 16) - g7y, _ := new(big.Int).SetString("168ada6cd130dd52017bb54bfa19377aadfe3bf05d18f41b77809f7f60d4af9e", 16) - g2To3x, _ := new(big.Int).SetString("8b1d51d23480c10f472f5e93b9cfea88238c121fe155af7043937882c306a63", 16) - g2To3y, _ := new(big.Int).SetString("299836713dad3fa34e337aa412466015c366af8ec50b9d7bd05aa74642822021", 16) - g2To4x, _ := new(big.Int).SetString("17f485337f6e10fca0e385f7a93d1ac0a977e43995c3e4d9b8f89daa6a183f44", 16) - g2To4y, _ := new(big.Int).SetString("5ccdc1561db963516da62c66edd39d1bb9c6c4674990c4440403c88025c95ad", 16) - g2To5x, _ := new(big.Int).SetString("ac610b573e9fb98deaf5aa48feb447536418ddc4cefd17c277c852a2a02a413", 16) - g2To5y, _ := new(big.Int).SetString("1940e395f5eeaaf3b73a54a9db9910c3b7f907cad7f55137fb0c3847a682d315", 16) - g2To6x, _ := new(big.Int).SetString("6b7c24035a06c42bcb47d54df4104cd8880f68263afce13250ecc65f7669d1e", 16) - g2To6y, _ := new(big.Int).SetString("2179e38c6e6341d1c80b4ed2ad6d43188c01c2f70a8093b37fc02f9fd9e5f12f", 16) - g2To7x, _ := new(big.Int).SetString("2295215c9285bdc4f6beefdeccc5ccb67bbb9959f05f4c2a716a8f442fa69498", 16) - g2To7y, _ := new(big.Int).SetString("10174283cbb851eaf5f64a278b0fe58fb9b3b0b6a31439012ebe8d731bcdf851", 16) - g2To8x, _ := new(big.Int).SetString("2b9cd0bae01dfefdb859f3fbacbc897d6174d717103bf3b64dc43276541a2034", 16) - g2To8y, _ := new(big.Int).SetString("13b64ed1d986a508cbe5b28ca1429210b9c1aff6fb358af406159ff2773181ce", 16) - g2To9x, _ := new(big.Int).SetString("b0543208dea7cf4a213340ea328fe41297a9adae0d846bdba6a63682164520e", 16) - g2To9y, _ := new(big.Int).SetString("11fc9d481c85491a1c76370c03abb451edaad8d165909fd8bcef0b0523ea1598", 16) - g2To10x, _ := new(big.Int).SetString("24236c8ead13686698f502d88ced24d4a4f4d97d857f7a404dab22a7d7010281", 16) - g2To10y, _ := new(big.Int).SetString("14f25da82adf5997cd262a35f883666cd8fb73558e864094f04cafd100d70121", 16) - g2To11x, _ := new(big.Int).SetString("42075949fd411801cdb82e636cbaeba5913ee29901d9294e4ec8016fed7de8d", 16) - g2To11y, _ := new(big.Int).SetString("18cd5594fbf0daec1813cbbe6752ec1fc46f951b26c19031466364b772f37f47", 16) - g2To12x, _ := new(big.Int).SetString("1e55ddfd2bc59eed77164fe02d0232b3d497792ec225376f3c3f5ec2f731fcf9", 16) - g2To12y, _ := new(big.Int).SetString("24b3e64690c93b37546abdc4ee90b916e2d3605eb218cf26ef5868d2b666072b", 16) - g2To13x, _ := new(big.Int).SetString("133b598ecf07b15b4badc0af8b67d74f574a29c1ef79a426fe1271e235e61e00", 16) - g2To13y, _ := new(big.Int).SetString("65bab42b71a49a87ea2b1e39d69612daf58372130af040f503b71b689ac9b8d", 16) - g2To14x, _ := new(big.Int).SetString("15dab2550a7d9679f0a528cde54154b2d9ebd399a16691e13f3f28b17f72f7d6", 16) - g2To14y, _ := new(big.Int).SetString("178ce9329c1a5914a6561c281c981810a1554be17533bf6e7ce5a03e18f67889", 16) - g2To15x, _ := new(big.Int).SetString("145bc328b9b296659851f12d70e35a9ca48cbde2af8a8ad8c9f2b3e0dff32306", 16) - g2To15y, _ := new(big.Int).SetString("29556d2e78ac6045e5dd6d555ec184c802c9e0599a8d5173103841caaf829633", 16) - g2To16x, _ := new(big.Int).SetString("26e06be6332f9f22b10167247f35f7805a11658a38dbb75d480af28117a525c5", 16) - g2To16y, _ := new(big.Int).SetString("5e492d706a927c51e6180228d8be86d15017d61160867d231101e2790e2f451", 16) - g2To17x, _ := new(big.Int).SetString("173562ccf10ecd0d4fa859860fda7fbd91089fa60e69dc72fafdd35516ea77af", 16) - g2To17y, _ := new(big.Int).SetString("2ecf52567da025409374e147a7e63641b341b7b0e90104d86688d1c244890fce", 16) - g2To18x, _ := new(big.Int).SetString("1f2434b943605601a75d294aba1bf13f0ff5db8d7e0a3500b5f4c1bc41e786dc", 16) - g2To18y, _ := new(big.Int).SetString("262db6caeadc85809eec6eaec5a25cf46cc7c753a1e28313321fcdbaab1c38", 16) - g2To19x, _ := new(big.Int).SetString("3762e07278ae0306a4c00f906f8f2e4d59373bfe860160c0fd9c5e77c46be52", 16) - g2To19y, _ := new(big.Int).SetString("25537898872f823d23934c27f897ad4f40773d14b4fd32bc0cde718aa9cb87b9", 16) - g2To20x, _ := new(big.Int).SetString("2cbfb0fe6c22c116187ef88cab54ae9612bca6cc0738379098e3f0c4a4ffe44d", 16) - g2To20y, _ := new(big.Int).SetString("18e367e3d08db17ce4fa3e487e6268c2ba168da6b239a84bf2ea8f2ff0f4c469", 16) - g2To21x, _ := new(big.Int).SetString("55c8d5787694c618d99a4a31e6b68173176fd3ee152aa0bc009e99279a9b348", 16) - g2To21y, _ := new(big.Int).SetString("cb17a49107a9cfbe06478a33ba7e48e279bb9904ee0d6681cc72edea5b984e9", 16) - g2To22x, _ := new(big.Int).SetString("1f4465d62aac0c486d54b87e00f9ea1454aea3f1b0807c471fc172383b0886c8", 16) - g2To22y, _ := new(big.Int).SetString("2fee931883b4bf0d0d2e303bc10317533e6c974d3d884f9315f8d78840e1363c", 16) - g2To23x, _ := new(big.Int).SetString("127b3ab3ee067a5c41553648568b7882ce8ced215bfa190979668b3bc81eb1fc", 16) - g2To23y, _ := new(big.Int).SetString("5e5a09c5ae9de4c0492a8033cf035672a55797cadfc1e6860aab21c32a78112", 16) - g2To24x, _ := new(big.Int).SetString("35b261363afc5e03923315a3dfdfbc2c932d94bc19320f3ab411a203df4b44f", 16) - g2To24y, _ := new(big.Int).SetString("57df51fa44deb6f13412a77fd4325aceec98dfe6036cf74c71a5675f7fe1342", 16) - g2To25x, _ := new(big.Int).SetString("154aceb2bad07cdc9e1e0239e75f74d2b63a297881f9adcb166edb88fe076f4c", 16) - g2To25y, _ := new(big.Int).SetString("2f7568bf2fa097d86b7858e8701480e26d6d42fc819858b2137a427ee5b9a1da", 16) - g2To26x, _ := new(big.Int).SetString("9a6e5836835dd5677aa892580f15382da285a1b1379a67fd54d21664fe5681d", 16) - g2To26y, _ := new(big.Int).SetString("29f5850d45dfc5f3126fd0da3ea2c23ae965655112b9c2771cf2e73a2861ac5d", 16) - g2To27x, _ := new(big.Int).SetString("2566879ca48921f6fe14df4d20d2f9e24024c9d438b131bc30b06efc35dee0f9", 16) - g2To27y, _ := new(big.Int).SetString("2ddf0f6cd3e69d0a018bb01bf69ede7299a90eb9e40ee68dc50fc1b57f42011f", 16) - g2To28x, _ := new(big.Int).SetString("8c4de3bb9284981741584663ff2b08ad9fea7b6fd7f867f558d768cab6683f0", 16) - g2To28y, _ := new(big.Int).SetString("f9c2bd3727428ed114cd7860e28daf81cb9cb7dcdd26bb704dcc13b4314dd6a", 16) - g2To29x, _ := new(big.Int).SetString("a9cfe416626f75b3be8249cbcb7f3732bc7601cf581f774ebea4254dd06a31e", 16) - g2To29y, _ := new(big.Int).SetString("2f37ade304c81412d4ae613bf6d46db48b794a815bffc4413fc4872fd3e54e15", 16) - g2To30x, _ := new(big.Int).SetString("258872f55cb9b9d5085401f6dfd3ae97c4adf21c3f5a391ee055fbbd9dc4754e", 16) - g2To30y, _ := new(big.Int).SetString("537cfe016384089d64f027080a6061dc147732e6cd9c5bc1818d20ccf9958cc", 16) - g2To31x, _ := new(big.Int).SetString("1e46ffd3559b30f6d101a2b49be6d213a9c40979ce8cb6b3c30ac308259bb5f4", 16) - g2To31y, _ := new(big.Int).SetString("8c2c33416234b10c20e4b8bf0a1c1af83b964df68eda56adf0dae561518f704", 16) - g2To32x, _ := new(big.Int).SetString("8d1b64842bc402bf13683a6c6f35b5c3d20bc295b2b29547889abb503000938", 16) - g2To32y, _ := new(big.Int).SetString("8dd9da05595bb2f247f8254c0b5c522610ef4ff6de3397d6a35c2cd57d5ff0a", 16) - g2To33x, _ := new(big.Int).SetString("17ce741466bfe6b7ddd079fc1b829fc11c670ae647603cc16f07ec4ee9907076", 16) - g2To33y, _ := new(big.Int).SetString("135c40e7ae971f4f02715e9eacfb0edd48544329e207dcd9e09e3a1d6a7ef9d3", 16) - g2To34x, _ := new(big.Int).SetString("2560de7ec1fce358673f10c20b44ad547058e357b6abcad273e4de32f8901926", 16) - g2To34y, _ := new(big.Int).SetString("1ce0ed3c1313830bbf40fe0d7843c66dc5a67680004df9bac115c39ad61a6434", 16) - g2To35x, _ := new(big.Int).SetString("1d0ab19190a9eea7211606a352bc936d6605a190090ac0843a8beedb54bfcd60", 16) - g2To35y, _ := new(big.Int).SetString("11013587e7511d4a0d9511b142867820cea6cb9c3d7a8db3ac3230521bfdbb98", 16) - g2To36x, _ := new(big.Int).SetString("ce765d04f6147d2ec7fd6b47a674fe19734ba8732f9f5b2201fced57eac06d1", 16) - g2To36y, _ := new(big.Int).SetString("17e32bc3032ce94020638e7d2ab3cb5ccbe6f0b06faf6821fa8e3e4401a5c5f3", 16) - g2To37x, _ := new(big.Int).SetString("f4dc779722c9006a9c18edb82b48827e1620600ec0d8bf5ea38a9aff00b2fad", 16) - g2To37y, _ := new(big.Int).SetString("85e58b989c3118da095b0e96fe2b07080d4a7a2c1e68b00de0a673d6ba338c1", 16) - g2To38x, _ := new(big.Int).SetString("2732bbe06b941c9e2d5b43837d8c5d9c23b7d9e8d5e623427ff3b61f2f5a5a07", 16) - g2To38y, _ := new(big.Int).SetString("2b591b8a3c2bfe17bd639fc6a77244aa8629abe4bee101a444e4f24f36f1cef4", 16) - g2To39x, _ := new(big.Int).SetString("27e2e192f061b31a05a77bf2ef3197550a6a3d87137f94166ead6c6bc962dd79", 16) - g2To39y, _ := new(big.Int).SetString("2d6ed80f66dcba2fa0170b308717dd966f6f290acbf61affd81681234c8c2c06", 16) - g2To40x, _ := new(big.Int).SetString("2b74bc4a2f94e7ee3305368999840142e80348e9464caef350c14219abe982ba", 16) - g2To40y, _ := new(big.Int).SetString("28ece478e5bef9a805431237214101dd7e42d6619d13344fb5f38cfca35be682", 16) - g2To41x, _ := new(big.Int).SetString("22c175e3c8487841f7e95a1448695383526f6b54fa1bd5dc08abc316e31e3517", 16) - g2To41y, _ := new(big.Int).SetString("149630c26a8011eff9ef41663b42cb704da419e23b884b7b24414a6561bff9ab", 16) - g2To42x, _ := new(big.Int).SetString("1b05155447aaa6fa1ea292a769950cfdbf195dabb8101a25902b5da432322076", 16) - g2To42y, _ := new(big.Int).SetString("10575afe16844a09fe4b002623c91f29e52bdebbe29e235f2090c39a930e8c2c", 16) - g2To43x, _ := new(big.Int).SetString("2a8577ed48db5ac9e9fa8dfa247f27b3e60d89f1827647685799666c97f1a833", 16) - g2To43y, _ := new(big.Int).SetString("902486bd83fd098aa054ffc4cb97ab085cc2f16ac36046994cc30a023107b1d", 16) - g2To44x, _ := new(big.Int).SetString("1d9a6be49fb8d2ac15dc3d5c94e14a1503ab0b3ca6a21cad875d6b1a79faa9ae", 16) - g2To44y, _ := new(big.Int).SetString("28026c4fe5e3beecfefcfc52d868ec17888e6b9e926ecfebea979f4da743e98c", 16) - g2To45x, _ := new(big.Int).SetString("732fab1b46a9d2f5d4e4c0ae76b33d747b97fd120d5a48b403368c0ca59e3e0", 16) - g2To45y, _ := new(big.Int).SetString("10ee4d49117fc0c55faee5550615ab0e2020d1cffe21a9138b45be3861386f7", 16) - g2To46x, _ := new(big.Int).SetString("1781ee986bd68597bf4d4d208c4288599de61e144c3bdc0400d099816411cd05", 16) - g2To46y, _ := new(big.Int).SetString("2ab3082b4ee85457502bfd2c20b89df4181ecd32aba9f00d68a92d8f081c1846", 16) - g2To47x, _ := new(big.Int).SetString("2ef769820679d51c8ad33309549d630a069c2e0bedd5f6408bc7932f8bd47fc8", 16) - g2To47y, _ := new(big.Int).SetString("6abd56e6a2300623d6945f2f2e965836e0ea9518549579ae5626fbee7a98b01", 16) - g2To48x, _ := new(big.Int).SetString("c56565b409d0661559f47150adb952432a186ba0c316d0360db359b32b7b05a", 16) - g2To48y, _ := new(big.Int).SetString("1d312504121f5a89e8abc692156492ab42ade35fbeef59b84a720513f9407f51", 16) - g2To49x, _ := new(big.Int).SetString("2bd2e4fcc5e329ac6859e2bed1443604639c50181b461499a1ff41d65948615e", 16) - g2To49y, _ := new(big.Int).SetString("c6b0aaf39ab436c4d8245cce97c862198c92af61bcfa8e260b78f8b3125609f", 16) - g2To50x, _ := new(big.Int).SetString("111e14c693b4e2f022cd64a6fb0a9a2c30a43eb830af2d536d47d65e31621b35", 16) - g2To50y, _ := new(big.Int).SetString("2556301d79a6b88a9ee4e0c6c7cbf32c998de755f5229cae477b9ae2a688f6ea", 16) - g2To51x, _ := new(big.Int).SetString("61d62988ebd3a3a643e088f5a5117b03e3342eb44aeade5be5e769c8ec5471c", 16) - g2To51y, _ := new(big.Int).SetString("fd8ed00f9e0d1a9b4ce715d06e3a592a38e60e80bc6102764a208f72bab79cb", 16) - g2To52x, _ := new(big.Int).SetString("2bcb97abadf5cc9ebb2146867d6f7451db29fba33dfe8a34ab680dead115e00a", 16) - g2To52y, _ := new(big.Int).SetString("8cf030bdc7a851154cdcd01609d064c93b03ad7808e8f306ab488261db73320", 16) - g2To53x, _ := new(big.Int).SetString("1d174577a9c53cefd85d6bbbdcb5b8f292a884b26f0ea403dd10db43ed6f9a8b", 16) - g2To53y, _ := new(big.Int).SetString("7bb9915573ee3bf341981f4905a2d96167e228b90c8d9dd430530574cf75899", 16) - g2To54x, _ := new(big.Int).SetString("591f4466b7a4ba962d097beaecdb6bd8d17cbea3bd5fb9cc8e166322755869f", 16) - g2To54y, _ := new(big.Int).SetString("1b1808e9fc843a9efe02f7493cecb95c608c316d4ed98f194003ca292a8bbe89", 16) - g2To55x, _ := new(big.Int).SetString("33a47533babbe960c581d996a10c697efeecfcd62b36b6124f5d3c793348962", 16) - g2To55y, _ := new(big.Int).SetString("2f7a4ff5aaa8a0e2cfca3a1401601a52b80aa7cba4991b380f429d26d940924a", 16) - g2To56x, _ := new(big.Int).SetString("1425b11b4fe47a394dbfc0ad3e99dc93c3e1c0980b9bcb68529ba9de33dbf585", 16) - g2To56y, _ := new(big.Int).SetString("168b8cdff7ae7d084fd111608fa03e018b415fd4f0755f7e8f039a2d852bda0e", 16) - g2To57x, _ := new(big.Int).SetString("1281e1b4ae3aa4404c0181f688fecb6c0c4449ee646c0438702eab87f4b7dd1", 16) - g2To57y, _ := new(big.Int).SetString("18d37f7e79d7dfdd82187cc71e706ebe6353499493e23fb8ae536e47db8ce60a", 16) - g2To58x, _ := new(big.Int).SetString("3fd1c6811aba796990bec7a6e1c93456bc73bd41b090d6be589826e49b1ae21", 16) - g2To58y, _ := new(big.Int).SetString("269f5d44435fd8dea26779b7f46c23b4bed44fa1d9863c9880f010959bb4aa88", 16) - g2To59x, _ := new(big.Int).SetString("ec6fc4a5b4e315512f882a012443a460f0ad440410931b3d2f16125b5e08b17", 16) - g2To59y, _ := new(big.Int).SetString("13d2044189630abd18c6a3d7dad67c97b771597be79693a5de68da0ffa2676d3", 16) - g2To60x, _ := new(big.Int).SetString("1fd5ddc117799eac4054d556ea4dd922ae145542d5524a29a0cad3ec7ec810e8", 16) - g2To60y, _ := new(big.Int).SetString("27bb413910ef0b9339d3262cde13e189d0b2e64f0c073fc81da5747676ca645e", 16) - g2To61x, _ := new(big.Int).SetString("2d1b7db11118809263c79240df010a2415abafca8d4248788158bfd6f2141969", 16) - g2To61y, _ := new(big.Int).SetString("75158f7b9c5890a51d5b46a86e6e3f04f20dc8cafca5e5c3772eb508e2390f1", 16) - g2To62x, _ := new(big.Int).SetString("2dd2737976a05341def306c8899cf11d24b52f3230f36b6cdbba3fb971cfde1", 16) - g2To62y, _ := new(big.Int).SetString("1a15e9c72c124e695b6fe0c535bc1c0265ec884cf74b53de358de6d5c956ed73", 16) - g2To63x, _ := new(big.Int).SetString("1df18f1f725582b96a446cd7fb021d67a357626fbc37e35599ed2d117359d294", 16) - g2To63y, _ := new(big.Int).SetString("2110263f391b92233267e75ec5641be7385da935a46f8cccd0698a584c70848a", 16) - g2To64x, _ := new(big.Int).SetString("457cafda1576b6f5fea6125056e6d52c4b01de7b44ae5aae162e83c9fe86928", 16) - g2To64y, _ := new(big.Int).SetString("16471c8dad2cb3ea4c4645d8b108abfb95fdb1c87485a1d78a3d158e529aaabc", 16) - g2To65x, _ := new(big.Int).SetString("a431193edb58abf0df45b4bbd6cfc43bf2e39093ec0fd195f3120344b3ac3a0", 16) - g2To65y, _ := new(big.Int).SetString("b1261fe08f29cc99a084cda6e12f384e7a11f3fa0f75dfcd21005d951fdfc2b", 16) - g2To66x, _ := new(big.Int).SetString("1542e37f2c64d816c9dde4cdfeff540680cc90b767294ba9937a0de230676b4b", 16) - g2To66y, _ := new(big.Int).SetString("1717efcb51f08cccdbfe3e4a2da92e000a45a3e3d9eb40f9b9a2041dcbf14d3a", 16) - g2To67x, _ := new(big.Int).SetString("f39f1ee90eb802366254bf2555173a1bd988e09f8c5ad7bebfdb8d14d88b064", 16) - g2To67y, _ := new(big.Int).SetString("2cbbd9234ab4f9fd74defb1512b86385b038ea5ae995449b813235e047876986", 16) - g2To68x, _ := new(big.Int).SetString("250a8a1b9edcecc5f25879262ef2962fdf8499f60e8131c6c33320fd8c98ed15", 16) - g2To68y, _ := new(big.Int).SetString("1924e2b0b5e2c49449c5ef9b62c2d01207e012a0bc70b219ab44f026ce7e43b8", 16) - g2To69x, _ := new(big.Int).SetString("239aee62596123c53859dc2937ea9257e52034311bb81519b7f45330c5c883da", 16) - g2To69y, _ := new(big.Int).SetString("151f09f672db228c74304a2f68f65a7b586f93913b97b6d7dfd638b99571b7f3", 16) - g2To70x, _ := new(big.Int).SetString("1ec491fbe90a222adec9c417cd9c39393bf0e9fd4618f8688f20b587e10a92ec", 16) - g2To70y, _ := new(big.Int).SetString("2ad8de9952064d982be63f71a172dfddc4daf430bb5c7a0c0d3a53ff776b8474", 16) - g2To71x, _ := new(big.Int).SetString("2e5001cee2faa644502bbba6bf6b07e3b7cef0392326b48f300fc56f6982026e", 16) - g2To71y, _ := new(big.Int).SetString("180e823c991af5044dde58a9e671fa092d3ba5db98cc7e0376dd079323f80764", 16) - g2To72x, _ := new(big.Int).SetString("2715e750e68b52faa68b293da254e1b0049b5825804f4c2700adf08a0214e529", 16) - g2To72y, _ := new(big.Int).SetString("3921d1862445f32fb5afe510e7c4e23f41e4bad15c090b1de77447950003fc9", 16) - g2To73x, _ := new(big.Int).SetString("b4ae2be8e83c897e6d3aa46f67058f07e0d29edbe4eb1b6c1e325c737af51f7", 16) - g2To73y, _ := new(big.Int).SetString("cea4f5b9bc8e843c26cd4e67da727fe9cd09ca8e07b60410602c63c3b0baee6", 16) - g2To74x, _ := new(big.Int).SetString("252b5bf255b06eade647646139359221099916d1be9aa6a7edc3f7c9c6b3baa3", 16) - g2To74y, _ := new(big.Int).SetString("12f7f9b3871cd66f99e976138eedc4faaec30a67ce3c67d867999ce814f7644d", 16) - g2To75x, _ := new(big.Int).SetString("1977739937a75442ba424943233bb2ba55f9d4c62148285873a658581d5114ff", 16) - g2To75y, _ := new(big.Int).SetString("178ee53b5e50cc2078544a9cbd11841c47854fe604388a5defeac56ce805bfe6", 16) - g2To76x, _ := new(big.Int).SetString("e6581bf922d94d7079fa4b753f3ecedc525f516643a6bc894c5ab191fbf676b", 16) - g2To76y, _ := new(big.Int).SetString("160642bdf146cc3f6630cfa5c115629055ab653c0e7f2414391f22b25d6720f6", 16) - g2To77x, _ := new(big.Int).SetString("d4da3f9398685005d391d7c328ec8dc2ecab18c7d451901725375b1c373d860", 16) - g2To77y, _ := new(big.Int).SetString("1609e3ec29efd4abf1629be26b772ef4b8490bcedfae621851e413e84c513135", 16) - g2To78x, _ := new(big.Int).SetString("3a781e0964591a816d07c8d6aa23d23b2ad50ae3acc529f877abf4d13e3f35e", 16) - g2To78y, _ := new(big.Int).SetString("20a1f12ea58910335687316cf47761991bad8f11e109095279c05e14b370c876", 16) - g2To79x, _ := new(big.Int).SetString("2db5bda50b8b265684bb6e9c7af58513e9aa23abd3fa2a3cfc88dd057f90bef", 16) - g2To79y, _ := new(big.Int).SetString("103c36bd9eb69b53205b7fae6224bb36b5a50451261cf87128953b489594b6d8", 16) - g2To80x, _ := new(big.Int).SetString("513dfdf79ca36c0d5e56de067033a42d9e13ce86f261d9081a2dddbdb88127c", 16) - g2To80y, _ := new(big.Int).SetString("2902f0ba36cac9e8a907ae91f2486316258b0b9b3b2c5262ab965004167bfa0", 16) - g2To81x, _ := new(big.Int).SetString("bd86fa4e2f2da10f54c62d2f996d7813d6548785f88386b0286ba719dc973a", 16) - g2To81y, _ := new(big.Int).SetString("2495aed3ff4e37c6d20a260f9847fe15d2bb5c2b788454bbb6e450effafa8bea", 16) - g2To82x, _ := new(big.Int).SetString("18f64e4337ef0a3732be36ca6cf72393b821fe4914ec78b311ca3a343ce7b15c", 16) - g2To82y, _ := new(big.Int).SetString("21c0913ede0f09b5920b629b891a95a30aed5dd6001eda274649363d1877da", 16) - g2To83x, _ := new(big.Int).SetString("46cc874785e387f35fbc3278c63a7d66e89f4642ab9056ec3d0b8d26eb21ec4", 16) - g2To83y, _ := new(big.Int).SetString("1b759ad99b33626516327fbebf9c232e0fca6555b084ee311f62366d7d5f86b7", 16) - g2To84x, _ := new(big.Int).SetString("64fcc679f04e762d783f5b39e9bc9832d06a6809d8c101a216431f1dc792cfd", 16) - g2To84y, _ := new(big.Int).SetString("216690982d703eb77e4ea5a7dd74c7c00fb98033d17ec825ca4950f6c40aeb80", 16) - g2To85x, _ := new(big.Int).SetString("148b2e63d2d3d87f364f35c47d7cf6c006506cf224aac6f208c559a2ed58d834", 16) - g2To85y, _ := new(big.Int).SetString("2727c32af57debc90f6fc9eb1607f72e8180068d6d12c02c38498ddf0a998506", 16) - g2To86x, _ := new(big.Int).SetString("213b9a87905003543236ff3eb6b232083378cd7a9eed91eb78f2c60fa85a3ad2", 16) - g2To86y, _ := new(big.Int).SetString("28e04e92b62096e8d23915d545982855c21be5b3a1193e6e34c43db01192453b", 16) - g2To87x, _ := new(big.Int).SetString("2a4825bea894ae814c1678bbff2fe7c99cd63a77a0c703b2825a5f19b2d98fad", 16) - g2To87y, _ := new(big.Int).SetString("2a127b6261bc7a4f6e76e082d980d0af0bd0f5e0fd9cdb342bf9bbb7694a929d", 16) - g2To88x, _ := new(big.Int).SetString("2257c2e4b41831dd8d36aaca1ab106c26c796f1c8e0a2998431f9d4125d740eb", 16) - g2To88y, _ := new(big.Int).SetString("7b7ed1edbb583f469367ae24bf8e49c1ff6731dfff4abf92e163e595187203c", 16) - g2To89x, _ := new(big.Int).SetString("a8d78ab8a1fb7388787eeca33f3fe251ae93f28ac1fef89dae84057b55436ff", 16) - g2To89y, _ := new(big.Int).SetString("1aef7bd255bab9ae1a74c2b7cb61cb0c22f8c6c0a7da5d9d4753779f9fc3d456", 16) - g2To90x, _ := new(big.Int).SetString("1bca13199961ec30b02a2e464afef42ab60ef11b26573e11e22a1028afacd288", 16) - g2To90y, _ := new(big.Int).SetString("ad9ff00a04b9cbebcd54d75a6db4c6042799d29bf0e0d0fae7438c89233850c", 16) - g2To91x, _ := new(big.Int).SetString("6236320cf783a01e2b8be7816a84671de9e8bebda0e8f957809ee1253565bae", 16) - g2To91y, _ := new(big.Int).SetString("a4ce1ac405b9974e4eaf9342c2a43bd1fdc4edc2bd18235249bf51ec4328744", 16) - g2To92x, _ := new(big.Int).SetString("107a0928f1bbd09f3710ba91ea9d69152e2a2de8eb21984ec9caddb69ab37a8a", 16) - g2To92y, _ := new(big.Int).SetString("28c0d2c1d2b4dd590537fa55a7838a2bbd7aa7f2c0e91b36927b731752c34192", 16) - g2To93x, _ := new(big.Int).SetString("4c02961cf949cd155f736fdc4c29e4fe409c37994aef1b16cd170cc65b1b2ee", 16) - g2To93y, _ := new(big.Int).SetString("a92da6a165896cdb685afb42e80bec10097bc2083bc938550706fc5bc355795", 16) - g2To94x, _ := new(big.Int).SetString("165aabcf0d07544d16f06389ef1d3bd5ae9c4bdbb0f53065b64bc53346c75897", 16) - g2To94y, _ := new(big.Int).SetString("9dbc96d154f3fb8324230033265a8d5a31c9b88b5104ca5f56c714ac2e6a534", 16) - g2To95x, _ := new(big.Int).SetString("1bafc8265a8fb16e346e57060848c3ae00b0e2d8520ff8d287cd002705c4c1ab", 16) - g2To95y, _ := new(big.Int).SetString("3a87183d670bf95439912a7fce6570c957a4d5ecaa722ed50e7d7c55dc55d0a", 16) - g2To96x, _ := new(big.Int).SetString("1b5b281facfe95fb1144e0f7d0484d119ebe0dca0355e63ec70e5f94cd64e3e9", 16) - g2To96y, _ := new(big.Int).SetString("10e9c2dfd3e452f067fc71c60a08200402f8f4e5e8dad63e462ba1597a20c615", 16) - g2To97x, _ := new(big.Int).SetString("18dd61a6d1a9c55b35d048ffb667e7f05ee657481bdb86800e89aa48df541143", 16) - g2To97y, _ := new(big.Int).SetString("147653157294e50892424edb123ca14f08ae7da80350b6ffdf582aa7a939e371", 16) - g2To98x, _ := new(big.Int).SetString("24fe3fb77d48ea49e4c1b91c61b634dbd9525b20167226b19d7c603ac36c3d4c", 16) - g2To98y, _ := new(big.Int).SetString("2a4768c15d9b9c746e253eb271b28afab89da5412565d93c6220a5b14cfba611", 16) - g2To99x, _ := new(big.Int).SetString("119ba66c94aeb05b2309953c35df696ce195bf7d959770bb9b99ab944db0af91", 16) - g2To99y, _ := new(big.Int).SetString("29c96c201b71f6540f084e2fb6d4eb8a52b940c0c5585f258aba521311b805d1", 16) - g2To100x, _ := new(big.Int).SetString("15856673ff5b68543c671cbe735d53376dcfea3eef0ec5fb3a1ae3c37f5683bc", 16) - g2To100y, _ := new(big.Int).SetString("12224ed590244e93f1c6b7abff01b64dac0bb8bf14ae8e3d825322b6623d082", 16) - g2To101x, _ := new(big.Int).SetString("253ea43ba2e8c14da0df002c96422fb3234310a5774d8ec6cc9c1796df1789ff", 16) - g2To101y, _ := new(big.Int).SetString("234267257e751a5fcebb1e295b774700fcc16b5f270ac8720f4376dbc18281b3", 16) - g2To102x, _ := new(big.Int).SetString("2825afe1d583957680db4456ece011c28a7a5e2021a69a1bdb69707d944268e4", 16) - g2To102y, _ := new(big.Int).SetString("2870101fe628a0d69a362a7f52d4f57093aceffa7aea51a4544c3033109a05f9", 16) - g2To103x, _ := new(big.Int).SetString("f29f472f3b04c24a5ed6675f5ff33720a10826fe53cef56b2c9313b2bd31523", 16) - g2To103y, _ := new(big.Int).SetString("2483c78fb7a925e79bf63bb20e9198e12b41429b23fe8e2ce29f91f1112159be", 16) - g2To104x, _ := new(big.Int).SetString("28b2e5fdc60e4fa83c1fb52db348434f08b850cc205f98431deea3e8fe209ad8", 16) - g2To104y, _ := new(big.Int).SetString("fe1ae72d3f07fef610c96a45cadf362c41f3f902b7b81a735b2a98333f54f47", 16) - g2To105x, _ := new(big.Int).SetString("2267c8d0582c04e9568e83bb9155fd9fac11d9c0672455f63fc14112297855da", 16) - g2To105y, _ := new(big.Int).SetString("1a13b6e83105beb7164721a03aa0635d2214c68c0ce68c5737ff618f02f62bcc", 16) - g2To106x, _ := new(big.Int).SetString("2a3e86af529fb07cadac27f9eb5683abbdacac22e8e55a4b96c61249cb3ce975", 16) - g2To106y, _ := new(big.Int).SetString("1eea66c26412cd33e47d7745aa76f7251efdd09bf220e09889675d9896bd1772", 16) - g2To107x, _ := new(big.Int).SetString("c5111956406a1ce31b50a0d90fdca236871c353e3f75250304b08cef557b588", 16) - g2To107y, _ := new(big.Int).SetString("2b4948845ae79d5803bc258bcd951d476247eb24ebe416a89ad8fd9f465fe8b6", 16) - g2To108x, _ := new(big.Int).SetString("2854ffc7b3e8214133feba8d6eb09b263690572a3022b7fcf2871ab9219cdbad", 16) - g2To108y, _ := new(big.Int).SetString("106de3acc6519fe5e79d178c2c86abded16f791c8ef4d9335d97862a68f5590", 16) - g2To109x, _ := new(big.Int).SetString("24c6a00e705db722a2952db86bbe7f08cac7b6c3b50d023f24a3de1ea736074d", 16) - g2To109y, _ := new(big.Int).SetString("dc43ed6b87676e8dd55e167471a55f2eef0968e310767659123e48b357903a4", 16) - g2To110x, _ := new(big.Int).SetString("2644642ad942cfbd4736a0f7f18fc0197e029521ee087615e04a49e5f8fbb66e", 16) - g2To110y, _ := new(big.Int).SetString("22b30468bd6abb89a23a5dce7e57ae96e25e0417937368f6760147af32c7a7ef", 16) - g2To111x, _ := new(big.Int).SetString("139bc1dd75b831294bf28f4030675c0e05ab4f44f87a639b04228814b6cd5531", 16) - g2To111y, _ := new(big.Int).SetString("18c670606f2e48d361c347c0219ae8e678759c0b22c01a1756b6b0e3c679ef33", 16) - g2To112x, _ := new(big.Int).SetString("2699eb06108602cf13980e2b6e4f48c6d90f46de7eae60457e4d1019a4f3b9bd", 16) - g2To112y, _ := new(big.Int).SetString("626c5f10d9f788ba433f2be9ac352b4298ecd2cea3cfff1e15e9d48fbaa113c", 16) - g2To113x, _ := new(big.Int).SetString("1f4479f765ee101dfedcbb07e9033604da94dbbe5b781331484321af5b253dcd", 16) - g2To113y, _ := new(big.Int).SetString("21623c9b390babf2397d31ca4af79148ad304a121ae5edc1723c994d2828f444", 16) - g2To114x, _ := new(big.Int).SetString("2855725b3e68975ebe53642831ae4d5d2d7b4b137b95eb96e8151bc61f1bf053", 16) - g2To114y, _ := new(big.Int).SetString("ca0e44e2fd18ec91840ccfe99c3049de88d1cb70c63633b7aa4416b92b0336d", 16) - g2To115x, _ := new(big.Int).SetString("136dedcff58a79ef53df43747ab531ff7d38d5c7d2f7a6d652f57b415b808c10", 16) - g2To115y, _ := new(big.Int).SetString("108956df051470607a649a39f14ea5cf95a904a406ca3123eebe60a0eb4300fe", 16) - g2To116x, _ := new(big.Int).SetString("d744feede2a6bd63f61403043b33f81f56a61ae58c43e8b771ee0cf5f0dfdea", 16) - g2To116y, _ := new(big.Int).SetString("7edb65778a0aa859b8947ef31e601c311b25aa1bd2a5ccc3225cac13bfc1d18", 16) - g2To117x, _ := new(big.Int).SetString("23ecd41f06eb8051f907d416c36a9a6691dc87cc64de02261c7eacaf70b82beb", 16) - g2To117y, _ := new(big.Int).SetString("caf2de20986119d958e6de7c3f6cd4f8b38645c9e59a12f46003aa5625c1edb", 16) - g2To118x, _ := new(big.Int).SetString("15b08db406565282b6a0d3fc8022eadd2b61a559f3c92cc91521c45c6661a82f", 16) - g2To118y, _ := new(big.Int).SetString("37803c869368190f0443820670330b14439832989f2345a36e5a48b2c59e543", 16) - g2To119x, _ := new(big.Int).SetString("e1eca77e1fdfbc7a151ed32732cbbe093978b5d8724324d73929a30e58be078", 16) - g2To119y, _ := new(big.Int).SetString("2e23a2f478eff00d8f0c0d7ec3c2c76467aeb2ca3d26ef49ed19ef1a8cccf8ff", 16) - g2To120x, _ := new(big.Int).SetString("e16c46d7f01cd14637900379058cde52352483f90eba6350dea325a183e4c8e", 16) - g2To120y, _ := new(big.Int).SetString("2bc5983fad220b58189c50be25b200c54e70d0529e3dc96decbe801f0420786f", 16) - g2To121x, _ := new(big.Int).SetString("1ecf556e4ea1a22b395060ed7c79a79ad9af43103b935caf9d410aaf61ce4e9a", 16) - g2To121y, _ := new(big.Int).SetString("1ac123a28245de45fd811267a8e343a1b035e77aca8b4614d09722caff12b0eb", 16) - g2To122x, _ := new(big.Int).SetString("1211f23e5e92c74a454701bf173aaf1ea12f7042e85859c468d94974eaad551c", 16) - g2To122y, _ := new(big.Int).SetString("165d5f2fff807855a18513ebdb932dee6bfcb8293383f7b7bc5196d737053f73", 16) - g2To123x, _ := new(big.Int).SetString("2b9fcf34bf541a48ec88d66cf5bfc89700211ae76a79551757dfc50f41288227", 16) - g2To123y, _ := new(big.Int).SetString("ced96282d5edc9cbc32b1c16e750da8cf3237e07e3625d85bedaecfcd12c9c4", 16) - g2To124x, _ := new(big.Int).SetString("2f9ea4e44871cf87cfa80f71560253dc13ab58f9728495fddb4b9bdd11628735", 16) - g2To124y, _ := new(big.Int).SetString("28dadee7c5d2a42cd524d8396f69ee363aa95f85c98c3c836004589b6d73084b", 16) - g2To125x, _ := new(big.Int).SetString("15530bd41a96a8a225db6640075aecd1884a06bbac5f98c51e5a487bfedc8d70", 16) - g2To125y, _ := new(big.Int).SetString("1c86da90e9556705a7476bff65b8f53425e3d129db8f179ad6e4b033e0495a20", 16) - g2To126x, _ := new(big.Int).SetString("da53ef60fd433fe0ee377bedc0e2f7239b514bba5caa80c52991c619a029559", 16) - g2To126y, _ := new(big.Int).SetString("1e1a37d1bf9f0eb8677bb0fd215c26cecfb350ad226f42d569bb040234da117e", 16) - g2To127x, _ := new(big.Int).SetString("25d8a9ba3266bd80af59395320e940663ab8c05932a4280b42bfcd0ec4f69d62", 16) - g2To127y, _ := new(big.Int).SetString("2fc95abfe6be50f1add78a03a9b4e60931ac358a132ad5ef5076c4894fb14aab", 16) - g2To128x, _ := new(big.Int).SetString("13b8fec4a1eb2c7e3ccc07061ad516277c3bbe57bd4a302012b58a517f6437a4", 16) - g2To128y, _ := new(big.Int).SetString("224d978b5763831dff16ce9b2c42222684835fedfc70ffec005789bb0c10de36", 16) - g2To129x, _ := new(big.Int).SetString("2d035cd6cd9ca06a9aecee6826e38a30dd6fa18a9f139179142782803a05e6a4", 16) - g2To129y, _ := new(big.Int).SetString("bcbe75d48af9e7d4a45ef21e0348411bdf99be154fcc82ecefc6cbab8157291", 16) - g2To130x, _ := new(big.Int).SetString("1096e761836e74c5c654df817b4ace41e55cd812e97d2d0af5e2ea6f24dfd392", 16) - g2To130y, _ := new(big.Int).SetString("21ff527613e48f4a5e3548af70ec2c1076b85506cf767aceb570ee83983ac6ce", 16) - g2To131x, _ := new(big.Int).SetString("292c4a9ebfc080016a973ac9e24fb4b356c69db30308202a31d0bfb2e85443be", 16) - g2To131y, _ := new(big.Int).SetString("2d378fef5d7b4b008da52d0c98bb8daa702109aa7d5da477107d9f9559dd6eab", 16) - g2To132x, _ := new(big.Int).SetString("1d316fbe5c0ccef4caf35a917244ff619d92d4fbedc80b970205508e4b570595", 16) - g2To132y, _ := new(big.Int).SetString("22b85bd410a73800d3610f05dea0bc7d82960d317602cf44bf77ad8f8f254f79", 16) - g2To133x, _ := new(big.Int).SetString("2c961c9d2ad66f1049fdd0e8d7337e3449e8774836bb9981b56fc6e7385cd7e8", 16) - g2To133y, _ := new(big.Int).SetString("6bd01a16056ed018b2394a0ec6897cfbeb20a18c606b0d78bc78d1d84a6b892", 16) - g2To134x, _ := new(big.Int).SetString("2e8a8414affe97ed11410c27ac23b1f54b6a621ba39a9fd7f1685f9db88343a7", 16) - g2To134y, _ := new(big.Int).SetString("1efbc6e7cb379b246ad9278606ea10b7c74f52769c615cd67b833c5016ac7db4", 16) - g2To135x, _ := new(big.Int).SetString("2ed01ed41ec147ec1eba42d4b3c921568944e9a0d8a498706f99ec15d0ccc511", 16) - g2To135y, _ := new(big.Int).SetString("1dcc8b5251aa1008c792ac420bc9be5f1870042d0210ff8ae96804ddffc721ad", 16) - g2To136x, _ := new(big.Int).SetString("194c79506a89ea907a1e6777926f317f7231ea49bbde362689477b6ee04e9613", 16) - g2To136y, _ := new(big.Int).SetString("26c94fbfb503010b9cac6a4b4e8e5fe29553e60128e05cdbf5546cb7bcb34d7", 16) - g2To137x, _ := new(big.Int).SetString("277ac3a2889cea8febfa02110307c50b7d8da14e50adc4e86dc8d0aa73251dd", 16) - g2To137y, _ := new(big.Int).SetString("17eb791abc2495f664ffb38442265281a6f9a91c6169ec5a6e7365dcd3c64871", 16) - g2To138x, _ := new(big.Int).SetString("d3c84c79e806fda93ee88a7887b9daafa47969dad98217ab2bc82bdff4fbc25", 16) - g2To138y, _ := new(big.Int).SetString("213f847ffc2eb33fbb7a5fe6f9e52d792095ffd8c8ebccc3caf9ecfd610cf1b2", 16) - g2To139x, _ := new(big.Int).SetString("21d9001150f189e28d9e194e98bc5ac761eda5d600d7ef517983af606c5548b9", 16) - g2To139y, _ := new(big.Int).SetString("1e2fff3d9cd1f421a57ff2dade55ab4ce3b4628a60480cce558d3a77b8fd5227", 16) - g2To140x, _ := new(big.Int).SetString("8c4343a41a1dae81a6276852d405acd87e81ff4b1d190482b5718a6e31a761", 16) - g2To140y, _ := new(big.Int).SetString("12b4ca0371b8ee1bd20a1d65277bab81e59f6e5ce60ccc6b82c722cc29d07fa7", 16) - g2To141x, _ := new(big.Int).SetString("2bf8fac78021ac7b2753b1ecb80fb30160b6b3250b5cf0ec9ad46f7801e759b8", 16) - g2To141y, _ := new(big.Int).SetString("2c0016acf87d3833c0fb9709392747265f4202151c050427b3b5913ff39de477", 16) - g2To142x, _ := new(big.Int).SetString("1cf7146b4c1d2ea113417938e790a96fe811cd3dfef48ddf27dcba7cd820f6cf", 16) - g2To142y, _ := new(big.Int).SetString("2a5ed72cbb62ac7046edfdcf9d1b47368fb3e2291e1e85e26c4e8cd35e401ef5", 16) - g2To143x, _ := new(big.Int).SetString("5e61bbcbc655464ba1fd215e04fcf949939de110f05722431cd5084968d6db9", 16) - g2To143y, _ := new(big.Int).SetString("13e15f844fa2767fac2daae3fb818e93cf95082efd681debb31574defacad671", 16) - g2To144x, _ := new(big.Int).SetString("34bf641f495a59e3d28dc3163a1c74aec7f7ef60030c8614c193f7ae2281a96", 16) - g2To144y, _ := new(big.Int).SetString("8b45e915673d26d8c5c5258a951fcf9b439d6833e12d2c301dc2eabe23e3f61", 16) - g2To145x, _ := new(big.Int).SetString("2960a0634103632555b7ed048b833d198c75536bdfce550988dea08d1b2a4b69", 16) - g2To145y, _ := new(big.Int).SetString("1f29d4cddfdbbb9a3aae3c862def08730c9563529b888e065f77604d012c194e", 16) - g2To146x, _ := new(big.Int).SetString("2bed31e2b3ee10fa9cfea431196db0b201587e2e68ee74dc466450053177c5fd", 16) - g2To146y, _ := new(big.Int).SetString("22c3f8fb3346540004df204600e2a60f2b5232a3fcce889962561e1c98a80146", 16) - g2To147x, _ := new(big.Int).SetString("d452f069c9eb613854442c5e9830fff0cccbb7a0c37bb8fa9a81c242933b54e", 16) - g2To147y, _ := new(big.Int).SetString("1c8331a53da629b28d02f6ba74b52caf67c4418e22fd6caf57d627e110451251", 16) - g2To148x, _ := new(big.Int).SetString("f055c21e2d7e8617b71babc6b770fc9a7ef74c3913fcf610d599414096b700d", 16) - g2To148y, _ := new(big.Int).SetString("1ebeb82f257db891825c55b2c909f0210dbe84616c0f5a867aa9f380a9171929", 16) - g2To149x, _ := new(big.Int).SetString("21907afebc2ecfb8c7c376a0db9958b35a6540103391efa541a28b82f472f48a", 16) - g2To149y, _ := new(big.Int).SetString("27c5a8cf6fa01b72d31ac50942838b8362d01e25c82b2d9c4a0f231441de4197", 16) - g2To150x, _ := new(big.Int).SetString("205ba2fccb49fb5023e5114f84e961b9237b49ca8f5610bebb995b33ee249369", 16) - g2To150y, _ := new(big.Int).SetString("b388977d2e0a8fc0e63a06375d9fe19fc7b798b8b0f2c8b0885920cb5bae45e", 16) - g2To151x, _ := new(big.Int).SetString("2bb165ee76d92f26bdcbd9897c6519b8d89eeef2efc0c9521497068c735a54d2", 16) - g2To151y, _ := new(big.Int).SetString("152704fe7afc78056ee79211313a0b23b71de06863c6102e0f8daefc0f2e85df", 16) - g2To152x, _ := new(big.Int).SetString("f34d4d950bef2ee3b8e924b0183ca4e00aed6ea9209bc37c4e2202eb5bd7666", 16) - g2To152y, _ := new(big.Int).SetString("d676a2dac5fcab3731af3283d9c22989889fad53465781a73ea5aa81274798b", 16) - g2To153x, _ := new(big.Int).SetString("42fdcaca97128fd28b1ca4c90eaf39378d673af8d9f789d33b88c8284c1e4c7", 16) - g2To153y, _ := new(big.Int).SetString("c5f60e7eaf108af711035a4ca219da7c7926c882d40373d76d9fc5dc05bf2d6", 16) - g2To154x, _ := new(big.Int).SetString("15f74bf25691e3205d87c4ee7b798f00097551d1a14e732f8ec16be2c2b15424", 16) - g2To154y, _ := new(big.Int).SetString("e917f31facef054212b2376c65779119a28cf490a506e66d48dd45117ba7cab", 16) - g2To155x, _ := new(big.Int).SetString("8bd6a57ec62543e02f6fc7d0c3e832c7b7fc579d180a91071faa3d3ee9419d4", 16) - g2To155y, _ := new(big.Int).SetString("1bc48805b6f1636fbb3fcd6da38aafead46d19c009893b19cbeeeae7937a68b5", 16) - g2To156x, _ := new(big.Int).SetString("22d27fb14085110cb59094144fc0b73878d88c64957112740a8559878d34fc", 16) - g2To156y, _ := new(big.Int).SetString("8e1197fb288dbdfc3c45e74c7362e8d24eb51a66e6f601e078713114be490f2", 16) - g2To157x, _ := new(big.Int).SetString("1b9f573652906bd22ae891e98f72b280aa9f086974561858b06e57325bda14db", 16) - g2To157y, _ := new(big.Int).SetString("12aec4b8476606d47b077de794be45c888600e94486a93b3560d82c80bc5f8a8", 16) - g2To158x, _ := new(big.Int).SetString("2548e5ca7207fc244a56030fdee8726891f78b31b786050b01f535872604fef9", 16) - g2To158y, _ := new(big.Int).SetString("40f0788fad8ef4eca110681d934bc1875cce24d4b79708f50c5c5ade76284e5", 16) - g2To159x, _ := new(big.Int).SetString("8e2dcb5d0b19b7b0fd7b371bc43c5756f0377132cef98df0db4dd9eb393adca", 16) - g2To159y, _ := new(big.Int).SetString("2fe5e5ea9fb4e811da5043de233b0b4e971da2dd38941c5033de0afe61e945b5", 16) - g2To160x, _ := new(big.Int).SetString("1d4f9e8484dadc0b72b38138caad649253a61a9bf5ad2d9afe7330bf839fcbee", 16) - g2To160y, _ := new(big.Int).SetString("9bb9bbafbfbf4038ee64e73ebbb0975db22edcd2d1c1c6e83eca2672fab780b", 16) - g2To161x, _ := new(big.Int).SetString("fdbf5656758cf6806e65b7800be3b7c039ed1fe181a0d4b50fabcec79f0df5b", 16) - g2To161y, _ := new(big.Int).SetString("173a2bd7eab80c0e2c4cf6abb5b659d289de53889c437ef553167ecfddad034f", 16) - g2To162x, _ := new(big.Int).SetString("f1ca7aa3dd35f558481ea63cf19d446200c77835c45c63954770ad12616dade", 16) - g2To162y, _ := new(big.Int).SetString("6e0f716d88e8041c0021dd736593a6a3fa501e33faa9a6510b71467d749498e", 16) - g2To163x, _ := new(big.Int).SetString("2eb10a9a90309b08dee4cfa8070265358c54b21572d914c9e8fd36a959304d24", 16) - g2To163y, _ := new(big.Int).SetString("3b4ec52766ad398c08539c6f8acb2b39874f0e0b994010efa873cfdf680a88c", 16) - g2To164x, _ := new(big.Int).SetString("1b94be21f1fb7228d3f3d44204f4f3cac13090d7c5c2af9ac82f0475f5cf39b4", 16) - g2To164y, _ := new(big.Int).SetString("27e9d41ef829511094b2af4473637e9375eda5f9e914cf55aac02d9b4a969755", 16) - g2To165x, _ := new(big.Int).SetString("25710e3a7246b1e76b8d6fbe6ff44afd9fd30c9585351398c15d050238d3c2d6", 16) - g2To165y, _ := new(big.Int).SetString("1c855e42168e00cd947df9d3a268f0db1f8e471f730ca88d84e1c2de7083e4d", 16) - g2To166x, _ := new(big.Int).SetString("2b144261f16985c75bff2b9d0796d0bbb63ba9c927669e3839710eea66a8efa5", 16) - g2To166y, _ := new(big.Int).SetString("2bb766bc6b62691154fab15cc24ce09d7d0a86f180f7cfc60b459ccfe2bc1842", 16) - g2To167x, _ := new(big.Int).SetString("26b93a6de603f0cb5900242713c98a4690d087ee2701f953c81f562a0bcf691a", 16) - g2To167y, _ := new(big.Int).SetString("1f275bb2c0d7f2e06d4d3d7718ad405914e62af9dd182c0f3d8cf5bd436ef483", 16) - g2To168x, _ := new(big.Int).SetString("f43e8a6e923598ab55483d1cb864aa57273dd9173b898daae6c753e403d80a5", 16) - g2To168y, _ := new(big.Int).SetString("14351ad715d016d31bfa656c62512aaeeaf2dcaf8918bb24b379cf035722757c", 16) - g2To169x, _ := new(big.Int).SetString("13971d545d04b5639a6bd48a583d0e02bd46b717ae6404589d09ddcf8e0e1664", 16) - g2To169y, _ := new(big.Int).SetString("d9e7a36118a844d63b5778975a157e06f444516a730e37ee575079115e1a51a", 16) - g2To170x, _ := new(big.Int).SetString("2b6126f3432d0ab7149133ed284dc4b8f4c690a15d24a2012df8eafd1e584102", 16) - g2To170y, _ := new(big.Int).SetString("2ffed8dfeba141fb9d2ec5f5c4ea602a5dda428b2adbb7fdb83dbfd3cbe3ea36", 16) - g2To171x, _ := new(big.Int).SetString("f8ebff21f4475980919b8bf3a07e2bc3276c32aa8cc9be0d2b9e6ecda1eac62", 16) - g2To171y, _ := new(big.Int).SetString("2d5d4034ffbc3503e76dbfaab4569192bdc22c3297c74cbfc9faa36a1b168a61", 16) - g2To172x, _ := new(big.Int).SetString("f89469183d268e35a4e05882dbe1a6718f5246a18948c8bc421b21e2a1a8f90", 16) - g2To172y, _ := new(big.Int).SetString("c501e43476b33ec702b4a4cb163b64b2077f52e73fa21cf24c1d31e96a88c87", 16) - g2To173x, _ := new(big.Int).SetString("2a49dc5c6e7fe74ff00aaae703c26fe0916b22a76b66f11eb2f1c97a145c2fb9", 16) - g2To173y, _ := new(big.Int).SetString("a3d9acd50d6e2f9032d7708ffcc17a60ba20f887efaf42856b039cbc0a32483", 16) - g2To174x, _ := new(big.Int).SetString("195cdbddb30680997cfb2d5471c87c76f7cb4e61797ef85ec2c6f2d883b018f7", 16) - g2To174y, _ := new(big.Int).SetString("1bf08f1d94d1eeb02f28b7a1ae77f739697de40b672743de45182203b0fa20e0", 16) - g2To175x, _ := new(big.Int).SetString("19d00e5a8576bd737351c55095a19e59a94e4b7ebb3a505c54c194609719ff04", 16) - g2To175y, _ := new(big.Int).SetString("139cd47baae2140ee687714a64063dbcd8ee9c5ba41e8abec89d55eee1018d16", 16) - g2To176x, _ := new(big.Int).SetString("2f9e7f7800c6a9c653f48d4636d9dfad6e122c48c2ed4ad2e59551956563be7a", 16) - g2To176y, _ := new(big.Int).SetString("2414da5e0cd90394bd984c6886c3b7fc7d34a8418cc6898578ec0540d1d3bd48", 16) - g2To177x, _ := new(big.Int).SetString("2b2b8f5e7f644ee1c00937dc227da2e3de69762726d86036f4807b6aaae36c31", 16) - g2To177y, _ := new(big.Int).SetString("47853a419bb6b761e2bf666d6ca8f90e93ec84a6e5b425d5b74daf76ef9ccba", 16) - g2To178x, _ := new(big.Int).SetString("17b3259210a9a0e4339a3fe1caa896e56306745007e783373d47fe37c800b974", 16) - g2To178y, _ := new(big.Int).SetString("1ad16b73e4b32f988f8d9eebbee03224fe7bcbabbceb02973cd2e159c3a58e35", 16) - g2To179x, _ := new(big.Int).SetString("20be897f06fad7a92edf423db7ed12cb2bd2f6cb29c6bb8c6e394ff1aa3b3e9", 16) - g2To179y, _ := new(big.Int).SetString("7958a3fec65b6df34911a018aac0fa72ce89d92ba4bc67dcd06d1b4db184b90", 16) - g2To180x, _ := new(big.Int).SetString("253eba1d7cf606254ed9cff7613788a6d055495b779d9947a9cf46b9c1da311", 16) - g2To180y, _ := new(big.Int).SetString("1cabc4e498a23c3f5fcfcb887629459666b7513ac8c70ee43be83a8b4f5c4090", 16) - g2To181x, _ := new(big.Int).SetString("85fad322fc02ef1cd3e8473c56c6a1a26ecabadccf845a914d79c83beeb318a", 16) - g2To181y, _ := new(big.Int).SetString("3146780190be66eb78f6d6a2150da305d044739434f4d56ddccd160dafd43b1", 16) - g2To182x, _ := new(big.Int).SetString("22c33c8c594bf804b9c5a96835ed929dc99711327d5dc3723bb2bcfbb56f7fc4", 16) - g2To182y, _ := new(big.Int).SetString("2bc57d10207ca4af29f3a0a8eb864d8989e89371936e4544626fb999bf7a4fe2", 16) - g2To183x, _ := new(big.Int).SetString("225fdab8fe6cd876363d27075cdf0d01c209da61b1634b574a5d811cfae40700", 16) - g2To183y, _ := new(big.Int).SetString("1216b7c3e2adc07c3bef31771c7bb9e1d02f07ff3a5b74953c4fd5bf9a7a6dff", 16) - g2To184x, _ := new(big.Int).SetString("2a365a9299da85372ee0455de645cc2330e4c315d6250e3c0c72f10d77ac40e4", 16) - g2To184y, _ := new(big.Int).SetString("e54618ec8951f6b8be014e3f3bd12802b037ac48c2d0fd983f2343c5759c3db", 16) - g2To185x, _ := new(big.Int).SetString("2f31ee57ec760885e1e943c7d1602bff848dfde5cea6a4edf03476ad213591cc", 16) - g2To185y, _ := new(big.Int).SetString("bebf1d735e3aba48854ada67731601a179cd76b2bb690e6aed56a2fd963e9aa", 16) - g2To186x, _ := new(big.Int).SetString("242a698649332113b115eb3982fa5e454576bc05886f71489a31113fd737feb8", 16) - g2To186y, _ := new(big.Int).SetString("2e98af3e21c2fb8ecacd092858dc5ea8671f81867d371c9b1a010801ced7ae94", 16) - g2To187x, _ := new(big.Int).SetString("de2dce497fc378cf9875ea34483653ad21b40050a2be9f32713978fad365b6f", 16) - g2To187y, _ := new(big.Int).SetString("18818ed119e67e54970494ba4f5c5feb75fb8047779f910713af5793062885b1", 16) - g2To188x, _ := new(big.Int).SetString("143a5a6a69b89a9baf10bab59c62ddf7a747a8439541febe0964e2ea6e35147f", 16) - g2To188y, _ := new(big.Int).SetString("ace7c02bcdb98ce30c3b6c4b9d399287ebc911e8d44226bab0c3f06c1e7e717", 16) - g2To189x, _ := new(big.Int).SetString("18a2a13576df7d0be0daa67eea762a6894fc88a47a4b5d26bf6af3c826c91677", 16) - g2To189y, _ := new(big.Int).SetString("fc68277f2370379225a32315a25607a6341a371091589edeabda88ecc3d2a18", 16) - g2To190x, _ := new(big.Int).SetString("245ca02f753e3dcae81462215695192bb8de0ee8a3c195c1e2f735fb5510c791", 16) - g2To190y, _ := new(big.Int).SetString("22dfa007006c664c55102bfd2a79e5e79d89f3947b9f4556dc1ad20b80ff74d6", 16) - g2To191x, _ := new(big.Int).SetString("1ae696c232847d27e7b00f3ffeb36076d50514c4ee68bdcb08a892bce08f3ae9", 16) - g2To191y, _ := new(big.Int).SetString("1396047d0e2300586624c149388740f5c00e7cf4a7213598d8ca634cb7df215", 16) - g2To192x, _ := new(big.Int).SetString("2642b0d7d17b3ae1c6c1ddc1b018ecff936f658d2acc47474a330c8d6cd2d5f7", 16) - g2To192y, _ := new(big.Int).SetString("af05ffe2aa2cf4f27db4fc64b9bdc681e15f4fc2bb57f6ce23e2e1f89003c72", 16) - g2To193x, _ := new(big.Int).SetString("29d2b27d8d6db3791b3c64b2f61f5b2ab00d7f1ebc252cb97a9896a83c0e5d61", 16) - g2To193y, _ := new(big.Int).SetString("12a4333add04e8aad8478e3046268d23ed55292a96d7921460ce3d1f52ce28c6", 16) - g2To194x, _ := new(big.Int).SetString("252d6852ed68f5ff4420bf4ae9e5900a65fa7b2993dd3745e8dbceb436c5b94c", 16) - g2To194y, _ := new(big.Int).SetString("21df15aafa8dbc395e66f7bbf004139eb5b5bc1bcc071d61b02096cabcdc010e", 16) - g2To195x, _ := new(big.Int).SetString("1d115df69be93cf70619b0f005a92968a5ee561161a3dd3cc963c243447f391b", 16) - g2To195y, _ := new(big.Int).SetString("1555da4cf093578bc7a49518f3a49a24f57760186fd02a3eec3749ec72cf7ad1", 16) - g2To196x, _ := new(big.Int).SetString("2ad97c4b04758df61bf424363bd78665cbd24e20c13125ba2fc618312635a5db", 16) - g2To196y, _ := new(big.Int).SetString("f6b80288f228ae9b8cbfdb06a1362c5b4a4fa81cff38dffb36585b871ad747d", 16) - g2To197x, _ := new(big.Int).SetString("1385c47fcd92b51986c4ebf480519229ad13bb04255b24ffadf0d64a47c9c56c", 16) - g2To197y, _ := new(big.Int).SetString("1b5e107ac4e88ba1f6fe66fd02dffa0211cf505d105647adf3ecbcd475e22840", 16) - g2To198x, _ := new(big.Int).SetString("194ed40353d0e3fb0983152b872766ae5f1b4843ccdf294212a22af910755911", 16) - g2To198y, _ := new(big.Int).SetString("267aff505f0d68a76ebcb094b24df86ec272309368b812af86fa0bf390d148a9", 16) - g2To199x, _ := new(big.Int).SetString("2c87079e8db3eba1a27b14612b8f160b5a9452af0e76b942f61259a4119665cb", 16) - g2To199y, _ := new(big.Int).SetString("a26589e75263127c006b16e4c34db58765013d73c48a13c269b75e0fc34dac5", 16) - g2To200x, _ := new(big.Int).SetString("4f1cb752254ce1c92b01b10a5af73b1854c2c62841dc824781caaa56ddb87f1", 16) - g2To200y, _ := new(big.Int).SetString("2511226c45e2074e814befca9728e74afcbe0a2dbb8da9b61497527f7dc16fc7", 16) - g2To201x, _ := new(big.Int).SetString("1726c1df54ad0c394c53dbb2daa6b525d5337201f18ce540686af4310676a873", 16) - g2To201y, _ := new(big.Int).SetString("1ec01458207da40eb3b8483934f1281939e93fcbf8727a81eb45584ed2a3f61c", 16) - g2To202x, _ := new(big.Int).SetString("226c0947127b57567bc20c26508a688b2361f752eafe0072c005e589d8b9ef58", 16) - g2To202y, _ := new(big.Int).SetString("2dcfd6b7a3cb9423a68ca27d4e288f84067d1bca27ab18fa9a7b1c3cdc0876c3", 16) - g2To203x, _ := new(big.Int).SetString("1144eed8752daad82ce8c81c75d13e91c2d8a1368d8b7aece378bdb8f553f7d1", 16) - g2To203y, _ := new(big.Int).SetString("4d8b0b771a46ff8f2e0c18454b643f8908a5b96da44713263eaa0e7609149cb", 16) - g2To204x, _ := new(big.Int).SetString("1e6c7691756045003fd35cf5d449f1bf0c68b45b34905abd5fbf2d944251616", 16) - g2To204y, _ := new(big.Int).SetString("2c808764b3c2d8ba8b949a9f00efb3bac79481195ca7e34a146e913aff89859c", 16) - g2To205x, _ := new(big.Int).SetString("2846b54c3b22668dcbb8cccaae457e53d8b6f5ccac2b48128fc73c254c5e59b0", 16) - g2To205y, _ := new(big.Int).SetString("276f519936be5b3e2f91afc073e810e20473b09e963be92fe55aa82400eb9cfe", 16) - g2To206x, _ := new(big.Int).SetString("9ba7fc0c9257b32d14ef83b0b43ee1b4c875d4ddb70a1f8dff121bb0738d5f", 16) - g2To206y, _ := new(big.Int).SetString("e3b10575559f366d81f1b0076b0f2a8e57c4d11d5daba688a1926e17f22054b", 16) - g2To207x, _ := new(big.Int).SetString("2c8474246fb806dfd385f8358e4fe95f68fae97018d7db1a3fe43b670197d296", 16) - g2To207y, _ := new(big.Int).SetString("2d8ac3b14579252521443a0709069529e88578810f1c6cf4167f595f17c301e4", 16) - g2To208x, _ := new(big.Int).SetString("1ce9e693f0718940f328281f33872bf77e5160c73c0a6068e8855e4716316099", 16) - g2To208y, _ := new(big.Int).SetString("869d2297c13d0e7ed693bb3ef7cf72bade1c34dc9936633b458571bf7231764", 16) - g2To209x, _ := new(big.Int).SetString("25ef45e9014757ee53971d76a5c50e5b57b3daee31af4be46c9cd3d7a382068b", 16) - g2To209y, _ := new(big.Int).SetString("286b42c7d1cfc3387bb75355b59eccccddc593ba7c375c5ac7e8286ae03843e0", 16) - g2To210x, _ := new(big.Int).SetString("19bab36be51f69ef46db70c779126dadf51c2c4e31ed48a1623cebdce336b5d4", 16) - g2To210y, _ := new(big.Int).SetString("2854d9e8b595428c2accef0239bd031a4a2f37d751f1a992daf66e653b585686", 16) - g2To211x, _ := new(big.Int).SetString("1cbc558d34b723ebfa07c9630c96e81c74576d141801165e4710b5b0262c84db", 16) - g2To211y, _ := new(big.Int).SetString("2d4d9bfe1a7006a4eaf94fd681f467719a68a8231b6b46b496601a34cd8749ee", 16) - g2To212x, _ := new(big.Int).SetString("22e1b18187f92eab791a18a17bae522f674d76efd8c7188a18c9397350d25421", 16) - g2To212y, _ := new(big.Int).SetString("ad500831e4522a7fe456bd44967dbb8f56b3a7f36ac51ae95c3cbebd4e0ca7f", 16) - g2To213x, _ := new(big.Int).SetString("6b3c6bec4d1982470c5f1a033e43fca9cf142639d8d8c1e08e0390a4c5a7da4", 16) - g2To213y, _ := new(big.Int).SetString("1de78da2ba6a6e08b0b7f5a22bd59fe91abc05909196640e50e1d21741a4286d", 16) - g2To214x, _ := new(big.Int).SetString("18afa4a6bf750334eac73d2f93349a25819827c4f2e3b42ce8144f0c090e1b12", 16) - g2To214y, _ := new(big.Int).SetString("2bde7825dce391b931ca81ee1139e6d76760072c81ba53dd2db24ddc28694e92", 16) - g2To215x, _ := new(big.Int).SetString("28234f55a1ef2d10c29341f59be69a2090c49b57bbc64a58809d4d4b9a050326", 16) - g2To215y, _ := new(big.Int).SetString("f0d1a871d0f58ae80723f19adf08b8b04a9b11a1f0fb7c38c1dfb3b830939ab", 16) - g2To216x, _ := new(big.Int).SetString("1f87eb4ecf4979737f4ce5493a5d744349f50675c1e169bbf31689c3e8c04308", 16) - g2To216y, _ := new(big.Int).SetString("23d45d0cc26f83da885d957417f958f48d15afe583412df36ff2c46b0fae6198", 16) - g2To217x, _ := new(big.Int).SetString("265fe341276ba4ef03a3e1632e3eacc3c77af43355915017604e3297a2575e0d", 16) - g2To217y, _ := new(big.Int).SetString("2d96ebc6d29672f1fc80d5f711efc24b099d9e5805d6052db96dc6bfe58e8516", 16) - g2To218x, _ := new(big.Int).SetString("20adf422bb92e8ebca244338030fff6e5750b73e3b59bef4cf27f9b8b43d86cc", 16) - g2To218y, _ := new(big.Int).SetString("46d604bb8ba0f91062a910941f8640c12fee8aed73e49f47364de3375b82881", 16) - g2To219x, _ := new(big.Int).SetString("1b8b0974839d00fcb8ce8411303de0a7c1eb3a4fee51cfc81bc5555cf11e72d1", 16) - g2To219y, _ := new(big.Int).SetString("10f9785ecc740f71e35ac4bb5667d868c7e0f41d7ac008fe1002b98c74a13550", 16) - g2To220x, _ := new(big.Int).SetString("17804f51d82ccacb1f5c235f9229729042bba8586cf4439b4da2bf3ce9e3c6b4", 16) - g2To220y, _ := new(big.Int).SetString("4f911ef9571ad0f05275041c06fb56dd3ae9d6ca9faf59a98329140274dd0e3", 16) - g2To221x, _ := new(big.Int).SetString("2fcf22a313b481313f27289a45680aaf8805fe788fbdea9964bee963b47bbd6", 16) - g2To221y, _ := new(big.Int).SetString("29a1c6fa0c3cc610d930ef1748fecc57aae4d9b73762168af70432d5300acc6c", 16) - g2To222x, _ := new(big.Int).SetString("19d7f00e9da0ff3c5e36640d537dc9d8b297918680f8ef92ec5fb5c237e71d94", 16) - g2To222y, _ := new(big.Int).SetString("2b1aaab94d44134f97e647d973ec4f5db5627e6fd219f3f3f1e08f487f0b088e", 16) - g2To223x, _ := new(big.Int).SetString("1f84c3be21eedc0a6f3a0e8ed81866d2517d1ee09fb86a51601354cbc282c9ae", 16) - g2To223y, _ := new(big.Int).SetString("8b172a26e838681d0c4d3cfb013abf392141ee2f871903f94966ab2e7c67995", 16) - g2To224x, _ := new(big.Int).SetString("1803f42b6154c73df3776a86da598b72c820e0a39058a6272c97ec432746a253", 16) - g2To224y, _ := new(big.Int).SetString("11e4372b105bbbc4ee89496343eddd5f299ca4199190455953e6a4d5d0331172", 16) - g2To225x, _ := new(big.Int).SetString("13b103f06dec9eb67eeb1252f52e8ff88c2164c330742569ba6c0c1d79b43d58", 16) - g2To225y, _ := new(big.Int).SetString("24983f8c5d29be49c03a61673aa24b73b20f790d821a1832b61276203854ed41", 16) - g2To226x, _ := new(big.Int).SetString("2e1389cf976ee7d9ce2992c62c6bbd5268b1096f6e89c6870c25a4737c154fd4", 16) - g2To226y, _ := new(big.Int).SetString("2026565add482c9e333bf0f03cc1a0e6de8a45e2fcc79f298f1588852ebc239b", 16) - g2To227x, _ := new(big.Int).SetString("27816d71c08ddc593972e5d647880eb1c9fba52ddc130629a4867ec559903e7a", 16) - g2To227y, _ := new(big.Int).SetString("2d4342a5b94a716d13ddc4e034263d2526fa8f9dc4672b0490d326a0b2c24104", 16) - g2To228x, _ := new(big.Int).SetString("3e8748e8aa834f74f78325f4cade8beb5b2cd987e003dd2e01ca1e507b882ea", 16) - g2To228y, _ := new(big.Int).SetString("14e84a9b617bc3bbc51c7580aed6af624f108084aaa51c57c0f6bb42966a06e3", 16) - g2To229x, _ := new(big.Int).SetString("2e0333e017005d5580d8f37930910e83a4ec1cbb81513d5c4497e07bb4759ac3", 16) - g2To229y, _ := new(big.Int).SetString("2efa0d2056e33484bfd0d28038a697b52071ae3daad55e734c4f1788be4e26e0", 16) - g2To230x, _ := new(big.Int).SetString("66dd4f74bde89af1e484ee7999209deec62204f6fadfe137a007bd1b8a41322", 16) - g2To230y, _ := new(big.Int).SetString("1fafe097739d80d7254bcb0604d47a42a19606e61a5c9464b74c343740615c6d", 16) - g2To231x, _ := new(big.Int).SetString("d3abc9d71dd3d76ec536fdd34c3d535ccd3b2c92e344b04ea63e7a95bf1d40d", 16) - g2To231y, _ := new(big.Int).SetString("4e2d118cd7c19f8b38b28570d982bdf9398ec57fb2bb0d7e8f31e4c8ea3a7e", 16) - g2To232x, _ := new(big.Int).SetString("17a6c2b336d61bf255af78c33a67cf1de2896995df7e83f8241109a184dbbea7", 16) - g2To232y, _ := new(big.Int).SetString("123d241884de16c8078118cf8168546668a7c354c1aadc61505121f1c69318ee", 16) - g2To233x, _ := new(big.Int).SetString("a86bd18c2e2dc328a7fff99345d131988bdb003f53487da1d9affd07dfa4caa", 16) - g2To233y, _ := new(big.Int).SetString("270232b8aa979307cef134be75f5d025d01c3c6ba2f66499e3615e5b2dd00781", 16) - g2To234x, _ := new(big.Int).SetString("1e355fcab47dd4264a85652319a0dddf1ba3889eaaa9e05f21247e4202bda1a5", 16) - g2To234y, _ := new(big.Int).SetString("d60a88eb2f714752b7aecdeb65939828faa6e1e38e8ea1606a7a15e71e7a194", 16) - g2To235x, _ := new(big.Int).SetString("1eb1ba9d3cb37f1e320b57a13707f1b4b40333e1d9893d2d9c6012f5667001c9", 16) - g2To235y, _ := new(big.Int).SetString("c1dea44b0e7ba28967fe607c50f983c3bdec527612e81245029958308f7cbbb", 16) - g2To236x, _ := new(big.Int).SetString("dcd731a87dfac8e27719ecbe1098c415477febd6f06a227fb45f0b8b0b16d9", 16) - g2To236y, _ := new(big.Int).SetString("27218920b62eb55167704aa95c9929a79ead041e57e1f26d5f2b3affa474655b", 16) - g2To237x, _ := new(big.Int).SetString("3058fe52fd5ea77191aba39e84854d7d3f317390b1d869536d81544fad1a7e7f", 16) - g2To237y, _ := new(big.Int).SetString("1f64fd77c47fad6766218a0ca3e9b34b6207ed59f8eb2f902e1548d156584a90", 16) - g2To238x, _ := new(big.Int).SetString("1b5956deed90482c1cc4989e936ca265252d6dd8159a13270b78248b30843363", 16) - g2To238y, _ := new(big.Int).SetString("72ff5f961d1d225dec43bffd5f031562c9087a3a032305b1b716cdd158da5ca", 16) - g2To239x, _ := new(big.Int).SetString("1ee79768b58b0bbebf614d41fcfd9e17a88c38b41d697a2104a931a3cf3106d6", 16) - g2To239y, _ := new(big.Int).SetString("2ac2a26c534a3a84f696dd581ee7063f8910ca58954e436470d1fcc17dbbaad2", 16) - g2To240x, _ := new(big.Int).SetString("13932be07d7ef64690655fe3541d25b47caa20f0dba7e5843dc309e47fd4036", 16) - g2To240y, _ := new(big.Int).SetString("68daa9f3433ea9cfe8ab217593263464d3f3796d224d0c837ceb1ba5a388b5c", 16) - g2To241x, _ := new(big.Int).SetString("28982c2db4c7cc3f0ac38ae0d7a1774e276872fc2fc9be7b97038d1b7deeadad", 16) - g2To241y, _ := new(big.Int).SetString("fcd19a4ed741eac34e323909b7407f5a612a101c0d5687ea381bd36fd92d2c", 16) - g2To242x, _ := new(big.Int).SetString("233baee1bae9440f6456b6172b7b08e3b659265362d198e5196ef41d3a2d4b5a", 16) - g2To242y, _ := new(big.Int).SetString("2eae64ae6c81702e537c49c50c434556a49e9c734bf59580c86f19f2a0fb3374", 16) - g2To243x, _ := new(big.Int).SetString("2d5968f58c658153ee254d4bded6784e5e057251477b539a6d91f087985338ea", 16) - g2To243y, _ := new(big.Int).SetString("e0d8224d8090e8f7958bf46ea5f8d2d02370bbab1f4a449e50fee36e3f70773", 16) - g2To244x, _ := new(big.Int).SetString("282ba63c4d8d5c9d2477af22fa57cbb3618501dd22727c2a3244988179c98d2d", 16) - g2To244y, _ := new(big.Int).SetString("17957e0d498bd3694c8e62242bc37535cd445bf2a773ad9443cb3771fe113854", 16) - g2To245x, _ := new(big.Int).SetString("156e5523efb7270e38e80e154849f705a6184365b2261f3db870014428425d83", 16) - g2To245y, _ := new(big.Int).SetString("2a5e19cd3faf740e1f3ec427897c8da2804b0479bad28ce00ae15b088b04038b", 16) - g2To246x, _ := new(big.Int).SetString("7edfbd9cb99499052ada8d94e740625888f260adc45fcb5fe9be555b3221d74", 16) - g2To246y, _ := new(big.Int).SetString("1fd8c3a97911b6eac726e002fd3b84eceaa2b08a57e3df4227067fb5896aaed0", 16) - g2To247x, _ := new(big.Int).SetString("1725b4a59ea736ec816444dc53dbdf7e78d9194d537fa199c2883a38c60a06ed", 16) - g2To247y, _ := new(big.Int).SetString("249e0d5a519ef3f2ab6240aba00e912927ad4151be494765e2e31a1566828b06", 16) - g2To248x, _ := new(big.Int).SetString("5483b9dfbeb5b9fb31fd52b885335da4b23cdf83f2607d37e3fcbe112a85365", 16) - g2To248y, _ := new(big.Int).SetString("24e0ba9901789eaa6a0dc74bbf22debf9891bc5c03991db95f69df9c25ca6fcf", 16) - g2To249x, _ := new(big.Int).SetString("65a6b8b56220596ad72f24aea44c1d62f4c1544f23d4e968112d3d57f76c9b5", 16) - g2To249y, _ := new(big.Int).SetString("2d8d82657d6f9f9d5676cece3b7547be1b2ab34879690cd1d231716891525cf7", 16) - g2To250x, _ := new(big.Int).SetString("21f2133247ee84c3bd8c96271b6ad6482744b3367a13f0260535a908caea1d20", 16) - g2To250y, _ := new(big.Int).SetString("85b3a99f7d8418907dc897428443fae817137980fe5195974b11d212c6f2171", 16) - g2To251x, _ := new(big.Int).SetString("29eed773adae30e41534a519179a5193ace5c32048775a50d6e1a7f998c5636b", 16) - g2To251y, _ := new(big.Int).SetString("187868b2ac41a139f3563229e0ee02d65d27e38de3276ad2a4fd503c4f920010", 16) - g2To252x, _ := new(big.Int).SetString("ebf18cffd536c5521028aeab7afb898bf91d8abde80f16a70ab404b49dde064", 16) - g2To252y, _ := new(big.Int).SetString("2558d4421ddf231cf775888494c86ac8883a92df8b171dbc7e0f26978c2f1533", 16) - g2To253x, _ := new(big.Int).SetString("9a5c6756cfc787c9df52f40fa211edfed26f0303bb2e404fa53d486a8ec7963", 16) - g2To253y, _ := new(big.Int).SetString("28e47c414278b7f61d2e58077a5d6f12ebcd88950385108a733284e2861b8f81", 16) - g2To254x, _ := new(big.Int).SetString("3d541efe3a8777fd5cd6aea697dc2f83706644289adaa9380e68bc150476b0b", 16) - g2To254y, _ := new(big.Int).SetString("23fd426daa5672681e63f3c44963a131182ea5f8b9dffc4e4067f321b77648a2", 16) - g2To255x, _ := new(big.Int).SetString("18ba548c687cb306f9996e95ebff7530528177141ebd26680d2d994ea1f5b4dd", 16) - g2To255y, _ := new(big.Int).SetString("1a34ebd78433b90b62760d37f89ae069a85651a109939e329a4f266ce94c9d64", 16) return CurveParams{ A: big.NewInt(0), B: big.NewInt(3), Gx: gx, Gy: gy, - - Gmx: [256]*big.Int{g3x, g5x, g7x, g2To3x, g2To4x, g2To5x, g2To6x, g2To7x, g2To8x, g2To9x, g2To10x, g2To11x, g2To12x, g2To13x, g2To14x, g2To15x, g2To16x, g2To17x, g2To18x, g2To19x, g2To20x, g2To21x, g2To22x, g2To23x, g2To24x, g2To25x, g2To26x, g2To27x, g2To28x, g2To29x, g2To30x, g2To31x, g2To32x, g2To33x, g2To34x, g2To35x, g2To36x, g2To37x, g2To38x, g2To39x, g2To40x, g2To41x, g2To42x, g2To43x, g2To44x, g2To45x, g2To46x, g2To47x, g2To48x, g2To49x, g2To50x, g2To51x, g2To52x, g2To53x, g2To54x, g2To55x, g2To56x, g2To57x, g2To58x, g2To59x, g2To60x, g2To61x, g2To62x, g2To63x, g2To64x, g2To65x, g2To66x, g2To67x, g2To68x, g2To69x, g2To70x, g2To71x, g2To72x, g2To73x, g2To74x, g2To75x, g2To76x, g2To77x, g2To78x, g2To79x, g2To80x, g2To81x, g2To82x, g2To83x, g2To84x, g2To85x, g2To86x, g2To87x, g2To88x, g2To89x, g2To90x, g2To91x, g2To92x, g2To93x, g2To94x, g2To95x, g2To96x, g2To97x, g2To98x, g2To99x, g2To100x, g2To101x, g2To102x, g2To103x, g2To104x, g2To105x, g2To106x, g2To107x, g2To108x, g2To109x, g2To110x, g2To111x, g2To112x, g2To113x, g2To114x, g2To115x, g2To116x, g2To117x, g2To118x, g2To119x, g2To120x, g2To121x, g2To122x, g2To123x, g2To124x, g2To125x, g2To126x, g2To127x, g2To128x, g2To129x, g2To130x, g2To131x, g2To132x, g2To133x, g2To134x, g2To135x, g2To136x, g2To137x, g2To138x, g2To139x, g2To140x, g2To141x, g2To142x, g2To143x, g2To144x, g2To145x, g2To146x, g2To147x, g2To148x, g2To149x, g2To150x, g2To151x, g2To152x, g2To153x, g2To154x, g2To155x, g2To156x, g2To157x, g2To158x, g2To159x, g2To160x, g2To161x, g2To162x, g2To163x, g2To164x, g2To165x, g2To166x, g2To167x, g2To168x, g2To169x, g2To170x, g2To171x, g2To172x, g2To173x, g2To174x, g2To175x, g2To176x, g2To177x, g2To178x, g2To179x, g2To180x, g2To181x, g2To182x, g2To183x, g2To184x, g2To185x, g2To186x, g2To187x, g2To188x, g2To189x, g2To190x, g2To191x, g2To192x, g2To193x, g2To194x, g2To195x, g2To196x, g2To197x, g2To198x, g2To199x, g2To200x, g2To201x, g2To202x, g2To203x, g2To204x, g2To205x, g2To206x, g2To207x, g2To208x, g2To209x, g2To210x, g2To211x, g2To212x, g2To213x, g2To214x, g2To215x, g2To216x, g2To217x, g2To218x, g2To219x, g2To220x, g2To221x, g2To222x, g2To223x, g2To224x, g2To225x, g2To226x, g2To227x, g2To228x, g2To229x, g2To230x, g2To231x, g2To232x, g2To233x, g2To234x, g2To235x, g2To236x, g2To237x, g2To238x, g2To239x, g2To240x, g2To241x, g2To242x, g2To243x, g2To244x, g2To245x, g2To246x, g2To247x, g2To248x, g2To249x, g2To250x, g2To251x, g2To252x, g2To253x, g2To254x, g2To255x}, - Gmy: [256]*big.Int{g3y, g5y, g7y, g2To3y, g2To4y, g2To5y, g2To6y, g2To7y, g2To8y, g2To9y, g2To10y, g2To11y, g2To12y, g2To13y, g2To14y, g2To15y, g2To16y, g2To17y, g2To18y, g2To19y, g2To20y, g2To21y, g2To22y, g2To23y, g2To24y, g2To25y, g2To26y, g2To27y, g2To28y, g2To29y, g2To30y, g2To31y, g2To32y, g2To33y, g2To34y, g2To35y, g2To36y, g2To37y, g2To38y, g2To39y, g2To40y, g2To41y, g2To42y, g2To43y, g2To44y, g2To45y, g2To46y, g2To47y, g2To48y, g2To49y, g2To50y, g2To51y, g2To52y, g2To53y, g2To54y, g2To55y, g2To56y, g2To57y, g2To58y, g2To59y, g2To60y, g2To61y, g2To62y, g2To63y, g2To64y, g2To65y, g2To66y, g2To67y, g2To68y, g2To69y, g2To70y, g2To71y, g2To72y, g2To73y, g2To74y, g2To75y, g2To76y, g2To77y, g2To78y, g2To79y, g2To80y, g2To81y, g2To82y, g2To83y, g2To84y, g2To85y, g2To86y, g2To87y, g2To88y, g2To89y, g2To90y, g2To91y, g2To92y, g2To93y, g2To94y, g2To95y, g2To96y, g2To97y, g2To98y, g2To99y, g2To100y, g2To101y, g2To102y, g2To103y, g2To104y, g2To105y, g2To106y, g2To107y, g2To108y, g2To109y, g2To110y, g2To111y, g2To112y, g2To113y, g2To114y, g2To115y, g2To116y, g2To117y, g2To118y, g2To119y, g2To120y, g2To121y, g2To122y, g2To123y, g2To124y, g2To125y, g2To126y, g2To127y, g2To128y, g2To129y, g2To130y, g2To131y, g2To132y, g2To133y, g2To134y, g2To135y, g2To136y, g2To137y, g2To138y, g2To139y, g2To140y, g2To141y, g2To142y, g2To143y, g2To144y, g2To145y, g2To146y, g2To147y, g2To148y, g2To149y, g2To150y, g2To151y, g2To152y, g2To153y, g2To154y, g2To155y, g2To156y, g2To157y, g2To158y, g2To159y, g2To160y, g2To161y, g2To162y, g2To163y, g2To164y, g2To165y, g2To166y, g2To167y, g2To168y, g2To169y, g2To170y, g2To171y, g2To172y, g2To173y, g2To174y, g2To175y, g2To176y, g2To177y, g2To178y, g2To179y, g2To180y, g2To181y, g2To182y, g2To183y, g2To184y, g2To185y, g2To186y, g2To187y, g2To188y, g2To189y, g2To190y, g2To191y, g2To192y, g2To193y, g2To194y, g2To195y, g2To196y, g2To197y, g2To198y, g2To199y, g2To200y, g2To201y, g2To202y, g2To203y, g2To204y, g2To205y, g2To206y, g2To207y, g2To208y, g2To209y, g2To210y, g2To211y, g2To212y, g2To213y, g2To214y, g2To215y, g2To216y, g2To217y, g2To218y, g2To219y, g2To220y, g2To221y, g2To222y, g2To223y, g2To224y, g2To225y, g2To226y, g2To227y, g2To228y, g2To229y, g2To230y, g2To231y, g2To232y, g2To233y, g2To234y, g2To235y, g2To236y, g2To237y, g2To238y, g2To239y, g2To240y, g2To241y, g2To242y, g2To243y, g2To244y, g2To245y, g2To246y, g2To247y, g2To248y, g2To249y, g2To250y, g2To251y, g2To252y, g2To253y, g2To254y, g2To255y}, + Gm: computeBN254Table(), } } diff --git a/std/algebra/weierstrass/params_compute.go b/std/algebra/weierstrass/params_compute.go new file mode 100644 index 0000000000..0edf3f78b4 --- /dev/null +++ b/std/algebra/weierstrass/params_compute.go @@ -0,0 +1,60 @@ +package weierstrass + +import ( + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/secp256k1" +) + +func computeSecp256k1Table() [][2]*big.Int { + Gjac, _ := secp256k1.Generators() + table := make([][2]*big.Int, 256) + tmp := new(secp256k1.G1Jac).Set(&Gjac) + aff := new(secp256k1.G1Affine) + jac := new(secp256k1.G1Jac) + for i := 1; i < 256; i++ { + tmp = tmp.Double(tmp) + switch i { + case 1, 2: + jac.Set(tmp).AddAssign(&Gjac) + aff.FromJacobian(jac) + table[i-1] = [2]*big.Int{aff.X.BigInt(new(big.Int)), aff.Y.BigInt(new(big.Int))} + case 3: + jac.Set(tmp).SubAssign(&Gjac) + aff.FromJacobian(jac) + table[i-1] = [2]*big.Int{aff.X.BigInt(new(big.Int)), aff.Y.BigInt(new(big.Int))} + fallthrough + default: + aff.FromJacobian(tmp) + table[i] = [2]*big.Int{aff.X.BigInt(new(big.Int)), aff.Y.BigInt(new(big.Int))} + } + } + return table[:] +} + +func computeBN254Table() [][2]*big.Int { + Gjac, _, _, _ := bn254.Generators() + table := make([][2]*big.Int, 256) + tmp := new(bn254.G1Jac).Set(&Gjac) + aff := new(bn254.G1Affine) + jac := new(bn254.G1Jac) + for i := 1; i < 256; i++ { + tmp = tmp.Double(tmp) + switch i { + case 1, 2: + jac.Set(tmp).AddAssign(&Gjac) + aff.FromJacobian(jac) + table[i-1] = [2]*big.Int{aff.X.BigInt(new(big.Int)), aff.Y.BigInt(new(big.Int))} + case 3: + jac.Set(tmp).SubAssign(&Gjac) + aff.FromJacobian(jac) + table[i-1] = [2]*big.Int{aff.X.BigInt(new(big.Int)), aff.Y.BigInt(new(big.Int))} + fallthrough + default: + aff.FromJacobian(tmp) + table[i] = [2]*big.Int{aff.X.BigInt(new(big.Int)), aff.Y.BigInt(new(big.Int))} + } + } + return table +} diff --git a/std/algebra/weierstrass/point.go b/std/algebra/weierstrass/point.go index fcb648c20d..d076180101 100644 --- a/std/algebra/weierstrass/point.go +++ b/std/algebra/weierstrass/point.go @@ -21,520 +21,12 @@ func New[Base, Scalars emulated.FieldParams](api frontend.API, params CurveParam if err != nil { return nil, fmt.Errorf("new scalar api: %w", err) } + emuGm := make([]AffinePoint[Base], len(params.Gm)) + for i, v := range params.Gm { + emuGm[i] = AffinePoint[Base]{emulated.ValueOf[Base](v[0]), emulated.ValueOf[Base](v[1])} + } Gx := emulated.ValueOf[Base](params.Gx) Gy := emulated.ValueOf[Base](params.Gy) - G3x := emulated.ValueOf[Base](params.Gmx[0]) - G3y := emulated.ValueOf[Base](params.Gmy[0]) - G5x := emulated.ValueOf[Base](params.Gmx[1]) - G5y := emulated.ValueOf[Base](params.Gmy[1]) - G7x := emulated.ValueOf[Base](params.Gmx[2]) - G7y := emulated.ValueOf[Base](params.Gmy[2]) - G2To3x := emulated.ValueOf[Base](params.Gmx[3]) - G2To3y := emulated.ValueOf[Base](params.Gmy[3]) - G2To4x := emulated.ValueOf[Base](params.Gmx[4]) - G2To4y := emulated.ValueOf[Base](params.Gmy[4]) - G2To5x := emulated.ValueOf[Base](params.Gmx[5]) - G2To5y := emulated.ValueOf[Base](params.Gmy[5]) - G2To6x := emulated.ValueOf[Base](params.Gmx[6]) - G2To6y := emulated.ValueOf[Base](params.Gmy[6]) - G2To7x := emulated.ValueOf[Base](params.Gmx[7]) - G2To7y := emulated.ValueOf[Base](params.Gmy[7]) - G2To8x := emulated.ValueOf[Base](params.Gmx[8]) - G2To8y := emulated.ValueOf[Base](params.Gmy[8]) - G2To9x := emulated.ValueOf[Base](params.Gmx[9]) - G2To9y := emulated.ValueOf[Base](params.Gmy[9]) - G2To10x := emulated.ValueOf[Base](params.Gmx[10]) - G2To10y := emulated.ValueOf[Base](params.Gmy[10]) - G2To11x := emulated.ValueOf[Base](params.Gmx[11]) - G2To11y := emulated.ValueOf[Base](params.Gmy[11]) - G2To12x := emulated.ValueOf[Base](params.Gmx[12]) - G2To12y := emulated.ValueOf[Base](params.Gmy[12]) - G2To13x := emulated.ValueOf[Base](params.Gmx[13]) - G2To13y := emulated.ValueOf[Base](params.Gmy[13]) - G2To14x := emulated.ValueOf[Base](params.Gmx[14]) - G2To14y := emulated.ValueOf[Base](params.Gmy[14]) - G2To15x := emulated.ValueOf[Base](params.Gmx[15]) - G2To15y := emulated.ValueOf[Base](params.Gmy[15]) - G2To16x := emulated.ValueOf[Base](params.Gmx[16]) - G2To16y := emulated.ValueOf[Base](params.Gmy[16]) - G2To17x := emulated.ValueOf[Base](params.Gmx[17]) - G2To17y := emulated.ValueOf[Base](params.Gmy[17]) - G2To18x := emulated.ValueOf[Base](params.Gmx[18]) - G2To18y := emulated.ValueOf[Base](params.Gmy[18]) - G2To19x := emulated.ValueOf[Base](params.Gmx[19]) - G2To19y := emulated.ValueOf[Base](params.Gmy[19]) - G2To20x := emulated.ValueOf[Base](params.Gmx[20]) - G2To20y := emulated.ValueOf[Base](params.Gmy[20]) - G2To21x := emulated.ValueOf[Base](params.Gmx[21]) - G2To21y := emulated.ValueOf[Base](params.Gmy[21]) - G2To22x := emulated.ValueOf[Base](params.Gmx[22]) - G2To22y := emulated.ValueOf[Base](params.Gmy[22]) - G2To23x := emulated.ValueOf[Base](params.Gmx[23]) - G2To23y := emulated.ValueOf[Base](params.Gmy[23]) - G2To24x := emulated.ValueOf[Base](params.Gmx[24]) - G2To24y := emulated.ValueOf[Base](params.Gmy[24]) - G2To25x := emulated.ValueOf[Base](params.Gmx[25]) - G2To25y := emulated.ValueOf[Base](params.Gmy[25]) - G2To26x := emulated.ValueOf[Base](params.Gmx[26]) - G2To26y := emulated.ValueOf[Base](params.Gmy[26]) - G2To27x := emulated.ValueOf[Base](params.Gmx[27]) - G2To27y := emulated.ValueOf[Base](params.Gmy[27]) - G2To28x := emulated.ValueOf[Base](params.Gmx[28]) - G2To28y := emulated.ValueOf[Base](params.Gmy[28]) - G2To29x := emulated.ValueOf[Base](params.Gmx[29]) - G2To29y := emulated.ValueOf[Base](params.Gmy[29]) - G2To30x := emulated.ValueOf[Base](params.Gmx[30]) - G2To30y := emulated.ValueOf[Base](params.Gmy[30]) - G2To31x := emulated.ValueOf[Base](params.Gmx[31]) - G2To31y := emulated.ValueOf[Base](params.Gmy[31]) - G2To32x := emulated.ValueOf[Base](params.Gmx[32]) - G2To32y := emulated.ValueOf[Base](params.Gmy[32]) - G2To33x := emulated.ValueOf[Base](params.Gmx[33]) - G2To33y := emulated.ValueOf[Base](params.Gmy[33]) - G2To34x := emulated.ValueOf[Base](params.Gmx[34]) - G2To34y := emulated.ValueOf[Base](params.Gmy[34]) - G2To35x := emulated.ValueOf[Base](params.Gmx[35]) - G2To35y := emulated.ValueOf[Base](params.Gmy[35]) - G2To36x := emulated.ValueOf[Base](params.Gmx[36]) - G2To36y := emulated.ValueOf[Base](params.Gmy[36]) - G2To37x := emulated.ValueOf[Base](params.Gmx[37]) - G2To37y := emulated.ValueOf[Base](params.Gmy[37]) - G2To38x := emulated.ValueOf[Base](params.Gmx[38]) - G2To38y := emulated.ValueOf[Base](params.Gmy[38]) - G2To39x := emulated.ValueOf[Base](params.Gmx[39]) - G2To39y := emulated.ValueOf[Base](params.Gmy[39]) - G2To40x := emulated.ValueOf[Base](params.Gmx[40]) - G2To40y := emulated.ValueOf[Base](params.Gmy[40]) - G2To41x := emulated.ValueOf[Base](params.Gmx[41]) - G2To41y := emulated.ValueOf[Base](params.Gmy[41]) - G2To42x := emulated.ValueOf[Base](params.Gmx[42]) - G2To42y := emulated.ValueOf[Base](params.Gmy[42]) - G2To43x := emulated.ValueOf[Base](params.Gmx[43]) - G2To43y := emulated.ValueOf[Base](params.Gmy[43]) - G2To44x := emulated.ValueOf[Base](params.Gmx[44]) - G2To44y := emulated.ValueOf[Base](params.Gmy[44]) - G2To45x := emulated.ValueOf[Base](params.Gmx[45]) - G2To45y := emulated.ValueOf[Base](params.Gmy[45]) - G2To46x := emulated.ValueOf[Base](params.Gmx[46]) - G2To46y := emulated.ValueOf[Base](params.Gmy[46]) - G2To47x := emulated.ValueOf[Base](params.Gmx[47]) - G2To47y := emulated.ValueOf[Base](params.Gmy[47]) - G2To48x := emulated.ValueOf[Base](params.Gmx[48]) - G2To48y := emulated.ValueOf[Base](params.Gmy[48]) - G2To49x := emulated.ValueOf[Base](params.Gmx[49]) - G2To49y := emulated.ValueOf[Base](params.Gmy[49]) - G2To50x := emulated.ValueOf[Base](params.Gmx[50]) - G2To50y := emulated.ValueOf[Base](params.Gmy[50]) - G2To51x := emulated.ValueOf[Base](params.Gmx[51]) - G2To51y := emulated.ValueOf[Base](params.Gmy[51]) - G2To52x := emulated.ValueOf[Base](params.Gmx[52]) - G2To52y := emulated.ValueOf[Base](params.Gmy[52]) - G2To53x := emulated.ValueOf[Base](params.Gmx[53]) - G2To53y := emulated.ValueOf[Base](params.Gmy[53]) - G2To54x := emulated.ValueOf[Base](params.Gmx[54]) - G2To54y := emulated.ValueOf[Base](params.Gmy[54]) - G2To55x := emulated.ValueOf[Base](params.Gmx[55]) - G2To55y := emulated.ValueOf[Base](params.Gmy[55]) - G2To56x := emulated.ValueOf[Base](params.Gmx[56]) - G2To56y := emulated.ValueOf[Base](params.Gmy[56]) - G2To57x := emulated.ValueOf[Base](params.Gmx[57]) - G2To57y := emulated.ValueOf[Base](params.Gmy[57]) - G2To58x := emulated.ValueOf[Base](params.Gmx[58]) - G2To58y := emulated.ValueOf[Base](params.Gmy[58]) - G2To59x := emulated.ValueOf[Base](params.Gmx[59]) - G2To59y := emulated.ValueOf[Base](params.Gmy[59]) - G2To60x := emulated.ValueOf[Base](params.Gmx[60]) - G2To60y := emulated.ValueOf[Base](params.Gmy[60]) - G2To61x := emulated.ValueOf[Base](params.Gmx[61]) - G2To61y := emulated.ValueOf[Base](params.Gmy[61]) - G2To62x := emulated.ValueOf[Base](params.Gmx[62]) - G2To62y := emulated.ValueOf[Base](params.Gmy[62]) - G2To63x := emulated.ValueOf[Base](params.Gmx[63]) - G2To63y := emulated.ValueOf[Base](params.Gmy[63]) - G2To64x := emulated.ValueOf[Base](params.Gmx[64]) - G2To64y := emulated.ValueOf[Base](params.Gmy[64]) - G2To65x := emulated.ValueOf[Base](params.Gmx[65]) - G2To65y := emulated.ValueOf[Base](params.Gmy[65]) - G2To66x := emulated.ValueOf[Base](params.Gmx[66]) - G2To66y := emulated.ValueOf[Base](params.Gmy[66]) - G2To67x := emulated.ValueOf[Base](params.Gmx[67]) - G2To67y := emulated.ValueOf[Base](params.Gmy[67]) - G2To68x := emulated.ValueOf[Base](params.Gmx[68]) - G2To68y := emulated.ValueOf[Base](params.Gmy[68]) - G2To69x := emulated.ValueOf[Base](params.Gmx[69]) - G2To69y := emulated.ValueOf[Base](params.Gmy[69]) - G2To70x := emulated.ValueOf[Base](params.Gmx[70]) - G2To70y := emulated.ValueOf[Base](params.Gmy[70]) - G2To71x := emulated.ValueOf[Base](params.Gmx[71]) - G2To71y := emulated.ValueOf[Base](params.Gmy[71]) - G2To72x := emulated.ValueOf[Base](params.Gmx[72]) - G2To72y := emulated.ValueOf[Base](params.Gmy[72]) - G2To73x := emulated.ValueOf[Base](params.Gmx[73]) - G2To73y := emulated.ValueOf[Base](params.Gmy[73]) - G2To74x := emulated.ValueOf[Base](params.Gmx[74]) - G2To74y := emulated.ValueOf[Base](params.Gmy[74]) - G2To75x := emulated.ValueOf[Base](params.Gmx[75]) - G2To75y := emulated.ValueOf[Base](params.Gmy[75]) - G2To76x := emulated.ValueOf[Base](params.Gmx[76]) - G2To76y := emulated.ValueOf[Base](params.Gmy[76]) - G2To77x := emulated.ValueOf[Base](params.Gmx[77]) - G2To77y := emulated.ValueOf[Base](params.Gmy[77]) - G2To78x := emulated.ValueOf[Base](params.Gmx[78]) - G2To78y := emulated.ValueOf[Base](params.Gmy[78]) - G2To79x := emulated.ValueOf[Base](params.Gmx[79]) - G2To79y := emulated.ValueOf[Base](params.Gmy[79]) - G2To80x := emulated.ValueOf[Base](params.Gmx[80]) - G2To80y := emulated.ValueOf[Base](params.Gmy[80]) - G2To81x := emulated.ValueOf[Base](params.Gmx[81]) - G2To81y := emulated.ValueOf[Base](params.Gmy[81]) - G2To82x := emulated.ValueOf[Base](params.Gmx[82]) - G2To82y := emulated.ValueOf[Base](params.Gmy[82]) - G2To83x := emulated.ValueOf[Base](params.Gmx[83]) - G2To83y := emulated.ValueOf[Base](params.Gmy[83]) - G2To84x := emulated.ValueOf[Base](params.Gmx[84]) - G2To84y := emulated.ValueOf[Base](params.Gmy[84]) - G2To85x := emulated.ValueOf[Base](params.Gmx[85]) - G2To85y := emulated.ValueOf[Base](params.Gmy[85]) - G2To86x := emulated.ValueOf[Base](params.Gmx[86]) - G2To86y := emulated.ValueOf[Base](params.Gmy[86]) - G2To87x := emulated.ValueOf[Base](params.Gmx[87]) - G2To87y := emulated.ValueOf[Base](params.Gmy[87]) - G2To88x := emulated.ValueOf[Base](params.Gmx[88]) - G2To88y := emulated.ValueOf[Base](params.Gmy[88]) - G2To89x := emulated.ValueOf[Base](params.Gmx[89]) - G2To89y := emulated.ValueOf[Base](params.Gmy[89]) - G2To90x := emulated.ValueOf[Base](params.Gmx[90]) - G2To90y := emulated.ValueOf[Base](params.Gmy[90]) - G2To91x := emulated.ValueOf[Base](params.Gmx[91]) - G2To91y := emulated.ValueOf[Base](params.Gmy[91]) - G2To92x := emulated.ValueOf[Base](params.Gmx[92]) - G2To92y := emulated.ValueOf[Base](params.Gmy[92]) - G2To93x := emulated.ValueOf[Base](params.Gmx[93]) - G2To93y := emulated.ValueOf[Base](params.Gmy[93]) - G2To94x := emulated.ValueOf[Base](params.Gmx[94]) - G2To94y := emulated.ValueOf[Base](params.Gmy[94]) - G2To95x := emulated.ValueOf[Base](params.Gmx[95]) - G2To95y := emulated.ValueOf[Base](params.Gmy[95]) - G2To96x := emulated.ValueOf[Base](params.Gmx[96]) - G2To96y := emulated.ValueOf[Base](params.Gmy[96]) - G2To97x := emulated.ValueOf[Base](params.Gmx[97]) - G2To97y := emulated.ValueOf[Base](params.Gmy[97]) - G2To98x := emulated.ValueOf[Base](params.Gmx[98]) - G2To98y := emulated.ValueOf[Base](params.Gmy[98]) - G2To99x := emulated.ValueOf[Base](params.Gmx[99]) - G2To99y := emulated.ValueOf[Base](params.Gmy[99]) - G2To100x := emulated.ValueOf[Base](params.Gmx[100]) - G2To100y := emulated.ValueOf[Base](params.Gmy[100]) - G2To101x := emulated.ValueOf[Base](params.Gmx[101]) - G2To101y := emulated.ValueOf[Base](params.Gmy[101]) - G2To102x := emulated.ValueOf[Base](params.Gmx[102]) - G2To102y := emulated.ValueOf[Base](params.Gmy[102]) - G2To103x := emulated.ValueOf[Base](params.Gmx[103]) - G2To103y := emulated.ValueOf[Base](params.Gmy[103]) - G2To104x := emulated.ValueOf[Base](params.Gmx[104]) - G2To104y := emulated.ValueOf[Base](params.Gmy[104]) - G2To105x := emulated.ValueOf[Base](params.Gmx[105]) - G2To105y := emulated.ValueOf[Base](params.Gmy[105]) - G2To106x := emulated.ValueOf[Base](params.Gmx[106]) - G2To106y := emulated.ValueOf[Base](params.Gmy[106]) - G2To107x := emulated.ValueOf[Base](params.Gmx[107]) - G2To107y := emulated.ValueOf[Base](params.Gmy[107]) - G2To108x := emulated.ValueOf[Base](params.Gmx[108]) - G2To108y := emulated.ValueOf[Base](params.Gmy[108]) - G2To109x := emulated.ValueOf[Base](params.Gmx[109]) - G2To109y := emulated.ValueOf[Base](params.Gmy[109]) - G2To110x := emulated.ValueOf[Base](params.Gmx[110]) - G2To110y := emulated.ValueOf[Base](params.Gmy[110]) - G2To111x := emulated.ValueOf[Base](params.Gmx[111]) - G2To111y := emulated.ValueOf[Base](params.Gmy[111]) - G2To112x := emulated.ValueOf[Base](params.Gmx[112]) - G2To112y := emulated.ValueOf[Base](params.Gmy[112]) - G2To113x := emulated.ValueOf[Base](params.Gmx[113]) - G2To113y := emulated.ValueOf[Base](params.Gmy[113]) - G2To114x := emulated.ValueOf[Base](params.Gmx[114]) - G2To114y := emulated.ValueOf[Base](params.Gmy[114]) - G2To115x := emulated.ValueOf[Base](params.Gmx[115]) - G2To115y := emulated.ValueOf[Base](params.Gmy[115]) - G2To116x := emulated.ValueOf[Base](params.Gmx[116]) - G2To116y := emulated.ValueOf[Base](params.Gmy[116]) - G2To117x := emulated.ValueOf[Base](params.Gmx[117]) - G2To117y := emulated.ValueOf[Base](params.Gmy[117]) - G2To118x := emulated.ValueOf[Base](params.Gmx[118]) - G2To118y := emulated.ValueOf[Base](params.Gmy[118]) - G2To119x := emulated.ValueOf[Base](params.Gmx[119]) - G2To119y := emulated.ValueOf[Base](params.Gmy[119]) - G2To120x := emulated.ValueOf[Base](params.Gmx[120]) - G2To120y := emulated.ValueOf[Base](params.Gmy[120]) - G2To121x := emulated.ValueOf[Base](params.Gmx[121]) - G2To121y := emulated.ValueOf[Base](params.Gmy[121]) - G2To122x := emulated.ValueOf[Base](params.Gmx[122]) - G2To122y := emulated.ValueOf[Base](params.Gmy[122]) - G2To123x := emulated.ValueOf[Base](params.Gmx[123]) - G2To123y := emulated.ValueOf[Base](params.Gmy[123]) - G2To124x := emulated.ValueOf[Base](params.Gmx[124]) - G2To124y := emulated.ValueOf[Base](params.Gmy[124]) - G2To125x := emulated.ValueOf[Base](params.Gmx[125]) - G2To125y := emulated.ValueOf[Base](params.Gmy[125]) - G2To126x := emulated.ValueOf[Base](params.Gmx[126]) - G2To126y := emulated.ValueOf[Base](params.Gmy[126]) - G2To127x := emulated.ValueOf[Base](params.Gmx[127]) - G2To127y := emulated.ValueOf[Base](params.Gmy[127]) - G2To128x := emulated.ValueOf[Base](params.Gmx[128]) - G2To128y := emulated.ValueOf[Base](params.Gmy[128]) - G2To129x := emulated.ValueOf[Base](params.Gmx[129]) - G2To129y := emulated.ValueOf[Base](params.Gmy[129]) - G2To130x := emulated.ValueOf[Base](params.Gmx[130]) - G2To130y := emulated.ValueOf[Base](params.Gmy[130]) - G2To131x := emulated.ValueOf[Base](params.Gmx[131]) - G2To131y := emulated.ValueOf[Base](params.Gmy[131]) - G2To132x := emulated.ValueOf[Base](params.Gmx[132]) - G2To132y := emulated.ValueOf[Base](params.Gmy[132]) - G2To133x := emulated.ValueOf[Base](params.Gmx[133]) - G2To133y := emulated.ValueOf[Base](params.Gmy[133]) - G2To134x := emulated.ValueOf[Base](params.Gmx[134]) - G2To134y := emulated.ValueOf[Base](params.Gmy[134]) - G2To135x := emulated.ValueOf[Base](params.Gmx[135]) - G2To135y := emulated.ValueOf[Base](params.Gmy[135]) - G2To136x := emulated.ValueOf[Base](params.Gmx[136]) - G2To136y := emulated.ValueOf[Base](params.Gmy[136]) - G2To137x := emulated.ValueOf[Base](params.Gmx[137]) - G2To137y := emulated.ValueOf[Base](params.Gmy[137]) - G2To138x := emulated.ValueOf[Base](params.Gmx[138]) - G2To138y := emulated.ValueOf[Base](params.Gmy[138]) - G2To139x := emulated.ValueOf[Base](params.Gmx[139]) - G2To139y := emulated.ValueOf[Base](params.Gmy[139]) - G2To140x := emulated.ValueOf[Base](params.Gmx[140]) - G2To140y := emulated.ValueOf[Base](params.Gmy[140]) - G2To141x := emulated.ValueOf[Base](params.Gmx[141]) - G2To141y := emulated.ValueOf[Base](params.Gmy[141]) - G2To142x := emulated.ValueOf[Base](params.Gmx[142]) - G2To142y := emulated.ValueOf[Base](params.Gmy[142]) - G2To143x := emulated.ValueOf[Base](params.Gmx[143]) - G2To143y := emulated.ValueOf[Base](params.Gmy[143]) - G2To144x := emulated.ValueOf[Base](params.Gmx[144]) - G2To144y := emulated.ValueOf[Base](params.Gmy[144]) - G2To145x := emulated.ValueOf[Base](params.Gmx[145]) - G2To145y := emulated.ValueOf[Base](params.Gmy[145]) - G2To146x := emulated.ValueOf[Base](params.Gmx[146]) - G2To146y := emulated.ValueOf[Base](params.Gmy[146]) - G2To147x := emulated.ValueOf[Base](params.Gmx[147]) - G2To147y := emulated.ValueOf[Base](params.Gmy[147]) - G2To148x := emulated.ValueOf[Base](params.Gmx[148]) - G2To148y := emulated.ValueOf[Base](params.Gmy[148]) - G2To149x := emulated.ValueOf[Base](params.Gmx[149]) - G2To149y := emulated.ValueOf[Base](params.Gmy[149]) - G2To150x := emulated.ValueOf[Base](params.Gmx[150]) - G2To150y := emulated.ValueOf[Base](params.Gmy[150]) - G2To151x := emulated.ValueOf[Base](params.Gmx[151]) - G2To151y := emulated.ValueOf[Base](params.Gmy[151]) - G2To152x := emulated.ValueOf[Base](params.Gmx[152]) - G2To152y := emulated.ValueOf[Base](params.Gmy[152]) - G2To153x := emulated.ValueOf[Base](params.Gmx[153]) - G2To153y := emulated.ValueOf[Base](params.Gmy[153]) - G2To154x := emulated.ValueOf[Base](params.Gmx[154]) - G2To154y := emulated.ValueOf[Base](params.Gmy[154]) - G2To155x := emulated.ValueOf[Base](params.Gmx[155]) - G2To155y := emulated.ValueOf[Base](params.Gmy[155]) - G2To156x := emulated.ValueOf[Base](params.Gmx[156]) - G2To156y := emulated.ValueOf[Base](params.Gmy[156]) - G2To157x := emulated.ValueOf[Base](params.Gmx[157]) - G2To157y := emulated.ValueOf[Base](params.Gmy[157]) - G2To158x := emulated.ValueOf[Base](params.Gmx[158]) - G2To158y := emulated.ValueOf[Base](params.Gmy[158]) - G2To159x := emulated.ValueOf[Base](params.Gmx[159]) - G2To159y := emulated.ValueOf[Base](params.Gmy[159]) - G2To160x := emulated.ValueOf[Base](params.Gmx[160]) - G2To160y := emulated.ValueOf[Base](params.Gmy[160]) - G2To161x := emulated.ValueOf[Base](params.Gmx[161]) - G2To161y := emulated.ValueOf[Base](params.Gmy[161]) - G2To162x := emulated.ValueOf[Base](params.Gmx[162]) - G2To162y := emulated.ValueOf[Base](params.Gmy[162]) - G2To163x := emulated.ValueOf[Base](params.Gmx[163]) - G2To163y := emulated.ValueOf[Base](params.Gmy[163]) - G2To164x := emulated.ValueOf[Base](params.Gmx[164]) - G2To164y := emulated.ValueOf[Base](params.Gmy[164]) - G2To165x := emulated.ValueOf[Base](params.Gmx[165]) - G2To165y := emulated.ValueOf[Base](params.Gmy[165]) - G2To166x := emulated.ValueOf[Base](params.Gmx[166]) - G2To166y := emulated.ValueOf[Base](params.Gmy[166]) - G2To167x := emulated.ValueOf[Base](params.Gmx[167]) - G2To167y := emulated.ValueOf[Base](params.Gmy[167]) - G2To168x := emulated.ValueOf[Base](params.Gmx[168]) - G2To168y := emulated.ValueOf[Base](params.Gmy[168]) - G2To169x := emulated.ValueOf[Base](params.Gmx[169]) - G2To169y := emulated.ValueOf[Base](params.Gmy[169]) - G2To170x := emulated.ValueOf[Base](params.Gmx[170]) - G2To170y := emulated.ValueOf[Base](params.Gmy[170]) - G2To171x := emulated.ValueOf[Base](params.Gmx[171]) - G2To171y := emulated.ValueOf[Base](params.Gmy[171]) - G2To172x := emulated.ValueOf[Base](params.Gmx[172]) - G2To172y := emulated.ValueOf[Base](params.Gmy[172]) - G2To173x := emulated.ValueOf[Base](params.Gmx[173]) - G2To173y := emulated.ValueOf[Base](params.Gmy[173]) - G2To174x := emulated.ValueOf[Base](params.Gmx[174]) - G2To174y := emulated.ValueOf[Base](params.Gmy[174]) - G2To175x := emulated.ValueOf[Base](params.Gmx[175]) - G2To175y := emulated.ValueOf[Base](params.Gmy[175]) - G2To176x := emulated.ValueOf[Base](params.Gmx[176]) - G2To176y := emulated.ValueOf[Base](params.Gmy[176]) - G2To177x := emulated.ValueOf[Base](params.Gmx[177]) - G2To177y := emulated.ValueOf[Base](params.Gmy[177]) - G2To178x := emulated.ValueOf[Base](params.Gmx[178]) - G2To178y := emulated.ValueOf[Base](params.Gmy[178]) - G2To179x := emulated.ValueOf[Base](params.Gmx[179]) - G2To179y := emulated.ValueOf[Base](params.Gmy[179]) - G2To180x := emulated.ValueOf[Base](params.Gmx[180]) - G2To180y := emulated.ValueOf[Base](params.Gmy[180]) - G2To181x := emulated.ValueOf[Base](params.Gmx[181]) - G2To181y := emulated.ValueOf[Base](params.Gmy[181]) - G2To182x := emulated.ValueOf[Base](params.Gmx[182]) - G2To182y := emulated.ValueOf[Base](params.Gmy[182]) - G2To183x := emulated.ValueOf[Base](params.Gmx[183]) - G2To183y := emulated.ValueOf[Base](params.Gmy[183]) - G2To184x := emulated.ValueOf[Base](params.Gmx[184]) - G2To184y := emulated.ValueOf[Base](params.Gmy[184]) - G2To185x := emulated.ValueOf[Base](params.Gmx[185]) - G2To185y := emulated.ValueOf[Base](params.Gmy[185]) - G2To186x := emulated.ValueOf[Base](params.Gmx[186]) - G2To186y := emulated.ValueOf[Base](params.Gmy[186]) - G2To187x := emulated.ValueOf[Base](params.Gmx[187]) - G2To187y := emulated.ValueOf[Base](params.Gmy[187]) - G2To188x := emulated.ValueOf[Base](params.Gmx[188]) - G2To188y := emulated.ValueOf[Base](params.Gmy[188]) - G2To189x := emulated.ValueOf[Base](params.Gmx[189]) - G2To189y := emulated.ValueOf[Base](params.Gmy[189]) - G2To190x := emulated.ValueOf[Base](params.Gmx[190]) - G2To190y := emulated.ValueOf[Base](params.Gmy[190]) - G2To191x := emulated.ValueOf[Base](params.Gmx[191]) - G2To191y := emulated.ValueOf[Base](params.Gmy[191]) - G2To192x := emulated.ValueOf[Base](params.Gmx[192]) - G2To192y := emulated.ValueOf[Base](params.Gmy[192]) - G2To193x := emulated.ValueOf[Base](params.Gmx[193]) - G2To193y := emulated.ValueOf[Base](params.Gmy[193]) - G2To194x := emulated.ValueOf[Base](params.Gmx[194]) - G2To194y := emulated.ValueOf[Base](params.Gmy[194]) - G2To195x := emulated.ValueOf[Base](params.Gmx[195]) - G2To195y := emulated.ValueOf[Base](params.Gmy[195]) - G2To196x := emulated.ValueOf[Base](params.Gmx[196]) - G2To196y := emulated.ValueOf[Base](params.Gmy[196]) - G2To197x := emulated.ValueOf[Base](params.Gmx[197]) - G2To197y := emulated.ValueOf[Base](params.Gmy[197]) - G2To198x := emulated.ValueOf[Base](params.Gmx[198]) - G2To198y := emulated.ValueOf[Base](params.Gmy[198]) - G2To199x := emulated.ValueOf[Base](params.Gmx[199]) - G2To199y := emulated.ValueOf[Base](params.Gmy[199]) - G2To200x := emulated.ValueOf[Base](params.Gmx[200]) - G2To200y := emulated.ValueOf[Base](params.Gmy[200]) - G2To201x := emulated.ValueOf[Base](params.Gmx[201]) - G2To201y := emulated.ValueOf[Base](params.Gmy[201]) - G2To202x := emulated.ValueOf[Base](params.Gmx[202]) - G2To202y := emulated.ValueOf[Base](params.Gmy[202]) - G2To203x := emulated.ValueOf[Base](params.Gmx[203]) - G2To203y := emulated.ValueOf[Base](params.Gmy[203]) - G2To204x := emulated.ValueOf[Base](params.Gmx[204]) - G2To204y := emulated.ValueOf[Base](params.Gmy[204]) - G2To205x := emulated.ValueOf[Base](params.Gmx[205]) - G2To205y := emulated.ValueOf[Base](params.Gmy[205]) - G2To206x := emulated.ValueOf[Base](params.Gmx[206]) - G2To206y := emulated.ValueOf[Base](params.Gmy[206]) - G2To207x := emulated.ValueOf[Base](params.Gmx[207]) - G2To207y := emulated.ValueOf[Base](params.Gmy[207]) - G2To208x := emulated.ValueOf[Base](params.Gmx[208]) - G2To208y := emulated.ValueOf[Base](params.Gmy[208]) - G2To209x := emulated.ValueOf[Base](params.Gmx[209]) - G2To209y := emulated.ValueOf[Base](params.Gmy[209]) - G2To210x := emulated.ValueOf[Base](params.Gmx[210]) - G2To210y := emulated.ValueOf[Base](params.Gmy[210]) - G2To211x := emulated.ValueOf[Base](params.Gmx[211]) - G2To211y := emulated.ValueOf[Base](params.Gmy[211]) - G2To212x := emulated.ValueOf[Base](params.Gmx[212]) - G2To212y := emulated.ValueOf[Base](params.Gmy[212]) - G2To213x := emulated.ValueOf[Base](params.Gmx[213]) - G2To213y := emulated.ValueOf[Base](params.Gmy[213]) - G2To214x := emulated.ValueOf[Base](params.Gmx[214]) - G2To214y := emulated.ValueOf[Base](params.Gmy[214]) - G2To215x := emulated.ValueOf[Base](params.Gmx[215]) - G2To215y := emulated.ValueOf[Base](params.Gmy[215]) - G2To216x := emulated.ValueOf[Base](params.Gmx[216]) - G2To216y := emulated.ValueOf[Base](params.Gmy[216]) - G2To217x := emulated.ValueOf[Base](params.Gmx[217]) - G2To217y := emulated.ValueOf[Base](params.Gmy[217]) - G2To218x := emulated.ValueOf[Base](params.Gmx[218]) - G2To218y := emulated.ValueOf[Base](params.Gmy[218]) - G2To219x := emulated.ValueOf[Base](params.Gmx[219]) - G2To219y := emulated.ValueOf[Base](params.Gmy[219]) - G2To220x := emulated.ValueOf[Base](params.Gmx[220]) - G2To220y := emulated.ValueOf[Base](params.Gmy[220]) - G2To221x := emulated.ValueOf[Base](params.Gmx[221]) - G2To221y := emulated.ValueOf[Base](params.Gmy[221]) - G2To222x := emulated.ValueOf[Base](params.Gmx[222]) - G2To222y := emulated.ValueOf[Base](params.Gmy[222]) - G2To223x := emulated.ValueOf[Base](params.Gmx[223]) - G2To223y := emulated.ValueOf[Base](params.Gmy[223]) - G2To224x := emulated.ValueOf[Base](params.Gmx[224]) - G2To224y := emulated.ValueOf[Base](params.Gmy[224]) - G2To225x := emulated.ValueOf[Base](params.Gmx[225]) - G2To225y := emulated.ValueOf[Base](params.Gmy[225]) - G2To226x := emulated.ValueOf[Base](params.Gmx[226]) - G2To226y := emulated.ValueOf[Base](params.Gmy[226]) - G2To227x := emulated.ValueOf[Base](params.Gmx[227]) - G2To227y := emulated.ValueOf[Base](params.Gmy[227]) - G2To228x := emulated.ValueOf[Base](params.Gmx[228]) - G2To228y := emulated.ValueOf[Base](params.Gmy[228]) - G2To229x := emulated.ValueOf[Base](params.Gmx[229]) - G2To229y := emulated.ValueOf[Base](params.Gmy[229]) - G2To230x := emulated.ValueOf[Base](params.Gmx[230]) - G2To230y := emulated.ValueOf[Base](params.Gmy[230]) - G2To231x := emulated.ValueOf[Base](params.Gmx[231]) - G2To231y := emulated.ValueOf[Base](params.Gmy[231]) - G2To232x := emulated.ValueOf[Base](params.Gmx[232]) - G2To232y := emulated.ValueOf[Base](params.Gmy[232]) - G2To233x := emulated.ValueOf[Base](params.Gmx[233]) - G2To233y := emulated.ValueOf[Base](params.Gmy[233]) - G2To234x := emulated.ValueOf[Base](params.Gmx[234]) - G2To234y := emulated.ValueOf[Base](params.Gmy[234]) - G2To235x := emulated.ValueOf[Base](params.Gmx[235]) - G2To235y := emulated.ValueOf[Base](params.Gmy[235]) - G2To236x := emulated.ValueOf[Base](params.Gmx[236]) - G2To236y := emulated.ValueOf[Base](params.Gmy[236]) - G2To237x := emulated.ValueOf[Base](params.Gmx[237]) - G2To237y := emulated.ValueOf[Base](params.Gmy[237]) - G2To238x := emulated.ValueOf[Base](params.Gmx[238]) - G2To238y := emulated.ValueOf[Base](params.Gmy[238]) - G2To239x := emulated.ValueOf[Base](params.Gmx[239]) - G2To239y := emulated.ValueOf[Base](params.Gmy[239]) - G2To240x := emulated.ValueOf[Base](params.Gmx[240]) - G2To240y := emulated.ValueOf[Base](params.Gmy[240]) - G2To241x := emulated.ValueOf[Base](params.Gmx[241]) - G2To241y := emulated.ValueOf[Base](params.Gmy[241]) - G2To242x := emulated.ValueOf[Base](params.Gmx[242]) - G2To242y := emulated.ValueOf[Base](params.Gmy[242]) - G2To243x := emulated.ValueOf[Base](params.Gmx[243]) - G2To243y := emulated.ValueOf[Base](params.Gmy[243]) - G2To244x := emulated.ValueOf[Base](params.Gmx[244]) - G2To244y := emulated.ValueOf[Base](params.Gmy[244]) - G2To245x := emulated.ValueOf[Base](params.Gmx[245]) - G2To245y := emulated.ValueOf[Base](params.Gmy[245]) - G2To246x := emulated.ValueOf[Base](params.Gmx[246]) - G2To246y := emulated.ValueOf[Base](params.Gmy[246]) - G2To247x := emulated.ValueOf[Base](params.Gmx[247]) - G2To247y := emulated.ValueOf[Base](params.Gmy[247]) - G2To248x := emulated.ValueOf[Base](params.Gmx[248]) - G2To248y := emulated.ValueOf[Base](params.Gmy[248]) - G2To249x := emulated.ValueOf[Base](params.Gmx[249]) - G2To249y := emulated.ValueOf[Base](params.Gmy[249]) - G2To250x := emulated.ValueOf[Base](params.Gmx[250]) - G2To250y := emulated.ValueOf[Base](params.Gmy[250]) - G2To251x := emulated.ValueOf[Base](params.Gmx[251]) - G2To251y := emulated.ValueOf[Base](params.Gmy[251]) - G2To252x := emulated.ValueOf[Base](params.Gmx[252]) - G2To252y := emulated.ValueOf[Base](params.Gmy[252]) - G2To253x := emulated.ValueOf[Base](params.Gmx[253]) - G2To253y := emulated.ValueOf[Base](params.Gmy[253]) - G2To254x := emulated.ValueOf[Base](params.Gmx[254]) - G2To254y := emulated.ValueOf[Base](params.Gmy[254]) - G2To255x := emulated.ValueOf[Base](params.Gmx[255]) - G2To255y := emulated.ValueOf[Base](params.Gmy[255]) return &Curve[Base, Scalars]{ params: params, api: api, @@ -544,265 +36,7 @@ func New[Base, Scalars emulated.FieldParams](api frontend.API, params CurveParam X: Gx, Y: Gy, }, - gm: [256]AffinePoint[Base]{ - {X: G3x, Y: G3y}, - {X: G5x, Y: G5y}, - {X: G7x, Y: G7y}, - {X: G2To3x, Y: G2To3y}, - {X: G2To4x, Y: G2To4y}, - {X: G2To5x, Y: G2To5y}, - {X: G2To6x, Y: G2To6y}, - {X: G2To7x, Y: G2To7y}, - {X: G2To8x, Y: G2To8y}, - {X: G2To9x, Y: G2To9y}, - {X: G2To10x, Y: G2To10y}, - {X: G2To11x, Y: G2To11y}, - {X: G2To12x, Y: G2To12y}, - {X: G2To13x, Y: G2To13y}, - {X: G2To14x, Y: G2To14y}, - {X: G2To15x, Y: G2To15y}, - {X: G2To16x, Y: G2To16y}, - {X: G2To17x, Y: G2To17y}, - {X: G2To18x, Y: G2To18y}, - {X: G2To19x, Y: G2To19y}, - {X: G2To20x, Y: G2To20y}, - {X: G2To21x, Y: G2To21y}, - {X: G2To22x, Y: G2To22y}, - {X: G2To23x, Y: G2To23y}, - {X: G2To24x, Y: G2To24y}, - {X: G2To25x, Y: G2To25y}, - {X: G2To26x, Y: G2To26y}, - {X: G2To27x, Y: G2To27y}, - {X: G2To28x, Y: G2To28y}, - {X: G2To29x, Y: G2To29y}, - {X: G2To30x, Y: G2To30y}, - {X: G2To31x, Y: G2To31y}, - {X: G2To32x, Y: G2To32y}, - {X: G2To33x, Y: G2To33y}, - {X: G2To34x, Y: G2To34y}, - {X: G2To35x, Y: G2To35y}, - {X: G2To36x, Y: G2To36y}, - {X: G2To37x, Y: G2To37y}, - {X: G2To38x, Y: G2To38y}, - {X: G2To39x, Y: G2To39y}, - {X: G2To40x, Y: G2To40y}, - {X: G2To41x, Y: G2To41y}, - {X: G2To42x, Y: G2To42y}, - {X: G2To43x, Y: G2To43y}, - {X: G2To44x, Y: G2To44y}, - {X: G2To45x, Y: G2To45y}, - {X: G2To46x, Y: G2To46y}, - {X: G2To47x, Y: G2To47y}, - {X: G2To48x, Y: G2To48y}, - {X: G2To49x, Y: G2To49y}, - {X: G2To50x, Y: G2To50y}, - {X: G2To51x, Y: G2To51y}, - {X: G2To52x, Y: G2To52y}, - {X: G2To53x, Y: G2To53y}, - {X: G2To54x, Y: G2To54y}, - {X: G2To55x, Y: G2To55y}, - {X: G2To56x, Y: G2To56y}, - {X: G2To57x, Y: G2To57y}, - {X: G2To58x, Y: G2To58y}, - {X: G2To59x, Y: G2To59y}, - {X: G2To60x, Y: G2To60y}, - {X: G2To61x, Y: G2To61y}, - {X: G2To62x, Y: G2To62y}, - {X: G2To63x, Y: G2To63y}, - {X: G2To64x, Y: G2To64y}, - {X: G2To65x, Y: G2To65y}, - {X: G2To66x, Y: G2To66y}, - {X: G2To67x, Y: G2To67y}, - {X: G2To68x, Y: G2To68y}, - {X: G2To69x, Y: G2To69y}, - {X: G2To70x, Y: G2To70y}, - {X: G2To71x, Y: G2To71y}, - {X: G2To72x, Y: G2To72y}, - {X: G2To73x, Y: G2To73y}, - {X: G2To74x, Y: G2To74y}, - {X: G2To75x, Y: G2To75y}, - {X: G2To76x, Y: G2To76y}, - {X: G2To77x, Y: G2To77y}, - {X: G2To78x, Y: G2To78y}, - {X: G2To79x, Y: G2To79y}, - {X: G2To80x, Y: G2To80y}, - {X: G2To81x, Y: G2To81y}, - {X: G2To82x, Y: G2To82y}, - {X: G2To83x, Y: G2To83y}, - {X: G2To84x, Y: G2To84y}, - {X: G2To85x, Y: G2To85y}, - {X: G2To86x, Y: G2To86y}, - {X: G2To87x, Y: G2To87y}, - {X: G2To88x, Y: G2To88y}, - {X: G2To89x, Y: G2To89y}, - {X: G2To90x, Y: G2To90y}, - {X: G2To91x, Y: G2To91y}, - {X: G2To92x, Y: G2To92y}, - {X: G2To93x, Y: G2To93y}, - {X: G2To94x, Y: G2To94y}, - {X: G2To95x, Y: G2To95y}, - {X: G2To96x, Y: G2To96y}, - {X: G2To97x, Y: G2To97y}, - {X: G2To98x, Y: G2To98y}, - {X: G2To99x, Y: G2To99y}, - {X: G2To100x, Y: G2To100y}, - {X: G2To101x, Y: G2To101y}, - {X: G2To102x, Y: G2To102y}, - {X: G2To103x, Y: G2To103y}, - {X: G2To104x, Y: G2To104y}, - {X: G2To105x, Y: G2To105y}, - {X: G2To106x, Y: G2To106y}, - {X: G2To107x, Y: G2To107y}, - {X: G2To108x, Y: G2To108y}, - {X: G2To109x, Y: G2To109y}, - {X: G2To110x, Y: G2To110y}, - {X: G2To111x, Y: G2To111y}, - {X: G2To112x, Y: G2To112y}, - {X: G2To113x, Y: G2To113y}, - {X: G2To114x, Y: G2To114y}, - {X: G2To115x, Y: G2To115y}, - {X: G2To116x, Y: G2To116y}, - {X: G2To117x, Y: G2To117y}, - {X: G2To118x, Y: G2To118y}, - {X: G2To119x, Y: G2To119y}, - {X: G2To120x, Y: G2To120y}, - {X: G2To121x, Y: G2To121y}, - {X: G2To122x, Y: G2To122y}, - {X: G2To123x, Y: G2To123y}, - {X: G2To124x, Y: G2To124y}, - {X: G2To125x, Y: G2To125y}, - {X: G2To126x, Y: G2To126y}, - {X: G2To127x, Y: G2To127y}, - {X: G2To128x, Y: G2To128y}, - {X: G2To129x, Y: G2To129y}, - {X: G2To130x, Y: G2To130y}, - {X: G2To131x, Y: G2To131y}, - {X: G2To132x, Y: G2To132y}, - {X: G2To133x, Y: G2To133y}, - {X: G2To134x, Y: G2To134y}, - {X: G2To135x, Y: G2To135y}, - {X: G2To136x, Y: G2To136y}, - {X: G2To137x, Y: G2To137y}, - {X: G2To138x, Y: G2To138y}, - {X: G2To139x, Y: G2To139y}, - {X: G2To140x, Y: G2To140y}, - {X: G2To141x, Y: G2To141y}, - {X: G2To142x, Y: G2To142y}, - {X: G2To143x, Y: G2To143y}, - {X: G2To144x, Y: G2To144y}, - {X: G2To145x, Y: G2To145y}, - {X: G2To146x, Y: G2To146y}, - {X: G2To147x, Y: G2To147y}, - {X: G2To148x, Y: G2To148y}, - {X: G2To149x, Y: G2To149y}, - {X: G2To150x, Y: G2To150y}, - {X: G2To151x, Y: G2To151y}, - {X: G2To152x, Y: G2To152y}, - {X: G2To153x, Y: G2To153y}, - {X: G2To154x, Y: G2To154y}, - {X: G2To155x, Y: G2To155y}, - {X: G2To156x, Y: G2To156y}, - {X: G2To157x, Y: G2To157y}, - {X: G2To158x, Y: G2To158y}, - {X: G2To159x, Y: G2To159y}, - {X: G2To160x, Y: G2To160y}, - {X: G2To161x, Y: G2To161y}, - {X: G2To162x, Y: G2To162y}, - {X: G2To163x, Y: G2To163y}, - {X: G2To164x, Y: G2To164y}, - {X: G2To165x, Y: G2To165y}, - {X: G2To166x, Y: G2To166y}, - {X: G2To167x, Y: G2To167y}, - {X: G2To168x, Y: G2To168y}, - {X: G2To169x, Y: G2To169y}, - {X: G2To170x, Y: G2To170y}, - {X: G2To171x, Y: G2To171y}, - {X: G2To172x, Y: G2To172y}, - {X: G2To173x, Y: G2To173y}, - {X: G2To174x, Y: G2To174y}, - {X: G2To175x, Y: G2To175y}, - {X: G2To176x, Y: G2To176y}, - {X: G2To177x, Y: G2To177y}, - {X: G2To178x, Y: G2To178y}, - {X: G2To179x, Y: G2To179y}, - {X: G2To180x, Y: G2To180y}, - {X: G2To181x, Y: G2To181y}, - {X: G2To182x, Y: G2To182y}, - {X: G2To183x, Y: G2To183y}, - {X: G2To184x, Y: G2To184y}, - {X: G2To185x, Y: G2To185y}, - {X: G2To186x, Y: G2To186y}, - {X: G2To187x, Y: G2To187y}, - {X: G2To188x, Y: G2To188y}, - {X: G2To189x, Y: G2To189y}, - {X: G2To190x, Y: G2To190y}, - {X: G2To191x, Y: G2To191y}, - {X: G2To192x, Y: G2To192y}, - {X: G2To193x, Y: G2To193y}, - {X: G2To194x, Y: G2To194y}, - {X: G2To195x, Y: G2To195y}, - {X: G2To196x, Y: G2To196y}, - {X: G2To197x, Y: G2To197y}, - {X: G2To198x, Y: G2To198y}, - {X: G2To199x, Y: G2To199y}, - {X: G2To200x, Y: G2To200y}, - {X: G2To201x, Y: G2To201y}, - {X: G2To202x, Y: G2To202y}, - {X: G2To203x, Y: G2To203y}, - {X: G2To204x, Y: G2To204y}, - {X: G2To205x, Y: G2To205y}, - {X: G2To206x, Y: G2To206y}, - {X: G2To207x, Y: G2To207y}, - {X: G2To208x, Y: G2To208y}, - {X: G2To209x, Y: G2To209y}, - {X: G2To210x, Y: G2To210y}, - {X: G2To211x, Y: G2To211y}, - {X: G2To212x, Y: G2To212y}, - {X: G2To213x, Y: G2To213y}, - {X: G2To214x, Y: G2To214y}, - {X: G2To215x, Y: G2To215y}, - {X: G2To216x, Y: G2To216y}, - {X: G2To217x, Y: G2To217y}, - {X: G2To218x, Y: G2To218y}, - {X: G2To219x, Y: G2To219y}, - {X: G2To220x, Y: G2To220y}, - {X: G2To221x, Y: G2To221y}, - {X: G2To222x, Y: G2To222y}, - {X: G2To223x, Y: G2To223y}, - {X: G2To224x, Y: G2To224y}, - {X: G2To225x, Y: G2To225y}, - {X: G2To226x, Y: G2To226y}, - {X: G2To227x, Y: G2To227y}, - {X: G2To228x, Y: G2To228y}, - {X: G2To229x, Y: G2To229y}, - {X: G2To230x, Y: G2To230y}, - {X: G2To231x, Y: G2To231y}, - {X: G2To232x, Y: G2To232y}, - {X: G2To233x, Y: G2To233y}, - {X: G2To234x, Y: G2To234y}, - {X: G2To235x, Y: G2To235y}, - {X: G2To236x, Y: G2To236y}, - {X: G2To237x, Y: G2To237y}, - {X: G2To238x, Y: G2To238y}, - {X: G2To239x, Y: G2To239y}, - {X: G2To240x, Y: G2To240y}, - {X: G2To241x, Y: G2To241y}, - {X: G2To242x, Y: G2To242y}, - {X: G2To243x, Y: G2To243y}, - {X: G2To244x, Y: G2To244y}, - {X: G2To245x, Y: G2To245y}, - {X: G2To246x, Y: G2To246y}, - {X: G2To247x, Y: G2To247y}, - {X: G2To248x, Y: G2To248y}, - {X: G2To249x, Y: G2To249y}, - {X: G2To250x, Y: G2To250y}, - {X: G2To251x, Y: G2To251y}, - {X: G2To252x, Y: G2To252y}, - {X: G2To253x, Y: G2To253y}, - {X: G2To254x, Y: G2To254y}, - {X: G2To255x, Y: G2To255y}, - }, - + gm: emuGm, a: emulated.ValueOf[Base](params.A), addA: params.A.Cmp(big.NewInt(0)) != 0, }, nil @@ -823,7 +57,7 @@ type Curve[Base, Scalars emulated.FieldParams] struct { g AffinePoint[Base] // gm are the pre-computed multiples the generator (base point) of the curve. - gm [256]AffinePoint[Base] + gm []AffinePoint[Base] a emulated.Element[Base] addA bool @@ -837,7 +71,7 @@ func (c *Curve[B, S]) Generator() *AffinePoint[B] { // GeneratorMultiples returns the pre-computed multiples of the base point of the curve. The method does not copy and // modifying the returned element leads to undefined behaviour! -func (c *Curve[B, S]) GeneratorMultiples() [256]AffinePoint[B] { +func (c *Curve[B, S]) GeneratorMultiples() []AffinePoint[B] { return c.gm } From 98cd61ce301b189dfe6f47c9d1e1642d24553974 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Wed, 1 Mar 2023 12:58:34 +0100 Subject: [PATCH 033/464] docs: fix docs, make links --- std/algebra/weierstrass/point.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/std/algebra/weierstrass/point.go b/std/algebra/weierstrass/point.go index d076180101..c40f45a0cd 100644 --- a/std/algebra/weierstrass/point.go +++ b/std/algebra/weierstrass/point.go @@ -153,9 +153,9 @@ func (c *Curve[B, S]) Double(p *AffinePoint[B]) *AffinePoint[B] { // Saves the computation of the y coordinate of 2p as it is used only in the computation of λ2, // which can be computed as // -// diffλ2 = -λ1-2*p.y/(x2-p.x) instead. +// λ2 = -λ1-2*p.y/(x2-p.x) // -// It doesn't modify p. +// instead. It doesn't modify p. // // [ELM03]: https://arxiv.org/pdf/math/0208038.pdf func (c *Curve[B, S]) Triple(p *AffinePoint[B]) *AffinePoint[B] { @@ -200,7 +200,7 @@ func (c *Curve[B, S]) Triple(p *AffinePoint[B]) *AffinePoint[B] { // Saves the computation of the y coordinate of p+q as it is used only in the computation of λ2, // which can be computed as // -// diffλ2 = -λ1-2*p.y/(x2-p.x) +// λ2 = -λ1-2*p.y/(x2-p.x) // // instead. It doesn't modify p nor q. // @@ -281,7 +281,7 @@ func (c *Curve[B, S]) Lookup2(b0, b1 frontend.Variable, i0, i1, i2, i3 *AffinePo // constraints using [ELM03] (Section 3.1) // // [ELM03]: https://arxiv.org/pdf/math/0208038.pdf -// [HMV04]: Guide to Elliptic Curve Cryptography +// [HMV04]: https://link.springer.com/book/10.1007/b97644 func (c *Curve[B, S]) ScalarMul(p *AffinePoint[B], s *emulated.Element[S]) *AffinePoint[B] { var st S sr := c.scalarApi.Reduce(s) @@ -324,6 +324,8 @@ func (c *Curve[B, S]) ScalarMul(p *AffinePoint[B], s *emulated.Element[S]) *Affi // precomputed. The bits at positions 1 and 2 are handled outside of the loop // to optimize the number of constraints using a Lookup2 with pre-computed // [3]g, [5]g and [7]g points. +// +// [HMV04]: https://link.springer.com/book/10.1007/b97644 func (c *Curve[B, S]) ScalarMulBase(s *emulated.Element[S]) *AffinePoint[B] { g := c.Generator() gm := c.GeneratorMultiples() From 8f124abb45672960e70789ce803939baa1c61993 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 1 Mar 2023 13:14:40 +0100 Subject: [PATCH 034/464] perf: ScalarMulBase for sw_bls12377 on G2 --- std/algebra/fields_bls12377/e2.go | 9 + std/algebra/sw_bls12377/g1.go | 12 +- std/algebra/sw_bls12377/g2.go | 65 + std/algebra/sw_bls12377/g2_test.go | 32 + std/algebra/sw_bls12377/inner.go | 2076 ++++++++++++++++------ std/commitments/kzg_bls12377/verifier.go | 2 +- 6 files changed, 1672 insertions(+), 524 deletions(-) diff --git a/std/algebra/fields_bls12377/e2.go b/std/algebra/fields_bls12377/e2.go index 067e8242c4..ab43cc1c0e 100644 --- a/std/algebra/fields_bls12377/e2.go +++ b/std/algebra/fields_bls12377/e2.go @@ -240,3 +240,12 @@ func (e *E2) Select(api frontend.API, b frontend.Variable, r1, r2 E2) *E2 { return e } + +// Lookup2 ... +func (e *E2) Lookup2(api frontend.API, b1, b2 frontend.Variable, r1, r2, r3, r4 E2) *E2 { + + e.A0 = api.Lookup2(b1, b2, r1.A0, r2.A0, r3.A0, r4.A0) + e.A1 = api.Lookup2(b1, b2, r1.A1, r2.A1, r3.A1, r4.A1) + + return e +} diff --git a/std/algebra/sw_bls12377/g1.go b/std/algebra/sw_bls12377/g1.go index 134199e4ed..988af7a500 100644 --- a/std/algebra/sw_bls12377/g1.go +++ b/std/algebra/sw_bls12377/g1.go @@ -452,10 +452,10 @@ func (p *G1Affine) DoubleAndAdd(api frontend.API, p1, p2 *G1Affine) *G1Affine { return p } -// ScalarMulBase computes s * g and returns it, where g is the fixed generator. It doesn't modify s. +// ScalarMulBase computes s * g1 and returns it, where g1 is the fixed generator. It doesn't modify s. func (P *G1Affine) ScalarMulBase(api frontend.API, s frontend.Variable) *G1Affine { - points := GetBLS12377Points() + points := GetBLS12377CurvePoints() sBits := api.ToBinary(s, 253) @@ -463,19 +463,19 @@ func (P *G1Affine) ScalarMulBase(api frontend.API, s frontend.Variable) *G1Affin // i = 1, 2 // gm[0] = 3g, gm[1] = 5g, gm[2] = 7g - res.X = api.Lookup2(sBits[1], sBits[2], points.Gx, points.Gmx[0], points.Gmx[1], points.Gmx[2]) - res.Y = api.Lookup2(sBits[1], sBits[2], points.Gy, points.Gmy[0], points.Gmy[1], points.Gmy[2]) + res.X = api.Lookup2(sBits[1], sBits[2], points.G1x, points.G1mx[0], points.G1mx[1], points.G1mx[2]) + res.Y = api.Lookup2(sBits[1], sBits[2], points.G1y, points.G1my[0], points.G1my[1], points.G1my[2]) for i := 3; i < 253; i++ { // gm[i] = [2^i]g tmp.X = res.X tmp.Y = res.Y - tmp.AddAssign(api, G1Affine{points.Gmx[i], points.Gmy[i]}) + tmp.AddAssign(api, G1Affine{points.G1mx[i], points.G1my[i]}) res.Select(api, sBits[i], tmp, res) } // i = 0 - tmp.Neg(api, G1Affine{points.Gx, points.Gy}) + tmp.Neg(api, G1Affine{points.G1x, points.G1y}) tmp.AddAssign(api, res) res.Select(api, sBits[0], res, tmp) diff --git a/std/algebra/sw_bls12377/g2.go b/std/algebra/sw_bls12377/g2.go index fcfcdbcf20..e4da202870 100644 --- a/std/algebra/sw_bls12377/g2.go +++ b/std/algebra/sw_bls12377/g2.go @@ -471,3 +471,68 @@ func (p *G2Affine) DoubleAndAdd(api frontend.API, p1, p2 *G2Affine) *G2Affine { return p } + +// ScalarMulBase computes s * g2 and returns it, where g2 is the fixed generator. It doesn't modify s. +func (P *G2Affine) ScalarMulBase(api frontend.API, s frontend.Variable) *G2Affine { + + points := GetBLS12377TwistPoints() + + sBits := api.ToBinary(s, 253) + + var res, tmp G2Affine + + // i = 1, 2 + // gm[0] = 3g, gm[1] = 5g, gm[2] = 7g + res.X.Lookup2(api, sBits[1], sBits[2], + fields_bls12377.E2{ + points.G2x0, + points.G2x1}, + fields_bls12377.E2{ + points.G2mx0[0], + points.G2mx1[0]}, + fields_bls12377.E2{ + points.G2mx0[1], + points.G2mx1[1]}, + fields_bls12377.E2{ + points.G2mx0[2], + points.G2mx1[2]}) + res.Y.Lookup2(api, sBits[1], sBits[2], + fields_bls12377.E2{ + points.G2y0, + points.G2y1}, + fields_bls12377.E2{ + points.G2my0[0], + points.G2my1[0]}, + fields_bls12377.E2{ + points.G2my0[1], + points.G2my1[1]}, + fields_bls12377.E2{ + points.G2my0[2], + points.G2my1[2]}) + + for i := 3; i < 253; i++ { + // gm[i] = [2^i]g + tmp.X = res.X + tmp.Y = res.Y + tmp.AddAssign(api, G2Affine{ + fields_bls12377.E2{ + points.G2mx0[i], + points.G2mx1[i]}, + fields_bls12377.E2{ + points.G2my0[i], + points.G2my1[i]}}) + res.Select(api, sBits[i], tmp, res) + } + + // i = 0 + tmp.Neg(api, G2Affine{ + fields_bls12377.E2{points.G2x0, points.G2x1}, + fields_bls12377.E2{points.G2y0, points.G2y1}}) + tmp.AddAssign(api, res) + res.Select(api, sBits[0], res, tmp) + + P.X = res.X + P.Y = res.Y + + return P +} diff --git a/std/algebra/sw_bls12377/g2_test.go b/std/algebra/sw_bls12377/g2_test.go index 534a58b54c..2bca05f714 100644 --- a/std/algebra/sw_bls12377/g2_test.go +++ b/std/algebra/sw_bls12377/g2_test.go @@ -374,6 +374,38 @@ func TestScalarMulG2(t *testing.T) { assert := test.NewAssert(t) assert.SolvingSucceeded(&circuit, &witness, test.WithCurves(ecc.BW6_761)) } + +type g2varScalarMulBase struct { + C G2Affine `gnark:",public"` + R frontend.Variable +} + +func (circuit *g2varScalarMulBase) Define(api frontend.API) error { + expected := G2Affine{} + expected.ScalarMulBase(api, circuit.R) + expected.AssertIsEqual(api, circuit.C) + return nil +} + +func TestVarScalarMulBaseG2(t *testing.T) { + var c bls12377.G2Affine + _, gJac, _, _ := bls12377.Generators() + + // create the cs + var circuit, witness g2varScalarMulBase + var r fr.Element + _, _ = r.SetRandom() + witness.R = r.String() + // compute the result + var br big.Int + gJac.ScalarMultiplication(&gJac, r.BigInt(&br)) + c.FromJacobian(&gJac) + witness.C.Assign(&c) + + assert := test.NewAssert(t) + assert.SolvingSucceeded(&circuit, &witness, test.WithCurves(ecc.BW6_761)) +} + func randomPointG2() bls12377.G2Jac { _, p2, _, _ := bls12377.Generators() diff --git a/std/algebra/sw_bls12377/inner.go b/std/algebra/sw_bls12377/inner.go index f71f6f1523..868126297e 100644 --- a/std/algebra/sw_bls12377/inner.go +++ b/std/algebra/sw_bls12377/inner.go @@ -64,527 +64,1569 @@ func getInnerCurveConfig(outerCurveScalarField *big.Int) *innerConfig { } type CurvePoints struct { - Gx *big.Int // base point x - Gy *big.Int // base point y - Gmx [253]*big.Int // m*base point x - Gmy [253]*big.Int // m*base point y + G1x *big.Int // base point x + G1y *big.Int // base point y + G1mx [253]*big.Int // m*base point x + G1my [253]*big.Int // m*base point y } -func GetBLS12377Points() CurvePoints { - gx, _ := new(big.Int).SetString("8848defe740a67c8fc6225bf87ff5485951e2caa9d41bb188282c8bd37cb5cd5481512ffcd394eeab9b16eb21be9ef", 16) - gy, _ := new(big.Int).SetString("1914a69c5102eff1f674f5d30afeec4bd7fb348ca3e52d96d182ad44fb82305c2fe3d3634a9591afd82de55559c8ea6", 16) - g3x, _ := new(big.Int).SetString("1252b781171f507db36291b433a1f911a46543890a20ca9712e11f66a5d216e63d817bd8d96cef715abc604dcf6ec2e", 16) - g3y, _ := new(big.Int).SetString("14a00fa77c727e8987cc438b51bbe012c823a19955ae692c54ce572a61f0ea1fe5cd981533df419fd1330d1f6e6d802", 16) - g5x, _ := new(big.Int).SetString("17052d4e3eb642d32ef4989af253cc2a30ad376ce8f0b23c92b987e95cc718d02072bb78d37c09fd76f7014eecf797", 16) - g5y, _ := new(big.Int).SetString("16c206be738bf4644faff10bb82b19f6f07779903a6ad2524809ce29f94683be32bbdd072ec0be66ae0ed0d8781f277", 16) - g7x, _ := new(big.Int).SetString("916932fceb94ad7b80fcf492aa5ee0e120410017cc6d17c8962ba2eb799260d022c3de5a103e6edbb5ee9135c7f0fa", 16) - g7y, _ := new(big.Int).SetString("18efb7c0b6e083030a858e3e8b4d1db5857a3f6c60f01691eb9783f6a1f1064069da2e220952121c771f276888d5137", 16) - g2To3x, _ := new(big.Int).SetString("18aff632c0048f5afb5c07fd197a44a127c829be3ff6170c6cebc1154bc72633b45de2ac855e0da30cebfa33672e7f3", 16) - g2To3y, _ := new(big.Int).SetString("efb82d5f13565755df1445db9ed4c4969f09bb31cc610f83eb1490be76ab3817808c52d98074f1a98ff896012a78ab", 16) - g2To4x, _ := new(big.Int).SetString("107db75ab97dcb352b7e3e0596950ec2793cb394f821b1a2e7d5f54d11da8215a998cc84736ddffed74f549052a9df4", 16) - g2To4y, _ := new(big.Int).SetString("7d8459036fefe53ffd95028a2be4f8588b07cd359b0955e1cbe986d4b1ee854e452d7c14f05c41b861266522e3e887", 16) - g2To5x, _ := new(big.Int).SetString("680fb4caec4a06f92a7f4f1e20624b4eaf74001df5ab3ca6f4b3fd9c2d49f257d3021400f5844e227d9763090d8cb", 16) - g2To5y, _ := new(big.Int).SetString("1a9a941bd20effaea30f547d27e433ddf0e29bad201877d54995e73586e8847aaadc0b521762db07fc7906d3c39ee80", 16) - g2To6x, _ := new(big.Int).SetString("56827fbf50c974fda74996e7415fb0fa6c653d0279ae5e0726c124b222837c6ff5fb12682ba380984981f2442100cd", 16) - g2To6y, _ := new(big.Int).SetString("962aa4e39307e00d9934914a1ae85e57513ac9f7b7dbd11003d67d62f288d92f5bd2aedad3a9686ce807efe6f8fba4", 16) - g2To7x, _ := new(big.Int).SetString("880497aa4f51a84c24fb4d92ef46819156918734858556807059b6f6d3e62d2e3f589f33d7f8c5f6af63a0f072629a", 16) - g2To7y, _ := new(big.Int).SetString("111c794e9d2397062f763482bec5584abb31f5b73090174dc22c8dce191c94362ed75492067209bd63044d40f694ad1", 16) - g2To8x, _ := new(big.Int).SetString("e5ddb0da4a5b32e245f78e95760c03227b976ed310ef3922624473d3ca4ea85429797e145692f87d5cb39b4e9a807c", 16) - g2To8y, _ := new(big.Int).SetString("ee67ff3335bffe5cba6953e23e9a1953ee9c1f37371c01a0ceca424f98566df7c353e1eead76435e7854af3fe89c3e", 16) - g2To9x, _ := new(big.Int).SetString("13c910dadc716133218967c098a8f2889817ea5688f68c1878cf6b97e903f728b65dd7b7a6ad65226ee2089a3317b4a", 16) - g2To9y, _ := new(big.Int).SetString("13324bef362a2a30fef824ea32e78c5c1e628842afd2fe67baae1e80fe7eabdbe97ef70a9606fe8db5359a607750b8c", 16) - g2To10x, _ := new(big.Int).SetString("134fb9a0098e3581953df24b0cb4a16306a4eea26bdb08b92b5fe28c35c178873e7a3b813e3579b417f780a7585a027", 16) - g2To10y, _ := new(big.Int).SetString("11e922e78cc7bbf317f9e3013d3c4d35a134d8ff2b94cd33450331a67f3585dd6c548b494f4eaa21f325e45d5d01912", 16) - g2To11x, _ := new(big.Int).SetString("14fe16f6fbc301389a2ce1cf4380af5eace02eb0be172c174e0e6e59f22259b861eefe33fcd031bf94d23d3622b19dc", 16) - g2To11y, _ := new(big.Int).SetString("aeb36e0a5f8b155febe62a45c6d318fae2a035999d0c309e163721431c4e2d2185db90329a3a644cbe7c07d5042c05", 16) - g2To12x, _ := new(big.Int).SetString("ab8d63c61ea2a57f78951d45eca6a177a7dd1c7b753587d1d7348c6f158fea835c5a2c9b4b39be911a900d9d71753e", 16) - g2To12y, _ := new(big.Int).SetString("10b05d822a9665013d90ad837b75171e8b491636943329c997822f58577adac847d95b7f188b11ca33d14fd5d3acec8", 16) - g2To13x, _ := new(big.Int).SetString("add361f77572a949e411d6435d8121daecb31402c58a7cc6ebb737c26a11d6bfb60ef1eb0e1226b8e4ff4d7a1f19a1", 16) - g2To13y, _ := new(big.Int).SetString("ad05daef21794dd0d33692eb4743bfe28c6c85090622926a547e5122ef41a1dddad4cba10b798f89579cb2348e9d57", 16) - g2To14x, _ := new(big.Int).SetString("63929f07e03764ea4b3b4baa6e504c2bc7588a2c7f3e2b1029e94caf03e5f20d41bb644edcdb8f6869527047984d6b", 16) - g2To14y, _ := new(big.Int).SetString("6a51e86ce05f6f4bf7761db5143323f36250a620a3c5132ec24fe0a0ccce5375eea48bf39a27141acd8a6339587186", 16) - g2To15x, _ := new(big.Int).SetString("9d656058092638a500e7febd7c820798ec2e7139b02a10083ab6593d915a4ec4293d023ba59192b49845c0512a6686", 16) - g2To15y, _ := new(big.Int).SetString("191cac9f967d935ab360a6f6e58381956a7f9497e2c67175c7710ccf4c2db22bfbc390090fdb568f0e182b30df1a280", 16) - g2To16x, _ := new(big.Int).SetString("1371622e52c4790930c0dc81051c5d922318a05a5dddf4035838f88368cae1178db6ddafef464a9bd035fbe22311be9", 16) - g2To16y, _ := new(big.Int).SetString("5a6cf187acfb8a91dd2130b0d8f4f617b1bb0f9beb1a29ea908cb24254e4e2a3e8c14c3c5cc20bc714a1bcdfed1535", 16) - g2To17x, _ := new(big.Int).SetString("127f9cd4d32d5b68839ad50475180b572cf5a64a298bef23b2ed972dbe8f65e33056e5476e8716252635b980cecd7c5", 16) - g2To17y, _ := new(big.Int).SetString("1738a6dd32253efa3621c81b81eb1d109a35a1d182a04be293b75bbdeabf7f3090d32b0bae41fb0bb317f5c7b669f8b", 16) - g2To18x, _ := new(big.Int).SetString("7a60c7c738fb264482fe46a69c514cc4cbbc83370890dc1cbf39567e8b34bf5c388313c82804d1c7261dc99b2801ab", 16) - g2To18y, _ := new(big.Int).SetString("d0ab238b768b54b095db2aca7acfa16ae26264066fe7be9547b76c855188a07d287d0031fdc40d57dab98c7d073bca", 16) - g2To19x, _ := new(big.Int).SetString("6042f781b85a81d10048c15da22c5069b880f6d1f6f5c54bd327760bc1b4daa247aca6c96bee7d20c8578220981ef", 16) - g2To19y, _ := new(big.Int).SetString("c20df594f36b4a18be4c2e759c55a1c08d08fdd8e7f0d228e282727518eba66383cd667811c0d5e4baf03455e46f99", 16) - g2To20x, _ := new(big.Int).SetString("141937e53eb28e9328d805dec48045a9f258c632aa4e4f360fea78d16850921b636fc52df323fcae8051385364cff58", 16) - g2To20y, _ := new(big.Int).SetString("f82e14368390d59c28fcfb130566a936b446e783877578d7e27e15c14614be38a5927329189abda212bd4576ae6421", 16) - g2To21x, _ := new(big.Int).SetString("94e187a31d02354de6787d1abffc8b9fdb62f8dd91a01fe0af6265736966d8ec181bd65863c2b0c3020c1c7c26a9ee", 16) - g2To21y, _ := new(big.Int).SetString("77cb65bade2f40dd98b6ee8d84aff95295647f5f2744e9691ee8013537f714df467010007b8479a018dce66ecf011", 16) - g2To22x, _ := new(big.Int).SetString("f574cd8336eb82714f7cfe446d239ee89bafbe52b6cb5e7dc839fba89cfb78187f1aacbf92dc4d772519e500d3faae", 16) - g2To22y, _ := new(big.Int).SetString("4e3073dfae73051d165648b65a1910c82d22e2344db0a906e98485883d11f12e061c84e99905fa09c3a73c1a0dff86", 16) - g2To23x, _ := new(big.Int).SetString("879b817a80faf83a690e7d4cc5c7f802bae36cc397bb4fc5210a48b23227821ffe5b5fd90f34b37aee8bea5b143a1e", 16) - g2To23y, _ := new(big.Int).SetString("1387d2b720763e114e58702c269ff61007ab33c1e6e7d5834f010b970fb70ed7bc469b2129e613ac2fd2d3a6a6e34d1", 16) - g2To24x, _ := new(big.Int).SetString("f1e52f2ceb352869eac2a752dd6bc47b84724b3f4e74df4b72db06d9000456571cd58b4a1332f0c99f40eb4893e5c9", 16) - g2To24y, _ := new(big.Int).SetString("60e7d9eb062783ba26ec00ed46179386b4225a129fd044f84f9d7984147879c80f6b8d70eb6d55e160d7bc2a5c1684", 16) - g2To25x, _ := new(big.Int).SetString("133f8d1a44d868b95891a82ab4cd2343ce38e370e48a256f232b0077b411a12922bb919c599e6c5a1f9a81395d7d054", 16) - g2To25y, _ := new(big.Int).SetString("1414246490ffe596f7c8db806833128a661e98dc52b62a694caca1df3644c135bd8946d933275f2642f81e03f645daf", 16) - g2To26x, _ := new(big.Int).SetString("12982253bcdcfc660df538b5d004eb6bf283dbaf7788eec8d958bf77f10067e1f62ccc3194a65b0120fe15e92695667", 16) - g2To26y, _ := new(big.Int).SetString("97ec4a1c3de3030096011e1cce00814d216b19659fe3cb5eac04df4a12cf5e1f36ee47cd8acc02e51d031a65a17114", 16) - g2To27x, _ := new(big.Int).SetString("bafb585867ed534280a3a898ab8e7b8d6d0b393add86ba307b150dfaee25eea932e3a744d01b9d18950cc3f5670e4b", 16) - g2To27y, _ := new(big.Int).SetString("ba377e08bcc57ed719d82ffde026ea1c0fa3f3ec44e5e587507531731eb815ca6712e9eb92dfa63864b570e10e735", 16) - g2To28x, _ := new(big.Int).SetString("43ddf8732e7a29888831d1923985991bf6a9dc2fbe7916b12c8d676fafb96025023eeba8e208ff582fafefbd2af2bc", 16) - g2To28y, _ := new(big.Int).SetString("156dc34ce172d5dcdde35e9f77e0f23a3410f164b4ca2fdded4ffef71cd6c8be6605bbb2eb66522c15c7db50be316c4", 16) - g2To29x, _ := new(big.Int).SetString("13d7c2e8c14d861444f01eb7137520d1fc91ffd61c1c798710af6be926acc53921523d48708f41edb321ec779a2a92e", 16) - g2To29y, _ := new(big.Int).SetString("1108bb151007ff0b724046c4d5a641fbfe6e6a3bd71d3e1284cacc8e416a5fdedb4ed2693aded3d457d8ac72906070a", 16) - g2To30x, _ := new(big.Int).SetString("d2716f627351a4863060ab6777b148610d94e1b48b1607350f0098cc1289939097e4c3968506d152627350593d11a5", 16) - g2To30y, _ := new(big.Int).SetString("e64f79eb0f4d2fe93594259c1bc28f418a7ebd0a60769042315cac1fd6a1131e69ac868568526c3107c9176bab0c05", 16) - g2To31x, _ := new(big.Int).SetString("16c405bdc35a13c07c1157145face8ee9d13e41bb9e243d9a02c1900f26c7c062570cf56e1e992aab2b3bfbb61d387e", 16) - g2To31y, _ := new(big.Int).SetString("9c4f95f7c2c3fe1a4ac36d90ef98612c0691f3ed2ca212e9e1d38345606c2416652f5d8531bffbfbe1437f133b4e12", 16) - g2To32x, _ := new(big.Int).SetString("969e8eb9ce543735eb543a770a40903c3755d2e28c6c8ea9318440f2ea087f458f4b6f071aac44906b2a887d1a69a4", 16) - g2To32y, _ := new(big.Int).SetString("19f9bc3859f6781918a79e836d745c8787ba8b11c355e49e66b64e54428817e9fbbba06333e26d6b5dbd5fa6d7ea2f2", 16) - g2To33x, _ := new(big.Int).SetString("f14b7e7af6fa1d295f7b6ac8b1badf1fa3d65de31e79e94e69f02f21589642505a00ae1868525566cecce45fd62e44", 16) - g2To33y, _ := new(big.Int).SetString("1a115f0aa272d645be22ee308865c893e575c01aa55ace3410fd3e751a4e610655884c0a97427f37c9dcd90338b1626", 16) - g2To34x, _ := new(big.Int).SetString("148e97cb2504eb135a392a36e995694e281e727919ac5736e3f5dc45bd857e1a2b1fd48984147f762ff5a08e9eff340", 16) - g2To34y, _ := new(big.Int).SetString("18818155deaebb73bb615991f4aa7eb7750b2186f12d0aca0f56ecc22e7fb1cc4086d7fbf5da6cb8d12dfea5047975a", 16) - g2To35x, _ := new(big.Int).SetString("1826fdb3058eed244014b2cc2e84a61cfd4f4ec0e502e81ad5279246a8df015171bb35d70b4d21f0778b2bd46bba947", 16) - g2To35y, _ := new(big.Int).SetString("1511d311e43642cfa8ddc23dada8d387c5ebedbf1f96e22fea67c841550227148533e983b310f8287e50ef5462aef4d", 16) - g2To36x, _ := new(big.Int).SetString("1afe7f02e75acba6bb817bf762fddb0c50ed73ee7ad2abd3eb648a624dbb3649a70f8a0bed77b364dc64d5670e12c9", 16) - g2To36y, _ := new(big.Int).SetString("1141907296b72c2969a79f29523d5378b7c2323e87b93a667ccc0ece9f62a3bf7448dd8b2222a077de60f5245b0ab26", 16) - g2To37x, _ := new(big.Int).SetString("eaab1bcb93f8e64dd8dd822119af39e6db14b06a0dfda84a8948038412ce5f5e2e3d89492eec2242e2730c81e8651f", 16) - g2To37y, _ := new(big.Int).SetString("17f4f5be515e6bf8037faec8f667ee63a786a59688ea502ef4da6131ce63aaf4355b55e7dfa52f16c374105fb8bf924", 16) - g2To38x, _ := new(big.Int).SetString("1a5b9caa4a74b679c4186aadfcc8d05408728e9caf463724e9a9e8468d13f4e2895f0d0eb386a749009b7d6e5b2e75f", 16) - g2To38y, _ := new(big.Int).SetString("47e7ef7de6058e4ab1b2655164ae9df1cb3865dd5049f604b68cf77ea65a079ada29e524ed864792f7bf22283634a", 16) - g2To39x, _ := new(big.Int).SetString("14fcd5c9fda9b70d081e0b955145e5f5f7a15b4ca4f22e284a8c13bd7add0c67eec7bbd901e33991d94a8838638a9e7", 16) - g2To39y, _ := new(big.Int).SetString("ddfdb26ac57951cebfe2394dd4dd4d27c6efec24b70b1208b2dc5ca1f867974f3e8eec4050eb21af8497860af54d", 16) - g2To40x, _ := new(big.Int).SetString("252bee9b6ef8f22112ed489d3f56f08cc662d26783e4dfb44c65e5effe63e35e7df58894ff7c3e861dae155d0a021f", 16) - g2To40y, _ := new(big.Int).SetString("2bb53e9d3d1b2d87b5d1e237d39c3920dd4fbf9c34ca9b526b82472681c4c316e93a705dc28f2b6a262f21bf4138ce", 16) - g2To41x, _ := new(big.Int).SetString("174acac12c03f292f9c8c9ef1be3a1127fd64726cb9a3da1c37d18a0474830c5bdd294671a31e09670a0a9a357f640f", 16) - g2To41y, _ := new(big.Int).SetString("15cafb6ce83da980dbbbe486269ce721e9ae2d32b33773705904a74ab223df23e26b7655ff55d0c1ace86a72b4f6cfc", 16) - g2To42x, _ := new(big.Int).SetString("aa5ae22e7da20eb760d8be899a537d78c7f76aef985f6afa881020e7169a6960284c42bb5bf3301029b7ea78ddbab2", 16) - g2To42y, _ := new(big.Int).SetString("3cb9cf41a120b481b419ceda853a508337f74a91500f881629c0cb16c9be10b352929006ae300b93263ba01b378517", 16) - g2To43x, _ := new(big.Int).SetString("182b1745e5f859974d7ecbcec4da576a01cb5883ba5bae584709bd2e45d8eef002e4b093d8324372143460b4d0e4d5", 16) - g2To43y, _ := new(big.Int).SetString("187934573dca1cabc7a250d3e53091e9269009e3edfd0dc0ca2bc4843c1db9c0d7582c55dcc9a113728a37b4c7957b6", 16) - g2To44x, _ := new(big.Int).SetString("9008e86f9a7abb2b70044f3ea1565f3fe7df01bf46778f3a216a3605292382614dd4e807501c514760495f1fbad362", 16) - g2To44y, _ := new(big.Int).SetString("fe0c7b627908402489f139e577d86c527f9022a81cf6d4b20839b2886aeb4ade6cda54ddedab603a331acda5dc9997", 16) - g2To45x, _ := new(big.Int).SetString("db1db669a0f65547c0ef181afddcd6af4ebaae9a0b0977ac99aca37286bd94d9d14ee0a67de9f64d647ed58620aa46", 16) - g2To45y, _ := new(big.Int).SetString("1604ae03716ae90daa4711695fd86138eaaa4d03d3bf85217586783c77acad34497b1e89bab3c26036cc780b95cf98e", 16) - g2To46x, _ := new(big.Int).SetString("a961a93d8d69857b45972c45e7da4cc98fa11a28ef93b391bce2b4d7bb7472cf8dad04b0833443717085fbb14b8a0c", 16) - g2To46y, _ := new(big.Int).SetString("1222d52c8fb984fb00c1ebae3b66f52144b030bb2c28a304cbaa8a5335cd797cdb519cbcb6df298ff7ef426c80d53d6", 16) - g2To47x, _ := new(big.Int).SetString("605fbf7d4a4865e18a349f6af474d04c53ccd15aef07dc5c63d0aeaa9e35c732d5c25dce539d1018a8eb5ba1a1e703", 16) - g2To47y, _ := new(big.Int).SetString("1673edb028fae78421ab69bbf1d4c2116d0977a486f911a30354a6c6c74341c0a081dc604fdd130f1dbea16158a14c0", 16) - g2To48x, _ := new(big.Int).SetString("16b32d15667fbf3b37d2fd42b9648b8d12c1e8380df504dd6d1bb74387e615190aa158e31557e26710bddd3f62c448", 16) - g2To48y, _ := new(big.Int).SetString("1a96b7fb2441a65a1507e7b63bed23aa162ed2cc002553292d5b9009b1ccccebb7c597b12e1303afe406cad47d14b76", 16) - g2To49x, _ := new(big.Int).SetString("1ac0e778e13331dc87c9ec5c9eb608894f5ccb3448b6e537ef0481cd6534873c65c3b90265eeb87aefe7e0b6719df47", 16) - g2To49y, _ := new(big.Int).SetString("1374cc9941ddc21bf5d7fe0d3f6863d55084da5d3270756b2239d03dc0fe22ea67127f7eb04900e676d687f1479c4f", 16) - g2To50x, _ := new(big.Int).SetString("f2a9a16712080ab0597457b86c31c890fa22f1c512a9dda284f4d5b307742092ed7cf6e17e09a02e405bcb285aba7d", 16) - g2To50y, _ := new(big.Int).SetString("e6e13736ec424657d9f75e2e4817786a58c432f021b61c8a448af8b8f4d861dc0fe23cfde02b655fe8394d27b40ec9", 16) - g2To51x, _ := new(big.Int).SetString("2677277410ccf8b96bdd183733368cae50e14b757616979ee0975aa9e4201fdd12b86256c9f9a143653e1cc620a85", 16) - g2To51y, _ := new(big.Int).SetString("cd1b38e1e3b2e1067822422ba488a83c851a4f6d29680947fcac986ef07fa3148817a3840894b82daa4da2e274e94a", 16) - g2To52x, _ := new(big.Int).SetString("281b180d9e4aae07f4d6c11e679744d92592c26a6fb90692fe12f10eb16b58916ca87e74c9c0bd03887de8e2e45d0f", 16) - g2To52y, _ := new(big.Int).SetString("11101677eb41c6ca2c60d14456cfc148b4758a7dc86bb3f596d0afbf9677e403d9e8cbb9ad3afb08499e58ae295e9df", 16) - g2To53x, _ := new(big.Int).SetString("f1cc005ed80694095b1a61ba7e9700676450f5693e403aa9bba34b10be09111151dd9f4448d6bb287aabe37365d1c0", 16) - g2To53y, _ := new(big.Int).SetString("1a3e52c9f74db8b43d80c20e054c3a4849a441bebc44d444f4e7460036c46a1743320d75af77e11bb43ff521663aa29", 16) - g2To54x, _ := new(big.Int).SetString("7617573decd671474599623dd69aa96fe82794763eb49d2443f182428c6227145b7b6389cff20f9f46832fd2dbfcae", 16) - g2To54y, _ := new(big.Int).SetString("1a92a1f480f7d985d4e1abe80af96adf0e475571b80e99456d75b4218ee0c1e363afdd161789756f618f78cba51dd03", 16) - g2To55x, _ := new(big.Int).SetString("adff1ee838fd0e69694d32df4364308fec2313cd57c641367615c74f069f343a0c4888235308f22901084d9bcea913", 16) - g2To55y, _ := new(big.Int).SetString("9301a7eee38fe353161f286347647d566f8949fea78942d854a9b5c1639daeb83242ef6424caaba2095532f66b2e5b", 16) - g2To56x, _ := new(big.Int).SetString("2fd8f21f20fa1e949001314366e933d619b6e421c67c0bee21da9ef0d0318cec8fef099803b8e5629accd6d6b78e1c", 16) - g2To56y, _ := new(big.Int).SetString("ced044196c59388c333e8a0b17f9b9ee3c38ebee8c9c22b5be43c40737c6c9de7984b14c8f39127bc1c073ee60e25d", 16) - g2To57x, _ := new(big.Int).SetString("12d8246a5064c33a3b6e9be28e650715f2c62b696c90acc014ef9a2700bc1c7012f777b6af6d59949b3e0d87c1e88fe", 16) - g2To57y, _ := new(big.Int).SetString("19dbac773f76ba1a8c485090b6b10f9bc3110fe48e380da71a6b7f0336c4c818a3803126caadd7d3effecccf667097c", 16) - g2To58x, _ := new(big.Int).SetString("381bab5aa65d2b159bb82883559754e5fe26003013389761496d63eea249701c1b1eb742a28f529d6fea8c1b0aa726", 16) - g2To58y, _ := new(big.Int).SetString("7a43f15f319df3d07beadbe688619ac1ca80c76e472ea0d76555d200cc8f2c4e0b9a77065dbd41542d3dc7f0099622", 16) - g2To59x, _ := new(big.Int).SetString("eb3ba48bcae37c9ca7d0c66d42cd4f7a66640f14da2f439b7b1c27a05af916e818ba28eab92bf632f458eb02b962fb", 16) - g2To59y, _ := new(big.Int).SetString("fe6a0dddf3767c9f743eb544204739ddc4f9171c85cedf5f45f94d2fc2124df60c37ea0757ee4fdc98d1289f615b79", 16) - g2To60x, _ := new(big.Int).SetString("f64fccc7b7e1170569fa4ea7de6a25952252fdf82c1de13a3884a3384780d310d2ab52f42a15b46ef642f368b46f5d", 16) - g2To60y, _ := new(big.Int).SetString("a871d03f47a1889ce201513c353519e0cae34edea28f150f76b682c9b361feded8357d3bfdf5fff761ad18350fecad", 16) - g2To61x, _ := new(big.Int).SetString("138b8b61f53ba70e7b76545b01cf7ad7741eccb5ec524efd9d9a40d098c26c5fe99aff1565f5e66c331825dcd2c6f89", 16) - g2To61y, _ := new(big.Int).SetString("11360c12c63ce8faf10c63922afafb010bc325df0ae89fa87b8219dcac998e1add68d301475d12a483c85b48ae67068", 16) - g2To62x, _ := new(big.Int).SetString("18ec134222d187af5a8ede9ce9d4ab16c0a8e6c2113c92d6410e592b84c8df883cc6c05ae301e1f2e3c025eacc52b7a", 16) - g2To62y, _ := new(big.Int).SetString("1294ae9fe885df3c37931412484804feee91610b48fdd111baf15b5196ae8f5b7b16169ddac187c0447eb800127aa12", 16) - g2To63x, _ := new(big.Int).SetString("65813a9ec5492e7d799bafaf677f69d4630e24e47fe86ec0223181acc6ce0100e2de4a09db66616a01b48f7ab8b357", 16) - g2To63y, _ := new(big.Int).SetString("104147600c7118a89a55b524b254c8e14b17487b056f8a25cf793a7e6e4b44e137105a694d5421609fc5fa1d84edfbc", 16) - g2To64x, _ := new(big.Int).SetString("16ca0fa8a6de67c61d26f4263fe963c97726c7cd420b971b60fa3d8f19eeac52a059967f721c3f2f5cfd291eff79f95", 16) - g2To64y, _ := new(big.Int).SetString("1024b7a78a4be6db33eed9b9b0d6281408c344a3b7d7e50abb37b2766d3b6ec53321a398bc4abfb39589d73763fe4ad", 16) - g2To65x, _ := new(big.Int).SetString("ef930907a7c98f8ff74b03a671cf3e9f1ede0cc83fb570ef632f8c1808e03c623eebd12aeb80cab653ef808bfdaadf", 16) - g2To65y, _ := new(big.Int).SetString("163eaed12715d8b4e6669ed4d436ebf5a6e88d194081460ac58c43226c75b07e4d2d46f2afd5d092c5061ed5ada80fb", 16) - g2To66x, _ := new(big.Int).SetString("e55f91871935265fc666add9109b85a295b92dd1275e210e6752b88103551bb4a5054a820a8a7bea707b8152642d0f", 16) - g2To66y, _ := new(big.Int).SetString("3217a82630c2b2dcec5561f1af239b10612bd41f78cd69b109b90107d31c7bf25b7d822c629864c2b9ae95ddd9c6d4", 16) - g2To67x, _ := new(big.Int).SetString("32b0d40116e34b3c7001c348d371556b91b72af41555188ea23d442cf1748e80343e73af832f8ddd660b478aef3a82", 16) - g2To67y, _ := new(big.Int).SetString("190793652b804b0744c796f9c28b4ca77ae6c2c896c0b6420ca4802b270d322120313e4db6baddb5526b91479a69ef2", 16) - g2To68x, _ := new(big.Int).SetString("14db8a6116888ad28268bea38946ba5ddf9fdfec15250a3618f013233b12b2599934f639caa52e14ce78e65e4aca34c", 16) - g2To68y, _ := new(big.Int).SetString("11a146093cd40fdaa65c6ff93b3197cad47192f0645b8a5982a8abd9a15cae80167daf818ee820b02c31e42c10e9a98", 16) - g2To69x, _ := new(big.Int).SetString("721597f56b47a9b81055cbb92f68bd0f856d3314097b5008e255402093cecef95e10f34c66e9cf2c4636a5955f0401", 16) - g2To69y, _ := new(big.Int).SetString("9df9b789e238433aedccdb8996b9013095a5c72debc3d4161dc5517e3139352016137ebe5f1b88c7bccb464ae5932c", 16) - g2To70x, _ := new(big.Int).SetString("542bac3be82ab5260e405a2e37ce13ea57ec69523d412e640d6d44538c32b963d3536abb12d0796508013060181ab1", 16) - g2To70y, _ := new(big.Int).SetString("178910c28886167aaf6a3d2057951e5a046c2a2c90a621eda94c097b1b4b126f1dfe67f5efd496b244b9ebe02aff90a", 16) - g2To71x, _ := new(big.Int).SetString("c86c8ddd50b04e5bb33b5af20301eba97254ffb0f7f2190c2e4dc61fbda6560a4c6508813a74b2268b40af89b15a6", 16) - g2To71y, _ := new(big.Int).SetString("118d6c0fccd01732e48bb29539a0eaa8e7319d29a12cb9b87d76f4cfb0bf3a0a60250e8a3366bdeaafeda261ca834da", 16) - g2To72x, _ := new(big.Int).SetString("10b8803ef93d4428058963d394f1599bfd06ac2e8424ca8e33522f640bfb1f422263f9b3899cd6e857b78dc72d84835", 16) - g2To72y, _ := new(big.Int).SetString("16312e5482b4a4a69868094147c12514d3cd1e35a8e8e8a8fb67a6fbda08280b86352ba638314b0b731325d21928184", 16) - g2To73x, _ := new(big.Int).SetString("c1aa68b66a71e0925208c387cd45504c67c4c75e941d1c575385cb8595c24a24df762e9ff871f491254d8eca147de2", 16) - g2To73y, _ := new(big.Int).SetString("1a1ef925e585988f896c197af7a6b460f379b6eb5afa0b656702c3825b8ddbbc5384aaee6b61a1fea889c908f1b876e", 16) - g2To74x, _ := new(big.Int).SetString("1988799b72da095b8cd09fa266565ea14ac2bbdc8ce0d40c5cfc539d15d09f43bc6b540c598e8e2cd2e480df7f37979", 16) - g2To74y, _ := new(big.Int).SetString("d6f09872112bb080205ba42682dbb7127929850d7040458fb69ada42aa9c493f109a8eed018fb7bf731bb94870c666", 16) - g2To75x, _ := new(big.Int).SetString("985b8f67cd5043f0b04927caced7101f2e2416e1a3e54d9ef503b9f63258b8266e96280fed0ec57a020c9f871fa7e6", 16) - g2To75y, _ := new(big.Int).SetString("10dbd43d1277b59abcd4d63f4faa2abb22cd0630d44ae038b20596dcd5d9be2766621345db48f46d2602784a8874b33", 16) - g2To76x, _ := new(big.Int).SetString("128d9b00c2387f8b958a5e69235d7bc3c6566ffdaf6bf6baf9bf407501a905307b3db4fc93444ce9efefd717e6e704c", 16) - g2To76y, _ := new(big.Int).SetString("7e6df79c1ad8b8c57d71f284a1e9356a67c2211461c84eb277873500ad5f5600416c8ea67a0cb95b6395ede29080fb", 16) - g2To77x, _ := new(big.Int).SetString("19a8c6bec19d125a97a4636e38a9c71c482d1fd2c063bd4ab791fb84b508b2511c0c57832b0631d259b51524b3ac61c", 16) - g2To77y, _ := new(big.Int).SetString("beb651001b47818276d32281cebcacfb23ad81f9af4982bd94e936ef31c0a2165eb2f14ef545d735e04decf9c1efab", 16) - g2To78x, _ := new(big.Int).SetString("c0c3281519d3a66eeef710d61aa05a648c02108d193a0f60d69e4341f3d916eafdb4ff66559e365f44d5c1375a8c4f", 16) - g2To78y, _ := new(big.Int).SetString("1321f3814e3da08308073186aa0bd0e0c4fdac4effd332b58cc91b71d02f9c621b943c3d5d0796def3767afb7b67f8a", 16) - g2To79x, _ := new(big.Int).SetString("90830b4e3531c735e3842b3fb1bde63a7f73b380f9193bbe8ab7dea4af48f08d8cd085130fbcf1b328a3c9dcbe6a76", 16) - g2To79y, _ := new(big.Int).SetString("f509e10a3207e10696ccfa1abe78b556f532d6f5d8803a35186286466d65aabce571dfc3c644a8c448ee6014705cec", 16) - g2To80x, _ := new(big.Int).SetString("10531f514b920d4051719e3341c279e8e5892b73a6d03d7805f81d08cfac7367b3377f575cda8fc69ccb268f99937a", 16) - g2To80y, _ := new(big.Int).SetString("5a8aace529af52e6842a6dd12ef0d34a841a87edd0351f959a3fdf05316a40894b8424f5c8bc48896708a49c04a136", 16) - g2To81x, _ := new(big.Int).SetString("12a8f78469b6185103baf43ccb81fe98768366766da34efbea5ee12eaffe6f4b72dbbf615bddadf184c59326de5940c", 16) - g2To81y, _ := new(big.Int).SetString("60fe8174c79a00c14b389ef1bc853700b4fa990c34ffa2ca1c681c1decedbf9ba688dca5010fe8b7e5bbfe1b021b29", 16) - g2To82x, _ := new(big.Int).SetString("96a56b5bca31bb6f97724d57f7b80380e1f0a2fa32d2226d92c9335971d8a5dcfd765a75cbd2be6b5932b886eca12c", 16) - g2To82y, _ := new(big.Int).SetString("9f33be6bc8bea9511acf18ec9fd8b71025f75150a2ef9fe83b724c0acfe07a6faa7e96e4cd53bde14ae4b96a53ab2f", 16) - g2To83x, _ := new(big.Int).SetString("17862b6d524f16e02a084e9fb0654973aa92da25a0f118ba93df9a105d2c00c740d2169545e7494a1636a7ac086edda", 16) - g2To83y, _ := new(big.Int).SetString("10c1e04620e95976bfdf742bdb03533b7b55046a9aa5a8517e42db7b71aaf00ebb236eee62a1959b96bdad8ccc914bf", 16) - g2To84x, _ := new(big.Int).SetString("2b44930db60c5e62fda1ee9936201d3115c63e40894a354fedaffda074b07c6c54d3035cc69ba2622af4a1127d523a", 16) - g2To84y, _ := new(big.Int).SetString("afda5460f7fc032597d3fc38834540acd3037d394dd7aa3133d0d1082d6758e87c8422f7addfaa885a5d551132b275", 16) - g2To85x, _ := new(big.Int).SetString("7d20b0283582f3e2efb8ef9561e69f645ff108db1a9a94694783649acdaabb957ca2bd76c84714da306f36cf95b416", 16) - g2To85y, _ := new(big.Int).SetString("70a720b8f2f5aa5e9307245d554b599372203318b5ca241656bb133e38cadd215f0d46eac4dcfd144d27d9b1d8fcb8", 16) - g2To86x, _ := new(big.Int).SetString("19c3ef7b33932b842f91ecbee1b588277fdb1a8bb1dfdda304f94ea33b9a07420a1f54dfc6da8ed2865d3132c85fc1b", 16) - g2To86y, _ := new(big.Int).SetString("c5a8a15999fb9021ea63c9141795080d4ef705cb988c4a1c97bba7070584890c6ff6fb78422004bbc86fbb5910274", 16) - g2To87x, _ := new(big.Int).SetString("160475f653c938043ee3949cec0fbde6737e67a4153c900ca8e7c08f17c42c1065b9304f46753dad2c35eb29be942af", 16) - g2To87y, _ := new(big.Int).SetString("d11cb6b0c5394dd2cad261f7846de206762fbde37b91eca7421fde35763f0454277baeae33525668e619e5a2d025e6", 16) - g2To88x, _ := new(big.Int).SetString("17841df9133f6a38903b90a0a67b2f0374207566992a3312dd0f6a1df2213c788a5e716ca0aa49245d8321b094f3cda", 16) - g2To88y, _ := new(big.Int).SetString("4d13e575ddc348796fffc4eac9f510ffe1f079d531c2b524d462cd49384373be208e7903bd8e5c574085355a33d113", 16) - g2To89x, _ := new(big.Int).SetString("13c0591a0f059e36f943d0e24f1c27a7ec66d12057c958a22bdb3583e1d9a50a4a60e4aec16dd586e45275ba543cf1f", 16) - g2To89y, _ := new(big.Int).SetString("4a529fe7cc3a88767be9720803cc8c3ea908bd8b79ec3a635dc6d4a2ff526fa378f5e94f23fc462f67fe66f0727d03", 16) - g2To90x, _ := new(big.Int).SetString("c59e4fae1f057573b420ec1bd61f8be08bc040689990a9ee866b4803d4dc50a9ad832c470a6e10ebaa3c738afa1523", 16) - g2To90y, _ := new(big.Int).SetString("110ca4c030099d03f733ea9de3f674464b4b8ccb2385945a148414a9f95fd4579c630320e27baca3dc7fb2141bf2f5b", 16) - g2To91x, _ := new(big.Int).SetString("763925b8f5ef62d240d76aca100de7dfea130bf34a09f7e70fa74a0978137699840f7242086761595db4b5c844c872", 16) - g2To91y, _ := new(big.Int).SetString("1a7b4929003f677f9194349f5e72ea5fc2594a146405bb917a23b232991da2663763df8eb866603c11025ba823e13c8", 16) - g2To92x, _ := new(big.Int).SetString("773e594f149dd63a3b6180bc3ecd958a142c249a2c554d20a6ae08c4b8218dcfafba746100f395fba248d05cbedb56", 16) - g2To92y, _ := new(big.Int).SetString("170f97f41c75a7bdd7f45885847fb0e9c77482b345d8cdc212e43dcfe3172c4c2ef4f7bf0a85c35833eb0f07404a460", 16) - g2To93x, _ := new(big.Int).SetString("72f4cdc52c410c573a6b6877f123ce328312321d118a743d640a62208fd96ceecf94f5105d216628f327c131cd57f2", 16) - g2To93y, _ := new(big.Int).SetString("d979e10ef5e4bf4b079db8f4b92535d3163cfe65f4cf780f2f588a9ff15a17c2fd99abea87d947b3eba898e275189", 16) - g2To94x, _ := new(big.Int).SetString("1500f73c1580e754583a10830b68534664a92011ecb99fc49a6b8ff8e16403dec02ffc5025283f9daf89afded75aa4d", 16) - g2To94y, _ := new(big.Int).SetString("1123e023b823cb49e34b883254a55c6830213fae288a12638a3c4858db3324a780590a26eca1ab0bfeebe1231c64fc0", 16) - g2To95x, _ := new(big.Int).SetString("138dcd92af7921b62bd16966f89907ae6cf447bff72129cb94b945324fff201ed119837e4c789f7daf5d1348ccb3f4e", 16) - g2To95y, _ := new(big.Int).SetString("b316c8be8dc0963cf075e8ae59b4d8589dfc07e41b22351c5e77fa3ab75fd11bc0a7f16857609bd196725896f5492a", 16) - g2To96x, _ := new(big.Int).SetString("101ea5fdb817941a117aabea37c5409a815c527b3d2aeca08ebdc6888749da51efcc57e0f9413b38ff38937b5d75cef", 16) - g2To96y, _ := new(big.Int).SetString("16c70419efb5ee583789653307a3ad9ef5cc4e92cb36e050fe02d6ab5771c24059ed9042b32d2e3b80dabc9e76dbec0", 16) - g2To97x, _ := new(big.Int).SetString("6b196d937da669209d3180b6e0d1840c79ed567ff337c823075e3fcc0bcefc24be337af22e9a37bd282a4f73b39de", 16) - g2To97y, _ := new(big.Int).SetString("25c43a9d0e59c35eff1e825b2111e1e90b364b8a930a2d3745137a05b054242f377582b02e527a33bf2cb95b6ad919", 16) - g2To98x, _ := new(big.Int).SetString("3496658a2ecc3a834db0fc9d84fae1aa75e0f78f126423216ff6b66880755152b21c046e8c34b13f8a1d62e477b5b9", 16) - g2To98y, _ := new(big.Int).SetString("d479674629f00313a607397c5c90bdf27eb487ec9f04fff1e56a61b92240fdd93ef876dd14c4734311e876ac49f6ab", 16) - g2To99x, _ := new(big.Int).SetString("19a0aa4853b07b1cb768e74c4f7c628f734856a90f598ffd1441f11b1384477a4a05bf25f2d17e152a2417bfb0ae87d", 16) - g2To99y, _ := new(big.Int).SetString("14ce74b65fd7001822b0778c113cde10cb11b6cbd5014f766fb6bc1c2b72a4e9f7d72407c8a47e3427595ad0bacad9c", 16) - g2To100x, _ := new(big.Int).SetString("2044ddbbf0dec33e557caf3f2b88173c44bc9a26bcca970852f46cd3202c28a254fd14d2b44ef1343724691441e055", 16) - g2To100y, _ := new(big.Int).SetString("134e03d8d8900fde4f640624dd05c5f0120559df6bc9dae7dcee6e6a483ad7b749e00d97ba8b81df8cde07b16ad097d", 16) - g2To101x, _ := new(big.Int).SetString("320ddc8cec816f4f1b9d5cbc9782f28457e5034436f318b8bfc4ff5cea2426ca402b2cef332e5d1fd88c215f747e72", 16) - g2To101y, _ := new(big.Int).SetString("12a211c464b89f00c61302c790230e80ff8a3616bce1acffaaef0a40cda2ff68a2657ed5b7dc5025d3c2b0435bd0077", 16) - g2To102x, _ := new(big.Int).SetString("fb79ae0ecd6f1b3f46f5a1f67188388e3292ed3b2222b32d631ac8d6683a10724b9642b255cc3c233b18f8e44666cc", 16) - g2To102y, _ := new(big.Int).SetString("50d1ffc9d8a2e03d7054c716a9bc66d023ab40fe7f460538b27c3c55c24a4459bbad18340f3cea2021df64f0f842dd", 16) - g2To103x, _ := new(big.Int).SetString("1129ea0748cdb9b845b5bc40ed9e0be0ffb8cf89445ae3389d99c6ec446759a58d6c8d27b0576918bae0a58f8f0a029", 16) - g2To103y, _ := new(big.Int).SetString("11546c1a2cded1c9437a93e59dc9cc5101e3464af5c7270ac2b2336130bbbcdf2655b4465428377b805fcb059669410", 16) - g2To104x, _ := new(big.Int).SetString("18c8d9e58d0197ede9759ecd91b67d6b5015d325c7583946865b5d2de5a05adc3203172c3f7411374186ac4b453674b", 16) - g2To104y, _ := new(big.Int).SetString("19dd01ebcd952016ed6385a5394627c9298898908e73750fe55d3a23d84b8287dc2f9f3d9fb7c6648b0f8593eaece2d", 16) - g2To105x, _ := new(big.Int).SetString("d21dbcdc3d7262275f9350c31b675c22d06ab047ae8fbd181fd0753128bf0c8989f0cfcc73100b16a630eb07c99310", 16) - g2To105y, _ := new(big.Int).SetString("19f1f79a45e3f8c0e7052850671a64d6bdc7f98261bb81cd99b7cd802754b47870acfc7e12decee0a08bb89bdf27fac", 16) - g2To106x, _ := new(big.Int).SetString("393a7383d765c36e360dd01d29abdf0715d7168c59cce0efeea765c0b03f29c3a2ff76022a0ae3cfe44f94e7c47127", 16) - g2To106y, _ := new(big.Int).SetString("f4f07b787a555b1d7615ee63ec118f890ba99f98f470f88dfc5cff57fb3f01c077fb13c8703fa538a357b7837ccc19", 16) - g2To107x, _ := new(big.Int).SetString("80122ac51038d1ddef4ac8494a52920e89f63bcb7cd198192da5311acb3fe847017509fb9290f7bf262e786461b9fd", 16) - g2To107y, _ := new(big.Int).SetString("17e39ca2ee4a8eb9f89a4ac907a54209ea8a0b75a9ff6829c4cf98452891166bbd573b2a537cd740f620bab4fcc32cf", 16) - g2To108x, _ := new(big.Int).SetString("9b7138398d7017dab8c04b23364f37d17a61a44d50bff2e05ab096ad0ac5067d30889802dbe92f57b330e8752a8721", 16) - g2To108y, _ := new(big.Int).SetString("b0df5aabf78731bd4990843eb1f349c95670c6b67d2fcdc0fb170736b93b608de24aec60db88813e5c6ec199aa94fd", 16) - g2To109x, _ := new(big.Int).SetString("e091d99dc6037d1f4c24b74d4c4565da3af54c75fd095283cdfafce856e46844d450fb3488d3ba4598ebebb8327c2b", 16) - g2To109y, _ := new(big.Int).SetString("729e298310ea46c8038352f4af4e5ee9b33634f91b2fc252df262c6c39b54496f3b6894ed641bab49b0da26450b985", 16) - g2To110x, _ := new(big.Int).SetString("e3eed427c6a5017599b40f73cdb22e1d40fa9376f301fcf32f64b75fecde7a782320544b9cf3a59df3de15d1cd2275", 16) - g2To110y, _ := new(big.Int).SetString("72598a238bfdc22f2e5791853c64ba305d96051afb1367d57dec6191945c4ad39992dfed2f526f660235470e22d676", 16) - g2To111x, _ := new(big.Int).SetString("4ecb8e157e3531ab8f9018f6b205812ea61410c058a8cdc9a8f74b3dde14ea3255ca1771eb1fb38377cb4a45f5ac97", 16) - g2To111y, _ := new(big.Int).SetString("3ff73af8c95bca6d67fa2d006b8e737a3839b159179abfbbf851e549fb2eb134e6dd1d6bdda529079be3ee37d52366", 16) - g2To112x, _ := new(big.Int).SetString("af7a0c0e2c15f9f0fc230bf9e8dd54ce6e623c6e5e050c7784ce3274fdf2c68615b7b536f1fbd93a6c65d200f0dd2b", 16) - g2To112y, _ := new(big.Int).SetString("11c21280451bc798e2849a37eeaffdb8070b44812fcc1a42216e8261170e6faee5eb2e99a70479885481f868f7ffdab", 16) - g2To113x, _ := new(big.Int).SetString("467bb117e14f72ed478889189b78614ce929e0a11dc4c9fe5f4b3c94460845fc1a93a7e84f2d017ffcd8e766153108", 16) - g2To113y, _ := new(big.Int).SetString("11f478fc0b3d40880188a104fd6db94db06a96a11446b8204c5047f08361dd20b1c6d3b9e8c7683bc93a7e3f9b48009", 16) - g2To114x, _ := new(big.Int).SetString("21040890dbe4d60a532435850be5e3b85be4efa8d3e4b53f6e9b86435fd5b584707082f3f2013137bf7e83e6a6be87", 16) - g2To114y, _ := new(big.Int).SetString("3a46738a14f592e5f25cdb3687f23b572bdccf6e1bf3cf3c087573ddc2ddf56acb0f2f7c024b8f22e7fe215ffd569b", 16) - g2To115x, _ := new(big.Int).SetString("19d00592cb821b60089fdc0963e4d40c1d427a41bd99249b9209e79b15e53b5671f1f002f97b0a3a1a1d87799a065df", 16) - g2To115y, _ := new(big.Int).SetString("13cba57cdc23a8c650025500cbafd661cad5dd269f8569ced5c190ed94d1c97468e54472bdb19d8533c3efc24620283", 16) - g2To116x, _ := new(big.Int).SetString("5bcc22bdd1b8f6bd3697c48899f3c3c66d3ed95bde450507175df4e99bdfee8b5140b2113d09172309e7f92b1997cd", 16) - g2To116y, _ := new(big.Int).SetString("607ba58c3109aba00b398acdb1210b877194e6b658c85d99905af6b762c3a5d0290dd555af824cc6dd58221a8dc072", 16) - g2To117x, _ := new(big.Int).SetString("1fc7f19047611351202a7f5332c1fc97b359a1c521f20afa9b334963467485600b6f8016438e9c51af8442b86c1314", 16) - g2To117y, _ := new(big.Int).SetString("a72af1b9824439482958fd9e3f8fe750cd8409e2d527bcc3542a5e03e46378e7fb745f064ffd357e168234e8477687", 16) - g2To118x, _ := new(big.Int).SetString("7ae261965d9fe9cd01ede8ebdec85bcfd51970aa009425f795b27a625129c51fc4f209d21a43db6cb0f64b3c828c90", 16) - g2To118y, _ := new(big.Int).SetString("e1f9b9bc743372d94c063abf6ba56008f0d07472b7c0ba96362fcebcd267bba72133d5dd9d4e422a2cca2ee2e1a0f1", 16) - g2To119x, _ := new(big.Int).SetString("55838e6a68c9e022b657bf2cbb728021fabe867767bf84da222d2314f94d78cd7fc555fbb2384914daf68aa044fa10", 16) - g2To119y, _ := new(big.Int).SetString("1540e4114abff824399c889d0e259166858a8f950766b071267e7747ea9580ffb5d3b03d41ca558233eed812e920af3", 16) - g2To120x, _ := new(big.Int).SetString("944b4fc0ca112cfa7ac887aa61167fea6d2be550b52c31daf2b43c732bc3cca9a23bc7b7b9767eb59f2c15d3f53ecc", 16) - g2To120y, _ := new(big.Int).SetString("e10c7dcbdd84002e7da14bfd1337da7c1acd68c7604292020ea4756bab5dc9c29be790f59e9f19c6ddf2063c3b9ddf", 16) - g2To121x, _ := new(big.Int).SetString("1814aa8084352ca9646edc03f3a666a49d6c8c6b397c75a3f2db4e7367c961eec704d60b2f056ca622eba5e7d5aed17", 16) - g2To121y, _ := new(big.Int).SetString("1091aa493ba3e157ca796bbbda78c2a6173b353b98bfdf64cad515be0633dda924b04ec769a95a7b9907677210f4eca", 16) - g2To122x, _ := new(big.Int).SetString("4c79be993599aa6f2cc588c9a17729e07fd443b5d0be7d71e6374bc1b6cd7853a8d5cdd2fd1f355512cff3abd6847e", 16) - g2To122y, _ := new(big.Int).SetString("17969fb3d5c1520400aa5f89bc13dc5553bb16fbec5dc3d3b05719c593201b2384c81a3e52b72273ff4a7e10d17ec66", 16) - g2To123x, _ := new(big.Int).SetString("56e4cd225404894800e1a17d0a9b01b6210ed3e42d8df1912c77772ac47cab49b52054a7c3f6ebf8f77c00ccfcb888", 16) - g2To123y, _ := new(big.Int).SetString("48996d22cb69b2d6a9f29ce0c1d8bcb75725b77caa0f1dcefb6523d5f2056399c9c19c3eead6480dba0928cc691c8e", 16) - g2To124x, _ := new(big.Int).SetString("1795d38c0f3168e622a236ae402e9f1ae6b13fde7b65429b03453066489e147213b8ee6745ddfed915ff10fe780742c", 16) - g2To124y, _ := new(big.Int).SetString("5873e3cbcd5dcb0ece242388d565088fd2181264fad06534c9416a887f7eb115fe259b97987bd8bd794fe1bff88187", 16) - g2To125x, _ := new(big.Int).SetString("117f497140d0e102b9612a0c0760c5fae1bf451a40501debe6ff6a0c6bf0be1b0957dbc274f4a2c3d5b0db48ee39ca0", 16) - g2To125y, _ := new(big.Int).SetString("380dae20e3f1e6b897371384a44e757a2d7a84df6666e32cb6c8fbc5e06e762d27f9cfd6ba1459b45fb327432e49ce", 16) - g2To126x, _ := new(big.Int).SetString("bb69b209c8d3382211895e4f0c0f69efbbaac9b51bb76793fa50acc1254105433e8afad7511c492e6e864480fafd61", 16) - g2To126y, _ := new(big.Int).SetString("85f238d05a21136f7f88114e7cc8cb2e7ed0be3e4b73dfd1be654577ff75db8baffd94f1746044efbba8cbe219521d", 16) - g2To127x, _ := new(big.Int).SetString("19f732e83c5801519c11076d13d81be227279802aca85d79a7c70ab68df622942e496f46e175b88c4c3fc5fde7bfe31", 16) - g2To127y, _ := new(big.Int).SetString("66d4699239e91cf083b474b9e2eadda2754630528a209d7fdde9018dec26fc93c039c9315922abe377f6b2739d2a8a", 16) - g2To128x, _ := new(big.Int).SetString("e4792c45ea0374775d9005fcfca11a9cf28cef25cb45c4ce3a4fcf88fa648378d0473f07ff1a56a9f3b7a593fe5002", 16) - g2To128y, _ := new(big.Int).SetString("1acb4c048149b23c021e9df25fe5b3fc54b77d3f2295926565b6179955af9dcc41d53713878d285916f2e01c6fa6e31", 16) - g2To129x, _ := new(big.Int).SetString("18af57cc0cba6db0d3c81025895bb6c552297a1ff24f5fb93e01270405c3ca1a010f3cf3463f03893e45d68bc8a2f62", 16) - g2To129y, _ := new(big.Int).SetString("1fd7cfe2078a0e1e79ee9fb7877872c382fe387ccb8797007654656774e15bef83c3f55928d5454e620fe073de20ee", 16) - g2To130x, _ := new(big.Int).SetString("12cc5b7441a487be214269e527ec1176f2f6dde1bd1fe02a08fdc92410c91d8d883fe9f7151c19c235e9dde01f5d9d0", 16) - g2To130y, _ := new(big.Int).SetString("67dbd3814cdcd0c12ff13eff08e790faac9b3c9895a233d71ecb5399c16983ea1623fc1b7422c061d9c7338e82108e", 16) - g2To131x, _ := new(big.Int).SetString("15318da6e7435d4194e5253f4bfff8adec4aab7304e49182c5d3a1ee498d800cef3e3a5762d8d6e7029a8b396e5df96", 16) - g2To131y, _ := new(big.Int).SetString("557ecd16ceb9695e6909571f371b659738fb6e61e69b73fb7b932a88e6c064cc73191053606716df7747aa07ebd47b", 16) - g2To132x, _ := new(big.Int).SetString("320b3b8315d2f24baed0ead61c7ef235b7dab1b76a3120c99cf15ff76af149aaa37cfaf7751ed74d541aba79f7485d", 16) - g2To132y, _ := new(big.Int).SetString("1580b7920ee4b3407677ef153239024119a12cbd13e9811e6a1736dbb03a873b4bfd2c8bc897f94e94a01eecd6dd3fd", 16) - g2To133x, _ := new(big.Int).SetString("9c942c27e37b0eea666d85dc58a566e900f88451e4cd3dc5133a62f6dde3a5c93307f3c86e7d336573a95f38c86448", 16) - g2To133y, _ := new(big.Int).SetString("48250ddc92820ecd6fcadcca3d6bf73dd4d6bfa66f5b49bc59001574b09f05f99e74d3ea9f91c8579d7f38fb2c8763", 16) - g2To134x, _ := new(big.Int).SetString("15ebc88aac7bcbc57c2b057692e1b99cfc9ad13972d89eea008239c015b74ecaf80c889f65ddb8129f321b214f7e599", 16) - g2To134y, _ := new(big.Int).SetString("80e4b8b7ba1a7c5f1de2b62f64ba4693652a307dd9b1a92252c4291c69335cf0b8c6f8561a15462916c24a78141823", 16) - g2To135x, _ := new(big.Int).SetString("18b3a334505d4c7cc8b4f906dc3496316d8d02c128fcd88ca1139f09e0957a3d7360aa03f19d9aa9e1ca509ed0a7287", 16) - g2To135y, _ := new(big.Int).SetString("50899b31fb24615a49ab0f49bc38371ddf1ca7982cf30b43c929041bd16444ed13d4a851943d195275c55315a6bc4c", 16) - g2To136x, _ := new(big.Int).SetString("324957c3564d435c9e28916ce384b568bad35e8da0416becf4dcb8d47a5f9b99b59ff84e2f3d01306e32faf4ec1b1e", 16) - g2To136y, _ := new(big.Int).SetString("180b670ab4b14f4af15fad06c063199c831f15c730fe1ef169f2a24ee3c87ea18f9e8ea393b3ab693de860a3c3b19e3", 16) - g2To137x, _ := new(big.Int).SetString("55bcc692af3a8ed7313777f1085effcee98ddf6bdfd0a4cbab5e805c313b15a637bbe3097fd4328bb37c922e8e8d0", 16) - g2To137y, _ := new(big.Int).SetString("14ef17878c43aadf2bee219d4d4ac616ffe2bb2ca85c5add0e091ba5e4471a2e9a4324a02f5aad8c497d19a339fd64b", 16) - g2To138x, _ := new(big.Int).SetString("1d282049941b376a7bdb9b0e81c5d5fc6d3df7c4dd9059d02bee35ffe56481afd1911ce2efc80384f2221145747f84", 16) - g2To138y, _ := new(big.Int).SetString("12d5989e164bf32bc49ce538bc2185f3ba43d10e5bc5865cd523ff3681c14cc4c77a159dc77e909dc4ae17fb16c207a", 16) - g2To139x, _ := new(big.Int).SetString("cabdd2d555e7fdbf15eea8d9e879dae763b74813ca8e7e7201222d0163f7819dabb4e9a177d0215c8ee0209f818e3a", 16) - g2To139y, _ := new(big.Int).SetString("b5e9b30c2bee3862bcf355e0ae8402ceb6e595557d1d89799f9dac25e857690d6ab274d64f395b2e1875ad09a5f7c4", 16) - g2To140x, _ := new(big.Int).SetString("3756b96f44a0b8d81e869f8105fe226a1dc0c422b372ef16bf1c960151838075fc1d0be337631b42bd7a17ef158c20", 16) - g2To140y, _ := new(big.Int).SetString("185eff03736ded483448d28e5e609429609ff67094f880a79f9884a77ae121cef32aed642a1664ae5a0934e80e0a791", 16) - g2To141x, _ := new(big.Int).SetString("83abdf9576124e1579a07d704dfd0eb68b3eaef853a00d9ed7ce519bffd0f016b22053d2eea2478f69a668a26ec6cd", 16) - g2To141y, _ := new(big.Int).SetString("1a23389ceda0fae24bc826d9cad8cb0791f933d6d5fb549c08cb6a6fb420a9b2925a221b7a0d3c7e2078d728ac03bfd", 16) - g2To142x, _ := new(big.Int).SetString("1025af987dc0aa4594bf71b342b71dfa9be8ea9440f6cb940288c14fc53926062169a28fc6f968f5a06cdffc4c2f3bc", 16) - g2To142y, _ := new(big.Int).SetString("124266250eda81a840f60b00c5332d52404e97c4dab39fc2737fe972bd800ec451dcb55aba8f5c8a9bed1e4ed9e2f3f", 16) - g2To143x, _ := new(big.Int).SetString("f95cfdcb19aff123335c9294fa46f7df5585001076640f0306c04c5b7f826e314776ab7f8428e8e24d44cbff92b135", 16) - g2To143y, _ := new(big.Int).SetString("157fc1ecb3d469a07b6319864e2b0cdaf20b9ac53a34f2af7f960d6feaaa2c1c063e2b5f39256612f8517f6a1e8488c", 16) - g2To144x, _ := new(big.Int).SetString("d3f7e41e0d6dca357b0eb5ff58ad3edc9eb4cc825d96fb2db4c13bbc26d85cedd3d0bc1fc2259dff6493b150e7018d", 16) - g2To144y, _ := new(big.Int).SetString("14cf7eb25efc61049a02975c507595406a02915c85a361e72aeadfc65f647c576d87a28822880684b9e6f486d9341ac", 16) - g2To145x, _ := new(big.Int).SetString("d76126e3b8f6c41767722603e99dacdc2c07a20710e51da646d473fa0afebd76c30c230b6ab66539ad5813e7207f1", 16) - g2To145y, _ := new(big.Int).SetString("8ec28dd0b2eb92af66344e8beddf6b47962bf3564c4ec460261683910f35a996e48b0aedd1b4b204600638d935c85", 16) - g2To146x, _ := new(big.Int).SetString("1501b1cb3bad5faa01786c85390ea937130f8045f0c10c9dc2bc81a5a8f3dfdc6c44c38386a18c6aeaf32ae615628fb", 16) - g2To146y, _ := new(big.Int).SetString("483f53ba6eb054817101d01fd4b93c84dfbfcb4a003df00344798866f70c52bb53f6c1344f3727116b3eaea6191fcb", 16) - g2To147x, _ := new(big.Int).SetString("10086ea020c2276607abd7656c03d5ed96fde894a409d9a409fd363298da9741231e8d3ac02baac482431b157ace447", 16) - g2To147y, _ := new(big.Int).SetString("3fc52b9384c8a28f37cf21ad02c24a39f0c52d6c2bcba1b2ee2b0d0bf0093b7185445241f3dae009709d8c82fae8a7", 16) - g2To148x, _ := new(big.Int).SetString("42241569f4225c2ab29b43c20f2f91646397db50d2d48bc19c13a98b72c3cebd8b09ab7cd1e6d82a9f427b0dd6138a", 16) - g2To148y, _ := new(big.Int).SetString("f945aad154d8008cc453a734e92166572a3b0e2ec1dbfed5444990999849908c709383f23fa31f436bdfcedf11b75f", 16) - g2To149x, _ := new(big.Int).SetString("c9f67f6dbc91e05e5ddf0503a62858c29d86a0d183dac66a834a38c7351152f4a391864afee16226a94ab3c1a7c42e", 16) - g2To149y, _ := new(big.Int).SetString("a6609b594fcc8075bb3a73ce66bbf3b7665abafe4017d176067af46f52f5a9116644bfc0e5bca6ee1b8ac8158d4e12", 16) - g2To150x, _ := new(big.Int).SetString("1153c5af141928d2fc95e766c33dab8feef4b9130700659e5d8f5efebfb043d73ee4337c5f0fc733edc4539698a4a15", 16) - g2To150y, _ := new(big.Int).SetString("e12d0a44494b847726c36b27f89e9ad39e6550ccc1e4829f792a8ceb51eac58b8bd434c09111dd81beca462de88c2b", 16) - g2To151x, _ := new(big.Int).SetString("3c5aaf47dbcd0dd23a0fa0c2051ba8c3d0fe6ac1eaf40188bab2f9de5927217944a7c102ab828718ac8e7661b10d11", 16) - g2To151y, _ := new(big.Int).SetString("1776473aff44785cfa49c3c90d715081e987acc7652039db8a3df404b0804c124319dcebeed7da580ee9082e96cd671", 16) - g2To152x, _ := new(big.Int).SetString("14e85d6dd8e43ae3579caf05c4f60311bbef732d30a4adabb4718b14651f7cf649a1b211425e46a462cfc774aebfceb", 16) - g2To152y, _ := new(big.Int).SetString("12a314ef9a9376289103bce265dc11be2a3cf93080568d3b2a67e7c78e78950ce35338169501930e5e59c162e489c31", 16) - g2To153x, _ := new(big.Int).SetString("3bd85a843e5f7cb348c19ae3219a3ea7493b615acfdc2df784a5b386e520b0eb1b2e9b91431d24917a822bf779796", 16) - g2To153y, _ := new(big.Int).SetString("cb11b6ad47b64ddc1968ccdcc60f91159879bb11ac7b035111a622e805b33d81189e8f695df8e7f181f1751fe6f7a0", 16) - g2To154x, _ := new(big.Int).SetString("10e41425e5297f70eb296aaa09c5f2ba87f8d22fd05cb0b8a984441b4b9998bd896af921f19f8b5a2a9698e24fa764e", 16) - g2To154y, _ := new(big.Int).SetString("281547615a1a34525b0910a27a705f36b1fbf2629284007c1842ab8259d9c7fed09ce955d4923710275cacfdbbfc42", 16) - g2To155x, _ := new(big.Int).SetString("24dfaca436700b2a28321fbbb35a8a8710f0b53506da3444d25d7258c3557a7f04ff4066c3577a382b78cfeffb1fb9", 16) - g2To155y, _ := new(big.Int).SetString("17cce223736ad9349c8ba8e85fc84473331f94573d220051df7654a37ad183c0ee66cc65f21870945ccf2b3cb5a4a3a", 16) - g2To156x, _ := new(big.Int).SetString("108ffd6cd88e29e760c221a6a8630eea55741e4d69cf25bb18d27b48c142ae6bc909578a243af518fc431ce17632763", 16) - g2To156y, _ := new(big.Int).SetString("7a4007cbf16132fff1cc4672297bbac19491404299836b6f0462ca11b230f6a170a353bad9bd6cccca1e84e76104d4", 16) - g2To157x, _ := new(big.Int).SetString("127465b15bbe5570434356ab8b9a4288f764b9777d9be89b52d93af6ace9f18d79ef8d26fe686e935583bb1b35f2662", 16) - g2To157y, _ := new(big.Int).SetString("135739c799b7b80f38d3973e2c1a96519d0daf16e384c2a6e988bc9c512feeb36025dcc0bafbb4029a0baed39d08977", 16) - g2To158x, _ := new(big.Int).SetString("a47d778a09e9b91e8a66e1b7ff48855de7c086c22e97e2a33d78cd6ac0f03789ef65ad6c42bd7469d79e8a771b3014", 16) - g2To158y, _ := new(big.Int).SetString("19807686de5ade7f78c1e92df43e146f59458f7a7ed3632917bcee346a09b17c771c0c30ebfa30eb574db51825ff2ff", 16) - g2To159x, _ := new(big.Int).SetString("553bbe29a93925cacc8f63a35bf3111930ac49d6cf6c4748690697385b9beaff873f9d50e737a67035cc4630d304cd", 16) - g2To159y, _ := new(big.Int).SetString("7ae6ac5a15a6904163bd3f4231aecb2a3ff35ac04dcc88dcea26054957fee459b1d655210c82492a91d21e9c62eb86", 16) - g2To160x, _ := new(big.Int).SetString("15f77fdc47ab14c2101f763260f537f2350f2fd32bf1b2f27451524a2559baf8e683aa0362294c1e8c3f50e72f9142f", 16) - g2To160y, _ := new(big.Int).SetString("9d4009700bcd44218332952b3d1d7f2265e8e554bb6e991929b1e96d9fdca23b05acf0b70c7af4b5840f90c11371b", 16) - g2To161x, _ := new(big.Int).SetString("155082f9a8c24a6cf3200452141640bec8fae3a269872e4f535f5f58ecb3ae9789133dc3707cf1936be2461c942c1ac", 16) - g2To161y, _ := new(big.Int).SetString("16fab5585ec39985e7372355d7911eb1d3ab1fca71e920504172278c1a61ddb3d9959e0d4a61aac70d322f5c145dee2", 16) - g2To162x, _ := new(big.Int).SetString("3fb08dc59a282d83866eecc906b694f1d92b24e87658814ad685cb6b110b749db7a1d7c0185be7b4c8a325fb7bb6dc", 16) - g2To162y, _ := new(big.Int).SetString("3e98c7707613366535514c7bda8a9d20f4102fd81f3fcebe6734aae4e231c937b46b23d823b960cb8040a8287dd5bd", 16) - g2To163x, _ := new(big.Int).SetString("133c8d89b872593cf25925ba8d7f240a85029eea7006a58388a6f7549efff747a9f5f7a44f7016854ca345e8620e7f5", 16) - g2To163y, _ := new(big.Int).SetString("1028b91b8e2f13769a0190c0e9fed0d842f0c3efd531e5df212cecccfd314e189d56d54565cbe206c2ae326b882dac3", 16) - g2To164x, _ := new(big.Int).SetString("6422c61104e62eee280da427bdd2e91fde9e9a1f9df8d77b1b0e91ee5db2d2ade3c6986c5e8c0ec21035ccc35f93d4", 16) - g2To164y, _ := new(big.Int).SetString("18cf5bf95c516e422ff72afb2df3d1f99b08fcdd69657f5ce7ab8bcf6a8f3eb717dc69a32ffd79e048b7d45bd353f7f", 16) - g2To165x, _ := new(big.Int).SetString("bb49069be1114cd86fb632d7e3dfb7ba79bb3aa8e842298169ba74a53f61e182f27cad88e6c8b243b9e068120e6cc8", 16) - g2To165y, _ := new(big.Int).SetString("b50b69c4b23b3e07123aadd4119784e70c32735424b88094b08c75a456daa4f7626bff7daa51f2c73d30ddc5318570", 16) - g2To166x, _ := new(big.Int).SetString("12a19d3de6d72caac8d34bbd6e90546ec0a4009e574be029a66f339500bbe021b34383e410617fb0a526591286e0643", 16) - g2To166y, _ := new(big.Int).SetString("9b406052873481fafdb61a8adfc9019e48faac87c9e44121af21f0a4cff2774798e28fb783bb8e7e31dc4a313d7a91", 16) - g2To167x, _ := new(big.Int).SetString("10906d84db20b228bb0388b23ce4488e21775454205d723df5a075c51e4dd153774343fc43b58075de945f24bfebb67", 16) - g2To167y, _ := new(big.Int).SetString("7cfe72c84ca6b9dabb5c139ba427cc47e87b4ba07d24d410c430a2b9b5c6b7f9237bdd5fe199be039d8181b2d4649f", 16) - g2To168x, _ := new(big.Int).SetString("910bc0e25094b13d6e04b32302f247d99cb4a71d9a1d8cdc75a467bdce8160d8af85beccb93dabb2cf1e15cd359ea8", 16) - g2To168y, _ := new(big.Int).SetString("c3d5f0eecd86b5f0dbfa46038cf379197d0112e674dd50f6071eb9b787d000ecf2b4ad8717af94fdfc8bc162d91345", 16) - g2To169x, _ := new(big.Int).SetString("170f6e8c17ee0f447e7c56000ec81b125743fc7a71c61e099d368c89d7e9bdd6f91b9828865d1c21bcd01f1101e13b0", 16) - g2To169y, _ := new(big.Int).SetString("b4179cea51ddb18b7f53b44f96c32d409a5170ab59624bf81562545d451ed3a77e82287d8331b6077b76c920a79de7", 16) - g2To170x, _ := new(big.Int).SetString("5f3a211c40201fc17f6aac6f9ca51bf34e2adfe0c385fe9434db7e711b1c442fe8342da2f3ae012b26b932c3fec0cc", 16) - g2To170y, _ := new(big.Int).SetString("16173a4992b83b3a498bbade3c171fd251a1877fca293db16f50fb73cfb410c67c98a21c8e39c6f2ca22547a0096cbc", 16) - g2To171x, _ := new(big.Int).SetString("c4eb3ee27f8b8d47854a14084f3165ef885d4ef7aa848263e8e08326eb8ff10931e72237a46735f5b1abaf11850dad", 16) - g2To171y, _ := new(big.Int).SetString("ca881eb1904d3980dc3ad9e49dea9feb0333bb8f61b3ade8020a7108379fa9289e17f86ee0ff5ebd009dbb873bfdd7", 16) - g2To172x, _ := new(big.Int).SetString("bcace195e9b15a115edd0bc6cb21722ad3556a8945470c1a556bc83e45a913f9155febf07ec47769b47b8d5d6b2a40", 16) - g2To172y, _ := new(big.Int).SetString("14c699aa9adfe467f3977c6a1bdcc34029160b789d11d5e71980d044fc23666678cc2cb79738b6baa607ee733b3c8da", 16) - g2To173x, _ := new(big.Int).SetString("57e20231567347a7749584f82ad2ffc059698f0c4b702b9324414bcf5aa6f46a4462429172ae83f72512d1d8fb9f69", 16) - g2To173y, _ := new(big.Int).SetString("14581ba8e6fdb0222ddd92a5e87bf666ab7ca5cb86ca699bd16cc5daa67d6ac01afb81f266f06f4ea1f38b0aab90c61", 16) - g2To174x, _ := new(big.Int).SetString("143afae29780766b112a5952f024ae3145eab24719ec21babc615d8547634c5d4636389de5b5d11cce1143016efcfeb", 16) - g2To174y, _ := new(big.Int).SetString("de662f6be83569140af7ba194adc87b5bcb4aba0adcb4403884b64e7e89625d04f0028a80c2f2c9f8dc9dddf23b181", 16) - g2To175x, _ := new(big.Int).SetString("3bce098b21d2e1f1296592746475919ebf66ff784482579e32c9118ed276f978dffedf3ef07a77947b7d36f1ea93e3", 16) - g2To175y, _ := new(big.Int).SetString("9c76e0c83204761988945d5430ab3389502b8778103529176ef2ea285fee97c40946d4ef43f105f91dbf1222bffe0", 16) - g2To176x, _ := new(big.Int).SetString("e4bcab05cf3ecfa042fda48bda025cd28ae2e8b121c82cb8c35986605d6f2240eb17c9b9c27169095736d0198765f9", 16) - g2To176y, _ := new(big.Int).SetString("18555a4c275a57b24968df3885cec2c8feb1cf1ccbbc2a1dc5ff419b71a49abacc6a0167773590ab998bf5c2a5fc653", 16) - g2To177x, _ := new(big.Int).SetString("497522e3537513af8ab51673eafa636250d1ea15f90b2028bee227749c817db9d7094ff36ee24057d0b68b4b019523", 16) - g2To177y, _ := new(big.Int).SetString("c7735117d127fb022a8a3a6365faa220271467a986daeee92cfb913d584aec1eb93ab57e98c6108b225a83af8ab69f", 16) - g2To178x, _ := new(big.Int).SetString("1076cfe5560f5d378308b02b4b23efdf3f6f268b885340ffc6f3aaae8bf5b301aebc22939c012e0616bc519a34f318e", 16) - g2To178y, _ := new(big.Int).SetString("985107e1e9d76c2608d6784589ad58f744f7b8ccbf591e969758100af81f6c6cc751b35433af724e4aacaf48fdce39", 16) - g2To179x, _ := new(big.Int).SetString("e41cf5effab3711d615699c7a1aab2cf8aa8daf691b96b52449ceebc1b57cf29c74f782bd7500894e49ab1ce06e8a5", 16) - g2To179y, _ := new(big.Int).SetString("a8d52e34491822c0de9ed308007713d32ad8559f3ef8bff3d856f99ea1babc568f0b2a86d7c68a70f4dcad5a50631c", 16) - g2To180x, _ := new(big.Int).SetString("cc71f17e685ad819201a2a96b89fa2f0badb410fff58e2155407e08a0ce68f6e8fa26e083efd8233c6ee5517d095dd", 16) - g2To180y, _ := new(big.Int).SetString("a9381762747bb275934bcfd6c4023a3a2a140e498e16cc66ebc8460b218d590287f3eab54d885dbfac38ddaae6acdd", 16) - g2To181x, _ := new(big.Int).SetString("2d13c1f441c3a5f19d42c26699ab14fdf28a6b8dcd508e5f543a2ac444a5b0acf4228cb19f9e8e306f22dc3d6baa26", 16) - g2To181y, _ := new(big.Int).SetString("13b1d26048011fe25c9a47331ce9367876e2d9265eaa1d99135b942fa8312e7e57d7520bc7df9d6312e4c3835c2f174", 16) - g2To182x, _ := new(big.Int).SetString("19b39844d9593c8e4487ce996a33cb3dbb12c719750dbfaaaf0b43014dd8a48bca668bdb223741ec35c3f7579e8f930", 16) - g2To182y, _ := new(big.Int).SetString("d3e8168b65f3e54fcc0a390f176fb4e44845640a59deebfc5a27df65ff45b630d5b266a579d514794540000aae7d3b", 16) - g2To183x, _ := new(big.Int).SetString("b21d5c905a554590574da9b27c20b139ecc9ce777c62c35843f917a5f74dd0804e2035cb55262897d02f755ea7b68b", 16) - g2To183y, _ := new(big.Int).SetString("13364bb242ca69a09ab5433e0265a6d987539f6741bb66d393c6d1bb1e4a0378bb51c976783b25c5afc189de3a5e5ea", 16) - g2To184x, _ := new(big.Int).SetString("19e679044a9eca80829f98d71bf8ca98b1cdc60d0cd7cc8957e7865479ba79fa7608ecd608392f9293739f4d17aac3e", 16) - g2To184y, _ := new(big.Int).SetString("18c81a9bdd6d8e094e5192f7e4cfc90644260c334c489db57bf530185021e96ac4af6fd528337dd07e298db4a7de0b2", 16) - g2To185x, _ := new(big.Int).SetString("369dfd6ab7bf26a8d4e5d64dcfb3b63d455cf2ee4db02f7c7683b6bca035ed1100832f60313db7deaecb8251078873", 16) - g2To185y, _ := new(big.Int).SetString("44bafdb818f8499bb51328d51eb1632e8d14ad7152353f9a9b2d9f2fff57d3e994a923c843a4ffdfdadc46132e7d26", 16) - g2To186x, _ := new(big.Int).SetString("15ebc18f89a2b6fd6ed009fb65888d39a071e3fda69dd9bcea7578ea66689c08d0126947da592298137ddf6dfa6ec1f", 16) - g2To186y, _ := new(big.Int).SetString("127b260a21eb7668c14bc43e4235f7479af7043c32872b60e1038b37bfe1315aa7205fd1a8cf65f2836e6e8e374bf28", 16) - g2To187x, _ := new(big.Int).SetString("bcfc9e711ad2a3a8b6990a3df74642db48922f04dcb1a26bd88ce4c8ccb6d79914a5a29d33334b0636338fc2a8047d", 16) - g2To187y, _ := new(big.Int).SetString("9da171650b66c067d1c41602761278a215fd2987eab435b3d0882737189cedfc1972e9199f58a6d6c1c1d70bd393fe", 16) - g2To188x, _ := new(big.Int).SetString("d898ee857af4fafaf02b327345d90e824b964b954bd7366ad05b6a1c5d14acbbd011214b55440f87786de2a330c131", 16) - g2To188y, _ := new(big.Int).SetString("ceb2ff631bd5b2eebb78bc9bf5ed6ca1fa088baa3608bd202fc8ba88d88baeb6d2410fe89f2ac2cdc4fe615150cd0f", 16) - g2To189x, _ := new(big.Int).SetString("1047172b741e1bb646e4b98defcf554691d16d7de036d0cade3f72387a0ef2175206a55f5000afaf1fd5fdd143fad0a", 16) - g2To189y, _ := new(big.Int).SetString("f5b5d94ebe0e7fce2ccb9cf9c396f8a83367f4c80c45428222560d0c28f14153f1d302812cbb939c06e2e8f60f6dd2", 16) - g2To190x, _ := new(big.Int).SetString("abc14aec8a9cf6d7b1344f4a4e65164e1abcf369de4de55d20c91e966d4aeb11ed24cf663c60b7bd7a88c79cf5c623", 16) - g2To190y, _ := new(big.Int).SetString("7cc4b196c7dfef20b1ebc9e5b03385311bd591da7fbdd89c05ada304c99ae780eac02895fb6a5f01235208b71b4298", 16) - g2To191x, _ := new(big.Int).SetString("13f43125659111895ca3e60c4bfcdf74ed7c261581b2b077730a4ee2a50ae5fe948e4a597403b3368ddf58bfbdfa00a", 16) - g2To191y, _ := new(big.Int).SetString("d3bf81b2e73d05debda0abdd73ce206b8262a5ba42374cd350b6e7f67190d2a59214edc1df2aaa4f5a4a53f2a5dd37", 16) - g2To192x, _ := new(big.Int).SetString("12d30265ab77bb06db58babf408679b92e26fd367391b38a926b91bb6ec2ab6df0c3f4efb10f89a99474010a949b27e", 16) - g2To192y, _ := new(big.Int).SetString("18d1d446266830b4c625c3ccab5b5ef7c51bb10f15ba024ab9c7978996ab7620332b020e941e0f80d69d0a056af7937", 16) - g2To193x, _ := new(big.Int).SetString("6966169e2a61337377ccb7ecaeb7942adc5b170f0a1c1c5df11aa259b41587d9febafb4a901c8b005b5a0faa2baea", 16) - g2To193y, _ := new(big.Int).SetString("11ab8a505040f271f4fb7a90ff298e64dda579761ffc9ee299f01aed1ebecb034f541388d84f8bac4a7d2a72986864c", 16) - g2To194x, _ := new(big.Int).SetString("c55aeab8b28d83fd4804f4bdd1cdb1e5516015ce22af1e110808eb6796f62a48fe8eea251d514e887650dcadc39def", 16) - g2To194y, _ := new(big.Int).SetString("177c839def54a86f879deeb5f15c5dddb1c6adf3a3c1bd9e4e79b4d8b26bc43ede744075562d10b81a240138e8455e1", 16) - g2To195x, _ := new(big.Int).SetString("1105c20f194e40e47ddfc67d3c2847ed841f63e0e1af6546f73af72f260b11fe3fafe46b3a41686d110cb07be24ab33", 16) - g2To195y, _ := new(big.Int).SetString("714b782b7923dcbbb584eeb469ad872536aca104ce9bd473428e567af9b55a7ccf5a5fa9d56185b3ffe354b4298a01", 16) - g2To196x, _ := new(big.Int).SetString("1116c55421ef7370fd3656007023683a9b495478c870adfa074313df8187342031cdff474041f1651a73f4c9ff709d6", 16) - g2To196y, _ := new(big.Int).SetString("80791ddb2418bb4685fc9f4377b63b92f3c66d120b7c97d857f78886a501e1dd83f047a49f420b83b6957d2120b71", 16) - g2To197x, _ := new(big.Int).SetString("3df18d8a4dbc6781742de2628cc12170472db073be5804eb3606e0cd713f55536c35b20a060c48c0f51c2cb1f9af3d", 16) - g2To197y, _ := new(big.Int).SetString("3cd17e0a2f9bc57321467dae7f43b78b1c902c576558ff1fe389b5d5d570f13c0802e29b07e198c6b0ae18be8d39c2", 16) - g2To198x, _ := new(big.Int).SetString("3f21786ce8f4fc420a75fcbef2f60e48715f80da3429d88289d7d5d1366c76b3786d6541f281913d0847c6f4ce84a2", 16) - g2To198y, _ := new(big.Int).SetString("1419f8e19f28ae0d6bf54763dadc5861b16affa1c7e240f7ab7e6ec22b06edc07fc36912953af41850c2726bc8d79c1", 16) - g2To199x, _ := new(big.Int).SetString("118eacd4f99a7d65ea1a055bb139ddff1024284c1227afd27cebdf2a44ffd5272a998b390aa73b4f54f19898d460976", 16) - g2To199y, _ := new(big.Int).SetString("47e50aed98571fb91415d84c3417b6a0d17d990046112fae29005faa6d2ae98b1b9464b59829c0ae715a65d33525b2", 16) - g2To200x, _ := new(big.Int).SetString("cf4908fda94aa06c04d26e30491ac30ddce9a6a3266555b5686c1720120cdecc3ef91e7427f622727e79b1b86f8797", 16) - g2To200y, _ := new(big.Int).SetString("16e19b5fc4ebe0bb8abdb30aa933b8cef3c87c09a0f23ca356fe55314dddb83bafbaa7531641dc5cb8021f4ad5f6c4b", 16) - g2To201x, _ := new(big.Int).SetString("380a1af45213129ae237fc6da75d4982eb6636e2268c81379412961651ceb218a73290294dc28a44c38d6c9584a3bc", 16) - g2To201y, _ := new(big.Int).SetString("69fd537c980b67e523b0b3f3fde7d8538f96207be299b6752ffced4e8f11d7e0a325d8c86671cf00b91829c9bcd5e6", 16) - g2To202x, _ := new(big.Int).SetString("5fe086b1c4b10505db63f342fb415f6d6861d07ee468d3349e163092ab5e030033a7fdc2107a93747905a44cfaad95", 16) - g2To202y, _ := new(big.Int).SetString("41a6b3dd31fe367f16863e68f319627c8a3acf4bb80248f5abc4401afcfb333fe97ab35da581cf251d0991e9b57e49", 16) - g2To203x, _ := new(big.Int).SetString("136776a77fc774c7786b3ab805bd8497fd6c8e798865a250854863a5f05efa4c8c6c1cad56b74d5a8de2009b9de5847", 16) - g2To203y, _ := new(big.Int).SetString("1960e3ca3276ce29fbfd5e61985740c9e94baeaafa3c6ea8648d502e76c4771d91610806cf7db1845721425594fa105", 16) - g2To204x, _ := new(big.Int).SetString("51774de396e0456c71dd80a60f12d21cd8d394f444f8ec11cc1241172b823e5a2da0e4026f0463f6938507a28f61fd", 16) - g2To204y, _ := new(big.Int).SetString("70f63c6e5f10ca36d4f66cf255f49d38d272887072471f04e301922318eb176ee7fdbe5d37e730853dc70b2c97106d", 16) - g2To205x, _ := new(big.Int).SetString("114e44441bab56585d1f00e4698303b8ae52925ed22ff608f3f346d0c1796f00f954e240a5965aa50f6f684a2739c73", 16) - g2To205y, _ := new(big.Int).SetString("1add868b94031d9254694dc163765c071de69620dd7198b9e980407a82f2b5bad8c9ed3c151f965bb735754162776ad", 16) - g2To206x, _ := new(big.Int).SetString("94c916a63bafc36d0ff51f36dbf5abe60c974ccde1f2945e3f482a996e15063f9334ab874ae00d7d4baeeece68a76a", 16) - g2To206y, _ := new(big.Int).SetString("c5b8c12e8b085309c2218ab936a9f8486242ba4abe16605fcf53e2fa59b8b4f2f0d8fce0866a63ecc2b1d9559c887a", 16) - g2To207x, _ := new(big.Int).SetString("118440e9ea5d0ca6a4d593eadf149988b376ae79deba462c11b9c4146cbca71d93710184cddba8bf57e9bdf0f4fd5b3", 16) - g2To207y, _ := new(big.Int).SetString("9817389a50fe85127287e1c25d5c40a7c793e787f048bf02a69ff2492e898227d9d5d40ec3fd29f86d7cc912e4ad06", 16) - g2To208x, _ := new(big.Int).SetString("44e02fe124b5a7754ce07713a818b661a88e5b59609c2fb866fa26023d0499ea8ecf96ce2cfd661c67b2a7bbee76e8", 16) - g2To208y, _ := new(big.Int).SetString("d3ba51a10bbed75f98f791cb225080b3087e4668935e2d8200d2a42c0aa5ba28c1711c841a835882e2669c19e04fa7", 16) - g2To209x, _ := new(big.Int).SetString("ae715b1dd065c4e8b9df8d27c6f40868fdf5f5da8c17474258e2d7df84e69654d4fa23f574343c7746e4cedb04da5a", 16) - g2To209y, _ := new(big.Int).SetString("980127fbe1ac3176c4c3494a8f11b4d6f07b65aaa4c37a133007601111f8167cbd58cc4b755cfec8877b440618734a", 16) - g2To210x, _ := new(big.Int).SetString("d4e72f646af729fc96a5b6619ec898808a8bd12f9a0e2b60a54e844c04ae5a00dd215424a869037219d426f839d651", 16) - g2To210y, _ := new(big.Int).SetString("41ecfaf326ee4b88c5f81811ea8c338e943516ba7da547b0bafcd484de23e208b39dddf2ca0add4f420a9c2722bdbd", 16) - g2To211x, _ := new(big.Int).SetString("4bcbfa770bd4aeb8b160709c8a69fb22cdc4e58ca9a58763b99c53617358671e8c20d8ec33cb06a75d4da3a3982a1e", 16) - g2To211y, _ := new(big.Int).SetString("3d7b253a592e3fc11ca9d6b143348f88232abe363a699726bda6f9a61f4e84cd5bcf08f6f8278306de297060476df", 16) - g2To212x, _ := new(big.Int).SetString("f19dc610f4449da5420a5d5e6406bcb006b62faea414868d2e38eed978596cff8e86a4e47676101cb98259e082146b", 16) - g2To212y, _ := new(big.Int).SetString("830e4e2e50bfefce0bc558c9e74c9714a71a5a471ccbd3d9d7ac534c009f399e15f85c324a7d5dc2585d74946c6500", 16) - g2To213x, _ := new(big.Int).SetString("197885701bd9af118177ec0f6f791ef4251959a3f59b80a05e1653a1f633432c3a4018555ffd215db7f9d5084390b9f", 16) - g2To213y, _ := new(big.Int).SetString("608112aa435d04a0f05bd432e13b67ab7bda184ad23763a858a35aef57d59da082e1e842f75ee524f8de79ee794d8a", 16) - g2To214x, _ := new(big.Int).SetString("16bd8a55e3b1695699dea5763a5fe6418a55899f3c768a68ab1e04e676a7052446c609bc0e5506d7972397f6392910c", 16) - g2To214y, _ := new(big.Int).SetString("16feab32309d89d44a8b2868a130d3007b69b1ed83d601d1acdf9f6f8b2331ef9926fb47e0436802b064aae773d646d", 16) - g2To215x, _ := new(big.Int).SetString("192a288de4334ce746bf19aa8e26e736a51be264d605ebf93991272741aac00736aaa1db44f3e565c365a03304d4671", 16) - g2To215y, _ := new(big.Int).SetString("7f44babc07ca8bcf82dbc9ffc304e0e44a05005d9918850f89cf0e653073f8ce343cfa307e52156657ecafcb1d52ff", 16) - g2To216x, _ := new(big.Int).SetString("3bd781aa9a31d5ca87a7e692e86eec5b6229cc0199d804a1b8db429adea932c92788fbba31297cee74147a5e861395", 16) - g2To216y, _ := new(big.Int).SetString("1a3bf79a61de7f92887ed75e0fcba22522df68818ea86d86dfac86bf60ec06f77f058f06980b03fdff28d0fd57f2e0b", 16) - g2To217x, _ := new(big.Int).SetString("2402d983298af793f637561b68b08f470992fbda0ec4da86d7179ccc4b979a0f9164ceedc9c6a29a2cc54ee0ecf1bc", 16) - g2To217y, _ := new(big.Int).SetString("144e6b94177252db037f6a84f6d16d40758ada97caf5d7d9387a7928be61828c0459d7317a24bdb42caabc0966dc716", 16) - g2To218x, _ := new(big.Int).SetString("e0fcb99476c675900c955298c1df338e33e23b28a74ad9a27b4ffd47ea8bd67b9de3b5add072c8a1b072b9fb78066", 16) - g2To218y, _ := new(big.Int).SetString("6f388a7db5cbb124de08a246b079f628e61b1cd7c0e5edc65fb19cb21938071a56ccd33ca116f5a2397713c63048db", 16) - g2To219x, _ := new(big.Int).SetString("11498993939102f5740d8858f5ee70a087ae0d52b2cdb801e279e42ff150975019a92576cc14fd2b8e07efa76b2589b", 16) - g2To219y, _ := new(big.Int).SetString("9977f5d8f10e23098bdba68a286f25fb2b6db0aef7ee845934934f4268789a2c042f44a6c80f0162ed5b2bfe537d30", 16) - g2To220x, _ := new(big.Int).SetString("9ebce7cceb0314e1994f20d7a716ad5ef32c3cdd8171950dcef910261445412d9a5682dc2e0500370e2d6317c384d7", 16) - g2To220y, _ := new(big.Int).SetString("10d543e1a05b9c11d5a24ace56f05d04799b48c6f86a4df612fbea5ad2e2954ee8a041ecb5b765ac6a32392242903f0", 16) - g2To221x, _ := new(big.Int).SetString("82bbc0277954ba90241cc800aa18b05f2826378db66d59da11ec6a9fcda310415f8385f68f2eb25f2ed3abb21581c0", 16) - g2To221y, _ := new(big.Int).SetString("1258c7929372aef1be2ba403af16d1fe24d500c81499a17adae4fb94775cd7b593911ea2e04d7d4e7946d68ac301373", 16) - g2To222x, _ := new(big.Int).SetString("1130ab0736b48f526e01bc5fc4cf9164ac4704047e54f9d8e9f861dc9cae10a884b5b16423f344d86de58d1f0c8aa61", 16) - g2To222y, _ := new(big.Int).SetString("68b14390cb893f5e775837141eff37bf894c75899591a3e67779cd16d89567db5c69539bb486f57a24b6c4892b1b88", 16) - g2To223x, _ := new(big.Int).SetString("5e04b1e370b58aa76aa0071ab2e6586501eabf3d80c2b8967eab61f56dbc6a3943c1e9e6000729ffce3811f4478d2b", 16) - g2To223y, _ := new(big.Int).SetString("1374b8d7eb70c4cb81df2bb50e894791d5ab853520480e89c198c96ab7158993000b895e21b618d33f30e9f3dbd4930", 16) - g2To224x, _ := new(big.Int).SetString("174a97d44f91430e497ae21c793730e8b5441ee8708021e73637a9f8c30066e641794ffb913b92fbe64566879f9a194", 16) - g2To224y, _ := new(big.Int).SetString("151ce7878fa02ec8966f73c48125743a771018b3dc5743a2bd836b90ed38444df88aecff1dbbce14e0ee2888e1ef708", 16) - g2To225x, _ := new(big.Int).SetString("16a2d22751e0faeeef7844c4427269e26009b756ec7a4fbe5a727df769bdb9ef441142ce22daab727482ab2673435b7", 16) - g2To225y, _ := new(big.Int).SetString("1224d9344ee5398193bad09c691f4ea3067802c789714ebda5e62c2eef5c524b7ab9a73afbbcc3d3866b94b1e838f33", 16) - g2To226x, _ := new(big.Int).SetString("14de3ccef2af8ee23cf6b04f610838aa53cf823dc104d975f19db702bc56d5d25bea164369267dfe22d9feb60902e3f", 16) - g2To226y, _ := new(big.Int).SetString("58d7a014b6c3abb260b6569c61e74425a97fa90dc588966aff854c0fb682ce41d779079962b88a4425c29f06a6753c", 16) - g2To227x, _ := new(big.Int).SetString("6c19a89057fb87bfc179bf4062ab6459526bdc11146304f311f647ea5957e12244418386c0fe09da476630835add77", 16) - g2To227y, _ := new(big.Int).SetString("bbe679f18d53cd4df93bd02f6f5511050647d160c59514673f1e86e3891053b8445f45df4a3b373861503c71d58de9", 16) - g2To228x, _ := new(big.Int).SetString("ecf150e129cd512a141df58f95f8c38512fb2af1bd320a94842569f434fed7a0604cbf1b1528eb1118c11c32a692aa", 16) - g2To228y, _ := new(big.Int).SetString("122d71c7c5115b38a0f2aa28e8e21b649db953bbac9aeea82e7e14c02c8c1cf1cde06eb8914ceb29d2979533d0a8a1f", 16) - g2To229x, _ := new(big.Int).SetString("19a4e9478707019b033794bf784f3c37777efa971f51003a37b460479fcc05910dba5c852f534a299b9e2404288bc86", 16) - g2To229y, _ := new(big.Int).SetString("398ff16dcc00614b1e2257987ee2c339a53a29e67a2d6b4687089d36fc5d432e6c4d0bcf1609db45dc2f3f11fecc53", 16) - g2To230x, _ := new(big.Int).SetString("d4483fdce59dfd84042f5be7f8458962a8867c4ea38445f809abe00cf3286979a93ed8690630783455c17e06e37647", 16) - g2To230y, _ := new(big.Int).SetString("7bf259c13a02f5117d6e1f1b4a0899c1082c6ee6b71ca1511833e312c0a7c81732cec58d4fb8b5ca0c62a7c2e07807", 16) - g2To231x, _ := new(big.Int).SetString("7f0589fa75f0f5cc007a62fe6cc3e368adb2bb08de7eefc8821a031935ea2c98ffe212e6c15f031f2ed23aa58311", 16) - g2To231y, _ := new(big.Int).SetString("1612984f2bb0a5fe9f3c941a4cd2bb1946a3a4d1f605faa84161c6340cc1b1890cc6821fcb23f9111975839883d1792", 16) - g2To232x, _ := new(big.Int).SetString("f74be9f2e89f7fc9d63e1a380117e4ed633b936ae43735e6ff3f28056d1362725c791ebccd776fe43fd9436277c0", 16) - g2To232y, _ := new(big.Int).SetString("101552b0bc58c07276643717fea8a73853c5194ef7e4a39f72ae9d87f79402c42d18a67517760721113eb4efb6a6b72", 16) - g2To233x, _ := new(big.Int).SetString("15789f64a8d6d7d1ccd4501e25f29ef551f2a020b11948464b56943c8d893ad47241325be82cd684a12d8a94d178b50", 16) - g2To233y, _ := new(big.Int).SetString("16a632a4df6dea33665ac380117f717b7d38a0072d6a531e131f1fa3aa4db46b01339cc7b2c9f03f78acdd37982ddda", 16) - g2To234x, _ := new(big.Int).SetString("5eee70541f00b428410a9f0b6112ab6c14c01c3af8c6831709ba9baf84ce9dc1ba948251e603279474ebbd9dd432cb", 16) - g2To234y, _ := new(big.Int).SetString("1c026b8f77584b85ef151e4454cfe9ca90ab047b3e012ae5273a8c10a6c28584c14fa6855e21b6ff88dd3bd73a0125", 16) - g2To235x, _ := new(big.Int).SetString("98a5fb33dde33395886a093e83b6e681fa4ffc07ec561bd840281a6c464509203dcdf7ee209d109600907e6bf257dd", 16) - g2To235y, _ := new(big.Int).SetString("788c41665350ffaa411f7f87eb1841dc9c55a2a2d9eee4d53074d259ff8212be1412b24ade48b6659d73a2aeef2893", 16) - g2To236x, _ := new(big.Int).SetString("f11dccf426e9213ade8c9ee90b06f3bea1e6457601318092afdb2845873962a9ebdf44d6a52517e30e2fb59d47937d", 16) - g2To236y, _ := new(big.Int).SetString("11a2c73b55ae8b0418e23694e988a586a00e7d167972e66def5b18b80f5822e0386be601d0eb553a33e2dcea9d2f304", 16) - g2To237x, _ := new(big.Int).SetString("54733fda527c1d2c1967947da26074e803c5143b267a3661439bf3f773a42a754ef55d56dbb624d2daa933656b26ca", 16) - g2To237y, _ := new(big.Int).SetString("18f358aa4576692f77586da3ea26d5fa85516181e6838a7bf7b52b586c06d9f7074c5e90e7ba1ac4a925d368d8cb981", 16) - g2To238x, _ := new(big.Int).SetString("184c780c3114f29206d1533772298961a70b6fdaeccc642335a824909cdb6f906e957dce89627d1e7716d95a2cfb46d", 16) - g2To238y, _ := new(big.Int).SetString("12d98e699809d4e11aa2e0b33a6fbfef9e22336bdd90fffa323b7e3bb30ae239089b2be9ff8058ac6c15597788af01d", 16) - g2To239x, _ := new(big.Int).SetString("1585afaee8b5f5508cae51b92a6c44c8d49cb8dbe9673c33eb981efea193d06ccc524de0dfe21c4dc0981ae129d80d", 16) - g2To239y, _ := new(big.Int).SetString("13f2a75ebdb771622fc9ced0989babf38f67dfd65a083a692514dabe83b3a97eac4e42bdb47cf6d51b8f3d5c963565f", 16) - g2To240x, _ := new(big.Int).SetString("14355642d7750cbbba97db165768632badccfb6af700fff0805d22834e97eefcf84defb444cf0273b1a9944f7e5b91", 16) - g2To240y, _ := new(big.Int).SetString("1197f01614054d77e687096e7538f6a2545b860dac56f1891056c358e42ead9a2bb48b10afac6df3fce655328a5e818", 16) - g2To241x, _ := new(big.Int).SetString("13b73e44f2659f9e3107e77dfbdf6a1ef7f9bb9f50d1edef96f72a35233da9405700d898d93db5507d52dc52889823a", 16) - g2To241y, _ := new(big.Int).SetString("16b68db42349d35537fac003e9f2bb42031b338c12f4913997c4884ffd26990afd463d337dfbb5d29eeb5fe2385e77", 16) - g2To242x, _ := new(big.Int).SetString("89a89ab5b237b3cccd3fe1dcaa534fc6568ee9d460b3ca0df9c84f9ad0af74e11d99a258d42e2fdf90c87ffb008fda", 16) - g2To242y, _ := new(big.Int).SetString("116466cbf9bc5f5cf137f3b917fb95025546af24874a181f09a3798ffc6214dd8c60ee3dc473ba4693ca0c272dd993d", 16) - g2To243x, _ := new(big.Int).SetString("1955d0dba9ad4e82d07b90e40a406188df46abdc803974b4104fff90ad95f1ae7c278690cc349c3a35dd36e67eaedd5", 16) - g2To243y, _ := new(big.Int).SetString("17f6f0f43e95cce0f3091b701119eedb0631f018c3ee3adf30e011fadb07a460c18d08db250bae2d071fef1a92a1f79", 16) - g2To244x, _ := new(big.Int).SetString("1ac41b9b7179d3b109edaae37533c2eda16f2ef82ad3b6116001e33ca216786d72d5df4eaddc275a349be1f221ef018", 16) - g2To244y, _ := new(big.Int).SetString("17007d8c32333765265165962b19a98122d21d224d1529e10776c574997401b32af137363701401acd4f8b28337da6d", 16) - g2To245x, _ := new(big.Int).SetString("1173c60965d349c342b3423e4fdd4bd8e2d9321895e2e5131e4434094a918415e8ef88daa57f29e507345caec040621", 16) - g2To245y, _ := new(big.Int).SetString("175d01ed6f7e2a7cb9866762d30756dee408e5ebc1c34a2c84b795db33f09a89ef455ba08e99d8bb2a28b9e86616c4", 16) - g2To246x, _ := new(big.Int).SetString("5c1bc8f91e383e69293368e1b57038c922347f71ea365a4db593f71074875ef0e6d432ca81c4b80ee579965cf17c93", 16) - g2To246y, _ := new(big.Int).SetString("189e095fc94cb2e838ead34306a32b40924cccc78b4a0cf28af85fbe0b54538cf8a772b75095f356a1c0ef3296f5561", 16) - g2To247x, _ := new(big.Int).SetString("8a9efcf927af9dbe6e2d4c77d29df093ef459afced7a9f097f017091ff06e4bf4d6b640966c68c10b75f1e7149a85", 16) - g2To247y, _ := new(big.Int).SetString("70805ec8649c9a7c25d21736edb523b4790d3747f1a368d21293243c6dc11c5fe79daaf07c4d63fc9d187df46fd510", 16) - g2To248x, _ := new(big.Int).SetString("16e52b1a5b5ec2b3fe5af7e76b966000583cf9670843094480b65d13a592603e9cde594a02e2415372d36d238673d8d", 16) - g2To248y, _ := new(big.Int).SetString("d5022a2983f3d3fb721884c0af2829680a18dbbd005394c5065c498ae2c6826831da4f412db24ce93ab82ade2b9000", 16) - g2To249x, _ := new(big.Int).SetString("133fcd0d44b5e9b4101193f9d001faa4f8d888b85643e479c8e6e541a9270caaa8d54d5f0bb87a1f8ec5a25cf4be6cc", 16) - g2To249y, _ := new(big.Int).SetString("19c9d609e590e4b4eaf3f48c1a7c52c5a019da645e7411ea105ef0bc3ccf4682f0ff73522747157d7468f84c7cecebc", 16) - g2To250x, _ := new(big.Int).SetString("fee78dced3f99645d6043ff6106a2427a646ce40ef8bac3664c76edbb88b6e5106ee4cfaaf5858118ed3290b75621a", 16) - g2To250y, _ := new(big.Int).SetString("3e93b344b8faf9ac5549ed35296a660bac621823591228bb54e6d19b0c7985482f37e76d3d5e4744c568529023ba9b", 16) - g2To251x, _ := new(big.Int).SetString("1190d295e06f2de4269762adc2c605d3c767055ab628933f1a3a184b691ab73b7724beb9c126974b8f4553308c6c2bb", 16) - g2To251y, _ := new(big.Int).SetString("6895ecd12c1cfcc15a05cde2e775d7387754b5e3fc43b1961f370dc28fc9b6a5602389685b7251dd0f6ee1490e99ce", 16) - g2To252x, _ := new(big.Int).SetString("13a0c4f35b617ea8aa399aac8b1c977320c28204236dc32ada1b64e7a8c79165f34ba75baef06d41918e24984c8ddfc", 16) - g2To252y, _ := new(big.Int).SetString("8f6802c76d44e816b66d17f7be4e845edf2c12caae31d9223f8b9b40dcf782b222218ca0c725116b18986661f9068c", 16) +func GetBLS12377CurvePoints() CurvePoints { + g1x, _ := new(big.Int).SetString("8848defe740a67c8fc6225bf87ff5485951e2caa9d41bb188282c8bd37cb5cd5481512ffcd394eeab9b16eb21be9ef", 16) + g1y, _ := new(big.Int).SetString("1914a69c5102eff1f674f5d30afeec4bd7fb348ca3e52d96d182ad44fb82305c2fe3d3634a9591afd82de55559c8ea6", 16) + g13x, _ := new(big.Int).SetString("1252b781171f507db36291b433a1f911a46543890a20ca9712e11f66a5d216e63d817bd8d96cef715abc604dcf6ec2e", 16) + g13y, _ := new(big.Int).SetString("14a00fa77c727e8987cc438b51bbe012c823a19955ae692c54ce572a61f0ea1fe5cd981533df419fd1330d1f6e6d802", 16) + g15x, _ := new(big.Int).SetString("17052d4e3eb642d32ef4989af253cc2a30ad376ce8f0b23c92b987e95cc718d02072bb78d37c09fd76f7014eecf797", 16) + g15y, _ := new(big.Int).SetString("16c206be738bf4644faff10bb82b19f6f07779903a6ad2524809ce29f94683be32bbdd072ec0be66ae0ed0d8781f277", 16) + g17x, _ := new(big.Int).SetString("916932fceb94ad7b80fcf492aa5ee0e120410017cc6d17c8962ba2eb799260d022c3de5a103e6edbb5ee9135c7f0fa", 16) + g17y, _ := new(big.Int).SetString("18efb7c0b6e083030a858e3e8b4d1db5857a3f6c60f01691eb9783f6a1f1064069da2e220952121c771f276888d5137", 16) + g12To3x, _ := new(big.Int).SetString("18aff632c0048f5afb5c07fd197a44a127c829be3ff6170c6cebc1154bc72633b45de2ac855e0da30cebfa33672e7f3", 16) + g12To3y, _ := new(big.Int).SetString("efb82d5f13565755df1445db9ed4c4969f09bb31cc610f83eb1490be76ab3817808c52d98074f1a98ff896012a78ab", 16) + g12To4x, _ := new(big.Int).SetString("107db75ab97dcb352b7e3e0596950ec2793cb394f821b1a2e7d5f54d11da8215a998cc84736ddffed74f549052a9df4", 16) + g12To4y, _ := new(big.Int).SetString("7d8459036fefe53ffd95028a2be4f8588b07cd359b0955e1cbe986d4b1ee854e452d7c14f05c41b861266522e3e887", 16) + g12To5x, _ := new(big.Int).SetString("680fb4caec4a06f92a7f4f1e20624b4eaf74001df5ab3ca6f4b3fd9c2d49f257d3021400f5844e227d9763090d8cb", 16) + g12To5y, _ := new(big.Int).SetString("1a9a941bd20effaea30f547d27e433ddf0e29bad201877d54995e73586e8847aaadc0b521762db07fc7906d3c39ee80", 16) + g12To6x, _ := new(big.Int).SetString("56827fbf50c974fda74996e7415fb0fa6c653d0279ae5e0726c124b222837c6ff5fb12682ba380984981f2442100cd", 16) + g12To6y, _ := new(big.Int).SetString("962aa4e39307e00d9934914a1ae85e57513ac9f7b7dbd11003d67d62f288d92f5bd2aedad3a9686ce807efe6f8fba4", 16) + g12To7x, _ := new(big.Int).SetString("880497aa4f51a84c24fb4d92ef46819156918734858556807059b6f6d3e62d2e3f589f33d7f8c5f6af63a0f072629a", 16) + g12To7y, _ := new(big.Int).SetString("111c794e9d2397062f763482bec5584abb31f5b73090174dc22c8dce191c94362ed75492067209bd63044d40f694ad1", 16) + g12To8x, _ := new(big.Int).SetString("e5ddb0da4a5b32e245f78e95760c03227b976ed310ef3922624473d3ca4ea85429797e145692f87d5cb39b4e9a807c", 16) + g12To8y, _ := new(big.Int).SetString("ee67ff3335bffe5cba6953e23e9a1953ee9c1f37371c01a0ceca424f98566df7c353e1eead76435e7854af3fe89c3e", 16) + g12To9x, _ := new(big.Int).SetString("13c910dadc716133218967c098a8f2889817ea5688f68c1878cf6b97e903f728b65dd7b7a6ad65226ee2089a3317b4a", 16) + g12To9y, _ := new(big.Int).SetString("13324bef362a2a30fef824ea32e78c5c1e628842afd2fe67baae1e80fe7eabdbe97ef70a9606fe8db5359a607750b8c", 16) + g12To10x, _ := new(big.Int).SetString("134fb9a0098e3581953df24b0cb4a16306a4eea26bdb08b92b5fe28c35c178873e7a3b813e3579b417f780a7585a027", 16) + g12To10y, _ := new(big.Int).SetString("11e922e78cc7bbf317f9e3013d3c4d35a134d8ff2b94cd33450331a67f3585dd6c548b494f4eaa21f325e45d5d01912", 16) + g12To11x, _ := new(big.Int).SetString("14fe16f6fbc301389a2ce1cf4380af5eace02eb0be172c174e0e6e59f22259b861eefe33fcd031bf94d23d3622b19dc", 16) + g12To11y, _ := new(big.Int).SetString("aeb36e0a5f8b155febe62a45c6d318fae2a035999d0c309e163721431c4e2d2185db90329a3a644cbe7c07d5042c05", 16) + g12To12x, _ := new(big.Int).SetString("ab8d63c61ea2a57f78951d45eca6a177a7dd1c7b753587d1d7348c6f158fea835c5a2c9b4b39be911a900d9d71753e", 16) + g12To12y, _ := new(big.Int).SetString("10b05d822a9665013d90ad837b75171e8b491636943329c997822f58577adac847d95b7f188b11ca33d14fd5d3acec8", 16) + g12To13x, _ := new(big.Int).SetString("add361f77572a949e411d6435d8121daecb31402c58a7cc6ebb737c26a11d6bfb60ef1eb0e1226b8e4ff4d7a1f19a1", 16) + g12To13y, _ := new(big.Int).SetString("ad05daef21794dd0d33692eb4743bfe28c6c85090622926a547e5122ef41a1dddad4cba10b798f89579cb2348e9d57", 16) + g12To14x, _ := new(big.Int).SetString("63929f07e03764ea4b3b4baa6e504c2bc7588a2c7f3e2b1029e94caf03e5f20d41bb644edcdb8f6869527047984d6b", 16) + g12To14y, _ := new(big.Int).SetString("6a51e86ce05f6f4bf7761db5143323f36250a620a3c5132ec24fe0a0ccce5375eea48bf39a27141acd8a6339587186", 16) + g12To15x, _ := new(big.Int).SetString("9d656058092638a500e7febd7c820798ec2e7139b02a10083ab6593d915a4ec4293d023ba59192b49845c0512a6686", 16) + g12To15y, _ := new(big.Int).SetString("191cac9f967d935ab360a6f6e58381956a7f9497e2c67175c7710ccf4c2db22bfbc390090fdb568f0e182b30df1a280", 16) + g12To16x, _ := new(big.Int).SetString("1371622e52c4790930c0dc81051c5d922318a05a5dddf4035838f88368cae1178db6ddafef464a9bd035fbe22311be9", 16) + g12To16y, _ := new(big.Int).SetString("5a6cf187acfb8a91dd2130b0d8f4f617b1bb0f9beb1a29ea908cb24254e4e2a3e8c14c3c5cc20bc714a1bcdfed1535", 16) + g12To17x, _ := new(big.Int).SetString("127f9cd4d32d5b68839ad50475180b572cf5a64a298bef23b2ed972dbe8f65e33056e5476e8716252635b980cecd7c5", 16) + g12To17y, _ := new(big.Int).SetString("1738a6dd32253efa3621c81b81eb1d109a35a1d182a04be293b75bbdeabf7f3090d32b0bae41fb0bb317f5c7b669f8b", 16) + g12To18x, _ := new(big.Int).SetString("7a60c7c738fb264482fe46a69c514cc4cbbc83370890dc1cbf39567e8b34bf5c388313c82804d1c7261dc99b2801ab", 16) + g12To18y, _ := new(big.Int).SetString("d0ab238b768b54b095db2aca7acfa16ae26264066fe7be9547b76c855188a07d287d0031fdc40d57dab98c7d073bca", 16) + g12To19x, _ := new(big.Int).SetString("6042f781b85a81d10048c15da22c5069b880f6d1f6f5c54bd327760bc1b4daa247aca6c96bee7d20c8578220981ef", 16) + g12To19y, _ := new(big.Int).SetString("c20df594f36b4a18be4c2e759c55a1c08d08fdd8e7f0d228e282727518eba66383cd667811c0d5e4baf03455e46f99", 16) + g12To20x, _ := new(big.Int).SetString("141937e53eb28e9328d805dec48045a9f258c632aa4e4f360fea78d16850921b636fc52df323fcae8051385364cff58", 16) + g12To20y, _ := new(big.Int).SetString("f82e14368390d59c28fcfb130566a936b446e783877578d7e27e15c14614be38a5927329189abda212bd4576ae6421", 16) + g12To21x, _ := new(big.Int).SetString("94e187a31d02354de6787d1abffc8b9fdb62f8dd91a01fe0af6265736966d8ec181bd65863c2b0c3020c1c7c26a9ee", 16) + g12To21y, _ := new(big.Int).SetString("77cb65bade2f40dd98b6ee8d84aff95295647f5f2744e9691ee8013537f714df467010007b8479a018dce66ecf011", 16) + g12To22x, _ := new(big.Int).SetString("f574cd8336eb82714f7cfe446d239ee89bafbe52b6cb5e7dc839fba89cfb78187f1aacbf92dc4d772519e500d3faae", 16) + g12To22y, _ := new(big.Int).SetString("4e3073dfae73051d165648b65a1910c82d22e2344db0a906e98485883d11f12e061c84e99905fa09c3a73c1a0dff86", 16) + g12To23x, _ := new(big.Int).SetString("879b817a80faf83a690e7d4cc5c7f802bae36cc397bb4fc5210a48b23227821ffe5b5fd90f34b37aee8bea5b143a1e", 16) + g12To23y, _ := new(big.Int).SetString("1387d2b720763e114e58702c269ff61007ab33c1e6e7d5834f010b970fb70ed7bc469b2129e613ac2fd2d3a6a6e34d1", 16) + g12To24x, _ := new(big.Int).SetString("f1e52f2ceb352869eac2a752dd6bc47b84724b3f4e74df4b72db06d9000456571cd58b4a1332f0c99f40eb4893e5c9", 16) + g12To24y, _ := new(big.Int).SetString("60e7d9eb062783ba26ec00ed46179386b4225a129fd044f84f9d7984147879c80f6b8d70eb6d55e160d7bc2a5c1684", 16) + g12To25x, _ := new(big.Int).SetString("133f8d1a44d868b95891a82ab4cd2343ce38e370e48a256f232b0077b411a12922bb919c599e6c5a1f9a81395d7d054", 16) + g12To25y, _ := new(big.Int).SetString("1414246490ffe596f7c8db806833128a661e98dc52b62a694caca1df3644c135bd8946d933275f2642f81e03f645daf", 16) + g12To26x, _ := new(big.Int).SetString("12982253bcdcfc660df538b5d004eb6bf283dbaf7788eec8d958bf77f10067e1f62ccc3194a65b0120fe15e92695667", 16) + g12To26y, _ := new(big.Int).SetString("97ec4a1c3de3030096011e1cce00814d216b19659fe3cb5eac04df4a12cf5e1f36ee47cd8acc02e51d031a65a17114", 16) + g12To27x, _ := new(big.Int).SetString("bafb585867ed534280a3a898ab8e7b8d6d0b393add86ba307b150dfaee25eea932e3a744d01b9d18950cc3f5670e4b", 16) + g12To27y, _ := new(big.Int).SetString("ba377e08bcc57ed719d82ffde026ea1c0fa3f3ec44e5e587507531731eb815ca6712e9eb92dfa63864b570e10e735", 16) + g12To28x, _ := new(big.Int).SetString("43ddf8732e7a29888831d1923985991bf6a9dc2fbe7916b12c8d676fafb96025023eeba8e208ff582fafefbd2af2bc", 16) + g12To28y, _ := new(big.Int).SetString("156dc34ce172d5dcdde35e9f77e0f23a3410f164b4ca2fdded4ffef71cd6c8be6605bbb2eb66522c15c7db50be316c4", 16) + g12To29x, _ := new(big.Int).SetString("13d7c2e8c14d861444f01eb7137520d1fc91ffd61c1c798710af6be926acc53921523d48708f41edb321ec779a2a92e", 16) + g12To29y, _ := new(big.Int).SetString("1108bb151007ff0b724046c4d5a641fbfe6e6a3bd71d3e1284cacc8e416a5fdedb4ed2693aded3d457d8ac72906070a", 16) + g12To30x, _ := new(big.Int).SetString("d2716f627351a4863060ab6777b148610d94e1b48b1607350f0098cc1289939097e4c3968506d152627350593d11a5", 16) + g12To30y, _ := new(big.Int).SetString("e64f79eb0f4d2fe93594259c1bc28f418a7ebd0a60769042315cac1fd6a1131e69ac868568526c3107c9176bab0c05", 16) + g12To31x, _ := new(big.Int).SetString("16c405bdc35a13c07c1157145face8ee9d13e41bb9e243d9a02c1900f26c7c062570cf56e1e992aab2b3bfbb61d387e", 16) + g12To31y, _ := new(big.Int).SetString("9c4f95f7c2c3fe1a4ac36d90ef98612c0691f3ed2ca212e9e1d38345606c2416652f5d8531bffbfbe1437f133b4e12", 16) + g12To32x, _ := new(big.Int).SetString("969e8eb9ce543735eb543a770a40903c3755d2e28c6c8ea9318440f2ea087f458f4b6f071aac44906b2a887d1a69a4", 16) + g12To32y, _ := new(big.Int).SetString("19f9bc3859f6781918a79e836d745c8787ba8b11c355e49e66b64e54428817e9fbbba06333e26d6b5dbd5fa6d7ea2f2", 16) + g12To33x, _ := new(big.Int).SetString("f14b7e7af6fa1d295f7b6ac8b1badf1fa3d65de31e79e94e69f02f21589642505a00ae1868525566cecce45fd62e44", 16) + g12To33y, _ := new(big.Int).SetString("1a115f0aa272d645be22ee308865c893e575c01aa55ace3410fd3e751a4e610655884c0a97427f37c9dcd90338b1626", 16) + g12To34x, _ := new(big.Int).SetString("148e97cb2504eb135a392a36e995694e281e727919ac5736e3f5dc45bd857e1a2b1fd48984147f762ff5a08e9eff340", 16) + g12To34y, _ := new(big.Int).SetString("18818155deaebb73bb615991f4aa7eb7750b2186f12d0aca0f56ecc22e7fb1cc4086d7fbf5da6cb8d12dfea5047975a", 16) + g12To35x, _ := new(big.Int).SetString("1826fdb3058eed244014b2cc2e84a61cfd4f4ec0e502e81ad5279246a8df015171bb35d70b4d21f0778b2bd46bba947", 16) + g12To35y, _ := new(big.Int).SetString("1511d311e43642cfa8ddc23dada8d387c5ebedbf1f96e22fea67c841550227148533e983b310f8287e50ef5462aef4d", 16) + g12To36x, _ := new(big.Int).SetString("1afe7f02e75acba6bb817bf762fddb0c50ed73ee7ad2abd3eb648a624dbb3649a70f8a0bed77b364dc64d5670e12c9", 16) + g12To36y, _ := new(big.Int).SetString("1141907296b72c2969a79f29523d5378b7c2323e87b93a667ccc0ece9f62a3bf7448dd8b2222a077de60f5245b0ab26", 16) + g12To37x, _ := new(big.Int).SetString("eaab1bcb93f8e64dd8dd822119af39e6db14b06a0dfda84a8948038412ce5f5e2e3d89492eec2242e2730c81e8651f", 16) + g12To37y, _ := new(big.Int).SetString("17f4f5be515e6bf8037faec8f667ee63a786a59688ea502ef4da6131ce63aaf4355b55e7dfa52f16c374105fb8bf924", 16) + g12To38x, _ := new(big.Int).SetString("1a5b9caa4a74b679c4186aadfcc8d05408728e9caf463724e9a9e8468d13f4e2895f0d0eb386a749009b7d6e5b2e75f", 16) + g12To38y, _ := new(big.Int).SetString("47e7ef7de6058e4ab1b2655164ae9df1cb3865dd5049f604b68cf77ea65a079ada29e524ed864792f7bf22283634a", 16) + g12To39x, _ := new(big.Int).SetString("14fcd5c9fda9b70d081e0b955145e5f5f7a15b4ca4f22e284a8c13bd7add0c67eec7bbd901e33991d94a8838638a9e7", 16) + g12To39y, _ := new(big.Int).SetString("ddfdb26ac57951cebfe2394dd4dd4d27c6efec24b70b1208b2dc5ca1f867974f3e8eec4050eb21af8497860af54d", 16) + g12To40x, _ := new(big.Int).SetString("252bee9b6ef8f22112ed489d3f56f08cc662d26783e4dfb44c65e5effe63e35e7df58894ff7c3e861dae155d0a021f", 16) + g12To40y, _ := new(big.Int).SetString("2bb53e9d3d1b2d87b5d1e237d39c3920dd4fbf9c34ca9b526b82472681c4c316e93a705dc28f2b6a262f21bf4138ce", 16) + g12To41x, _ := new(big.Int).SetString("174acac12c03f292f9c8c9ef1be3a1127fd64726cb9a3da1c37d18a0474830c5bdd294671a31e09670a0a9a357f640f", 16) + g12To41y, _ := new(big.Int).SetString("15cafb6ce83da980dbbbe486269ce721e9ae2d32b33773705904a74ab223df23e26b7655ff55d0c1ace86a72b4f6cfc", 16) + g12To42x, _ := new(big.Int).SetString("aa5ae22e7da20eb760d8be899a537d78c7f76aef985f6afa881020e7169a6960284c42bb5bf3301029b7ea78ddbab2", 16) + g12To42y, _ := new(big.Int).SetString("3cb9cf41a120b481b419ceda853a508337f74a91500f881629c0cb16c9be10b352929006ae300b93263ba01b378517", 16) + g12To43x, _ := new(big.Int).SetString("182b1745e5f859974d7ecbcec4da576a01cb5883ba5bae584709bd2e45d8eef002e4b093d8324372143460b4d0e4d5", 16) + g12To43y, _ := new(big.Int).SetString("187934573dca1cabc7a250d3e53091e9269009e3edfd0dc0ca2bc4843c1db9c0d7582c55dcc9a113728a37b4c7957b6", 16) + g12To44x, _ := new(big.Int).SetString("9008e86f9a7abb2b70044f3ea1565f3fe7df01bf46778f3a216a3605292382614dd4e807501c514760495f1fbad362", 16) + g12To44y, _ := new(big.Int).SetString("fe0c7b627908402489f139e577d86c527f9022a81cf6d4b20839b2886aeb4ade6cda54ddedab603a331acda5dc9997", 16) + g12To45x, _ := new(big.Int).SetString("db1db669a0f65547c0ef181afddcd6af4ebaae9a0b0977ac99aca37286bd94d9d14ee0a67de9f64d647ed58620aa46", 16) + g12To45y, _ := new(big.Int).SetString("1604ae03716ae90daa4711695fd86138eaaa4d03d3bf85217586783c77acad34497b1e89bab3c26036cc780b95cf98e", 16) + g12To46x, _ := new(big.Int).SetString("a961a93d8d69857b45972c45e7da4cc98fa11a28ef93b391bce2b4d7bb7472cf8dad04b0833443717085fbb14b8a0c", 16) + g12To46y, _ := new(big.Int).SetString("1222d52c8fb984fb00c1ebae3b66f52144b030bb2c28a304cbaa8a5335cd797cdb519cbcb6df298ff7ef426c80d53d6", 16) + g12To47x, _ := new(big.Int).SetString("605fbf7d4a4865e18a349f6af474d04c53ccd15aef07dc5c63d0aeaa9e35c732d5c25dce539d1018a8eb5ba1a1e703", 16) + g12To47y, _ := new(big.Int).SetString("1673edb028fae78421ab69bbf1d4c2116d0977a486f911a30354a6c6c74341c0a081dc604fdd130f1dbea16158a14c0", 16) + g12To48x, _ := new(big.Int).SetString("16b32d15667fbf3b37d2fd42b9648b8d12c1e8380df504dd6d1bb74387e615190aa158e31557e26710bddd3f62c448", 16) + g12To48y, _ := new(big.Int).SetString("1a96b7fb2441a65a1507e7b63bed23aa162ed2cc002553292d5b9009b1ccccebb7c597b12e1303afe406cad47d14b76", 16) + g12To49x, _ := new(big.Int).SetString("1ac0e778e13331dc87c9ec5c9eb608894f5ccb3448b6e537ef0481cd6534873c65c3b90265eeb87aefe7e0b6719df47", 16) + g12To49y, _ := new(big.Int).SetString("1374cc9941ddc21bf5d7fe0d3f6863d55084da5d3270756b2239d03dc0fe22ea67127f7eb04900e676d687f1479c4f", 16) + g12To50x, _ := new(big.Int).SetString("f2a9a16712080ab0597457b86c31c890fa22f1c512a9dda284f4d5b307742092ed7cf6e17e09a02e405bcb285aba7d", 16) + g12To50y, _ := new(big.Int).SetString("e6e13736ec424657d9f75e2e4817786a58c432f021b61c8a448af8b8f4d861dc0fe23cfde02b655fe8394d27b40ec9", 16) + g12To51x, _ := new(big.Int).SetString("2677277410ccf8b96bdd183733368cae50e14b757616979ee0975aa9e4201fdd12b86256c9f9a143653e1cc620a85", 16) + g12To51y, _ := new(big.Int).SetString("cd1b38e1e3b2e1067822422ba488a83c851a4f6d29680947fcac986ef07fa3148817a3840894b82daa4da2e274e94a", 16) + g12To52x, _ := new(big.Int).SetString("281b180d9e4aae07f4d6c11e679744d92592c26a6fb90692fe12f10eb16b58916ca87e74c9c0bd03887de8e2e45d0f", 16) + g12To52y, _ := new(big.Int).SetString("11101677eb41c6ca2c60d14456cfc148b4758a7dc86bb3f596d0afbf9677e403d9e8cbb9ad3afb08499e58ae295e9df", 16) + g12To53x, _ := new(big.Int).SetString("f1cc005ed80694095b1a61ba7e9700676450f5693e403aa9bba34b10be09111151dd9f4448d6bb287aabe37365d1c0", 16) + g12To53y, _ := new(big.Int).SetString("1a3e52c9f74db8b43d80c20e054c3a4849a441bebc44d444f4e7460036c46a1743320d75af77e11bb43ff521663aa29", 16) + g12To54x, _ := new(big.Int).SetString("7617573decd671474599623dd69aa96fe82794763eb49d2443f182428c6227145b7b6389cff20f9f46832fd2dbfcae", 16) + g12To54y, _ := new(big.Int).SetString("1a92a1f480f7d985d4e1abe80af96adf0e475571b80e99456d75b4218ee0c1e363afdd161789756f618f78cba51dd03", 16) + g12To55x, _ := new(big.Int).SetString("adff1ee838fd0e69694d32df4364308fec2313cd57c641367615c74f069f343a0c4888235308f22901084d9bcea913", 16) + g12To55y, _ := new(big.Int).SetString("9301a7eee38fe353161f286347647d566f8949fea78942d854a9b5c1639daeb83242ef6424caaba2095532f66b2e5b", 16) + g12To56x, _ := new(big.Int).SetString("2fd8f21f20fa1e949001314366e933d619b6e421c67c0bee21da9ef0d0318cec8fef099803b8e5629accd6d6b78e1c", 16) + g12To56y, _ := new(big.Int).SetString("ced044196c59388c333e8a0b17f9b9ee3c38ebee8c9c22b5be43c40737c6c9de7984b14c8f39127bc1c073ee60e25d", 16) + g12To57x, _ := new(big.Int).SetString("12d8246a5064c33a3b6e9be28e650715f2c62b696c90acc014ef9a2700bc1c7012f777b6af6d59949b3e0d87c1e88fe", 16) + g12To57y, _ := new(big.Int).SetString("19dbac773f76ba1a8c485090b6b10f9bc3110fe48e380da71a6b7f0336c4c818a3803126caadd7d3effecccf667097c", 16) + g12To58x, _ := new(big.Int).SetString("381bab5aa65d2b159bb82883559754e5fe26003013389761496d63eea249701c1b1eb742a28f529d6fea8c1b0aa726", 16) + g12To58y, _ := new(big.Int).SetString("7a43f15f319df3d07beadbe688619ac1ca80c76e472ea0d76555d200cc8f2c4e0b9a77065dbd41542d3dc7f0099622", 16) + g12To59x, _ := new(big.Int).SetString("eb3ba48bcae37c9ca7d0c66d42cd4f7a66640f14da2f439b7b1c27a05af916e818ba28eab92bf632f458eb02b962fb", 16) + g12To59y, _ := new(big.Int).SetString("fe6a0dddf3767c9f743eb544204739ddc4f9171c85cedf5f45f94d2fc2124df60c37ea0757ee4fdc98d1289f615b79", 16) + g12To60x, _ := new(big.Int).SetString("f64fccc7b7e1170569fa4ea7de6a25952252fdf82c1de13a3884a3384780d310d2ab52f42a15b46ef642f368b46f5d", 16) + g12To60y, _ := new(big.Int).SetString("a871d03f47a1889ce201513c353519e0cae34edea28f150f76b682c9b361feded8357d3bfdf5fff761ad18350fecad", 16) + g12To61x, _ := new(big.Int).SetString("138b8b61f53ba70e7b76545b01cf7ad7741eccb5ec524efd9d9a40d098c26c5fe99aff1565f5e66c331825dcd2c6f89", 16) + g12To61y, _ := new(big.Int).SetString("11360c12c63ce8faf10c63922afafb010bc325df0ae89fa87b8219dcac998e1add68d301475d12a483c85b48ae67068", 16) + g12To62x, _ := new(big.Int).SetString("18ec134222d187af5a8ede9ce9d4ab16c0a8e6c2113c92d6410e592b84c8df883cc6c05ae301e1f2e3c025eacc52b7a", 16) + g12To62y, _ := new(big.Int).SetString("1294ae9fe885df3c37931412484804feee91610b48fdd111baf15b5196ae8f5b7b16169ddac187c0447eb800127aa12", 16) + g12To63x, _ := new(big.Int).SetString("65813a9ec5492e7d799bafaf677f69d4630e24e47fe86ec0223181acc6ce0100e2de4a09db66616a01b48f7ab8b357", 16) + g12To63y, _ := new(big.Int).SetString("104147600c7118a89a55b524b254c8e14b17487b056f8a25cf793a7e6e4b44e137105a694d5421609fc5fa1d84edfbc", 16) + g12To64x, _ := new(big.Int).SetString("16ca0fa8a6de67c61d26f4263fe963c97726c7cd420b971b60fa3d8f19eeac52a059967f721c3f2f5cfd291eff79f95", 16) + g12To64y, _ := new(big.Int).SetString("1024b7a78a4be6db33eed9b9b0d6281408c344a3b7d7e50abb37b2766d3b6ec53321a398bc4abfb39589d73763fe4ad", 16) + g12To65x, _ := new(big.Int).SetString("ef930907a7c98f8ff74b03a671cf3e9f1ede0cc83fb570ef632f8c1808e03c623eebd12aeb80cab653ef808bfdaadf", 16) + g12To65y, _ := new(big.Int).SetString("163eaed12715d8b4e6669ed4d436ebf5a6e88d194081460ac58c43226c75b07e4d2d46f2afd5d092c5061ed5ada80fb", 16) + g12To66x, _ := new(big.Int).SetString("e55f91871935265fc666add9109b85a295b92dd1275e210e6752b88103551bb4a5054a820a8a7bea707b8152642d0f", 16) + g12To66y, _ := new(big.Int).SetString("3217a82630c2b2dcec5561f1af239b10612bd41f78cd69b109b90107d31c7bf25b7d822c629864c2b9ae95ddd9c6d4", 16) + g12To67x, _ := new(big.Int).SetString("32b0d40116e34b3c7001c348d371556b91b72af41555188ea23d442cf1748e80343e73af832f8ddd660b478aef3a82", 16) + g12To67y, _ := new(big.Int).SetString("190793652b804b0744c796f9c28b4ca77ae6c2c896c0b6420ca4802b270d322120313e4db6baddb5526b91479a69ef2", 16) + g12To68x, _ := new(big.Int).SetString("14db8a6116888ad28268bea38946ba5ddf9fdfec15250a3618f013233b12b2599934f639caa52e14ce78e65e4aca34c", 16) + g12To68y, _ := new(big.Int).SetString("11a146093cd40fdaa65c6ff93b3197cad47192f0645b8a5982a8abd9a15cae80167daf818ee820b02c31e42c10e9a98", 16) + g12To69x, _ := new(big.Int).SetString("721597f56b47a9b81055cbb92f68bd0f856d3314097b5008e255402093cecef95e10f34c66e9cf2c4636a5955f0401", 16) + g12To69y, _ := new(big.Int).SetString("9df9b789e238433aedccdb8996b9013095a5c72debc3d4161dc5517e3139352016137ebe5f1b88c7bccb464ae5932c", 16) + g12To70x, _ := new(big.Int).SetString("542bac3be82ab5260e405a2e37ce13ea57ec69523d412e640d6d44538c32b963d3536abb12d0796508013060181ab1", 16) + g12To70y, _ := new(big.Int).SetString("178910c28886167aaf6a3d2057951e5a046c2a2c90a621eda94c097b1b4b126f1dfe67f5efd496b244b9ebe02aff90a", 16) + g12To71x, _ := new(big.Int).SetString("c86c8ddd50b04e5bb33b5af20301eba97254ffb0f7f2190c2e4dc61fbda6560a4c6508813a74b2268b40af89b15a6", 16) + g12To71y, _ := new(big.Int).SetString("118d6c0fccd01732e48bb29539a0eaa8e7319d29a12cb9b87d76f4cfb0bf3a0a60250e8a3366bdeaafeda261ca834da", 16) + g12To72x, _ := new(big.Int).SetString("10b8803ef93d4428058963d394f1599bfd06ac2e8424ca8e33522f640bfb1f422263f9b3899cd6e857b78dc72d84835", 16) + g12To72y, _ := new(big.Int).SetString("16312e5482b4a4a69868094147c12514d3cd1e35a8e8e8a8fb67a6fbda08280b86352ba638314b0b731325d21928184", 16) + g12To73x, _ := new(big.Int).SetString("c1aa68b66a71e0925208c387cd45504c67c4c75e941d1c575385cb8595c24a24df762e9ff871f491254d8eca147de2", 16) + g12To73y, _ := new(big.Int).SetString("1a1ef925e585988f896c197af7a6b460f379b6eb5afa0b656702c3825b8ddbbc5384aaee6b61a1fea889c908f1b876e", 16) + g12To74x, _ := new(big.Int).SetString("1988799b72da095b8cd09fa266565ea14ac2bbdc8ce0d40c5cfc539d15d09f43bc6b540c598e8e2cd2e480df7f37979", 16) + g12To74y, _ := new(big.Int).SetString("d6f09872112bb080205ba42682dbb7127929850d7040458fb69ada42aa9c493f109a8eed018fb7bf731bb94870c666", 16) + g12To75x, _ := new(big.Int).SetString("985b8f67cd5043f0b04927caced7101f2e2416e1a3e54d9ef503b9f63258b8266e96280fed0ec57a020c9f871fa7e6", 16) + g12To75y, _ := new(big.Int).SetString("10dbd43d1277b59abcd4d63f4faa2abb22cd0630d44ae038b20596dcd5d9be2766621345db48f46d2602784a8874b33", 16) + g12To76x, _ := new(big.Int).SetString("128d9b00c2387f8b958a5e69235d7bc3c6566ffdaf6bf6baf9bf407501a905307b3db4fc93444ce9efefd717e6e704c", 16) + g12To76y, _ := new(big.Int).SetString("7e6df79c1ad8b8c57d71f284a1e9356a67c2211461c84eb277873500ad5f5600416c8ea67a0cb95b6395ede29080fb", 16) + g12To77x, _ := new(big.Int).SetString("19a8c6bec19d125a97a4636e38a9c71c482d1fd2c063bd4ab791fb84b508b2511c0c57832b0631d259b51524b3ac61c", 16) + g12To77y, _ := new(big.Int).SetString("beb651001b47818276d32281cebcacfb23ad81f9af4982bd94e936ef31c0a2165eb2f14ef545d735e04decf9c1efab", 16) + g12To78x, _ := new(big.Int).SetString("c0c3281519d3a66eeef710d61aa05a648c02108d193a0f60d69e4341f3d916eafdb4ff66559e365f44d5c1375a8c4f", 16) + g12To78y, _ := new(big.Int).SetString("1321f3814e3da08308073186aa0bd0e0c4fdac4effd332b58cc91b71d02f9c621b943c3d5d0796def3767afb7b67f8a", 16) + g12To79x, _ := new(big.Int).SetString("90830b4e3531c735e3842b3fb1bde63a7f73b380f9193bbe8ab7dea4af48f08d8cd085130fbcf1b328a3c9dcbe6a76", 16) + g12To79y, _ := new(big.Int).SetString("f509e10a3207e10696ccfa1abe78b556f532d6f5d8803a35186286466d65aabce571dfc3c644a8c448ee6014705cec", 16) + g12To80x, _ := new(big.Int).SetString("10531f514b920d4051719e3341c279e8e5892b73a6d03d7805f81d08cfac7367b3377f575cda8fc69ccb268f99937a", 16) + g12To80y, _ := new(big.Int).SetString("5a8aace529af52e6842a6dd12ef0d34a841a87edd0351f959a3fdf05316a40894b8424f5c8bc48896708a49c04a136", 16) + g12To81x, _ := new(big.Int).SetString("12a8f78469b6185103baf43ccb81fe98768366766da34efbea5ee12eaffe6f4b72dbbf615bddadf184c59326de5940c", 16) + g12To81y, _ := new(big.Int).SetString("60fe8174c79a00c14b389ef1bc853700b4fa990c34ffa2ca1c681c1decedbf9ba688dca5010fe8b7e5bbfe1b021b29", 16) + g12To82x, _ := new(big.Int).SetString("96a56b5bca31bb6f97724d57f7b80380e1f0a2fa32d2226d92c9335971d8a5dcfd765a75cbd2be6b5932b886eca12c", 16) + g12To82y, _ := new(big.Int).SetString("9f33be6bc8bea9511acf18ec9fd8b71025f75150a2ef9fe83b724c0acfe07a6faa7e96e4cd53bde14ae4b96a53ab2f", 16) + g12To83x, _ := new(big.Int).SetString("17862b6d524f16e02a084e9fb0654973aa92da25a0f118ba93df9a105d2c00c740d2169545e7494a1636a7ac086edda", 16) + g12To83y, _ := new(big.Int).SetString("10c1e04620e95976bfdf742bdb03533b7b55046a9aa5a8517e42db7b71aaf00ebb236eee62a1959b96bdad8ccc914bf", 16) + g12To84x, _ := new(big.Int).SetString("2b44930db60c5e62fda1ee9936201d3115c63e40894a354fedaffda074b07c6c54d3035cc69ba2622af4a1127d523a", 16) + g12To84y, _ := new(big.Int).SetString("afda5460f7fc032597d3fc38834540acd3037d394dd7aa3133d0d1082d6758e87c8422f7addfaa885a5d551132b275", 16) + g12To85x, _ := new(big.Int).SetString("7d20b0283582f3e2efb8ef9561e69f645ff108db1a9a94694783649acdaabb957ca2bd76c84714da306f36cf95b416", 16) + g12To85y, _ := new(big.Int).SetString("70a720b8f2f5aa5e9307245d554b599372203318b5ca241656bb133e38cadd215f0d46eac4dcfd144d27d9b1d8fcb8", 16) + g12To86x, _ := new(big.Int).SetString("19c3ef7b33932b842f91ecbee1b588277fdb1a8bb1dfdda304f94ea33b9a07420a1f54dfc6da8ed2865d3132c85fc1b", 16) + g12To86y, _ := new(big.Int).SetString("c5a8a15999fb9021ea63c9141795080d4ef705cb988c4a1c97bba7070584890c6ff6fb78422004bbc86fbb5910274", 16) + g12To87x, _ := new(big.Int).SetString("160475f653c938043ee3949cec0fbde6737e67a4153c900ca8e7c08f17c42c1065b9304f46753dad2c35eb29be942af", 16) + g12To87y, _ := new(big.Int).SetString("d11cb6b0c5394dd2cad261f7846de206762fbde37b91eca7421fde35763f0454277baeae33525668e619e5a2d025e6", 16) + g12To88x, _ := new(big.Int).SetString("17841df9133f6a38903b90a0a67b2f0374207566992a3312dd0f6a1df2213c788a5e716ca0aa49245d8321b094f3cda", 16) + g12To88y, _ := new(big.Int).SetString("4d13e575ddc348796fffc4eac9f510ffe1f079d531c2b524d462cd49384373be208e7903bd8e5c574085355a33d113", 16) + g12To89x, _ := new(big.Int).SetString("13c0591a0f059e36f943d0e24f1c27a7ec66d12057c958a22bdb3583e1d9a50a4a60e4aec16dd586e45275ba543cf1f", 16) + g12To89y, _ := new(big.Int).SetString("4a529fe7cc3a88767be9720803cc8c3ea908bd8b79ec3a635dc6d4a2ff526fa378f5e94f23fc462f67fe66f0727d03", 16) + g12To90x, _ := new(big.Int).SetString("c59e4fae1f057573b420ec1bd61f8be08bc040689990a9ee866b4803d4dc50a9ad832c470a6e10ebaa3c738afa1523", 16) + g12To90y, _ := new(big.Int).SetString("110ca4c030099d03f733ea9de3f674464b4b8ccb2385945a148414a9f95fd4579c630320e27baca3dc7fb2141bf2f5b", 16) + g12To91x, _ := new(big.Int).SetString("763925b8f5ef62d240d76aca100de7dfea130bf34a09f7e70fa74a0978137699840f7242086761595db4b5c844c872", 16) + g12To91y, _ := new(big.Int).SetString("1a7b4929003f677f9194349f5e72ea5fc2594a146405bb917a23b232991da2663763df8eb866603c11025ba823e13c8", 16) + g12To92x, _ := new(big.Int).SetString("773e594f149dd63a3b6180bc3ecd958a142c249a2c554d20a6ae08c4b8218dcfafba746100f395fba248d05cbedb56", 16) + g12To92y, _ := new(big.Int).SetString("170f97f41c75a7bdd7f45885847fb0e9c77482b345d8cdc212e43dcfe3172c4c2ef4f7bf0a85c35833eb0f07404a460", 16) + g12To93x, _ := new(big.Int).SetString("72f4cdc52c410c573a6b6877f123ce328312321d118a743d640a62208fd96ceecf94f5105d216628f327c131cd57f2", 16) + g12To93y, _ := new(big.Int).SetString("d979e10ef5e4bf4b079db8f4b92535d3163cfe65f4cf780f2f588a9ff15a17c2fd99abea87d947b3eba898e275189", 16) + g12To94x, _ := new(big.Int).SetString("1500f73c1580e754583a10830b68534664a92011ecb99fc49a6b8ff8e16403dec02ffc5025283f9daf89afded75aa4d", 16) + g12To94y, _ := new(big.Int).SetString("1123e023b823cb49e34b883254a55c6830213fae288a12638a3c4858db3324a780590a26eca1ab0bfeebe1231c64fc0", 16) + g12To95x, _ := new(big.Int).SetString("138dcd92af7921b62bd16966f89907ae6cf447bff72129cb94b945324fff201ed119837e4c789f7daf5d1348ccb3f4e", 16) + g12To95y, _ := new(big.Int).SetString("b316c8be8dc0963cf075e8ae59b4d8589dfc07e41b22351c5e77fa3ab75fd11bc0a7f16857609bd196725896f5492a", 16) + g12To96x, _ := new(big.Int).SetString("101ea5fdb817941a117aabea37c5409a815c527b3d2aeca08ebdc6888749da51efcc57e0f9413b38ff38937b5d75cef", 16) + g12To96y, _ := new(big.Int).SetString("16c70419efb5ee583789653307a3ad9ef5cc4e92cb36e050fe02d6ab5771c24059ed9042b32d2e3b80dabc9e76dbec0", 16) + g12To97x, _ := new(big.Int).SetString("6b196d937da669209d3180b6e0d1840c79ed567ff337c823075e3fcc0bcefc24be337af22e9a37bd282a4f73b39de", 16) + g12To97y, _ := new(big.Int).SetString("25c43a9d0e59c35eff1e825b2111e1e90b364b8a930a2d3745137a05b054242f377582b02e527a33bf2cb95b6ad919", 16) + g12To98x, _ := new(big.Int).SetString("3496658a2ecc3a834db0fc9d84fae1aa75e0f78f126423216ff6b66880755152b21c046e8c34b13f8a1d62e477b5b9", 16) + g12To98y, _ := new(big.Int).SetString("d479674629f00313a607397c5c90bdf27eb487ec9f04fff1e56a61b92240fdd93ef876dd14c4734311e876ac49f6ab", 16) + g12To99x, _ := new(big.Int).SetString("19a0aa4853b07b1cb768e74c4f7c628f734856a90f598ffd1441f11b1384477a4a05bf25f2d17e152a2417bfb0ae87d", 16) + g12To99y, _ := new(big.Int).SetString("14ce74b65fd7001822b0778c113cde10cb11b6cbd5014f766fb6bc1c2b72a4e9f7d72407c8a47e3427595ad0bacad9c", 16) + g12To100x, _ := new(big.Int).SetString("2044ddbbf0dec33e557caf3f2b88173c44bc9a26bcca970852f46cd3202c28a254fd14d2b44ef1343724691441e055", 16) + g12To100y, _ := new(big.Int).SetString("134e03d8d8900fde4f640624dd05c5f0120559df6bc9dae7dcee6e6a483ad7b749e00d97ba8b81df8cde07b16ad097d", 16) + g12To101x, _ := new(big.Int).SetString("320ddc8cec816f4f1b9d5cbc9782f28457e5034436f318b8bfc4ff5cea2426ca402b2cef332e5d1fd88c215f747e72", 16) + g12To101y, _ := new(big.Int).SetString("12a211c464b89f00c61302c790230e80ff8a3616bce1acffaaef0a40cda2ff68a2657ed5b7dc5025d3c2b0435bd0077", 16) + g12To102x, _ := new(big.Int).SetString("fb79ae0ecd6f1b3f46f5a1f67188388e3292ed3b2222b32d631ac8d6683a10724b9642b255cc3c233b18f8e44666cc", 16) + g12To102y, _ := new(big.Int).SetString("50d1ffc9d8a2e03d7054c716a9bc66d023ab40fe7f460538b27c3c55c24a4459bbad18340f3cea2021df64f0f842dd", 16) + g12To103x, _ := new(big.Int).SetString("1129ea0748cdb9b845b5bc40ed9e0be0ffb8cf89445ae3389d99c6ec446759a58d6c8d27b0576918bae0a58f8f0a029", 16) + g12To103y, _ := new(big.Int).SetString("11546c1a2cded1c9437a93e59dc9cc5101e3464af5c7270ac2b2336130bbbcdf2655b4465428377b805fcb059669410", 16) + g12To104x, _ := new(big.Int).SetString("18c8d9e58d0197ede9759ecd91b67d6b5015d325c7583946865b5d2de5a05adc3203172c3f7411374186ac4b453674b", 16) + g12To104y, _ := new(big.Int).SetString("19dd01ebcd952016ed6385a5394627c9298898908e73750fe55d3a23d84b8287dc2f9f3d9fb7c6648b0f8593eaece2d", 16) + g12To105x, _ := new(big.Int).SetString("d21dbcdc3d7262275f9350c31b675c22d06ab047ae8fbd181fd0753128bf0c8989f0cfcc73100b16a630eb07c99310", 16) + g12To105y, _ := new(big.Int).SetString("19f1f79a45e3f8c0e7052850671a64d6bdc7f98261bb81cd99b7cd802754b47870acfc7e12decee0a08bb89bdf27fac", 16) + g12To106x, _ := new(big.Int).SetString("393a7383d765c36e360dd01d29abdf0715d7168c59cce0efeea765c0b03f29c3a2ff76022a0ae3cfe44f94e7c47127", 16) + g12To106y, _ := new(big.Int).SetString("f4f07b787a555b1d7615ee63ec118f890ba99f98f470f88dfc5cff57fb3f01c077fb13c8703fa538a357b7837ccc19", 16) + g12To107x, _ := new(big.Int).SetString("80122ac51038d1ddef4ac8494a52920e89f63bcb7cd198192da5311acb3fe847017509fb9290f7bf262e786461b9fd", 16) + g12To107y, _ := new(big.Int).SetString("17e39ca2ee4a8eb9f89a4ac907a54209ea8a0b75a9ff6829c4cf98452891166bbd573b2a537cd740f620bab4fcc32cf", 16) + g12To108x, _ := new(big.Int).SetString("9b7138398d7017dab8c04b23364f37d17a61a44d50bff2e05ab096ad0ac5067d30889802dbe92f57b330e8752a8721", 16) + g12To108y, _ := new(big.Int).SetString("b0df5aabf78731bd4990843eb1f349c95670c6b67d2fcdc0fb170736b93b608de24aec60db88813e5c6ec199aa94fd", 16) + g12To109x, _ := new(big.Int).SetString("e091d99dc6037d1f4c24b74d4c4565da3af54c75fd095283cdfafce856e46844d450fb3488d3ba4598ebebb8327c2b", 16) + g12To109y, _ := new(big.Int).SetString("729e298310ea46c8038352f4af4e5ee9b33634f91b2fc252df262c6c39b54496f3b6894ed641bab49b0da26450b985", 16) + g12To110x, _ := new(big.Int).SetString("e3eed427c6a5017599b40f73cdb22e1d40fa9376f301fcf32f64b75fecde7a782320544b9cf3a59df3de15d1cd2275", 16) + g12To110y, _ := new(big.Int).SetString("72598a238bfdc22f2e5791853c64ba305d96051afb1367d57dec6191945c4ad39992dfed2f526f660235470e22d676", 16) + g12To111x, _ := new(big.Int).SetString("4ecb8e157e3531ab8f9018f6b205812ea61410c058a8cdc9a8f74b3dde14ea3255ca1771eb1fb38377cb4a45f5ac97", 16) + g12To111y, _ := new(big.Int).SetString("3ff73af8c95bca6d67fa2d006b8e737a3839b159179abfbbf851e549fb2eb134e6dd1d6bdda529079be3ee37d52366", 16) + g12To112x, _ := new(big.Int).SetString("af7a0c0e2c15f9f0fc230bf9e8dd54ce6e623c6e5e050c7784ce3274fdf2c68615b7b536f1fbd93a6c65d200f0dd2b", 16) + g12To112y, _ := new(big.Int).SetString("11c21280451bc798e2849a37eeaffdb8070b44812fcc1a42216e8261170e6faee5eb2e99a70479885481f868f7ffdab", 16) + g12To113x, _ := new(big.Int).SetString("467bb117e14f72ed478889189b78614ce929e0a11dc4c9fe5f4b3c94460845fc1a93a7e84f2d017ffcd8e766153108", 16) + g12To113y, _ := new(big.Int).SetString("11f478fc0b3d40880188a104fd6db94db06a96a11446b8204c5047f08361dd20b1c6d3b9e8c7683bc93a7e3f9b48009", 16) + g12To114x, _ := new(big.Int).SetString("21040890dbe4d60a532435850be5e3b85be4efa8d3e4b53f6e9b86435fd5b584707082f3f2013137bf7e83e6a6be87", 16) + g12To114y, _ := new(big.Int).SetString("3a46738a14f592e5f25cdb3687f23b572bdccf6e1bf3cf3c087573ddc2ddf56acb0f2f7c024b8f22e7fe215ffd569b", 16) + g12To115x, _ := new(big.Int).SetString("19d00592cb821b60089fdc0963e4d40c1d427a41bd99249b9209e79b15e53b5671f1f002f97b0a3a1a1d87799a065df", 16) + g12To115y, _ := new(big.Int).SetString("13cba57cdc23a8c650025500cbafd661cad5dd269f8569ced5c190ed94d1c97468e54472bdb19d8533c3efc24620283", 16) + g12To116x, _ := new(big.Int).SetString("5bcc22bdd1b8f6bd3697c48899f3c3c66d3ed95bde450507175df4e99bdfee8b5140b2113d09172309e7f92b1997cd", 16) + g12To116y, _ := new(big.Int).SetString("607ba58c3109aba00b398acdb1210b877194e6b658c85d99905af6b762c3a5d0290dd555af824cc6dd58221a8dc072", 16) + g12To117x, _ := new(big.Int).SetString("1fc7f19047611351202a7f5332c1fc97b359a1c521f20afa9b334963467485600b6f8016438e9c51af8442b86c1314", 16) + g12To117y, _ := new(big.Int).SetString("a72af1b9824439482958fd9e3f8fe750cd8409e2d527bcc3542a5e03e46378e7fb745f064ffd357e168234e8477687", 16) + g12To118x, _ := new(big.Int).SetString("7ae261965d9fe9cd01ede8ebdec85bcfd51970aa009425f795b27a625129c51fc4f209d21a43db6cb0f64b3c828c90", 16) + g12To118y, _ := new(big.Int).SetString("e1f9b9bc743372d94c063abf6ba56008f0d07472b7c0ba96362fcebcd267bba72133d5dd9d4e422a2cca2ee2e1a0f1", 16) + g12To119x, _ := new(big.Int).SetString("55838e6a68c9e022b657bf2cbb728021fabe867767bf84da222d2314f94d78cd7fc555fbb2384914daf68aa044fa10", 16) + g12To119y, _ := new(big.Int).SetString("1540e4114abff824399c889d0e259166858a8f950766b071267e7747ea9580ffb5d3b03d41ca558233eed812e920af3", 16) + g12To120x, _ := new(big.Int).SetString("944b4fc0ca112cfa7ac887aa61167fea6d2be550b52c31daf2b43c732bc3cca9a23bc7b7b9767eb59f2c15d3f53ecc", 16) + g12To120y, _ := new(big.Int).SetString("e10c7dcbdd84002e7da14bfd1337da7c1acd68c7604292020ea4756bab5dc9c29be790f59e9f19c6ddf2063c3b9ddf", 16) + g12To121x, _ := new(big.Int).SetString("1814aa8084352ca9646edc03f3a666a49d6c8c6b397c75a3f2db4e7367c961eec704d60b2f056ca622eba5e7d5aed17", 16) + g12To121y, _ := new(big.Int).SetString("1091aa493ba3e157ca796bbbda78c2a6173b353b98bfdf64cad515be0633dda924b04ec769a95a7b9907677210f4eca", 16) + g12To122x, _ := new(big.Int).SetString("4c79be993599aa6f2cc588c9a17729e07fd443b5d0be7d71e6374bc1b6cd7853a8d5cdd2fd1f355512cff3abd6847e", 16) + g12To122y, _ := new(big.Int).SetString("17969fb3d5c1520400aa5f89bc13dc5553bb16fbec5dc3d3b05719c593201b2384c81a3e52b72273ff4a7e10d17ec66", 16) + g12To123x, _ := new(big.Int).SetString("56e4cd225404894800e1a17d0a9b01b6210ed3e42d8df1912c77772ac47cab49b52054a7c3f6ebf8f77c00ccfcb888", 16) + g12To123y, _ := new(big.Int).SetString("48996d22cb69b2d6a9f29ce0c1d8bcb75725b77caa0f1dcefb6523d5f2056399c9c19c3eead6480dba0928cc691c8e", 16) + g12To124x, _ := new(big.Int).SetString("1795d38c0f3168e622a236ae402e9f1ae6b13fde7b65429b03453066489e147213b8ee6745ddfed915ff10fe780742c", 16) + g12To124y, _ := new(big.Int).SetString("5873e3cbcd5dcb0ece242388d565088fd2181264fad06534c9416a887f7eb115fe259b97987bd8bd794fe1bff88187", 16) + g12To125x, _ := new(big.Int).SetString("117f497140d0e102b9612a0c0760c5fae1bf451a40501debe6ff6a0c6bf0be1b0957dbc274f4a2c3d5b0db48ee39ca0", 16) + g12To125y, _ := new(big.Int).SetString("380dae20e3f1e6b897371384a44e757a2d7a84df6666e32cb6c8fbc5e06e762d27f9cfd6ba1459b45fb327432e49ce", 16) + g12To126x, _ := new(big.Int).SetString("bb69b209c8d3382211895e4f0c0f69efbbaac9b51bb76793fa50acc1254105433e8afad7511c492e6e864480fafd61", 16) + g12To126y, _ := new(big.Int).SetString("85f238d05a21136f7f88114e7cc8cb2e7ed0be3e4b73dfd1be654577ff75db8baffd94f1746044efbba8cbe219521d", 16) + g12To127x, _ := new(big.Int).SetString("19f732e83c5801519c11076d13d81be227279802aca85d79a7c70ab68df622942e496f46e175b88c4c3fc5fde7bfe31", 16) + g12To127y, _ := new(big.Int).SetString("66d4699239e91cf083b474b9e2eadda2754630528a209d7fdde9018dec26fc93c039c9315922abe377f6b2739d2a8a", 16) + g12To128x, _ := new(big.Int).SetString("e4792c45ea0374775d9005fcfca11a9cf28cef25cb45c4ce3a4fcf88fa648378d0473f07ff1a56a9f3b7a593fe5002", 16) + g12To128y, _ := new(big.Int).SetString("1acb4c048149b23c021e9df25fe5b3fc54b77d3f2295926565b6179955af9dcc41d53713878d285916f2e01c6fa6e31", 16) + g12To129x, _ := new(big.Int).SetString("18af57cc0cba6db0d3c81025895bb6c552297a1ff24f5fb93e01270405c3ca1a010f3cf3463f03893e45d68bc8a2f62", 16) + g12To129y, _ := new(big.Int).SetString("1fd7cfe2078a0e1e79ee9fb7877872c382fe387ccb8797007654656774e15bef83c3f55928d5454e620fe073de20ee", 16) + g12To130x, _ := new(big.Int).SetString("12cc5b7441a487be214269e527ec1176f2f6dde1bd1fe02a08fdc92410c91d8d883fe9f7151c19c235e9dde01f5d9d0", 16) + g12To130y, _ := new(big.Int).SetString("67dbd3814cdcd0c12ff13eff08e790faac9b3c9895a233d71ecb5399c16983ea1623fc1b7422c061d9c7338e82108e", 16) + g12To131x, _ := new(big.Int).SetString("15318da6e7435d4194e5253f4bfff8adec4aab7304e49182c5d3a1ee498d800cef3e3a5762d8d6e7029a8b396e5df96", 16) + g12To131y, _ := new(big.Int).SetString("557ecd16ceb9695e6909571f371b659738fb6e61e69b73fb7b932a88e6c064cc73191053606716df7747aa07ebd47b", 16) + g12To132x, _ := new(big.Int).SetString("320b3b8315d2f24baed0ead61c7ef235b7dab1b76a3120c99cf15ff76af149aaa37cfaf7751ed74d541aba79f7485d", 16) + g12To132y, _ := new(big.Int).SetString("1580b7920ee4b3407677ef153239024119a12cbd13e9811e6a1736dbb03a873b4bfd2c8bc897f94e94a01eecd6dd3fd", 16) + g12To133x, _ := new(big.Int).SetString("9c942c27e37b0eea666d85dc58a566e900f88451e4cd3dc5133a62f6dde3a5c93307f3c86e7d336573a95f38c86448", 16) + g12To133y, _ := new(big.Int).SetString("48250ddc92820ecd6fcadcca3d6bf73dd4d6bfa66f5b49bc59001574b09f05f99e74d3ea9f91c8579d7f38fb2c8763", 16) + g12To134x, _ := new(big.Int).SetString("15ebc88aac7bcbc57c2b057692e1b99cfc9ad13972d89eea008239c015b74ecaf80c889f65ddb8129f321b214f7e599", 16) + g12To134y, _ := new(big.Int).SetString("80e4b8b7ba1a7c5f1de2b62f64ba4693652a307dd9b1a92252c4291c69335cf0b8c6f8561a15462916c24a78141823", 16) + g12To135x, _ := new(big.Int).SetString("18b3a334505d4c7cc8b4f906dc3496316d8d02c128fcd88ca1139f09e0957a3d7360aa03f19d9aa9e1ca509ed0a7287", 16) + g12To135y, _ := new(big.Int).SetString("50899b31fb24615a49ab0f49bc38371ddf1ca7982cf30b43c929041bd16444ed13d4a851943d195275c55315a6bc4c", 16) + g12To136x, _ := new(big.Int).SetString("324957c3564d435c9e28916ce384b568bad35e8da0416becf4dcb8d47a5f9b99b59ff84e2f3d01306e32faf4ec1b1e", 16) + g12To136y, _ := new(big.Int).SetString("180b670ab4b14f4af15fad06c063199c831f15c730fe1ef169f2a24ee3c87ea18f9e8ea393b3ab693de860a3c3b19e3", 16) + g12To137x, _ := new(big.Int).SetString("55bcc692af3a8ed7313777f1085effcee98ddf6bdfd0a4cbab5e805c313b15a637bbe3097fd4328bb37c922e8e8d0", 16) + g12To137y, _ := new(big.Int).SetString("14ef17878c43aadf2bee219d4d4ac616ffe2bb2ca85c5add0e091ba5e4471a2e9a4324a02f5aad8c497d19a339fd64b", 16) + g12To138x, _ := new(big.Int).SetString("1d282049941b376a7bdb9b0e81c5d5fc6d3df7c4dd9059d02bee35ffe56481afd1911ce2efc80384f2221145747f84", 16) + g12To138y, _ := new(big.Int).SetString("12d5989e164bf32bc49ce538bc2185f3ba43d10e5bc5865cd523ff3681c14cc4c77a159dc77e909dc4ae17fb16c207a", 16) + g12To139x, _ := new(big.Int).SetString("cabdd2d555e7fdbf15eea8d9e879dae763b74813ca8e7e7201222d0163f7819dabb4e9a177d0215c8ee0209f818e3a", 16) + g12To139y, _ := new(big.Int).SetString("b5e9b30c2bee3862bcf355e0ae8402ceb6e595557d1d89799f9dac25e857690d6ab274d64f395b2e1875ad09a5f7c4", 16) + g12To140x, _ := new(big.Int).SetString("3756b96f44a0b8d81e869f8105fe226a1dc0c422b372ef16bf1c960151838075fc1d0be337631b42bd7a17ef158c20", 16) + g12To140y, _ := new(big.Int).SetString("185eff03736ded483448d28e5e609429609ff67094f880a79f9884a77ae121cef32aed642a1664ae5a0934e80e0a791", 16) + g12To141x, _ := new(big.Int).SetString("83abdf9576124e1579a07d704dfd0eb68b3eaef853a00d9ed7ce519bffd0f016b22053d2eea2478f69a668a26ec6cd", 16) + g12To141y, _ := new(big.Int).SetString("1a23389ceda0fae24bc826d9cad8cb0791f933d6d5fb549c08cb6a6fb420a9b2925a221b7a0d3c7e2078d728ac03bfd", 16) + g12To142x, _ := new(big.Int).SetString("1025af987dc0aa4594bf71b342b71dfa9be8ea9440f6cb940288c14fc53926062169a28fc6f968f5a06cdffc4c2f3bc", 16) + g12To142y, _ := new(big.Int).SetString("124266250eda81a840f60b00c5332d52404e97c4dab39fc2737fe972bd800ec451dcb55aba8f5c8a9bed1e4ed9e2f3f", 16) + g12To143x, _ := new(big.Int).SetString("f95cfdcb19aff123335c9294fa46f7df5585001076640f0306c04c5b7f826e314776ab7f8428e8e24d44cbff92b135", 16) + g12To143y, _ := new(big.Int).SetString("157fc1ecb3d469a07b6319864e2b0cdaf20b9ac53a34f2af7f960d6feaaa2c1c063e2b5f39256612f8517f6a1e8488c", 16) + g12To144x, _ := new(big.Int).SetString("d3f7e41e0d6dca357b0eb5ff58ad3edc9eb4cc825d96fb2db4c13bbc26d85cedd3d0bc1fc2259dff6493b150e7018d", 16) + g12To144y, _ := new(big.Int).SetString("14cf7eb25efc61049a02975c507595406a02915c85a361e72aeadfc65f647c576d87a28822880684b9e6f486d9341ac", 16) + g12To145x, _ := new(big.Int).SetString("d76126e3b8f6c41767722603e99dacdc2c07a20710e51da646d473fa0afebd76c30c230b6ab66539ad5813e7207f1", 16) + g12To145y, _ := new(big.Int).SetString("8ec28dd0b2eb92af66344e8beddf6b47962bf3564c4ec460261683910f35a996e48b0aedd1b4b204600638d935c85", 16) + g12To146x, _ := new(big.Int).SetString("1501b1cb3bad5faa01786c85390ea937130f8045f0c10c9dc2bc81a5a8f3dfdc6c44c38386a18c6aeaf32ae615628fb", 16) + g12To146y, _ := new(big.Int).SetString("483f53ba6eb054817101d01fd4b93c84dfbfcb4a003df00344798866f70c52bb53f6c1344f3727116b3eaea6191fcb", 16) + g12To147x, _ := new(big.Int).SetString("10086ea020c2276607abd7656c03d5ed96fde894a409d9a409fd363298da9741231e8d3ac02baac482431b157ace447", 16) + g12To147y, _ := new(big.Int).SetString("3fc52b9384c8a28f37cf21ad02c24a39f0c52d6c2bcba1b2ee2b0d0bf0093b7185445241f3dae009709d8c82fae8a7", 16) + g12To148x, _ := new(big.Int).SetString("42241569f4225c2ab29b43c20f2f91646397db50d2d48bc19c13a98b72c3cebd8b09ab7cd1e6d82a9f427b0dd6138a", 16) + g12To148y, _ := new(big.Int).SetString("f945aad154d8008cc453a734e92166572a3b0e2ec1dbfed5444990999849908c709383f23fa31f436bdfcedf11b75f", 16) + g12To149x, _ := new(big.Int).SetString("c9f67f6dbc91e05e5ddf0503a62858c29d86a0d183dac66a834a38c7351152f4a391864afee16226a94ab3c1a7c42e", 16) + g12To149y, _ := new(big.Int).SetString("a6609b594fcc8075bb3a73ce66bbf3b7665abafe4017d176067af46f52f5a9116644bfc0e5bca6ee1b8ac8158d4e12", 16) + g12To150x, _ := new(big.Int).SetString("1153c5af141928d2fc95e766c33dab8feef4b9130700659e5d8f5efebfb043d73ee4337c5f0fc733edc4539698a4a15", 16) + g12To150y, _ := new(big.Int).SetString("e12d0a44494b847726c36b27f89e9ad39e6550ccc1e4829f792a8ceb51eac58b8bd434c09111dd81beca462de88c2b", 16) + g12To151x, _ := new(big.Int).SetString("3c5aaf47dbcd0dd23a0fa0c2051ba8c3d0fe6ac1eaf40188bab2f9de5927217944a7c102ab828718ac8e7661b10d11", 16) + g12To151y, _ := new(big.Int).SetString("1776473aff44785cfa49c3c90d715081e987acc7652039db8a3df404b0804c124319dcebeed7da580ee9082e96cd671", 16) + g12To152x, _ := new(big.Int).SetString("14e85d6dd8e43ae3579caf05c4f60311bbef732d30a4adabb4718b14651f7cf649a1b211425e46a462cfc774aebfceb", 16) + g12To152y, _ := new(big.Int).SetString("12a314ef9a9376289103bce265dc11be2a3cf93080568d3b2a67e7c78e78950ce35338169501930e5e59c162e489c31", 16) + g12To153x, _ := new(big.Int).SetString("3bd85a843e5f7cb348c19ae3219a3ea7493b615acfdc2df784a5b386e520b0eb1b2e9b91431d24917a822bf779796", 16) + g12To153y, _ := new(big.Int).SetString("cb11b6ad47b64ddc1968ccdcc60f91159879bb11ac7b035111a622e805b33d81189e8f695df8e7f181f1751fe6f7a0", 16) + g12To154x, _ := new(big.Int).SetString("10e41425e5297f70eb296aaa09c5f2ba87f8d22fd05cb0b8a984441b4b9998bd896af921f19f8b5a2a9698e24fa764e", 16) + g12To154y, _ := new(big.Int).SetString("281547615a1a34525b0910a27a705f36b1fbf2629284007c1842ab8259d9c7fed09ce955d4923710275cacfdbbfc42", 16) + g12To155x, _ := new(big.Int).SetString("24dfaca436700b2a28321fbbb35a8a8710f0b53506da3444d25d7258c3557a7f04ff4066c3577a382b78cfeffb1fb9", 16) + g12To155y, _ := new(big.Int).SetString("17cce223736ad9349c8ba8e85fc84473331f94573d220051df7654a37ad183c0ee66cc65f21870945ccf2b3cb5a4a3a", 16) + g12To156x, _ := new(big.Int).SetString("108ffd6cd88e29e760c221a6a8630eea55741e4d69cf25bb18d27b48c142ae6bc909578a243af518fc431ce17632763", 16) + g12To156y, _ := new(big.Int).SetString("7a4007cbf16132fff1cc4672297bbac19491404299836b6f0462ca11b230f6a170a353bad9bd6cccca1e84e76104d4", 16) + g12To157x, _ := new(big.Int).SetString("127465b15bbe5570434356ab8b9a4288f764b9777d9be89b52d93af6ace9f18d79ef8d26fe686e935583bb1b35f2662", 16) + g12To157y, _ := new(big.Int).SetString("135739c799b7b80f38d3973e2c1a96519d0daf16e384c2a6e988bc9c512feeb36025dcc0bafbb4029a0baed39d08977", 16) + g12To158x, _ := new(big.Int).SetString("a47d778a09e9b91e8a66e1b7ff48855de7c086c22e97e2a33d78cd6ac0f03789ef65ad6c42bd7469d79e8a771b3014", 16) + g12To158y, _ := new(big.Int).SetString("19807686de5ade7f78c1e92df43e146f59458f7a7ed3632917bcee346a09b17c771c0c30ebfa30eb574db51825ff2ff", 16) + g12To159x, _ := new(big.Int).SetString("553bbe29a93925cacc8f63a35bf3111930ac49d6cf6c4748690697385b9beaff873f9d50e737a67035cc4630d304cd", 16) + g12To159y, _ := new(big.Int).SetString("7ae6ac5a15a6904163bd3f4231aecb2a3ff35ac04dcc88dcea26054957fee459b1d655210c82492a91d21e9c62eb86", 16) + g12To160x, _ := new(big.Int).SetString("15f77fdc47ab14c2101f763260f537f2350f2fd32bf1b2f27451524a2559baf8e683aa0362294c1e8c3f50e72f9142f", 16) + g12To160y, _ := new(big.Int).SetString("9d4009700bcd44218332952b3d1d7f2265e8e554bb6e991929b1e96d9fdca23b05acf0b70c7af4b5840f90c11371b", 16) + g12To161x, _ := new(big.Int).SetString("155082f9a8c24a6cf3200452141640bec8fae3a269872e4f535f5f58ecb3ae9789133dc3707cf1936be2461c942c1ac", 16) + g12To161y, _ := new(big.Int).SetString("16fab5585ec39985e7372355d7911eb1d3ab1fca71e920504172278c1a61ddb3d9959e0d4a61aac70d322f5c145dee2", 16) + g12To162x, _ := new(big.Int).SetString("3fb08dc59a282d83866eecc906b694f1d92b24e87658814ad685cb6b110b749db7a1d7c0185be7b4c8a325fb7bb6dc", 16) + g12To162y, _ := new(big.Int).SetString("3e98c7707613366535514c7bda8a9d20f4102fd81f3fcebe6734aae4e231c937b46b23d823b960cb8040a8287dd5bd", 16) + g12To163x, _ := new(big.Int).SetString("133c8d89b872593cf25925ba8d7f240a85029eea7006a58388a6f7549efff747a9f5f7a44f7016854ca345e8620e7f5", 16) + g12To163y, _ := new(big.Int).SetString("1028b91b8e2f13769a0190c0e9fed0d842f0c3efd531e5df212cecccfd314e189d56d54565cbe206c2ae326b882dac3", 16) + g12To164x, _ := new(big.Int).SetString("6422c61104e62eee280da427bdd2e91fde9e9a1f9df8d77b1b0e91ee5db2d2ade3c6986c5e8c0ec21035ccc35f93d4", 16) + g12To164y, _ := new(big.Int).SetString("18cf5bf95c516e422ff72afb2df3d1f99b08fcdd69657f5ce7ab8bcf6a8f3eb717dc69a32ffd79e048b7d45bd353f7f", 16) + g12To165x, _ := new(big.Int).SetString("bb49069be1114cd86fb632d7e3dfb7ba79bb3aa8e842298169ba74a53f61e182f27cad88e6c8b243b9e068120e6cc8", 16) + g12To165y, _ := new(big.Int).SetString("b50b69c4b23b3e07123aadd4119784e70c32735424b88094b08c75a456daa4f7626bff7daa51f2c73d30ddc5318570", 16) + g12To166x, _ := new(big.Int).SetString("12a19d3de6d72caac8d34bbd6e90546ec0a4009e574be029a66f339500bbe021b34383e410617fb0a526591286e0643", 16) + g12To166y, _ := new(big.Int).SetString("9b406052873481fafdb61a8adfc9019e48faac87c9e44121af21f0a4cff2774798e28fb783bb8e7e31dc4a313d7a91", 16) + g12To167x, _ := new(big.Int).SetString("10906d84db20b228bb0388b23ce4488e21775454205d723df5a075c51e4dd153774343fc43b58075de945f24bfebb67", 16) + g12To167y, _ := new(big.Int).SetString("7cfe72c84ca6b9dabb5c139ba427cc47e87b4ba07d24d410c430a2b9b5c6b7f9237bdd5fe199be039d8181b2d4649f", 16) + g12To168x, _ := new(big.Int).SetString("910bc0e25094b13d6e04b32302f247d99cb4a71d9a1d8cdc75a467bdce8160d8af85beccb93dabb2cf1e15cd359ea8", 16) + g12To168y, _ := new(big.Int).SetString("c3d5f0eecd86b5f0dbfa46038cf379197d0112e674dd50f6071eb9b787d000ecf2b4ad8717af94fdfc8bc162d91345", 16) + g12To169x, _ := new(big.Int).SetString("170f6e8c17ee0f447e7c56000ec81b125743fc7a71c61e099d368c89d7e9bdd6f91b9828865d1c21bcd01f1101e13b0", 16) + g12To169y, _ := new(big.Int).SetString("b4179cea51ddb18b7f53b44f96c32d409a5170ab59624bf81562545d451ed3a77e82287d8331b6077b76c920a79de7", 16) + g12To170x, _ := new(big.Int).SetString("5f3a211c40201fc17f6aac6f9ca51bf34e2adfe0c385fe9434db7e711b1c442fe8342da2f3ae012b26b932c3fec0cc", 16) + g12To170y, _ := new(big.Int).SetString("16173a4992b83b3a498bbade3c171fd251a1877fca293db16f50fb73cfb410c67c98a21c8e39c6f2ca22547a0096cbc", 16) + g12To171x, _ := new(big.Int).SetString("c4eb3ee27f8b8d47854a14084f3165ef885d4ef7aa848263e8e08326eb8ff10931e72237a46735f5b1abaf11850dad", 16) + g12To171y, _ := new(big.Int).SetString("ca881eb1904d3980dc3ad9e49dea9feb0333bb8f61b3ade8020a7108379fa9289e17f86ee0ff5ebd009dbb873bfdd7", 16) + g12To172x, _ := new(big.Int).SetString("bcace195e9b15a115edd0bc6cb21722ad3556a8945470c1a556bc83e45a913f9155febf07ec47769b47b8d5d6b2a40", 16) + g12To172y, _ := new(big.Int).SetString("14c699aa9adfe467f3977c6a1bdcc34029160b789d11d5e71980d044fc23666678cc2cb79738b6baa607ee733b3c8da", 16) + g12To173x, _ := new(big.Int).SetString("57e20231567347a7749584f82ad2ffc059698f0c4b702b9324414bcf5aa6f46a4462429172ae83f72512d1d8fb9f69", 16) + g12To173y, _ := new(big.Int).SetString("14581ba8e6fdb0222ddd92a5e87bf666ab7ca5cb86ca699bd16cc5daa67d6ac01afb81f266f06f4ea1f38b0aab90c61", 16) + g12To174x, _ := new(big.Int).SetString("143afae29780766b112a5952f024ae3145eab24719ec21babc615d8547634c5d4636389de5b5d11cce1143016efcfeb", 16) + g12To174y, _ := new(big.Int).SetString("de662f6be83569140af7ba194adc87b5bcb4aba0adcb4403884b64e7e89625d04f0028a80c2f2c9f8dc9dddf23b181", 16) + g12To175x, _ := new(big.Int).SetString("3bce098b21d2e1f1296592746475919ebf66ff784482579e32c9118ed276f978dffedf3ef07a77947b7d36f1ea93e3", 16) + g12To175y, _ := new(big.Int).SetString("9c76e0c83204761988945d5430ab3389502b8778103529176ef2ea285fee97c40946d4ef43f105f91dbf1222bffe0", 16) + g12To176x, _ := new(big.Int).SetString("e4bcab05cf3ecfa042fda48bda025cd28ae2e8b121c82cb8c35986605d6f2240eb17c9b9c27169095736d0198765f9", 16) + g12To176y, _ := new(big.Int).SetString("18555a4c275a57b24968df3885cec2c8feb1cf1ccbbc2a1dc5ff419b71a49abacc6a0167773590ab998bf5c2a5fc653", 16) + g12To177x, _ := new(big.Int).SetString("497522e3537513af8ab51673eafa636250d1ea15f90b2028bee227749c817db9d7094ff36ee24057d0b68b4b019523", 16) + g12To177y, _ := new(big.Int).SetString("c7735117d127fb022a8a3a6365faa220271467a986daeee92cfb913d584aec1eb93ab57e98c6108b225a83af8ab69f", 16) + g12To178x, _ := new(big.Int).SetString("1076cfe5560f5d378308b02b4b23efdf3f6f268b885340ffc6f3aaae8bf5b301aebc22939c012e0616bc519a34f318e", 16) + g12To178y, _ := new(big.Int).SetString("985107e1e9d76c2608d6784589ad58f744f7b8ccbf591e969758100af81f6c6cc751b35433af724e4aacaf48fdce39", 16) + g12To179x, _ := new(big.Int).SetString("e41cf5effab3711d615699c7a1aab2cf8aa8daf691b96b52449ceebc1b57cf29c74f782bd7500894e49ab1ce06e8a5", 16) + g12To179y, _ := new(big.Int).SetString("a8d52e34491822c0de9ed308007713d32ad8559f3ef8bff3d856f99ea1babc568f0b2a86d7c68a70f4dcad5a50631c", 16) + g12To180x, _ := new(big.Int).SetString("cc71f17e685ad819201a2a96b89fa2f0badb410fff58e2155407e08a0ce68f6e8fa26e083efd8233c6ee5517d095dd", 16) + g12To180y, _ := new(big.Int).SetString("a9381762747bb275934bcfd6c4023a3a2a140e498e16cc66ebc8460b218d590287f3eab54d885dbfac38ddaae6acdd", 16) + g12To181x, _ := new(big.Int).SetString("2d13c1f441c3a5f19d42c26699ab14fdf28a6b8dcd508e5f543a2ac444a5b0acf4228cb19f9e8e306f22dc3d6baa26", 16) + g12To181y, _ := new(big.Int).SetString("13b1d26048011fe25c9a47331ce9367876e2d9265eaa1d99135b942fa8312e7e57d7520bc7df9d6312e4c3835c2f174", 16) + g12To182x, _ := new(big.Int).SetString("19b39844d9593c8e4487ce996a33cb3dbb12c719750dbfaaaf0b43014dd8a48bca668bdb223741ec35c3f7579e8f930", 16) + g12To182y, _ := new(big.Int).SetString("d3e8168b65f3e54fcc0a390f176fb4e44845640a59deebfc5a27df65ff45b630d5b266a579d514794540000aae7d3b", 16) + g12To183x, _ := new(big.Int).SetString("b21d5c905a554590574da9b27c20b139ecc9ce777c62c35843f917a5f74dd0804e2035cb55262897d02f755ea7b68b", 16) + g12To183y, _ := new(big.Int).SetString("13364bb242ca69a09ab5433e0265a6d987539f6741bb66d393c6d1bb1e4a0378bb51c976783b25c5afc189de3a5e5ea", 16) + g12To184x, _ := new(big.Int).SetString("19e679044a9eca80829f98d71bf8ca98b1cdc60d0cd7cc8957e7865479ba79fa7608ecd608392f9293739f4d17aac3e", 16) + g12To184y, _ := new(big.Int).SetString("18c81a9bdd6d8e094e5192f7e4cfc90644260c334c489db57bf530185021e96ac4af6fd528337dd07e298db4a7de0b2", 16) + g12To185x, _ := new(big.Int).SetString("369dfd6ab7bf26a8d4e5d64dcfb3b63d455cf2ee4db02f7c7683b6bca035ed1100832f60313db7deaecb8251078873", 16) + g12To185y, _ := new(big.Int).SetString("44bafdb818f8499bb51328d51eb1632e8d14ad7152353f9a9b2d9f2fff57d3e994a923c843a4ffdfdadc46132e7d26", 16) + g12To186x, _ := new(big.Int).SetString("15ebc18f89a2b6fd6ed009fb65888d39a071e3fda69dd9bcea7578ea66689c08d0126947da592298137ddf6dfa6ec1f", 16) + g12To186y, _ := new(big.Int).SetString("127b260a21eb7668c14bc43e4235f7479af7043c32872b60e1038b37bfe1315aa7205fd1a8cf65f2836e6e8e374bf28", 16) + g12To187x, _ := new(big.Int).SetString("bcfc9e711ad2a3a8b6990a3df74642db48922f04dcb1a26bd88ce4c8ccb6d79914a5a29d33334b0636338fc2a8047d", 16) + g12To187y, _ := new(big.Int).SetString("9da171650b66c067d1c41602761278a215fd2987eab435b3d0882737189cedfc1972e9199f58a6d6c1c1d70bd393fe", 16) + g12To188x, _ := new(big.Int).SetString("d898ee857af4fafaf02b327345d90e824b964b954bd7366ad05b6a1c5d14acbbd011214b55440f87786de2a330c131", 16) + g12To188y, _ := new(big.Int).SetString("ceb2ff631bd5b2eebb78bc9bf5ed6ca1fa088baa3608bd202fc8ba88d88baeb6d2410fe89f2ac2cdc4fe615150cd0f", 16) + g12To189x, _ := new(big.Int).SetString("1047172b741e1bb646e4b98defcf554691d16d7de036d0cade3f72387a0ef2175206a55f5000afaf1fd5fdd143fad0a", 16) + g12To189y, _ := new(big.Int).SetString("f5b5d94ebe0e7fce2ccb9cf9c396f8a83367f4c80c45428222560d0c28f14153f1d302812cbb939c06e2e8f60f6dd2", 16) + g12To190x, _ := new(big.Int).SetString("abc14aec8a9cf6d7b1344f4a4e65164e1abcf369de4de55d20c91e966d4aeb11ed24cf663c60b7bd7a88c79cf5c623", 16) + g12To190y, _ := new(big.Int).SetString("7cc4b196c7dfef20b1ebc9e5b03385311bd591da7fbdd89c05ada304c99ae780eac02895fb6a5f01235208b71b4298", 16) + g12To191x, _ := new(big.Int).SetString("13f43125659111895ca3e60c4bfcdf74ed7c261581b2b077730a4ee2a50ae5fe948e4a597403b3368ddf58bfbdfa00a", 16) + g12To191y, _ := new(big.Int).SetString("d3bf81b2e73d05debda0abdd73ce206b8262a5ba42374cd350b6e7f67190d2a59214edc1df2aaa4f5a4a53f2a5dd37", 16) + g12To192x, _ := new(big.Int).SetString("12d30265ab77bb06db58babf408679b92e26fd367391b38a926b91bb6ec2ab6df0c3f4efb10f89a99474010a949b27e", 16) + g12To192y, _ := new(big.Int).SetString("18d1d446266830b4c625c3ccab5b5ef7c51bb10f15ba024ab9c7978996ab7620332b020e941e0f80d69d0a056af7937", 16) + g12To193x, _ := new(big.Int).SetString("6966169e2a61337377ccb7ecaeb7942adc5b170f0a1c1c5df11aa259b41587d9febafb4a901c8b005b5a0faa2baea", 16) + g12To193y, _ := new(big.Int).SetString("11ab8a505040f271f4fb7a90ff298e64dda579761ffc9ee299f01aed1ebecb034f541388d84f8bac4a7d2a72986864c", 16) + g12To194x, _ := new(big.Int).SetString("c55aeab8b28d83fd4804f4bdd1cdb1e5516015ce22af1e110808eb6796f62a48fe8eea251d514e887650dcadc39def", 16) + g12To194y, _ := new(big.Int).SetString("177c839def54a86f879deeb5f15c5dddb1c6adf3a3c1bd9e4e79b4d8b26bc43ede744075562d10b81a240138e8455e1", 16) + g12To195x, _ := new(big.Int).SetString("1105c20f194e40e47ddfc67d3c2847ed841f63e0e1af6546f73af72f260b11fe3fafe46b3a41686d110cb07be24ab33", 16) + g12To195y, _ := new(big.Int).SetString("714b782b7923dcbbb584eeb469ad872536aca104ce9bd473428e567af9b55a7ccf5a5fa9d56185b3ffe354b4298a01", 16) + g12To196x, _ := new(big.Int).SetString("1116c55421ef7370fd3656007023683a9b495478c870adfa074313df8187342031cdff474041f1651a73f4c9ff709d6", 16) + g12To196y, _ := new(big.Int).SetString("80791ddb2418bb4685fc9f4377b63b92f3c66d120b7c97d857f78886a501e1dd83f047a49f420b83b6957d2120b71", 16) + g12To197x, _ := new(big.Int).SetString("3df18d8a4dbc6781742de2628cc12170472db073be5804eb3606e0cd713f55536c35b20a060c48c0f51c2cb1f9af3d", 16) + g12To197y, _ := new(big.Int).SetString("3cd17e0a2f9bc57321467dae7f43b78b1c902c576558ff1fe389b5d5d570f13c0802e29b07e198c6b0ae18be8d39c2", 16) + g12To198x, _ := new(big.Int).SetString("3f21786ce8f4fc420a75fcbef2f60e48715f80da3429d88289d7d5d1366c76b3786d6541f281913d0847c6f4ce84a2", 16) + g12To198y, _ := new(big.Int).SetString("1419f8e19f28ae0d6bf54763dadc5861b16affa1c7e240f7ab7e6ec22b06edc07fc36912953af41850c2726bc8d79c1", 16) + g12To199x, _ := new(big.Int).SetString("118eacd4f99a7d65ea1a055bb139ddff1024284c1227afd27cebdf2a44ffd5272a998b390aa73b4f54f19898d460976", 16) + g12To199y, _ := new(big.Int).SetString("47e50aed98571fb91415d84c3417b6a0d17d990046112fae29005faa6d2ae98b1b9464b59829c0ae715a65d33525b2", 16) + g12To200x, _ := new(big.Int).SetString("cf4908fda94aa06c04d26e30491ac30ddce9a6a3266555b5686c1720120cdecc3ef91e7427f622727e79b1b86f8797", 16) + g12To200y, _ := new(big.Int).SetString("16e19b5fc4ebe0bb8abdb30aa933b8cef3c87c09a0f23ca356fe55314dddb83bafbaa7531641dc5cb8021f4ad5f6c4b", 16) + g12To201x, _ := new(big.Int).SetString("380a1af45213129ae237fc6da75d4982eb6636e2268c81379412961651ceb218a73290294dc28a44c38d6c9584a3bc", 16) + g12To201y, _ := new(big.Int).SetString("69fd537c980b67e523b0b3f3fde7d8538f96207be299b6752ffced4e8f11d7e0a325d8c86671cf00b91829c9bcd5e6", 16) + g12To202x, _ := new(big.Int).SetString("5fe086b1c4b10505db63f342fb415f6d6861d07ee468d3349e163092ab5e030033a7fdc2107a93747905a44cfaad95", 16) + g12To202y, _ := new(big.Int).SetString("41a6b3dd31fe367f16863e68f319627c8a3acf4bb80248f5abc4401afcfb333fe97ab35da581cf251d0991e9b57e49", 16) + g12To203x, _ := new(big.Int).SetString("136776a77fc774c7786b3ab805bd8497fd6c8e798865a250854863a5f05efa4c8c6c1cad56b74d5a8de2009b9de5847", 16) + g12To203y, _ := new(big.Int).SetString("1960e3ca3276ce29fbfd5e61985740c9e94baeaafa3c6ea8648d502e76c4771d91610806cf7db1845721425594fa105", 16) + g12To204x, _ := new(big.Int).SetString("51774de396e0456c71dd80a60f12d21cd8d394f444f8ec11cc1241172b823e5a2da0e4026f0463f6938507a28f61fd", 16) + g12To204y, _ := new(big.Int).SetString("70f63c6e5f10ca36d4f66cf255f49d38d272887072471f04e301922318eb176ee7fdbe5d37e730853dc70b2c97106d", 16) + g12To205x, _ := new(big.Int).SetString("114e44441bab56585d1f00e4698303b8ae52925ed22ff608f3f346d0c1796f00f954e240a5965aa50f6f684a2739c73", 16) + g12To205y, _ := new(big.Int).SetString("1add868b94031d9254694dc163765c071de69620dd7198b9e980407a82f2b5bad8c9ed3c151f965bb735754162776ad", 16) + g12To206x, _ := new(big.Int).SetString("94c916a63bafc36d0ff51f36dbf5abe60c974ccde1f2945e3f482a996e15063f9334ab874ae00d7d4baeeece68a76a", 16) + g12To206y, _ := new(big.Int).SetString("c5b8c12e8b085309c2218ab936a9f8486242ba4abe16605fcf53e2fa59b8b4f2f0d8fce0866a63ecc2b1d9559c887a", 16) + g12To207x, _ := new(big.Int).SetString("118440e9ea5d0ca6a4d593eadf149988b376ae79deba462c11b9c4146cbca71d93710184cddba8bf57e9bdf0f4fd5b3", 16) + g12To207y, _ := new(big.Int).SetString("9817389a50fe85127287e1c25d5c40a7c793e787f048bf02a69ff2492e898227d9d5d40ec3fd29f86d7cc912e4ad06", 16) + g12To208x, _ := new(big.Int).SetString("44e02fe124b5a7754ce07713a818b661a88e5b59609c2fb866fa26023d0499ea8ecf96ce2cfd661c67b2a7bbee76e8", 16) + g12To208y, _ := new(big.Int).SetString("d3ba51a10bbed75f98f791cb225080b3087e4668935e2d8200d2a42c0aa5ba28c1711c841a835882e2669c19e04fa7", 16) + g12To209x, _ := new(big.Int).SetString("ae715b1dd065c4e8b9df8d27c6f40868fdf5f5da8c17474258e2d7df84e69654d4fa23f574343c7746e4cedb04da5a", 16) + g12To209y, _ := new(big.Int).SetString("980127fbe1ac3176c4c3494a8f11b4d6f07b65aaa4c37a133007601111f8167cbd58cc4b755cfec8877b440618734a", 16) + g12To210x, _ := new(big.Int).SetString("d4e72f646af729fc96a5b6619ec898808a8bd12f9a0e2b60a54e844c04ae5a00dd215424a869037219d426f839d651", 16) + g12To210y, _ := new(big.Int).SetString("41ecfaf326ee4b88c5f81811ea8c338e943516ba7da547b0bafcd484de23e208b39dddf2ca0add4f420a9c2722bdbd", 16) + g12To211x, _ := new(big.Int).SetString("4bcbfa770bd4aeb8b160709c8a69fb22cdc4e58ca9a58763b99c53617358671e8c20d8ec33cb06a75d4da3a3982a1e", 16) + g12To211y, _ := new(big.Int).SetString("3d7b253a592e3fc11ca9d6b143348f88232abe363a699726bda6f9a61f4e84cd5bcf08f6f8278306de297060476df", 16) + g12To212x, _ := new(big.Int).SetString("f19dc610f4449da5420a5d5e6406bcb006b62faea414868d2e38eed978596cff8e86a4e47676101cb98259e082146b", 16) + g12To212y, _ := new(big.Int).SetString("830e4e2e50bfefce0bc558c9e74c9714a71a5a471ccbd3d9d7ac534c009f399e15f85c324a7d5dc2585d74946c6500", 16) + g12To213x, _ := new(big.Int).SetString("197885701bd9af118177ec0f6f791ef4251959a3f59b80a05e1653a1f633432c3a4018555ffd215db7f9d5084390b9f", 16) + g12To213y, _ := new(big.Int).SetString("608112aa435d04a0f05bd432e13b67ab7bda184ad23763a858a35aef57d59da082e1e842f75ee524f8de79ee794d8a", 16) + g12To214x, _ := new(big.Int).SetString("16bd8a55e3b1695699dea5763a5fe6418a55899f3c768a68ab1e04e676a7052446c609bc0e5506d7972397f6392910c", 16) + g12To214y, _ := new(big.Int).SetString("16feab32309d89d44a8b2868a130d3007b69b1ed83d601d1acdf9f6f8b2331ef9926fb47e0436802b064aae773d646d", 16) + g12To215x, _ := new(big.Int).SetString("192a288de4334ce746bf19aa8e26e736a51be264d605ebf93991272741aac00736aaa1db44f3e565c365a03304d4671", 16) + g12To215y, _ := new(big.Int).SetString("7f44babc07ca8bcf82dbc9ffc304e0e44a05005d9918850f89cf0e653073f8ce343cfa307e52156657ecafcb1d52ff", 16) + g12To216x, _ := new(big.Int).SetString("3bd781aa9a31d5ca87a7e692e86eec5b6229cc0199d804a1b8db429adea932c92788fbba31297cee74147a5e861395", 16) + g12To216y, _ := new(big.Int).SetString("1a3bf79a61de7f92887ed75e0fcba22522df68818ea86d86dfac86bf60ec06f77f058f06980b03fdff28d0fd57f2e0b", 16) + g12To217x, _ := new(big.Int).SetString("2402d983298af793f637561b68b08f470992fbda0ec4da86d7179ccc4b979a0f9164ceedc9c6a29a2cc54ee0ecf1bc", 16) + g12To217y, _ := new(big.Int).SetString("144e6b94177252db037f6a84f6d16d40758ada97caf5d7d9387a7928be61828c0459d7317a24bdb42caabc0966dc716", 16) + g12To218x, _ := new(big.Int).SetString("e0fcb99476c675900c955298c1df338e33e23b28a74ad9a27b4ffd47ea8bd67b9de3b5add072c8a1b072b9fb78066", 16) + g12To218y, _ := new(big.Int).SetString("6f388a7db5cbb124de08a246b079f628e61b1cd7c0e5edc65fb19cb21938071a56ccd33ca116f5a2397713c63048db", 16) + g12To219x, _ := new(big.Int).SetString("11498993939102f5740d8858f5ee70a087ae0d52b2cdb801e279e42ff150975019a92576cc14fd2b8e07efa76b2589b", 16) + g12To219y, _ := new(big.Int).SetString("9977f5d8f10e23098bdba68a286f25fb2b6db0aef7ee845934934f4268789a2c042f44a6c80f0162ed5b2bfe537d30", 16) + g12To220x, _ := new(big.Int).SetString("9ebce7cceb0314e1994f20d7a716ad5ef32c3cdd8171950dcef910261445412d9a5682dc2e0500370e2d6317c384d7", 16) + g12To220y, _ := new(big.Int).SetString("10d543e1a05b9c11d5a24ace56f05d04799b48c6f86a4df612fbea5ad2e2954ee8a041ecb5b765ac6a32392242903f0", 16) + g12To221x, _ := new(big.Int).SetString("82bbc0277954ba90241cc800aa18b05f2826378db66d59da11ec6a9fcda310415f8385f68f2eb25f2ed3abb21581c0", 16) + g12To221y, _ := new(big.Int).SetString("1258c7929372aef1be2ba403af16d1fe24d500c81499a17adae4fb94775cd7b593911ea2e04d7d4e7946d68ac301373", 16) + g12To222x, _ := new(big.Int).SetString("1130ab0736b48f526e01bc5fc4cf9164ac4704047e54f9d8e9f861dc9cae10a884b5b16423f344d86de58d1f0c8aa61", 16) + g12To222y, _ := new(big.Int).SetString("68b14390cb893f5e775837141eff37bf894c75899591a3e67779cd16d89567db5c69539bb486f57a24b6c4892b1b88", 16) + g12To223x, _ := new(big.Int).SetString("5e04b1e370b58aa76aa0071ab2e6586501eabf3d80c2b8967eab61f56dbc6a3943c1e9e6000729ffce3811f4478d2b", 16) + g12To223y, _ := new(big.Int).SetString("1374b8d7eb70c4cb81df2bb50e894791d5ab853520480e89c198c96ab7158993000b895e21b618d33f30e9f3dbd4930", 16) + g12To224x, _ := new(big.Int).SetString("174a97d44f91430e497ae21c793730e8b5441ee8708021e73637a9f8c30066e641794ffb913b92fbe64566879f9a194", 16) + g12To224y, _ := new(big.Int).SetString("151ce7878fa02ec8966f73c48125743a771018b3dc5743a2bd836b90ed38444df88aecff1dbbce14e0ee2888e1ef708", 16) + g12To225x, _ := new(big.Int).SetString("16a2d22751e0faeeef7844c4427269e26009b756ec7a4fbe5a727df769bdb9ef441142ce22daab727482ab2673435b7", 16) + g12To225y, _ := new(big.Int).SetString("1224d9344ee5398193bad09c691f4ea3067802c789714ebda5e62c2eef5c524b7ab9a73afbbcc3d3866b94b1e838f33", 16) + g12To226x, _ := new(big.Int).SetString("14de3ccef2af8ee23cf6b04f610838aa53cf823dc104d975f19db702bc56d5d25bea164369267dfe22d9feb60902e3f", 16) + g12To226y, _ := new(big.Int).SetString("58d7a014b6c3abb260b6569c61e74425a97fa90dc588966aff854c0fb682ce41d779079962b88a4425c29f06a6753c", 16) + g12To227x, _ := new(big.Int).SetString("6c19a89057fb87bfc179bf4062ab6459526bdc11146304f311f647ea5957e12244418386c0fe09da476630835add77", 16) + g12To227y, _ := new(big.Int).SetString("bbe679f18d53cd4df93bd02f6f5511050647d160c59514673f1e86e3891053b8445f45df4a3b373861503c71d58de9", 16) + g12To228x, _ := new(big.Int).SetString("ecf150e129cd512a141df58f95f8c38512fb2af1bd320a94842569f434fed7a0604cbf1b1528eb1118c11c32a692aa", 16) + g12To228y, _ := new(big.Int).SetString("122d71c7c5115b38a0f2aa28e8e21b649db953bbac9aeea82e7e14c02c8c1cf1cde06eb8914ceb29d2979533d0a8a1f", 16) + g12To229x, _ := new(big.Int).SetString("19a4e9478707019b033794bf784f3c37777efa971f51003a37b460479fcc05910dba5c852f534a299b9e2404288bc86", 16) + g12To229y, _ := new(big.Int).SetString("398ff16dcc00614b1e2257987ee2c339a53a29e67a2d6b4687089d36fc5d432e6c4d0bcf1609db45dc2f3f11fecc53", 16) + g12To230x, _ := new(big.Int).SetString("d4483fdce59dfd84042f5be7f8458962a8867c4ea38445f809abe00cf3286979a93ed8690630783455c17e06e37647", 16) + g12To230y, _ := new(big.Int).SetString("7bf259c13a02f5117d6e1f1b4a0899c1082c6ee6b71ca1511833e312c0a7c81732cec58d4fb8b5ca0c62a7c2e07807", 16) + g12To231x, _ := new(big.Int).SetString("7f0589fa75f0f5cc007a62fe6cc3e368adb2bb08de7eefc8821a031935ea2c98ffe212e6c15f031f2ed23aa58311", 16) + g12To231y, _ := new(big.Int).SetString("1612984f2bb0a5fe9f3c941a4cd2bb1946a3a4d1f605faa84161c6340cc1b1890cc6821fcb23f9111975839883d1792", 16) + g12To232x, _ := new(big.Int).SetString("f74be9f2e89f7fc9d63e1a380117e4ed633b936ae43735e6ff3f28056d1362725c791ebccd776fe43fd9436277c0", 16) + g12To232y, _ := new(big.Int).SetString("101552b0bc58c07276643717fea8a73853c5194ef7e4a39f72ae9d87f79402c42d18a67517760721113eb4efb6a6b72", 16) + g12To233x, _ := new(big.Int).SetString("15789f64a8d6d7d1ccd4501e25f29ef551f2a020b11948464b56943c8d893ad47241325be82cd684a12d8a94d178b50", 16) + g12To233y, _ := new(big.Int).SetString("16a632a4df6dea33665ac380117f717b7d38a0072d6a531e131f1fa3aa4db46b01339cc7b2c9f03f78acdd37982ddda", 16) + g12To234x, _ := new(big.Int).SetString("5eee70541f00b428410a9f0b6112ab6c14c01c3af8c6831709ba9baf84ce9dc1ba948251e603279474ebbd9dd432cb", 16) + g12To234y, _ := new(big.Int).SetString("1c026b8f77584b85ef151e4454cfe9ca90ab047b3e012ae5273a8c10a6c28584c14fa6855e21b6ff88dd3bd73a0125", 16) + g12To235x, _ := new(big.Int).SetString("98a5fb33dde33395886a093e83b6e681fa4ffc07ec561bd840281a6c464509203dcdf7ee209d109600907e6bf257dd", 16) + g12To235y, _ := new(big.Int).SetString("788c41665350ffaa411f7f87eb1841dc9c55a2a2d9eee4d53074d259ff8212be1412b24ade48b6659d73a2aeef2893", 16) + g12To236x, _ := new(big.Int).SetString("f11dccf426e9213ade8c9ee90b06f3bea1e6457601318092afdb2845873962a9ebdf44d6a52517e30e2fb59d47937d", 16) + g12To236y, _ := new(big.Int).SetString("11a2c73b55ae8b0418e23694e988a586a00e7d167972e66def5b18b80f5822e0386be601d0eb553a33e2dcea9d2f304", 16) + g12To237x, _ := new(big.Int).SetString("54733fda527c1d2c1967947da26074e803c5143b267a3661439bf3f773a42a754ef55d56dbb624d2daa933656b26ca", 16) + g12To237y, _ := new(big.Int).SetString("18f358aa4576692f77586da3ea26d5fa85516181e6838a7bf7b52b586c06d9f7074c5e90e7ba1ac4a925d368d8cb981", 16) + g12To238x, _ := new(big.Int).SetString("184c780c3114f29206d1533772298961a70b6fdaeccc642335a824909cdb6f906e957dce89627d1e7716d95a2cfb46d", 16) + g12To238y, _ := new(big.Int).SetString("12d98e699809d4e11aa2e0b33a6fbfef9e22336bdd90fffa323b7e3bb30ae239089b2be9ff8058ac6c15597788af01d", 16) + g12To239x, _ := new(big.Int).SetString("1585afaee8b5f5508cae51b92a6c44c8d49cb8dbe9673c33eb981efea193d06ccc524de0dfe21c4dc0981ae129d80d", 16) + g12To239y, _ := new(big.Int).SetString("13f2a75ebdb771622fc9ced0989babf38f67dfd65a083a692514dabe83b3a97eac4e42bdb47cf6d51b8f3d5c963565f", 16) + g12To240x, _ := new(big.Int).SetString("14355642d7750cbbba97db165768632badccfb6af700fff0805d22834e97eefcf84defb444cf0273b1a9944f7e5b91", 16) + g12To240y, _ := new(big.Int).SetString("1197f01614054d77e687096e7538f6a2545b860dac56f1891056c358e42ead9a2bb48b10afac6df3fce655328a5e818", 16) + g12To241x, _ := new(big.Int).SetString("13b73e44f2659f9e3107e77dfbdf6a1ef7f9bb9f50d1edef96f72a35233da9405700d898d93db5507d52dc52889823a", 16) + g12To241y, _ := new(big.Int).SetString("16b68db42349d35537fac003e9f2bb42031b338c12f4913997c4884ffd26990afd463d337dfbb5d29eeb5fe2385e77", 16) + g12To242x, _ := new(big.Int).SetString("89a89ab5b237b3cccd3fe1dcaa534fc6568ee9d460b3ca0df9c84f9ad0af74e11d99a258d42e2fdf90c87ffb008fda", 16) + g12To242y, _ := new(big.Int).SetString("116466cbf9bc5f5cf137f3b917fb95025546af24874a181f09a3798ffc6214dd8c60ee3dc473ba4693ca0c272dd993d", 16) + g12To243x, _ := new(big.Int).SetString("1955d0dba9ad4e82d07b90e40a406188df46abdc803974b4104fff90ad95f1ae7c278690cc349c3a35dd36e67eaedd5", 16) + g12To243y, _ := new(big.Int).SetString("17f6f0f43e95cce0f3091b701119eedb0631f018c3ee3adf30e011fadb07a460c18d08db250bae2d071fef1a92a1f79", 16) + g12To244x, _ := new(big.Int).SetString("1ac41b9b7179d3b109edaae37533c2eda16f2ef82ad3b6116001e33ca216786d72d5df4eaddc275a349be1f221ef018", 16) + g12To244y, _ := new(big.Int).SetString("17007d8c32333765265165962b19a98122d21d224d1529e10776c574997401b32af137363701401acd4f8b28337da6d", 16) + g12To245x, _ := new(big.Int).SetString("1173c60965d349c342b3423e4fdd4bd8e2d9321895e2e5131e4434094a918415e8ef88daa57f29e507345caec040621", 16) + g12To245y, _ := new(big.Int).SetString("175d01ed6f7e2a7cb9866762d30756dee408e5ebc1c34a2c84b795db33f09a89ef455ba08e99d8bb2a28b9e86616c4", 16) + g12To246x, _ := new(big.Int).SetString("5c1bc8f91e383e69293368e1b57038c922347f71ea365a4db593f71074875ef0e6d432ca81c4b80ee579965cf17c93", 16) + g12To246y, _ := new(big.Int).SetString("189e095fc94cb2e838ead34306a32b40924cccc78b4a0cf28af85fbe0b54538cf8a772b75095f356a1c0ef3296f5561", 16) + g12To247x, _ := new(big.Int).SetString("8a9efcf927af9dbe6e2d4c77d29df093ef459afced7a9f097f017091ff06e4bf4d6b640966c68c10b75f1e7149a85", 16) + g12To247y, _ := new(big.Int).SetString("70805ec8649c9a7c25d21736edb523b4790d3747f1a368d21293243c6dc11c5fe79daaf07c4d63fc9d187df46fd510", 16) + g12To248x, _ := new(big.Int).SetString("16e52b1a5b5ec2b3fe5af7e76b966000583cf9670843094480b65d13a592603e9cde594a02e2415372d36d238673d8d", 16) + g12To248y, _ := new(big.Int).SetString("d5022a2983f3d3fb721884c0af2829680a18dbbd005394c5065c498ae2c6826831da4f412db24ce93ab82ade2b9000", 16) + g12To249x, _ := new(big.Int).SetString("133fcd0d44b5e9b4101193f9d001faa4f8d888b85643e479c8e6e541a9270caaa8d54d5f0bb87a1f8ec5a25cf4be6cc", 16) + g12To249y, _ := new(big.Int).SetString("19c9d609e590e4b4eaf3f48c1a7c52c5a019da645e7411ea105ef0bc3ccf4682f0ff73522747157d7468f84c7cecebc", 16) + g12To250x, _ := new(big.Int).SetString("fee78dced3f99645d6043ff6106a2427a646ce40ef8bac3664c76edbb88b6e5106ee4cfaaf5858118ed3290b75621a", 16) + g12To250y, _ := new(big.Int).SetString("3e93b344b8faf9ac5549ed35296a660bac621823591228bb54e6d19b0c7985482f37e76d3d5e4744c568529023ba9b", 16) + g12To251x, _ := new(big.Int).SetString("1190d295e06f2de4269762adc2c605d3c767055ab628933f1a3a184b691ab73b7724beb9c126974b8f4553308c6c2bb", 16) + g12To251y, _ := new(big.Int).SetString("6895ecd12c1cfcc15a05cde2e775d7387754b5e3fc43b1961f370dc28fc9b6a5602389685b7251dd0f6ee1490e99ce", 16) + g12To252x, _ := new(big.Int).SetString("13a0c4f35b617ea8aa399aac8b1c977320c28204236dc32ada1b64e7a8c79165f34ba75baef06d41918e24984c8ddfc", 16) + g12To252y, _ := new(big.Int).SetString("8f6802c76d44e816b66d17f7be4e845edf2c12caae31d9223f8b9b40dcf782b222218ca0c725116b18986661f9068c", 16) return CurvePoints{ - Gx: gx, - Gy: gy, + G1x: g1x, + G1y: g1y, - Gmx: [253]*big.Int{g3x, g5x, g7x, g2To3x, g2To4x, g2To5x, g2To6x, g2To7x, g2To8x, g2To9x, g2To10x, g2To11x, g2To12x, g2To13x, g2To14x, g2To15x, g2To16x, g2To17x, g2To18x, g2To19x, g2To20x, g2To21x, g2To22x, g2To23x, g2To24x, g2To25x, g2To26x, g2To27x, g2To28x, g2To29x, g2To30x, g2To31x, g2To32x, g2To33x, g2To34x, g2To35x, g2To36x, g2To37x, g2To38x, g2To39x, g2To40x, g2To41x, g2To42x, g2To43x, g2To44x, g2To45x, g2To46x, g2To47x, g2To48x, g2To49x, g2To50x, g2To51x, g2To52x, g2To53x, g2To54x, g2To55x, g2To56x, g2To57x, g2To58x, g2To59x, g2To60x, g2To61x, g2To62x, g2To63x, g2To64x, g2To65x, g2To66x, g2To67x, g2To68x, g2To69x, g2To70x, g2To71x, g2To72x, g2To73x, g2To74x, g2To75x, g2To76x, g2To77x, g2To78x, g2To79x, g2To80x, g2To81x, g2To82x, g2To83x, g2To84x, g2To85x, g2To86x, g2To87x, g2To88x, g2To89x, g2To90x, g2To91x, g2To92x, g2To93x, g2To94x, g2To95x, g2To96x, g2To97x, g2To98x, g2To99x, g2To100x, g2To101x, g2To102x, g2To103x, g2To104x, g2To105x, g2To106x, g2To107x, g2To108x, g2To109x, g2To110x, g2To111x, g2To112x, g2To113x, g2To114x, g2To115x, g2To116x, g2To117x, g2To118x, g2To119x, g2To120x, g2To121x, g2To122x, g2To123x, g2To124x, g2To125x, g2To126x, g2To127x, g2To128x, g2To129x, g2To130x, g2To131x, g2To132x, g2To133x, g2To134x, g2To135x, g2To136x, g2To137x, g2To138x, g2To139x, g2To140x, g2To141x, g2To142x, g2To143x, g2To144x, g2To145x, g2To146x, g2To147x, g2To148x, g2To149x, g2To150x, g2To151x, g2To152x, g2To153x, g2To154x, g2To155x, g2To156x, g2To157x, g2To158x, g2To159x, g2To160x, g2To161x, g2To162x, g2To163x, g2To164x, g2To165x, g2To166x, g2To167x, g2To168x, g2To169x, g2To170x, g2To171x, g2To172x, g2To173x, g2To174x, g2To175x, g2To176x, g2To177x, g2To178x, g2To179x, g2To180x, g2To181x, g2To182x, g2To183x, g2To184x, g2To185x, g2To186x, g2To187x, g2To188x, g2To189x, g2To190x, g2To191x, g2To192x, g2To193x, g2To194x, g2To195x, g2To196x, g2To197x, g2To198x, g2To199x, g2To200x, g2To201x, g2To202x, g2To203x, g2To204x, g2To205x, g2To206x, g2To207x, g2To208x, g2To209x, g2To210x, g2To211x, g2To212x, g2To213x, g2To214x, g2To215x, g2To216x, g2To217x, g2To218x, g2To219x, g2To220x, g2To221x, g2To222x, g2To223x, g2To224x, g2To225x, g2To226x, g2To227x, g2To228x, g2To229x, g2To230x, g2To231x, g2To232x, g2To233x, g2To234x, g2To235x, g2To236x, g2To237x, g2To238x, g2To239x, g2To240x, g2To241x, g2To242x, g2To243x, g2To244x, g2To245x, g2To246x, g2To247x, g2To248x, g2To249x, g2To250x, g2To251x, g2To252x}, - Gmy: [253]*big.Int{g3y, g5y, g7y, g2To3y, g2To4y, g2To5y, g2To6y, g2To7y, g2To8y, g2To9y, g2To10y, g2To11y, g2To12y, g2To13y, g2To14y, g2To15y, g2To16y, g2To17y, g2To18y, g2To19y, g2To20y, g2To21y, g2To22y, g2To23y, g2To24y, g2To25y, g2To26y, g2To27y, g2To28y, g2To29y, g2To30y, g2To31y, g2To32y, g2To33y, g2To34y, g2To35y, g2To36y, g2To37y, g2To38y, g2To39y, g2To40y, g2To41y, g2To42y, g2To43y, g2To44y, g2To45y, g2To46y, g2To47y, g2To48y, g2To49y, g2To50y, g2To51y, g2To52y, g2To53y, g2To54y, g2To55y, g2To56y, g2To57y, g2To58y, g2To59y, g2To60y, g2To61y, g2To62y, g2To63y, g2To64y, g2To65y, g2To66y, g2To67y, g2To68y, g2To69y, g2To70y, g2To71y, g2To72y, g2To73y, g2To74y, g2To75y, g2To76y, g2To77y, g2To78y, g2To79y, g2To80y, g2To81y, g2To82y, g2To83y, g2To84y, g2To85y, g2To86y, g2To87y, g2To88y, g2To89y, g2To90y, g2To91y, g2To92y, g2To93y, g2To94y, g2To95y, g2To96y, g2To97y, g2To98y, g2To99y, g2To100y, g2To101y, g2To102y, g2To103y, g2To104y, g2To105y, g2To106y, g2To107y, g2To108y, g2To109y, g2To110y, g2To111y, g2To112y, g2To113y, g2To114y, g2To115y, g2To116y, g2To117y, g2To118y, g2To119y, g2To120y, g2To121y, g2To122y, g2To123y, g2To124y, g2To125y, g2To126y, g2To127y, g2To128y, g2To129y, g2To130y, g2To131y, g2To132y, g2To133y, g2To134y, g2To135y, g2To136y, g2To137y, g2To138y, g2To139y, g2To140y, g2To141y, g2To142y, g2To143y, g2To144y, g2To145y, g2To146y, g2To147y, g2To148y, g2To149y, g2To150y, g2To151y, g2To152y, g2To153y, g2To154y, g2To155y, g2To156y, g2To157y, g2To158y, g2To159y, g2To160y, g2To161y, g2To162y, g2To163y, g2To164y, g2To165y, g2To166y, g2To167y, g2To168y, g2To169y, g2To170y, g2To171y, g2To172y, g2To173y, g2To174y, g2To175y, g2To176y, g2To177y, g2To178y, g2To179y, g2To180y, g2To181y, g2To182y, g2To183y, g2To184y, g2To185y, g2To186y, g2To187y, g2To188y, g2To189y, g2To190y, g2To191y, g2To192y, g2To193y, g2To194y, g2To195y, g2To196y, g2To197y, g2To198y, g2To199y, g2To200y, g2To201y, g2To202y, g2To203y, g2To204y, g2To205y, g2To206y, g2To207y, g2To208y, g2To209y, g2To210y, g2To211y, g2To212y, g2To213y, g2To214y, g2To215y, g2To216y, g2To217y, g2To218y, g2To219y, g2To220y, g2To221y, g2To222y, g2To223y, g2To224y, g2To225y, g2To226y, g2To227y, g2To228y, g2To229y, g2To230y, g2To231y, g2To232y, g2To233y, g2To234y, g2To235y, g2To236y, g2To237y, g2To238y, g2To239y, g2To240y, g2To241y, g2To242y, g2To243y, g2To244y, g2To245y, g2To246y, g2To247y, g2To248y, g2To249y, g2To250y, g2To251y, g2To252y}, + G1mx: [253]*big.Int{g13x, g15x, g17x, g12To3x, g12To4x, g12To5x, g12To6x, g12To7x, g12To8x, g12To9x, g12To10x, g12To11x, g12To12x, g12To13x, g12To14x, g12To15x, g12To16x, g12To17x, g12To18x, g12To19x, g12To20x, g12To21x, g12To22x, g12To23x, g12To24x, g12To25x, g12To26x, g12To27x, g12To28x, g12To29x, g12To30x, g12To31x, g12To32x, g12To33x, g12To34x, g12To35x, g12To36x, g12To37x, g12To38x, g12To39x, g12To40x, g12To41x, g12To42x, g12To43x, g12To44x, g12To45x, g12To46x, g12To47x, g12To48x, g12To49x, g12To50x, g12To51x, g12To52x, g12To53x, g12To54x, g12To55x, g12To56x, g12To57x, g12To58x, g12To59x, g12To60x, g12To61x, g12To62x, g12To63x, g12To64x, g12To65x, g12To66x, g12To67x, g12To68x, g12To69x, g12To70x, g12To71x, g12To72x, g12To73x, g12To74x, g12To75x, g12To76x, g12To77x, g12To78x, g12To79x, g12To80x, g12To81x, g12To82x, g12To83x, g12To84x, g12To85x, g12To86x, g12To87x, g12To88x, g12To89x, g12To90x, g12To91x, g12To92x, g12To93x, g12To94x, g12To95x, g12To96x, g12To97x, g12To98x, g12To99x, g12To100x, g12To101x, g12To102x, g12To103x, g12To104x, g12To105x, g12To106x, g12To107x, g12To108x, g12To109x, g12To110x, g12To111x, g12To112x, g12To113x, g12To114x, g12To115x, g12To116x, g12To117x, g12To118x, g12To119x, g12To120x, g12To121x, g12To122x, g12To123x, g12To124x, g12To125x, g12To126x, g12To127x, g12To128x, g12To129x, g12To130x, g12To131x, g12To132x, g12To133x, g12To134x, g12To135x, g12To136x, g12To137x, g12To138x, g12To139x, g12To140x, g12To141x, g12To142x, g12To143x, g12To144x, g12To145x, g12To146x, g12To147x, g12To148x, g12To149x, g12To150x, g12To151x, g12To152x, g12To153x, g12To154x, g12To155x, g12To156x, g12To157x, g12To158x, g12To159x, g12To160x, g12To161x, g12To162x, g12To163x, g12To164x, g12To165x, g12To166x, g12To167x, g12To168x, g12To169x, g12To170x, g12To171x, g12To172x, g12To173x, g12To174x, g12To175x, g12To176x, g12To177x, g12To178x, g12To179x, g12To180x, g12To181x, g12To182x, g12To183x, g12To184x, g12To185x, g12To186x, g12To187x, g12To188x, g12To189x, g12To190x, g12To191x, g12To192x, g12To193x, g12To194x, g12To195x, g12To196x, g12To197x, g12To198x, g12To199x, g12To200x, g12To201x, g12To202x, g12To203x, g12To204x, g12To205x, g12To206x, g12To207x, g12To208x, g12To209x, g12To210x, g12To211x, g12To212x, g12To213x, g12To214x, g12To215x, g12To216x, g12To217x, g12To218x, g12To219x, g12To220x, g12To221x, g12To222x, g12To223x, g12To224x, g12To225x, g12To226x, g12To227x, g12To228x, g12To229x, g12To230x, g12To231x, g12To232x, g12To233x, g12To234x, g12To235x, g12To236x, g12To237x, g12To238x, g12To239x, g12To240x, g12To241x, g12To242x, g12To243x, g12To244x, g12To245x, g12To246x, g12To247x, g12To248x, g12To249x, g12To250x, g12To251x, g12To252x}, + G1my: [253]*big.Int{g13y, g15y, g17y, g12To3y, g12To4y, g12To5y, g12To6y, g12To7y, g12To8y, g12To9y, g12To10y, g12To11y, g12To12y, g12To13y, g12To14y, g12To15y, g12To16y, g12To17y, g12To18y, g12To19y, g12To20y, g12To21y, g12To22y, g12To23y, g12To24y, g12To25y, g12To26y, g12To27y, g12To28y, g12To29y, g12To30y, g12To31y, g12To32y, g12To33y, g12To34y, g12To35y, g12To36y, g12To37y, g12To38y, g12To39y, g12To40y, g12To41y, g12To42y, g12To43y, g12To44y, g12To45y, g12To46y, g12To47y, g12To48y, g12To49y, g12To50y, g12To51y, g12To52y, g12To53y, g12To54y, g12To55y, g12To56y, g12To57y, g12To58y, g12To59y, g12To60y, g12To61y, g12To62y, g12To63y, g12To64y, g12To65y, g12To66y, g12To67y, g12To68y, g12To69y, g12To70y, g12To71y, g12To72y, g12To73y, g12To74y, g12To75y, g12To76y, g12To77y, g12To78y, g12To79y, g12To80y, g12To81y, g12To82y, g12To83y, g12To84y, g12To85y, g12To86y, g12To87y, g12To88y, g12To89y, g12To90y, g12To91y, g12To92y, g12To93y, g12To94y, g12To95y, g12To96y, g12To97y, g12To98y, g12To99y, g12To100y, g12To101y, g12To102y, g12To103y, g12To104y, g12To105y, g12To106y, g12To107y, g12To108y, g12To109y, g12To110y, g12To111y, g12To112y, g12To113y, g12To114y, g12To115y, g12To116y, g12To117y, g12To118y, g12To119y, g12To120y, g12To121y, g12To122y, g12To123y, g12To124y, g12To125y, g12To126y, g12To127y, g12To128y, g12To129y, g12To130y, g12To131y, g12To132y, g12To133y, g12To134y, g12To135y, g12To136y, g12To137y, g12To138y, g12To139y, g12To140y, g12To141y, g12To142y, g12To143y, g12To144y, g12To145y, g12To146y, g12To147y, g12To148y, g12To149y, g12To150y, g12To151y, g12To152y, g12To153y, g12To154y, g12To155y, g12To156y, g12To157y, g12To158y, g12To159y, g12To160y, g12To161y, g12To162y, g12To163y, g12To164y, g12To165y, g12To166y, g12To167y, g12To168y, g12To169y, g12To170y, g12To171y, g12To172y, g12To173y, g12To174y, g12To175y, g12To176y, g12To177y, g12To178y, g12To179y, g12To180y, g12To181y, g12To182y, g12To183y, g12To184y, g12To185y, g12To186y, g12To187y, g12To188y, g12To189y, g12To190y, g12To191y, g12To192y, g12To193y, g12To194y, g12To195y, g12To196y, g12To197y, g12To198y, g12To199y, g12To200y, g12To201y, g12To202y, g12To203y, g12To204y, g12To205y, g12To206y, g12To207y, g12To208y, g12To209y, g12To210y, g12To211y, g12To212y, g12To213y, g12To214y, g12To215y, g12To216y, g12To217y, g12To218y, g12To219y, g12To220y, g12To221y, g12To222y, g12To223y, g12To224y, g12To225y, g12To226y, g12To227y, g12To228y, g12To229y, g12To230y, g12To231y, g12To232y, g12To233y, g12To234y, g12To235y, g12To236y, g12To237y, g12To238y, g12To239y, g12To240y, g12To241y, g12To242y, g12To243y, g12To244y, g12To245y, g12To246y, g12To247y, g12To248y, g12To249y, g12To250y, g12To251y, g12To252y}, } } + +type TwistPoints struct { + G2x0 *big.Int // base point x + G2x1 *big.Int // base point x + G2y0 *big.Int // base point y + G2y1 *big.Int // base point y + G2mx0 [253]*big.Int // m*base point x0 + G2mx1 [253]*big.Int // m*base point x1 + G2my0 [253]*big.Int // m*base point y0 + G2my1 [253]*big.Int // m*base point y1 +} + +func GetBLS12377TwistPoints() TwistPoints { + g2x0, _ := new(big.Int).SetString("18480be71c785fec89630a2a3841d01c565f071203e50317ea501f557db6b9b71889f52bb53540274e3e48f7c005196", 16) + g2x1, _ := new(big.Int).SetString("ea6040e700403170dc5a51b1b140d5532777ee6651cecbe7223ece0799c9de5cf89984bff76fe6b26bfefa6ea16afe", 16) + g2y0, _ := new(big.Int).SetString("690d665d446f7bd960736bcbb2efb4de03ed7274b49a58e458c282f832d204f2cf88886d8c7c2ef094094409fd4ddf", 16) + g2y1, _ := new(big.Int).SetString("f8169fd28355189e549da3151a70aa61ef11ac3d591bf12463b01acee304c24279b83f5e52270bd9a1cdd185eb8f93", 16) + g23x0, _ := new(big.Int).SetString("10989ed742d307e93acdd3ef1a3680e0bb12886bc4ee3fca003f51b04dc60ea6ff6d482b888da1601f96e4acccdeb2a", 16) + g23x1, _ := new(big.Int).SetString("69c7a695505c5042f73f3f69027e0f97c21244c0fd397209582ac6f6f58d1a8b1e6118d9550c7f3d81a461fd12b64c", 16) + g23y0, _ := new(big.Int).SetString("191cd587c9c65903e2cc24a5b031bb76ac23a2968294c604aa74e4574c8b60754fdb3abc99d7dd35707109e4f98c99a", 16) + g23y1, _ := new(big.Int).SetString("4ffd6a638c1b4eeba9769cee5a2ef0e87bbd284704f4ee4870771ad3dbf7510c7799240851ea08209d1ea57c8e2f5a", 16) + g25x0, _ := new(big.Int).SetString("dee4599c0dfec75b85f181ad4ad7c6d220539aa199ff5cef404593273076f21a7edc6de5e2659619e42685605949ee", 16) + g25x1, _ := new(big.Int).SetString("1fb7aac7d4a7034251c904f1304fdf183465e17424a6f6d57f4dc89ab74935f9cf0666aa9d0b80b114feb90f8ee744", 16) + g25y0, _ := new(big.Int).SetString("12af400a1adf1aa920bb79f091e8a28031ee76f6176d9e5ddcd6adae01874e9eddfe1b437efdbf8770a31609116db1a", 16) + g25y1, _ := new(big.Int).SetString("69babca211bf7b049fa5a1446955793f13a916a5c3a542ce016ca6bac631e86ed4f3060406025fa5f10ca06222d98f", 16) + g27x0, _ := new(big.Int).SetString("140f206987ef5eaaf9698aa46ecda04e79abbcbf4179d039224f78a14b59894f3218e0565fc9bd57bc06707f828e729", 16) + g27x1, _ := new(big.Int).SetString("18c1f631463ba7a011c2487841e341a50c4c47be271fd206347e1a6b19da6707f25723da99b827267b226bb6a8ec2dc", 16) + g27y0, _ := new(big.Int).SetString("16e1f5c9a922f928dc069601cf988df26e766a3f64f472bae97cc99dacd0cd593e0269b5c16b773e5ea4cc652c4f4bc", 16) + g27y1, _ := new(big.Int).SetString("af3a712608d508f1adb1c63264a1ba1dd87fe094b643c2c88177a45828a33d8a223ea2c154c247444a010bbfd57311", 16) + g22To3x0, _ := new(big.Int).SetString("12f5e069064c44f6bbb7fcf49b8f1f7bd3fc26228250e50a9358700418a9f2f6d5edc7ef26e8f5ad2547179ca480654", 16) + g22To3x1, _ := new(big.Int).SetString("e84a4d39433ddf62fc22c00f5638ba238757208c08925f7f820a8b2e8a4feb1265fab17dfd0680fad4852a48136431", 16) + g22To3y0, _ := new(big.Int).SetString("147b999363dd973ef30ea09490d512c2cfd38af634198cad2da7be80f547caa51a025a57e5bc55aba5072523da80286", 16) + g22To3y1, _ := new(big.Int).SetString("2beb4a3f2fde9ba09104e96264bf931293f16650c5cad6f74d7ed858dc6bf797d15f3e35cbeb9e784ae913b5b219d1", 16) + g22To4x0, _ := new(big.Int).SetString("8effe15bb484c716ebd3e58b10d96a40351ce1386db2d07371c3e17b79f45a2957f2ba316ddfbf2180494602e222f2", 16) + g22To4x1, _ := new(big.Int).SetString("13859ab95f4a14caf37ed638410ce11d45cdc8fb9e14bbaf4052596b42218e1aba8bfa427f932af88ccfb76f2c533f3", 16) + g22To4y0, _ := new(big.Int).SetString("c8e82def66465b27d678352a0b8cf4d2570e9a8c169c7f7ff1c9ab718862cdf97f1891aef725cea218cb79ff7de8ba", 16) + g22To4y1, _ := new(big.Int).SetString("6e6e163fbd111cbb29722fa4fcd425af241addc28220cf3de8ee0337d46d95556f2344d47c80b2fca05adf8fefce9b", 16) + g22To5x0, _ := new(big.Int).SetString("11cf999d9e3baa60a66c68b4ddd3e0daa8c18eac38a538cb936054d2986814f66ec2fbd579041f36a71ffc32482c441", 16) + g22To5x1, _ := new(big.Int).SetString("7552f8a6c70b31e068d88374a8ba1b75aba13b9e324fc8569c23a97e5b5250b2a74efa4a8667c50ba2923a17ef65eb", 16) + g22To5y0, _ := new(big.Int).SetString("814b87a592f0054fa6f293db2439b13171d94e758adda863a61702b22df78e2554754cde7638a26a757295e5e2d2c4", 16) + g22To5y1, _ := new(big.Int).SetString("f75582d5ace6be7aeeb116787666a4d053b05654f22075f4a109e2ab54164b6e45e526f854c356d1025dca4d5ff721", 16) + g22To6x0, _ := new(big.Int).SetString("1e39bbafad1fedf4757b2595cbb34f41e6a3abd0d57a5af1d2dc9b98a663863bcffabfc0986ab4b10546c038b1dcb1", 16) + g22To6x1, _ := new(big.Int).SetString("47fcd0f33ddb5da867e023d7ccfb58b758bd74acc4d9cf648a1acdffcc7d7a27b8d868fafecd00f3f07a18c7907dd0", 16) + g22To6y0, _ := new(big.Int).SetString("12a50239879e229aa23c146f16b1e504e4cb3f1afa73873caf0de6d64d84a3cf89852595b7a44478d6a30ad6445d69d", 16) + g22To6y1, _ := new(big.Int).SetString("29eb007d42fed95c103084eeec01ccdb7511717ac33cbdb4b4a1e52ebf3227724d9a08091f4ae9b8c27d86edc56ad2", 16) + g22To7x0, _ := new(big.Int).SetString("12950600cdfffaf34d639580fb98c007b122b54f18ac59fa2b398125c8a6d3c4b7f63706e8eaf5891d4b98d9275733d", 16) + g22To7x1, _ := new(big.Int).SetString("f9a82f822549931056e3f3e5692149503b488aa5ac7c2b545108f7947f6b37f91856ff94d093d87c17e41719e4e63a", 16) + g22To7y0, _ := new(big.Int).SetString("1d1caa73f44d96df5dc74ac6a0e5bcb0b24234bb12eeff0be0c2f65cea74fe9e1dc626ce0225608957bc2f8484385d", 16) + g22To7y1, _ := new(big.Int).SetString("d4f0d64b400203912711a00208f02fd900dfb7b99555a98491449e51ac01dea06b726d30603b5786b438695baa3a82", 16) + g22To8x0, _ := new(big.Int).SetString("3de403c785305f79e59eb82ac0a3d7fcea96ff9de04a12bdfdc7e17c11a73d7fd2f88f602ea654e2cd74554c13c3cb", 16) + g22To8x1, _ := new(big.Int).SetString("1799deda9f502a0d6c72b1232af7c0c12f9317d9620a565f61da043e6210e0676ee06a91983df260c13408a17beb220", 16) + g22To8y0, _ := new(big.Int).SetString("ea526f8c945290f17e233052609f33a3692bdacdbd8bb25ec4cbb4c8925a7c5401747d93e663b14d16dcfffdcdaef2", 16) + g22To8y1, _ := new(big.Int).SetString("2748e0d45be676e07d5bef7efaa46e44bea276b25c4675d7c61dca0b2092d63821e2b6517c2840266e0cc4b52883b1", 16) + g22To9x0, _ := new(big.Int).SetString("19adf058d65aefbcd7b5d02c230627b6b3a1a0b9b74cb7de927ff4de31b6fece1f6b7843e2944ccea35f018524cefad", 16) + g22To9x1, _ := new(big.Int).SetString("15c44caf3ed39760e66bce1fabc8ac8a59490b26a5d85d9712db0d99265642695257c7525f79dd037f15c5ae9391f8", 16) + g22To9y0, _ := new(big.Int).SetString("edbdaa165a52c9a62702d2018cd32c102b1567effef73429479512e41f34e9a43e53339594a83974a0589f4fa4fe27", 16) + g22To9y1, _ := new(big.Int).SetString("80cd4d53eab6d7d668dc963dfa0e18c34e86805877169b98188a3a895ab44d6f992714942648ffd34d704cf955a261", 16) + g22To10x0, _ := new(big.Int).SetString("a8e803e07b76357e9a2a8eec1b173dbfb8b71301740737a8c29d1b2f5e37d074cfc9d5b40c6e4a6b93345d957fbf07", 16) + g22To10x1, _ := new(big.Int).SetString("1a20236744d0b3173ad4ab380783ec784cd2b50e4dd051cb1b49056fc9197c83387bdfe79800174cc6dc0d1429b4b2e", 16) + g22To10y0, _ := new(big.Int).SetString("137dee5b26f1b7538a9d369bc88d0fceef9a64af39c6e2854288a251ff466c17f45f972a5b4edde1638ede7628b1179", 16) + g22To10y1, _ := new(big.Int).SetString("11cb8c99dd080d4c728d8690266d12af4de2c48662f0f82f8e33a195e9d262cfd6268285a4a42fc0d89136646bd4198", 16) + g22To11x0, _ := new(big.Int).SetString("abadfbeecce6fc90d0cb1fe7696fe56e6bfbccef068f67244bd5d2c83dcc26bfae60c2a30aab449b70ce1dd270c5e8", 16) + g22To11x1, _ := new(big.Int).SetString("c9052fe78ebe75b7fa99f24ca3ca20af4e39b68d11d78636727f6f4aed9926f03800859fbf016a23e3aaff8e17b285", 16) + g22To11y0, _ := new(big.Int).SetString("d799913fe584af4a12d3e5959473c938dc6b38bd2968e0007a4f81a77d05444093254ee65f4ca41b9a7008f37aa221", 16) + g22To11y1, _ := new(big.Int).SetString("1326a327ec5614f3fb1b0f8fc93f45eea65e6335de14fd535780bf4f462fad683eb4e9d3fded42a5940f890df5993de", 16) + g22To12x0, _ := new(big.Int).SetString("16b0671fd5344d612e1bdac46df9eff8065baef6fd99f469a1b1e3d985f61fa2b02025c287548b3b64a4d2d26375a83", 16) + g22To12x1, _ := new(big.Int).SetString("10d2132d8dd55879cc1b40e6ef19bb1b6a05a8537e5d1536d4245265eec0cf0da4f05a219b13655bfc278b13a8a7d7a", 16) + g22To12y0, _ := new(big.Int).SetString("c24f8bed9e0e7e496455604d1fff6043141e3eb68e3bba0d8bd3cdb441bd6febfc844ba6db2f7de549cd01104bcd10", 16) + g22To12y1, _ := new(big.Int).SetString("140445167894cf4b3fa1139431cfdc94d529666e70988804fc70ea478a0427e9fe38bb6c6899b1e22a995c9cb426d19", 16) + g22To13x0, _ := new(big.Int).SetString("160ea6b124d79e95abead2958f985312f13b5606af895e50320bb83c4ab303f6478a228de33b1e0c40535842a76c1d4", 16) + g22To13x1, _ := new(big.Int).SetString("17513c8a2cda894c9607d728e1af448c701db9017dc653b6664f48470642279b649a26b7043ebd9f2a81dc58633a6ab", 16) + g22To13y0, _ := new(big.Int).SetString("e98bfd3883a8f107d08e5bec3aea9722bf66cfd7b3907f4ede8b84f274118b3b0045b013ba689d0d54210a26cd7c80", 16) + g22To13y1, _ := new(big.Int).SetString("114eb083ea66e1403d1b89a4e375e80d849af0de61d29165f13fe69c2348e9b61a7dcb956e543ddd4045af0b189a7ce", 16) + g22To14x0, _ := new(big.Int).SetString("de1654d81177ba984e02c0d88d2fceffedc11f45511939c909043364ae3edd6aa51d6325ff5074fc6d09665417a9fb", 16) + g22To14x1, _ := new(big.Int).SetString("1e8439dbc7a8de80abffd6949efe6b8308fd10f6f730ffd586bc0a5838f505d9833d1c2cf1328bd5ed81ae16ad4995", 16) + g22To14y0, _ := new(big.Int).SetString("a7acf9a3df51c95b50516ab06b09649ef6944530e5adab8369e15dda3bfcdfa9906f64d8f2320670895756d41b1aaa", 16) + g22To14y1, _ := new(big.Int).SetString("e1a8e22d5b004506a3a298df7d3defe2ed0beeebfd78fe65ddffe1d64f9738e7e45014ccfc0debea4db0c749064eab", 16) + g22To15x0, _ := new(big.Int).SetString("10c70577d4310643681536cf7ba7a13e6085a04f42d1894bee65431813646f14298fb561b63acab77631b3eb374aa13", 16) + g22To15x1, _ := new(big.Int).SetString("167121005cf185e638605dd7ab198c379b5d7905d787256056c6497c6ebe1ab5b6b82805625fbb53c7dafefa955183f", 16) + g22To15y0, _ := new(big.Int).SetString("c3ee9dc727ff9fc8eb45cb338ecf5d41e6419ae6b59cec26d6009e06bd8e46a08a4d2bebb9bc8074e22c55e773e227", 16) + g22To15y1, _ := new(big.Int).SetString("146addeedac5da862e21b7e1346c9940895bb12c3b9a1933dbe601fb6d792d347c4d764ea0274df8a161d445d2331c1", 16) + g22To16x0, _ := new(big.Int).SetString("277ecdf734f7d8bb54d81d926bc9d8825e00263122598aba2e3c7897b4f2b2fabb56eede81351ae8124f8687f6d9d7", 16) + g22To16x1, _ := new(big.Int).SetString("369c77b06cd39c8fa63a4d6e93d8be88dd9729b7d654c745ebdfa39a9163facf95bcac1e060572c713dec3cc15c6fd", 16) + g22To16y0, _ := new(big.Int).SetString("c3823aa2d90cfe8d394263f5a5742959be02999941203d3464d1a32fc2d2afe0fee1680ca003b1c1c1db9cc855456", 16) + g22To16y1, _ := new(big.Int).SetString("170ea235bdd969ecdac824259891897b4d47f424b59e5c3adb0d2150b37c08a49f2453cc66c717c44b24b54b435e420", 16) + g22To17x0, _ := new(big.Int).SetString("c99dd3c2ac74d8b17b87cd187ec66ce411566eac353fcbe01834ba2f876de662abffb19fd37c85be1e59c72f33384a", 16) + g22To17x1, _ := new(big.Int).SetString("b43460420042bbd15095d3bd42a55e6c932704af6671a1317f2ad781d929384de6e8bacc4cefc0ad3bf73c3e114d74", 16) + g22To17y0, _ := new(big.Int).SetString("d015978f6517cbf720051c789e15acc1e64cc5eed6aceed867a5eb92bc62bb84f0ba25a0fcc02c172464f7031bf9d9", 16) + g22To17y1, _ := new(big.Int).SetString("e21ffd0bd2c0158f8d510ece087179af97f4cda168414697aced2e7e4d3bb672e3b89cb3c1143db3b644955ebb78ab", 16) + g22To18x0, _ := new(big.Int).SetString("170a754724c6f0a5ba9b83851361cd6c99172a8eda8e9761a7c206ee3ee6ff1749fec7075743f21e2058620eae00cbc", 16) + g22To18x1, _ := new(big.Int).SetString("13955d1bab3aca0b685c24abe4ec2f5174892b193213de7d73ea1db62bdf5a330538feba6e0ec3b3911b3253d278904", 16) + g22To18y0, _ := new(big.Int).SetString("16bb6c53936acd0cc847c199f6122c57469a4cd5d7dfe0921d5873d5f86d3cdef13db5395f14d9f410f4c2ed6edd5f", 16) + g22To18y1, _ := new(big.Int).SetString("da59d695c7c45a874e4bd2bd742a27ec148a4ba2cd7f5d816cf7f8cec7cbd60fc80b65bde3e0e8a1c26c968205d069", 16) + g22To19x0, _ := new(big.Int).SetString("1a993a512f398bb265b918475d1f1d17e6651f6f7b80a684b90811cf4b18a8f4149367d27eff97c5e3ef5f6318ae75e", 16) + g22To19x1, _ := new(big.Int).SetString("198ee87aadbe5970dca24e4d501681539cd153fd58843db0bd82773e259c3bb94d9ef28c3353e0818b157c798b27073", 16) + g22To19y0, _ := new(big.Int).SetString("1456cff762f88c5ea9e8df9c26748b175c021b14022ca084e2a5215e328bcd6bdf91623243a54e106d143d6b54230c7", 16) + g22To19y1, _ := new(big.Int).SetString("585a875a23fa8688bd10cd8b32d4523c0c44978c9d68dcd126cdaf3a00fb3d64ad11ac9e2111dfaa47a597a5ce07f2", 16) + g22To20x0, _ := new(big.Int).SetString("c1060ff2e135a34dbf8d35ed85d2fe246da8c867983de83590c4caf1edd5b1d17a98526b77c307a8af05183b5af1f8", 16) + g22To20x1, _ := new(big.Int).SetString("7af14740987e9af9e3291a62b06e40d59ed5734d0f4e936e29d1bf28ed27253399bff412fd09fbc240e84fc00b6f34", 16) + g22To20y0, _ := new(big.Int).SetString("16be5e4c0374f4a06d8b56a0cc554db53c81f0ebac202bb025dbc55ed8184c004b4a381c0400d926722c76f655a1e1f", 16) + g22To20y1, _ := new(big.Int).SetString("7ccddc31c6210cb04d2ff180578919b9ecd6bdc8b2eb7fb435f4f3f295cfadb7814728ff4c72f50a551889d0020f7e", 16) + g22To21x0, _ := new(big.Int).SetString("e896461817dc205f31e0a7246076dec0e025999b2960e56b54aec8ee263ae1cb1ff6b6eb3fe9ef374727e5b982b525", 16) + g22To21x1, _ := new(big.Int).SetString("156cf7c802010ab47ae6afde1fa7a6ac0550ed6eadccae63f045ca8b04bc30b09d549ae1fec2057648a16cfb82e6072", 16) + g22To21y0, _ := new(big.Int).SetString("830a8f5b519c3fc54b4e0db3d9a8206a59f0ffa35bfababcd9dfc90fd30e7fd16c05a75ab9cd74db4dbef0cd88084a", 16) + g22To21y1, _ := new(big.Int).SetString("1079cf245699cb058b76d3b8eda6c4c774f015263c479a96b7c297a942d975b4150f5912ed8c0e805012757bfe733e2", 16) + g22To22x0, _ := new(big.Int).SetString("4703638b7729037a2ad9da30cc15800df92624fc57cae4bc6eaf1a727458eb1b44b3ebbdd9b2041f9a14226ca8fc52", 16) + g22To22x1, _ := new(big.Int).SetString("13e0a8fcbaefe05e6f889f48f247407222a7f27766a663146ea3f264dfe37d95764d5709ee4949a1558f3c457cb119e", 16) + g22To22y0, _ := new(big.Int).SetString("1859896a24a3e277b5d0f3ffed9075651998a0971543cfc40a9f0d3e6f533098a1b0169fd547fb3b75868d146c93bc0", 16) + g22To22y1, _ := new(big.Int).SetString("83b05c6c75424d3c8fa42b735c78018c291210571c273d5c21b6141d54d33a21a11b92a450dd35f87553b3949eece0", 16) + g22To23x0, _ := new(big.Int).SetString("d85acb2eea8dba429004ae1d475edbd1be7e750e21a0cde31208344398bc8fb4ffa34bb12c00032934b70ffd635829", 16) + g22To23x1, _ := new(big.Int).SetString("e194ea812428c1f04823c23619b6b5e788b70f722141fb876805798d65db87fc3ca702e357f6f70f6c16aa4043d99d", 16) + g22To23y0, _ := new(big.Int).SetString("8ffe743115002b9e70b229ce28c25b043e4e199d7db30e1beb024da231daaf60cbadfa0291fa0a33442aef8775ff23", 16) + g22To23y1, _ := new(big.Int).SetString("f6a816973f80d8fd3644ac9776e027ef4964e0fef56cc5d1826ec1362b34248b7b15d8df67edfbe07d3d0c55fd489a", 16) + g22To24x0, _ := new(big.Int).SetString("1334f92c69b0c0ecaa8866050189cd5beff27879c63d6b7f1a371660c3b52ab76e3c80743ae6e0fd5d1eb1844efca7f", 16) + g22To24x1, _ := new(big.Int).SetString("773baf6bfe61e4f596ea0f1df3270be5fd1ffab4bf5fa3462a961f12536ab4867bb72be600a11403a09eec6e5d22fb", 16) + g22To24y0, _ := new(big.Int).SetString("1c48cb073300bf742629e289e58c1ac5152786e8f655ae21b0255b82b806d1c98a3ec69c8e26718b05b8945790b229", 16) + g22To24y1, _ := new(big.Int).SetString("42aeb0add0c216c4c4113c9c99496d3151dd0495ecd550672a10e9e718475644477510ec61bd5ab5949be396aaf192", 16) + g22To25x0, _ := new(big.Int).SetString("ce9f7d851983fae51e3683aea9caba3e1fbd1814d04bf236b69871f40ac95ac1394d2c3e8e545211f720546233a37a", 16) + g22To25x1, _ := new(big.Int).SetString("156aaff406e7c7a21f959f27206b29fbfb1e515f0bae5f5f6cd3690aa61102d4222f5eb685f097ddfe10df1c0ccbfc0", 16) + g22To25y0, _ := new(big.Int).SetString("2c54abb20c95f0ed43de472e17cbaaacd1649765c2665a2704d23b3d5d01d98c31159c26cfa699b2e92bb2e460cd", 16) + g22To25y1, _ := new(big.Int).SetString("14c25adca1d7b02b8155dd867f9efaebeb1d720f2cbd00383321be1d3e6403da91835308e91ef6db786e4f02a22549e", 16) + g22To26x0, _ := new(big.Int).SetString("15001e7ecc37bae4befb9454970069eb6ec9ea58ef49ac3c3e381de57399b5eddd893af1779e3936dc40ccb39fe25f1", 16) + g22To26x1, _ := new(big.Int).SetString("1892f5bedd5c0614cd7305ff64b8733718c5c89202b93067398c26476215b09effabf495663727960f2c46b95c04bdb", 16) + g22To26y0, _ := new(big.Int).SetString("10f7aa01eb848efd9b3de430b0f6507017549201d859f2f80444edf69470d8bd05d9e81d23485f5b0a2fea612f5bf06", 16) + g22To26y1, _ := new(big.Int).SetString("177707b5b522d7a2872138854c489221160f077805e56fea004a128552c8f16d0b43f0ccda2674879b15c9641f4564d", 16) + g22To27x0, _ := new(big.Int).SetString("d0ff8991599422d91d4a3e2ffe6b29e7fb6ad84d2b23ee0415c1d0288c7be65a30e0c81247057033ecf2b7301c4207", 16) + g22To27x1, _ := new(big.Int).SetString("28e47fa8013afaf501b8b030bc935c9dfa622830c3afb5d8901d61589a39183adb1c33de1e86acc89cd5f408a96a2d", 16) + g22To27y0, _ := new(big.Int).SetString("6ef0d3c529b8c020c4b46b31956d6d3926d0dab34bcbd553830686e20cb930657e88bffc4d91f3e19c689ee6f5837c", 16) + g22To27y1, _ := new(big.Int).SetString("173f44537f5f89935806b99af3589224bdce765bd80bf3095ad577bc3dae0205dbfd2098663d4b6b900221267ad6177", 16) + g22To28x0, _ := new(big.Int).SetString("17eb02ee81e7e5e5e5f1aeadb4ac4e0d78d90d6a1cc6258e697817f42df4408e2bd6663b2a9152ef1d83afed7cc6fde", 16) + g22To28x1, _ := new(big.Int).SetString("940acbe9e94c2e0a7637304492caff98193920bf0a4fa562db034f0969de217a76d8fd57bd95efca6234d7b20693ae", 16) + g22To28y0, _ := new(big.Int).SetString("1617e1d3f900cf0dd2db9907811cdde059c9c58ecf392a6ad677f76b370f1f4f9d5b34ba1959729168f3586c9f60141", 16) + g22To28y1, _ := new(big.Int).SetString("10fe5eb72866b7036e270e6fd905b38e98e03138357e5e6760c0c81e48a0180ffe2f787d78d390095977f40f364de1d", 16) + g22To29x0, _ := new(big.Int).SetString("383bc8db0aa13584b4f146d00bedb1b59d59b9ce91384bf6f5e28ef1a80bd8c8dec268e51dd16dd560b741cbbbd454", 16) + g22To29x1, _ := new(big.Int).SetString("c533310d0cbb1246a86e98be953ad677066338ba0c92095c808b8b197cd9170bcfd84f62db6836e093e72bf98e75db", 16) + g22To29y0, _ := new(big.Int).SetString("6a6eb93e94720c777c9b027bd15a21b7a03060980a6775f4c447a993b92454cc9f660bef1a6aa1c1dece9c864be9f8", 16) + g22To29y1, _ := new(big.Int).SetString("ef7483a0e257cb26e5f18f2c5a78af68095e88c43848ebace5023c031ddeacee4d6ba3a55b0ffc3b3187e152fd3733", 16) + g22To30x0, _ := new(big.Int).SetString("1036a17a68a664dfd56888eea3b34267ee1f913b09284a79e85a4a1d2ca7a89fcfb6afba3cd037f3f7f56ad6ee0b6c", 16) + g22To30x1, _ := new(big.Int).SetString("561f0e90d0c0d9387a52a60f4053a245417ddb28abd67e00a9a335a37f98a63a43f2d6a36ff9d86e29110564164739", 16) + g22To30y0, _ := new(big.Int).SetString("a03f1caa0380f1fce736ec84f793f1f0cb840046e7a646eb85533ac2db5c9079bc6d3d90a93f9b8d65d0698f790c70", 16) + g22To30y1, _ := new(big.Int).SetString("6eb4902e132878419be85733246d0b635a1dcfe0e10c25262bdfd7d5cb63bcd1c38228a8442c43723b38230026d8a5", 16) + g22To31x0, _ := new(big.Int).SetString("e48d3d52685b6d5f6345afe258b0fd77a1ed31871190d6415f7681884cdc7366dcde04a6e35e76ff77f00901c3d655", 16) + g22To31x1, _ := new(big.Int).SetString("2c63bf171f9f26aaa7c57584d06089a23d4e999a626dd69ed2090a1d3d3fafacc67422717b06161177ea6722ece560", 16) + g22To31y0, _ := new(big.Int).SetString("161f0e4706ddc56952d82a566bec832320e58cdb1823a7c4059d16c8bc8beb521699f3b8a8d03509b4f473a5a2fe8b9", 16) + g22To31y1, _ := new(big.Int).SetString("a3787c215a9e54fee577e4f14c0e3a4f5f88473158a3d45e3ef04c8a524750527abc2cf20f38ce55b7506dba3e6856", 16) + g22To32x0, _ := new(big.Int).SetString("153b5984f164e843530674b0df059e5d90431a37fbd885bff9576cbd19b12cd82fff84b786089afe0db68235662ed5e", 16) + g22To32x1, _ := new(big.Int).SetString("f84d4709fd3c5b8cd5ec2f44b0ab6479c8281627ebdbc3fe9139ceb495db78a6b7417986a5209cb56c09b11d1c3568", 16) + g22To32y0, _ := new(big.Int).SetString("7e30c9329d4d30b19f43c9dcfbc18cc9e18a415949715174d71721580fe94e3eff291ba91c528a200c9d26b99c371e", 16) + g22To32y1, _ := new(big.Int).SetString("458e123e65bbf750a89da00855cbd49d6b30494bdedb82c212e81abf5d577018a04333698a360a44a62505977e7c1d", 16) + g22To33x0, _ := new(big.Int).SetString("d8ec95f95a22c8444a656a84372caf02240b63e3c3cba833d9dd938f896ba7c197c776661459cfbd581cd12316257a", 16) + g22To33x1, _ := new(big.Int).SetString("10512f0f0b166f7a0baaf6a78e0385c5404116c83a4023d73ab0f17df35d3353be9e08508e6de550d6f26bce1eda20a", 16) + g22To33y0, _ := new(big.Int).SetString("11bb3de43848a38febfcb4e849bc0d5c86855556a2d46d233a7df29e51198335cac38b7efce2a1c6ff84c4349d64eb5", 16) + g22To33y1, _ := new(big.Int).SetString("141e67f88c5dd004cdd85912a561f46fb061406fff5ff784f57ecab4535293003a0e67eee038fcc0cb0d0955e0ce151", 16) + g22To34x0, _ := new(big.Int).SetString("583a2742d555ede1fda4c58d58b4baec89581e357312ef4ebf3cf6c8ac335a9160d28d5916d362b68708e5810d1f7a", 16) + g22To34x1, _ := new(big.Int).SetString("1a93480b413b2a164b2afd21166b5551ce59e5fe7625bce3b282aebfec20114ba941779b4e215d8219c53132d2d5b41", 16) + g22To34y0, _ := new(big.Int).SetString("30e831e25b1d2406d80769237a2ebb6a78e550fabc5337661e9c4043d9b5897038e2409161988f9ad4b54be62b76aa", 16) + g22To34y1, _ := new(big.Int).SetString("59ebd475497b882477ef33e5797f0f1daab745b91128b01d1008f80640dd9c0c298928856d3ebac7129cbd09353143", 16) + g22To35x0, _ := new(big.Int).SetString("b1992cf3d3ca2d71aaf59972205abcb0f1e56a5e3d740785c85f9000de581ca4d59aae19653d437e24c20dc4696074", 16) + g22To35x1, _ := new(big.Int).SetString("bf892e16dafb0073b5187262ab8d7cc4aaaeff6f01da56760cacc3e1611c116264f3210feac156c30c90cf7a7df09d", 16) + g22To35y0, _ := new(big.Int).SetString("183bc9010b27f8b3f38861ea0193383b032fb8a9c1ad2986d714ac6fa0bd7e9fc81fac1cdefb7801feb75fe8b8da8ae", 16) + g22To35y1, _ := new(big.Int).SetString("116cac547878bf1c88320d24f772bf6b6d88b1b210a0a6b83c81c9340bcb22674ce4382cf785dad1db5bc36b9a4ff6f", 16) + g22To36x0, _ := new(big.Int).SetString("d95801464ff9172a6bc1c74d82baea62b43364526688a02903672f934d7455ec4b212e490fc563aee0fab5a229f6f5", 16) + g22To36x1, _ := new(big.Int).SetString("9780d32246507cce00e50289af8d16b11d4605f550aa8129265f9f217e735cd92aaace24f2af39838b2112514b35e0", 16) + g22To36y0, _ := new(big.Int).SetString("1a71f82f9796e5b4e5760e7110283e3c1dec0d2b6b70e39f9368f166dfab551a10743324dd6c858596c273c6d5e74ff", 16) + g22To36y1, _ := new(big.Int).SetString("1bef4ffa86bffa3189dfef8a3b595b13e1113268c86d3024f4e27a023d10cb570cb90b67fbc867084f2fc81f714809", 16) + g22To37x0, _ := new(big.Int).SetString("41bd35e554843b52b936e39f382002dea1dd180a8b4f5331c69703a811efc366aa5fb9280e0634ef0019f19e2feef4", 16) + g22To37x1, _ := new(big.Int).SetString("18b87fd624d95900a7a8a51283ae17b1071788b1a2f1b7afd3a4042210645912bedfd955bdbd58e379decaed85cee62", 16) + g22To37y0, _ := new(big.Int).SetString("192afef2350f8ef6039cfd8b266cdd29181f2c368289c7baedc61eafe4b070ca3586d465dbad5fc655a504c2e222b20", 16) + g22To37y1, _ := new(big.Int).SetString("88d94d50c9439023a93ad40ae2edd8199c0dc2c6eed9f2a6dca9b6b856968e20dd98918ad17855ec7ad4d8a2c8c120", 16) + g22To38x0, _ := new(big.Int).SetString("b5362830d25667c44fcd884f44d8a8df1c414a13a7cd885fea688ac6f68eab8d370da4a2e88cdf828204ef6329a437", 16) + g22To38x1, _ := new(big.Int).SetString("362f1b305ff3c693c87bf1b3d3812a3350bec2ee6a11670bbcfdd0ed2a3650993761e85593bf35af5d2600db6ad6ed", 16) + g22To38y0, _ := new(big.Int).SetString("a05a8af2a94b833806746ef4d44a986180888a5979e08676bab3ad61ea45b0acc0b391d0595a95f547a2ae30593e4d", 16) + g22To38y1, _ := new(big.Int).SetString("d2d9e77346ee01e20a3c37519509d139461bab10a396ad1a275bae47145fc207a216ad5ce58d79a28bbea7adff2b34", 16) + g22To39x0, _ := new(big.Int).SetString("6a10d0ac3533744d21fc6cff820b6356c5e3bcc31929a225aca8e093502cdc3e00b29ecf4281cff7a949da6a4f281d", 16) + g22To39x1, _ := new(big.Int).SetString("30dadf6df2b936b6df91ab89305c183cc5d7b1be73a2b089808a2774dc99337a548b93f5604617c5cc96b0673e5622", 16) + g22To39y0, _ := new(big.Int).SetString("18d188fcf89f3cc3df1362232ae5f12cf6ee6c9fab12bcaa00c28f8502b44418e7d3f03a865b13ff1b085a43b9a3fc7", 16) + g22To39y1, _ := new(big.Int).SetString("176e51903e994790397ac33519bb5baa8152c81e03853a3ab1c12d7dedd7bfcb122a037e988e28ce8947cf7e347c756", 16) + g22To40x0, _ := new(big.Int).SetString("abc050eb147e2ad213e89474acab0dbe4a4ee756a55dce940cad73410a189f9c65531f11d14638837a658f35ba9dc2", 16) + g22To40x1, _ := new(big.Int).SetString("999af94ab61ed896a424fe97a7db3415d7e5de0d73e5cb99e2cfc204296d52ba2ce2919ade970c09cc6994aeefd3de", 16) + g22To40y0, _ := new(big.Int).SetString("58d79ac5d0f6af0e5c756a728f6752ac67ebf93b9dafbb2a1ab70b5b68b912f82cc8e3dbd539771fb2c57c83754b32", 16) + g22To40y1, _ := new(big.Int).SetString("192a6e7eabd38c76ff48083d5218ccd93d6fe057e6a74ab0f9c0b9b129c147598e2c5c6dbae488b5357cf8186356a91", 16) + g22To41x0, _ := new(big.Int).SetString("19f0dbfd7cb68c747dcac52b386416d6e272d8820befec449bea4b1252998002d29bd7d54b59fbcde8af2b82e85e267", 16) + g22To41x1, _ := new(big.Int).SetString("fa4a3a54e2e673448f13616133584f9db4489be2089917474129e4648a00168618761ca72a65ce922cc0e2e9ca8dfd", 16) + g22To41y0, _ := new(big.Int).SetString("12e5a463086e98cfefd688092eae7e0a3976d68381b716c95bad23964e3d296f4af4f23f647e119c8e5f438957addea", 16) + g22To41y1, _ := new(big.Int).SetString("6c4edc6593bd6dda6803f8ae55e145edca6f73d2b2d2af9ff1a82177f20fe787c50e2be8437d136ed351598c1ea118", 16) + g22To42x0, _ := new(big.Int).SetString("6419674f432214f07127fb72a0d07592b20bcd07b7f8ee84dc4f7740b68a7fa853d4532dba1f162476b8d0f166dbc7", 16) + g22To42x1, _ := new(big.Int).SetString("17c81beb87e609762776a30c9b74015e319e263de01336af618cba0f3dec9ab38e639e6ba5d8172df01104c7c2a9d80", 16) + g22To42y0, _ := new(big.Int).SetString("15bf1ded44db5dea5e91631a6f7cfce49cc7b4bbf21e010d5ad687d7ce44b48712e6f806e635568471aff28a3a043d4", 16) + g22To42y1, _ := new(big.Int).SetString("13ed2ac7089a3b1e5c9a69bbc5a76f5191f36736d78e45cac82cef570cf6074941bfe2cf015fdba67f915dec98c9c1", 16) + g22To43x0, _ := new(big.Int).SetString("185be4aa0279869a762b50cbad5d0ac6d33bdc1758d93101a27293eecaba0f242cc8d1f51a4ee177f347c0759e6588d", 16) + g22To43x1, _ := new(big.Int).SetString("48e5eabbdb45fe372cfe79be6eb4b51b765f60111e3bad144a03e9ab482672125b1e85a692ef352e3326cbc0597274", 16) + g22To43y0, _ := new(big.Int).SetString("2d82d3fd4240435ed7639eb4dfbff8ff795153665df35756e64c365fd32c3fe76ff1c1fca0d4708c4aa11f05eb9128", 16) + g22To43y1, _ := new(big.Int).SetString("e04348ea4052ac77ab211fe4e9bcb9037b75f8bf382fadd8826105ba8199260d64179c784b3e69a23ffe4c279d1058", 16) + g22To44x0, _ := new(big.Int).SetString("1490209d72244cbd78872ec84c6afecd3f832ecf7e28008c82fbc0d6d091c93f63fa24b0f383ef53f4559f11f8009cc", 16) + g22To44x1, _ := new(big.Int).SetString("18c5c95f94d8714d84e59c8d030442e28deb22ee3af962fa204dea3f7934f4d6cccd711bc3a1245cd45acc3d6971c7f", 16) + g22To44y0, _ := new(big.Int).SetString("18263db3571d47415932668d9f6ee7cbfb7ec087af44380b533ee5139c8f012c45c8363dba54ca0ddd301489394e12a", 16) + g22To44y1, _ := new(big.Int).SetString("914cf9f4bd51f4a38fc8b1673a0ce33cf6bce9fa2c7a92c130ef0bee0d058091aacd37d2c8cb2da3b42e4374adb917", 16) + g22To45x0, _ := new(big.Int).SetString("da298a31a0ab144bc2cff38e71fa72e6c96d9f760547111bfb6e18477daae63433b0afdaa91ef34f53c68ad47c75ab", 16) + g22To45x1, _ := new(big.Int).SetString("41ca4e4f18b7b5bcd9f806b494dcf37cf7c5030f31ba6a554140941bc3d621f436b65ee0c30bb3851b9cb987989f93", 16) + g22To45y0, _ := new(big.Int).SetString("5e751fd9a96852e1589b4dafd24541bd27fcf9bd900041b7bec69c5a71e7d8995930b4cd3c3fe3e01d37df1733e515", 16) + g22To45y1, _ := new(big.Int).SetString("2f13e69c6be44996217714c43ad2a3a0b227a09eab012e3a7c545b226b549861275c4448cc8e3d6ed27de7b44e31a7", 16) + g22To46x0, _ := new(big.Int).SetString("1a2026ccb033d3855aff0d8833771bc384f6cbe459c104dc6f2c124a6ea62dd32a28894fd38f4bc087df0d6f2b3ca83", 16) + g22To46x1, _ := new(big.Int).SetString("fe37752eaaa9e9236ffd1da54fe4e667e94533b2cb94c8598906277ac432858be2d30037516bbc44c71a33feb8726c", 16) + g22To46y0, _ := new(big.Int).SetString("f03c56414679e18e5c2db662ca5ac18887d5343abb858d3d25feccb241caa74aaf81c339fba2ec6392d2cdc2d33a3c", 16) + g22To46y1, _ := new(big.Int).SetString("14143d24ae7942388cc41230d6972358490fb11640e9e4748eca6670624b61aa7528b23b2117f6096467588fdb26063", 16) + g22To47x0, _ := new(big.Int).SetString("15b56f4a2f70826a0d7b3b7c5dac9f69e3ac44589a694570225d90f532041fdd35ebf09fd041fe06284b9567c19c7d", 16) + g22To47x1, _ := new(big.Int).SetString("381ad72ec64de0aaf137d78566bebb1bb8a3893db8083b00e0e36a3947c2777f0e9433bc8df99df1f5207eb4368539", 16) + g22To47y0, _ := new(big.Int).SetString("ea36e74304a872c97f28466d58b853563c61286e9bacd8be957b98ac49778bb8c411019cd53013057d798eb29a8a05", 16) + g22To47y1, _ := new(big.Int).SetString("1563b7c5815ed23d91f64f9f301571685e2aa40815489ea2721f398b8eb1aaa4bc891da210da11e3fd83991fa69b6cc", 16) + g22To48x0, _ := new(big.Int).SetString("97e9c3bd458894adbdf0366dc70920dfd274ca84c6b94a4bdfec4f2308b2764d0909f6a411e359f95b4fbdf2b61e3e", 16) + g22To48x1, _ := new(big.Int).SetString("1934e67afc63e035ec73f9ac0bd04401c913f12958695cece66bcd7ee0340beeb5c679bf3198bdd740e93151d55cda0", 16) + g22To48y0, _ := new(big.Int).SetString("e45dc92ebb78eea7f3d12d43e6c882792690c2d3bf01bbc6a3eb587a6318aa549421fa4c8738aa7537acb1cfb773aa", 16) + g22To48y1, _ := new(big.Int).SetString("d0ab25bfc31965111e2bd7e01859f30b61fb89a362a50281709c52b19f410bbaaf4d9c1ffccfbd115ba131c3ccc0f3", 16) + g22To49x0, _ := new(big.Int).SetString("18075d009ccf790da4ae26377c5a74f7d48109cad34ac18d3f02951d7ba44f025c26430c6ca0df8cc2f6c8f82e61d59", 16) + g22To49x1, _ := new(big.Int).SetString("aabaa12fe1c640959fe0f78fda1446f422677dffdf6972ff34193c2422703a713d679e03c2424bc2025630a0909f6a", 16) + g22To49y0, _ := new(big.Int).SetString("f08ce21221f1b1356b24cf796dab84edb9c96807855b5761ea83920c71d3f216d23ffab41bb7602473808d1d8460a6", 16) + g22To49y1, _ := new(big.Int).SetString("de28901cf5c2b7868e494abf385488d77ad1142018e1ca68747c9c5ee7469924a172f763243da45e42c8143364e400", 16) + g22To50x0, _ := new(big.Int).SetString("1473cc23a296003180995405451e5f64153da19265119c136d6e2e393ecf0ef536db7f8570c7460efda230c3e5d4f8c", 16) + g22To50x1, _ := new(big.Int).SetString("f442c4e3859b4d1b92e1ee549016812d4e8c19784dac74941e393d19a1c95ef93e921bb71e7fd3ebd37caf49b18edc", 16) + g22To50y0, _ := new(big.Int).SetString("1860cf772380cbff871fbbda474cc84cc8acfb76ce65516bf00172c4aca8983c7caa04b25e97aadb56ea74ae21a4112", 16) + g22To50y1, _ := new(big.Int).SetString("a5bbbc7ee8cec2e71a28ce4395ae299d1de52718182afc38a489bf9a72a61075c3a52b61c6de864cbfb80aab5d59f3", 16) + g22To51x0, _ := new(big.Int).SetString("70341bc9e98b79fbeea0c732a19d2ba7656b666534d350c749fece947a1993fba1bd50fdfb609b9c7b0731b496e06d", 16) + g22To51x1, _ := new(big.Int).SetString("e3b2e7a10996d7d52088bcacfb8b4f694bf407865056889e9a887ad421f3580299ed660f1f6bb0cfb8079469b2051", 16) + g22To51y0, _ := new(big.Int).SetString("3e2224f7654d02f9d4afa4bd67ea3af7e133f348e257cd9c20b86a0e7b70efe73be58f0c348fd979f3ea2b260420e4", 16) + g22To51y1, _ := new(big.Int).SetString("3d9d2b19ee6bd645650bc65a3397d39f76d234bae781804b9e50e32f86ed03aad807c008845f002b84bef53130a63e", 16) + g22To52x0, _ := new(big.Int).SetString("bd1b636033a60520ad4baf7614b45ae11735803bde97952299c19b7e95778b4a0cae7130f948724b11994c28d43f14", 16) + g22To52x1, _ := new(big.Int).SetString("16cbdf5573228721f3958d5a962faa581a6f49db89c5146037270e55a923fc321756cb671865bf6b4d242866a4babb4", 16) + g22To52y0, _ := new(big.Int).SetString("16e92f58bc93251c73759651a74bc4e3ec2c023d2444dfe68eb9561426d4b06a123d7de85b19c0e40c81c9e731d475f", 16) + g22To52y1, _ := new(big.Int).SetString("19ff3565b3f00965ad038551f61f9f5daad2e16ad223789b6115655ce133423adb97cfaf1b4e47fb2c56864da1fff7b", 16) + g22To53x0, _ := new(big.Int).SetString("2ef4527bab5dffae6720c1871dbf20581aed57cba7e707d9b1fa04965577981da8d9145a7a9d9c8db3f6754a267fb3", 16) + g22To53x1, _ := new(big.Int).SetString("d023cecaf1a41f33c29b57650fc683bb115b9012c6ec5744c223f2dc759912010901dc77aef33a128e3d92954ddabd", 16) + g22To53y0, _ := new(big.Int).SetString("12c72763616c5589eda281c7312b536be2d61100ac6364ce20ae77441e5fea6e56aa5eba821ab1d24cf660a67a501ca", 16) + g22To53y1, _ := new(big.Int).SetString("394347d359dce2eac6adc8773190bd1436b66c2f1cd3f1755426f343e69f6345593fdb262b251645b5820f4f6b1007", 16) + g22To54x0, _ := new(big.Int).SetString("c28246812797dd5fbd542f2dce015360e9b9782a87664c00473b735659cebe14fcc96d79bde7bd7a13d2841043b142", 16) + g22To54x1, _ := new(big.Int).SetString("1292225d4f829a19bbbc0bc15f48b64f07d7d6a58ea4b6e35a3edfe49dc1cd2b0a869c4a087b603b7f023e4225cadf2", 16) + g22To54y0, _ := new(big.Int).SetString("f967af7f410f57a9657793bc17f35b9318b9696b129f5a05cecb5b1f8e1e472e54e2dd9dd4115f576099278dfe39ad", 16) + g22To54y1, _ := new(big.Int).SetString("b1c827d3d66c942325e00d23d9b39e9bb6ecd23b6d2aed46aed7da46b9cbf4d092e344bfdf5cc4066b5ad25f2af3bb", 16) + g22To55x0, _ := new(big.Int).SetString("e0d71063b9f86daab4fc886785166c5fbc6fae99ba269fdc91244426925e49006d26099b251e9892eceff9af0e2bef", 16) + g22To55x1, _ := new(big.Int).SetString("658874db7d71fb8a4f5496ce170789b7e899baf0590cf7105f82c6bb6827ae718977104c165b463cb2856f62497e59", 16) + g22To55y0, _ := new(big.Int).SetString("6e48b3612381351a5200f5401f6bba656f1a0501429f54a44890aecc79396ef9972fcaee886b9ca5988bb976ff4267", 16) + g22To55y1, _ := new(big.Int).SetString("fea7f298af04217463943d781dbde85fe7336b6a98ce53d1acd322c3a2770deee0d9f5ca29c9ba259e93200a228aaa", 16) + g22To56x0, _ := new(big.Int).SetString("fb2ece7568abe698fc1be5aa914c31429f76beef1d7eab24f89ed3631484fda67044f406ca985d4392062b23589d9c", 16) + g22To56x1, _ := new(big.Int).SetString("12eb1042f943a2ea2213d740bec86dcd70b9dc81d9f9b6084a529ee13aea98de1ca3e84288a1f6748f2bf096757905c", 16) + g22To56y0, _ := new(big.Int).SetString("fd2052aaee0b618fd532c963a07a280423a54893417545fb495374b5b7712b56986fcb19ce65ca80199eb49cdfa635", 16) + g22To56y1, _ := new(big.Int).SetString("10ee9ad1193a5c6d03384a6dd0c9c4cbd9bef1533624fc56740700ab6739322b5e0f4213378434980ac97ed0ceb4bdf", 16) + g22To57x0, _ := new(big.Int).SetString("18cd416b6151272f709dc5854bad02640d3dba0e6e4b03376c32febc3ea505b3bfc7a6c99ec4fb16aba5956b2a2ebdd", 16) + g22To57x1, _ := new(big.Int).SetString("5e69ec1ec7df8ebce7949305f1c52558a84ae75bcb21726534b26caf24535cad1d34dc9f3a172ddaa136d9272750f6", 16) + g22To57y0, _ := new(big.Int).SetString("cd228db30a6c8bf4f877b0e142587dfa0ab5fb6ee9c200ebf640984fc2d18e00e0132df6d93d950c9097db4ec7acec", 16) + g22To57y1, _ := new(big.Int).SetString("39f29109c3306f291d4edccd872a57416792658e276b7119a7d51f9d558d991432f2520c63015f2f28032c51b15828", 16) + g22To58x0, _ := new(big.Int).SetString("c1ca6a7a5cd1647de7eb0d75b28a4f1a6fed2520b332a4cfe2aa7c56428768102eb40302b9e4801d35c862fb2496d9", 16) + g22To58x1, _ := new(big.Int).SetString("16b26c38c4b73c482a04b58729d40d63ae220c929ace32debd56288bc28d20c3edff4b0859d02dc5825481d8b95e563", 16) + g22To58y0, _ := new(big.Int).SetString("13bd107d3575ce63d37b91fd4c54e3bdd54b86e87766db6b3b1f49a80892aaa5a4c56bba15c56fe84fb89d239bfab2c", 16) + g22To58y1, _ := new(big.Int).SetString("114946c000ccf9fd0140560be3ade8b56bfead96908141fef5562d8e8c3f898ed15aaa465c831fbfaf5ba495e67cb63", 16) + g22To59x0, _ := new(big.Int).SetString("bcd9b04f5b56ceb2a2767fae531b4cecb44cb4d8acc91c95c80de1cf98698148829ac984192ee355bcf728f0286e47", 16) + g22To59x1, _ := new(big.Int).SetString("19d26674d69cbf1d6f135e8bc55e1b7c233be1fed55c047a8fedd8263be90a18c6c9982d0a28db4019b9a3289f92bef", 16) + g22To59y0, _ := new(big.Int).SetString("13f4a5cf1f863bbe248ad11eafd3c805daccd2e75fe9cba26863257c1014d02105c2ac370e944d8b52927525efcdc9a", 16) + g22To59y1, _ := new(big.Int).SetString("7325a886621bab4f44aa4cf1a4bbb183f801d16226e802d581651f3b3e1d7c063aac47d0dc2034ee1d3f6c0d6b73b8", 16) + g22To60x0, _ := new(big.Int).SetString("bae46db808530ea7195ef8982c4a0756c664308871122bb62e40c8faf88b907eeb4abc462286c67360a6a7d852ccfc", 16) + g22To60x1, _ := new(big.Int).SetString("207028b920fb4f2e51ef16d2a79be68c3a21256b0460f7d29867eb97f64a41aeb06be372570604e11e69c5f4f10404", 16) + g22To60y0, _ := new(big.Int).SetString("a9e0319f178e190e9919bf7630a91ca27c3f394709da9ee630a0a2faad928c5af37634b1afd57779f99146f25c4a78", 16) + g22To60y1, _ := new(big.Int).SetString("1687de3a00c54789c835f3bae67b0c74432beafa16f74d2052b49287741e3a5a29d9474650c3b5f43e807818e4a129d", 16) + g22To61x0, _ := new(big.Int).SetString("195d3360215a8f2fd6bfd0eb457e1f1aabbc2aaa38082525462d93da6803da01c9c4c7fe0dbfb2b1af0fa6444e6bdbd", 16) + g22To61x1, _ := new(big.Int).SetString("15213ea05e70ff026413ff536d8a6931c5dead45e5512de3981f59eb4cb2ea45a5a5d179e50b89c7f33e2735d54f163", 16) + g22To61y0, _ := new(big.Int).SetString("8e450a2b9bb55c930a330dcc3645706913072dc9e76a03f7ae81d62f5851dc692525369eacf0b4d7eba9c4a0c541af", 16) + g22To61y1, _ := new(big.Int).SetString("181e7fb361bfc23dc30b6b12de204658bd97ee10a2303c35cde890068617da05ff604d9e9ab8fb7dcec47d8af32d110", 16) + g22To62x0, _ := new(big.Int).SetString("9caab0ac2242bff84e280bb08ff944037da8f90893717b88a202885f9c29d20b472cf36a2076340954c2d3f9980b58", 16) + g22To62x1, _ := new(big.Int).SetString("10d26dc2a0e15257f4b4d518e5e313f12c0fbf7efa35719ceac2920115b7b210232001a9272aa09993ea1767ebdf657", 16) + g22To62y0, _ := new(big.Int).SetString("10a8df7f196b2dd52cbe3264d6899b4f0bac1a21757df6dc074c62ba8612b91a9572eb65408337084e3f8cc50589ded", 16) + g22To62y1, _ := new(big.Int).SetString("c988f26b9f9ff5eb31b9984debae90d14a68b96ccd18be600e0c560597cfdc415f48ed7924f198c90f0293d8455381", 16) + g22To63x0, _ := new(big.Int).SetString("18d111f764de031ce64357b8ef65ef4d7f5be47c630637cffefa6b3614b74371c13435e3c85ab0d33e27fc573fb58f9", 16) + g22To63x1, _ := new(big.Int).SetString("854850ab2f7b25960ce9cd5627040a4da0854c752ff86231b709280cd1256892a49b01d783da5e5bd26d3e9d24c757", 16) + g22To63y0, _ := new(big.Int).SetString("aa4ccd1dfc38d3ea9848fc19aa6dc3b78357c3ccf3e6b85fce5a6ed23feb80e9db5f69ce118ad818d7077221b244b6", 16) + g22To63y1, _ := new(big.Int).SetString("bb7f0ea545d089958c5f173e653800740885499e85e391110e720c8009d6a2923690e3a65c9c428db7573c082c2989", 16) + g22To64x0, _ := new(big.Int).SetString("e7b0b743e9097108fd3c5cdd0bdf7ea33dcb648c482be658444a5d6f27b46999665f11a083268a2b39b27a82834103", 16) + g22To64x1, _ := new(big.Int).SetString("10a35d867dd3f610ce40db92cebab6997056c92357a2b84df0774fc7f82116cd7e680590adb9a1f4da01a9e210a5ef3", 16) + g22To64y0, _ := new(big.Int).SetString("138e999e863e80b96b1a87e2c6f75ad2164ced765b5d1fdbc51b9c186cb4c460509749eb4cd234a1d62396fa3a24500", 16) + g22To64y1, _ := new(big.Int).SetString("69cb46bad13f9c343d15771b7a6911dad591ee36122b763076654a3dd88fc3a87229e43875324c2be66dab9949e504", 16) + g22To65x0, _ := new(big.Int).SetString("d0250c6a7a26f261bd039480891b7872063952cd9cfebb98a2759c895bf88be81f4779b9c160d13f873d59b64ba137", 16) + g22To65x1, _ := new(big.Int).SetString("8f0b9cdb43a062d6e79a53d0b992bc54c6d3f2cc9538298b5b88a6299244fc61f4d1ae7d45ecb829801b20d0653b31", 16) + g22To65y0, _ := new(big.Int).SetString("3373603eb2ac404a0a642c7a0cbb9c897d0c37108eaa7009754b456715df6cf60f64efcc4df555cd052291d81390be", 16) + g22To65y1, _ := new(big.Int).SetString("89c1cf8bfcbef353f34c2b5443337175d2c0f6b22518f273f35878f38cf9521607f6112b474e6db2324c4340b0df5b", 16) + g22To66x0, _ := new(big.Int).SetString("148a07dd6f324ab084b71847054aa2228097d6abd1b13b0ff91bc521f048ca3013648aa3d72d6ee7541f5b554f1e934", 16) + g22To66x1, _ := new(big.Int).SetString("17dd6bcc1548a813d4313eeaf87b549fab32356a6df0a71acfd8b72a64b91322b94f7cc42ee26126e7be36464486814", 16) + g22To66y0, _ := new(big.Int).SetString("163a932dca566cd9647f4b33e171f5b4debd1ca68fa3ea52afa45fc75fdaee7829c6e92ec40f993982abf7e2a6bc848", 16) + g22To66y1, _ := new(big.Int).SetString("101cf0fe70ac42be3c79013cb1f195d4655df9688c2bdf06d51d1f04ab99ca10fef61f910db95838065b4cb9f5575f8", 16) + g22To67x0, _ := new(big.Int).SetString("10321b2aa34e0ddc75c042fd21a8b3f92e7d2b3bc891bf9735c74e923024538f99c0d4217de78b2d76000efe1f3ac54", 16) + g22To67x1, _ := new(big.Int).SetString("569a0b5626e2f4901b0473e478388a91035fb960a082d53b807573658a28e3ff8773e7c64ed04347c53d87a2b223cd", 16) + g22To67y0, _ := new(big.Int).SetString("15147f5ed9295bd84ec43fb64536868dcf4a9833949c7d347a18a2b60c17302396806144ebec360a8d1100047df4eb5", 16) + g22To67y1, _ := new(big.Int).SetString("1457c872d3e98ba96224f71c8194cd73d38284640da99960cab9cbf73c7974f1b72edeee65d77761c9b97e750bf16ad", 16) + g22To68x0, _ := new(big.Int).SetString("351ea718fc4bdfe3e53dd987b89c5d4188445344dc1368d33a898dee4b8c1f965e81a729ef6b4e9349cb025ec795ef", 16) + g22To68x1, _ := new(big.Int).SetString("1504daa48b8a9c245447ae19d9ee19213724ef5d34950f7f258a52cd864d4a47eec2cd1adfa3de0fd3219a8492b5033", 16) + g22To68y0, _ := new(big.Int).SetString("1ab8b27f1efe33fa8047707c59ec8221cab6a82500d581b7dcef501518272a9ae12871daa5e240a5ed3dcc120978d0a", 16) + g22To68y1, _ := new(big.Int).SetString("3bc61ed73db328586a09afaedb9c2a46c3a5d68ab29f13aa2d1f50a49de088b22d81d756cebcf09371194323201d46", 16) + g22To69x0, _ := new(big.Int).SetString("18f4b1130a34501fd97c5997dfe4e8f2c4f02fa7f5685202025e1cea075d6f0bf987dcaccba10b435275aa90d545adf", 16) + g22To69x1, _ := new(big.Int).SetString("5aec1fc98b428aec86c5daba6b074e99ee1c18e5f81a38bd40f4a4560cc7b34db995616cd319a444a9aeedc0f8e613", 16) + g22To69y0, _ := new(big.Int).SetString("1520fb252fd7fb3bed1bc73333cd8766980028d7831fcea590b946fc38a1e6d65bc0a7875b390e26858bbe6b09241fd", 16) + g22To69y1, _ := new(big.Int).SetString("79c278494d7ea6336aeb182daf2870fba68614bca24e34f988d6b0c69f4f051d68e23fdfa1f09cf0873470828ce93", 16) + g22To70x0, _ := new(big.Int).SetString("d22b2485547804bb50dea0b66ed1ccf5b9eab46be6a93cf55cdf9ca184494123700a9b7a694c5fb53c0b43bb09d9d0", 16) + g22To70x1, _ := new(big.Int).SetString("1ac59a298fad0037a75e909eda4affe9c3eb559c3d3109ede94c86e1c24c69090c361c4b6055011a6d839436a8ed3a5", 16) + g22To70y0, _ := new(big.Int).SetString("a819653da6c309b6b2b505927a14ee9c28d6237bd83aa2316826c8f2fcdcaeaa0d61d1e95858cd797faec9b67af39e", 16) + g22To70y1, _ := new(big.Int).SetString("42d43bda2903aaf4c0708d522ea03cdac318ee9b2fab2568e51ffb2aedd71fa13d0fd418bf56f0f38d39b3a1b834cf", 16) + g22To71x0, _ := new(big.Int).SetString("c79f0901536150e560849aadee3f42d78e55111b60509f93a00f1978138ccae15f5e2dbbb0457a515d5290a4e45d46", 16) + g22To71x1, _ := new(big.Int).SetString("9e1e0e1766774aec08aa43c70cada370a28bb5c0ecc220072e14ba0cbbbb58e678bf57480c57edf6150d33a3c34f4d", 16) + g22To71y0, _ := new(big.Int).SetString("d3b252e29ffe10984f4d53408ef620b7c4289cc91e23da402326a5664757a30fe86783d7cb84c8d6e84bc344bcc05e", 16) + g22To71y1, _ := new(big.Int).SetString("28c6b7501123220871c207a31dcbd6af0aa4123f984acf3055b68839fa31b6bd145d897cf2a1275a0dbe7200b97f1f", 16) + g22To72x0, _ := new(big.Int).SetString("124f44279c3f1933ba37767ccdb88580b574874f91e3159b75bf9af3eab72470671bfa31c40d73b8c9787c8f16de4dd", 16) + g22To72x1, _ := new(big.Int).SetString("1ab1b43b8176c351df7a8e26154430b77a24d062ba13027684b56dc540698e4cefd90f402b902f431a9de0669556ced", 16) + g22To72y0, _ := new(big.Int).SetString("17883be6b70e0537170818fab873c00f0f025b3592c09aa6d64e7a497e9dc2860f26bc919d6b317894435aa7740284b", 16) + g22To72y1, _ := new(big.Int).SetString("3dd81383aa384eadf9f0f90192f5a209ebe97e82c749d237ddceb789f65cb9016155f65fc2766a42fa65f557854d52", 16) + g22To73x0, _ := new(big.Int).SetString("4b1ecafade072f4ced75ad605cdfe5adb4899487ef9e8ff9daaf436b15c3dce31c901d87a2bd8c6397246cb05676f0", 16) + g22To73x1, _ := new(big.Int).SetString("dd219177c4343134c9552c02273cecf4dab4e6baaf954eadf8e48b432aae0510d4786db8b7032bb8b540223499bb6f", 16) + g22To73y0, _ := new(big.Int).SetString("f18ab1def75928516522df2c7ac746a29ea1c9b7f0fea041c1926575c71df068a2929f3bbfe933ce7cd60c4f957489", 16) + g22To73y1, _ := new(big.Int).SetString("38148ccd89951885a322b0a6130cad8af4be29ea32703e30f7bbb4a10c06c383104387abf67914e46972b12ebef374", 16) + g22To74x0, _ := new(big.Int).SetString("d3b3aaa330f5b2cd8fc8319e31be046801263219eb676ab2633974c8c713cde38cc148666123054755a31e2992b058", 16) + g22To74x1, _ := new(big.Int).SetString("1675a8d21aefda4993fc13e86d812eba60713ec36b5581df406f59b86d73c71d5f1c099a7fea88da449491f9fbbd509", 16) + g22To74y0, _ := new(big.Int).SetString("10133d4935f5044f763c07e879c85014fcfde93851f0d9009c5e357b9ff31cac1f16f8ea269b48f51857fe73ca09eb0", 16) + g22To74y1, _ := new(big.Int).SetString("cae20b51c4f750514fef4aa88ba1a2965d4eb9a7fc5d5e2b26bb5dc3454e48027ab3dec39f5181fb6fdcd7fcd7af7d", 16) + g22To75x0, _ := new(big.Int).SetString("2593bb67dbd8d568ac0b461b6feee2e49769b263942e90eb523fc978b4b62e4dc8973d3242cbc4fb7cdfe854234d85", 16) + g22To75x1, _ := new(big.Int).SetString("1508bc877d9736e881548244b61e69acba4be93d0c0984f27d18b5f970d5d830eb404d4ea091e1a3d8cd8b39ed1e211", 16) + g22To75y0, _ := new(big.Int).SetString("10b6c335d3c710c80136307ee584dbaad0f829ab91c04ae02094b5494ccf09bcf4de1aa01102f873ac40250cd839b5c", 16) + g22To75y1, _ := new(big.Int).SetString("1900ba6c05f671fff756f093ef608b49cfb5d6339c231fd2354f99924cc81e35391c7c188815c2fa9629acc4150e62e", 16) + g22To76x0, _ := new(big.Int).SetString("2c56863f60469ccc0d7eff667a2d1ca48adbdd1234168235aaa08ee71a0a2fd960d84b1f732c7afd82d6a7ede7e363", 16) + g22To76x1, _ := new(big.Int).SetString("13e01caa1014daa0b75ad572951ced122a16369511ad5a2fcd340a958bebb2e32a4cd246a4305a785c98274b54fa1e7", 16) + g22To76y0, _ := new(big.Int).SetString("195f038785df02735c533cbcb28feef0b48afbe1bc9d7421337be4b61e6c788e76eb4132b43e087cc3a4332e1de110a", 16) + g22To76y1, _ := new(big.Int).SetString("d94f79c96cf519bd13255649a31efd1e0537d72f46c3167c6520b5110ca0ceac5674ea9dfb0eb00b86d29f87a6c54d", 16) + g22To77x0, _ := new(big.Int).SetString("9b197d8005b9350cb9f06d6f3063f12183358c15977e346a63532a2a85616640d0e408631aa4785ed0ffb19754d9a3", 16) + g22To77x1, _ := new(big.Int).SetString("1a0d561c897eb1cbd769da09b54a3e9965ec51d5ba757a86bc96095a9276f088f727bbf489b12e1189b9d401df34696", 16) + g22To77y0, _ := new(big.Int).SetString("856797b8636ccc0833c3055e61d51127e6f3f15b2d9cabc7d63b0136ebbde94440d44ca5d90d6d97a0689c9ff1ffc0", 16) + g22To77y1, _ := new(big.Int).SetString("227178e6db12cdf5be209b35ab31f09758b239ace14a3f789eb663180c8a9a951c433fba883568efcdcd3cdd5ff467", 16) + g22To78x0, _ := new(big.Int).SetString("d2c6e9eb02b68911233ed4f42b4da20c220ef0a1222cac683c48a9c144ff79d50f5a309855fab4d986848707f6652e", 16) + g22To78x1, _ := new(big.Int).SetString("27d32b60caa22386c8037bc96458cfdf400e1ef5e1ce8255692d918f0a9a82d4036345517a304629af7e36baf2a86b", 16) + g22To78y0, _ := new(big.Int).SetString("4a24b3c1017ad1de15ebccb44b8c1abac2c0bd4ccc298445a9ac26146467d1bf1f411c841afbc9e7ac9bd030c2cc3f", 16) + g22To78y1, _ := new(big.Int).SetString("ba92e8e6bc6749dfaf7b6d11e5938d5a26a64002a2a074019537f30a9e28e70508fd8de67f5dd785ce4992e9530d7e", 16) + g22To79x0, _ := new(big.Int).SetString("13f7e0fc75bb088729fe9327774be4ae190d593de7ae8e401057546558a28ab747d6cd23fc93666ee869037cefbc4b5", 16) + g22To79x1, _ := new(big.Int).SetString("1036a6d40eccc3aacbae20664824bbcbca52dfa34e1f1942830a86514d23e5aa00455a59a5bab5d263a8c8782b8d3d8", 16) + g22To79y0, _ := new(big.Int).SetString("17b0783d5741e46005be967221c0b609bf87988bccc3dcc3945494061feeafbf81f58e3870f5326d97111c1b40e0c20", 16) + g22To79y1, _ := new(big.Int).SetString("bb79177fbbb7ec6f8abfdba5fb7a494b679ef5bca53f1c341e43808fcd6e936cd97785342fb581933ba61c75c47299", 16) + g22To80x0, _ := new(big.Int).SetString("94232b96901fe4476fc56d9786411aaea718c2c888bacf9d2c85fc5d5fccd1d0a10564d319dad8824cbfb0d08fa083", 16) + g22To80x1, _ := new(big.Int).SetString("155e8ac0e0836f153031e57b286abbdd600069cde69e1d863b34bd21ef725436211f6168ef9595e69d18ff3cc90828", 16) + g22To80y0, _ := new(big.Int).SetString("9166f7b44d7400b2a52dba38a6a99c82d0bf418fe44500e9d6a8dd31ac37d0b1c160d6fa2ac7faa66664c5fe7a1b0f", 16) + g22To80y1, _ := new(big.Int).SetString("12536490956de6eec731d5ed966a7c71de40f66f37beca4cd7ff22de8e9d934c7d0578836316b2bbde65c79a3b52df7", 16) + g22To81x0, _ := new(big.Int).SetString("18c235ac09ef6982ec724f4f92f067124134c75aa86fcdb5457c29fe0d4b0b6c96903a161be07a774c7826ae63691d1", 16) + g22To81x1, _ := new(big.Int).SetString("13d708687fc894a72a009451cc1fc6043238a7acd0739db93ab3baa724b3c144b7a8bf37c44631107f92b071c3638aa", 16) + g22To81y0, _ := new(big.Int).SetString("a20ced53578f8fe4fdabc3e6afb7ea6031540fd98c5cdd747e9a18cf226532b62f8497bec6421c485539bf55841918", 16) + g22To81y1, _ := new(big.Int).SetString("bcf5a70b1842c1254b51e3d01eb6e8745de80ce1dcc9595036f37e3d05345bd63e41e656319d733d335ddef0f755ae", 16) + g22To82x0, _ := new(big.Int).SetString("203158ebc49b5dd5f67e3c26a9fa8748c3e43ecfda7b2a4df9ab543382b35b95637130f6ff2e7d46a4e8806348fc6e", 16) + g22To82x1, _ := new(big.Int).SetString("14825e67201566a0a5f34908bbed91f85d0255a84ab8d66eec39f0b03587ec50141461589225999a55fc81646561cc", 16) + g22To82y0, _ := new(big.Int).SetString("1a9e7ffeaa972ba5b31e84f29923b12a7581554be6dd7dd9cb51d1eb9212584c47f7ca99100daf1a3a27369ff075210", 16) + g22To82y1, _ := new(big.Int).SetString("184b04e9e7c21a09c534dfd1f93b6552450da9708b28ba0a5e4310d5ef3f760a51f62d8481f7beb403c2e357bd561b1", 16) + g22To83x0, _ := new(big.Int).SetString("1376260b6e40c74c979b4189610e7993baafc35ba7fb5a82db25a94ef3725794585b85426594df0b1d16d726c455c9e", 16) + g22To83x1, _ := new(big.Int).SetString("17805d42f60c085db5e1408f7411b227d99842ad1d0ccce8460b692ab3a376acfb6322234c81a23f89b4a9eb3a90b8a", 16) + g22To83y0, _ := new(big.Int).SetString("3b4daa7ed8abc50412eadfb5942260908d2c9bceb2418112b105d10c32b31fd7f6b0d9309f7988e9ae4d2f4afc08f8", 16) + g22To83y1, _ := new(big.Int).SetString("16e28e73b580b637ea88108f05bef5e2ba4edcd4f506f43a5ac9dd6cf5219287c27cacc8312d792c08d5f2d0892ddab", 16) + g22To84x0, _ := new(big.Int).SetString("187b9a941c3bec8c3fcf25095ffc41d4221a7021eba2e397442569e837a7518c6757e8edd8fcb27979f7031c84d7c23", 16) + g22To84x1, _ := new(big.Int).SetString("1a5fd78972667724f3db2bb8e236eb3b252cbdf3488e16cb52da6a50b09f1b068bd3c42b29f3de27702ab453c1cdfb9", 16) + g22To84y0, _ := new(big.Int).SetString("99720688665688cd1f60734d86d6d0716a67fb0f3e52cd4e82bc69fdfe7b3a000ca2f1bab6f31dd9fc527ba0e71cc0", 16) + g22To84y1, _ := new(big.Int).SetString("d1f9fe007ce93ac084221980bd11657b01cba5155ad5b043a84d8f2373af54c774253739358b465f175d1058700f35", 16) + g22To85x0, _ := new(big.Int).SetString("b098e11ea939f2ca53c66c19096d264039adb023551c0db49d73b239e5bf695c432d9a3e13b7fe8cf04429bf2bec23", 16) + g22To85x1, _ := new(big.Int).SetString("11c55b2dfe0072a577e1573f9f045649faa825abd16246a07f6474dd24586a3f118ba8d4ce83485b98f3bacc1ea5627", 16) + g22To85y0, _ := new(big.Int).SetString("2fb138c393a166fc34900c55f08275c4c66523383fc5b978526768926aefba70f17b8a5626b958b61304e763d26779", 16) + g22To85y1, _ := new(big.Int).SetString("8a692b70e6208362c3d706e27e5c6cef81437417f3857546684c04b45fcfc318acb7f82355c4410c7688507b4652d8", 16) + g22To86x0, _ := new(big.Int).SetString("1d89701f684e3b4dd50cf7a27aa4ed2a345dcd3eb6db87586e6c56cd2e8fbc7d721eb2f032384ab43bc6ae2dc0e4d0", 16) + g22To86x1, _ := new(big.Int).SetString("a5c71f56be7b743ccb5d7b92aba64d1a9a9077cc53a1d8a7f81d85a492617f3c8e76ec6ce5a233e872b2be5c9ea9df", 16) + g22To86y0, _ := new(big.Int).SetString("8508151cd914c85e0cf0355212886c97833fbc09b34c9728ffdadf38d50d4d00cef0692b8a6dc58f850c45ddfd6394", 16) + g22To86y1, _ := new(big.Int).SetString("bdbf7855d55baa52cc7e38520774d48d74bc66fff80dcf03f01dcf44b2ac7231f316e193638ae2fc52b6049de79bf0", 16) + g22To87x0, _ := new(big.Int).SetString("9bef9e9e72b3161c411368d460ea474a924971b08e96730462ba356ae26ecddf64ffd892a1a0c319022e96b2cbb50e", 16) + g22To87x1, _ := new(big.Int).SetString("132eff4944b380b3a45d31dea6fe7f85953525da34a0d7b76758f552b17c7b4aa1f136c06edebfb267d08ba98c6c678", 16) + g22To87y0, _ := new(big.Int).SetString("116dd3c70261e339360c7d05c2d2993df0fcc389dc2f990e095b1e51948838c6d3d6d74da835562210f2e6dc0dc910e", 16) + g22To87y1, _ := new(big.Int).SetString("14acf16e432daf1c6c9f0a4ce37364f18229e18f6df4b1dde6d841d4977a8096c1e18ef9b49dbda26ccef64e2a0c9fe", 16) + g22To88x0, _ := new(big.Int).SetString("10fdc7434fa6e5d4aca0af0b744984416e302c9206816ebd8518a32b65aa94cc93fd71472c706a7d1d5965ce2128814", 16) + g22To88x1, _ := new(big.Int).SetString("19535bc89bcc4869caa416b459a7426fbae92cec1f9e2b767e727e5eee1b528ec995be59194d871f79a710bd4227577", 16) + g22To88y0, _ := new(big.Int).SetString("1a1c785e7bb03bc84ef5a8c84863b3fa298f94e1b70722824df10b37694d4aa357580c02ad0164d23ae2c2009394b5e", 16) + g22To88y1, _ := new(big.Int).SetString("e4a9d5cfe2fd183edca0803f9f211b9f6147d81ce3f3ad92a085a5da63cba441f5243b890802844be5c9f8ffe43241", 16) + g22To89x0, _ := new(big.Int).SetString("17d3584e68adde4b3ba6ed1245f94d4d8caca9b5b2929f5a1dd8d0e8a8f964fab5f4412d4ffe260cb6779fa38187744", 16) + g22To89x1, _ := new(big.Int).SetString("b72810ba75b293f75a84a46c3dfda0ca0e78e28c4fe0d48e09b75caa3bfa8de2358bcde88ece4849503683161b84bb", 16) + g22To89y0, _ := new(big.Int).SetString("11fe5e23e0fb187f67b4c40789b58e09df6a0b3e6dbf1cd5ae161a999cd5a33dd64f36bea222c9fb58bf1e717c4a25b", 16) + g22To89y1, _ := new(big.Int).SetString("120aba0f5960ff1f80450c0312026d063be918de41d83c1d1fc2512c7065baa0516185e9f8d03aae90e44eafb73798b", 16) + g22To90x0, _ := new(big.Int).SetString("7e5bc386efe6a685e8952068c72af0599cf260863c4d971ba19b2fb6bf0a08eb4260727c84579542b288baa5e94629", 16) + g22To90x1, _ := new(big.Int).SetString("d2c6894aed31f81623ef71456d30ebfe785adcd98b1e630f31fbf6a577753f87d578f204bc14eb22a8615cddd8157d", 16) + g22To90y0, _ := new(big.Int).SetString("ba0fd34fd06cfe512def3ca63a5d78f56e453485fc91f2a9b4ea0cfcc5201cc29576e6d0d14397eba14240c0206d15", 16) + g22To90y1, _ := new(big.Int).SetString("120af5e505fab6358a1012b5447099f602212fcedba2e049af330d6a9d6573becf9c4e7bf68d09c8c456cca720c92e2", 16) + g22To91x0, _ := new(big.Int).SetString("1174fefe1537445fcf50d034065612ef8dd5511123b9c96f76660353f7de340e6998e115ae829cc51727648f61d6f59", 16) + g22To91x1, _ := new(big.Int).SetString("166b7f926ac753ca5c3a9f85c4770e826a4258fe1cc94d20e99bb68abf9fc9ff1b7f807a84026ce0dedf2e33bc99573", 16) + g22To91y0, _ := new(big.Int).SetString("d98dca8ba804a4d0c6caa9fcdb42843f800c6df85529cbf2c58bfbdba3ce88b6081d01830c8c597f709494bc1d0698", 16) + g22To91y1, _ := new(big.Int).SetString("15578b78fcba88a1be3182798a7ae76f422a1fef607a6cac01eb666208e7a580973dbef56f1ddcf8faab94be5b218dc", 16) + g22To92x0, _ := new(big.Int).SetString("fc61ead5646562df74ec30afaedbb0915bbd29e15e624027bc10f8e529db0295827e0a5c3c90cda7f83eb97e933feb", 16) + g22To92x1, _ := new(big.Int).SetString("b15b59c9dbcce34b28a3095f7b3befc2e1c818914e8a1b6d1df383ae86d64a7783d3debbe1669a5f5207ffa0d1aae", 16) + g22To92y0, _ := new(big.Int).SetString("18244101b385749a9407e4c57ae74864c45d76ec0d5aba9802457712fa9fcb1ffe61aafde08a76985cd55242471f217", 16) + g22To92y1, _ := new(big.Int).SetString("1907e297c0664a8400af7b569983c606e2852e7bb63539b2031413bcf7535bccbc585046b7de86d61fd781244ca85e", 16) + g22To93x0, _ := new(big.Int).SetString("1210b122a5616f20e997d502673fefc5cf4118a619b61ee99cf3f65bcbf5da8a15dba884094c400031100fbec206a75", 16) + g22To93x1, _ := new(big.Int).SetString("17ce05e3754a40a4adf2cbd6276d9c581c7c747d9e48c35401579140813c0b4da0881b0f919da893bb482bc221145bb", 16) + g22To93y0, _ := new(big.Int).SetString("aac2d4083f8e87de21a48e3300e811ab711c8d883ca709003cd9adedd42bdabbafde9ec3a6aebbce50984900404096", 16) + g22To93y1, _ := new(big.Int).SetString("1748abe303f82c9dfe410a8edaa9ca705961bdd99bbe75277239b2591fa172252656f799ee0f01bf2daac437e209783", 16) + g22To94x0, _ := new(big.Int).SetString("bbd4c59f3b17c68bc9704ca68ca7a8f6fcb174cbd28b938ae10846a11100145a4ba0566a83143fc9e78cfea637de46", 16) + g22To94x1, _ := new(big.Int).SetString("1151c80769ac75ccb8bfbe89d5d414de3bccb20161eed22804b63b2f2e1675f1abfc29f6325106cd77ed9d00b8ea2d", 16) + g22To94y0, _ := new(big.Int).SetString("12fd57cd0ba9b496335209c191009a09125fa0806b40cc11d404e2831bf8c2024347385666ad64107608cdd6caa3b71", 16) + g22To94y1, _ := new(big.Int).SetString("5bafe652e00121fee3e826e8b1bab162a091747a678890d019c570084c3f615e4f184048c2c2f2ba79249a17d4e695", 16) + g22To95x0, _ := new(big.Int).SetString("16425b99bff4b8576a65dd2382ca48e7645027855b20378c267c5c02e34bd5e3f6384e762775f7b1ae3807f5203fb00", 16) + g22To95x1, _ := new(big.Int).SetString("c4f2212923ee54f6aae19e81f8d6238ea24d4a53673cfd45e857c081c6efa37e5855985004a45c363c2ff842416890", 16) + g22To95y0, _ := new(big.Int).SetString("169ba0bb3e42f757629871e9666f707d8a1aa48c7480c0547e8decc10e68c744d0bef7a024763d53cd5cc2c20d99892", 16) + g22To95y1, _ := new(big.Int).SetString("100289f0c67b96678631a127ce88217f46b78d4397a79329bda8ee22b1d431f8b73b16946735efc987e4f4ddc78e911", 16) + g22To96x0, _ := new(big.Int).SetString("9cae168d2beb85064442c5d48d1d81257f720daf8da84eaaa5928f9ce3b0b02397e68e307e2bf121b0b08eea3e380a", 16) + g22To96x1, _ := new(big.Int).SetString("10b9e23ff1ff46ead2dd6eec0787e571d1730d53d92b57b4725542fcad3db59384ab86ef6311f20938aec75edb40726", 16) + g22To96y0, _ := new(big.Int).SetString("5107c0205417087f0eedd9e5a72a930a7a64dba962fdca1f8d513601360268d444c026566204c8536b54e446933bee", 16) + g22To96y1, _ := new(big.Int).SetString("f6391690abdb069891f2de469db322a91f9ac98422aaefa4155f9c01c1eee9831329a245361d2bf0d1807906d63f82", 16) + g22To97x0, _ := new(big.Int).SetString("189d873a3c3c95266c85196c4c2a0f9699da0b5fc6f2d7027483c05dee86a3987c5a923f275331deb38965ae50ce27b", 16) + g22To97x1, _ := new(big.Int).SetString("106b16c4eaf3b168dd5b3c060177758e29539f6775a73d57e185ba35af56e7cf2e8b0becfcd6c9bc7ee422e607affe2", 16) + g22To97y0, _ := new(big.Int).SetString("718c860187a5132f149d0111b8a83c27cb0a5662c1e2293d23b626429879775a46db397975669f7801ac2906c7f202", 16) + g22To97y1, _ := new(big.Int).SetString("4f54175597d0ab67171247f711cb83725a4aebbbb208f222f081a2e71d7fde76e5c60675cd6feabfcdbbfcabb8d5bb", 16) + g22To98x0, _ := new(big.Int).SetString("1f19d3cf501e5ce40cf8b7c600f39c3269c71939890eb1e978851b419c6105f39258d7269503b4ca8052ab82ae284a", 16) + g22To98x1, _ := new(big.Int).SetString("1faffc6b4a583783173b60d3652c2a4aea891be320809b5c385c1c1e0fd11e0d6afddf4271497c6553d06a26c24384", 16) + g22To98y0, _ := new(big.Int).SetString("24e54d6e7fa810babdcf81ade8cfc1ca57f3b566d0cd6a94a317853ba4192e14058f722b745f9c2830983fbaa104c6", 16) + g22To98y1, _ := new(big.Int).SetString("48c55a947b49101171abfd3cda838acb364087029772e87c5e9b8e2c64d5d371e226cb4fa6fea43e49b17c27561bb7", 16) + g22To99x0, _ := new(big.Int).SetString("1091aedfd19f924dd7b2dbd629a2777966dcc93d9137c3bdb603a4818c3ac2c3301b9a42f5f4533ef017611a7dd35fe", 16) + g22To99x1, _ := new(big.Int).SetString("702ca5c683b735ded694e3af1298adee4efd45980a9bad0f154d3cf11141c949b82406373dc15f66c208b4df49a0b", 16) + g22To99y0, _ := new(big.Int).SetString("9d02b061ce034b067b5665e234cf255f0351e5e1e699f613b58d55488b1f91910830cf2bd4be26a1367c279a4fdbcf", 16) + g22To99y1, _ := new(big.Int).SetString("8b94bdf8a6d8f1d0712ea40fe5cad5e6ab82e036238df204291833c4476e434686f0869af372a392d0c19f985a8cb1", 16) + g22To100x0, _ := new(big.Int).SetString("14032d23cb84889d291673674fb0cc81f6d7fff5945bda9017512e2c4401a61364f2b9a7511b726a992ace963a7c9c8", 16) + g22To100x1, _ := new(big.Int).SetString("556042f4058dd5debd733ea53d2ed96d9e3b85f2b1d9f8157b7054806ec58888027c8a4a9c1036c192020758178301", 16) + g22To100y0, _ := new(big.Int).SetString("e76108a0471939696bb514e3fa68c9e69112f952abaa2b79fc45ee2f8790d70b60c5920d6217d04e72c7daadf2efe3", 16) + g22To100y1, _ := new(big.Int).SetString("15a99f10d35cf3e4cfaa214bbc19a465d117952add821ab89f49cae6682550ec136a1df19d9f9823a5d8fca4b65a94b", 16) + g22To101x0, _ := new(big.Int).SetString("5faba4f85c7be8b85607aa383d0f4a8974d450fee30e5a93f3903818f899364ccad8428c4ea6ec293845c9f6fa36d1", 16) + g22To101x1, _ := new(big.Int).SetString("19772a622b879f67b46290507d3a1ccdb8ea4009c26b67dbcb63f67dfff82fa10073e591f7a7e8dffd0b129ca98a2e6", 16) + g22To101y0, _ := new(big.Int).SetString("16babbf5b65e60b9af1bde401343ec3cc97fa560dcb7402d7906aaee459b5bf1f4774cfa92d0fe2b2686eba37854f2", 16) + g22To101y1, _ := new(big.Int).SetString("10bce0b14de90c6b4a63389707eab405a34dd5afb49957ce1d492d2c113ebda90b424550a5550f5a14fb5fad2c24db8", 16) + g22To102x0, _ := new(big.Int).SetString("122e0dfcc52b1e188cbd0f8b961d8a7750980d20eb7c25130b56bb9f882c8d7040f374ddef3492dd9b76e5a6ade6a18", 16) + g22To102x1, _ := new(big.Int).SetString("1a2b09c5c507570a6d17c5c6b47b0212e4d0f5715194018353740f0470b3822ad2fd571dca5eae24c286b710b73de9", 16) + g22To102y0, _ := new(big.Int).SetString("d28d027cacada3ee31e77fd5de409cf7ab7ef1d02508884fad99332b3878176b84efd46aedb81c285ca964837f9f3e", 16) + g22To102y1, _ := new(big.Int).SetString("1cb2594a6e61a98bd5dcde210a43552c68af9b95c09962ac6795ce568419651fc7aa115a63ef23918c41850cd27b7b", 16) + g22To103x0, _ := new(big.Int).SetString("b879e6f999c7673e2e84711463a084d89ce2f2722f0c9130844cadaf1ee33e5e858e53872360317f462a8e353b7e52", 16) + g22To103x1, _ := new(big.Int).SetString("777a62990bad6e9473770a60a6aeb985e2ecbed1ae2f063cfa1c8383dfcdba0b6a0471c13d88605f7b20b85765f57", 16) + g22To103y0, _ := new(big.Int).SetString("17a59286ee10486729a13740812be956ab7a95fa47d8813a852626f1aac49ff84fec74df85c9fa0c077fa71936f6ccb", 16) + g22To103y1, _ := new(big.Int).SetString("67b5d8f00febab51bdff3b00c3e9738955dd0fdba76a3fbb9fbb86b5e7caf6b1c67b039f06f9a595207e0b19248ddd", 16) + g22To104x0, _ := new(big.Int).SetString("137cb180674fa5e29385dd1696481ff08c5efe27a81009cf821b469f394ddc402c65e3331fc6d78f9886e8d9fde9781", 16) + g22To104x1, _ := new(big.Int).SetString("133cf155c8efe036f92dc3abe8281dce6b4a723027c5378ec5fdbee613331533451fb8e6b483942ea2350767721a124", 16) + g22To104y0, _ := new(big.Int).SetString("a482c18bc8ec6221559eb719c2ca37812aceb007161a01534bab0238a342a485f2e77d28ee8bfdb38fb633a160f422", 16) + g22To104y1, _ := new(big.Int).SetString("fc146f7bc0bb0ee04866fbaa73eb4ffdc77e455e1ad9a87ce8468d941735f263e62917b1c06bfaa78bb9fdb5a91746", 16) + g22To105x0, _ := new(big.Int).SetString("116dee9c4666d651c84821b5a8252f580608cdaf21132cef77a24fbcee9a5429b957f8f5d1c0a804e5e92676b52564b", 16) + g22To105x1, _ := new(big.Int).SetString("e5be1c7cfeb3aa1e899859ad51a6f24c488d215bc1b965d898c8cf85fae6a23f91bf8cdf12cafa8986078917ea13cd", 16) + g22To105y0, _ := new(big.Int).SetString("2c068dae0363b2ed8d1ce1b5e5155cbff7dc31063d33daa6e27bfa953ba9e886cd7d6e85b17f2589160cdf2a010f91", 16) + g22To105y1, _ := new(big.Int).SetString("33774fcf567fd930a2bea77b50481405fc4ff66e7fc1389c39651c5d15808deb68a42ce488d2fd112c8f0a5baf1fb2", 16) + g22To106x0, _ := new(big.Int).SetString("c7c081627ad153f088434d8f03fe40d9ac8001bdabd1665306992a0ceca3133aff86d35fc0a0e411535912729e9c78", 16) + g22To106x1, _ := new(big.Int).SetString("9489c71929f4c68707ff719a5cfafc645dfa0855c57cd86256ddde49410495b63caffe8d66b016f4b63fcdbc37d053", 16) + g22To106y0, _ := new(big.Int).SetString("a518e734be0ae302a98730a56e76fad774b0b503d4f376c9fe02c2e0969659493299c5b479b290aae53e31271bf855", 16) + g22To106y1, _ := new(big.Int).SetString("c6c060a1c862dfb5aec242de081c4f5ffa5b101ec4eb4b92f6b293c4ea6b738e77b5b59b1877ec5b9e1742c5a5623e", 16) + g22To107x0, _ := new(big.Int).SetString("13becbe4792c3dc9cdc4ecabbc0142b1470ad4064856db9d2e0fabb6b51accec4e9be97c86ef30d725c442a0d6f37ea", 16) + g22To107x1, _ := new(big.Int).SetString("136b7eef72220ed5f709e3022be60b3a28cd5a687feaf3f952e6b5451454d981ed067dd4faecebc22301c501134038c", 16) + g22To107y0, _ := new(big.Int).SetString("17c1428bc2ff6801d0e4c76c5b6e2f331a200471bce5aaabee05ac850c3e041182daf8820cd9d1e6649e1273d7bde96", 16) + g22To107y1, _ := new(big.Int).SetString("194ba0d16fbb45e78ec331394145f50873c35f0a4eccbb623a8629cbbb37362d6c4460360f2e942666d4195fa3f05a0", 16) + g22To108x0, _ := new(big.Int).SetString("186aa20f6663b4ddbe0aa889560ec74f71fd20c817dc21e657c5b375c2617c352a140c7fa7cbe2ccc4fa369607ea676", 16) + g22To108x1, _ := new(big.Int).SetString("ec607cdb75ba895c0cfa64431294490fc54b683033b07b92e6d72fa4749b3e2859e7487451e30c980e6fe3f65a0686", 16) + g22To108y0, _ := new(big.Int).SetString("ec43c1cb87d160f5ce51ebd294cd3c2c5ff7a3a02cf7ef831b584befae7ce33ed13820581d5ee70889e5075f1b2be6", 16) + g22To108y1, _ := new(big.Int).SetString("1f674975271c4d2e6cf37781aba7207e35c1158836a47002827aaf1f66ea0d58f2e89126070fa3c3c0b7cbe033b668", 16) + g22To109x0, _ := new(big.Int).SetString("1882dd4554816996525224fbe03d539546f5d00a13ef79e4d38d3300d0cbb87fd7fb3e1aae6523ea8645b80c22c1795", 16) + g22To109x1, _ := new(big.Int).SetString("21c4b1b500001a18ce9d8174de87203750df294f1835217022b33bd0e1e969a894f91c1de2b1be41a923fc6b2616cb", 16) + g22To109y0, _ := new(big.Int).SetString("19a3914c1247b5ad192a43436a5a65dc3116f96dc33567cfb7f48325e8433d990212090b009aca8172a01b192abab86", 16) + g22To109y1, _ := new(big.Int).SetString("1a53aaba50b4750d284100cfe5ba1f70ff28b7fedf6241b17abea88e59337cc4d473fdb0225a0339c985ac9d9c6a8b4", 16) + g22To110x0, _ := new(big.Int).SetString("15ba08f8ccf6b06bfc8258d9e8f60f63ce0ed2ff7b9e17317b2b59792f325cf0a6cc055480afec020c737ab94d39370", 16) + g22To110x1, _ := new(big.Int).SetString("12bbafe613a920d757a8cc75963e701767c307f94daef4a4893c77d5d9273759b7f6fa37de6cf73c1c8b9005776dce0", 16) + g22To110y0, _ := new(big.Int).SetString("12c19203d2fb64f421cff9f536f98f0db30f2e76d243656459242cdfc75a8ba139604d8e125c8d15be8688aa8b71808", 16) + g22To110y1, _ := new(big.Int).SetString("857c55d28da757acb1d4dcedccf89ff54f0ee8a68785c83a76a7ee2d3e1a15bf78b66927f7a914bced01b822986d6d", 16) + g22To111x0, _ := new(big.Int).SetString("16f80a7a30c317af0103d8d8e8fae69d75491921aecc038e22416c9f59e1ba8cf2d9c5e6586e54c62a69a1a010d4db6", 16) + g22To111x1, _ := new(big.Int).SetString("1967bda1bd60098ef7289fcbf288e3de7fc2764fbb210a9ac5c92498982baa9e6f09ad367c368800a14ba90f4c3f8e4", 16) + g22To111y0, _ := new(big.Int).SetString("956ff4717c9a52fb3056dc185a2166f76ce1fcac3ef1db9412ed9e04194c37dfccb7f2eb977572b0cc92930e805b77", 16) + g22To111y1, _ := new(big.Int).SetString("1995917263b0c39e974e544b8cf6741a642b76389fd0cf8fb0561c867c20ebae977ed85dafe2aef3e326e4c2ef2dd0c", 16) + g22To112x0, _ := new(big.Int).SetString("8b306ecdf4c97bd0fc88cc756f7aced4e7701464f96e535bc9b10c1c79eb66eb84ec07bf96d83b7c4e14a0c5a4dc87", 16) + g22To112x1, _ := new(big.Int).SetString("de6706372245870847f47aae22da4f8b56e64330a7d64dec23c7a098ec9126e48477e1396664356e40cabcd777f122", 16) + g22To112y0, _ := new(big.Int).SetString("11df20d23ede31c4526bd0b0ac4da9971755b90d9ad7aec5b55a89b4940ba1c044a0644a3086b2a8e8b48689e41974b", 16) + g22To112y1, _ := new(big.Int).SetString("10a2f94d3b6ac6a31eef91311328c9bd5450bdbd9de0ccc5cc3aef08d909acb228265f35af749f588119d087ca53c34", 16) + g22To113x0, _ := new(big.Int).SetString("10db59775fe44676cb087b9e8aeed8e8fd4204a0776a2d14d74a980e311ba9e7a90c85ad36dc867b10e5228b7838c2f", 16) + g22To113x1, _ := new(big.Int).SetString("e8f40636d57e8b22d9fd6c859963a846cdf50bf5b4a10236cae231f5115f0861a105dd6254f9538cefd53f441e9ad0", 16) + g22To113y0, _ := new(big.Int).SetString("5c69342ca0eed49339f69e16f6f5bfc05e1cf7ba712a19fa7789cd37340a2c86a4a75907f9b413398a6b056d106276", 16) + g22To113y1, _ := new(big.Int).SetString("15d3b19eed664079a60594a5d4dce11f2a47f21d563c3a283546bf81fb735175ed41d4d7701d1442db4b97eecdfa2ad", 16) + g22To114x0, _ := new(big.Int).SetString("113b08f27a3e294e1c8c76ec1c56b8f20f9975e5fe0a438a0e07db0d6aff6c16dce7dd4f1c54699d90ec9190857cdb1", 16) + g22To114x1, _ := new(big.Int).SetString("4a0acd850208c6f2aa5b7b63f93091a868fd5fbb7b98458c177394517ebd60ab360850d3cfe88614787267d48b2205", 16) + g22To114y0, _ := new(big.Int).SetString("17820619757a4551d1aee5388055818247ad1e016185c21ffc885497e9b0b733440d3ffb724147646c08b94660bd3ab", 16) + g22To114y1, _ := new(big.Int).SetString("3e99118c1c22ae4b8b6b7c3415e94fc7a1175c9e21431b754a585c3ff8d1458096213d49864d21c95abbb9e54e97fe", 16) + g22To115x0, _ := new(big.Int).SetString("105fc9c61c4239c7d77484ffd28b72740db901c8e645c91ba32fe6d27e27f80fe0d6bf1413432cc61b586e466d0a13c", 16) + g22To115x1, _ := new(big.Int).SetString("d5004ed754fd6d84cf35574d10f182aba51d4912f29dfb2eba5d5bf912e77f493c453b5c3e667e53912879068bebe4", 16) + g22To115y0, _ := new(big.Int).SetString("18b85ac19fa596898556653a2964ccc763d20040702268e68b31edc9a9c8e1f0d9190f1f9aba8ebd209674c7959dfbc", 16) + g22To115y1, _ := new(big.Int).SetString("174181bdee36788c13f7b8f596fbf606458317e6d8ffb6dd7ab3845095b14c6abb0b74f127a8bd70b60692589e476f7", 16) + g22To116x0, _ := new(big.Int).SetString("19c2e893795c9f4908c30ec87ebec028bb867656b3cddfd1860c0ce7e098580601d312595d25d87e66379f4ffa9b97e", 16) + g22To116x1, _ := new(big.Int).SetString("141710b3ba533bdd477919ef42f241ba8d0be61313f93d593535226a3be959fffe37e8e74086d0fe870e54de9a7e681", 16) + g22To116y0, _ := new(big.Int).SetString("c5724ad1486360a40e063ae0dd3341a17e459a4733bd7a55b3730e6fe374f7b6cb54f07af84177a7a6ab378b71a809", 16) + g22To116y1, _ := new(big.Int).SetString("8eb5b60ed48594c2047c1220efdb7b51dabc76522761aa1d18bf8cfb46c402f1867666f63dc6b406d1f3e9159141ba", 16) + g22To117x0, _ := new(big.Int).SetString("96c716d6221b9a07a2a463e79d6fad45d2439b3523d668ce390fb1f3044a61e25baa6ecc1a0db6eaff46a52709a2f5", 16) + g22To117x1, _ := new(big.Int).SetString("12d78ace80c0e9fb450808c38c714d3503a9a9927d12484263811f6271b5c5ee5d826cd502ceb95f30e3e2acaac59f6", 16) + g22To117y0, _ := new(big.Int).SetString("118133b9785c2ff52708bb511b0b10c8b979520e4c889e0ed4c3932ff864c4acf79c328b28d36c04fcba4e96b633e4", 16) + g22To117y1, _ := new(big.Int).SetString("c22a5acc14253e329632bdc6911844fceedcb42ba617c223542b51898258a9ac968338ab95070c16022b190dc8aeb0", 16) + g22To118x0, _ := new(big.Int).SetString("128b27a2e71c8b85cbcacae660242b7e96678c6ffe6484d8aef314095dd810e7ecd1bbf223f023782af6983829e59c8", 16) + g22To118x1, _ := new(big.Int).SetString("17bab7106a88e2b1c839b93bc8e0354765193a1db6de504e626f1725ce6ed51ac839c146c08830607703cf58539c089", 16) + g22To118y0, _ := new(big.Int).SetString("17336add0948febfa4425131247a1ad32b37d1e8bddd4576bf8c6e20b02be459c1d7a13e78308c99155b9a049b510df", 16) + g22To118y1, _ := new(big.Int).SetString("a12a9dac4455259b060c0255e4583d3a062cf9cc4fea1b75fbd2a58ce3837d3ee938afb5de51d7c0dc27b854b495f8", 16) + g22To119x0, _ := new(big.Int).SetString("896f479259586aa0b36b54f08af5e24953ba519262b3c8e9a1363fd12e791bad83868503c011fd3bf47a22fd79d763", 16) + g22To119x1, _ := new(big.Int).SetString("338a2904485eb48063d71ac60f5eb531fa5249e33d1e9adb4807ceecc360ed58cf5272ba1f2f4c8b12a6eaab9ef6e3", 16) + g22To119y0, _ := new(big.Int).SetString("474ab6f27e41c0df056f2cb7e3059d199fc4f92a9d16778ce32d56aaa62c5b9d3656d985be5d076366b8bb644de524", 16) + g22To119y1, _ := new(big.Int).SetString("3aae5a5f5a55b603a3fd0c46b4e007d41f8189c6154debcb168c08b7e38906332cdec201b0f7866012fd9a9097b825", 16) + g22To120x0, _ := new(big.Int).SetString("120a93c9b760fee587c33aa906c84cd3c797d40ecad10043e0450f90d5abe3542801bed7373c787c32892cab0e50559", 16) + g22To120x1, _ := new(big.Int).SetString("1624cd7090d8f657a2ff62e5693b8b3a72a4b7deb9b4875de356fc269559a71aaf88363ce4d9808c5bc9ad908d04887", 16) + g22To120y0, _ := new(big.Int).SetString("9f49a1743816757697e88399227fb7d51c1c4877032bf65b05c4a8d02e43be6ef55551394135dde051e9fede6b605c", 16) + g22To120y1, _ := new(big.Int).SetString("1a7fc715ce4d2ecb482ad02aa7f62e593d9892affdda2f72e2dbd0e4d35762fad42c77c9d02fb0b10f75cecb11803ab", 16) + g22To121x0, _ := new(big.Int).SetString("1a65ab96154bcf80f685b48371079cdde4cd34625b3c8f5f29ad17554f9913a7b4e693674e9f203672dbd2b445b85fd", 16) + g22To121x1, _ := new(big.Int).SetString("2524466b8d04adba4d1bf36e1ccbe80623e846adf23a615c5d1ecce579b4dbcd9a86915d2c0f5d1c83d6a5bbfac43a", 16) + g22To121y0, _ := new(big.Int).SetString("c7dfa1f05fccb625d733f052f238f199bfbdb3cda099b2ed018f7f4d9feb650134bb59c02e800deb3b5482289540a0", 16) + g22To121y1, _ := new(big.Int).SetString("1146360a8cd64439a81ea8374d25a4c6122156d266ff2bf9599f8d7c98d1509213cbd806a06313210eb5a0aeac97123", 16) + g22To122x0, _ := new(big.Int).SetString("188f43a5494590ecc5a8c79dd6e8370a448fd4b931627c404a56c041a1def5920d2b92f3a1bb04ae4aec56d5c904b9d", 16) + g22To122x1, _ := new(big.Int).SetString("192f56e3fa6b843efa225b84b7d2ae1674bf3bb01598c2baeecc3828a5c110cdbc7cc1bc4ee127ff2cc5119ad467f1a", 16) + g22To122y0, _ := new(big.Int).SetString("15717c6bd7aadb4a150fb4181cccf2b797b1647f9e7c10d51fcb919f542c9fcb1f233d32dc1594fb8e774598e3115cb", 16) + g22To122y1, _ := new(big.Int).SetString("10159285c6eeae18aa0d81b91d815b3150350f3197a50226c7b26fba968e1e03584f505349d6d63032cc0eca128ed93", 16) + g22To123x0, _ := new(big.Int).SetString("bc4a3957e3c08f898dc2413596ada5054c808809dcbaa3d01508bbfc3ab3d6b19db9f33492ffc6a3e22cd59bb77c0c", 16) + g22To123x1, _ := new(big.Int).SetString("65f26a6e864dfde14c7b3b49b423bafaa8076a09053668346ea337a0639ebf92559aaee8d2439fb84c412aae2ebb62", 16) + g22To123y0, _ := new(big.Int).SetString("b6692b1bfef88946d2127940e90b68da09caf45b86743e1c0e82fffa86b8acbdfcc90ff491b20a3064d4344476fae8", 16) + g22To123y1, _ := new(big.Int).SetString("176ba90c125485e53467da463d2a9382af69e51b4b1f42be07e3e1532ffa4872408fb36ca89a4b2cee3667b0585f4d3", 16) + g22To124x0, _ := new(big.Int).SetString("422c51a3aa49055455f62bd71c4a66831f8740bc94d61a3933f951178d76b70fef1732ad75e93c19dad32355289b6a", 16) + g22To124x1, _ := new(big.Int).SetString("a733eb66828edc2487c60f073b038f64292c957f670ee3988e63346c66bf28767200c4ba94fdf992a165269f424cd6", 16) + g22To124y0, _ := new(big.Int).SetString("fe987e737da4551904e19d07446d3615091ddeac6fbe51e264532872e0958eefde0537787692e2e7cbc9fda97dd896", 16) + g22To124y1, _ := new(big.Int).SetString("10ed2b3accdd399b80c8f76e24c6d7ff6ce59c6e8ec35217a63e5e7bc9660cba283540994d4b1738d5fcb78f38edcc", 16) + g22To125x0, _ := new(big.Int).SetString("1a4fc71b2ff27db2dfbf3a9cddd2422f42b229942fb410c38d386ec4b635f1a45aa627c976ced771ac3293bba0ffdfd", 16) + g22To125x1, _ := new(big.Int).SetString("6e5f5486f88051c93d84c4260198e712799e547e259fd7f4cc05f1964daa129c98728a8a24822112d7f2ef35aa6d81", 16) + g22To125y0, _ := new(big.Int).SetString("12b009d98fd0fa1feae1a4a7293187df2d1a368cdcb82cd05afedb8f60b87bac4a156dcafb2b73aa44cb85792c8629e", 16) + g22To125y1, _ := new(big.Int).SetString("13d1c92964479a73166e36883d4530ab0e9f6bd582ce60fa98b2a5760ba4c92eb0fcdceeedeb3682545b818fd98d3c8", 16) + g22To126x0, _ := new(big.Int).SetString("16d19082b276c13e9988c42008e5cfda4afce19b4c1addd0ab43c08528e51c9011d860e2f91e40e283c4ebd211b8aca", 16) + g22To126x1, _ := new(big.Int).SetString("1506770a5dad74bb30f07e0c32eb6e46049eb49aaf600e769ed1ec162d627129b1bf72ef08d5a95bdd4c4b36178255c", 16) + g22To126y0, _ := new(big.Int).SetString("11f9157b2bcdd2254394e22e5badc8bb25f5bd07082a053dca96c784ab79262e706eef2f39e4397bcb017d99d367b0d", 16) + g22To126y1, _ := new(big.Int).SetString("d1d9dafbf7e515925ab383deaa096a6e8dbd478c0f15d20b48299ce21fc574004eec2a6df2d414694f848e2630d1a7", 16) + g22To127x0, _ := new(big.Int).SetString("1067d650a5123138159b5a8e4d42313a3db29277f8a7130e1206e419d8abcc7ef9420af2793610e715d66b5a41b7326", 16) + g22To127x1, _ := new(big.Int).SetString("f44bccd7183dca1e52a3942b861222ded61113b703cb2497070dc326093d614d1b75b78b56c0e2fdafa41dfa6da927", 16) + g22To127y0, _ := new(big.Int).SetString("4b106d8eb6f92e8c7462f058b94e13a33933cebd4f0a4eff6501c757348909f1cd51719b3f654fc70f33fb423fba9e", 16) + g22To127y1, _ := new(big.Int).SetString("22f04d598b4c8ee181b01bc002b408bffd0275e0047785988c8878edc1b94e312cf4d0fba0ebbc861937699ebb7a81", 16) + g22To128x0, _ := new(big.Int).SetString("20d50fb3da7da5a58f114c7f0c1b2c3fb65b401756083636706c896dceb2e6b80e51b23cb2935569ef0d80aac7dabd", 16) + g22To128x1, _ := new(big.Int).SetString("d008b7ddca1fda0728aa306a2443c4a34974ccd4396af4117ca27a9fba99671335080b3005059271d6165132528f1a", 16) + g22To128y0, _ := new(big.Int).SetString("195a4ed75e004ce37815124c82f3d9797d6d0bdbace5f10e96cb2762f8cfb5381f71b54d4bdab9ec6182f3d3cb633be", 16) + g22To128y1, _ := new(big.Int).SetString("18fa7ec54b9808d0f754dd6d437cb42d3edef11b4d3ef1b05ccc29d0e4a829f48ea0e00b696c3ad248080b880c44fe9", 16) + g22To129x0, _ := new(big.Int).SetString("114c6d0ff787cbe23601bdfd05318d0646569932969458a171ca5e819a8c8bc028113f0553b6fd0c676b642dee71184", 16) + g22To129x1, _ := new(big.Int).SetString("127b99fa7c10f86aae2cd16d891e0020d0bc968924e439e297ab760383b869ffceaa20642afea8de99b50242ab5185e", 16) + g22To129y0, _ := new(big.Int).SetString("19d49f0d8cf4200b14e5f6ec93b6e05e16a9465eaa7291749dc0379b35b1607b0dad2134111479ffbd0f33346ad83b8", 16) + g22To129y1, _ := new(big.Int).SetString("7f20077279ff727c20a7469fc888f9c7c6eda38a8554b5f3c05a2b5944cfebe2ddb84aec499b0985390c05f1f3e518", 16) + g22To130x0, _ := new(big.Int).SetString("a572f87094301722b128def142ad4a5d676cc7fe91cd5c42a625abbf8f9270d0e7e271647b3aa16f210a03e1530931", 16) + g22To130x1, _ := new(big.Int).SetString("169c40a033abf367a4c2a2721a67c23aa22a414965636212ceb374d69bf2bf4807646790b99d77939dacf5c0d0fdbf8", 16) + g22To130y0, _ := new(big.Int).SetString("10abf4fa5662529debdbe36fd2d10880d5fde7b8ea81c3e2d8657b916c48be5f90daab4a3de0906ebacf518154b5e19", 16) + g22To130y1, _ := new(big.Int).SetString("b040108d3a887eb0c77d9acf4737e67d0a045d9f2be2ff4530293b9665f999c96950f62d953858372c9f9e7514f9d9", 16) + g22To131x0, _ := new(big.Int).SetString("a6d18b51f12bd85474f97de2e33d41d51732cd467e4bd09744b4a476118a98c160a2c1fd002e8e34ab2a4d1f332ac8", 16) + g22To131x1, _ := new(big.Int).SetString("1bdd9277e55486d6a8dffe97ebcc8731a3d586048b929d7febacbfb295f09e630695569009f05f7bd56a1066504fba", 16) + g22To131y0, _ := new(big.Int).SetString("cdd3bcd279f3bd4a4a26dbadfca0e16540df483420f7a29e1ce637d06dfb75989ab676d6234f20ec85fad8146b0008", 16) + g22To131y1, _ := new(big.Int).SetString("12e998cdcd2b23a768c17d4fc01cde98e30989e904c537332545b77cafefbd2877f2981721b1310d9e8e37061e5e40e", 16) + g22To132x0, _ := new(big.Int).SetString("c77f98d1987ae9a571660b786d68e60b5c23af634976eee9b511db07eb640bf1d065b380b286d2ad40804fe747155e", 16) + g22To132x1, _ := new(big.Int).SetString("169b1024a30d0413daae8dd6550b94c2bc0ec94a36ab8c7e98051bfc3c3abeaea57f15e64c3fd879992fe9355fecf5a", 16) + g22To132y0, _ := new(big.Int).SetString("8c5ebb3993e33ad7aff2e4738a492862b6c2f926b7540fa81b3850a8f965a27292d11e389e30b8e1e7f91969a4e7ca", 16) + g22To132y1, _ := new(big.Int).SetString("8abaaa30dd5aea7b1cde6d15c611db8d789bb6f70a10e2f196180ef07e65f7299b4579356fb4485a5bdc9072450322", 16) + g22To133x0, _ := new(big.Int).SetString("c4bf538a7a280c12bb5e44b38f94011740c152df73256112c2a9f5c56034b3c68ea225c026e687f1ce11c1f9425fe0", 16) + g22To133x1, _ := new(big.Int).SetString("a785fdd2407f9322d0b866ffc97a99aa99ce73fa04d875ec236c8ca7a64d16a3ba4e648c2a180001ca46bcf6450b20", 16) + g22To133y0, _ := new(big.Int).SetString("1a1470931d33a5269d2fafa33c8b87bd9e8f1d20786f1468addf18077486475b02067326ff0d388f225478ed55d6a91", 16) + g22To133y1, _ := new(big.Int).SetString("15f39e78bed905cb8ef2cd15ab67a8a31b9369c23e1ec4a8772a588f594962c93cede07826133572e29e33a89c3792b", 16) + g22To134x0, _ := new(big.Int).SetString("aa6df791d6b38ae79ada370750ca7a46308b69a82aaad306faf6a2f609276d8b3ff34abb23bb00eb387c09f12d0ddd", 16) + g22To134x1, _ := new(big.Int).SetString("16075bbc5f6ffc8dda29163bd466786c633572722053abfbbc87618ccc40f332cc1e809411ececb09e842ef79343207", 16) + g22To134y0, _ := new(big.Int).SetString("f911f7d1589c9b220665c775b9c20a62b3abda1ddce0aaaf1a6bfd625b3ac5b6e6e7adf429d85278d1316cab1f2228", 16) + g22To134y1, _ := new(big.Int).SetString("16221b6d70f51b5917e77e50f6a8c607df80749df9ac67f98ea75c83e15d39056267e9d8b39cf80637c1a8489f35c28", 16) + g22To135x0, _ := new(big.Int).SetString("b81e8584edc14fc3977c91e1cad8c7d96adc3452ee6b096c6091ff72d346af2b0c3a7265ec69993d7b1a0fd0622a90", 16) + g22To135x1, _ := new(big.Int).SetString("1303303a47b5012fc91dac476355191d7448c7ddeb2563fd3eeaac32d866dab3d1448355e6a424b04f77c7ab83590f2", 16) + g22To135y0, _ := new(big.Int).SetString("174cc481b2beb71ffbf6fd9b20ed623f56e8449dace2d660345e7f7393fc8db345a930c74512378ba666e670ea85b9a", 16) + g22To135y1, _ := new(big.Int).SetString("1371b79a39c2f453b69fb4ab3cd311ea3ce67705891b7b975204330f2986b55a25be2938e6a83bac6c5c90866195828", 16) + g22To136x0, _ := new(big.Int).SetString("7396d3b10e9bc30ab854f26cb7ddc957f2553af8acf33d0b40cb61e74eb4b7507e00d3ca8063fff22a38d22b3f1413", 16) + g22To136x1, _ := new(big.Int).SetString("17801f7bd1f473e6902ef85d74ffe904886cd49b6c94e10a55af4b31c6e55bd696e597c4bb9534f9ea2980474871ccd", 16) + g22To136y0, _ := new(big.Int).SetString("9d40c9a6e80ee86c838c9ae31ad6bd44afe6eb0e1b65aef0af818cfc92d75a0717ee2d50f43e45eddf695075debf5f", 16) + g22To136y1, _ := new(big.Int).SetString("13f32f4dd35f751abac1dccf194b5e676de1f83e24ec050489d4123dc3c7f5604b63e759f9cb661116fcbbd798c8adc", 16) + g22To137x0, _ := new(big.Int).SetString("14f2d2f3e6ca2d3faf140441e955231b4dd6ac3a491f6d61fdaa9a0964113691efb7570c0d940d6be65b9b92cfdad82", 16) + g22To137x1, _ := new(big.Int).SetString("1279c38ff3c132324171dabefcc2db6328be5be7f14117a99727bbdc84896bc28b6d7d7b73e65c46080ea6f79b742cf", 16) + g22To137y0, _ := new(big.Int).SetString("1ade12a0e3145a93f6b1f984a6b8809e0969ffefd992c3a06f73f802a8a820169a5edfa145ae487bac7b8beab74643c", 16) + g22To137y1, _ := new(big.Int).SetString("501fbbc3a2519805188dde6cb618f44d4548209b9779a879f7e75cef81ecebed7b3e21efb2c398a650b53839f1f33f", 16) + g22To138x0, _ := new(big.Int).SetString("16ab50189fa1ed0980ebd251a6d5d1c60e6f61286f49a7b1def2bb6b16c008411eee51e30c9837b7d5abc7416dcab9c", 16) + g22To138x1, _ := new(big.Int).SetString("16a25abdbacd210f68ac4a8925ba642a4cf53747e2f0769711ed596b78150486b62743b71a7714ecaa790b63d48ad94", 16) + g22To138y0, _ := new(big.Int).SetString("825b72644cef348b8100cac35ac5c4b04cc680935d76f4962ee4f75e0ae371663965f23fd24b048fdcc35ec589de85", 16) + g22To138y1, _ := new(big.Int).SetString("b3a1150db077c0a619eb8554935c99dcce9d6743a7287d4e979746e51505c1602aef3a457f898f2054c163e09f9306", 16) + g22To139x0, _ := new(big.Int).SetString("dbd9c09a759b9a2f8e3799c9772ad6ce710b996299d1c29d314cd062c5fb6379f712b359fd4a3b550e2371df15c63a", 16) + g22To139x1, _ := new(big.Int).SetString("a889014db555ed84eb50abdd8bf40a4e95bd518b882f9270462ab4a2ba481ebcac2748ca4fa558f88179fcf343fab5", 16) + g22To139y0, _ := new(big.Int).SetString("37e62c7bc97bac76c034f62421705fa6ff7bfd900df4b99c852fb735cf9f74a168d003a1c04c99cb5cdede0fe41b7a", 16) + g22To139y1, _ := new(big.Int).SetString("77e0c6d5454c78a8086b77dea8ac6d70ab3634253398776aad2df2d77dc1ba5a97a6d172fa7bffe90237b4b1edfef5", 16) + g22To140x0, _ := new(big.Int).SetString("9731f787fac3e03b37fdf4cf1b7ce97a2717534d046330021c800237ec4514abaf50491d135ef84186d8ee33f4fa60", 16) + g22To140x1, _ := new(big.Int).SetString("6ee7f6a61591f00c376d4c1fc02f8408422a65b6ac4a33d7eaa52a2a9b92abbc13871a6503d3f373f968c0e8fe27f8", 16) + g22To140y0, _ := new(big.Int).SetString("b1b6df1dbcb7c0d0301295c3053c095e59b94b956e04641a2eb4d6557f3daa97ba227e92824d6500cd9650272db6c2", 16) + g22To140y1, _ := new(big.Int).SetString("e94a1100050875466c448cd85d807bbd26dd7c5fd0362acd765cf1a3dc0570254e4cb1de899f3131264c8fb7f19b97", 16) + g22To141x0, _ := new(big.Int).SetString("7d3064a62328de1eca2a196ee03aa86c17d80c9ec6e4e379baa53ef235b236935f5a67e134070f82dd083d89e4ed5c", 16) + g22To141x1, _ := new(big.Int).SetString("df4838b1791e3eda0dd41dd734d340666d97fe47299422e82e5436e26fe5962b495cc9581cd0b099c1db149a9e5b40", 16) + g22To141y0, _ := new(big.Int).SetString("1329083f9f71707b7da69139fb6a24aefbde9258ca3453ca73e4cf71d858f1008b1abb2b286e3a8d320fdded2867919", 16) + g22To141y1, _ := new(big.Int).SetString("100593443c2f917ada3ec375d67c17071b6e9805630247e8343077e5e06d16140cba660a3c98ac6e8ece3d57191c3ba", 16) + g22To142x0, _ := new(big.Int).SetString("adcf903b9fa22ab52008e7224cb2c5b977940c0b6809523a9f9239612fe0c085e56eb8bd70396f87f06c5c74035248", 16) + g22To142x1, _ := new(big.Int).SetString("142ac4f91706a6c6356fbdbeaa3af8c25af57abadc3d266a90ff949b53e7bee83093e4d4d71f4f015b90c4fd7846a0e", 16) + g22To142y0, _ := new(big.Int).SetString("fd3266d726769a8c62574b8fb8c001a76e4938bce1a627d11145bc6f73673bfadbc172d166f91d679c48e7604a3832", 16) + g22To142y1, _ := new(big.Int).SetString("40c9c3e13d49a2ca6b46f7be71200240565e318ca252d33877b5db572bf183ede0eb05cf66343b082fd5417a19d2e6", 16) + g22To143x0, _ := new(big.Int).SetString("65b04e658dd09abf30fc7ed9789ae945c6cf6f7ea0b98b2ab05e501ac135da63fc4f807d8f90c2aa2813770ec02fc9", 16) + g22To143x1, _ := new(big.Int).SetString("19e2b88ba4a575cf96e15de0da3cd46dea2de5040b9ab2f02c9808701081189b4018b7546c455d69f4239faed0cf597", 16) + g22To143y0, _ := new(big.Int).SetString("123dc7944ad512afffd36ddc49cbaf03f4ec18d5bdba0fe13e8591eca3f813763851d33d0a0cc47db7dc994167fde6a", 16) + g22To143y1, _ := new(big.Int).SetString("108562a9fa3713d0a0b55639bcbb52deeed1b6cd08d868a4279db0177336eef65a3095e300b2ebcaa7d9b9d12ab0a1e", 16) + g22To144x0, _ := new(big.Int).SetString("225fce36cbbfedd78f1351a0c016f531fb61a849baeaadb56b2add9846564e26d2457f8916fae2ff08e8188606cff3", 16) + g22To144x1, _ := new(big.Int).SetString("4e2e3fd4ad10d25a0b78b798b521578fdadea0d05d3befd068c4a6201e4919b8a372b90a95640b46562730d7e0fdc5", 16) + g22To144y0, _ := new(big.Int).SetString("180af5fa0899a03733ff535415dc34898bcb7cb59b034788ae6047b8858f7436c2255a79c48234c5fea9f2874694de2", 16) + g22To144y1, _ := new(big.Int).SetString("1830600f6c6655b6ea2a261e1fb63ce8b5bfb418140f04144eb3fa5146f3edf29314b05582af1fd1a14365f5ea7ba49", 16) + g22To145x0, _ := new(big.Int).SetString("db5d4750c58e860fcf92ff53bf2259232d083c57affcbd50fc5938388ed90ed5e787dd8f1c900daa83500f93763cb7", 16) + g22To145x1, _ := new(big.Int).SetString("1bf14d05ac48621c7e1ad6d8a361ccfe9df60cac3478dcae920a25c9be9b60ac35ae1d95676b47bc18d56305101bd4", 16) + g22To145y0, _ := new(big.Int).SetString("11a0eadadc176b6648db052a60a057417f5f3998e13883dbca5a86ed3b8ca0e78678f406277623f018b697c0967cbf6", 16) + g22To145y1, _ := new(big.Int).SetString("242f0719dfbed734ff3d0fa0ac56ce3c1cfd05a5421127de1aa63471b18208699af6deb6bbcb87cfd0d9a931c4d61a", 16) + g22To146x0, _ := new(big.Int).SetString("a778740a1f0e65e4aef6c1243d4885213afb5dc1a5b9ea4667ace7a888bd65542af9f942428a9d3bfaa353f401c71a", 16) + g22To146x1, _ := new(big.Int).SetString("e6073d07b9eab1770a096a6dac8d2d9eb78c8d0d484e2098746a1a1549d5bb28a5e6acd8594b0ab802e675bbe093c6", 16) + g22To146y0, _ := new(big.Int).SetString("1045bb84ae65dca6c2bec79946262e6aa1c30f53171b30ae4cfea3851e8db45b278e1b688c461578164ac1e19a8deb6", 16) + g22To146y1, _ := new(big.Int).SetString("928a0d8347ec975f0a1f9d6a207f490bcd049a13f904dc55ce9df39d134e264d499bc05535f482d2037d71eb6feebf", 16) + g22To147x0, _ := new(big.Int).SetString("1306b2126bd4b97747d684a0de877307bdc33feddbb6c02c76c2dfc214b6e3668190d3e6fbcf8202a0348ffee5ef989", 16) + g22To147x1, _ := new(big.Int).SetString("852e78e1a2c9f842e69e246a951241ab6e63cbac75d6bb92354bf6926dcafb215222daa81172febd8bc23ac5716917", 16) + g22To147y0, _ := new(big.Int).SetString("22864c20b7fbc59ae01af7fa71def57d8fe63654a710a3188567522fa9b01f753df3c5c8fe291a60e937314c51cb12", 16) + g22To147y1, _ := new(big.Int).SetString("5aa3763b34c307f5b9d390b6fdeb414157973c024f08ff9ec0e7629e7797a8029ff344f8877e4728d95b6ab1e12c5f", 16) + g22To148x0, _ := new(big.Int).SetString("178bbfa6d69a3dfb3128c5fd3ee756ae7b20ea60b559123aa24b7a3609dddf04a6064347328ec03910a2d024c574b9f", 16) + g22To148x1, _ := new(big.Int).SetString("19175dc69cf894648e8f5b311941f618578707a6d567989ebf4d9807e5028243b40cbaa8e8a92afe0dc7de2a6fbd98a", 16) + g22To148y0, _ := new(big.Int).SetString("dceda675a2422440c838a990290ac7e632fb28372dd4ae8336d0663db7a8fd91dea772c3d80b1c1e018818333a22de", 16) + g22To148y1, _ := new(big.Int).SetString("17cafb1b930c763224262b6fd63a12cd5df5473438cf8a4cfeba55cf790a4ddb5212b7f8d40729b33691165009cc28a", 16) + g22To149x0, _ := new(big.Int).SetString("18593f92cc3092ccc64dcd9a18f0a5fa87a6886cabadbadfaf53d23dccd3ed6926d21c36068f2e6faa826fcd2be3c92", 16) + g22To149x1, _ := new(big.Int).SetString("16a1b31a52b66bbe74fb45aff847726bab0c7d56672483f1843878990ae11fe10a1742dbf02ce1a9637517f043e2955", 16) + g22To149y0, _ := new(big.Int).SetString("46145d8e6a8b9dfd48bfc60601c5d5234b1dde952f5c76abd2ce13b18fe25fa3c5e559cfb3520dd95339aab7a18d51", 16) + g22To149y1, _ := new(big.Int).SetString("92234fa5281c1b677374f2fb6e9164a38ed394fe0361f133cc4e572740a7da287f6968dfb515345eeeb7335c195dab", 16) + g22To150x0, _ := new(big.Int).SetString("fb40d932a721efae5d100d179b4c3c57239d4a2856d1755088eaae138d23c310334aabc438fb3294393d793f596b97", 16) + g22To150x1, _ := new(big.Int).SetString("1a433a2ff230a12d858ce2a0d392526bc61fdc47ad830cfc3245583249d9c95e6da834ccb0888b2350586ded9450ebd", 16) + g22To150y0, _ := new(big.Int).SetString("4825df67dbee5607d31d4c3382b32995b1bd6f6f296c898b9cef80f216c8d76a889e93291f06ea5d0851f0be67635c", 16) + g22To150y1, _ := new(big.Int).SetString("899ea93468eaf190e1e235648aff5a51d02f1d9eb387c8498ae1207d58211eb43bf56df2a62341a844ab8cacab796d", 16) + g22To151x0, _ := new(big.Int).SetString("7d766177ae55cab993416a97b47a9442478f185f0c8854aaab63355f628e1ffe0277daef2e9d6df3332d72f275f27f", 16) + g22To151x1, _ := new(big.Int).SetString("13922ae44179c6e950ba65d5e8670ceb367d7811e8e54b209d2688273f605b2273844fd57a8fa1f9208d0b70686a3c2", 16) + g22To151y0, _ := new(big.Int).SetString("10814f00e74e65669c7319f9294abdf44176d79ca76a754f7dd4ea6918a91aad78ab70d91e9eee84a208f6ccdaf9ec7", 16) + g22To151y1, _ := new(big.Int).SetString("b9cba49ef4a54df69715a7bf3dcbf4c14b58effadaadd6e896c2d4155ae1cdbeeac5b0dbfc0aa645ac0c17b8f6397d", 16) + g22To152x0, _ := new(big.Int).SetString("195873c205b8a396c90d3dbad1d658ddae06605bc03e548b5d58bc153590be282c332c62becf35647a44cb4735b4c87", 16) + g22To152x1, _ := new(big.Int).SetString("638213aabdf9f718923bdfd4db762bec7656c7bf8c730db21f277a1df6cd7ee01021481d24bcca8858dcdd48dfc7e2", 16) + g22To152y0, _ := new(big.Int).SetString("4487fedf3c4a3bade73f0ca2563dd6619a2aad7c1d57f266056ee9e3200b6be7dbd6e294c37b17e6ee96e38442b6f3", 16) + g22To152y1, _ := new(big.Int).SetString("10533d60757b534d1cc4cb03327068db40e728fa382a55ba5160bb1bca12228a710caacad72829ff1bbf28d42028357", 16) + g22To153x0, _ := new(big.Int).SetString("112aef81303fae5eb3b56d5d00ca9bfa73140ce05e6a0cefaefe6771c43c13ec566e77e48f5b8bff59be0370cbe226c", 16) + g22To153x1, _ := new(big.Int).SetString("12111b116a0dee480d483f0e36eb6dc5f2c1b3e052100f2838fddc7d52f55295be7cb6bb720f12e980e5bc81afd37eb", 16) + g22To153y0, _ := new(big.Int).SetString("3860ffe6a37e209d510f8f1a50a0f4aedbc05d6c7a8c39ff9abc10f570353f4b1b2bee6ad1baebae3653cb703e27ec", 16) + g22To153y1, _ := new(big.Int).SetString("1446ea61d416fbbd24a000284667dae8c03893affa5b13c0481be65c5ae59679ea5bfd659cf410e281971c2cdb97241", 16) + g22To154x0, _ := new(big.Int).SetString("18e6e06754a969226c043399f1f432dcc1fca211d9607f7a073545640f92ce7fa444be2bf2085d6a728bd3a33528f15", 16) + g22To154x1, _ := new(big.Int).SetString("13290121536ccdd158ac44fd4f49f6f236c1223a3ce7b27d4f8f8b48d7465b26499df351aa362fbb0c300de7c1fa0a8", 16) + g22To154y0, _ := new(big.Int).SetString("174ff5b2ab9e104c2407c05ee1f8c63877fb9191cf8d904db090f4fe21be3654cb1b7c57c42f312e2b3388d20bd489d", 16) + g22To154y1, _ := new(big.Int).SetString("e8d4efa9025ddd3ae8c631c7f92d4904b30836d41c18168834215a32cbe21489568967a798f3d21cc4bfa367627aae", 16) + g22To155x0, _ := new(big.Int).SetString("9724b55a8f7dbf0f4b2bcd140bf6d2e0f289258ac2a9f70a6c99eda60259d307be9d490761739ed46b0e944c63a548", 16) + g22To155x1, _ := new(big.Int).SetString("181c9cde6698345306d01fa15c9aa1728633ffa3df07d7fb1420ec20f002f7a769b9b50f0402913b0aa158a846ec6ea", 16) + g22To155y0, _ := new(big.Int).SetString("19cd573e8f7ef75da1fed08569009881edc9a68c56b5ab259b33006fcec80eb3754015bdf2170b7cf9e49f84cd38241", 16) + g22To155y1, _ := new(big.Int).SetString("64bb6849f998e14ada755ea499fd6e3cbc56a2762f69dc496657a46139950e1a0b294748624bdae01a38cd60680209", 16) + g22To156x0, _ := new(big.Int).SetString("934c42747f0d7e7ef78c9932d1c51e9ee1e12512878acbb5cbb8d654cdf04bda3f602ff39b62b41568d4f4d3ff1175", 16) + g22To156x1, _ := new(big.Int).SetString("2143667f4949d68db340fcfd57d1ab5e30deb6bdab32f090b916dc852d436e1bb971653ffb2ca8c22a4f10966823dd", 16) + g22To156y0, _ := new(big.Int).SetString("5f4d7973803baf12c827ec3bc006f512b019c6a031601ba773550fd605a1a97bf891967061699567f932ce5ebba372", 16) + g22To156y1, _ := new(big.Int).SetString("6cde56ce6019fb89fc5890600e036d0edfa2e084127674d0086e4e6b7084e97ea7bec79a6ba9980b03df3fec699ff3", 16) + g22To157x0, _ := new(big.Int).SetString("1a417ca4ee5b2d3f3a18d65497ecd1f15ee36e3b1da7d5fa7fde67d979e5455817d6b1ed756ed0b7be36623a422cd6b", 16) + g22To157x1, _ := new(big.Int).SetString("f06da39347fd3c2ec06b145041f2973789d7b52c88d8131f438f11397b51894f654605f1a4506f945ad8fca7b4a922", 16) + g22To157y0, _ := new(big.Int).SetString("bdd621509a691aec4b88044d71da5a2091b3f35b12ba6e23bfac872b9988e1d304f61ed5891ea59b9ca9754a1413a7", 16) + g22To157y1, _ := new(big.Int).SetString("65da5d15ffad537798719b8896aae8c5cb5b73887b4b3a1c8045c719e9034f4ae3ce427b9dea491f7cc30a73b97429", 16) + g22To158x0, _ := new(big.Int).SetString("b7245118a4ba4031057e9488e71260ee2cc38740e64ac8e8e45a62d47af26f29b63eff27deb4c2bb17e5d0e0c28884", 16) + g22To158x1, _ := new(big.Int).SetString("426dbb2cb5ea9893c5a36aa60f31997665c9d25fd986a3e3ad803011edfe830d391d5c0a06771c2cc438250d3b68b1", 16) + g22To158y0, _ := new(big.Int).SetString("186025585358b83c1c9aecb8fe47cf89715c08060346c71ff5067eec6d26719ebe934668ed9781dd79060b33b92606f", 16) + g22To158y1, _ := new(big.Int).SetString("152abe45db68965e5afd15a4edf76bd95cab91ba0190d2e4f8193f856e8ca15b62e586190352d4ece067b1225a53c7a", 16) + g22To159x0, _ := new(big.Int).SetString("1122bc0cc4ba4d7a49d71e84953dff86707a5fbf90cfcd4ee8d18e7da07e9a36c0c84efa94090ecad17de759add0cd8", 16) + g22To159x1, _ := new(big.Int).SetString("b793bab0a7a988065e9cef52a8894b86be64a81acb6d839778c334b896e2e0522a579876ddf5401623fd653eccaa78", 16) + g22To159y0, _ := new(big.Int).SetString("b11d9b881d07a4791f6aaa5db8eca850534d07f8ad344e89c014d06778f458551edfd80b809c7a1c6437dcd9e13022", 16) + g22To159y1, _ := new(big.Int).SetString("ebeabaf4521eea82a43001e254ff86a6250baa0925514955b834a95d95a14f4805217e24c90468f3ddd3ea5ca2f0c3", 16) + g22To160x0, _ := new(big.Int).SetString("34cdc4cb85c787da7c14412f557001e97aa8af9287271293bb53c6a073257fa2fb960bde862b131abda93a62f2cd42", 16) + g22To160x1, _ := new(big.Int).SetString("9b1869faa8e967f52d5014719e091a6449fd0f16da434fda3c8e1c0f664036f5269a3dfbcd955afce3f4786399f93b", 16) + g22To160y0, _ := new(big.Int).SetString("105127b44fcd4b6372954f549f3c5c74270cee4ba94e361e4621e3265a85827cb4f583212cf934e0300681aa23ebf40", 16) + g22To160y1, _ := new(big.Int).SetString("12dfdf5375c3f091604909824e1892ff4f6a8980ece75d2ad0afa7325992ab2cada983bb6f585a1b6947c4b09729539", 16) + g22To161x0, _ := new(big.Int).SetString("1b801ad1026fcdb81e265cc4f191f164bbafaaafc7c91b1c6d7fd5e9ec92b370b3306e48202f282446ce68f4b67687", 16) + g22To161x1, _ := new(big.Int).SetString("12964087b8ddd4bf68725b59f9fd12e835483c8456f7254d6232de8111c40fe22e985ead67d0a41e94b9429aa907805", 16) + g22To161y0, _ := new(big.Int).SetString("3d28e1871209df32609e8786b9e414f757bce8d8da35556cead21a32e00d60ba60d6de0578ee30921070237e9b2e72", 16) + g22To161y1, _ := new(big.Int).SetString("48a22d8116418a5cde329de2ee7603cb5a38efbdad5a64f471595241566bd9ebe3b786aa6bcf9debcb5a2b5b4d4515", 16) + g22To162x0, _ := new(big.Int).SetString("14785f244b218b8ed9f26173527e3e1dc4c36b312b2fee5fcdc9486189c1d971128ee937f0a1dc1485f7366708500b", 16) + g22To162x1, _ := new(big.Int).SetString("11c239e8ab8999138c5ab032dc83a14859d7160713fa2a9df137e18f559f343e2c6951cbfdd1b70cebeb1784bb95565", 16) + g22To162y0, _ := new(big.Int).SetString("13c21f6786fc95b72d4053edf1a4f38c2a323c6a2fd0c934d987f776a6f3366e364b57cf6e63306b3a83ea81a516e41", 16) + g22To162y1, _ := new(big.Int).SetString("b70c814f6220b6fdc1bea846efae250764ca457bf0af4c9252bc5011182f50e71a2d5e5d4353d33416b72f7b45b7af", 16) + g22To163x0, _ := new(big.Int).SetString("1268de52d553be697456965d840b9649539d26824f18c0a7752921ddfed39d44d3335e11493d7a95896515a9cdce6f9", 16) + g22To163x1, _ := new(big.Int).SetString("734c630cf3113a798cbe0a5956c011f0f03c98f8d2b986b25f1461acebdd65b6beb34be8dfad9bdb44acc88a82d661", 16) + g22To163y0, _ := new(big.Int).SetString("d515acad3ca797950762ee9fc03a379cca20e9eb9efe9e7534e4c6feeb20677d8447876ddba2a3b72ce962b18cbae", 16) + g22To163y1, _ := new(big.Int).SetString("3c06d1b83753e622ddced8b989469c3b0db7d438b9ef86f132843b19402b7da1d2ebab68af7a7748feda43e9c1d5d", 16) + g22To164x0, _ := new(big.Int).SetString("ab426d03d781675f341bfb0342cc1f365803cecf7b77a5bd035853123dd75c84e4121fafa20251dbc4e457700066a2", 16) + g22To164x1, _ := new(big.Int).SetString("fe73fc1d54259bf0105ed62ff51c77b7776149096ff738597054d958e53452843ed873de67aec0b7bb0d0cf6f99fc6", 16) + g22To164y0, _ := new(big.Int).SetString("11e62abd5c1fe8b96d8c7c43bfcf73cc25a0a360fc22e06019fb76e2aff6100641ac69a6a0445ca9111ebe926a8c0c2", 16) + g22To164y1, _ := new(big.Int).SetString("2ab563980bd58b949d10444421cd7f824515bc7c9fb10b4060baed61f8d49b2e20dbd5777f8141c0d0875bf58909d5", 16) + g22To165x0, _ := new(big.Int).SetString("18d88751787c71464c380f49a7b446737876cdf9ec99b05f07dac65cc3461400f7e0626eb8d5868e73e0119b49c4f93", 16) + g22To165x1, _ := new(big.Int).SetString("2eba1511fbf969d719f5f90ad90437ea51b421603d872b5fe8bec93f8c6cefdf6b0359808477ca8cd8c14917b68f45", 16) + g22To165y0, _ := new(big.Int).SetString("197b4019bc9a9904030b80577d3f876f9338933a605ee8dc38f38684ccbe310c71c479e52f5b6491370b7c6d48440a5", 16) + g22To165y1, _ := new(big.Int).SetString("1250dd1975c4ce2a0ca8696f553228a8f0bc5ec835ac7ba4a246aa708c75457e7298330b038593f40db2c9912d2af5c", 16) + g22To166x0, _ := new(big.Int).SetString("e4e95116c9f67d0cca628ce0bcba3bbb4db3c19fa87faae79ee6fbeec5e5916117f7127af9fb0f29cc3ca92d03ad68", 16) + g22To166x1, _ := new(big.Int).SetString("ca43ef715bab239563c30c85d2e2e255d1bf4adac0a0976fef3c90bc0dadd4eb32477feca71c461a9805689e0c8edd", 16) + g22To166y0, _ := new(big.Int).SetString("b4d83664ba7d8a4230a1010eac05d6c6cc7efc1a87313bc3182ae33b83ab712fc0ee6b761144e58321cee48fdb11d7", 16) + g22To166y1, _ := new(big.Int).SetString("1783452da9e728d9d626ebf1067c114b449d9c5b6f2a8d321bed4c5bb065cf8db40166863b77918f71bfabf1022d068", 16) + g22To167x0, _ := new(big.Int).SetString("1785343b8d3c90ea256d119f46afe79f973baa0cb38582cf349e62e2b3a971b152c8c910a643251bfeb0d7d30500d28", 16) + g22To167x1, _ := new(big.Int).SetString("b03095ee270dcf95a80e40dbbcab03aabe005784a6c1d4af7bced134aecdd013c89ecf6af45f0ec1a9b0a4faab695e", 16) + g22To167y0, _ := new(big.Int).SetString("b775b2198362285d659b9ffc47c71afefd7c134c0b1a186686b26297f148185cf2a17b2efd6cdf695e773a28caabd8", 16) + g22To167y1, _ := new(big.Int).SetString("194a0fe85e939d4b9ea621b20661ac493666c1cd7103cec77464d376482e0d9e0577e4ba1991393c91e6081b7616cb4", 16) + g22To168x0, _ := new(big.Int).SetString("13d57818a8d575d0d26112819ef30240da84ea0760235cb1c2645be7db84eca73b1b3e1cb6821749091ca33629868fd", 16) + g22To168x1, _ := new(big.Int).SetString("7e9f1f023be3f7ffbcb807c5edb89d0d00ae87a67636e522d98df751ba0122a2c27a71fbccc2ac37091bed1b6d13b6", 16) + g22To168y0, _ := new(big.Int).SetString("e81ee2d6b656b930924cddc1efc437490c45b8bd56062a01c26f1619aab49614f5313841410df24a64ee7d8936574", 16) + g22To168y1, _ := new(big.Int).SetString("e2463afa2f0436f9ce3390a7031bc4acccccf05638741c1b9dfe7d5a6b57ca4df8483229eb23d96560d7f0c1e376c5", 16) + g22To169x0, _ := new(big.Int).SetString("a660477fa15e554af2e6b41cc221edd322f86a803589ccfeed0a0aec7eaed827632d69750bdee6325a79bcc8cdeaef", 16) + g22To169x1, _ := new(big.Int).SetString("29943ba93103da145a33598da393f26161e257b7709b263735d07210450b4dae347badc66ddcbc6319d7ea10b20d78", 16) + g22To169y0, _ := new(big.Int).SetString("16578637825c5641ad7816f20532d6b9456e6e20a8d5f9ae2dd8228b2d363a881de7e5a17bd661a96e8bcea73695ec0", 16) + g22To169y1, _ := new(big.Int).SetString("eb9fa9b2ff1a54768463a3543ad3cab025b848ce347092785437c32f89462ce442e74e961c3178f57ffd615e707229", 16) + g22To170x0, _ := new(big.Int).SetString("964429f4cfd4c044380c9c7a285beb866c85143367d701684f5622f3ac0794a223c050d738b1819419b07ee840ed34", 16) + g22To170x1, _ := new(big.Int).SetString("9db142c0c482a63de55c2b37d424b82f8596f50f7da5951d2c24431419c8bc64bb8ec79fa071484825088795eb1e27", 16) + g22To170y0, _ := new(big.Int).SetString("de17ef78c59372003f8331f1b732413d8a8ef29a669b9d1d00b401af62dd38f88ada21cd53d06b247b450f084ca810", 16) + g22To170y1, _ := new(big.Int).SetString("11372e56e2e33c10cb73480f5fc5c0b4d8e000ec4b6cd2053755a5e82edfc3e2d702574d68cf08911c8398f4ab2efc8", 16) + g22To171x0, _ := new(big.Int).SetString("6ab88dc7b0408be4fb2f7f3fd3df811ce763d3086bda785d652c0dd26bd68f35fcbc17e1538022ac3f0e8b664617fa", 16) + g22To171x1, _ := new(big.Int).SetString("14b21a03a57b940e1d5d1739af80f8b8a9270ab99fe31d5bf81563d74d6190dbcded1dfa064e3040df5d45401a0dbf", 16) + g22To171y0, _ := new(big.Int).SetString("14a7f24155c15ff39bfcc5a7f358c9530e770747f6019773d92bac2df69a51e792d10ba8518bf3e9e6cf6f58349f3a2", 16) + g22To171y1, _ := new(big.Int).SetString("151c1f726ac3768af1981153cd913dbae40721029a517dd9a0765ccbd724c269d7235749caacd9ba8070241fb285feb", 16) + g22To172x0, _ := new(big.Int).SetString("12efd6c2f6911aee3d21d8fa488b605347c41125fe68829262b00247d74e84f06ccb597bee1d921911211e593df0450", 16) + g22To172x1, _ := new(big.Int).SetString("6255edac9111a1e7074c4cfbd8102072b5a9ac55b83af683d85abf2ad60bb4d0a6f9f3a5d16b3acae502f541cc99b9", 16) + g22To172y0, _ := new(big.Int).SetString("5b213cafb5c6c7c34a28b0c6ab235d7de110ddea1f917741f56072754f800855ad5a059c144dc850e94723468f2130", 16) + g22To172y1, _ := new(big.Int).SetString("46eb29842f0444847a3de13da0b2e75765504e3dfc0b77c3e7b068755a0c0ed0963d9adad93b42178e98a38a23a5e2", 16) + g22To173x0, _ := new(big.Int).SetString("3814ec251b7b79f1e70f064ff139b0c27b808972a2fd740b03e8332577cc789906b9935609f4f73b3daf96bd87acdd", 16) + g22To173x1, _ := new(big.Int).SetString("26a23046751895915b52ede7c9f21a423c2b5eaa30d948b56f98fcf8dbd241e6e978b055c1b7a19605c709976d3086", 16) + g22To173y0, _ := new(big.Int).SetString("7129e3ba7668ae67910718320388b23c5132fb6954b4cdbeb83d3a9362dc35771d1229690336c8162392800b0d023c", 16) + g22To173y1, _ := new(big.Int).SetString("1352ee185e0a3d76d1edf9fb77385d1330fb619cb986091c271b47443d47962116ee62cf43d7255a9f532c8c36f45a3", 16) + g22To174x0, _ := new(big.Int).SetString("191581ab909f78c8564732d07db80a5d64e75915f4ef218362870ee353cc9e2166e6535ea8b3551a2a25a294f475ccf", 16) + g22To174x1, _ := new(big.Int).SetString("1083861af27e47601f66688173f994cf1f2c2a0941150f7786ecae4055aa383c954892829206ebe949b30d16641cca5", 16) + g22To174y0, _ := new(big.Int).SetString("150cf58ab9072e91391513d8417703bd1d57daaed70a2b7f9a2607efa5731b529ecee031e7a10338b4415d755732c13", 16) + g22To174y1, _ := new(big.Int).SetString("19c6ebb093c4c1fdd3ea83dab59e32e2f65c494a0d07637212cb2fba70eba9020598f6d7c539c0762f4482199bf257d", 16) + g22To175x0, _ := new(big.Int).SetString("3c8b331eeccd65e4e28efde4779237f919acbb4dad26a1719d6097b8a4e0ed0db0692e2e6796e36671d750ee8f35d4", 16) + g22To175x1, _ := new(big.Int).SetString("1670e9256ec07bb6df7921a9f09b7f3be1c5ae107565988a2dd66e5f8856d6b3e6f43f9db3fd0b6adb327e892daf22f", 16) + g22To175y0, _ := new(big.Int).SetString("1065e362ed88dd61b9c6197c2d8aa21c4eb29e784d5e5196ecc98fc1b9037963d6c7efd7b3eca906d77af1f9a240b0", 16) + g22To175y1, _ := new(big.Int).SetString("149453bedf02098828820834fe7fdb0112c6e5f40b495c4dd794153077a67577d183d91c452e017d3e29f7e5bad8203", 16) + g22To176x0, _ := new(big.Int).SetString("3d8494dfe4b6a0b2c0a2ae7afb0209e57550b2ad841dc1ff12d4b1e040661083a9c7e8272143ea13ee6265ad05c55d", 16) + g22To176x1, _ := new(big.Int).SetString("14b51e710b10b0c8579eb1cea3b3ebb9d9952198c31b7a985614943323110813f7cf038cda7fb75cee1cfee37498110", 16) + g22To176y0, _ := new(big.Int).SetString("ac65b6b7b11c15aa71ebef8b7eded583ae3da5b9b7c3ca1fd27d3d435bb3e63e97eae24f3e54e288222c98e3a6d148", 16) + g22To176y1, _ := new(big.Int).SetString("14796638f84710cb87d1ab2a59627ec217c1f01ef87dab0d5e000d608fef957386d83bf5648d96747f8a2a949fd0a8d", 16) + g22To177x0, _ := new(big.Int).SetString("161ea981379a6afca65a93ba3a4daf23ffd0446e96acc7ecc1aeba00a0a74524935b75de10de14ed40207f3a6f6b954", 16) + g22To177x1, _ := new(big.Int).SetString("a5f8c35b788bd6f5ceff4ac6e45f32bde0e6184dc049537da188800e6cf6ffccae73235e55b8f40c97e01366d5ac38", 16) + g22To177y0, _ := new(big.Int).SetString("12ded1c786e998099bae2681b841801245b253010102d06cafc13ce60db2ddb8cc6875a1ed1a7b43f4eec3a7f3e636f", 16) + g22To177y1, _ := new(big.Int).SetString("611263b6649d86793ffb0bc7f5d3d5dddd95c285e99cfd27f30803d0bdff388ff4cf65e7ced280c19b5cdd4a1404d3", 16) + g22To178x0, _ := new(big.Int).SetString("10f8e43f38286b18461d07793eb04a35aa44a68c7f01122af1f9ed7ffaf7d3c2955f2ff46c755d19a2499392b0c1976", 16) + g22To178x1, _ := new(big.Int).SetString("ec440608db7429a9a8d22c4c52db6ab8bbdfa0effd5ce1766872919cb9fc116bc0f228c51364689ba6d8116df5c7c2", 16) + g22To178y0, _ := new(big.Int).SetString("47ab8f5a9e4d0632548f4ff5c545a178ebf35ff2903432e3f0c89450dffdaa268323bc50d8665406831327765353e0", 16) + g22To178y1, _ := new(big.Int).SetString("9256c5e29f1efa3ecc4755fa80e5be91b9921a30732ee911ffee2f88c12757453358b93a8e4ec8ed8437c28d9623a5", 16) + g22To179x0, _ := new(big.Int).SetString("3cb62eb22b3539f4c4b936f6ca48ad922879be90406618f462a24d81ccd398f8251feedbf3d566492a4fde1036ad5", 16) + g22To179x1, _ := new(big.Int).SetString("d8f0a91e62d1e81ab2e885ea64d5e8b459381850aa7322e78cf90897d43cc82d150dc16e09be130d9f891fa401cba8", 16) + g22To179y0, _ := new(big.Int).SetString("1418b1e6a76eb7661359ffa07a4853286c8e704b579bb90928dcc520f100a6b7a10dbce333ed65f278a389c1460b0ab", 16) + g22To179y1, _ := new(big.Int).SetString("15d56c73bcfa1ff5ee36a5f7d3aa2f8f9963b85f8190317bddc0dd2eaf599d0533697c7a7ce85cf14f605dcf40d8e10", 16) + g22To180x0, _ := new(big.Int).SetString("162d941ebdad5e4b76f11e7cf6ce152c5f218ed9500f99e25d2e3813177d53c80150d377028593000d3a7b088507cf", 16) + g22To180x1, _ := new(big.Int).SetString("19a054614381d2c5a64780aaab6bdf93bca7995752813a92419ee5c99f4065f4205bf0204b48cd91db006b4ba795ce7", 16) + g22To180y0, _ := new(big.Int).SetString("7c80715d6e78ca83584728739e276deb8e4095ac8ec8a969c230c273bf53b505942e6a27e8be98f3d7d42a6975cba4", 16) + g22To180y1, _ := new(big.Int).SetString("11e57634d82e5e15ee91501e88daec71a9aa859dffffb517b5d089404799022ec87b03e4f4c2f4893d831d97f56782b", 16) + g22To181x0, _ := new(big.Int).SetString("e8924bdb603f0698717cc1a1cc609fb239f084829d8111e69793bc4135f450f03705426a1c79cfd1bde27a706abd18", 16) + g22To181x1, _ := new(big.Int).SetString("1855031de3a0ee38255aa2ef851579cae1c28de22118659a51f19aa34390e108efde00ba29c74f39696eb6ba87d647f", 16) + g22To181y0, _ := new(big.Int).SetString("60cf4b043da7ee813d0133ce50cc7d7fc474ec7a3ee6872356a7ec3213136bbdc68c82c74174b319c6013652579caa", 16) + g22To181y1, _ := new(big.Int).SetString("13a362ccf8e31afb614dfeca85b929a7e92b0ebf4916373255d6add81f7408c23b39d5ccdc0351a64f464b7a1c26d92", 16) + g22To182x0, _ := new(big.Int).SetString("16c865109bada2d39410992462c0018fb339e3003b48129866b539db10476dfd5605da6f5b7c87c718526d23e9a9c58", 16) + g22To182x1, _ := new(big.Int).SetString("b1ec4e33168476362c95600845b12b64a188a2d867c2769b85c1cc1b4006f5082bef453b0266875a26e6259186d9fc", 16) + g22To182y0, _ := new(big.Int).SetString("54f4f301628ca2e66517afecc925d04c7c74cc086aec0394b01aae096179018ba9df43cec90574dcbc3f527f638408", 16) + g22To182y1, _ := new(big.Int).SetString("490838e264f89b1226916b1d7f929b43b009059d539116014ae9f31182f350283ba2f1cc7cfe31399b0cacc719a566", 16) + g22To183x0, _ := new(big.Int).SetString("16c41d43990fd3d34ba8c3f23f23af26444aef9f963aaf19d3cea7546487189febda6f22feda351a79e5aa9e58185d0", 16) + g22To183x1, _ := new(big.Int).SetString("96eeb12f356f1b2a5602ee1f72c19448e4551f4c0492fc86b939e741a12b976eb91fa3355b5e48ddd292e411c18ffd", 16) + g22To183y0, _ := new(big.Int).SetString("af2980eddaab0c34a5bd64b4d677748ae56356880cefde773b8ed82ad4d45f839dd04026455b53dc55f317ca8c1842", 16) + g22To183y1, _ := new(big.Int).SetString("a16bbd8b7b66293813e3d1f1327559e9bed4407a02c57d956cea5ad3ceacaaa92536fa0b123d752dc2324091d284af", 16) + g22To184x0, _ := new(big.Int).SetString("177e123409a926662dbb1597a8289a94a5f57d6d6a3d02ef895e8b22ed3b82fd6585f263857fa14d2a4dd6c6f6a2d3b", 16) + g22To184x1, _ := new(big.Int).SetString("174d2b0b4dd659ade185d68db78bc92c3ac92636586e8ddd759944f5ed7dd81ff5bf8309b9360e569a505028773be24", 16) + g22To184y0, _ := new(big.Int).SetString("ced151199bd6562922d7802531a53ae04f721d19362a421ede53e5e0d9b9c6dc7e2ac306764e053d98eaa8f4fac7ef", 16) + g22To184y1, _ := new(big.Int).SetString("19a5ddd6b518b0c6c5168afe24612acdfad1912da50027bdf6a30df292d5dcc74bbaf73ab560317bd68c3e325e59205", 16) + g22To185x0, _ := new(big.Int).SetString("c43f38e341a9fbf94dcbe89e11fabf3d63e50bf48b32ceea64801e3e2adf0a32ae0dd9deac34158a6387d6f6103329", 16) + g22To185x1, _ := new(big.Int).SetString("9227c18ba33206a6dfb7c6a1ef2a1dd8589565649143f371bff6829beb072ba09fe1cb1c86fbf8e0cf8106b4dfb171", 16) + g22To185y0, _ := new(big.Int).SetString("175defc61f1c9f27d12f56770fe1381961f867749223765108dc80426079a5d5737161b8153653b7a3f17264f16e0af", 16) + g22To185y1, _ := new(big.Int).SetString("7cc92c44849b5c3c819d9abce5d93f7e32b8028fa061d59b4477dda5919157cb6a3af81b39de6e381017c1d9f6802e", 16) + g22To186x0, _ := new(big.Int).SetString("1d0b14a712e20c2dabea0c6713fec6eb7e5620961eac79c37e3af948d00d302250541f51da564bcb70b87f536f12dc", 16) + g22To186x1, _ := new(big.Int).SetString("155854c6c319992a201136c825474e74eb23b1cc77c0656912133125cafd7409f3a27485f72edc1f084c09f9b00c152", 16) + g22To186y0, _ := new(big.Int).SetString("19eada35bd6b5c4c2173c017e99f2fbfad0d45423800d35448e47bf66b9855c2ff137c2b8c37d9f9af11f8b61b9bfe9", 16) + g22To186y1, _ := new(big.Int).SetString("153fbc4db6232ced58e8c0157b98acdccdd2e4e244d249c380db6c49bd2976f4453fa37f3dc479c11651fd031dc2141", 16) + g22To187x0, _ := new(big.Int).SetString("82a47c2d4814cc657f2af54a1393fbd8a662e5c245f7f30d822615978b05b20f6f08baef524fe08e9c3adc4d599d22", 16) + g22To187x1, _ := new(big.Int).SetString("ad6ef72085678215fe05ee6ce8666cb74674145953c934ca22a91691a625bd3a66484e275d055bfc1b61ca7b16aa16", 16) + g22To187y0, _ := new(big.Int).SetString("17ae5fbd82fada89872b3409fbe7a6e9410c8e3d134a11830e97dc41677c4775e06f87a528c945fd587c52c78255fed", 16) + g22To187y1, _ := new(big.Int).SetString("14fac643b226643cb21099fa596706a4096f5096af2b7883c9743665715a7cd3462cb7744c73e0efd0647c6bd0782b2", 16) + g22To188x0, _ := new(big.Int).SetString("12a1e00e666b0f5d26ebb82fc9fd58ebfb380f7d418bdc0db518c27c88571b156c4e50f1f579b4b09bd42a9d626ecc9", 16) + g22To188x1, _ := new(big.Int).SetString("15dea18b4e760631fd445e531798908f30780c840269e64445b9ed47c56858246e46d7b752efd953090f8f7c2507519", 16) + g22To188y0, _ := new(big.Int).SetString("164e4a7613d8404530158ad89e80143699cdfbdea58a61d341c611a92187257ced9fe355cb72b15f60ed06028042ec8", 16) + g22To188y1, _ := new(big.Int).SetString("13659364f1d7f033ec672ebab4398452cfee7cb0ed7597dd84167a6ee87257099b3fe39ae463c5a137017556fcdd21a", 16) + g22To189x0, _ := new(big.Int).SetString("bb7a545c75873f572bae79a8e7dec8011b6328b90f71821a77c4488ce7285c6894276d8ad64c06715d520828579464", 16) + g22To189x1, _ := new(big.Int).SetString("fa6238e908ce234a6cc8982bbb3bbc3c9f0f20db267d6bebc666761a03a14657c879a2a826a2cee7cade70d210426", 16) + g22To189y0, _ := new(big.Int).SetString("17c937fc9f0a0f35fd7f57cd5f19959ccd4a620f0b9926a096331b20db4406f3ae1f5199a2700bd3f902e3b195a65f0", 16) + g22To189y1, _ := new(big.Int).SetString("1a07b76a76d2791a83994a2362e75083f198629b7377696514151ad1ab7b00e0ab89e3d5b426e74751887d53b0027b3", 16) + g22To190x0, _ := new(big.Int).SetString("1061752353a1a4ed2967fc5bf4d6fcfc7cb11ce432f6e91fd1161aa7f873b37d40697297738d3e4acf1d20cc341eadf", 16) + g22To190x1, _ := new(big.Int).SetString("462ef0cf13510a6dff4e77120135f4620ae55cd3ae8171623e61833373197b347e1fc2556759b509a1828cea59b904", 16) + g22To190y0, _ := new(big.Int).SetString("1d699d18f4ae8c9ed8b9cc9b31b22cba2ea1d60b354166f3e2435a00991600fe837ae3efc88935214c877aa0ba4fcc", 16) + g22To190y1, _ := new(big.Int).SetString("e7cd74c48870cc438a08a5b526f951b26551c5e4f15d0ed7813283bb2bc5bcf8bb3f4b31c6fb7a0d9e52443f60018f", 16) + g22To191x0, _ := new(big.Int).SetString("176f7d137de6b389689628affd2b553c59c50eb5ba35cfbaf204cf1a9cefef3ef8385a3f3bf5bb00e2bb883b905cce8", 16) + g22To191x1, _ := new(big.Int).SetString("101a3ea411540c648ec08269a59743bd0ceaeef46eefadd3fd6af78695871d26e1c3d84e2ed36025e0743e34153f777", 16) + g22To191y0, _ := new(big.Int).SetString("10b2bc6f4f0fe34adf2addc89bfb25a6953d8255c836b15b2695e75acc928c80c2d2e3b73f57b28ad659959533fbb74", 16) + g22To191y1, _ := new(big.Int).SetString("5a78199d438e4e4fbb5c86c0f5929918c2d8cf7db522b103ce51c5c1a67f350fb6701946d5059b3ade69be1ba3ac75", 16) + g22To192x0, _ := new(big.Int).SetString("153558b37cb8f931ba7e4064529d424d994ee31338561340d20f1d5719cd70218ef666ab5174509e445a4a58ce7f13b", 16) + g22To192x1, _ := new(big.Int).SetString("69f3b76b5777c75ad357739f340dffc92385af60a8885a3aed3e3ad7964407bb4c21231e253ffffe5f502767cb48", 16) + g22To192y0, _ := new(big.Int).SetString("6ea050f302f35784f852191a6e2d81fdc44724c8f23b0532f89d6ad34f92e40ac9c878135322b69b5479ce62d65b1d", 16) + g22To192y1, _ := new(big.Int).SetString("bfaed965cbc9161c6035cabcf83111a3366a72235c0001049acec069ddc4b046e8ea464a512497bb9dafc3e73873fe", 16) + g22To193x0, _ := new(big.Int).SetString("77e9d758ecf3cfcd1f819b205c5743e580294a24b64fda64b7cf39bdb7224f2808039a0e711b85ed1d2f1104cfed5d", 16) + g22To193x1, _ := new(big.Int).SetString("15a37bccef73d05e789897b29ecb339d2ee7715a1fda7b7bbab1af9087b4df7788c1af72e0a2144e24780eb1df1868c", 16) + g22To193y0, _ := new(big.Int).SetString("afc88792d7c8af2e08375f1bb75b15ef00a88941ceea5be159138506d69e87a0dfa24e8984cbc82a0a29fb50ea99ec", 16) + g22To193y1, _ := new(big.Int).SetString("faaf1bce65d00c1e1d084b68adf8b903f38c21ae11551a60aabcc95b2287614df3fa1c7696e964d5477f898694da99", 16) + g22To194x0, _ := new(big.Int).SetString("156acbed69aac3eef3180485cc061d66000c51604ca8b712be5bc2674a45cef5937a509510d4a89910fd425793b743d", 16) + g22To194x1, _ := new(big.Int).SetString("eec5b89fe13ddba6e10aa81246643cd74a15a0e399c6e10fbfdb393ee28ef487cdab642820daf9b7c614460abe1e28", 16) + g22To194y0, _ := new(big.Int).SetString("e37062d03b1e305fd12c5bc7d5fddc20cdd2f64b00da3d0da04844f5e94cc1f1aac190fe8c91388d480b713496997c", 16) + g22To194y1, _ := new(big.Int).SetString("2029e5dea105184417f748170c9f4fedb613dc8f19636dbd03801629cf195bdc556f45ac00742d9cbd5675517d7d3b", 16) + g22To195x0, _ := new(big.Int).SetString("48c0cff908c19de347216fa7b7ea3b7988579a9dc8f180308226a0498ac7e8430b1287fac3d4c6120cc89df96681ec", 16) + g22To195x1, _ := new(big.Int).SetString("ead70a85053d30a2692c6181249e90515c1f61b98ea75a27eeabb5048c203a28058919c49aac7d1ac82cfac6db81e", 16) + g22To195y0, _ := new(big.Int).SetString("c612c93d06d53d4f15a06940554aa24aa74120c6045fc21442f73d68ffd0e5054a09c66229e77e8b4ce104535706ca", 16) + g22To195y1, _ := new(big.Int).SetString("117947328de124499f06bcbfa4bab52aa5b654a23471a1f0123ae5f3a3d600e5520d69deefcee0100e3ba42508a8784", 16) + g22To196x0, _ := new(big.Int).SetString("136bb1151504b58908928901ee1b122bfaf38d5458c2321ed849918ea312936da4be57348767c15143a515f41791431", 16) + g22To196x1, _ := new(big.Int).SetString("137ead55c1e232cb4d37376192c0f26f6d532fef24c13a4c42f81130e15efa864b825241cece715bb6e5d4489240ee3", 16) + g22To196y0, _ := new(big.Int).SetString("d83faffa108a1bb3dac1927e34c91ba7ee25eeac3fa16384dfaa907baef1fbd07c1c7886ed618f78a30b9553e0dbff", 16) + g22To196y1, _ := new(big.Int).SetString("2df77fd6250ee3ac5b276dfcef7d988b15dafb2d58702f4823befbbf434dc94f04f32be62b415b41443edd67b38f00", 16) + g22To197x0, _ := new(big.Int).SetString("177b8fff5b018fce944bdd0fdb05c50f56b883cac4d00b1165e81775ebae4392731addb19664282a083e802d9a05d04", 16) + g22To197x1, _ := new(big.Int).SetString("11ae7d925d111f31692ea118660651f948958d3294a4894da543814781b57f826bfebbf9c6e87303c8ae693c523b180", 16) + g22To197y0, _ := new(big.Int).SetString("18d6326b0c103c61909f340244ea7c5b8ef1bad5f216eb7849656181da2a1f57f558c92402833d44a497906cf3b8c15", 16) + g22To197y1, _ := new(big.Int).SetString("135c96c2568aad584c9f292e892ab7a152de779331f95652d8e29940d8f4a028aefb88b6e3f21006fa68f5d1a0fc567", 16) + g22To198x0, _ := new(big.Int).SetString("31c0e8da14145a4c9ba9a41a0ffd1197180517506a0593e60e92c4da5264638d9e3d3e3be42dac813f2c85a0ed2946", 16) + g22To198x1, _ := new(big.Int).SetString("1335a426519ff4cd9bc2c0e22b55958a61f4759395a206b3aceeabf37054a1d152a7b572353f374f8855425ef88dbb7", 16) + g22To198y0, _ := new(big.Int).SetString("ea5c383b2fdcd22089a0d5528a7966117a931a2ef54df7a723ad90e77844ea107f0167080828e8af146d5b389b245c", 16) + g22To198y1, _ := new(big.Int).SetString("864cdaf78cdd6d1806e0590b4d1a8fcbc5d391d4a0d6db17cfe9c7b272adf90904fc4d7131cb69863cb4b19dcca279", 16) + g22To199x0, _ := new(big.Int).SetString("eaf6ff91c8655d9ca6ef855568d730582855094b4532ebfd837c3f3f2b27af92d23f57fe2a3398132cba49a6ff5baf", 16) + g22To199x1, _ := new(big.Int).SetString("94669b0884fa8def9975c8d2ba4ada9a7e17b949b0446195b3129562b2ed5bf6dc33e93b6007fa3e18625e139793db", 16) + g22To199y0, _ := new(big.Int).SetString("b850a2a668d756e4e277ec1a5b124289ce9439832cf1dde56701660bccfc307453fd0c4cf57b9604eeb4b2fa0cbd3", 16) + g22To199y1, _ := new(big.Int).SetString("76128cc540b5194496af06b79be254c0335301980a8aacb330a3cd90bbfa5a350c06fdf742f3de055fef4158d2e389", 16) + g22To200x0, _ := new(big.Int).SetString("b113ceec83ff707b0693261d9ac074f97d23ded30d1e0f9bc9baf1bd962ca5ad2d3cf59290a5a5cbf6b9e8bada334b", 16) + g22To200x1, _ := new(big.Int).SetString("459cb96a51adc949db844c54ca3390d113a2e494b0d3fc712e22e21132a40948192e63483894fb3c8a2a40a7711746", 16) + g22To200y0, _ := new(big.Int).SetString("104a9851495bbdba65ad32abb29311898f27847d2b338f206b797855e7d2c10a3f36996f79936e9e4860e4dee596c40", 16) + g22To200y1, _ := new(big.Int).SetString("1a1ef4db81dda4ef6163109b09e4fa0dab796d4252e84b9c96f8e536fcf00b161508a59faf69084cbc9b5d67c3f21c", 16) + g22To201x0, _ := new(big.Int).SetString("198ab2694f6b2e0345d371476ad14a21646f21fec717bfd6a04dabe2f7a53b7582831e681295dea95c04cf73ffbaa07", 16) + g22To201x1, _ := new(big.Int).SetString("4063062d8e19103a82ec8703aafe1c5a7f3716db3f9b77d9ca2cf5c604b8883110191f5af9a034f45a3952f4fcddcb", 16) + g22To201y0, _ := new(big.Int).SetString("dd8d89c99a615ec5c8000549b84315eeeaaf4553902bf3c05c8f01b6d4dd98945b61c807fc03dd861d817cafbf1745", 16) + g22To201y1, _ := new(big.Int).SetString("6d9af1577122ea9c28281c4114305e0e206a52e738a454cdae6203a67a560b2b06ed21e2d2cfa84634197b4d6e709d", 16) + g22To202x0, _ := new(big.Int).SetString("9f80c9431f688a7715779dde5bc1beed5204ea40249660a678544ee75c0b0e188ae70f38d9947194f123e62ece8ebc", 16) + g22To202x1, _ := new(big.Int).SetString("9d2f3926446dfc91dc28dfc1ecf272e83bf1d616fe2b9e0d82e8e1fa9014ebb0fd66e8b1aa83820580e5608ae61a8f", 16) + g22To202y0, _ := new(big.Int).SetString("662e6756f4e627a61114c5836f14e80e295760e8132c8a6f94ab06b972d0b943facc90108fee75cfe375ecdffd37b", 16) + g22To202y1, _ := new(big.Int).SetString("4aed4448a94ee6c5972cd7c05595a079b52958473e347dffc65b296eae9edef46c66583195cb03dd796e694eca4f36", 16) + g22To203x0, _ := new(big.Int).SetString("1ab17aaf8075b8fc284e2beaa2ed81e2b1bb3f1c2ee8d337f9786106fa213954c7b1cddcee7346604439d3fabdae17f", 16) + g22To203x1, _ := new(big.Int).SetString("bf0d7fd2ca6c218672ba72961a01ef89fd5f60fd992e92ed20570388c71285e134de6573691b3a212ee11dc0c3eb0f", 16) + g22To203y0, _ := new(big.Int).SetString("173d203eb2952b75a82b63840cabb7c2d1fb1d7664946fac70e1136ac1ac60c74c23a4ac9356b6890d64f6a051e8617", 16) + g22To203y1, _ := new(big.Int).SetString("fa6e142fc5cabcc91392bd358358e1e807856f7056f947f395e1814c3edfe3db4278c8f82e61bf782482d74318bd91", 16) + g22To204x0, _ := new(big.Int).SetString("348acd4d6785f18aed4a7622f3144e040346b13f98748c5ba2acf3ad57dd7d22707d76471527420d1f461ff7cfd945", 16) + g22To204x1, _ := new(big.Int).SetString("a8c42e5ec8ba9102f936c8ff759df3faf70a2324e15caf325e6749ed2272bc2fe0f7c0eaf4cde618aa2781a8e27f9c", 16) + g22To204y0, _ := new(big.Int).SetString("13a51f84df15f42d157eb1e108e5d6997ac70865f60b56cc93a1caf72953ffa958e7178fb4e06c79895b6159f0c19ed", 16) + g22To204y1, _ := new(big.Int).SetString("f7ea55d09a79727470ebd74deaf4d1b88ee3bdfbc79d23deeb21c28a3d71fa0f82b08b4856432118815f76e73bddd0", 16) + g22To205x0, _ := new(big.Int).SetString("ab5b6137e856ed06dfaaa0b0b08f5a156403c93ddfe396775a02e509d5780ef132ed5cbda659e3c7b35df9d031e1d7", 16) + g22To205x1, _ := new(big.Int).SetString("60b441f4c1a4c167f0d5bdb183bb943c699f621d6647f43aeecdb604572d5145798a37e23e086e961b1a91ba526ec", 16) + g22To205y0, _ := new(big.Int).SetString("b850ec8720b432839de3b926bc58b9653915ec82cf04fbeedd3137afe76f55bd2a4774f8fc634ceb638d12fef64dd5", 16) + g22To205y1, _ := new(big.Int).SetString("2610171308947d7c42e16d8f3d5736d1d6911289c334b798657fb9b3e215f813f057516d0e5d91b004249d284ec049", 16) + g22To206x0, _ := new(big.Int).SetString("16c6f81e979798fe552216dabe1330e911779cf05b825bd4ca194f018474a794eb968676954dba6949010d19a7b7e5f", 16) + g22To206x1, _ := new(big.Int).SetString("8888ef840299100263b71574456212a520694b39e2ad4545eb049dce06924f152386850b6cfd572eaa89b3391539bc", 16) + g22To206y0, _ := new(big.Int).SetString("17dc29c178237c91ebe464860b1182a66607454a08b7e8d1b4cbceb7bf5375c96874dd5fe7d8f18a12c013fc7ff17dd", 16) + g22To206y1, _ := new(big.Int).SetString("ce7522e2e16e5fdc62f624791194184310983d7f3d1c43089035986d2538cf0e6dcc676a31631ee31bc9ac54995651", 16) + g22To207x0, _ := new(big.Int).SetString("741f39638bb4a63810f47a05dda4f7520ba8203a576b78135ab14bc4f88f3a3cfff8bcf421600b2f9376a608f869be", 16) + g22To207x1, _ := new(big.Int).SetString("ac32c37ae515b407eb4c472c0c5307a980b04a5598289820f35cfc66933275fb62fe3505b94a58676cd449b83ca31a", 16) + g22To207y0, _ := new(big.Int).SetString("127a483a5df9a7b05c723b6274777f9cd168fe8c030228a5e4ce48c448bfc2023a025753dbe6c39127ed7b394195f19", 16) + g22To207y1, _ := new(big.Int).SetString("b3d1a6503a06cfeb8713d43b5990ad13b3e521443c35fc7aad472255d298d329297ac577bb1ab5ae352b940887cb9b", 16) + g22To208x0, _ := new(big.Int).SetString("1452ff3b8c522c8445376fc61e9ff3ceec2604d7daed18e8d7baab2bf5ec3492ee50dab342e68cd1d139fb0e51492a5", 16) + g22To208x1, _ := new(big.Int).SetString("52f527f154daadffb0b9afce9485807fb9c2bbcdd15a82f6a103f50fe8b4590c036261a0419a28478a654f4c678bd0", 16) + g22To208y0, _ := new(big.Int).SetString("1996efba4768bfb2e3850ccdf7305e144f16db087d301c98ba395efa6cdca7894383918380f9564fb25f5b1f96dc84b", 16) + g22To208y1, _ := new(big.Int).SetString("b2af89268ecdb16607739faf90c6af26d71f891eaaf313a084a932b55f8451dac65acfc856d4a2eae4d7718fda606", 16) + g22To209x0, _ := new(big.Int).SetString("4a00eff14f4ddf49366b64f760488d3ee4b187ddc999b98b5b1c97c32501ae6f034cc60e743bbe82357727760052cd", 16) + g22To209x1, _ := new(big.Int).SetString("b26aa66a535cec9f94562f9fac63395a15e538ea441bde98b981adffee7fe98daf7477a650ee9d462dfae375e4f868", 16) + g22To209y0, _ := new(big.Int).SetString("fe6523f21147790c6b78309cc00acae32f95a8faeca79b81e9ce099181cd4acee7fe5b011365d51b47c2f80e972fcf", 16) + g22To209y1, _ := new(big.Int).SetString("121431f8ae0c9511d5a2e994022c98b318f683494fcd790bc28436702d63f80c2b717e90888e8ec4c2537800e5493eb", 16) + g22To210x0, _ := new(big.Int).SetString("19355d4cf0c47145baa990e1cf3e153eceaabc87fb497381fbd9dd1fb102fbd513a535bd5567912293f8a1c59e76074", 16) + g22To210x1, _ := new(big.Int).SetString("888054cf69ca0a10a3ec9a954bd265fbaaa263715e4838a99e5e6a75a4ac9eb509753d3bb74bfb4ccdb39bc8726969", 16) + g22To210y0, _ := new(big.Int).SetString("905f0d44fb3cb8a6c6d28e000b87e88353866e796d85d7f815a50cf997e6bd858c4078b97a4dd7afa0359117edd7ad", 16) + g22To210y1, _ := new(big.Int).SetString("13d79edb468dc530f8873a394d8e6e7ddb56ddd78b0953f26555ec9757bb9c1979e6ac46fa138c80a91faff2e3a5660", 16) + g22To211x0, _ := new(big.Int).SetString("110a8c3f295f025eada473c6b65f7b619168d441bab0e0948df726471e1e93f6af56520e7a1707c80501b02c1faf16a", 16) + g22To211x1, _ := new(big.Int).SetString("64d01b4cde6756b6b7e02cfbb89819b3e5ea4ea2d46d6d4048723ca187a691f06be49c6caf80c8048f1c9575d41ade", 16) + g22To211y0, _ := new(big.Int).SetString("6c700c522391f0b8aa1afdf102d87a23fce2f397fcb6d77e36e287874b32cf971946472bef4e57bab85fe21690007d", 16) + g22To211y1, _ := new(big.Int).SetString("7b26c301bbeb28fe4beab46dfef5da6206cc0eef61d7bd2c039981ecf2eb1135e6afffa9c0b21efb25511109e32c4b", 16) + g22To212x0, _ := new(big.Int).SetString("13997c8b33b9bf4c9e9322c320032694874d31dd7c3eaba08e8a07b0a89cb564652e29f6fe225cd9500fbf237e15d1d", 16) + g22To212x1, _ := new(big.Int).SetString("10ac932f6960da32d2d0ee894c3d4b21a4092ed0edcd7d97ca1fac350eff6d8178d9ff7c16450e093605b83f586b118", 16) + g22To212y0, _ := new(big.Int).SetString("11ada44e1dac10a55c3255591eb904fcc3186f071f39b2cca85850a000b2096c3ef38f43c5da644c6acb0b056273bd3", 16) + g22To212y1, _ := new(big.Int).SetString("2f161d6478db3e8f63d1c0d4843af0ebd3c78dbb8908f088f8ed21816ff36af4c4ea0414e9feac55eb00043b2b2137", 16) + g22To213x0, _ := new(big.Int).SetString("ffbd295d0e1f192ef8c0b335157612d81ed83620355e8e5bd4c835a7a2f94436b385149f3fd5a3cdf53df91e5b68e4", 16) + g22To213x1, _ := new(big.Int).SetString("e91515eac195331d5d730a1abb09406ebd4be677b51341c366bdcb9b492712db2ea4692668ea255c87bbffb2e2112c", 16) + g22To213y0, _ := new(big.Int).SetString("a2c2281a3c4492fae55515b92b00a4662f0ece234461b398e906cbf8c7d437a75d9e23550ab08ff369716b6859c837", 16) + g22To213y1, _ := new(big.Int).SetString("197b8fd3caaaefd2c72911dbe06c4c51da4937cd5aaade9e926ff32147be4c502a3408ef8a3acf9b9133c83a41e236", 16) + g22To214x0, _ := new(big.Int).SetString("157e11dbf1ca62677ec906d598ffd809b891c1802d3c0b49aceae1b7b55ceda16d49540c68e9872ce43bcd295c44e66", 16) + g22To214x1, _ := new(big.Int).SetString("15fa8e5909586dbf5b37b6a5da517550cbbbb17c5e975d4b5eef2e08f334affd760517a862ffe2f1f9df26651aaac0", 16) + g22To214y0, _ := new(big.Int).SetString("b0b4846c4a9ce5435d9ce2ba86a1d56d4621ee7bfc938f132f614b0da05b57d835036e488c00981eb619fcdbe1511e", 16) + g22To214y1, _ := new(big.Int).SetString("e5cfc53c396d46a7c5c79d4e33be93ca1dbfcd17045f91b22657a7c3795c58de2e4a005efaf0d66d84b1b93865e684", 16) + g22To215x0, _ := new(big.Int).SetString("191eca222e502481d76a9713567036c58d7dd1dd1df90bebc1b9928183fed70de03070d92ce8b11c3f64a413b0bdae", 16) + g22To215x1, _ := new(big.Int).SetString("865e84e1d254131d957527cd50f050a7a597250ed59282b4815e3ccd46073d5cc6b63a91fc58f52391c7b102fe3e4e", 16) + g22To215y0, _ := new(big.Int).SetString("e3ca4183433fb83fe90096eec4f70a9e4329c382a1e9ef718b17be368f2f28c042aaad1c62cb5f96972b10c1bdc1cb", 16) + g22To215y1, _ := new(big.Int).SetString("d721b04e9f391e0faa3a2379e25dc43f6057b97d4a155df052536f61f8cf334f2bdf59e667988dc9a31d159583d776", 16) + g22To216x0, _ := new(big.Int).SetString("6e1948e65150c93d666d6e028050177c4076fcfb720107ba92b6307eaba28382abe24875de412fef2bf59d100ccea2", 16) + g22To216x1, _ := new(big.Int).SetString("e3e3f028f3c74a41611e6813c989a4d31f012625a300a325ecc31b7a896c12c7deacc4a1f050a879e0c3f03ea4c12", 16) + g22To216y0, _ := new(big.Int).SetString("17188bb3a62e5465aa9b863f718020203847296ab5ddaafecc24a0dcac9a62cd9c31fa47fd6849ea9934ac637d8f176", 16) + g22To216y1, _ := new(big.Int).SetString("4bea3a574031e0e6c8adaed3a83a711b7f0450feae9a59be11d01443e5ab1a6f44790ee954c3792fa7c14a24827048", 16) + g22To217x0, _ := new(big.Int).SetString("70dc1cc5d4bf5cfd9c67e26183705be849acfb21c7513a4747c5004a7ed8566599d7367fff982bea041ed0141af08a", 16) + g22To217x1, _ := new(big.Int).SetString("15d758c63e0e6c24aef576fd54798b15b11820656153f62136280c19c2a70ff05de656c9d046e98e5de0340f54b657c", 16) + g22To217y0, _ := new(big.Int).SetString("860be86306055efd432c5195e3725fd579b1aef12441c15854565261a66a5f1309c9d368be4b932cfade14833269fd", 16) + g22To217y1, _ := new(big.Int).SetString("180a3c7b276c3411473f239c4ad1620b215423bf87608eb9b2d8b0db0765db2117559cfefd8fc59bd7931750ee7dc4b", 16) + g22To218x0, _ := new(big.Int).SetString("1d6d1784ebe66fb63b21a4e732fe0692cdd5fcc20ce11a711e738fe16153686b476ad736e84dac1872671de84f2004", 16) + g22To218x1, _ := new(big.Int).SetString("3decfd5520bbeb68a70cdd0208194bba2e111e1091a87c59726291cc436e25083026fc956577b1655ffaa279b550ba", 16) + g22To218y0, _ := new(big.Int).SetString("f2a01a887f8047aa0cdd8fb49348d5e11b286fa1416fe0c48f9a2d8850af5c2e5d6de11c335f6276396c3b1681f7d1", 16) + g22To218y1, _ := new(big.Int).SetString("8bc2179809e0f17380b105ff91037dcc766e67f77f43dc39121df7beaff211cf9b463b312e6ed741937dff14a51989", 16) + g22To219x0, _ := new(big.Int).SetString("120eda2d7d4c511efd6dcb461d50a2a4b48e97a97260f33642ccc0b3b29722509ed5fc97d3ed2e39caa5f5760beb45a", 16) + g22To219x1, _ := new(big.Int).SetString("186df8d3f20605e42d3f2d8d2150ea86ca45860081264c1e5abdb8086e61f455ff266f6e9e2cacc59672efd91ffdb7b", 16) + g22To219y0, _ := new(big.Int).SetString("61aebbeacab0ce635509c12346cb8afa0e3774c38a47b630ccdf0f089896e991f31b0828585243d1eb02827e1dd6b7", 16) + g22To219y1, _ := new(big.Int).SetString("9e01cac99ed79cd02b0ceff5bcddcaf863a15650e613d6f723ef253db92f646d73af7dcd3ac3bc4df8589b8bd18642", 16) + g22To220x0, _ := new(big.Int).SetString("5a1a9d300817a41602d7f15759fecd4bf5e9500b970299db86481c859646c80681f21751cf290ed7406b88ea48cb03", 16) + g22To220x1, _ := new(big.Int).SetString("e400147dd0cc103e015cd1b75d685e5727f118b9da65e844c055a255ae9bf10b643383041704b5c6aa30a152a36842", 16) + g22To220y0, _ := new(big.Int).SetString("1f6c19fa4d7362c289c47089d675892271c1f005a7df2bba3cc37ce41533c08455e50b841710f2919ff0f8794926", 16) + g22To220y1, _ := new(big.Int).SetString("143f1584851efe371aad348de294b120eb37c9935305ef0ee8866d091a2b017be034f52a4e2c027d8926eba0c6cf9f5", 16) + g22To221x0, _ := new(big.Int).SetString("f5668c211784ed87672b7620ad688ee57ec41aff06101c424c161c08a87addc8f3b924aad8255df5f004b7b5db4bdb", 16) + g22To221x1, _ := new(big.Int).SetString("16cf08dd1d150c6070fd12e06a8ba6b2f77dc5be36e5b0e62f9687edc8372e3c5064143f5a2a7c2ebfb54189146c551", 16) + g22To221y0, _ := new(big.Int).SetString("d32a7cc3fe8314436a9f1d38abbd8928068c08130ef5a2d2cf97426c4ed790ec50f9b7a9aa57f955e31b471ff0cc0c", 16) + g22To221y1, _ := new(big.Int).SetString("e142c5a795d78e4efdde9f3d447a343353797b1ceb6167225ae71a2db43dbe13539a051ccbda97ade033f81d83b413", 16) + g22To222x0, _ := new(big.Int).SetString("9320a66ae1094daa2da35d4908ff3d351b302e58a04141a7f7034d5e30aa49a4f764a7075bec251be845bf1abff360", 16) + g22To222x1, _ := new(big.Int).SetString("1a9b4df145e26ed4b6f73aba7f7be16c981572f3bf2b8645f26c5051c0ee595006a668cb095876f9c9c353abbba30f6", 16) + g22To222y0, _ := new(big.Int).SetString("b5affa0378e3f5e34e03cbd7c45d2cb32c20bd4ffa209ec04c7e624afc84d1dcc3bac9bd16a1041c8fe778e3475c25", 16) + g22To222y1, _ := new(big.Int).SetString("d91c606c2bbc3bed18233dd8b46d9e3253a8f2ec97ee56db359e25a41cae267ca9fca2088f1ae87e6a6ef2959be19c", 16) + g22To223x0, _ := new(big.Int).SetString("15338392455ef6346a9a9eb4d5849cea042a73f6d340dc4f2f7b8ad137f88964f906edaa55734f57b69a620ead71b78", 16) + g22To223x1, _ := new(big.Int).SetString("123cd61a10bfb7c4bae6e9038eb9ffadb4ae909f5433162ec468cb9738ec4bbb28c3a9f6a09fb91f5d390d3724d3d36", 16) + g22To223y0, _ := new(big.Int).SetString("4fabcdfee1c086066bd2785a48488dc32c822145a4f8d5de3a5434eea9141aa4c1d2c673d57bf6ca23b1724c685d9b", 16) + g22To223y1, _ := new(big.Int).SetString("132dc69324eec9822f4a30adf15a995c81d17d4691271652e1010f588a7d40b618f50db0dcad20f0558d3e28bc63010", 16) + g22To224x0, _ := new(big.Int).SetString("61d4511e9dc2037be8e756685b3d5075b7ec82415ded4a4e035e6885c2c38edd0e27871c3c360556ad5751574703fb", 16) + g22To224x1, _ := new(big.Int).SetString("c9462feef2524b9908963cac7b430eee4bce6bcceb844cce1ccc773e2ccd36b0682dea752f1ee9d6a6895012e18a58", 16) + g22To224y0, _ := new(big.Int).SetString("bee4fab502334f893d3ec109cbb394a74e1e009618d1a38fad9be1e2eaac59c587dc357d8a95b7d35cb69e665c3b32", 16) + g22To224y1, _ := new(big.Int).SetString("f1ef013be3f9bbc623cc7fe8b0f1499abeb22274805543005e7699320d422894a60a4864f382cc3d1e021d229f59f2", 16) + g22To225x0, _ := new(big.Int).SetString("4f3fa4b5053eae4b485c646003ffb1c25044e73cedd2998d3ecae536accb2e710e719f542ab9786f92d78461c2844a", 16) + g22To225x1, _ := new(big.Int).SetString("1976db83465f99d82278ae334c19d560bb9ac010d153d7352146095a1ae9ad5e62d9d1ffc06eb02eb87d49907d30056", 16) + g22To225y0, _ := new(big.Int).SetString("ab8a57fe54fe7b286e5f5697c3b22685a296faff6f5bd378a95d4355fa7a85e8783313dc88da0bf94dafa8d49fc059", 16) + g22To225y1, _ := new(big.Int).SetString("4b16f1828e210e6b3fc39dc227cf78c2f6ff253134d03088ca9d60804e8f8eb88b471c1d28fecbb7180e5b4c2e0c8e", 16) + g22To226x0, _ := new(big.Int).SetString("15cf5513c9747ee517b2bc3538b7f3c9a49bedfc9f16c6bc3c72668d6f229bd611ee14cab207496fe101b626a07075", 16) + g22To226x1, _ := new(big.Int).SetString("baacba9de1367afe1a725a314091cdf8f82ebdccb4814b27d5b83629deb2de9d7414c01f7ea465919951836ec9924", 16) + g22To226y0, _ := new(big.Int).SetString("19b594ab4f2fb02b3c23dcfb9dc3fcc7f58784ea8aa9101960fd94c40b05edd054073e0ea80672bee0acb8707e67595", 16) + g22To226y1, _ := new(big.Int).SetString("184e6ea6c562999533a28c2490c07b6fe5ccfc7b096fb9f332f542f8f6f9d503008c0bc621faf0681c323c2b6d70b54", 16) + g22To227x0, _ := new(big.Int).SetString("140dda6b70030990ec4f70f0d67c3eef5c7e5b558e34c5b7590813f3180c22446d959d57417ea98b7f7d2ca11dbf24f", 16) + g22To227x1, _ := new(big.Int).SetString("29357be1292cc6817921868e7e8eeafb8642e78526effb1502b10358291af8051dab733c1cc1598aa737682f694d27", 16) + g22To227y0, _ := new(big.Int).SetString("113fedeb0f9efbe82266582f2cd2b8c6876742d9ebbff621817a48a39d2f41f321629ce6af86e2c5465b651f28c4a32", 16) + g22To227y1, _ := new(big.Int).SetString("1b41bfe9fa90eb9205deaf2903e0cef4cd9beef290a59c402f75ca0fe117e8c4a6d375675554dc29dc409d623c04dd", 16) + g22To228x0, _ := new(big.Int).SetString("e6e3677e32cad86caad64cf7606fc172a33f1b327c9c70b3cdfaa05c4aea82e170e7bfb231c2ba74e0b6d51493c0af", 16) + g22To228x1, _ := new(big.Int).SetString("196fdec7c41f332672b4a66dd5f283741cdd71e81901546257f29cfd5f527b7b926342d5803666d0309790463267ea3", 16) + g22To228y0, _ := new(big.Int).SetString("30fbb81162ae3de583bbb1c3273a005a1c4bf8b15a07e0f1f6af337677f81a86c0bc5b24a063017370fa075445aa79", 16) + g22To228y1, _ := new(big.Int).SetString("15c4c7cdee11fd16ac0634ab32d20b386c9a29a729fda738cc17d83d2c87f96f5438904f462959a624f3e1c3e1b726c", 16) + g22To229x0, _ := new(big.Int).SetString("4a77c7561b46da0b0a57a8268e008415028f0522a551b7d703c06a899e3adce6fc6f1f84fe8c692ba9d6579a5d304d", 16) + g22To229x1, _ := new(big.Int).SetString("d00c3b8f25001c2298a5f3081d03cdde801483b97cfe9111abaa89d98d9f7441bb48a532e7b560da8efb52cbfa488f", 16) + g22To229y0, _ := new(big.Int).SetString("bfaed42b7cc7bd372815959fc4b52bd5d9762e3e4833f898c48fc81378f0b3bf2aca094fab422d872e7af87bcf974e", 16) + g22To229y1, _ := new(big.Int).SetString("1486c6643f69f5591afe2d1a337e661597408b4fae61fc4d7eee62170f00aead41983833d0b9eb6aa41c2b19d6fb9b3", 16) + g22To230x0, _ := new(big.Int).SetString("13aaa58535630c43f1e8e025859a4e191558b3b17faeb27a8872d79c16190e60de785808c2d8e8861feafa4f652bb46", 16) + g22To230x1, _ := new(big.Int).SetString("9c7e94232022e629f74519e65595804f32ef7e8f9be8d4038bce9421ff1b1cbeafba1f66be885b6c266ff444d2c511", 16) + g22To230y0, _ := new(big.Int).SetString("116da7b271188a56aaeb876185defe78ca59a495c9560ebafa5caf8a600dc5095ecf75cdba9a5102feca678e61159e1", 16) + g22To230y1, _ := new(big.Int).SetString("b5399b58ca2c25a8c7789db511df7390dbef89f66447a21d8b05f8543dea26d73c7e237b1ad4b38633bcecb0d80c08", 16) + g22To231x0, _ := new(big.Int).SetString("12a44f17e10f72712477180a7750afaa68580ccd8aa4e4d93c8dc26b6f4f032f67acbd25450b24abea23e9b89df5f2", 16) + g22To231x1, _ := new(big.Int).SetString("16291c5c964c26b266ad096dd25d2dc3164b5f49e9380fd5abf1bb28671695e34307dd7efc5e3bc41b7331c1e956321", 16) + g22To231y0, _ := new(big.Int).SetString("1900f5b15e6fadb3aaed13b94ca07f8e1450773726a957d38c90e7a440cef16a8087e55b2ef4eea5aa6bed27ae6d420", 16) + g22To231y1, _ := new(big.Int).SetString("149303e315fc1ffb4fabd80a831f544d672731a540878c10aae7b328deabaa3bbb4b4c4a3194b0354c812cd0c1079", 16) + g22To232x0, _ := new(big.Int).SetString("116c99dae3f682fd8dcf85d0f779ae92d5958f20b3edd25dc39b4ed2e4eb9bbeeae1fbc7eb4728371210648d021ad1f", 16) + g22To232x1, _ := new(big.Int).SetString("1299faff92dc33b032ca70e2370534c3cbfba3710ed085507661f5efa1d861d7a0e67b38664ac963262601670f7fa51", 16) + g22To232y0, _ := new(big.Int).SetString("153dcdec0417a48ead29f5f9ced04d2305092610e029bf9ac52f195231df53c82e14f2d93b9c177a85565149a2edfa2", 16) + g22To232y1, _ := new(big.Int).SetString("992274638c287a52667a854f7ffeb4eec4ee0c240c47c50b4cbc5ac6be56a963f481e640cb422eb02a794ab970c275", 16) + g22To233x0, _ := new(big.Int).SetString("1143b4bacc8856a63feb0a276f78e90a379c410260eb54793064e408922beff4b68b85c714aa905f3db357422e32309", 16) + g22To233x1, _ := new(big.Int).SetString("183856881b671e7cd3e26af84dbfe9dbfa925c329ccd949acf4f69800de1c399283979b1b53ba02ac3907a6f48a381f", 16) + g22To233y0, _ := new(big.Int).SetString("1684aaa6017dbc7a9e6b350cd6837030cff2f9b12ad4baf885b017efdb7d2ccfa85df6e627153462924bae9c22df82d", 16) + g22To233y1, _ := new(big.Int).SetString("333c4214484749cc15f984a445b36c19a04ea7e91d55e2f4061933018ea8153687a8b8937dea0467002455dbd374c7", 16) + g22To234x0, _ := new(big.Int).SetString("965ffa8ede763b0b5cf7a2c0b4c866ddded70fda83bd2e3894c5c5b3189a9d79014c24ab1413b89a39e357b4181c9b", 16) + g22To234x1, _ := new(big.Int).SetString("da45f5f4e50d5990a7e9df94ce2c6cfd2048c3632b1069d361be77f16122ddb5ee4fe4f7367846768f89619bb8bc2e", 16) + g22To234y0, _ := new(big.Int).SetString("167ae7a77ed6ef24f1c2924d4568d99b3e08caf2a18eb4466c7bdb9b2e1c560947a64323526892b069eb84bc7224c36", 16) + g22To234y1, _ := new(big.Int).SetString("3311cb8a8ca09f70e301d426246544f9b66db0902570f246554d72cbe38626df187410ebcc1310a836ca4d97af33f4", 16) + g22To235x0, _ := new(big.Int).SetString("35385cab023bc6dbedd6643338cfa15e1421f1c18fc9de93385ee68524f8eaeec3906be6f71fd5550d2ce91f9aa3fd", 16) + g22To235x1, _ := new(big.Int).SetString("5c39fd2f51e867eb27c7ecfcefd5cd6a36a067ad472baec9a622302de9a2cd7288f95233ab42516339198a4f34eaaf", 16) + g22To235y0, _ := new(big.Int).SetString("eae53f60df32166ee25cb9625ba6849926e825bcfb1dcd15ca9c7543f7bb9a35a02138bf408d556196f064eaddb348", 16) + g22To235y1, _ := new(big.Int).SetString("175b0f13d347a24b6f44226c44c6cfa35a93b3a9f7cf47e56cda0c7fcdce810d3d7653356e3cf51d4b9060a32e779c5", 16) + g22To236x0, _ := new(big.Int).SetString("76f214f94aa49a9e9b02d2d4b09d71b2b8afff460726d6f94ea61e0a824390c63ec31ec00326894de9dd81da189d1", 16) + g22To236x1, _ := new(big.Int).SetString("73720be0d041b24e035c2bddacb6fe3ca767866d27c70090a4db7e6d7d679f748e79b7bfc29ead058d829cb2a1c78b", 16) + g22To236y0, _ := new(big.Int).SetString("6baa768820770ff572f6c7aaee545f673c676f1b483f086b0e88010c61b8cb74b47bfa63301034530e89467ca1b6fc", 16) + g22To236y1, _ := new(big.Int).SetString("12c0c461ef5acf11748a53f4be776a47aed227f72f958cb510ae7ad4d9e3039e95864abe6a776465cc19c2f281b2c98", 16) + g22To237x0, _ := new(big.Int).SetString("1a56ab3c91a2d7ac04ba3845e5b04635cc21df603cc5f4a272917dc3c0f29ae900d47094a908b9ef67c9f3c92f210e7", 16) + g22To237x1, _ := new(big.Int).SetString("78f75d52c39d9e3008fb77c113d4517492ac9526dc5720b3ac000bba2bcda9fa6f235f71358e699de3f41ae766ba30", 16) + g22To237y0, _ := new(big.Int).SetString("9db0e79b6dc6591f7bfea52e20fbccb67f04bab057fa4c823b03bc11cc3e3b034308ca19f4dba9e55c8ea75da96a8", 16) + g22To237y1, _ := new(big.Int).SetString("18ef4258b1ab95b589ae734e9a5788844b2ab463058ab598441d6eb762f857baabd540f004de0516dacef459ef1484a", 16) + g22To238x0, _ := new(big.Int).SetString("124d5e181b32f8c19fb318876519723395c00cd96032ecc3e2786e7766c4f8acb21343b7c3373210496c2626b0f375c", 16) + g22To238x1, _ := new(big.Int).SetString("11dc8c2412867901d60d67978cba757346c3c540b1c28d0e4ed34eaf4377b12fa662cc111e9a1c469194852f3f5fa91", 16) + g22To238y0, _ := new(big.Int).SetString("16be0077d1fd4af0aa2195a5558aac35ccba794c4bce87780c47331304c506aa550ca2b007d348f857772efcb8e8526", 16) + g22To238y1, _ := new(big.Int).SetString("ac0d33c186f9c22e81bbb09682bf81a905d600d677f085a22eac434870780f711de3f6e2e6129b4ee56e1da45246a5", 16) + g22To239x0, _ := new(big.Int).SetString("578d0421ff60488232428f9e12894b28901b159ace1e824c42a1a098918edae07af911a8390af95aa8ff97559046e7", 16) + g22To239x1, _ := new(big.Int).SetString("91497555e71e73f92f6837caaf01fac73cc08b9811f4aa5da734b9d964fd7012898f232b9f81d9de1403e9a1b58e6", 16) + g22To239y0, _ := new(big.Int).SetString("11bbb9a065838a523f055bcec91f196377d8f45bb7c517c4df45d6933a63c43359666df85d46de2318de648af6ef91", 16) + g22To239y1, _ := new(big.Int).SetString("9bf515871398492a11022b61a7feb80a90e284152893d799df28dd6ad525a7f3d1dc699e2088c5ccd061db4ac9fc2e", 16) + g22To240x0, _ := new(big.Int).SetString("11413f10be45a4e80ba653a128bb8e5d6fbfd469dc3d8e220a0c6b494de4499d84f0588ca0e6d8d3578b9c65b812fe0", 16) + g22To240x1, _ := new(big.Int).SetString("73a4e05fd7e2a8df57e2ebe110da0cfd999573e0163e68b69a85ca0be643161b608a5bc9d86d12bb6c9f7448a3f4b9", 16) + g22To240y0, _ := new(big.Int).SetString("1edd87e38174140d357b08660655eda55c076e3acfd5c1863fb65033066af23e49465c844084c3f7c87438da34f7eb", 16) + g22To240y1, _ := new(big.Int).SetString("18f5d01090cafd077c6a98644270e80449328651a2bc55e9db82d2a4f9807d88b38adffb2e98555ad6f9cb62ba4e05", 16) + g22To241x0, _ := new(big.Int).SetString("4a92e81d429af6a236903d48df00d65edeb772581a585d69abef382ba292b86cfbc9819883e5e0b3787a2a604a91f0", 16) + g22To241x1, _ := new(big.Int).SetString("15e451c638d369335d7724bcc75296c09f308736e177277a75dc1a788289873307067f5e39342d614ccef88468cf829", 16) + g22To241y0, _ := new(big.Int).SetString("c87525377a7435706a90d868c11f0d49c5b26f5367c1f8c48122dfff1796ee3d5a28d9fddb914c39c800e2d627236b", 16) + g22To241y1, _ := new(big.Int).SetString("e5b696f8d74484dbe15fe35db89a9462775cd0efe73b0aef441130c1f95ce00b9d5deb80d8dcb50f3e3361934057a6", 16) + g22To242x0, _ := new(big.Int).SetString("5b7f202db9381f207dd36810498fd463f92138f48739dbd77f9dac3c7275ea8784e35067d5f6d0db19e5438446c164", 16) + g22To242x1, _ := new(big.Int).SetString("c24ad376e7254204d6f04bcdb35ca331c66d62b84c924f8cd045efac3f41f8b3a09c0f5fb5c343150312d650394fd4", 16) + g22To242y0, _ := new(big.Int).SetString("b115f6f48cb887fde92ce968dfee1f04cab2ab03f5258701853f792389029a55bbd827e7d09c8458e2548fbafaab41", 16) + g22To242y1, _ := new(big.Int).SetString("1908a57854335e598dfa6af88d8249f29b46d5afb26e62e5799d9e870b8b1e2fb81b95c3e355c369a6e0315a966ba8b", 16) + g22To243x0, _ := new(big.Int).SetString("167a83029b379191f6296ea06c6cc6744b7640926f2d5ddc0653611c8da92e50417687117913f9540fa3a785104ac94", 16) + g22To243x1, _ := new(big.Int).SetString("40f6dba9d8ab6c0ceb6abdae0c7b3ab348b7f47abdbd6e4d3d30ae71874e58a4c977d8262d320d1f8778e415f9f9ef", 16) + g22To243y0, _ := new(big.Int).SetString("e172bf2e3e6e6df910d6b60a90b07662e5d69b30108f6a415f5dd1700ad0a449e45b1faf629cfa42035250958f84d5", 16) + g22To243y1, _ := new(big.Int).SetString("1016a8a4114e72056cd959a645b00f15a0d5fededd4977dce708f712926603edad76f2223e5c6ad6e585f54d484faa7", 16) + g22To244x0, _ := new(big.Int).SetString("13f5e1adcd4b83f044847335a9972caee9eb296bfe575a30ef816d3a57021a371eb68917f0d4d0d8522a1d47ac499bb", 16) + g22To244x1, _ := new(big.Int).SetString("126e7bdd01c2647f5c959bfe62089338ee624d707c8988cb01d138a0b57712192d4c252b8f3d2a85282fb3db109b3bb", 16) + g22To244y0, _ := new(big.Int).SetString("1349025f99acabf89d7eee0f4004fcba91ba314a0aaf57a9ebaa2ff43fb275d71b93911d7bdbbc62900eb44338b4d9f", 16) + g22To244y1, _ := new(big.Int).SetString("19077a04f81a725a1acefc2ab88ca7056f29b094364453f8431f88bec49f74a7741687926a12a7c3a06e9f86ce2c50b", 16) + g22To245x0, _ := new(big.Int).SetString("144645305a00a758d65f778728b9f6e113b436e10f202fdfb1fe82aa64fb7da7ce7ec58d2ac69fce6fb7b9da0384c34", 16) + g22To245x1, _ := new(big.Int).SetString("48b190744f4c58ab0e7bd0bb1b6470382d1d735a753fd16dba1c8fa5694361ad0d8ad36640e3e657b3458d76ac08f3", 16) + g22To245y0, _ := new(big.Int).SetString("7f7e9a1dc2efda5632d6d7ee989cd2d7037ee37bb7ff2ac6d89fe4b3f0f43cfe994b23678992e77f6ea940cd9d7eab", 16) + g22To245y1, _ := new(big.Int).SetString("1237f19dbbd6b8e1a2167457309351c1e93cfebcc1ceb1b4e3989df47db8886c4f16fedfd04b95d7940957f69befd71", 16) + g22To246x0, _ := new(big.Int).SetString("36ae22d7ed9f06ff2d17dbc8299a3486cd1f2a6912fa00dac6d6ca65808add68eba6ad17785ca822ce911a4b60b52e", 16) + g22To246x1, _ := new(big.Int).SetString("9749db79743deb0062665447bea365a22feac03ca22d0568561a9debd6c22c6b9b76e554d57a98fb90ff69c920a5ce", 16) + g22To246y0, _ := new(big.Int).SetString("107564a4a2d698231d1ad267e3d3aa937af10a1d00a5f871921b362a91d44ff841e29fdb916a5c627305104dd546157", 16) + g22To246y1, _ := new(big.Int).SetString("7c93373097b6a5455c5efe406ea2c2193d059a9a99a6a03be8a762425f80a35bb9ea476fa2072e462ae5dd9f2309ab", 16) + g22To247x0, _ := new(big.Int).SetString("6a22dae324168e17c2f5d424d4285f6c932c09fa4bd404f729d93b9d0b64aa24c473a1574a3c6099f5409cbe1becaa", 16) + g22To247x1, _ := new(big.Int).SetString("a0ec3f2f65e1701067e9a0e1ab8de88f847db33b381bd09f368532994d021bdd980897457ed7a268812bce0069592a", 16) + g22To247y0, _ := new(big.Int).SetString("189487e1bc350ca03ca356f978b8ed2d90d3d1fc0b541a3c4dd03b1e40acaa4b2e475d7e07a04a5f9ce9c7442af4962", 16) + g22To247y1, _ := new(big.Int).SetString("7ebcde469687f32084e1241c889c754aa72d62ea26a3e81d89ad089341faf83bffc87f6733f1749a2897c168d7cd18", 16) + g22To248x0, _ := new(big.Int).SetString("10006f4d936154c76ee3db68b01e6b322851cf0b8aadadf5569e20ee4286e63119b417ac0fc2656b998c8eba0a2d9a3", 16) + g22To248x1, _ := new(big.Int).SetString("d8257b429b89e8d51f6448780a2d2c680cff8e6298f72d0e988094f4e5f286f0b3b60c2f40418f55d1b01817a9c91f", 16) + g22To248y0, _ := new(big.Int).SetString("d9f578a615bdb373c9f728a55224d3712351bce6ecab3d5f8d4f9e8eaa252275aa6a1cf5b5a8d50689818b37166020", 16) + g22To248y1, _ := new(big.Int).SetString("5e68fc0e03db30d88f33c714671489b149db943910e08d106f48ab5cec28d1ffa8f19a1bf1bfc3fd11fc1a8b89cf72", 16) + g22To249x0, _ := new(big.Int).SetString("923c1d69a1ec9eeb1be661762df7c1a6209ce73f59011e66d70cfa0d450d7e541ce8f0d0178e7bdeb70bd9afe6630a", 16) + g22To249x1, _ := new(big.Int).SetString("89305c6d004561928965f44298a018b59e815779372a838a6bc041f60179ac74e6250381ec892c925d0829de05cf02", 16) + g22To249y0, _ := new(big.Int).SetString("ba7546c5ee31e6e41487d7b03a60b1db7e3c13fd680e246a835911347101b038a307c9b619fa681fbf3641d0773da4", 16) + g22To249y1, _ := new(big.Int).SetString("846f47f95e12ef41c4a41dd918ba41f4896411fbdc00a3680b425adbf3431b2274a6a0759401231d74caf733ed98cd", 16) + g22To250x0, _ := new(big.Int).SetString("d1e044cae44743f417bb1e3dc5d26c51148a187a5c1a93893a8d16145d5277beb5568b67df8a2120a94cdb1940c116", 16) + g22To250x1, _ := new(big.Int).SetString("1446b710797615d55733b96ca9c6fc631ae1738af4fcc641e0cf9fb2270182b09b2468781a05ca30977ef7b582a3290", 16) + g22To250y0, _ := new(big.Int).SetString("606fa401dd62679f112a7c7e8601a4ce3a7ab6a3a6fd9eee07566fc578ae3168eb3457e45db0e967d07d0e06f31571", 16) + g22To250y1, _ := new(big.Int).SetString("3225d95c006667f610fe975864c45c1b54f5711d08be4081a964956e1821a9d73598c3a9e9f2a5466e077a8a873e89", 16) + g22To251x0, _ := new(big.Int).SetString("1605ee47664ae98270c966ef8f54e82bb23c28f34348229ce0ccb2dd66095bd11375edb3bb5e4107aa68d881f74dd99", 16) + g22To251x1, _ := new(big.Int).SetString("163046b6f1986ff5a271e96079b8c305168eb91678d387893cbdc3067b3ad6117080f7927be358284dff9ace2aca23b", 16) + g22To251y0, _ := new(big.Int).SetString("152a37dc98ec8ebb9db9adfbce7220effaab6a0e60b759789776ca771b65ce96c1e15ceaac5e8304eeb8f03d977ccdc", 16) + g22To251y1, _ := new(big.Int).SetString("227beb5ba0867d1ab14b486e365a88cabf816a64ba04f453424eb8ebf9017bbe7a92c03b951247e2c36b5c3ad75ec7", 16) + g22To252x0, _ := new(big.Int).SetString("144304b66063c76234971bb9464e767a22b4b013c101a92018a0f5b0ea4d6e1bc73a906c5e4ac5dcbec7751dd3e8315", 16) + g22To252x1, _ := new(big.Int).SetString("9c18b1626b97e33efe848129737f01518a052b0baea0958863db86ca0be561fc462ced7e3d1e12fc08e4a19a0b046d", 16) + g22To252y0, _ := new(big.Int).SetString("159c60b8f19e916856e4825008524eeb7baaec5c2943881d3a3b6a13f4a4de3d834b5d1a53f7fae59b52e06a446a2d1", 16) + g22To252y1, _ := new(big.Int).SetString("e80fe9da96d1acc3fd31cf625b173de483b99dab76db9cecf6899414d3df9962fb613fbf16ad49acbcd8521c3bba30", 16) + return TwistPoints{ + G2x0: g2x0, + G2x1: g2x1, + G2y0: g2y0, + G2y1: g2y1, + + G2mx0: [253]*big.Int{g23x0, g25x0, g27x0, g22To3x0, g22To4x0, g22To5x0, g22To6x0, g22To7x0, g22To8x0, g22To9x0, g22To10x0, g22To11x0, g22To12x0, g22To13x0, g22To14x0, g22To15x0, g22To16x0, g22To17x0, g22To18x0, g22To19x0, g22To20x0, g22To21x0, g22To22x0, g22To23x0, g22To24x0, g22To25x0, g22To26x0, g22To27x0, g22To28x0, g22To29x0, g22To30x0, g22To31x0, g22To32x0, g22To33x0, g22To34x0, g22To35x0, g22To36x0, g22To37x0, g22To38x0, g22To39x0, g22To40x0, g22To41x0, g22To42x0, g22To43x0, g22To44x0, g22To45x0, g22To46x0, g22To47x0, g22To48x0, g22To49x0, g22To50x0, g22To51x0, g22To52x0, g22To53x0, g22To54x0, g22To55x0, g22To56x0, g22To57x0, g22To58x0, g22To59x0, g22To60x0, g22To61x0, g22To62x0, g22To63x0, g22To64x0, g22To65x0, g22To66x0, g22To67x0, g22To68x0, g22To69x0, g22To70x0, g22To71x0, g22To72x0, g22To73x0, g22To74x0, g22To75x0, g22To76x0, g22To77x0, g22To78x0, g22To79x0, g22To80x0, g22To81x0, g22To82x0, g22To83x0, g22To84x0, g22To85x0, g22To86x0, g22To87x0, g22To88x0, g22To89x0, g22To90x0, g22To91x0, g22To92x0, g22To93x0, g22To94x0, g22To95x0, g22To96x0, g22To97x0, g22To98x0, g22To99x0, g22To100x0, g22To101x0, g22To102x0, g22To103x0, g22To104x0, g22To105x0, g22To106x0, g22To107x0, g22To108x0, g22To109x0, g22To110x0, g22To111x0, g22To112x0, g22To113x0, g22To114x0, g22To115x0, g22To116x0, g22To117x0, g22To118x0, g22To119x0, g22To120x0, g22To121x0, g22To122x0, g22To123x0, g22To124x0, g22To125x0, g22To126x0, g22To127x0, g22To128x0, g22To129x0, g22To130x0, g22To131x0, g22To132x0, g22To133x0, g22To134x0, g22To135x0, g22To136x0, g22To137x0, g22To138x0, g22To139x0, g22To140x0, g22To141x0, g22To142x0, g22To143x0, g22To144x0, g22To145x0, g22To146x0, g22To147x0, g22To148x0, g22To149x0, g22To150x0, g22To151x0, g22To152x0, g22To153x0, g22To154x0, g22To155x0, g22To156x0, g22To157x0, g22To158x0, g22To159x0, g22To160x0, g22To161x0, g22To162x0, g22To163x0, g22To164x0, g22To165x0, g22To166x0, g22To167x0, g22To168x0, g22To169x0, g22To170x0, g22To171x0, g22To172x0, g22To173x0, g22To174x0, g22To175x0, g22To176x0, g22To177x0, g22To178x0, g22To179x0, g22To180x0, g22To181x0, g22To182x0, g22To183x0, g22To184x0, g22To185x0, g22To186x0, g22To187x0, g22To188x0, g22To189x0, g22To190x0, g22To191x0, g22To192x0, g22To193x0, g22To194x0, g22To195x0, g22To196x0, g22To197x0, g22To198x0, g22To199x0, g22To200x0, g22To201x0, g22To202x0, g22To203x0, g22To204x0, g22To205x0, g22To206x0, g22To207x0, g22To208x0, g22To209x0, g22To210x0, g22To211x0, g22To212x0, g22To213x0, g22To214x0, g22To215x0, g22To216x0, g22To217x0, g22To218x0, g22To219x0, g22To220x0, g22To221x0, g22To222x0, g22To223x0, g22To224x0, g22To225x0, g22To226x0, g22To227x0, g22To228x0, g22To229x0, g22To230x0, g22To231x0, g22To232x0, g22To233x0, g22To234x0, g22To235x0, g22To236x0, g22To237x0, g22To238x0, g22To239x0, g22To240x0, g22To241x0, g22To242x0, g22To243x0, g22To244x0, g22To245x0, g22To246x0, g22To247x0, g22To248x0, g22To249x0, g22To250x0, g22To251x0, g22To252x0}, + G2mx1: [253]*big.Int{g23x1, g25x1, g27x1, g22To3x1, g22To4x1, g22To5x1, g22To6x1, g22To7x1, g22To8x1, g22To9x1, g22To10x1, g22To11x1, g22To12x1, g22To13x1, g22To14x1, g22To15x1, g22To16x1, g22To17x1, g22To18x1, g22To19x1, g22To20x1, g22To21x1, g22To22x1, g22To23x1, g22To24x1, g22To25x1, g22To26x1, g22To27x1, g22To28x1, g22To29x1, g22To30x1, g22To31x1, g22To32x1, g22To33x1, g22To34x1, g22To35x1, g22To36x1, g22To37x1, g22To38x1, g22To39x1, g22To40x1, g22To41x1, g22To42x1, g22To43x1, g22To44x1, g22To45x1, g22To46x1, g22To47x1, g22To48x1, g22To49x1, g22To50x1, g22To51x1, g22To52x1, g22To53x1, g22To54x1, g22To55x1, g22To56x1, g22To57x1, g22To58x1, g22To59x1, g22To60x1, g22To61x1, g22To62x1, g22To63x1, g22To64x1, g22To65x1, g22To66x1, g22To67x1, g22To68x1, g22To69x1, g22To70x1, g22To71x1, g22To72x1, g22To73x1, g22To74x1, g22To75x1, g22To76x1, g22To77x1, g22To78x1, g22To79x1, g22To80x1, g22To81x1, g22To82x1, g22To83x1, g22To84x1, g22To85x1, g22To86x1, g22To87x1, g22To88x1, g22To89x1, g22To90x1, g22To91x1, g22To92x1, g22To93x1, g22To94x1, g22To95x1, g22To96x1, g22To97x1, g22To98x1, g22To99x1, g22To100x1, g22To101x1, g22To102x1, g22To103x1, g22To104x1, g22To105x1, g22To106x1, g22To107x1, g22To108x1, g22To109x1, g22To110x1, g22To111x1, g22To112x1, g22To113x1, g22To114x1, g22To115x1, g22To116x1, g22To117x1, g22To118x1, g22To119x1, g22To120x1, g22To121x1, g22To122x1, g22To123x1, g22To124x1, g22To125x1, g22To126x1, g22To127x1, g22To128x1, g22To129x1, g22To130x1, g22To131x1, g22To132x1, g22To133x1, g22To134x1, g22To135x1, g22To136x1, g22To137x1, g22To138x1, g22To139x1, g22To140x1, g22To141x1, g22To142x1, g22To143x1, g22To144x1, g22To145x1, g22To146x1, g22To147x1, g22To148x1, g22To149x1, g22To150x1, g22To151x1, g22To152x1, g22To153x1, g22To154x1, g22To155x1, g22To156x1, g22To157x1, g22To158x1, g22To159x1, g22To160x1, g22To161x1, g22To162x1, g22To163x1, g22To164x1, g22To165x1, g22To166x1, g22To167x1, g22To168x1, g22To169x1, g22To170x1, g22To171x1, g22To172x1, g22To173x1, g22To174x1, g22To175x1, g22To176x1, g22To177x1, g22To178x1, g22To179x1, g22To180x1, g22To181x1, g22To182x1, g22To183x1, g22To184x1, g22To185x1, g22To186x1, g22To187x1, g22To188x1, g22To189x1, g22To190x1, g22To191x1, g22To192x1, g22To193x1, g22To194x1, g22To195x1, g22To196x1, g22To197x1, g22To198x1, g22To199x1, g22To200x1, g22To201x1, g22To202x1, g22To203x1, g22To204x1, g22To205x1, g22To206x1, g22To207x1, g22To208x1, g22To209x1, g22To210x1, g22To211x1, g22To212x1, g22To213x1, g22To214x1, g22To215x1, g22To216x1, g22To217x1, g22To218x1, g22To219x1, g22To220x1, g22To221x1, g22To222x1, g22To223x1, g22To224x1, g22To225x1, g22To226x1, g22To227x1, g22To228x1, g22To229x1, g22To230x1, g22To231x1, g22To232x1, g22To233x1, g22To234x1, g22To235x1, g22To236x1, g22To237x1, g22To238x1, g22To239x1, g22To240x1, g22To241x1, g22To242x1, g22To243x1, g22To244x1, g22To245x1, g22To246x1, g22To247x1, g22To248x1, g22To249x1, g22To250x1, g22To251x1, g22To252x1}, + G2my0: [253]*big.Int{g23y0, g25y0, g27y0, g22To3y0, g22To4y0, g22To5y0, g22To6y0, g22To7y0, g22To8y0, g22To9y0, g22To10y0, g22To11y0, g22To12y0, g22To13y0, g22To14y0, g22To15y0, g22To16y0, g22To17y0, g22To18y0, g22To19y0, g22To20y0, g22To21y0, g22To22y0, g22To23y0, g22To24y0, g22To25y0, g22To26y0, g22To27y0, g22To28y0, g22To29y0, g22To30y0, g22To31y0, g22To32y0, g22To33y0, g22To34y0, g22To35y0, g22To36y0, g22To37y0, g22To38y0, g22To39y0, g22To40y0, g22To41y0, g22To42y0, g22To43y0, g22To44y0, g22To45y0, g22To46y0, g22To47y0, g22To48y0, g22To49y0, g22To50y0, g22To51y0, g22To52y0, g22To53y0, g22To54y0, g22To55y0, g22To56y0, g22To57y0, g22To58y0, g22To59y0, g22To60y0, g22To61y0, g22To62y0, g22To63y0, g22To64y0, g22To65y0, g22To66y0, g22To67y0, g22To68y0, g22To69y0, g22To70y0, g22To71y0, g22To72y0, g22To73y0, g22To74y0, g22To75y0, g22To76y0, g22To77y0, g22To78y0, g22To79y0, g22To80y0, g22To81y0, g22To82y0, g22To83y0, g22To84y0, g22To85y0, g22To86y0, g22To87y0, g22To88y0, g22To89y0, g22To90y0, g22To91y0, g22To92y0, g22To93y0, g22To94y0, g22To95y0, g22To96y0, g22To97y0, g22To98y0, g22To99y0, g22To100y0, g22To101y0, g22To102y0, g22To103y0, g22To104y0, g22To105y0, g22To106y0, g22To107y0, g22To108y0, g22To109y0, g22To110y0, g22To111y0, g22To112y0, g22To113y0, g22To114y0, g22To115y0, g22To116y0, g22To117y0, g22To118y0, g22To119y0, g22To120y0, g22To121y0, g22To122y0, g22To123y0, g22To124y0, g22To125y0, g22To126y0, g22To127y0, g22To128y0, g22To129y0, g22To130y0, g22To131y0, g22To132y0, g22To133y0, g22To134y0, g22To135y0, g22To136y0, g22To137y0, g22To138y0, g22To139y0, g22To140y0, g22To141y0, g22To142y0, g22To143y0, g22To144y0, g22To145y0, g22To146y0, g22To147y0, g22To148y0, g22To149y0, g22To150y0, g22To151y0, g22To152y0, g22To153y0, g22To154y0, g22To155y0, g22To156y0, g22To157y0, g22To158y0, g22To159y0, g22To160y0, g22To161y0, g22To162y0, g22To163y0, g22To164y0, g22To165y0, g22To166y0, g22To167y0, g22To168y0, g22To169y0, g22To170y0, g22To171y0, g22To172y0, g22To173y0, g22To174y0, g22To175y0, g22To176y0, g22To177y0, g22To178y0, g22To179y0, g22To180y0, g22To181y0, g22To182y0, g22To183y0, g22To184y0, g22To185y0, g22To186y0, g22To187y0, g22To188y0, g22To189y0, g22To190y0, g22To191y0, g22To192y0, g22To193y0, g22To194y0, g22To195y0, g22To196y0, g22To197y0, g22To198y0, g22To199y0, g22To200y0, g22To201y0, g22To202y0, g22To203y0, g22To204y0, g22To205y0, g22To206y0, g22To207y0, g22To208y0, g22To209y0, g22To210y0, g22To211y0, g22To212y0, g22To213y0, g22To214y0, g22To215y0, g22To216y0, g22To217y0, g22To218y0, g22To219y0, g22To220y0, g22To221y0, g22To222y0, g22To223y0, g22To224y0, g22To225y0, g22To226y0, g22To227y0, g22To228y0, g22To229y0, g22To230y0, g22To231y0, g22To232y0, g22To233y0, g22To234y0, g22To235y0, g22To236y0, g22To237y0, g22To238y0, g22To239y0, g22To240y0, g22To241y0, g22To242y0, g22To243y0, g22To244y0, g22To245y0, g22To246y0, g22To247y0, g22To248y0, g22To249y0, g22To250y0, g22To251y0, g22To252y0}, + G2my1: [253]*big.Int{g23y1, g25y1, g27y1, g22To3y1, g22To4y1, g22To5y1, g22To6y1, g22To7y1, g22To8y1, g22To9y1, g22To10y1, g22To11y1, g22To12y1, g22To13y1, g22To14y1, g22To15y1, g22To16y1, g22To17y1, g22To18y1, g22To19y1, g22To20y1, g22To21y1, g22To22y1, g22To23y1, g22To24y1, g22To25y1, g22To26y1, g22To27y1, g22To28y1, g22To29y1, g22To30y1, g22To31y1, g22To32y1, g22To33y1, g22To34y1, g22To35y1, g22To36y1, g22To37y1, g22To38y1, g22To39y1, g22To40y1, g22To41y1, g22To42y1, g22To43y1, g22To44y1, g22To45y1, g22To46y1, g22To47y1, g22To48y1, g22To49y1, g22To50y1, g22To51y1, g22To52y1, g22To53y1, g22To54y1, g22To55y1, g22To56y1, g22To57y1, g22To58y1, g22To59y1, g22To60y1, g22To61y1, g22To62y1, g22To63y1, g22To64y1, g22To65y1, g22To66y1, g22To67y1, g22To68y1, g22To69y1, g22To70y1, g22To71y1, g22To72y1, g22To73y1, g22To74y1, g22To75y1, g22To76y1, g22To77y1, g22To78y1, g22To79y1, g22To80y1, g22To81y1, g22To82y1, g22To83y1, g22To84y1, g22To85y1, g22To86y1, g22To87y1, g22To88y1, g22To89y1, g22To90y1, g22To91y1, g22To92y1, g22To93y1, g22To94y1, g22To95y1, g22To96y1, g22To97y1, g22To98y1, g22To99y1, g22To100y1, g22To101y1, g22To102y1, g22To103y1, g22To104y1, g22To105y1, g22To106y1, g22To107y1, g22To108y1, g22To109y1, g22To110y1, g22To111y1, g22To112y1, g22To113y1, g22To114y1, g22To115y1, g22To116y1, g22To117y1, g22To118y1, g22To119y1, g22To120y1, g22To121y1, g22To122y1, g22To123y1, g22To124y1, g22To125y1, g22To126y1, g22To127y1, g22To128y1, g22To129y1, g22To130y1, g22To131y1, g22To132y1, g22To133y1, g22To134y1, g22To135y1, g22To136y1, g22To137y1, g22To138y1, g22To139y1, g22To140y1, g22To141y1, g22To142y1, g22To143y1, g22To144y1, g22To145y1, g22To146y1, g22To147y1, g22To148y1, g22To149y1, g22To150y1, g22To151y1, g22To152y1, g22To153y1, g22To154y1, g22To155y1, g22To156y1, g22To157y1, g22To158y1, g22To159y1, g22To160y1, g22To161y1, g22To162y1, g22To163y1, g22To164y1, g22To165y1, g22To166y1, g22To167y1, g22To168y1, g22To169y1, g22To170y1, g22To171y1, g22To172y1, g22To173y1, g22To174y1, g22To175y1, g22To176y1, g22To177y1, g22To178y1, g22To179y1, g22To180y1, g22To181y1, g22To182y1, g22To183y1, g22To184y1, g22To185y1, g22To186y1, g22To187y1, g22To188y1, g22To189y1, g22To190y1, g22To191y1, g22To192y1, g22To193y1, g22To194y1, g22To195y1, g22To196y1, g22To197y1, g22To198y1, g22To199y1, g22To200y1, g22To201y1, g22To202y1, g22To203y1, g22To204y1, g22To205y1, g22To206y1, g22To207y1, g22To208y1, g22To209y1, g22To210y1, g22To211y1, g22To212y1, g22To213y1, g22To214y1, g22To215y1, g22To216y1, g22To217y1, g22To218y1, g22To219y1, g22To220y1, g22To221y1, g22To222y1, g22To223y1, g22To224y1, g22To225y1, g22To226y1, g22To227y1, g22To228y1, g22To229y1, g22To230y1, g22To231y1, g22To232y1, g22To233y1, g22To234y1, g22To235y1, g22To236y1, g22To237y1, g22To238y1, g22To239y1, g22To240y1, g22To241y1, g22To242y1, g22To243y1, g22To244y1, g22To245y1, g22To246y1, g22To247y1, g22To248y1, g22To249y1, g22To250y1, g22To251y1, g22To252y1}, + } + +} diff --git a/std/commitments/kzg_bls12377/verifier.go b/std/commitments/kzg_bls12377/verifier.go index 264f76dc70..d999e6396e 100644 --- a/std/commitments/kzg_bls12377/verifier.go +++ b/std/commitments/kzg_bls12377/verifier.go @@ -65,7 +65,7 @@ func Verify(api frontend.API, commitment Digest, proof OpeningProof, point front // [α-a]G₂ var alphaMinusaG2 sw_bls12377.G2Affine - alphaMinusaG2.ScalarMul(api, srs.G2[0], point). + alphaMinusaG2.ScalarMulBase(api, point). Neg(api, alphaMinusaG2). AddAssign(api, srs.G2[1]) From b11c2f0b180bc9b9fb022f1307d94214dc726633 Mon Sep 17 00:00:00 2001 From: ThomasPiellard Date: Wed, 1 Mar 2023 15:27:02 +0100 Subject: [PATCH 035/464] Fix/issue 476 (#505) * fix: fixed size Z groth16 bn254 * fix: fix #476 --- internal/backend/bls12-377/groth16/prove.go | 3 +- internal/backend/bls12-377/groth16/setup.go | 5 +- internal/backend/bls12-381/groth16/prove.go | 3 +- internal/backend/bls12-381/groth16/setup.go | 5 +- internal/backend/bls24-315/groth16/prove.go | 3 +- internal/backend/bls24-315/groth16/setup.go | 5 +- internal/backend/bls24-317/groth16/prove.go | 3 +- internal/backend/bls24-317/groth16/setup.go | 5 +- internal/backend/bn254/groth16/prove.go | 3 +- internal/backend/bn254/groth16/setup.go | 5 +- internal/backend/bw6-633/groth16/prove.go | 3 +- internal/backend/bw6-633/groth16/setup.go | 5 +- internal/backend/bw6-761/groth16/prove.go | 3 +- internal/backend/bw6-761/groth16/setup.go | 5 +- .../zkpschemes/groth16/groth16.prove.go.tmpl | 51 ++++++++++--------- .../zkpschemes/groth16/groth16.setup.go.tmpl | 5 +- 16 files changed, 64 insertions(+), 48 deletions(-) diff --git a/internal/backend/bls12-377/groth16/prove.go b/internal/backend/bls12-377/groth16/prove.go index 79eab8cbef..e902208028 100644 --- a/internal/backend/bls12-377/groth16/prove.go +++ b/internal/backend/bls12-377/groth16/prove.go @@ -203,8 +203,9 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness fr.Vector, opt backend.ProverC var krs, krs2, p1 curve.G1Jac chKrs2Done := make(chan error, 1) + sizeH := int(pk.Domain.Cardinality - 1) // comes from the fact the deg(H)=(n-1)+(n-1)-n=n-2 go func() { - _, err := krs2.MultiExp(pk.G1.Z, h, ecc.MultiExpConfig{NbTasks: n / 2}) + _, err := krs2.MultiExp(pk.G1.Z, h[:sizeH], ecc.MultiExpConfig{NbTasks: n / 2}) chKrs2Done <- err }() diff --git a/internal/backend/bls12-377/groth16/setup.go b/internal/backend/bls12-377/groth16/setup.go index 8b3beb485e..2665004ce3 100644 --- a/internal/backend/bls12-377/groth16/setup.go +++ b/internal/backend/bls12-377/groth16/setup.go @@ -238,8 +238,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pk.G1.B = g1PointsAff[offset : offset+len(B)] offset += len(B) - pk.G1.Z = g1PointsAff[offset : offset+int(domain.Cardinality)] - bitReverse(pk.G1.Z) + bitReverse(g1PointsAff[offset : offset+int(domain.Cardinality)]) + sizeZ := int(domain.Cardinality) - 1 // deg(H)=deg(A*B-C/X^n-1)=(n-1)+(n-1)-n=n-2 + pk.G1.Z = g1PointsAff[offset : offset+sizeZ] offset += int(domain.Cardinality) diff --git a/internal/backend/bls12-381/groth16/prove.go b/internal/backend/bls12-381/groth16/prove.go index 775bd83af9..4d39b25160 100644 --- a/internal/backend/bls12-381/groth16/prove.go +++ b/internal/backend/bls12-381/groth16/prove.go @@ -203,8 +203,9 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness fr.Vector, opt backend.ProverC var krs, krs2, p1 curve.G1Jac chKrs2Done := make(chan error, 1) + sizeH := int(pk.Domain.Cardinality - 1) // comes from the fact the deg(H)=(n-1)+(n-1)-n=n-2 go func() { - _, err := krs2.MultiExp(pk.G1.Z, h, ecc.MultiExpConfig{NbTasks: n / 2}) + _, err := krs2.MultiExp(pk.G1.Z, h[:sizeH], ecc.MultiExpConfig{NbTasks: n / 2}) chKrs2Done <- err }() diff --git a/internal/backend/bls12-381/groth16/setup.go b/internal/backend/bls12-381/groth16/setup.go index f1b05f3cc8..b5878333f6 100644 --- a/internal/backend/bls12-381/groth16/setup.go +++ b/internal/backend/bls12-381/groth16/setup.go @@ -238,8 +238,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pk.G1.B = g1PointsAff[offset : offset+len(B)] offset += len(B) - pk.G1.Z = g1PointsAff[offset : offset+int(domain.Cardinality)] - bitReverse(pk.G1.Z) + bitReverse(g1PointsAff[offset : offset+int(domain.Cardinality)]) + sizeZ := int(domain.Cardinality) - 1 // deg(H)=deg(A*B-C/X^n-1)=(n-1)+(n-1)-n=n-2 + pk.G1.Z = g1PointsAff[offset : offset+sizeZ] offset += int(domain.Cardinality) diff --git a/internal/backend/bls24-315/groth16/prove.go b/internal/backend/bls24-315/groth16/prove.go index d822d3780c..c7fa4a254d 100644 --- a/internal/backend/bls24-315/groth16/prove.go +++ b/internal/backend/bls24-315/groth16/prove.go @@ -203,8 +203,9 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness fr.Vector, opt backend.ProverC var krs, krs2, p1 curve.G1Jac chKrs2Done := make(chan error, 1) + sizeH := int(pk.Domain.Cardinality - 1) // comes from the fact the deg(H)=(n-1)+(n-1)-n=n-2 go func() { - _, err := krs2.MultiExp(pk.G1.Z, h, ecc.MultiExpConfig{NbTasks: n / 2}) + _, err := krs2.MultiExp(pk.G1.Z, h[:sizeH], ecc.MultiExpConfig{NbTasks: n / 2}) chKrs2Done <- err }() diff --git a/internal/backend/bls24-315/groth16/setup.go b/internal/backend/bls24-315/groth16/setup.go index 8a80f7f023..414a6743f4 100644 --- a/internal/backend/bls24-315/groth16/setup.go +++ b/internal/backend/bls24-315/groth16/setup.go @@ -238,8 +238,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pk.G1.B = g1PointsAff[offset : offset+len(B)] offset += len(B) - pk.G1.Z = g1PointsAff[offset : offset+int(domain.Cardinality)] - bitReverse(pk.G1.Z) + bitReverse(g1PointsAff[offset : offset+int(domain.Cardinality)]) + sizeZ := int(domain.Cardinality) - 1 // deg(H)=deg(A*B-C/X^n-1)=(n-1)+(n-1)-n=n-2 + pk.G1.Z = g1PointsAff[offset : offset+sizeZ] offset += int(domain.Cardinality) diff --git a/internal/backend/bls24-317/groth16/prove.go b/internal/backend/bls24-317/groth16/prove.go index d80167098d..9e5119930f 100644 --- a/internal/backend/bls24-317/groth16/prove.go +++ b/internal/backend/bls24-317/groth16/prove.go @@ -203,8 +203,9 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness fr.Vector, opt backend.ProverC var krs, krs2, p1 curve.G1Jac chKrs2Done := make(chan error, 1) + sizeH := int(pk.Domain.Cardinality - 1) // comes from the fact the deg(H)=(n-1)+(n-1)-n=n-2 go func() { - _, err := krs2.MultiExp(pk.G1.Z, h, ecc.MultiExpConfig{NbTasks: n / 2}) + _, err := krs2.MultiExp(pk.G1.Z, h[:sizeH], ecc.MultiExpConfig{NbTasks: n / 2}) chKrs2Done <- err }() diff --git a/internal/backend/bls24-317/groth16/setup.go b/internal/backend/bls24-317/groth16/setup.go index c49e1718ea..cddbac53ae 100644 --- a/internal/backend/bls24-317/groth16/setup.go +++ b/internal/backend/bls24-317/groth16/setup.go @@ -238,8 +238,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pk.G1.B = g1PointsAff[offset : offset+len(B)] offset += len(B) - pk.G1.Z = g1PointsAff[offset : offset+int(domain.Cardinality)] - bitReverse(pk.G1.Z) + bitReverse(g1PointsAff[offset : offset+int(domain.Cardinality)]) + sizeZ := int(domain.Cardinality) - 1 // deg(H)=deg(A*B-C/X^n-1)=(n-1)+(n-1)-n=n-2 + pk.G1.Z = g1PointsAff[offset : offset+sizeZ] offset += int(domain.Cardinality) diff --git a/internal/backend/bn254/groth16/prove.go b/internal/backend/bn254/groth16/prove.go index d3dcc1ba5a..ed5bcf588b 100644 --- a/internal/backend/bn254/groth16/prove.go +++ b/internal/backend/bn254/groth16/prove.go @@ -203,8 +203,9 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness fr.Vector, opt backend.ProverC var krs, krs2, p1 curve.G1Jac chKrs2Done := make(chan error, 1) + sizeH := int(pk.Domain.Cardinality - 1) // comes from the fact the deg(H)=(n-1)+(n-1)-n=n-2 go func() { - _, err := krs2.MultiExp(pk.G1.Z, h, ecc.MultiExpConfig{NbTasks: n / 2}) + _, err := krs2.MultiExp(pk.G1.Z, h[:sizeH], ecc.MultiExpConfig{NbTasks: n / 2}) chKrs2Done <- err }() diff --git a/internal/backend/bn254/groth16/setup.go b/internal/backend/bn254/groth16/setup.go index e13869bbcb..0ddf89346a 100644 --- a/internal/backend/bn254/groth16/setup.go +++ b/internal/backend/bn254/groth16/setup.go @@ -238,8 +238,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pk.G1.B = g1PointsAff[offset : offset+len(B)] offset += len(B) - pk.G1.Z = g1PointsAff[offset : offset+int(domain.Cardinality)] - bitReverse(pk.G1.Z) + bitReverse(g1PointsAff[offset : offset+int(domain.Cardinality)]) + sizeZ := int(domain.Cardinality) - 1 // deg(H)=deg(A*B-C/X^n-1)=(n-1)+(n-1)-n=n-2 + pk.G1.Z = g1PointsAff[offset : offset+sizeZ] offset += int(domain.Cardinality) diff --git a/internal/backend/bw6-633/groth16/prove.go b/internal/backend/bw6-633/groth16/prove.go index e22ef4e7a0..34178eab4b 100644 --- a/internal/backend/bw6-633/groth16/prove.go +++ b/internal/backend/bw6-633/groth16/prove.go @@ -203,8 +203,9 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness fr.Vector, opt backend.ProverC var krs, krs2, p1 curve.G1Jac chKrs2Done := make(chan error, 1) + sizeH := int(pk.Domain.Cardinality - 1) // comes from the fact the deg(H)=(n-1)+(n-1)-n=n-2 go func() { - _, err := krs2.MultiExp(pk.G1.Z, h, ecc.MultiExpConfig{NbTasks: n / 2}) + _, err := krs2.MultiExp(pk.G1.Z, h[:sizeH], ecc.MultiExpConfig{NbTasks: n / 2}) chKrs2Done <- err }() diff --git a/internal/backend/bw6-633/groth16/setup.go b/internal/backend/bw6-633/groth16/setup.go index d6777090eb..1a80792363 100644 --- a/internal/backend/bw6-633/groth16/setup.go +++ b/internal/backend/bw6-633/groth16/setup.go @@ -238,8 +238,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pk.G1.B = g1PointsAff[offset : offset+len(B)] offset += len(B) - pk.G1.Z = g1PointsAff[offset : offset+int(domain.Cardinality)] - bitReverse(pk.G1.Z) + bitReverse(g1PointsAff[offset : offset+int(domain.Cardinality)]) + sizeZ := int(domain.Cardinality) - 1 // deg(H)=deg(A*B-C/X^n-1)=(n-1)+(n-1)-n=n-2 + pk.G1.Z = g1PointsAff[offset : offset+sizeZ] offset += int(domain.Cardinality) diff --git a/internal/backend/bw6-761/groth16/prove.go b/internal/backend/bw6-761/groth16/prove.go index 80b4df34fd..dd67fc5d1e 100644 --- a/internal/backend/bw6-761/groth16/prove.go +++ b/internal/backend/bw6-761/groth16/prove.go @@ -203,8 +203,9 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness fr.Vector, opt backend.ProverC var krs, krs2, p1 curve.G1Jac chKrs2Done := make(chan error, 1) + sizeH := int(pk.Domain.Cardinality - 1) // comes from the fact the deg(H)=(n-1)+(n-1)-n=n-2 go func() { - _, err := krs2.MultiExp(pk.G1.Z, h, ecc.MultiExpConfig{NbTasks: n / 2}) + _, err := krs2.MultiExp(pk.G1.Z, h[:sizeH], ecc.MultiExpConfig{NbTasks: n / 2}) chKrs2Done <- err }() diff --git a/internal/backend/bw6-761/groth16/setup.go b/internal/backend/bw6-761/groth16/setup.go index c0616ff53a..9fb10e6cb4 100644 --- a/internal/backend/bw6-761/groth16/setup.go +++ b/internal/backend/bw6-761/groth16/setup.go @@ -238,8 +238,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pk.G1.B = g1PointsAff[offset : offset+len(B)] offset += len(B) - pk.G1.Z = g1PointsAff[offset : offset+int(domain.Cardinality)] - bitReverse(pk.G1.Z) + bitReverse(g1PointsAff[offset : offset+int(domain.Cardinality)]) + sizeZ := int(domain.Cardinality) - 1 // deg(H)=deg(A*B-C/X^n-1)=(n-1)+(n-1)-n=n-2 + pk.G1.Z = g1PointsAff[offset : offset+sizeZ] offset += int(domain.Cardinality) diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl index dec4db8338..2391be837a 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl @@ -76,7 +76,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness fr.Vector, opt backend.ProverC } var wireValues []fr.Element - var err error + var err error if wireValues, err = r1cs.Solve(witness, a, b, c, opt); err != nil { if !opt.Force { return nil, err @@ -105,12 +105,12 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness fr.Vector, opt backend.ProverC // we need to copy and filter the wireValues for each multi exp // as pk.G1.A, pk.G1.B and pk.G2.B may have (a significant) number of point at infinity - var wireValuesA, wireValuesB []fr.Element - chWireValuesA, chWireValuesB := make(chan struct{}, 1) , make(chan struct{}, 1) + var wireValuesA, wireValuesB []fr.Element + chWireValuesA, chWireValuesB := make(chan struct{}, 1), make(chan struct{}, 1) go func() { - wireValuesA = make([]fr.Element , len(wireValues) - int(pk.NbInfinityA)) - for i,j :=0,0; j Date: Thu, 2 Mar 2023 00:02:05 +0100 Subject: [PATCH 036/464] docs: implement lookup2 comment --- std/algebra/fields_bls12377/e2.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/std/algebra/fields_bls12377/e2.go b/std/algebra/fields_bls12377/e2.go index ab43cc1c0e..4e3df6a6e8 100644 --- a/std/algebra/fields_bls12377/e2.go +++ b/std/algebra/fields_bls12377/e2.go @@ -241,7 +241,11 @@ func (e *E2) Select(api frontend.API, b frontend.Variable, r1, r2 E2) *E2 { return e } -// Lookup2 ... +// Lookup2 implements two-bit lookup. It returns: +// - r1 if b1=0 and b2=0, +// - r2 if b1=0 and b2=1, +// - r3 if b1=1 and b2=0, +// - r3 if b1=1 and b2=1. func (e *E2) Lookup2(api frontend.API, b1, b2 frontend.Variable, r1, r2, r3, r4 E2) *E2 { e.A0 = api.Lookup2(b1, b2, r1.A0, r2.A0, r3.A0, r4.A0) From 0bbe5d0a35bbc100e77ea591c565bd9cef46aa78 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 2 Mar 2023 00:02:21 +0100 Subject: [PATCH 037/464] fix: used keyed struct fields, silence linter --- std/algebra/sw_bls12377/g2.go | 44 +++++++++++++++++------------------ 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/std/algebra/sw_bls12377/g2.go b/std/algebra/sw_bls12377/g2.go index e4da202870..c9576f7f00 100644 --- a/std/algebra/sw_bls12377/g2.go +++ b/std/algebra/sw_bls12377/g2.go @@ -485,30 +485,30 @@ func (P *G2Affine) ScalarMulBase(api frontend.API, s frontend.Variable) *G2Affin // gm[0] = 3g, gm[1] = 5g, gm[2] = 7g res.X.Lookup2(api, sBits[1], sBits[2], fields_bls12377.E2{ - points.G2x0, - points.G2x1}, + A0: points.G2x0, + A1: points.G2x1}, fields_bls12377.E2{ - points.G2mx0[0], - points.G2mx1[0]}, + A0: points.G2mx0[0], + A1: points.G2mx1[0]}, fields_bls12377.E2{ - points.G2mx0[1], - points.G2mx1[1]}, + A0: points.G2mx0[1], + A1: points.G2mx1[1]}, fields_bls12377.E2{ - points.G2mx0[2], - points.G2mx1[2]}) + A0: points.G2mx0[2], + A1: points.G2mx1[2]}) res.Y.Lookup2(api, sBits[1], sBits[2], fields_bls12377.E2{ - points.G2y0, - points.G2y1}, + A0: points.G2y0, + A1: points.G2y1}, fields_bls12377.E2{ - points.G2my0[0], - points.G2my1[0]}, + A0: points.G2my0[0], + A1: points.G2my1[0]}, fields_bls12377.E2{ - points.G2my0[1], - points.G2my1[1]}, + A0: points.G2my0[1], + A1: points.G2my1[1]}, fields_bls12377.E2{ - points.G2my0[2], - points.G2my1[2]}) + A0: points.G2my0[2], + A1: points.G2my1[2]}) for i := 3; i < 253; i++ { // gm[i] = [2^i]g @@ -516,18 +516,18 @@ func (P *G2Affine) ScalarMulBase(api frontend.API, s frontend.Variable) *G2Affin tmp.Y = res.Y tmp.AddAssign(api, G2Affine{ fields_bls12377.E2{ - points.G2mx0[i], - points.G2mx1[i]}, + A0: points.G2mx0[i], + A1: points.G2mx1[i]}, fields_bls12377.E2{ - points.G2my0[i], - points.G2my1[i]}}) + A0: points.G2my0[i], + A1: points.G2my1[i]}}) res.Select(api, sBits[i], tmp, res) } // i = 0 tmp.Neg(api, G2Affine{ - fields_bls12377.E2{points.G2x0, points.G2x1}, - fields_bls12377.E2{points.G2y0, points.G2y1}}) + fields_bls12377.E2{A0: points.G2x0, A1: points.G2x1}, + fields_bls12377.E2{A0: points.G2y0, A1: points.G2y1}}) tmp.AddAssign(api, res) res.Select(api, sBits[0], res, tmp) From a9c4ad539ddb73cfcf877c3ca51f81fe40adfca7 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 2 Mar 2023 00:06:51 +0100 Subject: [PATCH 038/464] fix: remove profiling --- std/commitments/kzg_bls12377/verifier_test.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/std/commitments/kzg_bls12377/verifier_test.go b/std/commitments/kzg_bls12377/verifier_test.go index 7acd1e55aa..58563a44ea 100644 --- a/std/commitments/kzg_bls12377/verifier_test.go +++ b/std/commitments/kzg_bls12377/verifier_test.go @@ -27,7 +27,6 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/consensys/gnark/frontend/cs/scs" - "github.com/consensys/gnark/profile" "github.com/consensys/gnark/test" ) @@ -153,9 +152,7 @@ func BenchmarkVerifyKZG(b *testing.B) { b.ResetTimer() b.Run("groth16", func(b *testing.B) { for i := 0; i < b.N; i++ { - p := profile.Start() ccsBench, _ = frontend.Compile(ecc.BW6_761.ScalarField(), r1cs.NewBuilder, &c) - p.Stop() } }) b.Log("groth16", ccsBench.GetNbConstraints()) From c866c30868f6be44bd385688f0cd7cfdf2d64b5a Mon Sep 17 00:00:00 2001 From: ThomasPiellard Date: Thu, 2 Mar 2023 06:08:12 +0100 Subject: [PATCH 039/464] Feat/export solution (#492) * feat: addition of Trace + GetTrace methods * feat: use GetTrace in groth16 + plonkProver on bn254 * feat: fixed the trace for Groth16 + use getTrace in plonkfri * feat: code gen * fix: fixed nil pointer dereference * feat: restored capacity for a, b, c * fix: fixed solver_test.go * refactor: cleaned solver_test * refactor: restore CoeffEngine in ConstraintSystem * refactor: trace -> solution * refactor: IsSolved deprecated; added ExampleR1CS_Solve * style: code cleaning and record fixes #476 * refactor: move backend/hint and backend.Options to constraint/solver (#508) * refactor: move backend/options into constraint/solver * refactor: move backend/hint into constraint/solver * refactor: constaint.Hint -> constraint.HintMapping * refactor: remove dead code in plonk provers * refactor: plonk trace -> solution --------- Co-authored-by: Gautam Botrel --- backend/backend.go | 56 +----- backend/groth16/groth16.go | 55 ++---- backend/hint/builtin.go | 25 --- backend/hint/hint.go | 102 ---------- backend/hint/registry.go | 37 ---- backend/plonk/plonk.go | 48 +---- backend/plonkfri/plonkfri.go | 50 +---- constraint/bls12-377/r1cs.go | 52 +++-- constraint/bls12-377/r1cs_sparse.go | 80 ++++++-- constraint/bls12-377/solution.go | 100 +++++++++- constraint/bls12-381/r1cs.go | 52 +++-- constraint/bls12-381/r1cs_sparse.go | 80 ++++++-- constraint/bls12-381/solution.go | 100 +++++++++- constraint/bls24-315/r1cs.go | 52 +++-- constraint/bls24-315/r1cs_sparse.go | 80 ++++++-- constraint/bls24-315/solution.go | 100 +++++++++- constraint/bls24-317/r1cs.go | 52 +++-- constraint/bls24-317/r1cs_sparse.go | 80 ++++++-- constraint/bls24-317/solution.go | 100 +++++++++- constraint/bn254/r1cs.go | 52 +++-- constraint/bn254/r1cs_sparse.go | 80 ++++++-- constraint/bn254/solution.go | 100 +++++++++- constraint/bw6-633/r1cs.go | 52 +++-- constraint/bw6-633/r1cs_sparse.go | 80 ++++++-- constraint/bw6-633/solution.go | 100 +++++++++- constraint/bw6-761/r1cs.go | 52 +++-- constraint/bw6-761/r1cs_sparse.go | 80 ++++++-- constraint/bw6-761/solution.go | 100 +++++++++- constraint/commitment.go | 4 +- constraint/hint.go | 16 +- constraint/level_builder.go | 4 +- constraint/r1cs_test.go | 38 ++++ constraint/solver/hint.go | 101 ++++++++++ constraint/solver/hint_registry.go | 60 ++++++ constraint/solver/options.go | 69 +++++++ constraint/system.go | 39 ++-- constraint/tinyfield/r1cs.go | 52 +++-- constraint/tinyfield/r1cs_sparse.go | 80 ++++++-- constraint/tinyfield/solution.go | 100 +++++++++- debug_test.go | 15 +- frontend/api.go | 4 +- frontend/builder.go | 4 +- frontend/cs/r1cs/api.go | 6 +- frontend/cs/r1cs/builder.go | 4 +- frontend/cs/scs/api.go | 4 +- frontend/cs/scs/builder.go | 4 +- integration_test.go | 5 +- internal/backend/bls12-377/groth16/prove.go | 57 +++--- internal/backend/bls12-377/plonk/prove.go | 81 +++----- internal/backend/bls12-377/plonkfri/prove.go | 74 ++----- internal/backend/bls12-381/groth16/prove.go | 57 +++--- internal/backend/bls12-381/plonk/prove.go | 81 +++----- internal/backend/bls12-381/plonkfri/prove.go | 74 ++----- internal/backend/bls24-315/groth16/prove.go | 57 +++--- internal/backend/bls24-315/plonk/prove.go | 81 +++----- internal/backend/bls24-315/plonkfri/prove.go | 74 ++----- internal/backend/bls24-317/groth16/prove.go | 57 +++--- internal/backend/bls24-317/plonk/prove.go | 81 +++----- internal/backend/bls24-317/plonkfri/prove.go | 74 ++----- internal/backend/bn254/groth16/prove.go | 57 +++--- internal/backend/bn254/plonk/prove.go | 81 +++----- internal/backend/bn254/plonkfri/prove.go | 74 ++----- internal/backend/bw6-633/groth16/prove.go | 57 +++--- internal/backend/bw6-633/plonk/prove.go | 81 +++----- internal/backend/bw6-633/plonkfri/prove.go | 74 ++----- internal/backend/bw6-761/groth16/prove.go | 57 +++--- internal/backend/bw6-761/plonk/prove.go | 81 +++----- internal/backend/bw6-761/plonkfri/prove.go | 74 ++----- internal/backend/circuits/circuits.go | 8 +- .../template/representations/r1cs.go.tmpl | 53 ++++-- .../representations/r1cs.sparse.go.tmpl | 82 ++++++-- .../template/representations/solution.go.tmpl | 106 ++++++++++- .../zkpschemes/groth16/groth16.prove.go.tmpl | 57 +++--- .../zkpschemes/plonk/plonk.prove.go.tmpl | 99 ++++------ .../zkpschemes/plonkfri/plonk.prove.go.tmpl | 78 +++----- std/accumulator/merkle/verify_test.go | 11 +- std/algebra/fields_bls12377/e12.go | 7 +- std/algebra/fields_bls12377/e2.go | 7 +- std/algebra/fields_bls12377/e6.go | 7 +- std/algebra/fields_bls24315/e12.go | 6 +- std/algebra/fields_bls24315/e2.go | 6 +- std/algebra/fields_bls24315/e24.go | 6 +- std/algebra/fields_bls24315/e4.go | 6 +- std/algebra/sw_bls12377/g1.go | 5 +- std/algebra/sw_bls12377/g2.go | 5 +- std/algebra/sw_bls24315/g1.go | 4 +- std/algebra/sw_bls24315/g2.go | 4 +- std/algebra/twistededwards/scalarmul_glv.go | 4 +- std/commitments/fri/utils.go | 4 +- std/groth16_bls12377/verifier_test.go | 4 +- std/groth16_bls24315/verifier_test.go | 3 +- std/hints.go | 26 +-- std/hints_test.go | 2 +- std/math/bits/conversion_binary.go | 6 +- std/math/bits/conversion_ternary.go | 4 +- std/math/bits/naf.go | 4 +- std/math/emulated/doc_example_field_test.go | 3 +- std/math/emulated/hints.go | 8 +- std/selector/multiplexer.go | 6 +- test/assert.go | 40 +--- test/engine.go | 4 +- test/engine_test.go | 7 +- test/options.go | 13 +- test/solver_test.go | 180 ++++++++++-------- 104 files changed, 2855 insertions(+), 2110 deletions(-) delete mode 100644 backend/hint/builtin.go delete mode 100644 backend/hint/hint.go delete mode 100644 backend/hint/registry.go create mode 100644 constraint/solver/hint.go create mode 100644 constraint/solver/hint_registry.go create mode 100644 constraint/solver/options.go diff --git a/backend/backend.go b/backend/backend.go index 73c3f05bae..84a05271ab 100644 --- a/backend/backend.go +++ b/backend/backend.go @@ -15,11 +15,7 @@ // Package backend implements Zero Knowledge Proof systems: it consumes circuit compiled with gnark/frontend. package backend -import ( - "github.com/consensys/gnark/backend/hint" - "github.com/consensys/gnark/logger" - "github.com/rs/zerolog" -) +import "github.com/consensys/gnark/constraint/solver" // ID represent a unique ID for a proving scheme type ID uint16 @@ -50,26 +46,20 @@ func (id ID) String() string { } } -// ProverOption defines option for altering the behaviour of the prover in +// ProverOption defines option for altering the behavior of the prover in // Prove, ReadAndProve and IsSolved methods. See the descriptions of functions // returning instances of this type for implemented options. type ProverOption func(*ProverConfig) error // ProverConfig is the configuration for the prover with the options applied. type ProverConfig struct { - Force bool // defaults to false - HintFunctions map[hint.ID]hint.Function // defaults to all built-in hint functions - CircuitLogger zerolog.Logger // defaults to gnark.Logger + SolverOpts []solver.Option } // NewProverConfig returns a default ProverConfig with given prover options opts // applied. func NewProverConfig(opts ...ProverOption) (ProverConfig, error) { - log := logger.Logger() - opt := ProverConfig{CircuitLogger: log, HintFunctions: make(map[hint.ID]hint.Function)} - for _, v := range hint.GetRegistered() { - opt.HintFunctions[hint.UUID(v)] = v - } + opt := ProverConfig{} for _, option := range opts { if err := option(&opt); err != nil { return ProverConfig{}, err @@ -78,42 +68,10 @@ func NewProverConfig(opts ...ProverOption) (ProverConfig, error) { return opt, nil } -// IgnoreSolverError is a prover option that indicates that the Prove algorithm -// should complete even if constraint system is not solved. In that case, Prove -// will output an invalid Proof, but will execute all algorithms which is useful -// for test and benchmarking purposes. -func IgnoreSolverError() ProverOption { - return func(opt *ProverConfig) error { - opt.Force = true - return nil - } -} - -// WithHints is a prover option that specifies additional hint functions to be used -// by the constraint solver. -func WithHints(hintFunctions ...hint.Function) ProverOption { - log := logger.Logger() - return func(opt *ProverConfig) error { - // it is an error to register hint function several times, but as the - // prover already checks it then omit here. - for _, h := range hintFunctions { - uuid := hint.UUID(h) - if _, ok := opt.HintFunctions[uuid]; ok { - log.Warn().Int("hintID", int(uuid)).Str("name", hint.Name(h)).Msg("duplicate hint function") - } else { - opt.HintFunctions[uuid] = h - } - } - return nil - } -} - -// WithCircuitLogger is a prover option that specifies zerolog.Logger as a destination for the -// logs printed by api.Println(). By default, uses gnark/logger. -// zerolog.Nop() will disable logging -func WithCircuitLogger(l zerolog.Logger) ProverOption { +// WithSolverOptions specifies the constraint system solver options. +func WithSolverOptions(solverOpts ...solver.Option) ProverOption { return func(opt *ProverConfig) error { - opt.CircuitLogger = l + opt.SolverOpts = solverOpts return nil } } diff --git a/backend/groth16/groth16.go b/backend/groth16/groth16.go index 1aefdfa072..9e4bf92150 100644 --- a/backend/groth16/groth16.go +++ b/backend/groth16/groth16.go @@ -168,55 +168,28 @@ func Verify(proof Proof, vk VerifyingKey, publicWitness witness.Witness) error { // internally, the solution vector to the R1CS will be filled with random values which may impact benchmarking func Prove(r1cs constraint.ConstraintSystem, pk ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (Proof, error) { - // apply options - opt, err := backend.NewProverConfig(opts...) - if err != nil { - return nil, err - } - switch _r1cs := r1cs.(type) { case *cs_bls12377.R1CS: - w, ok := fullWitness.Vector().(fr_bls12377.Vector) - if !ok { - return nil, witness.ErrInvalidWitness - } - return groth16_bls12377.Prove(_r1cs, pk.(*groth16_bls12377.ProvingKey), w, opt) + return groth16_bls12377.Prove(_r1cs, pk.(*groth16_bls12377.ProvingKey), fullWitness, opts...) + case *cs_bls12381.R1CS: - w, ok := fullWitness.Vector().(fr_bls12381.Vector) - if !ok { - return nil, witness.ErrInvalidWitness - } - return groth16_bls12381.Prove(_r1cs, pk.(*groth16_bls12381.ProvingKey), w, opt) + return groth16_bls12381.Prove(_r1cs, pk.(*groth16_bls12381.ProvingKey), fullWitness, opts...) + case *cs_bn254.R1CS: - w, ok := fullWitness.Vector().(fr_bn254.Vector) - if !ok { - return nil, witness.ErrInvalidWitness - } - return groth16_bn254.Prove(_r1cs, pk.(*groth16_bn254.ProvingKey), w, opt) + return groth16_bn254.Prove(_r1cs, pk.(*groth16_bn254.ProvingKey), fullWitness, opts...) + case *cs_bw6761.R1CS: - w, ok := fullWitness.Vector().(fr_bw6761.Vector) - if !ok { - return nil, witness.ErrInvalidWitness - } - return groth16_bw6761.Prove(_r1cs, pk.(*groth16_bw6761.ProvingKey), w, opt) + return groth16_bw6761.Prove(_r1cs, pk.(*groth16_bw6761.ProvingKey), fullWitness, opts...) + case *cs_bls24317.R1CS: - w, ok := fullWitness.Vector().(fr_bls24317.Vector) - if !ok { - return nil, witness.ErrInvalidWitness - } - return groth16_bls24317.Prove(_r1cs, pk.(*groth16_bls24317.ProvingKey), w, opt) + return groth16_bls24317.Prove(_r1cs, pk.(*groth16_bls24317.ProvingKey), fullWitness, opts...) + case *cs_bls24315.R1CS: - w, ok := fullWitness.Vector().(fr_bls24315.Vector) - if !ok { - return nil, witness.ErrInvalidWitness - } - return groth16_bls24315.Prove(_r1cs, pk.(*groth16_bls24315.ProvingKey), w, opt) + return groth16_bls24315.Prove(_r1cs, pk.(*groth16_bls24315.ProvingKey), fullWitness, opts...) + case *cs_bw6633.R1CS: - w, ok := fullWitness.Vector().(fr_bw6633.Vector) - if !ok { - return nil, witness.ErrInvalidWitness - } - return groth16_bw6633.Prove(_r1cs, pk.(*groth16_bw6633.ProvingKey), w, opt) + return groth16_bw6633.Prove(_r1cs, pk.(*groth16_bw6633.ProvingKey), fullWitness, opts...) + default: panic("unrecognized R1CS curve type") } diff --git a/backend/hint/builtin.go b/backend/hint/builtin.go deleted file mode 100644 index 4d0ee814d3..0000000000 --- a/backend/hint/builtin.go +++ /dev/null @@ -1,25 +0,0 @@ -package hint - -import ( - "math/big" -) - -func init() { - Register(InvZero) -} - -// InvZero computes the value 1/a for the single input a. If a == 0, returns 0. -func InvZero(q *big.Int, inputs []*big.Int, results []*big.Int) error { - result := results[0] - - // save input - result.Set(inputs[0]) - - // a == 0, return - if result.IsUint64() && result.Uint64() == 0 { - return nil - } - - result.ModInverse(result, q) - return nil -} diff --git a/backend/hint/hint.go b/backend/hint/hint.go deleted file mode 100644 index 60976a3dc8..0000000000 --- a/backend/hint/hint.go +++ /dev/null @@ -1,102 +0,0 @@ -/* -Package hint allows to define computations outside of a circuit. - -Usually, it is expected that computations in circuits are performed on -variables. However, in some cases defining the computations in circuits may be -complicated or computationally expensive. By using hints, the computations are -performed outside of the circuit on integers (compared to the frontend.Variable -values inside the circuits) and the result of a hint function is assigned to a -newly created variable in a circuit. - -As the computations are perfomed outside of the circuit, then the correctness of -the result is not guaranteed. This also means that the result of a hint function -is unconstrained by default, leading to failure while composing circuit proof. -Thus, it is the circuit developer responsibility to verify the correctness hint -result by adding necessary constraints in the circuit. - -As an example, lets say the hint function computes a factorization of a -semiprime n: - - p, q <- hint(n) st. p * q = n - -into primes p and q. Then, the circuit developer needs to assert in the circuit -that p*q indeed equals to n: - - n == p * q. - -However, if the hint function is incorrectly defined (e.g. in the previous -example, it returns 1 and n instead of p and q), then the assertion may still -hold, but the constructed proof is semantically invalid. Thus, the user -constructing the proof must be extremely cautious when using hints. - -# Using hint functions in circuits - -To use a hint function in a circuit, the developer first needs to define a hint -function hintFn according to the Function interface. Then, in a circuit, the -developer applies the hint function with frontend.API.NewHint(hintFn, vars...), -where vars are the variables the hint function will be applied to (and -correspond to the argument inputs in the Function type) which returns a new -unconstrained variable. The returned variables must be constrained using -frontend.API.Assert[.*] methods. - -As explained, the hints are essentially black boxes from the circuit point of -view and thus the defined hints in circuits are not used when constructing a -proof. To allow the particular hint functions to be used during proof -construction, the user needs to supply a backend.ProverOption indicating the -enabled hints. Such options can be optained by a call to -backend.WithHints(hintFns...), where hintFns are the corresponding hint -functions. - -# Using hint functions in gadgets - -Similar considerations apply for hint functions used in gadgets as in -user-defined circuits. However, listing all hint functions used in a particular -gadget for constructing backend.ProverOption puts high overhead for the user to -enable all necessary hints. - -For that, this package also provides a registry of trusted hint functions. When -a gadget registers a hint function, then it is automatically enabled during -proof computation and the prover does not need to provide a corresponding -proving option. - -In the init() method of the gadget, call the method Register(hintFn) method on -the hint function hintFn to register a hint function in the package registry. -*/ -package hint - -import ( - "hash/fnv" - "math/big" - "reflect" - "runtime" -) - -// ID is a unique identifier for a hint function used for lookup. -type ID uint32 - -// Function defines an annotated hint function; the number of inputs and outputs injected at solving -// time is defined in the circuit (compile time). -// -// For example: -// -// b := api.NewHint(hint, 2, a) -// --> at solving time, hint is going to be invoked with 1 input (a) and is expected to return 2 outputs -// b[0] and b[1]. -type Function func(field *big.Int, inputs []*big.Int, outputs []*big.Int) error - -// UUID is a reference function for computing the hint ID based on a function name -func UUID(fn Function) ID { - hf := fnv.New32a() - name := Name(fn) - - // TODO relying on name to derive UUID is risky; if fn is an anonymous func, wil be package.glob..funcN - // and if new anonymous functions are added in the package, N may change, so will UUID. - hf.Write([]byte(name)) // #nosec G104 -- does not err - - return ID(hf.Sum32()) -} - -func Name(fn Function) string { - fnptr := reflect.ValueOf(fn).Pointer() - return runtime.FuncForPC(fnptr).Name() -} diff --git a/backend/hint/registry.go b/backend/hint/registry.go deleted file mode 100644 index dfd5a66b8d..0000000000 --- a/backend/hint/registry.go +++ /dev/null @@ -1,37 +0,0 @@ -package hint - -import ( - "sync" - - "github.com/consensys/gnark/logger" -) - -var registry = make(map[ID]Function) -var registryM sync.RWMutex - -// Register registers a hint function in the global registry. -func Register(hintFns ...Function) { - registryM.Lock() - defer registryM.Unlock() - for _, hintFn := range hintFns { - key := UUID(hintFn) - name := Name(hintFn) - if _, ok := registry[key]; ok { - log := logger.Logger() - log.Warn().Str("name", name).Msg("function registered multiple times") - return - } - registry[key] = hintFn - } -} - -// GetRegistered returns all registered hint functions. -func GetRegistered() []Function { - registryM.RLock() - defer registryM.RUnlock() - ret := make([]Function, 0, len(registry)) - for _, v := range registry { - ret = append(ret, v) - } - return ret -} diff --git a/backend/plonk/plonk.go b/backend/plonk/plonk.go index 0a6fbc4330..22fb4a84e6 100644 --- a/backend/plonk/plonk.go +++ b/backend/plonk/plonk.go @@ -125,61 +125,27 @@ func Setup(ccs constraint.ConstraintSystem, kzgSRS kzg.SRS) (ProvingKey, Verifyi // internally, the solution vector to the SparseR1CS will be filled with random values which may impact benchmarking func Prove(ccs constraint.ConstraintSystem, pk ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (Proof, error) { - // apply options - opt, err := backend.NewProverConfig(opts...) - if err != nil { - return nil, err - } - switch tccs := ccs.(type) { case *cs_bn254.SparseR1CS: - w, ok := fullWitness.Vector().(fr_bn254.Vector) - if !ok { - return nil, witness.ErrInvalidWitness - } - return plonk_bn254.Prove(tccs, pk.(*plonk_bn254.ProvingKey), w, opt) + return plonk_bn254.Prove(tccs, pk.(*plonk_bn254.ProvingKey), fullWitness, opts...) case *cs_bls12381.SparseR1CS: - w, ok := fullWitness.Vector().(fr_bls12381.Vector) - if !ok { - return nil, witness.ErrInvalidWitness - } - return plonk_bls12381.Prove(tccs, pk.(*plonk_bls12381.ProvingKey), w, opt) + return plonk_bls12381.Prove(tccs, pk.(*plonk_bls12381.ProvingKey), fullWitness, opts...) case *cs_bls12377.SparseR1CS: - w, ok := fullWitness.Vector().(fr_bls12377.Vector) - if !ok { - return nil, witness.ErrInvalidWitness - } - return plonk_bls12377.Prove(tccs, pk.(*plonk_bls12377.ProvingKey), w, opt) + return plonk_bls12377.Prove(tccs, pk.(*plonk_bls12377.ProvingKey), fullWitness, opts...) case *cs_bw6761.SparseR1CS: - w, ok := fullWitness.Vector().(fr_bw6761.Vector) - if !ok { - return nil, witness.ErrInvalidWitness - } - return plonk_bw6761.Prove(tccs, pk.(*plonk_bw6761.ProvingKey), w, opt) + return plonk_bw6761.Prove(tccs, pk.(*plonk_bw6761.ProvingKey), fullWitness, opts...) case *cs_bw6633.SparseR1CS: - w, ok := fullWitness.Vector().(fr_bw6633.Vector) - if !ok { - return nil, witness.ErrInvalidWitness - } - return plonk_bw6633.Prove(tccs, pk.(*plonk_bw6633.ProvingKey), w, opt) + return plonk_bw6633.Prove(tccs, pk.(*plonk_bw6633.ProvingKey), fullWitness, opts...) case *cs_bls24317.SparseR1CS: - w, ok := fullWitness.Vector().(fr_bls24317.Vector) - if !ok { - return nil, witness.ErrInvalidWitness - } - return plonk_bls24317.Prove(tccs, pk.(*plonk_bls24317.ProvingKey), w, opt) + return plonk_bls24317.Prove(tccs, pk.(*plonk_bls24317.ProvingKey), fullWitness, opts...) case *cs_bls24315.SparseR1CS: - w, ok := fullWitness.Vector().(fr_bls24315.Vector) - if !ok { - return nil, witness.ErrInvalidWitness - } - return plonk_bls24315.Prove(tccs, pk.(*plonk_bls24315.ProvingKey), w, opt) + return plonk_bls24315.Prove(tccs, pk.(*plonk_bls24315.ProvingKey), fullWitness, opts...) default: panic("unrecognized SparseR1CS curve type") diff --git a/backend/plonkfri/plonkfri.go b/backend/plonkfri/plonkfri.go index b2cab82fd6..54954f89a8 100644 --- a/backend/plonkfri/plonkfri.go +++ b/backend/plonkfri/plonkfri.go @@ -106,60 +106,28 @@ func Setup(ccs constraint.ConstraintSystem) (ProvingKey, VerifyingKey, error) { // internally, the solution vector to the SparseR1CS will be filled with random values which may impact benchmarking func Prove(ccs constraint.ConstraintSystem, pk ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (Proof, error) { - // apply options - opt, err := backend.NewProverConfig(opts...) - if err != nil { - return nil, err - } - switch tccs := ccs.(type) { case *cs_bn254.SparseR1CS: - w, ok := fullWitness.Vector().(fr_bn254.Vector) - if !ok { - return nil, witness.ErrInvalidWitness - } - return plonk_bn254.Prove(tccs, pk.(*plonk_bn254.ProvingKey), w, opt) + return plonk_bn254.Prove(tccs, pk.(*plonk_bn254.ProvingKey), fullWitness, opts...) case *cs_bls12381.SparseR1CS: - w, ok := fullWitness.Vector().(fr_bls12381.Vector) - if !ok { - return nil, witness.ErrInvalidWitness - } - return plonk_bls12381.Prove(tccs, pk.(*plonk_bls12381.ProvingKey), w, opt) + return plonk_bls12381.Prove(tccs, pk.(*plonk_bls12381.ProvingKey), fullWitness, opts...) case *cs_bls12377.SparseR1CS: - w, ok := fullWitness.Vector().(fr_bls12377.Vector) - if !ok { - return nil, witness.ErrInvalidWitness - } - return plonk_bls12377.Prove(tccs, pk.(*plonk_bls12377.ProvingKey), w, opt) + return plonk_bls12377.Prove(tccs, pk.(*plonk_bls12377.ProvingKey), fullWitness, opts...) case *cs_bw6761.SparseR1CS: - w, ok := fullWitness.Vector().(fr_bw6761.Vector) - if !ok { - return nil, witness.ErrInvalidWitness - } - return plonk_bw6761.Prove(tccs, pk.(*plonk_bw6761.ProvingKey), w, opt) + return plonk_bw6761.Prove(tccs, pk.(*plonk_bw6761.ProvingKey), fullWitness, opts...) case *cs_bw6633.SparseR1CS: - w, ok := fullWitness.Vector().(fr_bw6633.Vector) - if !ok { - return nil, witness.ErrInvalidWitness - } - return plonk_bw6633.Prove(tccs, pk.(*plonk_bw6633.ProvingKey), w, opt) + return plonk_bw6633.Prove(tccs, pk.(*plonk_bw6633.ProvingKey), fullWitness, opts...) case *cs_bls24315.SparseR1CS: - w, ok := fullWitness.Vector().(fr_bls24315.Vector) - if !ok { - return nil, witness.ErrInvalidWitness - } - return plonk_bls24315.Prove(tccs, pk.(*plonk_bls24315.ProvingKey), w, opt) + return plonk_bls24315.Prove(tccs, pk.(*plonk_bls24315.ProvingKey), fullWitness, opts...) + case *cs_bls24317.SparseR1CS: - w, ok := fullWitness.Vector().(fr_bls24317.Vector) - if !ok { - return nil, witness.ErrInvalidWitness - } - return plonk_bls24317.Prove(tccs, pk.(*plonk_bls24317.ProvingKey), w, opt) + return plonk_bls24317.Prove(tccs, pk.(*plonk_bls24317.ProvingKey), fullWitness, opts...) + default: panic("unrecognized SparseR1CS curve type") } diff --git a/constraint/bls12-377/r1cs.go b/constraint/bls12-377/r1cs.go index 8d678db082..40c9af537f 100644 --- a/constraint/bls12-377/r1cs.go +++ b/constraint/bls12-377/r1cs.go @@ -25,9 +25,9 @@ import ( "sync" "time" - "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/backend/ioutils" "github.com/consensys/gnark/logger" "github.com/consensys/gnark/profile" @@ -73,12 +73,37 @@ func (cs *R1CS) AddConstraint(r1c constraint.R1C, debugInfo ...constraint.DebugI return cID } +// Solve returns the vector w solution to the system, that is +// Aw o Bw - Cw = 0 +func (cs *R1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { + opt, err := solver.NewConfig(opts...) + if err != nil { + return nil, err + } + + var res R1CSSolution + + s := ecc.NextPowerOfTwo(uint64(len(cs.Constraints))) + res.A = make(fr.Vector, len(cs.Constraints), s) + res.B = make(fr.Vector, len(cs.Constraints), s) + res.C = make(fr.Vector, len(cs.Constraints), s) + + v := witness.Vector().(fr.Vector) + + res.W, err = cs.solve(v, res.A, res.B, res.C, opt) + if err != nil { + return nil, err + } + + return &res, nil +} + // Solve sets all the wires and returns the a, b, c vectors. // the cs system should have been compiled before. The entries in a, b, c are in Montgomery form. // a, b, c vectors: ab-c = hz // witness = [publicWires | secretWires] (without the ONE_WIRE !) // returns [publicWires | secretWires | internalWires ] -func (cs *R1CS) Solve(witness, a, b, c fr.Vector, opt backend.ProverConfig) (fr.Vector, error) { +func (cs *R1CS) solve(witness, a, b, c fr.Vector, opt solver.Config) (fr.Vector, error) { log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables @@ -114,7 +139,7 @@ func (cs *R1CS) Solve(witness, a, b, c fr.Vector, opt backend.ProverConfig) (fr. // now that we know all inputs are set, defer log printing once all solution.values are computed // (or sooner, if a constraint is not satisfied) - defer solution.printLogs(opt.CircuitLogger, cs.Logs) + defer solution.printLogs(opt.Logger, cs.Logs) if err := cs.parallelSolve(a, b, c, &solution); err != nil { if unsatisfiedErr, ok := err.(*UnsatisfiedConstraintError); ok { @@ -205,8 +230,8 @@ func (cs *R1CS) parallelSolve(a, b, c fr.Vector, solution *solution) error { continue } - // number of tasks for this level is set to num cpus - // but if we don't have enough work for all our CPUS, it can be lower. + // number of tasks for this level is set to number of CPU + // but if we don't have enough work for all our CPU, it can be lower. nbTasks := runtime.NumCPU() maxTasks := int(math.Ceil(maxCPU)) if nbTasks > maxTasks { @@ -249,19 +274,10 @@ func (cs *R1CS) parallelSolve(a, b, c fr.Vector, solution *solution) error { return nil } -// IsSolved returns nil if given witness solves the R1CS and error otherwise -// this method wraps cs.Solve() and allocates cs.Solve() inputs -func (cs *R1CS) IsSolved(witness witness.Witness, opts ...backend.ProverOption) error { - opt, err := backend.NewProverConfig(opts...) - if err != nil { - return err - } - - a := make(fr.Vector, len(cs.Constraints)) - b := make(fr.Vector, len(cs.Constraints)) - c := make(fr.Vector, len(cs.Constraints)) - v := witness.Vector().(fr.Vector) - _, err = cs.Solve(v, a, b, c, opt) +// IsSolved +// Deprecated: use _, err := Solve(...) instead +func (cs *R1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { + _, err := cs.Solve(witness, opts...) return err } diff --git a/constraint/bls12-377/r1cs_sparse.go b/constraint/bls12-377/r1cs_sparse.go index ed01b36846..2fd9f5cd64 100644 --- a/constraint/bls12-377/r1cs_sparse.go +++ b/constraint/bls12-377/r1cs_sparse.go @@ -27,9 +27,9 @@ import ( "sync" "time" - "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/backend/ioutils" "github.com/consensys/gnark/logger" "github.com/consensys/gnark/profile" @@ -70,11 +70,67 @@ func (cs *SparseR1CS) AddConstraint(c constraint.SparseR1C, debugInfo ...constra return cID } +func (c *SparseR1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { + opt, err := solver.NewConfig(opts...) + if err != nil { + return nil, err + } + + // compute the constraint system solution + var solution []fr.Element + if solution, err = c.solve(witness.Vector().(fr.Vector), opt); err != nil { + return nil, err + } + + var res SparseR1CSSolution + // query l, r, o in Lagrange basis, not blinded + res.L, res.R, res.O = c.evaluateLROSmallDomain(solution) + + return &res, nil +} + +// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. +// solution = [ public | secret | internal ] +func (c *SparseR1CS) evaluateLROSmallDomain(solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { + + //s := int(pk.Domain[0].Cardinality) + s := c.GetNbConstraints() + len(c.Public) // len(spr.Public) is for the placeholder constraints + s = int(ecc.NextPowerOfTwo(uint64(s))) + + var l, r, o []fr.Element + l = make([]fr.Element, s) + r = make([]fr.Element, s) + o = make([]fr.Element, s) + s0 := solution[0] + + for i := 0; i < len(c.Public); i++ { // placeholders + l[i] = solution[i] + r[i] = s0 + o[i] = s0 + } + offset := len(c.Public) + for i := 0; i < len(c.Constraints); i++ { // constraints + l[offset+i] = solution[c.Constraints[i].L.WireID()] + r[offset+i] = solution[c.Constraints[i].R.WireID()] + o[offset+i] = solution[c.Constraints[i].O.WireID()] + } + offset += len(c.Constraints) + + for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) + l[offset+i] = s0 + r[offset+i] = s0 + o[offset+i] = s0 + } + + return l, r, o + +} + // Solve sets all the wires. // solution.values = [publicInputs | secretInputs | internalVariables ] // witness: contains the input variables // it returns the full slice of wires -func (cs *SparseR1CS) Solve(witness fr.Vector, opt backend.ProverConfig) (fr.Vector, error) { +func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, error) { log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "plonk").Logger() // set the slices holding the solution.values and monitoring which variables have been solved @@ -110,7 +166,7 @@ func (cs *SparseR1CS) Solve(witness fr.Vector, opt backend.ProverConfig) (fr.Vec solution.nbSolved += uint64(len(witness)) // defer log printing once all solution.values are computed - defer solution.printLogs(opt.CircuitLogger, cs.Logs) + defer solution.printLogs(opt.Logger, cs.Logs) // batch invert the coefficients to avoid many divisions in the solver coefficientsNegInv := fr.BatchInvert(cs.Coefficients) @@ -210,8 +266,8 @@ func (cs *SparseR1CS) parallelSolve(solution *solution, coefficientsNegInv fr.Ve continue } - // number of tasks for this level is set to num cpus - // but if we don't have enough work for all our CPUS, it can be lower. + // number of tasks for this level is set to number of CPU + // but if we don't have enough work for all our CPU, it can be lower. nbTasks := runtime.NumCPU() maxTasks := int(math.Ceil(maxCPU)) if nbTasks > maxTasks { @@ -369,16 +425,10 @@ func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution return nil } -// IsSolved returns nil if given witness solves the SparseR1CS and error otherwise -// this method wraps cs.Solve() and allocates cs.Solve() inputs -func (cs *SparseR1CS) IsSolved(witness witness.Witness, opts ...backend.ProverOption) error { - opt, err := backend.NewProverConfig(opts...) - if err != nil { - return err - } - - v := witness.Vector().(fr.Vector) - _, err = cs.Solve(v, opt) +// IsSolved +// Deprecated: use _, err := Solve(...) instead +func (cs *SparseR1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { + _, err := cs.Solve(witness, opts...) return err } diff --git a/constraint/bls12-377/solution.go b/constraint/bls12-377/solution.go index 8849a30acb..e93dc7bfa1 100644 --- a/constraint/bls12-377/solution.go +++ b/constraint/bls12-377/solution.go @@ -19,10 +19,11 @@ package cs import ( "errors" "fmt" - "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/debug" "github.com/rs/zerolog" + "io" "math/big" "strconv" "strings" @@ -37,12 +38,12 @@ type solution struct { values, coefficients []fr.Element solved []bool nbSolved uint64 - mHintsFunctions map[hint.ID]hint.Function // maps hintID to hint function - mHints map[int]*constraint.Hint // maps wireID to hint + mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function + mHints map[int]*constraint.HintMapping // maps wireID to hint st *debug.SymbolTable } -func newSolution(nbWires int, hintFunctions map[hint.ID]hint.Function, hintsDependencies map[hint.ID]string, mHints map[int]*constraint.Hint, coefficients []fr.Element, st *debug.SymbolTable) (solution, error) { +func newSolution(nbWires int, hintFunctions map[solver.HintID]solver.Hint, hintsDependencies map[solver.HintID]string, mHints map[int]*constraint.HintMapping, coefficients []fr.Element, st *debug.SymbolTable) (solution, error) { s := solution{ st: st, @@ -139,21 +140,21 @@ func (s *solution) accumulateInto(t constraint.Term, r *fr.Element) { } // solveHint compute solution.values[vID] using provided solver hint -func (s *solution) solveWithHint(vID int, h *constraint.Hint) error { +func (s *solution) solveWithHint(vID int, h *constraint.HintMapping) error { // skip if the wire is already solved by a call to the same hint // function on the same inputs if s.solved[vID] { return nil } // ensure hint function was provided - f, ok := s.mHintsFunctions[h.ID] + f, ok := s.mHintsFunctions[h.HintID] if !ok { return errors.New("missing hint function") } // tmp IO big int memory nbInputs := len(h.Inputs) - nbOutputs := len(h.Wires) + nbOutputs := len(h.Outputs) inputs := make([]*big.Int, nbInputs) outputs := make([]*big.Int, nbOutputs) for i := 0; i < nbOutputs; i++ { @@ -203,7 +204,7 @@ func (s *solution) solveWithHint(vID int, h *constraint.Hint) error { var v fr.Element for i := range outputs { v.SetBigInt(outputs[i]) - s.set(h.Wires[i], v) + s.set(h.Outputs[i], v) } return err @@ -294,3 +295,86 @@ func (r *UnsatisfiedConstraintError) Error() string { } return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, r.Err.Error()) } + +// R1CSSolution represent a valid assignment to all the variables in the constraint system. +// The vector W such that Aw o Bw - Cw = 0 +type R1CSSolution struct { + W fr.Vector + A, B, C fr.Vector +} + +func (t *R1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.W.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.A.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.B.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.C.WriteTo(w) + n += a + return n, err +} + +func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.W.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.A.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.B.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.C.ReadFrom(r) + n += a + return n, err +} + +// SparseR1CSSolution represent a valid assignment to all the variables in the constraint system. +type SparseR1CSSolution struct { + L, R, O fr.Vector +} + +func (t *SparseR1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.L.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.R.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.O.WriteTo(w) + n += a + return n, err + +} + +func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.L.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.R.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.O.ReadFrom(r) + a += n + return n, err +} diff --git a/constraint/bls12-381/r1cs.go b/constraint/bls12-381/r1cs.go index f818fb9f42..f007cee3de 100644 --- a/constraint/bls12-381/r1cs.go +++ b/constraint/bls12-381/r1cs.go @@ -25,9 +25,9 @@ import ( "sync" "time" - "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/backend/ioutils" "github.com/consensys/gnark/logger" "github.com/consensys/gnark/profile" @@ -73,12 +73,37 @@ func (cs *R1CS) AddConstraint(r1c constraint.R1C, debugInfo ...constraint.DebugI return cID } +// Solve returns the vector w solution to the system, that is +// Aw o Bw - Cw = 0 +func (cs *R1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { + opt, err := solver.NewConfig(opts...) + if err != nil { + return nil, err + } + + var res R1CSSolution + + s := ecc.NextPowerOfTwo(uint64(len(cs.Constraints))) + res.A = make(fr.Vector, len(cs.Constraints), s) + res.B = make(fr.Vector, len(cs.Constraints), s) + res.C = make(fr.Vector, len(cs.Constraints), s) + + v := witness.Vector().(fr.Vector) + + res.W, err = cs.solve(v, res.A, res.B, res.C, opt) + if err != nil { + return nil, err + } + + return &res, nil +} + // Solve sets all the wires and returns the a, b, c vectors. // the cs system should have been compiled before. The entries in a, b, c are in Montgomery form. // a, b, c vectors: ab-c = hz // witness = [publicWires | secretWires] (without the ONE_WIRE !) // returns [publicWires | secretWires | internalWires ] -func (cs *R1CS) Solve(witness, a, b, c fr.Vector, opt backend.ProverConfig) (fr.Vector, error) { +func (cs *R1CS) solve(witness, a, b, c fr.Vector, opt solver.Config) (fr.Vector, error) { log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables @@ -114,7 +139,7 @@ func (cs *R1CS) Solve(witness, a, b, c fr.Vector, opt backend.ProverConfig) (fr. // now that we know all inputs are set, defer log printing once all solution.values are computed // (or sooner, if a constraint is not satisfied) - defer solution.printLogs(opt.CircuitLogger, cs.Logs) + defer solution.printLogs(opt.Logger, cs.Logs) if err := cs.parallelSolve(a, b, c, &solution); err != nil { if unsatisfiedErr, ok := err.(*UnsatisfiedConstraintError); ok { @@ -205,8 +230,8 @@ func (cs *R1CS) parallelSolve(a, b, c fr.Vector, solution *solution) error { continue } - // number of tasks for this level is set to num cpus - // but if we don't have enough work for all our CPUS, it can be lower. + // number of tasks for this level is set to number of CPU + // but if we don't have enough work for all our CPU, it can be lower. nbTasks := runtime.NumCPU() maxTasks := int(math.Ceil(maxCPU)) if nbTasks > maxTasks { @@ -249,19 +274,10 @@ func (cs *R1CS) parallelSolve(a, b, c fr.Vector, solution *solution) error { return nil } -// IsSolved returns nil if given witness solves the R1CS and error otherwise -// this method wraps cs.Solve() and allocates cs.Solve() inputs -func (cs *R1CS) IsSolved(witness witness.Witness, opts ...backend.ProverOption) error { - opt, err := backend.NewProverConfig(opts...) - if err != nil { - return err - } - - a := make(fr.Vector, len(cs.Constraints)) - b := make(fr.Vector, len(cs.Constraints)) - c := make(fr.Vector, len(cs.Constraints)) - v := witness.Vector().(fr.Vector) - _, err = cs.Solve(v, a, b, c, opt) +// IsSolved +// Deprecated: use _, err := Solve(...) instead +func (cs *R1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { + _, err := cs.Solve(witness, opts...) return err } diff --git a/constraint/bls12-381/r1cs_sparse.go b/constraint/bls12-381/r1cs_sparse.go index 393287d780..63a023a9ff 100644 --- a/constraint/bls12-381/r1cs_sparse.go +++ b/constraint/bls12-381/r1cs_sparse.go @@ -27,9 +27,9 @@ import ( "sync" "time" - "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/backend/ioutils" "github.com/consensys/gnark/logger" "github.com/consensys/gnark/profile" @@ -70,11 +70,67 @@ func (cs *SparseR1CS) AddConstraint(c constraint.SparseR1C, debugInfo ...constra return cID } +func (c *SparseR1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { + opt, err := solver.NewConfig(opts...) + if err != nil { + return nil, err + } + + // compute the constraint system solution + var solution []fr.Element + if solution, err = c.solve(witness.Vector().(fr.Vector), opt); err != nil { + return nil, err + } + + var res SparseR1CSSolution + // query l, r, o in Lagrange basis, not blinded + res.L, res.R, res.O = c.evaluateLROSmallDomain(solution) + + return &res, nil +} + +// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. +// solution = [ public | secret | internal ] +func (c *SparseR1CS) evaluateLROSmallDomain(solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { + + //s := int(pk.Domain[0].Cardinality) + s := c.GetNbConstraints() + len(c.Public) // len(spr.Public) is for the placeholder constraints + s = int(ecc.NextPowerOfTwo(uint64(s))) + + var l, r, o []fr.Element + l = make([]fr.Element, s) + r = make([]fr.Element, s) + o = make([]fr.Element, s) + s0 := solution[0] + + for i := 0; i < len(c.Public); i++ { // placeholders + l[i] = solution[i] + r[i] = s0 + o[i] = s0 + } + offset := len(c.Public) + for i := 0; i < len(c.Constraints); i++ { // constraints + l[offset+i] = solution[c.Constraints[i].L.WireID()] + r[offset+i] = solution[c.Constraints[i].R.WireID()] + o[offset+i] = solution[c.Constraints[i].O.WireID()] + } + offset += len(c.Constraints) + + for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) + l[offset+i] = s0 + r[offset+i] = s0 + o[offset+i] = s0 + } + + return l, r, o + +} + // Solve sets all the wires. // solution.values = [publicInputs | secretInputs | internalVariables ] // witness: contains the input variables // it returns the full slice of wires -func (cs *SparseR1CS) Solve(witness fr.Vector, opt backend.ProverConfig) (fr.Vector, error) { +func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, error) { log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "plonk").Logger() // set the slices holding the solution.values and monitoring which variables have been solved @@ -110,7 +166,7 @@ func (cs *SparseR1CS) Solve(witness fr.Vector, opt backend.ProverConfig) (fr.Vec solution.nbSolved += uint64(len(witness)) // defer log printing once all solution.values are computed - defer solution.printLogs(opt.CircuitLogger, cs.Logs) + defer solution.printLogs(opt.Logger, cs.Logs) // batch invert the coefficients to avoid many divisions in the solver coefficientsNegInv := fr.BatchInvert(cs.Coefficients) @@ -210,8 +266,8 @@ func (cs *SparseR1CS) parallelSolve(solution *solution, coefficientsNegInv fr.Ve continue } - // number of tasks for this level is set to num cpus - // but if we don't have enough work for all our CPUS, it can be lower. + // number of tasks for this level is set to number of CPU + // but if we don't have enough work for all our CPU, it can be lower. nbTasks := runtime.NumCPU() maxTasks := int(math.Ceil(maxCPU)) if nbTasks > maxTasks { @@ -369,16 +425,10 @@ func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution return nil } -// IsSolved returns nil if given witness solves the SparseR1CS and error otherwise -// this method wraps cs.Solve() and allocates cs.Solve() inputs -func (cs *SparseR1CS) IsSolved(witness witness.Witness, opts ...backend.ProverOption) error { - opt, err := backend.NewProverConfig(opts...) - if err != nil { - return err - } - - v := witness.Vector().(fr.Vector) - _, err = cs.Solve(v, opt) +// IsSolved +// Deprecated: use _, err := Solve(...) instead +func (cs *SparseR1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { + _, err := cs.Solve(witness, opts...) return err } diff --git a/constraint/bls12-381/solution.go b/constraint/bls12-381/solution.go index dbf96fadc4..2e0d32172c 100644 --- a/constraint/bls12-381/solution.go +++ b/constraint/bls12-381/solution.go @@ -19,10 +19,11 @@ package cs import ( "errors" "fmt" - "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/debug" "github.com/rs/zerolog" + "io" "math/big" "strconv" "strings" @@ -37,12 +38,12 @@ type solution struct { values, coefficients []fr.Element solved []bool nbSolved uint64 - mHintsFunctions map[hint.ID]hint.Function // maps hintID to hint function - mHints map[int]*constraint.Hint // maps wireID to hint + mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function + mHints map[int]*constraint.HintMapping // maps wireID to hint st *debug.SymbolTable } -func newSolution(nbWires int, hintFunctions map[hint.ID]hint.Function, hintsDependencies map[hint.ID]string, mHints map[int]*constraint.Hint, coefficients []fr.Element, st *debug.SymbolTable) (solution, error) { +func newSolution(nbWires int, hintFunctions map[solver.HintID]solver.Hint, hintsDependencies map[solver.HintID]string, mHints map[int]*constraint.HintMapping, coefficients []fr.Element, st *debug.SymbolTable) (solution, error) { s := solution{ st: st, @@ -139,21 +140,21 @@ func (s *solution) accumulateInto(t constraint.Term, r *fr.Element) { } // solveHint compute solution.values[vID] using provided solver hint -func (s *solution) solveWithHint(vID int, h *constraint.Hint) error { +func (s *solution) solveWithHint(vID int, h *constraint.HintMapping) error { // skip if the wire is already solved by a call to the same hint // function on the same inputs if s.solved[vID] { return nil } // ensure hint function was provided - f, ok := s.mHintsFunctions[h.ID] + f, ok := s.mHintsFunctions[h.HintID] if !ok { return errors.New("missing hint function") } // tmp IO big int memory nbInputs := len(h.Inputs) - nbOutputs := len(h.Wires) + nbOutputs := len(h.Outputs) inputs := make([]*big.Int, nbInputs) outputs := make([]*big.Int, nbOutputs) for i := 0; i < nbOutputs; i++ { @@ -203,7 +204,7 @@ func (s *solution) solveWithHint(vID int, h *constraint.Hint) error { var v fr.Element for i := range outputs { v.SetBigInt(outputs[i]) - s.set(h.Wires[i], v) + s.set(h.Outputs[i], v) } return err @@ -294,3 +295,86 @@ func (r *UnsatisfiedConstraintError) Error() string { } return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, r.Err.Error()) } + +// R1CSSolution represent a valid assignment to all the variables in the constraint system. +// The vector W such that Aw o Bw - Cw = 0 +type R1CSSolution struct { + W fr.Vector + A, B, C fr.Vector +} + +func (t *R1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.W.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.A.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.B.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.C.WriteTo(w) + n += a + return n, err +} + +func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.W.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.A.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.B.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.C.ReadFrom(r) + n += a + return n, err +} + +// SparseR1CSSolution represent a valid assignment to all the variables in the constraint system. +type SparseR1CSSolution struct { + L, R, O fr.Vector +} + +func (t *SparseR1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.L.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.R.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.O.WriteTo(w) + n += a + return n, err + +} + +func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.L.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.R.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.O.ReadFrom(r) + a += n + return n, err +} diff --git a/constraint/bls24-315/r1cs.go b/constraint/bls24-315/r1cs.go index 76f1c63a4e..64925c8a5b 100644 --- a/constraint/bls24-315/r1cs.go +++ b/constraint/bls24-315/r1cs.go @@ -25,9 +25,9 @@ import ( "sync" "time" - "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/backend/ioutils" "github.com/consensys/gnark/logger" "github.com/consensys/gnark/profile" @@ -73,12 +73,37 @@ func (cs *R1CS) AddConstraint(r1c constraint.R1C, debugInfo ...constraint.DebugI return cID } +// Solve returns the vector w solution to the system, that is +// Aw o Bw - Cw = 0 +func (cs *R1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { + opt, err := solver.NewConfig(opts...) + if err != nil { + return nil, err + } + + var res R1CSSolution + + s := ecc.NextPowerOfTwo(uint64(len(cs.Constraints))) + res.A = make(fr.Vector, len(cs.Constraints), s) + res.B = make(fr.Vector, len(cs.Constraints), s) + res.C = make(fr.Vector, len(cs.Constraints), s) + + v := witness.Vector().(fr.Vector) + + res.W, err = cs.solve(v, res.A, res.B, res.C, opt) + if err != nil { + return nil, err + } + + return &res, nil +} + // Solve sets all the wires and returns the a, b, c vectors. // the cs system should have been compiled before. The entries in a, b, c are in Montgomery form. // a, b, c vectors: ab-c = hz // witness = [publicWires | secretWires] (without the ONE_WIRE !) // returns [publicWires | secretWires | internalWires ] -func (cs *R1CS) Solve(witness, a, b, c fr.Vector, opt backend.ProverConfig) (fr.Vector, error) { +func (cs *R1CS) solve(witness, a, b, c fr.Vector, opt solver.Config) (fr.Vector, error) { log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables @@ -114,7 +139,7 @@ func (cs *R1CS) Solve(witness, a, b, c fr.Vector, opt backend.ProverConfig) (fr. // now that we know all inputs are set, defer log printing once all solution.values are computed // (or sooner, if a constraint is not satisfied) - defer solution.printLogs(opt.CircuitLogger, cs.Logs) + defer solution.printLogs(opt.Logger, cs.Logs) if err := cs.parallelSolve(a, b, c, &solution); err != nil { if unsatisfiedErr, ok := err.(*UnsatisfiedConstraintError); ok { @@ -205,8 +230,8 @@ func (cs *R1CS) parallelSolve(a, b, c fr.Vector, solution *solution) error { continue } - // number of tasks for this level is set to num cpus - // but if we don't have enough work for all our CPUS, it can be lower. + // number of tasks for this level is set to number of CPU + // but if we don't have enough work for all our CPU, it can be lower. nbTasks := runtime.NumCPU() maxTasks := int(math.Ceil(maxCPU)) if nbTasks > maxTasks { @@ -249,19 +274,10 @@ func (cs *R1CS) parallelSolve(a, b, c fr.Vector, solution *solution) error { return nil } -// IsSolved returns nil if given witness solves the R1CS and error otherwise -// this method wraps cs.Solve() and allocates cs.Solve() inputs -func (cs *R1CS) IsSolved(witness witness.Witness, opts ...backend.ProverOption) error { - opt, err := backend.NewProverConfig(opts...) - if err != nil { - return err - } - - a := make(fr.Vector, len(cs.Constraints)) - b := make(fr.Vector, len(cs.Constraints)) - c := make(fr.Vector, len(cs.Constraints)) - v := witness.Vector().(fr.Vector) - _, err = cs.Solve(v, a, b, c, opt) +// IsSolved +// Deprecated: use _, err := Solve(...) instead +func (cs *R1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { + _, err := cs.Solve(witness, opts...) return err } diff --git a/constraint/bls24-315/r1cs_sparse.go b/constraint/bls24-315/r1cs_sparse.go index 69e3d01d03..827bd37fc3 100644 --- a/constraint/bls24-315/r1cs_sparse.go +++ b/constraint/bls24-315/r1cs_sparse.go @@ -27,9 +27,9 @@ import ( "sync" "time" - "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/backend/ioutils" "github.com/consensys/gnark/logger" "github.com/consensys/gnark/profile" @@ -70,11 +70,67 @@ func (cs *SparseR1CS) AddConstraint(c constraint.SparseR1C, debugInfo ...constra return cID } +func (c *SparseR1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { + opt, err := solver.NewConfig(opts...) + if err != nil { + return nil, err + } + + // compute the constraint system solution + var solution []fr.Element + if solution, err = c.solve(witness.Vector().(fr.Vector), opt); err != nil { + return nil, err + } + + var res SparseR1CSSolution + // query l, r, o in Lagrange basis, not blinded + res.L, res.R, res.O = c.evaluateLROSmallDomain(solution) + + return &res, nil +} + +// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. +// solution = [ public | secret | internal ] +func (c *SparseR1CS) evaluateLROSmallDomain(solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { + + //s := int(pk.Domain[0].Cardinality) + s := c.GetNbConstraints() + len(c.Public) // len(spr.Public) is for the placeholder constraints + s = int(ecc.NextPowerOfTwo(uint64(s))) + + var l, r, o []fr.Element + l = make([]fr.Element, s) + r = make([]fr.Element, s) + o = make([]fr.Element, s) + s0 := solution[0] + + for i := 0; i < len(c.Public); i++ { // placeholders + l[i] = solution[i] + r[i] = s0 + o[i] = s0 + } + offset := len(c.Public) + for i := 0; i < len(c.Constraints); i++ { // constraints + l[offset+i] = solution[c.Constraints[i].L.WireID()] + r[offset+i] = solution[c.Constraints[i].R.WireID()] + o[offset+i] = solution[c.Constraints[i].O.WireID()] + } + offset += len(c.Constraints) + + for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) + l[offset+i] = s0 + r[offset+i] = s0 + o[offset+i] = s0 + } + + return l, r, o + +} + // Solve sets all the wires. // solution.values = [publicInputs | secretInputs | internalVariables ] // witness: contains the input variables // it returns the full slice of wires -func (cs *SparseR1CS) Solve(witness fr.Vector, opt backend.ProverConfig) (fr.Vector, error) { +func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, error) { log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "plonk").Logger() // set the slices holding the solution.values and monitoring which variables have been solved @@ -110,7 +166,7 @@ func (cs *SparseR1CS) Solve(witness fr.Vector, opt backend.ProverConfig) (fr.Vec solution.nbSolved += uint64(len(witness)) // defer log printing once all solution.values are computed - defer solution.printLogs(opt.CircuitLogger, cs.Logs) + defer solution.printLogs(opt.Logger, cs.Logs) // batch invert the coefficients to avoid many divisions in the solver coefficientsNegInv := fr.BatchInvert(cs.Coefficients) @@ -210,8 +266,8 @@ func (cs *SparseR1CS) parallelSolve(solution *solution, coefficientsNegInv fr.Ve continue } - // number of tasks for this level is set to num cpus - // but if we don't have enough work for all our CPUS, it can be lower. + // number of tasks for this level is set to number of CPU + // but if we don't have enough work for all our CPU, it can be lower. nbTasks := runtime.NumCPU() maxTasks := int(math.Ceil(maxCPU)) if nbTasks > maxTasks { @@ -369,16 +425,10 @@ func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution return nil } -// IsSolved returns nil if given witness solves the SparseR1CS and error otherwise -// this method wraps cs.Solve() and allocates cs.Solve() inputs -func (cs *SparseR1CS) IsSolved(witness witness.Witness, opts ...backend.ProverOption) error { - opt, err := backend.NewProverConfig(opts...) - if err != nil { - return err - } - - v := witness.Vector().(fr.Vector) - _, err = cs.Solve(v, opt) +// IsSolved +// Deprecated: use _, err := Solve(...) instead +func (cs *SparseR1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { + _, err := cs.Solve(witness, opts...) return err } diff --git a/constraint/bls24-315/solution.go b/constraint/bls24-315/solution.go index f65a2821b1..4efab5606e 100644 --- a/constraint/bls24-315/solution.go +++ b/constraint/bls24-315/solution.go @@ -19,10 +19,11 @@ package cs import ( "errors" "fmt" - "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/debug" "github.com/rs/zerolog" + "io" "math/big" "strconv" "strings" @@ -37,12 +38,12 @@ type solution struct { values, coefficients []fr.Element solved []bool nbSolved uint64 - mHintsFunctions map[hint.ID]hint.Function // maps hintID to hint function - mHints map[int]*constraint.Hint // maps wireID to hint + mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function + mHints map[int]*constraint.HintMapping // maps wireID to hint st *debug.SymbolTable } -func newSolution(nbWires int, hintFunctions map[hint.ID]hint.Function, hintsDependencies map[hint.ID]string, mHints map[int]*constraint.Hint, coefficients []fr.Element, st *debug.SymbolTable) (solution, error) { +func newSolution(nbWires int, hintFunctions map[solver.HintID]solver.Hint, hintsDependencies map[solver.HintID]string, mHints map[int]*constraint.HintMapping, coefficients []fr.Element, st *debug.SymbolTable) (solution, error) { s := solution{ st: st, @@ -139,21 +140,21 @@ func (s *solution) accumulateInto(t constraint.Term, r *fr.Element) { } // solveHint compute solution.values[vID] using provided solver hint -func (s *solution) solveWithHint(vID int, h *constraint.Hint) error { +func (s *solution) solveWithHint(vID int, h *constraint.HintMapping) error { // skip if the wire is already solved by a call to the same hint // function on the same inputs if s.solved[vID] { return nil } // ensure hint function was provided - f, ok := s.mHintsFunctions[h.ID] + f, ok := s.mHintsFunctions[h.HintID] if !ok { return errors.New("missing hint function") } // tmp IO big int memory nbInputs := len(h.Inputs) - nbOutputs := len(h.Wires) + nbOutputs := len(h.Outputs) inputs := make([]*big.Int, nbInputs) outputs := make([]*big.Int, nbOutputs) for i := 0; i < nbOutputs; i++ { @@ -203,7 +204,7 @@ func (s *solution) solveWithHint(vID int, h *constraint.Hint) error { var v fr.Element for i := range outputs { v.SetBigInt(outputs[i]) - s.set(h.Wires[i], v) + s.set(h.Outputs[i], v) } return err @@ -294,3 +295,86 @@ func (r *UnsatisfiedConstraintError) Error() string { } return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, r.Err.Error()) } + +// R1CSSolution represent a valid assignment to all the variables in the constraint system. +// The vector W such that Aw o Bw - Cw = 0 +type R1CSSolution struct { + W fr.Vector + A, B, C fr.Vector +} + +func (t *R1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.W.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.A.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.B.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.C.WriteTo(w) + n += a + return n, err +} + +func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.W.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.A.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.B.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.C.ReadFrom(r) + n += a + return n, err +} + +// SparseR1CSSolution represent a valid assignment to all the variables in the constraint system. +type SparseR1CSSolution struct { + L, R, O fr.Vector +} + +func (t *SparseR1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.L.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.R.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.O.WriteTo(w) + n += a + return n, err + +} + +func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.L.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.R.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.O.ReadFrom(r) + a += n + return n, err +} diff --git a/constraint/bls24-317/r1cs.go b/constraint/bls24-317/r1cs.go index 889ec4bc13..2c6eb08acd 100644 --- a/constraint/bls24-317/r1cs.go +++ b/constraint/bls24-317/r1cs.go @@ -25,9 +25,9 @@ import ( "sync" "time" - "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/backend/ioutils" "github.com/consensys/gnark/logger" "github.com/consensys/gnark/profile" @@ -73,12 +73,37 @@ func (cs *R1CS) AddConstraint(r1c constraint.R1C, debugInfo ...constraint.DebugI return cID } +// Solve returns the vector w solution to the system, that is +// Aw o Bw - Cw = 0 +func (cs *R1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { + opt, err := solver.NewConfig(opts...) + if err != nil { + return nil, err + } + + var res R1CSSolution + + s := ecc.NextPowerOfTwo(uint64(len(cs.Constraints))) + res.A = make(fr.Vector, len(cs.Constraints), s) + res.B = make(fr.Vector, len(cs.Constraints), s) + res.C = make(fr.Vector, len(cs.Constraints), s) + + v := witness.Vector().(fr.Vector) + + res.W, err = cs.solve(v, res.A, res.B, res.C, opt) + if err != nil { + return nil, err + } + + return &res, nil +} + // Solve sets all the wires and returns the a, b, c vectors. // the cs system should have been compiled before. The entries in a, b, c are in Montgomery form. // a, b, c vectors: ab-c = hz // witness = [publicWires | secretWires] (without the ONE_WIRE !) // returns [publicWires | secretWires | internalWires ] -func (cs *R1CS) Solve(witness, a, b, c fr.Vector, opt backend.ProverConfig) (fr.Vector, error) { +func (cs *R1CS) solve(witness, a, b, c fr.Vector, opt solver.Config) (fr.Vector, error) { log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables @@ -114,7 +139,7 @@ func (cs *R1CS) Solve(witness, a, b, c fr.Vector, opt backend.ProverConfig) (fr. // now that we know all inputs are set, defer log printing once all solution.values are computed // (or sooner, if a constraint is not satisfied) - defer solution.printLogs(opt.CircuitLogger, cs.Logs) + defer solution.printLogs(opt.Logger, cs.Logs) if err := cs.parallelSolve(a, b, c, &solution); err != nil { if unsatisfiedErr, ok := err.(*UnsatisfiedConstraintError); ok { @@ -205,8 +230,8 @@ func (cs *R1CS) parallelSolve(a, b, c fr.Vector, solution *solution) error { continue } - // number of tasks for this level is set to num cpus - // but if we don't have enough work for all our CPUS, it can be lower. + // number of tasks for this level is set to number of CPU + // but if we don't have enough work for all our CPU, it can be lower. nbTasks := runtime.NumCPU() maxTasks := int(math.Ceil(maxCPU)) if nbTasks > maxTasks { @@ -249,19 +274,10 @@ func (cs *R1CS) parallelSolve(a, b, c fr.Vector, solution *solution) error { return nil } -// IsSolved returns nil if given witness solves the R1CS and error otherwise -// this method wraps cs.Solve() and allocates cs.Solve() inputs -func (cs *R1CS) IsSolved(witness witness.Witness, opts ...backend.ProverOption) error { - opt, err := backend.NewProverConfig(opts...) - if err != nil { - return err - } - - a := make(fr.Vector, len(cs.Constraints)) - b := make(fr.Vector, len(cs.Constraints)) - c := make(fr.Vector, len(cs.Constraints)) - v := witness.Vector().(fr.Vector) - _, err = cs.Solve(v, a, b, c, opt) +// IsSolved +// Deprecated: use _, err := Solve(...) instead +func (cs *R1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { + _, err := cs.Solve(witness, opts...) return err } diff --git a/constraint/bls24-317/r1cs_sparse.go b/constraint/bls24-317/r1cs_sparse.go index 5acd85dd99..c8503d0f54 100644 --- a/constraint/bls24-317/r1cs_sparse.go +++ b/constraint/bls24-317/r1cs_sparse.go @@ -27,9 +27,9 @@ import ( "sync" "time" - "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/backend/ioutils" "github.com/consensys/gnark/logger" "github.com/consensys/gnark/profile" @@ -70,11 +70,67 @@ func (cs *SparseR1CS) AddConstraint(c constraint.SparseR1C, debugInfo ...constra return cID } +func (c *SparseR1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { + opt, err := solver.NewConfig(opts...) + if err != nil { + return nil, err + } + + // compute the constraint system solution + var solution []fr.Element + if solution, err = c.solve(witness.Vector().(fr.Vector), opt); err != nil { + return nil, err + } + + var res SparseR1CSSolution + // query l, r, o in Lagrange basis, not blinded + res.L, res.R, res.O = c.evaluateLROSmallDomain(solution) + + return &res, nil +} + +// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. +// solution = [ public | secret | internal ] +func (c *SparseR1CS) evaluateLROSmallDomain(solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { + + //s := int(pk.Domain[0].Cardinality) + s := c.GetNbConstraints() + len(c.Public) // len(spr.Public) is for the placeholder constraints + s = int(ecc.NextPowerOfTwo(uint64(s))) + + var l, r, o []fr.Element + l = make([]fr.Element, s) + r = make([]fr.Element, s) + o = make([]fr.Element, s) + s0 := solution[0] + + for i := 0; i < len(c.Public); i++ { // placeholders + l[i] = solution[i] + r[i] = s0 + o[i] = s0 + } + offset := len(c.Public) + for i := 0; i < len(c.Constraints); i++ { // constraints + l[offset+i] = solution[c.Constraints[i].L.WireID()] + r[offset+i] = solution[c.Constraints[i].R.WireID()] + o[offset+i] = solution[c.Constraints[i].O.WireID()] + } + offset += len(c.Constraints) + + for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) + l[offset+i] = s0 + r[offset+i] = s0 + o[offset+i] = s0 + } + + return l, r, o + +} + // Solve sets all the wires. // solution.values = [publicInputs | secretInputs | internalVariables ] // witness: contains the input variables // it returns the full slice of wires -func (cs *SparseR1CS) Solve(witness fr.Vector, opt backend.ProverConfig) (fr.Vector, error) { +func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, error) { log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "plonk").Logger() // set the slices holding the solution.values and monitoring which variables have been solved @@ -110,7 +166,7 @@ func (cs *SparseR1CS) Solve(witness fr.Vector, opt backend.ProverConfig) (fr.Vec solution.nbSolved += uint64(len(witness)) // defer log printing once all solution.values are computed - defer solution.printLogs(opt.CircuitLogger, cs.Logs) + defer solution.printLogs(opt.Logger, cs.Logs) // batch invert the coefficients to avoid many divisions in the solver coefficientsNegInv := fr.BatchInvert(cs.Coefficients) @@ -210,8 +266,8 @@ func (cs *SparseR1CS) parallelSolve(solution *solution, coefficientsNegInv fr.Ve continue } - // number of tasks for this level is set to num cpus - // but if we don't have enough work for all our CPUS, it can be lower. + // number of tasks for this level is set to number of CPU + // but if we don't have enough work for all our CPU, it can be lower. nbTasks := runtime.NumCPU() maxTasks := int(math.Ceil(maxCPU)) if nbTasks > maxTasks { @@ -369,16 +425,10 @@ func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution return nil } -// IsSolved returns nil if given witness solves the SparseR1CS and error otherwise -// this method wraps cs.Solve() and allocates cs.Solve() inputs -func (cs *SparseR1CS) IsSolved(witness witness.Witness, opts ...backend.ProverOption) error { - opt, err := backend.NewProverConfig(opts...) - if err != nil { - return err - } - - v := witness.Vector().(fr.Vector) - _, err = cs.Solve(v, opt) +// IsSolved +// Deprecated: use _, err := Solve(...) instead +func (cs *SparseR1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { + _, err := cs.Solve(witness, opts...) return err } diff --git a/constraint/bls24-317/solution.go b/constraint/bls24-317/solution.go index d26c56f931..a3628fc04b 100644 --- a/constraint/bls24-317/solution.go +++ b/constraint/bls24-317/solution.go @@ -19,10 +19,11 @@ package cs import ( "errors" "fmt" - "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/debug" "github.com/rs/zerolog" + "io" "math/big" "strconv" "strings" @@ -37,12 +38,12 @@ type solution struct { values, coefficients []fr.Element solved []bool nbSolved uint64 - mHintsFunctions map[hint.ID]hint.Function // maps hintID to hint function - mHints map[int]*constraint.Hint // maps wireID to hint + mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function + mHints map[int]*constraint.HintMapping // maps wireID to hint st *debug.SymbolTable } -func newSolution(nbWires int, hintFunctions map[hint.ID]hint.Function, hintsDependencies map[hint.ID]string, mHints map[int]*constraint.Hint, coefficients []fr.Element, st *debug.SymbolTable) (solution, error) { +func newSolution(nbWires int, hintFunctions map[solver.HintID]solver.Hint, hintsDependencies map[solver.HintID]string, mHints map[int]*constraint.HintMapping, coefficients []fr.Element, st *debug.SymbolTable) (solution, error) { s := solution{ st: st, @@ -139,21 +140,21 @@ func (s *solution) accumulateInto(t constraint.Term, r *fr.Element) { } // solveHint compute solution.values[vID] using provided solver hint -func (s *solution) solveWithHint(vID int, h *constraint.Hint) error { +func (s *solution) solveWithHint(vID int, h *constraint.HintMapping) error { // skip if the wire is already solved by a call to the same hint // function on the same inputs if s.solved[vID] { return nil } // ensure hint function was provided - f, ok := s.mHintsFunctions[h.ID] + f, ok := s.mHintsFunctions[h.HintID] if !ok { return errors.New("missing hint function") } // tmp IO big int memory nbInputs := len(h.Inputs) - nbOutputs := len(h.Wires) + nbOutputs := len(h.Outputs) inputs := make([]*big.Int, nbInputs) outputs := make([]*big.Int, nbOutputs) for i := 0; i < nbOutputs; i++ { @@ -203,7 +204,7 @@ func (s *solution) solveWithHint(vID int, h *constraint.Hint) error { var v fr.Element for i := range outputs { v.SetBigInt(outputs[i]) - s.set(h.Wires[i], v) + s.set(h.Outputs[i], v) } return err @@ -294,3 +295,86 @@ func (r *UnsatisfiedConstraintError) Error() string { } return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, r.Err.Error()) } + +// R1CSSolution represent a valid assignment to all the variables in the constraint system. +// The vector W such that Aw o Bw - Cw = 0 +type R1CSSolution struct { + W fr.Vector + A, B, C fr.Vector +} + +func (t *R1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.W.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.A.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.B.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.C.WriteTo(w) + n += a + return n, err +} + +func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.W.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.A.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.B.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.C.ReadFrom(r) + n += a + return n, err +} + +// SparseR1CSSolution represent a valid assignment to all the variables in the constraint system. +type SparseR1CSSolution struct { + L, R, O fr.Vector +} + +func (t *SparseR1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.L.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.R.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.O.WriteTo(w) + n += a + return n, err + +} + +func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.L.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.R.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.O.ReadFrom(r) + a += n + return n, err +} diff --git a/constraint/bn254/r1cs.go b/constraint/bn254/r1cs.go index 5bc4cb56aa..8a80571d90 100644 --- a/constraint/bn254/r1cs.go +++ b/constraint/bn254/r1cs.go @@ -25,9 +25,9 @@ import ( "sync" "time" - "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/backend/ioutils" "github.com/consensys/gnark/logger" "github.com/consensys/gnark/profile" @@ -73,12 +73,37 @@ func (cs *R1CS) AddConstraint(r1c constraint.R1C, debugInfo ...constraint.DebugI return cID } +// Solve returns the vector w solution to the system, that is +// Aw o Bw - Cw = 0 +func (cs *R1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { + opt, err := solver.NewConfig(opts...) + if err != nil { + return nil, err + } + + var res R1CSSolution + + s := ecc.NextPowerOfTwo(uint64(len(cs.Constraints))) + res.A = make(fr.Vector, len(cs.Constraints), s) + res.B = make(fr.Vector, len(cs.Constraints), s) + res.C = make(fr.Vector, len(cs.Constraints), s) + + v := witness.Vector().(fr.Vector) + + res.W, err = cs.solve(v, res.A, res.B, res.C, opt) + if err != nil { + return nil, err + } + + return &res, nil +} + // Solve sets all the wires and returns the a, b, c vectors. // the cs system should have been compiled before. The entries in a, b, c are in Montgomery form. // a, b, c vectors: ab-c = hz // witness = [publicWires | secretWires] (without the ONE_WIRE !) // returns [publicWires | secretWires | internalWires ] -func (cs *R1CS) Solve(witness, a, b, c fr.Vector, opt backend.ProverConfig) (fr.Vector, error) { +func (cs *R1CS) solve(witness, a, b, c fr.Vector, opt solver.Config) (fr.Vector, error) { log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables @@ -114,7 +139,7 @@ func (cs *R1CS) Solve(witness, a, b, c fr.Vector, opt backend.ProverConfig) (fr. // now that we know all inputs are set, defer log printing once all solution.values are computed // (or sooner, if a constraint is not satisfied) - defer solution.printLogs(opt.CircuitLogger, cs.Logs) + defer solution.printLogs(opt.Logger, cs.Logs) if err := cs.parallelSolve(a, b, c, &solution); err != nil { if unsatisfiedErr, ok := err.(*UnsatisfiedConstraintError); ok { @@ -205,8 +230,8 @@ func (cs *R1CS) parallelSolve(a, b, c fr.Vector, solution *solution) error { continue } - // number of tasks for this level is set to num cpus - // but if we don't have enough work for all our CPUS, it can be lower. + // number of tasks for this level is set to number of CPU + // but if we don't have enough work for all our CPU, it can be lower. nbTasks := runtime.NumCPU() maxTasks := int(math.Ceil(maxCPU)) if nbTasks > maxTasks { @@ -249,19 +274,10 @@ func (cs *R1CS) parallelSolve(a, b, c fr.Vector, solution *solution) error { return nil } -// IsSolved returns nil if given witness solves the R1CS and error otherwise -// this method wraps cs.Solve() and allocates cs.Solve() inputs -func (cs *R1CS) IsSolved(witness witness.Witness, opts ...backend.ProverOption) error { - opt, err := backend.NewProverConfig(opts...) - if err != nil { - return err - } - - a := make(fr.Vector, len(cs.Constraints)) - b := make(fr.Vector, len(cs.Constraints)) - c := make(fr.Vector, len(cs.Constraints)) - v := witness.Vector().(fr.Vector) - _, err = cs.Solve(v, a, b, c, opt) +// IsSolved +// Deprecated: use _, err := Solve(...) instead +func (cs *R1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { + _, err := cs.Solve(witness, opts...) return err } diff --git a/constraint/bn254/r1cs_sparse.go b/constraint/bn254/r1cs_sparse.go index 4a9df0856e..4cf27221b9 100644 --- a/constraint/bn254/r1cs_sparse.go +++ b/constraint/bn254/r1cs_sparse.go @@ -27,9 +27,9 @@ import ( "sync" "time" - "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/backend/ioutils" "github.com/consensys/gnark/logger" "github.com/consensys/gnark/profile" @@ -70,11 +70,67 @@ func (cs *SparseR1CS) AddConstraint(c constraint.SparseR1C, debugInfo ...constra return cID } +func (c *SparseR1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { + opt, err := solver.NewConfig(opts...) + if err != nil { + return nil, err + } + + // compute the constraint system solution + var solution []fr.Element + if solution, err = c.solve(witness.Vector().(fr.Vector), opt); err != nil { + return nil, err + } + + var res SparseR1CSSolution + // query l, r, o in Lagrange basis, not blinded + res.L, res.R, res.O = c.evaluateLROSmallDomain(solution) + + return &res, nil +} + +// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. +// solution = [ public | secret | internal ] +func (c *SparseR1CS) evaluateLROSmallDomain(solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { + + //s := int(pk.Domain[0].Cardinality) + s := c.GetNbConstraints() + len(c.Public) // len(spr.Public) is for the placeholder constraints + s = int(ecc.NextPowerOfTwo(uint64(s))) + + var l, r, o []fr.Element + l = make([]fr.Element, s) + r = make([]fr.Element, s) + o = make([]fr.Element, s) + s0 := solution[0] + + for i := 0; i < len(c.Public); i++ { // placeholders + l[i] = solution[i] + r[i] = s0 + o[i] = s0 + } + offset := len(c.Public) + for i := 0; i < len(c.Constraints); i++ { // constraints + l[offset+i] = solution[c.Constraints[i].L.WireID()] + r[offset+i] = solution[c.Constraints[i].R.WireID()] + o[offset+i] = solution[c.Constraints[i].O.WireID()] + } + offset += len(c.Constraints) + + for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) + l[offset+i] = s0 + r[offset+i] = s0 + o[offset+i] = s0 + } + + return l, r, o + +} + // Solve sets all the wires. // solution.values = [publicInputs | secretInputs | internalVariables ] // witness: contains the input variables // it returns the full slice of wires -func (cs *SparseR1CS) Solve(witness fr.Vector, opt backend.ProverConfig) (fr.Vector, error) { +func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, error) { log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "plonk").Logger() // set the slices holding the solution.values and monitoring which variables have been solved @@ -110,7 +166,7 @@ func (cs *SparseR1CS) Solve(witness fr.Vector, opt backend.ProverConfig) (fr.Vec solution.nbSolved += uint64(len(witness)) // defer log printing once all solution.values are computed - defer solution.printLogs(opt.CircuitLogger, cs.Logs) + defer solution.printLogs(opt.Logger, cs.Logs) // batch invert the coefficients to avoid many divisions in the solver coefficientsNegInv := fr.BatchInvert(cs.Coefficients) @@ -210,8 +266,8 @@ func (cs *SparseR1CS) parallelSolve(solution *solution, coefficientsNegInv fr.Ve continue } - // number of tasks for this level is set to num cpus - // but if we don't have enough work for all our CPUS, it can be lower. + // number of tasks for this level is set to number of CPU + // but if we don't have enough work for all our CPU, it can be lower. nbTasks := runtime.NumCPU() maxTasks := int(math.Ceil(maxCPU)) if nbTasks > maxTasks { @@ -369,16 +425,10 @@ func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution return nil } -// IsSolved returns nil if given witness solves the SparseR1CS and error otherwise -// this method wraps cs.Solve() and allocates cs.Solve() inputs -func (cs *SparseR1CS) IsSolved(witness witness.Witness, opts ...backend.ProverOption) error { - opt, err := backend.NewProverConfig(opts...) - if err != nil { - return err - } - - v := witness.Vector().(fr.Vector) - _, err = cs.Solve(v, opt) +// IsSolved +// Deprecated: use _, err := Solve(...) instead +func (cs *SparseR1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { + _, err := cs.Solve(witness, opts...) return err } diff --git a/constraint/bn254/solution.go b/constraint/bn254/solution.go index 3346fc9f1c..24a5d94396 100644 --- a/constraint/bn254/solution.go +++ b/constraint/bn254/solution.go @@ -19,10 +19,11 @@ package cs import ( "errors" "fmt" - "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/debug" "github.com/rs/zerolog" + "io" "math/big" "strconv" "strings" @@ -37,12 +38,12 @@ type solution struct { values, coefficients []fr.Element solved []bool nbSolved uint64 - mHintsFunctions map[hint.ID]hint.Function // maps hintID to hint function - mHints map[int]*constraint.Hint // maps wireID to hint + mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function + mHints map[int]*constraint.HintMapping // maps wireID to hint st *debug.SymbolTable } -func newSolution(nbWires int, hintFunctions map[hint.ID]hint.Function, hintsDependencies map[hint.ID]string, mHints map[int]*constraint.Hint, coefficients []fr.Element, st *debug.SymbolTable) (solution, error) { +func newSolution(nbWires int, hintFunctions map[solver.HintID]solver.Hint, hintsDependencies map[solver.HintID]string, mHints map[int]*constraint.HintMapping, coefficients []fr.Element, st *debug.SymbolTable) (solution, error) { s := solution{ st: st, @@ -139,21 +140,21 @@ func (s *solution) accumulateInto(t constraint.Term, r *fr.Element) { } // solveHint compute solution.values[vID] using provided solver hint -func (s *solution) solveWithHint(vID int, h *constraint.Hint) error { +func (s *solution) solveWithHint(vID int, h *constraint.HintMapping) error { // skip if the wire is already solved by a call to the same hint // function on the same inputs if s.solved[vID] { return nil } // ensure hint function was provided - f, ok := s.mHintsFunctions[h.ID] + f, ok := s.mHintsFunctions[h.HintID] if !ok { return errors.New("missing hint function") } // tmp IO big int memory nbInputs := len(h.Inputs) - nbOutputs := len(h.Wires) + nbOutputs := len(h.Outputs) inputs := make([]*big.Int, nbInputs) outputs := make([]*big.Int, nbOutputs) for i := 0; i < nbOutputs; i++ { @@ -203,7 +204,7 @@ func (s *solution) solveWithHint(vID int, h *constraint.Hint) error { var v fr.Element for i := range outputs { v.SetBigInt(outputs[i]) - s.set(h.Wires[i], v) + s.set(h.Outputs[i], v) } return err @@ -294,3 +295,86 @@ func (r *UnsatisfiedConstraintError) Error() string { } return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, r.Err.Error()) } + +// R1CSSolution represent a valid assignment to all the variables in the constraint system. +// The vector W such that Aw o Bw - Cw = 0 +type R1CSSolution struct { + W fr.Vector + A, B, C fr.Vector +} + +func (t *R1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.W.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.A.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.B.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.C.WriteTo(w) + n += a + return n, err +} + +func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.W.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.A.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.B.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.C.ReadFrom(r) + n += a + return n, err +} + +// SparseR1CSSolution represent a valid assignment to all the variables in the constraint system. +type SparseR1CSSolution struct { + L, R, O fr.Vector +} + +func (t *SparseR1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.L.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.R.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.O.WriteTo(w) + n += a + return n, err + +} + +func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.L.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.R.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.O.ReadFrom(r) + a += n + return n, err +} diff --git a/constraint/bw6-633/r1cs.go b/constraint/bw6-633/r1cs.go index b73a94b155..6bd0f697c1 100644 --- a/constraint/bw6-633/r1cs.go +++ b/constraint/bw6-633/r1cs.go @@ -25,9 +25,9 @@ import ( "sync" "time" - "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/backend/ioutils" "github.com/consensys/gnark/logger" "github.com/consensys/gnark/profile" @@ -73,12 +73,37 @@ func (cs *R1CS) AddConstraint(r1c constraint.R1C, debugInfo ...constraint.DebugI return cID } +// Solve returns the vector w solution to the system, that is +// Aw o Bw - Cw = 0 +func (cs *R1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { + opt, err := solver.NewConfig(opts...) + if err != nil { + return nil, err + } + + var res R1CSSolution + + s := ecc.NextPowerOfTwo(uint64(len(cs.Constraints))) + res.A = make(fr.Vector, len(cs.Constraints), s) + res.B = make(fr.Vector, len(cs.Constraints), s) + res.C = make(fr.Vector, len(cs.Constraints), s) + + v := witness.Vector().(fr.Vector) + + res.W, err = cs.solve(v, res.A, res.B, res.C, opt) + if err != nil { + return nil, err + } + + return &res, nil +} + // Solve sets all the wires and returns the a, b, c vectors. // the cs system should have been compiled before. The entries in a, b, c are in Montgomery form. // a, b, c vectors: ab-c = hz // witness = [publicWires | secretWires] (without the ONE_WIRE !) // returns [publicWires | secretWires | internalWires ] -func (cs *R1CS) Solve(witness, a, b, c fr.Vector, opt backend.ProverConfig) (fr.Vector, error) { +func (cs *R1CS) solve(witness, a, b, c fr.Vector, opt solver.Config) (fr.Vector, error) { log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables @@ -114,7 +139,7 @@ func (cs *R1CS) Solve(witness, a, b, c fr.Vector, opt backend.ProverConfig) (fr. // now that we know all inputs are set, defer log printing once all solution.values are computed // (or sooner, if a constraint is not satisfied) - defer solution.printLogs(opt.CircuitLogger, cs.Logs) + defer solution.printLogs(opt.Logger, cs.Logs) if err := cs.parallelSolve(a, b, c, &solution); err != nil { if unsatisfiedErr, ok := err.(*UnsatisfiedConstraintError); ok { @@ -205,8 +230,8 @@ func (cs *R1CS) parallelSolve(a, b, c fr.Vector, solution *solution) error { continue } - // number of tasks for this level is set to num cpus - // but if we don't have enough work for all our CPUS, it can be lower. + // number of tasks for this level is set to number of CPU + // but if we don't have enough work for all our CPU, it can be lower. nbTasks := runtime.NumCPU() maxTasks := int(math.Ceil(maxCPU)) if nbTasks > maxTasks { @@ -249,19 +274,10 @@ func (cs *R1CS) parallelSolve(a, b, c fr.Vector, solution *solution) error { return nil } -// IsSolved returns nil if given witness solves the R1CS and error otherwise -// this method wraps cs.Solve() and allocates cs.Solve() inputs -func (cs *R1CS) IsSolved(witness witness.Witness, opts ...backend.ProverOption) error { - opt, err := backend.NewProverConfig(opts...) - if err != nil { - return err - } - - a := make(fr.Vector, len(cs.Constraints)) - b := make(fr.Vector, len(cs.Constraints)) - c := make(fr.Vector, len(cs.Constraints)) - v := witness.Vector().(fr.Vector) - _, err = cs.Solve(v, a, b, c, opt) +// IsSolved +// Deprecated: use _, err := Solve(...) instead +func (cs *R1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { + _, err := cs.Solve(witness, opts...) return err } diff --git a/constraint/bw6-633/r1cs_sparse.go b/constraint/bw6-633/r1cs_sparse.go index 0cba25ce7b..80cdacb38c 100644 --- a/constraint/bw6-633/r1cs_sparse.go +++ b/constraint/bw6-633/r1cs_sparse.go @@ -27,9 +27,9 @@ import ( "sync" "time" - "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/backend/ioutils" "github.com/consensys/gnark/logger" "github.com/consensys/gnark/profile" @@ -70,11 +70,67 @@ func (cs *SparseR1CS) AddConstraint(c constraint.SparseR1C, debugInfo ...constra return cID } +func (c *SparseR1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { + opt, err := solver.NewConfig(opts...) + if err != nil { + return nil, err + } + + // compute the constraint system solution + var solution []fr.Element + if solution, err = c.solve(witness.Vector().(fr.Vector), opt); err != nil { + return nil, err + } + + var res SparseR1CSSolution + // query l, r, o in Lagrange basis, not blinded + res.L, res.R, res.O = c.evaluateLROSmallDomain(solution) + + return &res, nil +} + +// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. +// solution = [ public | secret | internal ] +func (c *SparseR1CS) evaluateLROSmallDomain(solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { + + //s := int(pk.Domain[0].Cardinality) + s := c.GetNbConstraints() + len(c.Public) // len(spr.Public) is for the placeholder constraints + s = int(ecc.NextPowerOfTwo(uint64(s))) + + var l, r, o []fr.Element + l = make([]fr.Element, s) + r = make([]fr.Element, s) + o = make([]fr.Element, s) + s0 := solution[0] + + for i := 0; i < len(c.Public); i++ { // placeholders + l[i] = solution[i] + r[i] = s0 + o[i] = s0 + } + offset := len(c.Public) + for i := 0; i < len(c.Constraints); i++ { // constraints + l[offset+i] = solution[c.Constraints[i].L.WireID()] + r[offset+i] = solution[c.Constraints[i].R.WireID()] + o[offset+i] = solution[c.Constraints[i].O.WireID()] + } + offset += len(c.Constraints) + + for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) + l[offset+i] = s0 + r[offset+i] = s0 + o[offset+i] = s0 + } + + return l, r, o + +} + // Solve sets all the wires. // solution.values = [publicInputs | secretInputs | internalVariables ] // witness: contains the input variables // it returns the full slice of wires -func (cs *SparseR1CS) Solve(witness fr.Vector, opt backend.ProverConfig) (fr.Vector, error) { +func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, error) { log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "plonk").Logger() // set the slices holding the solution.values and monitoring which variables have been solved @@ -110,7 +166,7 @@ func (cs *SparseR1CS) Solve(witness fr.Vector, opt backend.ProverConfig) (fr.Vec solution.nbSolved += uint64(len(witness)) // defer log printing once all solution.values are computed - defer solution.printLogs(opt.CircuitLogger, cs.Logs) + defer solution.printLogs(opt.Logger, cs.Logs) // batch invert the coefficients to avoid many divisions in the solver coefficientsNegInv := fr.BatchInvert(cs.Coefficients) @@ -210,8 +266,8 @@ func (cs *SparseR1CS) parallelSolve(solution *solution, coefficientsNegInv fr.Ve continue } - // number of tasks for this level is set to num cpus - // but if we don't have enough work for all our CPUS, it can be lower. + // number of tasks for this level is set to number of CPU + // but if we don't have enough work for all our CPU, it can be lower. nbTasks := runtime.NumCPU() maxTasks := int(math.Ceil(maxCPU)) if nbTasks > maxTasks { @@ -369,16 +425,10 @@ func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution return nil } -// IsSolved returns nil if given witness solves the SparseR1CS and error otherwise -// this method wraps cs.Solve() and allocates cs.Solve() inputs -func (cs *SparseR1CS) IsSolved(witness witness.Witness, opts ...backend.ProverOption) error { - opt, err := backend.NewProverConfig(opts...) - if err != nil { - return err - } - - v := witness.Vector().(fr.Vector) - _, err = cs.Solve(v, opt) +// IsSolved +// Deprecated: use _, err := Solve(...) instead +func (cs *SparseR1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { + _, err := cs.Solve(witness, opts...) return err } diff --git a/constraint/bw6-633/solution.go b/constraint/bw6-633/solution.go index aea0b28a49..7b403823f2 100644 --- a/constraint/bw6-633/solution.go +++ b/constraint/bw6-633/solution.go @@ -19,10 +19,11 @@ package cs import ( "errors" "fmt" - "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/debug" "github.com/rs/zerolog" + "io" "math/big" "strconv" "strings" @@ -37,12 +38,12 @@ type solution struct { values, coefficients []fr.Element solved []bool nbSolved uint64 - mHintsFunctions map[hint.ID]hint.Function // maps hintID to hint function - mHints map[int]*constraint.Hint // maps wireID to hint + mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function + mHints map[int]*constraint.HintMapping // maps wireID to hint st *debug.SymbolTable } -func newSolution(nbWires int, hintFunctions map[hint.ID]hint.Function, hintsDependencies map[hint.ID]string, mHints map[int]*constraint.Hint, coefficients []fr.Element, st *debug.SymbolTable) (solution, error) { +func newSolution(nbWires int, hintFunctions map[solver.HintID]solver.Hint, hintsDependencies map[solver.HintID]string, mHints map[int]*constraint.HintMapping, coefficients []fr.Element, st *debug.SymbolTable) (solution, error) { s := solution{ st: st, @@ -139,21 +140,21 @@ func (s *solution) accumulateInto(t constraint.Term, r *fr.Element) { } // solveHint compute solution.values[vID] using provided solver hint -func (s *solution) solveWithHint(vID int, h *constraint.Hint) error { +func (s *solution) solveWithHint(vID int, h *constraint.HintMapping) error { // skip if the wire is already solved by a call to the same hint // function on the same inputs if s.solved[vID] { return nil } // ensure hint function was provided - f, ok := s.mHintsFunctions[h.ID] + f, ok := s.mHintsFunctions[h.HintID] if !ok { return errors.New("missing hint function") } // tmp IO big int memory nbInputs := len(h.Inputs) - nbOutputs := len(h.Wires) + nbOutputs := len(h.Outputs) inputs := make([]*big.Int, nbInputs) outputs := make([]*big.Int, nbOutputs) for i := 0; i < nbOutputs; i++ { @@ -203,7 +204,7 @@ func (s *solution) solveWithHint(vID int, h *constraint.Hint) error { var v fr.Element for i := range outputs { v.SetBigInt(outputs[i]) - s.set(h.Wires[i], v) + s.set(h.Outputs[i], v) } return err @@ -294,3 +295,86 @@ func (r *UnsatisfiedConstraintError) Error() string { } return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, r.Err.Error()) } + +// R1CSSolution represent a valid assignment to all the variables in the constraint system. +// The vector W such that Aw o Bw - Cw = 0 +type R1CSSolution struct { + W fr.Vector + A, B, C fr.Vector +} + +func (t *R1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.W.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.A.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.B.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.C.WriteTo(w) + n += a + return n, err +} + +func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.W.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.A.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.B.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.C.ReadFrom(r) + n += a + return n, err +} + +// SparseR1CSSolution represent a valid assignment to all the variables in the constraint system. +type SparseR1CSSolution struct { + L, R, O fr.Vector +} + +func (t *SparseR1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.L.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.R.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.O.WriteTo(w) + n += a + return n, err + +} + +func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.L.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.R.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.O.ReadFrom(r) + a += n + return n, err +} diff --git a/constraint/bw6-761/r1cs.go b/constraint/bw6-761/r1cs.go index f7347529f8..12dec7e3a0 100644 --- a/constraint/bw6-761/r1cs.go +++ b/constraint/bw6-761/r1cs.go @@ -25,9 +25,9 @@ import ( "sync" "time" - "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/backend/ioutils" "github.com/consensys/gnark/logger" "github.com/consensys/gnark/profile" @@ -73,12 +73,37 @@ func (cs *R1CS) AddConstraint(r1c constraint.R1C, debugInfo ...constraint.DebugI return cID } +// Solve returns the vector w solution to the system, that is +// Aw o Bw - Cw = 0 +func (cs *R1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { + opt, err := solver.NewConfig(opts...) + if err != nil { + return nil, err + } + + var res R1CSSolution + + s := ecc.NextPowerOfTwo(uint64(len(cs.Constraints))) + res.A = make(fr.Vector, len(cs.Constraints), s) + res.B = make(fr.Vector, len(cs.Constraints), s) + res.C = make(fr.Vector, len(cs.Constraints), s) + + v := witness.Vector().(fr.Vector) + + res.W, err = cs.solve(v, res.A, res.B, res.C, opt) + if err != nil { + return nil, err + } + + return &res, nil +} + // Solve sets all the wires and returns the a, b, c vectors. // the cs system should have been compiled before. The entries in a, b, c are in Montgomery form. // a, b, c vectors: ab-c = hz // witness = [publicWires | secretWires] (without the ONE_WIRE !) // returns [publicWires | secretWires | internalWires ] -func (cs *R1CS) Solve(witness, a, b, c fr.Vector, opt backend.ProverConfig) (fr.Vector, error) { +func (cs *R1CS) solve(witness, a, b, c fr.Vector, opt solver.Config) (fr.Vector, error) { log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables @@ -114,7 +139,7 @@ func (cs *R1CS) Solve(witness, a, b, c fr.Vector, opt backend.ProverConfig) (fr. // now that we know all inputs are set, defer log printing once all solution.values are computed // (or sooner, if a constraint is not satisfied) - defer solution.printLogs(opt.CircuitLogger, cs.Logs) + defer solution.printLogs(opt.Logger, cs.Logs) if err := cs.parallelSolve(a, b, c, &solution); err != nil { if unsatisfiedErr, ok := err.(*UnsatisfiedConstraintError); ok { @@ -205,8 +230,8 @@ func (cs *R1CS) parallelSolve(a, b, c fr.Vector, solution *solution) error { continue } - // number of tasks for this level is set to num cpus - // but if we don't have enough work for all our CPUS, it can be lower. + // number of tasks for this level is set to number of CPU + // but if we don't have enough work for all our CPU, it can be lower. nbTasks := runtime.NumCPU() maxTasks := int(math.Ceil(maxCPU)) if nbTasks > maxTasks { @@ -249,19 +274,10 @@ func (cs *R1CS) parallelSolve(a, b, c fr.Vector, solution *solution) error { return nil } -// IsSolved returns nil if given witness solves the R1CS and error otherwise -// this method wraps cs.Solve() and allocates cs.Solve() inputs -func (cs *R1CS) IsSolved(witness witness.Witness, opts ...backend.ProverOption) error { - opt, err := backend.NewProverConfig(opts...) - if err != nil { - return err - } - - a := make(fr.Vector, len(cs.Constraints)) - b := make(fr.Vector, len(cs.Constraints)) - c := make(fr.Vector, len(cs.Constraints)) - v := witness.Vector().(fr.Vector) - _, err = cs.Solve(v, a, b, c, opt) +// IsSolved +// Deprecated: use _, err := Solve(...) instead +func (cs *R1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { + _, err := cs.Solve(witness, opts...) return err } diff --git a/constraint/bw6-761/r1cs_sparse.go b/constraint/bw6-761/r1cs_sparse.go index 6f9f1ff048..09c22e4d48 100644 --- a/constraint/bw6-761/r1cs_sparse.go +++ b/constraint/bw6-761/r1cs_sparse.go @@ -27,9 +27,9 @@ import ( "sync" "time" - "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/backend/ioutils" "github.com/consensys/gnark/logger" "github.com/consensys/gnark/profile" @@ -70,11 +70,67 @@ func (cs *SparseR1CS) AddConstraint(c constraint.SparseR1C, debugInfo ...constra return cID } +func (c *SparseR1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { + opt, err := solver.NewConfig(opts...) + if err != nil { + return nil, err + } + + // compute the constraint system solution + var solution []fr.Element + if solution, err = c.solve(witness.Vector().(fr.Vector), opt); err != nil { + return nil, err + } + + var res SparseR1CSSolution + // query l, r, o in Lagrange basis, not blinded + res.L, res.R, res.O = c.evaluateLROSmallDomain(solution) + + return &res, nil +} + +// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. +// solution = [ public | secret | internal ] +func (c *SparseR1CS) evaluateLROSmallDomain(solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { + + //s := int(pk.Domain[0].Cardinality) + s := c.GetNbConstraints() + len(c.Public) // len(spr.Public) is for the placeholder constraints + s = int(ecc.NextPowerOfTwo(uint64(s))) + + var l, r, o []fr.Element + l = make([]fr.Element, s) + r = make([]fr.Element, s) + o = make([]fr.Element, s) + s0 := solution[0] + + for i := 0; i < len(c.Public); i++ { // placeholders + l[i] = solution[i] + r[i] = s0 + o[i] = s0 + } + offset := len(c.Public) + for i := 0; i < len(c.Constraints); i++ { // constraints + l[offset+i] = solution[c.Constraints[i].L.WireID()] + r[offset+i] = solution[c.Constraints[i].R.WireID()] + o[offset+i] = solution[c.Constraints[i].O.WireID()] + } + offset += len(c.Constraints) + + for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) + l[offset+i] = s0 + r[offset+i] = s0 + o[offset+i] = s0 + } + + return l, r, o + +} + // Solve sets all the wires. // solution.values = [publicInputs | secretInputs | internalVariables ] // witness: contains the input variables // it returns the full slice of wires -func (cs *SparseR1CS) Solve(witness fr.Vector, opt backend.ProverConfig) (fr.Vector, error) { +func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, error) { log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "plonk").Logger() // set the slices holding the solution.values and monitoring which variables have been solved @@ -110,7 +166,7 @@ func (cs *SparseR1CS) Solve(witness fr.Vector, opt backend.ProverConfig) (fr.Vec solution.nbSolved += uint64(len(witness)) // defer log printing once all solution.values are computed - defer solution.printLogs(opt.CircuitLogger, cs.Logs) + defer solution.printLogs(opt.Logger, cs.Logs) // batch invert the coefficients to avoid many divisions in the solver coefficientsNegInv := fr.BatchInvert(cs.Coefficients) @@ -210,8 +266,8 @@ func (cs *SparseR1CS) parallelSolve(solution *solution, coefficientsNegInv fr.Ve continue } - // number of tasks for this level is set to num cpus - // but if we don't have enough work for all our CPUS, it can be lower. + // number of tasks for this level is set to number of CPU + // but if we don't have enough work for all our CPU, it can be lower. nbTasks := runtime.NumCPU() maxTasks := int(math.Ceil(maxCPU)) if nbTasks > maxTasks { @@ -369,16 +425,10 @@ func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution return nil } -// IsSolved returns nil if given witness solves the SparseR1CS and error otherwise -// this method wraps cs.Solve() and allocates cs.Solve() inputs -func (cs *SparseR1CS) IsSolved(witness witness.Witness, opts ...backend.ProverOption) error { - opt, err := backend.NewProverConfig(opts...) - if err != nil { - return err - } - - v := witness.Vector().(fr.Vector) - _, err = cs.Solve(v, opt) +// IsSolved +// Deprecated: use _, err := Solve(...) instead +func (cs *SparseR1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { + _, err := cs.Solve(witness, opts...) return err } diff --git a/constraint/bw6-761/solution.go b/constraint/bw6-761/solution.go index 54e9eee0bb..139b58737d 100644 --- a/constraint/bw6-761/solution.go +++ b/constraint/bw6-761/solution.go @@ -19,10 +19,11 @@ package cs import ( "errors" "fmt" - "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/debug" "github.com/rs/zerolog" + "io" "math/big" "strconv" "strings" @@ -37,12 +38,12 @@ type solution struct { values, coefficients []fr.Element solved []bool nbSolved uint64 - mHintsFunctions map[hint.ID]hint.Function // maps hintID to hint function - mHints map[int]*constraint.Hint // maps wireID to hint + mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function + mHints map[int]*constraint.HintMapping // maps wireID to hint st *debug.SymbolTable } -func newSolution(nbWires int, hintFunctions map[hint.ID]hint.Function, hintsDependencies map[hint.ID]string, mHints map[int]*constraint.Hint, coefficients []fr.Element, st *debug.SymbolTable) (solution, error) { +func newSolution(nbWires int, hintFunctions map[solver.HintID]solver.Hint, hintsDependencies map[solver.HintID]string, mHints map[int]*constraint.HintMapping, coefficients []fr.Element, st *debug.SymbolTable) (solution, error) { s := solution{ st: st, @@ -139,21 +140,21 @@ func (s *solution) accumulateInto(t constraint.Term, r *fr.Element) { } // solveHint compute solution.values[vID] using provided solver hint -func (s *solution) solveWithHint(vID int, h *constraint.Hint) error { +func (s *solution) solveWithHint(vID int, h *constraint.HintMapping) error { // skip if the wire is already solved by a call to the same hint // function on the same inputs if s.solved[vID] { return nil } // ensure hint function was provided - f, ok := s.mHintsFunctions[h.ID] + f, ok := s.mHintsFunctions[h.HintID] if !ok { return errors.New("missing hint function") } // tmp IO big int memory nbInputs := len(h.Inputs) - nbOutputs := len(h.Wires) + nbOutputs := len(h.Outputs) inputs := make([]*big.Int, nbInputs) outputs := make([]*big.Int, nbOutputs) for i := 0; i < nbOutputs; i++ { @@ -203,7 +204,7 @@ func (s *solution) solveWithHint(vID int, h *constraint.Hint) error { var v fr.Element for i := range outputs { v.SetBigInt(outputs[i]) - s.set(h.Wires[i], v) + s.set(h.Outputs[i], v) } return err @@ -294,3 +295,86 @@ func (r *UnsatisfiedConstraintError) Error() string { } return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, r.Err.Error()) } + +// R1CSSolution represent a valid assignment to all the variables in the constraint system. +// The vector W such that Aw o Bw - Cw = 0 +type R1CSSolution struct { + W fr.Vector + A, B, C fr.Vector +} + +func (t *R1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.W.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.A.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.B.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.C.WriteTo(w) + n += a + return n, err +} + +func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.W.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.A.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.B.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.C.ReadFrom(r) + n += a + return n, err +} + +// SparseR1CSSolution represent a valid assignment to all the variables in the constraint system. +type SparseR1CSSolution struct { + L, R, O fr.Vector +} + +func (t *SparseR1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.L.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.R.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.O.WriteTo(w) + n += a + return n, err + +} + +func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.L.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.R.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.O.ReadFrom(r) + a += n + return n, err +} diff --git a/constraint/commitment.go b/constraint/commitment.go index bc6a0e8d0a..4e97f76a8f 100644 --- a/constraint/commitment.go +++ b/constraint/commitment.go @@ -3,7 +3,7 @@ package constraint import ( "math/big" - "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/constraint/solver" ) const CommitmentDst = "bsb22-commitment" @@ -11,7 +11,7 @@ const CommitmentDst = "bsb22-commitment" type Commitment struct { Committed []int // sorted list of id's of committed variables NbPrivateCommitted int - HintID hint.ID // TODO @gbotrel we probably don't need that here + HintID solver.HintID // TODO @gbotrel we probably don't need that here CommitmentIndex int CommittedAndCommitment []int // sorted list of id's of committed variables AND the commitment itself } diff --git a/constraint/hint.go b/constraint/hint.go index 0e92d6afd6..9085e5eb9e 100644 --- a/constraint/hint.go +++ b/constraint/hint.go @@ -1,14 +1,10 @@ package constraint -import ( - "github.com/consensys/gnark/backend/hint" -) +import "github.com/consensys/gnark/constraint/solver" -// Hint represents a solver hint -// it enables the solver to compute a Wire with a function provided at solving time -// using pre-defined inputs -type Hint struct { - ID hint.ID // hint function id - Inputs []LinearExpression // terms to inject in the hint function - Wires []int // IDs of wires the hint outputs map to +// HintMapping mark a list of output variables to be computed using provided hint and inputs. +type HintMapping struct { + HintID solver.HintID // Hint function id + Inputs []LinearExpression // Terms to inject in the hint function + Outputs []int // IDs of wires the hint outputs map to } diff --git a/constraint/level_builder.go b/constraint/level_builder.go index 80c24614b8..c2b1d8c155 100644 --- a/constraint/level_builder.go +++ b/constraint/level_builder.go @@ -10,7 +10,7 @@ package constraint // --> l = max(level_of_dependencies(wire)) + 1 func (system *System) updateLevel(cID int, c Iterable) { system.lbOutputs = system.lbOutputs[:0] - system.lbHints = map[*Hint]struct{}{} + system.lbHints = map[*HintMapping]struct{}{} level := -1 wireIterator := c.WireIterator() for wID := wireIterator(); wID != -1; wID = wireIterator() { @@ -65,7 +65,7 @@ func (system *System) processWire(wireID uint32, maxLevel *int) { } system.lbHints[h] = struct{}{} - for _, hwid := range h.Wires { + for _, hwid := range h.Outputs { system.lbOutputs = append(system.lbOutputs, uint32(hwid)) } for _, in := range h.Inputs { diff --git a/constraint/r1cs_test.go b/constraint/r1cs_test.go index b2736d3073..aa2c06fe27 100644 --- a/constraint/r1cs_test.go +++ b/constraint/r1cs_test.go @@ -3,8 +3,11 @@ package constraint_test import ( "fmt" + "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/constraint" cs "github.com/consensys/gnark/constraint/bn254" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" ) func ExampleR1CS_GetConstraints() { @@ -63,3 +66,38 @@ func ExampleR1CS_GetConstraints() { // v0 ⋅ X == v1 // Y ⋅ 1 == 5 + X + v1 } + +func ExampleR1CS_Solve() { + // build a constraint system and a witness; + ccs, _ := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &cubic{}) + w, _ := frontend.NewWitness(&cubic{X: 3, Y: 35}, ecc.BN254.ScalarField()) + + _solution, _ := ccs.Solve(w) + + // concrete solution + solution := _solution.(*cs.R1CSSolution) + + // solution vector should have [1, 3, 35, 9, 27] + for _, v := range solution.W { + fmt.Println(v.String()) + } + + // Output: + // 1 + // 3 + // 35 + // 9 + // 27 +} + +type cubic struct { + X, Y frontend.Variable +} + +// Define declares the circuit constraints +// x**3 + x + 5 == y +func (circuit *cubic) Define(api frontend.API) error { + x3 := api.Mul(circuit.X, circuit.X, circuit.X) + api.AssertIsEqual(circuit.Y, api.Add(x3, circuit.X, 5)) + return nil +} diff --git a/constraint/solver/hint.go b/constraint/solver/hint.go new file mode 100644 index 0000000000..5ffc3f1f31 --- /dev/null +++ b/constraint/solver/hint.go @@ -0,0 +1,101 @@ +package solver + +import ( + "hash/fnv" + "math/big" + "reflect" + "runtime" +) + +// HintID is a unique identifier for a hint function used for lookup. +type HintID uint32 + +// Hint allows to define computations outside of a circuit. +// +// It defines an annotated hint function; the number of inputs and outputs injected at solving +// time is defined in the circuit (compile time). +// +// For example: +// +// b := api.NewHint(hint, 2, a) +// --> at solving time, hint is going to be invoked with 1 input (a) and is expected to return 2 outputs +// b[0] and b[1]. +// +// Usually, it is expected that computations in circuits are performed on +// variables. However, in some cases defining the computations in circuits may be +// complicated or computationally expensive. By using hints, the computations are +// performed outside of the circuit on integers (compared to the frontend.Variable +// values inside the circuits) and the result of a hint function is assigned to a +// newly created variable in a circuit. +// +// As the computations are performed outside of the circuit, then the correctness of +// the result is not guaranteed. This also means that the result of a hint function +// is unconstrained by default, leading to failure while composing circuit proof. +// Thus, it is the circuit developer responsibility to verify the correctness hint +// result by adding necessary constraints in the circuit. +// +// As an example, lets say the hint function computes a factorization of a +// semiprime n: +// +// p, q <- hint(n) st. p * q = n +// +// into primes p and q. Then, the circuit developer needs to assert in the circuit +// that p*q indeed equals to n: +// +// n == p * q. +// +// However, if the hint function is incorrectly defined (e.g. in the previous +// example, it returns 1 and n instead of p and q), then the assertion may still +// hold, but the constructed proof is semantically invalid. Thus, the user +// constructing the proof must be extremely cautious when using hints. +// +// # Using hint functions in circuits +// +// To use a hint function in a circuit, the developer first needs to define a hint +// function hintFn according to the Function interface. Then, in a circuit, the +// developer applies the hint function with frontend.API.NewHint(hintFn, vars...), +// where vars are the variables the hint function will be applied to (and +// correspond to the argument inputs in the Function type) which returns a new +// unconstrained variable. The returned variables must be constrained using +// frontend.API.Assert[.*] methods. +// +// As explained, the hints are essentially black boxes from the circuit point of +// view and thus the defined hints in circuits are not used when constructing a +// proof. To allow the particular hint functions to be used during proof +// construction, the user needs to supply a solver.Option indicating the +// enabled hints. Such options can be obtained by a call to +// solver.WithHints(hintFns...), where hintFns are the corresponding hint +// functions. +// +// # Using hint functions in gadgets +// +// Similar considerations apply for hint functions used in gadgets as in +// user-defined circuits. However, listing all hint functions used in a particular +// gadget for constructing solver.Option puts high overhead for the user to +// enable all necessary hints. +// +// For that, this package also provides a registry of trusted hint functions. When +// a gadget registers a hint function, then it is automatically enabled during +// proof computation and the prover does not need to provide a corresponding +// proving option. +// +// In the init() method of the gadget, call the method RegisterHint(hintFn) function on +// the hint function hintFn to register a hint function in the package registry. +type Hint func(field *big.Int, inputs []*big.Int, outputs []*big.Int) error + +// GetHintID is a reference function for computing the hint ID based on a function name +func GetHintID(fn Hint) HintID { + hf := fnv.New32a() + name := GetHintName(fn) + + // TODO relying on name to derive UUID is risky; if fn is an anonymous func, wil be package.glob..funcN + // and if new anonymous functions are added in the package, N may change, so will UUID. + hf.Write([]byte(name)) // #nosec G104 -- does not err + + return HintID(hf.Sum32()) +} + +func GetHintName(fn Hint) string { + fnptr := reflect.ValueOf(fn).Pointer() + return runtime.FuncForPC(fnptr).Name() +} diff --git a/constraint/solver/hint_registry.go b/constraint/solver/hint_registry.go new file mode 100644 index 0000000000..d9f412839f --- /dev/null +++ b/constraint/solver/hint_registry.go @@ -0,0 +1,60 @@ +package solver + +import ( + "math/big" + "sync" + + "github.com/consensys/gnark/logger" +) + +func init() { + RegisterHint(InvZeroHint) +} + +var ( + registry = make(map[HintID]Hint) + registryM sync.RWMutex +) + +// RegisterHint registers a hint function in the global registry. +func RegisterHint(hintFns ...Hint) { + registryM.Lock() + defer registryM.Unlock() + for _, hintFn := range hintFns { + key := GetHintID(hintFn) + name := GetHintName(hintFn) + if _, ok := registry[key]; ok { + log := logger.Logger() + log.Warn().Str("name", name).Msg("function registered multiple times") + return + } + registry[key] = hintFn + } +} + +// GetRegisteredHints returns all registered hint functions. +func GetRegisteredHints() []Hint { + registryM.RLock() + defer registryM.RUnlock() + ret := make([]Hint, 0, len(registry)) + for _, v := range registry { + ret = append(ret, v) + } + return ret +} + +// InvZeroHint computes the value 1/a for the single input a. If a == 0, returns 0. +func InvZeroHint(q *big.Int, inputs []*big.Int, results []*big.Int) error { + result := results[0] + + // save input + result.Set(inputs[0]) + + // a == 0, return + if result.IsUint64() && result.Uint64() == 0 { + return nil + } + + result.ModInverse(result, q) + return nil +} diff --git a/constraint/solver/options.go b/constraint/solver/options.go new file mode 100644 index 0000000000..368eff3f56 --- /dev/null +++ b/constraint/solver/options.go @@ -0,0 +1,69 @@ +package solver + +import ( + "github.com/consensys/gnark/logger" + "github.com/rs/zerolog" +) + +// Option defines option for altering the behavior of a constraint system +// solver (Solve() method). See the descriptions of functions returning instances +// of this type for implemented options. +type Option func(*Config) error + +// Config is the configuration for the solver with the options applied. +type Config struct { + HintFunctions map[HintID]Hint // defaults to all built-in hint functions + Logger zerolog.Logger // defaults to gnark.Logger +} + +// WithHints is a solver option that specifies additional hint functions to be used +// by the constraint solver. +func WithHints(hintFunctions ...Hint) Option { + log := logger.Logger() + return func(opt *Config) error { + // it is an error to register hint function several times, but as the + // prover already checks it then omit here. + for _, h := range hintFunctions { + uuid := GetHintID(h) + if _, ok := opt.HintFunctions[uuid]; ok { + log.Warn().Int("hintID", int(uuid)).Str("name", GetHintName(h)).Msg("duplicate hint function") + } else { + opt.HintFunctions[uuid] = h + } + } + return nil + } +} + +// OverrideHint forces the solver to use provided hint function for given id. +func OverrideHint(id HintID, f Hint) Option { + return func(opt *Config) error { + opt.HintFunctions[id] = f + return nil + } +} + +// WithLogger is a prover option that specifies zerolog.Logger as a destination for the +// logs printed by api.Println(). By default, uses gnark/logger. +// zerolog.Nop() will disable logging +func WithLogger(l zerolog.Logger) Option { + return func(opt *Config) error { + opt.Logger = l + return nil + } +} + +// NewConfig returns a default SolverConfig with given prover options opts applied. +func NewConfig(opts ...Option) (Config, error) { + log := logger.Logger() + opt := Config{Logger: log, HintFunctions: make(map[HintID]Hint)} + for _, v := range GetRegisteredHints() { + opt.HintFunctions[GetHintID(v)] = v + } + for _, option := range opts { + if err := option(&opt); err != nil { + return Config{}, err + } + } + return opt, nil +} diff --git a/constraint/system.go b/constraint/system.go index 2462f4aebb..fc7e0eea67 100644 --- a/constraint/system.go +++ b/constraint/system.go @@ -8,9 +8,8 @@ import ( "github.com/blang/semver/v4" "github.com/consensys/gnark" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark/backend" - "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/debug" "github.com/consensys/gnark/internal/tinyfield" "github.com/consensys/gnark/internal/utils" @@ -24,7 +23,13 @@ type ConstraintSystem interface { CoeffEngine // IsSolved returns nil if given witness solves the constraint system and error otherwise - IsSolved(witness witness.Witness, opts ...backend.ProverOption) error + // Deprecated: use _, err := Solve(...) instead + IsSolved(witness witness.Witness, opts ...solver.Option) error + + // Solve attempts to solves the constraint system using provided witness. + // Returns an error if the witness does not allow all the constraints to be satisfied. + // Returns a typed solution (R1CSSolution or SparseR1CSSolution) and nil otherwise. + Solve(witness witness.Witness, opts ...solver.Option) (any, error) // GetNbVariables return number of internal, secret and public Variables // Deprecated: use GetNbSecretVariables() instead @@ -46,7 +51,7 @@ type ConstraintSystem interface { // AddSolverHint adds a hint to the solver such that the output variables will be computed // using a call to output := f(input...) at solve time. - AddSolverHint(f hint.Function, input []LinearExpression, nbOutput int) (internalVariables []int, err error) + AddSolverHint(f solver.Hint, input []LinearExpression, nbOutput int) (internalVariables []int, err error) AddCommitment(c Commitment) error @@ -105,8 +110,8 @@ type System struct { // several constraints may point to the same debug info MDebug map[int]int - MHints map[int]*Hint // maps wireID to hint - MHintsDependencies map[hint.ID]string // maps hintID to hint string identifier + MHints map[int]*HintMapping // maps wireID to hint + MHintsDependencies map[solver.HintID]string // maps hintID to hint string identifier // each level contains independent constraints and can be parallelized // it is guaranteed that all dependencies for constraints in a level l are solved @@ -121,9 +126,9 @@ type System struct { bitLen int `cbor:"-"` // level builder - lbWireLevel []int `cbor:"-"` // at which level we solve a wire. init at -1. - lbOutputs []uint32 `cbor:"-"` // wire outputs for current constraint. - lbHints map[*Hint]struct{} `cbor:"-"` // hints we processed in current round + lbWireLevel []int `cbor:"-"` // at which level we solve a wire. init at -1. + lbOutputs []uint32 `cbor:"-"` // wire outputs for current constraint. + lbHints map[*HintMapping]struct{} `cbor:"-"` // hints we processed in current round CommitmentInfo Commitment } @@ -135,11 +140,11 @@ func NewSystem(scalarField *big.Int) System { MDebug: map[int]int{}, GnarkVersion: gnark.Version.String(), ScalarField: scalarField.Text(16), - MHints: make(map[int]*Hint), - MHintsDependencies: make(map[hint.ID]string), + MHints: make(map[int]*HintMapping), + MHintsDependencies: make(map[solver.HintID]string), q: new(big.Int).Set(scalarField), bitLen: scalarField.BitLen(), - lbHints: map[*Hint]struct{}{}, + lbHints: map[*HintMapping]struct{}{}, } } @@ -170,7 +175,7 @@ func (system *System) CheckSerializationHeader() error { } // TODO @gbotrel maintain version changes and compare versions properly - // (ie if major didn't change,we shouldn't have a compat issue) + // (ie if major didn't change,we shouldn't have a compatibility issue) scalarField := new(big.Int) _, ok := scalarField.SetString(system.ScalarField, 16) @@ -179,7 +184,7 @@ func (system *System) CheckSerializationHeader() error { } curveID := utils.FieldToCurve(scalarField) if curveID == ecc.UNKNOWN && scalarField.Cmp(tinyfield.Modulus()) != 0 { - return fmt.Errorf("unsupported scalard field %s", scalarField.Text(16)) + return fmt.Errorf("unsupported scalar field %s", scalarField.Text(16)) } system.q = new(big.Int).Set(scalarField) system.bitLen = system.q.BitLen() @@ -218,13 +223,13 @@ func (system *System) AddSecretVariable(name string) (idx int) { return idx } -func (system *System) AddSolverHint(f hint.Function, input []LinearExpression, nbOutput int) (internalVariables []int, err error) { +func (system *System) AddSolverHint(f solver.Hint, input []LinearExpression, nbOutput int) (internalVariables []int, err error) { if nbOutput <= 0 { return nil, fmt.Errorf("hint function must return at least one output") } // register the hint as dependency - hintUUID, hintID := hint.UUID(f), hint.Name(f) + hintUUID, hintID := solver.GetHintID(f), solver.GetHintName(f) if id, ok := system.MHintsDependencies[hintUUID]; ok { // hint already registered, let's ensure string id matches if id != hintID { @@ -241,7 +246,7 @@ func (system *System) AddSolverHint(f hint.Function, input []LinearExpression, n } // associate these wires with the solver hint - ch := &Hint{ID: hintUUID, Inputs: input, Wires: internalVariables} + ch := &HintMapping{HintID: hintUUID, Inputs: input, Outputs: internalVariables} for _, vID := range internalVariables { system.MHints[vID] = ch } diff --git a/constraint/tinyfield/r1cs.go b/constraint/tinyfield/r1cs.go index accfdaef50..a38085f0fb 100644 --- a/constraint/tinyfield/r1cs.go +++ b/constraint/tinyfield/r1cs.go @@ -25,9 +25,9 @@ import ( "sync" "time" - "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/backend/ioutils" "github.com/consensys/gnark/logger" "github.com/consensys/gnark/profile" @@ -73,12 +73,37 @@ func (cs *R1CS) AddConstraint(r1c constraint.R1C, debugInfo ...constraint.DebugI return cID } +// Solve returns the vector w solution to the system, that is +// Aw o Bw - Cw = 0 +func (cs *R1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { + opt, err := solver.NewConfig(opts...) + if err != nil { + return nil, err + } + + var res R1CSSolution + + s := ecc.NextPowerOfTwo(uint64(len(cs.Constraints))) + res.A = make(fr.Vector, len(cs.Constraints), s) + res.B = make(fr.Vector, len(cs.Constraints), s) + res.C = make(fr.Vector, len(cs.Constraints), s) + + v := witness.Vector().(fr.Vector) + + res.W, err = cs.solve(v, res.A, res.B, res.C, opt) + if err != nil { + return nil, err + } + + return &res, nil +} + // Solve sets all the wires and returns the a, b, c vectors. // the cs system should have been compiled before. The entries in a, b, c are in Montgomery form. // a, b, c vectors: ab-c = hz // witness = [publicWires | secretWires] (without the ONE_WIRE !) // returns [publicWires | secretWires | internalWires ] -func (cs *R1CS) Solve(witness, a, b, c fr.Vector, opt backend.ProverConfig) (fr.Vector, error) { +func (cs *R1CS) solve(witness, a, b, c fr.Vector, opt solver.Config) (fr.Vector, error) { log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables @@ -114,7 +139,7 @@ func (cs *R1CS) Solve(witness, a, b, c fr.Vector, opt backend.ProverConfig) (fr. // now that we know all inputs are set, defer log printing once all solution.values are computed // (or sooner, if a constraint is not satisfied) - defer solution.printLogs(opt.CircuitLogger, cs.Logs) + defer solution.printLogs(opt.Logger, cs.Logs) if err := cs.parallelSolve(a, b, c, &solution); err != nil { if unsatisfiedErr, ok := err.(*UnsatisfiedConstraintError); ok { @@ -205,8 +230,8 @@ func (cs *R1CS) parallelSolve(a, b, c fr.Vector, solution *solution) error { continue } - // number of tasks for this level is set to num cpus - // but if we don't have enough work for all our CPUS, it can be lower. + // number of tasks for this level is set to number of CPU + // but if we don't have enough work for all our CPU, it can be lower. nbTasks := runtime.NumCPU() maxTasks := int(math.Ceil(maxCPU)) if nbTasks > maxTasks { @@ -249,19 +274,10 @@ func (cs *R1CS) parallelSolve(a, b, c fr.Vector, solution *solution) error { return nil } -// IsSolved returns nil if given witness solves the R1CS and error otherwise -// this method wraps cs.Solve() and allocates cs.Solve() inputs -func (cs *R1CS) IsSolved(witness witness.Witness, opts ...backend.ProverOption) error { - opt, err := backend.NewProverConfig(opts...) - if err != nil { - return err - } - - a := make(fr.Vector, len(cs.Constraints)) - b := make(fr.Vector, len(cs.Constraints)) - c := make(fr.Vector, len(cs.Constraints)) - v := witness.Vector().(fr.Vector) - _, err = cs.Solve(v, a, b, c, opt) +// IsSolved +// Deprecated: use _, err := Solve(...) instead +func (cs *R1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { + _, err := cs.Solve(witness, opts...) return err } diff --git a/constraint/tinyfield/r1cs_sparse.go b/constraint/tinyfield/r1cs_sparse.go index 4ad9f0023c..b3fe2373a9 100644 --- a/constraint/tinyfield/r1cs_sparse.go +++ b/constraint/tinyfield/r1cs_sparse.go @@ -27,9 +27,9 @@ import ( "sync" "time" - "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/backend/ioutils" "github.com/consensys/gnark/logger" "github.com/consensys/gnark/profile" @@ -70,11 +70,67 @@ func (cs *SparseR1CS) AddConstraint(c constraint.SparseR1C, debugInfo ...constra return cID } +func (c *SparseR1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { + opt, err := solver.NewConfig(opts...) + if err != nil { + return nil, err + } + + // compute the constraint system solution + var solution []fr.Element + if solution, err = c.solve(witness.Vector().(fr.Vector), opt); err != nil { + return nil, err + } + + var res SparseR1CSSolution + // query l, r, o in Lagrange basis, not blinded + res.L, res.R, res.O = c.evaluateLROSmallDomain(solution) + + return &res, nil +} + +// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. +// solution = [ public | secret | internal ] +func (c *SparseR1CS) evaluateLROSmallDomain(solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { + + //s := int(pk.Domain[0].Cardinality) + s := c.GetNbConstraints() + len(c.Public) // len(spr.Public) is for the placeholder constraints + s = int(ecc.NextPowerOfTwo(uint64(s))) + + var l, r, o []fr.Element + l = make([]fr.Element, s) + r = make([]fr.Element, s) + o = make([]fr.Element, s) + s0 := solution[0] + + for i := 0; i < len(c.Public); i++ { // placeholders + l[i] = solution[i] + r[i] = s0 + o[i] = s0 + } + offset := len(c.Public) + for i := 0; i < len(c.Constraints); i++ { // constraints + l[offset+i] = solution[c.Constraints[i].L.WireID()] + r[offset+i] = solution[c.Constraints[i].R.WireID()] + o[offset+i] = solution[c.Constraints[i].O.WireID()] + } + offset += len(c.Constraints) + + for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) + l[offset+i] = s0 + r[offset+i] = s0 + o[offset+i] = s0 + } + + return l, r, o + +} + // Solve sets all the wires. // solution.values = [publicInputs | secretInputs | internalVariables ] // witness: contains the input variables // it returns the full slice of wires -func (cs *SparseR1CS) Solve(witness fr.Vector, opt backend.ProverConfig) (fr.Vector, error) { +func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, error) { log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "plonk").Logger() // set the slices holding the solution.values and monitoring which variables have been solved @@ -110,7 +166,7 @@ func (cs *SparseR1CS) Solve(witness fr.Vector, opt backend.ProverConfig) (fr.Vec solution.nbSolved += uint64(len(witness)) // defer log printing once all solution.values are computed - defer solution.printLogs(opt.CircuitLogger, cs.Logs) + defer solution.printLogs(opt.Logger, cs.Logs) // batch invert the coefficients to avoid many divisions in the solver coefficientsNegInv := fr.BatchInvert(cs.Coefficients) @@ -210,8 +266,8 @@ func (cs *SparseR1CS) parallelSolve(solution *solution, coefficientsNegInv fr.Ve continue } - // number of tasks for this level is set to num cpus - // but if we don't have enough work for all our CPUS, it can be lower. + // number of tasks for this level is set to number of CPU + // but if we don't have enough work for all our CPU, it can be lower. nbTasks := runtime.NumCPU() maxTasks := int(math.Ceil(maxCPU)) if nbTasks > maxTasks { @@ -369,16 +425,10 @@ func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution return nil } -// IsSolved returns nil if given witness solves the SparseR1CS and error otherwise -// this method wraps cs.Solve() and allocates cs.Solve() inputs -func (cs *SparseR1CS) IsSolved(witness witness.Witness, opts ...backend.ProverOption) error { - opt, err := backend.NewProverConfig(opts...) - if err != nil { - return err - } - - v := witness.Vector().(fr.Vector) - _, err = cs.Solve(v, opt) +// IsSolved +// Deprecated: use _, err := Solve(...) instead +func (cs *SparseR1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { + _, err := cs.Solve(witness, opts...) return err } diff --git a/constraint/tinyfield/solution.go b/constraint/tinyfield/solution.go index 2f5eb4caec..090b97f78d 100644 --- a/constraint/tinyfield/solution.go +++ b/constraint/tinyfield/solution.go @@ -19,10 +19,11 @@ package cs import ( "errors" "fmt" - "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/debug" "github.com/rs/zerolog" + "io" "math/big" "strconv" "strings" @@ -37,12 +38,12 @@ type solution struct { values, coefficients []fr.Element solved []bool nbSolved uint64 - mHintsFunctions map[hint.ID]hint.Function // maps hintID to hint function - mHints map[int]*constraint.Hint // maps wireID to hint + mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function + mHints map[int]*constraint.HintMapping // maps wireID to hint st *debug.SymbolTable } -func newSolution(nbWires int, hintFunctions map[hint.ID]hint.Function, hintsDependencies map[hint.ID]string, mHints map[int]*constraint.Hint, coefficients []fr.Element, st *debug.SymbolTable) (solution, error) { +func newSolution(nbWires int, hintFunctions map[solver.HintID]solver.Hint, hintsDependencies map[solver.HintID]string, mHints map[int]*constraint.HintMapping, coefficients []fr.Element, st *debug.SymbolTable) (solution, error) { s := solution{ st: st, @@ -139,21 +140,21 @@ func (s *solution) accumulateInto(t constraint.Term, r *fr.Element) { } // solveHint compute solution.values[vID] using provided solver hint -func (s *solution) solveWithHint(vID int, h *constraint.Hint) error { +func (s *solution) solveWithHint(vID int, h *constraint.HintMapping) error { // skip if the wire is already solved by a call to the same hint // function on the same inputs if s.solved[vID] { return nil } // ensure hint function was provided - f, ok := s.mHintsFunctions[h.ID] + f, ok := s.mHintsFunctions[h.HintID] if !ok { return errors.New("missing hint function") } // tmp IO big int memory nbInputs := len(h.Inputs) - nbOutputs := len(h.Wires) + nbOutputs := len(h.Outputs) inputs := make([]*big.Int, nbInputs) outputs := make([]*big.Int, nbOutputs) for i := 0; i < nbOutputs; i++ { @@ -203,7 +204,7 @@ func (s *solution) solveWithHint(vID int, h *constraint.Hint) error { var v fr.Element for i := range outputs { v.SetBigInt(outputs[i]) - s.set(h.Wires[i], v) + s.set(h.Outputs[i], v) } return err @@ -294,3 +295,86 @@ func (r *UnsatisfiedConstraintError) Error() string { } return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, r.Err.Error()) } + +// R1CSSolution represent a valid assignment to all the variables in the constraint system. +// The vector W such that Aw o Bw - Cw = 0 +type R1CSSolution struct { + W fr.Vector + A, B, C fr.Vector +} + +func (t *R1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.W.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.A.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.B.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.C.WriteTo(w) + n += a + return n, err +} + +func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.W.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.A.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.B.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.C.ReadFrom(r) + n += a + return n, err +} + +// SparseR1CSSolution represent a valid assignment to all the variables in the constraint system. +type SparseR1CSSolution struct { + L, R, O fr.Vector +} + +func (t *SparseR1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.L.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.R.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.O.WriteTo(w) + n += a + return n, err + +} + +func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.L.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.R.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.O.ReadFrom(r) + a += n + return n, err +} diff --git a/debug_test.go b/debug_test.go index bd5b538325..34d4d075bf 100644 --- a/debug_test.go +++ b/debug_test.go @@ -9,6 +9,7 @@ import ( "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/backend/plonk" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/consensys/gnark/frontend/cs/scs" @@ -46,11 +47,11 @@ func TestPrintln(t *testing.T) { witness.B = 11 var expected bytes.Buffer - expected.WriteString("debug_test.go:28 > 13 is the addition\n") - expected.WriteString("debug_test.go:30 > 26 42\n") - expected.WriteString("debug_test.go:32 > bits 1\n") - expected.WriteString("debug_test.go:33 > circuit {A: 2, B: 11}\n") - expected.WriteString("debug_test.go:37 > m .*\n") + expected.WriteString("debug_test.go:29 > 13 is the addition\n") + expected.WriteString("debug_test.go:31 > 26 42\n") + expected.WriteString("debug_test.go:33 > bits 1\n") + expected.WriteString("debug_test.go:34 > circuit {A: 2, B: 11}\n") + expected.WriteString("debug_test.go:38 > m .*\n") { trace, _ := getGroth16Trace(&circuit, &witness) @@ -158,7 +159,7 @@ func getPlonkTrace(circuit, w frontend.Circuit) (string, error) { return "", err } log := zerolog.New(&zerolog.ConsoleWriter{Out: &buf, NoColor: true, PartsExclude: []string{zerolog.LevelFieldName, zerolog.TimestampFieldName}}) - _, err = plonk.Prove(ccs, pk, sw, backend.WithCircuitLogger(log)) + _, err = plonk.Prove(ccs, pk, sw, backend.WithSolverOptions(solver.WithLogger(log))) return buf.String(), err } @@ -179,6 +180,6 @@ func getGroth16Trace(circuit, w frontend.Circuit) (string, error) { return "", err } log := zerolog.New(&zerolog.ConsoleWriter{Out: &buf, NoColor: true, PartsExclude: []string{zerolog.LevelFieldName, zerolog.TimestampFieldName}}) - _, err = groth16.Prove(ccs, pk, sw, backend.WithCircuitLogger(log)) + _, err = groth16.Prove(ccs, pk, sw, backend.WithSolverOptions(solver.WithLogger(log))) return buf.String(), err } diff --git a/frontend/api.go b/frontend/api.go index 3645f04197..5742617c20 100644 --- a/frontend/api.go +++ b/frontend/api.go @@ -19,7 +19,7 @@ package frontend import ( "math/big" - "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/constraint/solver" ) // API represents the available functions to circuit developers @@ -122,7 +122,7 @@ type API interface { // NewHint is a shortcut to api.Compiler().NewHint() // Deprecated: use api.Compiler().NewHint() instead - NewHint(f hint.Function, nbOutputs int, inputs ...Variable) ([]Variable, error) + NewHint(f solver.Hint, nbOutputs int, inputs ...Variable) ([]Variable, error) // ConstantValue is a shortcut to api.Compiler().ConstantValue() // Deprecated: use api.Compiler().ConstantValue() instead diff --git a/frontend/builder.go b/frontend/builder.go index 372752cf5f..7dd1b6c488 100644 --- a/frontend/builder.go +++ b/frontend/builder.go @@ -3,8 +3,8 @@ package frontend import ( "math/big" - "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend/schema" ) @@ -36,7 +36,7 @@ type Compiler interface { // manually in the circuit. Failing to do so leads to solver failure. // // If nbOutputs is specified, it must be >= 1 and <= f.NbOutputs - NewHint(f hint.Function, nbOutputs int, inputs ...Variable) ([]Variable, error) + NewHint(f solver.Hint, nbOutputs int, inputs ...Variable) ([]Variable, error) // ConstantValue returns the big.Int value of v and true if op is a success. // nil and false if failure. This API returns a boolean to allow for future refactoring diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index 92f6281de9..75d0d31326 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -25,8 +25,8 @@ import ( "runtime" "strings" - "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/internal/expr" "github.com/consensys/gnark/frontend/schema" @@ -543,7 +543,7 @@ func (builder *builder) IsZero(i1 frontend.Variable) frontend.Variable { m := builder.newInternalVariable() // x = 1/a // in a hint (x == 0 if a == 0) - x, err := builder.NewHint(hint.InvZero, 1, a) + x, err := builder.NewHint(solver.InvZeroHint, 1, a) if err != nil { // the function errs only if the number of inputs is invalid. panic(err) @@ -731,7 +731,7 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error return nil, err } cVar := hintOut[0] - commitment.HintID = hint.UUID(bsb22CommitmentComputePlaceholder) // TODO @gbotrel probably not needed + commitment.HintID = solver.GetHintID(bsb22CommitmentComputePlaceholder) // TODO @gbotrel probably not needed commitment.CommitmentIndex = (cVar.(expr.LinearExpression))[0].WireID() diff --git a/frontend/cs/r1cs/builder.go b/frontend/cs/r1cs/builder.go index 8cd5883d5d..87ac36d348 100644 --- a/frontend/cs/r1cs/builder.go +++ b/frontend/cs/r1cs/builder.go @@ -23,7 +23,6 @@ import ( "sort" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/debug" "github.com/consensys/gnark/frontend" @@ -42,6 +41,7 @@ import ( bn254r1cs "github.com/consensys/gnark/constraint/bn254" bw6633r1cs "github.com/consensys/gnark/constraint/bw6-633" bw6761r1cs "github.com/consensys/gnark/constraint/bw6-761" + "github.com/consensys/gnark/constraint/solver" tinyfieldr1cs "github.com/consensys/gnark/constraint/tinyfield" ) @@ -354,7 +354,7 @@ func (builder *builder) toVariables(in ...frontend.Variable) ([]expr.LinearExpre // // No new constraints are added to the newly created wire and must be added // manually in the circuit. Failing to do so leads to solver failure. -func (builder *builder) NewHint(f hint.Function, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { +func (builder *builder) NewHint(f solver.Hint, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { hintInputs := make([]constraint.LinearExpression, len(inputs)) // TODO @gbotrel hint input pass diff --git a/frontend/cs/scs/api.go b/frontend/cs/scs/api.go index db721158a4..f9f379fcf5 100644 --- a/frontend/cs/scs/api.go +++ b/frontend/cs/scs/api.go @@ -23,8 +23,8 @@ import ( "runtime" "strings" - "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/internal/expr" "github.com/consensys/gnark/frontend/schema" @@ -432,7 +432,7 @@ func (builder *builder) IsZero(i1 frontend.Variable) frontend.Variable { m := builder.newInternalVariable() // x = 1/a // in a hint (x == 0 if a == 0) - x, err := builder.NewHint(hint.InvZero, 1, a) + x, err := builder.NewHint(solver.InvZeroHint, 1, a) if err != nil { // the function errs only if the number of inputs is invalid. panic(err) diff --git a/frontend/cs/scs/builder.go b/frontend/cs/scs/builder.go index 5a9159ce24..b579c9d74c 100644 --- a/frontend/cs/scs/builder.go +++ b/frontend/cs/scs/builder.go @@ -22,7 +22,6 @@ import ( "sort" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/internal/expr" @@ -40,6 +39,7 @@ import ( bn254r1cs "github.com/consensys/gnark/constraint/bn254" bw6633r1cs "github.com/consensys/gnark/constraint/bw6-633" bw6761r1cs "github.com/consensys/gnark/constraint/bw6-761" + "github.com/consensys/gnark/constraint/solver" tinyfieldr1cs "github.com/consensys/gnark/constraint/tinyfield" ) @@ -262,7 +262,7 @@ func (builder *builder) constantValue(v frontend.Variable) (constraint.Coeff, bo // // No new constraints are added to the newly created wire and must be added // manually in the circuit. Failing to do so leads to solver failure. -func (builder *builder) NewHint(f hint.Function, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { +func (builder *builder) NewHint(f solver.Hint, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { hintInputs := make([]constraint.LinearExpression, len(inputs)) // ensure inputs are set and pack them in a []uint64 diff --git a/integration_test.go b/integration_test.go index 3024e003b2..99955e092f 100644 --- a/integration_test.go +++ b/integration_test.go @@ -22,6 +22,7 @@ import ( "testing" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/backend/circuits" "github.com/consensys/gnark/test" ) @@ -55,7 +56,7 @@ func TestIntegrationAPI(t *testing.T) { assert.Run(func(assert *test.Assert) { assert.ProverSucceeded( tData.Circuit, tData.ValidAssignments[i], - test.WithProverOpts(backend.WithHints(tData.HintFunctions...)), + test.WithSolverOpts(solver.WithHints(tData.HintFunctions...)), test.WithCurves(tData.Curves[0], tData.Curves[1:]...), test.WithBackends(backends[0], backends[1:]...)) }, fmt.Sprintf("valid-%d", i)) @@ -66,7 +67,7 @@ func TestIntegrationAPI(t *testing.T) { assert.ProverFailed( tData.Circuit, tData.InvalidAssignments[i], - test.WithProverOpts(backend.WithHints(tData.HintFunctions...)), + test.WithSolverOpts(solver.WithHints(tData.HintFunctions...)), test.WithCurves(tData.Curves[0], tData.Curves[1:]...), test.WithBackends(backends[0], backends[1:]...)) }, fmt.Sprintf("invalid-%d", i)) diff --git a/internal/backend/bls12-377/groth16/prove.go b/internal/backend/bls12-377/groth16/prove.go index e902208028..249e2088ef 100644 --- a/internal/backend/bls12-377/groth16/prove.go +++ b/internal/backend/bls12-377/groth16/prove.go @@ -23,7 +23,9 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint/bls12-377" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" "math/big" @@ -51,22 +53,20 @@ func (proof *Proof) CurveID() ecc.ID { } // Prove generates the proof of knowledge of a r1cs with full witness (secret + public part). -func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness fr.Vector, opt backend.ProverConfig) (*Proof, error) { - // TODO @gbotrel witness size check is done by R1CS, doesn't mean we shouldn't sanitize here. - // if len(witness) != r1cs.NbPublicVariables-1+r1cs.NbSecretVariables { - // return nil, fmt.Errorf("invalid witness size, got %d, expected %d = %d (public) + %d (secret)", len(witness), r1cs.NbPublicVariables-1+r1cs.NbSecretVariables, r1cs.NbPublicVariables, r1cs.NbSecretVariables) - // } +func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { + opt, err := backend.NewProverConfig(opts...) + if err != nil { + return nil, err + } log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", len(r1cs.Constraints)).Str("backend", "groth16").Logger() - // solve the R1CS and compute the a, b, c vectors - a := make([]fr.Element, len(r1cs.Constraints), pk.Domain.Cardinality) - b := make([]fr.Element, len(r1cs.Constraints), pk.Domain.Cardinality) - c := make([]fr.Element, len(r1cs.Constraints), pk.Domain.Cardinality) - proof := &Proof{} + + solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] + if r1cs.CommitmentInfo.Is() { - opt.HintFunctions[r1cs.CommitmentInfo.HintID] = func(_ *big.Int, in []*big.Int, out []*big.Int) error { + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo.HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function if len(in) != r1cs.CommitmentInfo.NbCommitted() { // TODO: Remove @@ -87,36 +87,29 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness fr.Vector, opt backend.ProverC var res fr.Element res, err = solveCommitmentWire(&r1cs.CommitmentInfo, &proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) - res.BigInt(out[0]) //Perf-TODO: Regular (non-mont) hashToField to obviate this conversion? + res.BigInt(out[0]) return err - } + })) } - var wireValues []fr.Element - var err error - if wireValues, err = r1cs.Solve(witness, a, b, c, opt); err != nil { - if !opt.Force { - return nil, err - } else { - // we need to fill wireValues with random values else multi exps don't do much - var r fr.Element - _, _ = r.SetRandom() - for i := r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables(); i < len(wireValues); i++ { - wireValues[i] = r - r.Double(&r) - } - } + _solution, err := r1cs.Solve(fullWitness, solverOpts...) + if err != nil { + return nil, err } + + solution := _solution.(*cs.R1CSSolution) + wireValues := []fr.Element(solution.W) + start := time.Now() // H (witness reduction / FFT part) var h []fr.Element chHDone := make(chan struct{}, 1) go func() { - h = computeH(a, b, c, &pk.Domain) - a = nil - b = nil - c = nil + h = computeH(solution.A, solution.B, solution.C, &pk.Domain) + solution.A = nil + solution.B = nil + solution.C = nil chHDone <- struct{}{} }() @@ -345,7 +338,7 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { den.Sub(&den, &one).Inverse(&den) // h = ifft_coset(ca o cb - cc) - // reusing a to avoid unecessary memalloc + // reusing a to avoid unnecessary memory allocation utils.Parallelize(n, func(start, end int) { for i := start; i < end; i++ { a[i].Mul(&a[i], &b[i]). diff --git a/internal/backend/bls12-377/plonk/prove.go b/internal/backend/bls12-377/plonk/prove.go index 489ab0dc61..7347d6f861 100644 --- a/internal/backend/bls12-377/plonk/prove.go +++ b/internal/backend/bls12-377/plonk/prove.go @@ -23,6 +23,8 @@ import ( "sync" "time" + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" curve "github.com/consensys/gnark-crypto/ecc/bls12-377" @@ -58,10 +60,15 @@ type Proof struct { ZShiftedOpening kzg.OpeningProof } -// Prove from the public data -func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backend.ProverConfig) (*Proof, error) { +func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", len(spr.Constraints)).Str("backend", "plonk").Logger() + + opt, err := backend.NewProverConfig(opts...) + if err != nil { + return nil, err + } + start := time.Now() // pick a hash function that will be used to derive the challenges hFunc := sha256.New() @@ -72,25 +79,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen // result proof := &Proof{} - // compute the constraint system solution - var solution []fr.Element - var err error - if solution, err = spr.Solve(fullWitness, opt); err != nil { - if !opt.Force { - return nil, err - } else { - // we need to fill solution with random values - var r fr.Element - _, _ = r.SetRandom() - for i := len(spr.Public) + len(spr.Secret); i < len(solution); i++ { - solution[i] = r - r.Double(&r) - } - } - } - // query l, r, o in Lagrange basis, not blinded - evaluationLDomainSmall, evaluationRDomainSmall, evaluationODomainSmall := evaluateLROSmallDomain(spr, pk, solution) + _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) + if err != nil { + return nil, err + } + solution := _solution.(*cs.SparseR1CSSolution) + evaluationLDomainSmall := []fr.Element(solution.L) + evaluationRDomainSmall := []fr.Element(solution.R) + evaluationODomainSmall := []fr.Element(solution.O) lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} liop := iop.NewPolynomial(&evaluationLDomainSmall, lagReg) @@ -112,10 +109,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen return nil, err } + fw, ok := fullWitness.Vector().(fr.Vector) + if !ok { + return nil, witness.ErrInvalidWitness + } + // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *pk.Vk, fullWitness[:len(spr.Public)]); err != nil { + if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)]); err != nil { return nil, err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) @@ -167,7 +169,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen // compute qk in canonical basis, completed with the public inputs qkCompletedCanonical := make([]fr.Element, pk.Domain[0].Cardinality) - copy(qkCompletedCanonical, fullWitness[:len(spr.Public)]) + copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], pk.LQk[len(spr.Public):]) pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -498,41 +500,6 @@ func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error return err1 } -// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. -// solution = [ public | secret | internal ] -func evaluateLROSmallDomain(spr *cs.SparseR1CS, pk *ProvingKey, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { - - s := int(pk.Domain[0].Cardinality) - - var l, r, o []fr.Element - l = make([]fr.Element, s) - r = make([]fr.Element, s) - o = make([]fr.Element, s) - s0 := solution[0] - - for i := 0; i < len(spr.Public); i++ { // placeholders - l[i] = solution[i] - r[i] = s0 - o[i] = s0 - } - offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // constraints - l[offset+i] = solution[spr.Constraints[i].L.WireID()] - r[offset+i] = solution[spr.Constraints[i].R.WireID()] - o[offset+i] = solution[spr.Constraints[i].O.WireID()] - } - offset += len(spr.Constraints) - - for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) - l[offset+i] = s0 - r[offset+i] = s0 - o[offset+i] = s0 - } - - return l, r, o - -} - // computeLinearizedPolynomial computes the linearized polynomial in canonical basis. // The purpose is to commit and open all in one ql, qr, qm, qo, qk. // * lZeta, rZeta, oZeta are the evaluation of l, r, o at zeta diff --git a/internal/backend/bls12-377/plonkfri/prove.go b/internal/backend/bls12-377/plonkfri/prove.go index 6fda5f6a49..a525c90cb5 100644 --- a/internal/backend/bls12-377/plonkfri/prove.go +++ b/internal/backend/bls12-377/plonkfri/prove.go @@ -22,6 +22,8 @@ import ( "math/bits" "runtime" + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft" @@ -36,7 +38,6 @@ import ( ) type Proof struct { - // commitments to the solution vectors LROpp [3]fri.ProofOfProximity @@ -67,7 +68,11 @@ type Proof struct { OpeningsId1Id2Id3mp [3]fri.OpeningProof } -func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backend.ProverConfig) (*Proof, error) { +func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { + opt, err := backend.NewProverConfig(opts...) + if err != nil { + return nil, err + } var proof Proof @@ -78,23 +83,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") // 1 - solve the system - var solution []fr.Element - var err error - if solution, err = spr.Solve(fullWitness, opt); err != nil { - if !opt.Force { - return nil, err - } else { - // we need to fill solution with random values - var r fr.Element - _, _ = r.SetRandom() - for i := len(spr.Public) + len(spr.Secret); i < len(solution); i++ { - solution[i] = r - r.Double(&r) - } - } + _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) + if err != nil { + return nil, err } - evaluationLDomainSmall, evaluationRDomainSmall, evaluationODomainSmall := evaluateLROSmallDomain(spr, pk, solution) + solution := _solution.(*cs.SparseR1CSSolution) + evaluationLDomainSmall := []fr.Element(solution.L) + evaluationRDomainSmall := []fr.Element(solution.R) + evaluationODomainSmall := []fr.Element(solution.O) // 2 - commit to lro blindedLCanonical, blindedRCanonical, blindedOCanonical, err := computeBlindedLROCanonical( @@ -119,9 +116,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen } // 3 - compute Z, challenges are derived using L, R, O + public inputs + fw, ok := fullWitness.Vector().(fr.Vector) + if !ok { + return nil, witness.ErrInvalidWitness + } dataFiatShamir := make([][fr.Bytes]byte, len(spr.Public)+3) for i := 0; i < len(spr.Public); i++ { - copy(dataFiatShamir[i][:], fullWitness[i].Marshal()) + copy(dataFiatShamir[i][:], fw[i].Marshal()) } copy(dataFiatShamir[len(spr.Public)][:], proof.LROpp[0].ID) copy(dataFiatShamir[len(spr.Public)+1][:], proof.LROpp[1].ID) @@ -164,7 +165,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen // alpha.SetUint64(11) evaluationQkCompleteDomainBigBitReversed := make([]fr.Element, pk.Domain[1].Cardinality) - copy(evaluationQkCompleteDomainBigBitReversed, fullWitness[:len(spr.Public)]) + copy(evaluationQkCompleteDomainBigBitReversed, fw[:len(spr.Public)]) copy(evaluationQkCompleteDomainBigBitReversed[len(spr.Public):], pk.LQkIncompleteDomainSmall[len(spr.Public):]) pk.Domain[0].FFTInverse(evaluationQkCompleteDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) fft.BitReverse(evaluationQkCompleteDomainBigBitReversed[:pk.Domain[0].Cardinality]) @@ -586,41 +587,6 @@ func computeBlindedZCanonical(l, r, o []fr.Element, pk *ProvingKey, beta, gamma } -// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. -// solution = [ public | secret | internal ] -func evaluateLROSmallDomain(spr *cs.SparseR1CS, pk *ProvingKey, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { - - s := int(pk.Domain[0].Cardinality) - - var l, r, o []fr.Element - l = make([]fr.Element, s) - r = make([]fr.Element, s) - o = make([]fr.Element, s) - s0 := solution[0] - - for i := 0; i < len(spr.Public); i++ { // placeholders - l[i] = solution[i] - r[i] = s0 - o[i] = s0 - } - offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // constraints - l[offset+i] = solution[spr.Constraints[i].L.WireID()] - r[offset+i] = solution[spr.Constraints[i].R.WireID()] - o[offset+i] = solution[spr.Constraints[i].O.WireID()] - } - offset += len(spr.Constraints) - - for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) - l[offset+i] = s0 - r[offset+i] = s0 - o[offset+i] = s0 - } - - return l, r, o - -} - // computeBlindedLROCanonical // l, r, o in canonical basis with blinding func computeBlindedLROCanonical( diff --git a/internal/backend/bls12-381/groth16/prove.go b/internal/backend/bls12-381/groth16/prove.go index 4d39b25160..0baec7df2e 100644 --- a/internal/backend/bls12-381/groth16/prove.go +++ b/internal/backend/bls12-381/groth16/prove.go @@ -23,7 +23,9 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/fft" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint/bls12-381" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" "math/big" @@ -51,22 +53,20 @@ func (proof *Proof) CurveID() ecc.ID { } // Prove generates the proof of knowledge of a r1cs with full witness (secret + public part). -func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness fr.Vector, opt backend.ProverConfig) (*Proof, error) { - // TODO @gbotrel witness size check is done by R1CS, doesn't mean we shouldn't sanitize here. - // if len(witness) != r1cs.NbPublicVariables-1+r1cs.NbSecretVariables { - // return nil, fmt.Errorf("invalid witness size, got %d, expected %d = %d (public) + %d (secret)", len(witness), r1cs.NbPublicVariables-1+r1cs.NbSecretVariables, r1cs.NbPublicVariables, r1cs.NbSecretVariables) - // } +func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { + opt, err := backend.NewProverConfig(opts...) + if err != nil { + return nil, err + } log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", len(r1cs.Constraints)).Str("backend", "groth16").Logger() - // solve the R1CS and compute the a, b, c vectors - a := make([]fr.Element, len(r1cs.Constraints), pk.Domain.Cardinality) - b := make([]fr.Element, len(r1cs.Constraints), pk.Domain.Cardinality) - c := make([]fr.Element, len(r1cs.Constraints), pk.Domain.Cardinality) - proof := &Proof{} + + solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] + if r1cs.CommitmentInfo.Is() { - opt.HintFunctions[r1cs.CommitmentInfo.HintID] = func(_ *big.Int, in []*big.Int, out []*big.Int) error { + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo.HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function if len(in) != r1cs.CommitmentInfo.NbCommitted() { // TODO: Remove @@ -87,36 +87,29 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness fr.Vector, opt backend.ProverC var res fr.Element res, err = solveCommitmentWire(&r1cs.CommitmentInfo, &proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) - res.BigInt(out[0]) //Perf-TODO: Regular (non-mont) hashToField to obviate this conversion? + res.BigInt(out[0]) return err - } + })) } - var wireValues []fr.Element - var err error - if wireValues, err = r1cs.Solve(witness, a, b, c, opt); err != nil { - if !opt.Force { - return nil, err - } else { - // we need to fill wireValues with random values else multi exps don't do much - var r fr.Element - _, _ = r.SetRandom() - for i := r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables(); i < len(wireValues); i++ { - wireValues[i] = r - r.Double(&r) - } - } + _solution, err := r1cs.Solve(fullWitness, solverOpts...) + if err != nil { + return nil, err } + + solution := _solution.(*cs.R1CSSolution) + wireValues := []fr.Element(solution.W) + start := time.Now() // H (witness reduction / FFT part) var h []fr.Element chHDone := make(chan struct{}, 1) go func() { - h = computeH(a, b, c, &pk.Domain) - a = nil - b = nil - c = nil + h = computeH(solution.A, solution.B, solution.C, &pk.Domain) + solution.A = nil + solution.B = nil + solution.C = nil chHDone <- struct{}{} }() @@ -345,7 +338,7 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { den.Sub(&den, &one).Inverse(&den) // h = ifft_coset(ca o cb - cc) - // reusing a to avoid unecessary memalloc + // reusing a to avoid unnecessary memory allocation utils.Parallelize(n, func(start, end int) { for i := start; i < end; i++ { a[i].Mul(&a[i], &b[i]). diff --git a/internal/backend/bls12-381/plonk/prove.go b/internal/backend/bls12-381/plonk/prove.go index 8d1402e02f..98267ceee0 100644 --- a/internal/backend/bls12-381/plonk/prove.go +++ b/internal/backend/bls12-381/plonk/prove.go @@ -23,6 +23,8 @@ import ( "sync" "time" + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" curve "github.com/consensys/gnark-crypto/ecc/bls12-381" @@ -58,10 +60,15 @@ type Proof struct { ZShiftedOpening kzg.OpeningProof } -// Prove from the public data -func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backend.ProverConfig) (*Proof, error) { +func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", len(spr.Constraints)).Str("backend", "plonk").Logger() + + opt, err := backend.NewProverConfig(opts...) + if err != nil { + return nil, err + } + start := time.Now() // pick a hash function that will be used to derive the challenges hFunc := sha256.New() @@ -72,25 +79,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen // result proof := &Proof{} - // compute the constraint system solution - var solution []fr.Element - var err error - if solution, err = spr.Solve(fullWitness, opt); err != nil { - if !opt.Force { - return nil, err - } else { - // we need to fill solution with random values - var r fr.Element - _, _ = r.SetRandom() - for i := len(spr.Public) + len(spr.Secret); i < len(solution); i++ { - solution[i] = r - r.Double(&r) - } - } - } - // query l, r, o in Lagrange basis, not blinded - evaluationLDomainSmall, evaluationRDomainSmall, evaluationODomainSmall := evaluateLROSmallDomain(spr, pk, solution) + _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) + if err != nil { + return nil, err + } + solution := _solution.(*cs.SparseR1CSSolution) + evaluationLDomainSmall := []fr.Element(solution.L) + evaluationRDomainSmall := []fr.Element(solution.R) + evaluationODomainSmall := []fr.Element(solution.O) lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} liop := iop.NewPolynomial(&evaluationLDomainSmall, lagReg) @@ -112,10 +109,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen return nil, err } + fw, ok := fullWitness.Vector().(fr.Vector) + if !ok { + return nil, witness.ErrInvalidWitness + } + // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *pk.Vk, fullWitness[:len(spr.Public)]); err != nil { + if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)]); err != nil { return nil, err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) @@ -167,7 +169,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen // compute qk in canonical basis, completed with the public inputs qkCompletedCanonical := make([]fr.Element, pk.Domain[0].Cardinality) - copy(qkCompletedCanonical, fullWitness[:len(spr.Public)]) + copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], pk.LQk[len(spr.Public):]) pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -498,41 +500,6 @@ func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error return err1 } -// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. -// solution = [ public | secret | internal ] -func evaluateLROSmallDomain(spr *cs.SparseR1CS, pk *ProvingKey, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { - - s := int(pk.Domain[0].Cardinality) - - var l, r, o []fr.Element - l = make([]fr.Element, s) - r = make([]fr.Element, s) - o = make([]fr.Element, s) - s0 := solution[0] - - for i := 0; i < len(spr.Public); i++ { // placeholders - l[i] = solution[i] - r[i] = s0 - o[i] = s0 - } - offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // constraints - l[offset+i] = solution[spr.Constraints[i].L.WireID()] - r[offset+i] = solution[spr.Constraints[i].R.WireID()] - o[offset+i] = solution[spr.Constraints[i].O.WireID()] - } - offset += len(spr.Constraints) - - for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) - l[offset+i] = s0 - r[offset+i] = s0 - o[offset+i] = s0 - } - - return l, r, o - -} - // computeLinearizedPolynomial computes the linearized polynomial in canonical basis. // The purpose is to commit and open all in one ql, qr, qm, qo, qk. // * lZeta, rZeta, oZeta are the evaluation of l, r, o at zeta diff --git a/internal/backend/bls12-381/plonkfri/prove.go b/internal/backend/bls12-381/plonkfri/prove.go index f0b7a2414a..3823ed3b26 100644 --- a/internal/backend/bls12-381/plonkfri/prove.go +++ b/internal/backend/bls12-381/plonkfri/prove.go @@ -22,6 +22,8 @@ import ( "math/bits" "runtime" + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/fft" @@ -36,7 +38,6 @@ import ( ) type Proof struct { - // commitments to the solution vectors LROpp [3]fri.ProofOfProximity @@ -67,7 +68,11 @@ type Proof struct { OpeningsId1Id2Id3mp [3]fri.OpeningProof } -func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backend.ProverConfig) (*Proof, error) { +func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { + opt, err := backend.NewProverConfig(opts...) + if err != nil { + return nil, err + } var proof Proof @@ -78,23 +83,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") // 1 - solve the system - var solution []fr.Element - var err error - if solution, err = spr.Solve(fullWitness, opt); err != nil { - if !opt.Force { - return nil, err - } else { - // we need to fill solution with random values - var r fr.Element - _, _ = r.SetRandom() - for i := len(spr.Public) + len(spr.Secret); i < len(solution); i++ { - solution[i] = r - r.Double(&r) - } - } + _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) + if err != nil { + return nil, err } - evaluationLDomainSmall, evaluationRDomainSmall, evaluationODomainSmall := evaluateLROSmallDomain(spr, pk, solution) + solution := _solution.(*cs.SparseR1CSSolution) + evaluationLDomainSmall := []fr.Element(solution.L) + evaluationRDomainSmall := []fr.Element(solution.R) + evaluationODomainSmall := []fr.Element(solution.O) // 2 - commit to lro blindedLCanonical, blindedRCanonical, blindedOCanonical, err := computeBlindedLROCanonical( @@ -119,9 +116,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen } // 3 - compute Z, challenges are derived using L, R, O + public inputs + fw, ok := fullWitness.Vector().(fr.Vector) + if !ok { + return nil, witness.ErrInvalidWitness + } dataFiatShamir := make([][fr.Bytes]byte, len(spr.Public)+3) for i := 0; i < len(spr.Public); i++ { - copy(dataFiatShamir[i][:], fullWitness[i].Marshal()) + copy(dataFiatShamir[i][:], fw[i].Marshal()) } copy(dataFiatShamir[len(spr.Public)][:], proof.LROpp[0].ID) copy(dataFiatShamir[len(spr.Public)+1][:], proof.LROpp[1].ID) @@ -164,7 +165,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen // alpha.SetUint64(11) evaluationQkCompleteDomainBigBitReversed := make([]fr.Element, pk.Domain[1].Cardinality) - copy(evaluationQkCompleteDomainBigBitReversed, fullWitness[:len(spr.Public)]) + copy(evaluationQkCompleteDomainBigBitReversed, fw[:len(spr.Public)]) copy(evaluationQkCompleteDomainBigBitReversed[len(spr.Public):], pk.LQkIncompleteDomainSmall[len(spr.Public):]) pk.Domain[0].FFTInverse(evaluationQkCompleteDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) fft.BitReverse(evaluationQkCompleteDomainBigBitReversed[:pk.Domain[0].Cardinality]) @@ -586,41 +587,6 @@ func computeBlindedZCanonical(l, r, o []fr.Element, pk *ProvingKey, beta, gamma } -// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. -// solution = [ public | secret | internal ] -func evaluateLROSmallDomain(spr *cs.SparseR1CS, pk *ProvingKey, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { - - s := int(pk.Domain[0].Cardinality) - - var l, r, o []fr.Element - l = make([]fr.Element, s) - r = make([]fr.Element, s) - o = make([]fr.Element, s) - s0 := solution[0] - - for i := 0; i < len(spr.Public); i++ { // placeholders - l[i] = solution[i] - r[i] = s0 - o[i] = s0 - } - offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // constraints - l[offset+i] = solution[spr.Constraints[i].L.WireID()] - r[offset+i] = solution[spr.Constraints[i].R.WireID()] - o[offset+i] = solution[spr.Constraints[i].O.WireID()] - } - offset += len(spr.Constraints) - - for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) - l[offset+i] = s0 - r[offset+i] = s0 - o[offset+i] = s0 - } - - return l, r, o - -} - // computeBlindedLROCanonical // l, r, o in canonical basis with blinding func computeBlindedLROCanonical( diff --git a/internal/backend/bls24-315/groth16/prove.go b/internal/backend/bls24-315/groth16/prove.go index c7fa4a254d..ecc9fa3ce7 100644 --- a/internal/backend/bls24-315/groth16/prove.go +++ b/internal/backend/bls24-315/groth16/prove.go @@ -23,7 +23,9 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/fft" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint/bls24-315" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" "math/big" @@ -51,22 +53,20 @@ func (proof *Proof) CurveID() ecc.ID { } // Prove generates the proof of knowledge of a r1cs with full witness (secret + public part). -func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness fr.Vector, opt backend.ProverConfig) (*Proof, error) { - // TODO @gbotrel witness size check is done by R1CS, doesn't mean we shouldn't sanitize here. - // if len(witness) != r1cs.NbPublicVariables-1+r1cs.NbSecretVariables { - // return nil, fmt.Errorf("invalid witness size, got %d, expected %d = %d (public) + %d (secret)", len(witness), r1cs.NbPublicVariables-1+r1cs.NbSecretVariables, r1cs.NbPublicVariables, r1cs.NbSecretVariables) - // } +func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { + opt, err := backend.NewProverConfig(opts...) + if err != nil { + return nil, err + } log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", len(r1cs.Constraints)).Str("backend", "groth16").Logger() - // solve the R1CS and compute the a, b, c vectors - a := make([]fr.Element, len(r1cs.Constraints), pk.Domain.Cardinality) - b := make([]fr.Element, len(r1cs.Constraints), pk.Domain.Cardinality) - c := make([]fr.Element, len(r1cs.Constraints), pk.Domain.Cardinality) - proof := &Proof{} + + solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] + if r1cs.CommitmentInfo.Is() { - opt.HintFunctions[r1cs.CommitmentInfo.HintID] = func(_ *big.Int, in []*big.Int, out []*big.Int) error { + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo.HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function if len(in) != r1cs.CommitmentInfo.NbCommitted() { // TODO: Remove @@ -87,36 +87,29 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness fr.Vector, opt backend.ProverC var res fr.Element res, err = solveCommitmentWire(&r1cs.CommitmentInfo, &proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) - res.BigInt(out[0]) //Perf-TODO: Regular (non-mont) hashToField to obviate this conversion? + res.BigInt(out[0]) return err - } + })) } - var wireValues []fr.Element - var err error - if wireValues, err = r1cs.Solve(witness, a, b, c, opt); err != nil { - if !opt.Force { - return nil, err - } else { - // we need to fill wireValues with random values else multi exps don't do much - var r fr.Element - _, _ = r.SetRandom() - for i := r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables(); i < len(wireValues); i++ { - wireValues[i] = r - r.Double(&r) - } - } + _solution, err := r1cs.Solve(fullWitness, solverOpts...) + if err != nil { + return nil, err } + + solution := _solution.(*cs.R1CSSolution) + wireValues := []fr.Element(solution.W) + start := time.Now() // H (witness reduction / FFT part) var h []fr.Element chHDone := make(chan struct{}, 1) go func() { - h = computeH(a, b, c, &pk.Domain) - a = nil - b = nil - c = nil + h = computeH(solution.A, solution.B, solution.C, &pk.Domain) + solution.A = nil + solution.B = nil + solution.C = nil chHDone <- struct{}{} }() @@ -345,7 +338,7 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { den.Sub(&den, &one).Inverse(&den) // h = ifft_coset(ca o cb - cc) - // reusing a to avoid unecessary memalloc + // reusing a to avoid unnecessary memory allocation utils.Parallelize(n, func(start, end int) { for i := start; i < end; i++ { a[i].Mul(&a[i], &b[i]). diff --git a/internal/backend/bls24-315/plonk/prove.go b/internal/backend/bls24-315/plonk/prove.go index eccaefd544..dcff52621b 100644 --- a/internal/backend/bls24-315/plonk/prove.go +++ b/internal/backend/bls24-315/plonk/prove.go @@ -23,6 +23,8 @@ import ( "sync" "time" + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" curve "github.com/consensys/gnark-crypto/ecc/bls24-315" @@ -58,10 +60,15 @@ type Proof struct { ZShiftedOpening kzg.OpeningProof } -// Prove from the public data -func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backend.ProverConfig) (*Proof, error) { +func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", len(spr.Constraints)).Str("backend", "plonk").Logger() + + opt, err := backend.NewProverConfig(opts...) + if err != nil { + return nil, err + } + start := time.Now() // pick a hash function that will be used to derive the challenges hFunc := sha256.New() @@ -72,25 +79,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen // result proof := &Proof{} - // compute the constraint system solution - var solution []fr.Element - var err error - if solution, err = spr.Solve(fullWitness, opt); err != nil { - if !opt.Force { - return nil, err - } else { - // we need to fill solution with random values - var r fr.Element - _, _ = r.SetRandom() - for i := len(spr.Public) + len(spr.Secret); i < len(solution); i++ { - solution[i] = r - r.Double(&r) - } - } - } - // query l, r, o in Lagrange basis, not blinded - evaluationLDomainSmall, evaluationRDomainSmall, evaluationODomainSmall := evaluateLROSmallDomain(spr, pk, solution) + _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) + if err != nil { + return nil, err + } + solution := _solution.(*cs.SparseR1CSSolution) + evaluationLDomainSmall := []fr.Element(solution.L) + evaluationRDomainSmall := []fr.Element(solution.R) + evaluationODomainSmall := []fr.Element(solution.O) lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} liop := iop.NewPolynomial(&evaluationLDomainSmall, lagReg) @@ -112,10 +109,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen return nil, err } + fw, ok := fullWitness.Vector().(fr.Vector) + if !ok { + return nil, witness.ErrInvalidWitness + } + // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *pk.Vk, fullWitness[:len(spr.Public)]); err != nil { + if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)]); err != nil { return nil, err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) @@ -167,7 +169,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen // compute qk in canonical basis, completed with the public inputs qkCompletedCanonical := make([]fr.Element, pk.Domain[0].Cardinality) - copy(qkCompletedCanonical, fullWitness[:len(spr.Public)]) + copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], pk.LQk[len(spr.Public):]) pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -498,41 +500,6 @@ func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error return err1 } -// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. -// solution = [ public | secret | internal ] -func evaluateLROSmallDomain(spr *cs.SparseR1CS, pk *ProvingKey, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { - - s := int(pk.Domain[0].Cardinality) - - var l, r, o []fr.Element - l = make([]fr.Element, s) - r = make([]fr.Element, s) - o = make([]fr.Element, s) - s0 := solution[0] - - for i := 0; i < len(spr.Public); i++ { // placeholders - l[i] = solution[i] - r[i] = s0 - o[i] = s0 - } - offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // constraints - l[offset+i] = solution[spr.Constraints[i].L.WireID()] - r[offset+i] = solution[spr.Constraints[i].R.WireID()] - o[offset+i] = solution[spr.Constraints[i].O.WireID()] - } - offset += len(spr.Constraints) - - for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) - l[offset+i] = s0 - r[offset+i] = s0 - o[offset+i] = s0 - } - - return l, r, o - -} - // computeLinearizedPolynomial computes the linearized polynomial in canonical basis. // The purpose is to commit and open all in one ql, qr, qm, qo, qk. // * lZeta, rZeta, oZeta are the evaluation of l, r, o at zeta diff --git a/internal/backend/bls24-315/plonkfri/prove.go b/internal/backend/bls24-315/plonkfri/prove.go index a73d5afac3..5d7f385ea1 100644 --- a/internal/backend/bls24-315/plonkfri/prove.go +++ b/internal/backend/bls24-315/plonkfri/prove.go @@ -22,6 +22,8 @@ import ( "math/bits" "runtime" + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/fft" @@ -36,7 +38,6 @@ import ( ) type Proof struct { - // commitments to the solution vectors LROpp [3]fri.ProofOfProximity @@ -67,7 +68,11 @@ type Proof struct { OpeningsId1Id2Id3mp [3]fri.OpeningProof } -func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backend.ProverConfig) (*Proof, error) { +func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { + opt, err := backend.NewProverConfig(opts...) + if err != nil { + return nil, err + } var proof Proof @@ -78,23 +83,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") // 1 - solve the system - var solution []fr.Element - var err error - if solution, err = spr.Solve(fullWitness, opt); err != nil { - if !opt.Force { - return nil, err - } else { - // we need to fill solution with random values - var r fr.Element - _, _ = r.SetRandom() - for i := len(spr.Public) + len(spr.Secret); i < len(solution); i++ { - solution[i] = r - r.Double(&r) - } - } + _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) + if err != nil { + return nil, err } - evaluationLDomainSmall, evaluationRDomainSmall, evaluationODomainSmall := evaluateLROSmallDomain(spr, pk, solution) + solution := _solution.(*cs.SparseR1CSSolution) + evaluationLDomainSmall := []fr.Element(solution.L) + evaluationRDomainSmall := []fr.Element(solution.R) + evaluationODomainSmall := []fr.Element(solution.O) // 2 - commit to lro blindedLCanonical, blindedRCanonical, blindedOCanonical, err := computeBlindedLROCanonical( @@ -119,9 +116,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen } // 3 - compute Z, challenges are derived using L, R, O + public inputs + fw, ok := fullWitness.Vector().(fr.Vector) + if !ok { + return nil, witness.ErrInvalidWitness + } dataFiatShamir := make([][fr.Bytes]byte, len(spr.Public)+3) for i := 0; i < len(spr.Public); i++ { - copy(dataFiatShamir[i][:], fullWitness[i].Marshal()) + copy(dataFiatShamir[i][:], fw[i].Marshal()) } copy(dataFiatShamir[len(spr.Public)][:], proof.LROpp[0].ID) copy(dataFiatShamir[len(spr.Public)+1][:], proof.LROpp[1].ID) @@ -164,7 +165,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen // alpha.SetUint64(11) evaluationQkCompleteDomainBigBitReversed := make([]fr.Element, pk.Domain[1].Cardinality) - copy(evaluationQkCompleteDomainBigBitReversed, fullWitness[:len(spr.Public)]) + copy(evaluationQkCompleteDomainBigBitReversed, fw[:len(spr.Public)]) copy(evaluationQkCompleteDomainBigBitReversed[len(spr.Public):], pk.LQkIncompleteDomainSmall[len(spr.Public):]) pk.Domain[0].FFTInverse(evaluationQkCompleteDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) fft.BitReverse(evaluationQkCompleteDomainBigBitReversed[:pk.Domain[0].Cardinality]) @@ -586,41 +587,6 @@ func computeBlindedZCanonical(l, r, o []fr.Element, pk *ProvingKey, beta, gamma } -// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. -// solution = [ public | secret | internal ] -func evaluateLROSmallDomain(spr *cs.SparseR1CS, pk *ProvingKey, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { - - s := int(pk.Domain[0].Cardinality) - - var l, r, o []fr.Element - l = make([]fr.Element, s) - r = make([]fr.Element, s) - o = make([]fr.Element, s) - s0 := solution[0] - - for i := 0; i < len(spr.Public); i++ { // placeholders - l[i] = solution[i] - r[i] = s0 - o[i] = s0 - } - offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // constraints - l[offset+i] = solution[spr.Constraints[i].L.WireID()] - r[offset+i] = solution[spr.Constraints[i].R.WireID()] - o[offset+i] = solution[spr.Constraints[i].O.WireID()] - } - offset += len(spr.Constraints) - - for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) - l[offset+i] = s0 - r[offset+i] = s0 - o[offset+i] = s0 - } - - return l, r, o - -} - // computeBlindedLROCanonical // l, r, o in canonical basis with blinding func computeBlindedLROCanonical( diff --git a/internal/backend/bls24-317/groth16/prove.go b/internal/backend/bls24-317/groth16/prove.go index 9e5119930f..9242f4a061 100644 --- a/internal/backend/bls24-317/groth16/prove.go +++ b/internal/backend/bls24-317/groth16/prove.go @@ -23,7 +23,9 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/fft" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint/bls24-317" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" "math/big" @@ -51,22 +53,20 @@ func (proof *Proof) CurveID() ecc.ID { } // Prove generates the proof of knowledge of a r1cs with full witness (secret + public part). -func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness fr.Vector, opt backend.ProverConfig) (*Proof, error) { - // TODO @gbotrel witness size check is done by R1CS, doesn't mean we shouldn't sanitize here. - // if len(witness) != r1cs.NbPublicVariables-1+r1cs.NbSecretVariables { - // return nil, fmt.Errorf("invalid witness size, got %d, expected %d = %d (public) + %d (secret)", len(witness), r1cs.NbPublicVariables-1+r1cs.NbSecretVariables, r1cs.NbPublicVariables, r1cs.NbSecretVariables) - // } +func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { + opt, err := backend.NewProverConfig(opts...) + if err != nil { + return nil, err + } log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", len(r1cs.Constraints)).Str("backend", "groth16").Logger() - // solve the R1CS and compute the a, b, c vectors - a := make([]fr.Element, len(r1cs.Constraints), pk.Domain.Cardinality) - b := make([]fr.Element, len(r1cs.Constraints), pk.Domain.Cardinality) - c := make([]fr.Element, len(r1cs.Constraints), pk.Domain.Cardinality) - proof := &Proof{} + + solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] + if r1cs.CommitmentInfo.Is() { - opt.HintFunctions[r1cs.CommitmentInfo.HintID] = func(_ *big.Int, in []*big.Int, out []*big.Int) error { + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo.HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function if len(in) != r1cs.CommitmentInfo.NbCommitted() { // TODO: Remove @@ -87,36 +87,29 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness fr.Vector, opt backend.ProverC var res fr.Element res, err = solveCommitmentWire(&r1cs.CommitmentInfo, &proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) - res.BigInt(out[0]) //Perf-TODO: Regular (non-mont) hashToField to obviate this conversion? + res.BigInt(out[0]) return err - } + })) } - var wireValues []fr.Element - var err error - if wireValues, err = r1cs.Solve(witness, a, b, c, opt); err != nil { - if !opt.Force { - return nil, err - } else { - // we need to fill wireValues with random values else multi exps don't do much - var r fr.Element - _, _ = r.SetRandom() - for i := r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables(); i < len(wireValues); i++ { - wireValues[i] = r - r.Double(&r) - } - } + _solution, err := r1cs.Solve(fullWitness, solverOpts...) + if err != nil { + return nil, err } + + solution := _solution.(*cs.R1CSSolution) + wireValues := []fr.Element(solution.W) + start := time.Now() // H (witness reduction / FFT part) var h []fr.Element chHDone := make(chan struct{}, 1) go func() { - h = computeH(a, b, c, &pk.Domain) - a = nil - b = nil - c = nil + h = computeH(solution.A, solution.B, solution.C, &pk.Domain) + solution.A = nil + solution.B = nil + solution.C = nil chHDone <- struct{}{} }() @@ -345,7 +338,7 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { den.Sub(&den, &one).Inverse(&den) // h = ifft_coset(ca o cb - cc) - // reusing a to avoid unecessary memalloc + // reusing a to avoid unnecessary memory allocation utils.Parallelize(n, func(start, end int) { for i := start; i < end; i++ { a[i].Mul(&a[i], &b[i]). diff --git a/internal/backend/bls24-317/plonk/prove.go b/internal/backend/bls24-317/plonk/prove.go index 162b2a6e28..400232aead 100644 --- a/internal/backend/bls24-317/plonk/prove.go +++ b/internal/backend/bls24-317/plonk/prove.go @@ -23,6 +23,8 @@ import ( "sync" "time" + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" curve "github.com/consensys/gnark-crypto/ecc/bls24-317" @@ -58,10 +60,15 @@ type Proof struct { ZShiftedOpening kzg.OpeningProof } -// Prove from the public data -func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backend.ProverConfig) (*Proof, error) { +func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", len(spr.Constraints)).Str("backend", "plonk").Logger() + + opt, err := backend.NewProverConfig(opts...) + if err != nil { + return nil, err + } + start := time.Now() // pick a hash function that will be used to derive the challenges hFunc := sha256.New() @@ -72,25 +79,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen // result proof := &Proof{} - // compute the constraint system solution - var solution []fr.Element - var err error - if solution, err = spr.Solve(fullWitness, opt); err != nil { - if !opt.Force { - return nil, err - } else { - // we need to fill solution with random values - var r fr.Element - _, _ = r.SetRandom() - for i := len(spr.Public) + len(spr.Secret); i < len(solution); i++ { - solution[i] = r - r.Double(&r) - } - } - } - // query l, r, o in Lagrange basis, not blinded - evaluationLDomainSmall, evaluationRDomainSmall, evaluationODomainSmall := evaluateLROSmallDomain(spr, pk, solution) + _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) + if err != nil { + return nil, err + } + solution := _solution.(*cs.SparseR1CSSolution) + evaluationLDomainSmall := []fr.Element(solution.L) + evaluationRDomainSmall := []fr.Element(solution.R) + evaluationODomainSmall := []fr.Element(solution.O) lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} liop := iop.NewPolynomial(&evaluationLDomainSmall, lagReg) @@ -112,10 +109,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen return nil, err } + fw, ok := fullWitness.Vector().(fr.Vector) + if !ok { + return nil, witness.ErrInvalidWitness + } + // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *pk.Vk, fullWitness[:len(spr.Public)]); err != nil { + if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)]); err != nil { return nil, err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) @@ -167,7 +169,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen // compute qk in canonical basis, completed with the public inputs qkCompletedCanonical := make([]fr.Element, pk.Domain[0].Cardinality) - copy(qkCompletedCanonical, fullWitness[:len(spr.Public)]) + copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], pk.LQk[len(spr.Public):]) pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -498,41 +500,6 @@ func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error return err1 } -// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. -// solution = [ public | secret | internal ] -func evaluateLROSmallDomain(spr *cs.SparseR1CS, pk *ProvingKey, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { - - s := int(pk.Domain[0].Cardinality) - - var l, r, o []fr.Element - l = make([]fr.Element, s) - r = make([]fr.Element, s) - o = make([]fr.Element, s) - s0 := solution[0] - - for i := 0; i < len(spr.Public); i++ { // placeholders - l[i] = solution[i] - r[i] = s0 - o[i] = s0 - } - offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // constraints - l[offset+i] = solution[spr.Constraints[i].L.WireID()] - r[offset+i] = solution[spr.Constraints[i].R.WireID()] - o[offset+i] = solution[spr.Constraints[i].O.WireID()] - } - offset += len(spr.Constraints) - - for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) - l[offset+i] = s0 - r[offset+i] = s0 - o[offset+i] = s0 - } - - return l, r, o - -} - // computeLinearizedPolynomial computes the linearized polynomial in canonical basis. // The purpose is to commit and open all in one ql, qr, qm, qo, qk. // * lZeta, rZeta, oZeta are the evaluation of l, r, o at zeta diff --git a/internal/backend/bls24-317/plonkfri/prove.go b/internal/backend/bls24-317/plonkfri/prove.go index 5dfebe9c2f..409d66b34e 100644 --- a/internal/backend/bls24-317/plonkfri/prove.go +++ b/internal/backend/bls24-317/plonkfri/prove.go @@ -22,6 +22,8 @@ import ( "math/bits" "runtime" + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/fft" @@ -36,7 +38,6 @@ import ( ) type Proof struct { - // commitments to the solution vectors LROpp [3]fri.ProofOfProximity @@ -67,7 +68,11 @@ type Proof struct { OpeningsId1Id2Id3mp [3]fri.OpeningProof } -func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backend.ProverConfig) (*Proof, error) { +func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { + opt, err := backend.NewProverConfig(opts...) + if err != nil { + return nil, err + } var proof Proof @@ -78,23 +83,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") // 1 - solve the system - var solution []fr.Element - var err error - if solution, err = spr.Solve(fullWitness, opt); err != nil { - if !opt.Force { - return nil, err - } else { - // we need to fill solution with random values - var r fr.Element - _, _ = r.SetRandom() - for i := len(spr.Public) + len(spr.Secret); i < len(solution); i++ { - solution[i] = r - r.Double(&r) - } - } + _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) + if err != nil { + return nil, err } - evaluationLDomainSmall, evaluationRDomainSmall, evaluationODomainSmall := evaluateLROSmallDomain(spr, pk, solution) + solution := _solution.(*cs.SparseR1CSSolution) + evaluationLDomainSmall := []fr.Element(solution.L) + evaluationRDomainSmall := []fr.Element(solution.R) + evaluationODomainSmall := []fr.Element(solution.O) // 2 - commit to lro blindedLCanonical, blindedRCanonical, blindedOCanonical, err := computeBlindedLROCanonical( @@ -119,9 +116,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen } // 3 - compute Z, challenges are derived using L, R, O + public inputs + fw, ok := fullWitness.Vector().(fr.Vector) + if !ok { + return nil, witness.ErrInvalidWitness + } dataFiatShamir := make([][fr.Bytes]byte, len(spr.Public)+3) for i := 0; i < len(spr.Public); i++ { - copy(dataFiatShamir[i][:], fullWitness[i].Marshal()) + copy(dataFiatShamir[i][:], fw[i].Marshal()) } copy(dataFiatShamir[len(spr.Public)][:], proof.LROpp[0].ID) copy(dataFiatShamir[len(spr.Public)+1][:], proof.LROpp[1].ID) @@ -164,7 +165,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen // alpha.SetUint64(11) evaluationQkCompleteDomainBigBitReversed := make([]fr.Element, pk.Domain[1].Cardinality) - copy(evaluationQkCompleteDomainBigBitReversed, fullWitness[:len(spr.Public)]) + copy(evaluationQkCompleteDomainBigBitReversed, fw[:len(spr.Public)]) copy(evaluationQkCompleteDomainBigBitReversed[len(spr.Public):], pk.LQkIncompleteDomainSmall[len(spr.Public):]) pk.Domain[0].FFTInverse(evaluationQkCompleteDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) fft.BitReverse(evaluationQkCompleteDomainBigBitReversed[:pk.Domain[0].Cardinality]) @@ -586,41 +587,6 @@ func computeBlindedZCanonical(l, r, o []fr.Element, pk *ProvingKey, beta, gamma } -// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. -// solution = [ public | secret | internal ] -func evaluateLROSmallDomain(spr *cs.SparseR1CS, pk *ProvingKey, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { - - s := int(pk.Domain[0].Cardinality) - - var l, r, o []fr.Element - l = make([]fr.Element, s) - r = make([]fr.Element, s) - o = make([]fr.Element, s) - s0 := solution[0] - - for i := 0; i < len(spr.Public); i++ { // placeholders - l[i] = solution[i] - r[i] = s0 - o[i] = s0 - } - offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // constraints - l[offset+i] = solution[spr.Constraints[i].L.WireID()] - r[offset+i] = solution[spr.Constraints[i].R.WireID()] - o[offset+i] = solution[spr.Constraints[i].O.WireID()] - } - offset += len(spr.Constraints) - - for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) - l[offset+i] = s0 - r[offset+i] = s0 - o[offset+i] = s0 - } - - return l, r, o - -} - // computeBlindedLROCanonical // l, r, o in canonical basis with blinding func computeBlindedLROCanonical( diff --git a/internal/backend/bn254/groth16/prove.go b/internal/backend/bn254/groth16/prove.go index ed5bcf588b..7377a93bba 100644 --- a/internal/backend/bn254/groth16/prove.go +++ b/internal/backend/bn254/groth16/prove.go @@ -23,7 +23,9 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint/bn254" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" "math/big" @@ -51,22 +53,20 @@ func (proof *Proof) CurveID() ecc.ID { } // Prove generates the proof of knowledge of a r1cs with full witness (secret + public part). -func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness fr.Vector, opt backend.ProverConfig) (*Proof, error) { - // TODO @gbotrel witness size check is done by R1CS, doesn't mean we shouldn't sanitize here. - // if len(witness) != r1cs.NbPublicVariables-1+r1cs.NbSecretVariables { - // return nil, fmt.Errorf("invalid witness size, got %d, expected %d = %d (public) + %d (secret)", len(witness), r1cs.NbPublicVariables-1+r1cs.NbSecretVariables, r1cs.NbPublicVariables, r1cs.NbSecretVariables) - // } +func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { + opt, err := backend.NewProverConfig(opts...) + if err != nil { + return nil, err + } log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", len(r1cs.Constraints)).Str("backend", "groth16").Logger() - // solve the R1CS and compute the a, b, c vectors - a := make([]fr.Element, len(r1cs.Constraints), pk.Domain.Cardinality) - b := make([]fr.Element, len(r1cs.Constraints), pk.Domain.Cardinality) - c := make([]fr.Element, len(r1cs.Constraints), pk.Domain.Cardinality) - proof := &Proof{} + + solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] + if r1cs.CommitmentInfo.Is() { - opt.HintFunctions[r1cs.CommitmentInfo.HintID] = func(_ *big.Int, in []*big.Int, out []*big.Int) error { + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo.HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function if len(in) != r1cs.CommitmentInfo.NbCommitted() { // TODO: Remove @@ -87,36 +87,29 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness fr.Vector, opt backend.ProverC var res fr.Element res, err = solveCommitmentWire(&r1cs.CommitmentInfo, &proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) - res.BigInt(out[0]) //Perf-TODO: Regular (non-mont) hashToField to obviate this conversion? + res.BigInt(out[0]) return err - } + })) } - var wireValues []fr.Element - var err error - if wireValues, err = r1cs.Solve(witness, a, b, c, opt); err != nil { - if !opt.Force { - return nil, err - } else { - // we need to fill wireValues with random values else multi exps don't do much - var r fr.Element - _, _ = r.SetRandom() - for i := r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables(); i < len(wireValues); i++ { - wireValues[i] = r - r.Double(&r) - } - } + _solution, err := r1cs.Solve(fullWitness, solverOpts...) + if err != nil { + return nil, err } + + solution := _solution.(*cs.R1CSSolution) + wireValues := []fr.Element(solution.W) + start := time.Now() // H (witness reduction / FFT part) var h []fr.Element chHDone := make(chan struct{}, 1) go func() { - h = computeH(a, b, c, &pk.Domain) - a = nil - b = nil - c = nil + h = computeH(solution.A, solution.B, solution.C, &pk.Domain) + solution.A = nil + solution.B = nil + solution.C = nil chHDone <- struct{}{} }() @@ -345,7 +338,7 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { den.Sub(&den, &one).Inverse(&den) // h = ifft_coset(ca o cb - cc) - // reusing a to avoid unecessary memalloc + // reusing a to avoid unnecessary memory allocation utils.Parallelize(n, func(start, end int) { for i := start; i < end; i++ { a[i].Mul(&a[i], &b[i]). diff --git a/internal/backend/bn254/plonk/prove.go b/internal/backend/bn254/plonk/prove.go index 0f5042889d..d6e483487c 100644 --- a/internal/backend/bn254/plonk/prove.go +++ b/internal/backend/bn254/plonk/prove.go @@ -23,6 +23,8 @@ import ( "sync" "time" + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" curve "github.com/consensys/gnark-crypto/ecc/bn254" @@ -58,10 +60,15 @@ type Proof struct { ZShiftedOpening kzg.OpeningProof } -// Prove from the public data -func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backend.ProverConfig) (*Proof, error) { +func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", len(spr.Constraints)).Str("backend", "plonk").Logger() + + opt, err := backend.NewProverConfig(opts...) + if err != nil { + return nil, err + } + start := time.Now() // pick a hash function that will be used to derive the challenges hFunc := sha256.New() @@ -72,25 +79,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen // result proof := &Proof{} - // compute the constraint system solution - var solution []fr.Element - var err error - if solution, err = spr.Solve(fullWitness, opt); err != nil { - if !opt.Force { - return nil, err - } else { - // we need to fill solution with random values - var r fr.Element - _, _ = r.SetRandom() - for i := len(spr.Public) + len(spr.Secret); i < len(solution); i++ { - solution[i] = r - r.Double(&r) - } - } - } - // query l, r, o in Lagrange basis, not blinded - evaluationLDomainSmall, evaluationRDomainSmall, evaluationODomainSmall := evaluateLROSmallDomain(spr, pk, solution) + _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) + if err != nil { + return nil, err + } + solution := _solution.(*cs.SparseR1CSSolution) + evaluationLDomainSmall := []fr.Element(solution.L) + evaluationRDomainSmall := []fr.Element(solution.R) + evaluationODomainSmall := []fr.Element(solution.O) lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} liop := iop.NewPolynomial(&evaluationLDomainSmall, lagReg) @@ -112,10 +109,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen return nil, err } + fw, ok := fullWitness.Vector().(fr.Vector) + if !ok { + return nil, witness.ErrInvalidWitness + } + // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *pk.Vk, fullWitness[:len(spr.Public)]); err != nil { + if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)]); err != nil { return nil, err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) @@ -167,7 +169,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen // compute qk in canonical basis, completed with the public inputs qkCompletedCanonical := make([]fr.Element, pk.Domain[0].Cardinality) - copy(qkCompletedCanonical, fullWitness[:len(spr.Public)]) + copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], pk.LQk[len(spr.Public):]) pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -498,41 +500,6 @@ func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error return err1 } -// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. -// solution = [ public | secret | internal ] -func evaluateLROSmallDomain(spr *cs.SparseR1CS, pk *ProvingKey, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { - - s := int(pk.Domain[0].Cardinality) - - var l, r, o []fr.Element - l = make([]fr.Element, s) - r = make([]fr.Element, s) - o = make([]fr.Element, s) - s0 := solution[0] - - for i := 0; i < len(spr.Public); i++ { // placeholders - l[i] = solution[i] - r[i] = s0 - o[i] = s0 - } - offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // constraints - l[offset+i] = solution[spr.Constraints[i].L.WireID()] - r[offset+i] = solution[spr.Constraints[i].R.WireID()] - o[offset+i] = solution[spr.Constraints[i].O.WireID()] - } - offset += len(spr.Constraints) - - for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) - l[offset+i] = s0 - r[offset+i] = s0 - o[offset+i] = s0 - } - - return l, r, o - -} - // computeLinearizedPolynomial computes the linearized polynomial in canonical basis. // The purpose is to commit and open all in one ql, qr, qm, qo, qk. // * lZeta, rZeta, oZeta are the evaluation of l, r, o at zeta diff --git a/internal/backend/bn254/plonkfri/prove.go b/internal/backend/bn254/plonkfri/prove.go index c4465d7ab4..1cb0e6fbc6 100644 --- a/internal/backend/bn254/plonkfri/prove.go +++ b/internal/backend/bn254/plonkfri/prove.go @@ -22,6 +22,8 @@ import ( "math/bits" "runtime" + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" @@ -36,7 +38,6 @@ import ( ) type Proof struct { - // commitments to the solution vectors LROpp [3]fri.ProofOfProximity @@ -67,7 +68,11 @@ type Proof struct { OpeningsId1Id2Id3mp [3]fri.OpeningProof } -func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backend.ProverConfig) (*Proof, error) { +func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { + opt, err := backend.NewProverConfig(opts...) + if err != nil { + return nil, err + } var proof Proof @@ -78,23 +83,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") // 1 - solve the system - var solution []fr.Element - var err error - if solution, err = spr.Solve(fullWitness, opt); err != nil { - if !opt.Force { - return nil, err - } else { - // we need to fill solution with random values - var r fr.Element - _, _ = r.SetRandom() - for i := len(spr.Public) + len(spr.Secret); i < len(solution); i++ { - solution[i] = r - r.Double(&r) - } - } + _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) + if err != nil { + return nil, err } - evaluationLDomainSmall, evaluationRDomainSmall, evaluationODomainSmall := evaluateLROSmallDomain(spr, pk, solution) + solution := _solution.(*cs.SparseR1CSSolution) + evaluationLDomainSmall := []fr.Element(solution.L) + evaluationRDomainSmall := []fr.Element(solution.R) + evaluationODomainSmall := []fr.Element(solution.O) // 2 - commit to lro blindedLCanonical, blindedRCanonical, blindedOCanonical, err := computeBlindedLROCanonical( @@ -119,9 +116,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen } // 3 - compute Z, challenges are derived using L, R, O + public inputs + fw, ok := fullWitness.Vector().(fr.Vector) + if !ok { + return nil, witness.ErrInvalidWitness + } dataFiatShamir := make([][fr.Bytes]byte, len(spr.Public)+3) for i := 0; i < len(spr.Public); i++ { - copy(dataFiatShamir[i][:], fullWitness[i].Marshal()) + copy(dataFiatShamir[i][:], fw[i].Marshal()) } copy(dataFiatShamir[len(spr.Public)][:], proof.LROpp[0].ID) copy(dataFiatShamir[len(spr.Public)+1][:], proof.LROpp[1].ID) @@ -164,7 +165,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen // alpha.SetUint64(11) evaluationQkCompleteDomainBigBitReversed := make([]fr.Element, pk.Domain[1].Cardinality) - copy(evaluationQkCompleteDomainBigBitReversed, fullWitness[:len(spr.Public)]) + copy(evaluationQkCompleteDomainBigBitReversed, fw[:len(spr.Public)]) copy(evaluationQkCompleteDomainBigBitReversed[len(spr.Public):], pk.LQkIncompleteDomainSmall[len(spr.Public):]) pk.Domain[0].FFTInverse(evaluationQkCompleteDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) fft.BitReverse(evaluationQkCompleteDomainBigBitReversed[:pk.Domain[0].Cardinality]) @@ -586,41 +587,6 @@ func computeBlindedZCanonical(l, r, o []fr.Element, pk *ProvingKey, beta, gamma } -// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. -// solution = [ public | secret | internal ] -func evaluateLROSmallDomain(spr *cs.SparseR1CS, pk *ProvingKey, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { - - s := int(pk.Domain[0].Cardinality) - - var l, r, o []fr.Element - l = make([]fr.Element, s) - r = make([]fr.Element, s) - o = make([]fr.Element, s) - s0 := solution[0] - - for i := 0; i < len(spr.Public); i++ { // placeholders - l[i] = solution[i] - r[i] = s0 - o[i] = s0 - } - offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // constraints - l[offset+i] = solution[spr.Constraints[i].L.WireID()] - r[offset+i] = solution[spr.Constraints[i].R.WireID()] - o[offset+i] = solution[spr.Constraints[i].O.WireID()] - } - offset += len(spr.Constraints) - - for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) - l[offset+i] = s0 - r[offset+i] = s0 - o[offset+i] = s0 - } - - return l, r, o - -} - // computeBlindedLROCanonical // l, r, o in canonical basis with blinding func computeBlindedLROCanonical( diff --git a/internal/backend/bw6-633/groth16/prove.go b/internal/backend/bw6-633/groth16/prove.go index 34178eab4b..6779247d96 100644 --- a/internal/backend/bw6-633/groth16/prove.go +++ b/internal/backend/bw6-633/groth16/prove.go @@ -23,7 +23,9 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/fft" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint/bw6-633" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" "math/big" @@ -51,22 +53,20 @@ func (proof *Proof) CurveID() ecc.ID { } // Prove generates the proof of knowledge of a r1cs with full witness (secret + public part). -func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness fr.Vector, opt backend.ProverConfig) (*Proof, error) { - // TODO @gbotrel witness size check is done by R1CS, doesn't mean we shouldn't sanitize here. - // if len(witness) != r1cs.NbPublicVariables-1+r1cs.NbSecretVariables { - // return nil, fmt.Errorf("invalid witness size, got %d, expected %d = %d (public) + %d (secret)", len(witness), r1cs.NbPublicVariables-1+r1cs.NbSecretVariables, r1cs.NbPublicVariables, r1cs.NbSecretVariables) - // } +func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { + opt, err := backend.NewProverConfig(opts...) + if err != nil { + return nil, err + } log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", len(r1cs.Constraints)).Str("backend", "groth16").Logger() - // solve the R1CS and compute the a, b, c vectors - a := make([]fr.Element, len(r1cs.Constraints), pk.Domain.Cardinality) - b := make([]fr.Element, len(r1cs.Constraints), pk.Domain.Cardinality) - c := make([]fr.Element, len(r1cs.Constraints), pk.Domain.Cardinality) - proof := &Proof{} + + solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] + if r1cs.CommitmentInfo.Is() { - opt.HintFunctions[r1cs.CommitmentInfo.HintID] = func(_ *big.Int, in []*big.Int, out []*big.Int) error { + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo.HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function if len(in) != r1cs.CommitmentInfo.NbCommitted() { // TODO: Remove @@ -87,36 +87,29 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness fr.Vector, opt backend.ProverC var res fr.Element res, err = solveCommitmentWire(&r1cs.CommitmentInfo, &proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) - res.BigInt(out[0]) //Perf-TODO: Regular (non-mont) hashToField to obviate this conversion? + res.BigInt(out[0]) return err - } + })) } - var wireValues []fr.Element - var err error - if wireValues, err = r1cs.Solve(witness, a, b, c, opt); err != nil { - if !opt.Force { - return nil, err - } else { - // we need to fill wireValues with random values else multi exps don't do much - var r fr.Element - _, _ = r.SetRandom() - for i := r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables(); i < len(wireValues); i++ { - wireValues[i] = r - r.Double(&r) - } - } + _solution, err := r1cs.Solve(fullWitness, solverOpts...) + if err != nil { + return nil, err } + + solution := _solution.(*cs.R1CSSolution) + wireValues := []fr.Element(solution.W) + start := time.Now() // H (witness reduction / FFT part) var h []fr.Element chHDone := make(chan struct{}, 1) go func() { - h = computeH(a, b, c, &pk.Domain) - a = nil - b = nil - c = nil + h = computeH(solution.A, solution.B, solution.C, &pk.Domain) + solution.A = nil + solution.B = nil + solution.C = nil chHDone <- struct{}{} }() @@ -345,7 +338,7 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { den.Sub(&den, &one).Inverse(&den) // h = ifft_coset(ca o cb - cc) - // reusing a to avoid unecessary memalloc + // reusing a to avoid unnecessary memory allocation utils.Parallelize(n, func(start, end int) { for i := start; i < end; i++ { a[i].Mul(&a[i], &b[i]). diff --git a/internal/backend/bw6-633/plonk/prove.go b/internal/backend/bw6-633/plonk/prove.go index bd6f3ff24b..d19ff91d8a 100644 --- a/internal/backend/bw6-633/plonk/prove.go +++ b/internal/backend/bw6-633/plonk/prove.go @@ -23,6 +23,8 @@ import ( "sync" "time" + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" curve "github.com/consensys/gnark-crypto/ecc/bw6-633" @@ -58,10 +60,15 @@ type Proof struct { ZShiftedOpening kzg.OpeningProof } -// Prove from the public data -func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backend.ProverConfig) (*Proof, error) { +func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", len(spr.Constraints)).Str("backend", "plonk").Logger() + + opt, err := backend.NewProverConfig(opts...) + if err != nil { + return nil, err + } + start := time.Now() // pick a hash function that will be used to derive the challenges hFunc := sha256.New() @@ -72,25 +79,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen // result proof := &Proof{} - // compute the constraint system solution - var solution []fr.Element - var err error - if solution, err = spr.Solve(fullWitness, opt); err != nil { - if !opt.Force { - return nil, err - } else { - // we need to fill solution with random values - var r fr.Element - _, _ = r.SetRandom() - for i := len(spr.Public) + len(spr.Secret); i < len(solution); i++ { - solution[i] = r - r.Double(&r) - } - } - } - // query l, r, o in Lagrange basis, not blinded - evaluationLDomainSmall, evaluationRDomainSmall, evaluationODomainSmall := evaluateLROSmallDomain(spr, pk, solution) + _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) + if err != nil { + return nil, err + } + solution := _solution.(*cs.SparseR1CSSolution) + evaluationLDomainSmall := []fr.Element(solution.L) + evaluationRDomainSmall := []fr.Element(solution.R) + evaluationODomainSmall := []fr.Element(solution.O) lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} liop := iop.NewPolynomial(&evaluationLDomainSmall, lagReg) @@ -112,10 +109,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen return nil, err } + fw, ok := fullWitness.Vector().(fr.Vector) + if !ok { + return nil, witness.ErrInvalidWitness + } + // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *pk.Vk, fullWitness[:len(spr.Public)]); err != nil { + if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)]); err != nil { return nil, err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) @@ -167,7 +169,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen // compute qk in canonical basis, completed with the public inputs qkCompletedCanonical := make([]fr.Element, pk.Domain[0].Cardinality) - copy(qkCompletedCanonical, fullWitness[:len(spr.Public)]) + copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], pk.LQk[len(spr.Public):]) pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -498,41 +500,6 @@ func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error return err1 } -// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. -// solution = [ public | secret | internal ] -func evaluateLROSmallDomain(spr *cs.SparseR1CS, pk *ProvingKey, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { - - s := int(pk.Domain[0].Cardinality) - - var l, r, o []fr.Element - l = make([]fr.Element, s) - r = make([]fr.Element, s) - o = make([]fr.Element, s) - s0 := solution[0] - - for i := 0; i < len(spr.Public); i++ { // placeholders - l[i] = solution[i] - r[i] = s0 - o[i] = s0 - } - offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // constraints - l[offset+i] = solution[spr.Constraints[i].L.WireID()] - r[offset+i] = solution[spr.Constraints[i].R.WireID()] - o[offset+i] = solution[spr.Constraints[i].O.WireID()] - } - offset += len(spr.Constraints) - - for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) - l[offset+i] = s0 - r[offset+i] = s0 - o[offset+i] = s0 - } - - return l, r, o - -} - // computeLinearizedPolynomial computes the linearized polynomial in canonical basis. // The purpose is to commit and open all in one ql, qr, qm, qo, qk. // * lZeta, rZeta, oZeta are the evaluation of l, r, o at zeta diff --git a/internal/backend/bw6-633/plonkfri/prove.go b/internal/backend/bw6-633/plonkfri/prove.go index 27e42784a5..3e9d8e8ef4 100644 --- a/internal/backend/bw6-633/plonkfri/prove.go +++ b/internal/backend/bw6-633/plonkfri/prove.go @@ -22,6 +22,8 @@ import ( "math/bits" "runtime" + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/fft" @@ -36,7 +38,6 @@ import ( ) type Proof struct { - // commitments to the solution vectors LROpp [3]fri.ProofOfProximity @@ -67,7 +68,11 @@ type Proof struct { OpeningsId1Id2Id3mp [3]fri.OpeningProof } -func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backend.ProverConfig) (*Proof, error) { +func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { + opt, err := backend.NewProverConfig(opts...) + if err != nil { + return nil, err + } var proof Proof @@ -78,23 +83,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") // 1 - solve the system - var solution []fr.Element - var err error - if solution, err = spr.Solve(fullWitness, opt); err != nil { - if !opt.Force { - return nil, err - } else { - // we need to fill solution with random values - var r fr.Element - _, _ = r.SetRandom() - for i := len(spr.Public) + len(spr.Secret); i < len(solution); i++ { - solution[i] = r - r.Double(&r) - } - } + _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) + if err != nil { + return nil, err } - evaluationLDomainSmall, evaluationRDomainSmall, evaluationODomainSmall := evaluateLROSmallDomain(spr, pk, solution) + solution := _solution.(*cs.SparseR1CSSolution) + evaluationLDomainSmall := []fr.Element(solution.L) + evaluationRDomainSmall := []fr.Element(solution.R) + evaluationODomainSmall := []fr.Element(solution.O) // 2 - commit to lro blindedLCanonical, blindedRCanonical, blindedOCanonical, err := computeBlindedLROCanonical( @@ -119,9 +116,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen } // 3 - compute Z, challenges are derived using L, R, O + public inputs + fw, ok := fullWitness.Vector().(fr.Vector) + if !ok { + return nil, witness.ErrInvalidWitness + } dataFiatShamir := make([][fr.Bytes]byte, len(spr.Public)+3) for i := 0; i < len(spr.Public); i++ { - copy(dataFiatShamir[i][:], fullWitness[i].Marshal()) + copy(dataFiatShamir[i][:], fw[i].Marshal()) } copy(dataFiatShamir[len(spr.Public)][:], proof.LROpp[0].ID) copy(dataFiatShamir[len(spr.Public)+1][:], proof.LROpp[1].ID) @@ -164,7 +165,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen // alpha.SetUint64(11) evaluationQkCompleteDomainBigBitReversed := make([]fr.Element, pk.Domain[1].Cardinality) - copy(evaluationQkCompleteDomainBigBitReversed, fullWitness[:len(spr.Public)]) + copy(evaluationQkCompleteDomainBigBitReversed, fw[:len(spr.Public)]) copy(evaluationQkCompleteDomainBigBitReversed[len(spr.Public):], pk.LQkIncompleteDomainSmall[len(spr.Public):]) pk.Domain[0].FFTInverse(evaluationQkCompleteDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) fft.BitReverse(evaluationQkCompleteDomainBigBitReversed[:pk.Domain[0].Cardinality]) @@ -586,41 +587,6 @@ func computeBlindedZCanonical(l, r, o []fr.Element, pk *ProvingKey, beta, gamma } -// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. -// solution = [ public | secret | internal ] -func evaluateLROSmallDomain(spr *cs.SparseR1CS, pk *ProvingKey, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { - - s := int(pk.Domain[0].Cardinality) - - var l, r, o []fr.Element - l = make([]fr.Element, s) - r = make([]fr.Element, s) - o = make([]fr.Element, s) - s0 := solution[0] - - for i := 0; i < len(spr.Public); i++ { // placeholders - l[i] = solution[i] - r[i] = s0 - o[i] = s0 - } - offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // constraints - l[offset+i] = solution[spr.Constraints[i].L.WireID()] - r[offset+i] = solution[spr.Constraints[i].R.WireID()] - o[offset+i] = solution[spr.Constraints[i].O.WireID()] - } - offset += len(spr.Constraints) - - for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) - l[offset+i] = s0 - r[offset+i] = s0 - o[offset+i] = s0 - } - - return l, r, o - -} - // computeBlindedLROCanonical // l, r, o in canonical basis with blinding func computeBlindedLROCanonical( diff --git a/internal/backend/bw6-761/groth16/prove.go b/internal/backend/bw6-761/groth16/prove.go index dd67fc5d1e..5dff18221e 100644 --- a/internal/backend/bw6-761/groth16/prove.go +++ b/internal/backend/bw6-761/groth16/prove.go @@ -23,7 +23,9 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/fft" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint/bw6-761" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" "math/big" @@ -51,22 +53,20 @@ func (proof *Proof) CurveID() ecc.ID { } // Prove generates the proof of knowledge of a r1cs with full witness (secret + public part). -func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness fr.Vector, opt backend.ProverConfig) (*Proof, error) { - // TODO @gbotrel witness size check is done by R1CS, doesn't mean we shouldn't sanitize here. - // if len(witness) != r1cs.NbPublicVariables-1+r1cs.NbSecretVariables { - // return nil, fmt.Errorf("invalid witness size, got %d, expected %d = %d (public) + %d (secret)", len(witness), r1cs.NbPublicVariables-1+r1cs.NbSecretVariables, r1cs.NbPublicVariables, r1cs.NbSecretVariables) - // } +func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { + opt, err := backend.NewProverConfig(opts...) + if err != nil { + return nil, err + } log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", len(r1cs.Constraints)).Str("backend", "groth16").Logger() - // solve the R1CS and compute the a, b, c vectors - a := make([]fr.Element, len(r1cs.Constraints), pk.Domain.Cardinality) - b := make([]fr.Element, len(r1cs.Constraints), pk.Domain.Cardinality) - c := make([]fr.Element, len(r1cs.Constraints), pk.Domain.Cardinality) - proof := &Proof{} + + solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] + if r1cs.CommitmentInfo.Is() { - opt.HintFunctions[r1cs.CommitmentInfo.HintID] = func(_ *big.Int, in []*big.Int, out []*big.Int) error { + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo.HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function if len(in) != r1cs.CommitmentInfo.NbCommitted() { // TODO: Remove @@ -87,36 +87,29 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness fr.Vector, opt backend.ProverC var res fr.Element res, err = solveCommitmentWire(&r1cs.CommitmentInfo, &proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) - res.BigInt(out[0]) //Perf-TODO: Regular (non-mont) hashToField to obviate this conversion? + res.BigInt(out[0]) return err - } + })) } - var wireValues []fr.Element - var err error - if wireValues, err = r1cs.Solve(witness, a, b, c, opt); err != nil { - if !opt.Force { - return nil, err - } else { - // we need to fill wireValues with random values else multi exps don't do much - var r fr.Element - _, _ = r.SetRandom() - for i := r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables(); i < len(wireValues); i++ { - wireValues[i] = r - r.Double(&r) - } - } + _solution, err := r1cs.Solve(fullWitness, solverOpts...) + if err != nil { + return nil, err } + + solution := _solution.(*cs.R1CSSolution) + wireValues := []fr.Element(solution.W) + start := time.Now() // H (witness reduction / FFT part) var h []fr.Element chHDone := make(chan struct{}, 1) go func() { - h = computeH(a, b, c, &pk.Domain) - a = nil - b = nil - c = nil + h = computeH(solution.A, solution.B, solution.C, &pk.Domain) + solution.A = nil + solution.B = nil + solution.C = nil chHDone <- struct{}{} }() @@ -345,7 +338,7 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { den.Sub(&den, &one).Inverse(&den) // h = ifft_coset(ca o cb - cc) - // reusing a to avoid unecessary memalloc + // reusing a to avoid unnecessary memory allocation utils.Parallelize(n, func(start, end int) { for i := start; i < end; i++ { a[i].Mul(&a[i], &b[i]). diff --git a/internal/backend/bw6-761/plonk/prove.go b/internal/backend/bw6-761/plonk/prove.go index 5a372eb87b..c8854b1938 100644 --- a/internal/backend/bw6-761/plonk/prove.go +++ b/internal/backend/bw6-761/plonk/prove.go @@ -23,6 +23,8 @@ import ( "sync" "time" + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" curve "github.com/consensys/gnark-crypto/ecc/bw6-761" @@ -58,10 +60,15 @@ type Proof struct { ZShiftedOpening kzg.OpeningProof } -// Prove from the public data -func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backend.ProverConfig) (*Proof, error) { +func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", len(spr.Constraints)).Str("backend", "plonk").Logger() + + opt, err := backend.NewProverConfig(opts...) + if err != nil { + return nil, err + } + start := time.Now() // pick a hash function that will be used to derive the challenges hFunc := sha256.New() @@ -72,25 +79,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen // result proof := &Proof{} - // compute the constraint system solution - var solution []fr.Element - var err error - if solution, err = spr.Solve(fullWitness, opt); err != nil { - if !opt.Force { - return nil, err - } else { - // we need to fill solution with random values - var r fr.Element - _, _ = r.SetRandom() - for i := len(spr.Public) + len(spr.Secret); i < len(solution); i++ { - solution[i] = r - r.Double(&r) - } - } - } - // query l, r, o in Lagrange basis, not blinded - evaluationLDomainSmall, evaluationRDomainSmall, evaluationODomainSmall := evaluateLROSmallDomain(spr, pk, solution) + _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) + if err != nil { + return nil, err + } + solution := _solution.(*cs.SparseR1CSSolution) + evaluationLDomainSmall := []fr.Element(solution.L) + evaluationRDomainSmall := []fr.Element(solution.R) + evaluationODomainSmall := []fr.Element(solution.O) lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} liop := iop.NewPolynomial(&evaluationLDomainSmall, lagReg) @@ -112,10 +109,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen return nil, err } + fw, ok := fullWitness.Vector().(fr.Vector) + if !ok { + return nil, witness.ErrInvalidWitness + } + // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *pk.Vk, fullWitness[:len(spr.Public)]); err != nil { + if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)]); err != nil { return nil, err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) @@ -167,7 +169,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen // compute qk in canonical basis, completed with the public inputs qkCompletedCanonical := make([]fr.Element, pk.Domain[0].Cardinality) - copy(qkCompletedCanonical, fullWitness[:len(spr.Public)]) + copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], pk.LQk[len(spr.Public):]) pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -498,41 +500,6 @@ func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error return err1 } -// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. -// solution = [ public | secret | internal ] -func evaluateLROSmallDomain(spr *cs.SparseR1CS, pk *ProvingKey, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { - - s := int(pk.Domain[0].Cardinality) - - var l, r, o []fr.Element - l = make([]fr.Element, s) - r = make([]fr.Element, s) - o = make([]fr.Element, s) - s0 := solution[0] - - for i := 0; i < len(spr.Public); i++ { // placeholders - l[i] = solution[i] - r[i] = s0 - o[i] = s0 - } - offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // constraints - l[offset+i] = solution[spr.Constraints[i].L.WireID()] - r[offset+i] = solution[spr.Constraints[i].R.WireID()] - o[offset+i] = solution[spr.Constraints[i].O.WireID()] - } - offset += len(spr.Constraints) - - for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) - l[offset+i] = s0 - r[offset+i] = s0 - o[offset+i] = s0 - } - - return l, r, o - -} - // computeLinearizedPolynomial computes the linearized polynomial in canonical basis. // The purpose is to commit and open all in one ql, qr, qm, qo, qk. // * lZeta, rZeta, oZeta are the evaluation of l, r, o at zeta diff --git a/internal/backend/bw6-761/plonkfri/prove.go b/internal/backend/bw6-761/plonkfri/prove.go index 41ab07bf26..f57bc4f6d3 100644 --- a/internal/backend/bw6-761/plonkfri/prove.go +++ b/internal/backend/bw6-761/plonkfri/prove.go @@ -22,6 +22,8 @@ import ( "math/bits" "runtime" + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/fft" @@ -36,7 +38,6 @@ import ( ) type Proof struct { - // commitments to the solution vectors LROpp [3]fri.ProofOfProximity @@ -67,7 +68,11 @@ type Proof struct { OpeningsId1Id2Id3mp [3]fri.OpeningProof } -func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backend.ProverConfig) (*Proof, error) { +func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { + opt, err := backend.NewProverConfig(opts...) + if err != nil { + return nil, err + } var proof Proof @@ -78,23 +83,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") // 1 - solve the system - var solution []fr.Element - var err error - if solution, err = spr.Solve(fullWitness, opt); err != nil { - if !opt.Force { - return nil, err - } else { - // we need to fill solution with random values - var r fr.Element - _, _ = r.SetRandom() - for i := len(spr.Public) + len(spr.Secret); i < len(solution); i++ { - solution[i] = r - r.Double(&r) - } - } + _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) + if err != nil { + return nil, err } - evaluationLDomainSmall, evaluationRDomainSmall, evaluationODomainSmall := evaluateLROSmallDomain(spr, pk, solution) + solution := _solution.(*cs.SparseR1CSSolution) + evaluationLDomainSmall := []fr.Element(solution.L) + evaluationRDomainSmall := []fr.Element(solution.R) + evaluationODomainSmall := []fr.Element(solution.O) // 2 - commit to lro blindedLCanonical, blindedRCanonical, blindedOCanonical, err := computeBlindedLROCanonical( @@ -119,9 +116,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen } // 3 - compute Z, challenges are derived using L, R, O + public inputs + fw, ok := fullWitness.Vector().(fr.Vector) + if !ok { + return nil, witness.ErrInvalidWitness + } dataFiatShamir := make([][fr.Bytes]byte, len(spr.Public)+3) for i := 0; i < len(spr.Public); i++ { - copy(dataFiatShamir[i][:], fullWitness[i].Marshal()) + copy(dataFiatShamir[i][:], fw[i].Marshal()) } copy(dataFiatShamir[len(spr.Public)][:], proof.LROpp[0].ID) copy(dataFiatShamir[len(spr.Public)+1][:], proof.LROpp[1].ID) @@ -164,7 +165,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen // alpha.SetUint64(11) evaluationQkCompleteDomainBigBitReversed := make([]fr.Element, pk.Domain[1].Cardinality) - copy(evaluationQkCompleteDomainBigBitReversed, fullWitness[:len(spr.Public)]) + copy(evaluationQkCompleteDomainBigBitReversed, fw[:len(spr.Public)]) copy(evaluationQkCompleteDomainBigBitReversed[len(spr.Public):], pk.LQkIncompleteDomainSmall[len(spr.Public):]) pk.Domain[0].FFTInverse(evaluationQkCompleteDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) fft.BitReverse(evaluationQkCompleteDomainBigBitReversed[:pk.Domain[0].Cardinality]) @@ -586,41 +587,6 @@ func computeBlindedZCanonical(l, r, o []fr.Element, pk *ProvingKey, beta, gamma } -// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. -// solution = [ public | secret | internal ] -func evaluateLROSmallDomain(spr *cs.SparseR1CS, pk *ProvingKey, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { - - s := int(pk.Domain[0].Cardinality) - - var l, r, o []fr.Element - l = make([]fr.Element, s) - r = make([]fr.Element, s) - o = make([]fr.Element, s) - s0 := solution[0] - - for i := 0; i < len(spr.Public); i++ { // placeholders - l[i] = solution[i] - r[i] = s0 - o[i] = s0 - } - offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // constraints - l[offset+i] = solution[spr.Constraints[i].L.WireID()] - r[offset+i] = solution[spr.Constraints[i].R.WireID()] - o[offset+i] = solution[spr.Constraints[i].O.WireID()] - } - offset += len(spr.Constraints) - - for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) - l[offset+i] = s0 - r[offset+i] = s0 - o[offset+i] = s0 - } - - return l, r, o - -} - // computeBlindedLROCanonical // l, r, o in canonical basis with blinding func computeBlindedLROCanonical( diff --git a/internal/backend/circuits/circuits.go b/internal/backend/circuits/circuits.go index 51bdb7b9a9..92b306de73 100644 --- a/internal/backend/circuits/circuits.go +++ b/internal/backend/circuits/circuits.go @@ -3,7 +3,8 @@ package circuits import ( "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark/backend/hint" + + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" ) @@ -11,7 +12,7 @@ import ( type TestCircuit struct { Circuit frontend.Circuit ValidAssignments, InvalidAssignments []frontend.Circuit // good and bad witness for the prover + public verifier data - HintFunctions []hint.Function + HintFunctions []solver.Hint Curves []ecc.ID } @@ -30,13 +31,14 @@ func addEntry(name string, circuit, proverGood, proverBad frontend.Circuit, curv Circuits[name] = TestCircuit{circuit, []frontend.Circuit{proverGood}, []frontend.Circuit{proverBad}, nil, curves} } -func addNewEntry(name string, circuit frontend.Circuit, proverGood, proverBad []frontend.Circuit, curves []ecc.ID, hintFunctions ...hint.Function) { +func addNewEntry(name string, circuit frontend.Circuit, proverGood, proverBad []frontend.Circuit, curves []ecc.ID, hintFunctions ...solver.Hint) { if Circuits == nil { Circuits = make(map[string]TestCircuit) } if _, ok := Circuits[name]; ok { panic("name " + name + "already taken by another test circuit ") } + solver.RegisterHint(hintFunctions...) Circuits[name] = TestCircuit{circuit, proverGood, proverBad, hintFunctions, curves} } diff --git a/internal/generator/backend/template/representations/r1cs.go.tmpl b/internal/generator/backend/template/representations/r1cs.go.tmpl index d65b171737..0d91c7f299 100644 --- a/internal/generator/backend/template/representations/r1cs.go.tmpl +++ b/internal/generator/backend/template/representations/r1cs.go.tmpl @@ -8,8 +8,8 @@ import ( "github.com/fxamacker/cbor/v2" "github.com/consensys/gnark/internal/backend/ioutils" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/backend" "github.com/consensys/gnark/logger" "github.com/consensys/gnark/profile" "github.com/consensys/gnark/backend/witness" @@ -57,13 +57,37 @@ func (cs *R1CS) AddConstraint(r1c constraint.R1C, debugInfo ...constraint.DebugI } +// Solve returns the vector w solution to the system, that is +// Aw o Bw - Cw = 0 +func (cs *R1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { + opt, err := solver.NewConfig(opts...) + if err != nil { + return nil, err + } + + var res R1CSSolution + + s := ecc.NextPowerOfTwo(uint64(len(cs.Constraints))) + res.A = make(fr.Vector, len(cs.Constraints), s) + res.B = make(fr.Vector, len(cs.Constraints), s) + res.C = make(fr.Vector, len(cs.Constraints), s) + + v := witness.Vector().(fr.Vector) + + res.W, err = cs.solve(v, res.A, res.B, res.C, opt) + if err != nil { + return nil, err + } + + return &res, nil +} // Solve sets all the wires and returns the a, b, c vectors. // the cs system should have been compiled before. The entries in a, b, c are in Montgomery form. // a, b, c vectors: ab-c = hz // witness = [publicWires | secretWires] (without the ONE_WIRE !) // returns [publicWires | secretWires | internalWires ] -func (cs *R1CS) Solve(witness, a, b, c fr.Vector, opt backend.ProverConfig) (fr.Vector, error) { +func (cs *R1CS) solve(witness, a, b, c fr.Vector, opt solver.Config) (fr.Vector, error) { log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables @@ -99,7 +123,7 @@ func (cs *R1CS) Solve(witness, a, b, c fr.Vector, opt backend.ProverConfig) (fr. // now that we know all inputs are set, defer log printing once all solution.values are computed // (or sooner, if a constraint is not satisfied) - defer solution.printLogs(opt.CircuitLogger, cs.Logs) + defer solution.printLogs(opt.Logger, cs.Logs) if err := cs.parallelSolve(a, b, c, &solution); err != nil { if unsatisfiedErr, ok := err.(*UnsatisfiedConstraintError); ok { @@ -194,8 +218,8 @@ func (cs *R1CS) parallelSolve(a, b, c fr.Vector, solution *solution) error { continue } - // number of tasks for this level is set to num cpus - // but if we don't have enough work for all our CPUS, it can be lower. + // number of tasks for this level is set to number of CPU + // but if we don't have enough work for all our CPU, it can be lower. nbTasks := runtime.NumCPU() maxTasks := int(math.Ceil(maxCPU)) if nbTasks > maxTasks { @@ -239,20 +263,11 @@ func (cs *R1CS) parallelSolve(a, b, c fr.Vector, solution *solution) error { return nil } -// IsSolved returns nil if given witness solves the R1CS and error otherwise -// this method wraps cs.Solve() and allocates cs.Solve() inputs -func (cs *R1CS) IsSolved(witness witness.Witness, opts ...backend.ProverOption) error { - opt, err := backend.NewProverConfig(opts...) - if err != nil { - return err - } - - a := make(fr.Vector, len(cs.Constraints)) - b := make(fr.Vector, len(cs.Constraints)) - c := make(fr.Vector, len(cs.Constraints)) - v := witness.Vector().(fr.Vector) - _, err = cs.Solve(v, a, b, c, opt) - return err +// IsSolved +// Deprecated: use _, err := Solve(...) instead +func (cs *R1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { + _, err := cs.Solve(witness, opts...) + return err } // divByCoeff sets res = res / t.Coeff diff --git a/internal/generator/backend/template/representations/r1cs.sparse.go.tmpl b/internal/generator/backend/template/representations/r1cs.sparse.go.tmpl index f5a35ea03e..eec1fd8d58 100644 --- a/internal/generator/backend/template/representations/r1cs.sparse.go.tmpl +++ b/internal/generator/backend/template/representations/r1cs.sparse.go.tmpl @@ -11,7 +11,7 @@ import ( "github.com/consensys/gnark/internal/backend/ioutils" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/logger" "github.com/consensys/gnark/profile" "github.com/consensys/gnark/backend/witness" @@ -53,12 +53,68 @@ func (cs *SparseR1CS) AddConstraint(c constraint.SparseR1C, debugInfo ...constra return cID } +func (c *SparseR1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { + opt, err := solver.NewConfig(opts...) + if err != nil { + return nil, err + } + + // compute the constraint system solution + var solution []fr.Element + if solution, err = c.solve(witness.Vector().(fr.Vector), opt); err != nil { + return nil, err + } + + var res SparseR1CSSolution + // query l, r, o in Lagrange basis, not blinded + res.L, res.R, res.O = c.evaluateLROSmallDomain(solution) + + return &res, nil +} + +// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. +// solution = [ public | secret | internal ] +func (c *SparseR1CS) evaluateLROSmallDomain(solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { + + //s := int(pk.Domain[0].Cardinality) + s := c.GetNbConstraints() + len(c.Public) // len(spr.Public) is for the placeholder constraints + s = int(ecc.NextPowerOfTwo(uint64(s))) + + var l, r, o []fr.Element + l = make([]fr.Element, s) + r = make([]fr.Element, s) + o = make([]fr.Element, s) + s0 := solution[0] + + for i := 0; i < len(c.Public); i++ { // placeholders + l[i] = solution[i] + r[i] = s0 + o[i] = s0 + } + offset := len(c.Public) + for i := 0; i < len(c.Constraints); i++ { // constraints + l[offset+i] = solution[c.Constraints[i].L.WireID()] + r[offset+i] = solution[c.Constraints[i].R.WireID()] + o[offset+i] = solution[c.Constraints[i].O.WireID()] + } + offset += len(c.Constraints) + + for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) + l[offset+i] = s0 + r[offset+i] = s0 + o[offset+i] = s0 + } + + return l, r, o + +} + // Solve sets all the wires. // solution.values = [publicInputs | secretInputs | internalVariables ] // witness: contains the input variables // it returns the full slice of wires -func (cs *SparseR1CS) Solve(witness fr.Vector, opt backend.ProverConfig) (fr.Vector, error) { +func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, error) { log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "plonk").Logger() // set the slices holding the solution.values and monitoring which variables have been solved @@ -95,7 +151,7 @@ func (cs *SparseR1CS) Solve(witness fr.Vector, opt backend.ProverConfig) (fr.Vec solution.nbSolved += uint64(len(witness)) // defer log printing once all solution.values are computed - defer solution.printLogs(opt.CircuitLogger, cs.Logs) + defer solution.printLogs(opt.Logger, cs.Logs) // batch invert the coefficients to avoid many divisions in the solver coefficientsNegInv := fr.BatchInvert(cs.Coefficients) @@ -196,8 +252,8 @@ func (cs *SparseR1CS) parallelSolve(solution *solution, coefficientsNegInv fr.Ve continue } - // number of tasks for this level is set to num cpus - // but if we don't have enough work for all our CPUS, it can be lower. + // number of tasks for this level is set to number of CPU + // but if we don't have enough work for all our CPU, it can be lower. nbTasks := runtime.NumCPU() maxTasks := int(math.Ceil(maxCPU)) if nbTasks > maxTasks { @@ -359,17 +415,11 @@ func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution return nil } -// IsSolved returns nil if given witness solves the SparseR1CS and error otherwise -// this method wraps cs.Solve() and allocates cs.Solve() inputs -func (cs *SparseR1CS) IsSolved(witness witness.Witness, opts ...backend.ProverOption) error { - opt, err := backend.NewProverConfig(opts...) - if err != nil { - return err - } - - v := witness.Vector().(fr.Vector) - _, err = cs.Solve(v, opt) - return err +// IsSolved +// Deprecated: use _, err := Solve(...) instead +func (cs *SparseR1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { + _, err := cs.Solve(witness, opts...) + return err } // GetConstraints return the list of SparseR1C and a coefficient resolver diff --git a/internal/generator/backend/template/representations/solution.go.tmpl b/internal/generator/backend/template/representations/solution.go.tmpl index e323a614f5..43835d3786 100644 --- a/internal/generator/backend/template/representations/solution.go.tmpl +++ b/internal/generator/backend/template/representations/solution.go.tmpl @@ -5,9 +5,10 @@ import ( "sync/atomic" "strings" "strconv" + "io" "github.com/consensys/gnark/debug" - "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/rs/zerolog" {{ template "import_fr" . }} ) @@ -18,12 +19,12 @@ type solution struct { values, coefficients []fr.Element solved []bool nbSolved uint64 - mHintsFunctions map[hint.ID]hint.Function // maps hintID to hint function - mHints map[int]*constraint.Hint // maps wireID to hint + mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function + mHints map[int]*constraint.HintMapping // maps wireID to hint st *debug.SymbolTable } -func newSolution( nbWires int, hintFunctions map[hint.ID]hint.Function, hintsDependencies map[hint.ID]string, mHints map[int]*constraint.Hint, coefficients []fr.Element, st *debug.SymbolTable) (solution, error) { +func newSolution( nbWires int, hintFunctions map[solver.HintID]solver.Hint, hintsDependencies map[solver.HintID]string, mHints map[int]*constraint.HintMapping, coefficients []fr.Element, st *debug.SymbolTable) (solution, error) { s := solution{ st: st, @@ -120,21 +121,21 @@ func (s *solution) accumulateInto(t constraint.Term, r *fr.Element) { } // solveHint compute solution.values[vID] using provided solver hint -func (s *solution) solveWithHint(vID int, h *constraint.Hint) error { +func (s *solution) solveWithHint(vID int, h *constraint.HintMapping) error { // skip if the wire is already solved by a call to the same hint // function on the same inputs if s.solved[vID] { return nil } // ensure hint function was provided - f, ok := s.mHintsFunctions[h.ID] + f, ok := s.mHintsFunctions[h.HintID] if !ok { return errors.New("missing hint function") } // tmp IO big int memory nbInputs := len(h.Inputs) - nbOutputs := len(h.Wires) + nbOutputs := len(h.Outputs) inputs := make([]*big.Int, nbInputs) outputs := make([]*big.Int, nbOutputs) for i :=0; i < nbOutputs; i++ { @@ -185,7 +186,7 @@ func (s *solution) solveWithHint(vID int, h *constraint.Hint) error { var v fr.Element for i := range outputs { v.SetBigInt(outputs[i]) - s.set(h.Wires[i], v) + s.set(h.Outputs[i], v) } return err @@ -276,4 +277,91 @@ func (r *UnsatisfiedConstraintError) Error() string { return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, *r.DebugInfo) } return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, r.Err.Error()) -} \ No newline at end of file +} + + + +// R1CSSolution represent a valid assignment to all the variables in the constraint system. +// The vector W such that Aw o Bw - Cw = 0 +type R1CSSolution struct { + W fr.Vector + A, B, C fr.Vector +} + +func (t *R1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.W.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.A.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.B.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.C.WriteTo(w) + n += a + return n, err +} + +func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.W.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.A.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.B.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.C.ReadFrom(r) + n += a + return n, err +} + + + +// SparseR1CSSolution represent a valid assignment to all the variables in the constraint system. +type SparseR1CSSolution struct { + L, R, O fr.Vector +} + +func (t *SparseR1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.L.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.R.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.O.WriteTo(w) + n += a + return n, err + +} + +func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.L.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.R.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.O.ReadFrom(r) + a += n + return n, err +} diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl index 2391be837a..1654735bfa 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl @@ -10,6 +10,8 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/logger" ) @@ -34,22 +36,20 @@ func (proof *Proof) CurveID() ecc.ID { } // Prove generates the proof of knowledge of a r1cs with full witness (secret + public part). -func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness fr.Vector, opt backend.ProverConfig) (*Proof, error) { - // TODO @gbotrel witness size check is done by R1CS, doesn't mean we shouldn't sanitize here. - // if len(witness) != r1cs.NbPublicVariables-1+r1cs.NbSecretVariables { - // return nil, fmt.Errorf("invalid witness size, got %d, expected %d = %d (public) + %d (secret)", len(witness), r1cs.NbPublicVariables-1+r1cs.NbSecretVariables, r1cs.NbPublicVariables, r1cs.NbSecretVariables) - // } +func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { + opt, err := backend.NewProverConfig(opts...) + if err != nil { + return nil, err + } log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", len(r1cs.Constraints)).Str("backend", "groth16").Logger() - // solve the R1CS and compute the a, b, c vectors - a := make([]fr.Element, len(r1cs.Constraints), pk.Domain.Cardinality) - b := make([]fr.Element, len(r1cs.Constraints), pk.Domain.Cardinality) - c := make([]fr.Element, len(r1cs.Constraints), pk.Domain.Cardinality) - proof := &Proof{} + + solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] + if r1cs.CommitmentInfo.Is() { - opt.HintFunctions[r1cs.CommitmentInfo.HintID] = func(_ *big.Int, in []*big.Int, out []*big.Int) error { + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo.HintID,func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function if len(in) != r1cs.CommitmentInfo.NbCommitted() { // TODO: Remove @@ -70,36 +70,29 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness fr.Vector, opt backend.ProverC var res fr.Element res, err = solveCommitmentWire(&r1cs.CommitmentInfo, &proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) - res.BigInt(out[0]) //Perf-TODO: Regular (non-mont) hashToField to obviate this conversion? + res.BigInt(out[0]) return err - } + } )) } - var wireValues []fr.Element - var err error - if wireValues, err = r1cs.Solve(witness, a, b, c, opt); err != nil { - if !opt.Force { - return nil, err - } else { - // we need to fill wireValues with random values else multi exps don't do much - var r fr.Element - _, _ = r.SetRandom() - for i := r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables(); i < len(wireValues); i++ { - wireValues[i] = r - r.Double(&r) - } - } + _solution, err := r1cs.Solve(fullWitness, solverOpts...) + if err != nil { + return nil, err } + + solution := _solution.(*cs.R1CSSolution) + wireValues := []fr.Element(solution.W) + start := time.Now() // H (witness reduction / FFT part) var h []fr.Element chHDone := make(chan struct{}, 1) go func() { - h = computeH(a, b, c, &pk.Domain) - a = nil - b = nil - c = nil + h = computeH(solution.A, solution.B, solution.C, &pk.Domain) + solution.A = nil + solution.B = nil + solution.C = nil chHDone <- struct{}{} }() @@ -328,7 +321,7 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { den.Sub(&den, &one).Inverse(&den) // h = ifft_coset(ca o cb - cc) - // reusing a to avoid unecessary memalloc + // reusing a to avoid unnecessary memory allocation utils.Parallelize(n, func(start, end int) { for i := start; i < end; i++ { a[i].Mul(&a[i], &b[i]). diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl index af921fded2..307ee05dbb 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl @@ -5,6 +5,8 @@ import ( "time" "sync" + "github.com/consensys/gnark/backend/witness" + {{ template "import_fr" . }} {{ template "import_curve" . }} {{ template "import_kzg" . }} @@ -36,10 +38,15 @@ type Proof struct { ZShiftedOpening kzg.OpeningProof } -// Prove from the public data -func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backend.ProverConfig) (*Proof, error) { +func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", len(spr.Constraints)).Str("backend", "plonk").Logger() + + opt, err := backend.NewProverConfig(opts...) + if err != nil { + return nil, err + } + start := time.Now() // pick a hash function that will be used to derive the challenges hFunc := sha256.New() @@ -50,30 +57,20 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen // result proof := &Proof{} - // compute the constraint system solution - var solution []fr.Element - var err error - if solution, err = spr.Solve(fullWitness, opt); err != nil { - if !opt.Force { - return nil, err - } else { - // we need to fill solution with random values - var r fr.Element - _, _ = r.SetRandom() - for i := len(spr.Public) + len(spr.Secret); i < len(solution); i++ { - solution[i] = r - r.Double(&r) - } - } - } - // query l, r, o in Lagrange basis, not blinded - evaluationLDomainSmall, evaluationRDomainSmall, evaluationODomainSmall := evaluateLROSmallDomain(spr, pk, solution) + _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) + if err != nil { + return nil, err + } + solution := _solution.(*cs.SparseR1CSSolution) + evaluationLDomainSmall := []fr.Element(solution.L) + evaluationRDomainSmall := []fr.Element(solution.R) + evaluationODomainSmall := []fr.Element(solution.O) lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} - liop := iop.NewPolynomial(&evaluationLDomainSmall,lagReg) - riop := iop.NewPolynomial(&evaluationRDomainSmall,lagReg) - oiop := iop.NewPolynomial(&evaluationODomainSmall,lagReg) + liop := iop.NewPolynomial(&evaluationLDomainSmall, lagReg) + riop := iop.NewPolynomial(&evaluationRDomainSmall, lagReg) + oiop := iop.NewPolynomial(&evaluationODomainSmall, lagReg) wliop := liop.ShallowClone() wriop := riop.ShallowClone() woiop := oiop.ShallowClone() @@ -90,10 +87,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen return nil, err } + fw, ok := fullWitness.Vector().(fr.Vector) + if !ok { + return nil, witness.ErrInvalidWitness + } + // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *pk.Vk, fullWitness[:len(spr.Public)]); err != nil { + if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)]); err != nil { return nil, err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) @@ -145,7 +147,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen // compute qk in canonical basis, completed with the public inputs qkCompletedCanonical := make([]fr.Element, pk.Domain[0].Cardinality) - copy(qkCompletedCanonical, fullWitness[:len(spr.Public)]) + copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], pk.LQk[len(spr.Public):]) pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -154,9 +156,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen bwliop.ToLagrangeCoset(&pk.Domain[1]) bwriop.ToLagrangeCoset(&pk.Domain[1]) bwoiop.ToLagrangeCoset(&pk.Domain[1]) - + lagrangeCosetBitReversed := iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse} - + // we don't mutate so no need to clone the coefficients from the proving key. wqliop := iop.NewPolynomial(&pk.lQl, lagrangeCosetBitReversed) wqriop := iop.NewPolynomial(&pk.lQr, lagrangeCosetBitReversed) @@ -173,7 +175,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen widiop := iop.NewPolynomial(&id, canReg) widiop.ToLagrangeCoset(&pk.Domain[1]) - // permutations in LagrangeCoset: we don't mutate so no need to clone the coefficients from the + // permutations in LagrangeCoset: we don't mutate so no need to clone the coefficients from the // proving key. ws1 := iop.NewPolynomial(&pk.lS1LagrangeCoset, lagrangeCosetBitReversed) ws2 := iop.NewPolynomial(&pk.lS2LagrangeCoset, lagrangeCosetBitReversed) @@ -294,7 +296,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen // compute evaluations of (blinded version of) l, r, o, z at zeta var blzeta, brzeta, bozeta fr.Element - + var wgEvals sync.WaitGroup wgEvals.Add(3) @@ -309,13 +311,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen brzeta = bwriop.Evaluate(zeta) wgEvals.Done() }() - + go func() { bwoiop.ToCanonical(&pk.Domain[1]).ToRegular() bozeta = bwoiop.Evaluate(zeta) wgEvals.Done() }() - + // open blinded Z at zeta*z bwziop.ToCanonical(&pk.Domain[1]).ToRegular() var zetaShifted fr.Element @@ -476,41 +478,6 @@ func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error return err1 } -// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. -// solution = [ public | secret | internal ] -func evaluateLROSmallDomain(spr *cs.SparseR1CS, pk *ProvingKey, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { - - s := int(pk.Domain[0].Cardinality) - - var l, r, o []fr.Element - l = make([]fr.Element, s) - r = make([]fr.Element, s) - o = make([]fr.Element, s) - s0 := solution[0] - - for i := 0; i < len(spr.Public); i++ { // placeholders - l[i] = solution[i] - r[i] = s0 - o[i] = s0 - } - offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // constraints - l[offset+i] = solution[spr.Constraints[i].L.WireID()] - r[offset+i] = solution[spr.Constraints[i].R.WireID()] - o[offset+i] = solution[spr.Constraints[i].O.WireID()] - } - offset += len(spr.Constraints) - - for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) - l[offset+i] = s0 - r[offset+i] = s0 - o[offset+i] = s0 - } - - return l, r, o - -} - // computeLinearizedPolynomial computes the linearized polynomial in canonical basis. // The purpose is to commit and open all in one ql, qr, qm, qo, qk. // * lZeta, rZeta, oZeta are the evaluation of l, r, o at zeta diff --git a/internal/generator/backend/template/zkpschemes/plonkfri/plonk.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/plonkfri/plonk.prove.go.tmpl index 20ee52c909..5f3ee2ccf2 100644 --- a/internal/generator/backend/template/zkpschemes/plonkfri/plonk.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonkfri/plonk.prove.go.tmpl @@ -4,6 +4,8 @@ import ( "math/bits" "runtime" + "github.com/consensys/gnark/backend/witness" + {{ template "import_fr" . }} {{ template "import_fft" . }} {{ template "import_backend_cs" . }} @@ -15,7 +17,6 @@ import ( ) type Proof struct { - // commitments to the solution vectors LROpp [3]fri.ProofOfProximity @@ -46,7 +47,11 @@ type Proof struct { OpeningsId1Id2Id3mp [3]fri.OpeningProof } -func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backend.ProverConfig) (*Proof, error) { +func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { + opt, err := backend.NewProverConfig(opts...) + if err != nil { + return nil, err + } var proof Proof @@ -57,23 +62,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") // 1 - solve the system - var solution []fr.Element - var err error - if solution, err = spr.Solve(fullWitness, opt); err != nil { - if !opt.Force { - return nil, err - } else { - // we need to fill solution with random values - var r fr.Element - _, _ = r.SetRandom() - for i := len(spr.Public) + len(spr.Secret); i < len(solution); i++ { - solution[i] = r - r.Double(&r) - } - } - } - - evaluationLDomainSmall, evaluationRDomainSmall, evaluationODomainSmall := evaluateLROSmallDomain(spr, pk, solution) + _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) + if err != nil { + return nil, err + } + + solution := _solution.(*cs.SparseR1CSSolution) + evaluationLDomainSmall := []fr.Element(solution.L) + evaluationRDomainSmall := []fr.Element(solution.R) + evaluationODomainSmall := []fr.Element(solution.O) // 2 - commit to lro blindedLCanonical, blindedRCanonical, blindedOCanonical, err := computeBlindedLROCanonical( @@ -98,9 +95,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen } // 3 - compute Z, challenges are derived using L, R, O + public inputs + fw, ok := fullWitness.Vector().(fr.Vector) + if !ok { + return nil, witness.ErrInvalidWitness + } dataFiatShamir := make([][fr.Bytes]byte, len(spr.Public)+3) for i := 0; i < len(spr.Public); i++ { - copy(dataFiatShamir[i][:], fullWitness[i].Marshal()) + copy(dataFiatShamir[i][:], fw[i].Marshal()) } copy(dataFiatShamir[len(spr.Public)][:], proof.LROpp[0].ID) copy(dataFiatShamir[len(spr.Public)+1][:], proof.LROpp[1].ID) @@ -143,7 +144,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen // alpha.SetUint64(11) evaluationQkCompleteDomainBigBitReversed := make([]fr.Element, pk.Domain[1].Cardinality) - copy(evaluationQkCompleteDomainBigBitReversed, fullWitness[:len(spr.Public)]) + copy(evaluationQkCompleteDomainBigBitReversed, fw[:len(spr.Public)]) copy(evaluationQkCompleteDomainBigBitReversed[len(spr.Public):], pk.LQkIncompleteDomainSmall[len(spr.Public):]) pk.Domain[0].FFTInverse(evaluationQkCompleteDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) fft.BitReverse(evaluationQkCompleteDomainBigBitReversed[:pk.Domain[0].Cardinality]) @@ -562,41 +563,6 @@ func computeBlindedZCanonical(l, r, o []fr.Element, pk *ProvingKey, beta, gamma } -// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. -// solution = [ public | secret | internal ] -func evaluateLROSmallDomain(spr *cs.SparseR1CS, pk *ProvingKey, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { - - s := int(pk.Domain[0].Cardinality) - - var l, r, o []fr.Element - l = make([]fr.Element, s) - r = make([]fr.Element, s) - o = make([]fr.Element, s) - s0 := solution[0] - - for i := 0; i < len(spr.Public); i++ { // placeholders - l[i] = solution[i] - r[i] = s0 - o[i] = s0 - } - offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // constraints - l[offset+i] = solution[spr.Constraints[i].L.WireID()] - r[offset+i] = solution[spr.Constraints[i].R.WireID()] - o[offset+i] = solution[spr.Constraints[i].O.WireID()] - } - offset += len(spr.Constraints) - - for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) - l[offset+i] = s0 - r[offset+i] = s0 - o[offset+i] = s0 - } - - return l, r, o - -} - // computeBlindedLROCanonical // l, r, o in canonical basis with blinding func computeBlindedLROCanonical( diff --git a/std/accumulator/merkle/verify_test.go b/std/accumulator/merkle/verify_test.go index 2b650a2ca8..51582df727 100644 --- a/std/accumulator/merkle/verify_test.go +++ b/std/accumulator/merkle/verify_test.go @@ -19,17 +19,18 @@ package merkle import ( "bytes" "crypto/rand" + "os" + "testing" + "github.com/consensys/gnark-crypto/accumulator/merkletree" "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/hash" - "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/consensys/gnark/logger" "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/test" - "os" - "testing" ) // MerkleProofTest used for testing only @@ -99,7 +100,7 @@ func TestVerify(t *testing.T) { os.Exit(-1) } - // verfiy the proof in plain go + // verify the proof in plain go verified := merkletree.VerifyProof(hGo, merkleRoot, proofPath, proofIndex, numLeaves) if !verified { t.Fatal("The merkle proof in plain go should pass") @@ -119,7 +120,7 @@ func TestVerify(t *testing.T) { t.Fatal(err) } logger.SetOutput(os.Stdout) - err = cc.IsSolved(w, backend.IgnoreSolverError(), backend.WithCircuitLogger(logger.Logger())) + err = cc.IsSolved(w, solver.WithLogger(logger.Logger())) if err != nil { t.Fatal(err) } diff --git a/std/algebra/fields_bls12377/e12.go b/std/algebra/fields_bls12377/e12.go index 64ed8fc024..9ae3ff02c7 100644 --- a/std/algebra/fields_bls12377/e12.go +++ b/std/algebra/fields_bls12377/e12.go @@ -20,7 +20,8 @@ import ( "math/big" bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377" - "github.com/consensys/gnark/backend/hint" + + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" ) @@ -464,7 +465,7 @@ var InverseE12Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { } func init() { - hint.Register(InverseE12Hint) + solver.RegisterHint(InverseE12Hint) } // Inverse e12 elmts @@ -537,7 +538,7 @@ var DivE12Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { } func init() { - hint.Register(DivE12Hint) + solver.RegisterHint(DivE12Hint) } // DivUnchecked e12 elmts diff --git a/std/algebra/fields_bls12377/e2.go b/std/algebra/fields_bls12377/e2.go index 067e8242c4..dcf9b95c02 100644 --- a/std/algebra/fields_bls12377/e2.go +++ b/std/algebra/fields_bls12377/e2.go @@ -21,7 +21,8 @@ import ( bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" - "github.com/consensys/gnark/backend/hint" + + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" ) @@ -154,7 +155,7 @@ var InverseE2Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { } func init() { - hint.Register(InverseE2Hint) + solver.RegisterHint(InverseE2Hint) } // Inverse e2 elmts @@ -196,7 +197,7 @@ var DivE2Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { } func init() { - hint.Register(DivE2Hint) + solver.RegisterHint(DivE2Hint) } // DivUnchecked e2 elmts diff --git a/std/algebra/fields_bls12377/e6.go b/std/algebra/fields_bls12377/e6.go index b8d15605e8..4fe8b911da 100644 --- a/std/algebra/fields_bls12377/e6.go +++ b/std/algebra/fields_bls12377/e6.go @@ -20,7 +20,8 @@ import ( "math/big" bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377" - "github.com/consensys/gnark/backend/hint" + + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" ) @@ -198,7 +199,7 @@ var DivE6Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { } func init() { - hint.Register(DivE6Hint) + solver.RegisterHint(DivE6Hint) } // DivUnchecked e6 elmts @@ -246,7 +247,7 @@ var InverseE6Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { } func init() { - hint.Register(InverseE6Hint) + solver.RegisterHint(InverseE6Hint) } // Inverse e6 elmts diff --git a/std/algebra/fields_bls24315/e12.go b/std/algebra/fields_bls24315/e12.go index 2a8583f3f8..569602c222 100644 --- a/std/algebra/fields_bls24315/e12.go +++ b/std/algebra/fields_bls24315/e12.go @@ -20,7 +20,7 @@ import ( "math/big" bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315" - "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" ) @@ -209,7 +209,7 @@ var InverseE12Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { } func init() { - hint.Register(InverseE12Hint) + solver.RegisterHint(InverseE12Hint) } // Inverse e12 elmts @@ -282,7 +282,7 @@ var DivE12Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { } func init() { - hint.Register(DivE12Hint) + solver.RegisterHint(DivE12Hint) } // DivUnchecked e12 elmts diff --git a/std/algebra/fields_bls24315/e2.go b/std/algebra/fields_bls24315/e2.go index b850ef025b..1ebd62b683 100644 --- a/std/algebra/fields_bls24315/e2.go +++ b/std/algebra/fields_bls24315/e2.go @@ -21,7 +21,7 @@ import ( bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" - "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/internal/utils" ) @@ -160,7 +160,7 @@ var DivE2Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { } func init() { - hint.Register(DivE2Hint) + solver.RegisterHint(DivE2Hint) } // DivUnchecked e2 elmts @@ -199,7 +199,7 @@ var InverseE2Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { } func init() { - hint.Register(InverseE2Hint) + solver.RegisterHint(InverseE2Hint) } // Inverse e2 elmts diff --git a/std/algebra/fields_bls24315/e24.go b/std/algebra/fields_bls24315/e24.go index d70722cb70..7394f86374 100644 --- a/std/algebra/fields_bls24315/e24.go +++ b/std/algebra/fields_bls24315/e24.go @@ -20,7 +20,7 @@ import ( "math/big" bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315" - "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" ) @@ -447,7 +447,7 @@ var InverseE24Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { } func init() { - hint.Register(InverseE24Hint) + solver.RegisterHint(InverseE24Hint) } // Inverse e24 elmts @@ -557,7 +557,7 @@ var DivE24Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { } func init() { - hint.Register(DivE24Hint) + solver.RegisterHint(DivE24Hint) } // DivUnchecked e24 elmts diff --git a/std/algebra/fields_bls24315/e4.go b/std/algebra/fields_bls24315/e4.go index 57abb6ccf8..8d9a2f3f33 100644 --- a/std/algebra/fields_bls24315/e4.go +++ b/std/algebra/fields_bls24315/e4.go @@ -20,7 +20,7 @@ import ( "math/big" bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315" - "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" ) @@ -165,7 +165,7 @@ var DivE4Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { } func init() { - hint.Register(DivE4Hint) + solver.RegisterHint(DivE4Hint) } // DivUnchecked e4 elmts @@ -208,7 +208,7 @@ var InverseE4Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { } func init() { - hint.Register(InverseE4Hint) + solver.RegisterHint(InverseE4Hint) } // Inverse e4 elmts diff --git a/std/algebra/sw_bls12377/g1.go b/std/algebra/sw_bls12377/g1.go index 303315a833..fcaef42445 100644 --- a/std/algebra/sw_bls12377/g1.go +++ b/std/algebra/sw_bls12377/g1.go @@ -22,7 +22,8 @@ import ( "github.com/consensys/gnark-crypto/ecc" bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" - "github.com/consensys/gnark/backend/hint" + + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" ) @@ -228,7 +229,7 @@ var DecomposeScalarG1 = func(scalarField *big.Int, inputs []*big.Int, res []*big } func init() { - hint.Register(DecomposeScalarG1) + solver.RegisterHint(DecomposeScalarG1) } // varScalarMul sets P = [s] Q and returns P. diff --git a/std/algebra/sw_bls12377/g2.go b/std/algebra/sw_bls12377/g2.go index fcfcdbcf20..e7b892027f 100644 --- a/std/algebra/sw_bls12377/g2.go +++ b/std/algebra/sw_bls12377/g2.go @@ -21,7 +21,8 @@ import ( "github.com/consensys/gnark-crypto/ecc" bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377" - "github.com/consensys/gnark/backend/hint" + + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/algebra/fields_bls12377" ) @@ -243,7 +244,7 @@ var DecomposeScalarG2 = func(scalarField *big.Int, inputs []*big.Int, res []*big } func init() { - hint.Register(DecomposeScalarG2) + solver.RegisterHint(DecomposeScalarG2) } // varScalarMul sets P = [s] Q and returns P. diff --git a/std/algebra/sw_bls24315/g1.go b/std/algebra/sw_bls24315/g1.go index 1e8b12fd0e..58f24baead 100644 --- a/std/algebra/sw_bls24315/g1.go +++ b/std/algebra/sw_bls24315/g1.go @@ -22,7 +22,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" - "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" ) @@ -228,7 +228,7 @@ var DecomposeScalarG1 = func(scalarField *big.Int, inputs []*big.Int, res []*big } func init() { - hint.Register(DecomposeScalarG1) + solver.RegisterHint(DecomposeScalarG1) } // varScalarMul sets P = [s] Q and returns P. diff --git a/std/algebra/sw_bls24315/g2.go b/std/algebra/sw_bls24315/g2.go index 001fe45f5d..a9d39cdb47 100644 --- a/std/algebra/sw_bls24315/g2.go +++ b/std/algebra/sw_bls24315/g2.go @@ -21,7 +21,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315" - "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/algebra/fields_bls24315" ) @@ -243,7 +243,7 @@ var DecomposeScalarG2 = func(scalarField *big.Int, inputs []*big.Int, res []*big } func init() { - hint.Register(DecomposeScalarG2) + solver.RegisterHint(DecomposeScalarG2) } // varScalarMul sets P = [s] Q and returns P. diff --git a/std/algebra/twistededwards/scalarmul_glv.go b/std/algebra/twistededwards/scalarmul_glv.go index b429d866ce..7b959a2db4 100644 --- a/std/algebra/twistededwards/scalarmul_glv.go +++ b/std/algebra/twistededwards/scalarmul_glv.go @@ -22,7 +22,7 @@ import ( "sync" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" ) @@ -82,7 +82,7 @@ var DecomposeScalar = func(scalarField *big.Int, inputs []*big.Int, res []*big.I } func init() { - hint.Register(DecomposeScalar) + solver.RegisterHint(DecomposeScalar) } // ScalarMul computes the scalar multiplication of a point on a twisted Edwards curve diff --git a/std/commitments/fri/utils.go b/std/commitments/fri/utils.go index 13efcf98d9..24c0716073 100644 --- a/std/commitments/fri/utils.go +++ b/std/commitments/fri/utils.go @@ -3,7 +3,7 @@ package fri import ( "math/big" - "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" ) @@ -84,5 +84,5 @@ var DeriveQueriesPositions = func(_ *big.Int, inputs []*big.Int, res []*big.Int) } func init() { - hint.Register(DeriveQueriesPositions) + solver.RegisterHint(DeriveQueriesPositions) } diff --git a/std/groth16_bls12377/verifier_test.go b/std/groth16_bls12377/verifier_test.go index 10bcd53d8b..61bc403ca5 100644 --- a/std/groth16_bls12377/verifier_test.go +++ b/std/groth16_bls12377/verifier_test.go @@ -22,7 +22,6 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" - "github.com/consensys/gnark/backend" "github.com/consensys/gnark/constraint" cs_bls12377 "github.com/consensys/gnark/constraint/bls12-377" "github.com/consensys/gnark/frontend" @@ -86,7 +85,8 @@ func generateBls12377InnerProof(t *testing.T, vk *groth16_bls12377.VerifyingKey, t.Fatal(err) } - _proof, err := groth16_bls12377.Prove(r1cs.(*cs_bls12377.R1CS), &pk, witness.Vector().(fr.Vector), backend.ProverConfig{}) + //_proof, err := groth16_bls12377.Prove(r1cs.(*cs_bls12377.R1CS), &pk, witness.Vector().(fr.Vector), backend.ProverConfig{}) + _proof, err := groth16_bls12377.Prove(r1cs.(*cs_bls12377.R1CS), &pk, witness) if err != nil { t.Fatal(err) } diff --git a/std/groth16_bls24315/verifier_test.go b/std/groth16_bls24315/verifier_test.go index 7144014e8d..18da40b4b4 100644 --- a/std/groth16_bls24315/verifier_test.go +++ b/std/groth16_bls24315/verifier_test.go @@ -22,7 +22,6 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" - "github.com/consensys/gnark/backend" "github.com/consensys/gnark/constraint" cs_bls24315 "github.com/consensys/gnark/constraint/bls24-315" "github.com/consensys/gnark/frontend" @@ -87,7 +86,7 @@ func generateBls24315InnerProof(t *testing.T, vk *groth16_bls24315.VerifyingKey, t.Fatal(err) } - _proof, err := groth16_bls24315.Prove(r1cs.(*cs_bls24315.R1CS), &pk, witness.Vector().(fr.Vector), backend.ProverConfig{}) + _proof, err := groth16_bls24315.Prove(r1cs.(*cs_bls24315.R1CS), &pk, witness) if err != nil { t.Fatal(err) } diff --git a/std/hints.go b/std/hints.go index b4b16ae52f..c3bdc3713b 100644 --- a/std/hints.go +++ b/std/hints.go @@ -3,7 +3,7 @@ package std import ( "sync" - "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/std/algebra/sw_bls12377" "github.com/consensys/gnark/std/algebra/sw_bls24315" "github.com/consensys/gnark/std/math/bits" @@ -22,16 +22,16 @@ func RegisterHints() { } func registerHints() { - // note that importing these packages may already trigger a call to hint.Register(...) - hint.Register(sw_bls24315.DecomposeScalarG1) - hint.Register(sw_bls12377.DecomposeScalarG1) - hint.Register(sw_bls24315.DecomposeScalarG2) - hint.Register(sw_bls12377.DecomposeScalarG2) - hint.Register(bits.NTrits) - hint.Register(bits.NNAF) - hint.Register(bits.IthBit) - hint.Register(bits.NBits) - hint.Register(selector.MuxIndicators) - hint.Register(selector.MapIndicators) - hint.Register(emulated.GetHints()...) + // note that importing these packages may already trigger a call to solver.RegisterHint(...) + solver.RegisterHint(sw_bls24315.DecomposeScalarG1) + solver.RegisterHint(sw_bls12377.DecomposeScalarG1) + solver.RegisterHint(sw_bls24315.DecomposeScalarG2) + solver.RegisterHint(sw_bls12377.DecomposeScalarG2) + solver.RegisterHint(bits.NTrits) + solver.RegisterHint(bits.NNAF) + solver.RegisterHint(bits.IthBit) + solver.RegisterHint(bits.NBits) + solver.RegisterHint(selector.MuxIndicators) + solver.RegisterHint(selector.MapIndicators) + solver.RegisterHint(emulated.GetHints()...) } diff --git a/std/hints_test.go b/std/hints_test.go index f88779b231..64bf7b362d 100644 --- a/std/hints_test.go +++ b/std/hints_test.go @@ -10,7 +10,7 @@ func ExampleRegisterHints() { var ccs constraint.ConstraintSystem // since package bits is not imported, the hint NNAF is not registered - // --> hint.Register(bits.NNAF) + // --> solver.RegisterHint(bits.NNAF) // rather than to keep track on which hints are needed, a prover/solver service can register all // gnark/std hints with this call RegisterHints() diff --git a/std/math/bits/conversion_binary.go b/std/math/bits/conversion_binary.go index 5d93af06c6..88edb6b504 100644 --- a/std/math/bits/conversion_binary.go +++ b/std/math/bits/conversion_binary.go @@ -3,14 +3,14 @@ package bits import ( "math/big" - "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" ) func init() { // register hints - hint.Register(IthBit) - hint.Register(NBits) + solver.RegisterHint(IthBit) + solver.RegisterHint(NBits) } // ToBinary is an alias of ToBase(api, Binary, v, opts) diff --git a/std/math/bits/conversion_ternary.go b/std/math/bits/conversion_ternary.go index 302868361b..f71cbf74fe 100644 --- a/std/math/bits/conversion_ternary.go +++ b/std/math/bits/conversion_ternary.go @@ -4,7 +4,7 @@ import ( "math" "math/big" - "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" ) @@ -13,7 +13,7 @@ import ( var NTrits = nTrits func init() { - hint.Register(NTrits) + solver.RegisterHint(NTrits) } // ToTernary is an alias of ToBase(api, Ternary, v, opts...) diff --git a/std/math/bits/naf.go b/std/math/bits/naf.go index b8e21ed965..fdabb71bb6 100644 --- a/std/math/bits/naf.go +++ b/std/math/bits/naf.go @@ -4,7 +4,7 @@ import ( "errors" "math/big" - "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" ) @@ -13,7 +13,7 @@ import ( var NNAF = nNaf func init() { - hint.Register(NNAF) + solver.RegisterHint(NNAF) } // ToNAF returns the NAF decomposition of given input. diff --git a/std/math/emulated/doc_example_field_test.go b/std/math/emulated/doc_example_field_test.go index b6f3b8a18e..338c18b4ec 100644 --- a/std/math/emulated/doc_example_field_test.go +++ b/std/math/emulated/doc_example_field_test.go @@ -6,6 +6,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/groth16" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/consensys/gnark/std/math/emulated" @@ -61,7 +62,7 @@ func ExampleField() { } else { fmt.Println("setup done") } - proof, err := groth16.Prove(ccs, pk, witnessData, backend.WithHints(emulated.GetHints()...)) + proof, err := groth16.Prove(ccs, pk, witnessData, backend.WithSolverOptions(solver.WithHints(emulated.GetHints()...))) if err != nil { panic(err) } else { diff --git a/std/math/emulated/hints.go b/std/math/emulated/hints.go index 9e799e4e17..9901aab49f 100644 --- a/std/math/emulated/hints.go +++ b/std/math/emulated/hints.go @@ -4,7 +4,7 @@ import ( "fmt" "math/big" - "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" ) @@ -12,12 +12,12 @@ import ( // inside a func, then it becomes anonymous and hint identification is screwed. func init() { - hint.Register(GetHints()...) + solver.RegisterHint(GetHints()...) } // GetHints returns all hint functions used in the package. -func GetHints() []hint.Function { - return []hint.Function{ +func GetHints() []solver.Hint { + return []solver.Hint{ DivHint, QuoHint, InverseHint, diff --git a/std/selector/multiplexer.go b/std/selector/multiplexer.go index 8e9bec5003..d76e291e4f 100644 --- a/std/selector/multiplexer.go +++ b/std/selector/multiplexer.go @@ -15,14 +15,14 @@ package selector import ( "math/big" - "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" ) func init() { // register hints - hint.Register(MuxIndicators) - hint.Register(MapIndicators) + solver.RegisterHint(MuxIndicators) + solver.RegisterHint(MapIndicators) } // Map is a key value associative array: the output will be values[i] such that keys[i] == queryKey. If keys does not diff --git a/test/assert.go b/test/assert.go index b6a077d2a1..e15fc4aab5 100644 --- a/test/assert.go +++ b/test/assert.go @@ -208,8 +208,6 @@ func (assert *Assert) ProverFailed(circuit frontend.Circuit, invalidAssignment f opt := assert.options(opts...) - popts := append(opt.proverOpts, backend.IgnoreSolverError()) - for _, curve := range opt.curves { // parse assignment @@ -237,40 +235,6 @@ func (assert *Assert) ProverFailed(circuit frontend.Circuit, invalidAssignment f assert.t.Parallel() err = ccs.IsSolved(invalidPublicWitness) mustError(err) - - switch b { - case backend.GROTH16: - pk, vk, err := groth16.Setup(ccs) - checkError(err) - - proof, _ := groth16.Prove(ccs, pk, invalidWitness, popts...) - - err = groth16.Verify(proof, vk, invalidPublicWitness) - mustError(err) - - case backend.PLONK: - srs, err := NewKZGSRS(ccs) - checkError(err) - - pk, vk, err := plonk.Setup(ccs, srs) - checkError(err) - - incorrectProof, _ := plonk.Prove(ccs, pk, invalidWitness, popts...) - err = plonk.Verify(incorrectProof, vk, invalidPublicWitness) - mustError(err) - - case backend.PLONKFRI: - - pk, vk, err := plonkfri.Setup(ccs) - checkError(err) - - incorrectProof, _ := plonkfri.Prove(ccs, pk, invalidWitness, popts...) - err = plonkfri.Verify(incorrectProof, vk, invalidPublicWitness) - mustError(err) - - default: - panic("backend not implemented") - } }, curve.String(), b.String()) } } @@ -306,7 +270,7 @@ func (assert *Assert) solvingSucceeded(circuit frontend.Circuit, validAssignment err = IsSolved(circuit, validAssignment, curve.ScalarField()) checkError(err) - err = ccs.IsSolved(validWitness, opt.proverOpts...) + err = ccs.IsSolved(validWitness, opt.solverOpts...) checkError(err) } @@ -352,7 +316,7 @@ func (assert *Assert) solvingFailed(circuit frontend.Circuit, invalidAssignment err = IsSolved(circuit, invalidAssignment, curve.ScalarField()) mustError(err) - err = ccs.IsSolved(invalidWitness, opt.proverOpts...) + err = ccs.IsSolved(invalidWitness, opt.solverOpts...) mustError(err) } diff --git a/test/engine.go b/test/engine.go index d8e5f36389..ece99f8bad 100644 --- a/test/engine.go +++ b/test/engine.go @@ -25,6 +25,7 @@ import ( "strconv" "strings" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/debug" "github.com/consensys/gnark/frontend/schema" "github.com/consensys/gnark/logger" @@ -33,7 +34,6 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/field/pool" "github.com/consensys/gnark/backend" - "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/internal/circuitdefer" "github.com/consensys/gnark/internal/kvstore" @@ -447,7 +447,7 @@ func (e *engine) print(sbb *strings.Builder, x interface{}) { } } -func (e *engine) NewHint(f hint.Function, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { +func (e *engine) NewHint(f solver.Hint, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { if nbOutputs <= 0 { return nil, fmt.Errorf("hint function must return at least one output") diff --git a/test/engine_test.go b/test/engine_test.go index fe91f550cf..a02b81ff34 100644 --- a/test/engine_test.go +++ b/test/engine_test.go @@ -7,7 +7,8 @@ import ( "github.com/consensys/gnark" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark/backend/hint" + + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/math/bits" ) @@ -28,13 +29,13 @@ func (circuit *hintCircuit) Define(api frontend.API) error { } a25b := res[0] - res, err = api.Compiler().NewHint(hint.InvZero, 1, circuit.A) + res, err = api.Compiler().NewHint(solver.InvZeroHint, 1, circuit.A) if err != nil { return fmt.Errorf("IsZero CircuitA: %w", err) } aInvZero := res[0] - res, err = api.Compiler().NewHint(hint.InvZero, 1, circuit.B) + res, err = api.Compiler().NewHint(solver.InvZeroHint, 1, circuit.B) if err != nil { return fmt.Errorf("IsZero, CircuitB") } diff --git a/test/options.go b/test/options.go index bcdae0eee8..c40104b886 100644 --- a/test/options.go +++ b/test/options.go @@ -19,10 +19,11 @@ package test import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" ) -// TestingOption defines option for altering the behaviour of Assert methods. +// TestingOption defines option for altering the behavior of Assert methods. // See the descriptions of functions returning instances of this type for // particular options. type TestingOption func(*testingConfig) error @@ -31,6 +32,7 @@ type testingConfig struct { backends []backend.ID curves []ecc.ID witnessSerialization bool + solverOpts []solver.Option proverOpts []backend.ProverOption compileOpts []frontend.CompileOption fuzzing bool @@ -83,6 +85,15 @@ func WithProverOpts(proverOpts ...backend.ProverOption) TestingOption { } } +// WithSolverOpts is a testing option which uses the given solverOpts when +// calling constraint system solver. +func WithSolverOpts(solverOpts ...solver.Option) TestingOption { + return func(opt *testingConfig) error { + opt.solverOpts = solverOpts + return nil + } +} + // WithCompileOpts is a testing option which uses the given compileOpts when // calling frontend.Compile in assertions. func WithCompileOpts(compileOpts ...frontend.CompileOption) TestingOption { diff --git a/test/solver_test.go b/test/solver_test.go index 2b9ec9de9d..9fb88da92d 100644 --- a/test/solver_test.go +++ b/test/solver_test.go @@ -1,17 +1,17 @@ package test import ( - "errors" "fmt" + "io" "math/big" "reflect" "strconv" "strings" "testing" - "github.com/consensys/gnark/backend" - "github.com/consensys/gnark/backend/hint" - cs "github.com/consensys/gnark/constraint/tinyfield" + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/debug" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" @@ -27,6 +27,11 @@ import ( // ignore witness size larger than this bound const permutterBound = 3 +// r1cs + sparser1cs +const nbSystems = 2 + +var builders [2]frontend.NewBuilder + func TestSolverConsistency(t *testing.T) { if testing.Short() { t.Skip("skipping R1CS solver test with testing.Short() flag set") @@ -51,15 +56,59 @@ func TestSolverConsistency(t *testing.T) { } } +// witness used for the permutter. It implements the Witness interface +// using mock methods (only the undererlying vector is required). +type permutterWitness struct { + vector any +} + +func (pw *permutterWitness) WriteTo(w io.Writer) (int64, error) { + return 0, nil +} + +func (pw *permutterWitness) ReadFrom(r io.Reader) (int64, error) { + return 0, nil +} + +func (pw *permutterWitness) MarshalBinary() ([]byte, error) { + return nil, nil +} + +func (pw *permutterWitness) UnmarshalBinary([]byte) error { + return nil +} + +func (pw *permutterWitness) Public() (witness.Witness, error) { + return pw, nil +} + +func (pw *permutterWitness) Vector() any { + return pw.vector +} + +func (pw *permutterWitness) ToJSON(s *schema.Schema) ([]byte, error) { + return nil, nil +} + +func (pw *permutterWitness) FromJSON(s *schema.Schema, data []byte) error { + return nil +} + +func (pw *permutterWitness) Fill(nbPublic, nbSecret int, values <-chan any) error { + return nil +} + +func newPermutterWitness(pv tinyfield.Vector) witness.Witness { + return &permutterWitness{ + vector: pv, + } +} + type permutter struct { - circuit frontend.Circuit - r1cs *cs.R1CS - scs *cs.SparseR1CS - witness []tinyfield.Element - hints []hint.Function - - // used to avoid allocations in R1CS solver - a, b, c []tinyfield.Element + circuit frontend.Circuit + constraintSystems [2]constraint.ConstraintSystem + witness []tinyfield.Element + hints []solver.Hint } // note that circuit will be mutated and this is not thread safe @@ -68,30 +117,36 @@ func (p *permutter) permuteAndTest(index int) error { for i := 0; i < len(tinyfieldElements); i++ { p.witness[index].SetUint64(tinyfieldElements[i]) if index == len(p.witness)-1 { + // we have a unique permutation + var errorSystems [2]error + var errorEngines [2]error - // solve the cs using R1CS solver - errR1CS := p.solveR1CS() - errSCS := p.solveSCS() + // 2 constraints systems + for k := 0; k < nbSystems; k++ { - // solve the cs using test engine - // first copy the witness in the circuit - copyWitnessFromVector(p.circuit, p.witness) - errEngine1 := isSolvedEngine(p.circuit, tinyfield.Modulus()) + errorSystems[k] = p.solve(k) - copyWitnessFromVector(p.circuit, p.witness) - errEngine2 := isSolvedEngine(p.circuit, tinyfield.Modulus(), SetAllVariablesAsConstants()) + // solve the cs using test engine + // first copy the witness in the circuit + copyWitnessFromVector(p.circuit, p.witness) + errorEngines[0] = isSolvedEngine(p.circuit, tinyfield.Modulus()) - if (errR1CS == nil) != (errEngine1 == nil) || - (errSCS == nil) != (errEngine1 == nil) || - (errEngine1 == nil) != (errEngine2 == nil) { + copyWitnessFromVector(p.circuit, p.witness) + errorEngines[1] = isSolvedEngine(p.circuit, tinyfield.Modulus(), SetAllVariablesAsConstants()) + + } + if (errorSystems[0] == nil) != (errorEngines[0] == nil) || + (errorSystems[1] == nil) != (errorEngines[0] == nil) || + (errorEngines[0] == nil) != (errorEngines[1] == nil) { return fmt.Errorf("errSCS :%s\nerrR1CS :%s\nerrEngine(const=false): %s\nerrEngine(const=true): %s\nwitness: %s", - formatError(errSCS), - formatError(errR1CS), - formatError(errEngine1), - formatError(errEngine2), + formatError(errorSystems[0]), + formatError(errorSystems[1]), + formatError(errorEngines[0]), + formatError(errorEngines[1]), formatWitness(p.witness)) } + } else { // recurse if err := p.permuteAndTest(index + 1); err != nil { @@ -125,28 +180,9 @@ func formatWitness(witness []tinyfield.Element) string { return sbb.String() } -func (p *permutter) solveSCS() error { - opt, err := backend.NewProverConfig(backend.WithHints(p.hints...)) - if err != nil { - return err - } - - _, err = p.scs.Solve(p.witness, opt) - return err -} - -func (p *permutter) solveR1CS() error { - opt, err := backend.NewProverConfig(backend.WithHints(p.hints...)) - if err != nil { - return err - } - - for i := 0; i < len(p.r1cs.Constraints); i++ { - p.a[i].SetZero() - p.b[i].SetZero() - p.c[i].SetZero() - } - _, err = p.r1cs.Solve(p.witness, p.a, p.b, p.c, opt) +func (p *permutter) solve(i int) error { + pw := newPermutterWitness(p.witness) + _, err := p.constraintSystems[i].Solve(pw, solver.WithHints(p.hints...)) return err } @@ -206,41 +242,30 @@ func copyWitnessFromVector(to frontend.Circuit, from []tinyfield.Element) { // ConsistentSolver solves given circuit with all possible witness combinations using internal/tinyfield // // Since the goal of this method is to flag potential solver issues, it is not exposed as an API for now -func consistentSolver(circuit frontend.Circuit, hintFunctions []hint.Function) error { +func consistentSolver(circuit frontend.Circuit, hintFunctions []solver.Hint) error { p := permutter{ circuit: circuit, hints: hintFunctions, } - // compile R1CS - ccs, err := frontend.Compile(tinyfield.Modulus(), r1cs.NewBuilder, circuit) - if err != nil { - return err - } - - p.r1cs = ccs.(*cs.R1CS) - - // witness len - n := len(p.r1cs.Public) - 1 + len(p.r1cs.Secret) - if n > permutterBound { - return nil - } + // compile the systems + for i := 0; i < nbSystems; i++ { - p.a = make([]tinyfield.Element, p.r1cs.GetNbConstraints()) - p.b = make([]tinyfield.Element, p.r1cs.GetNbConstraints()) - p.c = make([]tinyfield.Element, p.r1cs.GetNbConstraints()) - p.witness = make([]tinyfield.Element, n) + ccs, err := frontend.Compile(tinyfield.Modulus(), builders[i], circuit) + if err != nil { + return err + } + p.constraintSystems[i] = ccs - // compile SparseR1CS - ccs, err = frontend.Compile(tinyfield.Modulus(), scs.NewBuilder, circuit) - if err != nil { - return err - } + if i == 0 { // the -1 is only for r1cs... + n := ccs.GetNbPublicVariables() - 1 + ccs.GetNbSecretVariables() + if n > permutterBound { + return nil + } + p.witness = make([]tinyfield.Element, n) + } - p.scs = ccs.(*cs.SparseR1CS) - if (len(p.scs.Public) + len(p.scs.Secret)) != n { - return errors.New("mismatch of witness size for same circuit") } return p.permuteAndTest(0) @@ -255,4 +280,7 @@ func init() { for i := uint64(0); i < n; i++ { tinyfieldElements[i] = i } + + builders[0] = r1cs.NewBuilder + builders[1] = scs.NewBuilder } From 6ed8ac7281edab7ca6eed0519535873eeab1da6e Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Thu, 2 Mar 2023 10:17:25 +0100 Subject: [PATCH 040/464] refactor(sw_bls12377/ScalarMulBase): lazy-compute base point multiples --- std/algebra/sw_bls12377/g1.go | 6 +- std/algebra/sw_bls12377/inner.go | 518 +---------------------- std/algebra/sw_bls12377/inner_compute.go | 33 ++ 3 files changed, 40 insertions(+), 517 deletions(-) create mode 100644 std/algebra/sw_bls12377/inner_compute.go diff --git a/std/algebra/sw_bls12377/g1.go b/std/algebra/sw_bls12377/g1.go index 988af7a500..6b3bcdeca3 100644 --- a/std/algebra/sw_bls12377/g1.go +++ b/std/algebra/sw_bls12377/g1.go @@ -463,14 +463,14 @@ func (P *G1Affine) ScalarMulBase(api frontend.API, s frontend.Variable) *G1Affin // i = 1, 2 // gm[0] = 3g, gm[1] = 5g, gm[2] = 7g - res.X = api.Lookup2(sBits[1], sBits[2], points.G1x, points.G1mx[0], points.G1mx[1], points.G1mx[2]) - res.Y = api.Lookup2(sBits[1], sBits[2], points.G1y, points.G1my[0], points.G1my[1], points.G1my[2]) + res.X = api.Lookup2(sBits[1], sBits[2], points.G1x, points.G1m[0][0], points.G1m[1][0], points.G1m[2][0]) + res.Y = api.Lookup2(sBits[1], sBits[2], points.G1y, points.G1m[0][1], points.G1m[1][1], points.G1m[2][1]) for i := 3; i < 253; i++ { // gm[i] = [2^i]g tmp.X = res.X tmp.Y = res.Y - tmp.AddAssign(api, G1Affine{points.G1mx[i], points.G1my[i]}) + tmp.AddAssign(api, G1Affine{points.G1m[i][0], points.G1m[i][1]}) res.Select(api, sBits[i], tmp, res) } diff --git a/std/algebra/sw_bls12377/inner.go b/std/algebra/sw_bls12377/inner.go index 868126297e..b4ddb0553b 100644 --- a/std/algebra/sw_bls12377/inner.go +++ b/std/algebra/sw_bls12377/inner.go @@ -64,528 +64,18 @@ func getInnerCurveConfig(outerCurveScalarField *big.Int) *innerConfig { } type CurvePoints struct { - G1x *big.Int // base point x - G1y *big.Int // base point y - G1mx [253]*big.Int // m*base point x - G1my [253]*big.Int // m*base point y + G1x *big.Int // base point x + G1y *big.Int // base point y + G1m [][2]*big.Int // m*base point (x,y) } func GetBLS12377CurvePoints() CurvePoints { g1x, _ := new(big.Int).SetString("8848defe740a67c8fc6225bf87ff5485951e2caa9d41bb188282c8bd37cb5cd5481512ffcd394eeab9b16eb21be9ef", 16) g1y, _ := new(big.Int).SetString("1914a69c5102eff1f674f5d30afeec4bd7fb348ca3e52d96d182ad44fb82305c2fe3d3634a9591afd82de55559c8ea6", 16) - g13x, _ := new(big.Int).SetString("1252b781171f507db36291b433a1f911a46543890a20ca9712e11f66a5d216e63d817bd8d96cef715abc604dcf6ec2e", 16) - g13y, _ := new(big.Int).SetString("14a00fa77c727e8987cc438b51bbe012c823a19955ae692c54ce572a61f0ea1fe5cd981533df419fd1330d1f6e6d802", 16) - g15x, _ := new(big.Int).SetString("17052d4e3eb642d32ef4989af253cc2a30ad376ce8f0b23c92b987e95cc718d02072bb78d37c09fd76f7014eecf797", 16) - g15y, _ := new(big.Int).SetString("16c206be738bf4644faff10bb82b19f6f07779903a6ad2524809ce29f94683be32bbdd072ec0be66ae0ed0d8781f277", 16) - g17x, _ := new(big.Int).SetString("916932fceb94ad7b80fcf492aa5ee0e120410017cc6d17c8962ba2eb799260d022c3de5a103e6edbb5ee9135c7f0fa", 16) - g17y, _ := new(big.Int).SetString("18efb7c0b6e083030a858e3e8b4d1db5857a3f6c60f01691eb9783f6a1f1064069da2e220952121c771f276888d5137", 16) - g12To3x, _ := new(big.Int).SetString("18aff632c0048f5afb5c07fd197a44a127c829be3ff6170c6cebc1154bc72633b45de2ac855e0da30cebfa33672e7f3", 16) - g12To3y, _ := new(big.Int).SetString("efb82d5f13565755df1445db9ed4c4969f09bb31cc610f83eb1490be76ab3817808c52d98074f1a98ff896012a78ab", 16) - g12To4x, _ := new(big.Int).SetString("107db75ab97dcb352b7e3e0596950ec2793cb394f821b1a2e7d5f54d11da8215a998cc84736ddffed74f549052a9df4", 16) - g12To4y, _ := new(big.Int).SetString("7d8459036fefe53ffd95028a2be4f8588b07cd359b0955e1cbe986d4b1ee854e452d7c14f05c41b861266522e3e887", 16) - g12To5x, _ := new(big.Int).SetString("680fb4caec4a06f92a7f4f1e20624b4eaf74001df5ab3ca6f4b3fd9c2d49f257d3021400f5844e227d9763090d8cb", 16) - g12To5y, _ := new(big.Int).SetString("1a9a941bd20effaea30f547d27e433ddf0e29bad201877d54995e73586e8847aaadc0b521762db07fc7906d3c39ee80", 16) - g12To6x, _ := new(big.Int).SetString("56827fbf50c974fda74996e7415fb0fa6c653d0279ae5e0726c124b222837c6ff5fb12682ba380984981f2442100cd", 16) - g12To6y, _ := new(big.Int).SetString("962aa4e39307e00d9934914a1ae85e57513ac9f7b7dbd11003d67d62f288d92f5bd2aedad3a9686ce807efe6f8fba4", 16) - g12To7x, _ := new(big.Int).SetString("880497aa4f51a84c24fb4d92ef46819156918734858556807059b6f6d3e62d2e3f589f33d7f8c5f6af63a0f072629a", 16) - g12To7y, _ := new(big.Int).SetString("111c794e9d2397062f763482bec5584abb31f5b73090174dc22c8dce191c94362ed75492067209bd63044d40f694ad1", 16) - g12To8x, _ := new(big.Int).SetString("e5ddb0da4a5b32e245f78e95760c03227b976ed310ef3922624473d3ca4ea85429797e145692f87d5cb39b4e9a807c", 16) - g12To8y, _ := new(big.Int).SetString("ee67ff3335bffe5cba6953e23e9a1953ee9c1f37371c01a0ceca424f98566df7c353e1eead76435e7854af3fe89c3e", 16) - g12To9x, _ := new(big.Int).SetString("13c910dadc716133218967c098a8f2889817ea5688f68c1878cf6b97e903f728b65dd7b7a6ad65226ee2089a3317b4a", 16) - g12To9y, _ := new(big.Int).SetString("13324bef362a2a30fef824ea32e78c5c1e628842afd2fe67baae1e80fe7eabdbe97ef70a9606fe8db5359a607750b8c", 16) - g12To10x, _ := new(big.Int).SetString("134fb9a0098e3581953df24b0cb4a16306a4eea26bdb08b92b5fe28c35c178873e7a3b813e3579b417f780a7585a027", 16) - g12To10y, _ := new(big.Int).SetString("11e922e78cc7bbf317f9e3013d3c4d35a134d8ff2b94cd33450331a67f3585dd6c548b494f4eaa21f325e45d5d01912", 16) - g12To11x, _ := new(big.Int).SetString("14fe16f6fbc301389a2ce1cf4380af5eace02eb0be172c174e0e6e59f22259b861eefe33fcd031bf94d23d3622b19dc", 16) - g12To11y, _ := new(big.Int).SetString("aeb36e0a5f8b155febe62a45c6d318fae2a035999d0c309e163721431c4e2d2185db90329a3a644cbe7c07d5042c05", 16) - g12To12x, _ := new(big.Int).SetString("ab8d63c61ea2a57f78951d45eca6a177a7dd1c7b753587d1d7348c6f158fea835c5a2c9b4b39be911a900d9d71753e", 16) - g12To12y, _ := new(big.Int).SetString("10b05d822a9665013d90ad837b75171e8b491636943329c997822f58577adac847d95b7f188b11ca33d14fd5d3acec8", 16) - g12To13x, _ := new(big.Int).SetString("add361f77572a949e411d6435d8121daecb31402c58a7cc6ebb737c26a11d6bfb60ef1eb0e1226b8e4ff4d7a1f19a1", 16) - g12To13y, _ := new(big.Int).SetString("ad05daef21794dd0d33692eb4743bfe28c6c85090622926a547e5122ef41a1dddad4cba10b798f89579cb2348e9d57", 16) - g12To14x, _ := new(big.Int).SetString("63929f07e03764ea4b3b4baa6e504c2bc7588a2c7f3e2b1029e94caf03e5f20d41bb644edcdb8f6869527047984d6b", 16) - g12To14y, _ := new(big.Int).SetString("6a51e86ce05f6f4bf7761db5143323f36250a620a3c5132ec24fe0a0ccce5375eea48bf39a27141acd8a6339587186", 16) - g12To15x, _ := new(big.Int).SetString("9d656058092638a500e7febd7c820798ec2e7139b02a10083ab6593d915a4ec4293d023ba59192b49845c0512a6686", 16) - g12To15y, _ := new(big.Int).SetString("191cac9f967d935ab360a6f6e58381956a7f9497e2c67175c7710ccf4c2db22bfbc390090fdb568f0e182b30df1a280", 16) - g12To16x, _ := new(big.Int).SetString("1371622e52c4790930c0dc81051c5d922318a05a5dddf4035838f88368cae1178db6ddafef464a9bd035fbe22311be9", 16) - g12To16y, _ := new(big.Int).SetString("5a6cf187acfb8a91dd2130b0d8f4f617b1bb0f9beb1a29ea908cb24254e4e2a3e8c14c3c5cc20bc714a1bcdfed1535", 16) - g12To17x, _ := new(big.Int).SetString("127f9cd4d32d5b68839ad50475180b572cf5a64a298bef23b2ed972dbe8f65e33056e5476e8716252635b980cecd7c5", 16) - g12To17y, _ := new(big.Int).SetString("1738a6dd32253efa3621c81b81eb1d109a35a1d182a04be293b75bbdeabf7f3090d32b0bae41fb0bb317f5c7b669f8b", 16) - g12To18x, _ := new(big.Int).SetString("7a60c7c738fb264482fe46a69c514cc4cbbc83370890dc1cbf39567e8b34bf5c388313c82804d1c7261dc99b2801ab", 16) - g12To18y, _ := new(big.Int).SetString("d0ab238b768b54b095db2aca7acfa16ae26264066fe7be9547b76c855188a07d287d0031fdc40d57dab98c7d073bca", 16) - g12To19x, _ := new(big.Int).SetString("6042f781b85a81d10048c15da22c5069b880f6d1f6f5c54bd327760bc1b4daa247aca6c96bee7d20c8578220981ef", 16) - g12To19y, _ := new(big.Int).SetString("c20df594f36b4a18be4c2e759c55a1c08d08fdd8e7f0d228e282727518eba66383cd667811c0d5e4baf03455e46f99", 16) - g12To20x, _ := new(big.Int).SetString("141937e53eb28e9328d805dec48045a9f258c632aa4e4f360fea78d16850921b636fc52df323fcae8051385364cff58", 16) - g12To20y, _ := new(big.Int).SetString("f82e14368390d59c28fcfb130566a936b446e783877578d7e27e15c14614be38a5927329189abda212bd4576ae6421", 16) - g12To21x, _ := new(big.Int).SetString("94e187a31d02354de6787d1abffc8b9fdb62f8dd91a01fe0af6265736966d8ec181bd65863c2b0c3020c1c7c26a9ee", 16) - g12To21y, _ := new(big.Int).SetString("77cb65bade2f40dd98b6ee8d84aff95295647f5f2744e9691ee8013537f714df467010007b8479a018dce66ecf011", 16) - g12To22x, _ := new(big.Int).SetString("f574cd8336eb82714f7cfe446d239ee89bafbe52b6cb5e7dc839fba89cfb78187f1aacbf92dc4d772519e500d3faae", 16) - g12To22y, _ := new(big.Int).SetString("4e3073dfae73051d165648b65a1910c82d22e2344db0a906e98485883d11f12e061c84e99905fa09c3a73c1a0dff86", 16) - g12To23x, _ := new(big.Int).SetString("879b817a80faf83a690e7d4cc5c7f802bae36cc397bb4fc5210a48b23227821ffe5b5fd90f34b37aee8bea5b143a1e", 16) - g12To23y, _ := new(big.Int).SetString("1387d2b720763e114e58702c269ff61007ab33c1e6e7d5834f010b970fb70ed7bc469b2129e613ac2fd2d3a6a6e34d1", 16) - g12To24x, _ := new(big.Int).SetString("f1e52f2ceb352869eac2a752dd6bc47b84724b3f4e74df4b72db06d9000456571cd58b4a1332f0c99f40eb4893e5c9", 16) - g12To24y, _ := new(big.Int).SetString("60e7d9eb062783ba26ec00ed46179386b4225a129fd044f84f9d7984147879c80f6b8d70eb6d55e160d7bc2a5c1684", 16) - g12To25x, _ := new(big.Int).SetString("133f8d1a44d868b95891a82ab4cd2343ce38e370e48a256f232b0077b411a12922bb919c599e6c5a1f9a81395d7d054", 16) - g12To25y, _ := new(big.Int).SetString("1414246490ffe596f7c8db806833128a661e98dc52b62a694caca1df3644c135bd8946d933275f2642f81e03f645daf", 16) - g12To26x, _ := new(big.Int).SetString("12982253bcdcfc660df538b5d004eb6bf283dbaf7788eec8d958bf77f10067e1f62ccc3194a65b0120fe15e92695667", 16) - g12To26y, _ := new(big.Int).SetString("97ec4a1c3de3030096011e1cce00814d216b19659fe3cb5eac04df4a12cf5e1f36ee47cd8acc02e51d031a65a17114", 16) - g12To27x, _ := new(big.Int).SetString("bafb585867ed534280a3a898ab8e7b8d6d0b393add86ba307b150dfaee25eea932e3a744d01b9d18950cc3f5670e4b", 16) - g12To27y, _ := new(big.Int).SetString("ba377e08bcc57ed719d82ffde026ea1c0fa3f3ec44e5e587507531731eb815ca6712e9eb92dfa63864b570e10e735", 16) - g12To28x, _ := new(big.Int).SetString("43ddf8732e7a29888831d1923985991bf6a9dc2fbe7916b12c8d676fafb96025023eeba8e208ff582fafefbd2af2bc", 16) - g12To28y, _ := new(big.Int).SetString("156dc34ce172d5dcdde35e9f77e0f23a3410f164b4ca2fdded4ffef71cd6c8be6605bbb2eb66522c15c7db50be316c4", 16) - g12To29x, _ := new(big.Int).SetString("13d7c2e8c14d861444f01eb7137520d1fc91ffd61c1c798710af6be926acc53921523d48708f41edb321ec779a2a92e", 16) - g12To29y, _ := new(big.Int).SetString("1108bb151007ff0b724046c4d5a641fbfe6e6a3bd71d3e1284cacc8e416a5fdedb4ed2693aded3d457d8ac72906070a", 16) - g12To30x, _ := new(big.Int).SetString("d2716f627351a4863060ab6777b148610d94e1b48b1607350f0098cc1289939097e4c3968506d152627350593d11a5", 16) - g12To30y, _ := new(big.Int).SetString("e64f79eb0f4d2fe93594259c1bc28f418a7ebd0a60769042315cac1fd6a1131e69ac868568526c3107c9176bab0c05", 16) - g12To31x, _ := new(big.Int).SetString("16c405bdc35a13c07c1157145face8ee9d13e41bb9e243d9a02c1900f26c7c062570cf56e1e992aab2b3bfbb61d387e", 16) - g12To31y, _ := new(big.Int).SetString("9c4f95f7c2c3fe1a4ac36d90ef98612c0691f3ed2ca212e9e1d38345606c2416652f5d8531bffbfbe1437f133b4e12", 16) - g12To32x, _ := new(big.Int).SetString("969e8eb9ce543735eb543a770a40903c3755d2e28c6c8ea9318440f2ea087f458f4b6f071aac44906b2a887d1a69a4", 16) - g12To32y, _ := new(big.Int).SetString("19f9bc3859f6781918a79e836d745c8787ba8b11c355e49e66b64e54428817e9fbbba06333e26d6b5dbd5fa6d7ea2f2", 16) - g12To33x, _ := new(big.Int).SetString("f14b7e7af6fa1d295f7b6ac8b1badf1fa3d65de31e79e94e69f02f21589642505a00ae1868525566cecce45fd62e44", 16) - g12To33y, _ := new(big.Int).SetString("1a115f0aa272d645be22ee308865c893e575c01aa55ace3410fd3e751a4e610655884c0a97427f37c9dcd90338b1626", 16) - g12To34x, _ := new(big.Int).SetString("148e97cb2504eb135a392a36e995694e281e727919ac5736e3f5dc45bd857e1a2b1fd48984147f762ff5a08e9eff340", 16) - g12To34y, _ := new(big.Int).SetString("18818155deaebb73bb615991f4aa7eb7750b2186f12d0aca0f56ecc22e7fb1cc4086d7fbf5da6cb8d12dfea5047975a", 16) - g12To35x, _ := new(big.Int).SetString("1826fdb3058eed244014b2cc2e84a61cfd4f4ec0e502e81ad5279246a8df015171bb35d70b4d21f0778b2bd46bba947", 16) - g12To35y, _ := new(big.Int).SetString("1511d311e43642cfa8ddc23dada8d387c5ebedbf1f96e22fea67c841550227148533e983b310f8287e50ef5462aef4d", 16) - g12To36x, _ := new(big.Int).SetString("1afe7f02e75acba6bb817bf762fddb0c50ed73ee7ad2abd3eb648a624dbb3649a70f8a0bed77b364dc64d5670e12c9", 16) - g12To36y, _ := new(big.Int).SetString("1141907296b72c2969a79f29523d5378b7c2323e87b93a667ccc0ece9f62a3bf7448dd8b2222a077de60f5245b0ab26", 16) - g12To37x, _ := new(big.Int).SetString("eaab1bcb93f8e64dd8dd822119af39e6db14b06a0dfda84a8948038412ce5f5e2e3d89492eec2242e2730c81e8651f", 16) - g12To37y, _ := new(big.Int).SetString("17f4f5be515e6bf8037faec8f667ee63a786a59688ea502ef4da6131ce63aaf4355b55e7dfa52f16c374105fb8bf924", 16) - g12To38x, _ := new(big.Int).SetString("1a5b9caa4a74b679c4186aadfcc8d05408728e9caf463724e9a9e8468d13f4e2895f0d0eb386a749009b7d6e5b2e75f", 16) - g12To38y, _ := new(big.Int).SetString("47e7ef7de6058e4ab1b2655164ae9df1cb3865dd5049f604b68cf77ea65a079ada29e524ed864792f7bf22283634a", 16) - g12To39x, _ := new(big.Int).SetString("14fcd5c9fda9b70d081e0b955145e5f5f7a15b4ca4f22e284a8c13bd7add0c67eec7bbd901e33991d94a8838638a9e7", 16) - g12To39y, _ := new(big.Int).SetString("ddfdb26ac57951cebfe2394dd4dd4d27c6efec24b70b1208b2dc5ca1f867974f3e8eec4050eb21af8497860af54d", 16) - g12To40x, _ := new(big.Int).SetString("252bee9b6ef8f22112ed489d3f56f08cc662d26783e4dfb44c65e5effe63e35e7df58894ff7c3e861dae155d0a021f", 16) - g12To40y, _ := new(big.Int).SetString("2bb53e9d3d1b2d87b5d1e237d39c3920dd4fbf9c34ca9b526b82472681c4c316e93a705dc28f2b6a262f21bf4138ce", 16) - g12To41x, _ := new(big.Int).SetString("174acac12c03f292f9c8c9ef1be3a1127fd64726cb9a3da1c37d18a0474830c5bdd294671a31e09670a0a9a357f640f", 16) - g12To41y, _ := new(big.Int).SetString("15cafb6ce83da980dbbbe486269ce721e9ae2d32b33773705904a74ab223df23e26b7655ff55d0c1ace86a72b4f6cfc", 16) - g12To42x, _ := new(big.Int).SetString("aa5ae22e7da20eb760d8be899a537d78c7f76aef985f6afa881020e7169a6960284c42bb5bf3301029b7ea78ddbab2", 16) - g12To42y, _ := new(big.Int).SetString("3cb9cf41a120b481b419ceda853a508337f74a91500f881629c0cb16c9be10b352929006ae300b93263ba01b378517", 16) - g12To43x, _ := new(big.Int).SetString("182b1745e5f859974d7ecbcec4da576a01cb5883ba5bae584709bd2e45d8eef002e4b093d8324372143460b4d0e4d5", 16) - g12To43y, _ := new(big.Int).SetString("187934573dca1cabc7a250d3e53091e9269009e3edfd0dc0ca2bc4843c1db9c0d7582c55dcc9a113728a37b4c7957b6", 16) - g12To44x, _ := new(big.Int).SetString("9008e86f9a7abb2b70044f3ea1565f3fe7df01bf46778f3a216a3605292382614dd4e807501c514760495f1fbad362", 16) - g12To44y, _ := new(big.Int).SetString("fe0c7b627908402489f139e577d86c527f9022a81cf6d4b20839b2886aeb4ade6cda54ddedab603a331acda5dc9997", 16) - g12To45x, _ := new(big.Int).SetString("db1db669a0f65547c0ef181afddcd6af4ebaae9a0b0977ac99aca37286bd94d9d14ee0a67de9f64d647ed58620aa46", 16) - g12To45y, _ := new(big.Int).SetString("1604ae03716ae90daa4711695fd86138eaaa4d03d3bf85217586783c77acad34497b1e89bab3c26036cc780b95cf98e", 16) - g12To46x, _ := new(big.Int).SetString("a961a93d8d69857b45972c45e7da4cc98fa11a28ef93b391bce2b4d7bb7472cf8dad04b0833443717085fbb14b8a0c", 16) - g12To46y, _ := new(big.Int).SetString("1222d52c8fb984fb00c1ebae3b66f52144b030bb2c28a304cbaa8a5335cd797cdb519cbcb6df298ff7ef426c80d53d6", 16) - g12To47x, _ := new(big.Int).SetString("605fbf7d4a4865e18a349f6af474d04c53ccd15aef07dc5c63d0aeaa9e35c732d5c25dce539d1018a8eb5ba1a1e703", 16) - g12To47y, _ := new(big.Int).SetString("1673edb028fae78421ab69bbf1d4c2116d0977a486f911a30354a6c6c74341c0a081dc604fdd130f1dbea16158a14c0", 16) - g12To48x, _ := new(big.Int).SetString("16b32d15667fbf3b37d2fd42b9648b8d12c1e8380df504dd6d1bb74387e615190aa158e31557e26710bddd3f62c448", 16) - g12To48y, _ := new(big.Int).SetString("1a96b7fb2441a65a1507e7b63bed23aa162ed2cc002553292d5b9009b1ccccebb7c597b12e1303afe406cad47d14b76", 16) - g12To49x, _ := new(big.Int).SetString("1ac0e778e13331dc87c9ec5c9eb608894f5ccb3448b6e537ef0481cd6534873c65c3b90265eeb87aefe7e0b6719df47", 16) - g12To49y, _ := new(big.Int).SetString("1374cc9941ddc21bf5d7fe0d3f6863d55084da5d3270756b2239d03dc0fe22ea67127f7eb04900e676d687f1479c4f", 16) - g12To50x, _ := new(big.Int).SetString("f2a9a16712080ab0597457b86c31c890fa22f1c512a9dda284f4d5b307742092ed7cf6e17e09a02e405bcb285aba7d", 16) - g12To50y, _ := new(big.Int).SetString("e6e13736ec424657d9f75e2e4817786a58c432f021b61c8a448af8b8f4d861dc0fe23cfde02b655fe8394d27b40ec9", 16) - g12To51x, _ := new(big.Int).SetString("2677277410ccf8b96bdd183733368cae50e14b757616979ee0975aa9e4201fdd12b86256c9f9a143653e1cc620a85", 16) - g12To51y, _ := new(big.Int).SetString("cd1b38e1e3b2e1067822422ba488a83c851a4f6d29680947fcac986ef07fa3148817a3840894b82daa4da2e274e94a", 16) - g12To52x, _ := new(big.Int).SetString("281b180d9e4aae07f4d6c11e679744d92592c26a6fb90692fe12f10eb16b58916ca87e74c9c0bd03887de8e2e45d0f", 16) - g12To52y, _ := new(big.Int).SetString("11101677eb41c6ca2c60d14456cfc148b4758a7dc86bb3f596d0afbf9677e403d9e8cbb9ad3afb08499e58ae295e9df", 16) - g12To53x, _ := new(big.Int).SetString("f1cc005ed80694095b1a61ba7e9700676450f5693e403aa9bba34b10be09111151dd9f4448d6bb287aabe37365d1c0", 16) - g12To53y, _ := new(big.Int).SetString("1a3e52c9f74db8b43d80c20e054c3a4849a441bebc44d444f4e7460036c46a1743320d75af77e11bb43ff521663aa29", 16) - g12To54x, _ := new(big.Int).SetString("7617573decd671474599623dd69aa96fe82794763eb49d2443f182428c6227145b7b6389cff20f9f46832fd2dbfcae", 16) - g12To54y, _ := new(big.Int).SetString("1a92a1f480f7d985d4e1abe80af96adf0e475571b80e99456d75b4218ee0c1e363afdd161789756f618f78cba51dd03", 16) - g12To55x, _ := new(big.Int).SetString("adff1ee838fd0e69694d32df4364308fec2313cd57c641367615c74f069f343a0c4888235308f22901084d9bcea913", 16) - g12To55y, _ := new(big.Int).SetString("9301a7eee38fe353161f286347647d566f8949fea78942d854a9b5c1639daeb83242ef6424caaba2095532f66b2e5b", 16) - g12To56x, _ := new(big.Int).SetString("2fd8f21f20fa1e949001314366e933d619b6e421c67c0bee21da9ef0d0318cec8fef099803b8e5629accd6d6b78e1c", 16) - g12To56y, _ := new(big.Int).SetString("ced044196c59388c333e8a0b17f9b9ee3c38ebee8c9c22b5be43c40737c6c9de7984b14c8f39127bc1c073ee60e25d", 16) - g12To57x, _ := new(big.Int).SetString("12d8246a5064c33a3b6e9be28e650715f2c62b696c90acc014ef9a2700bc1c7012f777b6af6d59949b3e0d87c1e88fe", 16) - g12To57y, _ := new(big.Int).SetString("19dbac773f76ba1a8c485090b6b10f9bc3110fe48e380da71a6b7f0336c4c818a3803126caadd7d3effecccf667097c", 16) - g12To58x, _ := new(big.Int).SetString("381bab5aa65d2b159bb82883559754e5fe26003013389761496d63eea249701c1b1eb742a28f529d6fea8c1b0aa726", 16) - g12To58y, _ := new(big.Int).SetString("7a43f15f319df3d07beadbe688619ac1ca80c76e472ea0d76555d200cc8f2c4e0b9a77065dbd41542d3dc7f0099622", 16) - g12To59x, _ := new(big.Int).SetString("eb3ba48bcae37c9ca7d0c66d42cd4f7a66640f14da2f439b7b1c27a05af916e818ba28eab92bf632f458eb02b962fb", 16) - g12To59y, _ := new(big.Int).SetString("fe6a0dddf3767c9f743eb544204739ddc4f9171c85cedf5f45f94d2fc2124df60c37ea0757ee4fdc98d1289f615b79", 16) - g12To60x, _ := new(big.Int).SetString("f64fccc7b7e1170569fa4ea7de6a25952252fdf82c1de13a3884a3384780d310d2ab52f42a15b46ef642f368b46f5d", 16) - g12To60y, _ := new(big.Int).SetString("a871d03f47a1889ce201513c353519e0cae34edea28f150f76b682c9b361feded8357d3bfdf5fff761ad18350fecad", 16) - g12To61x, _ := new(big.Int).SetString("138b8b61f53ba70e7b76545b01cf7ad7741eccb5ec524efd9d9a40d098c26c5fe99aff1565f5e66c331825dcd2c6f89", 16) - g12To61y, _ := new(big.Int).SetString("11360c12c63ce8faf10c63922afafb010bc325df0ae89fa87b8219dcac998e1add68d301475d12a483c85b48ae67068", 16) - g12To62x, _ := new(big.Int).SetString("18ec134222d187af5a8ede9ce9d4ab16c0a8e6c2113c92d6410e592b84c8df883cc6c05ae301e1f2e3c025eacc52b7a", 16) - g12To62y, _ := new(big.Int).SetString("1294ae9fe885df3c37931412484804feee91610b48fdd111baf15b5196ae8f5b7b16169ddac187c0447eb800127aa12", 16) - g12To63x, _ := new(big.Int).SetString("65813a9ec5492e7d799bafaf677f69d4630e24e47fe86ec0223181acc6ce0100e2de4a09db66616a01b48f7ab8b357", 16) - g12To63y, _ := new(big.Int).SetString("104147600c7118a89a55b524b254c8e14b17487b056f8a25cf793a7e6e4b44e137105a694d5421609fc5fa1d84edfbc", 16) - g12To64x, _ := new(big.Int).SetString("16ca0fa8a6de67c61d26f4263fe963c97726c7cd420b971b60fa3d8f19eeac52a059967f721c3f2f5cfd291eff79f95", 16) - g12To64y, _ := new(big.Int).SetString("1024b7a78a4be6db33eed9b9b0d6281408c344a3b7d7e50abb37b2766d3b6ec53321a398bc4abfb39589d73763fe4ad", 16) - g12To65x, _ := new(big.Int).SetString("ef930907a7c98f8ff74b03a671cf3e9f1ede0cc83fb570ef632f8c1808e03c623eebd12aeb80cab653ef808bfdaadf", 16) - g12To65y, _ := new(big.Int).SetString("163eaed12715d8b4e6669ed4d436ebf5a6e88d194081460ac58c43226c75b07e4d2d46f2afd5d092c5061ed5ada80fb", 16) - g12To66x, _ := new(big.Int).SetString("e55f91871935265fc666add9109b85a295b92dd1275e210e6752b88103551bb4a5054a820a8a7bea707b8152642d0f", 16) - g12To66y, _ := new(big.Int).SetString("3217a82630c2b2dcec5561f1af239b10612bd41f78cd69b109b90107d31c7bf25b7d822c629864c2b9ae95ddd9c6d4", 16) - g12To67x, _ := new(big.Int).SetString("32b0d40116e34b3c7001c348d371556b91b72af41555188ea23d442cf1748e80343e73af832f8ddd660b478aef3a82", 16) - g12To67y, _ := new(big.Int).SetString("190793652b804b0744c796f9c28b4ca77ae6c2c896c0b6420ca4802b270d322120313e4db6baddb5526b91479a69ef2", 16) - g12To68x, _ := new(big.Int).SetString("14db8a6116888ad28268bea38946ba5ddf9fdfec15250a3618f013233b12b2599934f639caa52e14ce78e65e4aca34c", 16) - g12To68y, _ := new(big.Int).SetString("11a146093cd40fdaa65c6ff93b3197cad47192f0645b8a5982a8abd9a15cae80167daf818ee820b02c31e42c10e9a98", 16) - g12To69x, _ := new(big.Int).SetString("721597f56b47a9b81055cbb92f68bd0f856d3314097b5008e255402093cecef95e10f34c66e9cf2c4636a5955f0401", 16) - g12To69y, _ := new(big.Int).SetString("9df9b789e238433aedccdb8996b9013095a5c72debc3d4161dc5517e3139352016137ebe5f1b88c7bccb464ae5932c", 16) - g12To70x, _ := new(big.Int).SetString("542bac3be82ab5260e405a2e37ce13ea57ec69523d412e640d6d44538c32b963d3536abb12d0796508013060181ab1", 16) - g12To70y, _ := new(big.Int).SetString("178910c28886167aaf6a3d2057951e5a046c2a2c90a621eda94c097b1b4b126f1dfe67f5efd496b244b9ebe02aff90a", 16) - g12To71x, _ := new(big.Int).SetString("c86c8ddd50b04e5bb33b5af20301eba97254ffb0f7f2190c2e4dc61fbda6560a4c6508813a74b2268b40af89b15a6", 16) - g12To71y, _ := new(big.Int).SetString("118d6c0fccd01732e48bb29539a0eaa8e7319d29a12cb9b87d76f4cfb0bf3a0a60250e8a3366bdeaafeda261ca834da", 16) - g12To72x, _ := new(big.Int).SetString("10b8803ef93d4428058963d394f1599bfd06ac2e8424ca8e33522f640bfb1f422263f9b3899cd6e857b78dc72d84835", 16) - g12To72y, _ := new(big.Int).SetString("16312e5482b4a4a69868094147c12514d3cd1e35a8e8e8a8fb67a6fbda08280b86352ba638314b0b731325d21928184", 16) - g12To73x, _ := new(big.Int).SetString("c1aa68b66a71e0925208c387cd45504c67c4c75e941d1c575385cb8595c24a24df762e9ff871f491254d8eca147de2", 16) - g12To73y, _ := new(big.Int).SetString("1a1ef925e585988f896c197af7a6b460f379b6eb5afa0b656702c3825b8ddbbc5384aaee6b61a1fea889c908f1b876e", 16) - g12To74x, _ := new(big.Int).SetString("1988799b72da095b8cd09fa266565ea14ac2bbdc8ce0d40c5cfc539d15d09f43bc6b540c598e8e2cd2e480df7f37979", 16) - g12To74y, _ := new(big.Int).SetString("d6f09872112bb080205ba42682dbb7127929850d7040458fb69ada42aa9c493f109a8eed018fb7bf731bb94870c666", 16) - g12To75x, _ := new(big.Int).SetString("985b8f67cd5043f0b04927caced7101f2e2416e1a3e54d9ef503b9f63258b8266e96280fed0ec57a020c9f871fa7e6", 16) - g12To75y, _ := new(big.Int).SetString("10dbd43d1277b59abcd4d63f4faa2abb22cd0630d44ae038b20596dcd5d9be2766621345db48f46d2602784a8874b33", 16) - g12To76x, _ := new(big.Int).SetString("128d9b00c2387f8b958a5e69235d7bc3c6566ffdaf6bf6baf9bf407501a905307b3db4fc93444ce9efefd717e6e704c", 16) - g12To76y, _ := new(big.Int).SetString("7e6df79c1ad8b8c57d71f284a1e9356a67c2211461c84eb277873500ad5f5600416c8ea67a0cb95b6395ede29080fb", 16) - g12To77x, _ := new(big.Int).SetString("19a8c6bec19d125a97a4636e38a9c71c482d1fd2c063bd4ab791fb84b508b2511c0c57832b0631d259b51524b3ac61c", 16) - g12To77y, _ := new(big.Int).SetString("beb651001b47818276d32281cebcacfb23ad81f9af4982bd94e936ef31c0a2165eb2f14ef545d735e04decf9c1efab", 16) - g12To78x, _ := new(big.Int).SetString("c0c3281519d3a66eeef710d61aa05a648c02108d193a0f60d69e4341f3d916eafdb4ff66559e365f44d5c1375a8c4f", 16) - g12To78y, _ := new(big.Int).SetString("1321f3814e3da08308073186aa0bd0e0c4fdac4effd332b58cc91b71d02f9c621b943c3d5d0796def3767afb7b67f8a", 16) - g12To79x, _ := new(big.Int).SetString("90830b4e3531c735e3842b3fb1bde63a7f73b380f9193bbe8ab7dea4af48f08d8cd085130fbcf1b328a3c9dcbe6a76", 16) - g12To79y, _ := new(big.Int).SetString("f509e10a3207e10696ccfa1abe78b556f532d6f5d8803a35186286466d65aabce571dfc3c644a8c448ee6014705cec", 16) - g12To80x, _ := new(big.Int).SetString("10531f514b920d4051719e3341c279e8e5892b73a6d03d7805f81d08cfac7367b3377f575cda8fc69ccb268f99937a", 16) - g12To80y, _ := new(big.Int).SetString("5a8aace529af52e6842a6dd12ef0d34a841a87edd0351f959a3fdf05316a40894b8424f5c8bc48896708a49c04a136", 16) - g12To81x, _ := new(big.Int).SetString("12a8f78469b6185103baf43ccb81fe98768366766da34efbea5ee12eaffe6f4b72dbbf615bddadf184c59326de5940c", 16) - g12To81y, _ := new(big.Int).SetString("60fe8174c79a00c14b389ef1bc853700b4fa990c34ffa2ca1c681c1decedbf9ba688dca5010fe8b7e5bbfe1b021b29", 16) - g12To82x, _ := new(big.Int).SetString("96a56b5bca31bb6f97724d57f7b80380e1f0a2fa32d2226d92c9335971d8a5dcfd765a75cbd2be6b5932b886eca12c", 16) - g12To82y, _ := new(big.Int).SetString("9f33be6bc8bea9511acf18ec9fd8b71025f75150a2ef9fe83b724c0acfe07a6faa7e96e4cd53bde14ae4b96a53ab2f", 16) - g12To83x, _ := new(big.Int).SetString("17862b6d524f16e02a084e9fb0654973aa92da25a0f118ba93df9a105d2c00c740d2169545e7494a1636a7ac086edda", 16) - g12To83y, _ := new(big.Int).SetString("10c1e04620e95976bfdf742bdb03533b7b55046a9aa5a8517e42db7b71aaf00ebb236eee62a1959b96bdad8ccc914bf", 16) - g12To84x, _ := new(big.Int).SetString("2b44930db60c5e62fda1ee9936201d3115c63e40894a354fedaffda074b07c6c54d3035cc69ba2622af4a1127d523a", 16) - g12To84y, _ := new(big.Int).SetString("afda5460f7fc032597d3fc38834540acd3037d394dd7aa3133d0d1082d6758e87c8422f7addfaa885a5d551132b275", 16) - g12To85x, _ := new(big.Int).SetString("7d20b0283582f3e2efb8ef9561e69f645ff108db1a9a94694783649acdaabb957ca2bd76c84714da306f36cf95b416", 16) - g12To85y, _ := new(big.Int).SetString("70a720b8f2f5aa5e9307245d554b599372203318b5ca241656bb133e38cadd215f0d46eac4dcfd144d27d9b1d8fcb8", 16) - g12To86x, _ := new(big.Int).SetString("19c3ef7b33932b842f91ecbee1b588277fdb1a8bb1dfdda304f94ea33b9a07420a1f54dfc6da8ed2865d3132c85fc1b", 16) - g12To86y, _ := new(big.Int).SetString("c5a8a15999fb9021ea63c9141795080d4ef705cb988c4a1c97bba7070584890c6ff6fb78422004bbc86fbb5910274", 16) - g12To87x, _ := new(big.Int).SetString("160475f653c938043ee3949cec0fbde6737e67a4153c900ca8e7c08f17c42c1065b9304f46753dad2c35eb29be942af", 16) - g12To87y, _ := new(big.Int).SetString("d11cb6b0c5394dd2cad261f7846de206762fbde37b91eca7421fde35763f0454277baeae33525668e619e5a2d025e6", 16) - g12To88x, _ := new(big.Int).SetString("17841df9133f6a38903b90a0a67b2f0374207566992a3312dd0f6a1df2213c788a5e716ca0aa49245d8321b094f3cda", 16) - g12To88y, _ := new(big.Int).SetString("4d13e575ddc348796fffc4eac9f510ffe1f079d531c2b524d462cd49384373be208e7903bd8e5c574085355a33d113", 16) - g12To89x, _ := new(big.Int).SetString("13c0591a0f059e36f943d0e24f1c27a7ec66d12057c958a22bdb3583e1d9a50a4a60e4aec16dd586e45275ba543cf1f", 16) - g12To89y, _ := new(big.Int).SetString("4a529fe7cc3a88767be9720803cc8c3ea908bd8b79ec3a635dc6d4a2ff526fa378f5e94f23fc462f67fe66f0727d03", 16) - g12To90x, _ := new(big.Int).SetString("c59e4fae1f057573b420ec1bd61f8be08bc040689990a9ee866b4803d4dc50a9ad832c470a6e10ebaa3c738afa1523", 16) - g12To90y, _ := new(big.Int).SetString("110ca4c030099d03f733ea9de3f674464b4b8ccb2385945a148414a9f95fd4579c630320e27baca3dc7fb2141bf2f5b", 16) - g12To91x, _ := new(big.Int).SetString("763925b8f5ef62d240d76aca100de7dfea130bf34a09f7e70fa74a0978137699840f7242086761595db4b5c844c872", 16) - g12To91y, _ := new(big.Int).SetString("1a7b4929003f677f9194349f5e72ea5fc2594a146405bb917a23b232991da2663763df8eb866603c11025ba823e13c8", 16) - g12To92x, _ := new(big.Int).SetString("773e594f149dd63a3b6180bc3ecd958a142c249a2c554d20a6ae08c4b8218dcfafba746100f395fba248d05cbedb56", 16) - g12To92y, _ := new(big.Int).SetString("170f97f41c75a7bdd7f45885847fb0e9c77482b345d8cdc212e43dcfe3172c4c2ef4f7bf0a85c35833eb0f07404a460", 16) - g12To93x, _ := new(big.Int).SetString("72f4cdc52c410c573a6b6877f123ce328312321d118a743d640a62208fd96ceecf94f5105d216628f327c131cd57f2", 16) - g12To93y, _ := new(big.Int).SetString("d979e10ef5e4bf4b079db8f4b92535d3163cfe65f4cf780f2f588a9ff15a17c2fd99abea87d947b3eba898e275189", 16) - g12To94x, _ := new(big.Int).SetString("1500f73c1580e754583a10830b68534664a92011ecb99fc49a6b8ff8e16403dec02ffc5025283f9daf89afded75aa4d", 16) - g12To94y, _ := new(big.Int).SetString("1123e023b823cb49e34b883254a55c6830213fae288a12638a3c4858db3324a780590a26eca1ab0bfeebe1231c64fc0", 16) - g12To95x, _ := new(big.Int).SetString("138dcd92af7921b62bd16966f89907ae6cf447bff72129cb94b945324fff201ed119837e4c789f7daf5d1348ccb3f4e", 16) - g12To95y, _ := new(big.Int).SetString("b316c8be8dc0963cf075e8ae59b4d8589dfc07e41b22351c5e77fa3ab75fd11bc0a7f16857609bd196725896f5492a", 16) - g12To96x, _ := new(big.Int).SetString("101ea5fdb817941a117aabea37c5409a815c527b3d2aeca08ebdc6888749da51efcc57e0f9413b38ff38937b5d75cef", 16) - g12To96y, _ := new(big.Int).SetString("16c70419efb5ee583789653307a3ad9ef5cc4e92cb36e050fe02d6ab5771c24059ed9042b32d2e3b80dabc9e76dbec0", 16) - g12To97x, _ := new(big.Int).SetString("6b196d937da669209d3180b6e0d1840c79ed567ff337c823075e3fcc0bcefc24be337af22e9a37bd282a4f73b39de", 16) - g12To97y, _ := new(big.Int).SetString("25c43a9d0e59c35eff1e825b2111e1e90b364b8a930a2d3745137a05b054242f377582b02e527a33bf2cb95b6ad919", 16) - g12To98x, _ := new(big.Int).SetString("3496658a2ecc3a834db0fc9d84fae1aa75e0f78f126423216ff6b66880755152b21c046e8c34b13f8a1d62e477b5b9", 16) - g12To98y, _ := new(big.Int).SetString("d479674629f00313a607397c5c90bdf27eb487ec9f04fff1e56a61b92240fdd93ef876dd14c4734311e876ac49f6ab", 16) - g12To99x, _ := new(big.Int).SetString("19a0aa4853b07b1cb768e74c4f7c628f734856a90f598ffd1441f11b1384477a4a05bf25f2d17e152a2417bfb0ae87d", 16) - g12To99y, _ := new(big.Int).SetString("14ce74b65fd7001822b0778c113cde10cb11b6cbd5014f766fb6bc1c2b72a4e9f7d72407c8a47e3427595ad0bacad9c", 16) - g12To100x, _ := new(big.Int).SetString("2044ddbbf0dec33e557caf3f2b88173c44bc9a26bcca970852f46cd3202c28a254fd14d2b44ef1343724691441e055", 16) - g12To100y, _ := new(big.Int).SetString("134e03d8d8900fde4f640624dd05c5f0120559df6bc9dae7dcee6e6a483ad7b749e00d97ba8b81df8cde07b16ad097d", 16) - g12To101x, _ := new(big.Int).SetString("320ddc8cec816f4f1b9d5cbc9782f28457e5034436f318b8bfc4ff5cea2426ca402b2cef332e5d1fd88c215f747e72", 16) - g12To101y, _ := new(big.Int).SetString("12a211c464b89f00c61302c790230e80ff8a3616bce1acffaaef0a40cda2ff68a2657ed5b7dc5025d3c2b0435bd0077", 16) - g12To102x, _ := new(big.Int).SetString("fb79ae0ecd6f1b3f46f5a1f67188388e3292ed3b2222b32d631ac8d6683a10724b9642b255cc3c233b18f8e44666cc", 16) - g12To102y, _ := new(big.Int).SetString("50d1ffc9d8a2e03d7054c716a9bc66d023ab40fe7f460538b27c3c55c24a4459bbad18340f3cea2021df64f0f842dd", 16) - g12To103x, _ := new(big.Int).SetString("1129ea0748cdb9b845b5bc40ed9e0be0ffb8cf89445ae3389d99c6ec446759a58d6c8d27b0576918bae0a58f8f0a029", 16) - g12To103y, _ := new(big.Int).SetString("11546c1a2cded1c9437a93e59dc9cc5101e3464af5c7270ac2b2336130bbbcdf2655b4465428377b805fcb059669410", 16) - g12To104x, _ := new(big.Int).SetString("18c8d9e58d0197ede9759ecd91b67d6b5015d325c7583946865b5d2de5a05adc3203172c3f7411374186ac4b453674b", 16) - g12To104y, _ := new(big.Int).SetString("19dd01ebcd952016ed6385a5394627c9298898908e73750fe55d3a23d84b8287dc2f9f3d9fb7c6648b0f8593eaece2d", 16) - g12To105x, _ := new(big.Int).SetString("d21dbcdc3d7262275f9350c31b675c22d06ab047ae8fbd181fd0753128bf0c8989f0cfcc73100b16a630eb07c99310", 16) - g12To105y, _ := new(big.Int).SetString("19f1f79a45e3f8c0e7052850671a64d6bdc7f98261bb81cd99b7cd802754b47870acfc7e12decee0a08bb89bdf27fac", 16) - g12To106x, _ := new(big.Int).SetString("393a7383d765c36e360dd01d29abdf0715d7168c59cce0efeea765c0b03f29c3a2ff76022a0ae3cfe44f94e7c47127", 16) - g12To106y, _ := new(big.Int).SetString("f4f07b787a555b1d7615ee63ec118f890ba99f98f470f88dfc5cff57fb3f01c077fb13c8703fa538a357b7837ccc19", 16) - g12To107x, _ := new(big.Int).SetString("80122ac51038d1ddef4ac8494a52920e89f63bcb7cd198192da5311acb3fe847017509fb9290f7bf262e786461b9fd", 16) - g12To107y, _ := new(big.Int).SetString("17e39ca2ee4a8eb9f89a4ac907a54209ea8a0b75a9ff6829c4cf98452891166bbd573b2a537cd740f620bab4fcc32cf", 16) - g12To108x, _ := new(big.Int).SetString("9b7138398d7017dab8c04b23364f37d17a61a44d50bff2e05ab096ad0ac5067d30889802dbe92f57b330e8752a8721", 16) - g12To108y, _ := new(big.Int).SetString("b0df5aabf78731bd4990843eb1f349c95670c6b67d2fcdc0fb170736b93b608de24aec60db88813e5c6ec199aa94fd", 16) - g12To109x, _ := new(big.Int).SetString("e091d99dc6037d1f4c24b74d4c4565da3af54c75fd095283cdfafce856e46844d450fb3488d3ba4598ebebb8327c2b", 16) - g12To109y, _ := new(big.Int).SetString("729e298310ea46c8038352f4af4e5ee9b33634f91b2fc252df262c6c39b54496f3b6894ed641bab49b0da26450b985", 16) - g12To110x, _ := new(big.Int).SetString("e3eed427c6a5017599b40f73cdb22e1d40fa9376f301fcf32f64b75fecde7a782320544b9cf3a59df3de15d1cd2275", 16) - g12To110y, _ := new(big.Int).SetString("72598a238bfdc22f2e5791853c64ba305d96051afb1367d57dec6191945c4ad39992dfed2f526f660235470e22d676", 16) - g12To111x, _ := new(big.Int).SetString("4ecb8e157e3531ab8f9018f6b205812ea61410c058a8cdc9a8f74b3dde14ea3255ca1771eb1fb38377cb4a45f5ac97", 16) - g12To111y, _ := new(big.Int).SetString("3ff73af8c95bca6d67fa2d006b8e737a3839b159179abfbbf851e549fb2eb134e6dd1d6bdda529079be3ee37d52366", 16) - g12To112x, _ := new(big.Int).SetString("af7a0c0e2c15f9f0fc230bf9e8dd54ce6e623c6e5e050c7784ce3274fdf2c68615b7b536f1fbd93a6c65d200f0dd2b", 16) - g12To112y, _ := new(big.Int).SetString("11c21280451bc798e2849a37eeaffdb8070b44812fcc1a42216e8261170e6faee5eb2e99a70479885481f868f7ffdab", 16) - g12To113x, _ := new(big.Int).SetString("467bb117e14f72ed478889189b78614ce929e0a11dc4c9fe5f4b3c94460845fc1a93a7e84f2d017ffcd8e766153108", 16) - g12To113y, _ := new(big.Int).SetString("11f478fc0b3d40880188a104fd6db94db06a96a11446b8204c5047f08361dd20b1c6d3b9e8c7683bc93a7e3f9b48009", 16) - g12To114x, _ := new(big.Int).SetString("21040890dbe4d60a532435850be5e3b85be4efa8d3e4b53f6e9b86435fd5b584707082f3f2013137bf7e83e6a6be87", 16) - g12To114y, _ := new(big.Int).SetString("3a46738a14f592e5f25cdb3687f23b572bdccf6e1bf3cf3c087573ddc2ddf56acb0f2f7c024b8f22e7fe215ffd569b", 16) - g12To115x, _ := new(big.Int).SetString("19d00592cb821b60089fdc0963e4d40c1d427a41bd99249b9209e79b15e53b5671f1f002f97b0a3a1a1d87799a065df", 16) - g12To115y, _ := new(big.Int).SetString("13cba57cdc23a8c650025500cbafd661cad5dd269f8569ced5c190ed94d1c97468e54472bdb19d8533c3efc24620283", 16) - g12To116x, _ := new(big.Int).SetString("5bcc22bdd1b8f6bd3697c48899f3c3c66d3ed95bde450507175df4e99bdfee8b5140b2113d09172309e7f92b1997cd", 16) - g12To116y, _ := new(big.Int).SetString("607ba58c3109aba00b398acdb1210b877194e6b658c85d99905af6b762c3a5d0290dd555af824cc6dd58221a8dc072", 16) - g12To117x, _ := new(big.Int).SetString("1fc7f19047611351202a7f5332c1fc97b359a1c521f20afa9b334963467485600b6f8016438e9c51af8442b86c1314", 16) - g12To117y, _ := new(big.Int).SetString("a72af1b9824439482958fd9e3f8fe750cd8409e2d527bcc3542a5e03e46378e7fb745f064ffd357e168234e8477687", 16) - g12To118x, _ := new(big.Int).SetString("7ae261965d9fe9cd01ede8ebdec85bcfd51970aa009425f795b27a625129c51fc4f209d21a43db6cb0f64b3c828c90", 16) - g12To118y, _ := new(big.Int).SetString("e1f9b9bc743372d94c063abf6ba56008f0d07472b7c0ba96362fcebcd267bba72133d5dd9d4e422a2cca2ee2e1a0f1", 16) - g12To119x, _ := new(big.Int).SetString("55838e6a68c9e022b657bf2cbb728021fabe867767bf84da222d2314f94d78cd7fc555fbb2384914daf68aa044fa10", 16) - g12To119y, _ := new(big.Int).SetString("1540e4114abff824399c889d0e259166858a8f950766b071267e7747ea9580ffb5d3b03d41ca558233eed812e920af3", 16) - g12To120x, _ := new(big.Int).SetString("944b4fc0ca112cfa7ac887aa61167fea6d2be550b52c31daf2b43c732bc3cca9a23bc7b7b9767eb59f2c15d3f53ecc", 16) - g12To120y, _ := new(big.Int).SetString("e10c7dcbdd84002e7da14bfd1337da7c1acd68c7604292020ea4756bab5dc9c29be790f59e9f19c6ddf2063c3b9ddf", 16) - g12To121x, _ := new(big.Int).SetString("1814aa8084352ca9646edc03f3a666a49d6c8c6b397c75a3f2db4e7367c961eec704d60b2f056ca622eba5e7d5aed17", 16) - g12To121y, _ := new(big.Int).SetString("1091aa493ba3e157ca796bbbda78c2a6173b353b98bfdf64cad515be0633dda924b04ec769a95a7b9907677210f4eca", 16) - g12To122x, _ := new(big.Int).SetString("4c79be993599aa6f2cc588c9a17729e07fd443b5d0be7d71e6374bc1b6cd7853a8d5cdd2fd1f355512cff3abd6847e", 16) - g12To122y, _ := new(big.Int).SetString("17969fb3d5c1520400aa5f89bc13dc5553bb16fbec5dc3d3b05719c593201b2384c81a3e52b72273ff4a7e10d17ec66", 16) - g12To123x, _ := new(big.Int).SetString("56e4cd225404894800e1a17d0a9b01b6210ed3e42d8df1912c77772ac47cab49b52054a7c3f6ebf8f77c00ccfcb888", 16) - g12To123y, _ := new(big.Int).SetString("48996d22cb69b2d6a9f29ce0c1d8bcb75725b77caa0f1dcefb6523d5f2056399c9c19c3eead6480dba0928cc691c8e", 16) - g12To124x, _ := new(big.Int).SetString("1795d38c0f3168e622a236ae402e9f1ae6b13fde7b65429b03453066489e147213b8ee6745ddfed915ff10fe780742c", 16) - g12To124y, _ := new(big.Int).SetString("5873e3cbcd5dcb0ece242388d565088fd2181264fad06534c9416a887f7eb115fe259b97987bd8bd794fe1bff88187", 16) - g12To125x, _ := new(big.Int).SetString("117f497140d0e102b9612a0c0760c5fae1bf451a40501debe6ff6a0c6bf0be1b0957dbc274f4a2c3d5b0db48ee39ca0", 16) - g12To125y, _ := new(big.Int).SetString("380dae20e3f1e6b897371384a44e757a2d7a84df6666e32cb6c8fbc5e06e762d27f9cfd6ba1459b45fb327432e49ce", 16) - g12To126x, _ := new(big.Int).SetString("bb69b209c8d3382211895e4f0c0f69efbbaac9b51bb76793fa50acc1254105433e8afad7511c492e6e864480fafd61", 16) - g12To126y, _ := new(big.Int).SetString("85f238d05a21136f7f88114e7cc8cb2e7ed0be3e4b73dfd1be654577ff75db8baffd94f1746044efbba8cbe219521d", 16) - g12To127x, _ := new(big.Int).SetString("19f732e83c5801519c11076d13d81be227279802aca85d79a7c70ab68df622942e496f46e175b88c4c3fc5fde7bfe31", 16) - g12To127y, _ := new(big.Int).SetString("66d4699239e91cf083b474b9e2eadda2754630528a209d7fdde9018dec26fc93c039c9315922abe377f6b2739d2a8a", 16) - g12To128x, _ := new(big.Int).SetString("e4792c45ea0374775d9005fcfca11a9cf28cef25cb45c4ce3a4fcf88fa648378d0473f07ff1a56a9f3b7a593fe5002", 16) - g12To128y, _ := new(big.Int).SetString("1acb4c048149b23c021e9df25fe5b3fc54b77d3f2295926565b6179955af9dcc41d53713878d285916f2e01c6fa6e31", 16) - g12To129x, _ := new(big.Int).SetString("18af57cc0cba6db0d3c81025895bb6c552297a1ff24f5fb93e01270405c3ca1a010f3cf3463f03893e45d68bc8a2f62", 16) - g12To129y, _ := new(big.Int).SetString("1fd7cfe2078a0e1e79ee9fb7877872c382fe387ccb8797007654656774e15bef83c3f55928d5454e620fe073de20ee", 16) - g12To130x, _ := new(big.Int).SetString("12cc5b7441a487be214269e527ec1176f2f6dde1bd1fe02a08fdc92410c91d8d883fe9f7151c19c235e9dde01f5d9d0", 16) - g12To130y, _ := new(big.Int).SetString("67dbd3814cdcd0c12ff13eff08e790faac9b3c9895a233d71ecb5399c16983ea1623fc1b7422c061d9c7338e82108e", 16) - g12To131x, _ := new(big.Int).SetString("15318da6e7435d4194e5253f4bfff8adec4aab7304e49182c5d3a1ee498d800cef3e3a5762d8d6e7029a8b396e5df96", 16) - g12To131y, _ := new(big.Int).SetString("557ecd16ceb9695e6909571f371b659738fb6e61e69b73fb7b932a88e6c064cc73191053606716df7747aa07ebd47b", 16) - g12To132x, _ := new(big.Int).SetString("320b3b8315d2f24baed0ead61c7ef235b7dab1b76a3120c99cf15ff76af149aaa37cfaf7751ed74d541aba79f7485d", 16) - g12To132y, _ := new(big.Int).SetString("1580b7920ee4b3407677ef153239024119a12cbd13e9811e6a1736dbb03a873b4bfd2c8bc897f94e94a01eecd6dd3fd", 16) - g12To133x, _ := new(big.Int).SetString("9c942c27e37b0eea666d85dc58a566e900f88451e4cd3dc5133a62f6dde3a5c93307f3c86e7d336573a95f38c86448", 16) - g12To133y, _ := new(big.Int).SetString("48250ddc92820ecd6fcadcca3d6bf73dd4d6bfa66f5b49bc59001574b09f05f99e74d3ea9f91c8579d7f38fb2c8763", 16) - g12To134x, _ := new(big.Int).SetString("15ebc88aac7bcbc57c2b057692e1b99cfc9ad13972d89eea008239c015b74ecaf80c889f65ddb8129f321b214f7e599", 16) - g12To134y, _ := new(big.Int).SetString("80e4b8b7ba1a7c5f1de2b62f64ba4693652a307dd9b1a92252c4291c69335cf0b8c6f8561a15462916c24a78141823", 16) - g12To135x, _ := new(big.Int).SetString("18b3a334505d4c7cc8b4f906dc3496316d8d02c128fcd88ca1139f09e0957a3d7360aa03f19d9aa9e1ca509ed0a7287", 16) - g12To135y, _ := new(big.Int).SetString("50899b31fb24615a49ab0f49bc38371ddf1ca7982cf30b43c929041bd16444ed13d4a851943d195275c55315a6bc4c", 16) - g12To136x, _ := new(big.Int).SetString("324957c3564d435c9e28916ce384b568bad35e8da0416becf4dcb8d47a5f9b99b59ff84e2f3d01306e32faf4ec1b1e", 16) - g12To136y, _ := new(big.Int).SetString("180b670ab4b14f4af15fad06c063199c831f15c730fe1ef169f2a24ee3c87ea18f9e8ea393b3ab693de860a3c3b19e3", 16) - g12To137x, _ := new(big.Int).SetString("55bcc692af3a8ed7313777f1085effcee98ddf6bdfd0a4cbab5e805c313b15a637bbe3097fd4328bb37c922e8e8d0", 16) - g12To137y, _ := new(big.Int).SetString("14ef17878c43aadf2bee219d4d4ac616ffe2bb2ca85c5add0e091ba5e4471a2e9a4324a02f5aad8c497d19a339fd64b", 16) - g12To138x, _ := new(big.Int).SetString("1d282049941b376a7bdb9b0e81c5d5fc6d3df7c4dd9059d02bee35ffe56481afd1911ce2efc80384f2221145747f84", 16) - g12To138y, _ := new(big.Int).SetString("12d5989e164bf32bc49ce538bc2185f3ba43d10e5bc5865cd523ff3681c14cc4c77a159dc77e909dc4ae17fb16c207a", 16) - g12To139x, _ := new(big.Int).SetString("cabdd2d555e7fdbf15eea8d9e879dae763b74813ca8e7e7201222d0163f7819dabb4e9a177d0215c8ee0209f818e3a", 16) - g12To139y, _ := new(big.Int).SetString("b5e9b30c2bee3862bcf355e0ae8402ceb6e595557d1d89799f9dac25e857690d6ab274d64f395b2e1875ad09a5f7c4", 16) - g12To140x, _ := new(big.Int).SetString("3756b96f44a0b8d81e869f8105fe226a1dc0c422b372ef16bf1c960151838075fc1d0be337631b42bd7a17ef158c20", 16) - g12To140y, _ := new(big.Int).SetString("185eff03736ded483448d28e5e609429609ff67094f880a79f9884a77ae121cef32aed642a1664ae5a0934e80e0a791", 16) - g12To141x, _ := new(big.Int).SetString("83abdf9576124e1579a07d704dfd0eb68b3eaef853a00d9ed7ce519bffd0f016b22053d2eea2478f69a668a26ec6cd", 16) - g12To141y, _ := new(big.Int).SetString("1a23389ceda0fae24bc826d9cad8cb0791f933d6d5fb549c08cb6a6fb420a9b2925a221b7a0d3c7e2078d728ac03bfd", 16) - g12To142x, _ := new(big.Int).SetString("1025af987dc0aa4594bf71b342b71dfa9be8ea9440f6cb940288c14fc53926062169a28fc6f968f5a06cdffc4c2f3bc", 16) - g12To142y, _ := new(big.Int).SetString("124266250eda81a840f60b00c5332d52404e97c4dab39fc2737fe972bd800ec451dcb55aba8f5c8a9bed1e4ed9e2f3f", 16) - g12To143x, _ := new(big.Int).SetString("f95cfdcb19aff123335c9294fa46f7df5585001076640f0306c04c5b7f826e314776ab7f8428e8e24d44cbff92b135", 16) - g12To143y, _ := new(big.Int).SetString("157fc1ecb3d469a07b6319864e2b0cdaf20b9ac53a34f2af7f960d6feaaa2c1c063e2b5f39256612f8517f6a1e8488c", 16) - g12To144x, _ := new(big.Int).SetString("d3f7e41e0d6dca357b0eb5ff58ad3edc9eb4cc825d96fb2db4c13bbc26d85cedd3d0bc1fc2259dff6493b150e7018d", 16) - g12To144y, _ := new(big.Int).SetString("14cf7eb25efc61049a02975c507595406a02915c85a361e72aeadfc65f647c576d87a28822880684b9e6f486d9341ac", 16) - g12To145x, _ := new(big.Int).SetString("d76126e3b8f6c41767722603e99dacdc2c07a20710e51da646d473fa0afebd76c30c230b6ab66539ad5813e7207f1", 16) - g12To145y, _ := new(big.Int).SetString("8ec28dd0b2eb92af66344e8beddf6b47962bf3564c4ec460261683910f35a996e48b0aedd1b4b204600638d935c85", 16) - g12To146x, _ := new(big.Int).SetString("1501b1cb3bad5faa01786c85390ea937130f8045f0c10c9dc2bc81a5a8f3dfdc6c44c38386a18c6aeaf32ae615628fb", 16) - g12To146y, _ := new(big.Int).SetString("483f53ba6eb054817101d01fd4b93c84dfbfcb4a003df00344798866f70c52bb53f6c1344f3727116b3eaea6191fcb", 16) - g12To147x, _ := new(big.Int).SetString("10086ea020c2276607abd7656c03d5ed96fde894a409d9a409fd363298da9741231e8d3ac02baac482431b157ace447", 16) - g12To147y, _ := new(big.Int).SetString("3fc52b9384c8a28f37cf21ad02c24a39f0c52d6c2bcba1b2ee2b0d0bf0093b7185445241f3dae009709d8c82fae8a7", 16) - g12To148x, _ := new(big.Int).SetString("42241569f4225c2ab29b43c20f2f91646397db50d2d48bc19c13a98b72c3cebd8b09ab7cd1e6d82a9f427b0dd6138a", 16) - g12To148y, _ := new(big.Int).SetString("f945aad154d8008cc453a734e92166572a3b0e2ec1dbfed5444990999849908c709383f23fa31f436bdfcedf11b75f", 16) - g12To149x, _ := new(big.Int).SetString("c9f67f6dbc91e05e5ddf0503a62858c29d86a0d183dac66a834a38c7351152f4a391864afee16226a94ab3c1a7c42e", 16) - g12To149y, _ := new(big.Int).SetString("a6609b594fcc8075bb3a73ce66bbf3b7665abafe4017d176067af46f52f5a9116644bfc0e5bca6ee1b8ac8158d4e12", 16) - g12To150x, _ := new(big.Int).SetString("1153c5af141928d2fc95e766c33dab8feef4b9130700659e5d8f5efebfb043d73ee4337c5f0fc733edc4539698a4a15", 16) - g12To150y, _ := new(big.Int).SetString("e12d0a44494b847726c36b27f89e9ad39e6550ccc1e4829f792a8ceb51eac58b8bd434c09111dd81beca462de88c2b", 16) - g12To151x, _ := new(big.Int).SetString("3c5aaf47dbcd0dd23a0fa0c2051ba8c3d0fe6ac1eaf40188bab2f9de5927217944a7c102ab828718ac8e7661b10d11", 16) - g12To151y, _ := new(big.Int).SetString("1776473aff44785cfa49c3c90d715081e987acc7652039db8a3df404b0804c124319dcebeed7da580ee9082e96cd671", 16) - g12To152x, _ := new(big.Int).SetString("14e85d6dd8e43ae3579caf05c4f60311bbef732d30a4adabb4718b14651f7cf649a1b211425e46a462cfc774aebfceb", 16) - g12To152y, _ := new(big.Int).SetString("12a314ef9a9376289103bce265dc11be2a3cf93080568d3b2a67e7c78e78950ce35338169501930e5e59c162e489c31", 16) - g12To153x, _ := new(big.Int).SetString("3bd85a843e5f7cb348c19ae3219a3ea7493b615acfdc2df784a5b386e520b0eb1b2e9b91431d24917a822bf779796", 16) - g12To153y, _ := new(big.Int).SetString("cb11b6ad47b64ddc1968ccdcc60f91159879bb11ac7b035111a622e805b33d81189e8f695df8e7f181f1751fe6f7a0", 16) - g12To154x, _ := new(big.Int).SetString("10e41425e5297f70eb296aaa09c5f2ba87f8d22fd05cb0b8a984441b4b9998bd896af921f19f8b5a2a9698e24fa764e", 16) - g12To154y, _ := new(big.Int).SetString("281547615a1a34525b0910a27a705f36b1fbf2629284007c1842ab8259d9c7fed09ce955d4923710275cacfdbbfc42", 16) - g12To155x, _ := new(big.Int).SetString("24dfaca436700b2a28321fbbb35a8a8710f0b53506da3444d25d7258c3557a7f04ff4066c3577a382b78cfeffb1fb9", 16) - g12To155y, _ := new(big.Int).SetString("17cce223736ad9349c8ba8e85fc84473331f94573d220051df7654a37ad183c0ee66cc65f21870945ccf2b3cb5a4a3a", 16) - g12To156x, _ := new(big.Int).SetString("108ffd6cd88e29e760c221a6a8630eea55741e4d69cf25bb18d27b48c142ae6bc909578a243af518fc431ce17632763", 16) - g12To156y, _ := new(big.Int).SetString("7a4007cbf16132fff1cc4672297bbac19491404299836b6f0462ca11b230f6a170a353bad9bd6cccca1e84e76104d4", 16) - g12To157x, _ := new(big.Int).SetString("127465b15bbe5570434356ab8b9a4288f764b9777d9be89b52d93af6ace9f18d79ef8d26fe686e935583bb1b35f2662", 16) - g12To157y, _ := new(big.Int).SetString("135739c799b7b80f38d3973e2c1a96519d0daf16e384c2a6e988bc9c512feeb36025dcc0bafbb4029a0baed39d08977", 16) - g12To158x, _ := new(big.Int).SetString("a47d778a09e9b91e8a66e1b7ff48855de7c086c22e97e2a33d78cd6ac0f03789ef65ad6c42bd7469d79e8a771b3014", 16) - g12To158y, _ := new(big.Int).SetString("19807686de5ade7f78c1e92df43e146f59458f7a7ed3632917bcee346a09b17c771c0c30ebfa30eb574db51825ff2ff", 16) - g12To159x, _ := new(big.Int).SetString("553bbe29a93925cacc8f63a35bf3111930ac49d6cf6c4748690697385b9beaff873f9d50e737a67035cc4630d304cd", 16) - g12To159y, _ := new(big.Int).SetString("7ae6ac5a15a6904163bd3f4231aecb2a3ff35ac04dcc88dcea26054957fee459b1d655210c82492a91d21e9c62eb86", 16) - g12To160x, _ := new(big.Int).SetString("15f77fdc47ab14c2101f763260f537f2350f2fd32bf1b2f27451524a2559baf8e683aa0362294c1e8c3f50e72f9142f", 16) - g12To160y, _ := new(big.Int).SetString("9d4009700bcd44218332952b3d1d7f2265e8e554bb6e991929b1e96d9fdca23b05acf0b70c7af4b5840f90c11371b", 16) - g12To161x, _ := new(big.Int).SetString("155082f9a8c24a6cf3200452141640bec8fae3a269872e4f535f5f58ecb3ae9789133dc3707cf1936be2461c942c1ac", 16) - g12To161y, _ := new(big.Int).SetString("16fab5585ec39985e7372355d7911eb1d3ab1fca71e920504172278c1a61ddb3d9959e0d4a61aac70d322f5c145dee2", 16) - g12To162x, _ := new(big.Int).SetString("3fb08dc59a282d83866eecc906b694f1d92b24e87658814ad685cb6b110b749db7a1d7c0185be7b4c8a325fb7bb6dc", 16) - g12To162y, _ := new(big.Int).SetString("3e98c7707613366535514c7bda8a9d20f4102fd81f3fcebe6734aae4e231c937b46b23d823b960cb8040a8287dd5bd", 16) - g12To163x, _ := new(big.Int).SetString("133c8d89b872593cf25925ba8d7f240a85029eea7006a58388a6f7549efff747a9f5f7a44f7016854ca345e8620e7f5", 16) - g12To163y, _ := new(big.Int).SetString("1028b91b8e2f13769a0190c0e9fed0d842f0c3efd531e5df212cecccfd314e189d56d54565cbe206c2ae326b882dac3", 16) - g12To164x, _ := new(big.Int).SetString("6422c61104e62eee280da427bdd2e91fde9e9a1f9df8d77b1b0e91ee5db2d2ade3c6986c5e8c0ec21035ccc35f93d4", 16) - g12To164y, _ := new(big.Int).SetString("18cf5bf95c516e422ff72afb2df3d1f99b08fcdd69657f5ce7ab8bcf6a8f3eb717dc69a32ffd79e048b7d45bd353f7f", 16) - g12To165x, _ := new(big.Int).SetString("bb49069be1114cd86fb632d7e3dfb7ba79bb3aa8e842298169ba74a53f61e182f27cad88e6c8b243b9e068120e6cc8", 16) - g12To165y, _ := new(big.Int).SetString("b50b69c4b23b3e07123aadd4119784e70c32735424b88094b08c75a456daa4f7626bff7daa51f2c73d30ddc5318570", 16) - g12To166x, _ := new(big.Int).SetString("12a19d3de6d72caac8d34bbd6e90546ec0a4009e574be029a66f339500bbe021b34383e410617fb0a526591286e0643", 16) - g12To166y, _ := new(big.Int).SetString("9b406052873481fafdb61a8adfc9019e48faac87c9e44121af21f0a4cff2774798e28fb783bb8e7e31dc4a313d7a91", 16) - g12To167x, _ := new(big.Int).SetString("10906d84db20b228bb0388b23ce4488e21775454205d723df5a075c51e4dd153774343fc43b58075de945f24bfebb67", 16) - g12To167y, _ := new(big.Int).SetString("7cfe72c84ca6b9dabb5c139ba427cc47e87b4ba07d24d410c430a2b9b5c6b7f9237bdd5fe199be039d8181b2d4649f", 16) - g12To168x, _ := new(big.Int).SetString("910bc0e25094b13d6e04b32302f247d99cb4a71d9a1d8cdc75a467bdce8160d8af85beccb93dabb2cf1e15cd359ea8", 16) - g12To168y, _ := new(big.Int).SetString("c3d5f0eecd86b5f0dbfa46038cf379197d0112e674dd50f6071eb9b787d000ecf2b4ad8717af94fdfc8bc162d91345", 16) - g12To169x, _ := new(big.Int).SetString("170f6e8c17ee0f447e7c56000ec81b125743fc7a71c61e099d368c89d7e9bdd6f91b9828865d1c21bcd01f1101e13b0", 16) - g12To169y, _ := new(big.Int).SetString("b4179cea51ddb18b7f53b44f96c32d409a5170ab59624bf81562545d451ed3a77e82287d8331b6077b76c920a79de7", 16) - g12To170x, _ := new(big.Int).SetString("5f3a211c40201fc17f6aac6f9ca51bf34e2adfe0c385fe9434db7e711b1c442fe8342da2f3ae012b26b932c3fec0cc", 16) - g12To170y, _ := new(big.Int).SetString("16173a4992b83b3a498bbade3c171fd251a1877fca293db16f50fb73cfb410c67c98a21c8e39c6f2ca22547a0096cbc", 16) - g12To171x, _ := new(big.Int).SetString("c4eb3ee27f8b8d47854a14084f3165ef885d4ef7aa848263e8e08326eb8ff10931e72237a46735f5b1abaf11850dad", 16) - g12To171y, _ := new(big.Int).SetString("ca881eb1904d3980dc3ad9e49dea9feb0333bb8f61b3ade8020a7108379fa9289e17f86ee0ff5ebd009dbb873bfdd7", 16) - g12To172x, _ := new(big.Int).SetString("bcace195e9b15a115edd0bc6cb21722ad3556a8945470c1a556bc83e45a913f9155febf07ec47769b47b8d5d6b2a40", 16) - g12To172y, _ := new(big.Int).SetString("14c699aa9adfe467f3977c6a1bdcc34029160b789d11d5e71980d044fc23666678cc2cb79738b6baa607ee733b3c8da", 16) - g12To173x, _ := new(big.Int).SetString("57e20231567347a7749584f82ad2ffc059698f0c4b702b9324414bcf5aa6f46a4462429172ae83f72512d1d8fb9f69", 16) - g12To173y, _ := new(big.Int).SetString("14581ba8e6fdb0222ddd92a5e87bf666ab7ca5cb86ca699bd16cc5daa67d6ac01afb81f266f06f4ea1f38b0aab90c61", 16) - g12To174x, _ := new(big.Int).SetString("143afae29780766b112a5952f024ae3145eab24719ec21babc615d8547634c5d4636389de5b5d11cce1143016efcfeb", 16) - g12To174y, _ := new(big.Int).SetString("de662f6be83569140af7ba194adc87b5bcb4aba0adcb4403884b64e7e89625d04f0028a80c2f2c9f8dc9dddf23b181", 16) - g12To175x, _ := new(big.Int).SetString("3bce098b21d2e1f1296592746475919ebf66ff784482579e32c9118ed276f978dffedf3ef07a77947b7d36f1ea93e3", 16) - g12To175y, _ := new(big.Int).SetString("9c76e0c83204761988945d5430ab3389502b8778103529176ef2ea285fee97c40946d4ef43f105f91dbf1222bffe0", 16) - g12To176x, _ := new(big.Int).SetString("e4bcab05cf3ecfa042fda48bda025cd28ae2e8b121c82cb8c35986605d6f2240eb17c9b9c27169095736d0198765f9", 16) - g12To176y, _ := new(big.Int).SetString("18555a4c275a57b24968df3885cec2c8feb1cf1ccbbc2a1dc5ff419b71a49abacc6a0167773590ab998bf5c2a5fc653", 16) - g12To177x, _ := new(big.Int).SetString("497522e3537513af8ab51673eafa636250d1ea15f90b2028bee227749c817db9d7094ff36ee24057d0b68b4b019523", 16) - g12To177y, _ := new(big.Int).SetString("c7735117d127fb022a8a3a6365faa220271467a986daeee92cfb913d584aec1eb93ab57e98c6108b225a83af8ab69f", 16) - g12To178x, _ := new(big.Int).SetString("1076cfe5560f5d378308b02b4b23efdf3f6f268b885340ffc6f3aaae8bf5b301aebc22939c012e0616bc519a34f318e", 16) - g12To178y, _ := new(big.Int).SetString("985107e1e9d76c2608d6784589ad58f744f7b8ccbf591e969758100af81f6c6cc751b35433af724e4aacaf48fdce39", 16) - g12To179x, _ := new(big.Int).SetString("e41cf5effab3711d615699c7a1aab2cf8aa8daf691b96b52449ceebc1b57cf29c74f782bd7500894e49ab1ce06e8a5", 16) - g12To179y, _ := new(big.Int).SetString("a8d52e34491822c0de9ed308007713d32ad8559f3ef8bff3d856f99ea1babc568f0b2a86d7c68a70f4dcad5a50631c", 16) - g12To180x, _ := new(big.Int).SetString("cc71f17e685ad819201a2a96b89fa2f0badb410fff58e2155407e08a0ce68f6e8fa26e083efd8233c6ee5517d095dd", 16) - g12To180y, _ := new(big.Int).SetString("a9381762747bb275934bcfd6c4023a3a2a140e498e16cc66ebc8460b218d590287f3eab54d885dbfac38ddaae6acdd", 16) - g12To181x, _ := new(big.Int).SetString("2d13c1f441c3a5f19d42c26699ab14fdf28a6b8dcd508e5f543a2ac444a5b0acf4228cb19f9e8e306f22dc3d6baa26", 16) - g12To181y, _ := new(big.Int).SetString("13b1d26048011fe25c9a47331ce9367876e2d9265eaa1d99135b942fa8312e7e57d7520bc7df9d6312e4c3835c2f174", 16) - g12To182x, _ := new(big.Int).SetString("19b39844d9593c8e4487ce996a33cb3dbb12c719750dbfaaaf0b43014dd8a48bca668bdb223741ec35c3f7579e8f930", 16) - g12To182y, _ := new(big.Int).SetString("d3e8168b65f3e54fcc0a390f176fb4e44845640a59deebfc5a27df65ff45b630d5b266a579d514794540000aae7d3b", 16) - g12To183x, _ := new(big.Int).SetString("b21d5c905a554590574da9b27c20b139ecc9ce777c62c35843f917a5f74dd0804e2035cb55262897d02f755ea7b68b", 16) - g12To183y, _ := new(big.Int).SetString("13364bb242ca69a09ab5433e0265a6d987539f6741bb66d393c6d1bb1e4a0378bb51c976783b25c5afc189de3a5e5ea", 16) - g12To184x, _ := new(big.Int).SetString("19e679044a9eca80829f98d71bf8ca98b1cdc60d0cd7cc8957e7865479ba79fa7608ecd608392f9293739f4d17aac3e", 16) - g12To184y, _ := new(big.Int).SetString("18c81a9bdd6d8e094e5192f7e4cfc90644260c334c489db57bf530185021e96ac4af6fd528337dd07e298db4a7de0b2", 16) - g12To185x, _ := new(big.Int).SetString("369dfd6ab7bf26a8d4e5d64dcfb3b63d455cf2ee4db02f7c7683b6bca035ed1100832f60313db7deaecb8251078873", 16) - g12To185y, _ := new(big.Int).SetString("44bafdb818f8499bb51328d51eb1632e8d14ad7152353f9a9b2d9f2fff57d3e994a923c843a4ffdfdadc46132e7d26", 16) - g12To186x, _ := new(big.Int).SetString("15ebc18f89a2b6fd6ed009fb65888d39a071e3fda69dd9bcea7578ea66689c08d0126947da592298137ddf6dfa6ec1f", 16) - g12To186y, _ := new(big.Int).SetString("127b260a21eb7668c14bc43e4235f7479af7043c32872b60e1038b37bfe1315aa7205fd1a8cf65f2836e6e8e374bf28", 16) - g12To187x, _ := new(big.Int).SetString("bcfc9e711ad2a3a8b6990a3df74642db48922f04dcb1a26bd88ce4c8ccb6d79914a5a29d33334b0636338fc2a8047d", 16) - g12To187y, _ := new(big.Int).SetString("9da171650b66c067d1c41602761278a215fd2987eab435b3d0882737189cedfc1972e9199f58a6d6c1c1d70bd393fe", 16) - g12To188x, _ := new(big.Int).SetString("d898ee857af4fafaf02b327345d90e824b964b954bd7366ad05b6a1c5d14acbbd011214b55440f87786de2a330c131", 16) - g12To188y, _ := new(big.Int).SetString("ceb2ff631bd5b2eebb78bc9bf5ed6ca1fa088baa3608bd202fc8ba88d88baeb6d2410fe89f2ac2cdc4fe615150cd0f", 16) - g12To189x, _ := new(big.Int).SetString("1047172b741e1bb646e4b98defcf554691d16d7de036d0cade3f72387a0ef2175206a55f5000afaf1fd5fdd143fad0a", 16) - g12To189y, _ := new(big.Int).SetString("f5b5d94ebe0e7fce2ccb9cf9c396f8a83367f4c80c45428222560d0c28f14153f1d302812cbb939c06e2e8f60f6dd2", 16) - g12To190x, _ := new(big.Int).SetString("abc14aec8a9cf6d7b1344f4a4e65164e1abcf369de4de55d20c91e966d4aeb11ed24cf663c60b7bd7a88c79cf5c623", 16) - g12To190y, _ := new(big.Int).SetString("7cc4b196c7dfef20b1ebc9e5b03385311bd591da7fbdd89c05ada304c99ae780eac02895fb6a5f01235208b71b4298", 16) - g12To191x, _ := new(big.Int).SetString("13f43125659111895ca3e60c4bfcdf74ed7c261581b2b077730a4ee2a50ae5fe948e4a597403b3368ddf58bfbdfa00a", 16) - g12To191y, _ := new(big.Int).SetString("d3bf81b2e73d05debda0abdd73ce206b8262a5ba42374cd350b6e7f67190d2a59214edc1df2aaa4f5a4a53f2a5dd37", 16) - g12To192x, _ := new(big.Int).SetString("12d30265ab77bb06db58babf408679b92e26fd367391b38a926b91bb6ec2ab6df0c3f4efb10f89a99474010a949b27e", 16) - g12To192y, _ := new(big.Int).SetString("18d1d446266830b4c625c3ccab5b5ef7c51bb10f15ba024ab9c7978996ab7620332b020e941e0f80d69d0a056af7937", 16) - g12To193x, _ := new(big.Int).SetString("6966169e2a61337377ccb7ecaeb7942adc5b170f0a1c1c5df11aa259b41587d9febafb4a901c8b005b5a0faa2baea", 16) - g12To193y, _ := new(big.Int).SetString("11ab8a505040f271f4fb7a90ff298e64dda579761ffc9ee299f01aed1ebecb034f541388d84f8bac4a7d2a72986864c", 16) - g12To194x, _ := new(big.Int).SetString("c55aeab8b28d83fd4804f4bdd1cdb1e5516015ce22af1e110808eb6796f62a48fe8eea251d514e887650dcadc39def", 16) - g12To194y, _ := new(big.Int).SetString("177c839def54a86f879deeb5f15c5dddb1c6adf3a3c1bd9e4e79b4d8b26bc43ede744075562d10b81a240138e8455e1", 16) - g12To195x, _ := new(big.Int).SetString("1105c20f194e40e47ddfc67d3c2847ed841f63e0e1af6546f73af72f260b11fe3fafe46b3a41686d110cb07be24ab33", 16) - g12To195y, _ := new(big.Int).SetString("714b782b7923dcbbb584eeb469ad872536aca104ce9bd473428e567af9b55a7ccf5a5fa9d56185b3ffe354b4298a01", 16) - g12To196x, _ := new(big.Int).SetString("1116c55421ef7370fd3656007023683a9b495478c870adfa074313df8187342031cdff474041f1651a73f4c9ff709d6", 16) - g12To196y, _ := new(big.Int).SetString("80791ddb2418bb4685fc9f4377b63b92f3c66d120b7c97d857f78886a501e1dd83f047a49f420b83b6957d2120b71", 16) - g12To197x, _ := new(big.Int).SetString("3df18d8a4dbc6781742de2628cc12170472db073be5804eb3606e0cd713f55536c35b20a060c48c0f51c2cb1f9af3d", 16) - g12To197y, _ := new(big.Int).SetString("3cd17e0a2f9bc57321467dae7f43b78b1c902c576558ff1fe389b5d5d570f13c0802e29b07e198c6b0ae18be8d39c2", 16) - g12To198x, _ := new(big.Int).SetString("3f21786ce8f4fc420a75fcbef2f60e48715f80da3429d88289d7d5d1366c76b3786d6541f281913d0847c6f4ce84a2", 16) - g12To198y, _ := new(big.Int).SetString("1419f8e19f28ae0d6bf54763dadc5861b16affa1c7e240f7ab7e6ec22b06edc07fc36912953af41850c2726bc8d79c1", 16) - g12To199x, _ := new(big.Int).SetString("118eacd4f99a7d65ea1a055bb139ddff1024284c1227afd27cebdf2a44ffd5272a998b390aa73b4f54f19898d460976", 16) - g12To199y, _ := new(big.Int).SetString("47e50aed98571fb91415d84c3417b6a0d17d990046112fae29005faa6d2ae98b1b9464b59829c0ae715a65d33525b2", 16) - g12To200x, _ := new(big.Int).SetString("cf4908fda94aa06c04d26e30491ac30ddce9a6a3266555b5686c1720120cdecc3ef91e7427f622727e79b1b86f8797", 16) - g12To200y, _ := new(big.Int).SetString("16e19b5fc4ebe0bb8abdb30aa933b8cef3c87c09a0f23ca356fe55314dddb83bafbaa7531641dc5cb8021f4ad5f6c4b", 16) - g12To201x, _ := new(big.Int).SetString("380a1af45213129ae237fc6da75d4982eb6636e2268c81379412961651ceb218a73290294dc28a44c38d6c9584a3bc", 16) - g12To201y, _ := new(big.Int).SetString("69fd537c980b67e523b0b3f3fde7d8538f96207be299b6752ffced4e8f11d7e0a325d8c86671cf00b91829c9bcd5e6", 16) - g12To202x, _ := new(big.Int).SetString("5fe086b1c4b10505db63f342fb415f6d6861d07ee468d3349e163092ab5e030033a7fdc2107a93747905a44cfaad95", 16) - g12To202y, _ := new(big.Int).SetString("41a6b3dd31fe367f16863e68f319627c8a3acf4bb80248f5abc4401afcfb333fe97ab35da581cf251d0991e9b57e49", 16) - g12To203x, _ := new(big.Int).SetString("136776a77fc774c7786b3ab805bd8497fd6c8e798865a250854863a5f05efa4c8c6c1cad56b74d5a8de2009b9de5847", 16) - g12To203y, _ := new(big.Int).SetString("1960e3ca3276ce29fbfd5e61985740c9e94baeaafa3c6ea8648d502e76c4771d91610806cf7db1845721425594fa105", 16) - g12To204x, _ := new(big.Int).SetString("51774de396e0456c71dd80a60f12d21cd8d394f444f8ec11cc1241172b823e5a2da0e4026f0463f6938507a28f61fd", 16) - g12To204y, _ := new(big.Int).SetString("70f63c6e5f10ca36d4f66cf255f49d38d272887072471f04e301922318eb176ee7fdbe5d37e730853dc70b2c97106d", 16) - g12To205x, _ := new(big.Int).SetString("114e44441bab56585d1f00e4698303b8ae52925ed22ff608f3f346d0c1796f00f954e240a5965aa50f6f684a2739c73", 16) - g12To205y, _ := new(big.Int).SetString("1add868b94031d9254694dc163765c071de69620dd7198b9e980407a82f2b5bad8c9ed3c151f965bb735754162776ad", 16) - g12To206x, _ := new(big.Int).SetString("94c916a63bafc36d0ff51f36dbf5abe60c974ccde1f2945e3f482a996e15063f9334ab874ae00d7d4baeeece68a76a", 16) - g12To206y, _ := new(big.Int).SetString("c5b8c12e8b085309c2218ab936a9f8486242ba4abe16605fcf53e2fa59b8b4f2f0d8fce0866a63ecc2b1d9559c887a", 16) - g12To207x, _ := new(big.Int).SetString("118440e9ea5d0ca6a4d593eadf149988b376ae79deba462c11b9c4146cbca71d93710184cddba8bf57e9bdf0f4fd5b3", 16) - g12To207y, _ := new(big.Int).SetString("9817389a50fe85127287e1c25d5c40a7c793e787f048bf02a69ff2492e898227d9d5d40ec3fd29f86d7cc912e4ad06", 16) - g12To208x, _ := new(big.Int).SetString("44e02fe124b5a7754ce07713a818b661a88e5b59609c2fb866fa26023d0499ea8ecf96ce2cfd661c67b2a7bbee76e8", 16) - g12To208y, _ := new(big.Int).SetString("d3ba51a10bbed75f98f791cb225080b3087e4668935e2d8200d2a42c0aa5ba28c1711c841a835882e2669c19e04fa7", 16) - g12To209x, _ := new(big.Int).SetString("ae715b1dd065c4e8b9df8d27c6f40868fdf5f5da8c17474258e2d7df84e69654d4fa23f574343c7746e4cedb04da5a", 16) - g12To209y, _ := new(big.Int).SetString("980127fbe1ac3176c4c3494a8f11b4d6f07b65aaa4c37a133007601111f8167cbd58cc4b755cfec8877b440618734a", 16) - g12To210x, _ := new(big.Int).SetString("d4e72f646af729fc96a5b6619ec898808a8bd12f9a0e2b60a54e844c04ae5a00dd215424a869037219d426f839d651", 16) - g12To210y, _ := new(big.Int).SetString("41ecfaf326ee4b88c5f81811ea8c338e943516ba7da547b0bafcd484de23e208b39dddf2ca0add4f420a9c2722bdbd", 16) - g12To211x, _ := new(big.Int).SetString("4bcbfa770bd4aeb8b160709c8a69fb22cdc4e58ca9a58763b99c53617358671e8c20d8ec33cb06a75d4da3a3982a1e", 16) - g12To211y, _ := new(big.Int).SetString("3d7b253a592e3fc11ca9d6b143348f88232abe363a699726bda6f9a61f4e84cd5bcf08f6f8278306de297060476df", 16) - g12To212x, _ := new(big.Int).SetString("f19dc610f4449da5420a5d5e6406bcb006b62faea414868d2e38eed978596cff8e86a4e47676101cb98259e082146b", 16) - g12To212y, _ := new(big.Int).SetString("830e4e2e50bfefce0bc558c9e74c9714a71a5a471ccbd3d9d7ac534c009f399e15f85c324a7d5dc2585d74946c6500", 16) - g12To213x, _ := new(big.Int).SetString("197885701bd9af118177ec0f6f791ef4251959a3f59b80a05e1653a1f633432c3a4018555ffd215db7f9d5084390b9f", 16) - g12To213y, _ := new(big.Int).SetString("608112aa435d04a0f05bd432e13b67ab7bda184ad23763a858a35aef57d59da082e1e842f75ee524f8de79ee794d8a", 16) - g12To214x, _ := new(big.Int).SetString("16bd8a55e3b1695699dea5763a5fe6418a55899f3c768a68ab1e04e676a7052446c609bc0e5506d7972397f6392910c", 16) - g12To214y, _ := new(big.Int).SetString("16feab32309d89d44a8b2868a130d3007b69b1ed83d601d1acdf9f6f8b2331ef9926fb47e0436802b064aae773d646d", 16) - g12To215x, _ := new(big.Int).SetString("192a288de4334ce746bf19aa8e26e736a51be264d605ebf93991272741aac00736aaa1db44f3e565c365a03304d4671", 16) - g12To215y, _ := new(big.Int).SetString("7f44babc07ca8bcf82dbc9ffc304e0e44a05005d9918850f89cf0e653073f8ce343cfa307e52156657ecafcb1d52ff", 16) - g12To216x, _ := new(big.Int).SetString("3bd781aa9a31d5ca87a7e692e86eec5b6229cc0199d804a1b8db429adea932c92788fbba31297cee74147a5e861395", 16) - g12To216y, _ := new(big.Int).SetString("1a3bf79a61de7f92887ed75e0fcba22522df68818ea86d86dfac86bf60ec06f77f058f06980b03fdff28d0fd57f2e0b", 16) - g12To217x, _ := new(big.Int).SetString("2402d983298af793f637561b68b08f470992fbda0ec4da86d7179ccc4b979a0f9164ceedc9c6a29a2cc54ee0ecf1bc", 16) - g12To217y, _ := new(big.Int).SetString("144e6b94177252db037f6a84f6d16d40758ada97caf5d7d9387a7928be61828c0459d7317a24bdb42caabc0966dc716", 16) - g12To218x, _ := new(big.Int).SetString("e0fcb99476c675900c955298c1df338e33e23b28a74ad9a27b4ffd47ea8bd67b9de3b5add072c8a1b072b9fb78066", 16) - g12To218y, _ := new(big.Int).SetString("6f388a7db5cbb124de08a246b079f628e61b1cd7c0e5edc65fb19cb21938071a56ccd33ca116f5a2397713c63048db", 16) - g12To219x, _ := new(big.Int).SetString("11498993939102f5740d8858f5ee70a087ae0d52b2cdb801e279e42ff150975019a92576cc14fd2b8e07efa76b2589b", 16) - g12To219y, _ := new(big.Int).SetString("9977f5d8f10e23098bdba68a286f25fb2b6db0aef7ee845934934f4268789a2c042f44a6c80f0162ed5b2bfe537d30", 16) - g12To220x, _ := new(big.Int).SetString("9ebce7cceb0314e1994f20d7a716ad5ef32c3cdd8171950dcef910261445412d9a5682dc2e0500370e2d6317c384d7", 16) - g12To220y, _ := new(big.Int).SetString("10d543e1a05b9c11d5a24ace56f05d04799b48c6f86a4df612fbea5ad2e2954ee8a041ecb5b765ac6a32392242903f0", 16) - g12To221x, _ := new(big.Int).SetString("82bbc0277954ba90241cc800aa18b05f2826378db66d59da11ec6a9fcda310415f8385f68f2eb25f2ed3abb21581c0", 16) - g12To221y, _ := new(big.Int).SetString("1258c7929372aef1be2ba403af16d1fe24d500c81499a17adae4fb94775cd7b593911ea2e04d7d4e7946d68ac301373", 16) - g12To222x, _ := new(big.Int).SetString("1130ab0736b48f526e01bc5fc4cf9164ac4704047e54f9d8e9f861dc9cae10a884b5b16423f344d86de58d1f0c8aa61", 16) - g12To222y, _ := new(big.Int).SetString("68b14390cb893f5e775837141eff37bf894c75899591a3e67779cd16d89567db5c69539bb486f57a24b6c4892b1b88", 16) - g12To223x, _ := new(big.Int).SetString("5e04b1e370b58aa76aa0071ab2e6586501eabf3d80c2b8967eab61f56dbc6a3943c1e9e6000729ffce3811f4478d2b", 16) - g12To223y, _ := new(big.Int).SetString("1374b8d7eb70c4cb81df2bb50e894791d5ab853520480e89c198c96ab7158993000b895e21b618d33f30e9f3dbd4930", 16) - g12To224x, _ := new(big.Int).SetString("174a97d44f91430e497ae21c793730e8b5441ee8708021e73637a9f8c30066e641794ffb913b92fbe64566879f9a194", 16) - g12To224y, _ := new(big.Int).SetString("151ce7878fa02ec8966f73c48125743a771018b3dc5743a2bd836b90ed38444df88aecff1dbbce14e0ee2888e1ef708", 16) - g12To225x, _ := new(big.Int).SetString("16a2d22751e0faeeef7844c4427269e26009b756ec7a4fbe5a727df769bdb9ef441142ce22daab727482ab2673435b7", 16) - g12To225y, _ := new(big.Int).SetString("1224d9344ee5398193bad09c691f4ea3067802c789714ebda5e62c2eef5c524b7ab9a73afbbcc3d3866b94b1e838f33", 16) - g12To226x, _ := new(big.Int).SetString("14de3ccef2af8ee23cf6b04f610838aa53cf823dc104d975f19db702bc56d5d25bea164369267dfe22d9feb60902e3f", 16) - g12To226y, _ := new(big.Int).SetString("58d7a014b6c3abb260b6569c61e74425a97fa90dc588966aff854c0fb682ce41d779079962b88a4425c29f06a6753c", 16) - g12To227x, _ := new(big.Int).SetString("6c19a89057fb87bfc179bf4062ab6459526bdc11146304f311f647ea5957e12244418386c0fe09da476630835add77", 16) - g12To227y, _ := new(big.Int).SetString("bbe679f18d53cd4df93bd02f6f5511050647d160c59514673f1e86e3891053b8445f45df4a3b373861503c71d58de9", 16) - g12To228x, _ := new(big.Int).SetString("ecf150e129cd512a141df58f95f8c38512fb2af1bd320a94842569f434fed7a0604cbf1b1528eb1118c11c32a692aa", 16) - g12To228y, _ := new(big.Int).SetString("122d71c7c5115b38a0f2aa28e8e21b649db953bbac9aeea82e7e14c02c8c1cf1cde06eb8914ceb29d2979533d0a8a1f", 16) - g12To229x, _ := new(big.Int).SetString("19a4e9478707019b033794bf784f3c37777efa971f51003a37b460479fcc05910dba5c852f534a299b9e2404288bc86", 16) - g12To229y, _ := new(big.Int).SetString("398ff16dcc00614b1e2257987ee2c339a53a29e67a2d6b4687089d36fc5d432e6c4d0bcf1609db45dc2f3f11fecc53", 16) - g12To230x, _ := new(big.Int).SetString("d4483fdce59dfd84042f5be7f8458962a8867c4ea38445f809abe00cf3286979a93ed8690630783455c17e06e37647", 16) - g12To230y, _ := new(big.Int).SetString("7bf259c13a02f5117d6e1f1b4a0899c1082c6ee6b71ca1511833e312c0a7c81732cec58d4fb8b5ca0c62a7c2e07807", 16) - g12To231x, _ := new(big.Int).SetString("7f0589fa75f0f5cc007a62fe6cc3e368adb2bb08de7eefc8821a031935ea2c98ffe212e6c15f031f2ed23aa58311", 16) - g12To231y, _ := new(big.Int).SetString("1612984f2bb0a5fe9f3c941a4cd2bb1946a3a4d1f605faa84161c6340cc1b1890cc6821fcb23f9111975839883d1792", 16) - g12To232x, _ := new(big.Int).SetString("f74be9f2e89f7fc9d63e1a380117e4ed633b936ae43735e6ff3f28056d1362725c791ebccd776fe43fd9436277c0", 16) - g12To232y, _ := new(big.Int).SetString("101552b0bc58c07276643717fea8a73853c5194ef7e4a39f72ae9d87f79402c42d18a67517760721113eb4efb6a6b72", 16) - g12To233x, _ := new(big.Int).SetString("15789f64a8d6d7d1ccd4501e25f29ef551f2a020b11948464b56943c8d893ad47241325be82cd684a12d8a94d178b50", 16) - g12To233y, _ := new(big.Int).SetString("16a632a4df6dea33665ac380117f717b7d38a0072d6a531e131f1fa3aa4db46b01339cc7b2c9f03f78acdd37982ddda", 16) - g12To234x, _ := new(big.Int).SetString("5eee70541f00b428410a9f0b6112ab6c14c01c3af8c6831709ba9baf84ce9dc1ba948251e603279474ebbd9dd432cb", 16) - g12To234y, _ := new(big.Int).SetString("1c026b8f77584b85ef151e4454cfe9ca90ab047b3e012ae5273a8c10a6c28584c14fa6855e21b6ff88dd3bd73a0125", 16) - g12To235x, _ := new(big.Int).SetString("98a5fb33dde33395886a093e83b6e681fa4ffc07ec561bd840281a6c464509203dcdf7ee209d109600907e6bf257dd", 16) - g12To235y, _ := new(big.Int).SetString("788c41665350ffaa411f7f87eb1841dc9c55a2a2d9eee4d53074d259ff8212be1412b24ade48b6659d73a2aeef2893", 16) - g12To236x, _ := new(big.Int).SetString("f11dccf426e9213ade8c9ee90b06f3bea1e6457601318092afdb2845873962a9ebdf44d6a52517e30e2fb59d47937d", 16) - g12To236y, _ := new(big.Int).SetString("11a2c73b55ae8b0418e23694e988a586a00e7d167972e66def5b18b80f5822e0386be601d0eb553a33e2dcea9d2f304", 16) - g12To237x, _ := new(big.Int).SetString("54733fda527c1d2c1967947da26074e803c5143b267a3661439bf3f773a42a754ef55d56dbb624d2daa933656b26ca", 16) - g12To237y, _ := new(big.Int).SetString("18f358aa4576692f77586da3ea26d5fa85516181e6838a7bf7b52b586c06d9f7074c5e90e7ba1ac4a925d368d8cb981", 16) - g12To238x, _ := new(big.Int).SetString("184c780c3114f29206d1533772298961a70b6fdaeccc642335a824909cdb6f906e957dce89627d1e7716d95a2cfb46d", 16) - g12To238y, _ := new(big.Int).SetString("12d98e699809d4e11aa2e0b33a6fbfef9e22336bdd90fffa323b7e3bb30ae239089b2be9ff8058ac6c15597788af01d", 16) - g12To239x, _ := new(big.Int).SetString("1585afaee8b5f5508cae51b92a6c44c8d49cb8dbe9673c33eb981efea193d06ccc524de0dfe21c4dc0981ae129d80d", 16) - g12To239y, _ := new(big.Int).SetString("13f2a75ebdb771622fc9ced0989babf38f67dfd65a083a692514dabe83b3a97eac4e42bdb47cf6d51b8f3d5c963565f", 16) - g12To240x, _ := new(big.Int).SetString("14355642d7750cbbba97db165768632badccfb6af700fff0805d22834e97eefcf84defb444cf0273b1a9944f7e5b91", 16) - g12To240y, _ := new(big.Int).SetString("1197f01614054d77e687096e7538f6a2545b860dac56f1891056c358e42ead9a2bb48b10afac6df3fce655328a5e818", 16) - g12To241x, _ := new(big.Int).SetString("13b73e44f2659f9e3107e77dfbdf6a1ef7f9bb9f50d1edef96f72a35233da9405700d898d93db5507d52dc52889823a", 16) - g12To241y, _ := new(big.Int).SetString("16b68db42349d35537fac003e9f2bb42031b338c12f4913997c4884ffd26990afd463d337dfbb5d29eeb5fe2385e77", 16) - g12To242x, _ := new(big.Int).SetString("89a89ab5b237b3cccd3fe1dcaa534fc6568ee9d460b3ca0df9c84f9ad0af74e11d99a258d42e2fdf90c87ffb008fda", 16) - g12To242y, _ := new(big.Int).SetString("116466cbf9bc5f5cf137f3b917fb95025546af24874a181f09a3798ffc6214dd8c60ee3dc473ba4693ca0c272dd993d", 16) - g12To243x, _ := new(big.Int).SetString("1955d0dba9ad4e82d07b90e40a406188df46abdc803974b4104fff90ad95f1ae7c278690cc349c3a35dd36e67eaedd5", 16) - g12To243y, _ := new(big.Int).SetString("17f6f0f43e95cce0f3091b701119eedb0631f018c3ee3adf30e011fadb07a460c18d08db250bae2d071fef1a92a1f79", 16) - g12To244x, _ := new(big.Int).SetString("1ac41b9b7179d3b109edaae37533c2eda16f2ef82ad3b6116001e33ca216786d72d5df4eaddc275a349be1f221ef018", 16) - g12To244y, _ := new(big.Int).SetString("17007d8c32333765265165962b19a98122d21d224d1529e10776c574997401b32af137363701401acd4f8b28337da6d", 16) - g12To245x, _ := new(big.Int).SetString("1173c60965d349c342b3423e4fdd4bd8e2d9321895e2e5131e4434094a918415e8ef88daa57f29e507345caec040621", 16) - g12To245y, _ := new(big.Int).SetString("175d01ed6f7e2a7cb9866762d30756dee408e5ebc1c34a2c84b795db33f09a89ef455ba08e99d8bb2a28b9e86616c4", 16) - g12To246x, _ := new(big.Int).SetString("5c1bc8f91e383e69293368e1b57038c922347f71ea365a4db593f71074875ef0e6d432ca81c4b80ee579965cf17c93", 16) - g12To246y, _ := new(big.Int).SetString("189e095fc94cb2e838ead34306a32b40924cccc78b4a0cf28af85fbe0b54538cf8a772b75095f356a1c0ef3296f5561", 16) - g12To247x, _ := new(big.Int).SetString("8a9efcf927af9dbe6e2d4c77d29df093ef459afced7a9f097f017091ff06e4bf4d6b640966c68c10b75f1e7149a85", 16) - g12To247y, _ := new(big.Int).SetString("70805ec8649c9a7c25d21736edb523b4790d3747f1a368d21293243c6dc11c5fe79daaf07c4d63fc9d187df46fd510", 16) - g12To248x, _ := new(big.Int).SetString("16e52b1a5b5ec2b3fe5af7e76b966000583cf9670843094480b65d13a592603e9cde594a02e2415372d36d238673d8d", 16) - g12To248y, _ := new(big.Int).SetString("d5022a2983f3d3fb721884c0af2829680a18dbbd005394c5065c498ae2c6826831da4f412db24ce93ab82ade2b9000", 16) - g12To249x, _ := new(big.Int).SetString("133fcd0d44b5e9b4101193f9d001faa4f8d888b85643e479c8e6e541a9270caaa8d54d5f0bb87a1f8ec5a25cf4be6cc", 16) - g12To249y, _ := new(big.Int).SetString("19c9d609e590e4b4eaf3f48c1a7c52c5a019da645e7411ea105ef0bc3ccf4682f0ff73522747157d7468f84c7cecebc", 16) - g12To250x, _ := new(big.Int).SetString("fee78dced3f99645d6043ff6106a2427a646ce40ef8bac3664c76edbb88b6e5106ee4cfaaf5858118ed3290b75621a", 16) - g12To250y, _ := new(big.Int).SetString("3e93b344b8faf9ac5549ed35296a660bac621823591228bb54e6d19b0c7985482f37e76d3d5e4744c568529023ba9b", 16) - g12To251x, _ := new(big.Int).SetString("1190d295e06f2de4269762adc2c605d3c767055ab628933f1a3a184b691ab73b7724beb9c126974b8f4553308c6c2bb", 16) - g12To251y, _ := new(big.Int).SetString("6895ecd12c1cfcc15a05cde2e775d7387754b5e3fc43b1961f370dc28fc9b6a5602389685b7251dd0f6ee1490e99ce", 16) - g12To252x, _ := new(big.Int).SetString("13a0c4f35b617ea8aa399aac8b1c977320c28204236dc32ada1b64e7a8c79165f34ba75baef06d41918e24984c8ddfc", 16) - g12To252y, _ := new(big.Int).SetString("8f6802c76d44e816b66d17f7be4e845edf2c12caae31d9223f8b9b40dcf782b222218ca0c725116b18986661f9068c", 16) - return CurvePoints{ G1x: g1x, G1y: g1y, - - G1mx: [253]*big.Int{g13x, g15x, g17x, g12To3x, g12To4x, g12To5x, g12To6x, g12To7x, g12To8x, g12To9x, g12To10x, g12To11x, g12To12x, g12To13x, g12To14x, g12To15x, g12To16x, g12To17x, g12To18x, g12To19x, g12To20x, g12To21x, g12To22x, g12To23x, g12To24x, g12To25x, g12To26x, g12To27x, g12To28x, g12To29x, g12To30x, g12To31x, g12To32x, g12To33x, g12To34x, g12To35x, g12To36x, g12To37x, g12To38x, g12To39x, g12To40x, g12To41x, g12To42x, g12To43x, g12To44x, g12To45x, g12To46x, g12To47x, g12To48x, g12To49x, g12To50x, g12To51x, g12To52x, g12To53x, g12To54x, g12To55x, g12To56x, g12To57x, g12To58x, g12To59x, g12To60x, g12To61x, g12To62x, g12To63x, g12To64x, g12To65x, g12To66x, g12To67x, g12To68x, g12To69x, g12To70x, g12To71x, g12To72x, g12To73x, g12To74x, g12To75x, g12To76x, g12To77x, g12To78x, g12To79x, g12To80x, g12To81x, g12To82x, g12To83x, g12To84x, g12To85x, g12To86x, g12To87x, g12To88x, g12To89x, g12To90x, g12To91x, g12To92x, g12To93x, g12To94x, g12To95x, g12To96x, g12To97x, g12To98x, g12To99x, g12To100x, g12To101x, g12To102x, g12To103x, g12To104x, g12To105x, g12To106x, g12To107x, g12To108x, g12To109x, g12To110x, g12To111x, g12To112x, g12To113x, g12To114x, g12To115x, g12To116x, g12To117x, g12To118x, g12To119x, g12To120x, g12To121x, g12To122x, g12To123x, g12To124x, g12To125x, g12To126x, g12To127x, g12To128x, g12To129x, g12To130x, g12To131x, g12To132x, g12To133x, g12To134x, g12To135x, g12To136x, g12To137x, g12To138x, g12To139x, g12To140x, g12To141x, g12To142x, g12To143x, g12To144x, g12To145x, g12To146x, g12To147x, g12To148x, g12To149x, g12To150x, g12To151x, g12To152x, g12To153x, g12To154x, g12To155x, g12To156x, g12To157x, g12To158x, g12To159x, g12To160x, g12To161x, g12To162x, g12To163x, g12To164x, g12To165x, g12To166x, g12To167x, g12To168x, g12To169x, g12To170x, g12To171x, g12To172x, g12To173x, g12To174x, g12To175x, g12To176x, g12To177x, g12To178x, g12To179x, g12To180x, g12To181x, g12To182x, g12To183x, g12To184x, g12To185x, g12To186x, g12To187x, g12To188x, g12To189x, g12To190x, g12To191x, g12To192x, g12To193x, g12To194x, g12To195x, g12To196x, g12To197x, g12To198x, g12To199x, g12To200x, g12To201x, g12To202x, g12To203x, g12To204x, g12To205x, g12To206x, g12To207x, g12To208x, g12To209x, g12To210x, g12To211x, g12To212x, g12To213x, g12To214x, g12To215x, g12To216x, g12To217x, g12To218x, g12To219x, g12To220x, g12To221x, g12To222x, g12To223x, g12To224x, g12To225x, g12To226x, g12To227x, g12To228x, g12To229x, g12To230x, g12To231x, g12To232x, g12To233x, g12To234x, g12To235x, g12To236x, g12To237x, g12To238x, g12To239x, g12To240x, g12To241x, g12To242x, g12To243x, g12To244x, g12To245x, g12To246x, g12To247x, g12To248x, g12To249x, g12To250x, g12To251x, g12To252x}, - G1my: [253]*big.Int{g13y, g15y, g17y, g12To3y, g12To4y, g12To5y, g12To6y, g12To7y, g12To8y, g12To9y, g12To10y, g12To11y, g12To12y, g12To13y, g12To14y, g12To15y, g12To16y, g12To17y, g12To18y, g12To19y, g12To20y, g12To21y, g12To22y, g12To23y, g12To24y, g12To25y, g12To26y, g12To27y, g12To28y, g12To29y, g12To30y, g12To31y, g12To32y, g12To33y, g12To34y, g12To35y, g12To36y, g12To37y, g12To38y, g12To39y, g12To40y, g12To41y, g12To42y, g12To43y, g12To44y, g12To45y, g12To46y, g12To47y, g12To48y, g12To49y, g12To50y, g12To51y, g12To52y, g12To53y, g12To54y, g12To55y, g12To56y, g12To57y, g12To58y, g12To59y, g12To60y, g12To61y, g12To62y, g12To63y, g12To64y, g12To65y, g12To66y, g12To67y, g12To68y, g12To69y, g12To70y, g12To71y, g12To72y, g12To73y, g12To74y, g12To75y, g12To76y, g12To77y, g12To78y, g12To79y, g12To80y, g12To81y, g12To82y, g12To83y, g12To84y, g12To85y, g12To86y, g12To87y, g12To88y, g12To89y, g12To90y, g12To91y, g12To92y, g12To93y, g12To94y, g12To95y, g12To96y, g12To97y, g12To98y, g12To99y, g12To100y, g12To101y, g12To102y, g12To103y, g12To104y, g12To105y, g12To106y, g12To107y, g12To108y, g12To109y, g12To110y, g12To111y, g12To112y, g12To113y, g12To114y, g12To115y, g12To116y, g12To117y, g12To118y, g12To119y, g12To120y, g12To121y, g12To122y, g12To123y, g12To124y, g12To125y, g12To126y, g12To127y, g12To128y, g12To129y, g12To130y, g12To131y, g12To132y, g12To133y, g12To134y, g12To135y, g12To136y, g12To137y, g12To138y, g12To139y, g12To140y, g12To141y, g12To142y, g12To143y, g12To144y, g12To145y, g12To146y, g12To147y, g12To148y, g12To149y, g12To150y, g12To151y, g12To152y, g12To153y, g12To154y, g12To155y, g12To156y, g12To157y, g12To158y, g12To159y, g12To160y, g12To161y, g12To162y, g12To163y, g12To164y, g12To165y, g12To166y, g12To167y, g12To168y, g12To169y, g12To170y, g12To171y, g12To172y, g12To173y, g12To174y, g12To175y, g12To176y, g12To177y, g12To178y, g12To179y, g12To180y, g12To181y, g12To182y, g12To183y, g12To184y, g12To185y, g12To186y, g12To187y, g12To188y, g12To189y, g12To190y, g12To191y, g12To192y, g12To193y, g12To194y, g12To195y, g12To196y, g12To197y, g12To198y, g12To199y, g12To200y, g12To201y, g12To202y, g12To203y, g12To204y, g12To205y, g12To206y, g12To207y, g12To208y, g12To209y, g12To210y, g12To211y, g12To212y, g12To213y, g12To214y, g12To215y, g12To216y, g12To217y, g12To218y, g12To219y, g12To220y, g12To221y, g12To222y, g12To223y, g12To224y, g12To225y, g12To226y, g12To227y, g12To228y, g12To229y, g12To230y, g12To231y, g12To232y, g12To233y, g12To234y, g12To235y, g12To236y, g12To237y, g12To238y, g12To239y, g12To240y, g12To241y, g12To242y, g12To243y, g12To244y, g12To245y, g12To246y, g12To247y, g12To248y, g12To249y, g12To250y, g12To251y, g12To252y}, + G1m: computeBLS12377Table(), } } diff --git a/std/algebra/sw_bls12377/inner_compute.go b/std/algebra/sw_bls12377/inner_compute.go new file mode 100644 index 0000000000..88388a2535 --- /dev/null +++ b/std/algebra/sw_bls12377/inner_compute.go @@ -0,0 +1,33 @@ +package sw_bls12377 + +import ( + "math/big" + + bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377" +) + +func computeBLS12377Table() [][2]*big.Int { + Gjac, _, _, _ := bls12377.Generators() + table := make([][2]*big.Int, 253) + tmp := new(bls12377.G1Jac).Set(&Gjac) + aff := new(bls12377.G1Affine) + jac := new(bls12377.G1Jac) + for i := 1; i < 253; i++ { + tmp = tmp.Double(tmp) + switch i { + case 1, 2: + jac.Set(tmp).AddAssign(&Gjac) + aff.FromJacobian(jac) + table[i-1] = [2]*big.Int{aff.X.BigInt(new(big.Int)), aff.Y.BigInt(new(big.Int))} + case 3: + jac.Set(tmp).SubAssign(&Gjac) + aff.FromJacobian(jac) + table[i-1] = [2]*big.Int{aff.X.BigInt(new(big.Int)), aff.Y.BigInt(new(big.Int))} + fallthrough + default: + aff.FromJacobian(tmp) + table[i] = [2]*big.Int{aff.X.BigInt(new(big.Int)), aff.Y.BigInt(new(big.Int))} + } + } + return table[:] +} From 5e0ed5e2f8cc174b643190303071138c77b6e176 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Thu, 2 Mar 2023 10:39:27 +0100 Subject: [PATCH 041/464] refactor(sw_bls12377/ScalarMulBaseG2): lazy-compute base point multiples --- std/algebra/sw_bls12377/g2.go | 44 +- std/algebra/sw_bls12377/inner.go | 1039 +--------------------- std/algebra/sw_bls12377/inner_compute.go | 36 +- 3 files changed, 61 insertions(+), 1058 deletions(-) diff --git a/std/algebra/sw_bls12377/g2.go b/std/algebra/sw_bls12377/g2.go index c9576f7f00..b2e8b80ed3 100644 --- a/std/algebra/sw_bls12377/g2.go +++ b/std/algebra/sw_bls12377/g2.go @@ -485,30 +485,30 @@ func (P *G2Affine) ScalarMulBase(api frontend.API, s frontend.Variable) *G2Affin // gm[0] = 3g, gm[1] = 5g, gm[2] = 7g res.X.Lookup2(api, sBits[1], sBits[2], fields_bls12377.E2{ - A0: points.G2x0, - A1: points.G2x1}, + A0: points.G2x[0], + A1: points.G2x[1]}, fields_bls12377.E2{ - A0: points.G2mx0[0], - A1: points.G2mx1[0]}, + A0: points.G2m[0][0], + A1: points.G2m[0][1]}, fields_bls12377.E2{ - A0: points.G2mx0[1], - A1: points.G2mx1[1]}, + A0: points.G2m[1][0], + A1: points.G2m[1][1]}, fields_bls12377.E2{ - A0: points.G2mx0[2], - A1: points.G2mx1[2]}) + A0: points.G2m[2][0], + A1: points.G2m[2][1]}) res.Y.Lookup2(api, sBits[1], sBits[2], fields_bls12377.E2{ - A0: points.G2y0, - A1: points.G2y1}, + A0: points.G2y[0], + A1: points.G2y[1]}, fields_bls12377.E2{ - A0: points.G2my0[0], - A1: points.G2my1[0]}, + A0: points.G2m[0][2], + A1: points.G2m[0][3]}, fields_bls12377.E2{ - A0: points.G2my0[1], - A1: points.G2my1[1]}, + A0: points.G2m[1][2], + A1: points.G2m[1][3]}, fields_bls12377.E2{ - A0: points.G2my0[2], - A1: points.G2my1[2]}) + A0: points.G2m[2][2], + A1: points.G2m[2][3]}) for i := 3; i < 253; i++ { // gm[i] = [2^i]g @@ -516,18 +516,18 @@ func (P *G2Affine) ScalarMulBase(api frontend.API, s frontend.Variable) *G2Affin tmp.Y = res.Y tmp.AddAssign(api, G2Affine{ fields_bls12377.E2{ - A0: points.G2mx0[i], - A1: points.G2mx1[i]}, + A0: points.G2m[i][0], + A1: points.G2m[i][1]}, fields_bls12377.E2{ - A0: points.G2my0[i], - A1: points.G2my1[i]}}) + A0: points.G2m[i][2], + A1: points.G2m[i][3]}}) res.Select(api, sBits[i], tmp, res) } // i = 0 tmp.Neg(api, G2Affine{ - fields_bls12377.E2{A0: points.G2x0, A1: points.G2x1}, - fields_bls12377.E2{A0: points.G2y0, A1: points.G2y1}}) + fields_bls12377.E2{A0: points.G2x[0], A1: points.G2x[1]}, + fields_bls12377.E2{A0: points.G2y[0], A1: points.G2y[1]}}) tmp.AddAssign(api, res) res.Select(api, sBits[0], res, tmp) diff --git a/std/algebra/sw_bls12377/inner.go b/std/algebra/sw_bls12377/inner.go index b4ddb0553b..5214dc58ee 100644 --- a/std/algebra/sw_bls12377/inner.go +++ b/std/algebra/sw_bls12377/inner.go @@ -66,7 +66,7 @@ func getInnerCurveConfig(outerCurveScalarField *big.Int) *innerConfig { type CurvePoints struct { G1x *big.Int // base point x G1y *big.Int // base point y - G1m [][2]*big.Int // m*base point (x,y) + G1m [][2]*big.Int // m*base points (x,y) } func GetBLS12377CurvePoints() CurvePoints { @@ -75,19 +75,14 @@ func GetBLS12377CurvePoints() CurvePoints { return CurvePoints{ G1x: g1x, G1y: g1y, - G1m: computeBLS12377Table(), + G1m: computeBLS12377CurveTable(), } } type TwistPoints struct { - G2x0 *big.Int // base point x - G2x1 *big.Int // base point x - G2y0 *big.Int // base point y - G2y1 *big.Int // base point y - G2mx0 [253]*big.Int // m*base point x0 - G2mx1 [253]*big.Int // m*base point x1 - G2my0 [253]*big.Int // m*base point y0 - G2my1 [253]*big.Int // m*base point y1 + G2x [2]*big.Int // base point x ∈ E2 + G2y [2]*big.Int // base point y ∈ E2 + G2m [][4]*big.Int // m*base points (x,y) } func GetBLS12377TwistPoints() TwistPoints { @@ -95,1028 +90,10 @@ func GetBLS12377TwistPoints() TwistPoints { g2x1, _ := new(big.Int).SetString("ea6040e700403170dc5a51b1b140d5532777ee6651cecbe7223ece0799c9de5cf89984bff76fe6b26bfefa6ea16afe", 16) g2y0, _ := new(big.Int).SetString("690d665d446f7bd960736bcbb2efb4de03ed7274b49a58e458c282f832d204f2cf88886d8c7c2ef094094409fd4ddf", 16) g2y1, _ := new(big.Int).SetString("f8169fd28355189e549da3151a70aa61ef11ac3d591bf12463b01acee304c24279b83f5e52270bd9a1cdd185eb8f93", 16) - g23x0, _ := new(big.Int).SetString("10989ed742d307e93acdd3ef1a3680e0bb12886bc4ee3fca003f51b04dc60ea6ff6d482b888da1601f96e4acccdeb2a", 16) - g23x1, _ := new(big.Int).SetString("69c7a695505c5042f73f3f69027e0f97c21244c0fd397209582ac6f6f58d1a8b1e6118d9550c7f3d81a461fd12b64c", 16) - g23y0, _ := new(big.Int).SetString("191cd587c9c65903e2cc24a5b031bb76ac23a2968294c604aa74e4574c8b60754fdb3abc99d7dd35707109e4f98c99a", 16) - g23y1, _ := new(big.Int).SetString("4ffd6a638c1b4eeba9769cee5a2ef0e87bbd284704f4ee4870771ad3dbf7510c7799240851ea08209d1ea57c8e2f5a", 16) - g25x0, _ := new(big.Int).SetString("dee4599c0dfec75b85f181ad4ad7c6d220539aa199ff5cef404593273076f21a7edc6de5e2659619e42685605949ee", 16) - g25x1, _ := new(big.Int).SetString("1fb7aac7d4a7034251c904f1304fdf183465e17424a6f6d57f4dc89ab74935f9cf0666aa9d0b80b114feb90f8ee744", 16) - g25y0, _ := new(big.Int).SetString("12af400a1adf1aa920bb79f091e8a28031ee76f6176d9e5ddcd6adae01874e9eddfe1b437efdbf8770a31609116db1a", 16) - g25y1, _ := new(big.Int).SetString("69babca211bf7b049fa5a1446955793f13a916a5c3a542ce016ca6bac631e86ed4f3060406025fa5f10ca06222d98f", 16) - g27x0, _ := new(big.Int).SetString("140f206987ef5eaaf9698aa46ecda04e79abbcbf4179d039224f78a14b59894f3218e0565fc9bd57bc06707f828e729", 16) - g27x1, _ := new(big.Int).SetString("18c1f631463ba7a011c2487841e341a50c4c47be271fd206347e1a6b19da6707f25723da99b827267b226bb6a8ec2dc", 16) - g27y0, _ := new(big.Int).SetString("16e1f5c9a922f928dc069601cf988df26e766a3f64f472bae97cc99dacd0cd593e0269b5c16b773e5ea4cc652c4f4bc", 16) - g27y1, _ := new(big.Int).SetString("af3a712608d508f1adb1c63264a1ba1dd87fe094b643c2c88177a45828a33d8a223ea2c154c247444a010bbfd57311", 16) - g22To3x0, _ := new(big.Int).SetString("12f5e069064c44f6bbb7fcf49b8f1f7bd3fc26228250e50a9358700418a9f2f6d5edc7ef26e8f5ad2547179ca480654", 16) - g22To3x1, _ := new(big.Int).SetString("e84a4d39433ddf62fc22c00f5638ba238757208c08925f7f820a8b2e8a4feb1265fab17dfd0680fad4852a48136431", 16) - g22To3y0, _ := new(big.Int).SetString("147b999363dd973ef30ea09490d512c2cfd38af634198cad2da7be80f547caa51a025a57e5bc55aba5072523da80286", 16) - g22To3y1, _ := new(big.Int).SetString("2beb4a3f2fde9ba09104e96264bf931293f16650c5cad6f74d7ed858dc6bf797d15f3e35cbeb9e784ae913b5b219d1", 16) - g22To4x0, _ := new(big.Int).SetString("8effe15bb484c716ebd3e58b10d96a40351ce1386db2d07371c3e17b79f45a2957f2ba316ddfbf2180494602e222f2", 16) - g22To4x1, _ := new(big.Int).SetString("13859ab95f4a14caf37ed638410ce11d45cdc8fb9e14bbaf4052596b42218e1aba8bfa427f932af88ccfb76f2c533f3", 16) - g22To4y0, _ := new(big.Int).SetString("c8e82def66465b27d678352a0b8cf4d2570e9a8c169c7f7ff1c9ab718862cdf97f1891aef725cea218cb79ff7de8ba", 16) - g22To4y1, _ := new(big.Int).SetString("6e6e163fbd111cbb29722fa4fcd425af241addc28220cf3de8ee0337d46d95556f2344d47c80b2fca05adf8fefce9b", 16) - g22To5x0, _ := new(big.Int).SetString("11cf999d9e3baa60a66c68b4ddd3e0daa8c18eac38a538cb936054d2986814f66ec2fbd579041f36a71ffc32482c441", 16) - g22To5x1, _ := new(big.Int).SetString("7552f8a6c70b31e068d88374a8ba1b75aba13b9e324fc8569c23a97e5b5250b2a74efa4a8667c50ba2923a17ef65eb", 16) - g22To5y0, _ := new(big.Int).SetString("814b87a592f0054fa6f293db2439b13171d94e758adda863a61702b22df78e2554754cde7638a26a757295e5e2d2c4", 16) - g22To5y1, _ := new(big.Int).SetString("f75582d5ace6be7aeeb116787666a4d053b05654f22075f4a109e2ab54164b6e45e526f854c356d1025dca4d5ff721", 16) - g22To6x0, _ := new(big.Int).SetString("1e39bbafad1fedf4757b2595cbb34f41e6a3abd0d57a5af1d2dc9b98a663863bcffabfc0986ab4b10546c038b1dcb1", 16) - g22To6x1, _ := new(big.Int).SetString("47fcd0f33ddb5da867e023d7ccfb58b758bd74acc4d9cf648a1acdffcc7d7a27b8d868fafecd00f3f07a18c7907dd0", 16) - g22To6y0, _ := new(big.Int).SetString("12a50239879e229aa23c146f16b1e504e4cb3f1afa73873caf0de6d64d84a3cf89852595b7a44478d6a30ad6445d69d", 16) - g22To6y1, _ := new(big.Int).SetString("29eb007d42fed95c103084eeec01ccdb7511717ac33cbdb4b4a1e52ebf3227724d9a08091f4ae9b8c27d86edc56ad2", 16) - g22To7x0, _ := new(big.Int).SetString("12950600cdfffaf34d639580fb98c007b122b54f18ac59fa2b398125c8a6d3c4b7f63706e8eaf5891d4b98d9275733d", 16) - g22To7x1, _ := new(big.Int).SetString("f9a82f822549931056e3f3e5692149503b488aa5ac7c2b545108f7947f6b37f91856ff94d093d87c17e41719e4e63a", 16) - g22To7y0, _ := new(big.Int).SetString("1d1caa73f44d96df5dc74ac6a0e5bcb0b24234bb12eeff0be0c2f65cea74fe9e1dc626ce0225608957bc2f8484385d", 16) - g22To7y1, _ := new(big.Int).SetString("d4f0d64b400203912711a00208f02fd900dfb7b99555a98491449e51ac01dea06b726d30603b5786b438695baa3a82", 16) - g22To8x0, _ := new(big.Int).SetString("3de403c785305f79e59eb82ac0a3d7fcea96ff9de04a12bdfdc7e17c11a73d7fd2f88f602ea654e2cd74554c13c3cb", 16) - g22To8x1, _ := new(big.Int).SetString("1799deda9f502a0d6c72b1232af7c0c12f9317d9620a565f61da043e6210e0676ee06a91983df260c13408a17beb220", 16) - g22To8y0, _ := new(big.Int).SetString("ea526f8c945290f17e233052609f33a3692bdacdbd8bb25ec4cbb4c8925a7c5401747d93e663b14d16dcfffdcdaef2", 16) - g22To8y1, _ := new(big.Int).SetString("2748e0d45be676e07d5bef7efaa46e44bea276b25c4675d7c61dca0b2092d63821e2b6517c2840266e0cc4b52883b1", 16) - g22To9x0, _ := new(big.Int).SetString("19adf058d65aefbcd7b5d02c230627b6b3a1a0b9b74cb7de927ff4de31b6fece1f6b7843e2944ccea35f018524cefad", 16) - g22To9x1, _ := new(big.Int).SetString("15c44caf3ed39760e66bce1fabc8ac8a59490b26a5d85d9712db0d99265642695257c7525f79dd037f15c5ae9391f8", 16) - g22To9y0, _ := new(big.Int).SetString("edbdaa165a52c9a62702d2018cd32c102b1567effef73429479512e41f34e9a43e53339594a83974a0589f4fa4fe27", 16) - g22To9y1, _ := new(big.Int).SetString("80cd4d53eab6d7d668dc963dfa0e18c34e86805877169b98188a3a895ab44d6f992714942648ffd34d704cf955a261", 16) - g22To10x0, _ := new(big.Int).SetString("a8e803e07b76357e9a2a8eec1b173dbfb8b71301740737a8c29d1b2f5e37d074cfc9d5b40c6e4a6b93345d957fbf07", 16) - g22To10x1, _ := new(big.Int).SetString("1a20236744d0b3173ad4ab380783ec784cd2b50e4dd051cb1b49056fc9197c83387bdfe79800174cc6dc0d1429b4b2e", 16) - g22To10y0, _ := new(big.Int).SetString("137dee5b26f1b7538a9d369bc88d0fceef9a64af39c6e2854288a251ff466c17f45f972a5b4edde1638ede7628b1179", 16) - g22To10y1, _ := new(big.Int).SetString("11cb8c99dd080d4c728d8690266d12af4de2c48662f0f82f8e33a195e9d262cfd6268285a4a42fc0d89136646bd4198", 16) - g22To11x0, _ := new(big.Int).SetString("abadfbeecce6fc90d0cb1fe7696fe56e6bfbccef068f67244bd5d2c83dcc26bfae60c2a30aab449b70ce1dd270c5e8", 16) - g22To11x1, _ := new(big.Int).SetString("c9052fe78ebe75b7fa99f24ca3ca20af4e39b68d11d78636727f6f4aed9926f03800859fbf016a23e3aaff8e17b285", 16) - g22To11y0, _ := new(big.Int).SetString("d799913fe584af4a12d3e5959473c938dc6b38bd2968e0007a4f81a77d05444093254ee65f4ca41b9a7008f37aa221", 16) - g22To11y1, _ := new(big.Int).SetString("1326a327ec5614f3fb1b0f8fc93f45eea65e6335de14fd535780bf4f462fad683eb4e9d3fded42a5940f890df5993de", 16) - g22To12x0, _ := new(big.Int).SetString("16b0671fd5344d612e1bdac46df9eff8065baef6fd99f469a1b1e3d985f61fa2b02025c287548b3b64a4d2d26375a83", 16) - g22To12x1, _ := new(big.Int).SetString("10d2132d8dd55879cc1b40e6ef19bb1b6a05a8537e5d1536d4245265eec0cf0da4f05a219b13655bfc278b13a8a7d7a", 16) - g22To12y0, _ := new(big.Int).SetString("c24f8bed9e0e7e496455604d1fff6043141e3eb68e3bba0d8bd3cdb441bd6febfc844ba6db2f7de549cd01104bcd10", 16) - g22To12y1, _ := new(big.Int).SetString("140445167894cf4b3fa1139431cfdc94d529666e70988804fc70ea478a0427e9fe38bb6c6899b1e22a995c9cb426d19", 16) - g22To13x0, _ := new(big.Int).SetString("160ea6b124d79e95abead2958f985312f13b5606af895e50320bb83c4ab303f6478a228de33b1e0c40535842a76c1d4", 16) - g22To13x1, _ := new(big.Int).SetString("17513c8a2cda894c9607d728e1af448c701db9017dc653b6664f48470642279b649a26b7043ebd9f2a81dc58633a6ab", 16) - g22To13y0, _ := new(big.Int).SetString("e98bfd3883a8f107d08e5bec3aea9722bf66cfd7b3907f4ede8b84f274118b3b0045b013ba689d0d54210a26cd7c80", 16) - g22To13y1, _ := new(big.Int).SetString("114eb083ea66e1403d1b89a4e375e80d849af0de61d29165f13fe69c2348e9b61a7dcb956e543ddd4045af0b189a7ce", 16) - g22To14x0, _ := new(big.Int).SetString("de1654d81177ba984e02c0d88d2fceffedc11f45511939c909043364ae3edd6aa51d6325ff5074fc6d09665417a9fb", 16) - g22To14x1, _ := new(big.Int).SetString("1e8439dbc7a8de80abffd6949efe6b8308fd10f6f730ffd586bc0a5838f505d9833d1c2cf1328bd5ed81ae16ad4995", 16) - g22To14y0, _ := new(big.Int).SetString("a7acf9a3df51c95b50516ab06b09649ef6944530e5adab8369e15dda3bfcdfa9906f64d8f2320670895756d41b1aaa", 16) - g22To14y1, _ := new(big.Int).SetString("e1a8e22d5b004506a3a298df7d3defe2ed0beeebfd78fe65ddffe1d64f9738e7e45014ccfc0debea4db0c749064eab", 16) - g22To15x0, _ := new(big.Int).SetString("10c70577d4310643681536cf7ba7a13e6085a04f42d1894bee65431813646f14298fb561b63acab77631b3eb374aa13", 16) - g22To15x1, _ := new(big.Int).SetString("167121005cf185e638605dd7ab198c379b5d7905d787256056c6497c6ebe1ab5b6b82805625fbb53c7dafefa955183f", 16) - g22To15y0, _ := new(big.Int).SetString("c3ee9dc727ff9fc8eb45cb338ecf5d41e6419ae6b59cec26d6009e06bd8e46a08a4d2bebb9bc8074e22c55e773e227", 16) - g22To15y1, _ := new(big.Int).SetString("146addeedac5da862e21b7e1346c9940895bb12c3b9a1933dbe601fb6d792d347c4d764ea0274df8a161d445d2331c1", 16) - g22To16x0, _ := new(big.Int).SetString("277ecdf734f7d8bb54d81d926bc9d8825e00263122598aba2e3c7897b4f2b2fabb56eede81351ae8124f8687f6d9d7", 16) - g22To16x1, _ := new(big.Int).SetString("369c77b06cd39c8fa63a4d6e93d8be88dd9729b7d654c745ebdfa39a9163facf95bcac1e060572c713dec3cc15c6fd", 16) - g22To16y0, _ := new(big.Int).SetString("c3823aa2d90cfe8d394263f5a5742959be02999941203d3464d1a32fc2d2afe0fee1680ca003b1c1c1db9cc855456", 16) - g22To16y1, _ := new(big.Int).SetString("170ea235bdd969ecdac824259891897b4d47f424b59e5c3adb0d2150b37c08a49f2453cc66c717c44b24b54b435e420", 16) - g22To17x0, _ := new(big.Int).SetString("c99dd3c2ac74d8b17b87cd187ec66ce411566eac353fcbe01834ba2f876de662abffb19fd37c85be1e59c72f33384a", 16) - g22To17x1, _ := new(big.Int).SetString("b43460420042bbd15095d3bd42a55e6c932704af6671a1317f2ad781d929384de6e8bacc4cefc0ad3bf73c3e114d74", 16) - g22To17y0, _ := new(big.Int).SetString("d015978f6517cbf720051c789e15acc1e64cc5eed6aceed867a5eb92bc62bb84f0ba25a0fcc02c172464f7031bf9d9", 16) - g22To17y1, _ := new(big.Int).SetString("e21ffd0bd2c0158f8d510ece087179af97f4cda168414697aced2e7e4d3bb672e3b89cb3c1143db3b644955ebb78ab", 16) - g22To18x0, _ := new(big.Int).SetString("170a754724c6f0a5ba9b83851361cd6c99172a8eda8e9761a7c206ee3ee6ff1749fec7075743f21e2058620eae00cbc", 16) - g22To18x1, _ := new(big.Int).SetString("13955d1bab3aca0b685c24abe4ec2f5174892b193213de7d73ea1db62bdf5a330538feba6e0ec3b3911b3253d278904", 16) - g22To18y0, _ := new(big.Int).SetString("16bb6c53936acd0cc847c199f6122c57469a4cd5d7dfe0921d5873d5f86d3cdef13db5395f14d9f410f4c2ed6edd5f", 16) - g22To18y1, _ := new(big.Int).SetString("da59d695c7c45a874e4bd2bd742a27ec148a4ba2cd7f5d816cf7f8cec7cbd60fc80b65bde3e0e8a1c26c968205d069", 16) - g22To19x0, _ := new(big.Int).SetString("1a993a512f398bb265b918475d1f1d17e6651f6f7b80a684b90811cf4b18a8f4149367d27eff97c5e3ef5f6318ae75e", 16) - g22To19x1, _ := new(big.Int).SetString("198ee87aadbe5970dca24e4d501681539cd153fd58843db0bd82773e259c3bb94d9ef28c3353e0818b157c798b27073", 16) - g22To19y0, _ := new(big.Int).SetString("1456cff762f88c5ea9e8df9c26748b175c021b14022ca084e2a5215e328bcd6bdf91623243a54e106d143d6b54230c7", 16) - g22To19y1, _ := new(big.Int).SetString("585a875a23fa8688bd10cd8b32d4523c0c44978c9d68dcd126cdaf3a00fb3d64ad11ac9e2111dfaa47a597a5ce07f2", 16) - g22To20x0, _ := new(big.Int).SetString("c1060ff2e135a34dbf8d35ed85d2fe246da8c867983de83590c4caf1edd5b1d17a98526b77c307a8af05183b5af1f8", 16) - g22To20x1, _ := new(big.Int).SetString("7af14740987e9af9e3291a62b06e40d59ed5734d0f4e936e29d1bf28ed27253399bff412fd09fbc240e84fc00b6f34", 16) - g22To20y0, _ := new(big.Int).SetString("16be5e4c0374f4a06d8b56a0cc554db53c81f0ebac202bb025dbc55ed8184c004b4a381c0400d926722c76f655a1e1f", 16) - g22To20y1, _ := new(big.Int).SetString("7ccddc31c6210cb04d2ff180578919b9ecd6bdc8b2eb7fb435f4f3f295cfadb7814728ff4c72f50a551889d0020f7e", 16) - g22To21x0, _ := new(big.Int).SetString("e896461817dc205f31e0a7246076dec0e025999b2960e56b54aec8ee263ae1cb1ff6b6eb3fe9ef374727e5b982b525", 16) - g22To21x1, _ := new(big.Int).SetString("156cf7c802010ab47ae6afde1fa7a6ac0550ed6eadccae63f045ca8b04bc30b09d549ae1fec2057648a16cfb82e6072", 16) - g22To21y0, _ := new(big.Int).SetString("830a8f5b519c3fc54b4e0db3d9a8206a59f0ffa35bfababcd9dfc90fd30e7fd16c05a75ab9cd74db4dbef0cd88084a", 16) - g22To21y1, _ := new(big.Int).SetString("1079cf245699cb058b76d3b8eda6c4c774f015263c479a96b7c297a942d975b4150f5912ed8c0e805012757bfe733e2", 16) - g22To22x0, _ := new(big.Int).SetString("4703638b7729037a2ad9da30cc15800df92624fc57cae4bc6eaf1a727458eb1b44b3ebbdd9b2041f9a14226ca8fc52", 16) - g22To22x1, _ := new(big.Int).SetString("13e0a8fcbaefe05e6f889f48f247407222a7f27766a663146ea3f264dfe37d95764d5709ee4949a1558f3c457cb119e", 16) - g22To22y0, _ := new(big.Int).SetString("1859896a24a3e277b5d0f3ffed9075651998a0971543cfc40a9f0d3e6f533098a1b0169fd547fb3b75868d146c93bc0", 16) - g22To22y1, _ := new(big.Int).SetString("83b05c6c75424d3c8fa42b735c78018c291210571c273d5c21b6141d54d33a21a11b92a450dd35f87553b3949eece0", 16) - g22To23x0, _ := new(big.Int).SetString("d85acb2eea8dba429004ae1d475edbd1be7e750e21a0cde31208344398bc8fb4ffa34bb12c00032934b70ffd635829", 16) - g22To23x1, _ := new(big.Int).SetString("e194ea812428c1f04823c23619b6b5e788b70f722141fb876805798d65db87fc3ca702e357f6f70f6c16aa4043d99d", 16) - g22To23y0, _ := new(big.Int).SetString("8ffe743115002b9e70b229ce28c25b043e4e199d7db30e1beb024da231daaf60cbadfa0291fa0a33442aef8775ff23", 16) - g22To23y1, _ := new(big.Int).SetString("f6a816973f80d8fd3644ac9776e027ef4964e0fef56cc5d1826ec1362b34248b7b15d8df67edfbe07d3d0c55fd489a", 16) - g22To24x0, _ := new(big.Int).SetString("1334f92c69b0c0ecaa8866050189cd5beff27879c63d6b7f1a371660c3b52ab76e3c80743ae6e0fd5d1eb1844efca7f", 16) - g22To24x1, _ := new(big.Int).SetString("773baf6bfe61e4f596ea0f1df3270be5fd1ffab4bf5fa3462a961f12536ab4867bb72be600a11403a09eec6e5d22fb", 16) - g22To24y0, _ := new(big.Int).SetString("1c48cb073300bf742629e289e58c1ac5152786e8f655ae21b0255b82b806d1c98a3ec69c8e26718b05b8945790b229", 16) - g22To24y1, _ := new(big.Int).SetString("42aeb0add0c216c4c4113c9c99496d3151dd0495ecd550672a10e9e718475644477510ec61bd5ab5949be396aaf192", 16) - g22To25x0, _ := new(big.Int).SetString("ce9f7d851983fae51e3683aea9caba3e1fbd1814d04bf236b69871f40ac95ac1394d2c3e8e545211f720546233a37a", 16) - g22To25x1, _ := new(big.Int).SetString("156aaff406e7c7a21f959f27206b29fbfb1e515f0bae5f5f6cd3690aa61102d4222f5eb685f097ddfe10df1c0ccbfc0", 16) - g22To25y0, _ := new(big.Int).SetString("2c54abb20c95f0ed43de472e17cbaaacd1649765c2665a2704d23b3d5d01d98c31159c26cfa699b2e92bb2e460cd", 16) - g22To25y1, _ := new(big.Int).SetString("14c25adca1d7b02b8155dd867f9efaebeb1d720f2cbd00383321be1d3e6403da91835308e91ef6db786e4f02a22549e", 16) - g22To26x0, _ := new(big.Int).SetString("15001e7ecc37bae4befb9454970069eb6ec9ea58ef49ac3c3e381de57399b5eddd893af1779e3936dc40ccb39fe25f1", 16) - g22To26x1, _ := new(big.Int).SetString("1892f5bedd5c0614cd7305ff64b8733718c5c89202b93067398c26476215b09effabf495663727960f2c46b95c04bdb", 16) - g22To26y0, _ := new(big.Int).SetString("10f7aa01eb848efd9b3de430b0f6507017549201d859f2f80444edf69470d8bd05d9e81d23485f5b0a2fea612f5bf06", 16) - g22To26y1, _ := new(big.Int).SetString("177707b5b522d7a2872138854c489221160f077805e56fea004a128552c8f16d0b43f0ccda2674879b15c9641f4564d", 16) - g22To27x0, _ := new(big.Int).SetString("d0ff8991599422d91d4a3e2ffe6b29e7fb6ad84d2b23ee0415c1d0288c7be65a30e0c81247057033ecf2b7301c4207", 16) - g22To27x1, _ := new(big.Int).SetString("28e47fa8013afaf501b8b030bc935c9dfa622830c3afb5d8901d61589a39183adb1c33de1e86acc89cd5f408a96a2d", 16) - g22To27y0, _ := new(big.Int).SetString("6ef0d3c529b8c020c4b46b31956d6d3926d0dab34bcbd553830686e20cb930657e88bffc4d91f3e19c689ee6f5837c", 16) - g22To27y1, _ := new(big.Int).SetString("173f44537f5f89935806b99af3589224bdce765bd80bf3095ad577bc3dae0205dbfd2098663d4b6b900221267ad6177", 16) - g22To28x0, _ := new(big.Int).SetString("17eb02ee81e7e5e5e5f1aeadb4ac4e0d78d90d6a1cc6258e697817f42df4408e2bd6663b2a9152ef1d83afed7cc6fde", 16) - g22To28x1, _ := new(big.Int).SetString("940acbe9e94c2e0a7637304492caff98193920bf0a4fa562db034f0969de217a76d8fd57bd95efca6234d7b20693ae", 16) - g22To28y0, _ := new(big.Int).SetString("1617e1d3f900cf0dd2db9907811cdde059c9c58ecf392a6ad677f76b370f1f4f9d5b34ba1959729168f3586c9f60141", 16) - g22To28y1, _ := new(big.Int).SetString("10fe5eb72866b7036e270e6fd905b38e98e03138357e5e6760c0c81e48a0180ffe2f787d78d390095977f40f364de1d", 16) - g22To29x0, _ := new(big.Int).SetString("383bc8db0aa13584b4f146d00bedb1b59d59b9ce91384bf6f5e28ef1a80bd8c8dec268e51dd16dd560b741cbbbd454", 16) - g22To29x1, _ := new(big.Int).SetString("c533310d0cbb1246a86e98be953ad677066338ba0c92095c808b8b197cd9170bcfd84f62db6836e093e72bf98e75db", 16) - g22To29y0, _ := new(big.Int).SetString("6a6eb93e94720c777c9b027bd15a21b7a03060980a6775f4c447a993b92454cc9f660bef1a6aa1c1dece9c864be9f8", 16) - g22To29y1, _ := new(big.Int).SetString("ef7483a0e257cb26e5f18f2c5a78af68095e88c43848ebace5023c031ddeacee4d6ba3a55b0ffc3b3187e152fd3733", 16) - g22To30x0, _ := new(big.Int).SetString("1036a17a68a664dfd56888eea3b34267ee1f913b09284a79e85a4a1d2ca7a89fcfb6afba3cd037f3f7f56ad6ee0b6c", 16) - g22To30x1, _ := new(big.Int).SetString("561f0e90d0c0d9387a52a60f4053a245417ddb28abd67e00a9a335a37f98a63a43f2d6a36ff9d86e29110564164739", 16) - g22To30y0, _ := new(big.Int).SetString("a03f1caa0380f1fce736ec84f793f1f0cb840046e7a646eb85533ac2db5c9079bc6d3d90a93f9b8d65d0698f790c70", 16) - g22To30y1, _ := new(big.Int).SetString("6eb4902e132878419be85733246d0b635a1dcfe0e10c25262bdfd7d5cb63bcd1c38228a8442c43723b38230026d8a5", 16) - g22To31x0, _ := new(big.Int).SetString("e48d3d52685b6d5f6345afe258b0fd77a1ed31871190d6415f7681884cdc7366dcde04a6e35e76ff77f00901c3d655", 16) - g22To31x1, _ := new(big.Int).SetString("2c63bf171f9f26aaa7c57584d06089a23d4e999a626dd69ed2090a1d3d3fafacc67422717b06161177ea6722ece560", 16) - g22To31y0, _ := new(big.Int).SetString("161f0e4706ddc56952d82a566bec832320e58cdb1823a7c4059d16c8bc8beb521699f3b8a8d03509b4f473a5a2fe8b9", 16) - g22To31y1, _ := new(big.Int).SetString("a3787c215a9e54fee577e4f14c0e3a4f5f88473158a3d45e3ef04c8a524750527abc2cf20f38ce55b7506dba3e6856", 16) - g22To32x0, _ := new(big.Int).SetString("153b5984f164e843530674b0df059e5d90431a37fbd885bff9576cbd19b12cd82fff84b786089afe0db68235662ed5e", 16) - g22To32x1, _ := new(big.Int).SetString("f84d4709fd3c5b8cd5ec2f44b0ab6479c8281627ebdbc3fe9139ceb495db78a6b7417986a5209cb56c09b11d1c3568", 16) - g22To32y0, _ := new(big.Int).SetString("7e30c9329d4d30b19f43c9dcfbc18cc9e18a415949715174d71721580fe94e3eff291ba91c528a200c9d26b99c371e", 16) - g22To32y1, _ := new(big.Int).SetString("458e123e65bbf750a89da00855cbd49d6b30494bdedb82c212e81abf5d577018a04333698a360a44a62505977e7c1d", 16) - g22To33x0, _ := new(big.Int).SetString("d8ec95f95a22c8444a656a84372caf02240b63e3c3cba833d9dd938f896ba7c197c776661459cfbd581cd12316257a", 16) - g22To33x1, _ := new(big.Int).SetString("10512f0f0b166f7a0baaf6a78e0385c5404116c83a4023d73ab0f17df35d3353be9e08508e6de550d6f26bce1eda20a", 16) - g22To33y0, _ := new(big.Int).SetString("11bb3de43848a38febfcb4e849bc0d5c86855556a2d46d233a7df29e51198335cac38b7efce2a1c6ff84c4349d64eb5", 16) - g22To33y1, _ := new(big.Int).SetString("141e67f88c5dd004cdd85912a561f46fb061406fff5ff784f57ecab4535293003a0e67eee038fcc0cb0d0955e0ce151", 16) - g22To34x0, _ := new(big.Int).SetString("583a2742d555ede1fda4c58d58b4baec89581e357312ef4ebf3cf6c8ac335a9160d28d5916d362b68708e5810d1f7a", 16) - g22To34x1, _ := new(big.Int).SetString("1a93480b413b2a164b2afd21166b5551ce59e5fe7625bce3b282aebfec20114ba941779b4e215d8219c53132d2d5b41", 16) - g22To34y0, _ := new(big.Int).SetString("30e831e25b1d2406d80769237a2ebb6a78e550fabc5337661e9c4043d9b5897038e2409161988f9ad4b54be62b76aa", 16) - g22To34y1, _ := new(big.Int).SetString("59ebd475497b882477ef33e5797f0f1daab745b91128b01d1008f80640dd9c0c298928856d3ebac7129cbd09353143", 16) - g22To35x0, _ := new(big.Int).SetString("b1992cf3d3ca2d71aaf59972205abcb0f1e56a5e3d740785c85f9000de581ca4d59aae19653d437e24c20dc4696074", 16) - g22To35x1, _ := new(big.Int).SetString("bf892e16dafb0073b5187262ab8d7cc4aaaeff6f01da56760cacc3e1611c116264f3210feac156c30c90cf7a7df09d", 16) - g22To35y0, _ := new(big.Int).SetString("183bc9010b27f8b3f38861ea0193383b032fb8a9c1ad2986d714ac6fa0bd7e9fc81fac1cdefb7801feb75fe8b8da8ae", 16) - g22To35y1, _ := new(big.Int).SetString("116cac547878bf1c88320d24f772bf6b6d88b1b210a0a6b83c81c9340bcb22674ce4382cf785dad1db5bc36b9a4ff6f", 16) - g22To36x0, _ := new(big.Int).SetString("d95801464ff9172a6bc1c74d82baea62b43364526688a02903672f934d7455ec4b212e490fc563aee0fab5a229f6f5", 16) - g22To36x1, _ := new(big.Int).SetString("9780d32246507cce00e50289af8d16b11d4605f550aa8129265f9f217e735cd92aaace24f2af39838b2112514b35e0", 16) - g22To36y0, _ := new(big.Int).SetString("1a71f82f9796e5b4e5760e7110283e3c1dec0d2b6b70e39f9368f166dfab551a10743324dd6c858596c273c6d5e74ff", 16) - g22To36y1, _ := new(big.Int).SetString("1bef4ffa86bffa3189dfef8a3b595b13e1113268c86d3024f4e27a023d10cb570cb90b67fbc867084f2fc81f714809", 16) - g22To37x0, _ := new(big.Int).SetString("41bd35e554843b52b936e39f382002dea1dd180a8b4f5331c69703a811efc366aa5fb9280e0634ef0019f19e2feef4", 16) - g22To37x1, _ := new(big.Int).SetString("18b87fd624d95900a7a8a51283ae17b1071788b1a2f1b7afd3a4042210645912bedfd955bdbd58e379decaed85cee62", 16) - g22To37y0, _ := new(big.Int).SetString("192afef2350f8ef6039cfd8b266cdd29181f2c368289c7baedc61eafe4b070ca3586d465dbad5fc655a504c2e222b20", 16) - g22To37y1, _ := new(big.Int).SetString("88d94d50c9439023a93ad40ae2edd8199c0dc2c6eed9f2a6dca9b6b856968e20dd98918ad17855ec7ad4d8a2c8c120", 16) - g22To38x0, _ := new(big.Int).SetString("b5362830d25667c44fcd884f44d8a8df1c414a13a7cd885fea688ac6f68eab8d370da4a2e88cdf828204ef6329a437", 16) - g22To38x1, _ := new(big.Int).SetString("362f1b305ff3c693c87bf1b3d3812a3350bec2ee6a11670bbcfdd0ed2a3650993761e85593bf35af5d2600db6ad6ed", 16) - g22To38y0, _ := new(big.Int).SetString("a05a8af2a94b833806746ef4d44a986180888a5979e08676bab3ad61ea45b0acc0b391d0595a95f547a2ae30593e4d", 16) - g22To38y1, _ := new(big.Int).SetString("d2d9e77346ee01e20a3c37519509d139461bab10a396ad1a275bae47145fc207a216ad5ce58d79a28bbea7adff2b34", 16) - g22To39x0, _ := new(big.Int).SetString("6a10d0ac3533744d21fc6cff820b6356c5e3bcc31929a225aca8e093502cdc3e00b29ecf4281cff7a949da6a4f281d", 16) - g22To39x1, _ := new(big.Int).SetString("30dadf6df2b936b6df91ab89305c183cc5d7b1be73a2b089808a2774dc99337a548b93f5604617c5cc96b0673e5622", 16) - g22To39y0, _ := new(big.Int).SetString("18d188fcf89f3cc3df1362232ae5f12cf6ee6c9fab12bcaa00c28f8502b44418e7d3f03a865b13ff1b085a43b9a3fc7", 16) - g22To39y1, _ := new(big.Int).SetString("176e51903e994790397ac33519bb5baa8152c81e03853a3ab1c12d7dedd7bfcb122a037e988e28ce8947cf7e347c756", 16) - g22To40x0, _ := new(big.Int).SetString("abc050eb147e2ad213e89474acab0dbe4a4ee756a55dce940cad73410a189f9c65531f11d14638837a658f35ba9dc2", 16) - g22To40x1, _ := new(big.Int).SetString("999af94ab61ed896a424fe97a7db3415d7e5de0d73e5cb99e2cfc204296d52ba2ce2919ade970c09cc6994aeefd3de", 16) - g22To40y0, _ := new(big.Int).SetString("58d79ac5d0f6af0e5c756a728f6752ac67ebf93b9dafbb2a1ab70b5b68b912f82cc8e3dbd539771fb2c57c83754b32", 16) - g22To40y1, _ := new(big.Int).SetString("192a6e7eabd38c76ff48083d5218ccd93d6fe057e6a74ab0f9c0b9b129c147598e2c5c6dbae488b5357cf8186356a91", 16) - g22To41x0, _ := new(big.Int).SetString("19f0dbfd7cb68c747dcac52b386416d6e272d8820befec449bea4b1252998002d29bd7d54b59fbcde8af2b82e85e267", 16) - g22To41x1, _ := new(big.Int).SetString("fa4a3a54e2e673448f13616133584f9db4489be2089917474129e4648a00168618761ca72a65ce922cc0e2e9ca8dfd", 16) - g22To41y0, _ := new(big.Int).SetString("12e5a463086e98cfefd688092eae7e0a3976d68381b716c95bad23964e3d296f4af4f23f647e119c8e5f438957addea", 16) - g22To41y1, _ := new(big.Int).SetString("6c4edc6593bd6dda6803f8ae55e145edca6f73d2b2d2af9ff1a82177f20fe787c50e2be8437d136ed351598c1ea118", 16) - g22To42x0, _ := new(big.Int).SetString("6419674f432214f07127fb72a0d07592b20bcd07b7f8ee84dc4f7740b68a7fa853d4532dba1f162476b8d0f166dbc7", 16) - g22To42x1, _ := new(big.Int).SetString("17c81beb87e609762776a30c9b74015e319e263de01336af618cba0f3dec9ab38e639e6ba5d8172df01104c7c2a9d80", 16) - g22To42y0, _ := new(big.Int).SetString("15bf1ded44db5dea5e91631a6f7cfce49cc7b4bbf21e010d5ad687d7ce44b48712e6f806e635568471aff28a3a043d4", 16) - g22To42y1, _ := new(big.Int).SetString("13ed2ac7089a3b1e5c9a69bbc5a76f5191f36736d78e45cac82cef570cf6074941bfe2cf015fdba67f915dec98c9c1", 16) - g22To43x0, _ := new(big.Int).SetString("185be4aa0279869a762b50cbad5d0ac6d33bdc1758d93101a27293eecaba0f242cc8d1f51a4ee177f347c0759e6588d", 16) - g22To43x1, _ := new(big.Int).SetString("48e5eabbdb45fe372cfe79be6eb4b51b765f60111e3bad144a03e9ab482672125b1e85a692ef352e3326cbc0597274", 16) - g22To43y0, _ := new(big.Int).SetString("2d82d3fd4240435ed7639eb4dfbff8ff795153665df35756e64c365fd32c3fe76ff1c1fca0d4708c4aa11f05eb9128", 16) - g22To43y1, _ := new(big.Int).SetString("e04348ea4052ac77ab211fe4e9bcb9037b75f8bf382fadd8826105ba8199260d64179c784b3e69a23ffe4c279d1058", 16) - g22To44x0, _ := new(big.Int).SetString("1490209d72244cbd78872ec84c6afecd3f832ecf7e28008c82fbc0d6d091c93f63fa24b0f383ef53f4559f11f8009cc", 16) - g22To44x1, _ := new(big.Int).SetString("18c5c95f94d8714d84e59c8d030442e28deb22ee3af962fa204dea3f7934f4d6cccd711bc3a1245cd45acc3d6971c7f", 16) - g22To44y0, _ := new(big.Int).SetString("18263db3571d47415932668d9f6ee7cbfb7ec087af44380b533ee5139c8f012c45c8363dba54ca0ddd301489394e12a", 16) - g22To44y1, _ := new(big.Int).SetString("914cf9f4bd51f4a38fc8b1673a0ce33cf6bce9fa2c7a92c130ef0bee0d058091aacd37d2c8cb2da3b42e4374adb917", 16) - g22To45x0, _ := new(big.Int).SetString("da298a31a0ab144bc2cff38e71fa72e6c96d9f760547111bfb6e18477daae63433b0afdaa91ef34f53c68ad47c75ab", 16) - g22To45x1, _ := new(big.Int).SetString("41ca4e4f18b7b5bcd9f806b494dcf37cf7c5030f31ba6a554140941bc3d621f436b65ee0c30bb3851b9cb987989f93", 16) - g22To45y0, _ := new(big.Int).SetString("5e751fd9a96852e1589b4dafd24541bd27fcf9bd900041b7bec69c5a71e7d8995930b4cd3c3fe3e01d37df1733e515", 16) - g22To45y1, _ := new(big.Int).SetString("2f13e69c6be44996217714c43ad2a3a0b227a09eab012e3a7c545b226b549861275c4448cc8e3d6ed27de7b44e31a7", 16) - g22To46x0, _ := new(big.Int).SetString("1a2026ccb033d3855aff0d8833771bc384f6cbe459c104dc6f2c124a6ea62dd32a28894fd38f4bc087df0d6f2b3ca83", 16) - g22To46x1, _ := new(big.Int).SetString("fe37752eaaa9e9236ffd1da54fe4e667e94533b2cb94c8598906277ac432858be2d30037516bbc44c71a33feb8726c", 16) - g22To46y0, _ := new(big.Int).SetString("f03c56414679e18e5c2db662ca5ac18887d5343abb858d3d25feccb241caa74aaf81c339fba2ec6392d2cdc2d33a3c", 16) - g22To46y1, _ := new(big.Int).SetString("14143d24ae7942388cc41230d6972358490fb11640e9e4748eca6670624b61aa7528b23b2117f6096467588fdb26063", 16) - g22To47x0, _ := new(big.Int).SetString("15b56f4a2f70826a0d7b3b7c5dac9f69e3ac44589a694570225d90f532041fdd35ebf09fd041fe06284b9567c19c7d", 16) - g22To47x1, _ := new(big.Int).SetString("381ad72ec64de0aaf137d78566bebb1bb8a3893db8083b00e0e36a3947c2777f0e9433bc8df99df1f5207eb4368539", 16) - g22To47y0, _ := new(big.Int).SetString("ea36e74304a872c97f28466d58b853563c61286e9bacd8be957b98ac49778bb8c411019cd53013057d798eb29a8a05", 16) - g22To47y1, _ := new(big.Int).SetString("1563b7c5815ed23d91f64f9f301571685e2aa40815489ea2721f398b8eb1aaa4bc891da210da11e3fd83991fa69b6cc", 16) - g22To48x0, _ := new(big.Int).SetString("97e9c3bd458894adbdf0366dc70920dfd274ca84c6b94a4bdfec4f2308b2764d0909f6a411e359f95b4fbdf2b61e3e", 16) - g22To48x1, _ := new(big.Int).SetString("1934e67afc63e035ec73f9ac0bd04401c913f12958695cece66bcd7ee0340beeb5c679bf3198bdd740e93151d55cda0", 16) - g22To48y0, _ := new(big.Int).SetString("e45dc92ebb78eea7f3d12d43e6c882792690c2d3bf01bbc6a3eb587a6318aa549421fa4c8738aa7537acb1cfb773aa", 16) - g22To48y1, _ := new(big.Int).SetString("d0ab25bfc31965111e2bd7e01859f30b61fb89a362a50281709c52b19f410bbaaf4d9c1ffccfbd115ba131c3ccc0f3", 16) - g22To49x0, _ := new(big.Int).SetString("18075d009ccf790da4ae26377c5a74f7d48109cad34ac18d3f02951d7ba44f025c26430c6ca0df8cc2f6c8f82e61d59", 16) - g22To49x1, _ := new(big.Int).SetString("aabaa12fe1c640959fe0f78fda1446f422677dffdf6972ff34193c2422703a713d679e03c2424bc2025630a0909f6a", 16) - g22To49y0, _ := new(big.Int).SetString("f08ce21221f1b1356b24cf796dab84edb9c96807855b5761ea83920c71d3f216d23ffab41bb7602473808d1d8460a6", 16) - g22To49y1, _ := new(big.Int).SetString("de28901cf5c2b7868e494abf385488d77ad1142018e1ca68747c9c5ee7469924a172f763243da45e42c8143364e400", 16) - g22To50x0, _ := new(big.Int).SetString("1473cc23a296003180995405451e5f64153da19265119c136d6e2e393ecf0ef536db7f8570c7460efda230c3e5d4f8c", 16) - g22To50x1, _ := new(big.Int).SetString("f442c4e3859b4d1b92e1ee549016812d4e8c19784dac74941e393d19a1c95ef93e921bb71e7fd3ebd37caf49b18edc", 16) - g22To50y0, _ := new(big.Int).SetString("1860cf772380cbff871fbbda474cc84cc8acfb76ce65516bf00172c4aca8983c7caa04b25e97aadb56ea74ae21a4112", 16) - g22To50y1, _ := new(big.Int).SetString("a5bbbc7ee8cec2e71a28ce4395ae299d1de52718182afc38a489bf9a72a61075c3a52b61c6de864cbfb80aab5d59f3", 16) - g22To51x0, _ := new(big.Int).SetString("70341bc9e98b79fbeea0c732a19d2ba7656b666534d350c749fece947a1993fba1bd50fdfb609b9c7b0731b496e06d", 16) - g22To51x1, _ := new(big.Int).SetString("e3b2e7a10996d7d52088bcacfb8b4f694bf407865056889e9a887ad421f3580299ed660f1f6bb0cfb8079469b2051", 16) - g22To51y0, _ := new(big.Int).SetString("3e2224f7654d02f9d4afa4bd67ea3af7e133f348e257cd9c20b86a0e7b70efe73be58f0c348fd979f3ea2b260420e4", 16) - g22To51y1, _ := new(big.Int).SetString("3d9d2b19ee6bd645650bc65a3397d39f76d234bae781804b9e50e32f86ed03aad807c008845f002b84bef53130a63e", 16) - g22To52x0, _ := new(big.Int).SetString("bd1b636033a60520ad4baf7614b45ae11735803bde97952299c19b7e95778b4a0cae7130f948724b11994c28d43f14", 16) - g22To52x1, _ := new(big.Int).SetString("16cbdf5573228721f3958d5a962faa581a6f49db89c5146037270e55a923fc321756cb671865bf6b4d242866a4babb4", 16) - g22To52y0, _ := new(big.Int).SetString("16e92f58bc93251c73759651a74bc4e3ec2c023d2444dfe68eb9561426d4b06a123d7de85b19c0e40c81c9e731d475f", 16) - g22To52y1, _ := new(big.Int).SetString("19ff3565b3f00965ad038551f61f9f5daad2e16ad223789b6115655ce133423adb97cfaf1b4e47fb2c56864da1fff7b", 16) - g22To53x0, _ := new(big.Int).SetString("2ef4527bab5dffae6720c1871dbf20581aed57cba7e707d9b1fa04965577981da8d9145a7a9d9c8db3f6754a267fb3", 16) - g22To53x1, _ := new(big.Int).SetString("d023cecaf1a41f33c29b57650fc683bb115b9012c6ec5744c223f2dc759912010901dc77aef33a128e3d92954ddabd", 16) - g22To53y0, _ := new(big.Int).SetString("12c72763616c5589eda281c7312b536be2d61100ac6364ce20ae77441e5fea6e56aa5eba821ab1d24cf660a67a501ca", 16) - g22To53y1, _ := new(big.Int).SetString("394347d359dce2eac6adc8773190bd1436b66c2f1cd3f1755426f343e69f6345593fdb262b251645b5820f4f6b1007", 16) - g22To54x0, _ := new(big.Int).SetString("c28246812797dd5fbd542f2dce015360e9b9782a87664c00473b735659cebe14fcc96d79bde7bd7a13d2841043b142", 16) - g22To54x1, _ := new(big.Int).SetString("1292225d4f829a19bbbc0bc15f48b64f07d7d6a58ea4b6e35a3edfe49dc1cd2b0a869c4a087b603b7f023e4225cadf2", 16) - g22To54y0, _ := new(big.Int).SetString("f967af7f410f57a9657793bc17f35b9318b9696b129f5a05cecb5b1f8e1e472e54e2dd9dd4115f576099278dfe39ad", 16) - g22To54y1, _ := new(big.Int).SetString("b1c827d3d66c942325e00d23d9b39e9bb6ecd23b6d2aed46aed7da46b9cbf4d092e344bfdf5cc4066b5ad25f2af3bb", 16) - g22To55x0, _ := new(big.Int).SetString("e0d71063b9f86daab4fc886785166c5fbc6fae99ba269fdc91244426925e49006d26099b251e9892eceff9af0e2bef", 16) - g22To55x1, _ := new(big.Int).SetString("658874db7d71fb8a4f5496ce170789b7e899baf0590cf7105f82c6bb6827ae718977104c165b463cb2856f62497e59", 16) - g22To55y0, _ := new(big.Int).SetString("6e48b3612381351a5200f5401f6bba656f1a0501429f54a44890aecc79396ef9972fcaee886b9ca5988bb976ff4267", 16) - g22To55y1, _ := new(big.Int).SetString("fea7f298af04217463943d781dbde85fe7336b6a98ce53d1acd322c3a2770deee0d9f5ca29c9ba259e93200a228aaa", 16) - g22To56x0, _ := new(big.Int).SetString("fb2ece7568abe698fc1be5aa914c31429f76beef1d7eab24f89ed3631484fda67044f406ca985d4392062b23589d9c", 16) - g22To56x1, _ := new(big.Int).SetString("12eb1042f943a2ea2213d740bec86dcd70b9dc81d9f9b6084a529ee13aea98de1ca3e84288a1f6748f2bf096757905c", 16) - g22To56y0, _ := new(big.Int).SetString("fd2052aaee0b618fd532c963a07a280423a54893417545fb495374b5b7712b56986fcb19ce65ca80199eb49cdfa635", 16) - g22To56y1, _ := new(big.Int).SetString("10ee9ad1193a5c6d03384a6dd0c9c4cbd9bef1533624fc56740700ab6739322b5e0f4213378434980ac97ed0ceb4bdf", 16) - g22To57x0, _ := new(big.Int).SetString("18cd416b6151272f709dc5854bad02640d3dba0e6e4b03376c32febc3ea505b3bfc7a6c99ec4fb16aba5956b2a2ebdd", 16) - g22To57x1, _ := new(big.Int).SetString("5e69ec1ec7df8ebce7949305f1c52558a84ae75bcb21726534b26caf24535cad1d34dc9f3a172ddaa136d9272750f6", 16) - g22To57y0, _ := new(big.Int).SetString("cd228db30a6c8bf4f877b0e142587dfa0ab5fb6ee9c200ebf640984fc2d18e00e0132df6d93d950c9097db4ec7acec", 16) - g22To57y1, _ := new(big.Int).SetString("39f29109c3306f291d4edccd872a57416792658e276b7119a7d51f9d558d991432f2520c63015f2f28032c51b15828", 16) - g22To58x0, _ := new(big.Int).SetString("c1ca6a7a5cd1647de7eb0d75b28a4f1a6fed2520b332a4cfe2aa7c56428768102eb40302b9e4801d35c862fb2496d9", 16) - g22To58x1, _ := new(big.Int).SetString("16b26c38c4b73c482a04b58729d40d63ae220c929ace32debd56288bc28d20c3edff4b0859d02dc5825481d8b95e563", 16) - g22To58y0, _ := new(big.Int).SetString("13bd107d3575ce63d37b91fd4c54e3bdd54b86e87766db6b3b1f49a80892aaa5a4c56bba15c56fe84fb89d239bfab2c", 16) - g22To58y1, _ := new(big.Int).SetString("114946c000ccf9fd0140560be3ade8b56bfead96908141fef5562d8e8c3f898ed15aaa465c831fbfaf5ba495e67cb63", 16) - g22To59x0, _ := new(big.Int).SetString("bcd9b04f5b56ceb2a2767fae531b4cecb44cb4d8acc91c95c80de1cf98698148829ac984192ee355bcf728f0286e47", 16) - g22To59x1, _ := new(big.Int).SetString("19d26674d69cbf1d6f135e8bc55e1b7c233be1fed55c047a8fedd8263be90a18c6c9982d0a28db4019b9a3289f92bef", 16) - g22To59y0, _ := new(big.Int).SetString("13f4a5cf1f863bbe248ad11eafd3c805daccd2e75fe9cba26863257c1014d02105c2ac370e944d8b52927525efcdc9a", 16) - g22To59y1, _ := new(big.Int).SetString("7325a886621bab4f44aa4cf1a4bbb183f801d16226e802d581651f3b3e1d7c063aac47d0dc2034ee1d3f6c0d6b73b8", 16) - g22To60x0, _ := new(big.Int).SetString("bae46db808530ea7195ef8982c4a0756c664308871122bb62e40c8faf88b907eeb4abc462286c67360a6a7d852ccfc", 16) - g22To60x1, _ := new(big.Int).SetString("207028b920fb4f2e51ef16d2a79be68c3a21256b0460f7d29867eb97f64a41aeb06be372570604e11e69c5f4f10404", 16) - g22To60y0, _ := new(big.Int).SetString("a9e0319f178e190e9919bf7630a91ca27c3f394709da9ee630a0a2faad928c5af37634b1afd57779f99146f25c4a78", 16) - g22To60y1, _ := new(big.Int).SetString("1687de3a00c54789c835f3bae67b0c74432beafa16f74d2052b49287741e3a5a29d9474650c3b5f43e807818e4a129d", 16) - g22To61x0, _ := new(big.Int).SetString("195d3360215a8f2fd6bfd0eb457e1f1aabbc2aaa38082525462d93da6803da01c9c4c7fe0dbfb2b1af0fa6444e6bdbd", 16) - g22To61x1, _ := new(big.Int).SetString("15213ea05e70ff026413ff536d8a6931c5dead45e5512de3981f59eb4cb2ea45a5a5d179e50b89c7f33e2735d54f163", 16) - g22To61y0, _ := new(big.Int).SetString("8e450a2b9bb55c930a330dcc3645706913072dc9e76a03f7ae81d62f5851dc692525369eacf0b4d7eba9c4a0c541af", 16) - g22To61y1, _ := new(big.Int).SetString("181e7fb361bfc23dc30b6b12de204658bd97ee10a2303c35cde890068617da05ff604d9e9ab8fb7dcec47d8af32d110", 16) - g22To62x0, _ := new(big.Int).SetString("9caab0ac2242bff84e280bb08ff944037da8f90893717b88a202885f9c29d20b472cf36a2076340954c2d3f9980b58", 16) - g22To62x1, _ := new(big.Int).SetString("10d26dc2a0e15257f4b4d518e5e313f12c0fbf7efa35719ceac2920115b7b210232001a9272aa09993ea1767ebdf657", 16) - g22To62y0, _ := new(big.Int).SetString("10a8df7f196b2dd52cbe3264d6899b4f0bac1a21757df6dc074c62ba8612b91a9572eb65408337084e3f8cc50589ded", 16) - g22To62y1, _ := new(big.Int).SetString("c988f26b9f9ff5eb31b9984debae90d14a68b96ccd18be600e0c560597cfdc415f48ed7924f198c90f0293d8455381", 16) - g22To63x0, _ := new(big.Int).SetString("18d111f764de031ce64357b8ef65ef4d7f5be47c630637cffefa6b3614b74371c13435e3c85ab0d33e27fc573fb58f9", 16) - g22To63x1, _ := new(big.Int).SetString("854850ab2f7b25960ce9cd5627040a4da0854c752ff86231b709280cd1256892a49b01d783da5e5bd26d3e9d24c757", 16) - g22To63y0, _ := new(big.Int).SetString("aa4ccd1dfc38d3ea9848fc19aa6dc3b78357c3ccf3e6b85fce5a6ed23feb80e9db5f69ce118ad818d7077221b244b6", 16) - g22To63y1, _ := new(big.Int).SetString("bb7f0ea545d089958c5f173e653800740885499e85e391110e720c8009d6a2923690e3a65c9c428db7573c082c2989", 16) - g22To64x0, _ := new(big.Int).SetString("e7b0b743e9097108fd3c5cdd0bdf7ea33dcb648c482be658444a5d6f27b46999665f11a083268a2b39b27a82834103", 16) - g22To64x1, _ := new(big.Int).SetString("10a35d867dd3f610ce40db92cebab6997056c92357a2b84df0774fc7f82116cd7e680590adb9a1f4da01a9e210a5ef3", 16) - g22To64y0, _ := new(big.Int).SetString("138e999e863e80b96b1a87e2c6f75ad2164ced765b5d1fdbc51b9c186cb4c460509749eb4cd234a1d62396fa3a24500", 16) - g22To64y1, _ := new(big.Int).SetString("69cb46bad13f9c343d15771b7a6911dad591ee36122b763076654a3dd88fc3a87229e43875324c2be66dab9949e504", 16) - g22To65x0, _ := new(big.Int).SetString("d0250c6a7a26f261bd039480891b7872063952cd9cfebb98a2759c895bf88be81f4779b9c160d13f873d59b64ba137", 16) - g22To65x1, _ := new(big.Int).SetString("8f0b9cdb43a062d6e79a53d0b992bc54c6d3f2cc9538298b5b88a6299244fc61f4d1ae7d45ecb829801b20d0653b31", 16) - g22To65y0, _ := new(big.Int).SetString("3373603eb2ac404a0a642c7a0cbb9c897d0c37108eaa7009754b456715df6cf60f64efcc4df555cd052291d81390be", 16) - g22To65y1, _ := new(big.Int).SetString("89c1cf8bfcbef353f34c2b5443337175d2c0f6b22518f273f35878f38cf9521607f6112b474e6db2324c4340b0df5b", 16) - g22To66x0, _ := new(big.Int).SetString("148a07dd6f324ab084b71847054aa2228097d6abd1b13b0ff91bc521f048ca3013648aa3d72d6ee7541f5b554f1e934", 16) - g22To66x1, _ := new(big.Int).SetString("17dd6bcc1548a813d4313eeaf87b549fab32356a6df0a71acfd8b72a64b91322b94f7cc42ee26126e7be36464486814", 16) - g22To66y0, _ := new(big.Int).SetString("163a932dca566cd9647f4b33e171f5b4debd1ca68fa3ea52afa45fc75fdaee7829c6e92ec40f993982abf7e2a6bc848", 16) - g22To66y1, _ := new(big.Int).SetString("101cf0fe70ac42be3c79013cb1f195d4655df9688c2bdf06d51d1f04ab99ca10fef61f910db95838065b4cb9f5575f8", 16) - g22To67x0, _ := new(big.Int).SetString("10321b2aa34e0ddc75c042fd21a8b3f92e7d2b3bc891bf9735c74e923024538f99c0d4217de78b2d76000efe1f3ac54", 16) - g22To67x1, _ := new(big.Int).SetString("569a0b5626e2f4901b0473e478388a91035fb960a082d53b807573658a28e3ff8773e7c64ed04347c53d87a2b223cd", 16) - g22To67y0, _ := new(big.Int).SetString("15147f5ed9295bd84ec43fb64536868dcf4a9833949c7d347a18a2b60c17302396806144ebec360a8d1100047df4eb5", 16) - g22To67y1, _ := new(big.Int).SetString("1457c872d3e98ba96224f71c8194cd73d38284640da99960cab9cbf73c7974f1b72edeee65d77761c9b97e750bf16ad", 16) - g22To68x0, _ := new(big.Int).SetString("351ea718fc4bdfe3e53dd987b89c5d4188445344dc1368d33a898dee4b8c1f965e81a729ef6b4e9349cb025ec795ef", 16) - g22To68x1, _ := new(big.Int).SetString("1504daa48b8a9c245447ae19d9ee19213724ef5d34950f7f258a52cd864d4a47eec2cd1adfa3de0fd3219a8492b5033", 16) - g22To68y0, _ := new(big.Int).SetString("1ab8b27f1efe33fa8047707c59ec8221cab6a82500d581b7dcef501518272a9ae12871daa5e240a5ed3dcc120978d0a", 16) - g22To68y1, _ := new(big.Int).SetString("3bc61ed73db328586a09afaedb9c2a46c3a5d68ab29f13aa2d1f50a49de088b22d81d756cebcf09371194323201d46", 16) - g22To69x0, _ := new(big.Int).SetString("18f4b1130a34501fd97c5997dfe4e8f2c4f02fa7f5685202025e1cea075d6f0bf987dcaccba10b435275aa90d545adf", 16) - g22To69x1, _ := new(big.Int).SetString("5aec1fc98b428aec86c5daba6b074e99ee1c18e5f81a38bd40f4a4560cc7b34db995616cd319a444a9aeedc0f8e613", 16) - g22To69y0, _ := new(big.Int).SetString("1520fb252fd7fb3bed1bc73333cd8766980028d7831fcea590b946fc38a1e6d65bc0a7875b390e26858bbe6b09241fd", 16) - g22To69y1, _ := new(big.Int).SetString("79c278494d7ea6336aeb182daf2870fba68614bca24e34f988d6b0c69f4f051d68e23fdfa1f09cf0873470828ce93", 16) - g22To70x0, _ := new(big.Int).SetString("d22b2485547804bb50dea0b66ed1ccf5b9eab46be6a93cf55cdf9ca184494123700a9b7a694c5fb53c0b43bb09d9d0", 16) - g22To70x1, _ := new(big.Int).SetString("1ac59a298fad0037a75e909eda4affe9c3eb559c3d3109ede94c86e1c24c69090c361c4b6055011a6d839436a8ed3a5", 16) - g22To70y0, _ := new(big.Int).SetString("a819653da6c309b6b2b505927a14ee9c28d6237bd83aa2316826c8f2fcdcaeaa0d61d1e95858cd797faec9b67af39e", 16) - g22To70y1, _ := new(big.Int).SetString("42d43bda2903aaf4c0708d522ea03cdac318ee9b2fab2568e51ffb2aedd71fa13d0fd418bf56f0f38d39b3a1b834cf", 16) - g22To71x0, _ := new(big.Int).SetString("c79f0901536150e560849aadee3f42d78e55111b60509f93a00f1978138ccae15f5e2dbbb0457a515d5290a4e45d46", 16) - g22To71x1, _ := new(big.Int).SetString("9e1e0e1766774aec08aa43c70cada370a28bb5c0ecc220072e14ba0cbbbb58e678bf57480c57edf6150d33a3c34f4d", 16) - g22To71y0, _ := new(big.Int).SetString("d3b252e29ffe10984f4d53408ef620b7c4289cc91e23da402326a5664757a30fe86783d7cb84c8d6e84bc344bcc05e", 16) - g22To71y1, _ := new(big.Int).SetString("28c6b7501123220871c207a31dcbd6af0aa4123f984acf3055b68839fa31b6bd145d897cf2a1275a0dbe7200b97f1f", 16) - g22To72x0, _ := new(big.Int).SetString("124f44279c3f1933ba37767ccdb88580b574874f91e3159b75bf9af3eab72470671bfa31c40d73b8c9787c8f16de4dd", 16) - g22To72x1, _ := new(big.Int).SetString("1ab1b43b8176c351df7a8e26154430b77a24d062ba13027684b56dc540698e4cefd90f402b902f431a9de0669556ced", 16) - g22To72y0, _ := new(big.Int).SetString("17883be6b70e0537170818fab873c00f0f025b3592c09aa6d64e7a497e9dc2860f26bc919d6b317894435aa7740284b", 16) - g22To72y1, _ := new(big.Int).SetString("3dd81383aa384eadf9f0f90192f5a209ebe97e82c749d237ddceb789f65cb9016155f65fc2766a42fa65f557854d52", 16) - g22To73x0, _ := new(big.Int).SetString("4b1ecafade072f4ced75ad605cdfe5adb4899487ef9e8ff9daaf436b15c3dce31c901d87a2bd8c6397246cb05676f0", 16) - g22To73x1, _ := new(big.Int).SetString("dd219177c4343134c9552c02273cecf4dab4e6baaf954eadf8e48b432aae0510d4786db8b7032bb8b540223499bb6f", 16) - g22To73y0, _ := new(big.Int).SetString("f18ab1def75928516522df2c7ac746a29ea1c9b7f0fea041c1926575c71df068a2929f3bbfe933ce7cd60c4f957489", 16) - g22To73y1, _ := new(big.Int).SetString("38148ccd89951885a322b0a6130cad8af4be29ea32703e30f7bbb4a10c06c383104387abf67914e46972b12ebef374", 16) - g22To74x0, _ := new(big.Int).SetString("d3b3aaa330f5b2cd8fc8319e31be046801263219eb676ab2633974c8c713cde38cc148666123054755a31e2992b058", 16) - g22To74x1, _ := new(big.Int).SetString("1675a8d21aefda4993fc13e86d812eba60713ec36b5581df406f59b86d73c71d5f1c099a7fea88da449491f9fbbd509", 16) - g22To74y0, _ := new(big.Int).SetString("10133d4935f5044f763c07e879c85014fcfde93851f0d9009c5e357b9ff31cac1f16f8ea269b48f51857fe73ca09eb0", 16) - g22To74y1, _ := new(big.Int).SetString("cae20b51c4f750514fef4aa88ba1a2965d4eb9a7fc5d5e2b26bb5dc3454e48027ab3dec39f5181fb6fdcd7fcd7af7d", 16) - g22To75x0, _ := new(big.Int).SetString("2593bb67dbd8d568ac0b461b6feee2e49769b263942e90eb523fc978b4b62e4dc8973d3242cbc4fb7cdfe854234d85", 16) - g22To75x1, _ := new(big.Int).SetString("1508bc877d9736e881548244b61e69acba4be93d0c0984f27d18b5f970d5d830eb404d4ea091e1a3d8cd8b39ed1e211", 16) - g22To75y0, _ := new(big.Int).SetString("10b6c335d3c710c80136307ee584dbaad0f829ab91c04ae02094b5494ccf09bcf4de1aa01102f873ac40250cd839b5c", 16) - g22To75y1, _ := new(big.Int).SetString("1900ba6c05f671fff756f093ef608b49cfb5d6339c231fd2354f99924cc81e35391c7c188815c2fa9629acc4150e62e", 16) - g22To76x0, _ := new(big.Int).SetString("2c56863f60469ccc0d7eff667a2d1ca48adbdd1234168235aaa08ee71a0a2fd960d84b1f732c7afd82d6a7ede7e363", 16) - g22To76x1, _ := new(big.Int).SetString("13e01caa1014daa0b75ad572951ced122a16369511ad5a2fcd340a958bebb2e32a4cd246a4305a785c98274b54fa1e7", 16) - g22To76y0, _ := new(big.Int).SetString("195f038785df02735c533cbcb28feef0b48afbe1bc9d7421337be4b61e6c788e76eb4132b43e087cc3a4332e1de110a", 16) - g22To76y1, _ := new(big.Int).SetString("d94f79c96cf519bd13255649a31efd1e0537d72f46c3167c6520b5110ca0ceac5674ea9dfb0eb00b86d29f87a6c54d", 16) - g22To77x0, _ := new(big.Int).SetString("9b197d8005b9350cb9f06d6f3063f12183358c15977e346a63532a2a85616640d0e408631aa4785ed0ffb19754d9a3", 16) - g22To77x1, _ := new(big.Int).SetString("1a0d561c897eb1cbd769da09b54a3e9965ec51d5ba757a86bc96095a9276f088f727bbf489b12e1189b9d401df34696", 16) - g22To77y0, _ := new(big.Int).SetString("856797b8636ccc0833c3055e61d51127e6f3f15b2d9cabc7d63b0136ebbde94440d44ca5d90d6d97a0689c9ff1ffc0", 16) - g22To77y1, _ := new(big.Int).SetString("227178e6db12cdf5be209b35ab31f09758b239ace14a3f789eb663180c8a9a951c433fba883568efcdcd3cdd5ff467", 16) - g22To78x0, _ := new(big.Int).SetString("d2c6e9eb02b68911233ed4f42b4da20c220ef0a1222cac683c48a9c144ff79d50f5a309855fab4d986848707f6652e", 16) - g22To78x1, _ := new(big.Int).SetString("27d32b60caa22386c8037bc96458cfdf400e1ef5e1ce8255692d918f0a9a82d4036345517a304629af7e36baf2a86b", 16) - g22To78y0, _ := new(big.Int).SetString("4a24b3c1017ad1de15ebccb44b8c1abac2c0bd4ccc298445a9ac26146467d1bf1f411c841afbc9e7ac9bd030c2cc3f", 16) - g22To78y1, _ := new(big.Int).SetString("ba92e8e6bc6749dfaf7b6d11e5938d5a26a64002a2a074019537f30a9e28e70508fd8de67f5dd785ce4992e9530d7e", 16) - g22To79x0, _ := new(big.Int).SetString("13f7e0fc75bb088729fe9327774be4ae190d593de7ae8e401057546558a28ab747d6cd23fc93666ee869037cefbc4b5", 16) - g22To79x1, _ := new(big.Int).SetString("1036a6d40eccc3aacbae20664824bbcbca52dfa34e1f1942830a86514d23e5aa00455a59a5bab5d263a8c8782b8d3d8", 16) - g22To79y0, _ := new(big.Int).SetString("17b0783d5741e46005be967221c0b609bf87988bccc3dcc3945494061feeafbf81f58e3870f5326d97111c1b40e0c20", 16) - g22To79y1, _ := new(big.Int).SetString("bb79177fbbb7ec6f8abfdba5fb7a494b679ef5bca53f1c341e43808fcd6e936cd97785342fb581933ba61c75c47299", 16) - g22To80x0, _ := new(big.Int).SetString("94232b96901fe4476fc56d9786411aaea718c2c888bacf9d2c85fc5d5fccd1d0a10564d319dad8824cbfb0d08fa083", 16) - g22To80x1, _ := new(big.Int).SetString("155e8ac0e0836f153031e57b286abbdd600069cde69e1d863b34bd21ef725436211f6168ef9595e69d18ff3cc90828", 16) - g22To80y0, _ := new(big.Int).SetString("9166f7b44d7400b2a52dba38a6a99c82d0bf418fe44500e9d6a8dd31ac37d0b1c160d6fa2ac7faa66664c5fe7a1b0f", 16) - g22To80y1, _ := new(big.Int).SetString("12536490956de6eec731d5ed966a7c71de40f66f37beca4cd7ff22de8e9d934c7d0578836316b2bbde65c79a3b52df7", 16) - g22To81x0, _ := new(big.Int).SetString("18c235ac09ef6982ec724f4f92f067124134c75aa86fcdb5457c29fe0d4b0b6c96903a161be07a774c7826ae63691d1", 16) - g22To81x1, _ := new(big.Int).SetString("13d708687fc894a72a009451cc1fc6043238a7acd0739db93ab3baa724b3c144b7a8bf37c44631107f92b071c3638aa", 16) - g22To81y0, _ := new(big.Int).SetString("a20ced53578f8fe4fdabc3e6afb7ea6031540fd98c5cdd747e9a18cf226532b62f8497bec6421c485539bf55841918", 16) - g22To81y1, _ := new(big.Int).SetString("bcf5a70b1842c1254b51e3d01eb6e8745de80ce1dcc9595036f37e3d05345bd63e41e656319d733d335ddef0f755ae", 16) - g22To82x0, _ := new(big.Int).SetString("203158ebc49b5dd5f67e3c26a9fa8748c3e43ecfda7b2a4df9ab543382b35b95637130f6ff2e7d46a4e8806348fc6e", 16) - g22To82x1, _ := new(big.Int).SetString("14825e67201566a0a5f34908bbed91f85d0255a84ab8d66eec39f0b03587ec50141461589225999a55fc81646561cc", 16) - g22To82y0, _ := new(big.Int).SetString("1a9e7ffeaa972ba5b31e84f29923b12a7581554be6dd7dd9cb51d1eb9212584c47f7ca99100daf1a3a27369ff075210", 16) - g22To82y1, _ := new(big.Int).SetString("184b04e9e7c21a09c534dfd1f93b6552450da9708b28ba0a5e4310d5ef3f760a51f62d8481f7beb403c2e357bd561b1", 16) - g22To83x0, _ := new(big.Int).SetString("1376260b6e40c74c979b4189610e7993baafc35ba7fb5a82db25a94ef3725794585b85426594df0b1d16d726c455c9e", 16) - g22To83x1, _ := new(big.Int).SetString("17805d42f60c085db5e1408f7411b227d99842ad1d0ccce8460b692ab3a376acfb6322234c81a23f89b4a9eb3a90b8a", 16) - g22To83y0, _ := new(big.Int).SetString("3b4daa7ed8abc50412eadfb5942260908d2c9bceb2418112b105d10c32b31fd7f6b0d9309f7988e9ae4d2f4afc08f8", 16) - g22To83y1, _ := new(big.Int).SetString("16e28e73b580b637ea88108f05bef5e2ba4edcd4f506f43a5ac9dd6cf5219287c27cacc8312d792c08d5f2d0892ddab", 16) - g22To84x0, _ := new(big.Int).SetString("187b9a941c3bec8c3fcf25095ffc41d4221a7021eba2e397442569e837a7518c6757e8edd8fcb27979f7031c84d7c23", 16) - g22To84x1, _ := new(big.Int).SetString("1a5fd78972667724f3db2bb8e236eb3b252cbdf3488e16cb52da6a50b09f1b068bd3c42b29f3de27702ab453c1cdfb9", 16) - g22To84y0, _ := new(big.Int).SetString("99720688665688cd1f60734d86d6d0716a67fb0f3e52cd4e82bc69fdfe7b3a000ca2f1bab6f31dd9fc527ba0e71cc0", 16) - g22To84y1, _ := new(big.Int).SetString("d1f9fe007ce93ac084221980bd11657b01cba5155ad5b043a84d8f2373af54c774253739358b465f175d1058700f35", 16) - g22To85x0, _ := new(big.Int).SetString("b098e11ea939f2ca53c66c19096d264039adb023551c0db49d73b239e5bf695c432d9a3e13b7fe8cf04429bf2bec23", 16) - g22To85x1, _ := new(big.Int).SetString("11c55b2dfe0072a577e1573f9f045649faa825abd16246a07f6474dd24586a3f118ba8d4ce83485b98f3bacc1ea5627", 16) - g22To85y0, _ := new(big.Int).SetString("2fb138c393a166fc34900c55f08275c4c66523383fc5b978526768926aefba70f17b8a5626b958b61304e763d26779", 16) - g22To85y1, _ := new(big.Int).SetString("8a692b70e6208362c3d706e27e5c6cef81437417f3857546684c04b45fcfc318acb7f82355c4410c7688507b4652d8", 16) - g22To86x0, _ := new(big.Int).SetString("1d89701f684e3b4dd50cf7a27aa4ed2a345dcd3eb6db87586e6c56cd2e8fbc7d721eb2f032384ab43bc6ae2dc0e4d0", 16) - g22To86x1, _ := new(big.Int).SetString("a5c71f56be7b743ccb5d7b92aba64d1a9a9077cc53a1d8a7f81d85a492617f3c8e76ec6ce5a233e872b2be5c9ea9df", 16) - g22To86y0, _ := new(big.Int).SetString("8508151cd914c85e0cf0355212886c97833fbc09b34c9728ffdadf38d50d4d00cef0692b8a6dc58f850c45ddfd6394", 16) - g22To86y1, _ := new(big.Int).SetString("bdbf7855d55baa52cc7e38520774d48d74bc66fff80dcf03f01dcf44b2ac7231f316e193638ae2fc52b6049de79bf0", 16) - g22To87x0, _ := new(big.Int).SetString("9bef9e9e72b3161c411368d460ea474a924971b08e96730462ba356ae26ecddf64ffd892a1a0c319022e96b2cbb50e", 16) - g22To87x1, _ := new(big.Int).SetString("132eff4944b380b3a45d31dea6fe7f85953525da34a0d7b76758f552b17c7b4aa1f136c06edebfb267d08ba98c6c678", 16) - g22To87y0, _ := new(big.Int).SetString("116dd3c70261e339360c7d05c2d2993df0fcc389dc2f990e095b1e51948838c6d3d6d74da835562210f2e6dc0dc910e", 16) - g22To87y1, _ := new(big.Int).SetString("14acf16e432daf1c6c9f0a4ce37364f18229e18f6df4b1dde6d841d4977a8096c1e18ef9b49dbda26ccef64e2a0c9fe", 16) - g22To88x0, _ := new(big.Int).SetString("10fdc7434fa6e5d4aca0af0b744984416e302c9206816ebd8518a32b65aa94cc93fd71472c706a7d1d5965ce2128814", 16) - g22To88x1, _ := new(big.Int).SetString("19535bc89bcc4869caa416b459a7426fbae92cec1f9e2b767e727e5eee1b528ec995be59194d871f79a710bd4227577", 16) - g22To88y0, _ := new(big.Int).SetString("1a1c785e7bb03bc84ef5a8c84863b3fa298f94e1b70722824df10b37694d4aa357580c02ad0164d23ae2c2009394b5e", 16) - g22To88y1, _ := new(big.Int).SetString("e4a9d5cfe2fd183edca0803f9f211b9f6147d81ce3f3ad92a085a5da63cba441f5243b890802844be5c9f8ffe43241", 16) - g22To89x0, _ := new(big.Int).SetString("17d3584e68adde4b3ba6ed1245f94d4d8caca9b5b2929f5a1dd8d0e8a8f964fab5f4412d4ffe260cb6779fa38187744", 16) - g22To89x1, _ := new(big.Int).SetString("b72810ba75b293f75a84a46c3dfda0ca0e78e28c4fe0d48e09b75caa3bfa8de2358bcde88ece4849503683161b84bb", 16) - g22To89y0, _ := new(big.Int).SetString("11fe5e23e0fb187f67b4c40789b58e09df6a0b3e6dbf1cd5ae161a999cd5a33dd64f36bea222c9fb58bf1e717c4a25b", 16) - g22To89y1, _ := new(big.Int).SetString("120aba0f5960ff1f80450c0312026d063be918de41d83c1d1fc2512c7065baa0516185e9f8d03aae90e44eafb73798b", 16) - g22To90x0, _ := new(big.Int).SetString("7e5bc386efe6a685e8952068c72af0599cf260863c4d971ba19b2fb6bf0a08eb4260727c84579542b288baa5e94629", 16) - g22To90x1, _ := new(big.Int).SetString("d2c6894aed31f81623ef71456d30ebfe785adcd98b1e630f31fbf6a577753f87d578f204bc14eb22a8615cddd8157d", 16) - g22To90y0, _ := new(big.Int).SetString("ba0fd34fd06cfe512def3ca63a5d78f56e453485fc91f2a9b4ea0cfcc5201cc29576e6d0d14397eba14240c0206d15", 16) - g22To90y1, _ := new(big.Int).SetString("120af5e505fab6358a1012b5447099f602212fcedba2e049af330d6a9d6573becf9c4e7bf68d09c8c456cca720c92e2", 16) - g22To91x0, _ := new(big.Int).SetString("1174fefe1537445fcf50d034065612ef8dd5511123b9c96f76660353f7de340e6998e115ae829cc51727648f61d6f59", 16) - g22To91x1, _ := new(big.Int).SetString("166b7f926ac753ca5c3a9f85c4770e826a4258fe1cc94d20e99bb68abf9fc9ff1b7f807a84026ce0dedf2e33bc99573", 16) - g22To91y0, _ := new(big.Int).SetString("d98dca8ba804a4d0c6caa9fcdb42843f800c6df85529cbf2c58bfbdba3ce88b6081d01830c8c597f709494bc1d0698", 16) - g22To91y1, _ := new(big.Int).SetString("15578b78fcba88a1be3182798a7ae76f422a1fef607a6cac01eb666208e7a580973dbef56f1ddcf8faab94be5b218dc", 16) - g22To92x0, _ := new(big.Int).SetString("fc61ead5646562df74ec30afaedbb0915bbd29e15e624027bc10f8e529db0295827e0a5c3c90cda7f83eb97e933feb", 16) - g22To92x1, _ := new(big.Int).SetString("b15b59c9dbcce34b28a3095f7b3befc2e1c818914e8a1b6d1df383ae86d64a7783d3debbe1669a5f5207ffa0d1aae", 16) - g22To92y0, _ := new(big.Int).SetString("18244101b385749a9407e4c57ae74864c45d76ec0d5aba9802457712fa9fcb1ffe61aafde08a76985cd55242471f217", 16) - g22To92y1, _ := new(big.Int).SetString("1907e297c0664a8400af7b569983c606e2852e7bb63539b2031413bcf7535bccbc585046b7de86d61fd781244ca85e", 16) - g22To93x0, _ := new(big.Int).SetString("1210b122a5616f20e997d502673fefc5cf4118a619b61ee99cf3f65bcbf5da8a15dba884094c400031100fbec206a75", 16) - g22To93x1, _ := new(big.Int).SetString("17ce05e3754a40a4adf2cbd6276d9c581c7c747d9e48c35401579140813c0b4da0881b0f919da893bb482bc221145bb", 16) - g22To93y0, _ := new(big.Int).SetString("aac2d4083f8e87de21a48e3300e811ab711c8d883ca709003cd9adedd42bdabbafde9ec3a6aebbce50984900404096", 16) - g22To93y1, _ := new(big.Int).SetString("1748abe303f82c9dfe410a8edaa9ca705961bdd99bbe75277239b2591fa172252656f799ee0f01bf2daac437e209783", 16) - g22To94x0, _ := new(big.Int).SetString("bbd4c59f3b17c68bc9704ca68ca7a8f6fcb174cbd28b938ae10846a11100145a4ba0566a83143fc9e78cfea637de46", 16) - g22To94x1, _ := new(big.Int).SetString("1151c80769ac75ccb8bfbe89d5d414de3bccb20161eed22804b63b2f2e1675f1abfc29f6325106cd77ed9d00b8ea2d", 16) - g22To94y0, _ := new(big.Int).SetString("12fd57cd0ba9b496335209c191009a09125fa0806b40cc11d404e2831bf8c2024347385666ad64107608cdd6caa3b71", 16) - g22To94y1, _ := new(big.Int).SetString("5bafe652e00121fee3e826e8b1bab162a091747a678890d019c570084c3f615e4f184048c2c2f2ba79249a17d4e695", 16) - g22To95x0, _ := new(big.Int).SetString("16425b99bff4b8576a65dd2382ca48e7645027855b20378c267c5c02e34bd5e3f6384e762775f7b1ae3807f5203fb00", 16) - g22To95x1, _ := new(big.Int).SetString("c4f2212923ee54f6aae19e81f8d6238ea24d4a53673cfd45e857c081c6efa37e5855985004a45c363c2ff842416890", 16) - g22To95y0, _ := new(big.Int).SetString("169ba0bb3e42f757629871e9666f707d8a1aa48c7480c0547e8decc10e68c744d0bef7a024763d53cd5cc2c20d99892", 16) - g22To95y1, _ := new(big.Int).SetString("100289f0c67b96678631a127ce88217f46b78d4397a79329bda8ee22b1d431f8b73b16946735efc987e4f4ddc78e911", 16) - g22To96x0, _ := new(big.Int).SetString("9cae168d2beb85064442c5d48d1d81257f720daf8da84eaaa5928f9ce3b0b02397e68e307e2bf121b0b08eea3e380a", 16) - g22To96x1, _ := new(big.Int).SetString("10b9e23ff1ff46ead2dd6eec0787e571d1730d53d92b57b4725542fcad3db59384ab86ef6311f20938aec75edb40726", 16) - g22To96y0, _ := new(big.Int).SetString("5107c0205417087f0eedd9e5a72a930a7a64dba962fdca1f8d513601360268d444c026566204c8536b54e446933bee", 16) - g22To96y1, _ := new(big.Int).SetString("f6391690abdb069891f2de469db322a91f9ac98422aaefa4155f9c01c1eee9831329a245361d2bf0d1807906d63f82", 16) - g22To97x0, _ := new(big.Int).SetString("189d873a3c3c95266c85196c4c2a0f9699da0b5fc6f2d7027483c05dee86a3987c5a923f275331deb38965ae50ce27b", 16) - g22To97x1, _ := new(big.Int).SetString("106b16c4eaf3b168dd5b3c060177758e29539f6775a73d57e185ba35af56e7cf2e8b0becfcd6c9bc7ee422e607affe2", 16) - g22To97y0, _ := new(big.Int).SetString("718c860187a5132f149d0111b8a83c27cb0a5662c1e2293d23b626429879775a46db397975669f7801ac2906c7f202", 16) - g22To97y1, _ := new(big.Int).SetString("4f54175597d0ab67171247f711cb83725a4aebbbb208f222f081a2e71d7fde76e5c60675cd6feabfcdbbfcabb8d5bb", 16) - g22To98x0, _ := new(big.Int).SetString("1f19d3cf501e5ce40cf8b7c600f39c3269c71939890eb1e978851b419c6105f39258d7269503b4ca8052ab82ae284a", 16) - g22To98x1, _ := new(big.Int).SetString("1faffc6b4a583783173b60d3652c2a4aea891be320809b5c385c1c1e0fd11e0d6afddf4271497c6553d06a26c24384", 16) - g22To98y0, _ := new(big.Int).SetString("24e54d6e7fa810babdcf81ade8cfc1ca57f3b566d0cd6a94a317853ba4192e14058f722b745f9c2830983fbaa104c6", 16) - g22To98y1, _ := new(big.Int).SetString("48c55a947b49101171abfd3cda838acb364087029772e87c5e9b8e2c64d5d371e226cb4fa6fea43e49b17c27561bb7", 16) - g22To99x0, _ := new(big.Int).SetString("1091aedfd19f924dd7b2dbd629a2777966dcc93d9137c3bdb603a4818c3ac2c3301b9a42f5f4533ef017611a7dd35fe", 16) - g22To99x1, _ := new(big.Int).SetString("702ca5c683b735ded694e3af1298adee4efd45980a9bad0f154d3cf11141c949b82406373dc15f66c208b4df49a0b", 16) - g22To99y0, _ := new(big.Int).SetString("9d02b061ce034b067b5665e234cf255f0351e5e1e699f613b58d55488b1f91910830cf2bd4be26a1367c279a4fdbcf", 16) - g22To99y1, _ := new(big.Int).SetString("8b94bdf8a6d8f1d0712ea40fe5cad5e6ab82e036238df204291833c4476e434686f0869af372a392d0c19f985a8cb1", 16) - g22To100x0, _ := new(big.Int).SetString("14032d23cb84889d291673674fb0cc81f6d7fff5945bda9017512e2c4401a61364f2b9a7511b726a992ace963a7c9c8", 16) - g22To100x1, _ := new(big.Int).SetString("556042f4058dd5debd733ea53d2ed96d9e3b85f2b1d9f8157b7054806ec58888027c8a4a9c1036c192020758178301", 16) - g22To100y0, _ := new(big.Int).SetString("e76108a0471939696bb514e3fa68c9e69112f952abaa2b79fc45ee2f8790d70b60c5920d6217d04e72c7daadf2efe3", 16) - g22To100y1, _ := new(big.Int).SetString("15a99f10d35cf3e4cfaa214bbc19a465d117952add821ab89f49cae6682550ec136a1df19d9f9823a5d8fca4b65a94b", 16) - g22To101x0, _ := new(big.Int).SetString("5faba4f85c7be8b85607aa383d0f4a8974d450fee30e5a93f3903818f899364ccad8428c4ea6ec293845c9f6fa36d1", 16) - g22To101x1, _ := new(big.Int).SetString("19772a622b879f67b46290507d3a1ccdb8ea4009c26b67dbcb63f67dfff82fa10073e591f7a7e8dffd0b129ca98a2e6", 16) - g22To101y0, _ := new(big.Int).SetString("16babbf5b65e60b9af1bde401343ec3cc97fa560dcb7402d7906aaee459b5bf1f4774cfa92d0fe2b2686eba37854f2", 16) - g22To101y1, _ := new(big.Int).SetString("10bce0b14de90c6b4a63389707eab405a34dd5afb49957ce1d492d2c113ebda90b424550a5550f5a14fb5fad2c24db8", 16) - g22To102x0, _ := new(big.Int).SetString("122e0dfcc52b1e188cbd0f8b961d8a7750980d20eb7c25130b56bb9f882c8d7040f374ddef3492dd9b76e5a6ade6a18", 16) - g22To102x1, _ := new(big.Int).SetString("1a2b09c5c507570a6d17c5c6b47b0212e4d0f5715194018353740f0470b3822ad2fd571dca5eae24c286b710b73de9", 16) - g22To102y0, _ := new(big.Int).SetString("d28d027cacada3ee31e77fd5de409cf7ab7ef1d02508884fad99332b3878176b84efd46aedb81c285ca964837f9f3e", 16) - g22To102y1, _ := new(big.Int).SetString("1cb2594a6e61a98bd5dcde210a43552c68af9b95c09962ac6795ce568419651fc7aa115a63ef23918c41850cd27b7b", 16) - g22To103x0, _ := new(big.Int).SetString("b879e6f999c7673e2e84711463a084d89ce2f2722f0c9130844cadaf1ee33e5e858e53872360317f462a8e353b7e52", 16) - g22To103x1, _ := new(big.Int).SetString("777a62990bad6e9473770a60a6aeb985e2ecbed1ae2f063cfa1c8383dfcdba0b6a0471c13d88605f7b20b85765f57", 16) - g22To103y0, _ := new(big.Int).SetString("17a59286ee10486729a13740812be956ab7a95fa47d8813a852626f1aac49ff84fec74df85c9fa0c077fa71936f6ccb", 16) - g22To103y1, _ := new(big.Int).SetString("67b5d8f00febab51bdff3b00c3e9738955dd0fdba76a3fbb9fbb86b5e7caf6b1c67b039f06f9a595207e0b19248ddd", 16) - g22To104x0, _ := new(big.Int).SetString("137cb180674fa5e29385dd1696481ff08c5efe27a81009cf821b469f394ddc402c65e3331fc6d78f9886e8d9fde9781", 16) - g22To104x1, _ := new(big.Int).SetString("133cf155c8efe036f92dc3abe8281dce6b4a723027c5378ec5fdbee613331533451fb8e6b483942ea2350767721a124", 16) - g22To104y0, _ := new(big.Int).SetString("a482c18bc8ec6221559eb719c2ca37812aceb007161a01534bab0238a342a485f2e77d28ee8bfdb38fb633a160f422", 16) - g22To104y1, _ := new(big.Int).SetString("fc146f7bc0bb0ee04866fbaa73eb4ffdc77e455e1ad9a87ce8468d941735f263e62917b1c06bfaa78bb9fdb5a91746", 16) - g22To105x0, _ := new(big.Int).SetString("116dee9c4666d651c84821b5a8252f580608cdaf21132cef77a24fbcee9a5429b957f8f5d1c0a804e5e92676b52564b", 16) - g22To105x1, _ := new(big.Int).SetString("e5be1c7cfeb3aa1e899859ad51a6f24c488d215bc1b965d898c8cf85fae6a23f91bf8cdf12cafa8986078917ea13cd", 16) - g22To105y0, _ := new(big.Int).SetString("2c068dae0363b2ed8d1ce1b5e5155cbff7dc31063d33daa6e27bfa953ba9e886cd7d6e85b17f2589160cdf2a010f91", 16) - g22To105y1, _ := new(big.Int).SetString("33774fcf567fd930a2bea77b50481405fc4ff66e7fc1389c39651c5d15808deb68a42ce488d2fd112c8f0a5baf1fb2", 16) - g22To106x0, _ := new(big.Int).SetString("c7c081627ad153f088434d8f03fe40d9ac8001bdabd1665306992a0ceca3133aff86d35fc0a0e411535912729e9c78", 16) - g22To106x1, _ := new(big.Int).SetString("9489c71929f4c68707ff719a5cfafc645dfa0855c57cd86256ddde49410495b63caffe8d66b016f4b63fcdbc37d053", 16) - g22To106y0, _ := new(big.Int).SetString("a518e734be0ae302a98730a56e76fad774b0b503d4f376c9fe02c2e0969659493299c5b479b290aae53e31271bf855", 16) - g22To106y1, _ := new(big.Int).SetString("c6c060a1c862dfb5aec242de081c4f5ffa5b101ec4eb4b92f6b293c4ea6b738e77b5b59b1877ec5b9e1742c5a5623e", 16) - g22To107x0, _ := new(big.Int).SetString("13becbe4792c3dc9cdc4ecabbc0142b1470ad4064856db9d2e0fabb6b51accec4e9be97c86ef30d725c442a0d6f37ea", 16) - g22To107x1, _ := new(big.Int).SetString("136b7eef72220ed5f709e3022be60b3a28cd5a687feaf3f952e6b5451454d981ed067dd4faecebc22301c501134038c", 16) - g22To107y0, _ := new(big.Int).SetString("17c1428bc2ff6801d0e4c76c5b6e2f331a200471bce5aaabee05ac850c3e041182daf8820cd9d1e6649e1273d7bde96", 16) - g22To107y1, _ := new(big.Int).SetString("194ba0d16fbb45e78ec331394145f50873c35f0a4eccbb623a8629cbbb37362d6c4460360f2e942666d4195fa3f05a0", 16) - g22To108x0, _ := new(big.Int).SetString("186aa20f6663b4ddbe0aa889560ec74f71fd20c817dc21e657c5b375c2617c352a140c7fa7cbe2ccc4fa369607ea676", 16) - g22To108x1, _ := new(big.Int).SetString("ec607cdb75ba895c0cfa64431294490fc54b683033b07b92e6d72fa4749b3e2859e7487451e30c980e6fe3f65a0686", 16) - g22To108y0, _ := new(big.Int).SetString("ec43c1cb87d160f5ce51ebd294cd3c2c5ff7a3a02cf7ef831b584befae7ce33ed13820581d5ee70889e5075f1b2be6", 16) - g22To108y1, _ := new(big.Int).SetString("1f674975271c4d2e6cf37781aba7207e35c1158836a47002827aaf1f66ea0d58f2e89126070fa3c3c0b7cbe033b668", 16) - g22To109x0, _ := new(big.Int).SetString("1882dd4554816996525224fbe03d539546f5d00a13ef79e4d38d3300d0cbb87fd7fb3e1aae6523ea8645b80c22c1795", 16) - g22To109x1, _ := new(big.Int).SetString("21c4b1b500001a18ce9d8174de87203750df294f1835217022b33bd0e1e969a894f91c1de2b1be41a923fc6b2616cb", 16) - g22To109y0, _ := new(big.Int).SetString("19a3914c1247b5ad192a43436a5a65dc3116f96dc33567cfb7f48325e8433d990212090b009aca8172a01b192abab86", 16) - g22To109y1, _ := new(big.Int).SetString("1a53aaba50b4750d284100cfe5ba1f70ff28b7fedf6241b17abea88e59337cc4d473fdb0225a0339c985ac9d9c6a8b4", 16) - g22To110x0, _ := new(big.Int).SetString("15ba08f8ccf6b06bfc8258d9e8f60f63ce0ed2ff7b9e17317b2b59792f325cf0a6cc055480afec020c737ab94d39370", 16) - g22To110x1, _ := new(big.Int).SetString("12bbafe613a920d757a8cc75963e701767c307f94daef4a4893c77d5d9273759b7f6fa37de6cf73c1c8b9005776dce0", 16) - g22To110y0, _ := new(big.Int).SetString("12c19203d2fb64f421cff9f536f98f0db30f2e76d243656459242cdfc75a8ba139604d8e125c8d15be8688aa8b71808", 16) - g22To110y1, _ := new(big.Int).SetString("857c55d28da757acb1d4dcedccf89ff54f0ee8a68785c83a76a7ee2d3e1a15bf78b66927f7a914bced01b822986d6d", 16) - g22To111x0, _ := new(big.Int).SetString("16f80a7a30c317af0103d8d8e8fae69d75491921aecc038e22416c9f59e1ba8cf2d9c5e6586e54c62a69a1a010d4db6", 16) - g22To111x1, _ := new(big.Int).SetString("1967bda1bd60098ef7289fcbf288e3de7fc2764fbb210a9ac5c92498982baa9e6f09ad367c368800a14ba90f4c3f8e4", 16) - g22To111y0, _ := new(big.Int).SetString("956ff4717c9a52fb3056dc185a2166f76ce1fcac3ef1db9412ed9e04194c37dfccb7f2eb977572b0cc92930e805b77", 16) - g22To111y1, _ := new(big.Int).SetString("1995917263b0c39e974e544b8cf6741a642b76389fd0cf8fb0561c867c20ebae977ed85dafe2aef3e326e4c2ef2dd0c", 16) - g22To112x0, _ := new(big.Int).SetString("8b306ecdf4c97bd0fc88cc756f7aced4e7701464f96e535bc9b10c1c79eb66eb84ec07bf96d83b7c4e14a0c5a4dc87", 16) - g22To112x1, _ := new(big.Int).SetString("de6706372245870847f47aae22da4f8b56e64330a7d64dec23c7a098ec9126e48477e1396664356e40cabcd777f122", 16) - g22To112y0, _ := new(big.Int).SetString("11df20d23ede31c4526bd0b0ac4da9971755b90d9ad7aec5b55a89b4940ba1c044a0644a3086b2a8e8b48689e41974b", 16) - g22To112y1, _ := new(big.Int).SetString("10a2f94d3b6ac6a31eef91311328c9bd5450bdbd9de0ccc5cc3aef08d909acb228265f35af749f588119d087ca53c34", 16) - g22To113x0, _ := new(big.Int).SetString("10db59775fe44676cb087b9e8aeed8e8fd4204a0776a2d14d74a980e311ba9e7a90c85ad36dc867b10e5228b7838c2f", 16) - g22To113x1, _ := new(big.Int).SetString("e8f40636d57e8b22d9fd6c859963a846cdf50bf5b4a10236cae231f5115f0861a105dd6254f9538cefd53f441e9ad0", 16) - g22To113y0, _ := new(big.Int).SetString("5c69342ca0eed49339f69e16f6f5bfc05e1cf7ba712a19fa7789cd37340a2c86a4a75907f9b413398a6b056d106276", 16) - g22To113y1, _ := new(big.Int).SetString("15d3b19eed664079a60594a5d4dce11f2a47f21d563c3a283546bf81fb735175ed41d4d7701d1442db4b97eecdfa2ad", 16) - g22To114x0, _ := new(big.Int).SetString("113b08f27a3e294e1c8c76ec1c56b8f20f9975e5fe0a438a0e07db0d6aff6c16dce7dd4f1c54699d90ec9190857cdb1", 16) - g22To114x1, _ := new(big.Int).SetString("4a0acd850208c6f2aa5b7b63f93091a868fd5fbb7b98458c177394517ebd60ab360850d3cfe88614787267d48b2205", 16) - g22To114y0, _ := new(big.Int).SetString("17820619757a4551d1aee5388055818247ad1e016185c21ffc885497e9b0b733440d3ffb724147646c08b94660bd3ab", 16) - g22To114y1, _ := new(big.Int).SetString("3e99118c1c22ae4b8b6b7c3415e94fc7a1175c9e21431b754a585c3ff8d1458096213d49864d21c95abbb9e54e97fe", 16) - g22To115x0, _ := new(big.Int).SetString("105fc9c61c4239c7d77484ffd28b72740db901c8e645c91ba32fe6d27e27f80fe0d6bf1413432cc61b586e466d0a13c", 16) - g22To115x1, _ := new(big.Int).SetString("d5004ed754fd6d84cf35574d10f182aba51d4912f29dfb2eba5d5bf912e77f493c453b5c3e667e53912879068bebe4", 16) - g22To115y0, _ := new(big.Int).SetString("18b85ac19fa596898556653a2964ccc763d20040702268e68b31edc9a9c8e1f0d9190f1f9aba8ebd209674c7959dfbc", 16) - g22To115y1, _ := new(big.Int).SetString("174181bdee36788c13f7b8f596fbf606458317e6d8ffb6dd7ab3845095b14c6abb0b74f127a8bd70b60692589e476f7", 16) - g22To116x0, _ := new(big.Int).SetString("19c2e893795c9f4908c30ec87ebec028bb867656b3cddfd1860c0ce7e098580601d312595d25d87e66379f4ffa9b97e", 16) - g22To116x1, _ := new(big.Int).SetString("141710b3ba533bdd477919ef42f241ba8d0be61313f93d593535226a3be959fffe37e8e74086d0fe870e54de9a7e681", 16) - g22To116y0, _ := new(big.Int).SetString("c5724ad1486360a40e063ae0dd3341a17e459a4733bd7a55b3730e6fe374f7b6cb54f07af84177a7a6ab378b71a809", 16) - g22To116y1, _ := new(big.Int).SetString("8eb5b60ed48594c2047c1220efdb7b51dabc76522761aa1d18bf8cfb46c402f1867666f63dc6b406d1f3e9159141ba", 16) - g22To117x0, _ := new(big.Int).SetString("96c716d6221b9a07a2a463e79d6fad45d2439b3523d668ce390fb1f3044a61e25baa6ecc1a0db6eaff46a52709a2f5", 16) - g22To117x1, _ := new(big.Int).SetString("12d78ace80c0e9fb450808c38c714d3503a9a9927d12484263811f6271b5c5ee5d826cd502ceb95f30e3e2acaac59f6", 16) - g22To117y0, _ := new(big.Int).SetString("118133b9785c2ff52708bb511b0b10c8b979520e4c889e0ed4c3932ff864c4acf79c328b28d36c04fcba4e96b633e4", 16) - g22To117y1, _ := new(big.Int).SetString("c22a5acc14253e329632bdc6911844fceedcb42ba617c223542b51898258a9ac968338ab95070c16022b190dc8aeb0", 16) - g22To118x0, _ := new(big.Int).SetString("128b27a2e71c8b85cbcacae660242b7e96678c6ffe6484d8aef314095dd810e7ecd1bbf223f023782af6983829e59c8", 16) - g22To118x1, _ := new(big.Int).SetString("17bab7106a88e2b1c839b93bc8e0354765193a1db6de504e626f1725ce6ed51ac839c146c08830607703cf58539c089", 16) - g22To118y0, _ := new(big.Int).SetString("17336add0948febfa4425131247a1ad32b37d1e8bddd4576bf8c6e20b02be459c1d7a13e78308c99155b9a049b510df", 16) - g22To118y1, _ := new(big.Int).SetString("a12a9dac4455259b060c0255e4583d3a062cf9cc4fea1b75fbd2a58ce3837d3ee938afb5de51d7c0dc27b854b495f8", 16) - g22To119x0, _ := new(big.Int).SetString("896f479259586aa0b36b54f08af5e24953ba519262b3c8e9a1363fd12e791bad83868503c011fd3bf47a22fd79d763", 16) - g22To119x1, _ := new(big.Int).SetString("338a2904485eb48063d71ac60f5eb531fa5249e33d1e9adb4807ceecc360ed58cf5272ba1f2f4c8b12a6eaab9ef6e3", 16) - g22To119y0, _ := new(big.Int).SetString("474ab6f27e41c0df056f2cb7e3059d199fc4f92a9d16778ce32d56aaa62c5b9d3656d985be5d076366b8bb644de524", 16) - g22To119y1, _ := new(big.Int).SetString("3aae5a5f5a55b603a3fd0c46b4e007d41f8189c6154debcb168c08b7e38906332cdec201b0f7866012fd9a9097b825", 16) - g22To120x0, _ := new(big.Int).SetString("120a93c9b760fee587c33aa906c84cd3c797d40ecad10043e0450f90d5abe3542801bed7373c787c32892cab0e50559", 16) - g22To120x1, _ := new(big.Int).SetString("1624cd7090d8f657a2ff62e5693b8b3a72a4b7deb9b4875de356fc269559a71aaf88363ce4d9808c5bc9ad908d04887", 16) - g22To120y0, _ := new(big.Int).SetString("9f49a1743816757697e88399227fb7d51c1c4877032bf65b05c4a8d02e43be6ef55551394135dde051e9fede6b605c", 16) - g22To120y1, _ := new(big.Int).SetString("1a7fc715ce4d2ecb482ad02aa7f62e593d9892affdda2f72e2dbd0e4d35762fad42c77c9d02fb0b10f75cecb11803ab", 16) - g22To121x0, _ := new(big.Int).SetString("1a65ab96154bcf80f685b48371079cdde4cd34625b3c8f5f29ad17554f9913a7b4e693674e9f203672dbd2b445b85fd", 16) - g22To121x1, _ := new(big.Int).SetString("2524466b8d04adba4d1bf36e1ccbe80623e846adf23a615c5d1ecce579b4dbcd9a86915d2c0f5d1c83d6a5bbfac43a", 16) - g22To121y0, _ := new(big.Int).SetString("c7dfa1f05fccb625d733f052f238f199bfbdb3cda099b2ed018f7f4d9feb650134bb59c02e800deb3b5482289540a0", 16) - g22To121y1, _ := new(big.Int).SetString("1146360a8cd64439a81ea8374d25a4c6122156d266ff2bf9599f8d7c98d1509213cbd806a06313210eb5a0aeac97123", 16) - g22To122x0, _ := new(big.Int).SetString("188f43a5494590ecc5a8c79dd6e8370a448fd4b931627c404a56c041a1def5920d2b92f3a1bb04ae4aec56d5c904b9d", 16) - g22To122x1, _ := new(big.Int).SetString("192f56e3fa6b843efa225b84b7d2ae1674bf3bb01598c2baeecc3828a5c110cdbc7cc1bc4ee127ff2cc5119ad467f1a", 16) - g22To122y0, _ := new(big.Int).SetString("15717c6bd7aadb4a150fb4181cccf2b797b1647f9e7c10d51fcb919f542c9fcb1f233d32dc1594fb8e774598e3115cb", 16) - g22To122y1, _ := new(big.Int).SetString("10159285c6eeae18aa0d81b91d815b3150350f3197a50226c7b26fba968e1e03584f505349d6d63032cc0eca128ed93", 16) - g22To123x0, _ := new(big.Int).SetString("bc4a3957e3c08f898dc2413596ada5054c808809dcbaa3d01508bbfc3ab3d6b19db9f33492ffc6a3e22cd59bb77c0c", 16) - g22To123x1, _ := new(big.Int).SetString("65f26a6e864dfde14c7b3b49b423bafaa8076a09053668346ea337a0639ebf92559aaee8d2439fb84c412aae2ebb62", 16) - g22To123y0, _ := new(big.Int).SetString("b6692b1bfef88946d2127940e90b68da09caf45b86743e1c0e82fffa86b8acbdfcc90ff491b20a3064d4344476fae8", 16) - g22To123y1, _ := new(big.Int).SetString("176ba90c125485e53467da463d2a9382af69e51b4b1f42be07e3e1532ffa4872408fb36ca89a4b2cee3667b0585f4d3", 16) - g22To124x0, _ := new(big.Int).SetString("422c51a3aa49055455f62bd71c4a66831f8740bc94d61a3933f951178d76b70fef1732ad75e93c19dad32355289b6a", 16) - g22To124x1, _ := new(big.Int).SetString("a733eb66828edc2487c60f073b038f64292c957f670ee3988e63346c66bf28767200c4ba94fdf992a165269f424cd6", 16) - g22To124y0, _ := new(big.Int).SetString("fe987e737da4551904e19d07446d3615091ddeac6fbe51e264532872e0958eefde0537787692e2e7cbc9fda97dd896", 16) - g22To124y1, _ := new(big.Int).SetString("10ed2b3accdd399b80c8f76e24c6d7ff6ce59c6e8ec35217a63e5e7bc9660cba283540994d4b1738d5fcb78f38edcc", 16) - g22To125x0, _ := new(big.Int).SetString("1a4fc71b2ff27db2dfbf3a9cddd2422f42b229942fb410c38d386ec4b635f1a45aa627c976ced771ac3293bba0ffdfd", 16) - g22To125x1, _ := new(big.Int).SetString("6e5f5486f88051c93d84c4260198e712799e547e259fd7f4cc05f1964daa129c98728a8a24822112d7f2ef35aa6d81", 16) - g22To125y0, _ := new(big.Int).SetString("12b009d98fd0fa1feae1a4a7293187df2d1a368cdcb82cd05afedb8f60b87bac4a156dcafb2b73aa44cb85792c8629e", 16) - g22To125y1, _ := new(big.Int).SetString("13d1c92964479a73166e36883d4530ab0e9f6bd582ce60fa98b2a5760ba4c92eb0fcdceeedeb3682545b818fd98d3c8", 16) - g22To126x0, _ := new(big.Int).SetString("16d19082b276c13e9988c42008e5cfda4afce19b4c1addd0ab43c08528e51c9011d860e2f91e40e283c4ebd211b8aca", 16) - g22To126x1, _ := new(big.Int).SetString("1506770a5dad74bb30f07e0c32eb6e46049eb49aaf600e769ed1ec162d627129b1bf72ef08d5a95bdd4c4b36178255c", 16) - g22To126y0, _ := new(big.Int).SetString("11f9157b2bcdd2254394e22e5badc8bb25f5bd07082a053dca96c784ab79262e706eef2f39e4397bcb017d99d367b0d", 16) - g22To126y1, _ := new(big.Int).SetString("d1d9dafbf7e515925ab383deaa096a6e8dbd478c0f15d20b48299ce21fc574004eec2a6df2d414694f848e2630d1a7", 16) - g22To127x0, _ := new(big.Int).SetString("1067d650a5123138159b5a8e4d42313a3db29277f8a7130e1206e419d8abcc7ef9420af2793610e715d66b5a41b7326", 16) - g22To127x1, _ := new(big.Int).SetString("f44bccd7183dca1e52a3942b861222ded61113b703cb2497070dc326093d614d1b75b78b56c0e2fdafa41dfa6da927", 16) - g22To127y0, _ := new(big.Int).SetString("4b106d8eb6f92e8c7462f058b94e13a33933cebd4f0a4eff6501c757348909f1cd51719b3f654fc70f33fb423fba9e", 16) - g22To127y1, _ := new(big.Int).SetString("22f04d598b4c8ee181b01bc002b408bffd0275e0047785988c8878edc1b94e312cf4d0fba0ebbc861937699ebb7a81", 16) - g22To128x0, _ := new(big.Int).SetString("20d50fb3da7da5a58f114c7f0c1b2c3fb65b401756083636706c896dceb2e6b80e51b23cb2935569ef0d80aac7dabd", 16) - g22To128x1, _ := new(big.Int).SetString("d008b7ddca1fda0728aa306a2443c4a34974ccd4396af4117ca27a9fba99671335080b3005059271d6165132528f1a", 16) - g22To128y0, _ := new(big.Int).SetString("195a4ed75e004ce37815124c82f3d9797d6d0bdbace5f10e96cb2762f8cfb5381f71b54d4bdab9ec6182f3d3cb633be", 16) - g22To128y1, _ := new(big.Int).SetString("18fa7ec54b9808d0f754dd6d437cb42d3edef11b4d3ef1b05ccc29d0e4a829f48ea0e00b696c3ad248080b880c44fe9", 16) - g22To129x0, _ := new(big.Int).SetString("114c6d0ff787cbe23601bdfd05318d0646569932969458a171ca5e819a8c8bc028113f0553b6fd0c676b642dee71184", 16) - g22To129x1, _ := new(big.Int).SetString("127b99fa7c10f86aae2cd16d891e0020d0bc968924e439e297ab760383b869ffceaa20642afea8de99b50242ab5185e", 16) - g22To129y0, _ := new(big.Int).SetString("19d49f0d8cf4200b14e5f6ec93b6e05e16a9465eaa7291749dc0379b35b1607b0dad2134111479ffbd0f33346ad83b8", 16) - g22To129y1, _ := new(big.Int).SetString("7f20077279ff727c20a7469fc888f9c7c6eda38a8554b5f3c05a2b5944cfebe2ddb84aec499b0985390c05f1f3e518", 16) - g22To130x0, _ := new(big.Int).SetString("a572f87094301722b128def142ad4a5d676cc7fe91cd5c42a625abbf8f9270d0e7e271647b3aa16f210a03e1530931", 16) - g22To130x1, _ := new(big.Int).SetString("169c40a033abf367a4c2a2721a67c23aa22a414965636212ceb374d69bf2bf4807646790b99d77939dacf5c0d0fdbf8", 16) - g22To130y0, _ := new(big.Int).SetString("10abf4fa5662529debdbe36fd2d10880d5fde7b8ea81c3e2d8657b916c48be5f90daab4a3de0906ebacf518154b5e19", 16) - g22To130y1, _ := new(big.Int).SetString("b040108d3a887eb0c77d9acf4737e67d0a045d9f2be2ff4530293b9665f999c96950f62d953858372c9f9e7514f9d9", 16) - g22To131x0, _ := new(big.Int).SetString("a6d18b51f12bd85474f97de2e33d41d51732cd467e4bd09744b4a476118a98c160a2c1fd002e8e34ab2a4d1f332ac8", 16) - g22To131x1, _ := new(big.Int).SetString("1bdd9277e55486d6a8dffe97ebcc8731a3d586048b929d7febacbfb295f09e630695569009f05f7bd56a1066504fba", 16) - g22To131y0, _ := new(big.Int).SetString("cdd3bcd279f3bd4a4a26dbadfca0e16540df483420f7a29e1ce637d06dfb75989ab676d6234f20ec85fad8146b0008", 16) - g22To131y1, _ := new(big.Int).SetString("12e998cdcd2b23a768c17d4fc01cde98e30989e904c537332545b77cafefbd2877f2981721b1310d9e8e37061e5e40e", 16) - g22To132x0, _ := new(big.Int).SetString("c77f98d1987ae9a571660b786d68e60b5c23af634976eee9b511db07eb640bf1d065b380b286d2ad40804fe747155e", 16) - g22To132x1, _ := new(big.Int).SetString("169b1024a30d0413daae8dd6550b94c2bc0ec94a36ab8c7e98051bfc3c3abeaea57f15e64c3fd879992fe9355fecf5a", 16) - g22To132y0, _ := new(big.Int).SetString("8c5ebb3993e33ad7aff2e4738a492862b6c2f926b7540fa81b3850a8f965a27292d11e389e30b8e1e7f91969a4e7ca", 16) - g22To132y1, _ := new(big.Int).SetString("8abaaa30dd5aea7b1cde6d15c611db8d789bb6f70a10e2f196180ef07e65f7299b4579356fb4485a5bdc9072450322", 16) - g22To133x0, _ := new(big.Int).SetString("c4bf538a7a280c12bb5e44b38f94011740c152df73256112c2a9f5c56034b3c68ea225c026e687f1ce11c1f9425fe0", 16) - g22To133x1, _ := new(big.Int).SetString("a785fdd2407f9322d0b866ffc97a99aa99ce73fa04d875ec236c8ca7a64d16a3ba4e648c2a180001ca46bcf6450b20", 16) - g22To133y0, _ := new(big.Int).SetString("1a1470931d33a5269d2fafa33c8b87bd9e8f1d20786f1468addf18077486475b02067326ff0d388f225478ed55d6a91", 16) - g22To133y1, _ := new(big.Int).SetString("15f39e78bed905cb8ef2cd15ab67a8a31b9369c23e1ec4a8772a588f594962c93cede07826133572e29e33a89c3792b", 16) - g22To134x0, _ := new(big.Int).SetString("aa6df791d6b38ae79ada370750ca7a46308b69a82aaad306faf6a2f609276d8b3ff34abb23bb00eb387c09f12d0ddd", 16) - g22To134x1, _ := new(big.Int).SetString("16075bbc5f6ffc8dda29163bd466786c633572722053abfbbc87618ccc40f332cc1e809411ececb09e842ef79343207", 16) - g22To134y0, _ := new(big.Int).SetString("f911f7d1589c9b220665c775b9c20a62b3abda1ddce0aaaf1a6bfd625b3ac5b6e6e7adf429d85278d1316cab1f2228", 16) - g22To134y1, _ := new(big.Int).SetString("16221b6d70f51b5917e77e50f6a8c607df80749df9ac67f98ea75c83e15d39056267e9d8b39cf80637c1a8489f35c28", 16) - g22To135x0, _ := new(big.Int).SetString("b81e8584edc14fc3977c91e1cad8c7d96adc3452ee6b096c6091ff72d346af2b0c3a7265ec69993d7b1a0fd0622a90", 16) - g22To135x1, _ := new(big.Int).SetString("1303303a47b5012fc91dac476355191d7448c7ddeb2563fd3eeaac32d866dab3d1448355e6a424b04f77c7ab83590f2", 16) - g22To135y0, _ := new(big.Int).SetString("174cc481b2beb71ffbf6fd9b20ed623f56e8449dace2d660345e7f7393fc8db345a930c74512378ba666e670ea85b9a", 16) - g22To135y1, _ := new(big.Int).SetString("1371b79a39c2f453b69fb4ab3cd311ea3ce67705891b7b975204330f2986b55a25be2938e6a83bac6c5c90866195828", 16) - g22To136x0, _ := new(big.Int).SetString("7396d3b10e9bc30ab854f26cb7ddc957f2553af8acf33d0b40cb61e74eb4b7507e00d3ca8063fff22a38d22b3f1413", 16) - g22To136x1, _ := new(big.Int).SetString("17801f7bd1f473e6902ef85d74ffe904886cd49b6c94e10a55af4b31c6e55bd696e597c4bb9534f9ea2980474871ccd", 16) - g22To136y0, _ := new(big.Int).SetString("9d40c9a6e80ee86c838c9ae31ad6bd44afe6eb0e1b65aef0af818cfc92d75a0717ee2d50f43e45eddf695075debf5f", 16) - g22To136y1, _ := new(big.Int).SetString("13f32f4dd35f751abac1dccf194b5e676de1f83e24ec050489d4123dc3c7f5604b63e759f9cb661116fcbbd798c8adc", 16) - g22To137x0, _ := new(big.Int).SetString("14f2d2f3e6ca2d3faf140441e955231b4dd6ac3a491f6d61fdaa9a0964113691efb7570c0d940d6be65b9b92cfdad82", 16) - g22To137x1, _ := new(big.Int).SetString("1279c38ff3c132324171dabefcc2db6328be5be7f14117a99727bbdc84896bc28b6d7d7b73e65c46080ea6f79b742cf", 16) - g22To137y0, _ := new(big.Int).SetString("1ade12a0e3145a93f6b1f984a6b8809e0969ffefd992c3a06f73f802a8a820169a5edfa145ae487bac7b8beab74643c", 16) - g22To137y1, _ := new(big.Int).SetString("501fbbc3a2519805188dde6cb618f44d4548209b9779a879f7e75cef81ecebed7b3e21efb2c398a650b53839f1f33f", 16) - g22To138x0, _ := new(big.Int).SetString("16ab50189fa1ed0980ebd251a6d5d1c60e6f61286f49a7b1def2bb6b16c008411eee51e30c9837b7d5abc7416dcab9c", 16) - g22To138x1, _ := new(big.Int).SetString("16a25abdbacd210f68ac4a8925ba642a4cf53747e2f0769711ed596b78150486b62743b71a7714ecaa790b63d48ad94", 16) - g22To138y0, _ := new(big.Int).SetString("825b72644cef348b8100cac35ac5c4b04cc680935d76f4962ee4f75e0ae371663965f23fd24b048fdcc35ec589de85", 16) - g22To138y1, _ := new(big.Int).SetString("b3a1150db077c0a619eb8554935c99dcce9d6743a7287d4e979746e51505c1602aef3a457f898f2054c163e09f9306", 16) - g22To139x0, _ := new(big.Int).SetString("dbd9c09a759b9a2f8e3799c9772ad6ce710b996299d1c29d314cd062c5fb6379f712b359fd4a3b550e2371df15c63a", 16) - g22To139x1, _ := new(big.Int).SetString("a889014db555ed84eb50abdd8bf40a4e95bd518b882f9270462ab4a2ba481ebcac2748ca4fa558f88179fcf343fab5", 16) - g22To139y0, _ := new(big.Int).SetString("37e62c7bc97bac76c034f62421705fa6ff7bfd900df4b99c852fb735cf9f74a168d003a1c04c99cb5cdede0fe41b7a", 16) - g22To139y1, _ := new(big.Int).SetString("77e0c6d5454c78a8086b77dea8ac6d70ab3634253398776aad2df2d77dc1ba5a97a6d172fa7bffe90237b4b1edfef5", 16) - g22To140x0, _ := new(big.Int).SetString("9731f787fac3e03b37fdf4cf1b7ce97a2717534d046330021c800237ec4514abaf50491d135ef84186d8ee33f4fa60", 16) - g22To140x1, _ := new(big.Int).SetString("6ee7f6a61591f00c376d4c1fc02f8408422a65b6ac4a33d7eaa52a2a9b92abbc13871a6503d3f373f968c0e8fe27f8", 16) - g22To140y0, _ := new(big.Int).SetString("b1b6df1dbcb7c0d0301295c3053c095e59b94b956e04641a2eb4d6557f3daa97ba227e92824d6500cd9650272db6c2", 16) - g22To140y1, _ := new(big.Int).SetString("e94a1100050875466c448cd85d807bbd26dd7c5fd0362acd765cf1a3dc0570254e4cb1de899f3131264c8fb7f19b97", 16) - g22To141x0, _ := new(big.Int).SetString("7d3064a62328de1eca2a196ee03aa86c17d80c9ec6e4e379baa53ef235b236935f5a67e134070f82dd083d89e4ed5c", 16) - g22To141x1, _ := new(big.Int).SetString("df4838b1791e3eda0dd41dd734d340666d97fe47299422e82e5436e26fe5962b495cc9581cd0b099c1db149a9e5b40", 16) - g22To141y0, _ := new(big.Int).SetString("1329083f9f71707b7da69139fb6a24aefbde9258ca3453ca73e4cf71d858f1008b1abb2b286e3a8d320fdded2867919", 16) - g22To141y1, _ := new(big.Int).SetString("100593443c2f917ada3ec375d67c17071b6e9805630247e8343077e5e06d16140cba660a3c98ac6e8ece3d57191c3ba", 16) - g22To142x0, _ := new(big.Int).SetString("adcf903b9fa22ab52008e7224cb2c5b977940c0b6809523a9f9239612fe0c085e56eb8bd70396f87f06c5c74035248", 16) - g22To142x1, _ := new(big.Int).SetString("142ac4f91706a6c6356fbdbeaa3af8c25af57abadc3d266a90ff949b53e7bee83093e4d4d71f4f015b90c4fd7846a0e", 16) - g22To142y0, _ := new(big.Int).SetString("fd3266d726769a8c62574b8fb8c001a76e4938bce1a627d11145bc6f73673bfadbc172d166f91d679c48e7604a3832", 16) - g22To142y1, _ := new(big.Int).SetString("40c9c3e13d49a2ca6b46f7be71200240565e318ca252d33877b5db572bf183ede0eb05cf66343b082fd5417a19d2e6", 16) - g22To143x0, _ := new(big.Int).SetString("65b04e658dd09abf30fc7ed9789ae945c6cf6f7ea0b98b2ab05e501ac135da63fc4f807d8f90c2aa2813770ec02fc9", 16) - g22To143x1, _ := new(big.Int).SetString("19e2b88ba4a575cf96e15de0da3cd46dea2de5040b9ab2f02c9808701081189b4018b7546c455d69f4239faed0cf597", 16) - g22To143y0, _ := new(big.Int).SetString("123dc7944ad512afffd36ddc49cbaf03f4ec18d5bdba0fe13e8591eca3f813763851d33d0a0cc47db7dc994167fde6a", 16) - g22To143y1, _ := new(big.Int).SetString("108562a9fa3713d0a0b55639bcbb52deeed1b6cd08d868a4279db0177336eef65a3095e300b2ebcaa7d9b9d12ab0a1e", 16) - g22To144x0, _ := new(big.Int).SetString("225fce36cbbfedd78f1351a0c016f531fb61a849baeaadb56b2add9846564e26d2457f8916fae2ff08e8188606cff3", 16) - g22To144x1, _ := new(big.Int).SetString("4e2e3fd4ad10d25a0b78b798b521578fdadea0d05d3befd068c4a6201e4919b8a372b90a95640b46562730d7e0fdc5", 16) - g22To144y0, _ := new(big.Int).SetString("180af5fa0899a03733ff535415dc34898bcb7cb59b034788ae6047b8858f7436c2255a79c48234c5fea9f2874694de2", 16) - g22To144y1, _ := new(big.Int).SetString("1830600f6c6655b6ea2a261e1fb63ce8b5bfb418140f04144eb3fa5146f3edf29314b05582af1fd1a14365f5ea7ba49", 16) - g22To145x0, _ := new(big.Int).SetString("db5d4750c58e860fcf92ff53bf2259232d083c57affcbd50fc5938388ed90ed5e787dd8f1c900daa83500f93763cb7", 16) - g22To145x1, _ := new(big.Int).SetString("1bf14d05ac48621c7e1ad6d8a361ccfe9df60cac3478dcae920a25c9be9b60ac35ae1d95676b47bc18d56305101bd4", 16) - g22To145y0, _ := new(big.Int).SetString("11a0eadadc176b6648db052a60a057417f5f3998e13883dbca5a86ed3b8ca0e78678f406277623f018b697c0967cbf6", 16) - g22To145y1, _ := new(big.Int).SetString("242f0719dfbed734ff3d0fa0ac56ce3c1cfd05a5421127de1aa63471b18208699af6deb6bbcb87cfd0d9a931c4d61a", 16) - g22To146x0, _ := new(big.Int).SetString("a778740a1f0e65e4aef6c1243d4885213afb5dc1a5b9ea4667ace7a888bd65542af9f942428a9d3bfaa353f401c71a", 16) - g22To146x1, _ := new(big.Int).SetString("e6073d07b9eab1770a096a6dac8d2d9eb78c8d0d484e2098746a1a1549d5bb28a5e6acd8594b0ab802e675bbe093c6", 16) - g22To146y0, _ := new(big.Int).SetString("1045bb84ae65dca6c2bec79946262e6aa1c30f53171b30ae4cfea3851e8db45b278e1b688c461578164ac1e19a8deb6", 16) - g22To146y1, _ := new(big.Int).SetString("928a0d8347ec975f0a1f9d6a207f490bcd049a13f904dc55ce9df39d134e264d499bc05535f482d2037d71eb6feebf", 16) - g22To147x0, _ := new(big.Int).SetString("1306b2126bd4b97747d684a0de877307bdc33feddbb6c02c76c2dfc214b6e3668190d3e6fbcf8202a0348ffee5ef989", 16) - g22To147x1, _ := new(big.Int).SetString("852e78e1a2c9f842e69e246a951241ab6e63cbac75d6bb92354bf6926dcafb215222daa81172febd8bc23ac5716917", 16) - g22To147y0, _ := new(big.Int).SetString("22864c20b7fbc59ae01af7fa71def57d8fe63654a710a3188567522fa9b01f753df3c5c8fe291a60e937314c51cb12", 16) - g22To147y1, _ := new(big.Int).SetString("5aa3763b34c307f5b9d390b6fdeb414157973c024f08ff9ec0e7629e7797a8029ff344f8877e4728d95b6ab1e12c5f", 16) - g22To148x0, _ := new(big.Int).SetString("178bbfa6d69a3dfb3128c5fd3ee756ae7b20ea60b559123aa24b7a3609dddf04a6064347328ec03910a2d024c574b9f", 16) - g22To148x1, _ := new(big.Int).SetString("19175dc69cf894648e8f5b311941f618578707a6d567989ebf4d9807e5028243b40cbaa8e8a92afe0dc7de2a6fbd98a", 16) - g22To148y0, _ := new(big.Int).SetString("dceda675a2422440c838a990290ac7e632fb28372dd4ae8336d0663db7a8fd91dea772c3d80b1c1e018818333a22de", 16) - g22To148y1, _ := new(big.Int).SetString("17cafb1b930c763224262b6fd63a12cd5df5473438cf8a4cfeba55cf790a4ddb5212b7f8d40729b33691165009cc28a", 16) - g22To149x0, _ := new(big.Int).SetString("18593f92cc3092ccc64dcd9a18f0a5fa87a6886cabadbadfaf53d23dccd3ed6926d21c36068f2e6faa826fcd2be3c92", 16) - g22To149x1, _ := new(big.Int).SetString("16a1b31a52b66bbe74fb45aff847726bab0c7d56672483f1843878990ae11fe10a1742dbf02ce1a9637517f043e2955", 16) - g22To149y0, _ := new(big.Int).SetString("46145d8e6a8b9dfd48bfc60601c5d5234b1dde952f5c76abd2ce13b18fe25fa3c5e559cfb3520dd95339aab7a18d51", 16) - g22To149y1, _ := new(big.Int).SetString("92234fa5281c1b677374f2fb6e9164a38ed394fe0361f133cc4e572740a7da287f6968dfb515345eeeb7335c195dab", 16) - g22To150x0, _ := new(big.Int).SetString("fb40d932a721efae5d100d179b4c3c57239d4a2856d1755088eaae138d23c310334aabc438fb3294393d793f596b97", 16) - g22To150x1, _ := new(big.Int).SetString("1a433a2ff230a12d858ce2a0d392526bc61fdc47ad830cfc3245583249d9c95e6da834ccb0888b2350586ded9450ebd", 16) - g22To150y0, _ := new(big.Int).SetString("4825df67dbee5607d31d4c3382b32995b1bd6f6f296c898b9cef80f216c8d76a889e93291f06ea5d0851f0be67635c", 16) - g22To150y1, _ := new(big.Int).SetString("899ea93468eaf190e1e235648aff5a51d02f1d9eb387c8498ae1207d58211eb43bf56df2a62341a844ab8cacab796d", 16) - g22To151x0, _ := new(big.Int).SetString("7d766177ae55cab993416a97b47a9442478f185f0c8854aaab63355f628e1ffe0277daef2e9d6df3332d72f275f27f", 16) - g22To151x1, _ := new(big.Int).SetString("13922ae44179c6e950ba65d5e8670ceb367d7811e8e54b209d2688273f605b2273844fd57a8fa1f9208d0b70686a3c2", 16) - g22To151y0, _ := new(big.Int).SetString("10814f00e74e65669c7319f9294abdf44176d79ca76a754f7dd4ea6918a91aad78ab70d91e9eee84a208f6ccdaf9ec7", 16) - g22To151y1, _ := new(big.Int).SetString("b9cba49ef4a54df69715a7bf3dcbf4c14b58effadaadd6e896c2d4155ae1cdbeeac5b0dbfc0aa645ac0c17b8f6397d", 16) - g22To152x0, _ := new(big.Int).SetString("195873c205b8a396c90d3dbad1d658ddae06605bc03e548b5d58bc153590be282c332c62becf35647a44cb4735b4c87", 16) - g22To152x1, _ := new(big.Int).SetString("638213aabdf9f718923bdfd4db762bec7656c7bf8c730db21f277a1df6cd7ee01021481d24bcca8858dcdd48dfc7e2", 16) - g22To152y0, _ := new(big.Int).SetString("4487fedf3c4a3bade73f0ca2563dd6619a2aad7c1d57f266056ee9e3200b6be7dbd6e294c37b17e6ee96e38442b6f3", 16) - g22To152y1, _ := new(big.Int).SetString("10533d60757b534d1cc4cb03327068db40e728fa382a55ba5160bb1bca12228a710caacad72829ff1bbf28d42028357", 16) - g22To153x0, _ := new(big.Int).SetString("112aef81303fae5eb3b56d5d00ca9bfa73140ce05e6a0cefaefe6771c43c13ec566e77e48f5b8bff59be0370cbe226c", 16) - g22To153x1, _ := new(big.Int).SetString("12111b116a0dee480d483f0e36eb6dc5f2c1b3e052100f2838fddc7d52f55295be7cb6bb720f12e980e5bc81afd37eb", 16) - g22To153y0, _ := new(big.Int).SetString("3860ffe6a37e209d510f8f1a50a0f4aedbc05d6c7a8c39ff9abc10f570353f4b1b2bee6ad1baebae3653cb703e27ec", 16) - g22To153y1, _ := new(big.Int).SetString("1446ea61d416fbbd24a000284667dae8c03893affa5b13c0481be65c5ae59679ea5bfd659cf410e281971c2cdb97241", 16) - g22To154x0, _ := new(big.Int).SetString("18e6e06754a969226c043399f1f432dcc1fca211d9607f7a073545640f92ce7fa444be2bf2085d6a728bd3a33528f15", 16) - g22To154x1, _ := new(big.Int).SetString("13290121536ccdd158ac44fd4f49f6f236c1223a3ce7b27d4f8f8b48d7465b26499df351aa362fbb0c300de7c1fa0a8", 16) - g22To154y0, _ := new(big.Int).SetString("174ff5b2ab9e104c2407c05ee1f8c63877fb9191cf8d904db090f4fe21be3654cb1b7c57c42f312e2b3388d20bd489d", 16) - g22To154y1, _ := new(big.Int).SetString("e8d4efa9025ddd3ae8c631c7f92d4904b30836d41c18168834215a32cbe21489568967a798f3d21cc4bfa367627aae", 16) - g22To155x0, _ := new(big.Int).SetString("9724b55a8f7dbf0f4b2bcd140bf6d2e0f289258ac2a9f70a6c99eda60259d307be9d490761739ed46b0e944c63a548", 16) - g22To155x1, _ := new(big.Int).SetString("181c9cde6698345306d01fa15c9aa1728633ffa3df07d7fb1420ec20f002f7a769b9b50f0402913b0aa158a846ec6ea", 16) - g22To155y0, _ := new(big.Int).SetString("19cd573e8f7ef75da1fed08569009881edc9a68c56b5ab259b33006fcec80eb3754015bdf2170b7cf9e49f84cd38241", 16) - g22To155y1, _ := new(big.Int).SetString("64bb6849f998e14ada755ea499fd6e3cbc56a2762f69dc496657a46139950e1a0b294748624bdae01a38cd60680209", 16) - g22To156x0, _ := new(big.Int).SetString("934c42747f0d7e7ef78c9932d1c51e9ee1e12512878acbb5cbb8d654cdf04bda3f602ff39b62b41568d4f4d3ff1175", 16) - g22To156x1, _ := new(big.Int).SetString("2143667f4949d68db340fcfd57d1ab5e30deb6bdab32f090b916dc852d436e1bb971653ffb2ca8c22a4f10966823dd", 16) - g22To156y0, _ := new(big.Int).SetString("5f4d7973803baf12c827ec3bc006f512b019c6a031601ba773550fd605a1a97bf891967061699567f932ce5ebba372", 16) - g22To156y1, _ := new(big.Int).SetString("6cde56ce6019fb89fc5890600e036d0edfa2e084127674d0086e4e6b7084e97ea7bec79a6ba9980b03df3fec699ff3", 16) - g22To157x0, _ := new(big.Int).SetString("1a417ca4ee5b2d3f3a18d65497ecd1f15ee36e3b1da7d5fa7fde67d979e5455817d6b1ed756ed0b7be36623a422cd6b", 16) - g22To157x1, _ := new(big.Int).SetString("f06da39347fd3c2ec06b145041f2973789d7b52c88d8131f438f11397b51894f654605f1a4506f945ad8fca7b4a922", 16) - g22To157y0, _ := new(big.Int).SetString("bdd621509a691aec4b88044d71da5a2091b3f35b12ba6e23bfac872b9988e1d304f61ed5891ea59b9ca9754a1413a7", 16) - g22To157y1, _ := new(big.Int).SetString("65da5d15ffad537798719b8896aae8c5cb5b73887b4b3a1c8045c719e9034f4ae3ce427b9dea491f7cc30a73b97429", 16) - g22To158x0, _ := new(big.Int).SetString("b7245118a4ba4031057e9488e71260ee2cc38740e64ac8e8e45a62d47af26f29b63eff27deb4c2bb17e5d0e0c28884", 16) - g22To158x1, _ := new(big.Int).SetString("426dbb2cb5ea9893c5a36aa60f31997665c9d25fd986a3e3ad803011edfe830d391d5c0a06771c2cc438250d3b68b1", 16) - g22To158y0, _ := new(big.Int).SetString("186025585358b83c1c9aecb8fe47cf89715c08060346c71ff5067eec6d26719ebe934668ed9781dd79060b33b92606f", 16) - g22To158y1, _ := new(big.Int).SetString("152abe45db68965e5afd15a4edf76bd95cab91ba0190d2e4f8193f856e8ca15b62e586190352d4ece067b1225a53c7a", 16) - g22To159x0, _ := new(big.Int).SetString("1122bc0cc4ba4d7a49d71e84953dff86707a5fbf90cfcd4ee8d18e7da07e9a36c0c84efa94090ecad17de759add0cd8", 16) - g22To159x1, _ := new(big.Int).SetString("b793bab0a7a988065e9cef52a8894b86be64a81acb6d839778c334b896e2e0522a579876ddf5401623fd653eccaa78", 16) - g22To159y0, _ := new(big.Int).SetString("b11d9b881d07a4791f6aaa5db8eca850534d07f8ad344e89c014d06778f458551edfd80b809c7a1c6437dcd9e13022", 16) - g22To159y1, _ := new(big.Int).SetString("ebeabaf4521eea82a43001e254ff86a6250baa0925514955b834a95d95a14f4805217e24c90468f3ddd3ea5ca2f0c3", 16) - g22To160x0, _ := new(big.Int).SetString("34cdc4cb85c787da7c14412f557001e97aa8af9287271293bb53c6a073257fa2fb960bde862b131abda93a62f2cd42", 16) - g22To160x1, _ := new(big.Int).SetString("9b1869faa8e967f52d5014719e091a6449fd0f16da434fda3c8e1c0f664036f5269a3dfbcd955afce3f4786399f93b", 16) - g22To160y0, _ := new(big.Int).SetString("105127b44fcd4b6372954f549f3c5c74270cee4ba94e361e4621e3265a85827cb4f583212cf934e0300681aa23ebf40", 16) - g22To160y1, _ := new(big.Int).SetString("12dfdf5375c3f091604909824e1892ff4f6a8980ece75d2ad0afa7325992ab2cada983bb6f585a1b6947c4b09729539", 16) - g22To161x0, _ := new(big.Int).SetString("1b801ad1026fcdb81e265cc4f191f164bbafaaafc7c91b1c6d7fd5e9ec92b370b3306e48202f282446ce68f4b67687", 16) - g22To161x1, _ := new(big.Int).SetString("12964087b8ddd4bf68725b59f9fd12e835483c8456f7254d6232de8111c40fe22e985ead67d0a41e94b9429aa907805", 16) - g22To161y0, _ := new(big.Int).SetString("3d28e1871209df32609e8786b9e414f757bce8d8da35556cead21a32e00d60ba60d6de0578ee30921070237e9b2e72", 16) - g22To161y1, _ := new(big.Int).SetString("48a22d8116418a5cde329de2ee7603cb5a38efbdad5a64f471595241566bd9ebe3b786aa6bcf9debcb5a2b5b4d4515", 16) - g22To162x0, _ := new(big.Int).SetString("14785f244b218b8ed9f26173527e3e1dc4c36b312b2fee5fcdc9486189c1d971128ee937f0a1dc1485f7366708500b", 16) - g22To162x1, _ := new(big.Int).SetString("11c239e8ab8999138c5ab032dc83a14859d7160713fa2a9df137e18f559f343e2c6951cbfdd1b70cebeb1784bb95565", 16) - g22To162y0, _ := new(big.Int).SetString("13c21f6786fc95b72d4053edf1a4f38c2a323c6a2fd0c934d987f776a6f3366e364b57cf6e63306b3a83ea81a516e41", 16) - g22To162y1, _ := new(big.Int).SetString("b70c814f6220b6fdc1bea846efae250764ca457bf0af4c9252bc5011182f50e71a2d5e5d4353d33416b72f7b45b7af", 16) - g22To163x0, _ := new(big.Int).SetString("1268de52d553be697456965d840b9649539d26824f18c0a7752921ddfed39d44d3335e11493d7a95896515a9cdce6f9", 16) - g22To163x1, _ := new(big.Int).SetString("734c630cf3113a798cbe0a5956c011f0f03c98f8d2b986b25f1461acebdd65b6beb34be8dfad9bdb44acc88a82d661", 16) - g22To163y0, _ := new(big.Int).SetString("d515acad3ca797950762ee9fc03a379cca20e9eb9efe9e7534e4c6feeb20677d8447876ddba2a3b72ce962b18cbae", 16) - g22To163y1, _ := new(big.Int).SetString("3c06d1b83753e622ddced8b989469c3b0db7d438b9ef86f132843b19402b7da1d2ebab68af7a7748feda43e9c1d5d", 16) - g22To164x0, _ := new(big.Int).SetString("ab426d03d781675f341bfb0342cc1f365803cecf7b77a5bd035853123dd75c84e4121fafa20251dbc4e457700066a2", 16) - g22To164x1, _ := new(big.Int).SetString("fe73fc1d54259bf0105ed62ff51c77b7776149096ff738597054d958e53452843ed873de67aec0b7bb0d0cf6f99fc6", 16) - g22To164y0, _ := new(big.Int).SetString("11e62abd5c1fe8b96d8c7c43bfcf73cc25a0a360fc22e06019fb76e2aff6100641ac69a6a0445ca9111ebe926a8c0c2", 16) - g22To164y1, _ := new(big.Int).SetString("2ab563980bd58b949d10444421cd7f824515bc7c9fb10b4060baed61f8d49b2e20dbd5777f8141c0d0875bf58909d5", 16) - g22To165x0, _ := new(big.Int).SetString("18d88751787c71464c380f49a7b446737876cdf9ec99b05f07dac65cc3461400f7e0626eb8d5868e73e0119b49c4f93", 16) - g22To165x1, _ := new(big.Int).SetString("2eba1511fbf969d719f5f90ad90437ea51b421603d872b5fe8bec93f8c6cefdf6b0359808477ca8cd8c14917b68f45", 16) - g22To165y0, _ := new(big.Int).SetString("197b4019bc9a9904030b80577d3f876f9338933a605ee8dc38f38684ccbe310c71c479e52f5b6491370b7c6d48440a5", 16) - g22To165y1, _ := new(big.Int).SetString("1250dd1975c4ce2a0ca8696f553228a8f0bc5ec835ac7ba4a246aa708c75457e7298330b038593f40db2c9912d2af5c", 16) - g22To166x0, _ := new(big.Int).SetString("e4e95116c9f67d0cca628ce0bcba3bbb4db3c19fa87faae79ee6fbeec5e5916117f7127af9fb0f29cc3ca92d03ad68", 16) - g22To166x1, _ := new(big.Int).SetString("ca43ef715bab239563c30c85d2e2e255d1bf4adac0a0976fef3c90bc0dadd4eb32477feca71c461a9805689e0c8edd", 16) - g22To166y0, _ := new(big.Int).SetString("b4d83664ba7d8a4230a1010eac05d6c6cc7efc1a87313bc3182ae33b83ab712fc0ee6b761144e58321cee48fdb11d7", 16) - g22To166y1, _ := new(big.Int).SetString("1783452da9e728d9d626ebf1067c114b449d9c5b6f2a8d321bed4c5bb065cf8db40166863b77918f71bfabf1022d068", 16) - g22To167x0, _ := new(big.Int).SetString("1785343b8d3c90ea256d119f46afe79f973baa0cb38582cf349e62e2b3a971b152c8c910a643251bfeb0d7d30500d28", 16) - g22To167x1, _ := new(big.Int).SetString("b03095ee270dcf95a80e40dbbcab03aabe005784a6c1d4af7bced134aecdd013c89ecf6af45f0ec1a9b0a4faab695e", 16) - g22To167y0, _ := new(big.Int).SetString("b775b2198362285d659b9ffc47c71afefd7c134c0b1a186686b26297f148185cf2a17b2efd6cdf695e773a28caabd8", 16) - g22To167y1, _ := new(big.Int).SetString("194a0fe85e939d4b9ea621b20661ac493666c1cd7103cec77464d376482e0d9e0577e4ba1991393c91e6081b7616cb4", 16) - g22To168x0, _ := new(big.Int).SetString("13d57818a8d575d0d26112819ef30240da84ea0760235cb1c2645be7db84eca73b1b3e1cb6821749091ca33629868fd", 16) - g22To168x1, _ := new(big.Int).SetString("7e9f1f023be3f7ffbcb807c5edb89d0d00ae87a67636e522d98df751ba0122a2c27a71fbccc2ac37091bed1b6d13b6", 16) - g22To168y0, _ := new(big.Int).SetString("e81ee2d6b656b930924cddc1efc437490c45b8bd56062a01c26f1619aab49614f5313841410df24a64ee7d8936574", 16) - g22To168y1, _ := new(big.Int).SetString("e2463afa2f0436f9ce3390a7031bc4acccccf05638741c1b9dfe7d5a6b57ca4df8483229eb23d96560d7f0c1e376c5", 16) - g22To169x0, _ := new(big.Int).SetString("a660477fa15e554af2e6b41cc221edd322f86a803589ccfeed0a0aec7eaed827632d69750bdee6325a79bcc8cdeaef", 16) - g22To169x1, _ := new(big.Int).SetString("29943ba93103da145a33598da393f26161e257b7709b263735d07210450b4dae347badc66ddcbc6319d7ea10b20d78", 16) - g22To169y0, _ := new(big.Int).SetString("16578637825c5641ad7816f20532d6b9456e6e20a8d5f9ae2dd8228b2d363a881de7e5a17bd661a96e8bcea73695ec0", 16) - g22To169y1, _ := new(big.Int).SetString("eb9fa9b2ff1a54768463a3543ad3cab025b848ce347092785437c32f89462ce442e74e961c3178f57ffd615e707229", 16) - g22To170x0, _ := new(big.Int).SetString("964429f4cfd4c044380c9c7a285beb866c85143367d701684f5622f3ac0794a223c050d738b1819419b07ee840ed34", 16) - g22To170x1, _ := new(big.Int).SetString("9db142c0c482a63de55c2b37d424b82f8596f50f7da5951d2c24431419c8bc64bb8ec79fa071484825088795eb1e27", 16) - g22To170y0, _ := new(big.Int).SetString("de17ef78c59372003f8331f1b732413d8a8ef29a669b9d1d00b401af62dd38f88ada21cd53d06b247b450f084ca810", 16) - g22To170y1, _ := new(big.Int).SetString("11372e56e2e33c10cb73480f5fc5c0b4d8e000ec4b6cd2053755a5e82edfc3e2d702574d68cf08911c8398f4ab2efc8", 16) - g22To171x0, _ := new(big.Int).SetString("6ab88dc7b0408be4fb2f7f3fd3df811ce763d3086bda785d652c0dd26bd68f35fcbc17e1538022ac3f0e8b664617fa", 16) - g22To171x1, _ := new(big.Int).SetString("14b21a03a57b940e1d5d1739af80f8b8a9270ab99fe31d5bf81563d74d6190dbcded1dfa064e3040df5d45401a0dbf", 16) - g22To171y0, _ := new(big.Int).SetString("14a7f24155c15ff39bfcc5a7f358c9530e770747f6019773d92bac2df69a51e792d10ba8518bf3e9e6cf6f58349f3a2", 16) - g22To171y1, _ := new(big.Int).SetString("151c1f726ac3768af1981153cd913dbae40721029a517dd9a0765ccbd724c269d7235749caacd9ba8070241fb285feb", 16) - g22To172x0, _ := new(big.Int).SetString("12efd6c2f6911aee3d21d8fa488b605347c41125fe68829262b00247d74e84f06ccb597bee1d921911211e593df0450", 16) - g22To172x1, _ := new(big.Int).SetString("6255edac9111a1e7074c4cfbd8102072b5a9ac55b83af683d85abf2ad60bb4d0a6f9f3a5d16b3acae502f541cc99b9", 16) - g22To172y0, _ := new(big.Int).SetString("5b213cafb5c6c7c34a28b0c6ab235d7de110ddea1f917741f56072754f800855ad5a059c144dc850e94723468f2130", 16) - g22To172y1, _ := new(big.Int).SetString("46eb29842f0444847a3de13da0b2e75765504e3dfc0b77c3e7b068755a0c0ed0963d9adad93b42178e98a38a23a5e2", 16) - g22To173x0, _ := new(big.Int).SetString("3814ec251b7b79f1e70f064ff139b0c27b808972a2fd740b03e8332577cc789906b9935609f4f73b3daf96bd87acdd", 16) - g22To173x1, _ := new(big.Int).SetString("26a23046751895915b52ede7c9f21a423c2b5eaa30d948b56f98fcf8dbd241e6e978b055c1b7a19605c709976d3086", 16) - g22To173y0, _ := new(big.Int).SetString("7129e3ba7668ae67910718320388b23c5132fb6954b4cdbeb83d3a9362dc35771d1229690336c8162392800b0d023c", 16) - g22To173y1, _ := new(big.Int).SetString("1352ee185e0a3d76d1edf9fb77385d1330fb619cb986091c271b47443d47962116ee62cf43d7255a9f532c8c36f45a3", 16) - g22To174x0, _ := new(big.Int).SetString("191581ab909f78c8564732d07db80a5d64e75915f4ef218362870ee353cc9e2166e6535ea8b3551a2a25a294f475ccf", 16) - g22To174x1, _ := new(big.Int).SetString("1083861af27e47601f66688173f994cf1f2c2a0941150f7786ecae4055aa383c954892829206ebe949b30d16641cca5", 16) - g22To174y0, _ := new(big.Int).SetString("150cf58ab9072e91391513d8417703bd1d57daaed70a2b7f9a2607efa5731b529ecee031e7a10338b4415d755732c13", 16) - g22To174y1, _ := new(big.Int).SetString("19c6ebb093c4c1fdd3ea83dab59e32e2f65c494a0d07637212cb2fba70eba9020598f6d7c539c0762f4482199bf257d", 16) - g22To175x0, _ := new(big.Int).SetString("3c8b331eeccd65e4e28efde4779237f919acbb4dad26a1719d6097b8a4e0ed0db0692e2e6796e36671d750ee8f35d4", 16) - g22To175x1, _ := new(big.Int).SetString("1670e9256ec07bb6df7921a9f09b7f3be1c5ae107565988a2dd66e5f8856d6b3e6f43f9db3fd0b6adb327e892daf22f", 16) - g22To175y0, _ := new(big.Int).SetString("1065e362ed88dd61b9c6197c2d8aa21c4eb29e784d5e5196ecc98fc1b9037963d6c7efd7b3eca906d77af1f9a240b0", 16) - g22To175y1, _ := new(big.Int).SetString("149453bedf02098828820834fe7fdb0112c6e5f40b495c4dd794153077a67577d183d91c452e017d3e29f7e5bad8203", 16) - g22To176x0, _ := new(big.Int).SetString("3d8494dfe4b6a0b2c0a2ae7afb0209e57550b2ad841dc1ff12d4b1e040661083a9c7e8272143ea13ee6265ad05c55d", 16) - g22To176x1, _ := new(big.Int).SetString("14b51e710b10b0c8579eb1cea3b3ebb9d9952198c31b7a985614943323110813f7cf038cda7fb75cee1cfee37498110", 16) - g22To176y0, _ := new(big.Int).SetString("ac65b6b7b11c15aa71ebef8b7eded583ae3da5b9b7c3ca1fd27d3d435bb3e63e97eae24f3e54e288222c98e3a6d148", 16) - g22To176y1, _ := new(big.Int).SetString("14796638f84710cb87d1ab2a59627ec217c1f01ef87dab0d5e000d608fef957386d83bf5648d96747f8a2a949fd0a8d", 16) - g22To177x0, _ := new(big.Int).SetString("161ea981379a6afca65a93ba3a4daf23ffd0446e96acc7ecc1aeba00a0a74524935b75de10de14ed40207f3a6f6b954", 16) - g22To177x1, _ := new(big.Int).SetString("a5f8c35b788bd6f5ceff4ac6e45f32bde0e6184dc049537da188800e6cf6ffccae73235e55b8f40c97e01366d5ac38", 16) - g22To177y0, _ := new(big.Int).SetString("12ded1c786e998099bae2681b841801245b253010102d06cafc13ce60db2ddb8cc6875a1ed1a7b43f4eec3a7f3e636f", 16) - g22To177y1, _ := new(big.Int).SetString("611263b6649d86793ffb0bc7f5d3d5dddd95c285e99cfd27f30803d0bdff388ff4cf65e7ced280c19b5cdd4a1404d3", 16) - g22To178x0, _ := new(big.Int).SetString("10f8e43f38286b18461d07793eb04a35aa44a68c7f01122af1f9ed7ffaf7d3c2955f2ff46c755d19a2499392b0c1976", 16) - g22To178x1, _ := new(big.Int).SetString("ec440608db7429a9a8d22c4c52db6ab8bbdfa0effd5ce1766872919cb9fc116bc0f228c51364689ba6d8116df5c7c2", 16) - g22To178y0, _ := new(big.Int).SetString("47ab8f5a9e4d0632548f4ff5c545a178ebf35ff2903432e3f0c89450dffdaa268323bc50d8665406831327765353e0", 16) - g22To178y1, _ := new(big.Int).SetString("9256c5e29f1efa3ecc4755fa80e5be91b9921a30732ee911ffee2f88c12757453358b93a8e4ec8ed8437c28d9623a5", 16) - g22To179x0, _ := new(big.Int).SetString("3cb62eb22b3539f4c4b936f6ca48ad922879be90406618f462a24d81ccd398f8251feedbf3d566492a4fde1036ad5", 16) - g22To179x1, _ := new(big.Int).SetString("d8f0a91e62d1e81ab2e885ea64d5e8b459381850aa7322e78cf90897d43cc82d150dc16e09be130d9f891fa401cba8", 16) - g22To179y0, _ := new(big.Int).SetString("1418b1e6a76eb7661359ffa07a4853286c8e704b579bb90928dcc520f100a6b7a10dbce333ed65f278a389c1460b0ab", 16) - g22To179y1, _ := new(big.Int).SetString("15d56c73bcfa1ff5ee36a5f7d3aa2f8f9963b85f8190317bddc0dd2eaf599d0533697c7a7ce85cf14f605dcf40d8e10", 16) - g22To180x0, _ := new(big.Int).SetString("162d941ebdad5e4b76f11e7cf6ce152c5f218ed9500f99e25d2e3813177d53c80150d377028593000d3a7b088507cf", 16) - g22To180x1, _ := new(big.Int).SetString("19a054614381d2c5a64780aaab6bdf93bca7995752813a92419ee5c99f4065f4205bf0204b48cd91db006b4ba795ce7", 16) - g22To180y0, _ := new(big.Int).SetString("7c80715d6e78ca83584728739e276deb8e4095ac8ec8a969c230c273bf53b505942e6a27e8be98f3d7d42a6975cba4", 16) - g22To180y1, _ := new(big.Int).SetString("11e57634d82e5e15ee91501e88daec71a9aa859dffffb517b5d089404799022ec87b03e4f4c2f4893d831d97f56782b", 16) - g22To181x0, _ := new(big.Int).SetString("e8924bdb603f0698717cc1a1cc609fb239f084829d8111e69793bc4135f450f03705426a1c79cfd1bde27a706abd18", 16) - g22To181x1, _ := new(big.Int).SetString("1855031de3a0ee38255aa2ef851579cae1c28de22118659a51f19aa34390e108efde00ba29c74f39696eb6ba87d647f", 16) - g22To181y0, _ := new(big.Int).SetString("60cf4b043da7ee813d0133ce50cc7d7fc474ec7a3ee6872356a7ec3213136bbdc68c82c74174b319c6013652579caa", 16) - g22To181y1, _ := new(big.Int).SetString("13a362ccf8e31afb614dfeca85b929a7e92b0ebf4916373255d6add81f7408c23b39d5ccdc0351a64f464b7a1c26d92", 16) - g22To182x0, _ := new(big.Int).SetString("16c865109bada2d39410992462c0018fb339e3003b48129866b539db10476dfd5605da6f5b7c87c718526d23e9a9c58", 16) - g22To182x1, _ := new(big.Int).SetString("b1ec4e33168476362c95600845b12b64a188a2d867c2769b85c1cc1b4006f5082bef453b0266875a26e6259186d9fc", 16) - g22To182y0, _ := new(big.Int).SetString("54f4f301628ca2e66517afecc925d04c7c74cc086aec0394b01aae096179018ba9df43cec90574dcbc3f527f638408", 16) - g22To182y1, _ := new(big.Int).SetString("490838e264f89b1226916b1d7f929b43b009059d539116014ae9f31182f350283ba2f1cc7cfe31399b0cacc719a566", 16) - g22To183x0, _ := new(big.Int).SetString("16c41d43990fd3d34ba8c3f23f23af26444aef9f963aaf19d3cea7546487189febda6f22feda351a79e5aa9e58185d0", 16) - g22To183x1, _ := new(big.Int).SetString("96eeb12f356f1b2a5602ee1f72c19448e4551f4c0492fc86b939e741a12b976eb91fa3355b5e48ddd292e411c18ffd", 16) - g22To183y0, _ := new(big.Int).SetString("af2980eddaab0c34a5bd64b4d677748ae56356880cefde773b8ed82ad4d45f839dd04026455b53dc55f317ca8c1842", 16) - g22To183y1, _ := new(big.Int).SetString("a16bbd8b7b66293813e3d1f1327559e9bed4407a02c57d956cea5ad3ceacaaa92536fa0b123d752dc2324091d284af", 16) - g22To184x0, _ := new(big.Int).SetString("177e123409a926662dbb1597a8289a94a5f57d6d6a3d02ef895e8b22ed3b82fd6585f263857fa14d2a4dd6c6f6a2d3b", 16) - g22To184x1, _ := new(big.Int).SetString("174d2b0b4dd659ade185d68db78bc92c3ac92636586e8ddd759944f5ed7dd81ff5bf8309b9360e569a505028773be24", 16) - g22To184y0, _ := new(big.Int).SetString("ced151199bd6562922d7802531a53ae04f721d19362a421ede53e5e0d9b9c6dc7e2ac306764e053d98eaa8f4fac7ef", 16) - g22To184y1, _ := new(big.Int).SetString("19a5ddd6b518b0c6c5168afe24612acdfad1912da50027bdf6a30df292d5dcc74bbaf73ab560317bd68c3e325e59205", 16) - g22To185x0, _ := new(big.Int).SetString("c43f38e341a9fbf94dcbe89e11fabf3d63e50bf48b32ceea64801e3e2adf0a32ae0dd9deac34158a6387d6f6103329", 16) - g22To185x1, _ := new(big.Int).SetString("9227c18ba33206a6dfb7c6a1ef2a1dd8589565649143f371bff6829beb072ba09fe1cb1c86fbf8e0cf8106b4dfb171", 16) - g22To185y0, _ := new(big.Int).SetString("175defc61f1c9f27d12f56770fe1381961f867749223765108dc80426079a5d5737161b8153653b7a3f17264f16e0af", 16) - g22To185y1, _ := new(big.Int).SetString("7cc92c44849b5c3c819d9abce5d93f7e32b8028fa061d59b4477dda5919157cb6a3af81b39de6e381017c1d9f6802e", 16) - g22To186x0, _ := new(big.Int).SetString("1d0b14a712e20c2dabea0c6713fec6eb7e5620961eac79c37e3af948d00d302250541f51da564bcb70b87f536f12dc", 16) - g22To186x1, _ := new(big.Int).SetString("155854c6c319992a201136c825474e74eb23b1cc77c0656912133125cafd7409f3a27485f72edc1f084c09f9b00c152", 16) - g22To186y0, _ := new(big.Int).SetString("19eada35bd6b5c4c2173c017e99f2fbfad0d45423800d35448e47bf66b9855c2ff137c2b8c37d9f9af11f8b61b9bfe9", 16) - g22To186y1, _ := new(big.Int).SetString("153fbc4db6232ced58e8c0157b98acdccdd2e4e244d249c380db6c49bd2976f4453fa37f3dc479c11651fd031dc2141", 16) - g22To187x0, _ := new(big.Int).SetString("82a47c2d4814cc657f2af54a1393fbd8a662e5c245f7f30d822615978b05b20f6f08baef524fe08e9c3adc4d599d22", 16) - g22To187x1, _ := new(big.Int).SetString("ad6ef72085678215fe05ee6ce8666cb74674145953c934ca22a91691a625bd3a66484e275d055bfc1b61ca7b16aa16", 16) - g22To187y0, _ := new(big.Int).SetString("17ae5fbd82fada89872b3409fbe7a6e9410c8e3d134a11830e97dc41677c4775e06f87a528c945fd587c52c78255fed", 16) - g22To187y1, _ := new(big.Int).SetString("14fac643b226643cb21099fa596706a4096f5096af2b7883c9743665715a7cd3462cb7744c73e0efd0647c6bd0782b2", 16) - g22To188x0, _ := new(big.Int).SetString("12a1e00e666b0f5d26ebb82fc9fd58ebfb380f7d418bdc0db518c27c88571b156c4e50f1f579b4b09bd42a9d626ecc9", 16) - g22To188x1, _ := new(big.Int).SetString("15dea18b4e760631fd445e531798908f30780c840269e64445b9ed47c56858246e46d7b752efd953090f8f7c2507519", 16) - g22To188y0, _ := new(big.Int).SetString("164e4a7613d8404530158ad89e80143699cdfbdea58a61d341c611a92187257ced9fe355cb72b15f60ed06028042ec8", 16) - g22To188y1, _ := new(big.Int).SetString("13659364f1d7f033ec672ebab4398452cfee7cb0ed7597dd84167a6ee87257099b3fe39ae463c5a137017556fcdd21a", 16) - g22To189x0, _ := new(big.Int).SetString("bb7a545c75873f572bae79a8e7dec8011b6328b90f71821a77c4488ce7285c6894276d8ad64c06715d520828579464", 16) - g22To189x1, _ := new(big.Int).SetString("fa6238e908ce234a6cc8982bbb3bbc3c9f0f20db267d6bebc666761a03a14657c879a2a826a2cee7cade70d210426", 16) - g22To189y0, _ := new(big.Int).SetString("17c937fc9f0a0f35fd7f57cd5f19959ccd4a620f0b9926a096331b20db4406f3ae1f5199a2700bd3f902e3b195a65f0", 16) - g22To189y1, _ := new(big.Int).SetString("1a07b76a76d2791a83994a2362e75083f198629b7377696514151ad1ab7b00e0ab89e3d5b426e74751887d53b0027b3", 16) - g22To190x0, _ := new(big.Int).SetString("1061752353a1a4ed2967fc5bf4d6fcfc7cb11ce432f6e91fd1161aa7f873b37d40697297738d3e4acf1d20cc341eadf", 16) - g22To190x1, _ := new(big.Int).SetString("462ef0cf13510a6dff4e77120135f4620ae55cd3ae8171623e61833373197b347e1fc2556759b509a1828cea59b904", 16) - g22To190y0, _ := new(big.Int).SetString("1d699d18f4ae8c9ed8b9cc9b31b22cba2ea1d60b354166f3e2435a00991600fe837ae3efc88935214c877aa0ba4fcc", 16) - g22To190y1, _ := new(big.Int).SetString("e7cd74c48870cc438a08a5b526f951b26551c5e4f15d0ed7813283bb2bc5bcf8bb3f4b31c6fb7a0d9e52443f60018f", 16) - g22To191x0, _ := new(big.Int).SetString("176f7d137de6b389689628affd2b553c59c50eb5ba35cfbaf204cf1a9cefef3ef8385a3f3bf5bb00e2bb883b905cce8", 16) - g22To191x1, _ := new(big.Int).SetString("101a3ea411540c648ec08269a59743bd0ceaeef46eefadd3fd6af78695871d26e1c3d84e2ed36025e0743e34153f777", 16) - g22To191y0, _ := new(big.Int).SetString("10b2bc6f4f0fe34adf2addc89bfb25a6953d8255c836b15b2695e75acc928c80c2d2e3b73f57b28ad659959533fbb74", 16) - g22To191y1, _ := new(big.Int).SetString("5a78199d438e4e4fbb5c86c0f5929918c2d8cf7db522b103ce51c5c1a67f350fb6701946d5059b3ade69be1ba3ac75", 16) - g22To192x0, _ := new(big.Int).SetString("153558b37cb8f931ba7e4064529d424d994ee31338561340d20f1d5719cd70218ef666ab5174509e445a4a58ce7f13b", 16) - g22To192x1, _ := new(big.Int).SetString("69f3b76b5777c75ad357739f340dffc92385af60a8885a3aed3e3ad7964407bb4c21231e253ffffe5f502767cb48", 16) - g22To192y0, _ := new(big.Int).SetString("6ea050f302f35784f852191a6e2d81fdc44724c8f23b0532f89d6ad34f92e40ac9c878135322b69b5479ce62d65b1d", 16) - g22To192y1, _ := new(big.Int).SetString("bfaed965cbc9161c6035cabcf83111a3366a72235c0001049acec069ddc4b046e8ea464a512497bb9dafc3e73873fe", 16) - g22To193x0, _ := new(big.Int).SetString("77e9d758ecf3cfcd1f819b205c5743e580294a24b64fda64b7cf39bdb7224f2808039a0e711b85ed1d2f1104cfed5d", 16) - g22To193x1, _ := new(big.Int).SetString("15a37bccef73d05e789897b29ecb339d2ee7715a1fda7b7bbab1af9087b4df7788c1af72e0a2144e24780eb1df1868c", 16) - g22To193y0, _ := new(big.Int).SetString("afc88792d7c8af2e08375f1bb75b15ef00a88941ceea5be159138506d69e87a0dfa24e8984cbc82a0a29fb50ea99ec", 16) - g22To193y1, _ := new(big.Int).SetString("faaf1bce65d00c1e1d084b68adf8b903f38c21ae11551a60aabcc95b2287614df3fa1c7696e964d5477f898694da99", 16) - g22To194x0, _ := new(big.Int).SetString("156acbed69aac3eef3180485cc061d66000c51604ca8b712be5bc2674a45cef5937a509510d4a89910fd425793b743d", 16) - g22To194x1, _ := new(big.Int).SetString("eec5b89fe13ddba6e10aa81246643cd74a15a0e399c6e10fbfdb393ee28ef487cdab642820daf9b7c614460abe1e28", 16) - g22To194y0, _ := new(big.Int).SetString("e37062d03b1e305fd12c5bc7d5fddc20cdd2f64b00da3d0da04844f5e94cc1f1aac190fe8c91388d480b713496997c", 16) - g22To194y1, _ := new(big.Int).SetString("2029e5dea105184417f748170c9f4fedb613dc8f19636dbd03801629cf195bdc556f45ac00742d9cbd5675517d7d3b", 16) - g22To195x0, _ := new(big.Int).SetString("48c0cff908c19de347216fa7b7ea3b7988579a9dc8f180308226a0498ac7e8430b1287fac3d4c6120cc89df96681ec", 16) - g22To195x1, _ := new(big.Int).SetString("ead70a85053d30a2692c6181249e90515c1f61b98ea75a27eeabb5048c203a28058919c49aac7d1ac82cfac6db81e", 16) - g22To195y0, _ := new(big.Int).SetString("c612c93d06d53d4f15a06940554aa24aa74120c6045fc21442f73d68ffd0e5054a09c66229e77e8b4ce104535706ca", 16) - g22To195y1, _ := new(big.Int).SetString("117947328de124499f06bcbfa4bab52aa5b654a23471a1f0123ae5f3a3d600e5520d69deefcee0100e3ba42508a8784", 16) - g22To196x0, _ := new(big.Int).SetString("136bb1151504b58908928901ee1b122bfaf38d5458c2321ed849918ea312936da4be57348767c15143a515f41791431", 16) - g22To196x1, _ := new(big.Int).SetString("137ead55c1e232cb4d37376192c0f26f6d532fef24c13a4c42f81130e15efa864b825241cece715bb6e5d4489240ee3", 16) - g22To196y0, _ := new(big.Int).SetString("d83faffa108a1bb3dac1927e34c91ba7ee25eeac3fa16384dfaa907baef1fbd07c1c7886ed618f78a30b9553e0dbff", 16) - g22To196y1, _ := new(big.Int).SetString("2df77fd6250ee3ac5b276dfcef7d988b15dafb2d58702f4823befbbf434dc94f04f32be62b415b41443edd67b38f00", 16) - g22To197x0, _ := new(big.Int).SetString("177b8fff5b018fce944bdd0fdb05c50f56b883cac4d00b1165e81775ebae4392731addb19664282a083e802d9a05d04", 16) - g22To197x1, _ := new(big.Int).SetString("11ae7d925d111f31692ea118660651f948958d3294a4894da543814781b57f826bfebbf9c6e87303c8ae693c523b180", 16) - g22To197y0, _ := new(big.Int).SetString("18d6326b0c103c61909f340244ea7c5b8ef1bad5f216eb7849656181da2a1f57f558c92402833d44a497906cf3b8c15", 16) - g22To197y1, _ := new(big.Int).SetString("135c96c2568aad584c9f292e892ab7a152de779331f95652d8e29940d8f4a028aefb88b6e3f21006fa68f5d1a0fc567", 16) - g22To198x0, _ := new(big.Int).SetString("31c0e8da14145a4c9ba9a41a0ffd1197180517506a0593e60e92c4da5264638d9e3d3e3be42dac813f2c85a0ed2946", 16) - g22To198x1, _ := new(big.Int).SetString("1335a426519ff4cd9bc2c0e22b55958a61f4759395a206b3aceeabf37054a1d152a7b572353f374f8855425ef88dbb7", 16) - g22To198y0, _ := new(big.Int).SetString("ea5c383b2fdcd22089a0d5528a7966117a931a2ef54df7a723ad90e77844ea107f0167080828e8af146d5b389b245c", 16) - g22To198y1, _ := new(big.Int).SetString("864cdaf78cdd6d1806e0590b4d1a8fcbc5d391d4a0d6db17cfe9c7b272adf90904fc4d7131cb69863cb4b19dcca279", 16) - g22To199x0, _ := new(big.Int).SetString("eaf6ff91c8655d9ca6ef855568d730582855094b4532ebfd837c3f3f2b27af92d23f57fe2a3398132cba49a6ff5baf", 16) - g22To199x1, _ := new(big.Int).SetString("94669b0884fa8def9975c8d2ba4ada9a7e17b949b0446195b3129562b2ed5bf6dc33e93b6007fa3e18625e139793db", 16) - g22To199y0, _ := new(big.Int).SetString("b850a2a668d756e4e277ec1a5b124289ce9439832cf1dde56701660bccfc307453fd0c4cf57b9604eeb4b2fa0cbd3", 16) - g22To199y1, _ := new(big.Int).SetString("76128cc540b5194496af06b79be254c0335301980a8aacb330a3cd90bbfa5a350c06fdf742f3de055fef4158d2e389", 16) - g22To200x0, _ := new(big.Int).SetString("b113ceec83ff707b0693261d9ac074f97d23ded30d1e0f9bc9baf1bd962ca5ad2d3cf59290a5a5cbf6b9e8bada334b", 16) - g22To200x1, _ := new(big.Int).SetString("459cb96a51adc949db844c54ca3390d113a2e494b0d3fc712e22e21132a40948192e63483894fb3c8a2a40a7711746", 16) - g22To200y0, _ := new(big.Int).SetString("104a9851495bbdba65ad32abb29311898f27847d2b338f206b797855e7d2c10a3f36996f79936e9e4860e4dee596c40", 16) - g22To200y1, _ := new(big.Int).SetString("1a1ef4db81dda4ef6163109b09e4fa0dab796d4252e84b9c96f8e536fcf00b161508a59faf69084cbc9b5d67c3f21c", 16) - g22To201x0, _ := new(big.Int).SetString("198ab2694f6b2e0345d371476ad14a21646f21fec717bfd6a04dabe2f7a53b7582831e681295dea95c04cf73ffbaa07", 16) - g22To201x1, _ := new(big.Int).SetString("4063062d8e19103a82ec8703aafe1c5a7f3716db3f9b77d9ca2cf5c604b8883110191f5af9a034f45a3952f4fcddcb", 16) - g22To201y0, _ := new(big.Int).SetString("dd8d89c99a615ec5c8000549b84315eeeaaf4553902bf3c05c8f01b6d4dd98945b61c807fc03dd861d817cafbf1745", 16) - g22To201y1, _ := new(big.Int).SetString("6d9af1577122ea9c28281c4114305e0e206a52e738a454cdae6203a67a560b2b06ed21e2d2cfa84634197b4d6e709d", 16) - g22To202x0, _ := new(big.Int).SetString("9f80c9431f688a7715779dde5bc1beed5204ea40249660a678544ee75c0b0e188ae70f38d9947194f123e62ece8ebc", 16) - g22To202x1, _ := new(big.Int).SetString("9d2f3926446dfc91dc28dfc1ecf272e83bf1d616fe2b9e0d82e8e1fa9014ebb0fd66e8b1aa83820580e5608ae61a8f", 16) - g22To202y0, _ := new(big.Int).SetString("662e6756f4e627a61114c5836f14e80e295760e8132c8a6f94ab06b972d0b943facc90108fee75cfe375ecdffd37b", 16) - g22To202y1, _ := new(big.Int).SetString("4aed4448a94ee6c5972cd7c05595a079b52958473e347dffc65b296eae9edef46c66583195cb03dd796e694eca4f36", 16) - g22To203x0, _ := new(big.Int).SetString("1ab17aaf8075b8fc284e2beaa2ed81e2b1bb3f1c2ee8d337f9786106fa213954c7b1cddcee7346604439d3fabdae17f", 16) - g22To203x1, _ := new(big.Int).SetString("bf0d7fd2ca6c218672ba72961a01ef89fd5f60fd992e92ed20570388c71285e134de6573691b3a212ee11dc0c3eb0f", 16) - g22To203y0, _ := new(big.Int).SetString("173d203eb2952b75a82b63840cabb7c2d1fb1d7664946fac70e1136ac1ac60c74c23a4ac9356b6890d64f6a051e8617", 16) - g22To203y1, _ := new(big.Int).SetString("fa6e142fc5cabcc91392bd358358e1e807856f7056f947f395e1814c3edfe3db4278c8f82e61bf782482d74318bd91", 16) - g22To204x0, _ := new(big.Int).SetString("348acd4d6785f18aed4a7622f3144e040346b13f98748c5ba2acf3ad57dd7d22707d76471527420d1f461ff7cfd945", 16) - g22To204x1, _ := new(big.Int).SetString("a8c42e5ec8ba9102f936c8ff759df3faf70a2324e15caf325e6749ed2272bc2fe0f7c0eaf4cde618aa2781a8e27f9c", 16) - g22To204y0, _ := new(big.Int).SetString("13a51f84df15f42d157eb1e108e5d6997ac70865f60b56cc93a1caf72953ffa958e7178fb4e06c79895b6159f0c19ed", 16) - g22To204y1, _ := new(big.Int).SetString("f7ea55d09a79727470ebd74deaf4d1b88ee3bdfbc79d23deeb21c28a3d71fa0f82b08b4856432118815f76e73bddd0", 16) - g22To205x0, _ := new(big.Int).SetString("ab5b6137e856ed06dfaaa0b0b08f5a156403c93ddfe396775a02e509d5780ef132ed5cbda659e3c7b35df9d031e1d7", 16) - g22To205x1, _ := new(big.Int).SetString("60b441f4c1a4c167f0d5bdb183bb943c699f621d6647f43aeecdb604572d5145798a37e23e086e961b1a91ba526ec", 16) - g22To205y0, _ := new(big.Int).SetString("b850ec8720b432839de3b926bc58b9653915ec82cf04fbeedd3137afe76f55bd2a4774f8fc634ceb638d12fef64dd5", 16) - g22To205y1, _ := new(big.Int).SetString("2610171308947d7c42e16d8f3d5736d1d6911289c334b798657fb9b3e215f813f057516d0e5d91b004249d284ec049", 16) - g22To206x0, _ := new(big.Int).SetString("16c6f81e979798fe552216dabe1330e911779cf05b825bd4ca194f018474a794eb968676954dba6949010d19a7b7e5f", 16) - g22To206x1, _ := new(big.Int).SetString("8888ef840299100263b71574456212a520694b39e2ad4545eb049dce06924f152386850b6cfd572eaa89b3391539bc", 16) - g22To206y0, _ := new(big.Int).SetString("17dc29c178237c91ebe464860b1182a66607454a08b7e8d1b4cbceb7bf5375c96874dd5fe7d8f18a12c013fc7ff17dd", 16) - g22To206y1, _ := new(big.Int).SetString("ce7522e2e16e5fdc62f624791194184310983d7f3d1c43089035986d2538cf0e6dcc676a31631ee31bc9ac54995651", 16) - g22To207x0, _ := new(big.Int).SetString("741f39638bb4a63810f47a05dda4f7520ba8203a576b78135ab14bc4f88f3a3cfff8bcf421600b2f9376a608f869be", 16) - g22To207x1, _ := new(big.Int).SetString("ac32c37ae515b407eb4c472c0c5307a980b04a5598289820f35cfc66933275fb62fe3505b94a58676cd449b83ca31a", 16) - g22To207y0, _ := new(big.Int).SetString("127a483a5df9a7b05c723b6274777f9cd168fe8c030228a5e4ce48c448bfc2023a025753dbe6c39127ed7b394195f19", 16) - g22To207y1, _ := new(big.Int).SetString("b3d1a6503a06cfeb8713d43b5990ad13b3e521443c35fc7aad472255d298d329297ac577bb1ab5ae352b940887cb9b", 16) - g22To208x0, _ := new(big.Int).SetString("1452ff3b8c522c8445376fc61e9ff3ceec2604d7daed18e8d7baab2bf5ec3492ee50dab342e68cd1d139fb0e51492a5", 16) - g22To208x1, _ := new(big.Int).SetString("52f527f154daadffb0b9afce9485807fb9c2bbcdd15a82f6a103f50fe8b4590c036261a0419a28478a654f4c678bd0", 16) - g22To208y0, _ := new(big.Int).SetString("1996efba4768bfb2e3850ccdf7305e144f16db087d301c98ba395efa6cdca7894383918380f9564fb25f5b1f96dc84b", 16) - g22To208y1, _ := new(big.Int).SetString("b2af89268ecdb16607739faf90c6af26d71f891eaaf313a084a932b55f8451dac65acfc856d4a2eae4d7718fda606", 16) - g22To209x0, _ := new(big.Int).SetString("4a00eff14f4ddf49366b64f760488d3ee4b187ddc999b98b5b1c97c32501ae6f034cc60e743bbe82357727760052cd", 16) - g22To209x1, _ := new(big.Int).SetString("b26aa66a535cec9f94562f9fac63395a15e538ea441bde98b981adffee7fe98daf7477a650ee9d462dfae375e4f868", 16) - g22To209y0, _ := new(big.Int).SetString("fe6523f21147790c6b78309cc00acae32f95a8faeca79b81e9ce099181cd4acee7fe5b011365d51b47c2f80e972fcf", 16) - g22To209y1, _ := new(big.Int).SetString("121431f8ae0c9511d5a2e994022c98b318f683494fcd790bc28436702d63f80c2b717e90888e8ec4c2537800e5493eb", 16) - g22To210x0, _ := new(big.Int).SetString("19355d4cf0c47145baa990e1cf3e153eceaabc87fb497381fbd9dd1fb102fbd513a535bd5567912293f8a1c59e76074", 16) - g22To210x1, _ := new(big.Int).SetString("888054cf69ca0a10a3ec9a954bd265fbaaa263715e4838a99e5e6a75a4ac9eb509753d3bb74bfb4ccdb39bc8726969", 16) - g22To210y0, _ := new(big.Int).SetString("905f0d44fb3cb8a6c6d28e000b87e88353866e796d85d7f815a50cf997e6bd858c4078b97a4dd7afa0359117edd7ad", 16) - g22To210y1, _ := new(big.Int).SetString("13d79edb468dc530f8873a394d8e6e7ddb56ddd78b0953f26555ec9757bb9c1979e6ac46fa138c80a91faff2e3a5660", 16) - g22To211x0, _ := new(big.Int).SetString("110a8c3f295f025eada473c6b65f7b619168d441bab0e0948df726471e1e93f6af56520e7a1707c80501b02c1faf16a", 16) - g22To211x1, _ := new(big.Int).SetString("64d01b4cde6756b6b7e02cfbb89819b3e5ea4ea2d46d6d4048723ca187a691f06be49c6caf80c8048f1c9575d41ade", 16) - g22To211y0, _ := new(big.Int).SetString("6c700c522391f0b8aa1afdf102d87a23fce2f397fcb6d77e36e287874b32cf971946472bef4e57bab85fe21690007d", 16) - g22To211y1, _ := new(big.Int).SetString("7b26c301bbeb28fe4beab46dfef5da6206cc0eef61d7bd2c039981ecf2eb1135e6afffa9c0b21efb25511109e32c4b", 16) - g22To212x0, _ := new(big.Int).SetString("13997c8b33b9bf4c9e9322c320032694874d31dd7c3eaba08e8a07b0a89cb564652e29f6fe225cd9500fbf237e15d1d", 16) - g22To212x1, _ := new(big.Int).SetString("10ac932f6960da32d2d0ee894c3d4b21a4092ed0edcd7d97ca1fac350eff6d8178d9ff7c16450e093605b83f586b118", 16) - g22To212y0, _ := new(big.Int).SetString("11ada44e1dac10a55c3255591eb904fcc3186f071f39b2cca85850a000b2096c3ef38f43c5da644c6acb0b056273bd3", 16) - g22To212y1, _ := new(big.Int).SetString("2f161d6478db3e8f63d1c0d4843af0ebd3c78dbb8908f088f8ed21816ff36af4c4ea0414e9feac55eb00043b2b2137", 16) - g22To213x0, _ := new(big.Int).SetString("ffbd295d0e1f192ef8c0b335157612d81ed83620355e8e5bd4c835a7a2f94436b385149f3fd5a3cdf53df91e5b68e4", 16) - g22To213x1, _ := new(big.Int).SetString("e91515eac195331d5d730a1abb09406ebd4be677b51341c366bdcb9b492712db2ea4692668ea255c87bbffb2e2112c", 16) - g22To213y0, _ := new(big.Int).SetString("a2c2281a3c4492fae55515b92b00a4662f0ece234461b398e906cbf8c7d437a75d9e23550ab08ff369716b6859c837", 16) - g22To213y1, _ := new(big.Int).SetString("197b8fd3caaaefd2c72911dbe06c4c51da4937cd5aaade9e926ff32147be4c502a3408ef8a3acf9b9133c83a41e236", 16) - g22To214x0, _ := new(big.Int).SetString("157e11dbf1ca62677ec906d598ffd809b891c1802d3c0b49aceae1b7b55ceda16d49540c68e9872ce43bcd295c44e66", 16) - g22To214x1, _ := new(big.Int).SetString("15fa8e5909586dbf5b37b6a5da517550cbbbb17c5e975d4b5eef2e08f334affd760517a862ffe2f1f9df26651aaac0", 16) - g22To214y0, _ := new(big.Int).SetString("b0b4846c4a9ce5435d9ce2ba86a1d56d4621ee7bfc938f132f614b0da05b57d835036e488c00981eb619fcdbe1511e", 16) - g22To214y1, _ := new(big.Int).SetString("e5cfc53c396d46a7c5c79d4e33be93ca1dbfcd17045f91b22657a7c3795c58de2e4a005efaf0d66d84b1b93865e684", 16) - g22To215x0, _ := new(big.Int).SetString("191eca222e502481d76a9713567036c58d7dd1dd1df90bebc1b9928183fed70de03070d92ce8b11c3f64a413b0bdae", 16) - g22To215x1, _ := new(big.Int).SetString("865e84e1d254131d957527cd50f050a7a597250ed59282b4815e3ccd46073d5cc6b63a91fc58f52391c7b102fe3e4e", 16) - g22To215y0, _ := new(big.Int).SetString("e3ca4183433fb83fe90096eec4f70a9e4329c382a1e9ef718b17be368f2f28c042aaad1c62cb5f96972b10c1bdc1cb", 16) - g22To215y1, _ := new(big.Int).SetString("d721b04e9f391e0faa3a2379e25dc43f6057b97d4a155df052536f61f8cf334f2bdf59e667988dc9a31d159583d776", 16) - g22To216x0, _ := new(big.Int).SetString("6e1948e65150c93d666d6e028050177c4076fcfb720107ba92b6307eaba28382abe24875de412fef2bf59d100ccea2", 16) - g22To216x1, _ := new(big.Int).SetString("e3e3f028f3c74a41611e6813c989a4d31f012625a300a325ecc31b7a896c12c7deacc4a1f050a879e0c3f03ea4c12", 16) - g22To216y0, _ := new(big.Int).SetString("17188bb3a62e5465aa9b863f718020203847296ab5ddaafecc24a0dcac9a62cd9c31fa47fd6849ea9934ac637d8f176", 16) - g22To216y1, _ := new(big.Int).SetString("4bea3a574031e0e6c8adaed3a83a711b7f0450feae9a59be11d01443e5ab1a6f44790ee954c3792fa7c14a24827048", 16) - g22To217x0, _ := new(big.Int).SetString("70dc1cc5d4bf5cfd9c67e26183705be849acfb21c7513a4747c5004a7ed8566599d7367fff982bea041ed0141af08a", 16) - g22To217x1, _ := new(big.Int).SetString("15d758c63e0e6c24aef576fd54798b15b11820656153f62136280c19c2a70ff05de656c9d046e98e5de0340f54b657c", 16) - g22To217y0, _ := new(big.Int).SetString("860be86306055efd432c5195e3725fd579b1aef12441c15854565261a66a5f1309c9d368be4b932cfade14833269fd", 16) - g22To217y1, _ := new(big.Int).SetString("180a3c7b276c3411473f239c4ad1620b215423bf87608eb9b2d8b0db0765db2117559cfefd8fc59bd7931750ee7dc4b", 16) - g22To218x0, _ := new(big.Int).SetString("1d6d1784ebe66fb63b21a4e732fe0692cdd5fcc20ce11a711e738fe16153686b476ad736e84dac1872671de84f2004", 16) - g22To218x1, _ := new(big.Int).SetString("3decfd5520bbeb68a70cdd0208194bba2e111e1091a87c59726291cc436e25083026fc956577b1655ffaa279b550ba", 16) - g22To218y0, _ := new(big.Int).SetString("f2a01a887f8047aa0cdd8fb49348d5e11b286fa1416fe0c48f9a2d8850af5c2e5d6de11c335f6276396c3b1681f7d1", 16) - g22To218y1, _ := new(big.Int).SetString("8bc2179809e0f17380b105ff91037dcc766e67f77f43dc39121df7beaff211cf9b463b312e6ed741937dff14a51989", 16) - g22To219x0, _ := new(big.Int).SetString("120eda2d7d4c511efd6dcb461d50a2a4b48e97a97260f33642ccc0b3b29722509ed5fc97d3ed2e39caa5f5760beb45a", 16) - g22To219x1, _ := new(big.Int).SetString("186df8d3f20605e42d3f2d8d2150ea86ca45860081264c1e5abdb8086e61f455ff266f6e9e2cacc59672efd91ffdb7b", 16) - g22To219y0, _ := new(big.Int).SetString("61aebbeacab0ce635509c12346cb8afa0e3774c38a47b630ccdf0f089896e991f31b0828585243d1eb02827e1dd6b7", 16) - g22To219y1, _ := new(big.Int).SetString("9e01cac99ed79cd02b0ceff5bcddcaf863a15650e613d6f723ef253db92f646d73af7dcd3ac3bc4df8589b8bd18642", 16) - g22To220x0, _ := new(big.Int).SetString("5a1a9d300817a41602d7f15759fecd4bf5e9500b970299db86481c859646c80681f21751cf290ed7406b88ea48cb03", 16) - g22To220x1, _ := new(big.Int).SetString("e400147dd0cc103e015cd1b75d685e5727f118b9da65e844c055a255ae9bf10b643383041704b5c6aa30a152a36842", 16) - g22To220y0, _ := new(big.Int).SetString("1f6c19fa4d7362c289c47089d675892271c1f005a7df2bba3cc37ce41533c08455e50b841710f2919ff0f8794926", 16) - g22To220y1, _ := new(big.Int).SetString("143f1584851efe371aad348de294b120eb37c9935305ef0ee8866d091a2b017be034f52a4e2c027d8926eba0c6cf9f5", 16) - g22To221x0, _ := new(big.Int).SetString("f5668c211784ed87672b7620ad688ee57ec41aff06101c424c161c08a87addc8f3b924aad8255df5f004b7b5db4bdb", 16) - g22To221x1, _ := new(big.Int).SetString("16cf08dd1d150c6070fd12e06a8ba6b2f77dc5be36e5b0e62f9687edc8372e3c5064143f5a2a7c2ebfb54189146c551", 16) - g22To221y0, _ := new(big.Int).SetString("d32a7cc3fe8314436a9f1d38abbd8928068c08130ef5a2d2cf97426c4ed790ec50f9b7a9aa57f955e31b471ff0cc0c", 16) - g22To221y1, _ := new(big.Int).SetString("e142c5a795d78e4efdde9f3d447a343353797b1ceb6167225ae71a2db43dbe13539a051ccbda97ade033f81d83b413", 16) - g22To222x0, _ := new(big.Int).SetString("9320a66ae1094daa2da35d4908ff3d351b302e58a04141a7f7034d5e30aa49a4f764a7075bec251be845bf1abff360", 16) - g22To222x1, _ := new(big.Int).SetString("1a9b4df145e26ed4b6f73aba7f7be16c981572f3bf2b8645f26c5051c0ee595006a668cb095876f9c9c353abbba30f6", 16) - g22To222y0, _ := new(big.Int).SetString("b5affa0378e3f5e34e03cbd7c45d2cb32c20bd4ffa209ec04c7e624afc84d1dcc3bac9bd16a1041c8fe778e3475c25", 16) - g22To222y1, _ := new(big.Int).SetString("d91c606c2bbc3bed18233dd8b46d9e3253a8f2ec97ee56db359e25a41cae267ca9fca2088f1ae87e6a6ef2959be19c", 16) - g22To223x0, _ := new(big.Int).SetString("15338392455ef6346a9a9eb4d5849cea042a73f6d340dc4f2f7b8ad137f88964f906edaa55734f57b69a620ead71b78", 16) - g22To223x1, _ := new(big.Int).SetString("123cd61a10bfb7c4bae6e9038eb9ffadb4ae909f5433162ec468cb9738ec4bbb28c3a9f6a09fb91f5d390d3724d3d36", 16) - g22To223y0, _ := new(big.Int).SetString("4fabcdfee1c086066bd2785a48488dc32c822145a4f8d5de3a5434eea9141aa4c1d2c673d57bf6ca23b1724c685d9b", 16) - g22To223y1, _ := new(big.Int).SetString("132dc69324eec9822f4a30adf15a995c81d17d4691271652e1010f588a7d40b618f50db0dcad20f0558d3e28bc63010", 16) - g22To224x0, _ := new(big.Int).SetString("61d4511e9dc2037be8e756685b3d5075b7ec82415ded4a4e035e6885c2c38edd0e27871c3c360556ad5751574703fb", 16) - g22To224x1, _ := new(big.Int).SetString("c9462feef2524b9908963cac7b430eee4bce6bcceb844cce1ccc773e2ccd36b0682dea752f1ee9d6a6895012e18a58", 16) - g22To224y0, _ := new(big.Int).SetString("bee4fab502334f893d3ec109cbb394a74e1e009618d1a38fad9be1e2eaac59c587dc357d8a95b7d35cb69e665c3b32", 16) - g22To224y1, _ := new(big.Int).SetString("f1ef013be3f9bbc623cc7fe8b0f1499abeb22274805543005e7699320d422894a60a4864f382cc3d1e021d229f59f2", 16) - g22To225x0, _ := new(big.Int).SetString("4f3fa4b5053eae4b485c646003ffb1c25044e73cedd2998d3ecae536accb2e710e719f542ab9786f92d78461c2844a", 16) - g22To225x1, _ := new(big.Int).SetString("1976db83465f99d82278ae334c19d560bb9ac010d153d7352146095a1ae9ad5e62d9d1ffc06eb02eb87d49907d30056", 16) - g22To225y0, _ := new(big.Int).SetString("ab8a57fe54fe7b286e5f5697c3b22685a296faff6f5bd378a95d4355fa7a85e8783313dc88da0bf94dafa8d49fc059", 16) - g22To225y1, _ := new(big.Int).SetString("4b16f1828e210e6b3fc39dc227cf78c2f6ff253134d03088ca9d60804e8f8eb88b471c1d28fecbb7180e5b4c2e0c8e", 16) - g22To226x0, _ := new(big.Int).SetString("15cf5513c9747ee517b2bc3538b7f3c9a49bedfc9f16c6bc3c72668d6f229bd611ee14cab207496fe101b626a07075", 16) - g22To226x1, _ := new(big.Int).SetString("baacba9de1367afe1a725a314091cdf8f82ebdccb4814b27d5b83629deb2de9d7414c01f7ea465919951836ec9924", 16) - g22To226y0, _ := new(big.Int).SetString("19b594ab4f2fb02b3c23dcfb9dc3fcc7f58784ea8aa9101960fd94c40b05edd054073e0ea80672bee0acb8707e67595", 16) - g22To226y1, _ := new(big.Int).SetString("184e6ea6c562999533a28c2490c07b6fe5ccfc7b096fb9f332f542f8f6f9d503008c0bc621faf0681c323c2b6d70b54", 16) - g22To227x0, _ := new(big.Int).SetString("140dda6b70030990ec4f70f0d67c3eef5c7e5b558e34c5b7590813f3180c22446d959d57417ea98b7f7d2ca11dbf24f", 16) - g22To227x1, _ := new(big.Int).SetString("29357be1292cc6817921868e7e8eeafb8642e78526effb1502b10358291af8051dab733c1cc1598aa737682f694d27", 16) - g22To227y0, _ := new(big.Int).SetString("113fedeb0f9efbe82266582f2cd2b8c6876742d9ebbff621817a48a39d2f41f321629ce6af86e2c5465b651f28c4a32", 16) - g22To227y1, _ := new(big.Int).SetString("1b41bfe9fa90eb9205deaf2903e0cef4cd9beef290a59c402f75ca0fe117e8c4a6d375675554dc29dc409d623c04dd", 16) - g22To228x0, _ := new(big.Int).SetString("e6e3677e32cad86caad64cf7606fc172a33f1b327c9c70b3cdfaa05c4aea82e170e7bfb231c2ba74e0b6d51493c0af", 16) - g22To228x1, _ := new(big.Int).SetString("196fdec7c41f332672b4a66dd5f283741cdd71e81901546257f29cfd5f527b7b926342d5803666d0309790463267ea3", 16) - g22To228y0, _ := new(big.Int).SetString("30fbb81162ae3de583bbb1c3273a005a1c4bf8b15a07e0f1f6af337677f81a86c0bc5b24a063017370fa075445aa79", 16) - g22To228y1, _ := new(big.Int).SetString("15c4c7cdee11fd16ac0634ab32d20b386c9a29a729fda738cc17d83d2c87f96f5438904f462959a624f3e1c3e1b726c", 16) - g22To229x0, _ := new(big.Int).SetString("4a77c7561b46da0b0a57a8268e008415028f0522a551b7d703c06a899e3adce6fc6f1f84fe8c692ba9d6579a5d304d", 16) - g22To229x1, _ := new(big.Int).SetString("d00c3b8f25001c2298a5f3081d03cdde801483b97cfe9111abaa89d98d9f7441bb48a532e7b560da8efb52cbfa488f", 16) - g22To229y0, _ := new(big.Int).SetString("bfaed42b7cc7bd372815959fc4b52bd5d9762e3e4833f898c48fc81378f0b3bf2aca094fab422d872e7af87bcf974e", 16) - g22To229y1, _ := new(big.Int).SetString("1486c6643f69f5591afe2d1a337e661597408b4fae61fc4d7eee62170f00aead41983833d0b9eb6aa41c2b19d6fb9b3", 16) - g22To230x0, _ := new(big.Int).SetString("13aaa58535630c43f1e8e025859a4e191558b3b17faeb27a8872d79c16190e60de785808c2d8e8861feafa4f652bb46", 16) - g22To230x1, _ := new(big.Int).SetString("9c7e94232022e629f74519e65595804f32ef7e8f9be8d4038bce9421ff1b1cbeafba1f66be885b6c266ff444d2c511", 16) - g22To230y0, _ := new(big.Int).SetString("116da7b271188a56aaeb876185defe78ca59a495c9560ebafa5caf8a600dc5095ecf75cdba9a5102feca678e61159e1", 16) - g22To230y1, _ := new(big.Int).SetString("b5399b58ca2c25a8c7789db511df7390dbef89f66447a21d8b05f8543dea26d73c7e237b1ad4b38633bcecb0d80c08", 16) - g22To231x0, _ := new(big.Int).SetString("12a44f17e10f72712477180a7750afaa68580ccd8aa4e4d93c8dc26b6f4f032f67acbd25450b24abea23e9b89df5f2", 16) - g22To231x1, _ := new(big.Int).SetString("16291c5c964c26b266ad096dd25d2dc3164b5f49e9380fd5abf1bb28671695e34307dd7efc5e3bc41b7331c1e956321", 16) - g22To231y0, _ := new(big.Int).SetString("1900f5b15e6fadb3aaed13b94ca07f8e1450773726a957d38c90e7a440cef16a8087e55b2ef4eea5aa6bed27ae6d420", 16) - g22To231y1, _ := new(big.Int).SetString("149303e315fc1ffb4fabd80a831f544d672731a540878c10aae7b328deabaa3bbb4b4c4a3194b0354c812cd0c1079", 16) - g22To232x0, _ := new(big.Int).SetString("116c99dae3f682fd8dcf85d0f779ae92d5958f20b3edd25dc39b4ed2e4eb9bbeeae1fbc7eb4728371210648d021ad1f", 16) - g22To232x1, _ := new(big.Int).SetString("1299faff92dc33b032ca70e2370534c3cbfba3710ed085507661f5efa1d861d7a0e67b38664ac963262601670f7fa51", 16) - g22To232y0, _ := new(big.Int).SetString("153dcdec0417a48ead29f5f9ced04d2305092610e029bf9ac52f195231df53c82e14f2d93b9c177a85565149a2edfa2", 16) - g22To232y1, _ := new(big.Int).SetString("992274638c287a52667a854f7ffeb4eec4ee0c240c47c50b4cbc5ac6be56a963f481e640cb422eb02a794ab970c275", 16) - g22To233x0, _ := new(big.Int).SetString("1143b4bacc8856a63feb0a276f78e90a379c410260eb54793064e408922beff4b68b85c714aa905f3db357422e32309", 16) - g22To233x1, _ := new(big.Int).SetString("183856881b671e7cd3e26af84dbfe9dbfa925c329ccd949acf4f69800de1c399283979b1b53ba02ac3907a6f48a381f", 16) - g22To233y0, _ := new(big.Int).SetString("1684aaa6017dbc7a9e6b350cd6837030cff2f9b12ad4baf885b017efdb7d2ccfa85df6e627153462924bae9c22df82d", 16) - g22To233y1, _ := new(big.Int).SetString("333c4214484749cc15f984a445b36c19a04ea7e91d55e2f4061933018ea8153687a8b8937dea0467002455dbd374c7", 16) - g22To234x0, _ := new(big.Int).SetString("965ffa8ede763b0b5cf7a2c0b4c866ddded70fda83bd2e3894c5c5b3189a9d79014c24ab1413b89a39e357b4181c9b", 16) - g22To234x1, _ := new(big.Int).SetString("da45f5f4e50d5990a7e9df94ce2c6cfd2048c3632b1069d361be77f16122ddb5ee4fe4f7367846768f89619bb8bc2e", 16) - g22To234y0, _ := new(big.Int).SetString("167ae7a77ed6ef24f1c2924d4568d99b3e08caf2a18eb4466c7bdb9b2e1c560947a64323526892b069eb84bc7224c36", 16) - g22To234y1, _ := new(big.Int).SetString("3311cb8a8ca09f70e301d426246544f9b66db0902570f246554d72cbe38626df187410ebcc1310a836ca4d97af33f4", 16) - g22To235x0, _ := new(big.Int).SetString("35385cab023bc6dbedd6643338cfa15e1421f1c18fc9de93385ee68524f8eaeec3906be6f71fd5550d2ce91f9aa3fd", 16) - g22To235x1, _ := new(big.Int).SetString("5c39fd2f51e867eb27c7ecfcefd5cd6a36a067ad472baec9a622302de9a2cd7288f95233ab42516339198a4f34eaaf", 16) - g22To235y0, _ := new(big.Int).SetString("eae53f60df32166ee25cb9625ba6849926e825bcfb1dcd15ca9c7543f7bb9a35a02138bf408d556196f064eaddb348", 16) - g22To235y1, _ := new(big.Int).SetString("175b0f13d347a24b6f44226c44c6cfa35a93b3a9f7cf47e56cda0c7fcdce810d3d7653356e3cf51d4b9060a32e779c5", 16) - g22To236x0, _ := new(big.Int).SetString("76f214f94aa49a9e9b02d2d4b09d71b2b8afff460726d6f94ea61e0a824390c63ec31ec00326894de9dd81da189d1", 16) - g22To236x1, _ := new(big.Int).SetString("73720be0d041b24e035c2bddacb6fe3ca767866d27c70090a4db7e6d7d679f748e79b7bfc29ead058d829cb2a1c78b", 16) - g22To236y0, _ := new(big.Int).SetString("6baa768820770ff572f6c7aaee545f673c676f1b483f086b0e88010c61b8cb74b47bfa63301034530e89467ca1b6fc", 16) - g22To236y1, _ := new(big.Int).SetString("12c0c461ef5acf11748a53f4be776a47aed227f72f958cb510ae7ad4d9e3039e95864abe6a776465cc19c2f281b2c98", 16) - g22To237x0, _ := new(big.Int).SetString("1a56ab3c91a2d7ac04ba3845e5b04635cc21df603cc5f4a272917dc3c0f29ae900d47094a908b9ef67c9f3c92f210e7", 16) - g22To237x1, _ := new(big.Int).SetString("78f75d52c39d9e3008fb77c113d4517492ac9526dc5720b3ac000bba2bcda9fa6f235f71358e699de3f41ae766ba30", 16) - g22To237y0, _ := new(big.Int).SetString("9db0e79b6dc6591f7bfea52e20fbccb67f04bab057fa4c823b03bc11cc3e3b034308ca19f4dba9e55c8ea75da96a8", 16) - g22To237y1, _ := new(big.Int).SetString("18ef4258b1ab95b589ae734e9a5788844b2ab463058ab598441d6eb762f857baabd540f004de0516dacef459ef1484a", 16) - g22To238x0, _ := new(big.Int).SetString("124d5e181b32f8c19fb318876519723395c00cd96032ecc3e2786e7766c4f8acb21343b7c3373210496c2626b0f375c", 16) - g22To238x1, _ := new(big.Int).SetString("11dc8c2412867901d60d67978cba757346c3c540b1c28d0e4ed34eaf4377b12fa662cc111e9a1c469194852f3f5fa91", 16) - g22To238y0, _ := new(big.Int).SetString("16be0077d1fd4af0aa2195a5558aac35ccba794c4bce87780c47331304c506aa550ca2b007d348f857772efcb8e8526", 16) - g22To238y1, _ := new(big.Int).SetString("ac0d33c186f9c22e81bbb09682bf81a905d600d677f085a22eac434870780f711de3f6e2e6129b4ee56e1da45246a5", 16) - g22To239x0, _ := new(big.Int).SetString("578d0421ff60488232428f9e12894b28901b159ace1e824c42a1a098918edae07af911a8390af95aa8ff97559046e7", 16) - g22To239x1, _ := new(big.Int).SetString("91497555e71e73f92f6837caaf01fac73cc08b9811f4aa5da734b9d964fd7012898f232b9f81d9de1403e9a1b58e6", 16) - g22To239y0, _ := new(big.Int).SetString("11bbb9a065838a523f055bcec91f196377d8f45bb7c517c4df45d6933a63c43359666df85d46de2318de648af6ef91", 16) - g22To239y1, _ := new(big.Int).SetString("9bf515871398492a11022b61a7feb80a90e284152893d799df28dd6ad525a7f3d1dc699e2088c5ccd061db4ac9fc2e", 16) - g22To240x0, _ := new(big.Int).SetString("11413f10be45a4e80ba653a128bb8e5d6fbfd469dc3d8e220a0c6b494de4499d84f0588ca0e6d8d3578b9c65b812fe0", 16) - g22To240x1, _ := new(big.Int).SetString("73a4e05fd7e2a8df57e2ebe110da0cfd999573e0163e68b69a85ca0be643161b608a5bc9d86d12bb6c9f7448a3f4b9", 16) - g22To240y0, _ := new(big.Int).SetString("1edd87e38174140d357b08660655eda55c076e3acfd5c1863fb65033066af23e49465c844084c3f7c87438da34f7eb", 16) - g22To240y1, _ := new(big.Int).SetString("18f5d01090cafd077c6a98644270e80449328651a2bc55e9db82d2a4f9807d88b38adffb2e98555ad6f9cb62ba4e05", 16) - g22To241x0, _ := new(big.Int).SetString("4a92e81d429af6a236903d48df00d65edeb772581a585d69abef382ba292b86cfbc9819883e5e0b3787a2a604a91f0", 16) - g22To241x1, _ := new(big.Int).SetString("15e451c638d369335d7724bcc75296c09f308736e177277a75dc1a788289873307067f5e39342d614ccef88468cf829", 16) - g22To241y0, _ := new(big.Int).SetString("c87525377a7435706a90d868c11f0d49c5b26f5367c1f8c48122dfff1796ee3d5a28d9fddb914c39c800e2d627236b", 16) - g22To241y1, _ := new(big.Int).SetString("e5b696f8d74484dbe15fe35db89a9462775cd0efe73b0aef441130c1f95ce00b9d5deb80d8dcb50f3e3361934057a6", 16) - g22To242x0, _ := new(big.Int).SetString("5b7f202db9381f207dd36810498fd463f92138f48739dbd77f9dac3c7275ea8784e35067d5f6d0db19e5438446c164", 16) - g22To242x1, _ := new(big.Int).SetString("c24ad376e7254204d6f04bcdb35ca331c66d62b84c924f8cd045efac3f41f8b3a09c0f5fb5c343150312d650394fd4", 16) - g22To242y0, _ := new(big.Int).SetString("b115f6f48cb887fde92ce968dfee1f04cab2ab03f5258701853f792389029a55bbd827e7d09c8458e2548fbafaab41", 16) - g22To242y1, _ := new(big.Int).SetString("1908a57854335e598dfa6af88d8249f29b46d5afb26e62e5799d9e870b8b1e2fb81b95c3e355c369a6e0315a966ba8b", 16) - g22To243x0, _ := new(big.Int).SetString("167a83029b379191f6296ea06c6cc6744b7640926f2d5ddc0653611c8da92e50417687117913f9540fa3a785104ac94", 16) - g22To243x1, _ := new(big.Int).SetString("40f6dba9d8ab6c0ceb6abdae0c7b3ab348b7f47abdbd6e4d3d30ae71874e58a4c977d8262d320d1f8778e415f9f9ef", 16) - g22To243y0, _ := new(big.Int).SetString("e172bf2e3e6e6df910d6b60a90b07662e5d69b30108f6a415f5dd1700ad0a449e45b1faf629cfa42035250958f84d5", 16) - g22To243y1, _ := new(big.Int).SetString("1016a8a4114e72056cd959a645b00f15a0d5fededd4977dce708f712926603edad76f2223e5c6ad6e585f54d484faa7", 16) - g22To244x0, _ := new(big.Int).SetString("13f5e1adcd4b83f044847335a9972caee9eb296bfe575a30ef816d3a57021a371eb68917f0d4d0d8522a1d47ac499bb", 16) - g22To244x1, _ := new(big.Int).SetString("126e7bdd01c2647f5c959bfe62089338ee624d707c8988cb01d138a0b57712192d4c252b8f3d2a85282fb3db109b3bb", 16) - g22To244y0, _ := new(big.Int).SetString("1349025f99acabf89d7eee0f4004fcba91ba314a0aaf57a9ebaa2ff43fb275d71b93911d7bdbbc62900eb44338b4d9f", 16) - g22To244y1, _ := new(big.Int).SetString("19077a04f81a725a1acefc2ab88ca7056f29b094364453f8431f88bec49f74a7741687926a12a7c3a06e9f86ce2c50b", 16) - g22To245x0, _ := new(big.Int).SetString("144645305a00a758d65f778728b9f6e113b436e10f202fdfb1fe82aa64fb7da7ce7ec58d2ac69fce6fb7b9da0384c34", 16) - g22To245x1, _ := new(big.Int).SetString("48b190744f4c58ab0e7bd0bb1b6470382d1d735a753fd16dba1c8fa5694361ad0d8ad36640e3e657b3458d76ac08f3", 16) - g22To245y0, _ := new(big.Int).SetString("7f7e9a1dc2efda5632d6d7ee989cd2d7037ee37bb7ff2ac6d89fe4b3f0f43cfe994b23678992e77f6ea940cd9d7eab", 16) - g22To245y1, _ := new(big.Int).SetString("1237f19dbbd6b8e1a2167457309351c1e93cfebcc1ceb1b4e3989df47db8886c4f16fedfd04b95d7940957f69befd71", 16) - g22To246x0, _ := new(big.Int).SetString("36ae22d7ed9f06ff2d17dbc8299a3486cd1f2a6912fa00dac6d6ca65808add68eba6ad17785ca822ce911a4b60b52e", 16) - g22To246x1, _ := new(big.Int).SetString("9749db79743deb0062665447bea365a22feac03ca22d0568561a9debd6c22c6b9b76e554d57a98fb90ff69c920a5ce", 16) - g22To246y0, _ := new(big.Int).SetString("107564a4a2d698231d1ad267e3d3aa937af10a1d00a5f871921b362a91d44ff841e29fdb916a5c627305104dd546157", 16) - g22To246y1, _ := new(big.Int).SetString("7c93373097b6a5455c5efe406ea2c2193d059a9a99a6a03be8a762425f80a35bb9ea476fa2072e462ae5dd9f2309ab", 16) - g22To247x0, _ := new(big.Int).SetString("6a22dae324168e17c2f5d424d4285f6c932c09fa4bd404f729d93b9d0b64aa24c473a1574a3c6099f5409cbe1becaa", 16) - g22To247x1, _ := new(big.Int).SetString("a0ec3f2f65e1701067e9a0e1ab8de88f847db33b381bd09f368532994d021bdd980897457ed7a268812bce0069592a", 16) - g22To247y0, _ := new(big.Int).SetString("189487e1bc350ca03ca356f978b8ed2d90d3d1fc0b541a3c4dd03b1e40acaa4b2e475d7e07a04a5f9ce9c7442af4962", 16) - g22To247y1, _ := new(big.Int).SetString("7ebcde469687f32084e1241c889c754aa72d62ea26a3e81d89ad089341faf83bffc87f6733f1749a2897c168d7cd18", 16) - g22To248x0, _ := new(big.Int).SetString("10006f4d936154c76ee3db68b01e6b322851cf0b8aadadf5569e20ee4286e63119b417ac0fc2656b998c8eba0a2d9a3", 16) - g22To248x1, _ := new(big.Int).SetString("d8257b429b89e8d51f6448780a2d2c680cff8e6298f72d0e988094f4e5f286f0b3b60c2f40418f55d1b01817a9c91f", 16) - g22To248y0, _ := new(big.Int).SetString("d9f578a615bdb373c9f728a55224d3712351bce6ecab3d5f8d4f9e8eaa252275aa6a1cf5b5a8d50689818b37166020", 16) - g22To248y1, _ := new(big.Int).SetString("5e68fc0e03db30d88f33c714671489b149db943910e08d106f48ab5cec28d1ffa8f19a1bf1bfc3fd11fc1a8b89cf72", 16) - g22To249x0, _ := new(big.Int).SetString("923c1d69a1ec9eeb1be661762df7c1a6209ce73f59011e66d70cfa0d450d7e541ce8f0d0178e7bdeb70bd9afe6630a", 16) - g22To249x1, _ := new(big.Int).SetString("89305c6d004561928965f44298a018b59e815779372a838a6bc041f60179ac74e6250381ec892c925d0829de05cf02", 16) - g22To249y0, _ := new(big.Int).SetString("ba7546c5ee31e6e41487d7b03a60b1db7e3c13fd680e246a835911347101b038a307c9b619fa681fbf3641d0773da4", 16) - g22To249y1, _ := new(big.Int).SetString("846f47f95e12ef41c4a41dd918ba41f4896411fbdc00a3680b425adbf3431b2274a6a0759401231d74caf733ed98cd", 16) - g22To250x0, _ := new(big.Int).SetString("d1e044cae44743f417bb1e3dc5d26c51148a187a5c1a93893a8d16145d5277beb5568b67df8a2120a94cdb1940c116", 16) - g22To250x1, _ := new(big.Int).SetString("1446b710797615d55733b96ca9c6fc631ae1738af4fcc641e0cf9fb2270182b09b2468781a05ca30977ef7b582a3290", 16) - g22To250y0, _ := new(big.Int).SetString("606fa401dd62679f112a7c7e8601a4ce3a7ab6a3a6fd9eee07566fc578ae3168eb3457e45db0e967d07d0e06f31571", 16) - g22To250y1, _ := new(big.Int).SetString("3225d95c006667f610fe975864c45c1b54f5711d08be4081a964956e1821a9d73598c3a9e9f2a5466e077a8a873e89", 16) - g22To251x0, _ := new(big.Int).SetString("1605ee47664ae98270c966ef8f54e82bb23c28f34348229ce0ccb2dd66095bd11375edb3bb5e4107aa68d881f74dd99", 16) - g22To251x1, _ := new(big.Int).SetString("163046b6f1986ff5a271e96079b8c305168eb91678d387893cbdc3067b3ad6117080f7927be358284dff9ace2aca23b", 16) - g22To251y0, _ := new(big.Int).SetString("152a37dc98ec8ebb9db9adfbce7220effaab6a0e60b759789776ca771b65ce96c1e15ceaac5e8304eeb8f03d977ccdc", 16) - g22To251y1, _ := new(big.Int).SetString("227beb5ba0867d1ab14b486e365a88cabf816a64ba04f453424eb8ebf9017bbe7a92c03b951247e2c36b5c3ad75ec7", 16) - g22To252x0, _ := new(big.Int).SetString("144304b66063c76234971bb9464e767a22b4b013c101a92018a0f5b0ea4d6e1bc73a906c5e4ac5dcbec7751dd3e8315", 16) - g22To252x1, _ := new(big.Int).SetString("9c18b1626b97e33efe848129737f01518a052b0baea0958863db86ca0be561fc462ced7e3d1e12fc08e4a19a0b046d", 16) - g22To252y0, _ := new(big.Int).SetString("159c60b8f19e916856e4825008524eeb7baaec5c2943881d3a3b6a13f4a4de3d834b5d1a53f7fae59b52e06a446a2d1", 16) - g22To252y1, _ := new(big.Int).SetString("e80fe9da96d1acc3fd31cf625b173de483b99dab76db9cecf6899414d3df9962fb613fbf16ad49acbcd8521c3bba30", 16) return TwistPoints{ - G2x0: g2x0, - G2x1: g2x1, - G2y0: g2y0, - G2y1: g2y1, - - G2mx0: [253]*big.Int{g23x0, g25x0, g27x0, g22To3x0, g22To4x0, g22To5x0, g22To6x0, g22To7x0, g22To8x0, g22To9x0, g22To10x0, g22To11x0, g22To12x0, g22To13x0, g22To14x0, g22To15x0, g22To16x0, g22To17x0, g22To18x0, g22To19x0, g22To20x0, g22To21x0, g22To22x0, g22To23x0, g22To24x0, g22To25x0, g22To26x0, g22To27x0, g22To28x0, g22To29x0, g22To30x0, g22To31x0, g22To32x0, g22To33x0, g22To34x0, g22To35x0, g22To36x0, g22To37x0, g22To38x0, g22To39x0, g22To40x0, g22To41x0, g22To42x0, g22To43x0, g22To44x0, g22To45x0, g22To46x0, g22To47x0, g22To48x0, g22To49x0, g22To50x0, g22To51x0, g22To52x0, g22To53x0, g22To54x0, g22To55x0, g22To56x0, g22To57x0, g22To58x0, g22To59x0, g22To60x0, g22To61x0, g22To62x0, g22To63x0, g22To64x0, g22To65x0, g22To66x0, g22To67x0, g22To68x0, g22To69x0, g22To70x0, g22To71x0, g22To72x0, g22To73x0, g22To74x0, g22To75x0, g22To76x0, g22To77x0, g22To78x0, g22To79x0, g22To80x0, g22To81x0, g22To82x0, g22To83x0, g22To84x0, g22To85x0, g22To86x0, g22To87x0, g22To88x0, g22To89x0, g22To90x0, g22To91x0, g22To92x0, g22To93x0, g22To94x0, g22To95x0, g22To96x0, g22To97x0, g22To98x0, g22To99x0, g22To100x0, g22To101x0, g22To102x0, g22To103x0, g22To104x0, g22To105x0, g22To106x0, g22To107x0, g22To108x0, g22To109x0, g22To110x0, g22To111x0, g22To112x0, g22To113x0, g22To114x0, g22To115x0, g22To116x0, g22To117x0, g22To118x0, g22To119x0, g22To120x0, g22To121x0, g22To122x0, g22To123x0, g22To124x0, g22To125x0, g22To126x0, g22To127x0, g22To128x0, g22To129x0, g22To130x0, g22To131x0, g22To132x0, g22To133x0, g22To134x0, g22To135x0, g22To136x0, g22To137x0, g22To138x0, g22To139x0, g22To140x0, g22To141x0, g22To142x0, g22To143x0, g22To144x0, g22To145x0, g22To146x0, g22To147x0, g22To148x0, g22To149x0, g22To150x0, g22To151x0, g22To152x0, g22To153x0, g22To154x0, g22To155x0, g22To156x0, g22To157x0, g22To158x0, g22To159x0, g22To160x0, g22To161x0, g22To162x0, g22To163x0, g22To164x0, g22To165x0, g22To166x0, g22To167x0, g22To168x0, g22To169x0, g22To170x0, g22To171x0, g22To172x0, g22To173x0, g22To174x0, g22To175x0, g22To176x0, g22To177x0, g22To178x0, g22To179x0, g22To180x0, g22To181x0, g22To182x0, g22To183x0, g22To184x0, g22To185x0, g22To186x0, g22To187x0, g22To188x0, g22To189x0, g22To190x0, g22To191x0, g22To192x0, g22To193x0, g22To194x0, g22To195x0, g22To196x0, g22To197x0, g22To198x0, g22To199x0, g22To200x0, g22To201x0, g22To202x0, g22To203x0, g22To204x0, g22To205x0, g22To206x0, g22To207x0, g22To208x0, g22To209x0, g22To210x0, g22To211x0, g22To212x0, g22To213x0, g22To214x0, g22To215x0, g22To216x0, g22To217x0, g22To218x0, g22To219x0, g22To220x0, g22To221x0, g22To222x0, g22To223x0, g22To224x0, g22To225x0, g22To226x0, g22To227x0, g22To228x0, g22To229x0, g22To230x0, g22To231x0, g22To232x0, g22To233x0, g22To234x0, g22To235x0, g22To236x0, g22To237x0, g22To238x0, g22To239x0, g22To240x0, g22To241x0, g22To242x0, g22To243x0, g22To244x0, g22To245x0, g22To246x0, g22To247x0, g22To248x0, g22To249x0, g22To250x0, g22To251x0, g22To252x0}, - G2mx1: [253]*big.Int{g23x1, g25x1, g27x1, g22To3x1, g22To4x1, g22To5x1, g22To6x1, g22To7x1, g22To8x1, g22To9x1, g22To10x1, g22To11x1, g22To12x1, g22To13x1, g22To14x1, g22To15x1, g22To16x1, g22To17x1, g22To18x1, g22To19x1, g22To20x1, g22To21x1, g22To22x1, g22To23x1, g22To24x1, g22To25x1, g22To26x1, g22To27x1, g22To28x1, g22To29x1, g22To30x1, g22To31x1, g22To32x1, g22To33x1, g22To34x1, g22To35x1, g22To36x1, g22To37x1, g22To38x1, g22To39x1, g22To40x1, g22To41x1, g22To42x1, g22To43x1, g22To44x1, g22To45x1, g22To46x1, g22To47x1, g22To48x1, g22To49x1, g22To50x1, g22To51x1, g22To52x1, g22To53x1, g22To54x1, g22To55x1, g22To56x1, g22To57x1, g22To58x1, g22To59x1, g22To60x1, g22To61x1, g22To62x1, g22To63x1, g22To64x1, g22To65x1, g22To66x1, g22To67x1, g22To68x1, g22To69x1, g22To70x1, g22To71x1, g22To72x1, g22To73x1, g22To74x1, g22To75x1, g22To76x1, g22To77x1, g22To78x1, g22To79x1, g22To80x1, g22To81x1, g22To82x1, g22To83x1, g22To84x1, g22To85x1, g22To86x1, g22To87x1, g22To88x1, g22To89x1, g22To90x1, g22To91x1, g22To92x1, g22To93x1, g22To94x1, g22To95x1, g22To96x1, g22To97x1, g22To98x1, g22To99x1, g22To100x1, g22To101x1, g22To102x1, g22To103x1, g22To104x1, g22To105x1, g22To106x1, g22To107x1, g22To108x1, g22To109x1, g22To110x1, g22To111x1, g22To112x1, g22To113x1, g22To114x1, g22To115x1, g22To116x1, g22To117x1, g22To118x1, g22To119x1, g22To120x1, g22To121x1, g22To122x1, g22To123x1, g22To124x1, g22To125x1, g22To126x1, g22To127x1, g22To128x1, g22To129x1, g22To130x1, g22To131x1, g22To132x1, g22To133x1, g22To134x1, g22To135x1, g22To136x1, g22To137x1, g22To138x1, g22To139x1, g22To140x1, g22To141x1, g22To142x1, g22To143x1, g22To144x1, g22To145x1, g22To146x1, g22To147x1, g22To148x1, g22To149x1, g22To150x1, g22To151x1, g22To152x1, g22To153x1, g22To154x1, g22To155x1, g22To156x1, g22To157x1, g22To158x1, g22To159x1, g22To160x1, g22To161x1, g22To162x1, g22To163x1, g22To164x1, g22To165x1, g22To166x1, g22To167x1, g22To168x1, g22To169x1, g22To170x1, g22To171x1, g22To172x1, g22To173x1, g22To174x1, g22To175x1, g22To176x1, g22To177x1, g22To178x1, g22To179x1, g22To180x1, g22To181x1, g22To182x1, g22To183x1, g22To184x1, g22To185x1, g22To186x1, g22To187x1, g22To188x1, g22To189x1, g22To190x1, g22To191x1, g22To192x1, g22To193x1, g22To194x1, g22To195x1, g22To196x1, g22To197x1, g22To198x1, g22To199x1, g22To200x1, g22To201x1, g22To202x1, g22To203x1, g22To204x1, g22To205x1, g22To206x1, g22To207x1, g22To208x1, g22To209x1, g22To210x1, g22To211x1, g22To212x1, g22To213x1, g22To214x1, g22To215x1, g22To216x1, g22To217x1, g22To218x1, g22To219x1, g22To220x1, g22To221x1, g22To222x1, g22To223x1, g22To224x1, g22To225x1, g22To226x1, g22To227x1, g22To228x1, g22To229x1, g22To230x1, g22To231x1, g22To232x1, g22To233x1, g22To234x1, g22To235x1, g22To236x1, g22To237x1, g22To238x1, g22To239x1, g22To240x1, g22To241x1, g22To242x1, g22To243x1, g22To244x1, g22To245x1, g22To246x1, g22To247x1, g22To248x1, g22To249x1, g22To250x1, g22To251x1, g22To252x1}, - G2my0: [253]*big.Int{g23y0, g25y0, g27y0, g22To3y0, g22To4y0, g22To5y0, g22To6y0, g22To7y0, g22To8y0, g22To9y0, g22To10y0, g22To11y0, g22To12y0, g22To13y0, g22To14y0, g22To15y0, g22To16y0, g22To17y0, g22To18y0, g22To19y0, g22To20y0, g22To21y0, g22To22y0, g22To23y0, g22To24y0, g22To25y0, g22To26y0, g22To27y0, g22To28y0, g22To29y0, g22To30y0, g22To31y0, g22To32y0, g22To33y0, g22To34y0, g22To35y0, g22To36y0, g22To37y0, g22To38y0, g22To39y0, g22To40y0, g22To41y0, g22To42y0, g22To43y0, g22To44y0, g22To45y0, g22To46y0, g22To47y0, g22To48y0, g22To49y0, g22To50y0, g22To51y0, g22To52y0, g22To53y0, g22To54y0, g22To55y0, g22To56y0, g22To57y0, g22To58y0, g22To59y0, g22To60y0, g22To61y0, g22To62y0, g22To63y0, g22To64y0, g22To65y0, g22To66y0, g22To67y0, g22To68y0, g22To69y0, g22To70y0, g22To71y0, g22To72y0, g22To73y0, g22To74y0, g22To75y0, g22To76y0, g22To77y0, g22To78y0, g22To79y0, g22To80y0, g22To81y0, g22To82y0, g22To83y0, g22To84y0, g22To85y0, g22To86y0, g22To87y0, g22To88y0, g22To89y0, g22To90y0, g22To91y0, g22To92y0, g22To93y0, g22To94y0, g22To95y0, g22To96y0, g22To97y0, g22To98y0, g22To99y0, g22To100y0, g22To101y0, g22To102y0, g22To103y0, g22To104y0, g22To105y0, g22To106y0, g22To107y0, g22To108y0, g22To109y0, g22To110y0, g22To111y0, g22To112y0, g22To113y0, g22To114y0, g22To115y0, g22To116y0, g22To117y0, g22To118y0, g22To119y0, g22To120y0, g22To121y0, g22To122y0, g22To123y0, g22To124y0, g22To125y0, g22To126y0, g22To127y0, g22To128y0, g22To129y0, g22To130y0, g22To131y0, g22To132y0, g22To133y0, g22To134y0, g22To135y0, g22To136y0, g22To137y0, g22To138y0, g22To139y0, g22To140y0, g22To141y0, g22To142y0, g22To143y0, g22To144y0, g22To145y0, g22To146y0, g22To147y0, g22To148y0, g22To149y0, g22To150y0, g22To151y0, g22To152y0, g22To153y0, g22To154y0, g22To155y0, g22To156y0, g22To157y0, g22To158y0, g22To159y0, g22To160y0, g22To161y0, g22To162y0, g22To163y0, g22To164y0, g22To165y0, g22To166y0, g22To167y0, g22To168y0, g22To169y0, g22To170y0, g22To171y0, g22To172y0, g22To173y0, g22To174y0, g22To175y0, g22To176y0, g22To177y0, g22To178y0, g22To179y0, g22To180y0, g22To181y0, g22To182y0, g22To183y0, g22To184y0, g22To185y0, g22To186y0, g22To187y0, g22To188y0, g22To189y0, g22To190y0, g22To191y0, g22To192y0, g22To193y0, g22To194y0, g22To195y0, g22To196y0, g22To197y0, g22To198y0, g22To199y0, g22To200y0, g22To201y0, g22To202y0, g22To203y0, g22To204y0, g22To205y0, g22To206y0, g22To207y0, g22To208y0, g22To209y0, g22To210y0, g22To211y0, g22To212y0, g22To213y0, g22To214y0, g22To215y0, g22To216y0, g22To217y0, g22To218y0, g22To219y0, g22To220y0, g22To221y0, g22To222y0, g22To223y0, g22To224y0, g22To225y0, g22To226y0, g22To227y0, g22To228y0, g22To229y0, g22To230y0, g22To231y0, g22To232y0, g22To233y0, g22To234y0, g22To235y0, g22To236y0, g22To237y0, g22To238y0, g22To239y0, g22To240y0, g22To241y0, g22To242y0, g22To243y0, g22To244y0, g22To245y0, g22To246y0, g22To247y0, g22To248y0, g22To249y0, g22To250y0, g22To251y0, g22To252y0}, - G2my1: [253]*big.Int{g23y1, g25y1, g27y1, g22To3y1, g22To4y1, g22To5y1, g22To6y1, g22To7y1, g22To8y1, g22To9y1, g22To10y1, g22To11y1, g22To12y1, g22To13y1, g22To14y1, g22To15y1, g22To16y1, g22To17y1, g22To18y1, g22To19y1, g22To20y1, g22To21y1, g22To22y1, g22To23y1, g22To24y1, g22To25y1, g22To26y1, g22To27y1, g22To28y1, g22To29y1, g22To30y1, g22To31y1, g22To32y1, g22To33y1, g22To34y1, g22To35y1, g22To36y1, g22To37y1, g22To38y1, g22To39y1, g22To40y1, g22To41y1, g22To42y1, g22To43y1, g22To44y1, g22To45y1, g22To46y1, g22To47y1, g22To48y1, g22To49y1, g22To50y1, g22To51y1, g22To52y1, g22To53y1, g22To54y1, g22To55y1, g22To56y1, g22To57y1, g22To58y1, g22To59y1, g22To60y1, g22To61y1, g22To62y1, g22To63y1, g22To64y1, g22To65y1, g22To66y1, g22To67y1, g22To68y1, g22To69y1, g22To70y1, g22To71y1, g22To72y1, g22To73y1, g22To74y1, g22To75y1, g22To76y1, g22To77y1, g22To78y1, g22To79y1, g22To80y1, g22To81y1, g22To82y1, g22To83y1, g22To84y1, g22To85y1, g22To86y1, g22To87y1, g22To88y1, g22To89y1, g22To90y1, g22To91y1, g22To92y1, g22To93y1, g22To94y1, g22To95y1, g22To96y1, g22To97y1, g22To98y1, g22To99y1, g22To100y1, g22To101y1, g22To102y1, g22To103y1, g22To104y1, g22To105y1, g22To106y1, g22To107y1, g22To108y1, g22To109y1, g22To110y1, g22To111y1, g22To112y1, g22To113y1, g22To114y1, g22To115y1, g22To116y1, g22To117y1, g22To118y1, g22To119y1, g22To120y1, g22To121y1, g22To122y1, g22To123y1, g22To124y1, g22To125y1, g22To126y1, g22To127y1, g22To128y1, g22To129y1, g22To130y1, g22To131y1, g22To132y1, g22To133y1, g22To134y1, g22To135y1, g22To136y1, g22To137y1, g22To138y1, g22To139y1, g22To140y1, g22To141y1, g22To142y1, g22To143y1, g22To144y1, g22To145y1, g22To146y1, g22To147y1, g22To148y1, g22To149y1, g22To150y1, g22To151y1, g22To152y1, g22To153y1, g22To154y1, g22To155y1, g22To156y1, g22To157y1, g22To158y1, g22To159y1, g22To160y1, g22To161y1, g22To162y1, g22To163y1, g22To164y1, g22To165y1, g22To166y1, g22To167y1, g22To168y1, g22To169y1, g22To170y1, g22To171y1, g22To172y1, g22To173y1, g22To174y1, g22To175y1, g22To176y1, g22To177y1, g22To178y1, g22To179y1, g22To180y1, g22To181y1, g22To182y1, g22To183y1, g22To184y1, g22To185y1, g22To186y1, g22To187y1, g22To188y1, g22To189y1, g22To190y1, g22To191y1, g22To192y1, g22To193y1, g22To194y1, g22To195y1, g22To196y1, g22To197y1, g22To198y1, g22To199y1, g22To200y1, g22To201y1, g22To202y1, g22To203y1, g22To204y1, g22To205y1, g22To206y1, g22To207y1, g22To208y1, g22To209y1, g22To210y1, g22To211y1, g22To212y1, g22To213y1, g22To214y1, g22To215y1, g22To216y1, g22To217y1, g22To218y1, g22To219y1, g22To220y1, g22To221y1, g22To222y1, g22To223y1, g22To224y1, g22To225y1, g22To226y1, g22To227y1, g22To228y1, g22To229y1, g22To230y1, g22To231y1, g22To232y1, g22To233y1, g22To234y1, g22To235y1, g22To236y1, g22To237y1, g22To238y1, g22To239y1, g22To240y1, g22To241y1, g22To242y1, g22To243y1, g22To244y1, g22To245y1, g22To246y1, g22To247y1, g22To248y1, g22To249y1, g22To250y1, g22To251y1, g22To252y1}, + G2x: [2]*big.Int{g2x0, g2x1}, + G2y: [2]*big.Int{g2y0, g2y1}, + G2m: computeBLS12377TwistTable(), } } diff --git a/std/algebra/sw_bls12377/inner_compute.go b/std/algebra/sw_bls12377/inner_compute.go index 88388a2535..3ddbc2ece2 100644 --- a/std/algebra/sw_bls12377/inner_compute.go +++ b/std/algebra/sw_bls12377/inner_compute.go @@ -6,21 +6,21 @@ import ( bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377" ) -func computeBLS12377Table() [][2]*big.Int { - Gjac, _, _, _ := bls12377.Generators() +func computeBLS12377CurveTable() [][2]*big.Int { + G1jac, _, _, _ := bls12377.Generators() table := make([][2]*big.Int, 253) - tmp := new(bls12377.G1Jac).Set(&Gjac) + tmp := new(bls12377.G1Jac).Set(&G1jac) aff := new(bls12377.G1Affine) jac := new(bls12377.G1Jac) for i := 1; i < 253; i++ { tmp = tmp.Double(tmp) switch i { case 1, 2: - jac.Set(tmp).AddAssign(&Gjac) + jac.Set(tmp).AddAssign(&G1jac) aff.FromJacobian(jac) table[i-1] = [2]*big.Int{aff.X.BigInt(new(big.Int)), aff.Y.BigInt(new(big.Int))} case 3: - jac.Set(tmp).SubAssign(&Gjac) + jac.Set(tmp).SubAssign(&G1jac) aff.FromJacobian(jac) table[i-1] = [2]*big.Int{aff.X.BigInt(new(big.Int)), aff.Y.BigInt(new(big.Int))} fallthrough @@ -31,3 +31,29 @@ func computeBLS12377Table() [][2]*big.Int { } return table[:] } + +func computeBLS12377TwistTable() [][4]*big.Int { + _, G2jac, _, _ := bls12377.Generators() + table := make([][4]*big.Int, 253) + tmp := new(bls12377.G2Jac).Set(&G2jac) + aff := new(bls12377.G2Affine) + jac := new(bls12377.G2Jac) + for i := 1; i < 253; i++ { + tmp = tmp.Double(tmp) + switch i { + case 1, 2: + jac.Set(tmp).AddAssign(&G2jac) + aff.FromJacobian(jac) + table[i-1] = [4]*big.Int{aff.X.A0.BigInt(new(big.Int)), aff.X.A1.BigInt(new(big.Int)), aff.Y.A0.BigInt(new(big.Int)), aff.Y.A1.BigInt(new(big.Int))} + case 3: + jac.Set(tmp).SubAssign(&G2jac) + aff.FromJacobian(jac) + table[i-1] = [4]*big.Int{aff.X.A0.BigInt(new(big.Int)), aff.X.A1.BigInt(new(big.Int)), aff.Y.A0.BigInt(new(big.Int)), aff.Y.A1.BigInt(new(big.Int))} + fallthrough + default: + aff.FromJacobian(tmp) + table[i] = [4]*big.Int{aff.X.A0.BigInt(new(big.Int)), aff.X.A1.BigInt(new(big.Int)), aff.Y.A0.BigInt(new(big.Int)), aff.Y.A1.BigInt(new(big.Int))} + } + } + return table[:] +} From 7590869ca9a976f9e1015e579005b800b5113a10 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Thu, 2 Mar 2023 11:54:19 +0100 Subject: [PATCH 042/464] perf: ScalarMulBase for sw_bls24315 G1/G2 + KZG in-circuit --- std/algebra/fields_bls24315/e2.go | 13 ++++ std/algebra/fields_bls24315/e4.go | 13 ++++ std/algebra/sw_bls24315/g1.go | 33 +++++++++ std/algebra/sw_bls24315/g1_test.go | 31 ++++++++ std/algebra/sw_bls24315/g2.go | 70 +++++++++++++++++++ std/algebra/sw_bls24315/g2_test.go | 32 +++++++++ std/algebra/sw_bls24315/inner.go | 39 +++++++++++ std/algebra/sw_bls24315/inner_compute.go | 59 ++++++++++++++++ std/commitments/kzg_bls24315/verifier.go | 5 +- std/commitments/kzg_bls24315/verifier_test.go | 5 -- 10 files changed, 292 insertions(+), 8 deletions(-) create mode 100644 std/algebra/sw_bls24315/inner_compute.go diff --git a/std/algebra/fields_bls24315/e2.go b/std/algebra/fields_bls24315/e2.go index b850ef025b..1fd9944ee7 100644 --- a/std/algebra/fields_bls24315/e2.go +++ b/std/algebra/fields_bls24315/e2.go @@ -244,3 +244,16 @@ func (e *E2) Select(api frontend.API, b frontend.Variable, r1, r2 E2) *E2 { return e } + +// Lookup2 implements two-bit lookup. It returns: +// - r1 if b1=0 and b2=0, +// - r2 if b1=0 and b2=1, +// - r3 if b1=1 and b2=0, +// - r3 if b1=1 and b2=1. +func (e *E2) Lookup2(api frontend.API, b1, b2 frontend.Variable, r1, r2, r3, r4 E2) *E2 { + + e.A0 = api.Lookup2(b1, b2, r1.A0, r2.A0, r3.A0, r4.A0) + e.A1 = api.Lookup2(b1, b2, r1.A1, r2.A1, r3.A1, r4.A1) + + return e +} diff --git a/std/algebra/fields_bls24315/e4.go b/std/algebra/fields_bls24315/e4.go index 57abb6ccf8..8cec05902f 100644 --- a/std/algebra/fields_bls24315/e4.go +++ b/std/algebra/fields_bls24315/e4.go @@ -253,3 +253,16 @@ func (e *E4) Select(api frontend.API, b frontend.Variable, r1, r2 E4) *E4 { return e } + +// Lookup2 implements two-bit lookup. It returns: +// - r1 if b1=0 and b2=0, +// - r2 if b1=0 and b2=1, +// - r3 if b1=1 and b2=0, +// - r3 if b1=1 and b2=1. +func (e *E4) Lookup2(api frontend.API, b1, b2 frontend.Variable, r1, r2, r3, r4 E4) *E4 { + + e.B0.Lookup2(api, b1, b2, r1.B0, r2.B0, r3.B0, r4.B0) + e.B1.Lookup2(api, b1, b2, r1.B1, r2.B1, r3.B1, r4.B1) + + return e +} diff --git a/std/algebra/sw_bls24315/g1.go b/std/algebra/sw_bls24315/g1.go index 1e8b12fd0e..c2f6e9bb00 100644 --- a/std/algebra/sw_bls24315/g1.go +++ b/std/algebra/sw_bls24315/g1.go @@ -451,3 +451,36 @@ func (p *G1Affine) DoubleAndAdd(api frontend.API, p1, p2 *G1Affine) *G1Affine { return p } + +// ScalarMulBase computes s * g1 and returns it, where g1 is the fixed generator. It doesn't modify s. +func (P *G1Affine) ScalarMulBase(api frontend.API, s frontend.Variable) *G1Affine { + + points := GetBLS24315CurvePoints() + + sBits := api.ToBinary(s, 253) + + var res, tmp G1Affine + + // i = 1, 2 + // gm[0] = 3g, gm[1] = 5g, gm[2] = 7g + res.X = api.Lookup2(sBits[1], sBits[2], points.G1x, points.G1m[0][0], points.G1m[1][0], points.G1m[2][0]) + res.Y = api.Lookup2(sBits[1], sBits[2], points.G1y, points.G1m[0][1], points.G1m[1][1], points.G1m[2][1]) + + for i := 3; i < 253; i++ { + // gm[i] = [2^i]g + tmp.X = res.X + tmp.Y = res.Y + tmp.AddAssign(api, G1Affine{points.G1m[i][0], points.G1m[i][1]}) + res.Select(api, sBits[i], tmp, res) + } + + // i = 0 + tmp.Neg(api, G1Affine{points.G1x, points.G1y}) + tmp.AddAssign(api, res) + res.Select(api, sBits[0], res, tmp) + + P.X = res.X + P.Y = res.Y + + return P +} diff --git a/std/algebra/sw_bls24315/g1_test.go b/std/algebra/sw_bls24315/g1_test.go index 86feeeb571..c4e02779d0 100644 --- a/std/algebra/sw_bls24315/g1_test.go +++ b/std/algebra/sw_bls24315/g1_test.go @@ -369,6 +369,37 @@ func TestScalarMulG1(t *testing.T) { assert.SolvingSucceeded(&circuit, &witness, test.WithCurves(ecc.BW6_633)) } +type g1varScalarMulBase struct { + C G1Affine `gnark:",public"` + R frontend.Variable +} + +func (circuit *g1varScalarMulBase) Define(api frontend.API) error { + expected := G1Affine{} + expected.ScalarMulBase(api, circuit.R) + expected.AssertIsEqual(api, circuit.C) + return nil +} + +func TestVarScalarMulBaseG1(t *testing.T) { + var c bls24315.G1Affine + gJac, _, _, _ := bls24315.Generators() + + // create the cs + var circuit, witness g1varScalarMulBase + var r fr.Element + _, _ = r.SetRandom() + witness.R = r.String() + // compute the result + var br big.Int + gJac.ScalarMultiplication(&gJac, r.BigInt(&br)) + c.FromJacobian(&gJac) + witness.C.Assign(&c) + + assert := test.NewAssert(t) + assert.SolvingSucceeded(&circuit, &witness, test.WithCurves(ecc.BW6_633)) +} + func randomPointG1() bls24315.G1Jac { p1, _, _, _ := bls24315.Generators() diff --git a/std/algebra/sw_bls24315/g2.go b/std/algebra/sw_bls24315/g2.go index 001fe45f5d..3f15b48175 100644 --- a/std/algebra/sw_bls24315/g2.go +++ b/std/algebra/sw_bls24315/g2.go @@ -471,3 +471,73 @@ func (p *G2Affine) DoubleAndAdd(api frontend.API, p1, p2 *G2Affine) *G2Affine { return p } + +// ScalarMulBase computes s * g2 and returns it, where g2 is the fixed generator. It doesn't modify s. +func (P *G2Affine) ScalarMulBase(api frontend.API, s frontend.Variable) *G2Affine { + + points := GetBLS24315TwistPoints() + + sBits := api.ToBinary(s, 253) + + var res, tmp G2Affine + + // i = 1, 2 + // gm[0] = 3g, gm[1] = 5g, gm[2] = 7g + res.X.Lookup2(api, sBits[1], sBits[2], + fields_bls24315.E4{ + B0: fields_bls24315.E2{A0: points.G2x[0], A1: points.G2x[1]}, + B1: fields_bls24315.E2{A0: points.G2x[2], A1: points.G2x[3]}}, + fields_bls24315.E4{ + B0: fields_bls24315.E2{A0: points.G2m[0][0], A1: points.G2m[0][1]}, + B1: fields_bls24315.E2{A0: points.G2m[0][2], A1: points.G2m[0][3]}}, + fields_bls24315.E4{ + B0: fields_bls24315.E2{A0: points.G2m[1][0], A1: points.G2m[1][1]}, + B1: fields_bls24315.E2{A0: points.G2m[1][2], A1: points.G2m[1][3]}}, + fields_bls24315.E4{ + B0: fields_bls24315.E2{A0: points.G2m[2][0], A1: points.G2m[2][1]}, + B1: fields_bls24315.E2{A0: points.G2m[2][2], A1: points.G2m[2][3]}}) + + res.Y.Lookup2(api, sBits[1], sBits[2], + fields_bls24315.E4{ + B0: fields_bls24315.E2{A0: points.G2y[0], A1: points.G2y[1]}, + B1: fields_bls24315.E2{A0: points.G2y[2], A1: points.G2y[3]}}, + fields_bls24315.E4{ + B0: fields_bls24315.E2{A0: points.G2m[0][4], A1: points.G2m[0][5]}, + B1: fields_bls24315.E2{A0: points.G2m[0][6], A1: points.G2m[0][7]}}, + fields_bls24315.E4{ + B0: fields_bls24315.E2{A0: points.G2m[1][4], A1: points.G2m[1][5]}, + B1: fields_bls24315.E2{A0: points.G2m[1][6], A1: points.G2m[1][7]}}, + fields_bls24315.E4{ + B0: fields_bls24315.E2{A0: points.G2m[2][4], A1: points.G2m[2][5]}, + B1: fields_bls24315.E2{A0: points.G2m[2][6], A1: points.G2m[2][7]}}) + + for i := 3; i < 253; i++ { + // gm[i] = [2^i]g + tmp.X = res.X + tmp.Y = res.Y + tmp.AddAssign(api, G2Affine{ + X: fields_bls24315.E4{ + B0: fields_bls24315.E2{A0: points.G2m[i][0], A1: points.G2m[i][1]}, + B1: fields_bls24315.E2{A0: points.G2m[i][2], A1: points.G2m[i][3]}}, + Y: fields_bls24315.E4{ + B0: fields_bls24315.E2{A0: points.G2m[i][4], A1: points.G2m[i][5]}, + B1: fields_bls24315.E2{A0: points.G2m[i][6], A1: points.G2m[i][7]}}}) + res.Select(api, sBits[i], tmp, res) + } + + // i = 0 + tmp.Neg(api, G2Affine{ + X: fields_bls24315.E4{ + B0: fields_bls24315.E2{A0: points.G2x[0], A1: points.G2x[1]}, + B1: fields_bls24315.E2{A0: points.G2x[2], A1: points.G2x[3]}}, + Y: fields_bls24315.E4{ + B0: fields_bls24315.E2{A0: points.G2y[0], A1: points.G2y[1]}, + B1: fields_bls24315.E2{A0: points.G2y[2], A1: points.G2y[3]}}}) + tmp.AddAssign(api, res) + res.Select(api, sBits[0], res, tmp) + + P.X = res.X + P.Y = res.Y + + return P +} diff --git a/std/algebra/sw_bls24315/g2_test.go b/std/algebra/sw_bls24315/g2_test.go index 0c8fb3ad20..13034f058e 100644 --- a/std/algebra/sw_bls24315/g2_test.go +++ b/std/algebra/sw_bls24315/g2_test.go @@ -374,6 +374,38 @@ func TestScalarMulG2(t *testing.T) { assert := test.NewAssert(t) assert.SolvingSucceeded(&circuit, &witness, test.WithCurves(ecc.BW6_633)) } + +type g2varScalarMulBase struct { + C G2Affine `gnark:",public"` + R frontend.Variable +} + +func (circuit *g2varScalarMulBase) Define(api frontend.API) error { + expected := G2Affine{} + expected.ScalarMulBase(api, circuit.R) + expected.AssertIsEqual(api, circuit.C) + return nil +} + +func TestVarScalarMulBaseG2(t *testing.T) { + var c bls24315.G2Affine + _, gJac, _, _ := bls24315.Generators() + + // create the cs + var circuit, witness g2varScalarMulBase + var r fr.Element + _, _ = r.SetRandom() + witness.R = r.String() + // compute the result + var br big.Int + gJac.ScalarMultiplication(&gJac, r.BigInt(&br)) + c.FromJacobian(&gJac) + witness.C.Assign(&c) + + assert := test.NewAssert(t) + assert.SolvingSucceeded(&circuit, &witness, test.WithCurves(ecc.BW6_633)) +} + func randomPointG2() bls24315.G2Jac { _, p2, _, _ := bls24315.Generators() diff --git a/std/algebra/sw_bls24315/inner.go b/std/algebra/sw_bls24315/inner.go index 42b6355cd0..6ab2e94374 100644 --- a/std/algebra/sw_bls24315/inner.go +++ b/std/algebra/sw_bls24315/inner.go @@ -65,3 +65,42 @@ func (cc *innerConfig) phi2(api frontend.API, res, P *G2Affine) *G2Affine { res.Y = P.Y return res } + +type CurvePoints struct { + G1x *big.Int // base point x + G1y *big.Int // base point y + G1m [][2]*big.Int // m*base points (x,y) +} + +func GetBLS24315CurvePoints() CurvePoints { + g1x, _ := new(big.Int).SetString("41a0a424393988da1b2b117076ef6e4f54b344cc46dde3c983603a832cb638dbf4b721710866097", 16) + g1y, _ := new(big.Int).SetString("2e6f83c55deff20227ecdf0db2bb2ebb5d72c8a29010871d3cce9059e83dfb96f2922d5da4e4e5f", 16) + return CurvePoints{ + G1x: g1x, + G1y: g1y, + G1m: computeBLS24315CurveTable(), + } +} + +type TwistPoints struct { + G2x [4]*big.Int // base point x ∈ E4 + G2y [4]*big.Int // base point y ∈ E4 + G2m [][8]*big.Int // m*base points (x,y) +} + +func GetBLS24315TwistPoints() TwistPoints { + g2x0, _ := new(big.Int).SetString("2f339ada8942f92aefa14196bfee2552a7c5675f5e5e9da798458f72ff50f96f5c357cf13710f63", 16) + g2x1, _ := new(big.Int).SetString("20b1a8dca4b18842b40079be727cbfd1a16ed134a080b759ae503618e92871697838dc4c689911c", 16) + g2x2, _ := new(big.Int).SetString("16eab1e76670eb9affa1bc77400be688d5cd69566f9325b329b40db85b47f236d5c34e8ffed7536", 16) + g2x3, _ := new(big.Int).SetString("6e8c608261f21c41f2479ca4824deba561b9689a9c03a5b8b36a6cbbed0a7d9468e07e557d8569", 16) + g2y0, _ := new(big.Int).SetString("3cdd8218baa5276421c9923cde33a45399a1d878d5202fae600a8502a29681f74ccdcc053b278b7", 16) + g2y1, _ := new(big.Int).SetString("3a079c670190bb49b1bd21e10aac3191535e32ce99da592ddfa8bd09d57a7374ed63ad7f25e398d", 16) + g2y2, _ := new(big.Int).SetString("1b38dd0c5ec49a0883a950c631c688eb3b01f45b7c0d2990cd99052005ebf2fa9e7043bbd605ef5", 16) + g2y3, _ := new(big.Int).SetString("495d6de2e4fed6be3e1d24dd724163e01d88643f7e83d31528ab0a80ced619175a1a104574ac83", 16) + return TwistPoints{ + G2x: [4]*big.Int{g2x0, g2x1, g2x2, g2x3}, + G2y: [4]*big.Int{g2y0, g2y1, g2y2, g2y3}, + G2m: computeBLS24315TwistTable(), + } + +} diff --git a/std/algebra/sw_bls24315/inner_compute.go b/std/algebra/sw_bls24315/inner_compute.go new file mode 100644 index 0000000000..43d03e8b11 --- /dev/null +++ b/std/algebra/sw_bls24315/inner_compute.go @@ -0,0 +1,59 @@ +package sw_bls24315 + +import ( + "math/big" + + bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315" +) + +func computeBLS24315CurveTable() [][2]*big.Int { + G1jac, _, _, _ := bls24315.Generators() + table := make([][2]*big.Int, 253) + tmp := new(bls24315.G1Jac).Set(&G1jac) + aff := new(bls24315.G1Affine) + jac := new(bls24315.G1Jac) + for i := 1; i < 253; i++ { + tmp = tmp.Double(tmp) + switch i { + case 1, 2: + jac.Set(tmp).AddAssign(&G1jac) + aff.FromJacobian(jac) + table[i-1] = [2]*big.Int{aff.X.BigInt(new(big.Int)), aff.Y.BigInt(new(big.Int))} + case 3: + jac.Set(tmp).SubAssign(&G1jac) + aff.FromJacobian(jac) + table[i-1] = [2]*big.Int{aff.X.BigInt(new(big.Int)), aff.Y.BigInt(new(big.Int))} + fallthrough + default: + aff.FromJacobian(tmp) + table[i] = [2]*big.Int{aff.X.BigInt(new(big.Int)), aff.Y.BigInt(new(big.Int))} + } + } + return table[:] +} + +func computeBLS24315TwistTable() [][8]*big.Int { + _, G2jac, _, _ := bls24315.Generators() + table := make([][8]*big.Int, 253) + tmp := new(bls24315.G2Jac).Set(&G2jac) + aff := new(bls24315.G2Affine) + jac := new(bls24315.G2Jac) + for i := 1; i < 253; i++ { + tmp = tmp.Double(tmp) + switch i { + case 1, 2: + jac.Set(tmp).AddAssign(&G2jac) + aff.FromJacobian(jac) + table[i-1] = [8]*big.Int{aff.X.B0.A0.BigInt(new(big.Int)), aff.X.B0.A1.BigInt(new(big.Int)), aff.X.B1.A0.BigInt(new(big.Int)), aff.X.B1.A1.BigInt(new(big.Int)), aff.Y.B0.A0.BigInt(new(big.Int)), aff.Y.B0.A1.BigInt(new(big.Int)), aff.Y.B1.A0.BigInt(new(big.Int)), aff.Y.B1.A1.BigInt(new(big.Int))} + case 3: + jac.Set(tmp).SubAssign(&G2jac) + aff.FromJacobian(jac) + table[i-1] = [8]*big.Int{aff.X.B0.A0.BigInt(new(big.Int)), aff.X.B0.A1.BigInt(new(big.Int)), aff.X.B1.A0.BigInt(new(big.Int)), aff.X.B1.A1.BigInt(new(big.Int)), aff.Y.B0.A0.BigInt(new(big.Int)), aff.Y.B0.A1.BigInt(new(big.Int)), aff.Y.B1.A0.BigInt(new(big.Int)), aff.Y.B1.A1.BigInt(new(big.Int))} + fallthrough + default: + aff.FromJacobian(tmp) + table[i] = [8]*big.Int{aff.X.B0.A0.BigInt(new(big.Int)), aff.X.B0.A1.BigInt(new(big.Int)), aff.X.B1.A0.BigInt(new(big.Int)), aff.X.B1.A1.BigInt(new(big.Int)), aff.Y.B0.A0.BigInt(new(big.Int)), aff.Y.B0.A1.BigInt(new(big.Int)), aff.Y.B1.A0.BigInt(new(big.Int)), aff.Y.B1.A1.BigInt(new(big.Int))} + } + } + return table[:] +} diff --git a/std/commitments/kzg_bls24315/verifier.go b/std/commitments/kzg_bls24315/verifier.go index 4d7625e2e9..e5704525f8 100644 --- a/std/commitments/kzg_bls24315/verifier.go +++ b/std/commitments/kzg_bls24315/verifier.go @@ -28,7 +28,6 @@ type Digest = sw_bls24315.G1Affine // VK verification key (G2 part of SRS) type VK struct { - G1 sw_bls24315.G1Affine // G₁ G2 [2]sw_bls24315.G2Affine // [G₂, [α]G₂] } @@ -53,7 +52,7 @@ func Verify(api frontend.API, commitment Digest, proof OpeningProof, point front // [f(a)]G₁ var claimedValueG1Aff sw_bls24315.G1Affine - claimedValueG1Aff.ScalarMul(api, srs.G1, proof.ClaimedValue) + claimedValueG1Aff.ScalarMulBase(api, proof.ClaimedValue) // [f(α) - f(a)]G₁ var fminusfaG1 sw_bls24315.G1Affine @@ -66,7 +65,7 @@ func Verify(api frontend.API, commitment Digest, proof OpeningProof, point front // [α-a]G₂ var alphaMinusaG2 sw_bls24315.G2Affine - alphaMinusaG2.ScalarMul(api, srs.G2[0], point). + alphaMinusaG2.ScalarMulBase(api, point). Neg(api, alphaMinusaG2). AddAssign(api, srs.G2[1]) diff --git a/std/commitments/kzg_bls24315/verifier_test.go b/std/commitments/kzg_bls24315/verifier_test.go index d331ce82ed..a937e408ac 100644 --- a/std/commitments/kzg_bls24315/verifier_test.go +++ b/std/commitments/kzg_bls24315/verifier_test.go @@ -98,9 +98,6 @@ func TestVerifierDynamic(t *testing.T) { witness.S = point.String() - witness.VerifKey.G1.X = srs.G1[0].X.String() - witness.VerifKey.G1.Y = srs.G1[0].Y.String() - witness.VerifKey.G2[0].X.B0.A0 = srs.G2[0].X.B0.A0.String() witness.VerifKey.G2[0].X.B0.A1 = srs.G2[0].X.B0.A1.String() witness.VerifKey.G2[0].X.B1.A0 = srs.G2[0].X.B1.A0.String() @@ -141,8 +138,6 @@ func TestVerifier(t *testing.T) { witness.Proof.ClaimedValue = "10347231107172233075459792371577505115223937655290126532055162077965558980163" witness.S = "4321" - witness.VerifKey.G1.X = "34223510504517033132712852754388476272837911830964394866541204856091481856889569724484362330263" - witness.VerifKey.G1.Y = "24215295174889464585413596429561903295150472552154479431771837786124301185073987899223459122783" witness.VerifKey.G2[0].X.B0.A0 = "24614737899199071964341749845083777103809664018538138889239909664991294445469052467064654073699" witness.VerifKey.G2[0].X.B0.A1 = "17049297748993841127032249156255993089778266476087413538366212660716380683149731996715975282972" From 78bb02b7a3090b44f3e5d2e2bf3acb27ad38fb2b Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 2 Mar 2023 12:24:58 +0100 Subject: [PATCH 043/464] refactor: rename methods for getting tables The methods are local to the package. --- std/algebra/sw_bls12377/g1.go | 2 +- std/algebra/sw_bls12377/g2.go | 2 +- std/algebra/sw_bls12377/inner.go | 8 ++++---- std/algebra/sw_bls12377/inner_compute.go | 4 ++-- std/algebra/sw_bls24315/g1.go | 2 +- std/algebra/sw_bls24315/g2.go | 2 +- std/algebra/sw_bls24315/inner.go | 8 ++++---- std/algebra/sw_bls24315/inner_compute.go | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/std/algebra/sw_bls12377/g1.go b/std/algebra/sw_bls12377/g1.go index 6b3bcdeca3..b42d7b225e 100644 --- a/std/algebra/sw_bls12377/g1.go +++ b/std/algebra/sw_bls12377/g1.go @@ -455,7 +455,7 @@ func (p *G1Affine) DoubleAndAdd(api frontend.API, p1, p2 *G1Affine) *G1Affine { // ScalarMulBase computes s * g1 and returns it, where g1 is the fixed generator. It doesn't modify s. func (P *G1Affine) ScalarMulBase(api frontend.API, s frontend.Variable) *G1Affine { - points := GetBLS12377CurvePoints() + points := GetCurvePoints() sBits := api.ToBinary(s, 253) diff --git a/std/algebra/sw_bls12377/g2.go b/std/algebra/sw_bls12377/g2.go index b2e8b80ed3..4a61fcd338 100644 --- a/std/algebra/sw_bls12377/g2.go +++ b/std/algebra/sw_bls12377/g2.go @@ -475,7 +475,7 @@ func (p *G2Affine) DoubleAndAdd(api frontend.API, p1, p2 *G2Affine) *G2Affine { // ScalarMulBase computes s * g2 and returns it, where g2 is the fixed generator. It doesn't modify s. func (P *G2Affine) ScalarMulBase(api frontend.API, s frontend.Variable) *G2Affine { - points := GetBLS12377TwistPoints() + points := GetTwistPoints() sBits := api.ToBinary(s, 253) diff --git a/std/algebra/sw_bls12377/inner.go b/std/algebra/sw_bls12377/inner.go index 5214dc58ee..fee31f09e3 100644 --- a/std/algebra/sw_bls12377/inner.go +++ b/std/algebra/sw_bls12377/inner.go @@ -69,13 +69,13 @@ type CurvePoints struct { G1m [][2]*big.Int // m*base points (x,y) } -func GetBLS12377CurvePoints() CurvePoints { +func GetCurvePoints() CurvePoints { g1x, _ := new(big.Int).SetString("8848defe740a67c8fc6225bf87ff5485951e2caa9d41bb188282c8bd37cb5cd5481512ffcd394eeab9b16eb21be9ef", 16) g1y, _ := new(big.Int).SetString("1914a69c5102eff1f674f5d30afeec4bd7fb348ca3e52d96d182ad44fb82305c2fe3d3634a9591afd82de55559c8ea6", 16) return CurvePoints{ G1x: g1x, G1y: g1y, - G1m: computeBLS12377CurveTable(), + G1m: computeCurveTable(), } } @@ -85,7 +85,7 @@ type TwistPoints struct { G2m [][4]*big.Int // m*base points (x,y) } -func GetBLS12377TwistPoints() TwistPoints { +func GetTwistPoints() TwistPoints { g2x0, _ := new(big.Int).SetString("18480be71c785fec89630a2a3841d01c565f071203e50317ea501f557db6b9b71889f52bb53540274e3e48f7c005196", 16) g2x1, _ := new(big.Int).SetString("ea6040e700403170dc5a51b1b140d5532777ee6651cecbe7223ece0799c9de5cf89984bff76fe6b26bfefa6ea16afe", 16) g2y0, _ := new(big.Int).SetString("690d665d446f7bd960736bcbb2efb4de03ed7274b49a58e458c282f832d204f2cf88886d8c7c2ef094094409fd4ddf", 16) @@ -93,7 +93,7 @@ func GetBLS12377TwistPoints() TwistPoints { return TwistPoints{ G2x: [2]*big.Int{g2x0, g2x1}, G2y: [2]*big.Int{g2y0, g2y1}, - G2m: computeBLS12377TwistTable(), + G2m: computeTwistTable(), } } diff --git a/std/algebra/sw_bls12377/inner_compute.go b/std/algebra/sw_bls12377/inner_compute.go index 3ddbc2ece2..1bf12a2f5c 100644 --- a/std/algebra/sw_bls12377/inner_compute.go +++ b/std/algebra/sw_bls12377/inner_compute.go @@ -6,7 +6,7 @@ import ( bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377" ) -func computeBLS12377CurveTable() [][2]*big.Int { +func computeCurveTable() [][2]*big.Int { G1jac, _, _, _ := bls12377.Generators() table := make([][2]*big.Int, 253) tmp := new(bls12377.G1Jac).Set(&G1jac) @@ -32,7 +32,7 @@ func computeBLS12377CurveTable() [][2]*big.Int { return table[:] } -func computeBLS12377TwistTable() [][4]*big.Int { +func computeTwistTable() [][4]*big.Int { _, G2jac, _, _ := bls12377.Generators() table := make([][4]*big.Int, 253) tmp := new(bls12377.G2Jac).Set(&G2jac) diff --git a/std/algebra/sw_bls24315/g1.go b/std/algebra/sw_bls24315/g1.go index c2f6e9bb00..b303b25197 100644 --- a/std/algebra/sw_bls24315/g1.go +++ b/std/algebra/sw_bls24315/g1.go @@ -455,7 +455,7 @@ func (p *G1Affine) DoubleAndAdd(api frontend.API, p1, p2 *G1Affine) *G1Affine { // ScalarMulBase computes s * g1 and returns it, where g1 is the fixed generator. It doesn't modify s. func (P *G1Affine) ScalarMulBase(api frontend.API, s frontend.Variable) *G1Affine { - points := GetBLS24315CurvePoints() + points := GetCurvePoints() sBits := api.ToBinary(s, 253) diff --git a/std/algebra/sw_bls24315/g2.go b/std/algebra/sw_bls24315/g2.go index 3f15b48175..5eb3daf1ff 100644 --- a/std/algebra/sw_bls24315/g2.go +++ b/std/algebra/sw_bls24315/g2.go @@ -475,7 +475,7 @@ func (p *G2Affine) DoubleAndAdd(api frontend.API, p1, p2 *G2Affine) *G2Affine { // ScalarMulBase computes s * g2 and returns it, where g2 is the fixed generator. It doesn't modify s. func (P *G2Affine) ScalarMulBase(api frontend.API, s frontend.Variable) *G2Affine { - points := GetBLS24315TwistPoints() + points := GetTwistPoints() sBits := api.ToBinary(s, 253) diff --git a/std/algebra/sw_bls24315/inner.go b/std/algebra/sw_bls24315/inner.go index 6ab2e94374..76f449eb33 100644 --- a/std/algebra/sw_bls24315/inner.go +++ b/std/algebra/sw_bls24315/inner.go @@ -72,13 +72,13 @@ type CurvePoints struct { G1m [][2]*big.Int // m*base points (x,y) } -func GetBLS24315CurvePoints() CurvePoints { +func GetCurvePoints() CurvePoints { g1x, _ := new(big.Int).SetString("41a0a424393988da1b2b117076ef6e4f54b344cc46dde3c983603a832cb638dbf4b721710866097", 16) g1y, _ := new(big.Int).SetString("2e6f83c55deff20227ecdf0db2bb2ebb5d72c8a29010871d3cce9059e83dfb96f2922d5da4e4e5f", 16) return CurvePoints{ G1x: g1x, G1y: g1y, - G1m: computeBLS24315CurveTable(), + G1m: computeCurveTable(), } } @@ -88,7 +88,7 @@ type TwistPoints struct { G2m [][8]*big.Int // m*base points (x,y) } -func GetBLS24315TwistPoints() TwistPoints { +func GetTwistPoints() TwistPoints { g2x0, _ := new(big.Int).SetString("2f339ada8942f92aefa14196bfee2552a7c5675f5e5e9da798458f72ff50f96f5c357cf13710f63", 16) g2x1, _ := new(big.Int).SetString("20b1a8dca4b18842b40079be727cbfd1a16ed134a080b759ae503618e92871697838dc4c689911c", 16) g2x2, _ := new(big.Int).SetString("16eab1e76670eb9affa1bc77400be688d5cd69566f9325b329b40db85b47f236d5c34e8ffed7536", 16) @@ -100,7 +100,7 @@ func GetBLS24315TwistPoints() TwistPoints { return TwistPoints{ G2x: [4]*big.Int{g2x0, g2x1, g2x2, g2x3}, G2y: [4]*big.Int{g2y0, g2y1, g2y2, g2y3}, - G2m: computeBLS24315TwistTable(), + G2m: computeTwistTable(), } } diff --git a/std/algebra/sw_bls24315/inner_compute.go b/std/algebra/sw_bls24315/inner_compute.go index 43d03e8b11..158ef72999 100644 --- a/std/algebra/sw_bls24315/inner_compute.go +++ b/std/algebra/sw_bls24315/inner_compute.go @@ -6,7 +6,7 @@ import ( bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315" ) -func computeBLS24315CurveTable() [][2]*big.Int { +func computeCurveTable() [][2]*big.Int { G1jac, _, _, _ := bls24315.Generators() table := make([][2]*big.Int, 253) tmp := new(bls24315.G1Jac).Set(&G1jac) @@ -32,7 +32,7 @@ func computeBLS24315CurveTable() [][2]*big.Int { return table[:] } -func computeBLS24315TwistTable() [][8]*big.Int { +func computeTwistTable() [][8]*big.Int { _, G2jac, _, _ := bls24315.Generators() table := make([][8]*big.Int, 253) tmp := new(bls24315.G2Jac).Set(&G2jac) From 8bef9907879e21db652fb6f13675612b7d8f523b Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 2 Mar 2023 12:32:58 +0100 Subject: [PATCH 044/464] refactor: use generator from gnark-crypto to init points --- std/algebra/sw_bls12377/inner.go | 17 +++++++---------- std/algebra/sw_bls24315/inner.go | 31 +++++++++++++++++-------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/std/algebra/sw_bls12377/inner.go b/std/algebra/sw_bls12377/inner.go index fee31f09e3..d788de18f6 100644 --- a/std/algebra/sw_bls12377/inner.go +++ b/std/algebra/sw_bls12377/inner.go @@ -6,6 +6,7 @@ import ( "sync" "github.com/consensys/gnark-crypto/ecc" + bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377" "github.com/consensys/gnark/frontend" ) @@ -70,11 +71,10 @@ type CurvePoints struct { } func GetCurvePoints() CurvePoints { - g1x, _ := new(big.Int).SetString("8848defe740a67c8fc6225bf87ff5485951e2caa9d41bb188282c8bd37cb5cd5481512ffcd394eeab9b16eb21be9ef", 16) - g1y, _ := new(big.Int).SetString("1914a69c5102eff1f674f5d30afeec4bd7fb348ca3e52d96d182ad44fb82305c2fe3d3634a9591afd82de55559c8ea6", 16) + _, _, g1aff, _ := bls12377.Generators() return CurvePoints{ - G1x: g1x, - G1y: g1y, + G1x: g1aff.X.BigInt(new(big.Int)), + G1y: g1aff.Y.BigInt(new(big.Int)), G1m: computeCurveTable(), } } @@ -86,13 +86,10 @@ type TwistPoints struct { } func GetTwistPoints() TwistPoints { - g2x0, _ := new(big.Int).SetString("18480be71c785fec89630a2a3841d01c565f071203e50317ea501f557db6b9b71889f52bb53540274e3e48f7c005196", 16) - g2x1, _ := new(big.Int).SetString("ea6040e700403170dc5a51b1b140d5532777ee6651cecbe7223ece0799c9de5cf89984bff76fe6b26bfefa6ea16afe", 16) - g2y0, _ := new(big.Int).SetString("690d665d446f7bd960736bcbb2efb4de03ed7274b49a58e458c282f832d204f2cf88886d8c7c2ef094094409fd4ddf", 16) - g2y1, _ := new(big.Int).SetString("f8169fd28355189e549da3151a70aa61ef11ac3d591bf12463b01acee304c24279b83f5e52270bd9a1cdd185eb8f93", 16) + _, _, _, g2aff := bls12377.Generators() return TwistPoints{ - G2x: [2]*big.Int{g2x0, g2x1}, - G2y: [2]*big.Int{g2y0, g2y1}, + G2x: [2]*big.Int{g2aff.X.A0.BigInt(new(big.Int)), g2aff.X.A1.BigInt(new(big.Int))}, + G2y: [2]*big.Int{g2aff.Y.A0.BigInt(new(big.Int)), g2aff.Y.A1.BigInt(new(big.Int))}, G2m: computeTwistTable(), } diff --git a/std/algebra/sw_bls24315/inner.go b/std/algebra/sw_bls24315/inner.go index 76f449eb33..27eab19f6c 100644 --- a/std/algebra/sw_bls24315/inner.go +++ b/std/algebra/sw_bls24315/inner.go @@ -6,6 +6,7 @@ import ( "sync" "github.com/consensys/gnark-crypto/ecc" + bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315" "github.com/consensys/gnark/frontend" ) @@ -73,11 +74,10 @@ type CurvePoints struct { } func GetCurvePoints() CurvePoints { - g1x, _ := new(big.Int).SetString("41a0a424393988da1b2b117076ef6e4f54b344cc46dde3c983603a832cb638dbf4b721710866097", 16) - g1y, _ := new(big.Int).SetString("2e6f83c55deff20227ecdf0db2bb2ebb5d72c8a29010871d3cce9059e83dfb96f2922d5da4e4e5f", 16) + _, _, g1aff, _ := bls24315.Generators() return CurvePoints{ - G1x: g1x, - G1y: g1y, + G1x: g1aff.X.BigInt(new(big.Int)), + G1y: g1aff.Y.BigInt(new(big.Int)), G1m: computeCurveTable(), } } @@ -89,17 +89,20 @@ type TwistPoints struct { } func GetTwistPoints() TwistPoints { - g2x0, _ := new(big.Int).SetString("2f339ada8942f92aefa14196bfee2552a7c5675f5e5e9da798458f72ff50f96f5c357cf13710f63", 16) - g2x1, _ := new(big.Int).SetString("20b1a8dca4b18842b40079be727cbfd1a16ed134a080b759ae503618e92871697838dc4c689911c", 16) - g2x2, _ := new(big.Int).SetString("16eab1e76670eb9affa1bc77400be688d5cd69566f9325b329b40db85b47f236d5c34e8ffed7536", 16) - g2x3, _ := new(big.Int).SetString("6e8c608261f21c41f2479ca4824deba561b9689a9c03a5b8b36a6cbbed0a7d9468e07e557d8569", 16) - g2y0, _ := new(big.Int).SetString("3cdd8218baa5276421c9923cde33a45399a1d878d5202fae600a8502a29681f74ccdcc053b278b7", 16) - g2y1, _ := new(big.Int).SetString("3a079c670190bb49b1bd21e10aac3191535e32ce99da592ddfa8bd09d57a7374ed63ad7f25e398d", 16) - g2y2, _ := new(big.Int).SetString("1b38dd0c5ec49a0883a950c631c688eb3b01f45b7c0d2990cd99052005ebf2fa9e7043bbd605ef5", 16) - g2y3, _ := new(big.Int).SetString("495d6de2e4fed6be3e1d24dd724163e01d88643f7e83d31528ab0a80ced619175a1a104574ac83", 16) + _, _, _, g2aff := bls24315.Generators() return TwistPoints{ - G2x: [4]*big.Int{g2x0, g2x1, g2x2, g2x3}, - G2y: [4]*big.Int{g2y0, g2y1, g2y2, g2y3}, + G2x: [4]*big.Int{ + g2aff.X.B0.A0.BigInt(new(big.Int)), + g2aff.X.B0.A1.BigInt(new(big.Int)), + g2aff.X.B1.A0.BigInt(new(big.Int)), + g2aff.X.B1.A1.BigInt(new(big.Int)), + }, + G2y: [4]*big.Int{ + g2aff.Y.B0.A0.BigInt(new(big.Int)), + g2aff.Y.B0.A1.BigInt(new(big.Int)), + g2aff.Y.B1.A0.BigInt(new(big.Int)), + g2aff.Y.B1.A1.BigInt(new(big.Int)), + }, G2m: computeTwistTable(), } From ed883029c7b55afd906f3727fe430b2c9cb8b900 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 2 Mar 2023 12:33:17 +0100 Subject: [PATCH 045/464] feat: compute table on init once --- std/algebra/sw_bls12377/inner.go | 14 ++++++++++++-- std/algebra/sw_bls24315/inner.go | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/std/algebra/sw_bls12377/inner.go b/std/algebra/sw_bls12377/inner.go index d788de18f6..58d0e2a727 100644 --- a/std/algebra/sw_bls12377/inner.go +++ b/std/algebra/sw_bls12377/inner.go @@ -64,6 +64,16 @@ func getInnerCurveConfig(outerCurveScalarField *big.Int) *innerConfig { return &innerConfigBW6_761 } +var ( + computedCurveTable [][2]*big.Int + computedTwistTable [][4]*big.Int +) + +func init() { + computedCurveTable = computeCurveTable() + computedTwistTable = computeTwistTable() +} + type CurvePoints struct { G1x *big.Int // base point x G1y *big.Int // base point y @@ -75,7 +85,7 @@ func GetCurvePoints() CurvePoints { return CurvePoints{ G1x: g1aff.X.BigInt(new(big.Int)), G1y: g1aff.Y.BigInt(new(big.Int)), - G1m: computeCurveTable(), + G1m: computedCurveTable, } } @@ -90,7 +100,7 @@ func GetTwistPoints() TwistPoints { return TwistPoints{ G2x: [2]*big.Int{g2aff.X.A0.BigInt(new(big.Int)), g2aff.X.A1.BigInt(new(big.Int))}, G2y: [2]*big.Int{g2aff.Y.A0.BigInt(new(big.Int)), g2aff.Y.A1.BigInt(new(big.Int))}, - G2m: computeTwistTable(), + G2m: computedTwistTable, } } diff --git a/std/algebra/sw_bls24315/inner.go b/std/algebra/sw_bls24315/inner.go index 27eab19f6c..6c484726a1 100644 --- a/std/algebra/sw_bls24315/inner.go +++ b/std/algebra/sw_bls24315/inner.go @@ -73,12 +73,22 @@ type CurvePoints struct { G1m [][2]*big.Int // m*base points (x,y) } +var ( + computedCurveTable [][2]*big.Int + computedTwistTable [][8]*big.Int +) + +func init() { + computedCurveTable = computeCurveTable() + computedTwistTable = computeTwistTable() +} + func GetCurvePoints() CurvePoints { _, _, g1aff, _ := bls24315.Generators() return CurvePoints{ G1x: g1aff.X.BigInt(new(big.Int)), G1y: g1aff.Y.BigInt(new(big.Int)), - G1m: computeCurveTable(), + G1m: computedCurveTable, } } @@ -103,7 +113,7 @@ func GetTwistPoints() TwistPoints { g2aff.Y.B1.A0.BigInt(new(big.Int)), g2aff.Y.B1.A1.BigInt(new(big.Int)), }, - G2m: computeTwistTable(), + G2m: computedTwistTable, } } From 9b4739df234ed138551dbde26059d09e588266e9 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 2 Mar 2023 12:36:01 +0100 Subject: [PATCH 046/464] refactor: make internal methods private --- std/algebra/sw_bls12377/g1.go | 2 +- std/algebra/sw_bls12377/g2.go | 2 +- std/algebra/sw_bls12377/inner.go | 12 ++++++------ std/algebra/sw_bls24315/g1.go | 2 +- std/algebra/sw_bls24315/g2.go | 2 +- std/algebra/sw_bls24315/inner.go | 12 ++++++------ 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/std/algebra/sw_bls12377/g1.go b/std/algebra/sw_bls12377/g1.go index b42d7b225e..ac9c43221f 100644 --- a/std/algebra/sw_bls12377/g1.go +++ b/std/algebra/sw_bls12377/g1.go @@ -455,7 +455,7 @@ func (p *G1Affine) DoubleAndAdd(api frontend.API, p1, p2 *G1Affine) *G1Affine { // ScalarMulBase computes s * g1 and returns it, where g1 is the fixed generator. It doesn't modify s. func (P *G1Affine) ScalarMulBase(api frontend.API, s frontend.Variable) *G1Affine { - points := GetCurvePoints() + points := getCurvePoints() sBits := api.ToBinary(s, 253) diff --git a/std/algebra/sw_bls12377/g2.go b/std/algebra/sw_bls12377/g2.go index 4a61fcd338..76a00ef216 100644 --- a/std/algebra/sw_bls12377/g2.go +++ b/std/algebra/sw_bls12377/g2.go @@ -475,7 +475,7 @@ func (p *G2Affine) DoubleAndAdd(api frontend.API, p1, p2 *G2Affine) *G2Affine { // ScalarMulBase computes s * g2 and returns it, where g2 is the fixed generator. It doesn't modify s. func (P *G2Affine) ScalarMulBase(api frontend.API, s frontend.Variable) *G2Affine { - points := GetTwistPoints() + points := getTwistPoints() sBits := api.ToBinary(s, 253) diff --git a/std/algebra/sw_bls12377/inner.go b/std/algebra/sw_bls12377/inner.go index 58d0e2a727..3396afa7d1 100644 --- a/std/algebra/sw_bls12377/inner.go +++ b/std/algebra/sw_bls12377/inner.go @@ -74,30 +74,30 @@ func init() { computedTwistTable = computeTwistTable() } -type CurvePoints struct { +type curvePoints struct { G1x *big.Int // base point x G1y *big.Int // base point y G1m [][2]*big.Int // m*base points (x,y) } -func GetCurvePoints() CurvePoints { +func getCurvePoints() curvePoints { _, _, g1aff, _ := bls12377.Generators() - return CurvePoints{ + return curvePoints{ G1x: g1aff.X.BigInt(new(big.Int)), G1y: g1aff.Y.BigInt(new(big.Int)), G1m: computedCurveTable, } } -type TwistPoints struct { +type twistPoints struct { G2x [2]*big.Int // base point x ∈ E2 G2y [2]*big.Int // base point y ∈ E2 G2m [][4]*big.Int // m*base points (x,y) } -func GetTwistPoints() TwistPoints { +func getTwistPoints() twistPoints { _, _, _, g2aff := bls12377.Generators() - return TwistPoints{ + return twistPoints{ G2x: [2]*big.Int{g2aff.X.A0.BigInt(new(big.Int)), g2aff.X.A1.BigInt(new(big.Int))}, G2y: [2]*big.Int{g2aff.Y.A0.BigInt(new(big.Int)), g2aff.Y.A1.BigInt(new(big.Int))}, G2m: computedTwistTable, diff --git a/std/algebra/sw_bls24315/g1.go b/std/algebra/sw_bls24315/g1.go index b303b25197..87092040da 100644 --- a/std/algebra/sw_bls24315/g1.go +++ b/std/algebra/sw_bls24315/g1.go @@ -455,7 +455,7 @@ func (p *G1Affine) DoubleAndAdd(api frontend.API, p1, p2 *G1Affine) *G1Affine { // ScalarMulBase computes s * g1 and returns it, where g1 is the fixed generator. It doesn't modify s. func (P *G1Affine) ScalarMulBase(api frontend.API, s frontend.Variable) *G1Affine { - points := GetCurvePoints() + points := getCurvePoints() sBits := api.ToBinary(s, 253) diff --git a/std/algebra/sw_bls24315/g2.go b/std/algebra/sw_bls24315/g2.go index 5eb3daf1ff..961f5099e5 100644 --- a/std/algebra/sw_bls24315/g2.go +++ b/std/algebra/sw_bls24315/g2.go @@ -475,7 +475,7 @@ func (p *G2Affine) DoubleAndAdd(api frontend.API, p1, p2 *G2Affine) *G2Affine { // ScalarMulBase computes s * g2 and returns it, where g2 is the fixed generator. It doesn't modify s. func (P *G2Affine) ScalarMulBase(api frontend.API, s frontend.Variable) *G2Affine { - points := GetTwistPoints() + points := getTwistPoints() sBits := api.ToBinary(s, 253) diff --git a/std/algebra/sw_bls24315/inner.go b/std/algebra/sw_bls24315/inner.go index 6c484726a1..8630c645ed 100644 --- a/std/algebra/sw_bls24315/inner.go +++ b/std/algebra/sw_bls24315/inner.go @@ -67,7 +67,7 @@ func (cc *innerConfig) phi2(api frontend.API, res, P *G2Affine) *G2Affine { return res } -type CurvePoints struct { +type curvePoints struct { G1x *big.Int // base point x G1y *big.Int // base point y G1m [][2]*big.Int // m*base points (x,y) @@ -83,24 +83,24 @@ func init() { computedTwistTable = computeTwistTable() } -func GetCurvePoints() CurvePoints { +func getCurvePoints() curvePoints { _, _, g1aff, _ := bls24315.Generators() - return CurvePoints{ + return curvePoints{ G1x: g1aff.X.BigInt(new(big.Int)), G1y: g1aff.Y.BigInt(new(big.Int)), G1m: computedCurveTable, } } -type TwistPoints struct { +type twistPoints struct { G2x [4]*big.Int // base point x ∈ E4 G2y [4]*big.Int // base point y ∈ E4 G2m [][8]*big.Int // m*base points (x,y) } -func GetTwistPoints() TwistPoints { +func getTwistPoints() twistPoints { _, _, _, g2aff := bls24315.Generators() - return TwistPoints{ + return twistPoints{ G2x: [4]*big.Int{ g2aff.X.B0.A0.BigInt(new(big.Int)), g2aff.X.B0.A1.BigInt(new(big.Int)), From a243f6dfc817ca44229f532669861ee96c9b6552 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Thu, 2 Mar 2023 13:01:49 +0100 Subject: [PATCH 047/464] refactor: use generator from gnark-crypto to init points --- std/algebra/weierstrass/params.go | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/std/algebra/weierstrass/params.go b/std/algebra/weierstrass/params.go index 348b212008..32cd8812e8 100644 --- a/std/algebra/weierstrass/params.go +++ b/std/algebra/weierstrass/params.go @@ -3,6 +3,8 @@ package weierstrass import ( "math/big" + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/secp256k1" "github.com/consensys/gnark/std/math/emulated" ) @@ -24,13 +26,12 @@ type CurveParams struct { // initialising new curve, use the base field [emulated.Secp256k1Fp] and scalar // field [emulated.Secp256k1Fr]. func GetSecp256k1Params() CurveParams { - gx, _ := new(big.Int).SetString("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", 16) - gy, _ := new(big.Int).SetString("483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", 16) + _, g1aff := secp256k1.Generators() return CurveParams{ A: big.NewInt(0), B: big.NewInt(7), - Gx: gx, - Gy: gy, + Gx: g1aff.X.BigInt(new(big.Int)), + Gy: g1aff.Y.BigInt(new(big.Int)), Gm: computeSecp256k1Table(), } } @@ -39,14 +40,12 @@ func GetSecp256k1Params() CurveParams { // When initialising new curve, use the base field [emulated.BN254Fp] and scalar // field [emulated.BN254Fr]. func GetBN254Params() CurveParams { - gx := big.NewInt(1) - gy := big.NewInt(2) - + _, _, g1aff, _ := bn254.Generators() return CurveParams{ A: big.NewInt(0), B: big.NewInt(3), - Gx: gx, - Gy: gy, + Gx: g1aff.X.BigInt(new(big.Int)), + Gy: g1aff.Y.BigInt(new(big.Int)), Gm: computeBN254Table(), } } From 39aac4d99ac8ebe4369fd77bf18a06e6c275e06a Mon Sep 17 00:00:00 2001 From: Hisham Galal <0xhgalal@gmail.com> Date: Wed, 1 Mar 2023 20:51:54 -0500 Subject: [PATCH 048/464] groth16 MPC setup --- backend/groth16/setup/keys/keys.go | 111 ++++++++++ backend/groth16/setup/keys/marshal.go | 86 ++++++++ backend/groth16/setup/phase1/contribution.go | 125 +++++++++++ backend/groth16/setup/phase1/marshal.go | 64 ++++++ backend/groth16/setup/phase1/verifier.go | 72 ++++++ backend/groth16/setup/phase2/contribution.go | 212 ++++++++++++++++++ backend/groth16/setup/phase2/marshal.go | 87 ++++++++ backend/groth16/setup/phase2/verifier.go | 45 ++++ backend/groth16/setup/test/example_test.go | 111 ++++++++++ backend/groth16/setup/test/phase1_test.go | 45 ++++ backend/groth16/setup/utils/lagrange.go | 221 +++++++++++++++++++ backend/groth16/setup/utils/utils.go | 156 +++++++++++++ 12 files changed, 1335 insertions(+) create mode 100644 backend/groth16/setup/keys/keys.go create mode 100644 backend/groth16/setup/keys/marshal.go create mode 100644 backend/groth16/setup/phase1/contribution.go create mode 100644 backend/groth16/setup/phase1/marshal.go create mode 100644 backend/groth16/setup/phase1/verifier.go create mode 100644 backend/groth16/setup/phase2/contribution.go create mode 100644 backend/groth16/setup/phase2/marshal.go create mode 100644 backend/groth16/setup/phase2/verifier.go create mode 100644 backend/groth16/setup/test/example_test.go create mode 100644 backend/groth16/setup/test/phase1_test.go create mode 100644 backend/groth16/setup/utils/lagrange.go create mode 100644 backend/groth16/setup/utils/utils.go diff --git a/backend/groth16/setup/keys/keys.go b/backend/groth16/setup/keys/keys.go new file mode 100644 index 0000000000..9fc7a08892 --- /dev/null +++ b/backend/groth16/setup/keys/keys.go @@ -0,0 +1,111 @@ +package keys + +import ( + "github.com/consensys/gnark/backend/groth16/setup/phase1" + "github.com/consensys/gnark/backend/groth16/setup/phase2" + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" + "github.com/consensys/gnark/backend/groth16/setup/utils" +) + +type ProvingKey struct { + Domain fft.Domain + // [α]₁ , [β]₁, [δ]₁, [A(t)]₁, [B(t)]₁, [Kpk(t)]₁, [Z(t)]₁ + G1 struct { + Alpha, Beta, Delta bn254.G1Affine + A, B, Z []bn254.G1Affine + K []bn254.G1Affine // the indexes correspond to the private wires + } + + // [β]₂ , [δ]₂, [B(t)]₂ + G2 struct { + Beta, Delta bn254.G2Affine + B []bn254.G2Affine + } + + // if InfinityA[i] == true, the point G1.A[i] == infinity + InfinityA, InfinityB []bool + NbInfinityA, NbInfinityB uint64 +} + +type VerifyingKey struct { + // [α]₁, [Kvk]₁ + G1 struct { + Alpha, Beta, Delta bn254.G1Affine + K []bn254.G1Affine + } + + // [β]₂, [δ]₂, [γ]₂, + G2 struct { + Beta, Delta, Gamma bn254.G2Affine + } +} + +func ExtractKeys(srs1 *phase1.Contribution, srs2 *phase2.Contribution, evals *phase2.Evaluations, nConstraints int) (pk ProvingKey, vk VerifyingKey) { + _, _, _, g2 := bn254.Generators() + + // Initialize PK + pk.Domain = *fft.NewDomain(uint64(nConstraints)) + pk.G1.Alpha.Set(&srs1.Parameters.G1.AlphaTau[0]) + pk.G1.Beta.Set(&srs1.Parameters.G1.BetaTau[0]) + pk.G1.Delta.Set(&srs2.Parameters.G1.Delta) + pk.G1.Z = srs2.Parameters.G1.Z + utils.BitReverseG1(pk.G1.Z) + + pk.G1.K = srs2.Parameters.G1.L + pk.G2.Beta.Set(&srs1.Parameters.G2.Beta) + pk.G2.Delta.Set(&srs2.Parameters.G2.Delta) + + // Filter out infinity points + nWires := len(evals.G1.A) + pk.InfinityA = make([]bool, nWires) + A := make([]bn254.G1Affine, nWires) + j := 0 + for i, e := range evals.G1.A { + if e.IsInfinity() { + pk.InfinityA[i] = true + continue + } + A[j] = evals.G1.A[i] + j++ + } + pk.G1.A = A[:j] + pk.NbInfinityA = uint64(nWires - j) + + pk.InfinityB = make([]bool, nWires) + B := make([]bn254.G1Affine, nWires) + j = 0 + for i, e := range evals.G1.B { + if e.IsInfinity() { + pk.InfinityB[i] = true + continue + } + B[j] = evals.G1.B[i] + j++ + } + pk.G1.B = B[:j] + pk.NbInfinityB = uint64(nWires - j) + + B2 := make([]bn254.G2Affine, nWires) + j = 0 + for i, e := range evals.G2.B { + if e.IsInfinity() { + // pk.InfinityB[i] = true should be the same as in B + continue + } + B2[j] = evals.G2.B[i] + j++ + } + pk.G2.B = B2[:j] + + // Initialize VK + vk.G1.Alpha.Set(&srs1.Parameters.G1.AlphaTau[0]) + vk.G1.Beta.Set(&srs1.Parameters.G1.BetaTau[0]) + vk.G1.Delta.Set(&srs2.Parameters.G1.Delta) + vk.G2.Beta.Set(&srs1.Parameters.G2.Beta) + vk.G2.Delta.Set(&srs2.Parameters.G2.Delta) + vk.G2.Gamma.Set(&g2) + vk.G1.K = evals.G1.VKK + + return pk, vk +} diff --git a/backend/groth16/setup/keys/marshal.go b/backend/groth16/setup/keys/marshal.go new file mode 100644 index 0000000000..b02021030b --- /dev/null +++ b/backend/groth16/setup/keys/marshal.go @@ -0,0 +1,86 @@ +package keys + +import ( + "io" + + "github.com/consensys/gnark-crypto/ecc/bn254" +) +func (pk *ProvingKey) WriteTo(w io.Writer, raw bool) (int64, error) { + n, err := pk.Domain.WriteTo(w) + if err != nil { + return n, err + } + + var enc *bn254.Encoder + if raw { + enc = bn254.NewEncoder(w, bn254.RawEncoding()) + } else { + enc = bn254.NewEncoder(w) + } + nbWires := uint64(len(pk.InfinityA)) + + toEncode := []interface{}{ + &pk.G1.Alpha, + &pk.G1.Beta, + &pk.G1.Delta, + pk.G1.A, + pk.G1.B, + pk.G1.Z, + pk.G1.K, + &pk.G2.Beta, + &pk.G2.Delta, + pk.G2.B, + nbWires, + pk.NbInfinityA, + pk.NbInfinityB, + pk.InfinityA, + pk.InfinityB, + } + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return n + enc.BytesWritten(), err + } + } + + return n + enc.BytesWritten(), nil + +} + +// follows bellman format: +// https://github.com/zkcrypto/bellman/blob/fa9be45588227a8c6ec34957de3f68705f07bd92/src/groth16/mod.rs#L143 +// [α]1,[β]1,[β]2,[γ]2,[δ]1,[δ]2,uint32(len(Kvk)),[Kvk]1 +func (vk *VerifyingKey) WriteTo(w io.Writer, raw bool) (int64, error) { + var enc *bn254.Encoder + if raw { + enc = bn254.NewEncoder(w, bn254.RawEncoding()) + } else { + enc = bn254.NewEncoder(w) + } + + // [α]1,[β]1,[β]2,[γ]2,[δ]1,[δ]2 + if err := enc.Encode(&vk.G1.Alpha); err != nil { + return enc.BytesWritten(), err + } + if err := enc.Encode(&vk.G1.Beta); err != nil { + return enc.BytesWritten(), err + } + if err := enc.Encode(&vk.G2.Beta); err != nil { + return enc.BytesWritten(), err + } + if err := enc.Encode(&vk.G2.Gamma); err != nil { + return enc.BytesWritten(), err + } + if err := enc.Encode(&vk.G1.Delta); err != nil { + return enc.BytesWritten(), err + } + if err := enc.Encode(&vk.G2.Delta); err != nil { + return enc.BytesWritten(), err + } + + // uint32(len(Kvk)),[Kvk]1 + if err := enc.Encode(vk.G1.K); err != nil { + return enc.BytesWritten(), err + } + return enc.BytesWritten(), nil +} \ No newline at end of file diff --git a/backend/groth16/setup/phase1/contribution.go b/backend/groth16/setup/phase1/contribution.go new file mode 100644 index 0000000000..aec82a8352 --- /dev/null +++ b/backend/groth16/setup/phase1/contribution.go @@ -0,0 +1,125 @@ +package phase1 + +import ( + "crypto/sha256" + "math" + "math/big" + + "github.com/consensys/gnark/backend/groth16/setup/utils" + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +type Contribution struct { + Parameters struct { + G1 struct { + Tau []bn254.G1Affine // {[τ⁰]₁, [τ¹]₁, [τ²]₁, …, [τ²ⁿ⁻²]₁} + AlphaTau []bn254.G1Affine // {α[τ⁰]₁, α[τ¹]₁, α[τ²]₁, …, α[τⁿ⁻¹]₁} + BetaTau []bn254.G1Affine // {β[τ⁰]₁, β[τ¹]₁, β[τ²]₁, …, β[τⁿ⁻¹]₁} + } + G2 struct { + Tau []bn254.G2Affine // {[τ⁰]₂, [τ¹]₂, [τ²]₂, …, [τⁿ⁻¹]₂} + Beta bn254.G2Affine // [β]₂ + } + } + PublicKeys struct { + Tau, Alpha, Beta utils.PublicKey + } + Hash []byte // sha256 hash +} + +func (c *Contribution) Initialize(power int) { + N := int(math.Pow(2, float64(power))) + + // Generate key pairs + var tau, alpha, beta fr.Element + tau.SetOne() + alpha.SetOne() + beta.SetOne() + c.PublicKeys.Tau = utils.GenPublicKey(tau, nil, 1) + c.PublicKeys.Alpha = utils.GenPublicKey(alpha, nil, 2) + c.PublicKeys.Beta = utils.GenPublicKey(beta, nil, 3) + + // First contribution use generators + _, _, g1, g2 := bn254.Generators() + c.Parameters.G2.Beta.Set(&g2) + c.Parameters.G1.Tau = make([]bn254.G1Affine, 2*N-1) + c.Parameters.G2.Tau = make([]bn254.G2Affine, N) + c.Parameters.G1.AlphaTau = make([]bn254.G1Affine, N) + c.Parameters.G1.BetaTau = make([]bn254.G1Affine, N) + for i := 0; i < len(c.Parameters.G1.Tau); i++ { + c.Parameters.G1.Tau[i].Set(&g1) + } + for i := 0; i < len(c.Parameters.G2.Tau); i++ { + c.Parameters.G2.Tau[i].Set(&g2) + c.Parameters.G1.AlphaTau[i].Set(&g1) + c.Parameters.G1.BetaTau[i].Set(&g1) + } + + c.Parameters.G2.Beta.Set(&g2) + + // Compute hash of Contribution + c.Hash = HashContribution(c) +} + +func (c *Contribution) Contribute(prev *Contribution) { + N := len(prev.Parameters.G2.Tau) + + // Generate key pairs + var tau, alpha, beta fr.Element + tau.SetRandom() + alpha.SetRandom() + beta.SetRandom() + c.PublicKeys.Tau = utils.GenPublicKey(tau, prev.Hash[:], 1) + c.PublicKeys.Alpha = utils.GenPublicKey(alpha, prev.Hash[:], 2) + c.PublicKeys.Beta = utils.GenPublicKey(beta, prev.Hash[:], 3) + + // Compute powers of τ, ατ, and βτ + taus := utils.Powers(tau, 2*N-1) + alphaTau := make([]fr.Element, N) + betaTau := make([]fr.Element, N) + for i := 0; i < N; i++ { + alphaTau[i].Mul(&taus[i], &alpha) + betaTau[i].Mul(&taus[i], &beta) + } + + // Update using previous parameters + c.Parameters.G1.Tau = utils.ScaleG1(prev.Parameters.G1.Tau, taus) + c.Parameters.G2.Tau = utils.ScaleG2(prev.Parameters.G2.Tau, taus[0:N]) + c.Parameters.G1.AlphaTau = utils.ScaleG1(prev.Parameters.G1.AlphaTau, alphaTau) + c.Parameters.G1.BetaTau = utils.ScaleG1(prev.Parameters.G1.BetaTau, betaTau) + var betaBI big.Int + beta.BigInt(&betaBI) + c.Parameters.G2.Beta.ScalarMultiplication(&prev.Parameters.G2.Beta, &betaBI) + + // Compute hash of Contribution + c.Hash = HashContribution(c) +} + +func HashContribution(c *Contribution) []byte { + sha := sha256.New() + toEncode := []interface{}{ + &c.PublicKeys.Tau.SG, + &c.PublicKeys.Tau.SXG, + &c.PublicKeys.Tau.XR, + &c.PublicKeys.Alpha.SG, + &c.PublicKeys.Alpha.SXG, + &c.PublicKeys.Alpha.XR, + &c.PublicKeys.Beta.SG, + &c.PublicKeys.Beta.SXG, + &c.PublicKeys.Beta.XR, + c.Parameters.G1.Tau, + c.Parameters.G1.AlphaTau, + c.Parameters.G1.BetaTau, + c.Parameters.G2.Tau, + &c.Parameters.G2.Beta, + } + + enc := bn254.NewEncoder(sha) + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + panic(err) + } + } + return sha.Sum(nil) +} diff --git a/backend/groth16/setup/phase1/marshal.go b/backend/groth16/setup/phase1/marshal.go new file mode 100644 index 0000000000..23557a2379 --- /dev/null +++ b/backend/groth16/setup/phase1/marshal.go @@ -0,0 +1,64 @@ +package phase1 + +import ( + "io" + + "github.com/consensys/gnark-crypto/ecc/bn254" +) + +func (c *Contribution) WriteTo(writer io.Writer) (int64, error) { + toEncode := []interface{}{ + &c.PublicKeys.Tau.SG, + &c.PublicKeys.Tau.SXG, + &c.PublicKeys.Tau.XR, + &c.PublicKeys.Alpha.SG, + &c.PublicKeys.Alpha.SXG, + &c.PublicKeys.Alpha.XR, + &c.PublicKeys.Beta.SG, + &c.PublicKeys.Beta.SXG, + &c.PublicKeys.Beta.XR, + c.Parameters.G1.Tau, + c.Parameters.G1.AlphaTau, + c.Parameters.G1.BetaTau, + c.Parameters.G2.Tau, + &c.Parameters.G2.Beta, + } + + enc := bn254.NewEncoder(writer) + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + nBytes, err := writer.Write(c.Hash) + return int64(nBytes), err +} + +func (c *Contribution) ReadFrom(reader io.Reader) (int64, error) { + toEncode := []interface{}{ + &c.PublicKeys.Tau.SG, + &c.PublicKeys.Tau.SXG, + &c.PublicKeys.Tau.XR, + &c.PublicKeys.Alpha.SG, + &c.PublicKeys.Alpha.SXG, + &c.PublicKeys.Alpha.XR, + &c.PublicKeys.Beta.SG, + &c.PublicKeys.Beta.SXG, + &c.PublicKeys.Beta.XR, + &c.Parameters.G1.Tau, + &c.Parameters.G1.AlphaTau, + &c.Parameters.G1.BetaTau, + &c.Parameters.G2.Tau, + &c.Parameters.G2.Beta, + } + + dec := bn254.NewDecoder(reader) + for _, v := range toEncode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + c.Hash = make([]byte, 32) + nBytes, err := reader.Read(c.Hash) + return int64(nBytes), err +} diff --git a/backend/groth16/setup/phase1/verifier.go b/backend/groth16/setup/phase1/verifier.go new file mode 100644 index 0000000000..08e4d504be --- /dev/null +++ b/backend/groth16/setup/phase1/verifier.go @@ -0,0 +1,72 @@ +package phase1 + +import ( + "errors" + + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/backend/groth16/setup/utils" +) + +func (c *Contribution) Verify(prev *Contribution) error { + // Compute R for τ, α, β + tauR := utils.GenR(c.PublicKeys.Tau.SG, c.PublicKeys.Tau.SXG, prev.Hash[:], 1) + alphaR := utils.GenR(c.PublicKeys.Alpha.SG, c.PublicKeys.Alpha.SXG, prev.Hash[:], 2) + betaR := utils.GenR(c.PublicKeys.Beta.SG, c.PublicKeys.Beta.SXG, prev.Hash[:], 3) + + // Check for knowledge of toxic parameters + if !utils.SameRatio(c.PublicKeys.Tau.SG, c.PublicKeys.Tau.SXG, c.PublicKeys.Tau.XR, tauR) { + return errors.New("couldn't verify public key of τ") + } + if !utils.SameRatio(c.PublicKeys.Alpha.SG, c.PublicKeys.Alpha.SXG, c.PublicKeys.Alpha.XR, alphaR) { + return errors.New("couldn't verify public key of α") + } + if !utils.SameRatio(c.PublicKeys.Beta.SG, c.PublicKeys.Beta.SXG, c.PublicKeys.Beta.XR, betaR) { + return errors.New("couldn't verify public key of β") + } + + // Check for valid updates using previous parameters + if !utils.SameRatio(c.Parameters.G1.Tau[1], prev.Parameters.G1.Tau[1], tauR, c.PublicKeys.Tau.XR) { + return errors.New("couldn't verify that [τ]₁ is based on previous contribution") + } + if !utils.SameRatio(c.Parameters.G1.AlphaTau[0], prev.Parameters.G1.AlphaTau[0], alphaR, c.PublicKeys.Alpha.XR) { + return errors.New("couldn't verify that [α]₁ is based on previous contribution") + } + if !utils.SameRatio(c.Parameters.G1.BetaTau[0], prev.Parameters.G1.BetaTau[0], betaR, c.PublicKeys.Beta.XR) { + return errors.New("couldn't verify that [β]₁ is based on previous contribution") + } + if !utils.SameRatio(c.PublicKeys.Tau.SG, c.PublicKeys.Tau.SXG, c.Parameters.G2.Tau[1], prev.Parameters.G2.Tau[1]) { + return errors.New("couldn't verify that [τ]₂ is based on previous contribution") + } + if !utils.SameRatio(c.PublicKeys.Beta.SG, c.PublicKeys.Beta.SXG, c.Parameters.G2.Beta, prev.Parameters.G2.Beta) { + return errors.New("couldn't verify that [β]₂ is based on previous contribution") + } + + // Check for valid updates using powers of τ + _, _, g1, g2 := bn254.Generators() + tauL1, tauL2 := utils.LinearCombinationG1(c.Parameters.G1.Tau) + if !utils.SameRatio(tauL1, tauL2, c.Parameters.G2.Tau[1], g2) { + return errors.New("couldn't verify valid powers of τ in G₁") + } + alphaL1, alphaL2 := utils.LinearCombinationG1(c.Parameters.G1.AlphaTau) + if !utils.SameRatio(alphaL1, alphaL2, c.Parameters.G2.Tau[1], g2) { + return errors.New("couldn't verify valid powers of α(τ) in G₁") + } + betaL1, betaL2 := utils.LinearCombinationG1(c.Parameters.G1.BetaTau) + if !utils.SameRatio(betaL1, betaL2, c.Parameters.G2.Tau[1], g2) { + return errors.New("couldn't verify valid powers of α(τ) in G₁") + } + tau2L1, tau2L2 := utils.LinearCombinationG2(c.Parameters.G2.Tau) + if !utils.SameRatio(c.Parameters.G1.Tau[1], g1, tau2L1, tau2L2) { + return errors.New("couldn't verify valid powers of τ in G₂") + } + + // Check hash of the contribution + h := HashContribution(c) + for i := 0; i < len(h); i++ { + if h[i] != c.Hash[i] { + return errors.New("couldn't verify hash of contribution") + } + } + + return nil +} diff --git a/backend/groth16/setup/phase2/contribution.go b/backend/groth16/setup/phase2/contribution.go new file mode 100644 index 0000000000..7fc3ec957a --- /dev/null +++ b/backend/groth16/setup/phase2/contribution.go @@ -0,0 +1,212 @@ +package phase2 + +import ( + "crypto/sha256" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark/backend/groth16/setup/phase1" + utils "github.com/consensys/gnark/backend/groth16/setup/utils" + "github.com/consensys/gnark/constraint" + cs_bn254 "github.com/consensys/gnark/constraint/bn254" +) + +type Evaluations struct { + G1 struct { + A, B, VKK []bn254.G1Affine + } + G2 struct { + B []bn254.G2Affine + } +} + +type Contribution struct { + Parameters struct { + G1 struct { + Delta bn254.G1Affine + L, Z []bn254.G1Affine + } + G2 struct { + Delta bn254.G2Affine + } + } + PublicKey utils.PublicKey + Hash []byte +} + +func (c2 *Contribution) PreparePhase(c1 *phase1.Contribution, r1cs *cs_bn254.R1CS) Evaluations { + srs := c1.Parameters + size := len(srs.G1.AlphaTau) + if size < r1cs.GetNbConstraints() { + panic("Number of constraints is larger than expected") + } + + accumulateG1 := func(res *bn254.G1Affine, t constraint.Term, value *bn254.G1Affine) { + cID := t.CoeffID() + switch cID { + case constraint.CoeffIdZero: + return + case constraint.CoeffIdOne: + res.Add(res, value) + case constraint.CoeffIdMinusOne: + res.Sub(res, value) + case constraint.CoeffIdTwo: + res.Add(res, value).Add(res, value) + default: + var tmp bn254.G1Affine + var vBi big.Int + r1cs.Coefficients[cID].BigInt(&vBi) + tmp.ScalarMultiplication(value, &vBi) + res.Add(res, &tmp) + } + } + + accumulateG2 := func(res *bn254.G2Affine, t constraint.Term, value *bn254.G2Affine) { + cID := t.CoeffID() + switch cID { + case constraint.CoeffIdZero: + return + case constraint.CoeffIdOne: + res.Add(res, value) + case constraint.CoeffIdMinusOne: + res.Sub(res, value) + case constraint.CoeffIdTwo: + res.Add(res, value).Add(res, value) + default: + var tmp bn254.G2Affine + var vBi big.Int + r1cs.Coefficients[cID].BigInt(&vBi) + tmp.ScalarMultiplication(value, &vBi) + res.Add(res, &tmp) + } + } + + // Prepare Lagrange coefficients of [τ...]₁, [τ...]₂, [ατ...]₁, [βτ...]₁ + coeffTau1 := utils.LagrangeCoeffsG1(srs.G1.Tau, size) + coeffTau2 := utils.LagrangeCoeffsG2(srs.G2.Tau, size) + coeffAlphaTau1 := utils.LagrangeCoeffsG1(srs.G1.AlphaTau, size) + coeffBetaTau1 := utils.LagrangeCoeffsG1(srs.G1.BetaTau, size) + + internal, secret, public := r1cs.GetNbVariables() + nWires := internal + secret + public + var evals Evaluations + evals.G1.A = make([]bn254.G1Affine, nWires) + evals.G1.B = make([]bn254.G1Affine, nWires) + evals.G2.B = make([]bn254.G2Affine, nWires) + bA := make([]bn254.G1Affine, nWires) + aB := make([]bn254.G1Affine, nWires) + C := make([]bn254.G1Affine, nWires) + for i, c := range r1cs.Constraints { + // A + for _, t := range c.L { + accumulateG1(&evals.G1.A[t.WireID()], t, &coeffTau1[i]) + accumulateG1(&bA[t.WireID()], t, &coeffBetaTau1[i]) + } + // B + for _, t := range c.R { + accumulateG1(&evals.G1.B[t.WireID()], t, &coeffTau1[i]) + accumulateG2(&evals.G2.B[t.WireID()], t, &coeffTau2[i]) + accumulateG1(&aB[t.WireID()], t, &coeffAlphaTau1[i]) + } + // C + for _, t := range c.O { + accumulateG1(&C[t.WireID()], t, &coeffTau1[i]) + } + } + + // Prepare default contribution + _, _, g1, g2 := bn254.Generators() + c2.Parameters.G1.Delta = g1 + c2.Parameters.G2.Delta = g2 + + // Build Z in PK as τⁱ(τⁿ - 1) = τ⁽ⁱ⁺ⁿ⁾ - τⁱ for i ∈ [0, n-2] + // τⁱ(τⁿ - 1) = τ⁽ⁱ⁺ⁿ⁾ - τⁱ for i ∈ [0, n-2] + n := len(srs.G1.AlphaTau) + c2.Parameters.G1.Z = make([]bn254.G1Affine, n) + for i := 0; i < n-1; i++ { + c2.Parameters.G1.Z[i].Sub(&srs.G1.Tau[i+n], &srs.G1.Tau[i]) + } + // this is an extra point that is added for the sake of being compatible with gnark setup + // evenutally it is multiplied by zero, hence it won't affect the resutl + c2.Parameters.G1.Z[n-1].Set(&g1) + + // Evaluate L + nPrivate := internal + secret + c2.Parameters.G1.L = make([]bn254.G1Affine, nPrivate) + evals.G1.VKK = make([]bn254.G1Affine, public) + offset := public + for i := 0; i < nWires; i++ { + var tmp bn254.G1Affine + tmp.Add(&bA[i], &aB[i]) + tmp.Add(&tmp, &C[i]) + if i < public { + evals.G1.VKK[i].Set(&tmp) + } else { + c2.Parameters.G1.L[i-offset].Set(&tmp) + } + } + // Set δ public key + var delta fr.Element + delta.SetOne() + c2.PublicKey = utils.GenPublicKey(delta, nil, 1) + + // Hash initial contribution + c2.Hash = HashContribution(c2) + return evals +} + +func (c *Contribution) Contribute(prev *Contribution) { + // Sample toxic δ + var delta, deltaInv fr.Element + var deltaBI, deltaInvBI big.Int + delta.SetRandom() + deltaInv.Inverse(&delta) + + delta.BigInt(&deltaBI) + deltaInv.BigInt(&deltaInvBI) + + // Set δ public key + c.PublicKey = utils.GenPublicKey(delta, prev.Hash, 1) + + // Update δ + c.Parameters.G1.Delta.ScalarMultiplication(&prev.Parameters.G1.Delta, &deltaBI) + c.Parameters.G2.Delta.ScalarMultiplication(&prev.Parameters.G2.Delta, &deltaBI) + + // Update Z using δ⁻¹ + c.Parameters.G1.Z = make([]bn254.G1Affine, len(prev.Parameters.G1.Z)) + for i := 0; i < len(prev.Parameters.G1.Z); i++ { + c.Parameters.G1.Z[i].ScalarMultiplication(&prev.Parameters.G1.Z[i], &deltaInvBI) + } + + // Update Z using δ⁻¹ + c.Parameters.G1.L = make([]bn254.G1Affine, len(prev.Parameters.G1.L)) + for i := 0; i < len(prev.Parameters.G1.L); i++ { + c.Parameters.G1.L[i].ScalarMultiplication(&prev.Parameters.G1.L[i], &deltaInvBI) + } + + // 4. Hash contribution + c.Hash = HashContribution(c) +} + +func HashContribution(c *Contribution) []byte { + sha := sha256.New() + // Hash contribution + toEncode := []interface{}{ + &c.PublicKey.SG, + &c.PublicKey.SXG, + &c.PublicKey.XR, + &c.Parameters.G1.Delta, + c.Parameters.G1.L, + c.Parameters.G1.Z, + &c.Parameters.G2.Delta, + } + + enc := bn254.NewEncoder(sha) + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + panic(err) + } + } + return sha.Sum(nil) +} diff --git a/backend/groth16/setup/phase2/marshal.go b/backend/groth16/setup/phase2/marshal.go new file mode 100644 index 0000000000..3bc6c51dfa --- /dev/null +++ b/backend/groth16/setup/phase2/marshal.go @@ -0,0 +1,87 @@ +package phase2 + +import ( + "io" + + "github.com/consensys/gnark-crypto/ecc/bn254" +) + +func (c *Contribution) WriteTo(writer io.Writer) (int64, error) { + enc := bn254.NewEncoder(writer) + toEncode := []interface{}{ + &c.PublicKey.SG, + &c.PublicKey.SXG, + &c.PublicKey.XR, + &c.Parameters.G1.Delta, + c.Parameters.G1.L, + c.Parameters.G1.Z, + &c.Parameters.G2.Delta, + } + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + + n, err := writer.Write(c.Hash) + return int64(n), err + +} +func (c *Contribution) ReadFrom(reader io.Reader) (int64, error) { + dec := bn254.NewDecoder(reader) + toEncode := []interface{}{ + &c.PublicKey.SG, + &c.PublicKey.SXG, + &c.PublicKey.XR, + &c.Parameters.G1.Delta, + &c.Parameters.G1.L, + &c.Parameters.G1.Z, + &c.Parameters.G2.Delta, + } + + for _, v := range toEncode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + + c.Hash = make([]byte, 32) + n, err := reader.Read(c.Hash) + return int64(n), err + +} + +func (c *Evaluations) WriteTo(writer io.Writer) (int64, error) { + enc := bn254.NewEncoder(writer) + toEncode := []interface{}{ + c.G1.A, + c.G1.B, + c.G2.B, + } + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + + return enc.BytesWritten(), nil +} + +func (c *Evaluations) ReadFrom(reader io.Reader) (int64, error) { + dec := bn254.NewDecoder(reader) + toEncode := []interface{}{ + &c.G1.A, + &c.G1.B, + &c.G2.B, + } + + for _, v := range toEncode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + + return dec.BytesRead(), nil +} diff --git a/backend/groth16/setup/phase2/verifier.go b/backend/groth16/setup/phase2/verifier.go new file mode 100644 index 0000000000..8017ff3ef7 --- /dev/null +++ b/backend/groth16/setup/phase2/verifier.go @@ -0,0 +1,45 @@ +package phase2 + +import ( + "errors" + + "github.com/consensys/gnark/backend/groth16/setup/utils" +) + +func (c *Contribution) Verify(prev *Contribution) error { + // Compute R for δ + deltaR := utils.GenR(c.PublicKey.SG, c.PublicKey.SXG, prev.Hash[:], 1) + + // Check for knowledge of δ + if !utils.SameRatio(c.PublicKey.SG, c.PublicKey.SXG, c.PublicKey.XR, deltaR) { + return errors.New("couldn't verify knowledge of δ") + } + + // Check for valid updates using previous parameters + if !utils.SameRatio(c.Parameters.G1.Delta, prev.Parameters.G1.Delta, deltaR, c.PublicKey.XR) { + return errors.New("couldn't verify that [δ]₁ is based on previous contribution") + } + if !utils.SameRatio(c.PublicKey.SG, c.PublicKey.SXG, c.Parameters.G2.Delta, prev.Parameters.G2.Delta) { + return errors.New("couldn't verify that [δ]₂ is based on previous contribution") + } + + // Check for valid updates of L and Z using + L, prevL := utils.Merge(c.Parameters.G1.L, prev.Parameters.G1.L) + if !utils.SameRatio(L, prevL, c.Parameters.G2.Delta, prev.Parameters.G2.Delta) { + return errors.New("couldn't verify valid updates of L using δ⁻¹") + } + Z, prevZ := utils.Merge(c.Parameters.G1.Z, prev.Parameters.G1.Z) + if !utils.SameRatio(Z, prevZ, c.Parameters.G2.Delta, prev.Parameters.G2.Delta) { + return errors.New("couldn't verify valid updates of L using δ⁻¹") + } + + // Check hash of the contribution + h := HashContribution(c) + for i := 0; i < len(h); i++ { + if h[i] != c.Hash[i] { + return errors.New("couldn't verify hash of contribution") + } + } + + return nil +} diff --git a/backend/groth16/setup/test/example_test.go b/backend/groth16/setup/test/example_test.go new file mode 100644 index 0000000000..fada264f01 --- /dev/null +++ b/backend/groth16/setup/test/example_test.go @@ -0,0 +1,111 @@ +package test + +import ( + "bytes" + "testing" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/backend/groth16" + "github.com/consensys/gnark/backend/groth16/setup/keys" + "github.com/consensys/gnark/backend/groth16/setup/phase1" + "github.com/consensys/gnark/backend/groth16/setup/phase2" + cs_bn254 "github.com/consensys/gnark/constraint/bn254" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/std/hash/mimc" +) + +// Circuit defines a pre-image knowledge proof +// mimc(secret preImage) = public hash +type Circuit struct { + // struct tag on a variable is optional + // default uses variable name and secret visibility. + PreImage frontend.Variable + Hash frontend.Variable `gnark:",public"` +} + +// Define declares the circuit's constraints +// Hash = mimc(PreImage) +func (circuit *Circuit) Define(api frontend.API) error { + // hash function + mimc, _ := mimc.NewMiMC(api) + + // specify constraints + // mimc(preImage) == hash + mimc.Write(circuit.PreImage) + api.AssertIsEqual(circuit.Hash, mimc.Sum()) + + return nil +} + +func TestSetupCircuit(t *testing.T) { + nContributionsPhase1 := 3 + power := 9 + contributionsPhase1 := make([]phase1.Contribution, nContributionsPhase1) + contributionsPhase1[0].Initialize(power) + + // Make and verify contributions for phase1 + for i := 1; i < nContributionsPhase1; i++ { + contributionsPhase1[i].Contribute(&contributionsPhase1[i-1]) + err := contributionsPhase1[i].Verify(&contributionsPhase1[i-1]) + if err != nil { + t.Error(err) + } + } + + // Compile the circuit + var myCircuit Circuit + ccs, _ := frontend.Compile(bn254.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) + + nContributionsPhase2 := 3 + var evals phase2.Evaluations + contributionsPhase2 := make([]phase2.Contribution, nContributionsPhase2) + switch r1cs := ccs.(type) { + case *cs_bn254.R1CS: + // Prepare for phase-2 + evals = contributionsPhase2[0].PreparePhase(&contributionsPhase1[nContributionsPhase1-1], r1cs) + default: + panic("Unsupported curve") + } + + // Make and verify contributions for phase1 + for i := 1; i < nContributionsPhase2; i++ { + contributionsPhase2[i].Contribute(&contributionsPhase2[i-1]) + err := contributionsPhase2[i].Verify(&contributionsPhase2[i-1]) + if err != nil { + t.Error(err) + } + } + + pk, vk := keys.ExtractKeys(&contributionsPhase1[nContributionsPhase1-1], &contributionsPhase2[nContributionsPhase2-1], &evals, ccs.GetNbConstraints()) + var bufPK, bufVK bytes.Buffer + // Write PK and VK + pk.WriteTo(&bufPK, false) + vk.WriteTo(&bufVK, false) + + // Read PK and VK + + pkk := groth16.NewProvingKey(ecc.BN254) + pkk.ReadFrom(&bufPK) + vkk := groth16.NewVerifyingKey(ecc.BN254) + vkk.ReadFrom(&bufVK) + + assignment := &Circuit{ + PreImage: "16130099170765464552823636852555369511329944820189892919423002775646948828469", + Hash: "12886436712380113721405259596386800092738845035233065858332878701083870690753", + } + witness, _ := frontend.NewWitness(assignment, bn254.ID.ScalarField()) + prf, err := groth16.Prove(ccs, pkk, witness) + if err != nil { + panic(err) + } + pubWitness, err := witness.Public() + if err != nil { + panic(err) + } + err = groth16.Verify(prf, vkk, pubWitness) + if err != nil { + panic(err) + } +} diff --git a/backend/groth16/setup/test/phase1_test.go b/backend/groth16/setup/test/phase1_test.go new file mode 100644 index 0000000000..50f03c8c84 --- /dev/null +++ b/backend/groth16/setup/test/phase1_test.go @@ -0,0 +1,45 @@ +package test + +import ( + "github.com/consensys/gnark/backend/groth16/setup/phase1" + "bytes" + "testing" +) + +func TestContributeVerify(t *testing.T) { + // Contribute 10 times + nContributions := 10 + power := 8 + contributions := make([]phase1.Contribution, nContributions) + contributions[0].Initialize(power) + + // Make contributions + for i := 1; i < nContributions; i++ { + contributions[i].Contribute(&contributions[i-1]) + } + + // Verify contributions + for i := 1; i < nContributions; i++ { + err := contributions[i].Verify(&contributions[i-1]) + if err != nil { + t.Error(err) + } + } +} + +func TestContributionMarshal(t *testing.T) { + power := 8 + var c1, c2 phase1.Contribution + c1.Initialize(power) + var buf bytes.Buffer + if _, err := c1.WriteTo(&buf); err != nil { + t.Error(err) + } + if _, err := c2.ReadFrom(&buf); err != nil { + t.Error(err) + } + + if !bytes.Equal(phase1.HashContribution(&c1), phase1.HashContribution(&c2)) { + t.Error("failed to correctly marshal contribution") + } +} diff --git a/backend/groth16/setup/utils/lagrange.go b/backend/groth16/setup/utils/lagrange.go new file mode 100644 index 0000000000..6fa1f657b8 --- /dev/null +++ b/backend/groth16/setup/utils/lagrange.go @@ -0,0 +1,221 @@ +package utils + +import ( + "math/big" + "math/bits" + "runtime" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" +) + +func butterflyG1(a *bn254.G1Affine, b *bn254.G1Affine) { + t := *a + a.Add(a, b) + b.Sub(&t, b) +} + +func butterflyG2(a *bn254.G2Affine, b *bn254.G2Affine) { + t := *a + a.Add(a, b) + b.Sub(&t, b) +} + +// kerDIF8 is a kernel that process a FFT of size 8 +func kerDIF8G1(a []bn254.G1Affine, twiddles [][]fr.Element, stage int) { + butterflyG1(&a[0], &a[4]) + butterflyG1(&a[1], &a[5]) + butterflyG1(&a[2], &a[6]) + butterflyG1(&a[3], &a[7]) + + var twiddle big.Int + twiddles[stage+0][1].BigInt(&twiddle) + a[5].ScalarMultiplication(&a[5], &twiddle) + twiddles[stage+0][2].BigInt(&twiddle) + a[6].ScalarMultiplication(&a[6], &twiddle) + twiddles[stage+0][3].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG1(&a[0], &a[2]) + butterflyG1(&a[1], &a[3]) + butterflyG1(&a[4], &a[6]) + butterflyG1(&a[5], &a[7]) + twiddles[stage+1][1].BigInt(&twiddle) + a[3].ScalarMultiplication(&a[3], &twiddle) + twiddles[stage+1][1].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG1(&a[0], &a[1]) + butterflyG1(&a[2], &a[3]) + butterflyG1(&a[4], &a[5]) + butterflyG1(&a[6], &a[7]) +} + +// kerDIF8 is a kernel that process a FFT of size 8 +func kerDIF8G2(a []bn254.G2Affine, twiddles [][]fr.Element, stage int) { + butterflyG2(&a[0], &a[4]) + butterflyG2(&a[1], &a[5]) + butterflyG2(&a[2], &a[6]) + butterflyG2(&a[3], &a[7]) + + var twiddle big.Int + twiddles[stage+0][1].BigInt(&twiddle) + a[5].ScalarMultiplication(&a[5], &twiddle) + twiddles[stage+0][2].BigInt(&twiddle) + a[6].ScalarMultiplication(&a[6], &twiddle) + twiddles[stage+0][3].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG2(&a[0], &a[2]) + butterflyG2(&a[1], &a[3]) + butterflyG2(&a[4], &a[6]) + butterflyG2(&a[5], &a[7]) + twiddles[stage+1][1].BigInt(&twiddle) + a[3].ScalarMultiplication(&a[3], &twiddle) + twiddles[stage+1][1].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG2(&a[0], &a[1]) + butterflyG2(&a[2], &a[3]) + butterflyG2(&a[4], &a[5]) + butterflyG2(&a[6], &a[7]) +} + +func difFFTG1(a []bn254.G1Affine, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { + if chDone != nil { + defer close(chDone) + } + + n := len(a) + if n == 1 { + return + } else if n == 8 { + kerDIF8G1(a, twiddles, stage) + return + } + m := n >> 1 + + butterflyG1(&a[0], &a[m]) + + var twiddle big.Int + for i := 1; i < m; i++ { + butterflyG1(&a[i], &a[i+m]) + twiddles[stage][i].BigInt(&twiddle) + a[i+m].ScalarMultiplication(&a[i+m], &twiddle) + } + + if m == 1 { + return + } + + nextStage := stage + 1 + if stage < maxSplits { + chDone := make(chan struct{}, 1) + go difFFTG1(a[m:n], twiddles, nextStage, maxSplits, chDone) + difFFTG1(a[0:m], twiddles, nextStage, maxSplits, nil) + <-chDone + } else { + difFFTG1(a[0:m], twiddles, nextStage, maxSplits, nil) + difFFTG1(a[m:n], twiddles, nextStage, maxSplits, nil) + } +} +func difFFTG2(a []bn254.G2Affine, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { + if chDone != nil { + defer close(chDone) + } + + n := len(a) + if n == 1 { + return + } else if n == 8 { + kerDIF8G2(a, twiddles, stage) + return + } + m := n >> 1 + + butterflyG2(&a[0], &a[m]) + + var twiddle big.Int + for i := 1; i < m; i++ { + butterflyG2(&a[i], &a[i+m]) + twiddles[stage][i].BigInt(&twiddle) + a[i+m].ScalarMultiplication(&a[i+m], &twiddle) + } + + if m == 1 { + return + } + + nextStage := stage + 1 + if stage < maxSplits { + chDone := make(chan struct{}, 1) + go difFFTG2(a[m:n], twiddles, nextStage, maxSplits, chDone) + difFFTG2(a[0:m], twiddles, nextStage, maxSplits, nil) + <-chDone + } else { + difFFTG2(a[0:m], twiddles, nextStage, maxSplits, nil) + difFFTG2(a[m:n], twiddles, nextStage, maxSplits, nil) + } +} + +func BitReverseG1(a []bn254.G1Affine) { + n := uint64(len(a)) + nn := uint64(64 - bits.TrailingZeros64(n)) + + for i := uint64(0); i < n; i++ { + irev := bits.Reverse64(i) >> nn + if irev > i { + a[i], a[irev] = a[irev], a[i] + } + } +} + +func BitReverseG2(a []bn254.G2Affine) { + n := uint64(len(a)) + nn := uint64(64 - bits.TrailingZeros64(n)) + + for i := uint64(0); i < n; i++ { + irev := bits.Reverse64(i) >> nn + if irev > i { + a[i], a[irev] = a[irev], a[i] + } + } +} + +func LagrangeCoeffsG1(powers []bn254.G1Affine, size int) []bn254.G1Affine { + coeffs := make([]bn254.G1Affine, size) + copy(coeffs, powers[:size]) + domain := fft.NewDomain(uint64(size)) + numCPU := uint64(runtime.NumCPU()) + maxSplits := bits.TrailingZeros64(ecc.NextPowerOfTwo(numCPU)) + + difFFTG1(coeffs, domain.TwiddlesInv, 0, maxSplits, nil) + BitReverseG1(coeffs) + + var invBigint big.Int + domain.CardinalityInv.BigInt(&invBigint) + + for i := 0; i < size; i++ { + coeffs[i].ScalarMultiplication(&coeffs[i], &invBigint) + } + + return coeffs +} + +func LagrangeCoeffsG2(powers []bn254.G2Affine, size int) []bn254.G2Affine { + coeffs := make([]bn254.G2Affine, size) + copy(coeffs, powers[:size]) + domain := fft.NewDomain(uint64(size)) + numCPU := uint64(runtime.NumCPU()) + maxSplits := bits.TrailingZeros64(ecc.NextPowerOfTwo(numCPU)) + + difFFTG2(coeffs, domain.TwiddlesInv, 0, maxSplits, nil) + BitReverseG2(coeffs) + + var invBigint big.Int + domain.CardinalityInv.BigInt(&invBigint) + + for i := 0; i < size; i++ { + coeffs[i].ScalarMultiplication(&coeffs[i], &invBigint) + } + + return coeffs +} diff --git a/backend/groth16/setup/utils/utils.go b/backend/groth16/setup/utils/utils.go new file mode 100644 index 0000000000..18f4fc0313 --- /dev/null +++ b/backend/groth16/setup/utils/utils.go @@ -0,0 +1,156 @@ +package utils + +import ( + "math/big" + "runtime" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +type PublicKey struct { + SG bn254.G1Affine + SXG bn254.G1Affine + XR bn254.G2Affine +} + +// Returns [1, a, a², ..., aⁿ⁻¹ ] in Montgomery form +func Powers(a fr.Element, n int) []fr.Element { + result := make([]fr.Element, n) + result[0] = fr.NewElement(1) + for i := 1; i < n; i++ { + result[i].Mul(&result[i-1], &a) + } + return result +} + +// Returns [aᵢAᵢ, ...] in G1 +func ScaleG1(A []bn254.G1Affine, a []fr.Element) []bn254.G1Affine { + var tmp big.Int + result := make([]bn254.G1Affine, len(A)) + for i := 0; i < len(A); i++ { + a[i].BigInt(&tmp) + result[i].ScalarMultiplication(&A[i], &tmp) + } + return result +} + +// Returns [aᵢAᵢ, ...] in G2 +func ScaleG2(A []bn254.G2Affine, a []fr.Element) []bn254.G2Affine { + var tmp big.Int + result := make([]bn254.G2Affine, len(A)) + for i := 0; i < len(A); i++ { + a[i].BigInt(&tmp) + result[i].ScalarMultiplication(&A[i], &tmp) + } + return result +} + +func EvalG1(scalars []fr.Element, points []bn254.G1Affine) *bn254.G1Jac { + nc := runtime.NumCPU() + + var result bn254.G1Jac + if _, err := result.MultiExp(points, scalars, ecc.MultiExpConfig{NbTasks: nc / 2}); err != nil { + panic("Failed to MultiExp") + } + return &result +} + +func EvalG2(scalars []fr.Element, points []bn254.G2Affine) *bn254.G2Jac { + nc := runtime.NumCPU() + + var result bn254.G2Jac + if _, err := result.MultiExp(points, scalars, ecc.MultiExpConfig{NbTasks: nc / 2}); err != nil { + panic("Failed to MultiExp") + } + return &result +} + +// Check e(a₁, a₂) = e(b₁, b₂) +func SameRatio(a1, b1 bn254.G1Affine, a2, b2 bn254.G2Affine) bool { + if !a1.IsInSubGroup() || !b1.IsInSubGroup() || !a2.IsInSubGroup() || !b2.IsInSubGroup() { + panic("invalid point not in subgroup") + } + var na2 bn254.G2Affine + na2.Neg(&a2) + res, err := bn254.PairingCheck( + []bn254.G1Affine{a1, b1}, + []bn254.G2Affine{na2, b2}) + if err != nil { + panic(err) + } + return res +} + +// returnsa = ∑ rᵢAᵢ, b = ∑ rᵢBᵢ +func Merge(A, B []bn254.G1Affine) (a, b bn254.G1Affine) { + nc := runtime.NumCPU() + r := make([]fr.Element, len(A)) + for i := 0; i < len(A); i++ { + r[i].SetRandom() + } + a.MultiExp(A, r, ecc.MultiExpConfig{NbTasks: nc / 2}) + b.MultiExp(B, r, ecc.MultiExpConfig{NbTasks: nc / 2}) + return +} + +// L1 = ∑ rᵢAᵢ, L2 = ∑ rᵢAᵢ₊₁ in G1 +func LinearCombinationG1(A []bn254.G1Affine) (L1, L2 bn254.G1Affine) { + nc := runtime.NumCPU() + n := len(A) + r := make([]fr.Element, n-1) + for i := 0; i < n-1; i++ { + r[i].SetRandom() + } + L1.MultiExp(A[:n-1], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + L2.MultiExp(A[1:], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + return +} + +// L1 = ∑ rᵢAᵢ, L2 = ∑ rᵢAᵢ₊₁ in G2 +func LinearCombinationG2(A []bn254.G2Affine) (L1, L2 bn254.G2Affine) { + nc := runtime.NumCPU() + n := len(A) + r := make([]fr.Element, n-1) + for i := 0; i < n-1; i++ { + r[i].SetRandom() + } + L1.MultiExp(A[:n-1], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + L2.MultiExp(A[1:], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + return +} + +// Generate R in G₂ as Hash(gˢ, gˢˣ, challenge, dst) +func GenR(sG1, sxG1 bn254.G1Affine, challenge []byte, dst byte) bn254.G2Affine { + buffer := append(sG1.Marshal()[:], sxG1.Marshal()...) + buffer = append(buffer, challenge...) + spG2, err := bn254.HashToG2(buffer, []byte{dst}) + if err != nil { + panic(err) + } + return spG2 +} + +func GenPublicKey(x fr.Element, challenge []byte, dst byte) PublicKey { + var pk PublicKey + _, _, g1, _ := bn254.Generators() + + var s fr.Element + var sBi big.Int + s.SetRandom() + s.BigInt(&sBi) + pk.SG.ScalarMultiplication(&g1, &sBi) + + // compute x*sG1 + var xBi big.Int + x.BigInt(&xBi) + pk.SXG.ScalarMultiplication(&pk.SG, &xBi) + + // generate R based on sG1, sxG1, challenge, and domain separation tag (tau, alpha or beta) + R := GenR(pk.SG, pk.SXG, challenge, dst) + + // compute x*spG2 + pk.XR.ScalarMultiplication(&R, &xBi) + return pk +} From 78a02476111a64e031a54d69c8357866e5f513b9 Mon Sep 17 00:00:00 2001 From: Hisham Galal <0xhgalal@gmail.com> Date: Thu, 2 Mar 2023 10:20:32 -0500 Subject: [PATCH 049/464] fix Z in preparePhase2 --- backend/groth16/setup/phase2/contribution.go | 9 ++++----- backend/groth16/setup/test/example_test.go | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/backend/groth16/setup/phase2/contribution.go b/backend/groth16/setup/phase2/contribution.go index 7fc3ec957a..9bd43b5108 100644 --- a/backend/groth16/setup/phase2/contribution.go +++ b/backend/groth16/setup/phase2/contribution.go @@ -35,7 +35,7 @@ type Contribution struct { Hash []byte } -func (c2 *Contribution) PreparePhase(c1 *phase1.Contribution, r1cs *cs_bn254.R1CS) Evaluations { +func (c2 *Contribution) PreparePhase2(c1 *phase1.Contribution, r1cs *cs_bn254.R1CS) Evaluations { srs := c1.Parameters size := len(srs.G1.AlphaTau) if size < r1cs.GetNbConstraints() { @@ -127,9 +127,8 @@ func (c2 *Contribution) PreparePhase(c1 *phase1.Contribution, r1cs *cs_bn254.R1C for i := 0; i < n-1; i++ { c2.Parameters.G1.Z[i].Sub(&srs.G1.Tau[i+n], &srs.G1.Tau[i]) } - // this is an extra point that is added for the sake of being compatible with gnark setup - // evenutally it is multiplied by zero, hence it won't affect the resutl - c2.Parameters.G1.Z[n-1].Set(&g1) + utils.BitReverseG1(c2.Parameters.G1.Z) + c2.Parameters.G1.Z = c2.Parameters.G1.Z[:n-1] // Evaluate L nPrivate := internal + secret @@ -179,7 +178,7 @@ func (c *Contribution) Contribute(prev *Contribution) { c.Parameters.G1.Z[i].ScalarMultiplication(&prev.Parameters.G1.Z[i], &deltaInvBI) } - // Update Z using δ⁻¹ + // Update L using δ⁻¹ c.Parameters.G1.L = make([]bn254.G1Affine, len(prev.Parameters.G1.L)) for i := 0; i < len(prev.Parameters.G1.L); i++ { c.Parameters.G1.L[i].ScalarMultiplication(&prev.Parameters.G1.L[i], &deltaInvBI) diff --git a/backend/groth16/setup/test/example_test.go b/backend/groth16/setup/test/example_test.go index fada264f01..8cdd8416f5 100644 --- a/backend/groth16/setup/test/example_test.go +++ b/backend/groth16/setup/test/example_test.go @@ -64,7 +64,7 @@ func TestSetupCircuit(t *testing.T) { switch r1cs := ccs.(type) { case *cs_bn254.R1CS: // Prepare for phase-2 - evals = contributionsPhase2[0].PreparePhase(&contributionsPhase1[nContributionsPhase1-1], r1cs) + evals = contributionsPhase2[0].PreparePhase2(&contributionsPhase1[nContributionsPhase1-1], r1cs) default: panic("Unsupported curve") } From 02f598ef55b9d87768208bee0373e3c27054c0ab Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Thu, 2 Mar 2023 09:37:21 -0600 Subject: [PATCH 050/464] fix: closes #509 api did not handle AssertIsLessOrEqual with constant as first param (#511) * fix: closes #509 api did not handle AssertIsLessOrEqual with constant as first param * style: remove useless MarkBoolean on non-returned bits --- frontend/cs/r1cs/api_assertions.go | 46 +++++++++++++++++++++--------- frontend/cs/scs/api_assertions.go | 38 +++++++++++++++++------- frontend/cs/scs/builder.go | 6 ++++ 3 files changed, 67 insertions(+), 23 deletions(-) diff --git a/frontend/cs/r1cs/api_assertions.go b/frontend/cs/r1cs/api_assertions.go index 2d2db8f010..ec7351b4af 100644 --- a/frontend/cs/r1cs/api_assertions.go +++ b/frontend/cs/r1cs/api_assertions.go @@ -17,12 +17,12 @@ limitations under the License. package r1cs import ( + "fmt" "math/big" "github.com/consensys/gnark/debug" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/internal/expr" - "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/std/math/bits" ) @@ -80,18 +80,34 @@ func (builder *builder) AssertIsBoolean(i1 frontend.Variable) { // // derived from: // https://github.com/zcash/zips/blob/main/protocol/protocol.pdf -func (builder *builder) AssertIsLessOrEqual(_v frontend.Variable, bound frontend.Variable) { - v := builder.toVariable(_v) +func (builder *builder) AssertIsLessOrEqual(v frontend.Variable, bound frontend.Variable) { + cv, vConst := builder.constantValue(v) + cb, bConst := builder.constantValue(bound) + + // both inputs are constants + if vConst && bConst { + bv, bb := builder.cs.ToBigInt(&cv), builder.cs.ToBigInt(&cb) + if bv.Cmp(bb) == 1 { + panic(fmt.Sprintf("AssertIsLessOrEqual: %s > %s", bv.String(), bb.String())) + } + } - if b, ok := bound.(expr.LinearExpression); ok { - assertIsSet(b) - builder.mustBeLessOrEqVar(v, b) - } else { - builder.mustBeLessOrEqCst(v, utils.FromInterface(bound)) + // bound is constant + if bConst { + vv := builder.toVariable(v) + builder.mustBeLessOrEqCst(vv, builder.cs.ToBigInt(&cb)) + return } + + builder.mustBeLessOrEqVar(v, bound) } -func (builder *builder) mustBeLessOrEqVar(a, bound expr.LinearExpression) { +func (builder *builder) mustBeLessOrEqVar(a, bound frontend.Variable) { + // here bound is NOT a constant, + // but a can be either constant or a wire. + + _, aConst := builder.constantValue(a) + debug := builder.newDebugInfo("mustBeLessOrEq", a, " <= ", bound) nbBits := builder.cs.FieldBitLen() @@ -128,16 +144,21 @@ func (builder *builder) mustBeLessOrEqVar(a, bound expr.LinearExpression) { // note if bound[i] == 1, this constraint is (1 - ai) * ai == 0 // → this is a boolean constraint // if bound[i] == 0, t must be 0 or 1, thus ai must be 0 or 1 too - builder.MarkBoolean(aBits[i].(expr.LinearExpression)) // this does not create a constraint - added = append(added, builder.cs.AddConstraint(builder.newR1C(l, aBits[i], zero))) + if aConst { + // aBits[i] is a constant; + l = builder.Mul(l, aBits[i]) + added = append(added, builder.cs.AddConstraint(builder.newR1C(l, zero, zero))) + } else { + added = append(added, builder.cs.AddConstraint(builder.newR1C(l, aBits[i], zero))) + } } builder.cs.AttachDebugInfo(debug, added) } -func (builder *builder) mustBeLessOrEqCst(a expr.LinearExpression, bound big.Int) { +func (builder *builder) mustBeLessOrEqCst(a expr.LinearExpression, bound *big.Int) { nbBits := builder.cs.FieldBitLen() @@ -187,7 +208,6 @@ func (builder *builder) mustBeLessOrEqCst(a expr.LinearExpression, bound big.Int l = builder.Sub(l, aBits[i]) added = append(added, builder.cs.AddConstraint(builder.newR1C(l, aBits[i], builder.cstZero()))) - builder.MarkBoolean(aBits[i].(expr.LinearExpression)) } else { builder.AssertIsBoolean(aBits[i]) } diff --git a/frontend/cs/scs/api_assertions.go b/frontend/cs/scs/api_assertions.go index 976a60f1ab..27b5962420 100644 --- a/frontend/cs/scs/api_assertions.go +++ b/frontend/cs/scs/api_assertions.go @@ -110,13 +110,13 @@ func (builder *builder) AssertIsBoolean(i1 frontend.Variable) { func (builder *builder) AssertIsLessOrEqual(v frontend.Variable, bound frontend.Variable) { switch b := bound.(type) { case expr.Term: - builder.mustBeLessOrEqVar(v.(expr.Term), b) + builder.mustBeLessOrEqVar(v, b) default: - builder.mustBeLessOrEqCst(v.(expr.Term), utils.FromInterface(b)) + builder.mustBeLessOrEqCst(v, utils.FromInterface(b)) } } -func (builder *builder) mustBeLessOrEqVar(a expr.Term, bound expr.Term) { +func (builder *builder) mustBeLessOrEqVar(a frontend.Variable, bound expr.Term) { debug := builder.newDebugInfo("mustBeLessOrEq", a, " <= ", bound) @@ -147,18 +147,28 @@ func (builder *builder) mustBeLessOrEqVar(a expr.Term, bound expr.Term) { // note if bound[i] == 1, this constraint is (1 - ai) * ai == 0 // → this is a boolean constraint // if bound[i] == 0, t must be 0 or 1, thus ai must be 0 or 1 too - builder.MarkBoolean(aBits[i].(expr.Term)) // this does not create a constraint - builder.addPlonkConstraint(sparseR1C{ - xa: l.VID, - xb: aBits[i].(expr.Term).VID, - qM: l.Coeff, - }, debug) + if ai, ok := builder.constantValue(aBits[i]); ok { + // a is constant; ensure l == 0 + builder.cs.Mul(&l.Coeff, &ai) + builder.addPlonkConstraint(sparseR1C{ + xa: l.VID, + qL: l.Coeff, + }, debug) + } else { + // l * a[i] == 0 + builder.addPlonkConstraint(sparseR1C{ + xa: l.VID, + xb: aBits[i].(expr.Term).VID, + qM: l.Coeff, + }, debug) + } + } } -func (builder *builder) mustBeLessOrEqCst(a expr.Term, bound big.Int) { +func (builder *builder) mustBeLessOrEqCst(a frontend.Variable, bound big.Int) { nbBits := builder.cs.FieldBitLen() @@ -170,6 +180,14 @@ func (builder *builder) mustBeLessOrEqCst(a expr.Term, bound big.Int) { panic("AssertIsLessOrEqual: bound is too large, constraint will never be satisfied") } + if ca, ok := builder.constantValue(a); ok { + // a is constant, compare the big int values + ba := builder.cs.ToBigInt(&ca) + if ba.Cmp(&bound) == 1 { + panic(fmt.Sprintf("AssertIsLessOrEqual: %s > %s", ba.String(), bound.String())) + } + } + // debug info debug := builder.newDebugInfo("mustBeLessOrEq", a, " <= ", bound) diff --git a/frontend/cs/scs/builder.go b/frontend/cs/scs/builder.go index b579c9d74c..340e5fe0ab 100644 --- a/frontend/cs/scs/builder.go +++ b/frontend/cs/scs/builder.go @@ -136,6 +136,12 @@ func (builder *builder) addMulGate(a, b, c expr.Term, debug ...constraint.DebugI // addPlonkConstraint adds a sparseR1C to the underlying constraint system func (builder *builder) addPlonkConstraint(c sparseR1C, debug ...constraint.DebugInfo) { + if !c.qM.IsZero() && (c.xa == 0 || c.xb == 0) { + // TODO this is internal but not easy to detect; if qM is set, but one or both of xa / xb is not, + // since wireID == 0 is a valid wire, it may trigger unexpected behavior. + log := logger.Logger() + log.Warn().Msg("adding a plonk constraint with qM set but xa or xb == 0 (wire 0)") + } L := builder.cs.MakeTerm(&c.qL, c.xa) R := builder.cs.MakeTerm(&c.qR, c.xb) O := builder.cs.MakeTerm(&c.qO, c.xc) From 34f3c2b42d88ad8df6962312d78a8ad9a1a65c83 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Fri, 3 Mar 2023 15:58:03 +0100 Subject: [PATCH 051/464] fix: restrict constants in field emulation to width (#518) * fix: enforce constant limbs to width * docs: reformat NewElement description --- std/math/emulated/field.go | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/std/math/emulated/field.go b/std/math/emulated/field.go index e4c0c3d357..87653a430a 100644 --- a/std/math/emulated/field.go +++ b/std/math/emulated/field.go @@ -6,6 +6,7 @@ import ( "sync" "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" "github.com/rs/zerolog" "golang.org/x/exp/constraints" @@ -89,7 +90,9 @@ func NewField[T FieldParams](native frontend.API) (*Field[T], error) { // NewElement builds a new Element[T] from input v. // - if v is a Element[T] or *Element[T] it clones it // - if v is a constant this is equivalent to calling emulated.ValueOf[T] -// - if this methods interpret v (frontend.Variable or []frontend.Variable) as being the limbs; and constrain the limbs following the parameters of the Field. +// - if this methods interprets v as being the limbs (frontend.Variable or []frontend.Variable), +// it constructs a new Element[T] with v as limbs and constraints the limbs to the parameters +// of the Field[T]. func (f *Field[T]) NewElement(v interface{}) *Element[T] { if e, ok := v.(Element[T]); ok { return e.copy() @@ -157,14 +160,27 @@ func (f *Field[T]) enforceWidthConditional(a *Element[T]) (didConstrain bool) { return false } if _, isConst := f.constantValue(a); isConst { + // enforce constant element limbs not to be large. + for i := range a.Limbs { + val := utils.FromInterface(a.Limbs[i]) + if val.BitLen() > int(f.fParams.BitsPerLimb()) { + panic("constant element limb wider than emulated parameter") + } + } // constant values are constant return false } for i := range a.Limbs { if !frontend.IsCanonical(a.Limbs[i]) { - // this is not a variable. This may happen when some limbs are - // constant and some variables. A strange case but lets try to cover - // it anyway. + // this is not a canonical variable, nor a constant. This may happen + // when some limbs are constant and some variables. Or if we are + // running in a test engine. In either case, we must check that if + // this limb is a [*big.Int] that its bitwidth is less than the + // NbBits. + val := utils.FromInterface(a.Limbs[i]) + if val.BitLen() > int(f.fParams.BitsPerLimb()) { + panic("non-canonical integer limb wider than emulated parameter") + } continue } if vv, ok := a.Limbs[i].(interface{ HashCode() uint64 }); ok { From c22e9ba228ae302819c71b71efa911265a120f20 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Fri, 3 Mar 2023 16:12:43 +0100 Subject: [PATCH 052/464] chore: remove heavy profiling and compiling --- std/signature/ecdsa/ecdsa_test.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/std/signature/ecdsa/ecdsa_test.go b/std/signature/ecdsa/ecdsa_test.go index b1fad60ba0..711ec69554 100644 --- a/std/signature/ecdsa/ecdsa_test.go +++ b/std/signature/ecdsa/ecdsa_test.go @@ -3,15 +3,12 @@ package ecdsa import ( "crypto/rand" "crypto/sha256" - "fmt" "math/big" "testing" "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/secp256k1/ecdsa" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/profile" "github.com/consensys/gnark/std/algebra/weierstrass" "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/test" @@ -117,10 +114,6 @@ func TestEcdsaSHA256(t *testing.T) { assert := test.NewAssert(t) err := test.IsSolved(&circuit, &witness, ecc.BN254.ScalarField()) assert.NoError(err) - p := profile.Start() - _, _ = frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) - p.Stop() - fmt.Println(p.NbConstraints()) } // Example how to verify the signature inside the circuit. From db76d9e43be51cb1452cbf205a253114fefd5769 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Mon, 6 Mar 2023 15:17:37 +0100 Subject: [PATCH 053/464] feat: BN254 pairing (#411) * feat: add BN254 pairing using field emulation * refactor: make methods private * feat: add equality assertion for GT elements * docs: add package documentation and example --- std/algebra/pairing_bn254/doc.go | 7 + std/algebra/pairing_bn254/doc_test.go | 101 +++ std/algebra/pairing_bn254/g1.go | 16 + std/algebra/pairing_bn254/g2.go | 31 + std/algebra/pairing_bn254/gt.go | 41 ++ std/algebra/pairing_bn254/pairing.go | 282 ++++++++ std/algebra/pairing_bn254/pairing_test.go | 122 ++++ std/algebra/pairing_bn254/tower.go | 833 ++++++++++++++++++++++ 8 files changed, 1433 insertions(+) create mode 100644 std/algebra/pairing_bn254/doc.go create mode 100644 std/algebra/pairing_bn254/doc_test.go create mode 100644 std/algebra/pairing_bn254/g1.go create mode 100644 std/algebra/pairing_bn254/g2.go create mode 100644 std/algebra/pairing_bn254/gt.go create mode 100644 std/algebra/pairing_bn254/pairing.go create mode 100644 std/algebra/pairing_bn254/pairing_test.go create mode 100644 std/algebra/pairing_bn254/tower.go diff --git a/std/algebra/pairing_bn254/doc.go b/std/algebra/pairing_bn254/doc.go new file mode 100644 index 0000000000..5f04a7dd72 --- /dev/null +++ b/std/algebra/pairing_bn254/doc.go @@ -0,0 +1,7 @@ +// Package pairing_bn254 implements pairing over BN254 curve. +// +// The implementation follows very closely the implementation of its out-circuit +// counterpart in [gnark-crypto]. +// +// [gnark-crypto]: https://github.com/ConsenSys/gnark-crypto/tree/master/ecc/bn254 +package pairing_bn254 diff --git a/std/algebra/pairing_bn254/doc_test.go b/std/algebra/pairing_bn254/doc_test.go new file mode 100644 index 0000000000..8481c45361 --- /dev/null +++ b/std/algebra/pairing_bn254/doc_test.go @@ -0,0 +1,101 @@ +package pairing_bn254_test + +import ( + "crypto/rand" + "fmt" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/backend/groth16" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/std/algebra/pairing_bn254" +) + +type PairCircuit struct { + InG1 pairing_bn254.G1Affine + InG2 pairing_bn254.G2Affine + Res pairing_bn254.GTEl +} + +func (c *PairCircuit) Define(api frontend.API) error { + pairing, err := pairing_bn254.NewPairing(api) + if err != nil { + return fmt.Errorf("new pairing: %w", err) + } + res, err := pairing.Pair([]*pairing_bn254.G1Affine{&c.InG1}, []*pairing_bn254.G2Affine{&c.InG2}) + if err != nil { + return fmt.Errorf("pair: %w", err) + } + pairing.AssertIsEqual(res, &c.Res) + return nil +} + +func ExamplePairing() { + p, q, err := randomG1G2Affines() + if err != nil { + panic(err) + } + res, err := bn254.Pair([]bn254.G1Affine{p}, []bn254.G2Affine{q}) + if err != nil { + panic(err) + } + circuit := PairCircuit{} + witness := PairCircuit{ + InG1: pairing_bn254.NewG1Affine(p), + InG2: pairing_bn254.NewG2Affine(q), + Res: pairing_bn254.NewGTEl(res), + } + ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) + if err != nil { + panic(err) + } else { + fmt.Println("compiled") + } + pk, vk, err := groth16.Setup(ccs) + if err != nil { + panic(err) + } else { + fmt.Println("setup done") + } + secretWitness, err := frontend.NewWitness(&witness, ecc.BN254.ScalarField()) + if err != nil { + panic(err) + } else { + fmt.Println("secret witness") + } + publicWitness, err := secretWitness.Public() + if err != nil { + panic(err) + } else { + fmt.Println("public witness") + } + proof, err := groth16.Prove(ccs, pk, secretWitness) + if err != nil { + panic(err) + } else { + fmt.Println("proof") + } + err = groth16.Verify(proof, vk, publicWitness) + if err != nil { + panic(err) + } else { + fmt.Println("verify") + } +} + +func randomG1G2Affines() (p bn254.G1Affine, q bn254.G2Affine, err error) { + _, _, G1AffGen, G2AffGen := bn254.Generators() + mod := bn254.ID.ScalarField() + s1, err := rand.Int(rand.Reader, mod) + if err != nil { + return p, q, err + } + s2, err := rand.Int(rand.Reader, mod) + if err != nil { + return p, q, err + } + p.ScalarMultiplication(&G1AffGen, s1) + q.ScalarMultiplication(&G2AffGen, s2) + return +} diff --git a/std/algebra/pairing_bn254/g1.go b/std/algebra/pairing_bn254/g1.go new file mode 100644 index 0000000000..4f1fa5d2c4 --- /dev/null +++ b/std/algebra/pairing_bn254/g1.go @@ -0,0 +1,16 @@ +package pairing_bn254 + +import ( + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/std/algebra/weierstrass" + "github.com/consensys/gnark/std/math/emulated" +) + +type G1Affine = weierstrass.AffinePoint[emulated.BN254Fp] + +func NewG1Affine(v bn254.G1Affine) G1Affine { + return G1Affine{ + X: emulated.ValueOf[emulated.BN254Fp](v.X), + Y: emulated.ValueOf[emulated.BN254Fp](v.Y), + } +} diff --git a/std/algebra/pairing_bn254/g2.go b/std/algebra/pairing_bn254/g2.go new file mode 100644 index 0000000000..ace3b00efe --- /dev/null +++ b/std/algebra/pairing_bn254/g2.go @@ -0,0 +1,31 @@ +package pairing_bn254 + +import ( + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/std/math/emulated" +) + +type G2Affine struct { + X, Y e2 +} + +type g2Jacobian struct { + X, Y, Z e2 +} + +type g2Projective struct { + X, Y, Z e2 +} + +func NewG2Affine(v bn254.G2Affine) G2Affine { + return G2Affine{ + X: e2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.X.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.X.A1), + }, + Y: e2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.Y.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.Y.A1), + }, + } +} diff --git a/std/algebra/pairing_bn254/gt.go b/std/algebra/pairing_bn254/gt.go new file mode 100644 index 0000000000..2b84c9f0ed --- /dev/null +++ b/std/algebra/pairing_bn254/gt.go @@ -0,0 +1,41 @@ +package pairing_bn254 + +import ( + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/std/math/emulated" +) + +type GTEl = e12 + +func NewGTEl(v bn254.GT) GTEl { + return GTEl{ + C0: e6{ + B0: e2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B0.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B0.A1), + }, + B1: e2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B1.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B1.A1), + }, + B2: e2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B2.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B2.A1), + }, + }, + C1: e6{ + B0: e2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B0.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B0.A1), + }, + B1: e2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B1.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B1.A1), + }, + B2: e2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B2.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B2.A1), + }, + }, + } +} diff --git a/std/algebra/pairing_bn254/pairing.go b/std/algebra/pairing_bn254/pairing.go new file mode 100644 index 0000000000..ec0baa633b --- /dev/null +++ b/std/algebra/pairing_bn254/pairing.go @@ -0,0 +1,282 @@ +package pairing_bn254 + +import ( + "fmt" + + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/math/emulated" +) + +type Pairing struct { + *ext12 +} + +func NewPairing(api frontend.API) (*Pairing, error) { + ba, err := emulated.NewField[emulated.BN254Fp](api) + if err != nil { + return nil, fmt.Errorf("new base api: %w", err) + } + return &Pairing{ + ext12: newExt12(ba), + }, nil +} + +func (pr Pairing) doubleStep(p *g2Projective) (*g2Projective, *lineEvaluation) { + // var t1, A, B, C, D, E, EE, F, G, H, I, J, K fptower.E2 + A := pr.ext2.mul(&p.X, &p.Y) // A.Mul(&p.x, &p.y) + A = pr.ext2.halve(A) // A.Halve() + B := pr.ext2.square(&p.Y) // B.Square(&p.y) + C := pr.ext2.square(&p.Z) // C.Square(&p.z) + D := pr.ext2.double(C) // D.Double(&C). + D = pr.ext2.add(D, C) // Add(&D, &C) + E := pr.ext2.mulBybTwistCurveCoeff(D) // E.MulBybTwistCurveCoeff(&D) + F := pr.ext2.double(E) // F.Double(&E). + F = pr.ext2.add(F, E) // Add(&F, &E) + G := pr.ext2.add(B, F) // G.Add(&B, &F) + G = pr.ext2.halve(G) // G.Halve() + H := pr.ext2.add(&p.Y, &p.Z) // H.Add(&p.y, &p.z). + H = pr.ext2.square(H) // Square(&H) + t1 := pr.ext2.add(B, C) // t1.Add(&B, &C) + H = pr.ext2.sub(H, t1) // H.Sub(&H, &t1) + I := pr.ext2.sub(E, B) // I.Sub(&E, &B) + J := pr.ext2.square(&p.X) // J.Square(&p.x) + EE := pr.ext2.square(E) // EE.Square(&E) + K := pr.ext2.double(EE) // K.Double(&EE). + K = pr.ext2.add(K, EE) // Add(&K, &EE) + px := pr.ext2.sub(B, F) // p.x.Sub(&B, &F). + px = pr.ext2.mul(px, A) // Mul(&p.x, &A) + py := pr.ext2.square(G) // p.y.Square(&G). + py = pr.ext2.sub(py, K) // Sub(&p.y, &K) + pz := pr.ext2.mul(B, H) // p.z.Mul(&B, &H) + ev0 := pr.ext2.neg(H) // evaluations.r0.Neg(&H) + ev1 := pr.ext2.double(J) // evaluations.r1.Double(&J). + ev1 = pr.ext2.add(ev1, J) // Add(&evaluations.r1, &J) + ev2 := I // evaluations.r2.Set(&I) + return &g2Projective{ + X: *px, + Y: *py, + Z: *pz, + }, + &lineEvaluation{ + r0: *ev0, + r1: *ev1, + r2: *ev2, + } +} + +func (pr Pairing) affineToProjective(Q *G2Affine) *g2Projective { + // TODO: check point at infinity? We do not filter them in the Miller Loop neither. + // if Q.X.IsZero() && Q.Y.IsZero() { + // p.z.SetZero() + // p.x.SetOne() + // p.y.SetOne() + // return p + // } + pz := pr.ext2.one() // p.z.SetOne() + px := &Q.X // p.x.Set(&Q.X) + py := &Q.Y // p.y.Set(&Q.Y) + return &g2Projective{ // return p + X: *px, + Y: *py, + Z: *pz, + } +} + +func (pr Pairing) negAffine(a *G2Affine) *G2Affine { + px := &a.X // p.X = a.X + py := pr.ext2.neg(&a.Y) // p.Y.Neg(&a.Y) + return &G2Affine{ // return p + X: *px, + Y: *py, + } +} + +func (pr Pairing) addStep(p *g2Projective, a *G2Affine) (*g2Projective, *lineEvaluation) { + // var Y2Z1, X2Z1, O, L, C, D, E, F, G, H, t0, t1, t2, J fptower.E2 + Y2Z1 := pr.ext2.mul(&a.Y, &p.Z) // Y2Z1.Mul(&a.Y, &p.z) + O := pr.ext2.sub(&p.Y, Y2Z1) // O.Sub(&p.y, &Y2Z1) + X2Z1 := pr.ext2.mul(&a.X, &p.Z) // X2Z1.Mul(&a.X, &p.z) + L := pr.ext2.sub(&p.X, X2Z1) // L.Sub(&p.x, &X2Z1) + C := pr.ext2.square(O) // C.Square(&O) + D := pr.ext2.square(L) // D.Square(&L) + E := pr.ext2.mul(L, D) // E.Mul(&L, &D) + F := pr.ext2.mul(&p.Z, C) // F.Mul(&p.z, &C) + G := pr.ext2.mul(&p.X, D) // G.Mul(&p.x, &D) + t0 := pr.ext2.double(G) // t0.Double(&G) + H := pr.ext2.add(E, F) // H.Add(&E, &F). + H = pr.ext2.sub(H, t0) // Sub(&H, &t0) + t1 := pr.ext2.mul(&p.Y, E) // t1.Mul(&p.y, &E) + px := pr.ext2.mul(L, H) // p.x.Mul(&L, &H) + py := pr.ext2.sub(G, H) // p.y.Sub(&G, &H). + py = pr.ext2.mul(py, O) // Mul(&p.y, &O). + py = pr.ext2.sub(py, t1) // Sub(&p.y, &t1) + pz := pr.ext2.mul(E, &p.Z) // p.z.Mul(&E, &p.z) + t2 := pr.ext2.mul(L, &a.Y) // t2.Mul(&L, &a.Y) + J := pr.ext2.mul(&a.X, O) // J.Mul(&a.X, &O). + J = pr.ext2.sub(J, t2) // Sub(&J, &t2) + ev0 := L // evaluations.r0.Set(&L) + ev1 := pr.ext2.neg(O) // evaluations.r1.Neg(&O) + ev2 := J // evaluations.r2.Set(&J) + return &g2Projective{ + X: *px, + Y: *py, + Z: *pz, + }, &lineEvaluation{ + r0: *ev0, + r1: *ev1, + r2: *ev2, + } +} + +type lineEvaluation struct { + r0 e2 + r1 e2 + r2 e2 +} + +var loopCounter = [66]int8{ + 0, 0, 0, 1, 0, 1, 0, -1, 0, 0, -1, + 0, 0, 0, 1, 0, 0, -1, 0, -1, 0, 0, + 0, 1, 0, -1, 0, 0, 0, 0, -1, 0, 0, + 1, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, + -1, 0, 0, -1, 0, 1, 0, -1, 0, 0, 0, + -1, 0, -1, 0, 0, 0, 1, 0, -1, 0, 1, +} + +func (pr Pairing) MillerLoop(p []*G1Affine, q []*G2Affine) (*GTEl, error) { + n := len(p) + if n == 0 || n != len(q) { + return nil, fmt.Errorf("invalid inputs sizes") + } + + // TODO: we have omitted filtering for infinity points. + + // projective points for Q + qProj := make([]*g2Projective, n) // qProj := make([]g2Proj, n) + qNeg := make([]*G2Affine, n) // qNeg := make([]G2Affine, n) + for k := 0; k < n; k++ { + qProj[k] = pr.affineToProjective(q[k]) // qProj[k].FromAffine(&q[k]) + qNeg[k] = pr.negAffine(q[k]) // qNeg[k].Neg(&q[k]) + } + + var l, l0 *lineEvaluation + result := pr.ext12.one() // var tmp, result GTEl + + // i == len(loopCounter) - 2 + for k := 0; k < n; k++ { + qProj[k], l = pr.doubleStep(qProj[k]) // qProj[k].DoubleStep(&l) + l.r0 = *pr.ext12.ext2.mulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) + l.r1 = *pr.ext12.ext2.mulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) + result = pr.ext12.mulBy034(result, &l.r0, &l.r1, &l.r2) // result.MulBy034(&l.r0, &l.r1, &l.r2) + } + + for i := len(loopCounter) - 3; i >= 0; i-- { + result = pr.ext12.square(result) // result.Square(&result) + + for k := 0; k < n; k++ { + qProj[k], l = pr.doubleStep(qProj[k]) // qProj[k].DoubleStep(&l) + l.r0 = *pr.ext12.ext2.mulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) + l.r1 = *pr.ext12.ext2.mulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) + + if loopCounter[i] == 1 { + qProj[k], l0 = pr.addStep(qProj[k], q[k]) // qProj[k].AddMixedStep(&l0, &q[k]) + l0.r0 = *pr.ext12.ext2.mulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) + l0.r1 = *pr.ext12.ext2.mulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) + tmp := pr.ext12.mulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result = pr.ext12.mul(result, tmp) // result.Mul(&result, &tmp) + } else if loopCounter[i] == -1 { + qProj[k], l0 = pr.addStep(qProj[k], qNeg[k]) // qProj[k].AddMixedStep(&l0, &qNeg[k]) + l0.r0 = *pr.ext12.ext2.mulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) + l0.r1 = *pr.ext12.ext2.mulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) + tmp := pr.ext12.mulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result = pr.ext12.mul(result, tmp) //result.Mul(&result, &tmp) + } else { + result = pr.ext12.mulBy034(result, &l.r0, &l.r1, &l.r2) // result.MulBy034(&l.r0, &l.r1, &l.r2) + } + } + } + + Q1, Q2 := new(G2Affine), new(G2Affine) // var Q1, Q2 G2Affine + for k := 0; k < n; k++ { + //Q1 = π(Q) + // TODO(ivokub): define phi(Q) in G2 instead of doing manually? + Q1.X = *pr.ext12.ext2.conjugate(&q[k].X) // Q1.X.Conjugate(&q[k].X).MulByNonResidue1Power2(&Q1.X) + Q1.X = *pr.ext12.ext2.mulByNonResidue1Power2(&Q1.X) // Q1.X.Conjugate(&q[k].X).MulByNonResidue1Power2(&Q1.X) + Q1.Y = *pr.ext12.ext2.conjugate(&q[k].Y) // Q1.Y.Conjugate(&q[k].Y).MulByNonResidue1Power3(&Q1.Y) + Q1.Y = *pr.ext12.ext2.mulByNonResidue1Power3(&Q1.Y) // Q1.Y.Conjugate(&q[k].Y).MulByNonResidue1Power3(&Q1.Y) + + // Q2 = -π²(Q) + Q2.X = *pr.ext12.ext2.mulByNonResidue2Power2(&q[k].X) // Q2.X.MulByNonResidue2Power2(&q[k].X) + Q2.Y = *pr.ext12.ext2.mulByNonResidue2Power3(&q[k].Y) // Q2.Y.MulByNonResidue2Power3(&q[k].Y).Neg(&Q2.Y) + Q2.Y = *pr.ext12.ext2.neg(&Q2.Y) // Q2.Y.MulByNonResidue2Power3(&q[k].Y).Neg(&Q2.Y) + + qProj[k], l0 = pr.addStep(qProj[k], Q1) // qProj[k].AddMixedStep(&l0, &Q1) + l0.r0 = *pr.ext12.ext2.mulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) + l0.r1 = *pr.ext12.ext2.mulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) + + qProj[k], l = pr.addStep(qProj[k], Q2) // qProj[k].AddMixedStep(&l, &Q2) + l.r0 = *pr.ext12.ext2.mulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) + l.r1 = *pr.ext12.ext2.mulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) + tmp := pr.ext12.mulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result = pr.ext12.mul(result, tmp) // result.Mul(&result, &tmp) + } + + return result, nil +} + +func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { + // var result GT + // result.Set(z) + var t [4]*GTEl // var t [4]GT + + // easy part + t[0] = pr.ext12.conjugate(e) // t[0].Conjugate(&result) + result := pr.ext12.inverse(e) // result.Inverse(&result) + t[0] = pr.ext12.mul(t[0], result) // t[0].Mul(&t[0], &result) + result = pr.ext12.frobeniusSquare(t[0]) // result.FrobeniusSquare(&t[0]). + result = pr.ext12.mul(result, t[0]) // Mul(&result, &t[0]) + + //hard part + t[0] = pr.ext12.expt(result) // t[0].Expt(&result). + t[0] = pr.ext12.conjugate(t[0]) // Conjugate(&t[0]) + t[0] = pr.ext12.cyclotomicSquare(t[0]) // t[0].CyclotomicSquare(&t[0]) + t[2] = pr.ext12.expt(t[0]) // t[2].Expt(&t[0]). + t[2] = pr.ext12.conjugate(t[2]) // Conjugate(&t[2]) + t[1] = pr.ext12.cyclotomicSquare(t[2]) // t[1].CyclotomicSquare(&t[2]) + t[2] = pr.ext12.mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) + t[2] = pr.ext12.mul(t[2], result) // t[2].Mul(&t[2], &result) + t[1] = pr.ext12.expt(t[2]) // t[1].Expt(&t[2]). + t[1] = pr.ext12.cyclotomicSquare(t[1]) // CyclotomicSquare(&t[1]). + t[1] = pr.ext12.mul(t[1], t[2]) // Mul(&t[1], &t[2]). + t[1] = pr.ext12.conjugate(t[1]) // Conjugate(&t[1]) + t[3] = pr.ext12.conjugate(t[1]) // t[3].Conjugate(&t[1]) + t[1] = pr.ext12.cyclotomicSquare(t[0]) // t[1].CyclotomicSquare(&t[0]) + t[1] = pr.ext12.mul(t[1], result) // t[1].Mul(&t[1], &result) + t[1] = pr.ext12.conjugate(t[1]) // t[1].Conjugate(&t[1]) + t[1] = pr.ext12.mul(t[1], t[3]) // t[1].Mul(&t[1], &t[3]) + t[0] = pr.ext12.mul(t[0], t[1]) // t[0].Mul(&t[0], &t[1]) + t[2] = pr.ext12.mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) + t[3] = pr.ext12.frobeniusSquare(t[1]) // t[3].FrobeniusSquare(&t[1]) + t[2] = pr.ext12.mul(t[2], t[3]) // t[2].Mul(&t[2], &t[3]) + t[3] = pr.ext12.conjugate(result) // t[3].Conjugate(&result) + t[3] = pr.ext12.mul(t[3], t[0]) // t[3].Mul(&t[3], &t[0]) + t[1] = pr.ext12.frobeniusCube(t[3]) // t[1].FrobeniusCube(&t[3]) + t[2] = pr.ext12.mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) + t[1] = pr.ext12.frobenius(t[0]) // t[1].Frobenius(&t[0]) + t[1] = pr.ext12.mul(t[1], t[2]) // t[1].Mul(&t[1], &t[2]) + // result.Set(&t[1]) + return t[1] // return result +} + +func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { + res, err := pr.MillerLoop(P, Q) + if err != nil { + return nil, fmt.Errorf("miller loop: %w", err) + } + res = pr.FinalExponentiation(res) + return res, nil +} + +func (pr Pairing) AssertIsEqual(x, y *GTEl) { + pr.ext12.assertIsEqual(x, y) +} diff --git a/std/algebra/pairing_bn254/pairing_test.go b/std/algebra/pairing_bn254/pairing_test.go new file mode 100644 index 0000000000..30fddc1829 --- /dev/null +++ b/std/algebra/pairing_bn254/pairing_test.go @@ -0,0 +1,122 @@ +package pairing_bn254 + +import ( + "crypto/rand" + "fmt" + "testing" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/algebra/weierstrass" + "github.com/consensys/gnark/std/math/emulated" + "github.com/consensys/gnark/test" +) + +func randomG1G2Affines(assert *test.Assert) (bn254.G1Affine, bn254.G2Affine) { + _, _, G1AffGen, G2AffGen := bn254.Generators() + mod := bn254.ID.ScalarField() + s1, err := rand.Int(rand.Reader, mod) + assert.NoError(err) + s2, err := rand.Int(rand.Reader, mod) + assert.NoError(err) + var p bn254.G1Affine + p.ScalarMultiplication(&G1AffGen, s1) + var q bn254.G2Affine + q.ScalarMultiplication(&G2AffGen, s2) + return p, q +} + +type MillerLoopCircuit struct { + InG1 weierstrass.AffinePoint[emulated.BN254Fp] + InG2 G2Affine + Res GTEl +} + +func (c *MillerLoopCircuit) Define(api frontend.API) error { + pairing, err := NewPairing(api) + if err != nil { + return fmt.Errorf("new pairing: %w", err) + } + res, err := pairing.MillerLoop([]*G1Affine{&c.InG1}, []*G2Affine{&c.InG2}) + if err != nil { + return fmt.Errorf("pair: %w", err) + } + pairing.ext12.assertIsEqual(res, &c.Res) + return nil +} + +func TestMillerLoopTestSolve(t *testing.T) { + assert := test.NewAssert(t) + p, q := randomG1G2Affines(assert) + res, err := bn254.MillerLoop([]bn254.G1Affine{p}, []bn254.G2Affine{q}) + assert.NoError(err) + witness := MillerLoopCircuit{ + InG1: NewG1Affine(p), + InG2: NewG2Affine(q), + Res: NewGTEl(res), + } + err = test.IsSolved(&MillerLoopCircuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type FinalExponentiationCircuit struct { + InGt GTEl + Res GTEl +} + +func (c *FinalExponentiationCircuit) Define(api frontend.API) error { + pairing, err := NewPairing(api) + if err != nil { + return fmt.Errorf("new pairing: %w", err) + } + res := pairing.FinalExponentiation(&c.InGt) + pairing.ext12.assertIsEqual(res, &c.Res) + return nil +} + +func TestFinalExponentiationTestSolve(t *testing.T) { + assert := test.NewAssert(t) + var gt bn254.GT + gt.SetRandom() + res := bn254.FinalExponentiation(>) + witness := FinalExponentiationCircuit{ + InGt: NewGTEl(gt), + Res: NewGTEl(res), + } + err := test.IsSolved(&FinalExponentiationCircuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type PairCircuit struct { + InG1 G1Affine + InG2 G2Affine + Res GTEl +} + +func (c *PairCircuit) Define(api frontend.API) error { + pairing, err := NewPairing(api) + if err != nil { + return fmt.Errorf("new pairing: %w", err) + } + res, err := pairing.Pair([]*G1Affine{&c.InG1}, []*G2Affine{&c.InG2}) + if err != nil { + return fmt.Errorf("pair: %w", err) + } + pairing.ext12.assertIsEqual(res, &c.Res) + return nil +} + +func TestPairTestSolve(t *testing.T) { + assert := test.NewAssert(t) + p, q := randomG1G2Affines(assert) + res, err := bn254.Pair([]bn254.G1Affine{p}, []bn254.G2Affine{q}) + assert.NoError(err) + witness := PairCircuit{ + InG1: NewG1Affine(p), + InG2: NewG2Affine(q), + Res: NewGTEl(res), + } + err = test.IsSolved(&PairCircuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} diff --git a/std/algebra/pairing_bn254/tower.go b/std/algebra/pairing_bn254/tower.go new file mode 100644 index 0000000000..c555680885 --- /dev/null +++ b/std/algebra/pairing_bn254/tower.go @@ -0,0 +1,833 @@ +package pairing_bn254 + +import ( + "math/big" + + "github.com/consensys/gnark/std/math/emulated" +) + +type curveF = emulated.Field[emulated.BN254Fp] +type baseEl = emulated.Element[emulated.BN254Fp] + +type e2 struct { + A0, A1 baseEl +} + +type e6 struct { + B0, B1, B2 e2 +} + +type e12 struct { + C0, C1 e6 +} + +type ext2 struct { + fp *curveF + nonResidues map[int]map[int]*e2 +} + +func newExt2(baseField *curveF) *ext2 { + pwrs := map[int]map[int]struct { + A0 string + A1 string + }{ + 0: { + -1: {"21087453498479301738505683583845423561061080261299122796980902361914303298513", "14681138511599513868579906292550611339979233093309515871315818100066920017952"}, + 1: {"9", "1"}, + }, + 1: { + 1: {"8376118865763821496583973867626364092589906065868298776909617916018768340080", "16469823323077808223889137241176536799009286646108169935659301613961712198316"}, + 2: {"21575463638280843010398324269430826099269044274347216827212613867836435027261", "10307601595873709700152284273816112264069230130616436755625194854815875713954"}, + 3: {"2821565182194536844548159561693502659359617185244120367078079554186484126554", "3505843767911556378687030309984248845540243509899259641013678093033130930403"}, + 4: {"2581911344467009335267311115468803099551665605076196740867805258568234346338", "19937756971775647987995932169929341994314640652964949448313374472400716661030"}, + 5: {"685108087231508774477564247770172212460312782337200605669322048753928464687", "8447204650696766136447902020341177575205426561248465145919723016860428151883"}, + }, + 2: { + 1: {"21888242871839275220042445260109153167277707414472061641714758635765020556617", "0"}, + 2: {"21888242871839275220042445260109153167277707414472061641714758635765020556616", "0"}, + 3: {"21888242871839275222246405745257275088696311157297823662689037894645226208582", "0"}, + 4: {"2203960485148121921418603742825762020974279258880205651966", "0"}, + 5: {"2203960485148121921418603742825762020974279258880205651967", "0"}, + }, + 3: { + 1: {"11697423496358154304825782922584725312912383441159505038794027105778954184319", "303847389135065887422783454877609941456349188919719272345083954437860409601"}, + 2: {"3772000881919853776433695186713858239009073593817195771773381919316419345261", "2236595495967245188281701248203181795121068902605861227855261137820944008926"}, + 3: {"19066677689644738377698246183563772429336693972053703295610958340458742082029", "18382399103927718843559375435273026243156067647398564021675359801612095278180"}, + 4: {"5324479202449903542726783395506214481928257762400643279780343368557297135718", "16208900380737693084919495127334387981393726419856888799917914180988844123039"}, + 5: {"8941241848238582420466759817324047081148088512956452953208002715982955420483", "10338197737521362862238855242243140895517409139741313354160881284257516364953"}, + }, + } + nonResidues := make(map[int]map[int]*e2) + for pwr, v := range pwrs { + for coeff, v := range v { + el := e2{emulated.ValueOf[emulated.BN254Fp](v.A0), emulated.ValueOf[emulated.BN254Fp](v.A1)} + if nonResidues[pwr] == nil { + nonResidues[pwr] = make(map[int]*e2) + } + nonResidues[pwr][coeff] = &el + } + } + return &ext2{fp: baseField, nonResidues: nonResidues} +} + +type ext6 struct { + *ext2 +} + +func newExt6(baseField *curveF) *ext6 { + return &ext6{ext2: newExt2(baseField)} +} + +type ext12 struct { + *ext6 +} + +func newExt12(baseField *curveF) *ext12 { + return &ext12{ext6: newExt6(baseField)} +} + +// TODO: check where to use Mod and where ModMul. + +func (e ext2) mulByElement(x *e2, y *baseEl) *e2 { + // var yCopy fp.Element + // yCopy.Set(y) + z0 := e.fp.MulMod(&x.A0, y) // z.A0.Mul(&x.A0, &yCopy) + z1 := e.fp.MulMod(&x.A1, y) // z.A1.Mul(&x.A1, &yCopy) + return &e2{ // return z + A0: *z0, + A1: *z1, + } +} + +func (e ext2) conjugate(x *e2) *e2 { + z0 := x.A0 // z.A0 = x.A0 + z1 := e.fp.Neg(&x.A1) // z.A1.Neg(&x.A1) + return &e2{ // return z + A0: z0, + A1: *z1, + } +} + +func (e ext2) mulByNonResidueGeneric(x *e2, power, coef int) *e2 { + y := e.nonResidues[power][coef] + z := e.mul(x, y) + return z +} + +func (e ext2) mulByNonResidue(x *e2) *e2 { + /* + // below is the direct transliteration of the gnark-crypto code. Now only, + // for simplicity and debugging purposes, we do the non residue operations + // without optimisations. + + nine := big.NewInt(9) + // var a, b fp.Element + a := e.fp.MulConst(&x.A0, nine) // a.Double(&x.A0).Double(&a).Double(&a).Add(&a, &x.A0). + a = e.fp.Sub(a, &x.A1) // Sub(&a, &x.A1) + b := e.fp.MulConst(&x.A1, nine) // b.Double(&x.A1).Double(&b).Double(&b).Add(&b, &x.A1). + b = e.fp.Add(b, &x.A0) // Add(&b, &x.A0) + return &E2{ + A0: *a, // z.A0.Set(&a) + A1: *b, // z.A1.Set(&b) + } // return z + */ + // TODO: inline non-residue multiplication + return e.mulByNonResidueGeneric(x, 0, 1) +} + +func (e ext2) mulByNonResidueInv(x *e2) *e2 { + // TODO: to optimise with constant non-residue inverse + /* + // from gnark-crypto + // z.Mul(x, &nonResInverse) + // return z + */ + return e.mulByNonResidueGeneric(x, 0, -1) +} + +func (e ext2) mulByNonResidue1Power1(x *e2) *e2 { + return e.mulByNonResidueGeneric(x, 1, 1) +} + +func (e ext2) mulByNonResidue1Power2(x *e2) *e2 { + return e.mulByNonResidueGeneric(x, 1, 2) +} + +func (e ext2) mulByNonResidue1Power3(x *e2) *e2 { + return e.mulByNonResidueGeneric(x, 1, 3) +} + +func (e ext2) mulByNonResidue1Power4(x *e2) *e2 { + return e.mulByNonResidueGeneric(x, 1, 4) +} + +func (e ext2) mulByNonResidue1Power5(x *e2) *e2 { + return e.mulByNonResidueGeneric(x, 1, 5) +} + +func (e ext2) mulByNonResidue2Power1(x *e2) *e2 { + // TODO: A1 is 0, we can optimize for it + return e.mulByNonResidueGeneric(x, 2, 1) +} +func (e ext2) mulByNonResidue2Power2(x *e2) *e2 { + // TODO: A1 is 0, we can optimize for it + return e.mulByNonResidueGeneric(x, 2, 2) +} + +func (e ext2) mulByNonResidue2Power3(x *e2) *e2 { + // TODO: A1 is 0, we can optimize for it + return e.mulByNonResidueGeneric(x, 2, 3) +} + +func (e ext2) mulByNonResidue2Power4(x *e2) *e2 { + // TODO: A1 is 0, we can optimize for it + return e.mulByNonResidueGeneric(x, 2, 4) +} + +func (e ext2) mulByNonResidue2Power5(x *e2) *e2 { + // TODO: A1 is 0, we can optimize for it + return e.mulByNonResidueGeneric(x, 2, 5) +} + +func (e ext2) mulByNonResidue3Power1(x *e2) *e2 { + return e.mulByNonResidueGeneric(x, 3, 1) +} + +func (e ext2) mulByNonResidue3Power2(x *e2) *e2 { + return e.mulByNonResidueGeneric(x, 3, 2) +} + +func (e ext2) mulByNonResidue3Power3(x *e2) *e2 { + return e.mulByNonResidueGeneric(x, 3, 3) +} + +func (e ext2) mulByNonResidue3Power4(x *e2) *e2 { + return e.mulByNonResidueGeneric(x, 3, 4) +} + +func (e ext2) mulByNonResidue3Power5(x *e2) *e2 { + return e.mulByNonResidueGeneric(x, 3, 5) +} + +func (e ext2) mul(x, y *e2) *e2 { + // var a, b, c fp.Element + a := e.fp.Add(&x.A0, &x.A1) // a.Add(&x.A0, &x.A1) + b := e.fp.Add(&y.A0, &y.A1) // b.Add(&y.A0, &y.A1) + a = e.fp.MulMod(a, b) // a.Mul(&a, &b) + b = e.fp.MulMod(&x.A0, &y.A0) // b.Mul(&x.A0, &y.A0) + c := e.fp.MulMod(&x.A1, &y.A1) // c.Mul(&x.A1, &y.A1) + z1 := e.fp.Sub(a, b) // z.A1.Sub(&a, &b). + z1 = e.fp.Sub(z1, c) // Sub(&z.A1, &c) + z0 := e.fp.Sub(b, c) // z.A0.Sub(&b, &c) + return &e2{ + A0: *z0, + A1: *z1, + } +} + +func (e ext2) add(x, y *e2) *e2 { + z0 := e.fp.Add(&x.A0, &y.A0) // z.A0.Add(&x.A0, &y.A0) + z1 := e.fp.Add(&x.A1, &y.A1) // z.A1.Add(&x.A1, &y.A1) + return &e2{ + A0: *z0, + A1: *z1, + } +} + +func (e ext2) sub(x, y *e2) *e2 { + z0 := e.fp.Sub(&x.A0, &y.A0) // z.A0.Sub(&x.A0, &y.A0) + z1 := e.fp.Sub(&x.A1, &y.A1) // z.A1.Sub(&x.A1, &y.A1) + return &e2{ + A0: *z0, + A1: *z1, + } +} + +func (e ext2) neg(x *e2) *e2 { + z0 := e.fp.Neg(&x.A0) // z.A0.Neg(&x.A0) + z1 := e.fp.Neg(&x.A1) // z.A1.Neg(&x.A1) + return &e2{ + A0: *z0, + A1: *z1, + } +} + +func (e ext2) one() *e2 { + z0 := e.fp.One() // z.A0.SetOne() + z1 := e.fp.Zero() // z.A1.SetZero() + return &e2{ // return z + A0: *z0, + A1: *z1, + } +} + +func (e ext2) zero() *e2 { + z0 := e.fp.Zero() + z1 := e.fp.Zero() + return &e2{ + A0: *z0, + A1: *z1, + } +} + +func (e ext2) square(x *e2) *e2 { + // var a, b fp.Element + a := e.fp.Add(&x.A0, &x.A1) // a.Add(&x.A0, &x.A1) + b := e.fp.Sub(&x.A0, &x.A1) // b.Sub(&x.A0, &x.A1) + a = e.fp.MulMod(a, b) // a.Mul(&a, &b) + b = e.fp.MulMod(&x.A0, &x.A1) // b.Mul(&x.A0, &x.A1). + b = e.fp.MulConst(b, big.NewInt(2)) // Double(&b) + return &e2{ + A0: *a, // z.A0.Set(&a) + A1: *b, // z.A1.Set(&b) + } +} + +func (e ext2) double(x *e2) *e2 { + two := big.NewInt(2) + z0 := e.fp.MulConst(&x.A0, two) // z.A0.Double(&x.A0) + z1 := e.fp.MulConst(&x.A1, two) // z.A1.Double(&x.A1) + return &e2{ + A0: *z0, + A1: *z1, + } +} + +func (e ext2) halve(x *e2) *e2 { + // I'm trying to avoid hard-coding modulus here in case want to make generic + // for different curves. + // TODO: if implemented Half in field emulation, then replace with it. + one := e.fp.One() + two := e.fp.MulConst(one, big.NewInt(2)) + z0 := e.fp.Div(&x.A0, two) + z1 := e.fp.Div(&x.A1, two) + return &e2{ + A0: *z0, + A1: *z1, + } +} + +func (e ext2) mulBybTwistCurveCoeff(x *e2) *e2 { + // var res E2 + res := e.mulByNonResidueInv(x) // res.MulByNonResidueInv(x) + z := e.double(res) // z.Double(&res). + z = e.add(z, res) // Add(&res, z) + return z // return z +} + +func (e ext2) inverse(x *e2) *e2 { + // var t0, t1 fp.Element + t0 := e.fp.MulMod(&x.A0, &x.A0) // t0.Square(&x.A0) + t1 := e.fp.MulMod(&x.A1, &x.A1) // t1.Square(&x.A1) + t0 = e.fp.Add(t0, t1) // t0.Add(&t0, &t1) + t1 = e.fp.Inverse(t0) // t1.Inverse(&t0) + z0 := e.fp.MulMod(&x.A0, t1) // z.A0.Mul(&x.A0, &t1) + z1 := e.fp.MulMod(&x.A1, t1) // z.A1.Mul(&x.A1, &t1). + z1 = e.fp.Neg(z1) // Neg(&z.A1) + return &e2{ + A0: *z0, + A1: *z1, + } +} + +func (e ext2) assertIsEqual(x, y *e2) { + e.fp.AssertIsEqual(&x.A0, &y.A0) + e.fp.AssertIsEqual(&x.A1, &y.A1) +} + +func (e ext6) add(x, y *e6) *e6 { + z0 := e.ext2.add(&x.B0, &y.B0) // z.B0.Add(&x.B0, &y.B0) + z1 := e.ext2.add(&x.B1, &y.B1) // z.B1.Add(&x.B1, &y.B1) + z2 := e.ext2.add(&x.B2, &y.B2) // z.B2.Add(&x.B2, &y.B2) + return &e6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e ext6) neg(x *e6) *e6 { + z0 := e.ext2.neg(&x.B0) // z.B0.Neg(&x.B0) + z1 := e.ext2.neg(&x.B1) // z.B1.Neg(&x.B1) + z2 := e.ext2.neg(&x.B2) // z.B2.Neg(&x.B2) + return &e6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e ext6) sub(x, y *e6) *e6 { + z0 := e.ext2.sub(&x.B0, &y.B0) // z.B0.Sub(&x.B0, &y.B0) + z1 := e.ext2.sub(&x.B1, &y.B1) // z.B1.Sub(&x.B1, &y.B1) + z2 := e.ext2.sub(&x.B2, &y.B2) // z.B2.Sub(&x.B2, &y.B2) + return &e6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e ext6) mul(x, y *e6) *e6 { + // var t0, t1, t2, c0, c1, c2, tmp E2 + t0 := e.ext2.mul(&x.B0, &y.B0) // t0.Mul(&x.B0, &y.B0) + t1 := e.ext2.mul(&x.B1, &y.B1) // t1.Mul(&x.B1, &y.B1) + t2 := e.ext2.mul(&x.B2, &y.B2) // t2.Mul(&x.B2, &y.B2) + c0 := e.ext2.add(&x.B1, &x.B2) // c0.Add(&x.B1, &x.B2) + tmp := e.ext2.add(&y.B1, &y.B2) // tmp.Add(&y.B1, &y.B2) + c0 = e.ext2.mul(c0, tmp) // c0.Mul(&c0, &tmp). + c0 = e.ext2.sub(c0, t1) // Sub(&c0, &t1). + c0 = e.ext2.sub(c0, t2) // Sub(&c0, &t2). + c0 = e.ext2.mulByNonResidue(c0) // MulByNonResidue(&c0). + c0 = e.ext2.add(c0, t0) // Add(&c0, &t0) + c1 := e.ext2.add(&x.B0, &x.B1) // c1.Add(&x.B0, &x.B1) + tmp = e.ext2.add(&y.B0, &y.B1) // tmp.Add(&y.B0, &y.B1) + c1 = e.ext2.mul(c1, tmp) // c1.Mul(&c1, &tmp). + c1 = e.ext2.sub(c1, t0) // Sub(&c1, &t0). + c1 = e.ext2.sub(c1, t1) // Sub(&c1, &t1) + tmp = e.ext2.mulByNonResidue(t2) // tmp.MulByNonResidue(&t2) + c1 = e.ext2.add(c1, tmp) // c1.Add(&c1, &tmp) + tmp = e.ext2.add(&x.B0, &x.B2) // tmp.Add(&x.B0, &x.B2) + c2 := e.ext2.add(&y.B0, &y.B2) // c2.Add(&y.B0, &y.B2). + c2 = e.ext2.mul(c2, tmp) // Mul(&c2, &tmp). + c2 = e.ext2.sub(c2, t0) // Sub(&c2, &t0). + c2 = e.ext2.sub(c2, t2) // Sub(&c2, &t2). + c2 = e.ext2.add(c2, t1) // Add(&c2, &t1) + return &e6{ + B0: *c0, // z.B0.Set(&c0) + B1: *c1, // z.B1.Set(&c1) + B2: *c2, // z.B2.Set(&c2) + } // return z +} + +func (e ext6) double(x *e6) *e6 { + z0 := e.ext2.double(&x.B0) // z.B0.Double(&x.B0) + z1 := e.ext2.double(&x.B1) // z.B1.Double(&x.B1) + z2 := e.ext2.double(&x.B2) // z.B2.Double(&x.B2) + return &e6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e ext6) square(x *e6) *e6 { + // var c4, c5, c1, c2, c3, c0 E2 + c4 := e.ext2.mul(&x.B0, &x.B1) // c4.Mul(&x.B0, &x.B1). + c4 = e.ext2.double(c4) // Double(&c4) + c5 := e.ext2.square(&x.B2) // c5.Square(&x.B2) + c1 := e.ext2.mulByNonResidue(c5) // c1.MulByNonResidue(&c5). + c1 = e.ext2.add(c1, c4) // Add(&c1, &c4) + c2 := e.ext2.sub(c4, c5) // c2.Sub(&c4, &c5) + c3 := e.ext2.square(&x.B0) // c3.Square(&x.B0) + c4 = e.ext2.sub(&x.B0, &x.B1) // c4.Sub(&x.B0, &x.B1). + c4 = e.ext2.add(c4, &x.B2) // Add(&c4, &x.B2) + c5 = e.ext2.mul(&x.B1, &x.B2) // c5.Mul(&x.B1, &x.B2). + c5 = e.ext2.double(c5) // Double(&c5) + c4 = e.ext2.square(c4) // c4.Square(&c4) + c0 := e.ext2.mulByNonResidue(c5) // c0.MulByNonResidue(&c5). + c0 = e.ext2.add(c0, c3) // Add(&c0, &c3) + z2 := e.ext2.add(c2, c4) // z.B2.Add(&c2, &c4). + z2 = e.ext2.add(z2, c5) // Add(&z.B2, &c5). + z2 = e.ext2.sub(z2, c3) // Sub(&z.B2, &c3) + z0 := c0 // z.B0.Set(&c0) + z1 := c1 // z.B1.Set(&c1) + return &e6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e ext6) inverse(x *e6) *e6 { + // var t0, t1, t2, t3, t4, t5, t6, c0, c1, c2, d1, d2 E2 + t0 := e.ext2.square(&x.B0) // t0.Square(&x.B0) + t1 := e.ext2.square(&x.B1) // t1.Square(&x.B1) + t2 := e.ext2.square(&x.B2) // t2.Square(&x.B2) + t3 := e.ext2.mul(&x.B0, &x.B1) // t3.Mul(&x.B0, &x.B1) + t4 := e.ext2.mul(&x.B0, &x.B2) // t4.Mul(&x.B0, &x.B2) + t5 := e.ext2.mul(&x.B1, &x.B2) // t5.Mul(&x.B1, &x.B2) + c0 := e.ext2.mulByNonResidue(t5) // c0.MulByNonResidue(&t5). + c0 = e.ext2.neg(c0) // Neg(&c0). + c0 = e.ext2.add(c0, t0) // Add(&c0, &t0) + c1 := e.ext2.mulByNonResidue(t2) // c1.MulByNonResidue(&t2). + c1 = e.ext2.sub(c1, t3) // Sub(&c1, &t3) + c2 := e.ext2.sub(t1, t4) // c2.Sub(&t1, &t4) + t6 := e.ext2.mul(&x.B0, c0) // t6.Mul(&x.B0, &c0) + d1 := e.ext2.mul(&x.B2, c1) // d1.Mul(&x.B2, &c1) + d2 := e.ext2.mul(&x.B1, c2) // d2.Mul(&x.B1, &c2) + d1 = e.ext2.add(d1, d2) // d1.Add(&d1, &d2). + d1 = e.ext2.mulByNonResidue(d1) // MulByNonResidue(&d1) + t6 = e.ext2.add(t6, d1) // t6.Add(&t6, &d1) + t6 = e.ext2.inverse(t6) // t6.Inverse(&t6) + z0 := e.ext2.mul(c0, t6) // z.B0.Mul(&c0, &t6) + z1 := e.ext2.mul(c1, t6) // z.B1.Mul(&c1, &t6) + z2 := e.ext2.mul(c2, t6) // z.B2.Mul(&c2, &t6) + return &e6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} +func (e ext6) mulByE2(x *e6, y *e2) *e6 { + // var yCopy E2 + // yCopy.Set(y) + z0 := e.ext2.mul(&x.B0, y) // z.B0.Mul(&x.B0, &yCopy) + z1 := e.ext2.mul(&x.B1, y) // z.B1.Mul(&x.B1, &yCopy) + z2 := e.ext2.mul(&x.B2, y) // z.B2.Mul(&x.B2, &yCopy) + return &e6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e ext6) mulBy01(z *e6, c0, c1 *e2) *e6 { + // var a, b, tmp, t0, t1, t2 E2 + a := e.ext2.mul(&z.B0, c0) // a.Mul(&z.B0, c0) + b := e.ext2.mul(&z.B1, c1) // b.Mul(&z.B1, c1) + tmp := e.ext2.add(&z.B1, &z.B2) // tmp.Add(&z.B1, &z.B2) + t0 := e.ext2.mul(c1, tmp) // t0.Mul(c1, &tmp) + t0 = e.ext2.sub(t0, b) // t0.Sub(&t0, &b) + t0 = e.ext2.mulByNonResidue(t0) // t0.MulByNonResidue(&t0) + t0 = e.ext2.add(t0, a) // t0.Add(&t0, &a) + tmp = e.ext2.add(&z.B0, &z.B2) // tmp.Add(&z.B0, &z.B2) + t2 := e.ext2.mul(c0, tmp) // t2.Mul(c0, &tmp) + t2 = e.ext2.sub(t2, a) // t2.Sub(&t2, &a) + t2 = e.ext2.add(t2, b) // t2.Add(&t2, &b) + t1 := e.ext2.add(c0, c1) // t1.Add(c0, c1) + tmp = e.ext2.add(&z.B0, &z.B1) // tmp.Add(&z.B0, &z.B1) + t1 = e.ext2.mul(t1, tmp) // t1.Mul(&t1, &tmp) + t1 = e.ext2.sub(t1, a) // t1.Sub(&t1, &a) + t1 = e.ext2.sub(t1, b) // t1.Sub(&t1, &b) + return &e6{ + B0: *t0, // z.B0.Set(&t0) + B1: *t1, // z.B1.Set(&t1) + B2: *t2, // z.B2.Set(&t2) + } // return z +} + +func (e ext6) mulByNonResidue(x *e6) *e6 { + z2, z1, z0 := &x.B1, &x.B0, &x.B2 // z.B2, z.B1, z.B0 = x.B1, x.B0, x.B2 + z0 = e.ext2.mulByNonResidue(z0) // z.B0.MulByNonResidue(&z.B0) + return &e6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e ext6) assertIsEqual(x, y *e6) { + e.ext2.assertIsEqual(&x.B0, &y.B0) + e.ext2.assertIsEqual(&x.B1, &y.B1) + e.ext2.assertIsEqual(&x.B2, &y.B2) +} + +func (e ext12) conjugate(x *e12) *e12 { + z1 := e.ext6.neg(&x.C1) // z.C1.Neg(&z.C1) + return &e12{ // return z + C0: x.C0, + C1: *z1, + } +} + +func (e ext12) inverse(x *e12) *e12 { + // var t0, t1, tmp E6 + t0 := e.ext6.square(&x.C0) // t0.Square(&x.C0) + t1 := e.ext6.square(&x.C1) // t1.Square(&x.C1) + tmp := e.ext6.mulByNonResidue(t1) // tmp.MulByNonResidue(&t1) + t0 = e.ext6.sub(t0, tmp) // t0.Sub(&t0, &tmp) + t1 = e.ext6.inverse(t0) // t1.Inverse(&t0) + z0 := e.ext6.mul(&x.C0, t1) // z.C0.Mul(&x.C0, &t1) + z1 := e.ext6.mul(&x.C1, t1) // z.C1.Mul(&x.C1, &t1). + z1 = e.ext6.neg(z1) // Neg(&z.C1) + return &e12{ // return z + C0: *z0, + C1: *z1, + } +} + +func (e ext12) mul(x, y *e12) *e12 { + // var a, b, c E6 + a := e.ext6.add(&x.C0, &x.C1) // a.Add(&x.C0, &x.C1) + b := e.ext6.add(&y.C0, &y.C1) // b.Add(&y.C0, &y.C1) + a = e.ext6.mul(a, b) // a.Mul(&a, &b) + b = e.ext6.mul(&x.C0, &y.C0) // b.Mul(&x.C0, &y.C0) + c := e.ext6.mul(&x.C1, &y.C1) // c.Mul(&x.C1, &y.C1) + z1 := e.ext6.sub(a, b) // z.C1.Sub(&a, &b). + z1 = e.ext6.sub(z1, c) // Sub(&z.C1, &c) + z0 := e.ext6.mulByNonResidue(c) // z.C0.MulByNonResidue(&c). + z0 = e.ext6.add(z0, b) // Add(&z.C0, &b) + return &e12{ // return z + C0: *z0, + C1: *z1, + } +} + +func (e ext12) cyclotomicSquare(x *e12) *e12 { + // var t [9]E2 + t0 := e.ext2.square(&x.C1.B1) // t[0].Square(&x.C1.B1) + t1 := e.ext2.square(&x.C0.B0) // t[1].Square(&x.C0.B0) + t6 := e.ext2.add(&x.C1.B1, &x.C0.B0) // t[6].Add(&x.C1.B1, &x.C0.B0). + t6 = e.ext2.square(t6) // Square(&t[6]). + t6 = e.ext2.sub(t6, t0) // Sub(&t[6], &t[0]). + t6 = e.ext2.sub(t6, t1) // Sub(&t[6], &t[1]) + t2 := e.ext2.square(&x.C0.B2) // t[2].Square(&x.C0.B2) + t3 := e.ext2.square(&x.C1.B0) // t[3].Square(&x.C1.B0) + t7 := e.ext2.add(&x.C0.B2, &x.C1.B0) // t[7].Add(&x.C0.B2, &x.C1.B0). + t7 = e.ext2.square(t7) // Square(&t[7]). + t7 = e.ext2.sub(t7, t2) // Sub(&t[7], &t[2]). + t7 = e.ext2.sub(t7, t3) // Sub(&t[7], &t[3]) + t4 := e.ext2.square(&x.C1.B2) // t[4].Square(&x.C1.B2) + t5 := e.ext2.square(&x.C0.B1) // t[5].Square(&x.C0.B1) + t8 := e.ext2.add(&x.C1.B2, &x.C0.B1) // t[8].Add(&x.C1.B2, &x.C0.B1). + t8 = e.ext2.square(t8) // Square(&t[8]). + t8 = e.ext2.sub(t8, t4) // Sub(&t[8], &t[4]). + t8 = e.ext2.sub(t8, t5) // Sub(&t[8], &t[5]). + t8 = e.ext2.mulByNonResidue(t8) // MulByNonResidue(&t[8]) + t0 = e.ext2.mulByNonResidue(t0) // t[0].MulByNonResidue(&t[0]). + t0 = e.ext2.add(t0, t1) // Add(&t[0], &t[1]) + t2 = e.ext2.mulByNonResidue(t2) // t[2].MulByNonResidue(&t[2]). + t2 = e.ext2.add(t2, t3) // Add(&t[2], &t[3]) + t4 = e.ext2.mulByNonResidue(t4) // t[4].MulByNonResidue(&t[4]). + t4 = e.ext2.add(t4, t5) // Add(&t[4], &t[5]) + z00 := e.ext2.sub(t0, &x.C0.B0) // z.C0.B0.Sub(&t[0], &x.C0.B0). + z00 = e.ext2.double(z00) // Double(&z.C0.B0). + z00 = e.ext2.add(z00, t0) // Add(&z.C0.B0, &t[0]) + z01 := e.ext2.sub(t2, &x.C0.B1) // z.C0.B1.Sub(&t[2], &x.C0.B1). + z01 = e.ext2.double(z01) // Double(&z.C0.B1). + z01 = e.ext2.add(z01, t2) // Add(&z.C0.B1, &t[2]) + z02 := e.ext2.sub(t4, &x.C0.B2) // z.C0.B2.Sub(&t[4], &x.C0.B2). + z02 = e.ext2.double(z02) // Double(&z.C0.B2). + z02 = e.ext2.add(z02, t4) // Add(&z.C0.B2, &t[4]) + z10 := e.ext2.add(t8, &x.C1.B0) // z.C1.B0.Add(&t[8], &x.C1.B0). + z10 = e.ext2.double(z10) // Double(&z.C1.B0). + z10 = e.ext2.add(z10, t8) // Add(&z.C1.B0, &t[8]) + z11 := e.ext2.add(t6, &x.C1.B1) // z.C1.B1.Add(&t[6], &x.C1.B1). + z11 = e.ext2.double(z11) // Double(&z.C1.B1). + z11 = e.ext2.add(z11, t6) // Add(&z.C1.B1, &t[6]) + z12 := e.ext2.add(t7, &x.C1.B2) // z.C1.B2.Add(&t[7], &x.C1.B2). + z12 = e.ext2.double(z12) // Double(&z.C1.B2). + z12 = e.ext2.add(z12, t7) // Add(&z.C1.B2, &t[7]) + return &e12{ // return z + C0: e6{ + B0: *z00, + B1: *z01, + B2: *z02, + }, + C1: e6{ + B0: *z10, + B1: *z11, + B2: *z12, + }, + } +} + +func (e ext12) frobenius(x *e12) *e12 { + // var t [6]E2 + t0 := e.ext2.conjugate(&x.C0.B0) // t[0].Conjugate(&x.C0.B0) + t1 := e.ext2.conjugate(&x.C0.B1) // t[1].Conjugate(&x.C0.B1) + t2 := e.ext2.conjugate(&x.C0.B2) // t[2].Conjugate(&x.C0.B2) + t3 := e.ext2.conjugate(&x.C1.B0) // t[3].Conjugate(&x.C1.B0) + t4 := e.ext2.conjugate(&x.C1.B1) // t[4].Conjugate(&x.C1.B1) + t5 := e.ext2.conjugate(&x.C1.B2) // t[5].Conjugate(&x.C1.B2) + t1 = e.ext2.mulByNonResidue1Power2(t1) // t[1].MulByNonResidue1Power2(&t[1]) + t2 = e.ext2.mulByNonResidue1Power4(t2) // t[2].MulByNonResidue1Power4(&t[2]) + t3 = e.ext2.mulByNonResidue1Power1(t3) // t[3].MulByNonResidue1Power1(&t[3]) + t4 = e.ext2.mulByNonResidue1Power3(t4) // t[4].MulByNonResidue1Power3(&t[4]) + t5 = e.ext2.mulByNonResidue1Power5(t5) // t[5].MulByNonResidue1Power5(&t[5]) + return &e12{ // return z + C0: e6{ + B0: *t0, // z.C0.B0 = t[0] + B1: *t1, // z.C0.B1 = t[1] + B2: *t2, // z.C0.B2 = t[2] + }, + C1: e6{ + B0: *t3, // z.C1.B0 = t[3] + B1: *t4, // z.C1.B1 = t[4] + B2: *t5, // z.C1.B2 = t[5] + }, + } +} + +func (e ext12) frobeniusSquare(x *e12) *e12 { + z00 := &x.C0.B0 // z.C0.B0 = x.C0.B0 + z01 := e.ext2.mulByNonResidue2Power2(&x.C0.B1) // z.C0.B1.MulByNonResidue2Power2(&x.C0.B1) + z02 := e.ext2.mulByNonResidue2Power4(&x.C0.B2) // z.C0.B2.MulByNonResidue2Power4(&x.C0.B2) + z10 := e.ext2.mulByNonResidue2Power1(&x.C1.B0) // z.C1.B0.MulByNonResidue2Power1(&x.C1.B0) + z11 := e.ext2.mulByNonResidue2Power3(&x.C1.B1) // z.C1.B1.MulByNonResidue2Power3(&x.C1.B1) + z12 := e.ext2.mulByNonResidue2Power5(&x.C1.B2) // z.C1.B2.MulByNonResidue2Power5(&x.C1.B2) + return &e12{ // return z + C0: e6{B0: *z00, B1: *z01, B2: *z02}, + C1: e6{B0: *z10, B1: *z11, B2: *z12}, + } +} + +func (e ext12) frobeniusCube(x *e12) *e12 { + // var t [6]E2 + t0 := e.ext2.conjugate(&x.C0.B0) // t[0].Conjugate(&x.C0.B0) + t1 := e.ext2.conjugate(&x.C0.B1) // t[1].Conjugate(&x.C0.B1) + t2 := e.ext2.conjugate(&x.C0.B2) // t[2].Conjugate(&x.C0.B2) + t3 := e.ext2.conjugate(&x.C1.B0) // t[3].Conjugate(&x.C1.B0) + t4 := e.ext2.conjugate(&x.C1.B1) // t[4].Conjugate(&x.C1.B1) + t5 := e.ext2.conjugate(&x.C1.B2) // t[5].Conjugate(&x.C1.B2) + t1 = e.ext2.mulByNonResidue3Power2(t1) // t[1].MulByNonResidue3Power2(&t[1]) + t2 = e.ext2.mulByNonResidue3Power4(t2) // t[2].MulByNonResidue3Power4(&t[2]) + t3 = e.ext2.mulByNonResidue3Power1(t3) // t[3].MulByNonResidue3Power1(&t[3]) + t4 = e.ext2.mulByNonResidue3Power3(t4) // t[4].MulByNonResidue3Power3(&t[4]) + t5 = e.ext2.mulByNonResidue3Power5(t5) // t[5].MulByNonResidue3Power5(&t[5]) + return &e12{ // return z + C0: e6{ + B0: *t0, // z.C0.B0 = t[0] + B1: *t1, // z.C0.B1 = t[1] + B2: *t2, // z.C0.B2 = t[2] + }, + C1: e6{ + B0: *t3, // z.C1.B0 = t[3] + B1: *t4, // z.C1.B1 = t[4] + B2: *t5, // z.C1.B2 = t[5] + }, + } +} + +func (e ext12) expt(x *e12) *e12 { + // var result, t0, t1, t2, t3, t4, t5, t6 E12 + t3 := e.cyclotomicSquare(x) // t3.CyclotomicSquare(x) + t5 := e.cyclotomicSquare(t3) // t5.CyclotomicSquare(&t3) + result := e.cyclotomicSquare(t5) // result.CyclotomicSquare(&t5) + t0 := e.cyclotomicSquare(result) // t0.CyclotomicSquare(&result) + t2 := e.mul(x, t0) // t2.Mul(x, &t0) + t0 = e.mul(t3, t2) // t0.Mul(&t3, &t2) + t1 := e.mul(x, t0) // t1.Mul(x, &t0) + t4 := e.mul(result, t2) // t4.Mul(&result, &t2) + t6 := e.cyclotomicSquare(t2) // t6.CyclotomicSquare(&t2) + t1 = e.mul(t0, t1) // t1.Mul(&t0, &t1) + t0 = e.mul(t3, t1) // t0.Mul(&t3, &t1) + t6 = e.nSquare(t6, 6) // t6.nSquare(6) + t5 = e.mul(t5, t6) // t5.Mul(&t5, &t6) + t5 = e.mul(t4, t5) // t5.Mul(&t4, &t5) + t5 = e.nSquare(t5, 7) // t5.nSquare(7) + t4 = e.mul(t4, t5) // t4.Mul(&t4, &t5) + t4 = e.nSquare(t4, 8) // t4.nSquare(8) + t4 = e.mul(t0, t4) // t4.Mul(&t0, &t4) + t3 = e.mul(t3, t4) // t3.Mul(&t3, &t4) + t3 = e.nSquare(t3, 6) // t3.nSquare(6) + t2 = e.mul(t2, t3) // t2.Mul(&t2, &t3) + t2 = e.nSquare(t2, 8) // t2.nSquare(8) + t2 = e.mul(t0, t2) // t2.Mul(&t0, &t2) + t2 = e.nSquare(t2, 6) // t2.nSquare(6) + t2 = e.mul(t0, t2) // t2.Mul(&t0, &t2) + t2 = e.nSquare(t2, 10) // t2.nSquare(10) + t1 = e.mul(t1, t2) // t1.Mul(&t1, &t2) + t1 = e.nSquare(t1, 6) // t1.nSquare(6) + t0 = e.mul(t0, t1) // t0.Mul(&t0, &t1) + z := e.mul(result, t0) // z.Mul(&result, &t0) + return z // return z +} + +func (e ext12) one() *e12 { + z000 := e.fp.One() + zero := e.fp.Zero() + return &e12{ + C0: e6{ + B0: e2{A0: *z000, A1: *zero}, + B1: e2{A0: *zero, A1: *zero}, + B2: e2{A0: *zero, A1: *zero}, + }, + C1: e6{ + B0: e2{A0: *zero, A1: *zero}, + B1: e2{A0: *zero, A1: *zero}, + B2: e2{A0: *zero, A1: *zero}, + }, + } +} + +func (e ext12) mulBy034(z *e12, c0, c3, c4 *e2) *e12 { + // var a, b, d E6 + a := e.ext6.mulByE2(&z.C0, c0) // a.MulByE2(&z.C0, c0) + // b.Set(&z.C1) + b := e.ext6.mulBy01(&z.C1, c3, c4) // b.MulBy01(c3, c4) + c0 = e.ext2.add(c0, c3) // c0.Add(c0, c3) + d := e.ext6.add(&z.C0, &z.C1) // d.Add(&z.C0, &z.C1) + d = e.ext6.mulBy01(d, c0, c4) // d.MulBy01(c0, c4) + z1 := e.add(a, b) // z.C1.Add(&a, &b). + z1 = e.neg(z1) // Neg(&z.C1). + z1 = e.add(z1, d) // Add(&z.C1, &d) + z0 := e.mulByNonResidue(b) // z.C0.MulByNonResidue(&b). + z0 = e.add(z0, a) // Add(&z.C0, &a) + return &e12{ // return z + C0: *z0, + C1: *z1, + } +} + +func (e ext12) square(x *e12) *e12 { + // var c0, c2, c3 E6 + c0 := e.ext6.sub(&x.C0, &x.C1) // c0.Sub(&x.C0, &x.C1) + c3 := e.ext6.mulByNonResidue(&x.C1) // c3.MulByNonResidue(&x.C1). + c3 = e.ext6.neg(c3) // Neg(&c3). + c3 = e.ext6.add(&x.C0, c3) // Add(&x.C0, &c3) + c2 := e.ext6.mul(&x.C0, &x.C1) // c2.Mul(&x.C0, &x.C1) + c0 = e.ext6.mul(c0, c3) // c0.Mul(&c0, &c3). + c0 = e.ext6.add(c0, c2) // Add(&c0, &c2) + z1 := e.ext6.double(c2) // z.C1.Double(&c2) + c2 = e.ext6.mulByNonResidue(c2) // c2.MulByNonResidue(&c2) + z0 := e.ext6.add(c0, c2) // z.C0.Add(&c0, &c2) + return &e12{ // return z + C0: *z0, + C1: *z1, + } +} + +func (e ext12) mulBy034by034(d0, d3, d4, c0, c3, c4 *e2) *e12 { + // var tmp, x0, x3, x4, x04, x03, x34 E2 + x0 := e.ext2.mul(c0, d0) // x0.Mul(c0, d0) + x3 := e.ext2.mul(c3, d3) // x3.Mul(c3, d3) + x4 := e.ext2.mul(c4, d4) // x4.Mul(c4, d4) + tmp := e.ext2.add(c0, c4) // tmp.Add(c0, c4) + x04 := e.ext2.add(d0, d4) // x04.Add(d0, d4). + x04 = e.ext2.mul(x04, tmp) // Mul(&x04, &tmp). + x04 = e.ext2.sub(x04, x0) // Sub(&x04, &x0). + x04 = e.ext2.sub(x04, x4) // Sub(&x04, &x4) + tmp = e.ext2.add(c0, c3) // tmp.Add(c0, c3) + x03 := e.ext2.add(d0, d3) // x03.Add(d0, d3). + x03 = e.ext2.mul(x03, tmp) // Mul(&x03, &tmp). + x03 = e.ext2.sub(x03, x0) // Sub(&x03, &x0). + x03 = e.ext2.sub(x03, x3) // Sub(&x03, &x3) + tmp = e.ext2.add(c3, c4) // tmp.Add(c3, c4) + x34 := e.ext2.add(d3, d4) // x34.Add(d3, d4). + x34 = e.ext2.mul(x34, tmp) // Mul(&x34, &tmp). + x34 = e.ext2.sub(x34, x3) // Sub(&x34, &x3). + x34 = e.ext2.sub(x34, x4) // Sub(&x34, &x4) + z00 := e.ext2.mulByNonResidue(x4) // z.C0.B0.MulByNonResidue(&x4). + z00 = e.ext2.add(z00, x0) // Add(&z.C0.B0, &x0) + z01 := x3 // z.C0.B1.Set(&x3) + z02 := x34 // z.C0.B2.Set(&x34) + z10 := x03 // z.C1.B0.Set(&x03) + z11 := x04 // z.C1.B1.Set(&x04) + z12 := e.ext2.zero() // z.C1.B2.SetZero() + return &e12{ // return z + C0: e6{ + B0: *z00, + B1: *z01, + B2: *z02, + }, + C1: e6{ + B0: *z10, + B1: *z11, + B2: *z12, + }, + } +} + +func (e ext12) assertIsEqual(x, y *e12) { + e.ext6.assertIsEqual(&x.C0, &y.C0) + e.ext6.assertIsEqual(&x.C1, &y.C1) +} + +func (e ext12) nSquare(z *e12, n int) *e12 { + for i := 0; i < n; i++ { + z = e.cyclotomicSquare(z) + } + return z +} From 09849118fbca0de67030e9541732078822cc6ce1 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Mon, 6 Mar 2023 17:12:29 +0100 Subject: [PATCH 054/464] refactor: algebra into native (2-chain) and emulated --- std/algebra/emulated/fields_bn254/e12.go | 219 +++++ .../emulated/fields_bn254/e12_pairing.go | 142 +++ std/algebra/emulated/fields_bn254/e2.go | 312 +++++++ std/algebra/emulated/fields_bn254/e6.go | 201 +++++ .../sw_bn254}/doc.go | 4 +- .../sw_bn254}/doc_test.go | 21 +- .../sw_bn254}/g1.go | 6 +- .../sw_bn254}/g2.go | 13 +- std/algebra/emulated/sw_bn254/pairing.go | 283 ++++++ .../sw_bn254}/pairing_test.go | 29 +- .../sw_emulated}/doc.go | 4 +- .../sw_emulated}/doc_test.go | 10 +- .../sw_emulated}/params.go | 2 +- .../sw_emulated}/point.go | 2 +- .../sw_emulated}/point_test.go | 2 +- .../{ => native}/fields_bls12377/e12.go | 0 .../{ => native}/fields_bls12377/e12_test.go | 0 .../{ => native}/fields_bls12377/e2.go | 0 .../{ => native}/fields_bls12377/e2_test.go | 0 .../{ => native}/fields_bls12377/e6.go | 0 .../{ => native}/fields_bls12377/e6_test.go | 0 .../{ => native}/fields_bls24315/e12.go | 0 .../{ => native}/fields_bls24315/e12_test.go | 0 .../{ => native}/fields_bls24315/e2.go | 0 .../{ => native}/fields_bls24315/e24.go | 0 .../{ => native}/fields_bls24315/e24_test.go | 0 .../{ => native}/fields_bls24315/e2_test.go | 0 .../{ => native}/fields_bls24315/e4.go | 0 .../{ => native}/fields_bls24315/e4_test.go | 0 std/algebra/{ => native}/sw_bls12377/doc.go | 0 std/algebra/{ => native}/sw_bls12377/g1.go | 0 .../{ => native}/sw_bls12377/g1_test.go | 0 std/algebra/{ => native}/sw_bls12377/g2.go | 2 +- .../{ => native}/sw_bls12377/g2_test.go | 0 std/algebra/{ => native}/sw_bls12377/inner.go | 0 .../{ => native}/sw_bls12377/pairing.go | 2 +- .../{ => native}/sw_bls12377/pairing_test.go | 2 +- std/algebra/{ => native}/sw_bls24315/doc.go | 0 std/algebra/{ => native}/sw_bls24315/g1.go | 0 .../{ => native}/sw_bls24315/g1_test.go | 0 std/algebra/{ => native}/sw_bls24315/g2.go | 2 +- .../{ => native}/sw_bls24315/g2_test.go | 0 std/algebra/{ => native}/sw_bls24315/inner.go | 0 .../{ => native}/sw_bls24315/pairing.go | 2 +- .../{ => native}/sw_bls24315/pairing_test.go | 2 +- .../{ => native}/twistededwards/curve.go | 0 .../{ => native}/twistededwards/curve_test.go | 0 .../{ => native}/twistededwards/point.go | 0 .../twistededwards/scalarmul_glv.go | 0 .../twistededwards/twistededwards.go | 0 std/algebra/pairing_bn254/gt.go | 41 - std/algebra/pairing_bn254/pairing.go | 282 ------ std/algebra/pairing_bn254/tower.go | 833 ------------------ 53 files changed, 1211 insertions(+), 1207 deletions(-) create mode 100644 std/algebra/emulated/fields_bn254/e12.go create mode 100644 std/algebra/emulated/fields_bn254/e12_pairing.go create mode 100644 std/algebra/emulated/fields_bn254/e2.go create mode 100644 std/algebra/emulated/fields_bn254/e6.go rename std/algebra/{pairing_bn254 => emulated/sw_bn254}/doc.go (70%) rename std/algebra/{pairing_bn254 => emulated/sw_bn254}/doc_test.go (81%) rename std/algebra/{pairing_bn254 => emulated/sw_bn254}/g1.go (66%) rename std/algebra/{pairing_bn254 => emulated/sw_bn254}/g2.go (70%) create mode 100644 std/algebra/emulated/sw_bn254/pairing.go rename std/algebra/{pairing_bn254 => emulated/sw_bn254}/pairing_test.go (83%) rename std/algebra/{weierstrass => emulated/sw_emulated}/doc.go (94%) rename std/algebra/{weierstrass => emulated/sw_emulated}/doc_test.go (89%) rename std/algebra/{weierstrass => emulated/sw_emulated}/params.go (98%) rename std/algebra/{weierstrass => emulated/sw_emulated}/point.go (99%) rename std/algebra/{weierstrass => emulated/sw_emulated}/point_test.go (99%) rename std/algebra/{ => native}/fields_bls12377/e12.go (100%) rename std/algebra/{ => native}/fields_bls12377/e12_test.go (100%) rename std/algebra/{ => native}/fields_bls12377/e2.go (100%) rename std/algebra/{ => native}/fields_bls12377/e2_test.go (100%) rename std/algebra/{ => native}/fields_bls12377/e6.go (100%) rename std/algebra/{ => native}/fields_bls12377/e6_test.go (100%) rename std/algebra/{ => native}/fields_bls24315/e12.go (100%) rename std/algebra/{ => native}/fields_bls24315/e12_test.go (100%) rename std/algebra/{ => native}/fields_bls24315/e2.go (100%) rename std/algebra/{ => native}/fields_bls24315/e24.go (100%) rename std/algebra/{ => native}/fields_bls24315/e24_test.go (100%) rename std/algebra/{ => native}/fields_bls24315/e2_test.go (100%) rename std/algebra/{ => native}/fields_bls24315/e4.go (100%) rename std/algebra/{ => native}/fields_bls24315/e4_test.go (100%) rename std/algebra/{ => native}/sw_bls12377/doc.go (100%) rename std/algebra/{ => native}/sw_bls12377/g1.go (100%) rename std/algebra/{ => native}/sw_bls12377/g1_test.go (100%) rename std/algebra/{ => native}/sw_bls12377/g2.go (99%) rename std/algebra/{ => native}/sw_bls12377/g2_test.go (100%) rename std/algebra/{ => native}/sw_bls12377/inner.go (100%) rename std/algebra/{ => native}/sw_bls12377/pairing.go (98%) rename std/algebra/{ => native}/sw_bls12377/pairing_test.go (98%) rename std/algebra/{ => native}/sw_bls24315/doc.go (100%) rename std/algebra/{ => native}/sw_bls24315/g1.go (100%) rename std/algebra/{ => native}/sw_bls24315/g1_test.go (100%) rename std/algebra/{ => native}/sw_bls24315/g2.go (99%) rename std/algebra/{ => native}/sw_bls24315/g2_test.go (100%) rename std/algebra/{ => native}/sw_bls24315/inner.go (100%) rename std/algebra/{ => native}/sw_bls24315/pairing.go (98%) rename std/algebra/{ => native}/sw_bls24315/pairing_test.go (98%) rename std/algebra/{ => native}/twistededwards/curve.go (100%) rename std/algebra/{ => native}/twistededwards/curve_test.go (100%) rename std/algebra/{ => native}/twistededwards/point.go (100%) rename std/algebra/{ => native}/twistededwards/scalarmul_glv.go (100%) rename std/algebra/{ => native}/twistededwards/twistededwards.go (100%) delete mode 100644 std/algebra/pairing_bn254/gt.go delete mode 100644 std/algebra/pairing_bn254/pairing.go delete mode 100644 std/algebra/pairing_bn254/tower.go diff --git a/std/algebra/emulated/fields_bn254/e12.go b/std/algebra/emulated/fields_bn254/e12.go new file mode 100644 index 0000000000..4425085a93 --- /dev/null +++ b/std/algebra/emulated/fields_bn254/e12.go @@ -0,0 +1,219 @@ +package fields_bn254 + +type E12 struct { + C0, C1 E6 +} + +type Ext12 struct { + *Ext6 +} + +func NewExt12(baseField *curveF) *Ext12 { + return &Ext12{Ext6: NewExt6(baseField)} +} +func (e Ext12) Conjugate(x *E12) *E12 { + z1 := e.Ext6.Neg(&x.C1) // z.C1.Neg(&z.C1) + return &E12{ // return z + C0: x.C0, + C1: *z1, + } +} + +func (e Ext12) Inverse(x *E12) *E12 { + // var t0, t1, tmp E6 + t0 := e.Ext6.Square(&x.C0) // t0.Square(&x.C0) + t1 := e.Ext6.Square(&x.C1) // t1.Square(&x.C1) + tmp := e.Ext6.MulByNonResidue(t1) // tmp.MulByNonResidue(&t1) + t0 = e.Ext6.Sub(t0, tmp) // t0.Sub(&t0, &tmp) + t1 = e.Ext6.Inverse(t0) // t1.Inverse(&t0) + z0 := e.Ext6.Mul(&x.C0, t1) // z.C0.Mul(&x.C0, &t1) + z1 := e.Ext6.Mul(&x.C1, t1) // z.C1.Mul(&x.C1, &t1). + z1 = e.Ext6.Neg(z1) // Neg(&z.C1) + return &E12{ // return z + C0: *z0, + C1: *z1, + } +} + +func (e Ext12) Mul(x, y *E12) *E12 { + // var a, b, c E6 + a := e.Ext6.Add(&x.C0, &x.C1) // a.Add(&x.C0, &x.C1) + b := e.Ext6.Add(&y.C0, &y.C1) // b.Add(&y.C0, &y.C1) + a = e.Ext6.Mul(a, b) // a.Mul(&a, &b) + b = e.Ext6.Mul(&x.C0, &y.C0) // b.Mul(&x.C0, &y.C0) + c := e.Ext6.Mul(&x.C1, &y.C1) // c.Mul(&x.C1, &y.C1) + z1 := e.Ext6.Sub(a, b) // z.C1.Sub(&a, &b). + z1 = e.Ext6.Sub(z1, c) // Sub(&z.C1, &c) + z0 := e.Ext6.MulByNonResidue(c) // z.C0.MulByNonResidue(&c). + z0 = e.Ext6.Add(z0, b) // Add(&z.C0, &b) + return &E12{ // return z + C0: *z0, + C1: *z1, + } +} + +func (e Ext12) CyclotomicSquare(x *E12) *E12 { + // var t [9]E2 + t0 := e.Ext2.Square(&x.C1.B1) // t[0].Square(&x.C1.B1) + t1 := e.Ext2.Square(&x.C0.B0) // t[1].Square(&x.C0.B0) + t6 := e.Ext2.Add(&x.C1.B1, &x.C0.B0) // t[6].Add(&x.C1.B1, &x.C0.B0). + t6 = e.Ext2.Square(t6) // Square(&t[6]). + t6 = e.Ext2.Sub(t6, t0) // Sub(&t[6], &t[0]). + t6 = e.Ext2.Sub(t6, t1) // Sub(&t[6], &t[1]) + t2 := e.Ext2.Square(&x.C0.B2) // t[2].Square(&x.C0.B2) + t3 := e.Ext2.Square(&x.C1.B0) // t[3].Square(&x.C1.B0) + t7 := e.Ext2.Add(&x.C0.B2, &x.C1.B0) // t[7].Add(&x.C0.B2, &x.C1.B0). + t7 = e.Ext2.Square(t7) // Square(&t[7]). + t7 = e.Ext2.Sub(t7, t2) // Sub(&t[7], &t[2]). + t7 = e.Ext2.Sub(t7, t3) // Sub(&t[7], &t[3]) + t4 := e.Ext2.Square(&x.C1.B2) // t[4].Square(&x.C1.B2) + t5 := e.Ext2.Square(&x.C0.B1) // t[5].Square(&x.C0.B1) + t8 := e.Ext2.Add(&x.C1.B2, &x.C0.B1) // t[8].Add(&x.C1.B2, &x.C0.B1). + t8 = e.Ext2.Square(t8) // Square(&t[8]). + t8 = e.Ext2.Sub(t8, t4) // Sub(&t[8], &t[4]). + t8 = e.Ext2.Sub(t8, t5) // Sub(&t[8], &t[5]). + t8 = e.Ext2.MulByNonResidue(t8) // MulByNonResidue(&t[8]) + t0 = e.Ext2.MulByNonResidue(t0) // t[0].MulByNonResidue(&t[0]). + t0 = e.Ext2.Add(t0, t1) // Add(&t[0], &t[1]) + t2 = e.Ext2.MulByNonResidue(t2) // t[2].MulByNonResidue(&t[2]). + t2 = e.Ext2.Add(t2, t3) // Add(&t[2], &t[3]) + t4 = e.Ext2.MulByNonResidue(t4) // t[4].MulByNonResidue(&t[4]). + t4 = e.Ext2.Add(t4, t5) // Add(&t[4], &t[5]) + z00 := e.Ext2.Sub(t0, &x.C0.B0) // z.C0.B0.Sub(&t[0], &x.C0.B0). + z00 = e.Ext2.Double(z00) // Double(&z.C0.B0). + z00 = e.Ext2.Add(z00, t0) // Add(&z.C0.B0, &t[0]) + z01 := e.Ext2.Sub(t2, &x.C0.B1) // z.C0.B1.Sub(&t[2], &x.C0.B1). + z01 = e.Ext2.Double(z01) // Double(&z.C0.B1). + z01 = e.Ext2.Add(z01, t2) // Add(&z.C0.B1, &t[2]) + z02 := e.Ext2.Sub(t4, &x.C0.B2) // z.C0.B2.Sub(&t[4], &x.C0.B2). + z02 = e.Ext2.Double(z02) // Double(&z.C0.B2). + z02 = e.Ext2.Add(z02, t4) // Add(&z.C0.B2, &t[4]) + z10 := e.Ext2.Add(t8, &x.C1.B0) // z.C1.B0.Add(&t[8], &x.C1.B0). + z10 = e.Ext2.Double(z10) // Double(&z.C1.B0). + z10 = e.Ext2.Add(z10, t8) // Add(&z.C1.B0, &t[8]) + z11 := e.Ext2.Add(t6, &x.C1.B1) // z.C1.B1.Add(&t[6], &x.C1.B1). + z11 = e.Ext2.Double(z11) // Double(&z.C1.B1). + z11 = e.Ext2.Add(z11, t6) // Add(&z.C1.B1, &t[6]) + z12 := e.Ext2.Add(t7, &x.C1.B2) // z.C1.B2.Add(&t[7], &x.C1.B2). + z12 = e.Ext2.Double(z12) // Double(&z.C1.B2). + z12 = e.Ext2.Add(z12, t7) // Add(&z.C1.B2, &t[7]) + return &E12{ // return z + C0: E6{ + B0: *z00, + B1: *z01, + B2: *z02, + }, + C1: E6{ + B0: *z10, + B1: *z11, + B2: *z12, + }, + } +} + +func (e Ext12) Frobenius(x *E12) *E12 { + // var t [6]E2 + t0 := e.Ext2.Conjugate(&x.C0.B0) // t[0].Conjugate(&x.C0.B0) + t1 := e.Ext2.Conjugate(&x.C0.B1) // t[1].Conjugate(&x.C0.B1) + t2 := e.Ext2.Conjugate(&x.C0.B2) // t[2].Conjugate(&x.C0.B2) + t3 := e.Ext2.Conjugate(&x.C1.B0) // t[3].Conjugate(&x.C1.B0) + t4 := e.Ext2.Conjugate(&x.C1.B1) // t[4].Conjugate(&x.C1.B1) + t5 := e.Ext2.Conjugate(&x.C1.B2) // t[5].Conjugate(&x.C1.B2) + t1 = e.Ext2.MulByNonResidue1Power2(t1) // t[1].MulByNonResidue1Power2(&t[1]) + t2 = e.Ext2.MulByNonResidue1Power4(t2) // t[2].MulByNonResidue1Power4(&t[2]) + t3 = e.Ext2.MulByNonResidue1Power1(t3) // t[3].MulByNonResidue1Power1(&t[3]) + t4 = e.Ext2.MulByNonResidue1Power3(t4) // t[4].MulByNonResidue1Power3(&t[4]) + t5 = e.Ext2.MulByNonResidue1Power5(t5) // t[5].MulByNonResidue1Power5(&t[5]) + return &E12{ // return z + C0: E6{ + B0: *t0, // z.C0.B0 = t[0] + B1: *t1, // z.C0.B1 = t[1] + B2: *t2, // z.C0.B2 = t[2] + }, + C1: E6{ + B0: *t3, // z.C1.B0 = t[3] + B1: *t4, // z.C1.B1 = t[4] + B2: *t5, // z.C1.B2 = t[5] + }, + } +} + +func (e Ext12) FrobeniusSquare(x *E12) *E12 { + z00 := &x.C0.B0 // z.C0.B0 = x.C0.B0 + z01 := e.Ext2.MulByNonResidue2Power2(&x.C0.B1) // z.C0.B1.MulByNonResidue2Power2(&x.C0.B1) + z02 := e.Ext2.MulByNonResidue2Power4(&x.C0.B2) // z.C0.B2.MulByNonResidue2Power4(&x.C0.B2) + z10 := e.Ext2.MulByNonResidue2Power1(&x.C1.B0) // z.C1.B0.MulByNonResidue2Power1(&x.C1.B0) + z11 := e.Ext2.MulByNonResidue2Power3(&x.C1.B1) // z.C1.B1.MulByNonResidue2Power3(&x.C1.B1) + z12 := e.Ext2.MulByNonResidue2Power5(&x.C1.B2) // z.C1.B2.MulByNonResidue2Power5(&x.C1.B2) + return &E12{ // return z + C0: E6{B0: *z00, B1: *z01, B2: *z02}, + C1: E6{B0: *z10, B1: *z11, B2: *z12}, + } +} + +func (e Ext12) FrobeniusCube(x *E12) *E12 { + // var t [6]E2 + t0 := e.Ext2.Conjugate(&x.C0.B0) // t[0].Conjugate(&x.C0.B0) + t1 := e.Ext2.Conjugate(&x.C0.B1) // t[1].Conjugate(&x.C0.B1) + t2 := e.Ext2.Conjugate(&x.C0.B2) // t[2].Conjugate(&x.C0.B2) + t3 := e.Ext2.Conjugate(&x.C1.B0) // t[3].Conjugate(&x.C1.B0) + t4 := e.Ext2.Conjugate(&x.C1.B1) // t[4].Conjugate(&x.C1.B1) + t5 := e.Ext2.Conjugate(&x.C1.B2) // t[5].Conjugate(&x.C1.B2) + t1 = e.Ext2.MulByNonResidue3Power2(t1) // t[1].MulByNonResidue3Power2(&t[1]) + t2 = e.Ext2.MulByNonResidue3Power4(t2) // t[2].MulByNonResidue3Power4(&t[2]) + t3 = e.Ext2.MulByNonResidue3Power1(t3) // t[3].MulByNonResidue3Power1(&t[3]) + t4 = e.Ext2.MulByNonResidue3Power3(t4) // t[4].MulByNonResidue3Power3(&t[4]) + t5 = e.Ext2.MulByNonResidue3Power5(t5) // t[5].MulByNonResidue3Power5(&t[5]) + return &E12{ // return z + C0: E6{ + B0: *t0, // z.C0.B0 = t[0] + B1: *t1, // z.C0.B1 = t[1] + B2: *t2, // z.C0.B2 = t[2] + }, + C1: E6{ + B0: *t3, // z.C1.B0 = t[3] + B1: *t4, // z.C1.B1 = t[4] + B2: *t5, // z.C1.B2 = t[5] + }, + } +} + +func (e Ext12) One() *E12 { + z000 := e.fp.One() + zero := e.fp.Zero() + return &E12{ + C0: E6{ + B0: E2{A0: *z000, A1: *zero}, + B1: E2{A0: *zero, A1: *zero}, + B2: E2{A0: *zero, A1: *zero}, + }, + C1: E6{ + B0: E2{A0: *zero, A1: *zero}, + B1: E2{A0: *zero, A1: *zero}, + B2: E2{A0: *zero, A1: *zero}, + }, + } +} + +func (e Ext12) Square(x *E12) *E12 { + // var c0, c2, c3 E6 + c0 := e.Ext6.Sub(&x.C0, &x.C1) // c0.Sub(&x.C0, &x.C1) + c3 := e.Ext6.MulByNonResidue(&x.C1) // c3.MulByNonResidue(&x.C1). + c3 = e.Ext6.Neg(c3) // Neg(&c3). + c3 = e.Ext6.Add(&x.C0, c3) // Add(&x.C0, &c3) + c2 := e.Ext6.Mul(&x.C0, &x.C1) // c2.Mul(&x.C0, &x.C1) + c0 = e.Ext6.Mul(c0, c3) // c0.Mul(&c0, &c3). + c0 = e.Ext6.Add(c0, c2) // Add(&c0, &c2) + z1 := e.Ext6.double(c2) // z.C1.Double(&c2) + c2 = e.Ext6.MulByNonResidue(c2) // c2.MulByNonResidue(&c2) + z0 := e.Ext6.Add(c0, c2) // z.C0.Add(&c0, &c2) + return &E12{ // return z + C0: *z0, + C1: *z1, + } +} + +func (e Ext12) AssertIsEqual(x, y *E12) { + e.Ext6.AssertIsEqual(&x.C0, &y.C0) + e.Ext6.AssertIsEqual(&x.C1, &y.C1) +} diff --git a/std/algebra/emulated/fields_bn254/e12_pairing.go b/std/algebra/emulated/fields_bn254/e12_pairing.go new file mode 100644 index 0000000000..d3c0822cab --- /dev/null +++ b/std/algebra/emulated/fields_bn254/e12_pairing.go @@ -0,0 +1,142 @@ +package fields_bn254 + +import ( + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/std/math/emulated" +) + +type GTEl = E12 + +func NewGTEl(v bn254.GT) GTEl { + return GTEl{ + C0: E6{ + B0: E2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B0.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B0.A1), + }, + B1: E2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B1.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B1.A1), + }, + B2: E2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B2.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B2.A1), + }, + }, + C1: E6{ + B0: E2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B0.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B0.A1), + }, + B1: E2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B1.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B1.A1), + }, + B2: E2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B2.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B2.A1), + }, + }, + } +} + +func (e Ext12) Expt(x *E12) *E12 { + // var result, t0, t1, t2, t3, t4, t5, t6 E12 + t3 := e.CyclotomicSquare(x) // t3.CyclotomicSquare(x) + t5 := e.CyclotomicSquare(t3) // t5.CyclotomicSquare(&t3) + result := e.CyclotomicSquare(t5) // result.CyclotomicSquare(&t5) + t0 := e.CyclotomicSquare(result) // t0.CyclotomicSquare(&result) + t2 := e.Mul(x, t0) // t2.Mul(x, &t0) + t0 = e.Mul(t3, t2) // t0.Mul(&t3, &t2) + t1 := e.Mul(x, t0) // t1.Mul(x, &t0) + t4 := e.Mul(result, t2) // t4.Mul(&result, &t2) + t6 := e.CyclotomicSquare(t2) // t6.CyclotomicSquare(&t2) + t1 = e.Mul(t0, t1) // t1.Mul(&t0, &t1) + t0 = e.Mul(t3, t1) // t0.Mul(&t3, &t1) + t6 = e.NCycloSquare(t6, 6) // t6.NCycloSquare(6) + t5 = e.Mul(t5, t6) // t5.Mul(&t5, &t6) + t5 = e.Mul(t4, t5) // t5.Mul(&t4, &t5) + t5 = e.NCycloSquare(t5, 7) // t5.NCycloSquare(7) + t4 = e.Mul(t4, t5) // t4.Mul(&t4, &t5) + t4 = e.NCycloSquare(t4, 8) // t4.NCycloSquare(8) + t4 = e.Mul(t0, t4) // t4.Mul(&t0, &t4) + t3 = e.Mul(t3, t4) // t3.Mul(&t3, &t4) + t3 = e.NCycloSquare(t3, 6) // t3.NCycloSquare(6) + t2 = e.Mul(t2, t3) // t2.Mul(&t2, &t3) + t2 = e.NCycloSquare(t2, 8) // t2.NCycloSquare(8) + t2 = e.Mul(t0, t2) // t2.Mul(&t0, &t2) + t2 = e.NCycloSquare(t2, 6) // t2.NCycloSquare(6) + t2 = e.Mul(t0, t2) // t2.Mul(&t0, &t2) + t2 = e.NCycloSquare(t2, 10) // t2.NCycloSquare(10) + t1 = e.Mul(t1, t2) // t1.Mul(&t1, &t2) + t1 = e.NCycloSquare(t1, 6) // t1.NCycloSquare(6) + t0 = e.Mul(t0, t1) // t0.Mul(&t0, &t1) + z := e.Mul(result, t0) // z.Mul(&result, &t0) + return z // return z +} + +func (e Ext12) MulBy034(z *E12, c0, c3, c4 *E2) *E12 { + // var a, b, d E6 + a := e.Ext6.MulByE2(&z.C0, c0) // a.MulByE2(&z.C0, c0) + // b.Set(&z.C1) + b := e.Ext6.MulBy01(&z.C1, c3, c4) // b.MulBy01(c3, c4) + c0 = e.Ext2.Add(c0, c3) // c0.Add(c0, c3) + d := e.Ext6.Add(&z.C0, &z.C1) // d.Add(&z.C0, &z.C1) + d = e.Ext6.MulBy01(d, c0, c4) // d.MulBy01(c0, c4) + z1 := e.Add(a, b) // z.C1.Add(&a, &b). + z1 = e.Neg(z1) // Neg(&z.C1). + z1 = e.Add(z1, d) // Add(&z.C1, &d) + z0 := e.MulByNonResidue(b) // z.C0.MulByNonResidue(&b). + z0 = e.Add(z0, a) // Add(&z.C0, &a) + return &E12{ // return z + C0: *z0, + C1: *z1, + } +} + +func (e Ext12) NCycloSquare(z *E12, n int) *E12 { + for i := 0; i < n; i++ { + z = e.CyclotomicSquare(z) + } + return z +} +func (e Ext12) MulBy034by034(d0, d3, d4, c0, c3, c4 *E2) *E12 { + // var tmp, x0, x3, x4, x04, x03, x34 E2 + x0 := e.Ext2.Mul(c0, d0) // x0.Mul(c0, d0) + x3 := e.Ext2.Mul(c3, d3) // x3.Mul(c3, d3) + x4 := e.Ext2.Mul(c4, d4) // x4.Mul(c4, d4) + tmp := e.Ext2.Add(c0, c4) // tmp.Add(c0, c4) + x04 := e.Ext2.Add(d0, d4) // x04.Add(d0, d4). + x04 = e.Ext2.Mul(x04, tmp) // Mul(&x04, &tmp). + x04 = e.Ext2.Sub(x04, x0) // Sub(&x04, &x0). + x04 = e.Ext2.Sub(x04, x4) // Sub(&x04, &x4) + tmp = e.Ext2.Add(c0, c3) // tmp.Add(c0, c3) + x03 := e.Ext2.Add(d0, d3) // x03.Add(d0, d3). + x03 = e.Ext2.Mul(x03, tmp) // Mul(&x03, &tmp). + x03 = e.Ext2.Sub(x03, x0) // Sub(&x03, &x0). + x03 = e.Ext2.Sub(x03, x3) // Sub(&x03, &x3) + tmp = e.Ext2.Add(c3, c4) // tmp.Add(c3, c4) + x34 := e.Ext2.Add(d3, d4) // x34.Add(d3, d4). + x34 = e.Ext2.Mul(x34, tmp) // Mul(&x34, &tmp). + x34 = e.Ext2.Sub(x34, x3) // Sub(&x34, &x3). + x34 = e.Ext2.Sub(x34, x4) // Sub(&x34, &x4) + z00 := e.Ext2.MulByNonResidue(x4) // z.C0.B0.MulByNonResidue(&x4). + z00 = e.Ext2.Add(z00, x0) // Add(&z.C0.B0, &x0) + z01 := x3 // z.C0.B1.Set(&x3) + z02 := x34 // z.C0.B2.Set(&x34) + z10 := x03 // z.C1.B0.Set(&x03) + z11 := x04 // z.C1.B1.Set(&x04) + z12 := e.Ext2.Zero() // z.C1.B2.SetZero() + return &E12{ // return z + C0: E6{ + B0: *z00, + B1: *z01, + B2: *z02, + }, + C1: E6{ + B0: *z10, + B1: *z11, + B2: *z12, + }, + } +} diff --git a/std/algebra/emulated/fields_bn254/e2.go b/std/algebra/emulated/fields_bn254/e2.go new file mode 100644 index 0000000000..8ba71003c7 --- /dev/null +++ b/std/algebra/emulated/fields_bn254/e2.go @@ -0,0 +1,312 @@ +package fields_bn254 + +import ( + "math/big" + + "github.com/consensys/gnark/std/math/emulated" +) + +type curveF = emulated.Field[emulated.BN254Fp] +type baseEl = emulated.Element[emulated.BN254Fp] + +type E2 struct { + A0, A1 baseEl +} + +type Ext2 struct { + fp *curveF + nonResidues map[int]map[int]*E2 +} + +func NewExt2(baseField *curveF) *Ext2 { + pwrs := map[int]map[int]struct { + A0 string + A1 string + }{ + 0: { + -1: {"21087453498479301738505683583845423561061080261299122796980902361914303298513", "14681138511599513868579906292550611339979233093309515871315818100066920017952"}, + 1: {"9", "1"}, + }, + 1: { + 1: {"8376118865763821496583973867626364092589906065868298776909617916018768340080", "16469823323077808223889137241176536799009286646108169935659301613961712198316"}, + 2: {"21575463638280843010398324269430826099269044274347216827212613867836435027261", "10307601595873709700152284273816112264069230130616436755625194854815875713954"}, + 3: {"2821565182194536844548159561693502659359617185244120367078079554186484126554", "3505843767911556378687030309984248845540243509899259641013678093033130930403"}, + 4: {"2581911344467009335267311115468803099551665605076196740867805258568234346338", "19937756971775647987995932169929341994314640652964949448313374472400716661030"}, + 5: {"685108087231508774477564247770172212460312782337200605669322048753928464687", "8447204650696766136447902020341177575205426561248465145919723016860428151883"}, + }, + 2: { + 1: {"21888242871839275220042445260109153167277707414472061641714758635765020556617", "0"}, + 2: {"21888242871839275220042445260109153167277707414472061641714758635765020556616", "0"}, + 3: {"21888242871839275222246405745257275088696311157297823662689037894645226208582", "0"}, + 4: {"2203960485148121921418603742825762020974279258880205651966", "0"}, + 5: {"2203960485148121921418603742825762020974279258880205651967", "0"}, + }, + 3: { + 1: {"11697423496358154304825782922584725312912383441159505038794027105778954184319", "303847389135065887422783454877609941456349188919719272345083954437860409601"}, + 2: {"3772000881919853776433695186713858239009073593817195771773381919316419345261", "2236595495967245188281701248203181795121068902605861227855261137820944008926"}, + 3: {"19066677689644738377698246183563772429336693972053703295610958340458742082029", "18382399103927718843559375435273026243156067647398564021675359801612095278180"}, + 4: {"5324479202449903542726783395506214481928257762400643279780343368557297135718", "16208900380737693084919495127334387981393726419856888799917914180988844123039"}, + 5: {"8941241848238582420466759817324047081148088512956452953208002715982955420483", "10338197737521362862238855242243140895517409139741313354160881284257516364953"}, + }, + } + nonResidues := make(map[int]map[int]*E2) + for pwr, v := range pwrs { + for coeff, v := range v { + el := E2{emulated.ValueOf[emulated.BN254Fp](v.A0), emulated.ValueOf[emulated.BN254Fp](v.A1)} + if nonResidues[pwr] == nil { + nonResidues[pwr] = make(map[int]*E2) + } + nonResidues[pwr][coeff] = &el + } + } + return &Ext2{fp: baseField, nonResidues: nonResidues} +} + +// TODO: check where to use Mod and where ModMul. + +func (e Ext2) MulByElement(x *E2, y *baseEl) *E2 { + // var yCopy fp.Element + // yCopy.Set(y) + z0 := e.fp.MulMod(&x.A0, y) // z.A0.Mul(&x.A0, &yCopy) + z1 := e.fp.MulMod(&x.A1, y) // z.A1.Mul(&x.A1, &yCopy) + return &E2{ // return z + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) Conjugate(x *E2) *E2 { + z0 := x.A0 // z.A0 = x.A0 + z1 := e.fp.Neg(&x.A1) // z.A1.Neg(&x.A1) + return &E2{ // return z + A0: z0, + A1: *z1, + } +} + +func (e Ext2) MulByNonResidueGeneric(x *E2, power, coef int) *E2 { + y := e.nonResidues[power][coef] + z := e.Mul(x, y) + return z +} + +func (e Ext2) MulByNonResidue(x *E2) *E2 { + /* + // below is the direct transliteration of the gnark-crypto code. Now only, + // for simplicity and debugging purposes, we do the non residue operations + // without optimisations. + + nine := big.NewInt(9) + // var a, b fp.Element + a := e.fp.MulConst(&x.A0, nine) // a.Double(&x.A0).Double(&a).Double(&a).Add(&a, &x.A0). + a = e.fp.Sub(a, &x.A1) // Sub(&a, &x.A1) + b := e.fp.MulConst(&x.A1, nine) // b.Double(&x.A1).Double(&b).Double(&b).Add(&b, &x.A1). + b = e.fp.Add(b, &x.A0) // Add(&b, &x.A0) + return &E2{ + A0: *a, // z.A0.Set(&a) + A1: *b, // z.A1.Set(&b) + } // return z + */ + // TODO: inline non-residue Multiplication + return e.MulByNonResidueGeneric(x, 0, 1) +} + +func (e Ext2) MulByNonResidueInv(x *E2) *E2 { + // TODO: to optimise with constant non-residue inverse + /* + // from gnark-crypto + // z.Mul(x, &nonResInverse) + // return z + */ + return e.MulByNonResidueGeneric(x, 0, -1) +} + +func (e Ext2) MulByNonResidue1Power1(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 1, 1) +} + +func (e Ext2) MulByNonResidue1Power2(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 1, 2) +} + +func (e Ext2) MulByNonResidue1Power3(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 1, 3) +} + +func (e Ext2) MulByNonResidue1Power4(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 1, 4) +} + +func (e Ext2) MulByNonResidue1Power5(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 1, 5) +} + +func (e Ext2) MulByNonResidue2Power1(x *E2) *E2 { + // TODO: A1 is 0, we can optimize for it + return e.MulByNonResidueGeneric(x, 2, 1) +} +func (e Ext2) MulByNonResidue2Power2(x *E2) *E2 { + // TODO: A1 is 0, we can optimize for it + return e.MulByNonResidueGeneric(x, 2, 2) +} + +func (e Ext2) MulByNonResidue2Power3(x *E2) *E2 { + // TODO: A1 is 0, we can optimize for it + return e.MulByNonResidueGeneric(x, 2, 3) +} + +func (e Ext2) MulByNonResidue2Power4(x *E2) *E2 { + // TODO: A1 is 0, we can optimize for it + return e.MulByNonResidueGeneric(x, 2, 4) +} + +func (e Ext2) MulByNonResidue2Power5(x *E2) *E2 { + // TODO: A1 is 0, we can optimize for it + return e.MulByNonResidueGeneric(x, 2, 5) +} + +func (e Ext2) MulByNonResidue3Power1(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 3, 1) +} + +func (e Ext2) MulByNonResidue3Power2(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 3, 2) +} + +func (e Ext2) MulByNonResidue3Power3(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 3, 3) +} + +func (e Ext2) MulByNonResidue3Power4(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 3, 4) +} + +func (e Ext2) MulByNonResidue3Power5(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 3, 5) +} + +func (e Ext2) Mul(x, y *E2) *E2 { + // var a, b, c fp.Element + a := e.fp.Add(&x.A0, &x.A1) // a.Add(&x.A0, &x.A1) + b := e.fp.Add(&y.A0, &y.A1) // b.Add(&y.A0, &y.A1) + a = e.fp.MulMod(a, b) // a.Mul(&a, &b) + b = e.fp.MulMod(&x.A0, &y.A0) // b.Mul(&x.A0, &y.A0) + c := e.fp.MulMod(&x.A1, &y.A1) // c.Mul(&x.A1, &y.A1) + z1 := e.fp.Sub(a, b) // z.A1.Sub(&a, &b). + z1 = e.fp.Sub(z1, c) // Sub(&z.A1, &c) + z0 := e.fp.Sub(b, c) // z.A0.Sub(&b, &c) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) Add(x, y *E2) *E2 { + z0 := e.fp.Add(&x.A0, &y.A0) // z.A0.Add(&x.A0, &y.A0) + z1 := e.fp.Add(&x.A1, &y.A1) // z.A1.Add(&x.A1, &y.A1) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) Sub(x, y *E2) *E2 { + z0 := e.fp.Sub(&x.A0, &y.A0) // z.A0.Sub(&x.A0, &y.A0) + z1 := e.fp.Sub(&x.A1, &y.A1) // z.A1.Sub(&x.A1, &y.A1) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) Neg(x *E2) *E2 { + z0 := e.fp.Neg(&x.A0) // z.A0.Neg(&x.A0) + z1 := e.fp.Neg(&x.A1) // z.A1.Neg(&x.A1) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) One() *E2 { + z0 := e.fp.One() // z.A0.SetOne() + z1 := e.fp.Zero() // z.A1.SetZero() + return &E2{ // return z + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) Zero() *E2 { + z0 := e.fp.Zero() + z1 := e.fp.Zero() + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) Square(x *E2) *E2 { + // var a, b fp.Element + a := e.fp.Add(&x.A0, &x.A1) // a.Add(&x.A0, &x.A1) + b := e.fp.Sub(&x.A0, &x.A1) // b.Sub(&x.A0, &x.A1) + a = e.fp.MulMod(a, b) // a.Mul(&a, &b) + b = e.fp.MulMod(&x.A0, &x.A1) // b.Mul(&x.A0, &x.A1). + b = e.fp.MulConst(b, big.NewInt(2)) // Double(&b) + return &E2{ + A0: *a, // z.A0.Set(&a) + A1: *b, // z.A1.Set(&b) + } +} + +func (e Ext2) Double(x *E2) *E2 { + two := big.NewInt(2) + z0 := e.fp.MulConst(&x.A0, two) // z.A0.Double(&x.A0) + z1 := e.fp.MulConst(&x.A1, two) // z.A1.Double(&x.A1) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) Halve(x *E2) *E2 { + // I'm trying to avoid hard-coding modulus here in case want to make generic + // for different curves. + // TODO: if implemented Half in field emulation, then replace with it. + one := e.fp.One() + two := e.fp.MulConst(one, big.NewInt(2)) + z0 := e.fp.Div(&x.A0, two) + z1 := e.fp.Div(&x.A1, two) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) MulBybTwistCurveCoeff(x *E2) *E2 { + // var res E2 + res := e.MulByNonResidueInv(x) // res.MulByNonResidueInv(x) + z := e.Double(res) // z.Double(&res). + z = e.Add(z, res) // Add(&res, z) + return z // return z +} + +func (e Ext2) Inverse(x *E2) *E2 { + // var t0, t1 fp.Element + t0 := e.fp.MulMod(&x.A0, &x.A0) // t0.Square(&x.A0) + t1 := e.fp.MulMod(&x.A1, &x.A1) // t1.Square(&x.A1) + t0 = e.fp.Add(t0, t1) // t0.Add(&t0, &t1) + t1 = e.fp.Inverse(t0) // t1.Inverse(&t0) + z0 := e.fp.MulMod(&x.A0, t1) // z.A0.Mul(&x.A0, &t1) + z1 := e.fp.MulMod(&x.A1, t1) // z.A1.Mul(&x.A1, &t1). + z1 = e.fp.Neg(z1) // Neg(&z.A1) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) AssertIsEqual(x, y *E2) { + e.fp.AssertIsEqual(&x.A0, &y.A0) + e.fp.AssertIsEqual(&x.A1, &y.A1) +} diff --git a/std/algebra/emulated/fields_bn254/e6.go b/std/algebra/emulated/fields_bn254/e6.go new file mode 100644 index 0000000000..a07d04d015 --- /dev/null +++ b/std/algebra/emulated/fields_bn254/e6.go @@ -0,0 +1,201 @@ +package fields_bn254 + +type E6 struct { + B0, B1, B2 E2 +} + +type Ext6 struct { + *Ext2 +} + +func NewExt6(baseField *curveF) *Ext6 { + return &Ext6{Ext2: NewExt2(baseField)} +} + +func (e Ext6) Add(x, y *E6) *E6 { + z0 := e.Ext2.Add(&x.B0, &y.B0) // z.B0.Add(&x.B0, &y.B0) + z1 := e.Ext2.Add(&x.B1, &y.B1) // z.B1.Add(&x.B1, &y.B1) + z2 := e.Ext2.Add(&x.B2, &y.B2) // z.B2.Add(&x.B2, &y.B2) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Neg(x *E6) *E6 { + z0 := e.Ext2.Neg(&x.B0) // z.B0.Neg(&x.B0) + z1 := e.Ext2.Neg(&x.B1) // z.B1.Neg(&x.B1) + z2 := e.Ext2.Neg(&x.B2) // z.B2.Neg(&x.B2) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Sub(x, y *E6) *E6 { + z0 := e.Ext2.Sub(&x.B0, &y.B0) // z.B0.Sub(&x.B0, &y.B0) + z1 := e.Ext2.Sub(&x.B1, &y.B1) // z.B1.Sub(&x.B1, &y.B1) + z2 := e.Ext2.Sub(&x.B2, &y.B2) // z.B2.Sub(&x.B2, &y.B2) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Mul(x, y *E6) *E6 { + // var t0, t1, t2, c0, c1, c2, tmp E2 + t0 := e.Ext2.Mul(&x.B0, &y.B0) // t0.Mul(&x.B0, &y.B0) + t1 := e.Ext2.Mul(&x.B1, &y.B1) // t1.Mul(&x.B1, &y.B1) + t2 := e.Ext2.Mul(&x.B2, &y.B2) // t2.Mul(&x.B2, &y.B2) + c0 := e.Ext2.Add(&x.B1, &x.B2) // c0.Add(&x.B1, &x.B2) + tmp := e.Ext2.Add(&y.B1, &y.B2) // tmp.Add(&y.B1, &y.B2) + c0 = e.Ext2.Mul(c0, tmp) // c0.Mul(&c0, &tmp). + c0 = e.Ext2.Sub(c0, t1) // Sub(&c0, &t1). + c0 = e.Ext2.Sub(c0, t2) // Sub(&c0, &t2). + c0 = e.Ext2.MulByNonResidue(c0) // MulByNonResidue(&c0). + c0 = e.Ext2.Add(c0, t0) // Add(&c0, &t0) + c1 := e.Ext2.Add(&x.B0, &x.B1) // c1.Add(&x.B0, &x.B1) + tmp = e.Ext2.Add(&y.B0, &y.B1) // tmp.Add(&y.B0, &y.B1) + c1 = e.Ext2.Mul(c1, tmp) // c1.Mul(&c1, &tmp). + c1 = e.Ext2.Sub(c1, t0) // Sub(&c1, &t0). + c1 = e.Ext2.Sub(c1, t1) // Sub(&c1, &t1) + tmp = e.Ext2.MulByNonResidue(t2) // tmp.MulByNonResidue(&t2) + c1 = e.Ext2.Add(c1, tmp) // c1.Add(&c1, &tmp) + tmp = e.Ext2.Add(&x.B0, &x.B2) // tmp.Add(&x.B0, &x.B2) + c2 := e.Ext2.Add(&y.B0, &y.B2) // c2.Add(&y.B0, &y.B2). + c2 = e.Ext2.Mul(c2, tmp) // Mul(&c2, &tmp). + c2 = e.Ext2.Sub(c2, t0) // Sub(&c2, &t0). + c2 = e.Ext2.Sub(c2, t2) // Sub(&c2, &t2). + c2 = e.Ext2.Add(c2, t1) // Add(&c2, &t1) + return &E6{ + B0: *c0, // z.B0.Set(&c0) + B1: *c1, // z.B1.Set(&c1) + B2: *c2, // z.B2.Set(&c2) + } // return z +} + +func (e Ext6) double(x *E6) *E6 { + z0 := e.Ext2.Double(&x.B0) // z.B0.Double(&x.B0) + z1 := e.Ext2.Double(&x.B1) // z.B1.Double(&x.B1) + z2 := e.Ext2.Double(&x.B2) // z.B2.Double(&x.B2) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Square(x *E6) *E6 { + // var c4, c5, c1, c2, c3, c0 E2 + c4 := e.Ext2.Mul(&x.B0, &x.B1) // c4.Mul(&x.B0, &x.B1). + c4 = e.Ext2.Double(c4) // Double(&c4) + c5 := e.Ext2.Square(&x.B2) // c5.Square(&x.B2) + c1 := e.Ext2.MulByNonResidue(c5) // c1.MulByNonResidue(&c5). + c1 = e.Ext2.Add(c1, c4) // Add(&c1, &c4) + c2 := e.Ext2.Sub(c4, c5) // c2.Sub(&c4, &c5) + c3 := e.Ext2.Square(&x.B0) // c3.Square(&x.B0) + c4 = e.Ext2.Sub(&x.B0, &x.B1) // c4.Sub(&x.B0, &x.B1). + c4 = e.Ext2.Add(c4, &x.B2) // Add(&c4, &x.B2) + c5 = e.Ext2.Mul(&x.B1, &x.B2) // c5.Mul(&x.B1, &x.B2). + c5 = e.Ext2.Double(c5) // Double(&c5) + c4 = e.Ext2.Square(c4) // c4.Square(&c4) + c0 := e.Ext2.MulByNonResidue(c5) // c0.MulByNonResidue(&c5). + c0 = e.Ext2.Add(c0, c3) // Add(&c0, &c3) + z2 := e.Ext2.Add(c2, c4) // z.B2.Add(&c2, &c4). + z2 = e.Ext2.Add(z2, c5) // Add(&z.B2, &c5). + z2 = e.Ext2.Sub(z2, c3) // Sub(&z.B2, &c3) + z0 := c0 // z.B0.Set(&c0) + z1 := c1 // z.B1.Set(&c1) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Inverse(x *E6) *E6 { + // var t0, t1, t2, t3, t4, t5, t6, c0, c1, c2, d1, d2 E2 + t0 := e.Ext2.Square(&x.B0) // t0.Square(&x.B0) + t1 := e.Ext2.Square(&x.B1) // t1.Square(&x.B1) + t2 := e.Ext2.Square(&x.B2) // t2.Square(&x.B2) + t3 := e.Ext2.Mul(&x.B0, &x.B1) // t3.Mul(&x.B0, &x.B1) + t4 := e.Ext2.Mul(&x.B0, &x.B2) // t4.Mul(&x.B0, &x.B2) + t5 := e.Ext2.Mul(&x.B1, &x.B2) // t5.Mul(&x.B1, &x.B2) + c0 := e.Ext2.MulByNonResidue(t5) // c0.MulByNonResidue(&t5). + c0 = e.Ext2.Neg(c0) // Neg(&c0). + c0 = e.Ext2.Add(c0, t0) // Add(&c0, &t0) + c1 := e.Ext2.MulByNonResidue(t2) // c1.MulByNonResidue(&t2). + c1 = e.Ext2.Sub(c1, t3) // Sub(&c1, &t3) + c2 := e.Ext2.Sub(t1, t4) // c2.Sub(&t1, &t4) + t6 := e.Ext2.Mul(&x.B0, c0) // t6.Mul(&x.B0, &c0) + d1 := e.Ext2.Mul(&x.B2, c1) // d1.Mul(&x.B2, &c1) + d2 := e.Ext2.Mul(&x.B1, c2) // d2.Mul(&x.B1, &c2) + d1 = e.Ext2.Add(d1, d2) // d1.Add(&d1, &d2). + d1 = e.Ext2.MulByNonResidue(d1) // MulByNonResidue(&d1) + t6 = e.Ext2.Add(t6, d1) // t6.Add(&t6, &d1) + t6 = e.Ext2.Inverse(t6) // t6.Inverse(&t6) + z0 := e.Ext2.Mul(c0, t6) // z.B0.Mul(&c0, &t6) + z1 := e.Ext2.Mul(c1, t6) // z.B1.Mul(&c1, &t6) + z2 := e.Ext2.Mul(c2, t6) // z.B2.Mul(&c2, &t6) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} +func (e Ext6) MulByE2(x *E6, y *E2) *E6 { + // var yCopy E2 + // yCopy.Set(y) + z0 := e.Ext2.Mul(&x.B0, y) // z.B0.Mul(&x.B0, &yCopy) + z1 := e.Ext2.Mul(&x.B1, y) // z.B1.Mul(&x.B1, &yCopy) + z2 := e.Ext2.Mul(&x.B2, y) // z.B2.Mul(&x.B2, &yCopy) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) MulBy01(z *E6, c0, c1 *E2) *E6 { + // var a, b, tmp, t0, t1, t2 E2 + a := e.Ext2.Mul(&z.B0, c0) // a.Mul(&z.B0, c0) + b := e.Ext2.Mul(&z.B1, c1) // b.Mul(&z.B1, c1) + tmp := e.Ext2.Add(&z.B1, &z.B2) // tmp.Add(&z.B1, &z.B2) + t0 := e.Ext2.Mul(c1, tmp) // t0.Mul(c1, &tmp) + t0 = e.Ext2.Sub(t0, b) // t0.Sub(&t0, &b) + t0 = e.Ext2.MulByNonResidue(t0) // t0.MulByNonResidue(&t0) + t0 = e.Ext2.Add(t0, a) // t0.Add(&t0, &a) + tmp = e.Ext2.Add(&z.B0, &z.B2) // tmp.Add(&z.B0, &z.B2) + t2 := e.Ext2.Mul(c0, tmp) // t2.Mul(c0, &tmp) + t2 = e.Ext2.Sub(t2, a) // t2.Sub(&t2, &a) + t2 = e.Ext2.Add(t2, b) // t2.Add(&t2, &b) + t1 := e.Ext2.Add(c0, c1) // t1.Add(c0, c1) + tmp = e.Ext2.Add(&z.B0, &z.B1) // tmp.Add(&z.B0, &z.B1) + t1 = e.Ext2.Mul(t1, tmp) // t1.Mul(&t1, &tmp) + t1 = e.Ext2.Sub(t1, a) // t1.Sub(&t1, &a) + t1 = e.Ext2.Sub(t1, b) // t1.Sub(&t1, &b) + return &E6{ + B0: *t0, // z.B0.Set(&t0) + B1: *t1, // z.B1.Set(&t1) + B2: *t2, // z.B2.Set(&t2) + } // return z +} + +func (e Ext6) MulByNonResidue(x *E6) *E6 { + z2, z1, z0 := &x.B1, &x.B0, &x.B2 // z.B2, z.B1, z.B0 = x.B1, x.B0, x.B2 + z0 = e.Ext2.MulByNonResidue(z0) // z.B0.MulByNonResidue(&z.B0) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) AssertIsEqual(x, y *E6) { + e.Ext2.AssertIsEqual(&x.B0, &y.B0) + e.Ext2.AssertIsEqual(&x.B1, &y.B1) + e.Ext2.AssertIsEqual(&x.B2, &y.B2) +} diff --git a/std/algebra/pairing_bn254/doc.go b/std/algebra/emulated/sw_bn254/doc.go similarity index 70% rename from std/algebra/pairing_bn254/doc.go rename to std/algebra/emulated/sw_bn254/doc.go index 5f04a7dd72..3dcd2d45c0 100644 --- a/std/algebra/pairing_bn254/doc.go +++ b/std/algebra/emulated/sw_bn254/doc.go @@ -1,7 +1,7 @@ -// Package pairing_bn254 implements pairing over BN254 curve. +// Package sw_bn254 implements pairing over BN254 curve. // // The implementation follows very closely the implementation of its out-circuit // counterpart in [gnark-crypto]. // // [gnark-crypto]: https://github.com/ConsenSys/gnark-crypto/tree/master/ecc/bn254 -package pairing_bn254 +package sw_bn254 diff --git a/std/algebra/pairing_bn254/doc_test.go b/std/algebra/emulated/sw_bn254/doc_test.go similarity index 81% rename from std/algebra/pairing_bn254/doc_test.go rename to std/algebra/emulated/sw_bn254/doc_test.go index 8481c45361..c1d3ac22a1 100644 --- a/std/algebra/pairing_bn254/doc_test.go +++ b/std/algebra/emulated/sw_bn254/doc_test.go @@ -1,4 +1,4 @@ -package pairing_bn254_test +package sw_bn254_test import ( "crypto/rand" @@ -9,21 +9,22 @@ import ( "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/std/algebra/pairing_bn254" + "github.com/consensys/gnark/std/algebra/emulated/fields_bn254" + "github.com/consensys/gnark/std/algebra/emulated/sw_bn254" ) type PairCircuit struct { - InG1 pairing_bn254.G1Affine - InG2 pairing_bn254.G2Affine - Res pairing_bn254.GTEl + InG1 sw_bn254.G1Affine + InG2 sw_bn254.G2Affine + Res fields_bn254.GTEl } func (c *PairCircuit) Define(api frontend.API) error { - pairing, err := pairing_bn254.NewPairing(api) + pairing, err := sw_bn254.NewPairing(api) if err != nil { return fmt.Errorf("new pairing: %w", err) } - res, err := pairing.Pair([]*pairing_bn254.G1Affine{&c.InG1}, []*pairing_bn254.G2Affine{&c.InG2}) + res, err := pairing.Pair([]*sw_bn254.G1Affine{&c.InG1}, []*sw_bn254.G2Affine{&c.InG2}) if err != nil { return fmt.Errorf("pair: %w", err) } @@ -42,9 +43,9 @@ func ExamplePairing() { } circuit := PairCircuit{} witness := PairCircuit{ - InG1: pairing_bn254.NewG1Affine(p), - InG2: pairing_bn254.NewG2Affine(q), - Res: pairing_bn254.NewGTEl(res), + InG1: sw_bn254.NewG1Affine(p), + InG2: sw_bn254.NewG2Affine(q), + Res: fields_bn254.NewGTEl(res), } ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) if err != nil { diff --git a/std/algebra/pairing_bn254/g1.go b/std/algebra/emulated/sw_bn254/g1.go similarity index 66% rename from std/algebra/pairing_bn254/g1.go rename to std/algebra/emulated/sw_bn254/g1.go index 4f1fa5d2c4..69ce54898c 100644 --- a/std/algebra/pairing_bn254/g1.go +++ b/std/algebra/emulated/sw_bn254/g1.go @@ -1,12 +1,12 @@ -package pairing_bn254 +package sw_bn254 import ( "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark/std/algebra/weierstrass" + "github.com/consensys/gnark/std/algebra/emulated/sw_emulated" "github.com/consensys/gnark/std/math/emulated" ) -type G1Affine = weierstrass.AffinePoint[emulated.BN254Fp] +type G1Affine = sw_emulated.AffinePoint[emulated.BN254Fp] func NewG1Affine(v bn254.G1Affine) G1Affine { return G1Affine{ diff --git a/std/algebra/pairing_bn254/g2.go b/std/algebra/emulated/sw_bn254/g2.go similarity index 70% rename from std/algebra/pairing_bn254/g2.go rename to std/algebra/emulated/sw_bn254/g2.go index ace3b00efe..1ba7d154a6 100644 --- a/std/algebra/pairing_bn254/g2.go +++ b/std/algebra/emulated/sw_bn254/g2.go @@ -1,29 +1,30 @@ -package pairing_bn254 +package sw_bn254 import ( "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/std/algebra/emulated/fields_bn254" "github.com/consensys/gnark/std/math/emulated" ) type G2Affine struct { - X, Y e2 + X, Y fields_bn254.E2 } type g2Jacobian struct { - X, Y, Z e2 + X, Y, Z fields_bn254.E2 } type g2Projective struct { - X, Y, Z e2 + X, Y, Z fields_bn254.E2 } func NewG2Affine(v bn254.G2Affine) G2Affine { return G2Affine{ - X: e2{ + X: fields_bn254.E2{ A0: emulated.ValueOf[emulated.BN254Fp](v.X.A0), A1: emulated.ValueOf[emulated.BN254Fp](v.X.A1), }, - Y: e2{ + Y: fields_bn254.E2{ A0: emulated.ValueOf[emulated.BN254Fp](v.Y.A0), A1: emulated.ValueOf[emulated.BN254Fp](v.Y.A1), }, diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go new file mode 100644 index 0000000000..8ef59ab363 --- /dev/null +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -0,0 +1,283 @@ +package sw_bn254 + +import ( + "fmt" + + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/algebra/emulated/fields_bn254" + "github.com/consensys/gnark/std/math/emulated" +) + +type Pairing struct { + *fields_bn254.Ext12 +} + +func NewPairing(api frontend.API) (*Pairing, error) { + ba, err := emulated.NewField[emulated.BN254Fp](api) + if err != nil { + return nil, fmt.Errorf("new base api: %w", err) + } + return &Pairing{ + Ext12: fields_bn254.NewExt12(ba), + }, nil +} + +func (pr Pairing) DoubleStep(p *g2Projective) (*g2Projective, *lineEvaluation) { + // var t1, A, B, C, D, E, EE, F, G, H, I, J, K fptower.E2 + A := pr.Ext2.Mul(&p.X, &p.Y) // A.Mul(&p.x, &p.y) + A = pr.Ext2.Halve(A) // A.Halve() + B := pr.Ext2.Square(&p.Y) // B.Square(&p.y) + C := pr.Ext2.Square(&p.Z) // C.Square(&p.z) + D := pr.Ext2.Double(C) // D.Double(&C). + D = pr.Ext2.Add(D, C) // Add(&D, &C) + E := pr.Ext2.MulBybTwistCurveCoeff(D) // E.MulBybTwistCurveCoeff(&D) + F := pr.Ext2.Double(E) // F.Double(&E). + F = pr.Ext2.Add(F, E) // Add(&F, &E) + G := pr.Ext2.Add(B, F) // G.Add(&B, &F) + G = pr.Ext2.Halve(G) // G.Halve() + H := pr.Ext2.Add(&p.Y, &p.Z) // H.Add(&p.y, &p.z). + H = pr.Ext2.Square(H) // Square(&H) + t1 := pr.Ext2.Add(B, C) // t1.Add(&B, &C) + H = pr.Ext2.Sub(H, t1) // H.Sub(&H, &t1) + I := pr.Ext2.Sub(E, B) // I.Sub(&E, &B) + J := pr.Ext2.Square(&p.X) // J.Square(&p.x) + EE := pr.Ext2.Square(E) // EE.Square(&E) + K := pr.Ext2.Double(EE) // K.Double(&EE). + K = pr.Ext2.Add(K, EE) // Add(&K, &EE) + px := pr.Ext2.Sub(B, F) // p.x.Sub(&B, &F). + px = pr.Ext2.Mul(px, A) // Mul(&p.x, &A) + py := pr.Ext2.Square(G) // p.y.Square(&G). + py = pr.Ext2.Sub(py, K) // Sub(&p.y, &K) + pz := pr.Ext2.Mul(B, H) // p.z.Mul(&B, &H) + ev0 := pr.Ext2.Neg(H) // evaluations.r0.Neg(&H) + ev1 := pr.Ext2.Double(J) // evaluations.r1.Double(&J). + ev1 = pr.Ext2.Add(ev1, J) // Add(&evaluations.r1, &J) + ev2 := I // evaluations.r2.Set(&I) + return &g2Projective{ + X: *px, + Y: *py, + Z: *pz, + }, + &lineEvaluation{ + r0: *ev0, + r1: *ev1, + r2: *ev2, + } +} + +func (pr Pairing) affineToProjective(Q *G2Affine) *g2Projective { + // TODO: check point at infinity? We do not filter them in the Miller Loop neither. + // if Q.X.IsZero() && Q.Y.IsZero() { + // p.z.SetZero() + // p.x.SetOne() + // p.y.SetOne() + // return p + // } + pz := pr.Ext2.One() // p.z.SetOne() + px := &Q.X // p.x.Set(&Q.X) + py := &Q.Y // p.y.Set(&Q.Y) + return &g2Projective{ // return p + X: *px, + Y: *py, + Z: *pz, + } +} + +func (pr Pairing) NegAffine(a *G2Affine) *G2Affine { + px := &a.X // p.X = a.X + py := pr.Ext2.Neg(&a.Y) // p.Y.Neg(&a.Y) + return &G2Affine{ // return p + X: *px, + Y: *py, + } +} + +func (pr Pairing) AddStep(p *g2Projective, a *G2Affine) (*g2Projective, *lineEvaluation) { + // var Y2Z1, X2Z1, O, L, C, D, E, F, G, H, t0, t1, t2, J fptower.E2 + Y2Z1 := pr.Ext2.Mul(&a.Y, &p.Z) // Y2Z1.Mul(&a.Y, &p.z) + O := pr.Ext2.Sub(&p.Y, Y2Z1) // O.Sub(&p.y, &Y2Z1) + X2Z1 := pr.Ext2.Mul(&a.X, &p.Z) // X2Z1.Mul(&a.X, &p.z) + L := pr.Ext2.Sub(&p.X, X2Z1) // L.Sub(&p.x, &X2Z1) + C := pr.Ext2.Square(O) // C.Square(&O) + D := pr.Ext2.Square(L) // D.Square(&L) + E := pr.Ext2.Mul(L, D) // E.Mul(&L, &D) + F := pr.Ext2.Mul(&p.Z, C) // F.Mul(&p.z, &C) + G := pr.Ext2.Mul(&p.X, D) // G.Mul(&p.x, &D) + t0 := pr.Ext2.Double(G) // t0.Double(&G) + H := pr.Ext2.Add(E, F) // H.Add(&E, &F). + H = pr.Ext2.Sub(H, t0) // Sub(&H, &t0) + t1 := pr.Ext2.Mul(&p.Y, E) // t1.Mul(&p.y, &E) + px := pr.Ext2.Mul(L, H) // p.x.Mul(&L, &H) + py := pr.Ext2.Sub(G, H) // p.y.Sub(&G, &H). + py = pr.Ext2.Mul(py, O) // Mul(&p.y, &O). + py = pr.Ext2.Sub(py, t1) // Sub(&p.y, &t1) + pz := pr.Ext2.Mul(E, &p.Z) // p.z.Mul(&E, &p.z) + t2 := pr.Ext2.Mul(L, &a.Y) // t2.Mul(&L, &a.Y) + J := pr.Ext2.Mul(&a.X, O) // J.Mul(&a.X, &O). + J = pr.Ext2.Sub(J, t2) // Sub(&J, &t2) + ev0 := L // evaluations.r0.Set(&L) + ev1 := pr.Ext2.Neg(O) // evaluations.r1.Neg(&O) + ev2 := J // evaluations.r2.Set(&J) + return &g2Projective{ + X: *px, + Y: *py, + Z: *pz, + }, &lineEvaluation{ + r0: *ev0, + r1: *ev1, + r2: *ev2, + } +} + +type lineEvaluation struct { + r0 fields_bn254.E2 + r1 fields_bn254.E2 + r2 fields_bn254.E2 +} + +var loopCounter = [66]int8{ + 0, 0, 0, 1, 0, 1, 0, -1, 0, 0, -1, + 0, 0, 0, 1, 0, 0, -1, 0, -1, 0, 0, + 0, 1, 0, -1, 0, 0, 0, 0, -1, 0, 0, + 1, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, + -1, 0, 0, -1, 0, 1, 0, -1, 0, 0, 0, + -1, 0, -1, 0, 0, 0, 1, 0, -1, 0, 1, +} + +func (pr Pairing) MillerLoop(p []*G1Affine, q []*G2Affine) (*fields_bn254.GTEl, error) { + n := len(p) + if n == 0 || n != len(q) { + return nil, fmt.Errorf("invalid inputs sizes") + } + + // TODO: we have omitted filtering for infinity points. + + // projective points for Q + qProj := make([]*g2Projective, n) // qProj := make([]g2Proj, n) + qNeg := make([]*G2Affine, n) // qNeg := make([]G2Affine, n) + for k := 0; k < n; k++ { + qProj[k] = pr.affineToProjective(q[k]) // qProj[k].FromAffine(&q[k]) + qNeg[k] = pr.NegAffine(q[k]) // qNeg[k].Neg(&q[k]) + } + + var l, l0 *lineEvaluation + result := pr.Ext12.One() // var tmp, result GTEl + + // i == len(loopCounter) - 2 + for k := 0; k < n; k++ { + qProj[k], l = pr.DoubleStep(qProj[k]) // qProj[k].DoubleStep(&l) + l.r0 = *pr.Ext12.Ext2.MulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) + l.r1 = *pr.Ext12.Ext2.MulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) + result = pr.Ext12.MulBy034(result, &l.r0, &l.r1, &l.r2) // result.MulBy034(&l.r0, &l.r1, &l.r2) + } + + for i := len(loopCounter) - 3; i >= 0; i-- { + result = pr.Ext12.Square(result) // result.Square(&result) + + for k := 0; k < n; k++ { + qProj[k], l = pr.DoubleStep(qProj[k]) // qProj[k].DoubleStep(&l) + l.r0 = *pr.Ext12.Ext2.MulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) + l.r1 = *pr.Ext12.Ext2.MulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) + + if loopCounter[i] == 1 { + qProj[k], l0 = pr.AddStep(qProj[k], q[k]) // qProj[k].AddMixedStep(&l0, &q[k]) + l0.r0 = *pr.Ext12.Ext2.MulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) + l0.r1 = *pr.Ext12.Ext2.MulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) + tmp := pr.Ext12.MulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result = pr.Ext12.Mul(result, tmp) // result.Mul(&result, &tmp) + } else if loopCounter[i] == -1 { + qProj[k], l0 = pr.AddStep(qProj[k], qNeg[k]) // qProj[k].AddMixedStep(&l0, &qNeg[k]) + l0.r0 = *pr.Ext12.Ext2.MulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) + l0.r1 = *pr.Ext12.Ext2.MulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) + tmp := pr.Ext12.MulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result = pr.Ext12.Mul(result, tmp) //result.Mul(&result, &tmp) + } else { + result = pr.Ext12.MulBy034(result, &l.r0, &l.r1, &l.r2) // result.MulBy034(&l.r0, &l.r1, &l.r2) + } + } + } + + Q1, Q2 := new(G2Affine), new(G2Affine) // var Q1, Q2 G2Affine + for k := 0; k < n; k++ { + //Q1 = π(Q) + // TODO(ivokub): define phi(Q) in G2 instead of doing manually? + Q1.X = *pr.Ext12.Ext2.Conjugate(&q[k].X) // Q1.X.Conjugate(&q[k].X).MulByNonResidue1Power2(&Q1.X) + Q1.X = *pr.Ext12.Ext2.MulByNonResidue1Power2(&Q1.X) // Q1.X.Conjugate(&q[k].X).MulByNonResidue1Power2(&Q1.X) + Q1.Y = *pr.Ext12.Ext2.Conjugate(&q[k].Y) // Q1.Y.Conjugate(&q[k].Y).MulByNonResidue1Power3(&Q1.Y) + Q1.Y = *pr.Ext12.Ext2.MulByNonResidue1Power3(&Q1.Y) // Q1.Y.Conjugate(&q[k].Y).MulByNonResidue1Power3(&Q1.Y) + + // Q2 = -π²(Q) + Q2.X = *pr.Ext12.Ext2.MulByNonResidue2Power2(&q[k].X) // Q2.X.MulByNonResidufields_bn254.E2Power2(&q[k].X) + Q2.Y = *pr.Ext12.Ext2.MulByNonResidue2Power3(&q[k].Y) // Q2.Y.MulByNonResidufields_bn254.E2Power3(&q[k].Y).Neg(&Q2.Y) + Q2.Y = *pr.Ext12.Ext2.Neg(&Q2.Y) // Q2.Y.MulByNonResidufields_bn254.E2Power3(&q[k].Y).Neg(&Q2.Y) + + qProj[k], l0 = pr.AddStep(qProj[k], Q1) // qProj[k].AddMixedStep(&l0, &Q1) + l0.r0 = *pr.Ext12.Ext2.MulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) + l0.r1 = *pr.Ext12.Ext2.MulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) + + qProj[k], l = pr.AddStep(qProj[k], Q2) // qProj[k].AddMixedStep(&l, &Q2) + l.r0 = *pr.Ext12.Ext2.MulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) + l.r1 = *pr.Ext12.Ext2.MulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) + tmp := pr.Ext12.MulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result = pr.Ext12.Mul(result, tmp) // result.Mul(&result, &tmp) + } + + return result, nil +} + +func (pr Pairing) FinalExponentiation(e *fields_bn254.GTEl) *fields_bn254.GTEl { + // var result GT + // result.Set(z) + var t [4]*fields_bn254.GTEl // var t [4]GT + + // easy part + t[0] = pr.Ext12.Conjugate(e) // t[0].Conjugate(&result) + result := pr.Ext12.Inverse(e) // result.Inverse(&result) + t[0] = pr.Ext12.Mul(t[0], result) // t[0].Mul(&t[0], &result) + result = pr.Ext12.FrobeniusSquare(t[0]) // result.FrobeniusSquare(&t[0]). + result = pr.Ext12.Mul(result, t[0]) // Mul(&result, &t[0]) + + //hard part + t[0] = pr.Ext12.Expt(result) // t[0].Expt(&result). + t[0] = pr.Ext12.Conjugate(t[0]) // Conjugate(&t[0]) + t[0] = pr.Ext12.CyclotomicSquare(t[0]) // t[0].CyclotomicSquare(&t[0]) + t[2] = pr.Ext12.Expt(t[0]) // t[2].Expt(&t[0]). + t[2] = pr.Ext12.Conjugate(t[2]) // Conjugate(&t[2]) + t[1] = pr.Ext12.CyclotomicSquare(t[2]) // t[1].CyclotomicSquare(&t[2]) + t[2] = pr.Ext12.Mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) + t[2] = pr.Ext12.Mul(t[2], result) // t[2].Mul(&t[2], &result) + t[1] = pr.Ext12.Expt(t[2]) // t[1].Expt(&t[2]). + t[1] = pr.Ext12.CyclotomicSquare(t[1]) // CyclotomicSquare(&t[1]). + t[1] = pr.Ext12.Mul(t[1], t[2]) // Mul(&t[1], &t[2]). + t[1] = pr.Ext12.Conjugate(t[1]) // Conjugate(&t[1]) + t[3] = pr.Ext12.Conjugate(t[1]) // t[3].Conjugate(&t[1]) + t[1] = pr.Ext12.CyclotomicSquare(t[0]) // t[1].CyclotomicSquare(&t[0]) + t[1] = pr.Ext12.Mul(t[1], result) // t[1].Mul(&t[1], &result) + t[1] = pr.Ext12.Conjugate(t[1]) // t[1].Conjugate(&t[1]) + t[1] = pr.Ext12.Mul(t[1], t[3]) // t[1].Mul(&t[1], &t[3]) + t[0] = pr.Ext12.Mul(t[0], t[1]) // t[0].Mul(&t[0], &t[1]) + t[2] = pr.Ext12.Mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) + t[3] = pr.Ext12.FrobeniusSquare(t[1]) // t[3].FrobeniusSquare(&t[1]) + t[2] = pr.Ext12.Mul(t[2], t[3]) // t[2].Mul(&t[2], &t[3]) + t[3] = pr.Ext12.Conjugate(result) // t[3].Conjugate(&result) + t[3] = pr.Ext12.Mul(t[3], t[0]) // t[3].Mul(&t[3], &t[0]) + t[1] = pr.Ext12.FrobeniusCube(t[3]) // t[1].FrobeniusCube(&t[3]) + t[2] = pr.Ext12.Mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) + t[1] = pr.Ext12.Frobenius(t[0]) // t[1].Frobenius(&t[0]) + t[1] = pr.Ext12.Mul(t[1], t[2]) // t[1].Mul(&t[1], &t[2]) + // result.Set(&t[1]) + return t[1] // return result +} + +func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*fields_bn254.GTEl, error) { + res, err := pr.MillerLoop(P, Q) + if err != nil { + return nil, fmt.Errorf("miller loop: %w", err) + } + res = pr.FinalExponentiation(res) + return res, nil +} + +func (pr Pairing) AssertIsEqual(x, y *fields_bn254.GTEl) { + pr.Ext12.AssertIsEqual(x, y) +} diff --git a/std/algebra/pairing_bn254/pairing_test.go b/std/algebra/emulated/sw_bn254/pairing_test.go similarity index 83% rename from std/algebra/pairing_bn254/pairing_test.go rename to std/algebra/emulated/sw_bn254/pairing_test.go index 30fddc1829..bca01b7c10 100644 --- a/std/algebra/pairing_bn254/pairing_test.go +++ b/std/algebra/emulated/sw_bn254/pairing_test.go @@ -1,4 +1,4 @@ -package pairing_bn254 +package sw_bn254 import ( "crypto/rand" @@ -8,7 +8,8 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/weierstrass" + "github.com/consensys/gnark/std/algebra/emulated/fields_bn254" + "github.com/consensys/gnark/std/algebra/emulated/sw_emulated" "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/test" ) @@ -28,9 +29,9 @@ func randomG1G2Affines(assert *test.Assert) (bn254.G1Affine, bn254.G2Affine) { } type MillerLoopCircuit struct { - InG1 weierstrass.AffinePoint[emulated.BN254Fp] + InG1 sw_emulated.AffinePoint[emulated.BN254Fp] InG2 G2Affine - Res GTEl + Res fields_bn254.GTEl } func (c *MillerLoopCircuit) Define(api frontend.API) error { @@ -42,7 +43,7 @@ func (c *MillerLoopCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("pair: %w", err) } - pairing.ext12.assertIsEqual(res, &c.Res) + pairing.Ext12.AssertIsEqual(res, &c.Res) return nil } @@ -54,15 +55,15 @@ func TestMillerLoopTestSolve(t *testing.T) { witness := MillerLoopCircuit{ InG1: NewG1Affine(p), InG2: NewG2Affine(q), - Res: NewGTEl(res), + Res: fields_bn254.NewGTEl(res), } err = test.IsSolved(&MillerLoopCircuit{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } type FinalExponentiationCircuit struct { - InGt GTEl - Res GTEl + InGt fields_bn254.GTEl + Res fields_bn254.GTEl } func (c *FinalExponentiationCircuit) Define(api frontend.API) error { @@ -71,7 +72,7 @@ func (c *FinalExponentiationCircuit) Define(api frontend.API) error { return fmt.Errorf("new pairing: %w", err) } res := pairing.FinalExponentiation(&c.InGt) - pairing.ext12.assertIsEqual(res, &c.Res) + pairing.Ext12.AssertIsEqual(res, &c.Res) return nil } @@ -81,8 +82,8 @@ func TestFinalExponentiationTestSolve(t *testing.T) { gt.SetRandom() res := bn254.FinalExponentiation(>) witness := FinalExponentiationCircuit{ - InGt: NewGTEl(gt), - Res: NewGTEl(res), + InGt: fields_bn254.NewGTEl(gt), + Res: fields_bn254.NewGTEl(res), } err := test.IsSolved(&FinalExponentiationCircuit{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) @@ -91,7 +92,7 @@ func TestFinalExponentiationTestSolve(t *testing.T) { type PairCircuit struct { InG1 G1Affine InG2 G2Affine - Res GTEl + Res fields_bn254.GTEl } func (c *PairCircuit) Define(api frontend.API) error { @@ -103,7 +104,7 @@ func (c *PairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("pair: %w", err) } - pairing.ext12.assertIsEqual(res, &c.Res) + pairing.Ext12.AssertIsEqual(res, &c.Res) return nil } @@ -115,7 +116,7 @@ func TestPairTestSolve(t *testing.T) { witness := PairCircuit{ InG1: NewG1Affine(p), InG2: NewG2Affine(q), - Res: NewGTEl(res), + Res: fields_bn254.NewGTEl(res), } err = test.IsSolved(&PairCircuit{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) diff --git a/std/algebra/weierstrass/doc.go b/std/algebra/emulated/sw_emulated/doc.go similarity index 94% rename from std/algebra/weierstrass/doc.go rename to std/algebra/emulated/sw_emulated/doc.go index 72ff229dad..0bc7a2bcba 100644 --- a/std/algebra/weierstrass/doc.go +++ b/std/algebra/emulated/sw_emulated/doc.go @@ -1,5 +1,5 @@ /* -Package weierstrass implements elliptic curve group operations in (short) +Package sw_emulated implements elliptic curve group operations in (short) Weierstrass form. The elliptic curve is the set of points (X,Y) satisfying the equation: @@ -30,4 +30,4 @@ approach is the extreme cost of the operations. In R1CS, point addition on 4300 constraints. A full scalar multiplication is approximately 2M constraints. It is several times more in PLONKish aritmetisation. */ -package weierstrass +package sw_emulated diff --git a/std/algebra/weierstrass/doc_test.go b/std/algebra/emulated/sw_emulated/doc_test.go similarity index 89% rename from std/algebra/weierstrass/doc_test.go rename to std/algebra/emulated/sw_emulated/doc_test.go index cfa81a1fe0..3ceb577bf9 100644 --- a/std/algebra/weierstrass/doc_test.go +++ b/std/algebra/emulated/sw_emulated/doc_test.go @@ -1,4 +1,4 @@ -package weierstrass_test +package sw_emulated_test import ( "fmt" @@ -9,16 +9,16 @@ import ( "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/std/algebra/weierstrass" + "github.com/consensys/gnark/std/algebra/sw_emulated" "github.com/consensys/gnark/std/math/emulated" ) type ExampleCurveCircuit[Base, Scalar emulated.FieldParams] struct { - Res weierstrass.AffinePoint[Base] + Res sw_emulated.AffinePoint[Base] } func (c *ExampleCurveCircuit[B, S]) Define(api frontend.API) error { - curve, err := weierstrass.New[B, S](api, weierstrass.GetCurveParams[emulated.BN254Fp]()) + curve, err := sw_emulated.New[B, S](api, sw_emulated.GetCurveParams[emulated.BN254Fp]()) if err != nil { panic("initalize new curve") } @@ -41,7 +41,7 @@ func ExampleCurve() { circuit := ExampleCurveCircuit[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{} witness := ExampleCurveCircuit[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ - Res: weierstrass.AffinePoint[emulated.Secp256k1Fp]{ + Res: sw_emulated.AffinePoint[emulated.Secp256k1Fp]{ X: emulated.ValueOf[emulated.Secp256k1Fp](g.X), Y: emulated.ValueOf[emulated.Secp256k1Fp](g.Y), }, diff --git a/std/algebra/weierstrass/params.go b/std/algebra/emulated/sw_emulated/params.go similarity index 98% rename from std/algebra/weierstrass/params.go rename to std/algebra/emulated/sw_emulated/params.go index aadf2bce6a..e347d20637 100644 --- a/std/algebra/weierstrass/params.go +++ b/std/algebra/emulated/sw_emulated/params.go @@ -1,4 +1,4 @@ -package weierstrass +package sw_emulated import ( "math/big" diff --git a/std/algebra/weierstrass/point.go b/std/algebra/emulated/sw_emulated/point.go similarity index 99% rename from std/algebra/weierstrass/point.go rename to std/algebra/emulated/sw_emulated/point.go index 8c91ed2761..34b922b5a1 100644 --- a/std/algebra/weierstrass/point.go +++ b/std/algebra/emulated/sw_emulated/point.go @@ -1,4 +1,4 @@ -package weierstrass +package sw_emulated import ( "fmt" diff --git a/std/algebra/weierstrass/point_test.go b/std/algebra/emulated/sw_emulated/point_test.go similarity index 99% rename from std/algebra/weierstrass/point_test.go rename to std/algebra/emulated/sw_emulated/point_test.go index 28faf42109..d7b66dd450 100644 --- a/std/algebra/weierstrass/point_test.go +++ b/std/algebra/emulated/sw_emulated/point_test.go @@ -1,4 +1,4 @@ -package weierstrass +package sw_emulated import ( "math/big" diff --git a/std/algebra/fields_bls12377/e12.go b/std/algebra/native/fields_bls12377/e12.go similarity index 100% rename from std/algebra/fields_bls12377/e12.go rename to std/algebra/native/fields_bls12377/e12.go diff --git a/std/algebra/fields_bls12377/e12_test.go b/std/algebra/native/fields_bls12377/e12_test.go similarity index 100% rename from std/algebra/fields_bls12377/e12_test.go rename to std/algebra/native/fields_bls12377/e12_test.go diff --git a/std/algebra/fields_bls12377/e2.go b/std/algebra/native/fields_bls12377/e2.go similarity index 100% rename from std/algebra/fields_bls12377/e2.go rename to std/algebra/native/fields_bls12377/e2.go diff --git a/std/algebra/fields_bls12377/e2_test.go b/std/algebra/native/fields_bls12377/e2_test.go similarity index 100% rename from std/algebra/fields_bls12377/e2_test.go rename to std/algebra/native/fields_bls12377/e2_test.go diff --git a/std/algebra/fields_bls12377/e6.go b/std/algebra/native/fields_bls12377/e6.go similarity index 100% rename from std/algebra/fields_bls12377/e6.go rename to std/algebra/native/fields_bls12377/e6.go diff --git a/std/algebra/fields_bls12377/e6_test.go b/std/algebra/native/fields_bls12377/e6_test.go similarity index 100% rename from std/algebra/fields_bls12377/e6_test.go rename to std/algebra/native/fields_bls12377/e6_test.go diff --git a/std/algebra/fields_bls24315/e12.go b/std/algebra/native/fields_bls24315/e12.go similarity index 100% rename from std/algebra/fields_bls24315/e12.go rename to std/algebra/native/fields_bls24315/e12.go diff --git a/std/algebra/fields_bls24315/e12_test.go b/std/algebra/native/fields_bls24315/e12_test.go similarity index 100% rename from std/algebra/fields_bls24315/e12_test.go rename to std/algebra/native/fields_bls24315/e12_test.go diff --git a/std/algebra/fields_bls24315/e2.go b/std/algebra/native/fields_bls24315/e2.go similarity index 100% rename from std/algebra/fields_bls24315/e2.go rename to std/algebra/native/fields_bls24315/e2.go diff --git a/std/algebra/fields_bls24315/e24.go b/std/algebra/native/fields_bls24315/e24.go similarity index 100% rename from std/algebra/fields_bls24315/e24.go rename to std/algebra/native/fields_bls24315/e24.go diff --git a/std/algebra/fields_bls24315/e24_test.go b/std/algebra/native/fields_bls24315/e24_test.go similarity index 100% rename from std/algebra/fields_bls24315/e24_test.go rename to std/algebra/native/fields_bls24315/e24_test.go diff --git a/std/algebra/fields_bls24315/e2_test.go b/std/algebra/native/fields_bls24315/e2_test.go similarity index 100% rename from std/algebra/fields_bls24315/e2_test.go rename to std/algebra/native/fields_bls24315/e2_test.go diff --git a/std/algebra/fields_bls24315/e4.go b/std/algebra/native/fields_bls24315/e4.go similarity index 100% rename from std/algebra/fields_bls24315/e4.go rename to std/algebra/native/fields_bls24315/e4.go diff --git a/std/algebra/fields_bls24315/e4_test.go b/std/algebra/native/fields_bls24315/e4_test.go similarity index 100% rename from std/algebra/fields_bls24315/e4_test.go rename to std/algebra/native/fields_bls24315/e4_test.go diff --git a/std/algebra/sw_bls12377/doc.go b/std/algebra/native/sw_bls12377/doc.go similarity index 100% rename from std/algebra/sw_bls12377/doc.go rename to std/algebra/native/sw_bls12377/doc.go diff --git a/std/algebra/sw_bls12377/g1.go b/std/algebra/native/sw_bls12377/g1.go similarity index 100% rename from std/algebra/sw_bls12377/g1.go rename to std/algebra/native/sw_bls12377/g1.go diff --git a/std/algebra/sw_bls12377/g1_test.go b/std/algebra/native/sw_bls12377/g1_test.go similarity index 100% rename from std/algebra/sw_bls12377/g1_test.go rename to std/algebra/native/sw_bls12377/g1_test.go diff --git a/std/algebra/sw_bls12377/g2.go b/std/algebra/native/sw_bls12377/g2.go similarity index 99% rename from std/algebra/sw_bls12377/g2.go rename to std/algebra/native/sw_bls12377/g2.go index fcfcdbcf20..b384668d81 100644 --- a/std/algebra/sw_bls12377/g2.go +++ b/std/algebra/native/sw_bls12377/g2.go @@ -23,7 +23,7 @@ import ( bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377" "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/fields_bls12377" + "github.com/consensys/gnark/std/algebra/native/fields_bls12377" ) // G2Jac point in Jacobian coords diff --git a/std/algebra/sw_bls12377/g2_test.go b/std/algebra/native/sw_bls12377/g2_test.go similarity index 100% rename from std/algebra/sw_bls12377/g2_test.go rename to std/algebra/native/sw_bls12377/g2_test.go diff --git a/std/algebra/sw_bls12377/inner.go b/std/algebra/native/sw_bls12377/inner.go similarity index 100% rename from std/algebra/sw_bls12377/inner.go rename to std/algebra/native/sw_bls12377/inner.go diff --git a/std/algebra/sw_bls12377/pairing.go b/std/algebra/native/sw_bls12377/pairing.go similarity index 98% rename from std/algebra/sw_bls12377/pairing.go rename to std/algebra/native/sw_bls12377/pairing.go index 7ca86131e7..c0e4bfef68 100644 --- a/std/algebra/sw_bls12377/pairing.go +++ b/std/algebra/native/sw_bls12377/pairing.go @@ -21,7 +21,7 @@ import ( "math/big" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/fields_bls12377" + "github.com/consensys/gnark/std/algebra/native/fields_bls12377" ) // GT target group of the pairing diff --git a/std/algebra/sw_bls12377/pairing_test.go b/std/algebra/native/sw_bls12377/pairing_test.go similarity index 98% rename from std/algebra/sw_bls12377/pairing_test.go rename to std/algebra/native/sw_bls12377/pairing_test.go index bf09b6efad..dbe5639919 100644 --- a/std/algebra/sw_bls12377/pairing_test.go +++ b/std/algebra/native/sw_bls12377/pairing_test.go @@ -25,7 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/std/algebra/fields_bls12377" + "github.com/consensys/gnark/std/algebra/native/fields_bls12377" "github.com/consensys/gnark/test" ) diff --git a/std/algebra/sw_bls24315/doc.go b/std/algebra/native/sw_bls24315/doc.go similarity index 100% rename from std/algebra/sw_bls24315/doc.go rename to std/algebra/native/sw_bls24315/doc.go diff --git a/std/algebra/sw_bls24315/g1.go b/std/algebra/native/sw_bls24315/g1.go similarity index 100% rename from std/algebra/sw_bls24315/g1.go rename to std/algebra/native/sw_bls24315/g1.go diff --git a/std/algebra/sw_bls24315/g1_test.go b/std/algebra/native/sw_bls24315/g1_test.go similarity index 100% rename from std/algebra/sw_bls24315/g1_test.go rename to std/algebra/native/sw_bls24315/g1_test.go diff --git a/std/algebra/sw_bls24315/g2.go b/std/algebra/native/sw_bls24315/g2.go similarity index 99% rename from std/algebra/sw_bls24315/g2.go rename to std/algebra/native/sw_bls24315/g2.go index 001fe45f5d..f2d7729a37 100644 --- a/std/algebra/sw_bls24315/g2.go +++ b/std/algebra/native/sw_bls24315/g2.go @@ -23,7 +23,7 @@ import ( bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315" "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/fields_bls24315" + "github.com/consensys/gnark/std/algebra/native/fields_bls24315" ) // G2Jac point in Jacobian coords diff --git a/std/algebra/sw_bls24315/g2_test.go b/std/algebra/native/sw_bls24315/g2_test.go similarity index 100% rename from std/algebra/sw_bls24315/g2_test.go rename to std/algebra/native/sw_bls24315/g2_test.go diff --git a/std/algebra/sw_bls24315/inner.go b/std/algebra/native/sw_bls24315/inner.go similarity index 100% rename from std/algebra/sw_bls24315/inner.go rename to std/algebra/native/sw_bls24315/inner.go diff --git a/std/algebra/sw_bls24315/pairing.go b/std/algebra/native/sw_bls24315/pairing.go similarity index 98% rename from std/algebra/sw_bls24315/pairing.go rename to std/algebra/native/sw_bls24315/pairing.go index b1e1fb11e0..57b4b8e928 100644 --- a/std/algebra/sw_bls24315/pairing.go +++ b/std/algebra/native/sw_bls24315/pairing.go @@ -22,7 +22,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/fields_bls24315" + "github.com/consensys/gnark/std/algebra/native/fields_bls24315" ) // GT target group of the pairing diff --git a/std/algebra/sw_bls24315/pairing_test.go b/std/algebra/native/sw_bls24315/pairing_test.go similarity index 98% rename from std/algebra/sw_bls24315/pairing_test.go rename to std/algebra/native/sw_bls24315/pairing_test.go index c7bb53b4a5..44233d888d 100644 --- a/std/algebra/sw_bls24315/pairing_test.go +++ b/std/algebra/native/sw_bls24315/pairing_test.go @@ -25,7 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/std/algebra/fields_bls24315" + "github.com/consensys/gnark/std/algebra/native/fields_bls24315" "github.com/consensys/gnark/test" ) diff --git a/std/algebra/twistededwards/curve.go b/std/algebra/native/twistededwards/curve.go similarity index 100% rename from std/algebra/twistededwards/curve.go rename to std/algebra/native/twistededwards/curve.go diff --git a/std/algebra/twistededwards/curve_test.go b/std/algebra/native/twistededwards/curve_test.go similarity index 100% rename from std/algebra/twistededwards/curve_test.go rename to std/algebra/native/twistededwards/curve_test.go diff --git a/std/algebra/twistededwards/point.go b/std/algebra/native/twistededwards/point.go similarity index 100% rename from std/algebra/twistededwards/point.go rename to std/algebra/native/twistededwards/point.go diff --git a/std/algebra/twistededwards/scalarmul_glv.go b/std/algebra/native/twistededwards/scalarmul_glv.go similarity index 100% rename from std/algebra/twistededwards/scalarmul_glv.go rename to std/algebra/native/twistededwards/scalarmul_glv.go diff --git a/std/algebra/twistededwards/twistededwards.go b/std/algebra/native/twistededwards/twistededwards.go similarity index 100% rename from std/algebra/twistededwards/twistededwards.go rename to std/algebra/native/twistededwards/twistededwards.go diff --git a/std/algebra/pairing_bn254/gt.go b/std/algebra/pairing_bn254/gt.go deleted file mode 100644 index 2b84c9f0ed..0000000000 --- a/std/algebra/pairing_bn254/gt.go +++ /dev/null @@ -1,41 +0,0 @@ -package pairing_bn254 - -import ( - "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark/std/math/emulated" -) - -type GTEl = e12 - -func NewGTEl(v bn254.GT) GTEl { - return GTEl{ - C0: e6{ - B0: e2{ - A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B0.A0), - A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B0.A1), - }, - B1: e2{ - A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B1.A0), - A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B1.A1), - }, - B2: e2{ - A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B2.A0), - A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B2.A1), - }, - }, - C1: e6{ - B0: e2{ - A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B0.A0), - A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B0.A1), - }, - B1: e2{ - A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B1.A0), - A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B1.A1), - }, - B2: e2{ - A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B2.A0), - A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B2.A1), - }, - }, - } -} diff --git a/std/algebra/pairing_bn254/pairing.go b/std/algebra/pairing_bn254/pairing.go deleted file mode 100644 index ec0baa633b..0000000000 --- a/std/algebra/pairing_bn254/pairing.go +++ /dev/null @@ -1,282 +0,0 @@ -package pairing_bn254 - -import ( - "fmt" - - "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/math/emulated" -) - -type Pairing struct { - *ext12 -} - -func NewPairing(api frontend.API) (*Pairing, error) { - ba, err := emulated.NewField[emulated.BN254Fp](api) - if err != nil { - return nil, fmt.Errorf("new base api: %w", err) - } - return &Pairing{ - ext12: newExt12(ba), - }, nil -} - -func (pr Pairing) doubleStep(p *g2Projective) (*g2Projective, *lineEvaluation) { - // var t1, A, B, C, D, E, EE, F, G, H, I, J, K fptower.E2 - A := pr.ext2.mul(&p.X, &p.Y) // A.Mul(&p.x, &p.y) - A = pr.ext2.halve(A) // A.Halve() - B := pr.ext2.square(&p.Y) // B.Square(&p.y) - C := pr.ext2.square(&p.Z) // C.Square(&p.z) - D := pr.ext2.double(C) // D.Double(&C). - D = pr.ext2.add(D, C) // Add(&D, &C) - E := pr.ext2.mulBybTwistCurveCoeff(D) // E.MulBybTwistCurveCoeff(&D) - F := pr.ext2.double(E) // F.Double(&E). - F = pr.ext2.add(F, E) // Add(&F, &E) - G := pr.ext2.add(B, F) // G.Add(&B, &F) - G = pr.ext2.halve(G) // G.Halve() - H := pr.ext2.add(&p.Y, &p.Z) // H.Add(&p.y, &p.z). - H = pr.ext2.square(H) // Square(&H) - t1 := pr.ext2.add(B, C) // t1.Add(&B, &C) - H = pr.ext2.sub(H, t1) // H.Sub(&H, &t1) - I := pr.ext2.sub(E, B) // I.Sub(&E, &B) - J := pr.ext2.square(&p.X) // J.Square(&p.x) - EE := pr.ext2.square(E) // EE.Square(&E) - K := pr.ext2.double(EE) // K.Double(&EE). - K = pr.ext2.add(K, EE) // Add(&K, &EE) - px := pr.ext2.sub(B, F) // p.x.Sub(&B, &F). - px = pr.ext2.mul(px, A) // Mul(&p.x, &A) - py := pr.ext2.square(G) // p.y.Square(&G). - py = pr.ext2.sub(py, K) // Sub(&p.y, &K) - pz := pr.ext2.mul(B, H) // p.z.Mul(&B, &H) - ev0 := pr.ext2.neg(H) // evaluations.r0.Neg(&H) - ev1 := pr.ext2.double(J) // evaluations.r1.Double(&J). - ev1 = pr.ext2.add(ev1, J) // Add(&evaluations.r1, &J) - ev2 := I // evaluations.r2.Set(&I) - return &g2Projective{ - X: *px, - Y: *py, - Z: *pz, - }, - &lineEvaluation{ - r0: *ev0, - r1: *ev1, - r2: *ev2, - } -} - -func (pr Pairing) affineToProjective(Q *G2Affine) *g2Projective { - // TODO: check point at infinity? We do not filter them in the Miller Loop neither. - // if Q.X.IsZero() && Q.Y.IsZero() { - // p.z.SetZero() - // p.x.SetOne() - // p.y.SetOne() - // return p - // } - pz := pr.ext2.one() // p.z.SetOne() - px := &Q.X // p.x.Set(&Q.X) - py := &Q.Y // p.y.Set(&Q.Y) - return &g2Projective{ // return p - X: *px, - Y: *py, - Z: *pz, - } -} - -func (pr Pairing) negAffine(a *G2Affine) *G2Affine { - px := &a.X // p.X = a.X - py := pr.ext2.neg(&a.Y) // p.Y.Neg(&a.Y) - return &G2Affine{ // return p - X: *px, - Y: *py, - } -} - -func (pr Pairing) addStep(p *g2Projective, a *G2Affine) (*g2Projective, *lineEvaluation) { - // var Y2Z1, X2Z1, O, L, C, D, E, F, G, H, t0, t1, t2, J fptower.E2 - Y2Z1 := pr.ext2.mul(&a.Y, &p.Z) // Y2Z1.Mul(&a.Y, &p.z) - O := pr.ext2.sub(&p.Y, Y2Z1) // O.Sub(&p.y, &Y2Z1) - X2Z1 := pr.ext2.mul(&a.X, &p.Z) // X2Z1.Mul(&a.X, &p.z) - L := pr.ext2.sub(&p.X, X2Z1) // L.Sub(&p.x, &X2Z1) - C := pr.ext2.square(O) // C.Square(&O) - D := pr.ext2.square(L) // D.Square(&L) - E := pr.ext2.mul(L, D) // E.Mul(&L, &D) - F := pr.ext2.mul(&p.Z, C) // F.Mul(&p.z, &C) - G := pr.ext2.mul(&p.X, D) // G.Mul(&p.x, &D) - t0 := pr.ext2.double(G) // t0.Double(&G) - H := pr.ext2.add(E, F) // H.Add(&E, &F). - H = pr.ext2.sub(H, t0) // Sub(&H, &t0) - t1 := pr.ext2.mul(&p.Y, E) // t1.Mul(&p.y, &E) - px := pr.ext2.mul(L, H) // p.x.Mul(&L, &H) - py := pr.ext2.sub(G, H) // p.y.Sub(&G, &H). - py = pr.ext2.mul(py, O) // Mul(&p.y, &O). - py = pr.ext2.sub(py, t1) // Sub(&p.y, &t1) - pz := pr.ext2.mul(E, &p.Z) // p.z.Mul(&E, &p.z) - t2 := pr.ext2.mul(L, &a.Y) // t2.Mul(&L, &a.Y) - J := pr.ext2.mul(&a.X, O) // J.Mul(&a.X, &O). - J = pr.ext2.sub(J, t2) // Sub(&J, &t2) - ev0 := L // evaluations.r0.Set(&L) - ev1 := pr.ext2.neg(O) // evaluations.r1.Neg(&O) - ev2 := J // evaluations.r2.Set(&J) - return &g2Projective{ - X: *px, - Y: *py, - Z: *pz, - }, &lineEvaluation{ - r0: *ev0, - r1: *ev1, - r2: *ev2, - } -} - -type lineEvaluation struct { - r0 e2 - r1 e2 - r2 e2 -} - -var loopCounter = [66]int8{ - 0, 0, 0, 1, 0, 1, 0, -1, 0, 0, -1, - 0, 0, 0, 1, 0, 0, -1, 0, -1, 0, 0, - 0, 1, 0, -1, 0, 0, 0, 0, -1, 0, 0, - 1, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, - -1, 0, 0, -1, 0, 1, 0, -1, 0, 0, 0, - -1, 0, -1, 0, 0, 0, 1, 0, -1, 0, 1, -} - -func (pr Pairing) MillerLoop(p []*G1Affine, q []*G2Affine) (*GTEl, error) { - n := len(p) - if n == 0 || n != len(q) { - return nil, fmt.Errorf("invalid inputs sizes") - } - - // TODO: we have omitted filtering for infinity points. - - // projective points for Q - qProj := make([]*g2Projective, n) // qProj := make([]g2Proj, n) - qNeg := make([]*G2Affine, n) // qNeg := make([]G2Affine, n) - for k := 0; k < n; k++ { - qProj[k] = pr.affineToProjective(q[k]) // qProj[k].FromAffine(&q[k]) - qNeg[k] = pr.negAffine(q[k]) // qNeg[k].Neg(&q[k]) - } - - var l, l0 *lineEvaluation - result := pr.ext12.one() // var tmp, result GTEl - - // i == len(loopCounter) - 2 - for k := 0; k < n; k++ { - qProj[k], l = pr.doubleStep(qProj[k]) // qProj[k].DoubleStep(&l) - l.r0 = *pr.ext12.ext2.mulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1 = *pr.ext12.ext2.mulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) - result = pr.ext12.mulBy034(result, &l.r0, &l.r1, &l.r2) // result.MulBy034(&l.r0, &l.r1, &l.r2) - } - - for i := len(loopCounter) - 3; i >= 0; i-- { - result = pr.ext12.square(result) // result.Square(&result) - - for k := 0; k < n; k++ { - qProj[k], l = pr.doubleStep(qProj[k]) // qProj[k].DoubleStep(&l) - l.r0 = *pr.ext12.ext2.mulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1 = *pr.ext12.ext2.mulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) - - if loopCounter[i] == 1 { - qProj[k], l0 = pr.addStep(qProj[k], q[k]) // qProj[k].AddMixedStep(&l0, &q[k]) - l0.r0 = *pr.ext12.ext2.mulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) - l0.r1 = *pr.ext12.ext2.mulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) - tmp := pr.ext12.mulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result = pr.ext12.mul(result, tmp) // result.Mul(&result, &tmp) - } else if loopCounter[i] == -1 { - qProj[k], l0 = pr.addStep(qProj[k], qNeg[k]) // qProj[k].AddMixedStep(&l0, &qNeg[k]) - l0.r0 = *pr.ext12.ext2.mulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) - l0.r1 = *pr.ext12.ext2.mulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) - tmp := pr.ext12.mulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result = pr.ext12.mul(result, tmp) //result.Mul(&result, &tmp) - } else { - result = pr.ext12.mulBy034(result, &l.r0, &l.r1, &l.r2) // result.MulBy034(&l.r0, &l.r1, &l.r2) - } - } - } - - Q1, Q2 := new(G2Affine), new(G2Affine) // var Q1, Q2 G2Affine - for k := 0; k < n; k++ { - //Q1 = π(Q) - // TODO(ivokub): define phi(Q) in G2 instead of doing manually? - Q1.X = *pr.ext12.ext2.conjugate(&q[k].X) // Q1.X.Conjugate(&q[k].X).MulByNonResidue1Power2(&Q1.X) - Q1.X = *pr.ext12.ext2.mulByNonResidue1Power2(&Q1.X) // Q1.X.Conjugate(&q[k].X).MulByNonResidue1Power2(&Q1.X) - Q1.Y = *pr.ext12.ext2.conjugate(&q[k].Y) // Q1.Y.Conjugate(&q[k].Y).MulByNonResidue1Power3(&Q1.Y) - Q1.Y = *pr.ext12.ext2.mulByNonResidue1Power3(&Q1.Y) // Q1.Y.Conjugate(&q[k].Y).MulByNonResidue1Power3(&Q1.Y) - - // Q2 = -π²(Q) - Q2.X = *pr.ext12.ext2.mulByNonResidue2Power2(&q[k].X) // Q2.X.MulByNonResidue2Power2(&q[k].X) - Q2.Y = *pr.ext12.ext2.mulByNonResidue2Power3(&q[k].Y) // Q2.Y.MulByNonResidue2Power3(&q[k].Y).Neg(&Q2.Y) - Q2.Y = *pr.ext12.ext2.neg(&Q2.Y) // Q2.Y.MulByNonResidue2Power3(&q[k].Y).Neg(&Q2.Y) - - qProj[k], l0 = pr.addStep(qProj[k], Q1) // qProj[k].AddMixedStep(&l0, &Q1) - l0.r0 = *pr.ext12.ext2.mulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) - l0.r1 = *pr.ext12.ext2.mulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) - - qProj[k], l = pr.addStep(qProj[k], Q2) // qProj[k].AddMixedStep(&l, &Q2) - l.r0 = *pr.ext12.ext2.mulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1 = *pr.ext12.ext2.mulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) - tmp := pr.ext12.mulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result = pr.ext12.mul(result, tmp) // result.Mul(&result, &tmp) - } - - return result, nil -} - -func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { - // var result GT - // result.Set(z) - var t [4]*GTEl // var t [4]GT - - // easy part - t[0] = pr.ext12.conjugate(e) // t[0].Conjugate(&result) - result := pr.ext12.inverse(e) // result.Inverse(&result) - t[0] = pr.ext12.mul(t[0], result) // t[0].Mul(&t[0], &result) - result = pr.ext12.frobeniusSquare(t[0]) // result.FrobeniusSquare(&t[0]). - result = pr.ext12.mul(result, t[0]) // Mul(&result, &t[0]) - - //hard part - t[0] = pr.ext12.expt(result) // t[0].Expt(&result). - t[0] = pr.ext12.conjugate(t[0]) // Conjugate(&t[0]) - t[0] = pr.ext12.cyclotomicSquare(t[0]) // t[0].CyclotomicSquare(&t[0]) - t[2] = pr.ext12.expt(t[0]) // t[2].Expt(&t[0]). - t[2] = pr.ext12.conjugate(t[2]) // Conjugate(&t[2]) - t[1] = pr.ext12.cyclotomicSquare(t[2]) // t[1].CyclotomicSquare(&t[2]) - t[2] = pr.ext12.mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) - t[2] = pr.ext12.mul(t[2], result) // t[2].Mul(&t[2], &result) - t[1] = pr.ext12.expt(t[2]) // t[1].Expt(&t[2]). - t[1] = pr.ext12.cyclotomicSquare(t[1]) // CyclotomicSquare(&t[1]). - t[1] = pr.ext12.mul(t[1], t[2]) // Mul(&t[1], &t[2]). - t[1] = pr.ext12.conjugate(t[1]) // Conjugate(&t[1]) - t[3] = pr.ext12.conjugate(t[1]) // t[3].Conjugate(&t[1]) - t[1] = pr.ext12.cyclotomicSquare(t[0]) // t[1].CyclotomicSquare(&t[0]) - t[1] = pr.ext12.mul(t[1], result) // t[1].Mul(&t[1], &result) - t[1] = pr.ext12.conjugate(t[1]) // t[1].Conjugate(&t[1]) - t[1] = pr.ext12.mul(t[1], t[3]) // t[1].Mul(&t[1], &t[3]) - t[0] = pr.ext12.mul(t[0], t[1]) // t[0].Mul(&t[0], &t[1]) - t[2] = pr.ext12.mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) - t[3] = pr.ext12.frobeniusSquare(t[1]) // t[3].FrobeniusSquare(&t[1]) - t[2] = pr.ext12.mul(t[2], t[3]) // t[2].Mul(&t[2], &t[3]) - t[3] = pr.ext12.conjugate(result) // t[3].Conjugate(&result) - t[3] = pr.ext12.mul(t[3], t[0]) // t[3].Mul(&t[3], &t[0]) - t[1] = pr.ext12.frobeniusCube(t[3]) // t[1].FrobeniusCube(&t[3]) - t[2] = pr.ext12.mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) - t[1] = pr.ext12.frobenius(t[0]) // t[1].Frobenius(&t[0]) - t[1] = pr.ext12.mul(t[1], t[2]) // t[1].Mul(&t[1], &t[2]) - // result.Set(&t[1]) - return t[1] // return result -} - -func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { - res, err := pr.MillerLoop(P, Q) - if err != nil { - return nil, fmt.Errorf("miller loop: %w", err) - } - res = pr.FinalExponentiation(res) - return res, nil -} - -func (pr Pairing) AssertIsEqual(x, y *GTEl) { - pr.ext12.assertIsEqual(x, y) -} diff --git a/std/algebra/pairing_bn254/tower.go b/std/algebra/pairing_bn254/tower.go deleted file mode 100644 index c555680885..0000000000 --- a/std/algebra/pairing_bn254/tower.go +++ /dev/null @@ -1,833 +0,0 @@ -package pairing_bn254 - -import ( - "math/big" - - "github.com/consensys/gnark/std/math/emulated" -) - -type curveF = emulated.Field[emulated.BN254Fp] -type baseEl = emulated.Element[emulated.BN254Fp] - -type e2 struct { - A0, A1 baseEl -} - -type e6 struct { - B0, B1, B2 e2 -} - -type e12 struct { - C0, C1 e6 -} - -type ext2 struct { - fp *curveF - nonResidues map[int]map[int]*e2 -} - -func newExt2(baseField *curveF) *ext2 { - pwrs := map[int]map[int]struct { - A0 string - A1 string - }{ - 0: { - -1: {"21087453498479301738505683583845423561061080261299122796980902361914303298513", "14681138511599513868579906292550611339979233093309515871315818100066920017952"}, - 1: {"9", "1"}, - }, - 1: { - 1: {"8376118865763821496583973867626364092589906065868298776909617916018768340080", "16469823323077808223889137241176536799009286646108169935659301613961712198316"}, - 2: {"21575463638280843010398324269430826099269044274347216827212613867836435027261", "10307601595873709700152284273816112264069230130616436755625194854815875713954"}, - 3: {"2821565182194536844548159561693502659359617185244120367078079554186484126554", "3505843767911556378687030309984248845540243509899259641013678093033130930403"}, - 4: {"2581911344467009335267311115468803099551665605076196740867805258568234346338", "19937756971775647987995932169929341994314640652964949448313374472400716661030"}, - 5: {"685108087231508774477564247770172212460312782337200605669322048753928464687", "8447204650696766136447902020341177575205426561248465145919723016860428151883"}, - }, - 2: { - 1: {"21888242871839275220042445260109153167277707414472061641714758635765020556617", "0"}, - 2: {"21888242871839275220042445260109153167277707414472061641714758635765020556616", "0"}, - 3: {"21888242871839275222246405745257275088696311157297823662689037894645226208582", "0"}, - 4: {"2203960485148121921418603742825762020974279258880205651966", "0"}, - 5: {"2203960485148121921418603742825762020974279258880205651967", "0"}, - }, - 3: { - 1: {"11697423496358154304825782922584725312912383441159505038794027105778954184319", "303847389135065887422783454877609941456349188919719272345083954437860409601"}, - 2: {"3772000881919853776433695186713858239009073593817195771773381919316419345261", "2236595495967245188281701248203181795121068902605861227855261137820944008926"}, - 3: {"19066677689644738377698246183563772429336693972053703295610958340458742082029", "18382399103927718843559375435273026243156067647398564021675359801612095278180"}, - 4: {"5324479202449903542726783395506214481928257762400643279780343368557297135718", "16208900380737693084919495127334387981393726419856888799917914180988844123039"}, - 5: {"8941241848238582420466759817324047081148088512956452953208002715982955420483", "10338197737521362862238855242243140895517409139741313354160881284257516364953"}, - }, - } - nonResidues := make(map[int]map[int]*e2) - for pwr, v := range pwrs { - for coeff, v := range v { - el := e2{emulated.ValueOf[emulated.BN254Fp](v.A0), emulated.ValueOf[emulated.BN254Fp](v.A1)} - if nonResidues[pwr] == nil { - nonResidues[pwr] = make(map[int]*e2) - } - nonResidues[pwr][coeff] = &el - } - } - return &ext2{fp: baseField, nonResidues: nonResidues} -} - -type ext6 struct { - *ext2 -} - -func newExt6(baseField *curveF) *ext6 { - return &ext6{ext2: newExt2(baseField)} -} - -type ext12 struct { - *ext6 -} - -func newExt12(baseField *curveF) *ext12 { - return &ext12{ext6: newExt6(baseField)} -} - -// TODO: check where to use Mod and where ModMul. - -func (e ext2) mulByElement(x *e2, y *baseEl) *e2 { - // var yCopy fp.Element - // yCopy.Set(y) - z0 := e.fp.MulMod(&x.A0, y) // z.A0.Mul(&x.A0, &yCopy) - z1 := e.fp.MulMod(&x.A1, y) // z.A1.Mul(&x.A1, &yCopy) - return &e2{ // return z - A0: *z0, - A1: *z1, - } -} - -func (e ext2) conjugate(x *e2) *e2 { - z0 := x.A0 // z.A0 = x.A0 - z1 := e.fp.Neg(&x.A1) // z.A1.Neg(&x.A1) - return &e2{ // return z - A0: z0, - A1: *z1, - } -} - -func (e ext2) mulByNonResidueGeneric(x *e2, power, coef int) *e2 { - y := e.nonResidues[power][coef] - z := e.mul(x, y) - return z -} - -func (e ext2) mulByNonResidue(x *e2) *e2 { - /* - // below is the direct transliteration of the gnark-crypto code. Now only, - // for simplicity and debugging purposes, we do the non residue operations - // without optimisations. - - nine := big.NewInt(9) - // var a, b fp.Element - a := e.fp.MulConst(&x.A0, nine) // a.Double(&x.A0).Double(&a).Double(&a).Add(&a, &x.A0). - a = e.fp.Sub(a, &x.A1) // Sub(&a, &x.A1) - b := e.fp.MulConst(&x.A1, nine) // b.Double(&x.A1).Double(&b).Double(&b).Add(&b, &x.A1). - b = e.fp.Add(b, &x.A0) // Add(&b, &x.A0) - return &E2{ - A0: *a, // z.A0.Set(&a) - A1: *b, // z.A1.Set(&b) - } // return z - */ - // TODO: inline non-residue multiplication - return e.mulByNonResidueGeneric(x, 0, 1) -} - -func (e ext2) mulByNonResidueInv(x *e2) *e2 { - // TODO: to optimise with constant non-residue inverse - /* - // from gnark-crypto - // z.Mul(x, &nonResInverse) - // return z - */ - return e.mulByNonResidueGeneric(x, 0, -1) -} - -func (e ext2) mulByNonResidue1Power1(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 1, 1) -} - -func (e ext2) mulByNonResidue1Power2(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 1, 2) -} - -func (e ext2) mulByNonResidue1Power3(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 1, 3) -} - -func (e ext2) mulByNonResidue1Power4(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 1, 4) -} - -func (e ext2) mulByNonResidue1Power5(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 1, 5) -} - -func (e ext2) mulByNonResidue2Power1(x *e2) *e2 { - // TODO: A1 is 0, we can optimize for it - return e.mulByNonResidueGeneric(x, 2, 1) -} -func (e ext2) mulByNonResidue2Power2(x *e2) *e2 { - // TODO: A1 is 0, we can optimize for it - return e.mulByNonResidueGeneric(x, 2, 2) -} - -func (e ext2) mulByNonResidue2Power3(x *e2) *e2 { - // TODO: A1 is 0, we can optimize for it - return e.mulByNonResidueGeneric(x, 2, 3) -} - -func (e ext2) mulByNonResidue2Power4(x *e2) *e2 { - // TODO: A1 is 0, we can optimize for it - return e.mulByNonResidueGeneric(x, 2, 4) -} - -func (e ext2) mulByNonResidue2Power5(x *e2) *e2 { - // TODO: A1 is 0, we can optimize for it - return e.mulByNonResidueGeneric(x, 2, 5) -} - -func (e ext2) mulByNonResidue3Power1(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 3, 1) -} - -func (e ext2) mulByNonResidue3Power2(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 3, 2) -} - -func (e ext2) mulByNonResidue3Power3(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 3, 3) -} - -func (e ext2) mulByNonResidue3Power4(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 3, 4) -} - -func (e ext2) mulByNonResidue3Power5(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 3, 5) -} - -func (e ext2) mul(x, y *e2) *e2 { - // var a, b, c fp.Element - a := e.fp.Add(&x.A0, &x.A1) // a.Add(&x.A0, &x.A1) - b := e.fp.Add(&y.A0, &y.A1) // b.Add(&y.A0, &y.A1) - a = e.fp.MulMod(a, b) // a.Mul(&a, &b) - b = e.fp.MulMod(&x.A0, &y.A0) // b.Mul(&x.A0, &y.A0) - c := e.fp.MulMod(&x.A1, &y.A1) // c.Mul(&x.A1, &y.A1) - z1 := e.fp.Sub(a, b) // z.A1.Sub(&a, &b). - z1 = e.fp.Sub(z1, c) // Sub(&z.A1, &c) - z0 := e.fp.Sub(b, c) // z.A0.Sub(&b, &c) - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) add(x, y *e2) *e2 { - z0 := e.fp.Add(&x.A0, &y.A0) // z.A0.Add(&x.A0, &y.A0) - z1 := e.fp.Add(&x.A1, &y.A1) // z.A1.Add(&x.A1, &y.A1) - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) sub(x, y *e2) *e2 { - z0 := e.fp.Sub(&x.A0, &y.A0) // z.A0.Sub(&x.A0, &y.A0) - z1 := e.fp.Sub(&x.A1, &y.A1) // z.A1.Sub(&x.A1, &y.A1) - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) neg(x *e2) *e2 { - z0 := e.fp.Neg(&x.A0) // z.A0.Neg(&x.A0) - z1 := e.fp.Neg(&x.A1) // z.A1.Neg(&x.A1) - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) one() *e2 { - z0 := e.fp.One() // z.A0.SetOne() - z1 := e.fp.Zero() // z.A1.SetZero() - return &e2{ // return z - A0: *z0, - A1: *z1, - } -} - -func (e ext2) zero() *e2 { - z0 := e.fp.Zero() - z1 := e.fp.Zero() - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) square(x *e2) *e2 { - // var a, b fp.Element - a := e.fp.Add(&x.A0, &x.A1) // a.Add(&x.A0, &x.A1) - b := e.fp.Sub(&x.A0, &x.A1) // b.Sub(&x.A0, &x.A1) - a = e.fp.MulMod(a, b) // a.Mul(&a, &b) - b = e.fp.MulMod(&x.A0, &x.A1) // b.Mul(&x.A0, &x.A1). - b = e.fp.MulConst(b, big.NewInt(2)) // Double(&b) - return &e2{ - A0: *a, // z.A0.Set(&a) - A1: *b, // z.A1.Set(&b) - } -} - -func (e ext2) double(x *e2) *e2 { - two := big.NewInt(2) - z0 := e.fp.MulConst(&x.A0, two) // z.A0.Double(&x.A0) - z1 := e.fp.MulConst(&x.A1, two) // z.A1.Double(&x.A1) - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) halve(x *e2) *e2 { - // I'm trying to avoid hard-coding modulus here in case want to make generic - // for different curves. - // TODO: if implemented Half in field emulation, then replace with it. - one := e.fp.One() - two := e.fp.MulConst(one, big.NewInt(2)) - z0 := e.fp.Div(&x.A0, two) - z1 := e.fp.Div(&x.A1, two) - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) mulBybTwistCurveCoeff(x *e2) *e2 { - // var res E2 - res := e.mulByNonResidueInv(x) // res.MulByNonResidueInv(x) - z := e.double(res) // z.Double(&res). - z = e.add(z, res) // Add(&res, z) - return z // return z -} - -func (e ext2) inverse(x *e2) *e2 { - // var t0, t1 fp.Element - t0 := e.fp.MulMod(&x.A0, &x.A0) // t0.Square(&x.A0) - t1 := e.fp.MulMod(&x.A1, &x.A1) // t1.Square(&x.A1) - t0 = e.fp.Add(t0, t1) // t0.Add(&t0, &t1) - t1 = e.fp.Inverse(t0) // t1.Inverse(&t0) - z0 := e.fp.MulMod(&x.A0, t1) // z.A0.Mul(&x.A0, &t1) - z1 := e.fp.MulMod(&x.A1, t1) // z.A1.Mul(&x.A1, &t1). - z1 = e.fp.Neg(z1) // Neg(&z.A1) - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) assertIsEqual(x, y *e2) { - e.fp.AssertIsEqual(&x.A0, &y.A0) - e.fp.AssertIsEqual(&x.A1, &y.A1) -} - -func (e ext6) add(x, y *e6) *e6 { - z0 := e.ext2.add(&x.B0, &y.B0) // z.B0.Add(&x.B0, &y.B0) - z1 := e.ext2.add(&x.B1, &y.B1) // z.B1.Add(&x.B1, &y.B1) - z2 := e.ext2.add(&x.B2, &y.B2) // z.B2.Add(&x.B2, &y.B2) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} - -func (e ext6) neg(x *e6) *e6 { - z0 := e.ext2.neg(&x.B0) // z.B0.Neg(&x.B0) - z1 := e.ext2.neg(&x.B1) // z.B1.Neg(&x.B1) - z2 := e.ext2.neg(&x.B2) // z.B2.Neg(&x.B2) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} - -func (e ext6) sub(x, y *e6) *e6 { - z0 := e.ext2.sub(&x.B0, &y.B0) // z.B0.Sub(&x.B0, &y.B0) - z1 := e.ext2.sub(&x.B1, &y.B1) // z.B1.Sub(&x.B1, &y.B1) - z2 := e.ext2.sub(&x.B2, &y.B2) // z.B2.Sub(&x.B2, &y.B2) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} - -func (e ext6) mul(x, y *e6) *e6 { - // var t0, t1, t2, c0, c1, c2, tmp E2 - t0 := e.ext2.mul(&x.B0, &y.B0) // t0.Mul(&x.B0, &y.B0) - t1 := e.ext2.mul(&x.B1, &y.B1) // t1.Mul(&x.B1, &y.B1) - t2 := e.ext2.mul(&x.B2, &y.B2) // t2.Mul(&x.B2, &y.B2) - c0 := e.ext2.add(&x.B1, &x.B2) // c0.Add(&x.B1, &x.B2) - tmp := e.ext2.add(&y.B1, &y.B2) // tmp.Add(&y.B1, &y.B2) - c0 = e.ext2.mul(c0, tmp) // c0.Mul(&c0, &tmp). - c0 = e.ext2.sub(c0, t1) // Sub(&c0, &t1). - c0 = e.ext2.sub(c0, t2) // Sub(&c0, &t2). - c0 = e.ext2.mulByNonResidue(c0) // MulByNonResidue(&c0). - c0 = e.ext2.add(c0, t0) // Add(&c0, &t0) - c1 := e.ext2.add(&x.B0, &x.B1) // c1.Add(&x.B0, &x.B1) - tmp = e.ext2.add(&y.B0, &y.B1) // tmp.Add(&y.B0, &y.B1) - c1 = e.ext2.mul(c1, tmp) // c1.Mul(&c1, &tmp). - c1 = e.ext2.sub(c1, t0) // Sub(&c1, &t0). - c1 = e.ext2.sub(c1, t1) // Sub(&c1, &t1) - tmp = e.ext2.mulByNonResidue(t2) // tmp.MulByNonResidue(&t2) - c1 = e.ext2.add(c1, tmp) // c1.Add(&c1, &tmp) - tmp = e.ext2.add(&x.B0, &x.B2) // tmp.Add(&x.B0, &x.B2) - c2 := e.ext2.add(&y.B0, &y.B2) // c2.Add(&y.B0, &y.B2). - c2 = e.ext2.mul(c2, tmp) // Mul(&c2, &tmp). - c2 = e.ext2.sub(c2, t0) // Sub(&c2, &t0). - c2 = e.ext2.sub(c2, t2) // Sub(&c2, &t2). - c2 = e.ext2.add(c2, t1) // Add(&c2, &t1) - return &e6{ - B0: *c0, // z.B0.Set(&c0) - B1: *c1, // z.B1.Set(&c1) - B2: *c2, // z.B2.Set(&c2) - } // return z -} - -func (e ext6) double(x *e6) *e6 { - z0 := e.ext2.double(&x.B0) // z.B0.Double(&x.B0) - z1 := e.ext2.double(&x.B1) // z.B1.Double(&x.B1) - z2 := e.ext2.double(&x.B2) // z.B2.Double(&x.B2) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} - -func (e ext6) square(x *e6) *e6 { - // var c4, c5, c1, c2, c3, c0 E2 - c4 := e.ext2.mul(&x.B0, &x.B1) // c4.Mul(&x.B0, &x.B1). - c4 = e.ext2.double(c4) // Double(&c4) - c5 := e.ext2.square(&x.B2) // c5.Square(&x.B2) - c1 := e.ext2.mulByNonResidue(c5) // c1.MulByNonResidue(&c5). - c1 = e.ext2.add(c1, c4) // Add(&c1, &c4) - c2 := e.ext2.sub(c4, c5) // c2.Sub(&c4, &c5) - c3 := e.ext2.square(&x.B0) // c3.Square(&x.B0) - c4 = e.ext2.sub(&x.B0, &x.B1) // c4.Sub(&x.B0, &x.B1). - c4 = e.ext2.add(c4, &x.B2) // Add(&c4, &x.B2) - c5 = e.ext2.mul(&x.B1, &x.B2) // c5.Mul(&x.B1, &x.B2). - c5 = e.ext2.double(c5) // Double(&c5) - c4 = e.ext2.square(c4) // c4.Square(&c4) - c0 := e.ext2.mulByNonResidue(c5) // c0.MulByNonResidue(&c5). - c0 = e.ext2.add(c0, c3) // Add(&c0, &c3) - z2 := e.ext2.add(c2, c4) // z.B2.Add(&c2, &c4). - z2 = e.ext2.add(z2, c5) // Add(&z.B2, &c5). - z2 = e.ext2.sub(z2, c3) // Sub(&z.B2, &c3) - z0 := c0 // z.B0.Set(&c0) - z1 := c1 // z.B1.Set(&c1) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} - -func (e ext6) inverse(x *e6) *e6 { - // var t0, t1, t2, t3, t4, t5, t6, c0, c1, c2, d1, d2 E2 - t0 := e.ext2.square(&x.B0) // t0.Square(&x.B0) - t1 := e.ext2.square(&x.B1) // t1.Square(&x.B1) - t2 := e.ext2.square(&x.B2) // t2.Square(&x.B2) - t3 := e.ext2.mul(&x.B0, &x.B1) // t3.Mul(&x.B0, &x.B1) - t4 := e.ext2.mul(&x.B0, &x.B2) // t4.Mul(&x.B0, &x.B2) - t5 := e.ext2.mul(&x.B1, &x.B2) // t5.Mul(&x.B1, &x.B2) - c0 := e.ext2.mulByNonResidue(t5) // c0.MulByNonResidue(&t5). - c0 = e.ext2.neg(c0) // Neg(&c0). - c0 = e.ext2.add(c0, t0) // Add(&c0, &t0) - c1 := e.ext2.mulByNonResidue(t2) // c1.MulByNonResidue(&t2). - c1 = e.ext2.sub(c1, t3) // Sub(&c1, &t3) - c2 := e.ext2.sub(t1, t4) // c2.Sub(&t1, &t4) - t6 := e.ext2.mul(&x.B0, c0) // t6.Mul(&x.B0, &c0) - d1 := e.ext2.mul(&x.B2, c1) // d1.Mul(&x.B2, &c1) - d2 := e.ext2.mul(&x.B1, c2) // d2.Mul(&x.B1, &c2) - d1 = e.ext2.add(d1, d2) // d1.Add(&d1, &d2). - d1 = e.ext2.mulByNonResidue(d1) // MulByNonResidue(&d1) - t6 = e.ext2.add(t6, d1) // t6.Add(&t6, &d1) - t6 = e.ext2.inverse(t6) // t6.Inverse(&t6) - z0 := e.ext2.mul(c0, t6) // z.B0.Mul(&c0, &t6) - z1 := e.ext2.mul(c1, t6) // z.B1.Mul(&c1, &t6) - z2 := e.ext2.mul(c2, t6) // z.B2.Mul(&c2, &t6) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} -func (e ext6) mulByE2(x *e6, y *e2) *e6 { - // var yCopy E2 - // yCopy.Set(y) - z0 := e.ext2.mul(&x.B0, y) // z.B0.Mul(&x.B0, &yCopy) - z1 := e.ext2.mul(&x.B1, y) // z.B1.Mul(&x.B1, &yCopy) - z2 := e.ext2.mul(&x.B2, y) // z.B2.Mul(&x.B2, &yCopy) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} - -func (e ext6) mulBy01(z *e6, c0, c1 *e2) *e6 { - // var a, b, tmp, t0, t1, t2 E2 - a := e.ext2.mul(&z.B0, c0) // a.Mul(&z.B0, c0) - b := e.ext2.mul(&z.B1, c1) // b.Mul(&z.B1, c1) - tmp := e.ext2.add(&z.B1, &z.B2) // tmp.Add(&z.B1, &z.B2) - t0 := e.ext2.mul(c1, tmp) // t0.Mul(c1, &tmp) - t0 = e.ext2.sub(t0, b) // t0.Sub(&t0, &b) - t0 = e.ext2.mulByNonResidue(t0) // t0.MulByNonResidue(&t0) - t0 = e.ext2.add(t0, a) // t0.Add(&t0, &a) - tmp = e.ext2.add(&z.B0, &z.B2) // tmp.Add(&z.B0, &z.B2) - t2 := e.ext2.mul(c0, tmp) // t2.Mul(c0, &tmp) - t2 = e.ext2.sub(t2, a) // t2.Sub(&t2, &a) - t2 = e.ext2.add(t2, b) // t2.Add(&t2, &b) - t1 := e.ext2.add(c0, c1) // t1.Add(c0, c1) - tmp = e.ext2.add(&z.B0, &z.B1) // tmp.Add(&z.B0, &z.B1) - t1 = e.ext2.mul(t1, tmp) // t1.Mul(&t1, &tmp) - t1 = e.ext2.sub(t1, a) // t1.Sub(&t1, &a) - t1 = e.ext2.sub(t1, b) // t1.Sub(&t1, &b) - return &e6{ - B0: *t0, // z.B0.Set(&t0) - B1: *t1, // z.B1.Set(&t1) - B2: *t2, // z.B2.Set(&t2) - } // return z -} - -func (e ext6) mulByNonResidue(x *e6) *e6 { - z2, z1, z0 := &x.B1, &x.B0, &x.B2 // z.B2, z.B1, z.B0 = x.B1, x.B0, x.B2 - z0 = e.ext2.mulByNonResidue(z0) // z.B0.MulByNonResidue(&z.B0) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} - -func (e ext6) assertIsEqual(x, y *e6) { - e.ext2.assertIsEqual(&x.B0, &y.B0) - e.ext2.assertIsEqual(&x.B1, &y.B1) - e.ext2.assertIsEqual(&x.B2, &y.B2) -} - -func (e ext12) conjugate(x *e12) *e12 { - z1 := e.ext6.neg(&x.C1) // z.C1.Neg(&z.C1) - return &e12{ // return z - C0: x.C0, - C1: *z1, - } -} - -func (e ext12) inverse(x *e12) *e12 { - // var t0, t1, tmp E6 - t0 := e.ext6.square(&x.C0) // t0.Square(&x.C0) - t1 := e.ext6.square(&x.C1) // t1.Square(&x.C1) - tmp := e.ext6.mulByNonResidue(t1) // tmp.MulByNonResidue(&t1) - t0 = e.ext6.sub(t0, tmp) // t0.Sub(&t0, &tmp) - t1 = e.ext6.inverse(t0) // t1.Inverse(&t0) - z0 := e.ext6.mul(&x.C0, t1) // z.C0.Mul(&x.C0, &t1) - z1 := e.ext6.mul(&x.C1, t1) // z.C1.Mul(&x.C1, &t1). - z1 = e.ext6.neg(z1) // Neg(&z.C1) - return &e12{ // return z - C0: *z0, - C1: *z1, - } -} - -func (e ext12) mul(x, y *e12) *e12 { - // var a, b, c E6 - a := e.ext6.add(&x.C0, &x.C1) // a.Add(&x.C0, &x.C1) - b := e.ext6.add(&y.C0, &y.C1) // b.Add(&y.C0, &y.C1) - a = e.ext6.mul(a, b) // a.Mul(&a, &b) - b = e.ext6.mul(&x.C0, &y.C0) // b.Mul(&x.C0, &y.C0) - c := e.ext6.mul(&x.C1, &y.C1) // c.Mul(&x.C1, &y.C1) - z1 := e.ext6.sub(a, b) // z.C1.Sub(&a, &b). - z1 = e.ext6.sub(z1, c) // Sub(&z.C1, &c) - z0 := e.ext6.mulByNonResidue(c) // z.C0.MulByNonResidue(&c). - z0 = e.ext6.add(z0, b) // Add(&z.C0, &b) - return &e12{ // return z - C0: *z0, - C1: *z1, - } -} - -func (e ext12) cyclotomicSquare(x *e12) *e12 { - // var t [9]E2 - t0 := e.ext2.square(&x.C1.B1) // t[0].Square(&x.C1.B1) - t1 := e.ext2.square(&x.C0.B0) // t[1].Square(&x.C0.B0) - t6 := e.ext2.add(&x.C1.B1, &x.C0.B0) // t[6].Add(&x.C1.B1, &x.C0.B0). - t6 = e.ext2.square(t6) // Square(&t[6]). - t6 = e.ext2.sub(t6, t0) // Sub(&t[6], &t[0]). - t6 = e.ext2.sub(t6, t1) // Sub(&t[6], &t[1]) - t2 := e.ext2.square(&x.C0.B2) // t[2].Square(&x.C0.B2) - t3 := e.ext2.square(&x.C1.B0) // t[3].Square(&x.C1.B0) - t7 := e.ext2.add(&x.C0.B2, &x.C1.B0) // t[7].Add(&x.C0.B2, &x.C1.B0). - t7 = e.ext2.square(t7) // Square(&t[7]). - t7 = e.ext2.sub(t7, t2) // Sub(&t[7], &t[2]). - t7 = e.ext2.sub(t7, t3) // Sub(&t[7], &t[3]) - t4 := e.ext2.square(&x.C1.B2) // t[4].Square(&x.C1.B2) - t5 := e.ext2.square(&x.C0.B1) // t[5].Square(&x.C0.B1) - t8 := e.ext2.add(&x.C1.B2, &x.C0.B1) // t[8].Add(&x.C1.B2, &x.C0.B1). - t8 = e.ext2.square(t8) // Square(&t[8]). - t8 = e.ext2.sub(t8, t4) // Sub(&t[8], &t[4]). - t8 = e.ext2.sub(t8, t5) // Sub(&t[8], &t[5]). - t8 = e.ext2.mulByNonResidue(t8) // MulByNonResidue(&t[8]) - t0 = e.ext2.mulByNonResidue(t0) // t[0].MulByNonResidue(&t[0]). - t0 = e.ext2.add(t0, t1) // Add(&t[0], &t[1]) - t2 = e.ext2.mulByNonResidue(t2) // t[2].MulByNonResidue(&t[2]). - t2 = e.ext2.add(t2, t3) // Add(&t[2], &t[3]) - t4 = e.ext2.mulByNonResidue(t4) // t[4].MulByNonResidue(&t[4]). - t4 = e.ext2.add(t4, t5) // Add(&t[4], &t[5]) - z00 := e.ext2.sub(t0, &x.C0.B0) // z.C0.B0.Sub(&t[0], &x.C0.B0). - z00 = e.ext2.double(z00) // Double(&z.C0.B0). - z00 = e.ext2.add(z00, t0) // Add(&z.C0.B0, &t[0]) - z01 := e.ext2.sub(t2, &x.C0.B1) // z.C0.B1.Sub(&t[2], &x.C0.B1). - z01 = e.ext2.double(z01) // Double(&z.C0.B1). - z01 = e.ext2.add(z01, t2) // Add(&z.C0.B1, &t[2]) - z02 := e.ext2.sub(t4, &x.C0.B2) // z.C0.B2.Sub(&t[4], &x.C0.B2). - z02 = e.ext2.double(z02) // Double(&z.C0.B2). - z02 = e.ext2.add(z02, t4) // Add(&z.C0.B2, &t[4]) - z10 := e.ext2.add(t8, &x.C1.B0) // z.C1.B0.Add(&t[8], &x.C1.B0). - z10 = e.ext2.double(z10) // Double(&z.C1.B0). - z10 = e.ext2.add(z10, t8) // Add(&z.C1.B0, &t[8]) - z11 := e.ext2.add(t6, &x.C1.B1) // z.C1.B1.Add(&t[6], &x.C1.B1). - z11 = e.ext2.double(z11) // Double(&z.C1.B1). - z11 = e.ext2.add(z11, t6) // Add(&z.C1.B1, &t[6]) - z12 := e.ext2.add(t7, &x.C1.B2) // z.C1.B2.Add(&t[7], &x.C1.B2). - z12 = e.ext2.double(z12) // Double(&z.C1.B2). - z12 = e.ext2.add(z12, t7) // Add(&z.C1.B2, &t[7]) - return &e12{ // return z - C0: e6{ - B0: *z00, - B1: *z01, - B2: *z02, - }, - C1: e6{ - B0: *z10, - B1: *z11, - B2: *z12, - }, - } -} - -func (e ext12) frobenius(x *e12) *e12 { - // var t [6]E2 - t0 := e.ext2.conjugate(&x.C0.B0) // t[0].Conjugate(&x.C0.B0) - t1 := e.ext2.conjugate(&x.C0.B1) // t[1].Conjugate(&x.C0.B1) - t2 := e.ext2.conjugate(&x.C0.B2) // t[2].Conjugate(&x.C0.B2) - t3 := e.ext2.conjugate(&x.C1.B0) // t[3].Conjugate(&x.C1.B0) - t4 := e.ext2.conjugate(&x.C1.B1) // t[4].Conjugate(&x.C1.B1) - t5 := e.ext2.conjugate(&x.C1.B2) // t[5].Conjugate(&x.C1.B2) - t1 = e.ext2.mulByNonResidue1Power2(t1) // t[1].MulByNonResidue1Power2(&t[1]) - t2 = e.ext2.mulByNonResidue1Power4(t2) // t[2].MulByNonResidue1Power4(&t[2]) - t3 = e.ext2.mulByNonResidue1Power1(t3) // t[3].MulByNonResidue1Power1(&t[3]) - t4 = e.ext2.mulByNonResidue1Power3(t4) // t[4].MulByNonResidue1Power3(&t[4]) - t5 = e.ext2.mulByNonResidue1Power5(t5) // t[5].MulByNonResidue1Power5(&t[5]) - return &e12{ // return z - C0: e6{ - B0: *t0, // z.C0.B0 = t[0] - B1: *t1, // z.C0.B1 = t[1] - B2: *t2, // z.C0.B2 = t[2] - }, - C1: e6{ - B0: *t3, // z.C1.B0 = t[3] - B1: *t4, // z.C1.B1 = t[4] - B2: *t5, // z.C1.B2 = t[5] - }, - } -} - -func (e ext12) frobeniusSquare(x *e12) *e12 { - z00 := &x.C0.B0 // z.C0.B0 = x.C0.B0 - z01 := e.ext2.mulByNonResidue2Power2(&x.C0.B1) // z.C0.B1.MulByNonResidue2Power2(&x.C0.B1) - z02 := e.ext2.mulByNonResidue2Power4(&x.C0.B2) // z.C0.B2.MulByNonResidue2Power4(&x.C0.B2) - z10 := e.ext2.mulByNonResidue2Power1(&x.C1.B0) // z.C1.B0.MulByNonResidue2Power1(&x.C1.B0) - z11 := e.ext2.mulByNonResidue2Power3(&x.C1.B1) // z.C1.B1.MulByNonResidue2Power3(&x.C1.B1) - z12 := e.ext2.mulByNonResidue2Power5(&x.C1.B2) // z.C1.B2.MulByNonResidue2Power5(&x.C1.B2) - return &e12{ // return z - C0: e6{B0: *z00, B1: *z01, B2: *z02}, - C1: e6{B0: *z10, B1: *z11, B2: *z12}, - } -} - -func (e ext12) frobeniusCube(x *e12) *e12 { - // var t [6]E2 - t0 := e.ext2.conjugate(&x.C0.B0) // t[0].Conjugate(&x.C0.B0) - t1 := e.ext2.conjugate(&x.C0.B1) // t[1].Conjugate(&x.C0.B1) - t2 := e.ext2.conjugate(&x.C0.B2) // t[2].Conjugate(&x.C0.B2) - t3 := e.ext2.conjugate(&x.C1.B0) // t[3].Conjugate(&x.C1.B0) - t4 := e.ext2.conjugate(&x.C1.B1) // t[4].Conjugate(&x.C1.B1) - t5 := e.ext2.conjugate(&x.C1.B2) // t[5].Conjugate(&x.C1.B2) - t1 = e.ext2.mulByNonResidue3Power2(t1) // t[1].MulByNonResidue3Power2(&t[1]) - t2 = e.ext2.mulByNonResidue3Power4(t2) // t[2].MulByNonResidue3Power4(&t[2]) - t3 = e.ext2.mulByNonResidue3Power1(t3) // t[3].MulByNonResidue3Power1(&t[3]) - t4 = e.ext2.mulByNonResidue3Power3(t4) // t[4].MulByNonResidue3Power3(&t[4]) - t5 = e.ext2.mulByNonResidue3Power5(t5) // t[5].MulByNonResidue3Power5(&t[5]) - return &e12{ // return z - C0: e6{ - B0: *t0, // z.C0.B0 = t[0] - B1: *t1, // z.C0.B1 = t[1] - B2: *t2, // z.C0.B2 = t[2] - }, - C1: e6{ - B0: *t3, // z.C1.B0 = t[3] - B1: *t4, // z.C1.B1 = t[4] - B2: *t5, // z.C1.B2 = t[5] - }, - } -} - -func (e ext12) expt(x *e12) *e12 { - // var result, t0, t1, t2, t3, t4, t5, t6 E12 - t3 := e.cyclotomicSquare(x) // t3.CyclotomicSquare(x) - t5 := e.cyclotomicSquare(t3) // t5.CyclotomicSquare(&t3) - result := e.cyclotomicSquare(t5) // result.CyclotomicSquare(&t5) - t0 := e.cyclotomicSquare(result) // t0.CyclotomicSquare(&result) - t2 := e.mul(x, t0) // t2.Mul(x, &t0) - t0 = e.mul(t3, t2) // t0.Mul(&t3, &t2) - t1 := e.mul(x, t0) // t1.Mul(x, &t0) - t4 := e.mul(result, t2) // t4.Mul(&result, &t2) - t6 := e.cyclotomicSquare(t2) // t6.CyclotomicSquare(&t2) - t1 = e.mul(t0, t1) // t1.Mul(&t0, &t1) - t0 = e.mul(t3, t1) // t0.Mul(&t3, &t1) - t6 = e.nSquare(t6, 6) // t6.nSquare(6) - t5 = e.mul(t5, t6) // t5.Mul(&t5, &t6) - t5 = e.mul(t4, t5) // t5.Mul(&t4, &t5) - t5 = e.nSquare(t5, 7) // t5.nSquare(7) - t4 = e.mul(t4, t5) // t4.Mul(&t4, &t5) - t4 = e.nSquare(t4, 8) // t4.nSquare(8) - t4 = e.mul(t0, t4) // t4.Mul(&t0, &t4) - t3 = e.mul(t3, t4) // t3.Mul(&t3, &t4) - t3 = e.nSquare(t3, 6) // t3.nSquare(6) - t2 = e.mul(t2, t3) // t2.Mul(&t2, &t3) - t2 = e.nSquare(t2, 8) // t2.nSquare(8) - t2 = e.mul(t0, t2) // t2.Mul(&t0, &t2) - t2 = e.nSquare(t2, 6) // t2.nSquare(6) - t2 = e.mul(t0, t2) // t2.Mul(&t0, &t2) - t2 = e.nSquare(t2, 10) // t2.nSquare(10) - t1 = e.mul(t1, t2) // t1.Mul(&t1, &t2) - t1 = e.nSquare(t1, 6) // t1.nSquare(6) - t0 = e.mul(t0, t1) // t0.Mul(&t0, &t1) - z := e.mul(result, t0) // z.Mul(&result, &t0) - return z // return z -} - -func (e ext12) one() *e12 { - z000 := e.fp.One() - zero := e.fp.Zero() - return &e12{ - C0: e6{ - B0: e2{A0: *z000, A1: *zero}, - B1: e2{A0: *zero, A1: *zero}, - B2: e2{A0: *zero, A1: *zero}, - }, - C1: e6{ - B0: e2{A0: *zero, A1: *zero}, - B1: e2{A0: *zero, A1: *zero}, - B2: e2{A0: *zero, A1: *zero}, - }, - } -} - -func (e ext12) mulBy034(z *e12, c0, c3, c4 *e2) *e12 { - // var a, b, d E6 - a := e.ext6.mulByE2(&z.C0, c0) // a.MulByE2(&z.C0, c0) - // b.Set(&z.C1) - b := e.ext6.mulBy01(&z.C1, c3, c4) // b.MulBy01(c3, c4) - c0 = e.ext2.add(c0, c3) // c0.Add(c0, c3) - d := e.ext6.add(&z.C0, &z.C1) // d.Add(&z.C0, &z.C1) - d = e.ext6.mulBy01(d, c0, c4) // d.MulBy01(c0, c4) - z1 := e.add(a, b) // z.C1.Add(&a, &b). - z1 = e.neg(z1) // Neg(&z.C1). - z1 = e.add(z1, d) // Add(&z.C1, &d) - z0 := e.mulByNonResidue(b) // z.C0.MulByNonResidue(&b). - z0 = e.add(z0, a) // Add(&z.C0, &a) - return &e12{ // return z - C0: *z0, - C1: *z1, - } -} - -func (e ext12) square(x *e12) *e12 { - // var c0, c2, c3 E6 - c0 := e.ext6.sub(&x.C0, &x.C1) // c0.Sub(&x.C0, &x.C1) - c3 := e.ext6.mulByNonResidue(&x.C1) // c3.MulByNonResidue(&x.C1). - c3 = e.ext6.neg(c3) // Neg(&c3). - c3 = e.ext6.add(&x.C0, c3) // Add(&x.C0, &c3) - c2 := e.ext6.mul(&x.C0, &x.C1) // c2.Mul(&x.C0, &x.C1) - c0 = e.ext6.mul(c0, c3) // c0.Mul(&c0, &c3). - c0 = e.ext6.add(c0, c2) // Add(&c0, &c2) - z1 := e.ext6.double(c2) // z.C1.Double(&c2) - c2 = e.ext6.mulByNonResidue(c2) // c2.MulByNonResidue(&c2) - z0 := e.ext6.add(c0, c2) // z.C0.Add(&c0, &c2) - return &e12{ // return z - C0: *z0, - C1: *z1, - } -} - -func (e ext12) mulBy034by034(d0, d3, d4, c0, c3, c4 *e2) *e12 { - // var tmp, x0, x3, x4, x04, x03, x34 E2 - x0 := e.ext2.mul(c0, d0) // x0.Mul(c0, d0) - x3 := e.ext2.mul(c3, d3) // x3.Mul(c3, d3) - x4 := e.ext2.mul(c4, d4) // x4.Mul(c4, d4) - tmp := e.ext2.add(c0, c4) // tmp.Add(c0, c4) - x04 := e.ext2.add(d0, d4) // x04.Add(d0, d4). - x04 = e.ext2.mul(x04, tmp) // Mul(&x04, &tmp). - x04 = e.ext2.sub(x04, x0) // Sub(&x04, &x0). - x04 = e.ext2.sub(x04, x4) // Sub(&x04, &x4) - tmp = e.ext2.add(c0, c3) // tmp.Add(c0, c3) - x03 := e.ext2.add(d0, d3) // x03.Add(d0, d3). - x03 = e.ext2.mul(x03, tmp) // Mul(&x03, &tmp). - x03 = e.ext2.sub(x03, x0) // Sub(&x03, &x0). - x03 = e.ext2.sub(x03, x3) // Sub(&x03, &x3) - tmp = e.ext2.add(c3, c4) // tmp.Add(c3, c4) - x34 := e.ext2.add(d3, d4) // x34.Add(d3, d4). - x34 = e.ext2.mul(x34, tmp) // Mul(&x34, &tmp). - x34 = e.ext2.sub(x34, x3) // Sub(&x34, &x3). - x34 = e.ext2.sub(x34, x4) // Sub(&x34, &x4) - z00 := e.ext2.mulByNonResidue(x4) // z.C0.B0.MulByNonResidue(&x4). - z00 = e.ext2.add(z00, x0) // Add(&z.C0.B0, &x0) - z01 := x3 // z.C0.B1.Set(&x3) - z02 := x34 // z.C0.B2.Set(&x34) - z10 := x03 // z.C1.B0.Set(&x03) - z11 := x04 // z.C1.B1.Set(&x04) - z12 := e.ext2.zero() // z.C1.B2.SetZero() - return &e12{ // return z - C0: e6{ - B0: *z00, - B1: *z01, - B2: *z02, - }, - C1: e6{ - B0: *z10, - B1: *z11, - B2: *z12, - }, - } -} - -func (e ext12) assertIsEqual(x, y *e12) { - e.ext6.assertIsEqual(&x.C0, &y.C0) - e.ext6.assertIsEqual(&x.C1, &y.C1) -} - -func (e ext12) nSquare(z *e12, n int) *e12 { - for i := 0; i < n; i++ { - z = e.cyclotomicSquare(z) - } - return z -} From 1d76c5864e9046880a5d317b493d752d5d1f7da8 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Mon, 6 Mar 2023 17:22:12 +0100 Subject: [PATCH 055/464] fix: remove pairing_bn254 --- std/algebra/pairing_bn254/doc.go | 7 - std/algebra/pairing_bn254/doc_test.go | 101 --- std/algebra/pairing_bn254/g1.go | 16 - std/algebra/pairing_bn254/g2.go | 31 - std/algebra/pairing_bn254/gt.go | 41 -- std/algebra/pairing_bn254/pairing.go | 282 -------- std/algebra/pairing_bn254/pairing_test.go | 122 ---- std/algebra/pairing_bn254/tower.go | 833 ---------------------- 8 files changed, 1433 deletions(-) delete mode 100644 std/algebra/pairing_bn254/doc.go delete mode 100644 std/algebra/pairing_bn254/doc_test.go delete mode 100644 std/algebra/pairing_bn254/g1.go delete mode 100644 std/algebra/pairing_bn254/g2.go delete mode 100644 std/algebra/pairing_bn254/gt.go delete mode 100644 std/algebra/pairing_bn254/pairing.go delete mode 100644 std/algebra/pairing_bn254/pairing_test.go delete mode 100644 std/algebra/pairing_bn254/tower.go diff --git a/std/algebra/pairing_bn254/doc.go b/std/algebra/pairing_bn254/doc.go deleted file mode 100644 index 5f04a7dd72..0000000000 --- a/std/algebra/pairing_bn254/doc.go +++ /dev/null @@ -1,7 +0,0 @@ -// Package pairing_bn254 implements pairing over BN254 curve. -// -// The implementation follows very closely the implementation of its out-circuit -// counterpart in [gnark-crypto]. -// -// [gnark-crypto]: https://github.com/ConsenSys/gnark-crypto/tree/master/ecc/bn254 -package pairing_bn254 diff --git a/std/algebra/pairing_bn254/doc_test.go b/std/algebra/pairing_bn254/doc_test.go deleted file mode 100644 index 8481c45361..0000000000 --- a/std/algebra/pairing_bn254/doc_test.go +++ /dev/null @@ -1,101 +0,0 @@ -package pairing_bn254_test - -import ( - "crypto/rand" - "fmt" - - "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark/backend/groth16" - "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/std/algebra/pairing_bn254" -) - -type PairCircuit struct { - InG1 pairing_bn254.G1Affine - InG2 pairing_bn254.G2Affine - Res pairing_bn254.GTEl -} - -func (c *PairCircuit) Define(api frontend.API) error { - pairing, err := pairing_bn254.NewPairing(api) - if err != nil { - return fmt.Errorf("new pairing: %w", err) - } - res, err := pairing.Pair([]*pairing_bn254.G1Affine{&c.InG1}, []*pairing_bn254.G2Affine{&c.InG2}) - if err != nil { - return fmt.Errorf("pair: %w", err) - } - pairing.AssertIsEqual(res, &c.Res) - return nil -} - -func ExamplePairing() { - p, q, err := randomG1G2Affines() - if err != nil { - panic(err) - } - res, err := bn254.Pair([]bn254.G1Affine{p}, []bn254.G2Affine{q}) - if err != nil { - panic(err) - } - circuit := PairCircuit{} - witness := PairCircuit{ - InG1: pairing_bn254.NewG1Affine(p), - InG2: pairing_bn254.NewG2Affine(q), - Res: pairing_bn254.NewGTEl(res), - } - ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) - if err != nil { - panic(err) - } else { - fmt.Println("compiled") - } - pk, vk, err := groth16.Setup(ccs) - if err != nil { - panic(err) - } else { - fmt.Println("setup done") - } - secretWitness, err := frontend.NewWitness(&witness, ecc.BN254.ScalarField()) - if err != nil { - panic(err) - } else { - fmt.Println("secret witness") - } - publicWitness, err := secretWitness.Public() - if err != nil { - panic(err) - } else { - fmt.Println("public witness") - } - proof, err := groth16.Prove(ccs, pk, secretWitness) - if err != nil { - panic(err) - } else { - fmt.Println("proof") - } - err = groth16.Verify(proof, vk, publicWitness) - if err != nil { - panic(err) - } else { - fmt.Println("verify") - } -} - -func randomG1G2Affines() (p bn254.G1Affine, q bn254.G2Affine, err error) { - _, _, G1AffGen, G2AffGen := bn254.Generators() - mod := bn254.ID.ScalarField() - s1, err := rand.Int(rand.Reader, mod) - if err != nil { - return p, q, err - } - s2, err := rand.Int(rand.Reader, mod) - if err != nil { - return p, q, err - } - p.ScalarMultiplication(&G1AffGen, s1) - q.ScalarMultiplication(&G2AffGen, s2) - return -} diff --git a/std/algebra/pairing_bn254/g1.go b/std/algebra/pairing_bn254/g1.go deleted file mode 100644 index 4f1fa5d2c4..0000000000 --- a/std/algebra/pairing_bn254/g1.go +++ /dev/null @@ -1,16 +0,0 @@ -package pairing_bn254 - -import ( - "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark/std/algebra/weierstrass" - "github.com/consensys/gnark/std/math/emulated" -) - -type G1Affine = weierstrass.AffinePoint[emulated.BN254Fp] - -func NewG1Affine(v bn254.G1Affine) G1Affine { - return G1Affine{ - X: emulated.ValueOf[emulated.BN254Fp](v.X), - Y: emulated.ValueOf[emulated.BN254Fp](v.Y), - } -} diff --git a/std/algebra/pairing_bn254/g2.go b/std/algebra/pairing_bn254/g2.go deleted file mode 100644 index ace3b00efe..0000000000 --- a/std/algebra/pairing_bn254/g2.go +++ /dev/null @@ -1,31 +0,0 @@ -package pairing_bn254 - -import ( - "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark/std/math/emulated" -) - -type G2Affine struct { - X, Y e2 -} - -type g2Jacobian struct { - X, Y, Z e2 -} - -type g2Projective struct { - X, Y, Z e2 -} - -func NewG2Affine(v bn254.G2Affine) G2Affine { - return G2Affine{ - X: e2{ - A0: emulated.ValueOf[emulated.BN254Fp](v.X.A0), - A1: emulated.ValueOf[emulated.BN254Fp](v.X.A1), - }, - Y: e2{ - A0: emulated.ValueOf[emulated.BN254Fp](v.Y.A0), - A1: emulated.ValueOf[emulated.BN254Fp](v.Y.A1), - }, - } -} diff --git a/std/algebra/pairing_bn254/gt.go b/std/algebra/pairing_bn254/gt.go deleted file mode 100644 index 2b84c9f0ed..0000000000 --- a/std/algebra/pairing_bn254/gt.go +++ /dev/null @@ -1,41 +0,0 @@ -package pairing_bn254 - -import ( - "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark/std/math/emulated" -) - -type GTEl = e12 - -func NewGTEl(v bn254.GT) GTEl { - return GTEl{ - C0: e6{ - B0: e2{ - A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B0.A0), - A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B0.A1), - }, - B1: e2{ - A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B1.A0), - A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B1.A1), - }, - B2: e2{ - A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B2.A0), - A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B2.A1), - }, - }, - C1: e6{ - B0: e2{ - A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B0.A0), - A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B0.A1), - }, - B1: e2{ - A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B1.A0), - A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B1.A1), - }, - B2: e2{ - A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B2.A0), - A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B2.A1), - }, - }, - } -} diff --git a/std/algebra/pairing_bn254/pairing.go b/std/algebra/pairing_bn254/pairing.go deleted file mode 100644 index ec0baa633b..0000000000 --- a/std/algebra/pairing_bn254/pairing.go +++ /dev/null @@ -1,282 +0,0 @@ -package pairing_bn254 - -import ( - "fmt" - - "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/math/emulated" -) - -type Pairing struct { - *ext12 -} - -func NewPairing(api frontend.API) (*Pairing, error) { - ba, err := emulated.NewField[emulated.BN254Fp](api) - if err != nil { - return nil, fmt.Errorf("new base api: %w", err) - } - return &Pairing{ - ext12: newExt12(ba), - }, nil -} - -func (pr Pairing) doubleStep(p *g2Projective) (*g2Projective, *lineEvaluation) { - // var t1, A, B, C, D, E, EE, F, G, H, I, J, K fptower.E2 - A := pr.ext2.mul(&p.X, &p.Y) // A.Mul(&p.x, &p.y) - A = pr.ext2.halve(A) // A.Halve() - B := pr.ext2.square(&p.Y) // B.Square(&p.y) - C := pr.ext2.square(&p.Z) // C.Square(&p.z) - D := pr.ext2.double(C) // D.Double(&C). - D = pr.ext2.add(D, C) // Add(&D, &C) - E := pr.ext2.mulBybTwistCurveCoeff(D) // E.MulBybTwistCurveCoeff(&D) - F := pr.ext2.double(E) // F.Double(&E). - F = pr.ext2.add(F, E) // Add(&F, &E) - G := pr.ext2.add(B, F) // G.Add(&B, &F) - G = pr.ext2.halve(G) // G.Halve() - H := pr.ext2.add(&p.Y, &p.Z) // H.Add(&p.y, &p.z). - H = pr.ext2.square(H) // Square(&H) - t1 := pr.ext2.add(B, C) // t1.Add(&B, &C) - H = pr.ext2.sub(H, t1) // H.Sub(&H, &t1) - I := pr.ext2.sub(E, B) // I.Sub(&E, &B) - J := pr.ext2.square(&p.X) // J.Square(&p.x) - EE := pr.ext2.square(E) // EE.Square(&E) - K := pr.ext2.double(EE) // K.Double(&EE). - K = pr.ext2.add(K, EE) // Add(&K, &EE) - px := pr.ext2.sub(B, F) // p.x.Sub(&B, &F). - px = pr.ext2.mul(px, A) // Mul(&p.x, &A) - py := pr.ext2.square(G) // p.y.Square(&G). - py = pr.ext2.sub(py, K) // Sub(&p.y, &K) - pz := pr.ext2.mul(B, H) // p.z.Mul(&B, &H) - ev0 := pr.ext2.neg(H) // evaluations.r0.Neg(&H) - ev1 := pr.ext2.double(J) // evaluations.r1.Double(&J). - ev1 = pr.ext2.add(ev1, J) // Add(&evaluations.r1, &J) - ev2 := I // evaluations.r2.Set(&I) - return &g2Projective{ - X: *px, - Y: *py, - Z: *pz, - }, - &lineEvaluation{ - r0: *ev0, - r1: *ev1, - r2: *ev2, - } -} - -func (pr Pairing) affineToProjective(Q *G2Affine) *g2Projective { - // TODO: check point at infinity? We do not filter them in the Miller Loop neither. - // if Q.X.IsZero() && Q.Y.IsZero() { - // p.z.SetZero() - // p.x.SetOne() - // p.y.SetOne() - // return p - // } - pz := pr.ext2.one() // p.z.SetOne() - px := &Q.X // p.x.Set(&Q.X) - py := &Q.Y // p.y.Set(&Q.Y) - return &g2Projective{ // return p - X: *px, - Y: *py, - Z: *pz, - } -} - -func (pr Pairing) negAffine(a *G2Affine) *G2Affine { - px := &a.X // p.X = a.X - py := pr.ext2.neg(&a.Y) // p.Y.Neg(&a.Y) - return &G2Affine{ // return p - X: *px, - Y: *py, - } -} - -func (pr Pairing) addStep(p *g2Projective, a *G2Affine) (*g2Projective, *lineEvaluation) { - // var Y2Z1, X2Z1, O, L, C, D, E, F, G, H, t0, t1, t2, J fptower.E2 - Y2Z1 := pr.ext2.mul(&a.Y, &p.Z) // Y2Z1.Mul(&a.Y, &p.z) - O := pr.ext2.sub(&p.Y, Y2Z1) // O.Sub(&p.y, &Y2Z1) - X2Z1 := pr.ext2.mul(&a.X, &p.Z) // X2Z1.Mul(&a.X, &p.z) - L := pr.ext2.sub(&p.X, X2Z1) // L.Sub(&p.x, &X2Z1) - C := pr.ext2.square(O) // C.Square(&O) - D := pr.ext2.square(L) // D.Square(&L) - E := pr.ext2.mul(L, D) // E.Mul(&L, &D) - F := pr.ext2.mul(&p.Z, C) // F.Mul(&p.z, &C) - G := pr.ext2.mul(&p.X, D) // G.Mul(&p.x, &D) - t0 := pr.ext2.double(G) // t0.Double(&G) - H := pr.ext2.add(E, F) // H.Add(&E, &F). - H = pr.ext2.sub(H, t0) // Sub(&H, &t0) - t1 := pr.ext2.mul(&p.Y, E) // t1.Mul(&p.y, &E) - px := pr.ext2.mul(L, H) // p.x.Mul(&L, &H) - py := pr.ext2.sub(G, H) // p.y.Sub(&G, &H). - py = pr.ext2.mul(py, O) // Mul(&p.y, &O). - py = pr.ext2.sub(py, t1) // Sub(&p.y, &t1) - pz := pr.ext2.mul(E, &p.Z) // p.z.Mul(&E, &p.z) - t2 := pr.ext2.mul(L, &a.Y) // t2.Mul(&L, &a.Y) - J := pr.ext2.mul(&a.X, O) // J.Mul(&a.X, &O). - J = pr.ext2.sub(J, t2) // Sub(&J, &t2) - ev0 := L // evaluations.r0.Set(&L) - ev1 := pr.ext2.neg(O) // evaluations.r1.Neg(&O) - ev2 := J // evaluations.r2.Set(&J) - return &g2Projective{ - X: *px, - Y: *py, - Z: *pz, - }, &lineEvaluation{ - r0: *ev0, - r1: *ev1, - r2: *ev2, - } -} - -type lineEvaluation struct { - r0 e2 - r1 e2 - r2 e2 -} - -var loopCounter = [66]int8{ - 0, 0, 0, 1, 0, 1, 0, -1, 0, 0, -1, - 0, 0, 0, 1, 0, 0, -1, 0, -1, 0, 0, - 0, 1, 0, -1, 0, 0, 0, 0, -1, 0, 0, - 1, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, - -1, 0, 0, -1, 0, 1, 0, -1, 0, 0, 0, - -1, 0, -1, 0, 0, 0, 1, 0, -1, 0, 1, -} - -func (pr Pairing) MillerLoop(p []*G1Affine, q []*G2Affine) (*GTEl, error) { - n := len(p) - if n == 0 || n != len(q) { - return nil, fmt.Errorf("invalid inputs sizes") - } - - // TODO: we have omitted filtering for infinity points. - - // projective points for Q - qProj := make([]*g2Projective, n) // qProj := make([]g2Proj, n) - qNeg := make([]*G2Affine, n) // qNeg := make([]G2Affine, n) - for k := 0; k < n; k++ { - qProj[k] = pr.affineToProjective(q[k]) // qProj[k].FromAffine(&q[k]) - qNeg[k] = pr.negAffine(q[k]) // qNeg[k].Neg(&q[k]) - } - - var l, l0 *lineEvaluation - result := pr.ext12.one() // var tmp, result GTEl - - // i == len(loopCounter) - 2 - for k := 0; k < n; k++ { - qProj[k], l = pr.doubleStep(qProj[k]) // qProj[k].DoubleStep(&l) - l.r0 = *pr.ext12.ext2.mulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1 = *pr.ext12.ext2.mulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) - result = pr.ext12.mulBy034(result, &l.r0, &l.r1, &l.r2) // result.MulBy034(&l.r0, &l.r1, &l.r2) - } - - for i := len(loopCounter) - 3; i >= 0; i-- { - result = pr.ext12.square(result) // result.Square(&result) - - for k := 0; k < n; k++ { - qProj[k], l = pr.doubleStep(qProj[k]) // qProj[k].DoubleStep(&l) - l.r0 = *pr.ext12.ext2.mulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1 = *pr.ext12.ext2.mulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) - - if loopCounter[i] == 1 { - qProj[k], l0 = pr.addStep(qProj[k], q[k]) // qProj[k].AddMixedStep(&l0, &q[k]) - l0.r0 = *pr.ext12.ext2.mulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) - l0.r1 = *pr.ext12.ext2.mulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) - tmp := pr.ext12.mulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result = pr.ext12.mul(result, tmp) // result.Mul(&result, &tmp) - } else if loopCounter[i] == -1 { - qProj[k], l0 = pr.addStep(qProj[k], qNeg[k]) // qProj[k].AddMixedStep(&l0, &qNeg[k]) - l0.r0 = *pr.ext12.ext2.mulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) - l0.r1 = *pr.ext12.ext2.mulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) - tmp := pr.ext12.mulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result = pr.ext12.mul(result, tmp) //result.Mul(&result, &tmp) - } else { - result = pr.ext12.mulBy034(result, &l.r0, &l.r1, &l.r2) // result.MulBy034(&l.r0, &l.r1, &l.r2) - } - } - } - - Q1, Q2 := new(G2Affine), new(G2Affine) // var Q1, Q2 G2Affine - for k := 0; k < n; k++ { - //Q1 = π(Q) - // TODO(ivokub): define phi(Q) in G2 instead of doing manually? - Q1.X = *pr.ext12.ext2.conjugate(&q[k].X) // Q1.X.Conjugate(&q[k].X).MulByNonResidue1Power2(&Q1.X) - Q1.X = *pr.ext12.ext2.mulByNonResidue1Power2(&Q1.X) // Q1.X.Conjugate(&q[k].X).MulByNonResidue1Power2(&Q1.X) - Q1.Y = *pr.ext12.ext2.conjugate(&q[k].Y) // Q1.Y.Conjugate(&q[k].Y).MulByNonResidue1Power3(&Q1.Y) - Q1.Y = *pr.ext12.ext2.mulByNonResidue1Power3(&Q1.Y) // Q1.Y.Conjugate(&q[k].Y).MulByNonResidue1Power3(&Q1.Y) - - // Q2 = -π²(Q) - Q2.X = *pr.ext12.ext2.mulByNonResidue2Power2(&q[k].X) // Q2.X.MulByNonResidue2Power2(&q[k].X) - Q2.Y = *pr.ext12.ext2.mulByNonResidue2Power3(&q[k].Y) // Q2.Y.MulByNonResidue2Power3(&q[k].Y).Neg(&Q2.Y) - Q2.Y = *pr.ext12.ext2.neg(&Q2.Y) // Q2.Y.MulByNonResidue2Power3(&q[k].Y).Neg(&Q2.Y) - - qProj[k], l0 = pr.addStep(qProj[k], Q1) // qProj[k].AddMixedStep(&l0, &Q1) - l0.r0 = *pr.ext12.ext2.mulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) - l0.r1 = *pr.ext12.ext2.mulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) - - qProj[k], l = pr.addStep(qProj[k], Q2) // qProj[k].AddMixedStep(&l, &Q2) - l.r0 = *pr.ext12.ext2.mulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1 = *pr.ext12.ext2.mulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) - tmp := pr.ext12.mulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result = pr.ext12.mul(result, tmp) // result.Mul(&result, &tmp) - } - - return result, nil -} - -func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { - // var result GT - // result.Set(z) - var t [4]*GTEl // var t [4]GT - - // easy part - t[0] = pr.ext12.conjugate(e) // t[0].Conjugate(&result) - result := pr.ext12.inverse(e) // result.Inverse(&result) - t[0] = pr.ext12.mul(t[0], result) // t[0].Mul(&t[0], &result) - result = pr.ext12.frobeniusSquare(t[0]) // result.FrobeniusSquare(&t[0]). - result = pr.ext12.mul(result, t[0]) // Mul(&result, &t[0]) - - //hard part - t[0] = pr.ext12.expt(result) // t[0].Expt(&result). - t[0] = pr.ext12.conjugate(t[0]) // Conjugate(&t[0]) - t[0] = pr.ext12.cyclotomicSquare(t[0]) // t[0].CyclotomicSquare(&t[0]) - t[2] = pr.ext12.expt(t[0]) // t[2].Expt(&t[0]). - t[2] = pr.ext12.conjugate(t[2]) // Conjugate(&t[2]) - t[1] = pr.ext12.cyclotomicSquare(t[2]) // t[1].CyclotomicSquare(&t[2]) - t[2] = pr.ext12.mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) - t[2] = pr.ext12.mul(t[2], result) // t[2].Mul(&t[2], &result) - t[1] = pr.ext12.expt(t[2]) // t[1].Expt(&t[2]). - t[1] = pr.ext12.cyclotomicSquare(t[1]) // CyclotomicSquare(&t[1]). - t[1] = pr.ext12.mul(t[1], t[2]) // Mul(&t[1], &t[2]). - t[1] = pr.ext12.conjugate(t[1]) // Conjugate(&t[1]) - t[3] = pr.ext12.conjugate(t[1]) // t[3].Conjugate(&t[1]) - t[1] = pr.ext12.cyclotomicSquare(t[0]) // t[1].CyclotomicSquare(&t[0]) - t[1] = pr.ext12.mul(t[1], result) // t[1].Mul(&t[1], &result) - t[1] = pr.ext12.conjugate(t[1]) // t[1].Conjugate(&t[1]) - t[1] = pr.ext12.mul(t[1], t[3]) // t[1].Mul(&t[1], &t[3]) - t[0] = pr.ext12.mul(t[0], t[1]) // t[0].Mul(&t[0], &t[1]) - t[2] = pr.ext12.mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) - t[3] = pr.ext12.frobeniusSquare(t[1]) // t[3].FrobeniusSquare(&t[1]) - t[2] = pr.ext12.mul(t[2], t[3]) // t[2].Mul(&t[2], &t[3]) - t[3] = pr.ext12.conjugate(result) // t[3].Conjugate(&result) - t[3] = pr.ext12.mul(t[3], t[0]) // t[3].Mul(&t[3], &t[0]) - t[1] = pr.ext12.frobeniusCube(t[3]) // t[1].FrobeniusCube(&t[3]) - t[2] = pr.ext12.mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) - t[1] = pr.ext12.frobenius(t[0]) // t[1].Frobenius(&t[0]) - t[1] = pr.ext12.mul(t[1], t[2]) // t[1].Mul(&t[1], &t[2]) - // result.Set(&t[1]) - return t[1] // return result -} - -func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { - res, err := pr.MillerLoop(P, Q) - if err != nil { - return nil, fmt.Errorf("miller loop: %w", err) - } - res = pr.FinalExponentiation(res) - return res, nil -} - -func (pr Pairing) AssertIsEqual(x, y *GTEl) { - pr.ext12.assertIsEqual(x, y) -} diff --git a/std/algebra/pairing_bn254/pairing_test.go b/std/algebra/pairing_bn254/pairing_test.go deleted file mode 100644 index 30fddc1829..0000000000 --- a/std/algebra/pairing_bn254/pairing_test.go +++ /dev/null @@ -1,122 +0,0 @@ -package pairing_bn254 - -import ( - "crypto/rand" - "fmt" - "testing" - - "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/weierstrass" - "github.com/consensys/gnark/std/math/emulated" - "github.com/consensys/gnark/test" -) - -func randomG1G2Affines(assert *test.Assert) (bn254.G1Affine, bn254.G2Affine) { - _, _, G1AffGen, G2AffGen := bn254.Generators() - mod := bn254.ID.ScalarField() - s1, err := rand.Int(rand.Reader, mod) - assert.NoError(err) - s2, err := rand.Int(rand.Reader, mod) - assert.NoError(err) - var p bn254.G1Affine - p.ScalarMultiplication(&G1AffGen, s1) - var q bn254.G2Affine - q.ScalarMultiplication(&G2AffGen, s2) - return p, q -} - -type MillerLoopCircuit struct { - InG1 weierstrass.AffinePoint[emulated.BN254Fp] - InG2 G2Affine - Res GTEl -} - -func (c *MillerLoopCircuit) Define(api frontend.API) error { - pairing, err := NewPairing(api) - if err != nil { - return fmt.Errorf("new pairing: %w", err) - } - res, err := pairing.MillerLoop([]*G1Affine{&c.InG1}, []*G2Affine{&c.InG2}) - if err != nil { - return fmt.Errorf("pair: %w", err) - } - pairing.ext12.assertIsEqual(res, &c.Res) - return nil -} - -func TestMillerLoopTestSolve(t *testing.T) { - assert := test.NewAssert(t) - p, q := randomG1G2Affines(assert) - res, err := bn254.MillerLoop([]bn254.G1Affine{p}, []bn254.G2Affine{q}) - assert.NoError(err) - witness := MillerLoopCircuit{ - InG1: NewG1Affine(p), - InG2: NewG2Affine(q), - Res: NewGTEl(res), - } - err = test.IsSolved(&MillerLoopCircuit{}, &witness, ecc.BN254.ScalarField()) - assert.NoError(err) -} - -type FinalExponentiationCircuit struct { - InGt GTEl - Res GTEl -} - -func (c *FinalExponentiationCircuit) Define(api frontend.API) error { - pairing, err := NewPairing(api) - if err != nil { - return fmt.Errorf("new pairing: %w", err) - } - res := pairing.FinalExponentiation(&c.InGt) - pairing.ext12.assertIsEqual(res, &c.Res) - return nil -} - -func TestFinalExponentiationTestSolve(t *testing.T) { - assert := test.NewAssert(t) - var gt bn254.GT - gt.SetRandom() - res := bn254.FinalExponentiation(>) - witness := FinalExponentiationCircuit{ - InGt: NewGTEl(gt), - Res: NewGTEl(res), - } - err := test.IsSolved(&FinalExponentiationCircuit{}, &witness, ecc.BN254.ScalarField()) - assert.NoError(err) -} - -type PairCircuit struct { - InG1 G1Affine - InG2 G2Affine - Res GTEl -} - -func (c *PairCircuit) Define(api frontend.API) error { - pairing, err := NewPairing(api) - if err != nil { - return fmt.Errorf("new pairing: %w", err) - } - res, err := pairing.Pair([]*G1Affine{&c.InG1}, []*G2Affine{&c.InG2}) - if err != nil { - return fmt.Errorf("pair: %w", err) - } - pairing.ext12.assertIsEqual(res, &c.Res) - return nil -} - -func TestPairTestSolve(t *testing.T) { - assert := test.NewAssert(t) - p, q := randomG1G2Affines(assert) - res, err := bn254.Pair([]bn254.G1Affine{p}, []bn254.G2Affine{q}) - assert.NoError(err) - witness := PairCircuit{ - InG1: NewG1Affine(p), - InG2: NewG2Affine(q), - Res: NewGTEl(res), - } - err = test.IsSolved(&PairCircuit{}, &witness, ecc.BN254.ScalarField()) - assert.NoError(err) -} diff --git a/std/algebra/pairing_bn254/tower.go b/std/algebra/pairing_bn254/tower.go deleted file mode 100644 index c555680885..0000000000 --- a/std/algebra/pairing_bn254/tower.go +++ /dev/null @@ -1,833 +0,0 @@ -package pairing_bn254 - -import ( - "math/big" - - "github.com/consensys/gnark/std/math/emulated" -) - -type curveF = emulated.Field[emulated.BN254Fp] -type baseEl = emulated.Element[emulated.BN254Fp] - -type e2 struct { - A0, A1 baseEl -} - -type e6 struct { - B0, B1, B2 e2 -} - -type e12 struct { - C0, C1 e6 -} - -type ext2 struct { - fp *curveF - nonResidues map[int]map[int]*e2 -} - -func newExt2(baseField *curveF) *ext2 { - pwrs := map[int]map[int]struct { - A0 string - A1 string - }{ - 0: { - -1: {"21087453498479301738505683583845423561061080261299122796980902361914303298513", "14681138511599513868579906292550611339979233093309515871315818100066920017952"}, - 1: {"9", "1"}, - }, - 1: { - 1: {"8376118865763821496583973867626364092589906065868298776909617916018768340080", "16469823323077808223889137241176536799009286646108169935659301613961712198316"}, - 2: {"21575463638280843010398324269430826099269044274347216827212613867836435027261", "10307601595873709700152284273816112264069230130616436755625194854815875713954"}, - 3: {"2821565182194536844548159561693502659359617185244120367078079554186484126554", "3505843767911556378687030309984248845540243509899259641013678093033130930403"}, - 4: {"2581911344467009335267311115468803099551665605076196740867805258568234346338", "19937756971775647987995932169929341994314640652964949448313374472400716661030"}, - 5: {"685108087231508774477564247770172212460312782337200605669322048753928464687", "8447204650696766136447902020341177575205426561248465145919723016860428151883"}, - }, - 2: { - 1: {"21888242871839275220042445260109153167277707414472061641714758635765020556617", "0"}, - 2: {"21888242871839275220042445260109153167277707414472061641714758635765020556616", "0"}, - 3: {"21888242871839275222246405745257275088696311157297823662689037894645226208582", "0"}, - 4: {"2203960485148121921418603742825762020974279258880205651966", "0"}, - 5: {"2203960485148121921418603742825762020974279258880205651967", "0"}, - }, - 3: { - 1: {"11697423496358154304825782922584725312912383441159505038794027105778954184319", "303847389135065887422783454877609941456349188919719272345083954437860409601"}, - 2: {"3772000881919853776433695186713858239009073593817195771773381919316419345261", "2236595495967245188281701248203181795121068902605861227855261137820944008926"}, - 3: {"19066677689644738377698246183563772429336693972053703295610958340458742082029", "18382399103927718843559375435273026243156067647398564021675359801612095278180"}, - 4: {"5324479202449903542726783395506214481928257762400643279780343368557297135718", "16208900380737693084919495127334387981393726419856888799917914180988844123039"}, - 5: {"8941241848238582420466759817324047081148088512956452953208002715982955420483", "10338197737521362862238855242243140895517409139741313354160881284257516364953"}, - }, - } - nonResidues := make(map[int]map[int]*e2) - for pwr, v := range pwrs { - for coeff, v := range v { - el := e2{emulated.ValueOf[emulated.BN254Fp](v.A0), emulated.ValueOf[emulated.BN254Fp](v.A1)} - if nonResidues[pwr] == nil { - nonResidues[pwr] = make(map[int]*e2) - } - nonResidues[pwr][coeff] = &el - } - } - return &ext2{fp: baseField, nonResidues: nonResidues} -} - -type ext6 struct { - *ext2 -} - -func newExt6(baseField *curveF) *ext6 { - return &ext6{ext2: newExt2(baseField)} -} - -type ext12 struct { - *ext6 -} - -func newExt12(baseField *curveF) *ext12 { - return &ext12{ext6: newExt6(baseField)} -} - -// TODO: check where to use Mod and where ModMul. - -func (e ext2) mulByElement(x *e2, y *baseEl) *e2 { - // var yCopy fp.Element - // yCopy.Set(y) - z0 := e.fp.MulMod(&x.A0, y) // z.A0.Mul(&x.A0, &yCopy) - z1 := e.fp.MulMod(&x.A1, y) // z.A1.Mul(&x.A1, &yCopy) - return &e2{ // return z - A0: *z0, - A1: *z1, - } -} - -func (e ext2) conjugate(x *e2) *e2 { - z0 := x.A0 // z.A0 = x.A0 - z1 := e.fp.Neg(&x.A1) // z.A1.Neg(&x.A1) - return &e2{ // return z - A0: z0, - A1: *z1, - } -} - -func (e ext2) mulByNonResidueGeneric(x *e2, power, coef int) *e2 { - y := e.nonResidues[power][coef] - z := e.mul(x, y) - return z -} - -func (e ext2) mulByNonResidue(x *e2) *e2 { - /* - // below is the direct transliteration of the gnark-crypto code. Now only, - // for simplicity and debugging purposes, we do the non residue operations - // without optimisations. - - nine := big.NewInt(9) - // var a, b fp.Element - a := e.fp.MulConst(&x.A0, nine) // a.Double(&x.A0).Double(&a).Double(&a).Add(&a, &x.A0). - a = e.fp.Sub(a, &x.A1) // Sub(&a, &x.A1) - b := e.fp.MulConst(&x.A1, nine) // b.Double(&x.A1).Double(&b).Double(&b).Add(&b, &x.A1). - b = e.fp.Add(b, &x.A0) // Add(&b, &x.A0) - return &E2{ - A0: *a, // z.A0.Set(&a) - A1: *b, // z.A1.Set(&b) - } // return z - */ - // TODO: inline non-residue multiplication - return e.mulByNonResidueGeneric(x, 0, 1) -} - -func (e ext2) mulByNonResidueInv(x *e2) *e2 { - // TODO: to optimise with constant non-residue inverse - /* - // from gnark-crypto - // z.Mul(x, &nonResInverse) - // return z - */ - return e.mulByNonResidueGeneric(x, 0, -1) -} - -func (e ext2) mulByNonResidue1Power1(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 1, 1) -} - -func (e ext2) mulByNonResidue1Power2(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 1, 2) -} - -func (e ext2) mulByNonResidue1Power3(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 1, 3) -} - -func (e ext2) mulByNonResidue1Power4(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 1, 4) -} - -func (e ext2) mulByNonResidue1Power5(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 1, 5) -} - -func (e ext2) mulByNonResidue2Power1(x *e2) *e2 { - // TODO: A1 is 0, we can optimize for it - return e.mulByNonResidueGeneric(x, 2, 1) -} -func (e ext2) mulByNonResidue2Power2(x *e2) *e2 { - // TODO: A1 is 0, we can optimize for it - return e.mulByNonResidueGeneric(x, 2, 2) -} - -func (e ext2) mulByNonResidue2Power3(x *e2) *e2 { - // TODO: A1 is 0, we can optimize for it - return e.mulByNonResidueGeneric(x, 2, 3) -} - -func (e ext2) mulByNonResidue2Power4(x *e2) *e2 { - // TODO: A1 is 0, we can optimize for it - return e.mulByNonResidueGeneric(x, 2, 4) -} - -func (e ext2) mulByNonResidue2Power5(x *e2) *e2 { - // TODO: A1 is 0, we can optimize for it - return e.mulByNonResidueGeneric(x, 2, 5) -} - -func (e ext2) mulByNonResidue3Power1(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 3, 1) -} - -func (e ext2) mulByNonResidue3Power2(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 3, 2) -} - -func (e ext2) mulByNonResidue3Power3(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 3, 3) -} - -func (e ext2) mulByNonResidue3Power4(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 3, 4) -} - -func (e ext2) mulByNonResidue3Power5(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 3, 5) -} - -func (e ext2) mul(x, y *e2) *e2 { - // var a, b, c fp.Element - a := e.fp.Add(&x.A0, &x.A1) // a.Add(&x.A0, &x.A1) - b := e.fp.Add(&y.A0, &y.A1) // b.Add(&y.A0, &y.A1) - a = e.fp.MulMod(a, b) // a.Mul(&a, &b) - b = e.fp.MulMod(&x.A0, &y.A0) // b.Mul(&x.A0, &y.A0) - c := e.fp.MulMod(&x.A1, &y.A1) // c.Mul(&x.A1, &y.A1) - z1 := e.fp.Sub(a, b) // z.A1.Sub(&a, &b). - z1 = e.fp.Sub(z1, c) // Sub(&z.A1, &c) - z0 := e.fp.Sub(b, c) // z.A0.Sub(&b, &c) - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) add(x, y *e2) *e2 { - z0 := e.fp.Add(&x.A0, &y.A0) // z.A0.Add(&x.A0, &y.A0) - z1 := e.fp.Add(&x.A1, &y.A1) // z.A1.Add(&x.A1, &y.A1) - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) sub(x, y *e2) *e2 { - z0 := e.fp.Sub(&x.A0, &y.A0) // z.A0.Sub(&x.A0, &y.A0) - z1 := e.fp.Sub(&x.A1, &y.A1) // z.A1.Sub(&x.A1, &y.A1) - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) neg(x *e2) *e2 { - z0 := e.fp.Neg(&x.A0) // z.A0.Neg(&x.A0) - z1 := e.fp.Neg(&x.A1) // z.A1.Neg(&x.A1) - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) one() *e2 { - z0 := e.fp.One() // z.A0.SetOne() - z1 := e.fp.Zero() // z.A1.SetZero() - return &e2{ // return z - A0: *z0, - A1: *z1, - } -} - -func (e ext2) zero() *e2 { - z0 := e.fp.Zero() - z1 := e.fp.Zero() - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) square(x *e2) *e2 { - // var a, b fp.Element - a := e.fp.Add(&x.A0, &x.A1) // a.Add(&x.A0, &x.A1) - b := e.fp.Sub(&x.A0, &x.A1) // b.Sub(&x.A0, &x.A1) - a = e.fp.MulMod(a, b) // a.Mul(&a, &b) - b = e.fp.MulMod(&x.A0, &x.A1) // b.Mul(&x.A0, &x.A1). - b = e.fp.MulConst(b, big.NewInt(2)) // Double(&b) - return &e2{ - A0: *a, // z.A0.Set(&a) - A1: *b, // z.A1.Set(&b) - } -} - -func (e ext2) double(x *e2) *e2 { - two := big.NewInt(2) - z0 := e.fp.MulConst(&x.A0, two) // z.A0.Double(&x.A0) - z1 := e.fp.MulConst(&x.A1, two) // z.A1.Double(&x.A1) - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) halve(x *e2) *e2 { - // I'm trying to avoid hard-coding modulus here in case want to make generic - // for different curves. - // TODO: if implemented Half in field emulation, then replace with it. - one := e.fp.One() - two := e.fp.MulConst(one, big.NewInt(2)) - z0 := e.fp.Div(&x.A0, two) - z1 := e.fp.Div(&x.A1, two) - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) mulBybTwistCurveCoeff(x *e2) *e2 { - // var res E2 - res := e.mulByNonResidueInv(x) // res.MulByNonResidueInv(x) - z := e.double(res) // z.Double(&res). - z = e.add(z, res) // Add(&res, z) - return z // return z -} - -func (e ext2) inverse(x *e2) *e2 { - // var t0, t1 fp.Element - t0 := e.fp.MulMod(&x.A0, &x.A0) // t0.Square(&x.A0) - t1 := e.fp.MulMod(&x.A1, &x.A1) // t1.Square(&x.A1) - t0 = e.fp.Add(t0, t1) // t0.Add(&t0, &t1) - t1 = e.fp.Inverse(t0) // t1.Inverse(&t0) - z0 := e.fp.MulMod(&x.A0, t1) // z.A0.Mul(&x.A0, &t1) - z1 := e.fp.MulMod(&x.A1, t1) // z.A1.Mul(&x.A1, &t1). - z1 = e.fp.Neg(z1) // Neg(&z.A1) - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) assertIsEqual(x, y *e2) { - e.fp.AssertIsEqual(&x.A0, &y.A0) - e.fp.AssertIsEqual(&x.A1, &y.A1) -} - -func (e ext6) add(x, y *e6) *e6 { - z0 := e.ext2.add(&x.B0, &y.B0) // z.B0.Add(&x.B0, &y.B0) - z1 := e.ext2.add(&x.B1, &y.B1) // z.B1.Add(&x.B1, &y.B1) - z2 := e.ext2.add(&x.B2, &y.B2) // z.B2.Add(&x.B2, &y.B2) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} - -func (e ext6) neg(x *e6) *e6 { - z0 := e.ext2.neg(&x.B0) // z.B0.Neg(&x.B0) - z1 := e.ext2.neg(&x.B1) // z.B1.Neg(&x.B1) - z2 := e.ext2.neg(&x.B2) // z.B2.Neg(&x.B2) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} - -func (e ext6) sub(x, y *e6) *e6 { - z0 := e.ext2.sub(&x.B0, &y.B0) // z.B0.Sub(&x.B0, &y.B0) - z1 := e.ext2.sub(&x.B1, &y.B1) // z.B1.Sub(&x.B1, &y.B1) - z2 := e.ext2.sub(&x.B2, &y.B2) // z.B2.Sub(&x.B2, &y.B2) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} - -func (e ext6) mul(x, y *e6) *e6 { - // var t0, t1, t2, c0, c1, c2, tmp E2 - t0 := e.ext2.mul(&x.B0, &y.B0) // t0.Mul(&x.B0, &y.B0) - t1 := e.ext2.mul(&x.B1, &y.B1) // t1.Mul(&x.B1, &y.B1) - t2 := e.ext2.mul(&x.B2, &y.B2) // t2.Mul(&x.B2, &y.B2) - c0 := e.ext2.add(&x.B1, &x.B2) // c0.Add(&x.B1, &x.B2) - tmp := e.ext2.add(&y.B1, &y.B2) // tmp.Add(&y.B1, &y.B2) - c0 = e.ext2.mul(c0, tmp) // c0.Mul(&c0, &tmp). - c0 = e.ext2.sub(c0, t1) // Sub(&c0, &t1). - c0 = e.ext2.sub(c0, t2) // Sub(&c0, &t2). - c0 = e.ext2.mulByNonResidue(c0) // MulByNonResidue(&c0). - c0 = e.ext2.add(c0, t0) // Add(&c0, &t0) - c1 := e.ext2.add(&x.B0, &x.B1) // c1.Add(&x.B0, &x.B1) - tmp = e.ext2.add(&y.B0, &y.B1) // tmp.Add(&y.B0, &y.B1) - c1 = e.ext2.mul(c1, tmp) // c1.Mul(&c1, &tmp). - c1 = e.ext2.sub(c1, t0) // Sub(&c1, &t0). - c1 = e.ext2.sub(c1, t1) // Sub(&c1, &t1) - tmp = e.ext2.mulByNonResidue(t2) // tmp.MulByNonResidue(&t2) - c1 = e.ext2.add(c1, tmp) // c1.Add(&c1, &tmp) - tmp = e.ext2.add(&x.B0, &x.B2) // tmp.Add(&x.B0, &x.B2) - c2 := e.ext2.add(&y.B0, &y.B2) // c2.Add(&y.B0, &y.B2). - c2 = e.ext2.mul(c2, tmp) // Mul(&c2, &tmp). - c2 = e.ext2.sub(c2, t0) // Sub(&c2, &t0). - c2 = e.ext2.sub(c2, t2) // Sub(&c2, &t2). - c2 = e.ext2.add(c2, t1) // Add(&c2, &t1) - return &e6{ - B0: *c0, // z.B0.Set(&c0) - B1: *c1, // z.B1.Set(&c1) - B2: *c2, // z.B2.Set(&c2) - } // return z -} - -func (e ext6) double(x *e6) *e6 { - z0 := e.ext2.double(&x.B0) // z.B0.Double(&x.B0) - z1 := e.ext2.double(&x.B1) // z.B1.Double(&x.B1) - z2 := e.ext2.double(&x.B2) // z.B2.Double(&x.B2) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} - -func (e ext6) square(x *e6) *e6 { - // var c4, c5, c1, c2, c3, c0 E2 - c4 := e.ext2.mul(&x.B0, &x.B1) // c4.Mul(&x.B0, &x.B1). - c4 = e.ext2.double(c4) // Double(&c4) - c5 := e.ext2.square(&x.B2) // c5.Square(&x.B2) - c1 := e.ext2.mulByNonResidue(c5) // c1.MulByNonResidue(&c5). - c1 = e.ext2.add(c1, c4) // Add(&c1, &c4) - c2 := e.ext2.sub(c4, c5) // c2.Sub(&c4, &c5) - c3 := e.ext2.square(&x.B0) // c3.Square(&x.B0) - c4 = e.ext2.sub(&x.B0, &x.B1) // c4.Sub(&x.B0, &x.B1). - c4 = e.ext2.add(c4, &x.B2) // Add(&c4, &x.B2) - c5 = e.ext2.mul(&x.B1, &x.B2) // c5.Mul(&x.B1, &x.B2). - c5 = e.ext2.double(c5) // Double(&c5) - c4 = e.ext2.square(c4) // c4.Square(&c4) - c0 := e.ext2.mulByNonResidue(c5) // c0.MulByNonResidue(&c5). - c0 = e.ext2.add(c0, c3) // Add(&c0, &c3) - z2 := e.ext2.add(c2, c4) // z.B2.Add(&c2, &c4). - z2 = e.ext2.add(z2, c5) // Add(&z.B2, &c5). - z2 = e.ext2.sub(z2, c3) // Sub(&z.B2, &c3) - z0 := c0 // z.B0.Set(&c0) - z1 := c1 // z.B1.Set(&c1) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} - -func (e ext6) inverse(x *e6) *e6 { - // var t0, t1, t2, t3, t4, t5, t6, c0, c1, c2, d1, d2 E2 - t0 := e.ext2.square(&x.B0) // t0.Square(&x.B0) - t1 := e.ext2.square(&x.B1) // t1.Square(&x.B1) - t2 := e.ext2.square(&x.B2) // t2.Square(&x.B2) - t3 := e.ext2.mul(&x.B0, &x.B1) // t3.Mul(&x.B0, &x.B1) - t4 := e.ext2.mul(&x.B0, &x.B2) // t4.Mul(&x.B0, &x.B2) - t5 := e.ext2.mul(&x.B1, &x.B2) // t5.Mul(&x.B1, &x.B2) - c0 := e.ext2.mulByNonResidue(t5) // c0.MulByNonResidue(&t5). - c0 = e.ext2.neg(c0) // Neg(&c0). - c0 = e.ext2.add(c0, t0) // Add(&c0, &t0) - c1 := e.ext2.mulByNonResidue(t2) // c1.MulByNonResidue(&t2). - c1 = e.ext2.sub(c1, t3) // Sub(&c1, &t3) - c2 := e.ext2.sub(t1, t4) // c2.Sub(&t1, &t4) - t6 := e.ext2.mul(&x.B0, c0) // t6.Mul(&x.B0, &c0) - d1 := e.ext2.mul(&x.B2, c1) // d1.Mul(&x.B2, &c1) - d2 := e.ext2.mul(&x.B1, c2) // d2.Mul(&x.B1, &c2) - d1 = e.ext2.add(d1, d2) // d1.Add(&d1, &d2). - d1 = e.ext2.mulByNonResidue(d1) // MulByNonResidue(&d1) - t6 = e.ext2.add(t6, d1) // t6.Add(&t6, &d1) - t6 = e.ext2.inverse(t6) // t6.Inverse(&t6) - z0 := e.ext2.mul(c0, t6) // z.B0.Mul(&c0, &t6) - z1 := e.ext2.mul(c1, t6) // z.B1.Mul(&c1, &t6) - z2 := e.ext2.mul(c2, t6) // z.B2.Mul(&c2, &t6) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} -func (e ext6) mulByE2(x *e6, y *e2) *e6 { - // var yCopy E2 - // yCopy.Set(y) - z0 := e.ext2.mul(&x.B0, y) // z.B0.Mul(&x.B0, &yCopy) - z1 := e.ext2.mul(&x.B1, y) // z.B1.Mul(&x.B1, &yCopy) - z2 := e.ext2.mul(&x.B2, y) // z.B2.Mul(&x.B2, &yCopy) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} - -func (e ext6) mulBy01(z *e6, c0, c1 *e2) *e6 { - // var a, b, tmp, t0, t1, t2 E2 - a := e.ext2.mul(&z.B0, c0) // a.Mul(&z.B0, c0) - b := e.ext2.mul(&z.B1, c1) // b.Mul(&z.B1, c1) - tmp := e.ext2.add(&z.B1, &z.B2) // tmp.Add(&z.B1, &z.B2) - t0 := e.ext2.mul(c1, tmp) // t0.Mul(c1, &tmp) - t0 = e.ext2.sub(t0, b) // t0.Sub(&t0, &b) - t0 = e.ext2.mulByNonResidue(t0) // t0.MulByNonResidue(&t0) - t0 = e.ext2.add(t0, a) // t0.Add(&t0, &a) - tmp = e.ext2.add(&z.B0, &z.B2) // tmp.Add(&z.B0, &z.B2) - t2 := e.ext2.mul(c0, tmp) // t2.Mul(c0, &tmp) - t2 = e.ext2.sub(t2, a) // t2.Sub(&t2, &a) - t2 = e.ext2.add(t2, b) // t2.Add(&t2, &b) - t1 := e.ext2.add(c0, c1) // t1.Add(c0, c1) - tmp = e.ext2.add(&z.B0, &z.B1) // tmp.Add(&z.B0, &z.B1) - t1 = e.ext2.mul(t1, tmp) // t1.Mul(&t1, &tmp) - t1 = e.ext2.sub(t1, a) // t1.Sub(&t1, &a) - t1 = e.ext2.sub(t1, b) // t1.Sub(&t1, &b) - return &e6{ - B0: *t0, // z.B0.Set(&t0) - B1: *t1, // z.B1.Set(&t1) - B2: *t2, // z.B2.Set(&t2) - } // return z -} - -func (e ext6) mulByNonResidue(x *e6) *e6 { - z2, z1, z0 := &x.B1, &x.B0, &x.B2 // z.B2, z.B1, z.B0 = x.B1, x.B0, x.B2 - z0 = e.ext2.mulByNonResidue(z0) // z.B0.MulByNonResidue(&z.B0) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} - -func (e ext6) assertIsEqual(x, y *e6) { - e.ext2.assertIsEqual(&x.B0, &y.B0) - e.ext2.assertIsEqual(&x.B1, &y.B1) - e.ext2.assertIsEqual(&x.B2, &y.B2) -} - -func (e ext12) conjugate(x *e12) *e12 { - z1 := e.ext6.neg(&x.C1) // z.C1.Neg(&z.C1) - return &e12{ // return z - C0: x.C0, - C1: *z1, - } -} - -func (e ext12) inverse(x *e12) *e12 { - // var t0, t1, tmp E6 - t0 := e.ext6.square(&x.C0) // t0.Square(&x.C0) - t1 := e.ext6.square(&x.C1) // t1.Square(&x.C1) - tmp := e.ext6.mulByNonResidue(t1) // tmp.MulByNonResidue(&t1) - t0 = e.ext6.sub(t0, tmp) // t0.Sub(&t0, &tmp) - t1 = e.ext6.inverse(t0) // t1.Inverse(&t0) - z0 := e.ext6.mul(&x.C0, t1) // z.C0.Mul(&x.C0, &t1) - z1 := e.ext6.mul(&x.C1, t1) // z.C1.Mul(&x.C1, &t1). - z1 = e.ext6.neg(z1) // Neg(&z.C1) - return &e12{ // return z - C0: *z0, - C1: *z1, - } -} - -func (e ext12) mul(x, y *e12) *e12 { - // var a, b, c E6 - a := e.ext6.add(&x.C0, &x.C1) // a.Add(&x.C0, &x.C1) - b := e.ext6.add(&y.C0, &y.C1) // b.Add(&y.C0, &y.C1) - a = e.ext6.mul(a, b) // a.Mul(&a, &b) - b = e.ext6.mul(&x.C0, &y.C0) // b.Mul(&x.C0, &y.C0) - c := e.ext6.mul(&x.C1, &y.C1) // c.Mul(&x.C1, &y.C1) - z1 := e.ext6.sub(a, b) // z.C1.Sub(&a, &b). - z1 = e.ext6.sub(z1, c) // Sub(&z.C1, &c) - z0 := e.ext6.mulByNonResidue(c) // z.C0.MulByNonResidue(&c). - z0 = e.ext6.add(z0, b) // Add(&z.C0, &b) - return &e12{ // return z - C0: *z0, - C1: *z1, - } -} - -func (e ext12) cyclotomicSquare(x *e12) *e12 { - // var t [9]E2 - t0 := e.ext2.square(&x.C1.B1) // t[0].Square(&x.C1.B1) - t1 := e.ext2.square(&x.C0.B0) // t[1].Square(&x.C0.B0) - t6 := e.ext2.add(&x.C1.B1, &x.C0.B0) // t[6].Add(&x.C1.B1, &x.C0.B0). - t6 = e.ext2.square(t6) // Square(&t[6]). - t6 = e.ext2.sub(t6, t0) // Sub(&t[6], &t[0]). - t6 = e.ext2.sub(t6, t1) // Sub(&t[6], &t[1]) - t2 := e.ext2.square(&x.C0.B2) // t[2].Square(&x.C0.B2) - t3 := e.ext2.square(&x.C1.B0) // t[3].Square(&x.C1.B0) - t7 := e.ext2.add(&x.C0.B2, &x.C1.B0) // t[7].Add(&x.C0.B2, &x.C1.B0). - t7 = e.ext2.square(t7) // Square(&t[7]). - t7 = e.ext2.sub(t7, t2) // Sub(&t[7], &t[2]). - t7 = e.ext2.sub(t7, t3) // Sub(&t[7], &t[3]) - t4 := e.ext2.square(&x.C1.B2) // t[4].Square(&x.C1.B2) - t5 := e.ext2.square(&x.C0.B1) // t[5].Square(&x.C0.B1) - t8 := e.ext2.add(&x.C1.B2, &x.C0.B1) // t[8].Add(&x.C1.B2, &x.C0.B1). - t8 = e.ext2.square(t8) // Square(&t[8]). - t8 = e.ext2.sub(t8, t4) // Sub(&t[8], &t[4]). - t8 = e.ext2.sub(t8, t5) // Sub(&t[8], &t[5]). - t8 = e.ext2.mulByNonResidue(t8) // MulByNonResidue(&t[8]) - t0 = e.ext2.mulByNonResidue(t0) // t[0].MulByNonResidue(&t[0]). - t0 = e.ext2.add(t0, t1) // Add(&t[0], &t[1]) - t2 = e.ext2.mulByNonResidue(t2) // t[2].MulByNonResidue(&t[2]). - t2 = e.ext2.add(t2, t3) // Add(&t[2], &t[3]) - t4 = e.ext2.mulByNonResidue(t4) // t[4].MulByNonResidue(&t[4]). - t4 = e.ext2.add(t4, t5) // Add(&t[4], &t[5]) - z00 := e.ext2.sub(t0, &x.C0.B0) // z.C0.B0.Sub(&t[0], &x.C0.B0). - z00 = e.ext2.double(z00) // Double(&z.C0.B0). - z00 = e.ext2.add(z00, t0) // Add(&z.C0.B0, &t[0]) - z01 := e.ext2.sub(t2, &x.C0.B1) // z.C0.B1.Sub(&t[2], &x.C0.B1). - z01 = e.ext2.double(z01) // Double(&z.C0.B1). - z01 = e.ext2.add(z01, t2) // Add(&z.C0.B1, &t[2]) - z02 := e.ext2.sub(t4, &x.C0.B2) // z.C0.B2.Sub(&t[4], &x.C0.B2). - z02 = e.ext2.double(z02) // Double(&z.C0.B2). - z02 = e.ext2.add(z02, t4) // Add(&z.C0.B2, &t[4]) - z10 := e.ext2.add(t8, &x.C1.B0) // z.C1.B0.Add(&t[8], &x.C1.B0). - z10 = e.ext2.double(z10) // Double(&z.C1.B0). - z10 = e.ext2.add(z10, t8) // Add(&z.C1.B0, &t[8]) - z11 := e.ext2.add(t6, &x.C1.B1) // z.C1.B1.Add(&t[6], &x.C1.B1). - z11 = e.ext2.double(z11) // Double(&z.C1.B1). - z11 = e.ext2.add(z11, t6) // Add(&z.C1.B1, &t[6]) - z12 := e.ext2.add(t7, &x.C1.B2) // z.C1.B2.Add(&t[7], &x.C1.B2). - z12 = e.ext2.double(z12) // Double(&z.C1.B2). - z12 = e.ext2.add(z12, t7) // Add(&z.C1.B2, &t[7]) - return &e12{ // return z - C0: e6{ - B0: *z00, - B1: *z01, - B2: *z02, - }, - C1: e6{ - B0: *z10, - B1: *z11, - B2: *z12, - }, - } -} - -func (e ext12) frobenius(x *e12) *e12 { - // var t [6]E2 - t0 := e.ext2.conjugate(&x.C0.B0) // t[0].Conjugate(&x.C0.B0) - t1 := e.ext2.conjugate(&x.C0.B1) // t[1].Conjugate(&x.C0.B1) - t2 := e.ext2.conjugate(&x.C0.B2) // t[2].Conjugate(&x.C0.B2) - t3 := e.ext2.conjugate(&x.C1.B0) // t[3].Conjugate(&x.C1.B0) - t4 := e.ext2.conjugate(&x.C1.B1) // t[4].Conjugate(&x.C1.B1) - t5 := e.ext2.conjugate(&x.C1.B2) // t[5].Conjugate(&x.C1.B2) - t1 = e.ext2.mulByNonResidue1Power2(t1) // t[1].MulByNonResidue1Power2(&t[1]) - t2 = e.ext2.mulByNonResidue1Power4(t2) // t[2].MulByNonResidue1Power4(&t[2]) - t3 = e.ext2.mulByNonResidue1Power1(t3) // t[3].MulByNonResidue1Power1(&t[3]) - t4 = e.ext2.mulByNonResidue1Power3(t4) // t[4].MulByNonResidue1Power3(&t[4]) - t5 = e.ext2.mulByNonResidue1Power5(t5) // t[5].MulByNonResidue1Power5(&t[5]) - return &e12{ // return z - C0: e6{ - B0: *t0, // z.C0.B0 = t[0] - B1: *t1, // z.C0.B1 = t[1] - B2: *t2, // z.C0.B2 = t[2] - }, - C1: e6{ - B0: *t3, // z.C1.B0 = t[3] - B1: *t4, // z.C1.B1 = t[4] - B2: *t5, // z.C1.B2 = t[5] - }, - } -} - -func (e ext12) frobeniusSquare(x *e12) *e12 { - z00 := &x.C0.B0 // z.C0.B0 = x.C0.B0 - z01 := e.ext2.mulByNonResidue2Power2(&x.C0.B1) // z.C0.B1.MulByNonResidue2Power2(&x.C0.B1) - z02 := e.ext2.mulByNonResidue2Power4(&x.C0.B2) // z.C0.B2.MulByNonResidue2Power4(&x.C0.B2) - z10 := e.ext2.mulByNonResidue2Power1(&x.C1.B0) // z.C1.B0.MulByNonResidue2Power1(&x.C1.B0) - z11 := e.ext2.mulByNonResidue2Power3(&x.C1.B1) // z.C1.B1.MulByNonResidue2Power3(&x.C1.B1) - z12 := e.ext2.mulByNonResidue2Power5(&x.C1.B2) // z.C1.B2.MulByNonResidue2Power5(&x.C1.B2) - return &e12{ // return z - C0: e6{B0: *z00, B1: *z01, B2: *z02}, - C1: e6{B0: *z10, B1: *z11, B2: *z12}, - } -} - -func (e ext12) frobeniusCube(x *e12) *e12 { - // var t [6]E2 - t0 := e.ext2.conjugate(&x.C0.B0) // t[0].Conjugate(&x.C0.B0) - t1 := e.ext2.conjugate(&x.C0.B1) // t[1].Conjugate(&x.C0.B1) - t2 := e.ext2.conjugate(&x.C0.B2) // t[2].Conjugate(&x.C0.B2) - t3 := e.ext2.conjugate(&x.C1.B0) // t[3].Conjugate(&x.C1.B0) - t4 := e.ext2.conjugate(&x.C1.B1) // t[4].Conjugate(&x.C1.B1) - t5 := e.ext2.conjugate(&x.C1.B2) // t[5].Conjugate(&x.C1.B2) - t1 = e.ext2.mulByNonResidue3Power2(t1) // t[1].MulByNonResidue3Power2(&t[1]) - t2 = e.ext2.mulByNonResidue3Power4(t2) // t[2].MulByNonResidue3Power4(&t[2]) - t3 = e.ext2.mulByNonResidue3Power1(t3) // t[3].MulByNonResidue3Power1(&t[3]) - t4 = e.ext2.mulByNonResidue3Power3(t4) // t[4].MulByNonResidue3Power3(&t[4]) - t5 = e.ext2.mulByNonResidue3Power5(t5) // t[5].MulByNonResidue3Power5(&t[5]) - return &e12{ // return z - C0: e6{ - B0: *t0, // z.C0.B0 = t[0] - B1: *t1, // z.C0.B1 = t[1] - B2: *t2, // z.C0.B2 = t[2] - }, - C1: e6{ - B0: *t3, // z.C1.B0 = t[3] - B1: *t4, // z.C1.B1 = t[4] - B2: *t5, // z.C1.B2 = t[5] - }, - } -} - -func (e ext12) expt(x *e12) *e12 { - // var result, t0, t1, t2, t3, t4, t5, t6 E12 - t3 := e.cyclotomicSquare(x) // t3.CyclotomicSquare(x) - t5 := e.cyclotomicSquare(t3) // t5.CyclotomicSquare(&t3) - result := e.cyclotomicSquare(t5) // result.CyclotomicSquare(&t5) - t0 := e.cyclotomicSquare(result) // t0.CyclotomicSquare(&result) - t2 := e.mul(x, t0) // t2.Mul(x, &t0) - t0 = e.mul(t3, t2) // t0.Mul(&t3, &t2) - t1 := e.mul(x, t0) // t1.Mul(x, &t0) - t4 := e.mul(result, t2) // t4.Mul(&result, &t2) - t6 := e.cyclotomicSquare(t2) // t6.CyclotomicSquare(&t2) - t1 = e.mul(t0, t1) // t1.Mul(&t0, &t1) - t0 = e.mul(t3, t1) // t0.Mul(&t3, &t1) - t6 = e.nSquare(t6, 6) // t6.nSquare(6) - t5 = e.mul(t5, t6) // t5.Mul(&t5, &t6) - t5 = e.mul(t4, t5) // t5.Mul(&t4, &t5) - t5 = e.nSquare(t5, 7) // t5.nSquare(7) - t4 = e.mul(t4, t5) // t4.Mul(&t4, &t5) - t4 = e.nSquare(t4, 8) // t4.nSquare(8) - t4 = e.mul(t0, t4) // t4.Mul(&t0, &t4) - t3 = e.mul(t3, t4) // t3.Mul(&t3, &t4) - t3 = e.nSquare(t3, 6) // t3.nSquare(6) - t2 = e.mul(t2, t3) // t2.Mul(&t2, &t3) - t2 = e.nSquare(t2, 8) // t2.nSquare(8) - t2 = e.mul(t0, t2) // t2.Mul(&t0, &t2) - t2 = e.nSquare(t2, 6) // t2.nSquare(6) - t2 = e.mul(t0, t2) // t2.Mul(&t0, &t2) - t2 = e.nSquare(t2, 10) // t2.nSquare(10) - t1 = e.mul(t1, t2) // t1.Mul(&t1, &t2) - t1 = e.nSquare(t1, 6) // t1.nSquare(6) - t0 = e.mul(t0, t1) // t0.Mul(&t0, &t1) - z := e.mul(result, t0) // z.Mul(&result, &t0) - return z // return z -} - -func (e ext12) one() *e12 { - z000 := e.fp.One() - zero := e.fp.Zero() - return &e12{ - C0: e6{ - B0: e2{A0: *z000, A1: *zero}, - B1: e2{A0: *zero, A1: *zero}, - B2: e2{A0: *zero, A1: *zero}, - }, - C1: e6{ - B0: e2{A0: *zero, A1: *zero}, - B1: e2{A0: *zero, A1: *zero}, - B2: e2{A0: *zero, A1: *zero}, - }, - } -} - -func (e ext12) mulBy034(z *e12, c0, c3, c4 *e2) *e12 { - // var a, b, d E6 - a := e.ext6.mulByE2(&z.C0, c0) // a.MulByE2(&z.C0, c0) - // b.Set(&z.C1) - b := e.ext6.mulBy01(&z.C1, c3, c4) // b.MulBy01(c3, c4) - c0 = e.ext2.add(c0, c3) // c0.Add(c0, c3) - d := e.ext6.add(&z.C0, &z.C1) // d.Add(&z.C0, &z.C1) - d = e.ext6.mulBy01(d, c0, c4) // d.MulBy01(c0, c4) - z1 := e.add(a, b) // z.C1.Add(&a, &b). - z1 = e.neg(z1) // Neg(&z.C1). - z1 = e.add(z1, d) // Add(&z.C1, &d) - z0 := e.mulByNonResidue(b) // z.C0.MulByNonResidue(&b). - z0 = e.add(z0, a) // Add(&z.C0, &a) - return &e12{ // return z - C0: *z0, - C1: *z1, - } -} - -func (e ext12) square(x *e12) *e12 { - // var c0, c2, c3 E6 - c0 := e.ext6.sub(&x.C0, &x.C1) // c0.Sub(&x.C0, &x.C1) - c3 := e.ext6.mulByNonResidue(&x.C1) // c3.MulByNonResidue(&x.C1). - c3 = e.ext6.neg(c3) // Neg(&c3). - c3 = e.ext6.add(&x.C0, c3) // Add(&x.C0, &c3) - c2 := e.ext6.mul(&x.C0, &x.C1) // c2.Mul(&x.C0, &x.C1) - c0 = e.ext6.mul(c0, c3) // c0.Mul(&c0, &c3). - c0 = e.ext6.add(c0, c2) // Add(&c0, &c2) - z1 := e.ext6.double(c2) // z.C1.Double(&c2) - c2 = e.ext6.mulByNonResidue(c2) // c2.MulByNonResidue(&c2) - z0 := e.ext6.add(c0, c2) // z.C0.Add(&c0, &c2) - return &e12{ // return z - C0: *z0, - C1: *z1, - } -} - -func (e ext12) mulBy034by034(d0, d3, d4, c0, c3, c4 *e2) *e12 { - // var tmp, x0, x3, x4, x04, x03, x34 E2 - x0 := e.ext2.mul(c0, d0) // x0.Mul(c0, d0) - x3 := e.ext2.mul(c3, d3) // x3.Mul(c3, d3) - x4 := e.ext2.mul(c4, d4) // x4.Mul(c4, d4) - tmp := e.ext2.add(c0, c4) // tmp.Add(c0, c4) - x04 := e.ext2.add(d0, d4) // x04.Add(d0, d4). - x04 = e.ext2.mul(x04, tmp) // Mul(&x04, &tmp). - x04 = e.ext2.sub(x04, x0) // Sub(&x04, &x0). - x04 = e.ext2.sub(x04, x4) // Sub(&x04, &x4) - tmp = e.ext2.add(c0, c3) // tmp.Add(c0, c3) - x03 := e.ext2.add(d0, d3) // x03.Add(d0, d3). - x03 = e.ext2.mul(x03, tmp) // Mul(&x03, &tmp). - x03 = e.ext2.sub(x03, x0) // Sub(&x03, &x0). - x03 = e.ext2.sub(x03, x3) // Sub(&x03, &x3) - tmp = e.ext2.add(c3, c4) // tmp.Add(c3, c4) - x34 := e.ext2.add(d3, d4) // x34.Add(d3, d4). - x34 = e.ext2.mul(x34, tmp) // Mul(&x34, &tmp). - x34 = e.ext2.sub(x34, x3) // Sub(&x34, &x3). - x34 = e.ext2.sub(x34, x4) // Sub(&x34, &x4) - z00 := e.ext2.mulByNonResidue(x4) // z.C0.B0.MulByNonResidue(&x4). - z00 = e.ext2.add(z00, x0) // Add(&z.C0.B0, &x0) - z01 := x3 // z.C0.B1.Set(&x3) - z02 := x34 // z.C0.B2.Set(&x34) - z10 := x03 // z.C1.B0.Set(&x03) - z11 := x04 // z.C1.B1.Set(&x04) - z12 := e.ext2.zero() // z.C1.B2.SetZero() - return &e12{ // return z - C0: e6{ - B0: *z00, - B1: *z01, - B2: *z02, - }, - C1: e6{ - B0: *z10, - B1: *z11, - B2: *z12, - }, - } -} - -func (e ext12) assertIsEqual(x, y *e12) { - e.ext6.assertIsEqual(&x.C0, &y.C0) - e.ext6.assertIsEqual(&x.C1, &y.C1) -} - -func (e ext12) nSquare(z *e12, n int) *e12 { - for i := 0; i < n; i++ { - z = e.cyclotomicSquare(z) - } - return z -} From 130ed80b2d13732a8e20906a4c119f70244012d6 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Mon, 6 Mar 2023 17:28:57 +0100 Subject: [PATCH 056/464] fix: use sw_emulated instead of weierstrass --- std/algebra/emulated/sw_emulated/params_compute.go | 2 +- std/math/emulated/field_test.go | 2 +- std/signature/ecdsa/ecdsa.go | 12 ++++++------ std/signature/ecdsa/ecdsa_test.go | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/std/algebra/emulated/sw_emulated/params_compute.go b/std/algebra/emulated/sw_emulated/params_compute.go index 0edf3f78b4..fbdabea300 100644 --- a/std/algebra/emulated/sw_emulated/params_compute.go +++ b/std/algebra/emulated/sw_emulated/params_compute.go @@ -1,4 +1,4 @@ -package weierstrass +package sw_emulated import ( "math/big" diff --git a/std/math/emulated/field_test.go b/std/math/emulated/field_test.go index 927b23bc59..d1124f4e82 100644 --- a/std/math/emulated/field_test.go +++ b/std/math/emulated/field_test.go @@ -8,7 +8,7 @@ import ( bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/std/algebra/sw_bls12377" + "github.com/consensys/gnark/std/algebra/native/sw_bls12377" "github.com/consensys/gnark/test" ) diff --git a/std/signature/ecdsa/ecdsa.go b/std/signature/ecdsa/ecdsa.go index acf7286dcd..86bdb5bac7 100644 --- a/std/signature/ecdsa/ecdsa.go +++ b/std/signature/ecdsa/ecdsa.go @@ -1,7 +1,7 @@ /* Package ecdsa implements ECDSA signature verification over any elliptic curve. -The package depends on the [weierstrass] package for elliptic curve group +The package depends on the [emulated/sw_emulated] package for elliptic curve group operations using non-native arithmetic. Thus we can verify ECDSA signatures over any curve. The cost for a single secp256k1 signature verification is approximately 4M constraints in R1CS and 10M constraints in PLONKish. @@ -15,7 +15,7 @@ package ecdsa import ( "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/weierstrass" + "github.com/consensys/gnark/std/algebra/emulated/sw_emulated" "github.com/consensys/gnark/std/math/emulated" ) @@ -25,14 +25,14 @@ type Signature[Scalar emulated.FieldParams] struct { } // PublicKey represents the public key to verify the signature for. -type PublicKey[Base, Scalar emulated.FieldParams] weierstrass.AffinePoint[Base] +type PublicKey[Base, Scalar emulated.FieldParams] sw_emulated.AffinePoint[Base] // Verify asserts that the signature sig verifies for the message msg and public // key pk. The curve parameters params define the elliptic curve. // // We assume that the message msg is already hashed to the scalar field. -func (pk PublicKey[T, S]) Verify(api frontend.API, params weierstrass.CurveParams, msg *emulated.Element[S], sig *Signature[S]) { - cr, err := weierstrass.New[T, S](api, params) +func (pk PublicKey[T, S]) Verify(api frontend.API, params sw_emulated.CurveParams, msg *emulated.Element[S], sig *Signature[S]) { + cr, err := sw_emulated.New[T, S](api, params) if err != nil { // TODO: softer handling. panic(err) @@ -45,7 +45,7 @@ func (pk PublicKey[T, S]) Verify(api frontend.API, params weierstrass.CurveParam if err != nil { panic(err) } - pkpt := weierstrass.AffinePoint[T](pk) + pkpt := sw_emulated.AffinePoint[T](pk) sInv := scalarApi.Inverse(&sig.S) msInv := scalarApi.MulMod(msg, sInv) rsInv := scalarApi.MulMod(&sig.R, sInv) diff --git a/std/signature/ecdsa/ecdsa_test.go b/std/signature/ecdsa/ecdsa_test.go index 711ec69554..57ff1a4406 100644 --- a/std/signature/ecdsa/ecdsa_test.go +++ b/std/signature/ecdsa/ecdsa_test.go @@ -9,7 +9,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/secp256k1/ecdsa" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/weierstrass" + "github.com/consensys/gnark/std/algebra/emulated/sw_emulated" "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/test" ) @@ -21,7 +21,7 @@ type EcdsaCircuit[T, S emulated.FieldParams] struct { } func (c *EcdsaCircuit[T, S]) Define(api frontend.API) error { - c.Pub.Verify(api, weierstrass.GetCurveParams[T](), &c.Msg, &c.Sig) + c.Pub.Verify(api, sw_emulated.GetCurveParams[T](), &c.Msg, &c.Sig) return nil } @@ -134,7 +134,7 @@ func ExamplePublicKey_Verify() { Y: emulated.ValueOf[emulated.Secp256k1Fp](puby), } // signature verification assertion is done in-circuit - Pub.Verify(api, weierstrass.GetCurveParams[emulated.Secp256k1Fp](), &Msg, &Sig) + Pub.Verify(api, sw_emulated.GetCurveParams[emulated.Secp256k1Fp](), &Msg, &Sig) } // Example how to create a valid signature for secp256k1 From e88b1df86834bf09c3966c94e71436421e820357 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Mon, 6 Mar 2023 17:33:54 +0100 Subject: [PATCH 057/464] fix: update path to algebra/native --- std/commitments/kzg_bls12377/verifier.go | 4 ++-- std/commitments/kzg_bls24315/verifier.go | 4 ++-- std/groth16_bls12377/verifier.go | 4 ++-- std/groth16_bls12377/verifier_test.go | 2 +- std/groth16_bls24315/verifier.go | 4 ++-- std/groth16_bls24315/verifier_test.go | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/std/commitments/kzg_bls12377/verifier.go b/std/commitments/kzg_bls12377/verifier.go index d999e6396e..43dd15a83a 100644 --- a/std/commitments/kzg_bls12377/verifier.go +++ b/std/commitments/kzg_bls12377/verifier.go @@ -19,8 +19,8 @@ package kzg_bls12377 import ( "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/fields_bls12377" - "github.com/consensys/gnark/std/algebra/sw_bls12377" + "github.com/consensys/gnark/std/algebra/native/fields_bls12377" + "github.com/consensys/gnark/std/algebra/native/sw_bls12377" ) // Digest commitment of a polynomial. diff --git a/std/commitments/kzg_bls24315/verifier.go b/std/commitments/kzg_bls24315/verifier.go index e5704525f8..4d6680c072 100644 --- a/std/commitments/kzg_bls24315/verifier.go +++ b/std/commitments/kzg_bls24315/verifier.go @@ -19,8 +19,8 @@ package kzg_bls24315 import ( "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/fields_bls24315" - "github.com/consensys/gnark/std/algebra/sw_bls24315" + "github.com/consensys/gnark/std/algebra/native/fields_bls24315" + "github.com/consensys/gnark/std/algebra/native/sw_bls24315" ) // Digest commitment of a polynomial. diff --git a/std/groth16_bls12377/verifier.go b/std/groth16_bls12377/verifier.go index 6a43e585a8..8316d20479 100644 --- a/std/groth16_bls12377/verifier.go +++ b/std/groth16_bls12377/verifier.go @@ -24,8 +24,8 @@ import ( "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/frontend" groth16_bls12377 "github.com/consensys/gnark/internal/backend/bls12-377/groth16" - "github.com/consensys/gnark/std/algebra/fields_bls12377" - "github.com/consensys/gnark/std/algebra/sw_bls12377" + "github.com/consensys/gnark/std/algebra/native/fields_bls12377" + "github.com/consensys/gnark/std/algebra/native/sw_bls12377" ) // Proof represents a Groth16 proof diff --git a/std/groth16_bls12377/verifier_test.go b/std/groth16_bls12377/verifier_test.go index 61bc403ca5..beab2de62b 100644 --- a/std/groth16_bls12377/verifier_test.go +++ b/std/groth16_bls12377/verifier_test.go @@ -27,7 +27,7 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" groth16_bls12377 "github.com/consensys/gnark/internal/backend/bls12-377/groth16" - "github.com/consensys/gnark/std/algebra/sw_bls12377" + "github.com/consensys/gnark/std/algebra/native/sw_bls12377" "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/test" ) diff --git a/std/groth16_bls24315/verifier.go b/std/groth16_bls24315/verifier.go index 09487acbb3..836c20d33b 100644 --- a/std/groth16_bls24315/verifier.go +++ b/std/groth16_bls24315/verifier.go @@ -24,8 +24,8 @@ import ( "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/frontend" groth16_bls24315 "github.com/consensys/gnark/internal/backend/bls24-315/groth16" - "github.com/consensys/gnark/std/algebra/fields_bls24315" - "github.com/consensys/gnark/std/algebra/sw_bls24315" + "github.com/consensys/gnark/std/algebra/native/fields_bls24315" + "github.com/consensys/gnark/std/algebra/native/sw_bls24315" ) // Proof represents a Groth16 proof diff --git a/std/groth16_bls24315/verifier_test.go b/std/groth16_bls24315/verifier_test.go index 18da40b4b4..73bb075d19 100644 --- a/std/groth16_bls24315/verifier_test.go +++ b/std/groth16_bls24315/verifier_test.go @@ -27,7 +27,7 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" groth16_bls24315 "github.com/consensys/gnark/internal/backend/bls24-315/groth16" - "github.com/consensys/gnark/std/algebra/sw_bls24315" + "github.com/consensys/gnark/std/algebra/native/sw_bls24315" "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/test" ) From 440afdbe402e73af638e7a7038d972483db45791 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Mon, 6 Mar 2023 17:37:29 +0100 Subject: [PATCH 058/464] fix: update path to algebra/native --- internal/stats/snippet.go | 4 ++-- std/hints.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/stats/snippet.go b/internal/stats/snippet.go index 1f6ed7764c..a166bb849c 100644 --- a/internal/stats/snippet.go +++ b/internal/stats/snippet.go @@ -7,8 +7,8 @@ import ( "github.com/consensys/gnark" "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/sw_bls12377" - "github.com/consensys/gnark/std/algebra/sw_bls24315" + "github.com/consensys/gnark/std/algebra/native/sw_bls12377" + "github.com/consensys/gnark/std/algebra/native/sw_bls24315" "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/std/math/bits" "github.com/consensys/gnark/std/math/emulated" diff --git a/std/hints.go b/std/hints.go index c3bdc3713b..f9b85d3266 100644 --- a/std/hints.go +++ b/std/hints.go @@ -4,8 +4,8 @@ import ( "sync" "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/std/algebra/sw_bls12377" - "github.com/consensys/gnark/std/algebra/sw_bls24315" + "github.com/consensys/gnark/std/algebra/native/sw_bls12377" + "github.com/consensys/gnark/std/algebra/native/sw_bls24315" "github.com/consensys/gnark/std/math/bits" "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/std/selector" From 00d4c1a9d9afe184f14c8747e19f5d17408b042d Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Mon, 6 Mar 2023 20:42:00 +0100 Subject: [PATCH 059/464] fix: update path to algebra/native/twistededwards --- examples/rollup/circuit.go | 2 +- std/algebra/emulated/sw_emulated/doc.go | 4 ++-- std/algebra/emulated/sw_emulated/doc_test.go | 2 +- std/signature/eddsa/eddsa.go | 2 +- std/signature/eddsa/eddsa_test.go | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/rollup/circuit.go b/examples/rollup/circuit.go index 0b3b5000ba..27b47f4fda 100644 --- a/examples/rollup/circuit.go +++ b/examples/rollup/circuit.go @@ -20,7 +20,7 @@ import ( tedwards "github.com/consensys/gnark-crypto/ecc/twistededwards" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/accumulator/merkle" - "github.com/consensys/gnark/std/algebra/twistededwards" + "github.com/consensys/gnark/std/algebra/native/twistededwards" "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/std/signature/eddsa" ) diff --git a/std/algebra/emulated/sw_emulated/doc.go b/std/algebra/emulated/sw_emulated/doc.go index 085f6ac8d7..5ff58f9467 100644 --- a/std/algebra/emulated/sw_emulated/doc.go +++ b/std/algebra/emulated/sw_emulated/doc.go @@ -22,8 +22,8 @@ field. For now, we only have a single curve defined on every base field, but this may change in the future with the addition of additional curves. This package uses field emulation (unlike packages -[github.com/consensys/gnark/std/algebra/sw_bls12377] and -[github.com/consensys/gnark/std/algebra/sw_bls24315], which use 2-chains). This +[github.com/consensys/gnark/std/algebra/native/sw_bls12377] and +[github.com/consensys/gnark/std/algebra/native/sw_bls24315], which use 2-chains). This allows to use any curve over any native (SNARK) field. The drawback of this approach is the extreme cost of the operations. */ diff --git a/std/algebra/emulated/sw_emulated/doc_test.go b/std/algebra/emulated/sw_emulated/doc_test.go index 3ceb577bf9..bf939bfd3d 100644 --- a/std/algebra/emulated/sw_emulated/doc_test.go +++ b/std/algebra/emulated/sw_emulated/doc_test.go @@ -9,7 +9,7 @@ import ( "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/std/algebra/sw_emulated" + "github.com/consensys/gnark/std/algebra/emulated/sw_emulated" "github.com/consensys/gnark/std/math/emulated" ) diff --git a/std/signature/eddsa/eddsa.go b/std/signature/eddsa/eddsa.go index e285f00496..dcfcfc2870 100644 --- a/std/signature/eddsa/eddsa.go +++ b/std/signature/eddsa/eddsa.go @@ -24,7 +24,7 @@ import ( "github.com/consensys/gnark/std/hash" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/twistededwards" + "github.com/consensys/gnark/std/algebra/native/twistededwards" tedwards "github.com/consensys/gnark-crypto/ecc/twistededwards" diff --git a/std/signature/eddsa/eddsa_test.go b/std/signature/eddsa/eddsa_test.go index 657d337010..762bfb5ef0 100644 --- a/std/signature/eddsa/eddsa_test.go +++ b/std/signature/eddsa/eddsa_test.go @@ -27,7 +27,7 @@ import ( "github.com/consensys/gnark-crypto/signature/eddsa" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/internal/utils" - "github.com/consensys/gnark/std/algebra/twistededwards" + "github.com/consensys/gnark/std/algebra/native/twistededwards" "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/test" ) From 41cd258012233eaadabd752a94fc1d49c4cd2ef0 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 7 Mar 2023 00:34:51 +0100 Subject: [PATCH 060/464] fix: handle stack traces with deferred function (#521) * feat: add callDeferred method to test engine * fix: return error when deferred function fails * fix: always indent witness doctest output witness.ToJSON indents output when run in debug mode and not if in normal mode. But the doctest always expected non-indented output. * fix: further specify skipped stack frames in normal mode The function `callDeferred` is in `gnark/frontend`. We do not want to skip it as it is a break condition. --- backend/witness/witness_test.go | 14 +++++++++++--- debug/debug.go | 2 +- debug/symbol_table.go | 2 +- frontend/compile.go | 2 +- test/engine.go | 15 +++++++++++---- test/solver_test.go | 7 ++----- 6 files changed, 27 insertions(+), 15 deletions(-) diff --git a/backend/witness/witness_test.go b/backend/witness/witness_test.go index ba127b3240..d7feca17a4 100644 --- a/backend/witness/witness_test.go +++ b/backend/witness/witness_test.go @@ -1,6 +1,8 @@ package witness_test import ( + "bytes" + "encoding/json" "fmt" "reflect" "testing" @@ -47,11 +49,17 @@ func ExampleWitness() { // first get the circuit expected schema schema, _ := frontend.NewSchema(assignment) - json, _ := reconstructed.ToJSON(schema) + ret, _ := reconstructed.ToJSON(schema) - fmt.Println(string(json)) + var b bytes.Buffer + json.Indent(&b, ret, "", "\t") + fmt.Println(b.String()) // Output: - // {"X":42,"Y":8000,"E":1} + // { + // "X": 42, + // "Y": 8000, + // "E": 1 + // } } diff --git a/debug/debug.go b/debug/debug.go index 95e1079768..32b891c38a 100644 --- a/debug/debug.go +++ b/debug/debug.go @@ -56,7 +56,7 @@ func writeStack(sbb *strings.Builder, forceClean ...bool) { if strings.Contains(frame.File, "test/engine.go") { continue } - if strings.Contains(frame.File, "gnark/frontend") { + if strings.Contains(frame.File, "gnark/frontend/cs") { continue } file = filepath.Base(file) diff --git a/debug/symbol_table.go b/debug/symbol_table.go index 6ce2f68bb3..dc25c3e8d8 100644 --- a/debug/symbol_table.go +++ b/debug/symbol_table.go @@ -61,7 +61,7 @@ func (st *SymbolTable) CollectStack() []int { if strings.Contains(frame.File, "test/engine.go") { continue } - if strings.Contains(frame.File, "gnark/frontend") { + if strings.Contains(frame.File, "gnark/frontend/cs") { continue } frame.File = filepath.Base(frame.File) diff --git a/frontend/compile.go b/frontend/compile.go index 439b5802a5..02f0ec384f 100644 --- a/frontend/compile.go +++ b/frontend/compile.go @@ -124,7 +124,7 @@ func parseCircuit(builder Builder, circuit Circuit) (err error) { return fmt.Errorf("define circuit: %w", err) } if err = callDeferred(builder); err != nil { - return fmt.Errorf("") + return fmt.Errorf("deferred: %w", err) } return diff --git a/test/engine.go b/test/engine.go index ece99f8bad..e72ff5f8e7 100644 --- a/test/engine.go +++ b/test/engine.go @@ -125,10 +125,8 @@ func IsSolved(circuit, witness frontend.Circuit, field *big.Int, opts ...TestEng if err = c.Define(e); err != nil { return fmt.Errorf("define: %w", err) } - for i, cb := range circuitdefer.GetAll[func(frontend.API) error](e) { - if err = cb(e); err != nil { - return fmt.Errorf("defer %d: %w", i, err) - } + if err = callDeferred(e); err != nil { + return fmt.Errorf("deferred: %w", err) } log.Debug().Uint64("add", cptAdd). @@ -141,6 +139,15 @@ func IsSolved(circuit, witness frontend.Circuit, field *big.Int, opts ...TestEng return } +func callDeferred(builder *engine) error { + for i, cb := range circuitdefer.GetAll[func(frontend.API) error](builder) { + if err := cb(builder); err != nil { + return fmt.Errorf("defer fn %d: %w", i, err) + } + } + return nil +} + var cptAdd, cptMul, cptSub, cptToBinary, cptFromBinary, cptAssertIsEqual uint64 func (e *engine) Add(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { diff --git a/test/solver_test.go b/test/solver_test.go index 9fb88da92d..af8adbe9c1 100644 --- a/test/solver_test.go +++ b/test/solver_test.go @@ -18,7 +18,6 @@ import ( "github.com/consensys/gnark/frontend/cs/scs" "github.com/consensys/gnark/frontend/schema" "github.com/consensys/gnark/internal/backend/circuits" - "github.com/consensys/gnark/internal/circuitdefer" "github.com/consensys/gnark/internal/kvstore" "github.com/consensys/gnark/internal/tinyfield" "github.com/consensys/gnark/internal/utils" @@ -209,10 +208,8 @@ func isSolvedEngine(c frontend.Circuit, field *big.Int, opts ...TestEngineOption if err = c.Define(e); err != nil { return fmt.Errorf("define: %w", err) } - for i, cb := range circuitdefer.GetAll[func(frontend.API) error](e) { - if err = cb(e); err != nil { - return fmt.Errorf("defer %d: %w", i, err) - } + if err = callDeferred(e); err != nil { + return fmt.Errorf("") } return From 904cbc0dd2621c4af3f29985404a5048e9429d50 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 7 Mar 2023 10:22:41 +0100 Subject: [PATCH 061/464] docs: add documentation to std/algebra packages --- std/algebra/doc.go | 14 +++++++++++++ std/algebra/emulated/fields_bn254/doc.go | 7 +++++++ std/algebra/emulated/sw_bn254/doc.go | 2 +- std/algebra/native/fields_bls12377/doc.go | 9 +++++++++ std/algebra/native/fields_bls24315/doc.go | 10 ++++++++++ std/algebra/native/sw_bls12377/doc.go | 24 +++++++---------------- std/algebra/native/sw_bls24315/doc.go | 24 +++++++---------------- std/algebra/native/twistededwards/doc.go | 8 ++++++++ 8 files changed, 63 insertions(+), 35 deletions(-) create mode 100644 std/algebra/doc.go create mode 100644 std/algebra/emulated/fields_bn254/doc.go create mode 100644 std/algebra/native/fields_bls12377/doc.go create mode 100644 std/algebra/native/fields_bls24315/doc.go create mode 100644 std/algebra/native/twistededwards/doc.go diff --git a/std/algebra/doc.go b/std/algebra/doc.go new file mode 100644 index 0000000000..18e70aeac5 --- /dev/null +++ b/std/algebra/doc.go @@ -0,0 +1,14 @@ +// Package algebra implements: +// - base finite field 𝔽p arithmetic, +// - extension finite fields arithmetic (𝔽p², 𝔽p⁴, 𝔽p⁶, 𝔽p¹², 𝔽p²⁴), +// - short Weierstrass curve arithmetic over G1 (E/𝔽p) and G2 (Eₜ/𝔽p² or Eₜ/𝔽p⁴) +// - twisted Edwards curve arithmetic +// +// These arithmetic operations are implemented +// - using native field via the 2-chains BLS12-377/BW6-761 and BLS24-315/BW-633 +// (`native/`) or associated twisted Edwards (e.g. Jubjub/BLS12-381) and +// - using nonnative field via field emulation (`emulated/`). This allows to +// use any curve over any (SNARK) field (e.g. secp256k1 curve arithmetic over +// BN254 SNARK field or BN254 pairing over BN254 SNARK field). The drawback +// of this approach is the extreme cost of the operations. +package algebra diff --git a/std/algebra/emulated/fields_bn254/doc.go b/std/algebra/emulated/fields_bn254/doc.go new file mode 100644 index 0000000000..ae94b3c243 --- /dev/null +++ b/std/algebra/emulated/fields_bn254/doc.go @@ -0,0 +1,7 @@ +// Package fields_bn254 implements the fields arithmetic of the Fp12 tower +// used to compute the pairing over the BN254 curve. +// +// 𝔽p²[u] = 𝔽p/u²+1 +// 𝔽p⁶[v] = 𝔽p²/v³-9-u +// 𝔽p¹²[w] = 𝔽p⁶/w²-v +package fields_bn254 diff --git a/std/algebra/emulated/sw_bn254/doc.go b/std/algebra/emulated/sw_bn254/doc.go index 3dcd2d45c0..60bfca6876 100644 --- a/std/algebra/emulated/sw_bn254/doc.go +++ b/std/algebra/emulated/sw_bn254/doc.go @@ -1,4 +1,4 @@ -// Package sw_bn254 implements pairing over BN254 curve. +// Package sw_bn254 implements G1 and G2 arithmetics and pairing computation over BN254 curve. // // The implementation follows very closely the implementation of its out-circuit // counterpart in [gnark-crypto]. diff --git a/std/algebra/native/fields_bls12377/doc.go b/std/algebra/native/fields_bls12377/doc.go new file mode 100644 index 0000000000..69308f8280 --- /dev/null +++ b/std/algebra/native/fields_bls12377/doc.go @@ -0,0 +1,9 @@ +// Package fields_bls12377 implements the fields arithmetic of the Fp12 tower +// used to compute the pairing over the BLS12-377 curve. +// +// 𝔽p²[u] = 𝔽p/u²+5 +// 𝔽p⁶[v] = 𝔽p²/v³-u +// 𝔽p¹²[w] = 𝔽p⁶/w²-v +// +// Reference: https://eprint.iacr.org/2022/1162 +package fields_bls12377 diff --git a/std/algebra/native/fields_bls24315/doc.go b/std/algebra/native/fields_bls24315/doc.go new file mode 100644 index 0000000000..8b669480b7 --- /dev/null +++ b/std/algebra/native/fields_bls24315/doc.go @@ -0,0 +1,10 @@ +// Package fields_bls24315 implements the fields arithmetic of the Fp24 tower +// used to compute the pairing over the BLS24-315 curve. +// +// 𝔽p²[u] = 𝔽p/u²-13 +// 𝔽p⁴[v] = 𝔽p²/v²-u +// 𝔽p¹²[w] = 𝔽p⁴/w³-v +// 𝔽p²⁴[i] = 𝔽p¹²/i²-w +// +// Reference: https://eprint.iacr.org/2022/1162 +package fields_bls24315 diff --git a/std/algebra/native/sw_bls12377/doc.go b/std/algebra/native/sw_bls12377/doc.go index c9270127e8..3888dba835 100644 --- a/std/algebra/native/sw_bls12377/doc.go +++ b/std/algebra/native/sw_bls12377/doc.go @@ -1,18 +1,8 @@ -/* -Copyright © 2020 ConsenSys - -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 sw (short weierstrass) +// Package sw_bls12377 implements the arithmetics of G1, G2 and the pairing +// computation on BLS12-377 as a SNARK circuit over BW6-761. These two curves +// form a 2-chain so the operations use native field arithmetic. +// +// References: +// BW6-761: https://eprint.iacr.org/2020/351 +// Pairings in R1CS: https://eprint.iacr.org/2022/1162 package sw_bls12377 diff --git a/std/algebra/native/sw_bls24315/doc.go b/std/algebra/native/sw_bls24315/doc.go index 279e09879b..9a13dd4769 100644 --- a/std/algebra/native/sw_bls24315/doc.go +++ b/std/algebra/native/sw_bls24315/doc.go @@ -1,18 +1,8 @@ -/* -Copyright © 2020 ConsenSys - -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 sw (short weierstrass) +// Package sw_bls24315 implements the arithmetics of G1, G2 and the pairing +// computation on BLS24-315 as a SNARK circuit over BW6-633. These two curves +// form a 2-chain so the operations use native field arithmetic. +// +// References: +// BLS24-315/BW6-633: https://eprint.iacr.org/2021/1359 +// Pairings in R1CS: https://eprint.iacr.org/2022/1162 package sw_bls24315 diff --git a/std/algebra/native/twistededwards/doc.go b/std/algebra/native/twistededwards/doc.go new file mode 100644 index 0000000000..95b1486681 --- /dev/null +++ b/std/algebra/native/twistededwards/doc.go @@ -0,0 +1,8 @@ +// Package twistededwards implements the arithmetic of twisted Edwards curves +// in native fields. This uses associated twisted Edwards curves defined over +// the scalar field of the SNARK curves. +// +// Examples: +// Jubjub, Bandersnatch (a twisted Edwards) is defined over BLS12-381's scalar field +// Baby-Jubjub (a twisted Edwards) is defined over BN254's salar fields +package twistededwards From f2b7910c6a50c6272806bf21576e61efb2667167 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 7 Mar 2023 10:33:16 +0100 Subject: [PATCH 062/464] style(std/fields_*): separate Fpk ops specific to choice of pairing --- std/algebra/emulated/fields_bn254/e12.go | 7 ++ .../emulated/fields_bn254/e12_pairing.go | 6 -- std/algebra/native/fields_bls12377/e12.go | 74 ------------------ .../native/fields_bls12377/e12_pairing.go | 77 +++++++++++++++++++ std/algebra/native/fields_bls24315/e24.go | 72 ----------------- .../native/fields_bls24315/e24_pairing.go | 75 ++++++++++++++++++ 6 files changed, 159 insertions(+), 152 deletions(-) create mode 100644 std/algebra/native/fields_bls12377/e12_pairing.go create mode 100644 std/algebra/native/fields_bls24315/e24_pairing.go diff --git a/std/algebra/emulated/fields_bn254/e12.go b/std/algebra/emulated/fields_bn254/e12.go index 4425085a93..f8492ee5f0 100644 --- a/std/algebra/emulated/fields_bn254/e12.go +++ b/std/algebra/emulated/fields_bn254/e12.go @@ -111,6 +111,13 @@ func (e Ext12) CyclotomicSquare(x *E12) *E12 { } } +func (e Ext12) NCycloSquare(z *E12, n int) *E12 { + for i := 0; i < n; i++ { + z = e.CyclotomicSquare(z) + } + return z +} + func (e Ext12) Frobenius(x *E12) *E12 { // var t [6]E2 t0 := e.Ext2.Conjugate(&x.C0.B0) // t[0].Conjugate(&x.C0.B0) diff --git a/std/algebra/emulated/fields_bn254/e12_pairing.go b/std/algebra/emulated/fields_bn254/e12_pairing.go index d3c0822cab..2c31bb28ef 100644 --- a/std/algebra/emulated/fields_bn254/e12_pairing.go +++ b/std/algebra/emulated/fields_bn254/e12_pairing.go @@ -94,12 +94,6 @@ func (e Ext12) MulBy034(z *E12, c0, c3, c4 *E2) *E12 { } } -func (e Ext12) NCycloSquare(z *E12, n int) *E12 { - for i := 0; i < n; i++ { - z = e.CyclotomicSquare(z) - } - return z -} func (e Ext12) MulBy034by034(d0, d3, d4, c0, c3, c4 *E2) *E12 { // var tmp, x0, x3, x4, x04, x03, x34 E2 x0 := e.Ext2.Mul(c0, d0) // x0.Mul(c0, d0) diff --git a/std/algebra/native/fields_bls12377/e12.go b/std/algebra/native/fields_bls12377/e12.go index 9ae3ff02c7..f51413348b 100644 --- a/std/algebra/native/fields_bls12377/e12.go +++ b/std/algebra/native/fields_bls12377/e12.go @@ -345,51 +345,6 @@ func (e *E12) Conjugate(api frontend.API, e1 E12) *E12 { return e } -// MulBy034 multiplication by sparse element -func (e *E12) MulBy034(api frontend.API, c3, c4 E2) *E12 { - - var d E6 - - a := e.C0 - b := e.C1 - - b.MulBy01(api, c3, c4) - - c3.Add(api, E2{A0: 1, A1: 0}, c3) - d.Add(api, e.C0, e.C1) - d.MulBy01(api, c3, c4) - - e.C1.Add(api, a, b).Neg(api, e.C1).Add(api, e.C1, d) - e.C0.MulByNonResidue(api, b).Add(api, e.C0, a) - - return e -} - -// Mul034By034 multiplication of sparse element (1,0,0,c3,c4,0) by sparse element (1,0,0,d3,d4,0) -func (e *E12) Mul034By034(api frontend.API, d3, d4, c3, c4 E2) *E12 { - var one, tmp, x3, x4, x04, x03, x34 E2 - one.SetOne() - x3.Mul(api, c3, d3) - x4.Mul(api, c4, d4) - x04.Add(api, c4, d4) - x03.Add(api, c3, d3) - tmp.Add(api, c3, c4) - x34.Add(api, d3, d4). - Mul(api, x34, tmp). - Sub(api, x34, x3). - Sub(api, x34, x4) - - e.C0.B0.MulByNonResidue(api, x4). - Add(api, e.C0.B0, one) - e.C0.B1 = x3 - e.C0.B2 = x34 - e.C1.B0 = x03 - e.C1.B1 = x04 - e.C1.B2.SetZero() - - return e -} - // Frobenius applies frob to an fp12 elmt func (e *E12) Frobenius(api frontend.API, e1 E12) *E12 { @@ -588,35 +543,6 @@ func (e *E12) nSquareCompressed(api frontend.API, n int) { } } -// Expt compute e1**exponent, where the exponent is hardcoded -// This function is only used for the final expo of the pairing for bls12377, so the exponent is supposed to be hardcoded -// and on 64 bits. -func (e *E12) Expt(api frontend.API, e1 E12, exponent uint64) *E12 { - - res := e1 - - res.nSquareCompressed(api, 5) - res.Decompress(api, res) - res.Mul(api, res, e1) - x33 := res - res.nSquareCompressed(api, 7) - res.Decompress(api, res) - res.Mul(api, res, x33) - res.nSquareCompressed(api, 4) - res.Decompress(api, res) - res.Mul(api, res, e1) - res.CyclotomicSquare(api, res) - res.Mul(api, res, e1) - res.nSquareCompressed(api, 46) - res.Decompress(api, res) - res.Mul(api, res, e1) - - *e = res - - return e - -} - // Assign a value to self (witness assignment) func (e *E12) Assign(a *bls12377.E12) { e.C0.Assign(&a.C0) diff --git a/std/algebra/native/fields_bls12377/e12_pairing.go b/std/algebra/native/fields_bls12377/e12_pairing.go new file mode 100644 index 0000000000..5021d12ed2 --- /dev/null +++ b/std/algebra/native/fields_bls12377/e12_pairing.go @@ -0,0 +1,77 @@ +package fields_bls12377 + +import "github.com/consensys/gnark/frontend" + +// MulBy034 multiplication by sparse element +func (e *E12) MulBy034(api frontend.API, c3, c4 E2) *E12 { + + var d E6 + + a := e.C0 + b := e.C1 + + b.MulBy01(api, c3, c4) + + c3.Add(api, E2{A0: 1, A1: 0}, c3) + d.Add(api, e.C0, e.C1) + d.MulBy01(api, c3, c4) + + e.C1.Add(api, a, b).Neg(api, e.C1).Add(api, e.C1, d) + e.C0.MulByNonResidue(api, b).Add(api, e.C0, a) + + return e +} + +// Mul034By034 multiplication of sparse element (1,0,0,c3,c4,0) by sparse element (1,0,0,d3,d4,0) +func (e *E12) Mul034By034(api frontend.API, d3, d4, c3, c4 E2) *E12 { + var one, tmp, x3, x4, x04, x03, x34 E2 + one.SetOne() + x3.Mul(api, c3, d3) + x4.Mul(api, c4, d4) + x04.Add(api, c4, d4) + x03.Add(api, c3, d3) + tmp.Add(api, c3, c4) + x34.Add(api, d3, d4). + Mul(api, x34, tmp). + Sub(api, x34, x3). + Sub(api, x34, x4) + + e.C0.B0.MulByNonResidue(api, x4). + Add(api, e.C0.B0, one) + e.C0.B1 = x3 + e.C0.B2 = x34 + e.C1.B0 = x03 + e.C1.B1 = x04 + e.C1.B2.SetZero() + + return e +} + +// Expt compute e1**exponent, where the exponent is hardcoded +// This function is only used for the final expo of the pairing for bls12377, so the exponent is supposed to be hardcoded +// and on 64 bits. +func (e *E12) Expt(api frontend.API, e1 E12, exponent uint64) *E12 { + + res := e1 + + res.nSquareCompressed(api, 5) + res.Decompress(api, res) + res.Mul(api, res, e1) + x33 := res + res.nSquareCompressed(api, 7) + res.Decompress(api, res) + res.Mul(api, res, x33) + res.nSquareCompressed(api, 4) + res.Decompress(api, res) + res.Mul(api, res, e1) + res.CyclotomicSquare(api, res) + res.Mul(api, res, e1) + res.nSquareCompressed(api, 46) + res.Decompress(api, res) + res.Mul(api, res, e1) + + *e = res + + return e + +} diff --git a/std/algebra/native/fields_bls24315/e24.go b/std/algebra/native/fields_bls24315/e24.go index 7394f86374..ea21cf09c5 100644 --- a/std/algebra/native/fields_bls24315/e24.go +++ b/std/algebra/native/fields_bls24315/e24.go @@ -341,53 +341,6 @@ func (e *E24) Conjugate(api frontend.API, e1 E24) *E24 { return e } -// MulBy034 multiplication by sparse element -func (e *E24) MulBy034(api frontend.API, c3, c4 E4) *E24 { - - var d E12 - var one E4 - one.SetOne() - - a := e.D0 - b := e.D1 - - b.MulBy01(api, c3, c4) - - c3.Add(api, one, c3) - d.Add(api, e.D0, e.D1) - d.MulBy01(api, c3, c4) - - e.D1.Add(api, a, b).Neg(api, e.D1).Add(api, e.D1, d) - e.D0.MulByNonResidue(api, b).Add(api, e.D0, a) - - return e -} - -// Mul034By034 multiplication of sparse element (1,0,0,c3,c4,0) by sparse element (1,0,0,d3,d4,0) -func (e *E24) Mul034By034(api frontend.API, d3, d4, c3, c4 E4) *E24 { - var one, tmp, x3, x4, x04, x03, x34 E4 - one.SetOne() - x3.Mul(api, c3, d3) - x4.Mul(api, c4, d4) - x04.Add(api, c4, d4) - x03.Add(api, c3, d3) - tmp.Add(api, c3, c4) - x34.Add(api, d3, d4). - Mul(api, x34, tmp). - Sub(api, x34, x3). - Sub(api, x34, x4) - - e.D0.C0.MulByNonResidue(api, x4). - Add(api, e.D0.C0, one) - e.D0.C1 = x3 - e.D0.C2 = x34 - e.D1.C0 = x03 - e.D1.C1 = x04 - e.D1.C2.SetZero() - - return e -} - var InverseE24Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { var a, c bls24315.E24 @@ -595,31 +548,6 @@ func (e *E24) nSquare(api frontend.API, n int) { } } -// Expt compute e1**exponent, where the exponent is hardcoded -// This function is only used for the final expo of the pairing for bls24315, so the exponent is supposed to be hardcoded and on 32 bits. -func (e *E24) Expt(api frontend.API, x E24, exponent uint64) *E24 { - - xInv := E24{} - res := x - xInv.Conjugate(api, x) - - res.nSquare(api, 2) - res.Mul(api, res, xInv) - res.nSquareCompressed(api, 8) - res.Decompress(api, res) - res.Mul(api, res, xInv) - res.nSquare(api, 2) - res.Mul(api, res, x) - res.nSquareCompressed(api, 20) - res.Decompress(api, res) - res.Mul(api, res, xInv) - res.Conjugate(api, res) - - *e = res - - return e -} - // AssertIsEqual constraint self to be equal to other into the given constraint system func (e *E24) AssertIsEqual(api frontend.API, other E24) { e.D0.AssertIsEqual(api, other.D0) diff --git a/std/algebra/native/fields_bls24315/e24_pairing.go b/std/algebra/native/fields_bls24315/e24_pairing.go new file mode 100644 index 0000000000..b087eb8138 --- /dev/null +++ b/std/algebra/native/fields_bls24315/e24_pairing.go @@ -0,0 +1,75 @@ +package fields_bls24315 + +import "github.com/consensys/gnark/frontend" + +// MulBy034 multiplication by sparse element +func (e *E24) MulBy034(api frontend.API, c3, c4 E4) *E24 { + + var d E12 + var one E4 + one.SetOne() + + a := e.D0 + b := e.D1 + + b.MulBy01(api, c3, c4) + + c3.Add(api, one, c3) + d.Add(api, e.D0, e.D1) + d.MulBy01(api, c3, c4) + + e.D1.Add(api, a, b).Neg(api, e.D1).Add(api, e.D1, d) + e.D0.MulByNonResidue(api, b).Add(api, e.D0, a) + + return e +} + +// Mul034By034 multiplication of sparse element (1,0,0,c3,c4,0) by sparse element (1,0,0,d3,d4,0) +func (e *E24) Mul034By034(api frontend.API, d3, d4, c3, c4 E4) *E24 { + var one, tmp, x3, x4, x04, x03, x34 E4 + one.SetOne() + x3.Mul(api, c3, d3) + x4.Mul(api, c4, d4) + x04.Add(api, c4, d4) + x03.Add(api, c3, d3) + tmp.Add(api, c3, c4) + x34.Add(api, d3, d4). + Mul(api, x34, tmp). + Sub(api, x34, x3). + Sub(api, x34, x4) + + e.D0.C0.MulByNonResidue(api, x4). + Add(api, e.D0.C0, one) + e.D0.C1 = x3 + e.D0.C2 = x34 + e.D1.C0 = x03 + e.D1.C1 = x04 + e.D1.C2.SetZero() + + return e +} + +// Expt compute e1**exponent, where the exponent is hardcoded +// This function is only used for the final expo of the pairing for bls24315, so the exponent is supposed to be hardcoded and on 32 bits. +func (e *E24) Expt(api frontend.API, x E24, exponent uint64) *E24 { + + xInv := E24{} + res := x + xInv.Conjugate(api, x) + + res.nSquare(api, 2) + res.Mul(api, res, xInv) + res.nSquareCompressed(api, 8) + res.Decompress(api, res) + res.Mul(api, res, xInv) + res.nSquare(api, 2) + res.Mul(api, res, x) + res.nSquareCompressed(api, 20) + res.Decompress(api, res) + res.Mul(api, res, xInv) + res.Conjugate(api, res) + + *e = res + + return e +} From d400c0ba6003d8da863df11605f39f9d66112c44 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 7 Mar 2023 12:07:24 +0100 Subject: [PATCH 063/464] test: add emulated Fp2 tests --- std/algebra/emulated/fields_bn254/e2.go | 6 + std/algebra/emulated/fields_bn254/e2_test.go | 293 +++++++++++++++++++ 2 files changed, 299 insertions(+) create mode 100644 std/algebra/emulated/fields_bn254/e2_test.go diff --git a/std/algebra/emulated/fields_bn254/e2.go b/std/algebra/emulated/fields_bn254/e2.go index 8ba71003c7..0e81265933 100644 --- a/std/algebra/emulated/fields_bn254/e2.go +++ b/std/algebra/emulated/fields_bn254/e2.go @@ -3,6 +3,7 @@ package fields_bn254 import ( "math/big" + "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark/std/math/emulated" ) @@ -310,3 +311,8 @@ func (e Ext2) AssertIsEqual(x, y *E2) { e.fp.AssertIsEqual(&x.A0, &y.A0) e.fp.AssertIsEqual(&x.A1, &y.A1) } + +func (x *E2) assign(y *bn254.E2) { + x.A0 = emulated.ValueOf[emulated.BN254Fp](y.A0) + x.A1 = emulated.ValueOf[emulated.BN254Fp](y.A1) +} diff --git a/std/algebra/emulated/fields_bn254/e2_test.go b/std/algebra/emulated/fields_bn254/e2_test.go new file mode 100644 index 0000000000..175caa4741 --- /dev/null +++ b/std/algebra/emulated/fields_bn254/e2_test.go @@ -0,0 +1,293 @@ +package fields_bn254 + +import ( + "testing" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/bn254/fp" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/math/emulated" + "github.com/consensys/gnark/test" +) + +type e2Add struct { + A, B, C E2 +} + +func (circuit *e2Add) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt2(ba) + expected := e.Add(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestAddFp2(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bn254.E2 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Add(&a, &b) + + var witness e2Add + witness.A.assign(&a) + witness.B.assign(&b) + witness.C.assign(&c) + + err := test.IsSolved(&e2Add{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e2Sub struct { + A, B, C E2 +} + +func (circuit *e2Sub) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt2(ba) + expected := e.Sub(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestSubFp2(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bn254.E2 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Sub(&a, &b) + + var witness e2Sub + witness.A.assign(&a) + witness.B.assign(&b) + witness.C.assign(&c) + + err := test.IsSolved(&e2Sub{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e2Mul struct { + A, B, C E2 +} + +func (circuit *e2Mul) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt2(ba) + + expected := e.Mul(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestMulFp2(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bn254.E2 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Mul(&a, &b) + + var witness e2Mul + witness.A.assign(&a) + witness.B.assign(&b) + witness.C.assign(&c) + + err := test.IsSolved(&e2Mul{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e2Square struct { + A, C E2 +} + +func (circuit *e2Square) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt2(ba) + + expected := e.Square(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestSquareFp2(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E2 + _, _ = a.SetRandom() + c.Square(&a) + + var witness e2Square + witness.A.assign(&a) + witness.C.assign(&c) + + err := test.IsSolved(&e2Square{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e2MulByElement struct { + A E2 + B baseEl + C E2 `gnark:",public"` +} + +func (circuit *e2MulByElement) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt2(ba) + expected := e.MulByElement(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestMulByElement(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E2 + var b fp.Element + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.MulByElement(&a, &b) + + var witness e2MulByElement + witness.A.assign(&a) + witness.B = emulated.ValueOf[emulated.BN254Fp](b) + witness.C.assign(&c) + + err := test.IsSolved(&e2MulByElement{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e2MulBybTwistCurveCoeff struct { + A E2 + C E2 `gnark:",public"` +} + +func (circuit *e2MulBybTwistCurveCoeff) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt2(ba) + expected := e.MulBybTwistCurveCoeff(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestMulFp2BybTwistCurveCoeff(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E2 + _, _ = a.SetRandom() + c.MulBybTwistCurveCoeff(&a) + + var witness e2MulBybTwistCurveCoeff + witness.A.assign(&a) + witness.C.assign(&c) + + err := test.IsSolved(&e2MulBybTwistCurveCoeff{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e2Neg struct { + A E2 + C E2 `gnark:",public"` +} + +func (circuit *e2Neg) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt2(ba) + expected := e.Neg(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestNegFp2(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E2 + _, _ = a.SetRandom() + c.Neg(&a) + + var witness e2Neg + witness.A.assign(&a) + witness.C.assign(&c) + + err := test.IsSolved(&e2Neg{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type e2Conjugate struct { + A E2 + C E2 `gnark:",public"` +} + +func (circuit *e2Conjugate) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt2(ba) + expected := e.Conjugate(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestConjugateFp2(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E2 + _, _ = a.SetRandom() + c.Conjugate(&a) + + var witness e2Conjugate + witness.A.assign(&a) + witness.C.assign(&c) + + err := test.IsSolved(&e2Conjugate{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type e2Inverse struct { + A E2 + C E2 `gnark:",public"` +} + +func (circuit *e2Inverse) Define(api frontend.API) error { + + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt2(ba) + expected := e.Inverse(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestInverseFp2(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E2 + _, _ = a.SetRandom() + c.Inverse(&a) + + var witness e2Inverse + witness.A.assign(&a) + witness.C.assign(&c) + + err := test.IsSolved(&e2Inverse{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} From 26b9968a366ae9595f7819a0a29ca496e7450ee6 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 7 Mar 2023 12:17:03 +0100 Subject: [PATCH 064/464] test: add emulated Fp6 tests --- std/algebra/emulated/fields_bn254/e6.go | 10 + std/algebra/emulated/fields_bn254/e6_test.go | 231 +++++++++++++++++++ 2 files changed, 241 insertions(+) create mode 100644 std/algebra/emulated/fields_bn254/e6_test.go diff --git a/std/algebra/emulated/fields_bn254/e6.go b/std/algebra/emulated/fields_bn254/e6.go index a07d04d015..ead7d8278f 100644 --- a/std/algebra/emulated/fields_bn254/e6.go +++ b/std/algebra/emulated/fields_bn254/e6.go @@ -1,5 +1,9 @@ package fields_bn254 +import ( + "github.com/consensys/gnark-crypto/ecc/bn254" +) + type E6 struct { B0, B1, B2 E2 } @@ -199,3 +203,9 @@ func (e Ext6) AssertIsEqual(x, y *E6) { e.Ext2.AssertIsEqual(&x.B1, &y.B1) e.Ext2.AssertIsEqual(&x.B2, &y.B2) } + +func (x *E6) assign(y *bn254.E6) { + x.B0.assign(&y.B0) + x.B1.assign(&y.B1) + x.B2.assign(&y.B2) +} diff --git a/std/algebra/emulated/fields_bn254/e6_test.go b/std/algebra/emulated/fields_bn254/e6_test.go new file mode 100644 index 0000000000..d9af65ee68 --- /dev/null +++ b/std/algebra/emulated/fields_bn254/e6_test.go @@ -0,0 +1,231 @@ +package fields_bn254 + +import ( + "testing" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/math/emulated" + "github.com/consensys/gnark/test" +) + +type e6Add struct { + A, B, C E6 +} + +func (circuit *e6Add) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt6(ba) + expected := e.Add(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestAddFp6(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bn254.E6 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Add(&a, &b) + + var witness e6Add + witness.A.assign(&a) + witness.B.assign(&b) + witness.C.assign(&c) + + err := test.IsSolved(&e6Add{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e6Sub struct { + A, B, C E6 +} + +func (circuit *e6Sub) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt6(ba) + expected := e.Sub(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestSubFp6(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bn254.E6 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Sub(&a, &b) + + var witness e6Sub + witness.A.assign(&a) + witness.B.assign(&b) + witness.C.assign(&c) + + err := test.IsSolved(&e6Sub{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e6Mul struct { + A, B, C E6 +} + +func (circuit *e6Mul) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt6(ba) + + expected := e.Mul(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestMulFp6(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bn254.E6 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Mul(&a, &b) + + var witness e6Mul + witness.A.assign(&a) + witness.B.assign(&b) + witness.C.assign(&c) + + err := test.IsSolved(&e6Mul{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e6Square struct { + A, C E6 +} + +func (circuit *e6Square) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt6(ba) + + expected := e.Square(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestSquareFp6(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E6 + _, _ = a.SetRandom() + c.Square(&a) + + var witness e6Square + witness.A.assign(&a) + witness.C.assign(&c) + + err := test.IsSolved(&e6Square{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e6MulByE2 struct { + A E6 + B E2 + C E6 `gnark:",public"` +} + +func (circuit *e6MulByE2) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt6(ba) + expected := e.MulByE2(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestMulByE2(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E6 + var b bn254.E2 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.MulByE2(&a, &b) + + var witness e6MulByE2 + witness.A.assign(&a) + witness.B.assign(&b) + witness.C.assign(&c) + + err := test.IsSolved(&e6MulByE2{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e6Neg struct { + A E6 + C E6 `gnark:",public"` +} + +func (circuit *e6Neg) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt6(ba) + expected := e.Neg(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestNegFp6(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E6 + _, _ = a.SetRandom() + c.Neg(&a) + + var witness e6Neg + witness.A.assign(&a) + witness.C.assign(&c) + + err := test.IsSolved(&e6Neg{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type e6Inverse struct { + A E6 + C E6 `gnark:",public"` +} + +func (circuit *e6Inverse) Define(api frontend.API) error { + + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt6(ba) + expected := e.Inverse(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestInverseFp6(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E6 + _, _ = a.SetRandom() + c.Inverse(&a) + + var witness e6Inverse + witness.A.assign(&a) + witness.C.assign(&c) + + err := test.IsSolved(&e6Inverse{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} From 93d910390b1a257029c6beb00db8eb0515c210b9 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 7 Mar 2023 12:39:00 +0100 Subject: [PATCH 065/464] test: add emulated Fp12 tests --- std/algebra/emulated/fields_bn254/e12.go | 26 ++ .../emulated/fields_bn254/e12_pairing.go | 6 +- std/algebra/emulated/fields_bn254/e12_test.go | 235 ++++++++++++++++++ 3 files changed, 264 insertions(+), 3 deletions(-) create mode 100644 std/algebra/emulated/fields_bn254/e12_test.go diff --git a/std/algebra/emulated/fields_bn254/e12.go b/std/algebra/emulated/fields_bn254/e12.go index f8492ee5f0..77bd9727b7 100644 --- a/std/algebra/emulated/fields_bn254/e12.go +++ b/std/algebra/emulated/fields_bn254/e12.go @@ -1,5 +1,7 @@ package fields_bn254 +import "github.com/consensys/gnark-crypto/ecc/bn254" + type E12 struct { C0, C1 E6 } @@ -11,6 +13,25 @@ type Ext12 struct { func NewExt12(baseField *curveF) *Ext12 { return &Ext12{Ext6: NewExt6(baseField)} } + +func (e Ext12) Add(x, y *E12) *E12 { + z0 := e.Ext6.Add(&x.C0, &y.C0) // z.C0.Add(&x.A0, &y.A0) + z1 := e.Ext6.Add(&x.C1, &y.C1) // z.C1.Add(&x.A1, &y.A1) + return &E12{ + C0: *z0, + C1: *z1, + } +} + +func (e Ext12) Sub(x, y *E12) *E12 { + z0 := e.Ext6.Sub(&x.C0, &y.C0) // z.C0.Sub(&x.A0, &y.A0) + z1 := e.Ext6.Sub(&x.C1, &y.C1) // z.C1.Sub(&x.A1, &y.A1) + return &E12{ + C0: *z0, + C1: *z1, + } +} + func (e Ext12) Conjugate(x *E12) *E12 { z1 := e.Ext6.Neg(&x.C1) // z.C1.Neg(&z.C1) return &E12{ // return z @@ -224,3 +245,8 @@ func (e Ext12) AssertIsEqual(x, y *E12) { e.Ext6.AssertIsEqual(&x.C0, &y.C0) e.Ext6.AssertIsEqual(&x.C1, &y.C1) } + +func (x *E12) assign(y *bn254.E12) { + x.C0.assign(&y.C0) + x.C1.assign(&y.C1) +} diff --git a/std/algebra/emulated/fields_bn254/e12_pairing.go b/std/algebra/emulated/fields_bn254/e12_pairing.go index 2c31bb28ef..1f448e5ae2 100644 --- a/std/algebra/emulated/fields_bn254/e12_pairing.go +++ b/std/algebra/emulated/fields_bn254/e12_pairing.go @@ -83,11 +83,11 @@ func (e Ext12) MulBy034(z *E12, c0, c3, c4 *E2) *E12 { c0 = e.Ext2.Add(c0, c3) // c0.Add(c0, c3) d := e.Ext6.Add(&z.C0, &z.C1) // d.Add(&z.C0, &z.C1) d = e.Ext6.MulBy01(d, c0, c4) // d.MulBy01(c0, c4) - z1 := e.Add(a, b) // z.C1.Add(&a, &b). + z1 := e.Ext6.Add(a, b) // z.C1.Add(&a, &b). z1 = e.Neg(z1) // Neg(&z.C1). - z1 = e.Add(z1, d) // Add(&z.C1, &d) + z1 = e.Ext6.Add(z1, d) // Add(&z.C1, &d) z0 := e.MulByNonResidue(b) // z.C0.MulByNonResidue(&b). - z0 = e.Add(z0, a) // Add(&z.C0, &a) + z0 = e.Ext6.Add(z0, a) // Add(&z.C0, &a) return &E12{ // return z C0: *z0, C1: *z1, diff --git a/std/algebra/emulated/fields_bn254/e12_test.go b/std/algebra/emulated/fields_bn254/e12_test.go new file mode 100644 index 0000000000..b75fb62124 --- /dev/null +++ b/std/algebra/emulated/fields_bn254/e12_test.go @@ -0,0 +1,235 @@ +package fields_bn254 + +import ( + "testing" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/math/emulated" + "github.com/consensys/gnark/test" +) + +type e12Add struct { + A, B, C E12 +} + +func (circuit *e12Add) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt12(ba) + expected := e.Add(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestAddFp12(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bn254.E12 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Add(&a, &b) + + var witness e12Add + witness.A.assign(&a) + witness.B.assign(&b) + witness.C.assign(&c) + + err := test.IsSolved(&e12Add{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e12Sub struct { + A, B, C E12 +} + +func (circuit *e12Sub) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt12(ba) + expected := e.Sub(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestSubFp12(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bn254.E12 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Sub(&a, &b) + + var witness e12Sub + witness.A.assign(&a) + witness.B.assign(&b) + witness.C.assign(&c) + + err := test.IsSolved(&e12Sub{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e12Mul struct { + A, B, C E12 +} + +func (circuit *e12Mul) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt12(ba) + + expected := e.Mul(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestMulFp12(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bn254.E12 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Mul(&a, &b) + + var witness e12Mul + witness.A.assign(&a) + witness.B.assign(&b) + witness.C.assign(&c) + + err := test.IsSolved(&e12Mul{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e12Square struct { + A, C E12 +} + +func (circuit *e12Square) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt12(ba) + + expected := e.Square(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestSquareFp12(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E12 + _, _ = a.SetRandom() + c.Square(&a) + + var witness e12Square + witness.A.assign(&a) + witness.C.assign(&c) + + err := test.IsSolved(&e12Square{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e12CycloSquare struct { + A E12 + C E12 `gnark:",public"` +} + +func (circuit *e12CycloSquare) Define(api frontend.API) error { + + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt12(ba) + u := e.Square(&circuit.A) + v := e.CyclotomicSquare(&circuit.A) + e.AssertIsEqual(u, v) + e.AssertIsEqual(u, &circuit.C) + return nil +} + +func TestFp12CyclotomicSquare(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E12 + _, _ = a.SetRandom() + + // put a in the cyclotomic subgroup + var tmp bn254.E12 + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + c.CyclotomicSquare(&a) + + var witness e12Conjugate + witness.A.assign(&a) + witness.C.assign(&c) + + err := test.IsSolved(&e12CycloSquare{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type e12Conjugate struct { + A E12 + C E12 `gnark:",public"` +} + +func (circuit *e12Conjugate) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt12(ba) + expected := e.Conjugate(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestConjugateFp12(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E12 + _, _ = a.SetRandom() + c.Conjugate(&a) + + var witness e12Conjugate + witness.A.assign(&a) + witness.C.assign(&c) + + err := test.IsSolved(&e12Conjugate{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type e12Inverse struct { + A E12 + C E12 `gnark:",public"` +} + +func (circuit *e12Inverse) Define(api frontend.API) error { + + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt12(ba) + expected := e.Inverse(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestInverseFp12(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E12 + _, _ = a.SetRandom() + c.Inverse(&a) + + var witness e12Inverse + witness.A.assign(&a) + witness.C.assign(&c) + + err := test.IsSolved(&e12Inverse{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} From ee18ac8e9c0da692a4faa4e4846246dba4d0d8a4 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 7 Mar 2023 15:15:34 +0100 Subject: [PATCH 066/464] fix: initialize new variable if field emulation multiplication check (#534) * fix: create new variable before accumulating limbs in mul * docs: extend MulAcc documentation with creating new variable --- frontend/api.go | 13 ++++++++++--- std/math/emulated/field_ops.go | 6 +++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/frontend/api.go b/frontend/api.go index 5742617c20..a54e2ec3c0 100644 --- a/frontend/api.go +++ b/frontend/api.go @@ -30,9 +30,16 @@ type API interface { // Add returns res = i1+i2+...in Add(i1, i2 Variable, in ...Variable) Variable - // MulAcc sets and return a = a + (b*c) - // ! may mutate a without allocating a new result - // ! always use MulAcc(...) result for correctness + // MulAcc sets and return a = a + (b*c). + // + // ! The method may mutate a without allocating a new result. If the input + // is used elsewhere, then first initialize new variable, for example by + // doing: + // + // acopy := api.Mul(a, 1) + // acopy = MulAcc(acopy, b, c) + // + // ! But it may not modify a, always use MulAcc(...) result for correctness. MulAcc(a, b, c Variable) Variable // Neg returns -i diff --git a/std/math/emulated/field_ops.go b/std/math/emulated/field_ops.go index c64b6a24d7..099b588d70 100644 --- a/std/math/emulated/field_ops.go +++ b/std/math/emulated/field_ops.go @@ -178,9 +178,9 @@ func (f *Field[T]) mul(a, b *Element[T], nextOverflow uint) *Element[T] { w := new(big.Int) for c := 1; c <= len(mulResult); c++ { w.SetInt64(1) // c^i - l := a.Limbs[0] - r := b.Limbs[0] - o := mulResult[0] + l := f.api.Mul(a.Limbs[0], 1) + r := f.api.Mul(b.Limbs[0], 1) + o := f.api.Mul(mulResult[0], 1) for i := 1; i < len(mulResult); i++ { w.Lsh(w, uint(c)) From 73896a711dddede59a7da4cc2a3aab7677f63bba Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 7 Mar 2023 16:12:03 +0100 Subject: [PATCH 067/464] fix: stable levelbuilder hint mapping (#533) * test: add non-determinstic regression test * fix: level-builder stability * refactor: move also output map init to end for clarity --- constraint/level_builder.go | 7 ++++-- constraint/level_builder_test.go | 42 ++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 constraint/level_builder_test.go diff --git a/constraint/level_builder.go b/constraint/level_builder.go index c2b1d8c155..562cd0a930 100644 --- a/constraint/level_builder.go +++ b/constraint/level_builder.go @@ -9,10 +9,9 @@ package constraint // We build a graph of dependency; we say that a wire is solved at a level l // --> l = max(level_of_dependencies(wire)) + 1 func (system *System) updateLevel(cID int, c Iterable) { - system.lbOutputs = system.lbOutputs[:0] - system.lbHints = map[*HintMapping]struct{}{} level := -1 wireIterator := c.WireIterator() + for wID := wireIterator(); wID != -1; wID = wireIterator() { // iterate over all wires of the R1C system.processWire(uint32(wID), &level) @@ -36,6 +35,10 @@ func (system *System) updateLevel(cID int, c Iterable) { } else { system.Levels[level] = append(system.Levels[level], cID) } + // clean the table. NB! Do not remove or move, this is required to make the + // compilation deterministic. + system.lbOutputs = system.lbOutputs[:0] + system.lbHints = map[*HintMapping]struct{}{} } func (system *System) processWire(wireID uint32, maxLevel *int) { diff --git a/constraint/level_builder_test.go b/constraint/level_builder_test.go new file mode 100644 index 0000000000..c7489409e1 --- /dev/null +++ b/constraint/level_builder_test.go @@ -0,0 +1,42 @@ +package constraint_test + +import ( + "fmt" + "math/big" + "testing" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/test" +) + +func idHint(_ *big.Int, in []*big.Int, out []*big.Int) error { + if len(in) != len(out) { + return fmt.Errorf("in/out length mismatch %d≠%d", len(in), len(out)) + } + for i := range in { + out[i].Set(in[i]) + } + return nil +} + +type idHintCircuit struct { + X frontend.Variable +} + +func (c *idHintCircuit) Define(api frontend.API) error { + x, err := api.Compiler().NewHint(idHint, 1, c.X) + if err != nil { + return err + } + api.AssertIsEqual(x[0], c.X) + return nil +} + +func TestIdHint(t *testing.T) { + solver.RegisterHint(idHint) + assignment := idHintCircuit{0} + test.NewAssert(t).SolvingSucceeded(&idHintCircuit{}, &assignment, test.WithBackends(backend.GROTH16), test.WithCurves(ecc.BN254)) +} From 7dc3607eba99728e65dd85b22b44c1e8dc30b802 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 7 Mar 2023 17:02:27 +0100 Subject: [PATCH 068/464] test(fields_bn254): add remaing tests --- std/algebra/emulated/fields_bn254/e12_test.go | 81 ++++++++++++ std/algebra/emulated/fields_bn254/e2_test.go | 123 ++++++++++++++++++ std/algebra/emulated/fields_bn254/e6_test.go | 71 +++++++++- 3 files changed, 274 insertions(+), 1 deletion(-) diff --git a/std/algebra/emulated/fields_bn254/e12_test.go b/std/algebra/emulated/fields_bn254/e12_test.go index b75fb62124..040d3e16af 100644 --- a/std/algebra/emulated/fields_bn254/e12_test.go +++ b/std/algebra/emulated/fields_bn254/e12_test.go @@ -104,6 +104,48 @@ func TestMulFp12(t *testing.T) { } +type e12MulBy034by034 struct { + C0, C3, C4 E2 + D0, D3, D4 E2 + C E12 `gnark:",public"` +} + +func (circuit *e12MulBy034by034) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt12(ba) + expected := e.MulBy034by034(&circuit.C0, &circuit.C3, &circuit.C4, &circuit.D0, &circuit.D3, &circuit.D4) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestMulFp12By034by034(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var c bn254.E12 + var c0, c3, c4, d0, d3, d4 bn254.E2 + _, _ = c0.SetRandom() + _, _ = c3.SetRandom() + _, _ = c4.SetRandom() + _, _ = d0.SetRandom() + _, _ = d3.SetRandom() + _, _ = d4.SetRandom() + c.Mul034by034(&c0, &c3, &c4, &d0, &d3, &d4) + var witness e12MulBy034by034 + witness.C0.assign(&c0) + witness.C3.assign(&c3) + witness.C4.assign(&c4) + witness.D0.assign(&d0) + witness.D3.assign(&d3) + witness.D4.assign(&d4) + witness.C.assign(&c) + + err := test.IsSolved(&e12MulBy034by034{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + type e12Square struct { A, C E12 } @@ -233,3 +275,42 @@ func TestInverseFp12(t *testing.T) { err := test.IsSolved(&e12Inverse{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } + +type e12Expt struct { + A E12 + C E12 `gnark:",public"` +} + +func (circuit *e12Expt) Define(api frontend.API) error { + + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt12(ba) + expected := e.Expt(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestFp12Expt(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E12 + _, _ = a.SetRandom() + + // put a in the cyclotomic subgroup + var tmp bn254.E12 + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + + c.Expt(&a) + + var witness e12Expt + witness.A.assign(&a) + witness.C.assign(&c) + + err := test.IsSolved(&e12Expt{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} diff --git a/std/algebra/emulated/fields_bn254/e2_test.go b/std/algebra/emulated/fields_bn254/e2_test.go index 175caa4741..dcba17ff5c 100644 --- a/std/algebra/emulated/fields_bn254/e2_test.go +++ b/std/algebra/emulated/fields_bn254/e2_test.go @@ -73,6 +73,67 @@ func TestSubFp2(t *testing.T) { } +type e2Double struct { + A, C E2 +} + +func (circuit *e2Double) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt2(ba) + expected := e.Double(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestDoubleFp2(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bn254.E2 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Double(&a) + + var witness e2Double + witness.A.assign(&a) + witness.C.assign(&c) + + err := test.IsSolved(&e2Double{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e2Halve struct { + A, C E2 +} + +func (circuit *e2Halve) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt2(ba) + expected := e.Halve(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestHalveFp2(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bn254.E2 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c = a + c.Halve() + + var witness e2Halve + witness.A.assign(&a) + witness.C.assign(&c) + + err := test.IsSolved(&e2Halve{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + type e2Mul struct { A, B, C E2 } @@ -201,6 +262,68 @@ func TestMulFp2BybTwistCurveCoeff(t *testing.T) { } +type e2MulByNonResidue struct { + A E2 + C E2 `gnark:",public"` +} + +func (circuit *e2MulByNonResidue) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt2(ba) + expected := e.MulByNonResidue(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestMulFp2ByNonResidue(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E2 + _, _ = a.SetRandom() + c.MulByNonResidue(&a) + + var witness e2MulByNonResidue + witness.A.assign(&a) + witness.C.assign(&c) + + err := test.IsSolved(&e2MulByNonResidue{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e2MulByNonResidueInv struct { + A E2 + C E2 `gnark:",public"` +} + +func (circuit *e2MulByNonResidueInv) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt2(ba) + expected := e.MulByNonResidueInv(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestMulFp2ByNonResidueInv(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E2 + _, _ = a.SetRandom() + c.MulByNonResidueInv(&a) + + var witness e2MulByNonResidueInv + witness.A.assign(&a) + witness.C.assign(&c) + + err := test.IsSolved(&e2MulByNonResidueInv{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + type e2Neg struct { A E2 C E2 `gnark:",public"` diff --git a/std/algebra/emulated/fields_bn254/e6_test.go b/std/algebra/emulated/fields_bn254/e6_test.go index d9af65ee68..5f6aebd0d9 100644 --- a/std/algebra/emulated/fields_bn254/e6_test.go +++ b/std/algebra/emulated/fields_bn254/e6_test.go @@ -134,6 +134,37 @@ func TestSquareFp6(t *testing.T) { } +type e6MulByNonResidue struct { + A E6 + C E6 `gnark:",public"` +} + +func (circuit *e6MulByNonResidue) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt6(ba) + expected := e.MulByNonResidue(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestMulFp6ByNonResidue(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E6 + _, _ = a.SetRandom() + c.MulByNonResidue(&a) + + var witness e6MulByNonResidue + witness.A.assign(&a) + witness.C.assign(&c) + + err := test.IsSolved(&e6MulByNonResidue{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + type e6MulByE2 struct { A E6 B E2 @@ -149,7 +180,7 @@ func (circuit *e6MulByE2) Define(api frontend.API) error { return nil } -func TestMulByE2(t *testing.T) { +func TestMulFp6ByE2(t *testing.T) { assert := test.NewAssert(t) // witness values @@ -169,6 +200,44 @@ func TestMulByE2(t *testing.T) { } +type e6MulBy01 struct { + A E6 + C0, C1 E2 + C E6 `gnark:",public"` +} + +func (circuit *e6MulBy01) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt6(ba) + expected := e.MulBy01(&circuit.A, &circuit.C0, &circuit.C1) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestMulFp6By01(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E6 + var C0, C1 bn254.E2 + _, _ = a.SetRandom() + _, _ = C0.SetRandom() + _, _ = C1.SetRandom() + c.Set(&a) + c.MulBy01(&C0, &C1) + + var witness e6MulBy01 + witness.A.assign(&a) + witness.C0.assign(&C0) + witness.C1.assign(&C1) + witness.C.assign(&c) + + err := test.IsSolved(&e6MulBy01{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + type e6Neg struct { A E6 C E6 `gnark:",public"` From 25fc68cd7a136403c4466ea7c47f719a7f17c4fc Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 7 Mar 2023 18:41:37 +0100 Subject: [PATCH 069/464] perf(bn254/pairing): use Karabina cyclo sq instead of GS in Expt --- std/algebra/emulated/fields_bn254/e12.go | 148 ++++++++++++++++++ .../emulated/fields_bn254/e12_pairing.go | 71 +++++---- std/algebra/emulated/fields_bn254/e12_test.go | 42 ++++- std/algebra/emulated/sw_bn254/pairing.go | 72 +++++---- 4 files changed, 263 insertions(+), 70 deletions(-) diff --git a/std/algebra/emulated/fields_bn254/e12.go b/std/algebra/emulated/fields_bn254/e12.go index 77bd9727b7..9fd88faf79 100644 --- a/std/algebra/emulated/fields_bn254/e12.go +++ b/std/algebra/emulated/fields_bn254/e12.go @@ -139,6 +139,154 @@ func (e Ext12) NCycloSquare(z *E12, n int) *E12 { return z } +// Karabina's compressed cyclotomic square +// https://eprint.iacr.org/2010/542.pdf +// Th. 3.2 with minor modifications to fit our tower +func (e Ext12) CyclotomicSquareCompressed(x *E12) *E12 { + + // t0 = g1^2 + t0 := e.Ext6.Ext2.Square(&x.C0.B1) + // t1 = g5^2 + t1 := e.Ext6.Ext2.Square(&x.C1.B2) + // t5 = g1 + g5 + t5 := e.Ext6.Ext2.Add(&x.C0.B1, &x.C1.B2) + // t2 = (g1 + g5)^2 + t2 := e.Ext6.Ext2.Square(t5) + + // t3 = g1^2 + g5^2 + t3 := e.Ext6.Ext2.Add(t0, t1) + // t5 = 2 * g1 * g5 + t5 = e.Ext6.Ext2.Sub(t2, t3) + + // t6 = g3 + g2 + t6 := e.Ext6.Ext2.Add(&x.C1.B0, &x.C0.B2) + // t3 = (g3 + g2)^2 + t3 = e.Ext6.Ext2.Square(t6) + // t2 = g3^2 + t2 = e.Ext6.Ext2.Square(&x.C1.B0) + + // t6 = 2 * nr * g1 * g5 + t6 = e.Ext6.Ext2.MulByNonResidue(t5) + // t5 = 4 * nr * g1 * g5 + 2 * g3 + t5 = e.Ext6.Ext2.Add(t6, &x.C1.B0) + t5 = e.Ext6.Ext2.Double(t5) + // z3 = 6 * nr * g1 * g5 + 2 * g3 + C1B0 := *e.Ext6.Ext2.Add(t5, t6) + + // t4 = nr * g5^2 + t4 := e.Ext6.Ext2.MulByNonResidue(t1) + // t5 = nr * g5^2 + g1^2 + t5 = e.Ext6.Ext2.Add(t0, t4) + // t6 = nr * g5^2 + g1^2 - g2 + t6 = e.Ext6.Ext2.Sub(t5, &x.C0.B2) + + // t1 = g2^2 + t1 = e.Ext6.Ext2.Square(&x.C0.B2) + + // t6 = 2 * nr * g5^2 + 2 * g1^2 - 2*g2 + t6 = e.Ext6.Ext2.Double(t6) + // z2 = 3 * nr * g5^2 + 3 * g1^2 - 2*g2 + C0B2 := *e.Ext6.Ext2.Add(t6, t5) + + // t4 = nr * g2^2 + t4 = e.Ext6.Ext2.MulByNonResidue(t1) + // t5 = g3^2 + nr * g2^2 + t5 = e.Ext6.Ext2.Add(t2, t4) + // t6 = g3^2 + nr * g2^2 - g1 + t6 = e.Ext6.Ext2.Sub(t5, &x.C0.B1) + // t6 = 2 * g3^2 + 2 * nr * g2^2 - 2 * g1 + t6 = e.Ext6.Ext2.Double(t6) + // z1 = 3 * g3^2 + 3 * nr * g2^2 - 2 * g1 + C0B1 := *e.Ext6.Ext2.Add(t6, t5) + + // t0 = g2^2 + g3^2 + t0 = e.Ext6.Ext2.Add(t2, t1) + // t5 = 2 * g3 * g2 + t5 = e.Ext6.Ext2.Sub(t3, t0) + // t6 = 2 * g3 * g2 + g5 + t6 = e.Ext6.Ext2.Add(t5, &x.C1.B2) + // t6 = 4 * g3 * g2 + 2 * g5 + t6 = e.Ext6.Ext2.Double(t6) + // z5 = 6 * g3 * g2 + 2 * g5 + C1B2 := *e.Ext6.Ext2.Add(t5, t6) + + zero := e.Ext6.Ext2.Zero() + + return &E12{ + C0: E6{ + B0: *zero, + B1: C0B1, + B2: C0B2, + }, + C1: E6{ + B0: C1B0, + B1: *zero, + B2: C1B2, + }, + } +} + +func (e Ext12) NCycloSquareCompressed(z *E12, n int) *E12 { + for i := 0; i < n; i++ { + z = e.CyclotomicSquareCompressed(z) + } + return z +} + +// DecompressKarabina Karabina's cyclotomic square result +func (e Ext12) DecompressKarabina(x *E12) *E12 { + + one := e.Ext6.Ext2.One() + + // TODO: hadle the g3==0 case with MUX + + // t0 = g1^2 + t0 := e.Ext6.Ext2.Square(&x.C0.B1) + // t1 = 3 * g1^2 - 2 * g2 + t1 := e.Ext6.Ext2.Sub(t0, &x.C0.B2) + t1 = e.Ext6.Ext2.Double(t1) + t1 = e.Ext6.Ext2.Add(t1, t0) + // t0 = E * g5^2 + t1 + t2 := e.Ext6.Ext2.Square(&x.C1.B2) + t0 = e.Ext6.Ext2.MulByNonResidue(t2) + t0 = e.Ext6.Ext2.Add(t0, t1) + // t1 = 4 * g3 + t1 = e.Ext6.Ext2.Double(&x.C1.B0) + t1 = e.Ext6.Ext2.Double(t1) + + // z4 = g4 + // TODO: Div instead of Inv+Mul + C1B1 := e.Ext6.Ext2.Inverse(t1) + C1B1 = e.Ext6.Ext2.Mul(C1B1, t0) + + // t1 = g2 * g1 + t1 = e.Ext6.Ext2.Mul(&x.C0.B2, &x.C0.B1) + // t2 = 2 * g4^2 - 3 * g2 * g1 + t2 = e.Ext6.Ext2.Square(C1B1) + t2 = e.Ext6.Ext2.Sub(t2, t1) + t2 = e.Ext6.Ext2.Double(t2) + t2 = e.Ext6.Ext2.Sub(t2, t1) + // t1 = g3 * g5 (g3 can be 0) + t1 = e.Ext6.Ext2.Mul(&x.C1.B0, &x.C1.B2) + // c_0 = E * (2 * g4^2 + g3 * g5 - 3 * g2 * g1) + 1 + t2 = e.Ext6.Ext2.Add(t2, t1) + C0B0 := e.Ext6.Ext2.MulByNonResidue(t2) + C0B0 = e.Ext6.Ext2.Add(C0B0, one) + + return &E12{ + C0: E6{ + B0: *C0B0, + B1: x.C0.B1, + B2: x.C0.B2, + }, + C1: E6{ + B0: x.C1.B0, + B1: *C1B1, + B2: x.C1.B2, + }, + } +} + func (e Ext12) Frobenius(x *E12) *E12 { // var t [6]E2 t0 := e.Ext2.Conjugate(&x.C0.B0) // t[0].Conjugate(&x.C0.B0) diff --git a/std/algebra/emulated/fields_bn254/e12_pairing.go b/std/algebra/emulated/fields_bn254/e12_pairing.go index 1f448e5ae2..b704db61f3 100644 --- a/std/algebra/emulated/fields_bn254/e12_pairing.go +++ b/std/algebra/emulated/fields_bn254/e12_pairing.go @@ -41,38 +41,45 @@ func NewGTEl(v bn254.GT) GTEl { } func (e Ext12) Expt(x *E12) *E12 { - // var result, t0, t1, t2, t3, t4, t5, t6 E12 - t3 := e.CyclotomicSquare(x) // t3.CyclotomicSquare(x) - t5 := e.CyclotomicSquare(t3) // t5.CyclotomicSquare(&t3) - result := e.CyclotomicSquare(t5) // result.CyclotomicSquare(&t5) - t0 := e.CyclotomicSquare(result) // t0.CyclotomicSquare(&result) - t2 := e.Mul(x, t0) // t2.Mul(x, &t0) - t0 = e.Mul(t3, t2) // t0.Mul(&t3, &t2) - t1 := e.Mul(x, t0) // t1.Mul(x, &t0) - t4 := e.Mul(result, t2) // t4.Mul(&result, &t2) - t6 := e.CyclotomicSquare(t2) // t6.CyclotomicSquare(&t2) - t1 = e.Mul(t0, t1) // t1.Mul(&t0, &t1) - t0 = e.Mul(t3, t1) // t0.Mul(&t3, &t1) - t6 = e.NCycloSquare(t6, 6) // t6.NCycloSquare(6) - t5 = e.Mul(t5, t6) // t5.Mul(&t5, &t6) - t5 = e.Mul(t4, t5) // t5.Mul(&t4, &t5) - t5 = e.NCycloSquare(t5, 7) // t5.NCycloSquare(7) - t4 = e.Mul(t4, t5) // t4.Mul(&t4, &t5) - t4 = e.NCycloSquare(t4, 8) // t4.NCycloSquare(8) - t4 = e.Mul(t0, t4) // t4.Mul(&t0, &t4) - t3 = e.Mul(t3, t4) // t3.Mul(&t3, &t4) - t3 = e.NCycloSquare(t3, 6) // t3.NCycloSquare(6) - t2 = e.Mul(t2, t3) // t2.Mul(&t2, &t3) - t2 = e.NCycloSquare(t2, 8) // t2.NCycloSquare(8) - t2 = e.Mul(t0, t2) // t2.Mul(&t0, &t2) - t2 = e.NCycloSquare(t2, 6) // t2.NCycloSquare(6) - t2 = e.Mul(t0, t2) // t2.Mul(&t0, &t2) - t2 = e.NCycloSquare(t2, 10) // t2.NCycloSquare(10) - t1 = e.Mul(t1, t2) // t1.Mul(&t1, &t2) - t1 = e.NCycloSquare(t1, 6) // t1.NCycloSquare(6) - t0 = e.Mul(t0, t1) // t0.Mul(&t0, &t1) - z := e.Mul(result, t0) // z.Mul(&result, &t0) - return z // return z + t3 := e.CyclotomicSquare(x) + t5 := e.CyclotomicSquare(t3) + result := e.CyclotomicSquare(t5) + t0 := e.CyclotomicSquare(result) + t2 := e.Mul(x, t0) + t0 = e.Mul(t3, t2) + t1 := e.Mul(x, t0) + t4 := e.Mul(result, t2) + t6 := e.CyclotomicSquare(t2) + t1 = e.Mul(t0, t1) + t0 = e.Mul(t3, t1) + t6 = e.NCycloSquareCompressed(t6, 6) + t6 = e.DecompressKarabina(t6) + t5 = e.Mul(t5, t6) + t5 = e.Mul(t4, t5) + t5 = e.NCycloSquareCompressed(t5, 7) + t5 = e.DecompressKarabina(t5) + t4 = e.Mul(t4, t5) + t4 = e.NCycloSquareCompressed(t4, 8) + t4 = e.DecompressKarabina(t4) + t4 = e.Mul(t0, t4) + t3 = e.Mul(t3, t4) + t3 = e.NCycloSquareCompressed(t3, 6) + t3 = e.DecompressKarabina(t3) + t2 = e.Mul(t2, t3) + t2 = e.NCycloSquareCompressed(t2, 8) + t2 = e.DecompressKarabina(t2) + t2 = e.Mul(t0, t2) + t2 = e.NCycloSquareCompressed(t2, 6) + t2 = e.DecompressKarabina(t2) + t2 = e.Mul(t0, t2) + t2 = e.NCycloSquareCompressed(t2, 10) + t2 = e.DecompressKarabina(t2) + t1 = e.Mul(t1, t2) + t1 = e.NCycloSquareCompressed(t1, 6) + t1 = e.DecompressKarabina(t1) + t0 = e.Mul(t0, t1) + z := e.Mul(result, t0) + return z } func (e Ext12) MulBy034(z *E12, c0, c3, c4 *E2) *E12 { diff --git a/std/algebra/emulated/fields_bn254/e12_test.go b/std/algebra/emulated/fields_bn254/e12_test.go index 040d3e16af..b62db686ef 100644 --- a/std/algebra/emulated/fields_bn254/e12_test.go +++ b/std/algebra/emulated/fields_bn254/e12_test.go @@ -132,6 +132,7 @@ func TestMulFp12By034by034(t *testing.T) { _, _ = d3.SetRandom() _, _ = d4.SetRandom() c.Mul034by034(&c0, &c3, &c4, &d0, &d3, &d4) + var witness e12MulBy034by034 witness.C0.assign(&c0) witness.C3.assign(&c3) @@ -207,7 +208,7 @@ func TestFp12CyclotomicSquare(t *testing.T) { a.FrobeniusSquare(&tmp).Mul(&a, &tmp) c.CyclotomicSquare(&a) - var witness e12Conjugate + var witness e12CycloSquare witness.A.assign(&a) witness.C.assign(&c) @@ -215,6 +216,45 @@ func TestFp12CyclotomicSquare(t *testing.T) { assert.NoError(err) } +type e12CycloSquareKarabina struct { + A E12 + C E12 `gnark:",public"` +} + +func (circuit *e12CycloSquareKarabina) Define(api frontend.API) error { + + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt12(ba) + v := e.CyclotomicSquareCompressed(&circuit.A) + v = e.DecompressKarabina(v) + e.AssertIsEqual(v, &circuit.C) + return nil +} + +func TestFp12CyclotomicSquareKarabina(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E12 + _, _ = a.SetRandom() + + // put a in the cyclotomic subgroup + var tmp bn254.E12 + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + c.CyclotomicSquareCompressed(&a) + c.DecompressKarabina(&c) + + var witness e12CycloSquareKarabina + witness.A.assign(&a) + witness.C.assign(&c) + + err := test.IsSolved(&e12CycloSquareKarabina{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + type e12Conjugate struct { A E12 C E12 `gnark:",public"` diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 8ef59ab363..2542434e0e 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -226,47 +226,45 @@ func (pr Pairing) MillerLoop(p []*G1Affine, q []*G2Affine) (*fields_bn254.GTEl, } func (pr Pairing) FinalExponentiation(e *fields_bn254.GTEl) *fields_bn254.GTEl { - // var result GT - // result.Set(z) - var t [4]*fields_bn254.GTEl // var t [4]GT + var t [4]*fields_bn254.GTEl // easy part - t[0] = pr.Ext12.Conjugate(e) // t[0].Conjugate(&result) - result := pr.Ext12.Inverse(e) // result.Inverse(&result) - t[0] = pr.Ext12.Mul(t[0], result) // t[0].Mul(&t[0], &result) - result = pr.Ext12.FrobeniusSquare(t[0]) // result.FrobeniusSquare(&t[0]). - result = pr.Ext12.Mul(result, t[0]) // Mul(&result, &t[0]) + t[0] = pr.Ext12.Conjugate(e) + result := pr.Ext12.Inverse(e) + t[0] = pr.Ext12.Mul(t[0], result) + result = pr.Ext12.FrobeniusSquare(t[0]) + result = pr.Ext12.Mul(result, t[0]) //hard part - t[0] = pr.Ext12.Expt(result) // t[0].Expt(&result). - t[0] = pr.Ext12.Conjugate(t[0]) // Conjugate(&t[0]) - t[0] = pr.Ext12.CyclotomicSquare(t[0]) // t[0].CyclotomicSquare(&t[0]) - t[2] = pr.Ext12.Expt(t[0]) // t[2].Expt(&t[0]). - t[2] = pr.Ext12.Conjugate(t[2]) // Conjugate(&t[2]) - t[1] = pr.Ext12.CyclotomicSquare(t[2]) // t[1].CyclotomicSquare(&t[2]) - t[2] = pr.Ext12.Mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) - t[2] = pr.Ext12.Mul(t[2], result) // t[2].Mul(&t[2], &result) - t[1] = pr.Ext12.Expt(t[2]) // t[1].Expt(&t[2]). - t[1] = pr.Ext12.CyclotomicSquare(t[1]) // CyclotomicSquare(&t[1]). - t[1] = pr.Ext12.Mul(t[1], t[2]) // Mul(&t[1], &t[2]). - t[1] = pr.Ext12.Conjugate(t[1]) // Conjugate(&t[1]) - t[3] = pr.Ext12.Conjugate(t[1]) // t[3].Conjugate(&t[1]) - t[1] = pr.Ext12.CyclotomicSquare(t[0]) // t[1].CyclotomicSquare(&t[0]) - t[1] = pr.Ext12.Mul(t[1], result) // t[1].Mul(&t[1], &result) - t[1] = pr.Ext12.Conjugate(t[1]) // t[1].Conjugate(&t[1]) - t[1] = pr.Ext12.Mul(t[1], t[3]) // t[1].Mul(&t[1], &t[3]) - t[0] = pr.Ext12.Mul(t[0], t[1]) // t[0].Mul(&t[0], &t[1]) - t[2] = pr.Ext12.Mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) - t[3] = pr.Ext12.FrobeniusSquare(t[1]) // t[3].FrobeniusSquare(&t[1]) - t[2] = pr.Ext12.Mul(t[2], t[3]) // t[2].Mul(&t[2], &t[3]) - t[3] = pr.Ext12.Conjugate(result) // t[3].Conjugate(&result) - t[3] = pr.Ext12.Mul(t[3], t[0]) // t[3].Mul(&t[3], &t[0]) - t[1] = pr.Ext12.FrobeniusCube(t[3]) // t[1].FrobeniusCube(&t[3]) - t[2] = pr.Ext12.Mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) - t[1] = pr.Ext12.Frobenius(t[0]) // t[1].Frobenius(&t[0]) - t[1] = pr.Ext12.Mul(t[1], t[2]) // t[1].Mul(&t[1], &t[2]) - // result.Set(&t[1]) - return t[1] // return result + t[0] = pr.Ext12.Expt(result) + t[0] = pr.Ext12.Conjugate(t[0]) + t[0] = pr.Ext12.CyclotomicSquare(t[0]) + t[2] = pr.Ext12.Expt(t[0]) + t[2] = pr.Ext12.Conjugate(t[2]) + t[1] = pr.Ext12.CyclotomicSquare(t[2]) + t[2] = pr.Ext12.Mul(t[2], t[1]) + t[2] = pr.Ext12.Mul(t[2], result) + t[1] = pr.Ext12.Expt(t[2]) + t[1] = pr.Ext12.CyclotomicSquare(t[1]) + t[1] = pr.Ext12.Mul(t[1], t[2]) + t[1] = pr.Ext12.Conjugate(t[1]) + t[3] = pr.Ext12.Conjugate(t[1]) + t[1] = pr.Ext12.CyclotomicSquare(t[0]) + t[1] = pr.Ext12.Mul(t[1], result) + t[1] = pr.Ext12.Conjugate(t[1]) + t[1] = pr.Ext12.Mul(t[1], t[3]) + t[0] = pr.Ext12.Mul(t[0], t[1]) + t[2] = pr.Ext12.Mul(t[2], t[1]) + t[3] = pr.Ext12.FrobeniusSquare(t[1]) + t[2] = pr.Ext12.Mul(t[2], t[3]) + t[3] = pr.Ext12.Conjugate(result) + t[3] = pr.Ext12.Mul(t[3], t[0]) + t[1] = pr.Ext12.FrobeniusCube(t[3]) + t[2] = pr.Ext12.Mul(t[2], t[1]) + t[1] = pr.Ext12.Frobenius(t[0]) + t[1] = pr.Ext12.Mul(t[1], t[2]) + + return t[1] } func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*fields_bn254.GTEl, error) { From 8ed586e5f1c7791a1135ed9e4486fae53ea80a25 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 8 Mar 2023 03:59:57 +0100 Subject: [PATCH 070/464] Refactor: std/algebra (#526) * feat: add BN254 pairing using field emulation * refactor: make methods private * feat: add equality assertion for GT elements * docs: add package documentation and example * refactor: algebra into native (2-chain) and emulated * fix: remove pairing_bn254 * fix: use sw_emulated instead of weierstrass * fix: update path to algebra/native * fix: update path to algebra/native * fix: update path to algebra/native/twistededwards * docs: add documentation to std/algebra packages * style(std/fields_*): separate Fpk ops specific to choice of pairing * style: apply suggested edits --------- Co-authored-by: Ivo Kubjas --- examples/rollup/circuit.go | 2 +- internal/stats/snippet.go | 4 +- std/algebra/doc.go | 14 + std/algebra/emulated/fields_bn254/doc.go | 7 + std/algebra/emulated/fields_bn254/e12.go | 226 +++++ .../emulated/fields_bn254/e12_pairing.go | 96 ++ std/algebra/emulated/fields_bn254/e2.go | 312 +++++++ std/algebra/emulated/fields_bn254/e6.go | 201 +++++ .../sw_bn254}/doc.go | 4 +- .../sw_bn254}/doc_test.go | 20 +- .../sw_bn254}/g1.go | 6 +- .../sw_bn254}/g2.go | 13 +- std/algebra/emulated/sw_bn254/pairing.go | 319 +++++++ .../sw_bn254}/pairing_test.go | 12 +- .../sw_emulated}/doc.go | 8 +- .../sw_emulated}/doc_test.go | 10 +- .../sw_emulated}/params.go | 2 +- .../sw_emulated}/params_compute.go | 2 +- .../sw_emulated}/point.go | 2 +- .../sw_emulated}/point_test.go | 2 +- std/algebra/native/fields_bls12377/doc.go | 9 + .../{ => native}/fields_bls12377/e12.go | 74 -- .../native/fields_bls12377/e12_pairing.go | 77 ++ .../{ => native}/fields_bls12377/e12_test.go | 0 .../{ => native}/fields_bls12377/e2.go | 0 .../{ => native}/fields_bls12377/e2_test.go | 0 .../{ => native}/fields_bls12377/e6.go | 0 .../{ => native}/fields_bls12377/e6_test.go | 0 std/algebra/native/fields_bls24315/doc.go | 10 + .../{ => native}/fields_bls24315/e12.go | 0 .../{ => native}/fields_bls24315/e12_test.go | 0 .../{ => native}/fields_bls24315/e2.go | 0 .../{ => native}/fields_bls24315/e24.go | 72 -- .../native/fields_bls24315/e24_pairing.go | 75 ++ .../{ => native}/fields_bls24315/e24_test.go | 0 .../{ => native}/fields_bls24315/e2_test.go | 0 .../{ => native}/fields_bls24315/e4.go | 0 .../{ => native}/fields_bls24315/e4_test.go | 0 std/algebra/native/sw_bls12377/doc.go | 8 + std/algebra/{ => native}/sw_bls12377/g1.go | 0 .../{ => native}/sw_bls12377/g1_test.go | 0 std/algebra/{ => native}/sw_bls12377/g2.go | 2 +- .../{ => native}/sw_bls12377/g2_test.go | 0 std/algebra/{ => native}/sw_bls12377/inner.go | 0 .../{ => native}/sw_bls12377/inner_compute.go | 0 .../{ => native}/sw_bls12377/pairing.go | 2 +- .../{ => native}/sw_bls12377/pairing_test.go | 2 +- std/algebra/native/sw_bls24315/doc.go | 8 + std/algebra/{ => native}/sw_bls24315/g1.go | 0 .../{ => native}/sw_bls24315/g1_test.go | 0 std/algebra/{ => native}/sw_bls24315/g2.go | 2 +- .../{ => native}/sw_bls24315/g2_test.go | 0 std/algebra/{ => native}/sw_bls24315/inner.go | 0 .../{ => native}/sw_bls24315/inner_compute.go | 0 .../{ => native}/sw_bls24315/pairing.go | 2 +- .../{ => native}/sw_bls24315/pairing_test.go | 2 +- .../{ => native}/twistededwards/curve.go | 0 .../{ => native}/twistededwards/curve_test.go | 0 std/algebra/native/twistededwards/doc.go | 8 + .../{ => native}/twistededwards/point.go | 0 .../twistededwards/scalarmul_glv.go | 0 .../twistededwards/twistededwards.go | 0 std/algebra/pairing_bn254/gt.go | 41 - std/algebra/pairing_bn254/pairing.go | 282 ------ std/algebra/pairing_bn254/tower.go | 833 ------------------ std/algebra/sw_bls12377/doc.go | 18 - std/algebra/sw_bls24315/doc.go | 18 - std/commitments/kzg_bls12377/verifier.go | 4 +- std/commitments/kzg_bls24315/verifier.go | 4 +- std/groth16_bls12377/verifier.go | 4 +- std/groth16_bls12377/verifier_test.go | 2 +- std/groth16_bls24315/verifier.go | 4 +- std/groth16_bls24315/verifier_test.go | 2 +- std/hints.go | 4 +- std/math/emulated/field_test.go | 2 +- std/signature/ecdsa/ecdsa.go | 12 +- std/signature/ecdsa/ecdsa_test.go | 6 +- std/signature/eddsa/eddsa.go | 2 +- std/signature/eddsa/eddsa_test.go | 2 +- 79 files changed, 1443 insertions(+), 1412 deletions(-) create mode 100644 std/algebra/doc.go create mode 100644 std/algebra/emulated/fields_bn254/doc.go create mode 100644 std/algebra/emulated/fields_bn254/e12.go create mode 100644 std/algebra/emulated/fields_bn254/e12_pairing.go create mode 100644 std/algebra/emulated/fields_bn254/e2.go create mode 100644 std/algebra/emulated/fields_bn254/e6.go rename std/algebra/{pairing_bn254 => emulated/sw_bn254}/doc.go (64%) rename std/algebra/{pairing_bn254 => emulated/sw_bn254}/doc_test.go (81%) rename std/algebra/{pairing_bn254 => emulated/sw_bn254}/g1.go (66%) rename std/algebra/{pairing_bn254 => emulated/sw_bn254}/g2.go (70%) create mode 100644 std/algebra/emulated/sw_bn254/pairing.go rename std/algebra/{pairing_bn254 => emulated/sw_bn254}/pairing_test.go (90%) rename std/algebra/{weierstrass => emulated/sw_emulated}/doc.go (83%) rename std/algebra/{weierstrass => emulated/sw_emulated}/doc_test.go (89%) rename std/algebra/{weierstrass => emulated/sw_emulated}/params.go (99%) rename std/algebra/{weierstrass => emulated/sw_emulated}/params_compute.go (98%) rename std/algebra/{weierstrass => emulated/sw_emulated}/point.go (99%) rename std/algebra/{weierstrass => emulated/sw_emulated}/point_test.go (99%) create mode 100644 std/algebra/native/fields_bls12377/doc.go rename std/algebra/{ => native}/fields_bls12377/e12.go (91%) create mode 100644 std/algebra/native/fields_bls12377/e12_pairing.go rename std/algebra/{ => native}/fields_bls12377/e12_test.go (100%) rename std/algebra/{ => native}/fields_bls12377/e2.go (100%) rename std/algebra/{ => native}/fields_bls12377/e2_test.go (100%) rename std/algebra/{ => native}/fields_bls12377/e6.go (100%) rename std/algebra/{ => native}/fields_bls12377/e6_test.go (100%) create mode 100644 std/algebra/native/fields_bls24315/doc.go rename std/algebra/{ => native}/fields_bls24315/e12.go (100%) rename std/algebra/{ => native}/fields_bls24315/e12_test.go (100%) rename std/algebra/{ => native}/fields_bls24315/e2.go (100%) rename std/algebra/{ => native}/fields_bls24315/e24.go (92%) create mode 100644 std/algebra/native/fields_bls24315/e24_pairing.go rename std/algebra/{ => native}/fields_bls24315/e24_test.go (100%) rename std/algebra/{ => native}/fields_bls24315/e2_test.go (100%) rename std/algebra/{ => native}/fields_bls24315/e4.go (100%) rename std/algebra/{ => native}/fields_bls24315/e4_test.go (100%) create mode 100644 std/algebra/native/sw_bls12377/doc.go rename std/algebra/{ => native}/sw_bls12377/g1.go (100%) rename std/algebra/{ => native}/sw_bls12377/g1_test.go (100%) rename std/algebra/{ => native}/sw_bls12377/g2.go (99%) rename std/algebra/{ => native}/sw_bls12377/g2_test.go (100%) rename std/algebra/{ => native}/sw_bls12377/inner.go (100%) rename std/algebra/{ => native}/sw_bls12377/inner_compute.go (100%) rename std/algebra/{ => native}/sw_bls12377/pairing.go (98%) rename std/algebra/{ => native}/sw_bls12377/pairing_test.go (98%) create mode 100644 std/algebra/native/sw_bls24315/doc.go rename std/algebra/{ => native}/sw_bls24315/g1.go (100%) rename std/algebra/{ => native}/sw_bls24315/g1_test.go (100%) rename std/algebra/{ => native}/sw_bls24315/g2.go (99%) rename std/algebra/{ => native}/sw_bls24315/g2_test.go (100%) rename std/algebra/{ => native}/sw_bls24315/inner.go (100%) rename std/algebra/{ => native}/sw_bls24315/inner_compute.go (100%) rename std/algebra/{ => native}/sw_bls24315/pairing.go (98%) rename std/algebra/{ => native}/sw_bls24315/pairing_test.go (98%) rename std/algebra/{ => native}/twistededwards/curve.go (100%) rename std/algebra/{ => native}/twistededwards/curve_test.go (100%) create mode 100644 std/algebra/native/twistededwards/doc.go rename std/algebra/{ => native}/twistededwards/point.go (100%) rename std/algebra/{ => native}/twistededwards/scalarmul_glv.go (100%) rename std/algebra/{ => native}/twistededwards/twistededwards.go (100%) delete mode 100644 std/algebra/pairing_bn254/gt.go delete mode 100644 std/algebra/pairing_bn254/pairing.go delete mode 100644 std/algebra/pairing_bn254/tower.go delete mode 100644 std/algebra/sw_bls12377/doc.go delete mode 100644 std/algebra/sw_bls24315/doc.go diff --git a/examples/rollup/circuit.go b/examples/rollup/circuit.go index 0b3b5000ba..27b47f4fda 100644 --- a/examples/rollup/circuit.go +++ b/examples/rollup/circuit.go @@ -20,7 +20,7 @@ import ( tedwards "github.com/consensys/gnark-crypto/ecc/twistededwards" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/accumulator/merkle" - "github.com/consensys/gnark/std/algebra/twistededwards" + "github.com/consensys/gnark/std/algebra/native/twistededwards" "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/std/signature/eddsa" ) diff --git a/internal/stats/snippet.go b/internal/stats/snippet.go index 1f6ed7764c..a166bb849c 100644 --- a/internal/stats/snippet.go +++ b/internal/stats/snippet.go @@ -7,8 +7,8 @@ import ( "github.com/consensys/gnark" "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/sw_bls12377" - "github.com/consensys/gnark/std/algebra/sw_bls24315" + "github.com/consensys/gnark/std/algebra/native/sw_bls12377" + "github.com/consensys/gnark/std/algebra/native/sw_bls24315" "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/std/math/bits" "github.com/consensys/gnark/std/math/emulated" diff --git a/std/algebra/doc.go b/std/algebra/doc.go new file mode 100644 index 0000000000..18e70aeac5 --- /dev/null +++ b/std/algebra/doc.go @@ -0,0 +1,14 @@ +// Package algebra implements: +// - base finite field 𝔽p arithmetic, +// - extension finite fields arithmetic (𝔽p², 𝔽p⁴, 𝔽p⁶, 𝔽p¹², 𝔽p²⁴), +// - short Weierstrass curve arithmetic over G1 (E/𝔽p) and G2 (Eₜ/𝔽p² or Eₜ/𝔽p⁴) +// - twisted Edwards curve arithmetic +// +// These arithmetic operations are implemented +// - using native field via the 2-chains BLS12-377/BW6-761 and BLS24-315/BW-633 +// (`native/`) or associated twisted Edwards (e.g. Jubjub/BLS12-381) and +// - using nonnative field via field emulation (`emulated/`). This allows to +// use any curve over any (SNARK) field (e.g. secp256k1 curve arithmetic over +// BN254 SNARK field or BN254 pairing over BN254 SNARK field). The drawback +// of this approach is the extreme cost of the operations. +package algebra diff --git a/std/algebra/emulated/fields_bn254/doc.go b/std/algebra/emulated/fields_bn254/doc.go new file mode 100644 index 0000000000..ae94b3c243 --- /dev/null +++ b/std/algebra/emulated/fields_bn254/doc.go @@ -0,0 +1,7 @@ +// Package fields_bn254 implements the fields arithmetic of the Fp12 tower +// used to compute the pairing over the BN254 curve. +// +// 𝔽p²[u] = 𝔽p/u²+1 +// 𝔽p⁶[v] = 𝔽p²/v³-9-u +// 𝔽p¹²[w] = 𝔽p⁶/w²-v +package fields_bn254 diff --git a/std/algebra/emulated/fields_bn254/e12.go b/std/algebra/emulated/fields_bn254/e12.go new file mode 100644 index 0000000000..f8492ee5f0 --- /dev/null +++ b/std/algebra/emulated/fields_bn254/e12.go @@ -0,0 +1,226 @@ +package fields_bn254 + +type E12 struct { + C0, C1 E6 +} + +type Ext12 struct { + *Ext6 +} + +func NewExt12(baseField *curveF) *Ext12 { + return &Ext12{Ext6: NewExt6(baseField)} +} +func (e Ext12) Conjugate(x *E12) *E12 { + z1 := e.Ext6.Neg(&x.C1) // z.C1.Neg(&z.C1) + return &E12{ // return z + C0: x.C0, + C1: *z1, + } +} + +func (e Ext12) Inverse(x *E12) *E12 { + // var t0, t1, tmp E6 + t0 := e.Ext6.Square(&x.C0) // t0.Square(&x.C0) + t1 := e.Ext6.Square(&x.C1) // t1.Square(&x.C1) + tmp := e.Ext6.MulByNonResidue(t1) // tmp.MulByNonResidue(&t1) + t0 = e.Ext6.Sub(t0, tmp) // t0.Sub(&t0, &tmp) + t1 = e.Ext6.Inverse(t0) // t1.Inverse(&t0) + z0 := e.Ext6.Mul(&x.C0, t1) // z.C0.Mul(&x.C0, &t1) + z1 := e.Ext6.Mul(&x.C1, t1) // z.C1.Mul(&x.C1, &t1). + z1 = e.Ext6.Neg(z1) // Neg(&z.C1) + return &E12{ // return z + C0: *z0, + C1: *z1, + } +} + +func (e Ext12) Mul(x, y *E12) *E12 { + // var a, b, c E6 + a := e.Ext6.Add(&x.C0, &x.C1) // a.Add(&x.C0, &x.C1) + b := e.Ext6.Add(&y.C0, &y.C1) // b.Add(&y.C0, &y.C1) + a = e.Ext6.Mul(a, b) // a.Mul(&a, &b) + b = e.Ext6.Mul(&x.C0, &y.C0) // b.Mul(&x.C0, &y.C0) + c := e.Ext6.Mul(&x.C1, &y.C1) // c.Mul(&x.C1, &y.C1) + z1 := e.Ext6.Sub(a, b) // z.C1.Sub(&a, &b). + z1 = e.Ext6.Sub(z1, c) // Sub(&z.C1, &c) + z0 := e.Ext6.MulByNonResidue(c) // z.C0.MulByNonResidue(&c). + z0 = e.Ext6.Add(z0, b) // Add(&z.C0, &b) + return &E12{ // return z + C0: *z0, + C1: *z1, + } +} + +func (e Ext12) CyclotomicSquare(x *E12) *E12 { + // var t [9]E2 + t0 := e.Ext2.Square(&x.C1.B1) // t[0].Square(&x.C1.B1) + t1 := e.Ext2.Square(&x.C0.B0) // t[1].Square(&x.C0.B0) + t6 := e.Ext2.Add(&x.C1.B1, &x.C0.B0) // t[6].Add(&x.C1.B1, &x.C0.B0). + t6 = e.Ext2.Square(t6) // Square(&t[6]). + t6 = e.Ext2.Sub(t6, t0) // Sub(&t[6], &t[0]). + t6 = e.Ext2.Sub(t6, t1) // Sub(&t[6], &t[1]) + t2 := e.Ext2.Square(&x.C0.B2) // t[2].Square(&x.C0.B2) + t3 := e.Ext2.Square(&x.C1.B0) // t[3].Square(&x.C1.B0) + t7 := e.Ext2.Add(&x.C0.B2, &x.C1.B0) // t[7].Add(&x.C0.B2, &x.C1.B0). + t7 = e.Ext2.Square(t7) // Square(&t[7]). + t7 = e.Ext2.Sub(t7, t2) // Sub(&t[7], &t[2]). + t7 = e.Ext2.Sub(t7, t3) // Sub(&t[7], &t[3]) + t4 := e.Ext2.Square(&x.C1.B2) // t[4].Square(&x.C1.B2) + t5 := e.Ext2.Square(&x.C0.B1) // t[5].Square(&x.C0.B1) + t8 := e.Ext2.Add(&x.C1.B2, &x.C0.B1) // t[8].Add(&x.C1.B2, &x.C0.B1). + t8 = e.Ext2.Square(t8) // Square(&t[8]). + t8 = e.Ext2.Sub(t8, t4) // Sub(&t[8], &t[4]). + t8 = e.Ext2.Sub(t8, t5) // Sub(&t[8], &t[5]). + t8 = e.Ext2.MulByNonResidue(t8) // MulByNonResidue(&t[8]) + t0 = e.Ext2.MulByNonResidue(t0) // t[0].MulByNonResidue(&t[0]). + t0 = e.Ext2.Add(t0, t1) // Add(&t[0], &t[1]) + t2 = e.Ext2.MulByNonResidue(t2) // t[2].MulByNonResidue(&t[2]). + t2 = e.Ext2.Add(t2, t3) // Add(&t[2], &t[3]) + t4 = e.Ext2.MulByNonResidue(t4) // t[4].MulByNonResidue(&t[4]). + t4 = e.Ext2.Add(t4, t5) // Add(&t[4], &t[5]) + z00 := e.Ext2.Sub(t0, &x.C0.B0) // z.C0.B0.Sub(&t[0], &x.C0.B0). + z00 = e.Ext2.Double(z00) // Double(&z.C0.B0). + z00 = e.Ext2.Add(z00, t0) // Add(&z.C0.B0, &t[0]) + z01 := e.Ext2.Sub(t2, &x.C0.B1) // z.C0.B1.Sub(&t[2], &x.C0.B1). + z01 = e.Ext2.Double(z01) // Double(&z.C0.B1). + z01 = e.Ext2.Add(z01, t2) // Add(&z.C0.B1, &t[2]) + z02 := e.Ext2.Sub(t4, &x.C0.B2) // z.C0.B2.Sub(&t[4], &x.C0.B2). + z02 = e.Ext2.Double(z02) // Double(&z.C0.B2). + z02 = e.Ext2.Add(z02, t4) // Add(&z.C0.B2, &t[4]) + z10 := e.Ext2.Add(t8, &x.C1.B0) // z.C1.B0.Add(&t[8], &x.C1.B0). + z10 = e.Ext2.Double(z10) // Double(&z.C1.B0). + z10 = e.Ext2.Add(z10, t8) // Add(&z.C1.B0, &t[8]) + z11 := e.Ext2.Add(t6, &x.C1.B1) // z.C1.B1.Add(&t[6], &x.C1.B1). + z11 = e.Ext2.Double(z11) // Double(&z.C1.B1). + z11 = e.Ext2.Add(z11, t6) // Add(&z.C1.B1, &t[6]) + z12 := e.Ext2.Add(t7, &x.C1.B2) // z.C1.B2.Add(&t[7], &x.C1.B2). + z12 = e.Ext2.Double(z12) // Double(&z.C1.B2). + z12 = e.Ext2.Add(z12, t7) // Add(&z.C1.B2, &t[7]) + return &E12{ // return z + C0: E6{ + B0: *z00, + B1: *z01, + B2: *z02, + }, + C1: E6{ + B0: *z10, + B1: *z11, + B2: *z12, + }, + } +} + +func (e Ext12) NCycloSquare(z *E12, n int) *E12 { + for i := 0; i < n; i++ { + z = e.CyclotomicSquare(z) + } + return z +} + +func (e Ext12) Frobenius(x *E12) *E12 { + // var t [6]E2 + t0 := e.Ext2.Conjugate(&x.C0.B0) // t[0].Conjugate(&x.C0.B0) + t1 := e.Ext2.Conjugate(&x.C0.B1) // t[1].Conjugate(&x.C0.B1) + t2 := e.Ext2.Conjugate(&x.C0.B2) // t[2].Conjugate(&x.C0.B2) + t3 := e.Ext2.Conjugate(&x.C1.B0) // t[3].Conjugate(&x.C1.B0) + t4 := e.Ext2.Conjugate(&x.C1.B1) // t[4].Conjugate(&x.C1.B1) + t5 := e.Ext2.Conjugate(&x.C1.B2) // t[5].Conjugate(&x.C1.B2) + t1 = e.Ext2.MulByNonResidue1Power2(t1) // t[1].MulByNonResidue1Power2(&t[1]) + t2 = e.Ext2.MulByNonResidue1Power4(t2) // t[2].MulByNonResidue1Power4(&t[2]) + t3 = e.Ext2.MulByNonResidue1Power1(t3) // t[3].MulByNonResidue1Power1(&t[3]) + t4 = e.Ext2.MulByNonResidue1Power3(t4) // t[4].MulByNonResidue1Power3(&t[4]) + t5 = e.Ext2.MulByNonResidue1Power5(t5) // t[5].MulByNonResidue1Power5(&t[5]) + return &E12{ // return z + C0: E6{ + B0: *t0, // z.C0.B0 = t[0] + B1: *t1, // z.C0.B1 = t[1] + B2: *t2, // z.C0.B2 = t[2] + }, + C1: E6{ + B0: *t3, // z.C1.B0 = t[3] + B1: *t4, // z.C1.B1 = t[4] + B2: *t5, // z.C1.B2 = t[5] + }, + } +} + +func (e Ext12) FrobeniusSquare(x *E12) *E12 { + z00 := &x.C0.B0 // z.C0.B0 = x.C0.B0 + z01 := e.Ext2.MulByNonResidue2Power2(&x.C0.B1) // z.C0.B1.MulByNonResidue2Power2(&x.C0.B1) + z02 := e.Ext2.MulByNonResidue2Power4(&x.C0.B2) // z.C0.B2.MulByNonResidue2Power4(&x.C0.B2) + z10 := e.Ext2.MulByNonResidue2Power1(&x.C1.B0) // z.C1.B0.MulByNonResidue2Power1(&x.C1.B0) + z11 := e.Ext2.MulByNonResidue2Power3(&x.C1.B1) // z.C1.B1.MulByNonResidue2Power3(&x.C1.B1) + z12 := e.Ext2.MulByNonResidue2Power5(&x.C1.B2) // z.C1.B2.MulByNonResidue2Power5(&x.C1.B2) + return &E12{ // return z + C0: E6{B0: *z00, B1: *z01, B2: *z02}, + C1: E6{B0: *z10, B1: *z11, B2: *z12}, + } +} + +func (e Ext12) FrobeniusCube(x *E12) *E12 { + // var t [6]E2 + t0 := e.Ext2.Conjugate(&x.C0.B0) // t[0].Conjugate(&x.C0.B0) + t1 := e.Ext2.Conjugate(&x.C0.B1) // t[1].Conjugate(&x.C0.B1) + t2 := e.Ext2.Conjugate(&x.C0.B2) // t[2].Conjugate(&x.C0.B2) + t3 := e.Ext2.Conjugate(&x.C1.B0) // t[3].Conjugate(&x.C1.B0) + t4 := e.Ext2.Conjugate(&x.C1.B1) // t[4].Conjugate(&x.C1.B1) + t5 := e.Ext2.Conjugate(&x.C1.B2) // t[5].Conjugate(&x.C1.B2) + t1 = e.Ext2.MulByNonResidue3Power2(t1) // t[1].MulByNonResidue3Power2(&t[1]) + t2 = e.Ext2.MulByNonResidue3Power4(t2) // t[2].MulByNonResidue3Power4(&t[2]) + t3 = e.Ext2.MulByNonResidue3Power1(t3) // t[3].MulByNonResidue3Power1(&t[3]) + t4 = e.Ext2.MulByNonResidue3Power3(t4) // t[4].MulByNonResidue3Power3(&t[4]) + t5 = e.Ext2.MulByNonResidue3Power5(t5) // t[5].MulByNonResidue3Power5(&t[5]) + return &E12{ // return z + C0: E6{ + B0: *t0, // z.C0.B0 = t[0] + B1: *t1, // z.C0.B1 = t[1] + B2: *t2, // z.C0.B2 = t[2] + }, + C1: E6{ + B0: *t3, // z.C1.B0 = t[3] + B1: *t4, // z.C1.B1 = t[4] + B2: *t5, // z.C1.B2 = t[5] + }, + } +} + +func (e Ext12) One() *E12 { + z000 := e.fp.One() + zero := e.fp.Zero() + return &E12{ + C0: E6{ + B0: E2{A0: *z000, A1: *zero}, + B1: E2{A0: *zero, A1: *zero}, + B2: E2{A0: *zero, A1: *zero}, + }, + C1: E6{ + B0: E2{A0: *zero, A1: *zero}, + B1: E2{A0: *zero, A1: *zero}, + B2: E2{A0: *zero, A1: *zero}, + }, + } +} + +func (e Ext12) Square(x *E12) *E12 { + // var c0, c2, c3 E6 + c0 := e.Ext6.Sub(&x.C0, &x.C1) // c0.Sub(&x.C0, &x.C1) + c3 := e.Ext6.MulByNonResidue(&x.C1) // c3.MulByNonResidue(&x.C1). + c3 = e.Ext6.Neg(c3) // Neg(&c3). + c3 = e.Ext6.Add(&x.C0, c3) // Add(&x.C0, &c3) + c2 := e.Ext6.Mul(&x.C0, &x.C1) // c2.Mul(&x.C0, &x.C1) + c0 = e.Ext6.Mul(c0, c3) // c0.Mul(&c0, &c3). + c0 = e.Ext6.Add(c0, c2) // Add(&c0, &c2) + z1 := e.Ext6.double(c2) // z.C1.Double(&c2) + c2 = e.Ext6.MulByNonResidue(c2) // c2.MulByNonResidue(&c2) + z0 := e.Ext6.Add(c0, c2) // z.C0.Add(&c0, &c2) + return &E12{ // return z + C0: *z0, + C1: *z1, + } +} + +func (e Ext12) AssertIsEqual(x, y *E12) { + e.Ext6.AssertIsEqual(&x.C0, &y.C0) + e.Ext6.AssertIsEqual(&x.C1, &y.C1) +} diff --git a/std/algebra/emulated/fields_bn254/e12_pairing.go b/std/algebra/emulated/fields_bn254/e12_pairing.go new file mode 100644 index 0000000000..59de7433e0 --- /dev/null +++ b/std/algebra/emulated/fields_bn254/e12_pairing.go @@ -0,0 +1,96 @@ +package fields_bn254 + +func (e Ext12) Expt(x *E12) *E12 { + // var result, t0, t1, t2, t3, t4, t5, t6 E12 + t3 := e.CyclotomicSquare(x) // t3.CyclotomicSquare(x) + t5 := e.CyclotomicSquare(t3) // t5.CyclotomicSquare(&t3) + result := e.CyclotomicSquare(t5) // result.CyclotomicSquare(&t5) + t0 := e.CyclotomicSquare(result) // t0.CyclotomicSquare(&result) + t2 := e.Mul(x, t0) // t2.Mul(x, &t0) + t0 = e.Mul(t3, t2) // t0.Mul(&t3, &t2) + t1 := e.Mul(x, t0) // t1.Mul(x, &t0) + t4 := e.Mul(result, t2) // t4.Mul(&result, &t2) + t6 := e.CyclotomicSquare(t2) // t6.CyclotomicSquare(&t2) + t1 = e.Mul(t0, t1) // t1.Mul(&t0, &t1) + t0 = e.Mul(t3, t1) // t0.Mul(&t3, &t1) + t6 = e.NCycloSquare(t6, 6) // t6.NCycloSquare(6) + t5 = e.Mul(t5, t6) // t5.Mul(&t5, &t6) + t5 = e.Mul(t4, t5) // t5.Mul(&t4, &t5) + t5 = e.NCycloSquare(t5, 7) // t5.NCycloSquare(7) + t4 = e.Mul(t4, t5) // t4.Mul(&t4, &t5) + t4 = e.NCycloSquare(t4, 8) // t4.NCycloSquare(8) + t4 = e.Mul(t0, t4) // t4.Mul(&t0, &t4) + t3 = e.Mul(t3, t4) // t3.Mul(&t3, &t4) + t3 = e.NCycloSquare(t3, 6) // t3.NCycloSquare(6) + t2 = e.Mul(t2, t3) // t2.Mul(&t2, &t3) + t2 = e.NCycloSquare(t2, 8) // t2.NCycloSquare(8) + t2 = e.Mul(t0, t2) // t2.Mul(&t0, &t2) + t2 = e.NCycloSquare(t2, 6) // t2.NCycloSquare(6) + t2 = e.Mul(t0, t2) // t2.Mul(&t0, &t2) + t2 = e.NCycloSquare(t2, 10) // t2.NCycloSquare(10) + t1 = e.Mul(t1, t2) // t1.Mul(&t1, &t2) + t1 = e.NCycloSquare(t1, 6) // t1.NCycloSquare(6) + t0 = e.Mul(t0, t1) // t0.Mul(&t0, &t1) + z := e.Mul(result, t0) // z.Mul(&result, &t0) + return z // return z +} + +func (e Ext12) MulBy034(z *E12, c0, c3, c4 *E2) *E12 { + // var a, b, d E6 + a := e.Ext6.MulByE2(&z.C0, c0) // a.MulByE2(&z.C0, c0) + // b.Set(&z.C1) + b := e.Ext6.MulBy01(&z.C1, c3, c4) // b.MulBy01(c3, c4) + c0 = e.Ext2.Add(c0, c3) // c0.Add(c0, c3) + d := e.Ext6.Add(&z.C0, &z.C1) // d.Add(&z.C0, &z.C1) + d = e.Ext6.MulBy01(d, c0, c4) // d.MulBy01(c0, c4) + z1 := e.Add(a, b) // z.C1.Add(&a, &b). + z1 = e.Neg(z1) // Neg(&z.C1). + z1 = e.Add(z1, d) // Add(&z.C1, &d) + z0 := e.MulByNonResidue(b) // z.C0.MulByNonResidue(&b). + z0 = e.Add(z0, a) // Add(&z.C0, &a) + return &E12{ // return z + C0: *z0, + C1: *z1, + } +} + +func (e Ext12) MulBy034by034(d0, d3, d4, c0, c3, c4 *E2) *E12 { + // var tmp, x0, x3, x4, x04, x03, x34 E2 + x0 := e.Ext2.Mul(c0, d0) // x0.Mul(c0, d0) + x3 := e.Ext2.Mul(c3, d3) // x3.Mul(c3, d3) + x4 := e.Ext2.Mul(c4, d4) // x4.Mul(c4, d4) + tmp := e.Ext2.Add(c0, c4) // tmp.Add(c0, c4) + x04 := e.Ext2.Add(d0, d4) // x04.Add(d0, d4). + x04 = e.Ext2.Mul(x04, tmp) // Mul(&x04, &tmp). + x04 = e.Ext2.Sub(x04, x0) // Sub(&x04, &x0). + x04 = e.Ext2.Sub(x04, x4) // Sub(&x04, &x4) + tmp = e.Ext2.Add(c0, c3) // tmp.Add(c0, c3) + x03 := e.Ext2.Add(d0, d3) // x03.Add(d0, d3). + x03 = e.Ext2.Mul(x03, tmp) // Mul(&x03, &tmp). + x03 = e.Ext2.Sub(x03, x0) // Sub(&x03, &x0). + x03 = e.Ext2.Sub(x03, x3) // Sub(&x03, &x3) + tmp = e.Ext2.Add(c3, c4) // tmp.Add(c3, c4) + x34 := e.Ext2.Add(d3, d4) // x34.Add(d3, d4). + x34 = e.Ext2.Mul(x34, tmp) // Mul(&x34, &tmp). + x34 = e.Ext2.Sub(x34, x3) // Sub(&x34, &x3). + x34 = e.Ext2.Sub(x34, x4) // Sub(&x34, &x4) + z00 := e.Ext2.MulByNonResidue(x4) // z.C0.B0.MulByNonResidue(&x4). + z00 = e.Ext2.Add(z00, x0) // Add(&z.C0.B0, &x0) + z01 := x3 // z.C0.B1.Set(&x3) + z02 := x34 // z.C0.B2.Set(&x34) + z10 := x03 // z.C1.B0.Set(&x03) + z11 := x04 // z.C1.B1.Set(&x04) + z12 := e.Ext2.Zero() // z.C1.B2.SetZero() + return &E12{ // return z + C0: E6{ + B0: *z00, + B1: *z01, + B2: *z02, + }, + C1: E6{ + B0: *z10, + B1: *z11, + B2: *z12, + }, + } +} diff --git a/std/algebra/emulated/fields_bn254/e2.go b/std/algebra/emulated/fields_bn254/e2.go new file mode 100644 index 0000000000..8ba71003c7 --- /dev/null +++ b/std/algebra/emulated/fields_bn254/e2.go @@ -0,0 +1,312 @@ +package fields_bn254 + +import ( + "math/big" + + "github.com/consensys/gnark/std/math/emulated" +) + +type curveF = emulated.Field[emulated.BN254Fp] +type baseEl = emulated.Element[emulated.BN254Fp] + +type E2 struct { + A0, A1 baseEl +} + +type Ext2 struct { + fp *curveF + nonResidues map[int]map[int]*E2 +} + +func NewExt2(baseField *curveF) *Ext2 { + pwrs := map[int]map[int]struct { + A0 string + A1 string + }{ + 0: { + -1: {"21087453498479301738505683583845423561061080261299122796980902361914303298513", "14681138511599513868579906292550611339979233093309515871315818100066920017952"}, + 1: {"9", "1"}, + }, + 1: { + 1: {"8376118865763821496583973867626364092589906065868298776909617916018768340080", "16469823323077808223889137241176536799009286646108169935659301613961712198316"}, + 2: {"21575463638280843010398324269430826099269044274347216827212613867836435027261", "10307601595873709700152284273816112264069230130616436755625194854815875713954"}, + 3: {"2821565182194536844548159561693502659359617185244120367078079554186484126554", "3505843767911556378687030309984248845540243509899259641013678093033130930403"}, + 4: {"2581911344467009335267311115468803099551665605076196740867805258568234346338", "19937756971775647987995932169929341994314640652964949448313374472400716661030"}, + 5: {"685108087231508774477564247770172212460312782337200605669322048753928464687", "8447204650696766136447902020341177575205426561248465145919723016860428151883"}, + }, + 2: { + 1: {"21888242871839275220042445260109153167277707414472061641714758635765020556617", "0"}, + 2: {"21888242871839275220042445260109153167277707414472061641714758635765020556616", "0"}, + 3: {"21888242871839275222246405745257275088696311157297823662689037894645226208582", "0"}, + 4: {"2203960485148121921418603742825762020974279258880205651966", "0"}, + 5: {"2203960485148121921418603742825762020974279258880205651967", "0"}, + }, + 3: { + 1: {"11697423496358154304825782922584725312912383441159505038794027105778954184319", "303847389135065887422783454877609941456349188919719272345083954437860409601"}, + 2: {"3772000881919853776433695186713858239009073593817195771773381919316419345261", "2236595495967245188281701248203181795121068902605861227855261137820944008926"}, + 3: {"19066677689644738377698246183563772429336693972053703295610958340458742082029", "18382399103927718843559375435273026243156067647398564021675359801612095278180"}, + 4: {"5324479202449903542726783395506214481928257762400643279780343368557297135718", "16208900380737693084919495127334387981393726419856888799917914180988844123039"}, + 5: {"8941241848238582420466759817324047081148088512956452953208002715982955420483", "10338197737521362862238855242243140895517409139741313354160881284257516364953"}, + }, + } + nonResidues := make(map[int]map[int]*E2) + for pwr, v := range pwrs { + for coeff, v := range v { + el := E2{emulated.ValueOf[emulated.BN254Fp](v.A0), emulated.ValueOf[emulated.BN254Fp](v.A1)} + if nonResidues[pwr] == nil { + nonResidues[pwr] = make(map[int]*E2) + } + nonResidues[pwr][coeff] = &el + } + } + return &Ext2{fp: baseField, nonResidues: nonResidues} +} + +// TODO: check where to use Mod and where ModMul. + +func (e Ext2) MulByElement(x *E2, y *baseEl) *E2 { + // var yCopy fp.Element + // yCopy.Set(y) + z0 := e.fp.MulMod(&x.A0, y) // z.A0.Mul(&x.A0, &yCopy) + z1 := e.fp.MulMod(&x.A1, y) // z.A1.Mul(&x.A1, &yCopy) + return &E2{ // return z + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) Conjugate(x *E2) *E2 { + z0 := x.A0 // z.A0 = x.A0 + z1 := e.fp.Neg(&x.A1) // z.A1.Neg(&x.A1) + return &E2{ // return z + A0: z0, + A1: *z1, + } +} + +func (e Ext2) MulByNonResidueGeneric(x *E2, power, coef int) *E2 { + y := e.nonResidues[power][coef] + z := e.Mul(x, y) + return z +} + +func (e Ext2) MulByNonResidue(x *E2) *E2 { + /* + // below is the direct transliteration of the gnark-crypto code. Now only, + // for simplicity and debugging purposes, we do the non residue operations + // without optimisations. + + nine := big.NewInt(9) + // var a, b fp.Element + a := e.fp.MulConst(&x.A0, nine) // a.Double(&x.A0).Double(&a).Double(&a).Add(&a, &x.A0). + a = e.fp.Sub(a, &x.A1) // Sub(&a, &x.A1) + b := e.fp.MulConst(&x.A1, nine) // b.Double(&x.A1).Double(&b).Double(&b).Add(&b, &x.A1). + b = e.fp.Add(b, &x.A0) // Add(&b, &x.A0) + return &E2{ + A0: *a, // z.A0.Set(&a) + A1: *b, // z.A1.Set(&b) + } // return z + */ + // TODO: inline non-residue Multiplication + return e.MulByNonResidueGeneric(x, 0, 1) +} + +func (e Ext2) MulByNonResidueInv(x *E2) *E2 { + // TODO: to optimise with constant non-residue inverse + /* + // from gnark-crypto + // z.Mul(x, &nonResInverse) + // return z + */ + return e.MulByNonResidueGeneric(x, 0, -1) +} + +func (e Ext2) MulByNonResidue1Power1(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 1, 1) +} + +func (e Ext2) MulByNonResidue1Power2(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 1, 2) +} + +func (e Ext2) MulByNonResidue1Power3(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 1, 3) +} + +func (e Ext2) MulByNonResidue1Power4(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 1, 4) +} + +func (e Ext2) MulByNonResidue1Power5(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 1, 5) +} + +func (e Ext2) MulByNonResidue2Power1(x *E2) *E2 { + // TODO: A1 is 0, we can optimize for it + return e.MulByNonResidueGeneric(x, 2, 1) +} +func (e Ext2) MulByNonResidue2Power2(x *E2) *E2 { + // TODO: A1 is 0, we can optimize for it + return e.MulByNonResidueGeneric(x, 2, 2) +} + +func (e Ext2) MulByNonResidue2Power3(x *E2) *E2 { + // TODO: A1 is 0, we can optimize for it + return e.MulByNonResidueGeneric(x, 2, 3) +} + +func (e Ext2) MulByNonResidue2Power4(x *E2) *E2 { + // TODO: A1 is 0, we can optimize for it + return e.MulByNonResidueGeneric(x, 2, 4) +} + +func (e Ext2) MulByNonResidue2Power5(x *E2) *E2 { + // TODO: A1 is 0, we can optimize for it + return e.MulByNonResidueGeneric(x, 2, 5) +} + +func (e Ext2) MulByNonResidue3Power1(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 3, 1) +} + +func (e Ext2) MulByNonResidue3Power2(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 3, 2) +} + +func (e Ext2) MulByNonResidue3Power3(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 3, 3) +} + +func (e Ext2) MulByNonResidue3Power4(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 3, 4) +} + +func (e Ext2) MulByNonResidue3Power5(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 3, 5) +} + +func (e Ext2) Mul(x, y *E2) *E2 { + // var a, b, c fp.Element + a := e.fp.Add(&x.A0, &x.A1) // a.Add(&x.A0, &x.A1) + b := e.fp.Add(&y.A0, &y.A1) // b.Add(&y.A0, &y.A1) + a = e.fp.MulMod(a, b) // a.Mul(&a, &b) + b = e.fp.MulMod(&x.A0, &y.A0) // b.Mul(&x.A0, &y.A0) + c := e.fp.MulMod(&x.A1, &y.A1) // c.Mul(&x.A1, &y.A1) + z1 := e.fp.Sub(a, b) // z.A1.Sub(&a, &b). + z1 = e.fp.Sub(z1, c) // Sub(&z.A1, &c) + z0 := e.fp.Sub(b, c) // z.A0.Sub(&b, &c) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) Add(x, y *E2) *E2 { + z0 := e.fp.Add(&x.A0, &y.A0) // z.A0.Add(&x.A0, &y.A0) + z1 := e.fp.Add(&x.A1, &y.A1) // z.A1.Add(&x.A1, &y.A1) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) Sub(x, y *E2) *E2 { + z0 := e.fp.Sub(&x.A0, &y.A0) // z.A0.Sub(&x.A0, &y.A0) + z1 := e.fp.Sub(&x.A1, &y.A1) // z.A1.Sub(&x.A1, &y.A1) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) Neg(x *E2) *E2 { + z0 := e.fp.Neg(&x.A0) // z.A0.Neg(&x.A0) + z1 := e.fp.Neg(&x.A1) // z.A1.Neg(&x.A1) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) One() *E2 { + z0 := e.fp.One() // z.A0.SetOne() + z1 := e.fp.Zero() // z.A1.SetZero() + return &E2{ // return z + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) Zero() *E2 { + z0 := e.fp.Zero() + z1 := e.fp.Zero() + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) Square(x *E2) *E2 { + // var a, b fp.Element + a := e.fp.Add(&x.A0, &x.A1) // a.Add(&x.A0, &x.A1) + b := e.fp.Sub(&x.A0, &x.A1) // b.Sub(&x.A0, &x.A1) + a = e.fp.MulMod(a, b) // a.Mul(&a, &b) + b = e.fp.MulMod(&x.A0, &x.A1) // b.Mul(&x.A0, &x.A1). + b = e.fp.MulConst(b, big.NewInt(2)) // Double(&b) + return &E2{ + A0: *a, // z.A0.Set(&a) + A1: *b, // z.A1.Set(&b) + } +} + +func (e Ext2) Double(x *E2) *E2 { + two := big.NewInt(2) + z0 := e.fp.MulConst(&x.A0, two) // z.A0.Double(&x.A0) + z1 := e.fp.MulConst(&x.A1, two) // z.A1.Double(&x.A1) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) Halve(x *E2) *E2 { + // I'm trying to avoid hard-coding modulus here in case want to make generic + // for different curves. + // TODO: if implemented Half in field emulation, then replace with it. + one := e.fp.One() + two := e.fp.MulConst(one, big.NewInt(2)) + z0 := e.fp.Div(&x.A0, two) + z1 := e.fp.Div(&x.A1, two) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) MulBybTwistCurveCoeff(x *E2) *E2 { + // var res E2 + res := e.MulByNonResidueInv(x) // res.MulByNonResidueInv(x) + z := e.Double(res) // z.Double(&res). + z = e.Add(z, res) // Add(&res, z) + return z // return z +} + +func (e Ext2) Inverse(x *E2) *E2 { + // var t0, t1 fp.Element + t0 := e.fp.MulMod(&x.A0, &x.A0) // t0.Square(&x.A0) + t1 := e.fp.MulMod(&x.A1, &x.A1) // t1.Square(&x.A1) + t0 = e.fp.Add(t0, t1) // t0.Add(&t0, &t1) + t1 = e.fp.Inverse(t0) // t1.Inverse(&t0) + z0 := e.fp.MulMod(&x.A0, t1) // z.A0.Mul(&x.A0, &t1) + z1 := e.fp.MulMod(&x.A1, t1) // z.A1.Mul(&x.A1, &t1). + z1 = e.fp.Neg(z1) // Neg(&z.A1) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) AssertIsEqual(x, y *E2) { + e.fp.AssertIsEqual(&x.A0, &y.A0) + e.fp.AssertIsEqual(&x.A1, &y.A1) +} diff --git a/std/algebra/emulated/fields_bn254/e6.go b/std/algebra/emulated/fields_bn254/e6.go new file mode 100644 index 0000000000..a07d04d015 --- /dev/null +++ b/std/algebra/emulated/fields_bn254/e6.go @@ -0,0 +1,201 @@ +package fields_bn254 + +type E6 struct { + B0, B1, B2 E2 +} + +type Ext6 struct { + *Ext2 +} + +func NewExt6(baseField *curveF) *Ext6 { + return &Ext6{Ext2: NewExt2(baseField)} +} + +func (e Ext6) Add(x, y *E6) *E6 { + z0 := e.Ext2.Add(&x.B0, &y.B0) // z.B0.Add(&x.B0, &y.B0) + z1 := e.Ext2.Add(&x.B1, &y.B1) // z.B1.Add(&x.B1, &y.B1) + z2 := e.Ext2.Add(&x.B2, &y.B2) // z.B2.Add(&x.B2, &y.B2) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Neg(x *E6) *E6 { + z0 := e.Ext2.Neg(&x.B0) // z.B0.Neg(&x.B0) + z1 := e.Ext2.Neg(&x.B1) // z.B1.Neg(&x.B1) + z2 := e.Ext2.Neg(&x.B2) // z.B2.Neg(&x.B2) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Sub(x, y *E6) *E6 { + z0 := e.Ext2.Sub(&x.B0, &y.B0) // z.B0.Sub(&x.B0, &y.B0) + z1 := e.Ext2.Sub(&x.B1, &y.B1) // z.B1.Sub(&x.B1, &y.B1) + z2 := e.Ext2.Sub(&x.B2, &y.B2) // z.B2.Sub(&x.B2, &y.B2) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Mul(x, y *E6) *E6 { + // var t0, t1, t2, c0, c1, c2, tmp E2 + t0 := e.Ext2.Mul(&x.B0, &y.B0) // t0.Mul(&x.B0, &y.B0) + t1 := e.Ext2.Mul(&x.B1, &y.B1) // t1.Mul(&x.B1, &y.B1) + t2 := e.Ext2.Mul(&x.B2, &y.B2) // t2.Mul(&x.B2, &y.B2) + c0 := e.Ext2.Add(&x.B1, &x.B2) // c0.Add(&x.B1, &x.B2) + tmp := e.Ext2.Add(&y.B1, &y.B2) // tmp.Add(&y.B1, &y.B2) + c0 = e.Ext2.Mul(c0, tmp) // c0.Mul(&c0, &tmp). + c0 = e.Ext2.Sub(c0, t1) // Sub(&c0, &t1). + c0 = e.Ext2.Sub(c0, t2) // Sub(&c0, &t2). + c0 = e.Ext2.MulByNonResidue(c0) // MulByNonResidue(&c0). + c0 = e.Ext2.Add(c0, t0) // Add(&c0, &t0) + c1 := e.Ext2.Add(&x.B0, &x.B1) // c1.Add(&x.B0, &x.B1) + tmp = e.Ext2.Add(&y.B0, &y.B1) // tmp.Add(&y.B0, &y.B1) + c1 = e.Ext2.Mul(c1, tmp) // c1.Mul(&c1, &tmp). + c1 = e.Ext2.Sub(c1, t0) // Sub(&c1, &t0). + c1 = e.Ext2.Sub(c1, t1) // Sub(&c1, &t1) + tmp = e.Ext2.MulByNonResidue(t2) // tmp.MulByNonResidue(&t2) + c1 = e.Ext2.Add(c1, tmp) // c1.Add(&c1, &tmp) + tmp = e.Ext2.Add(&x.B0, &x.B2) // tmp.Add(&x.B0, &x.B2) + c2 := e.Ext2.Add(&y.B0, &y.B2) // c2.Add(&y.B0, &y.B2). + c2 = e.Ext2.Mul(c2, tmp) // Mul(&c2, &tmp). + c2 = e.Ext2.Sub(c2, t0) // Sub(&c2, &t0). + c2 = e.Ext2.Sub(c2, t2) // Sub(&c2, &t2). + c2 = e.Ext2.Add(c2, t1) // Add(&c2, &t1) + return &E6{ + B0: *c0, // z.B0.Set(&c0) + B1: *c1, // z.B1.Set(&c1) + B2: *c2, // z.B2.Set(&c2) + } // return z +} + +func (e Ext6) double(x *E6) *E6 { + z0 := e.Ext2.Double(&x.B0) // z.B0.Double(&x.B0) + z1 := e.Ext2.Double(&x.B1) // z.B1.Double(&x.B1) + z2 := e.Ext2.Double(&x.B2) // z.B2.Double(&x.B2) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Square(x *E6) *E6 { + // var c4, c5, c1, c2, c3, c0 E2 + c4 := e.Ext2.Mul(&x.B0, &x.B1) // c4.Mul(&x.B0, &x.B1). + c4 = e.Ext2.Double(c4) // Double(&c4) + c5 := e.Ext2.Square(&x.B2) // c5.Square(&x.B2) + c1 := e.Ext2.MulByNonResidue(c5) // c1.MulByNonResidue(&c5). + c1 = e.Ext2.Add(c1, c4) // Add(&c1, &c4) + c2 := e.Ext2.Sub(c4, c5) // c2.Sub(&c4, &c5) + c3 := e.Ext2.Square(&x.B0) // c3.Square(&x.B0) + c4 = e.Ext2.Sub(&x.B0, &x.B1) // c4.Sub(&x.B0, &x.B1). + c4 = e.Ext2.Add(c4, &x.B2) // Add(&c4, &x.B2) + c5 = e.Ext2.Mul(&x.B1, &x.B2) // c5.Mul(&x.B1, &x.B2). + c5 = e.Ext2.Double(c5) // Double(&c5) + c4 = e.Ext2.Square(c4) // c4.Square(&c4) + c0 := e.Ext2.MulByNonResidue(c5) // c0.MulByNonResidue(&c5). + c0 = e.Ext2.Add(c0, c3) // Add(&c0, &c3) + z2 := e.Ext2.Add(c2, c4) // z.B2.Add(&c2, &c4). + z2 = e.Ext2.Add(z2, c5) // Add(&z.B2, &c5). + z2 = e.Ext2.Sub(z2, c3) // Sub(&z.B2, &c3) + z0 := c0 // z.B0.Set(&c0) + z1 := c1 // z.B1.Set(&c1) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Inverse(x *E6) *E6 { + // var t0, t1, t2, t3, t4, t5, t6, c0, c1, c2, d1, d2 E2 + t0 := e.Ext2.Square(&x.B0) // t0.Square(&x.B0) + t1 := e.Ext2.Square(&x.B1) // t1.Square(&x.B1) + t2 := e.Ext2.Square(&x.B2) // t2.Square(&x.B2) + t3 := e.Ext2.Mul(&x.B0, &x.B1) // t3.Mul(&x.B0, &x.B1) + t4 := e.Ext2.Mul(&x.B0, &x.B2) // t4.Mul(&x.B0, &x.B2) + t5 := e.Ext2.Mul(&x.B1, &x.B2) // t5.Mul(&x.B1, &x.B2) + c0 := e.Ext2.MulByNonResidue(t5) // c0.MulByNonResidue(&t5). + c0 = e.Ext2.Neg(c0) // Neg(&c0). + c0 = e.Ext2.Add(c0, t0) // Add(&c0, &t0) + c1 := e.Ext2.MulByNonResidue(t2) // c1.MulByNonResidue(&t2). + c1 = e.Ext2.Sub(c1, t3) // Sub(&c1, &t3) + c2 := e.Ext2.Sub(t1, t4) // c2.Sub(&t1, &t4) + t6 := e.Ext2.Mul(&x.B0, c0) // t6.Mul(&x.B0, &c0) + d1 := e.Ext2.Mul(&x.B2, c1) // d1.Mul(&x.B2, &c1) + d2 := e.Ext2.Mul(&x.B1, c2) // d2.Mul(&x.B1, &c2) + d1 = e.Ext2.Add(d1, d2) // d1.Add(&d1, &d2). + d1 = e.Ext2.MulByNonResidue(d1) // MulByNonResidue(&d1) + t6 = e.Ext2.Add(t6, d1) // t6.Add(&t6, &d1) + t6 = e.Ext2.Inverse(t6) // t6.Inverse(&t6) + z0 := e.Ext2.Mul(c0, t6) // z.B0.Mul(&c0, &t6) + z1 := e.Ext2.Mul(c1, t6) // z.B1.Mul(&c1, &t6) + z2 := e.Ext2.Mul(c2, t6) // z.B2.Mul(&c2, &t6) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} +func (e Ext6) MulByE2(x *E6, y *E2) *E6 { + // var yCopy E2 + // yCopy.Set(y) + z0 := e.Ext2.Mul(&x.B0, y) // z.B0.Mul(&x.B0, &yCopy) + z1 := e.Ext2.Mul(&x.B1, y) // z.B1.Mul(&x.B1, &yCopy) + z2 := e.Ext2.Mul(&x.B2, y) // z.B2.Mul(&x.B2, &yCopy) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) MulBy01(z *E6, c0, c1 *E2) *E6 { + // var a, b, tmp, t0, t1, t2 E2 + a := e.Ext2.Mul(&z.B0, c0) // a.Mul(&z.B0, c0) + b := e.Ext2.Mul(&z.B1, c1) // b.Mul(&z.B1, c1) + tmp := e.Ext2.Add(&z.B1, &z.B2) // tmp.Add(&z.B1, &z.B2) + t0 := e.Ext2.Mul(c1, tmp) // t0.Mul(c1, &tmp) + t0 = e.Ext2.Sub(t0, b) // t0.Sub(&t0, &b) + t0 = e.Ext2.MulByNonResidue(t0) // t0.MulByNonResidue(&t0) + t0 = e.Ext2.Add(t0, a) // t0.Add(&t0, &a) + tmp = e.Ext2.Add(&z.B0, &z.B2) // tmp.Add(&z.B0, &z.B2) + t2 := e.Ext2.Mul(c0, tmp) // t2.Mul(c0, &tmp) + t2 = e.Ext2.Sub(t2, a) // t2.Sub(&t2, &a) + t2 = e.Ext2.Add(t2, b) // t2.Add(&t2, &b) + t1 := e.Ext2.Add(c0, c1) // t1.Add(c0, c1) + tmp = e.Ext2.Add(&z.B0, &z.B1) // tmp.Add(&z.B0, &z.B1) + t1 = e.Ext2.Mul(t1, tmp) // t1.Mul(&t1, &tmp) + t1 = e.Ext2.Sub(t1, a) // t1.Sub(&t1, &a) + t1 = e.Ext2.Sub(t1, b) // t1.Sub(&t1, &b) + return &E6{ + B0: *t0, // z.B0.Set(&t0) + B1: *t1, // z.B1.Set(&t1) + B2: *t2, // z.B2.Set(&t2) + } // return z +} + +func (e Ext6) MulByNonResidue(x *E6) *E6 { + z2, z1, z0 := &x.B1, &x.B0, &x.B2 // z.B2, z.B1, z.B0 = x.B1, x.B0, x.B2 + z0 = e.Ext2.MulByNonResidue(z0) // z.B0.MulByNonResidue(&z.B0) + return &E6{ // return z + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) AssertIsEqual(x, y *E6) { + e.Ext2.AssertIsEqual(&x.B0, &y.B0) + e.Ext2.AssertIsEqual(&x.B1, &y.B1) + e.Ext2.AssertIsEqual(&x.B2, &y.B2) +} diff --git a/std/algebra/pairing_bn254/doc.go b/std/algebra/emulated/sw_bn254/doc.go similarity index 64% rename from std/algebra/pairing_bn254/doc.go rename to std/algebra/emulated/sw_bn254/doc.go index 5f04a7dd72..60bfca6876 100644 --- a/std/algebra/pairing_bn254/doc.go +++ b/std/algebra/emulated/sw_bn254/doc.go @@ -1,7 +1,7 @@ -// Package pairing_bn254 implements pairing over BN254 curve. +// Package sw_bn254 implements G1 and G2 arithmetics and pairing computation over BN254 curve. // // The implementation follows very closely the implementation of its out-circuit // counterpart in [gnark-crypto]. // // [gnark-crypto]: https://github.com/ConsenSys/gnark-crypto/tree/master/ecc/bn254 -package pairing_bn254 +package sw_bn254 diff --git a/std/algebra/pairing_bn254/doc_test.go b/std/algebra/emulated/sw_bn254/doc_test.go similarity index 81% rename from std/algebra/pairing_bn254/doc_test.go rename to std/algebra/emulated/sw_bn254/doc_test.go index 8481c45361..db095a0210 100644 --- a/std/algebra/pairing_bn254/doc_test.go +++ b/std/algebra/emulated/sw_bn254/doc_test.go @@ -1,4 +1,4 @@ -package pairing_bn254_test +package sw_bn254_test import ( "crypto/rand" @@ -9,21 +9,21 @@ import ( "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/std/algebra/pairing_bn254" + "github.com/consensys/gnark/std/algebra/emulated/sw_bn254" ) type PairCircuit struct { - InG1 pairing_bn254.G1Affine - InG2 pairing_bn254.G2Affine - Res pairing_bn254.GTEl + InG1 sw_bn254.G1Affine + InG2 sw_bn254.G2Affine + Res sw_bn254.GTEl } func (c *PairCircuit) Define(api frontend.API) error { - pairing, err := pairing_bn254.NewPairing(api) + pairing, err := sw_bn254.NewPairing(api) if err != nil { return fmt.Errorf("new pairing: %w", err) } - res, err := pairing.Pair([]*pairing_bn254.G1Affine{&c.InG1}, []*pairing_bn254.G2Affine{&c.InG2}) + res, err := pairing.Pair([]*sw_bn254.G1Affine{&c.InG1}, []*sw_bn254.G2Affine{&c.InG2}) if err != nil { return fmt.Errorf("pair: %w", err) } @@ -42,9 +42,9 @@ func ExamplePairing() { } circuit := PairCircuit{} witness := PairCircuit{ - InG1: pairing_bn254.NewG1Affine(p), - InG2: pairing_bn254.NewG2Affine(q), - Res: pairing_bn254.NewGTEl(res), + InG1: sw_bn254.NewG1Affine(p), + InG2: sw_bn254.NewG2Affine(q), + Res: sw_bn254.NewGTEl(res), } ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) if err != nil { diff --git a/std/algebra/pairing_bn254/g1.go b/std/algebra/emulated/sw_bn254/g1.go similarity index 66% rename from std/algebra/pairing_bn254/g1.go rename to std/algebra/emulated/sw_bn254/g1.go index 4f1fa5d2c4..69ce54898c 100644 --- a/std/algebra/pairing_bn254/g1.go +++ b/std/algebra/emulated/sw_bn254/g1.go @@ -1,12 +1,12 @@ -package pairing_bn254 +package sw_bn254 import ( "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark/std/algebra/weierstrass" + "github.com/consensys/gnark/std/algebra/emulated/sw_emulated" "github.com/consensys/gnark/std/math/emulated" ) -type G1Affine = weierstrass.AffinePoint[emulated.BN254Fp] +type G1Affine = sw_emulated.AffinePoint[emulated.BN254Fp] func NewG1Affine(v bn254.G1Affine) G1Affine { return G1Affine{ diff --git a/std/algebra/pairing_bn254/g2.go b/std/algebra/emulated/sw_bn254/g2.go similarity index 70% rename from std/algebra/pairing_bn254/g2.go rename to std/algebra/emulated/sw_bn254/g2.go index ace3b00efe..1ba7d154a6 100644 --- a/std/algebra/pairing_bn254/g2.go +++ b/std/algebra/emulated/sw_bn254/g2.go @@ -1,29 +1,30 @@ -package pairing_bn254 +package sw_bn254 import ( "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/std/algebra/emulated/fields_bn254" "github.com/consensys/gnark/std/math/emulated" ) type G2Affine struct { - X, Y e2 + X, Y fields_bn254.E2 } type g2Jacobian struct { - X, Y, Z e2 + X, Y, Z fields_bn254.E2 } type g2Projective struct { - X, Y, Z e2 + X, Y, Z fields_bn254.E2 } func NewG2Affine(v bn254.G2Affine) G2Affine { return G2Affine{ - X: e2{ + X: fields_bn254.E2{ A0: emulated.ValueOf[emulated.BN254Fp](v.X.A0), A1: emulated.ValueOf[emulated.BN254Fp](v.X.A1), }, - Y: e2{ + Y: fields_bn254.E2{ A0: emulated.ValueOf[emulated.BN254Fp](v.Y.A0), A1: emulated.ValueOf[emulated.BN254Fp](v.Y.A1), }, diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go new file mode 100644 index 0000000000..8aceb63f2e --- /dev/null +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -0,0 +1,319 @@ +package sw_bn254 + +import ( + "fmt" + + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/algebra/emulated/fields_bn254" + "github.com/consensys/gnark/std/math/emulated" +) + +type Pairing struct { + *fields_bn254.Ext12 +} + +type GTEl = fields_bn254.E12 + +func NewGTEl(v bn254.GT) GTEl { + return GTEl{ + C0: fields_bn254.E6{ + B0: fields_bn254.E2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B0.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B0.A1), + }, + B1: fields_bn254.E2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B1.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B1.A1), + }, + B2: fields_bn254.E2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B2.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B2.A1), + }, + }, + C1: fields_bn254.E6{ + B0: fields_bn254.E2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B0.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B0.A1), + }, + B1: fields_bn254.E2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B1.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B1.A1), + }, + B2: fields_bn254.E2{ + A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B2.A0), + A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B2.A1), + }, + }, + } +} + +func NewPairing(api frontend.API) (*Pairing, error) { + ba, err := emulated.NewField[emulated.BN254Fp](api) + if err != nil { + return nil, fmt.Errorf("new base api: %w", err) + } + return &Pairing{ + Ext12: fields_bn254.NewExt12(ba), + }, nil +} + +func (pr Pairing) DoubleStep(p *g2Projective) (*g2Projective, *lineEvaluation) { + // var t1, A, B, C, D, E, EE, F, G, H, I, J, K fptower.E2 + A := pr.Ext2.Mul(&p.X, &p.Y) // A.Mul(&p.x, &p.y) + A = pr.Ext2.Halve(A) // A.Halve() + B := pr.Ext2.Square(&p.Y) // B.Square(&p.y) + C := pr.Ext2.Square(&p.Z) // C.Square(&p.z) + D := pr.Ext2.Double(C) // D.Double(&C). + D = pr.Ext2.Add(D, C) // Add(&D, &C) + E := pr.Ext2.MulBybTwistCurveCoeff(D) // E.MulBybTwistCurveCoeff(&D) + F := pr.Ext2.Double(E) // F.Double(&E). + F = pr.Ext2.Add(F, E) // Add(&F, &E) + G := pr.Ext2.Add(B, F) // G.Add(&B, &F) + G = pr.Ext2.Halve(G) // G.Halve() + H := pr.Ext2.Add(&p.Y, &p.Z) // H.Add(&p.y, &p.z). + H = pr.Ext2.Square(H) // Square(&H) + t1 := pr.Ext2.Add(B, C) // t1.Add(&B, &C) + H = pr.Ext2.Sub(H, t1) // H.Sub(&H, &t1) + I := pr.Ext2.Sub(E, B) // I.Sub(&E, &B) + J := pr.Ext2.Square(&p.X) // J.Square(&p.x) + EE := pr.Ext2.Square(E) // EE.Square(&E) + K := pr.Ext2.Double(EE) // K.Double(&EE). + K = pr.Ext2.Add(K, EE) // Add(&K, &EE) + px := pr.Ext2.Sub(B, F) // p.x.Sub(&B, &F). + px = pr.Ext2.Mul(px, A) // Mul(&p.x, &A) + py := pr.Ext2.Square(G) // p.y.Square(&G). + py = pr.Ext2.Sub(py, K) // Sub(&p.y, &K) + pz := pr.Ext2.Mul(B, H) // p.z.Mul(&B, &H) + ev0 := pr.Ext2.Neg(H) // evaluations.r0.Neg(&H) + ev1 := pr.Ext2.Double(J) // evaluations.r1.Double(&J). + ev1 = pr.Ext2.Add(ev1, J) // Add(&evaluations.r1, &J) + ev2 := I // evaluations.r2.Set(&I) + return &g2Projective{ + X: *px, + Y: *py, + Z: *pz, + }, + &lineEvaluation{ + r0: *ev0, + r1: *ev1, + r2: *ev2, + } +} + +func (pr Pairing) affineToProjective(Q *G2Affine) *g2Projective { + // TODO: check point at infinity? We do not filter them in the Miller Loop neither. + // if Q.X.IsZero() && Q.Y.IsZero() { + // p.z.SetZero() + // p.x.SetOne() + // p.y.SetOne() + // return p + // } + pz := pr.Ext2.One() // p.z.SetOne() + px := &Q.X // p.x.Set(&Q.X) + py := &Q.Y // p.y.Set(&Q.Y) + return &g2Projective{ // return p + X: *px, + Y: *py, + Z: *pz, + } +} + +func (pr Pairing) NegAffine(a *G2Affine) *G2Affine { + px := &a.X // p.X = a.X + py := pr.Ext2.Neg(&a.Y) // p.Y.Neg(&a.Y) + return &G2Affine{ // return p + X: *px, + Y: *py, + } +} + +func (pr Pairing) AddStep(p *g2Projective, a *G2Affine) (*g2Projective, *lineEvaluation) { + // var Y2Z1, X2Z1, O, L, C, D, E, F, G, H, t0, t1, t2, J fptower.E2 + Y2Z1 := pr.Ext2.Mul(&a.Y, &p.Z) // Y2Z1.Mul(&a.Y, &p.z) + O := pr.Ext2.Sub(&p.Y, Y2Z1) // O.Sub(&p.y, &Y2Z1) + X2Z1 := pr.Ext2.Mul(&a.X, &p.Z) // X2Z1.Mul(&a.X, &p.z) + L := pr.Ext2.Sub(&p.X, X2Z1) // L.Sub(&p.x, &X2Z1) + C := pr.Ext2.Square(O) // C.Square(&O) + D := pr.Ext2.Square(L) // D.Square(&L) + E := pr.Ext2.Mul(L, D) // E.Mul(&L, &D) + F := pr.Ext2.Mul(&p.Z, C) // F.Mul(&p.z, &C) + G := pr.Ext2.Mul(&p.X, D) // G.Mul(&p.x, &D) + t0 := pr.Ext2.Double(G) // t0.Double(&G) + H := pr.Ext2.Add(E, F) // H.Add(&E, &F). + H = pr.Ext2.Sub(H, t0) // Sub(&H, &t0) + t1 := pr.Ext2.Mul(&p.Y, E) // t1.Mul(&p.y, &E) + px := pr.Ext2.Mul(L, H) // p.x.Mul(&L, &H) + py := pr.Ext2.Sub(G, H) // p.y.Sub(&G, &H). + py = pr.Ext2.Mul(py, O) // Mul(&p.y, &O). + py = pr.Ext2.Sub(py, t1) // Sub(&p.y, &t1) + pz := pr.Ext2.Mul(E, &p.Z) // p.z.Mul(&E, &p.z) + t2 := pr.Ext2.Mul(L, &a.Y) // t2.Mul(&L, &a.Y) + J := pr.Ext2.Mul(&a.X, O) // J.Mul(&a.X, &O). + J = pr.Ext2.Sub(J, t2) // Sub(&J, &t2) + ev0 := L // evaluations.r0.Set(&L) + ev1 := pr.Ext2.Neg(O) // evaluations.r1.Neg(&O) + ev2 := J // evaluations.r2.Set(&J) + return &g2Projective{ + X: *px, + Y: *py, + Z: *pz, + }, &lineEvaluation{ + r0: *ev0, + r1: *ev1, + r2: *ev2, + } +} + +type lineEvaluation struct { + r0 fields_bn254.E2 + r1 fields_bn254.E2 + r2 fields_bn254.E2 +} + +var loopCounter = [66]int8{ + 0, 0, 0, 1, 0, 1, 0, -1, 0, 0, -1, + 0, 0, 0, 1, 0, 0, -1, 0, -1, 0, 0, + 0, 1, 0, -1, 0, 0, 0, 0, -1, 0, 0, + 1, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, + -1, 0, 0, -1, 0, 1, 0, -1, 0, 0, 0, + -1, 0, -1, 0, 0, 0, 1, 0, -1, 0, 1, +} + +func (pr Pairing) MillerLoop(p []*G1Affine, q []*G2Affine) (*GTEl, error) { + n := len(p) + if n == 0 || n != len(q) { + return nil, fmt.Errorf("invalid inputs sizes") + } + + // TODO: we have omitted filtering for infinity points. + + // projective points for Q + qProj := make([]*g2Projective, n) // qProj := make([]g2Proj, n) + qNeg := make([]*G2Affine, n) // qNeg := make([]G2Affine, n) + for k := 0; k < n; k++ { + qProj[k] = pr.affineToProjective(q[k]) // qProj[k].FromAffine(&q[k]) + qNeg[k] = pr.NegAffine(q[k]) // qNeg[k].Neg(&q[k]) + } + + var l, l0 *lineEvaluation + result := pr.Ext12.One() // var tmp, result GTEl + + // i == len(loopCounter) - 2 + for k := 0; k < n; k++ { + qProj[k], l = pr.DoubleStep(qProj[k]) // qProj[k].DoubleStep(&l) + l.r0 = *pr.Ext12.Ext2.MulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) + l.r1 = *pr.Ext12.Ext2.MulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) + result = pr.Ext12.MulBy034(result, &l.r0, &l.r1, &l.r2) // result.MulBy034(&l.r0, &l.r1, &l.r2) + } + + for i := len(loopCounter) - 3; i >= 0; i-- { + result = pr.Ext12.Square(result) // result.Square(&result) + + for k := 0; k < n; k++ { + qProj[k], l = pr.DoubleStep(qProj[k]) // qProj[k].DoubleStep(&l) + l.r0 = *pr.Ext12.Ext2.MulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) + l.r1 = *pr.Ext12.Ext2.MulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) + + if loopCounter[i] == 1 { + qProj[k], l0 = pr.AddStep(qProj[k], q[k]) // qProj[k].AddMixedStep(&l0, &q[k]) + l0.r0 = *pr.Ext12.Ext2.MulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) + l0.r1 = *pr.Ext12.Ext2.MulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) + tmp := pr.Ext12.MulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result = pr.Ext12.Mul(result, tmp) // result.Mul(&result, &tmp) + } else if loopCounter[i] == -1 { + qProj[k], l0 = pr.AddStep(qProj[k], qNeg[k]) // qProj[k].AddMixedStep(&l0, &qNeg[k]) + l0.r0 = *pr.Ext12.Ext2.MulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) + l0.r1 = *pr.Ext12.Ext2.MulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) + tmp := pr.Ext12.MulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result = pr.Ext12.Mul(result, tmp) //result.Mul(&result, &tmp) + } else { + result = pr.Ext12.MulBy034(result, &l.r0, &l.r1, &l.r2) // result.MulBy034(&l.r0, &l.r1, &l.r2) + } + } + } + + Q1, Q2 := new(G2Affine), new(G2Affine) // var Q1, Q2 G2Affine + for k := 0; k < n; k++ { + //Q1 = π(Q) + // TODO(ivokub): define phi(Q) in G2 instead of doing manually? + Q1.X = *pr.Ext12.Ext2.Conjugate(&q[k].X) // Q1.X.Conjugate(&q[k].X).MulByNonResidue1Power2(&Q1.X) + Q1.X = *pr.Ext12.Ext2.MulByNonResidue1Power2(&Q1.X) // Q1.X.Conjugate(&q[k].X).MulByNonResidue1Power2(&Q1.X) + Q1.Y = *pr.Ext12.Ext2.Conjugate(&q[k].Y) // Q1.Y.Conjugate(&q[k].Y).MulByNonResidue1Power3(&Q1.Y) + Q1.Y = *pr.Ext12.Ext2.MulByNonResidue1Power3(&Q1.Y) // Q1.Y.Conjugate(&q[k].Y).MulByNonResidue1Power3(&Q1.Y) + + // Q2 = -π²(Q) + Q2.X = *pr.Ext12.Ext2.MulByNonResidue2Power2(&q[k].X) // Q2.X.MulByNonResidufields_bn254.E2Power2(&q[k].X) + Q2.Y = *pr.Ext12.Ext2.MulByNonResidue2Power3(&q[k].Y) // Q2.Y.MulByNonResidufields_bn254.E2Power3(&q[k].Y).Neg(&Q2.Y) + Q2.Y = *pr.Ext12.Ext2.Neg(&Q2.Y) // Q2.Y.MulByNonResidufields_bn254.E2Power3(&q[k].Y).Neg(&Q2.Y) + + qProj[k], l0 = pr.AddStep(qProj[k], Q1) // qProj[k].AddMixedStep(&l0, &Q1) + l0.r0 = *pr.Ext12.Ext2.MulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) + l0.r1 = *pr.Ext12.Ext2.MulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) + + qProj[k], l = pr.AddStep(qProj[k], Q2) // qProj[k].AddMixedStep(&l, &Q2) + l.r0 = *pr.Ext12.Ext2.MulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) + l.r1 = *pr.Ext12.Ext2.MulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) + tmp := pr.Ext12.MulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) + result = pr.Ext12.Mul(result, tmp) // result.Mul(&result, &tmp) + } + + return result, nil +} + +func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { + // var result GT + // result.Set(z) + var t [4]*GTEl // var t [4]GT + + // easy part + t[0] = pr.Ext12.Conjugate(e) // t[0].Conjugate(&result) + result := pr.Ext12.Inverse(e) // result.Inverse(&result) + t[0] = pr.Ext12.Mul(t[0], result) // t[0].Mul(&t[0], &result) + result = pr.Ext12.FrobeniusSquare(t[0]) // result.FrobeniusSquare(&t[0]). + result = pr.Ext12.Mul(result, t[0]) // Mul(&result, &t[0]) + + //hard part + t[0] = pr.Ext12.Expt(result) // t[0].Expt(&result). + t[0] = pr.Ext12.Conjugate(t[0]) // Conjugate(&t[0]) + t[0] = pr.Ext12.CyclotomicSquare(t[0]) // t[0].CyclotomicSquare(&t[0]) + t[2] = pr.Ext12.Expt(t[0]) // t[2].Expt(&t[0]). + t[2] = pr.Ext12.Conjugate(t[2]) // Conjugate(&t[2]) + t[1] = pr.Ext12.CyclotomicSquare(t[2]) // t[1].CyclotomicSquare(&t[2]) + t[2] = pr.Ext12.Mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) + t[2] = pr.Ext12.Mul(t[2], result) // t[2].Mul(&t[2], &result) + t[1] = pr.Ext12.Expt(t[2]) // t[1].Expt(&t[2]). + t[1] = pr.Ext12.CyclotomicSquare(t[1]) // CyclotomicSquare(&t[1]). + t[1] = pr.Ext12.Mul(t[1], t[2]) // Mul(&t[1], &t[2]). + t[1] = pr.Ext12.Conjugate(t[1]) // Conjugate(&t[1]) + t[3] = pr.Ext12.Conjugate(t[1]) // t[3].Conjugate(&t[1]) + t[1] = pr.Ext12.CyclotomicSquare(t[0]) // t[1].CyclotomicSquare(&t[0]) + t[1] = pr.Ext12.Mul(t[1], result) // t[1].Mul(&t[1], &result) + t[1] = pr.Ext12.Conjugate(t[1]) // t[1].Conjugate(&t[1]) + t[1] = pr.Ext12.Mul(t[1], t[3]) // t[1].Mul(&t[1], &t[3]) + t[0] = pr.Ext12.Mul(t[0], t[1]) // t[0].Mul(&t[0], &t[1]) + t[2] = pr.Ext12.Mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) + t[3] = pr.Ext12.FrobeniusSquare(t[1]) // t[3].FrobeniusSquare(&t[1]) + t[2] = pr.Ext12.Mul(t[2], t[3]) // t[2].Mul(&t[2], &t[3]) + t[3] = pr.Ext12.Conjugate(result) // t[3].Conjugate(&result) + t[3] = pr.Ext12.Mul(t[3], t[0]) // t[3].Mul(&t[3], &t[0]) + t[1] = pr.Ext12.FrobeniusCube(t[3]) // t[1].FrobeniusCube(&t[3]) + t[2] = pr.Ext12.Mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) + t[1] = pr.Ext12.Frobenius(t[0]) // t[1].Frobenius(&t[0]) + t[1] = pr.Ext12.Mul(t[1], t[2]) // t[1].Mul(&t[1], &t[2]) + // result.Set(&t[1]) + return t[1] // return result +} + +func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { + res, err := pr.MillerLoop(P, Q) + if err != nil { + return nil, fmt.Errorf("miller loop: %w", err) + } + res = pr.FinalExponentiation(res) + return res, nil +} + +func (pr Pairing) AssertIsEqual(x, y *GTEl) { + pr.Ext12.AssertIsEqual(x, y) +} diff --git a/std/algebra/pairing_bn254/pairing_test.go b/std/algebra/emulated/sw_bn254/pairing_test.go similarity index 90% rename from std/algebra/pairing_bn254/pairing_test.go rename to std/algebra/emulated/sw_bn254/pairing_test.go index 30fddc1829..5de8a3bc89 100644 --- a/std/algebra/pairing_bn254/pairing_test.go +++ b/std/algebra/emulated/sw_bn254/pairing_test.go @@ -1,4 +1,4 @@ -package pairing_bn254 +package sw_bn254 import ( "crypto/rand" @@ -8,8 +8,6 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/weierstrass" - "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/test" ) @@ -28,7 +26,7 @@ func randomG1G2Affines(assert *test.Assert) (bn254.G1Affine, bn254.G2Affine) { } type MillerLoopCircuit struct { - InG1 weierstrass.AffinePoint[emulated.BN254Fp] + InG1 G1Affine InG2 G2Affine Res GTEl } @@ -42,7 +40,7 @@ func (c *MillerLoopCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("pair: %w", err) } - pairing.ext12.assertIsEqual(res, &c.Res) + pairing.AssertIsEqual(res, &c.Res) return nil } @@ -71,7 +69,7 @@ func (c *FinalExponentiationCircuit) Define(api frontend.API) error { return fmt.Errorf("new pairing: %w", err) } res := pairing.FinalExponentiation(&c.InGt) - pairing.ext12.assertIsEqual(res, &c.Res) + pairing.AssertIsEqual(res, &c.Res) return nil } @@ -103,7 +101,7 @@ func (c *PairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("pair: %w", err) } - pairing.ext12.assertIsEqual(res, &c.Res) + pairing.AssertIsEqual(res, &c.Res) return nil } diff --git a/std/algebra/weierstrass/doc.go b/std/algebra/emulated/sw_emulated/doc.go similarity index 83% rename from std/algebra/weierstrass/doc.go rename to std/algebra/emulated/sw_emulated/doc.go index dfcb647fe5..5ff58f9467 100644 --- a/std/algebra/weierstrass/doc.go +++ b/std/algebra/emulated/sw_emulated/doc.go @@ -1,5 +1,5 @@ /* -Package weierstrass implements elliptic curve group operations in (short) +Package sw_emulated implements elliptic curve group operations in (short) Weierstrass form. The elliptic curve is the set of points (X,Y) satisfying the equation: @@ -22,9 +22,9 @@ field. For now, we only have a single curve defined on every base field, but this may change in the future with the addition of additional curves. This package uses field emulation (unlike packages -[github.com/consensys/gnark/std/algebra/sw_bls12377] and -[github.com/consensys/gnark/std/algebra/sw_bls24315], which use 2-chains). This +[github.com/consensys/gnark/std/algebra/native/sw_bls12377] and +[github.com/consensys/gnark/std/algebra/native/sw_bls24315], which use 2-chains). This allows to use any curve over any native (SNARK) field. The drawback of this approach is the extreme cost of the operations. */ -package weierstrass +package sw_emulated diff --git a/std/algebra/weierstrass/doc_test.go b/std/algebra/emulated/sw_emulated/doc_test.go similarity index 89% rename from std/algebra/weierstrass/doc_test.go rename to std/algebra/emulated/sw_emulated/doc_test.go index cfa81a1fe0..bf939bfd3d 100644 --- a/std/algebra/weierstrass/doc_test.go +++ b/std/algebra/emulated/sw_emulated/doc_test.go @@ -1,4 +1,4 @@ -package weierstrass_test +package sw_emulated_test import ( "fmt" @@ -9,16 +9,16 @@ import ( "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/std/algebra/weierstrass" + "github.com/consensys/gnark/std/algebra/emulated/sw_emulated" "github.com/consensys/gnark/std/math/emulated" ) type ExampleCurveCircuit[Base, Scalar emulated.FieldParams] struct { - Res weierstrass.AffinePoint[Base] + Res sw_emulated.AffinePoint[Base] } func (c *ExampleCurveCircuit[B, S]) Define(api frontend.API) error { - curve, err := weierstrass.New[B, S](api, weierstrass.GetCurveParams[emulated.BN254Fp]()) + curve, err := sw_emulated.New[B, S](api, sw_emulated.GetCurveParams[emulated.BN254Fp]()) if err != nil { panic("initalize new curve") } @@ -41,7 +41,7 @@ func ExampleCurve() { circuit := ExampleCurveCircuit[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{} witness := ExampleCurveCircuit[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ - Res: weierstrass.AffinePoint[emulated.Secp256k1Fp]{ + Res: sw_emulated.AffinePoint[emulated.Secp256k1Fp]{ X: emulated.ValueOf[emulated.Secp256k1Fp](g.X), Y: emulated.ValueOf[emulated.Secp256k1Fp](g.Y), }, diff --git a/std/algebra/weierstrass/params.go b/std/algebra/emulated/sw_emulated/params.go similarity index 99% rename from std/algebra/weierstrass/params.go rename to std/algebra/emulated/sw_emulated/params.go index 32cd8812e8..b9f00ec707 100644 --- a/std/algebra/weierstrass/params.go +++ b/std/algebra/emulated/sw_emulated/params.go @@ -1,4 +1,4 @@ -package weierstrass +package sw_emulated import ( "math/big" diff --git a/std/algebra/weierstrass/params_compute.go b/std/algebra/emulated/sw_emulated/params_compute.go similarity index 98% rename from std/algebra/weierstrass/params_compute.go rename to std/algebra/emulated/sw_emulated/params_compute.go index 0edf3f78b4..fbdabea300 100644 --- a/std/algebra/weierstrass/params_compute.go +++ b/std/algebra/emulated/sw_emulated/params_compute.go @@ -1,4 +1,4 @@ -package weierstrass +package sw_emulated import ( "math/big" diff --git a/std/algebra/weierstrass/point.go b/std/algebra/emulated/sw_emulated/point.go similarity index 99% rename from std/algebra/weierstrass/point.go rename to std/algebra/emulated/sw_emulated/point.go index c40f45a0cd..414b011de2 100644 --- a/std/algebra/weierstrass/point.go +++ b/std/algebra/emulated/sw_emulated/point.go @@ -1,4 +1,4 @@ -package weierstrass +package sw_emulated import ( "fmt" diff --git a/std/algebra/weierstrass/point_test.go b/std/algebra/emulated/sw_emulated/point_test.go similarity index 99% rename from std/algebra/weierstrass/point_test.go rename to std/algebra/emulated/sw_emulated/point_test.go index 86a9295e7c..6703970c1a 100644 --- a/std/algebra/weierstrass/point_test.go +++ b/std/algebra/emulated/sw_emulated/point_test.go @@ -1,4 +1,4 @@ -package weierstrass +package sw_emulated import ( "math/big" diff --git a/std/algebra/native/fields_bls12377/doc.go b/std/algebra/native/fields_bls12377/doc.go new file mode 100644 index 0000000000..69308f8280 --- /dev/null +++ b/std/algebra/native/fields_bls12377/doc.go @@ -0,0 +1,9 @@ +// Package fields_bls12377 implements the fields arithmetic of the Fp12 tower +// used to compute the pairing over the BLS12-377 curve. +// +// 𝔽p²[u] = 𝔽p/u²+5 +// 𝔽p⁶[v] = 𝔽p²/v³-u +// 𝔽p¹²[w] = 𝔽p⁶/w²-v +// +// Reference: https://eprint.iacr.org/2022/1162 +package fields_bls12377 diff --git a/std/algebra/fields_bls12377/e12.go b/std/algebra/native/fields_bls12377/e12.go similarity index 91% rename from std/algebra/fields_bls12377/e12.go rename to std/algebra/native/fields_bls12377/e12.go index 9ae3ff02c7..f51413348b 100644 --- a/std/algebra/fields_bls12377/e12.go +++ b/std/algebra/native/fields_bls12377/e12.go @@ -345,51 +345,6 @@ func (e *E12) Conjugate(api frontend.API, e1 E12) *E12 { return e } -// MulBy034 multiplication by sparse element -func (e *E12) MulBy034(api frontend.API, c3, c4 E2) *E12 { - - var d E6 - - a := e.C0 - b := e.C1 - - b.MulBy01(api, c3, c4) - - c3.Add(api, E2{A0: 1, A1: 0}, c3) - d.Add(api, e.C0, e.C1) - d.MulBy01(api, c3, c4) - - e.C1.Add(api, a, b).Neg(api, e.C1).Add(api, e.C1, d) - e.C0.MulByNonResidue(api, b).Add(api, e.C0, a) - - return e -} - -// Mul034By034 multiplication of sparse element (1,0,0,c3,c4,0) by sparse element (1,0,0,d3,d4,0) -func (e *E12) Mul034By034(api frontend.API, d3, d4, c3, c4 E2) *E12 { - var one, tmp, x3, x4, x04, x03, x34 E2 - one.SetOne() - x3.Mul(api, c3, d3) - x4.Mul(api, c4, d4) - x04.Add(api, c4, d4) - x03.Add(api, c3, d3) - tmp.Add(api, c3, c4) - x34.Add(api, d3, d4). - Mul(api, x34, tmp). - Sub(api, x34, x3). - Sub(api, x34, x4) - - e.C0.B0.MulByNonResidue(api, x4). - Add(api, e.C0.B0, one) - e.C0.B1 = x3 - e.C0.B2 = x34 - e.C1.B0 = x03 - e.C1.B1 = x04 - e.C1.B2.SetZero() - - return e -} - // Frobenius applies frob to an fp12 elmt func (e *E12) Frobenius(api frontend.API, e1 E12) *E12 { @@ -588,35 +543,6 @@ func (e *E12) nSquareCompressed(api frontend.API, n int) { } } -// Expt compute e1**exponent, where the exponent is hardcoded -// This function is only used for the final expo of the pairing for bls12377, so the exponent is supposed to be hardcoded -// and on 64 bits. -func (e *E12) Expt(api frontend.API, e1 E12, exponent uint64) *E12 { - - res := e1 - - res.nSquareCompressed(api, 5) - res.Decompress(api, res) - res.Mul(api, res, e1) - x33 := res - res.nSquareCompressed(api, 7) - res.Decompress(api, res) - res.Mul(api, res, x33) - res.nSquareCompressed(api, 4) - res.Decompress(api, res) - res.Mul(api, res, e1) - res.CyclotomicSquare(api, res) - res.Mul(api, res, e1) - res.nSquareCompressed(api, 46) - res.Decompress(api, res) - res.Mul(api, res, e1) - - *e = res - - return e - -} - // Assign a value to self (witness assignment) func (e *E12) Assign(a *bls12377.E12) { e.C0.Assign(&a.C0) diff --git a/std/algebra/native/fields_bls12377/e12_pairing.go b/std/algebra/native/fields_bls12377/e12_pairing.go new file mode 100644 index 0000000000..5021d12ed2 --- /dev/null +++ b/std/algebra/native/fields_bls12377/e12_pairing.go @@ -0,0 +1,77 @@ +package fields_bls12377 + +import "github.com/consensys/gnark/frontend" + +// MulBy034 multiplication by sparse element +func (e *E12) MulBy034(api frontend.API, c3, c4 E2) *E12 { + + var d E6 + + a := e.C0 + b := e.C1 + + b.MulBy01(api, c3, c4) + + c3.Add(api, E2{A0: 1, A1: 0}, c3) + d.Add(api, e.C0, e.C1) + d.MulBy01(api, c3, c4) + + e.C1.Add(api, a, b).Neg(api, e.C1).Add(api, e.C1, d) + e.C0.MulByNonResidue(api, b).Add(api, e.C0, a) + + return e +} + +// Mul034By034 multiplication of sparse element (1,0,0,c3,c4,0) by sparse element (1,0,0,d3,d4,0) +func (e *E12) Mul034By034(api frontend.API, d3, d4, c3, c4 E2) *E12 { + var one, tmp, x3, x4, x04, x03, x34 E2 + one.SetOne() + x3.Mul(api, c3, d3) + x4.Mul(api, c4, d4) + x04.Add(api, c4, d4) + x03.Add(api, c3, d3) + tmp.Add(api, c3, c4) + x34.Add(api, d3, d4). + Mul(api, x34, tmp). + Sub(api, x34, x3). + Sub(api, x34, x4) + + e.C0.B0.MulByNonResidue(api, x4). + Add(api, e.C0.B0, one) + e.C0.B1 = x3 + e.C0.B2 = x34 + e.C1.B0 = x03 + e.C1.B1 = x04 + e.C1.B2.SetZero() + + return e +} + +// Expt compute e1**exponent, where the exponent is hardcoded +// This function is only used for the final expo of the pairing for bls12377, so the exponent is supposed to be hardcoded +// and on 64 bits. +func (e *E12) Expt(api frontend.API, e1 E12, exponent uint64) *E12 { + + res := e1 + + res.nSquareCompressed(api, 5) + res.Decompress(api, res) + res.Mul(api, res, e1) + x33 := res + res.nSquareCompressed(api, 7) + res.Decompress(api, res) + res.Mul(api, res, x33) + res.nSquareCompressed(api, 4) + res.Decompress(api, res) + res.Mul(api, res, e1) + res.CyclotomicSquare(api, res) + res.Mul(api, res, e1) + res.nSquareCompressed(api, 46) + res.Decompress(api, res) + res.Mul(api, res, e1) + + *e = res + + return e + +} diff --git a/std/algebra/fields_bls12377/e12_test.go b/std/algebra/native/fields_bls12377/e12_test.go similarity index 100% rename from std/algebra/fields_bls12377/e12_test.go rename to std/algebra/native/fields_bls12377/e12_test.go diff --git a/std/algebra/fields_bls12377/e2.go b/std/algebra/native/fields_bls12377/e2.go similarity index 100% rename from std/algebra/fields_bls12377/e2.go rename to std/algebra/native/fields_bls12377/e2.go diff --git a/std/algebra/fields_bls12377/e2_test.go b/std/algebra/native/fields_bls12377/e2_test.go similarity index 100% rename from std/algebra/fields_bls12377/e2_test.go rename to std/algebra/native/fields_bls12377/e2_test.go diff --git a/std/algebra/fields_bls12377/e6.go b/std/algebra/native/fields_bls12377/e6.go similarity index 100% rename from std/algebra/fields_bls12377/e6.go rename to std/algebra/native/fields_bls12377/e6.go diff --git a/std/algebra/fields_bls12377/e6_test.go b/std/algebra/native/fields_bls12377/e6_test.go similarity index 100% rename from std/algebra/fields_bls12377/e6_test.go rename to std/algebra/native/fields_bls12377/e6_test.go diff --git a/std/algebra/native/fields_bls24315/doc.go b/std/algebra/native/fields_bls24315/doc.go new file mode 100644 index 0000000000..8b669480b7 --- /dev/null +++ b/std/algebra/native/fields_bls24315/doc.go @@ -0,0 +1,10 @@ +// Package fields_bls24315 implements the fields arithmetic of the Fp24 tower +// used to compute the pairing over the BLS24-315 curve. +// +// 𝔽p²[u] = 𝔽p/u²-13 +// 𝔽p⁴[v] = 𝔽p²/v²-u +// 𝔽p¹²[w] = 𝔽p⁴/w³-v +// 𝔽p²⁴[i] = 𝔽p¹²/i²-w +// +// Reference: https://eprint.iacr.org/2022/1162 +package fields_bls24315 diff --git a/std/algebra/fields_bls24315/e12.go b/std/algebra/native/fields_bls24315/e12.go similarity index 100% rename from std/algebra/fields_bls24315/e12.go rename to std/algebra/native/fields_bls24315/e12.go diff --git a/std/algebra/fields_bls24315/e12_test.go b/std/algebra/native/fields_bls24315/e12_test.go similarity index 100% rename from std/algebra/fields_bls24315/e12_test.go rename to std/algebra/native/fields_bls24315/e12_test.go diff --git a/std/algebra/fields_bls24315/e2.go b/std/algebra/native/fields_bls24315/e2.go similarity index 100% rename from std/algebra/fields_bls24315/e2.go rename to std/algebra/native/fields_bls24315/e2.go diff --git a/std/algebra/fields_bls24315/e24.go b/std/algebra/native/fields_bls24315/e24.go similarity index 92% rename from std/algebra/fields_bls24315/e24.go rename to std/algebra/native/fields_bls24315/e24.go index 7394f86374..ea21cf09c5 100644 --- a/std/algebra/fields_bls24315/e24.go +++ b/std/algebra/native/fields_bls24315/e24.go @@ -341,53 +341,6 @@ func (e *E24) Conjugate(api frontend.API, e1 E24) *E24 { return e } -// MulBy034 multiplication by sparse element -func (e *E24) MulBy034(api frontend.API, c3, c4 E4) *E24 { - - var d E12 - var one E4 - one.SetOne() - - a := e.D0 - b := e.D1 - - b.MulBy01(api, c3, c4) - - c3.Add(api, one, c3) - d.Add(api, e.D0, e.D1) - d.MulBy01(api, c3, c4) - - e.D1.Add(api, a, b).Neg(api, e.D1).Add(api, e.D1, d) - e.D0.MulByNonResidue(api, b).Add(api, e.D0, a) - - return e -} - -// Mul034By034 multiplication of sparse element (1,0,0,c3,c4,0) by sparse element (1,0,0,d3,d4,0) -func (e *E24) Mul034By034(api frontend.API, d3, d4, c3, c4 E4) *E24 { - var one, tmp, x3, x4, x04, x03, x34 E4 - one.SetOne() - x3.Mul(api, c3, d3) - x4.Mul(api, c4, d4) - x04.Add(api, c4, d4) - x03.Add(api, c3, d3) - tmp.Add(api, c3, c4) - x34.Add(api, d3, d4). - Mul(api, x34, tmp). - Sub(api, x34, x3). - Sub(api, x34, x4) - - e.D0.C0.MulByNonResidue(api, x4). - Add(api, e.D0.C0, one) - e.D0.C1 = x3 - e.D0.C2 = x34 - e.D1.C0 = x03 - e.D1.C1 = x04 - e.D1.C2.SetZero() - - return e -} - var InverseE24Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { var a, c bls24315.E24 @@ -595,31 +548,6 @@ func (e *E24) nSquare(api frontend.API, n int) { } } -// Expt compute e1**exponent, where the exponent is hardcoded -// This function is only used for the final expo of the pairing for bls24315, so the exponent is supposed to be hardcoded and on 32 bits. -func (e *E24) Expt(api frontend.API, x E24, exponent uint64) *E24 { - - xInv := E24{} - res := x - xInv.Conjugate(api, x) - - res.nSquare(api, 2) - res.Mul(api, res, xInv) - res.nSquareCompressed(api, 8) - res.Decompress(api, res) - res.Mul(api, res, xInv) - res.nSquare(api, 2) - res.Mul(api, res, x) - res.nSquareCompressed(api, 20) - res.Decompress(api, res) - res.Mul(api, res, xInv) - res.Conjugate(api, res) - - *e = res - - return e -} - // AssertIsEqual constraint self to be equal to other into the given constraint system func (e *E24) AssertIsEqual(api frontend.API, other E24) { e.D0.AssertIsEqual(api, other.D0) diff --git a/std/algebra/native/fields_bls24315/e24_pairing.go b/std/algebra/native/fields_bls24315/e24_pairing.go new file mode 100644 index 0000000000..b087eb8138 --- /dev/null +++ b/std/algebra/native/fields_bls24315/e24_pairing.go @@ -0,0 +1,75 @@ +package fields_bls24315 + +import "github.com/consensys/gnark/frontend" + +// MulBy034 multiplication by sparse element +func (e *E24) MulBy034(api frontend.API, c3, c4 E4) *E24 { + + var d E12 + var one E4 + one.SetOne() + + a := e.D0 + b := e.D1 + + b.MulBy01(api, c3, c4) + + c3.Add(api, one, c3) + d.Add(api, e.D0, e.D1) + d.MulBy01(api, c3, c4) + + e.D1.Add(api, a, b).Neg(api, e.D1).Add(api, e.D1, d) + e.D0.MulByNonResidue(api, b).Add(api, e.D0, a) + + return e +} + +// Mul034By034 multiplication of sparse element (1,0,0,c3,c4,0) by sparse element (1,0,0,d3,d4,0) +func (e *E24) Mul034By034(api frontend.API, d3, d4, c3, c4 E4) *E24 { + var one, tmp, x3, x4, x04, x03, x34 E4 + one.SetOne() + x3.Mul(api, c3, d3) + x4.Mul(api, c4, d4) + x04.Add(api, c4, d4) + x03.Add(api, c3, d3) + tmp.Add(api, c3, c4) + x34.Add(api, d3, d4). + Mul(api, x34, tmp). + Sub(api, x34, x3). + Sub(api, x34, x4) + + e.D0.C0.MulByNonResidue(api, x4). + Add(api, e.D0.C0, one) + e.D0.C1 = x3 + e.D0.C2 = x34 + e.D1.C0 = x03 + e.D1.C1 = x04 + e.D1.C2.SetZero() + + return e +} + +// Expt compute e1**exponent, where the exponent is hardcoded +// This function is only used for the final expo of the pairing for bls24315, so the exponent is supposed to be hardcoded and on 32 bits. +func (e *E24) Expt(api frontend.API, x E24, exponent uint64) *E24 { + + xInv := E24{} + res := x + xInv.Conjugate(api, x) + + res.nSquare(api, 2) + res.Mul(api, res, xInv) + res.nSquareCompressed(api, 8) + res.Decompress(api, res) + res.Mul(api, res, xInv) + res.nSquare(api, 2) + res.Mul(api, res, x) + res.nSquareCompressed(api, 20) + res.Decompress(api, res) + res.Mul(api, res, xInv) + res.Conjugate(api, res) + + *e = res + + return e +} diff --git a/std/algebra/fields_bls24315/e24_test.go b/std/algebra/native/fields_bls24315/e24_test.go similarity index 100% rename from std/algebra/fields_bls24315/e24_test.go rename to std/algebra/native/fields_bls24315/e24_test.go diff --git a/std/algebra/fields_bls24315/e2_test.go b/std/algebra/native/fields_bls24315/e2_test.go similarity index 100% rename from std/algebra/fields_bls24315/e2_test.go rename to std/algebra/native/fields_bls24315/e2_test.go diff --git a/std/algebra/fields_bls24315/e4.go b/std/algebra/native/fields_bls24315/e4.go similarity index 100% rename from std/algebra/fields_bls24315/e4.go rename to std/algebra/native/fields_bls24315/e4.go diff --git a/std/algebra/fields_bls24315/e4_test.go b/std/algebra/native/fields_bls24315/e4_test.go similarity index 100% rename from std/algebra/fields_bls24315/e4_test.go rename to std/algebra/native/fields_bls24315/e4_test.go diff --git a/std/algebra/native/sw_bls12377/doc.go b/std/algebra/native/sw_bls12377/doc.go new file mode 100644 index 0000000000..3888dba835 --- /dev/null +++ b/std/algebra/native/sw_bls12377/doc.go @@ -0,0 +1,8 @@ +// Package sw_bls12377 implements the arithmetics of G1, G2 and the pairing +// computation on BLS12-377 as a SNARK circuit over BW6-761. These two curves +// form a 2-chain so the operations use native field arithmetic. +// +// References: +// BW6-761: https://eprint.iacr.org/2020/351 +// Pairings in R1CS: https://eprint.iacr.org/2022/1162 +package sw_bls12377 diff --git a/std/algebra/sw_bls12377/g1.go b/std/algebra/native/sw_bls12377/g1.go similarity index 100% rename from std/algebra/sw_bls12377/g1.go rename to std/algebra/native/sw_bls12377/g1.go diff --git a/std/algebra/sw_bls12377/g1_test.go b/std/algebra/native/sw_bls12377/g1_test.go similarity index 100% rename from std/algebra/sw_bls12377/g1_test.go rename to std/algebra/native/sw_bls12377/g1_test.go diff --git a/std/algebra/sw_bls12377/g2.go b/std/algebra/native/sw_bls12377/g2.go similarity index 99% rename from std/algebra/sw_bls12377/g2.go rename to std/algebra/native/sw_bls12377/g2.go index 3674196b98..7d0152f753 100644 --- a/std/algebra/sw_bls12377/g2.go +++ b/std/algebra/native/sw_bls12377/g2.go @@ -24,7 +24,7 @@ import ( "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/fields_bls12377" + "github.com/consensys/gnark/std/algebra/native/fields_bls12377" ) // G2Jac point in Jacobian coords diff --git a/std/algebra/sw_bls12377/g2_test.go b/std/algebra/native/sw_bls12377/g2_test.go similarity index 100% rename from std/algebra/sw_bls12377/g2_test.go rename to std/algebra/native/sw_bls12377/g2_test.go diff --git a/std/algebra/sw_bls12377/inner.go b/std/algebra/native/sw_bls12377/inner.go similarity index 100% rename from std/algebra/sw_bls12377/inner.go rename to std/algebra/native/sw_bls12377/inner.go diff --git a/std/algebra/sw_bls12377/inner_compute.go b/std/algebra/native/sw_bls12377/inner_compute.go similarity index 100% rename from std/algebra/sw_bls12377/inner_compute.go rename to std/algebra/native/sw_bls12377/inner_compute.go diff --git a/std/algebra/sw_bls12377/pairing.go b/std/algebra/native/sw_bls12377/pairing.go similarity index 98% rename from std/algebra/sw_bls12377/pairing.go rename to std/algebra/native/sw_bls12377/pairing.go index 7ca86131e7..c0e4bfef68 100644 --- a/std/algebra/sw_bls12377/pairing.go +++ b/std/algebra/native/sw_bls12377/pairing.go @@ -21,7 +21,7 @@ import ( "math/big" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/fields_bls12377" + "github.com/consensys/gnark/std/algebra/native/fields_bls12377" ) // GT target group of the pairing diff --git a/std/algebra/sw_bls12377/pairing_test.go b/std/algebra/native/sw_bls12377/pairing_test.go similarity index 98% rename from std/algebra/sw_bls12377/pairing_test.go rename to std/algebra/native/sw_bls12377/pairing_test.go index bf09b6efad..dbe5639919 100644 --- a/std/algebra/sw_bls12377/pairing_test.go +++ b/std/algebra/native/sw_bls12377/pairing_test.go @@ -25,7 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/std/algebra/fields_bls12377" + "github.com/consensys/gnark/std/algebra/native/fields_bls12377" "github.com/consensys/gnark/test" ) diff --git a/std/algebra/native/sw_bls24315/doc.go b/std/algebra/native/sw_bls24315/doc.go new file mode 100644 index 0000000000..9a13dd4769 --- /dev/null +++ b/std/algebra/native/sw_bls24315/doc.go @@ -0,0 +1,8 @@ +// Package sw_bls24315 implements the arithmetics of G1, G2 and the pairing +// computation on BLS24-315 as a SNARK circuit over BW6-633. These two curves +// form a 2-chain so the operations use native field arithmetic. +// +// References: +// BLS24-315/BW6-633: https://eprint.iacr.org/2021/1359 +// Pairings in R1CS: https://eprint.iacr.org/2022/1162 +package sw_bls24315 diff --git a/std/algebra/sw_bls24315/g1.go b/std/algebra/native/sw_bls24315/g1.go similarity index 100% rename from std/algebra/sw_bls24315/g1.go rename to std/algebra/native/sw_bls24315/g1.go diff --git a/std/algebra/sw_bls24315/g1_test.go b/std/algebra/native/sw_bls24315/g1_test.go similarity index 100% rename from std/algebra/sw_bls24315/g1_test.go rename to std/algebra/native/sw_bls24315/g1_test.go diff --git a/std/algebra/sw_bls24315/g2.go b/std/algebra/native/sw_bls24315/g2.go similarity index 99% rename from std/algebra/sw_bls24315/g2.go rename to std/algebra/native/sw_bls24315/g2.go index 06be5d9fe4..7997060144 100644 --- a/std/algebra/sw_bls24315/g2.go +++ b/std/algebra/native/sw_bls24315/g2.go @@ -23,7 +23,7 @@ import ( bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/fields_bls24315" + "github.com/consensys/gnark/std/algebra/native/fields_bls24315" ) // G2Jac point in Jacobian coords diff --git a/std/algebra/sw_bls24315/g2_test.go b/std/algebra/native/sw_bls24315/g2_test.go similarity index 100% rename from std/algebra/sw_bls24315/g2_test.go rename to std/algebra/native/sw_bls24315/g2_test.go diff --git a/std/algebra/sw_bls24315/inner.go b/std/algebra/native/sw_bls24315/inner.go similarity index 100% rename from std/algebra/sw_bls24315/inner.go rename to std/algebra/native/sw_bls24315/inner.go diff --git a/std/algebra/sw_bls24315/inner_compute.go b/std/algebra/native/sw_bls24315/inner_compute.go similarity index 100% rename from std/algebra/sw_bls24315/inner_compute.go rename to std/algebra/native/sw_bls24315/inner_compute.go diff --git a/std/algebra/sw_bls24315/pairing.go b/std/algebra/native/sw_bls24315/pairing.go similarity index 98% rename from std/algebra/sw_bls24315/pairing.go rename to std/algebra/native/sw_bls24315/pairing.go index b1e1fb11e0..57b4b8e928 100644 --- a/std/algebra/sw_bls24315/pairing.go +++ b/std/algebra/native/sw_bls24315/pairing.go @@ -22,7 +22,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/fields_bls24315" + "github.com/consensys/gnark/std/algebra/native/fields_bls24315" ) // GT target group of the pairing diff --git a/std/algebra/sw_bls24315/pairing_test.go b/std/algebra/native/sw_bls24315/pairing_test.go similarity index 98% rename from std/algebra/sw_bls24315/pairing_test.go rename to std/algebra/native/sw_bls24315/pairing_test.go index c7bb53b4a5..44233d888d 100644 --- a/std/algebra/sw_bls24315/pairing_test.go +++ b/std/algebra/native/sw_bls24315/pairing_test.go @@ -25,7 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/std/algebra/fields_bls24315" + "github.com/consensys/gnark/std/algebra/native/fields_bls24315" "github.com/consensys/gnark/test" ) diff --git a/std/algebra/twistededwards/curve.go b/std/algebra/native/twistededwards/curve.go similarity index 100% rename from std/algebra/twistededwards/curve.go rename to std/algebra/native/twistededwards/curve.go diff --git a/std/algebra/twistededwards/curve_test.go b/std/algebra/native/twistededwards/curve_test.go similarity index 100% rename from std/algebra/twistededwards/curve_test.go rename to std/algebra/native/twistededwards/curve_test.go diff --git a/std/algebra/native/twistededwards/doc.go b/std/algebra/native/twistededwards/doc.go new file mode 100644 index 0000000000..95b1486681 --- /dev/null +++ b/std/algebra/native/twistededwards/doc.go @@ -0,0 +1,8 @@ +// Package twistededwards implements the arithmetic of twisted Edwards curves +// in native fields. This uses associated twisted Edwards curves defined over +// the scalar field of the SNARK curves. +// +// Examples: +// Jubjub, Bandersnatch (a twisted Edwards) is defined over BLS12-381's scalar field +// Baby-Jubjub (a twisted Edwards) is defined over BN254's salar fields +package twistededwards diff --git a/std/algebra/twistededwards/point.go b/std/algebra/native/twistededwards/point.go similarity index 100% rename from std/algebra/twistededwards/point.go rename to std/algebra/native/twistededwards/point.go diff --git a/std/algebra/twistededwards/scalarmul_glv.go b/std/algebra/native/twistededwards/scalarmul_glv.go similarity index 100% rename from std/algebra/twistededwards/scalarmul_glv.go rename to std/algebra/native/twistededwards/scalarmul_glv.go diff --git a/std/algebra/twistededwards/twistededwards.go b/std/algebra/native/twistededwards/twistededwards.go similarity index 100% rename from std/algebra/twistededwards/twistededwards.go rename to std/algebra/native/twistededwards/twistededwards.go diff --git a/std/algebra/pairing_bn254/gt.go b/std/algebra/pairing_bn254/gt.go deleted file mode 100644 index 2b84c9f0ed..0000000000 --- a/std/algebra/pairing_bn254/gt.go +++ /dev/null @@ -1,41 +0,0 @@ -package pairing_bn254 - -import ( - "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark/std/math/emulated" -) - -type GTEl = e12 - -func NewGTEl(v bn254.GT) GTEl { - return GTEl{ - C0: e6{ - B0: e2{ - A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B0.A0), - A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B0.A1), - }, - B1: e2{ - A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B1.A0), - A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B1.A1), - }, - B2: e2{ - A0: emulated.ValueOf[emulated.BN254Fp](v.C0.B2.A0), - A1: emulated.ValueOf[emulated.BN254Fp](v.C0.B2.A1), - }, - }, - C1: e6{ - B0: e2{ - A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B0.A0), - A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B0.A1), - }, - B1: e2{ - A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B1.A0), - A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B1.A1), - }, - B2: e2{ - A0: emulated.ValueOf[emulated.BN254Fp](v.C1.B2.A0), - A1: emulated.ValueOf[emulated.BN254Fp](v.C1.B2.A1), - }, - }, - } -} diff --git a/std/algebra/pairing_bn254/pairing.go b/std/algebra/pairing_bn254/pairing.go deleted file mode 100644 index ec0baa633b..0000000000 --- a/std/algebra/pairing_bn254/pairing.go +++ /dev/null @@ -1,282 +0,0 @@ -package pairing_bn254 - -import ( - "fmt" - - "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/math/emulated" -) - -type Pairing struct { - *ext12 -} - -func NewPairing(api frontend.API) (*Pairing, error) { - ba, err := emulated.NewField[emulated.BN254Fp](api) - if err != nil { - return nil, fmt.Errorf("new base api: %w", err) - } - return &Pairing{ - ext12: newExt12(ba), - }, nil -} - -func (pr Pairing) doubleStep(p *g2Projective) (*g2Projective, *lineEvaluation) { - // var t1, A, B, C, D, E, EE, F, G, H, I, J, K fptower.E2 - A := pr.ext2.mul(&p.X, &p.Y) // A.Mul(&p.x, &p.y) - A = pr.ext2.halve(A) // A.Halve() - B := pr.ext2.square(&p.Y) // B.Square(&p.y) - C := pr.ext2.square(&p.Z) // C.Square(&p.z) - D := pr.ext2.double(C) // D.Double(&C). - D = pr.ext2.add(D, C) // Add(&D, &C) - E := pr.ext2.mulBybTwistCurveCoeff(D) // E.MulBybTwistCurveCoeff(&D) - F := pr.ext2.double(E) // F.Double(&E). - F = pr.ext2.add(F, E) // Add(&F, &E) - G := pr.ext2.add(B, F) // G.Add(&B, &F) - G = pr.ext2.halve(G) // G.Halve() - H := pr.ext2.add(&p.Y, &p.Z) // H.Add(&p.y, &p.z). - H = pr.ext2.square(H) // Square(&H) - t1 := pr.ext2.add(B, C) // t1.Add(&B, &C) - H = pr.ext2.sub(H, t1) // H.Sub(&H, &t1) - I := pr.ext2.sub(E, B) // I.Sub(&E, &B) - J := pr.ext2.square(&p.X) // J.Square(&p.x) - EE := pr.ext2.square(E) // EE.Square(&E) - K := pr.ext2.double(EE) // K.Double(&EE). - K = pr.ext2.add(K, EE) // Add(&K, &EE) - px := pr.ext2.sub(B, F) // p.x.Sub(&B, &F). - px = pr.ext2.mul(px, A) // Mul(&p.x, &A) - py := pr.ext2.square(G) // p.y.Square(&G). - py = pr.ext2.sub(py, K) // Sub(&p.y, &K) - pz := pr.ext2.mul(B, H) // p.z.Mul(&B, &H) - ev0 := pr.ext2.neg(H) // evaluations.r0.Neg(&H) - ev1 := pr.ext2.double(J) // evaluations.r1.Double(&J). - ev1 = pr.ext2.add(ev1, J) // Add(&evaluations.r1, &J) - ev2 := I // evaluations.r2.Set(&I) - return &g2Projective{ - X: *px, - Y: *py, - Z: *pz, - }, - &lineEvaluation{ - r0: *ev0, - r1: *ev1, - r2: *ev2, - } -} - -func (pr Pairing) affineToProjective(Q *G2Affine) *g2Projective { - // TODO: check point at infinity? We do not filter them in the Miller Loop neither. - // if Q.X.IsZero() && Q.Y.IsZero() { - // p.z.SetZero() - // p.x.SetOne() - // p.y.SetOne() - // return p - // } - pz := pr.ext2.one() // p.z.SetOne() - px := &Q.X // p.x.Set(&Q.X) - py := &Q.Y // p.y.Set(&Q.Y) - return &g2Projective{ // return p - X: *px, - Y: *py, - Z: *pz, - } -} - -func (pr Pairing) negAffine(a *G2Affine) *G2Affine { - px := &a.X // p.X = a.X - py := pr.ext2.neg(&a.Y) // p.Y.Neg(&a.Y) - return &G2Affine{ // return p - X: *px, - Y: *py, - } -} - -func (pr Pairing) addStep(p *g2Projective, a *G2Affine) (*g2Projective, *lineEvaluation) { - // var Y2Z1, X2Z1, O, L, C, D, E, F, G, H, t0, t1, t2, J fptower.E2 - Y2Z1 := pr.ext2.mul(&a.Y, &p.Z) // Y2Z1.Mul(&a.Y, &p.z) - O := pr.ext2.sub(&p.Y, Y2Z1) // O.Sub(&p.y, &Y2Z1) - X2Z1 := pr.ext2.mul(&a.X, &p.Z) // X2Z1.Mul(&a.X, &p.z) - L := pr.ext2.sub(&p.X, X2Z1) // L.Sub(&p.x, &X2Z1) - C := pr.ext2.square(O) // C.Square(&O) - D := pr.ext2.square(L) // D.Square(&L) - E := pr.ext2.mul(L, D) // E.Mul(&L, &D) - F := pr.ext2.mul(&p.Z, C) // F.Mul(&p.z, &C) - G := pr.ext2.mul(&p.X, D) // G.Mul(&p.x, &D) - t0 := pr.ext2.double(G) // t0.Double(&G) - H := pr.ext2.add(E, F) // H.Add(&E, &F). - H = pr.ext2.sub(H, t0) // Sub(&H, &t0) - t1 := pr.ext2.mul(&p.Y, E) // t1.Mul(&p.y, &E) - px := pr.ext2.mul(L, H) // p.x.Mul(&L, &H) - py := pr.ext2.sub(G, H) // p.y.Sub(&G, &H). - py = pr.ext2.mul(py, O) // Mul(&p.y, &O). - py = pr.ext2.sub(py, t1) // Sub(&p.y, &t1) - pz := pr.ext2.mul(E, &p.Z) // p.z.Mul(&E, &p.z) - t2 := pr.ext2.mul(L, &a.Y) // t2.Mul(&L, &a.Y) - J := pr.ext2.mul(&a.X, O) // J.Mul(&a.X, &O). - J = pr.ext2.sub(J, t2) // Sub(&J, &t2) - ev0 := L // evaluations.r0.Set(&L) - ev1 := pr.ext2.neg(O) // evaluations.r1.Neg(&O) - ev2 := J // evaluations.r2.Set(&J) - return &g2Projective{ - X: *px, - Y: *py, - Z: *pz, - }, &lineEvaluation{ - r0: *ev0, - r1: *ev1, - r2: *ev2, - } -} - -type lineEvaluation struct { - r0 e2 - r1 e2 - r2 e2 -} - -var loopCounter = [66]int8{ - 0, 0, 0, 1, 0, 1, 0, -1, 0, 0, -1, - 0, 0, 0, 1, 0, 0, -1, 0, -1, 0, 0, - 0, 1, 0, -1, 0, 0, 0, 0, -1, 0, 0, - 1, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, - -1, 0, 0, -1, 0, 1, 0, -1, 0, 0, 0, - -1, 0, -1, 0, 0, 0, 1, 0, -1, 0, 1, -} - -func (pr Pairing) MillerLoop(p []*G1Affine, q []*G2Affine) (*GTEl, error) { - n := len(p) - if n == 0 || n != len(q) { - return nil, fmt.Errorf("invalid inputs sizes") - } - - // TODO: we have omitted filtering for infinity points. - - // projective points for Q - qProj := make([]*g2Projective, n) // qProj := make([]g2Proj, n) - qNeg := make([]*G2Affine, n) // qNeg := make([]G2Affine, n) - for k := 0; k < n; k++ { - qProj[k] = pr.affineToProjective(q[k]) // qProj[k].FromAffine(&q[k]) - qNeg[k] = pr.negAffine(q[k]) // qNeg[k].Neg(&q[k]) - } - - var l, l0 *lineEvaluation - result := pr.ext12.one() // var tmp, result GTEl - - // i == len(loopCounter) - 2 - for k := 0; k < n; k++ { - qProj[k], l = pr.doubleStep(qProj[k]) // qProj[k].DoubleStep(&l) - l.r0 = *pr.ext12.ext2.mulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1 = *pr.ext12.ext2.mulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) - result = pr.ext12.mulBy034(result, &l.r0, &l.r1, &l.r2) // result.MulBy034(&l.r0, &l.r1, &l.r2) - } - - for i := len(loopCounter) - 3; i >= 0; i-- { - result = pr.ext12.square(result) // result.Square(&result) - - for k := 0; k < n; k++ { - qProj[k], l = pr.doubleStep(qProj[k]) // qProj[k].DoubleStep(&l) - l.r0 = *pr.ext12.ext2.mulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1 = *pr.ext12.ext2.mulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) - - if loopCounter[i] == 1 { - qProj[k], l0 = pr.addStep(qProj[k], q[k]) // qProj[k].AddMixedStep(&l0, &q[k]) - l0.r0 = *pr.ext12.ext2.mulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) - l0.r1 = *pr.ext12.ext2.mulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) - tmp := pr.ext12.mulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result = pr.ext12.mul(result, tmp) // result.Mul(&result, &tmp) - } else if loopCounter[i] == -1 { - qProj[k], l0 = pr.addStep(qProj[k], qNeg[k]) // qProj[k].AddMixedStep(&l0, &qNeg[k]) - l0.r0 = *pr.ext12.ext2.mulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) - l0.r1 = *pr.ext12.ext2.mulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) - tmp := pr.ext12.mulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result = pr.ext12.mul(result, tmp) //result.Mul(&result, &tmp) - } else { - result = pr.ext12.mulBy034(result, &l.r0, &l.r1, &l.r2) // result.MulBy034(&l.r0, &l.r1, &l.r2) - } - } - } - - Q1, Q2 := new(G2Affine), new(G2Affine) // var Q1, Q2 G2Affine - for k := 0; k < n; k++ { - //Q1 = π(Q) - // TODO(ivokub): define phi(Q) in G2 instead of doing manually? - Q1.X = *pr.ext12.ext2.conjugate(&q[k].X) // Q1.X.Conjugate(&q[k].X).MulByNonResidue1Power2(&Q1.X) - Q1.X = *pr.ext12.ext2.mulByNonResidue1Power2(&Q1.X) // Q1.X.Conjugate(&q[k].X).MulByNonResidue1Power2(&Q1.X) - Q1.Y = *pr.ext12.ext2.conjugate(&q[k].Y) // Q1.Y.Conjugate(&q[k].Y).MulByNonResidue1Power3(&Q1.Y) - Q1.Y = *pr.ext12.ext2.mulByNonResidue1Power3(&Q1.Y) // Q1.Y.Conjugate(&q[k].Y).MulByNonResidue1Power3(&Q1.Y) - - // Q2 = -π²(Q) - Q2.X = *pr.ext12.ext2.mulByNonResidue2Power2(&q[k].X) // Q2.X.MulByNonResidue2Power2(&q[k].X) - Q2.Y = *pr.ext12.ext2.mulByNonResidue2Power3(&q[k].Y) // Q2.Y.MulByNonResidue2Power3(&q[k].Y).Neg(&Q2.Y) - Q2.Y = *pr.ext12.ext2.neg(&Q2.Y) // Q2.Y.MulByNonResidue2Power3(&q[k].Y).Neg(&Q2.Y) - - qProj[k], l0 = pr.addStep(qProj[k], Q1) // qProj[k].AddMixedStep(&l0, &Q1) - l0.r0 = *pr.ext12.ext2.mulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) - l0.r1 = *pr.ext12.ext2.mulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) - - qProj[k], l = pr.addStep(qProj[k], Q2) // qProj[k].AddMixedStep(&l, &Q2) - l.r0 = *pr.ext12.ext2.mulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1 = *pr.ext12.ext2.mulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) - tmp := pr.ext12.mulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result = pr.ext12.mul(result, tmp) // result.Mul(&result, &tmp) - } - - return result, nil -} - -func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { - // var result GT - // result.Set(z) - var t [4]*GTEl // var t [4]GT - - // easy part - t[0] = pr.ext12.conjugate(e) // t[0].Conjugate(&result) - result := pr.ext12.inverse(e) // result.Inverse(&result) - t[0] = pr.ext12.mul(t[0], result) // t[0].Mul(&t[0], &result) - result = pr.ext12.frobeniusSquare(t[0]) // result.FrobeniusSquare(&t[0]). - result = pr.ext12.mul(result, t[0]) // Mul(&result, &t[0]) - - //hard part - t[0] = pr.ext12.expt(result) // t[0].Expt(&result). - t[0] = pr.ext12.conjugate(t[0]) // Conjugate(&t[0]) - t[0] = pr.ext12.cyclotomicSquare(t[0]) // t[0].CyclotomicSquare(&t[0]) - t[2] = pr.ext12.expt(t[0]) // t[2].Expt(&t[0]). - t[2] = pr.ext12.conjugate(t[2]) // Conjugate(&t[2]) - t[1] = pr.ext12.cyclotomicSquare(t[2]) // t[1].CyclotomicSquare(&t[2]) - t[2] = pr.ext12.mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) - t[2] = pr.ext12.mul(t[2], result) // t[2].Mul(&t[2], &result) - t[1] = pr.ext12.expt(t[2]) // t[1].Expt(&t[2]). - t[1] = pr.ext12.cyclotomicSquare(t[1]) // CyclotomicSquare(&t[1]). - t[1] = pr.ext12.mul(t[1], t[2]) // Mul(&t[1], &t[2]). - t[1] = pr.ext12.conjugate(t[1]) // Conjugate(&t[1]) - t[3] = pr.ext12.conjugate(t[1]) // t[3].Conjugate(&t[1]) - t[1] = pr.ext12.cyclotomicSquare(t[0]) // t[1].CyclotomicSquare(&t[0]) - t[1] = pr.ext12.mul(t[1], result) // t[1].Mul(&t[1], &result) - t[1] = pr.ext12.conjugate(t[1]) // t[1].Conjugate(&t[1]) - t[1] = pr.ext12.mul(t[1], t[3]) // t[1].Mul(&t[1], &t[3]) - t[0] = pr.ext12.mul(t[0], t[1]) // t[0].Mul(&t[0], &t[1]) - t[2] = pr.ext12.mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) - t[3] = pr.ext12.frobeniusSquare(t[1]) // t[3].FrobeniusSquare(&t[1]) - t[2] = pr.ext12.mul(t[2], t[3]) // t[2].Mul(&t[2], &t[3]) - t[3] = pr.ext12.conjugate(result) // t[3].Conjugate(&result) - t[3] = pr.ext12.mul(t[3], t[0]) // t[3].Mul(&t[3], &t[0]) - t[1] = pr.ext12.frobeniusCube(t[3]) // t[1].FrobeniusCube(&t[3]) - t[2] = pr.ext12.mul(t[2], t[1]) // t[2].Mul(&t[2], &t[1]) - t[1] = pr.ext12.frobenius(t[0]) // t[1].Frobenius(&t[0]) - t[1] = pr.ext12.mul(t[1], t[2]) // t[1].Mul(&t[1], &t[2]) - // result.Set(&t[1]) - return t[1] // return result -} - -func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { - res, err := pr.MillerLoop(P, Q) - if err != nil { - return nil, fmt.Errorf("miller loop: %w", err) - } - res = pr.FinalExponentiation(res) - return res, nil -} - -func (pr Pairing) AssertIsEqual(x, y *GTEl) { - pr.ext12.assertIsEqual(x, y) -} diff --git a/std/algebra/pairing_bn254/tower.go b/std/algebra/pairing_bn254/tower.go deleted file mode 100644 index c555680885..0000000000 --- a/std/algebra/pairing_bn254/tower.go +++ /dev/null @@ -1,833 +0,0 @@ -package pairing_bn254 - -import ( - "math/big" - - "github.com/consensys/gnark/std/math/emulated" -) - -type curveF = emulated.Field[emulated.BN254Fp] -type baseEl = emulated.Element[emulated.BN254Fp] - -type e2 struct { - A0, A1 baseEl -} - -type e6 struct { - B0, B1, B2 e2 -} - -type e12 struct { - C0, C1 e6 -} - -type ext2 struct { - fp *curveF - nonResidues map[int]map[int]*e2 -} - -func newExt2(baseField *curveF) *ext2 { - pwrs := map[int]map[int]struct { - A0 string - A1 string - }{ - 0: { - -1: {"21087453498479301738505683583845423561061080261299122796980902361914303298513", "14681138511599513868579906292550611339979233093309515871315818100066920017952"}, - 1: {"9", "1"}, - }, - 1: { - 1: {"8376118865763821496583973867626364092589906065868298776909617916018768340080", "16469823323077808223889137241176536799009286646108169935659301613961712198316"}, - 2: {"21575463638280843010398324269430826099269044274347216827212613867836435027261", "10307601595873709700152284273816112264069230130616436755625194854815875713954"}, - 3: {"2821565182194536844548159561693502659359617185244120367078079554186484126554", "3505843767911556378687030309984248845540243509899259641013678093033130930403"}, - 4: {"2581911344467009335267311115468803099551665605076196740867805258568234346338", "19937756971775647987995932169929341994314640652964949448313374472400716661030"}, - 5: {"685108087231508774477564247770172212460312782337200605669322048753928464687", "8447204650696766136447902020341177575205426561248465145919723016860428151883"}, - }, - 2: { - 1: {"21888242871839275220042445260109153167277707414472061641714758635765020556617", "0"}, - 2: {"21888242871839275220042445260109153167277707414472061641714758635765020556616", "0"}, - 3: {"21888242871839275222246405745257275088696311157297823662689037894645226208582", "0"}, - 4: {"2203960485148121921418603742825762020974279258880205651966", "0"}, - 5: {"2203960485148121921418603742825762020974279258880205651967", "0"}, - }, - 3: { - 1: {"11697423496358154304825782922584725312912383441159505038794027105778954184319", "303847389135065887422783454877609941456349188919719272345083954437860409601"}, - 2: {"3772000881919853776433695186713858239009073593817195771773381919316419345261", "2236595495967245188281701248203181795121068902605861227855261137820944008926"}, - 3: {"19066677689644738377698246183563772429336693972053703295610958340458742082029", "18382399103927718843559375435273026243156067647398564021675359801612095278180"}, - 4: {"5324479202449903542726783395506214481928257762400643279780343368557297135718", "16208900380737693084919495127334387981393726419856888799917914180988844123039"}, - 5: {"8941241848238582420466759817324047081148088512956452953208002715982955420483", "10338197737521362862238855242243140895517409139741313354160881284257516364953"}, - }, - } - nonResidues := make(map[int]map[int]*e2) - for pwr, v := range pwrs { - for coeff, v := range v { - el := e2{emulated.ValueOf[emulated.BN254Fp](v.A0), emulated.ValueOf[emulated.BN254Fp](v.A1)} - if nonResidues[pwr] == nil { - nonResidues[pwr] = make(map[int]*e2) - } - nonResidues[pwr][coeff] = &el - } - } - return &ext2{fp: baseField, nonResidues: nonResidues} -} - -type ext6 struct { - *ext2 -} - -func newExt6(baseField *curveF) *ext6 { - return &ext6{ext2: newExt2(baseField)} -} - -type ext12 struct { - *ext6 -} - -func newExt12(baseField *curveF) *ext12 { - return &ext12{ext6: newExt6(baseField)} -} - -// TODO: check where to use Mod and where ModMul. - -func (e ext2) mulByElement(x *e2, y *baseEl) *e2 { - // var yCopy fp.Element - // yCopy.Set(y) - z0 := e.fp.MulMod(&x.A0, y) // z.A0.Mul(&x.A0, &yCopy) - z1 := e.fp.MulMod(&x.A1, y) // z.A1.Mul(&x.A1, &yCopy) - return &e2{ // return z - A0: *z0, - A1: *z1, - } -} - -func (e ext2) conjugate(x *e2) *e2 { - z0 := x.A0 // z.A0 = x.A0 - z1 := e.fp.Neg(&x.A1) // z.A1.Neg(&x.A1) - return &e2{ // return z - A0: z0, - A1: *z1, - } -} - -func (e ext2) mulByNonResidueGeneric(x *e2, power, coef int) *e2 { - y := e.nonResidues[power][coef] - z := e.mul(x, y) - return z -} - -func (e ext2) mulByNonResidue(x *e2) *e2 { - /* - // below is the direct transliteration of the gnark-crypto code. Now only, - // for simplicity and debugging purposes, we do the non residue operations - // without optimisations. - - nine := big.NewInt(9) - // var a, b fp.Element - a := e.fp.MulConst(&x.A0, nine) // a.Double(&x.A0).Double(&a).Double(&a).Add(&a, &x.A0). - a = e.fp.Sub(a, &x.A1) // Sub(&a, &x.A1) - b := e.fp.MulConst(&x.A1, nine) // b.Double(&x.A1).Double(&b).Double(&b).Add(&b, &x.A1). - b = e.fp.Add(b, &x.A0) // Add(&b, &x.A0) - return &E2{ - A0: *a, // z.A0.Set(&a) - A1: *b, // z.A1.Set(&b) - } // return z - */ - // TODO: inline non-residue multiplication - return e.mulByNonResidueGeneric(x, 0, 1) -} - -func (e ext2) mulByNonResidueInv(x *e2) *e2 { - // TODO: to optimise with constant non-residue inverse - /* - // from gnark-crypto - // z.Mul(x, &nonResInverse) - // return z - */ - return e.mulByNonResidueGeneric(x, 0, -1) -} - -func (e ext2) mulByNonResidue1Power1(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 1, 1) -} - -func (e ext2) mulByNonResidue1Power2(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 1, 2) -} - -func (e ext2) mulByNonResidue1Power3(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 1, 3) -} - -func (e ext2) mulByNonResidue1Power4(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 1, 4) -} - -func (e ext2) mulByNonResidue1Power5(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 1, 5) -} - -func (e ext2) mulByNonResidue2Power1(x *e2) *e2 { - // TODO: A1 is 0, we can optimize for it - return e.mulByNonResidueGeneric(x, 2, 1) -} -func (e ext2) mulByNonResidue2Power2(x *e2) *e2 { - // TODO: A1 is 0, we can optimize for it - return e.mulByNonResidueGeneric(x, 2, 2) -} - -func (e ext2) mulByNonResidue2Power3(x *e2) *e2 { - // TODO: A1 is 0, we can optimize for it - return e.mulByNonResidueGeneric(x, 2, 3) -} - -func (e ext2) mulByNonResidue2Power4(x *e2) *e2 { - // TODO: A1 is 0, we can optimize for it - return e.mulByNonResidueGeneric(x, 2, 4) -} - -func (e ext2) mulByNonResidue2Power5(x *e2) *e2 { - // TODO: A1 is 0, we can optimize for it - return e.mulByNonResidueGeneric(x, 2, 5) -} - -func (e ext2) mulByNonResidue3Power1(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 3, 1) -} - -func (e ext2) mulByNonResidue3Power2(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 3, 2) -} - -func (e ext2) mulByNonResidue3Power3(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 3, 3) -} - -func (e ext2) mulByNonResidue3Power4(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 3, 4) -} - -func (e ext2) mulByNonResidue3Power5(x *e2) *e2 { - return e.mulByNonResidueGeneric(x, 3, 5) -} - -func (e ext2) mul(x, y *e2) *e2 { - // var a, b, c fp.Element - a := e.fp.Add(&x.A0, &x.A1) // a.Add(&x.A0, &x.A1) - b := e.fp.Add(&y.A0, &y.A1) // b.Add(&y.A0, &y.A1) - a = e.fp.MulMod(a, b) // a.Mul(&a, &b) - b = e.fp.MulMod(&x.A0, &y.A0) // b.Mul(&x.A0, &y.A0) - c := e.fp.MulMod(&x.A1, &y.A1) // c.Mul(&x.A1, &y.A1) - z1 := e.fp.Sub(a, b) // z.A1.Sub(&a, &b). - z1 = e.fp.Sub(z1, c) // Sub(&z.A1, &c) - z0 := e.fp.Sub(b, c) // z.A0.Sub(&b, &c) - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) add(x, y *e2) *e2 { - z0 := e.fp.Add(&x.A0, &y.A0) // z.A0.Add(&x.A0, &y.A0) - z1 := e.fp.Add(&x.A1, &y.A1) // z.A1.Add(&x.A1, &y.A1) - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) sub(x, y *e2) *e2 { - z0 := e.fp.Sub(&x.A0, &y.A0) // z.A0.Sub(&x.A0, &y.A0) - z1 := e.fp.Sub(&x.A1, &y.A1) // z.A1.Sub(&x.A1, &y.A1) - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) neg(x *e2) *e2 { - z0 := e.fp.Neg(&x.A0) // z.A0.Neg(&x.A0) - z1 := e.fp.Neg(&x.A1) // z.A1.Neg(&x.A1) - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) one() *e2 { - z0 := e.fp.One() // z.A0.SetOne() - z1 := e.fp.Zero() // z.A1.SetZero() - return &e2{ // return z - A0: *z0, - A1: *z1, - } -} - -func (e ext2) zero() *e2 { - z0 := e.fp.Zero() - z1 := e.fp.Zero() - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) square(x *e2) *e2 { - // var a, b fp.Element - a := e.fp.Add(&x.A0, &x.A1) // a.Add(&x.A0, &x.A1) - b := e.fp.Sub(&x.A0, &x.A1) // b.Sub(&x.A0, &x.A1) - a = e.fp.MulMod(a, b) // a.Mul(&a, &b) - b = e.fp.MulMod(&x.A0, &x.A1) // b.Mul(&x.A0, &x.A1). - b = e.fp.MulConst(b, big.NewInt(2)) // Double(&b) - return &e2{ - A0: *a, // z.A0.Set(&a) - A1: *b, // z.A1.Set(&b) - } -} - -func (e ext2) double(x *e2) *e2 { - two := big.NewInt(2) - z0 := e.fp.MulConst(&x.A0, two) // z.A0.Double(&x.A0) - z1 := e.fp.MulConst(&x.A1, two) // z.A1.Double(&x.A1) - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) halve(x *e2) *e2 { - // I'm trying to avoid hard-coding modulus here in case want to make generic - // for different curves. - // TODO: if implemented Half in field emulation, then replace with it. - one := e.fp.One() - two := e.fp.MulConst(one, big.NewInt(2)) - z0 := e.fp.Div(&x.A0, two) - z1 := e.fp.Div(&x.A1, two) - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) mulBybTwistCurveCoeff(x *e2) *e2 { - // var res E2 - res := e.mulByNonResidueInv(x) // res.MulByNonResidueInv(x) - z := e.double(res) // z.Double(&res). - z = e.add(z, res) // Add(&res, z) - return z // return z -} - -func (e ext2) inverse(x *e2) *e2 { - // var t0, t1 fp.Element - t0 := e.fp.MulMod(&x.A0, &x.A0) // t0.Square(&x.A0) - t1 := e.fp.MulMod(&x.A1, &x.A1) // t1.Square(&x.A1) - t0 = e.fp.Add(t0, t1) // t0.Add(&t0, &t1) - t1 = e.fp.Inverse(t0) // t1.Inverse(&t0) - z0 := e.fp.MulMod(&x.A0, t1) // z.A0.Mul(&x.A0, &t1) - z1 := e.fp.MulMod(&x.A1, t1) // z.A1.Mul(&x.A1, &t1). - z1 = e.fp.Neg(z1) // Neg(&z.A1) - return &e2{ - A0: *z0, - A1: *z1, - } -} - -func (e ext2) assertIsEqual(x, y *e2) { - e.fp.AssertIsEqual(&x.A0, &y.A0) - e.fp.AssertIsEqual(&x.A1, &y.A1) -} - -func (e ext6) add(x, y *e6) *e6 { - z0 := e.ext2.add(&x.B0, &y.B0) // z.B0.Add(&x.B0, &y.B0) - z1 := e.ext2.add(&x.B1, &y.B1) // z.B1.Add(&x.B1, &y.B1) - z2 := e.ext2.add(&x.B2, &y.B2) // z.B2.Add(&x.B2, &y.B2) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} - -func (e ext6) neg(x *e6) *e6 { - z0 := e.ext2.neg(&x.B0) // z.B0.Neg(&x.B0) - z1 := e.ext2.neg(&x.B1) // z.B1.Neg(&x.B1) - z2 := e.ext2.neg(&x.B2) // z.B2.Neg(&x.B2) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} - -func (e ext6) sub(x, y *e6) *e6 { - z0 := e.ext2.sub(&x.B0, &y.B0) // z.B0.Sub(&x.B0, &y.B0) - z1 := e.ext2.sub(&x.B1, &y.B1) // z.B1.Sub(&x.B1, &y.B1) - z2 := e.ext2.sub(&x.B2, &y.B2) // z.B2.Sub(&x.B2, &y.B2) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} - -func (e ext6) mul(x, y *e6) *e6 { - // var t0, t1, t2, c0, c1, c2, tmp E2 - t0 := e.ext2.mul(&x.B0, &y.B0) // t0.Mul(&x.B0, &y.B0) - t1 := e.ext2.mul(&x.B1, &y.B1) // t1.Mul(&x.B1, &y.B1) - t2 := e.ext2.mul(&x.B2, &y.B2) // t2.Mul(&x.B2, &y.B2) - c0 := e.ext2.add(&x.B1, &x.B2) // c0.Add(&x.B1, &x.B2) - tmp := e.ext2.add(&y.B1, &y.B2) // tmp.Add(&y.B1, &y.B2) - c0 = e.ext2.mul(c0, tmp) // c0.Mul(&c0, &tmp). - c0 = e.ext2.sub(c0, t1) // Sub(&c0, &t1). - c0 = e.ext2.sub(c0, t2) // Sub(&c0, &t2). - c0 = e.ext2.mulByNonResidue(c0) // MulByNonResidue(&c0). - c0 = e.ext2.add(c0, t0) // Add(&c0, &t0) - c1 := e.ext2.add(&x.B0, &x.B1) // c1.Add(&x.B0, &x.B1) - tmp = e.ext2.add(&y.B0, &y.B1) // tmp.Add(&y.B0, &y.B1) - c1 = e.ext2.mul(c1, tmp) // c1.Mul(&c1, &tmp). - c1 = e.ext2.sub(c1, t0) // Sub(&c1, &t0). - c1 = e.ext2.sub(c1, t1) // Sub(&c1, &t1) - tmp = e.ext2.mulByNonResidue(t2) // tmp.MulByNonResidue(&t2) - c1 = e.ext2.add(c1, tmp) // c1.Add(&c1, &tmp) - tmp = e.ext2.add(&x.B0, &x.B2) // tmp.Add(&x.B0, &x.B2) - c2 := e.ext2.add(&y.B0, &y.B2) // c2.Add(&y.B0, &y.B2). - c2 = e.ext2.mul(c2, tmp) // Mul(&c2, &tmp). - c2 = e.ext2.sub(c2, t0) // Sub(&c2, &t0). - c2 = e.ext2.sub(c2, t2) // Sub(&c2, &t2). - c2 = e.ext2.add(c2, t1) // Add(&c2, &t1) - return &e6{ - B0: *c0, // z.B0.Set(&c0) - B1: *c1, // z.B1.Set(&c1) - B2: *c2, // z.B2.Set(&c2) - } // return z -} - -func (e ext6) double(x *e6) *e6 { - z0 := e.ext2.double(&x.B0) // z.B0.Double(&x.B0) - z1 := e.ext2.double(&x.B1) // z.B1.Double(&x.B1) - z2 := e.ext2.double(&x.B2) // z.B2.Double(&x.B2) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} - -func (e ext6) square(x *e6) *e6 { - // var c4, c5, c1, c2, c3, c0 E2 - c4 := e.ext2.mul(&x.B0, &x.B1) // c4.Mul(&x.B0, &x.B1). - c4 = e.ext2.double(c4) // Double(&c4) - c5 := e.ext2.square(&x.B2) // c5.Square(&x.B2) - c1 := e.ext2.mulByNonResidue(c5) // c1.MulByNonResidue(&c5). - c1 = e.ext2.add(c1, c4) // Add(&c1, &c4) - c2 := e.ext2.sub(c4, c5) // c2.Sub(&c4, &c5) - c3 := e.ext2.square(&x.B0) // c3.Square(&x.B0) - c4 = e.ext2.sub(&x.B0, &x.B1) // c4.Sub(&x.B0, &x.B1). - c4 = e.ext2.add(c4, &x.B2) // Add(&c4, &x.B2) - c5 = e.ext2.mul(&x.B1, &x.B2) // c5.Mul(&x.B1, &x.B2). - c5 = e.ext2.double(c5) // Double(&c5) - c4 = e.ext2.square(c4) // c4.Square(&c4) - c0 := e.ext2.mulByNonResidue(c5) // c0.MulByNonResidue(&c5). - c0 = e.ext2.add(c0, c3) // Add(&c0, &c3) - z2 := e.ext2.add(c2, c4) // z.B2.Add(&c2, &c4). - z2 = e.ext2.add(z2, c5) // Add(&z.B2, &c5). - z2 = e.ext2.sub(z2, c3) // Sub(&z.B2, &c3) - z0 := c0 // z.B0.Set(&c0) - z1 := c1 // z.B1.Set(&c1) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} - -func (e ext6) inverse(x *e6) *e6 { - // var t0, t1, t2, t3, t4, t5, t6, c0, c1, c2, d1, d2 E2 - t0 := e.ext2.square(&x.B0) // t0.Square(&x.B0) - t1 := e.ext2.square(&x.B1) // t1.Square(&x.B1) - t2 := e.ext2.square(&x.B2) // t2.Square(&x.B2) - t3 := e.ext2.mul(&x.B0, &x.B1) // t3.Mul(&x.B0, &x.B1) - t4 := e.ext2.mul(&x.B0, &x.B2) // t4.Mul(&x.B0, &x.B2) - t5 := e.ext2.mul(&x.B1, &x.B2) // t5.Mul(&x.B1, &x.B2) - c0 := e.ext2.mulByNonResidue(t5) // c0.MulByNonResidue(&t5). - c0 = e.ext2.neg(c0) // Neg(&c0). - c0 = e.ext2.add(c0, t0) // Add(&c0, &t0) - c1 := e.ext2.mulByNonResidue(t2) // c1.MulByNonResidue(&t2). - c1 = e.ext2.sub(c1, t3) // Sub(&c1, &t3) - c2 := e.ext2.sub(t1, t4) // c2.Sub(&t1, &t4) - t6 := e.ext2.mul(&x.B0, c0) // t6.Mul(&x.B0, &c0) - d1 := e.ext2.mul(&x.B2, c1) // d1.Mul(&x.B2, &c1) - d2 := e.ext2.mul(&x.B1, c2) // d2.Mul(&x.B1, &c2) - d1 = e.ext2.add(d1, d2) // d1.Add(&d1, &d2). - d1 = e.ext2.mulByNonResidue(d1) // MulByNonResidue(&d1) - t6 = e.ext2.add(t6, d1) // t6.Add(&t6, &d1) - t6 = e.ext2.inverse(t6) // t6.Inverse(&t6) - z0 := e.ext2.mul(c0, t6) // z.B0.Mul(&c0, &t6) - z1 := e.ext2.mul(c1, t6) // z.B1.Mul(&c1, &t6) - z2 := e.ext2.mul(c2, t6) // z.B2.Mul(&c2, &t6) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} -func (e ext6) mulByE2(x *e6, y *e2) *e6 { - // var yCopy E2 - // yCopy.Set(y) - z0 := e.ext2.mul(&x.B0, y) // z.B0.Mul(&x.B0, &yCopy) - z1 := e.ext2.mul(&x.B1, y) // z.B1.Mul(&x.B1, &yCopy) - z2 := e.ext2.mul(&x.B2, y) // z.B2.Mul(&x.B2, &yCopy) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} - -func (e ext6) mulBy01(z *e6, c0, c1 *e2) *e6 { - // var a, b, tmp, t0, t1, t2 E2 - a := e.ext2.mul(&z.B0, c0) // a.Mul(&z.B0, c0) - b := e.ext2.mul(&z.B1, c1) // b.Mul(&z.B1, c1) - tmp := e.ext2.add(&z.B1, &z.B2) // tmp.Add(&z.B1, &z.B2) - t0 := e.ext2.mul(c1, tmp) // t0.Mul(c1, &tmp) - t0 = e.ext2.sub(t0, b) // t0.Sub(&t0, &b) - t0 = e.ext2.mulByNonResidue(t0) // t0.MulByNonResidue(&t0) - t0 = e.ext2.add(t0, a) // t0.Add(&t0, &a) - tmp = e.ext2.add(&z.B0, &z.B2) // tmp.Add(&z.B0, &z.B2) - t2 := e.ext2.mul(c0, tmp) // t2.Mul(c0, &tmp) - t2 = e.ext2.sub(t2, a) // t2.Sub(&t2, &a) - t2 = e.ext2.add(t2, b) // t2.Add(&t2, &b) - t1 := e.ext2.add(c0, c1) // t1.Add(c0, c1) - tmp = e.ext2.add(&z.B0, &z.B1) // tmp.Add(&z.B0, &z.B1) - t1 = e.ext2.mul(t1, tmp) // t1.Mul(&t1, &tmp) - t1 = e.ext2.sub(t1, a) // t1.Sub(&t1, &a) - t1 = e.ext2.sub(t1, b) // t1.Sub(&t1, &b) - return &e6{ - B0: *t0, // z.B0.Set(&t0) - B1: *t1, // z.B1.Set(&t1) - B2: *t2, // z.B2.Set(&t2) - } // return z -} - -func (e ext6) mulByNonResidue(x *e6) *e6 { - z2, z1, z0 := &x.B1, &x.B0, &x.B2 // z.B2, z.B1, z.B0 = x.B1, x.B0, x.B2 - z0 = e.ext2.mulByNonResidue(z0) // z.B0.MulByNonResidue(&z.B0) - return &e6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} - -func (e ext6) assertIsEqual(x, y *e6) { - e.ext2.assertIsEqual(&x.B0, &y.B0) - e.ext2.assertIsEqual(&x.B1, &y.B1) - e.ext2.assertIsEqual(&x.B2, &y.B2) -} - -func (e ext12) conjugate(x *e12) *e12 { - z1 := e.ext6.neg(&x.C1) // z.C1.Neg(&z.C1) - return &e12{ // return z - C0: x.C0, - C1: *z1, - } -} - -func (e ext12) inverse(x *e12) *e12 { - // var t0, t1, tmp E6 - t0 := e.ext6.square(&x.C0) // t0.Square(&x.C0) - t1 := e.ext6.square(&x.C1) // t1.Square(&x.C1) - tmp := e.ext6.mulByNonResidue(t1) // tmp.MulByNonResidue(&t1) - t0 = e.ext6.sub(t0, tmp) // t0.Sub(&t0, &tmp) - t1 = e.ext6.inverse(t0) // t1.Inverse(&t0) - z0 := e.ext6.mul(&x.C0, t1) // z.C0.Mul(&x.C0, &t1) - z1 := e.ext6.mul(&x.C1, t1) // z.C1.Mul(&x.C1, &t1). - z1 = e.ext6.neg(z1) // Neg(&z.C1) - return &e12{ // return z - C0: *z0, - C1: *z1, - } -} - -func (e ext12) mul(x, y *e12) *e12 { - // var a, b, c E6 - a := e.ext6.add(&x.C0, &x.C1) // a.Add(&x.C0, &x.C1) - b := e.ext6.add(&y.C0, &y.C1) // b.Add(&y.C0, &y.C1) - a = e.ext6.mul(a, b) // a.Mul(&a, &b) - b = e.ext6.mul(&x.C0, &y.C0) // b.Mul(&x.C0, &y.C0) - c := e.ext6.mul(&x.C1, &y.C1) // c.Mul(&x.C1, &y.C1) - z1 := e.ext6.sub(a, b) // z.C1.Sub(&a, &b). - z1 = e.ext6.sub(z1, c) // Sub(&z.C1, &c) - z0 := e.ext6.mulByNonResidue(c) // z.C0.MulByNonResidue(&c). - z0 = e.ext6.add(z0, b) // Add(&z.C0, &b) - return &e12{ // return z - C0: *z0, - C1: *z1, - } -} - -func (e ext12) cyclotomicSquare(x *e12) *e12 { - // var t [9]E2 - t0 := e.ext2.square(&x.C1.B1) // t[0].Square(&x.C1.B1) - t1 := e.ext2.square(&x.C0.B0) // t[1].Square(&x.C0.B0) - t6 := e.ext2.add(&x.C1.B1, &x.C0.B0) // t[6].Add(&x.C1.B1, &x.C0.B0). - t6 = e.ext2.square(t6) // Square(&t[6]). - t6 = e.ext2.sub(t6, t0) // Sub(&t[6], &t[0]). - t6 = e.ext2.sub(t6, t1) // Sub(&t[6], &t[1]) - t2 := e.ext2.square(&x.C0.B2) // t[2].Square(&x.C0.B2) - t3 := e.ext2.square(&x.C1.B0) // t[3].Square(&x.C1.B0) - t7 := e.ext2.add(&x.C0.B2, &x.C1.B0) // t[7].Add(&x.C0.B2, &x.C1.B0). - t7 = e.ext2.square(t7) // Square(&t[7]). - t7 = e.ext2.sub(t7, t2) // Sub(&t[7], &t[2]). - t7 = e.ext2.sub(t7, t3) // Sub(&t[7], &t[3]) - t4 := e.ext2.square(&x.C1.B2) // t[4].Square(&x.C1.B2) - t5 := e.ext2.square(&x.C0.B1) // t[5].Square(&x.C0.B1) - t8 := e.ext2.add(&x.C1.B2, &x.C0.B1) // t[8].Add(&x.C1.B2, &x.C0.B1). - t8 = e.ext2.square(t8) // Square(&t[8]). - t8 = e.ext2.sub(t8, t4) // Sub(&t[8], &t[4]). - t8 = e.ext2.sub(t8, t5) // Sub(&t[8], &t[5]). - t8 = e.ext2.mulByNonResidue(t8) // MulByNonResidue(&t[8]) - t0 = e.ext2.mulByNonResidue(t0) // t[0].MulByNonResidue(&t[0]). - t0 = e.ext2.add(t0, t1) // Add(&t[0], &t[1]) - t2 = e.ext2.mulByNonResidue(t2) // t[2].MulByNonResidue(&t[2]). - t2 = e.ext2.add(t2, t3) // Add(&t[2], &t[3]) - t4 = e.ext2.mulByNonResidue(t4) // t[4].MulByNonResidue(&t[4]). - t4 = e.ext2.add(t4, t5) // Add(&t[4], &t[5]) - z00 := e.ext2.sub(t0, &x.C0.B0) // z.C0.B0.Sub(&t[0], &x.C0.B0). - z00 = e.ext2.double(z00) // Double(&z.C0.B0). - z00 = e.ext2.add(z00, t0) // Add(&z.C0.B0, &t[0]) - z01 := e.ext2.sub(t2, &x.C0.B1) // z.C0.B1.Sub(&t[2], &x.C0.B1). - z01 = e.ext2.double(z01) // Double(&z.C0.B1). - z01 = e.ext2.add(z01, t2) // Add(&z.C0.B1, &t[2]) - z02 := e.ext2.sub(t4, &x.C0.B2) // z.C0.B2.Sub(&t[4], &x.C0.B2). - z02 = e.ext2.double(z02) // Double(&z.C0.B2). - z02 = e.ext2.add(z02, t4) // Add(&z.C0.B2, &t[4]) - z10 := e.ext2.add(t8, &x.C1.B0) // z.C1.B0.Add(&t[8], &x.C1.B0). - z10 = e.ext2.double(z10) // Double(&z.C1.B0). - z10 = e.ext2.add(z10, t8) // Add(&z.C1.B0, &t[8]) - z11 := e.ext2.add(t6, &x.C1.B1) // z.C1.B1.Add(&t[6], &x.C1.B1). - z11 = e.ext2.double(z11) // Double(&z.C1.B1). - z11 = e.ext2.add(z11, t6) // Add(&z.C1.B1, &t[6]) - z12 := e.ext2.add(t7, &x.C1.B2) // z.C1.B2.Add(&t[7], &x.C1.B2). - z12 = e.ext2.double(z12) // Double(&z.C1.B2). - z12 = e.ext2.add(z12, t7) // Add(&z.C1.B2, &t[7]) - return &e12{ // return z - C0: e6{ - B0: *z00, - B1: *z01, - B2: *z02, - }, - C1: e6{ - B0: *z10, - B1: *z11, - B2: *z12, - }, - } -} - -func (e ext12) frobenius(x *e12) *e12 { - // var t [6]E2 - t0 := e.ext2.conjugate(&x.C0.B0) // t[0].Conjugate(&x.C0.B0) - t1 := e.ext2.conjugate(&x.C0.B1) // t[1].Conjugate(&x.C0.B1) - t2 := e.ext2.conjugate(&x.C0.B2) // t[2].Conjugate(&x.C0.B2) - t3 := e.ext2.conjugate(&x.C1.B0) // t[3].Conjugate(&x.C1.B0) - t4 := e.ext2.conjugate(&x.C1.B1) // t[4].Conjugate(&x.C1.B1) - t5 := e.ext2.conjugate(&x.C1.B2) // t[5].Conjugate(&x.C1.B2) - t1 = e.ext2.mulByNonResidue1Power2(t1) // t[1].MulByNonResidue1Power2(&t[1]) - t2 = e.ext2.mulByNonResidue1Power4(t2) // t[2].MulByNonResidue1Power4(&t[2]) - t3 = e.ext2.mulByNonResidue1Power1(t3) // t[3].MulByNonResidue1Power1(&t[3]) - t4 = e.ext2.mulByNonResidue1Power3(t4) // t[4].MulByNonResidue1Power3(&t[4]) - t5 = e.ext2.mulByNonResidue1Power5(t5) // t[5].MulByNonResidue1Power5(&t[5]) - return &e12{ // return z - C0: e6{ - B0: *t0, // z.C0.B0 = t[0] - B1: *t1, // z.C0.B1 = t[1] - B2: *t2, // z.C0.B2 = t[2] - }, - C1: e6{ - B0: *t3, // z.C1.B0 = t[3] - B1: *t4, // z.C1.B1 = t[4] - B2: *t5, // z.C1.B2 = t[5] - }, - } -} - -func (e ext12) frobeniusSquare(x *e12) *e12 { - z00 := &x.C0.B0 // z.C0.B0 = x.C0.B0 - z01 := e.ext2.mulByNonResidue2Power2(&x.C0.B1) // z.C0.B1.MulByNonResidue2Power2(&x.C0.B1) - z02 := e.ext2.mulByNonResidue2Power4(&x.C0.B2) // z.C0.B2.MulByNonResidue2Power4(&x.C0.B2) - z10 := e.ext2.mulByNonResidue2Power1(&x.C1.B0) // z.C1.B0.MulByNonResidue2Power1(&x.C1.B0) - z11 := e.ext2.mulByNonResidue2Power3(&x.C1.B1) // z.C1.B1.MulByNonResidue2Power3(&x.C1.B1) - z12 := e.ext2.mulByNonResidue2Power5(&x.C1.B2) // z.C1.B2.MulByNonResidue2Power5(&x.C1.B2) - return &e12{ // return z - C0: e6{B0: *z00, B1: *z01, B2: *z02}, - C1: e6{B0: *z10, B1: *z11, B2: *z12}, - } -} - -func (e ext12) frobeniusCube(x *e12) *e12 { - // var t [6]E2 - t0 := e.ext2.conjugate(&x.C0.B0) // t[0].Conjugate(&x.C0.B0) - t1 := e.ext2.conjugate(&x.C0.B1) // t[1].Conjugate(&x.C0.B1) - t2 := e.ext2.conjugate(&x.C0.B2) // t[2].Conjugate(&x.C0.B2) - t3 := e.ext2.conjugate(&x.C1.B0) // t[3].Conjugate(&x.C1.B0) - t4 := e.ext2.conjugate(&x.C1.B1) // t[4].Conjugate(&x.C1.B1) - t5 := e.ext2.conjugate(&x.C1.B2) // t[5].Conjugate(&x.C1.B2) - t1 = e.ext2.mulByNonResidue3Power2(t1) // t[1].MulByNonResidue3Power2(&t[1]) - t2 = e.ext2.mulByNonResidue3Power4(t2) // t[2].MulByNonResidue3Power4(&t[2]) - t3 = e.ext2.mulByNonResidue3Power1(t3) // t[3].MulByNonResidue3Power1(&t[3]) - t4 = e.ext2.mulByNonResidue3Power3(t4) // t[4].MulByNonResidue3Power3(&t[4]) - t5 = e.ext2.mulByNonResidue3Power5(t5) // t[5].MulByNonResidue3Power5(&t[5]) - return &e12{ // return z - C0: e6{ - B0: *t0, // z.C0.B0 = t[0] - B1: *t1, // z.C0.B1 = t[1] - B2: *t2, // z.C0.B2 = t[2] - }, - C1: e6{ - B0: *t3, // z.C1.B0 = t[3] - B1: *t4, // z.C1.B1 = t[4] - B2: *t5, // z.C1.B2 = t[5] - }, - } -} - -func (e ext12) expt(x *e12) *e12 { - // var result, t0, t1, t2, t3, t4, t5, t6 E12 - t3 := e.cyclotomicSquare(x) // t3.CyclotomicSquare(x) - t5 := e.cyclotomicSquare(t3) // t5.CyclotomicSquare(&t3) - result := e.cyclotomicSquare(t5) // result.CyclotomicSquare(&t5) - t0 := e.cyclotomicSquare(result) // t0.CyclotomicSquare(&result) - t2 := e.mul(x, t0) // t2.Mul(x, &t0) - t0 = e.mul(t3, t2) // t0.Mul(&t3, &t2) - t1 := e.mul(x, t0) // t1.Mul(x, &t0) - t4 := e.mul(result, t2) // t4.Mul(&result, &t2) - t6 := e.cyclotomicSquare(t2) // t6.CyclotomicSquare(&t2) - t1 = e.mul(t0, t1) // t1.Mul(&t0, &t1) - t0 = e.mul(t3, t1) // t0.Mul(&t3, &t1) - t6 = e.nSquare(t6, 6) // t6.nSquare(6) - t5 = e.mul(t5, t6) // t5.Mul(&t5, &t6) - t5 = e.mul(t4, t5) // t5.Mul(&t4, &t5) - t5 = e.nSquare(t5, 7) // t5.nSquare(7) - t4 = e.mul(t4, t5) // t4.Mul(&t4, &t5) - t4 = e.nSquare(t4, 8) // t4.nSquare(8) - t4 = e.mul(t0, t4) // t4.Mul(&t0, &t4) - t3 = e.mul(t3, t4) // t3.Mul(&t3, &t4) - t3 = e.nSquare(t3, 6) // t3.nSquare(6) - t2 = e.mul(t2, t3) // t2.Mul(&t2, &t3) - t2 = e.nSquare(t2, 8) // t2.nSquare(8) - t2 = e.mul(t0, t2) // t2.Mul(&t0, &t2) - t2 = e.nSquare(t2, 6) // t2.nSquare(6) - t2 = e.mul(t0, t2) // t2.Mul(&t0, &t2) - t2 = e.nSquare(t2, 10) // t2.nSquare(10) - t1 = e.mul(t1, t2) // t1.Mul(&t1, &t2) - t1 = e.nSquare(t1, 6) // t1.nSquare(6) - t0 = e.mul(t0, t1) // t0.Mul(&t0, &t1) - z := e.mul(result, t0) // z.Mul(&result, &t0) - return z // return z -} - -func (e ext12) one() *e12 { - z000 := e.fp.One() - zero := e.fp.Zero() - return &e12{ - C0: e6{ - B0: e2{A0: *z000, A1: *zero}, - B1: e2{A0: *zero, A1: *zero}, - B2: e2{A0: *zero, A1: *zero}, - }, - C1: e6{ - B0: e2{A0: *zero, A1: *zero}, - B1: e2{A0: *zero, A1: *zero}, - B2: e2{A0: *zero, A1: *zero}, - }, - } -} - -func (e ext12) mulBy034(z *e12, c0, c3, c4 *e2) *e12 { - // var a, b, d E6 - a := e.ext6.mulByE2(&z.C0, c0) // a.MulByE2(&z.C0, c0) - // b.Set(&z.C1) - b := e.ext6.mulBy01(&z.C1, c3, c4) // b.MulBy01(c3, c4) - c0 = e.ext2.add(c0, c3) // c0.Add(c0, c3) - d := e.ext6.add(&z.C0, &z.C1) // d.Add(&z.C0, &z.C1) - d = e.ext6.mulBy01(d, c0, c4) // d.MulBy01(c0, c4) - z1 := e.add(a, b) // z.C1.Add(&a, &b). - z1 = e.neg(z1) // Neg(&z.C1). - z1 = e.add(z1, d) // Add(&z.C1, &d) - z0 := e.mulByNonResidue(b) // z.C0.MulByNonResidue(&b). - z0 = e.add(z0, a) // Add(&z.C0, &a) - return &e12{ // return z - C0: *z0, - C1: *z1, - } -} - -func (e ext12) square(x *e12) *e12 { - // var c0, c2, c3 E6 - c0 := e.ext6.sub(&x.C0, &x.C1) // c0.Sub(&x.C0, &x.C1) - c3 := e.ext6.mulByNonResidue(&x.C1) // c3.MulByNonResidue(&x.C1). - c3 = e.ext6.neg(c3) // Neg(&c3). - c3 = e.ext6.add(&x.C0, c3) // Add(&x.C0, &c3) - c2 := e.ext6.mul(&x.C0, &x.C1) // c2.Mul(&x.C0, &x.C1) - c0 = e.ext6.mul(c0, c3) // c0.Mul(&c0, &c3). - c0 = e.ext6.add(c0, c2) // Add(&c0, &c2) - z1 := e.ext6.double(c2) // z.C1.Double(&c2) - c2 = e.ext6.mulByNonResidue(c2) // c2.MulByNonResidue(&c2) - z0 := e.ext6.add(c0, c2) // z.C0.Add(&c0, &c2) - return &e12{ // return z - C0: *z0, - C1: *z1, - } -} - -func (e ext12) mulBy034by034(d0, d3, d4, c0, c3, c4 *e2) *e12 { - // var tmp, x0, x3, x4, x04, x03, x34 E2 - x0 := e.ext2.mul(c0, d0) // x0.Mul(c0, d0) - x3 := e.ext2.mul(c3, d3) // x3.Mul(c3, d3) - x4 := e.ext2.mul(c4, d4) // x4.Mul(c4, d4) - tmp := e.ext2.add(c0, c4) // tmp.Add(c0, c4) - x04 := e.ext2.add(d0, d4) // x04.Add(d0, d4). - x04 = e.ext2.mul(x04, tmp) // Mul(&x04, &tmp). - x04 = e.ext2.sub(x04, x0) // Sub(&x04, &x0). - x04 = e.ext2.sub(x04, x4) // Sub(&x04, &x4) - tmp = e.ext2.add(c0, c3) // tmp.Add(c0, c3) - x03 := e.ext2.add(d0, d3) // x03.Add(d0, d3). - x03 = e.ext2.mul(x03, tmp) // Mul(&x03, &tmp). - x03 = e.ext2.sub(x03, x0) // Sub(&x03, &x0). - x03 = e.ext2.sub(x03, x3) // Sub(&x03, &x3) - tmp = e.ext2.add(c3, c4) // tmp.Add(c3, c4) - x34 := e.ext2.add(d3, d4) // x34.Add(d3, d4). - x34 = e.ext2.mul(x34, tmp) // Mul(&x34, &tmp). - x34 = e.ext2.sub(x34, x3) // Sub(&x34, &x3). - x34 = e.ext2.sub(x34, x4) // Sub(&x34, &x4) - z00 := e.ext2.mulByNonResidue(x4) // z.C0.B0.MulByNonResidue(&x4). - z00 = e.ext2.add(z00, x0) // Add(&z.C0.B0, &x0) - z01 := x3 // z.C0.B1.Set(&x3) - z02 := x34 // z.C0.B2.Set(&x34) - z10 := x03 // z.C1.B0.Set(&x03) - z11 := x04 // z.C1.B1.Set(&x04) - z12 := e.ext2.zero() // z.C1.B2.SetZero() - return &e12{ // return z - C0: e6{ - B0: *z00, - B1: *z01, - B2: *z02, - }, - C1: e6{ - B0: *z10, - B1: *z11, - B2: *z12, - }, - } -} - -func (e ext12) assertIsEqual(x, y *e12) { - e.ext6.assertIsEqual(&x.C0, &y.C0) - e.ext6.assertIsEqual(&x.C1, &y.C1) -} - -func (e ext12) nSquare(z *e12, n int) *e12 { - for i := 0; i < n; i++ { - z = e.cyclotomicSquare(z) - } - return z -} diff --git a/std/algebra/sw_bls12377/doc.go b/std/algebra/sw_bls12377/doc.go deleted file mode 100644 index c9270127e8..0000000000 --- a/std/algebra/sw_bls12377/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -/* -Copyright © 2020 ConsenSys - -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 sw (short weierstrass) -package sw_bls12377 diff --git a/std/algebra/sw_bls24315/doc.go b/std/algebra/sw_bls24315/doc.go deleted file mode 100644 index 279e09879b..0000000000 --- a/std/algebra/sw_bls24315/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -/* -Copyright © 2020 ConsenSys - -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 sw (short weierstrass) -package sw_bls24315 diff --git a/std/commitments/kzg_bls12377/verifier.go b/std/commitments/kzg_bls12377/verifier.go index d999e6396e..43dd15a83a 100644 --- a/std/commitments/kzg_bls12377/verifier.go +++ b/std/commitments/kzg_bls12377/verifier.go @@ -19,8 +19,8 @@ package kzg_bls12377 import ( "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/fields_bls12377" - "github.com/consensys/gnark/std/algebra/sw_bls12377" + "github.com/consensys/gnark/std/algebra/native/fields_bls12377" + "github.com/consensys/gnark/std/algebra/native/sw_bls12377" ) // Digest commitment of a polynomial. diff --git a/std/commitments/kzg_bls24315/verifier.go b/std/commitments/kzg_bls24315/verifier.go index e5704525f8..4d6680c072 100644 --- a/std/commitments/kzg_bls24315/verifier.go +++ b/std/commitments/kzg_bls24315/verifier.go @@ -19,8 +19,8 @@ package kzg_bls24315 import ( "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/fields_bls24315" - "github.com/consensys/gnark/std/algebra/sw_bls24315" + "github.com/consensys/gnark/std/algebra/native/fields_bls24315" + "github.com/consensys/gnark/std/algebra/native/sw_bls24315" ) // Digest commitment of a polynomial. diff --git a/std/groth16_bls12377/verifier.go b/std/groth16_bls12377/verifier.go index 6a43e585a8..8316d20479 100644 --- a/std/groth16_bls12377/verifier.go +++ b/std/groth16_bls12377/verifier.go @@ -24,8 +24,8 @@ import ( "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/frontend" groth16_bls12377 "github.com/consensys/gnark/internal/backend/bls12-377/groth16" - "github.com/consensys/gnark/std/algebra/fields_bls12377" - "github.com/consensys/gnark/std/algebra/sw_bls12377" + "github.com/consensys/gnark/std/algebra/native/fields_bls12377" + "github.com/consensys/gnark/std/algebra/native/sw_bls12377" ) // Proof represents a Groth16 proof diff --git a/std/groth16_bls12377/verifier_test.go b/std/groth16_bls12377/verifier_test.go index 61bc403ca5..beab2de62b 100644 --- a/std/groth16_bls12377/verifier_test.go +++ b/std/groth16_bls12377/verifier_test.go @@ -27,7 +27,7 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" groth16_bls12377 "github.com/consensys/gnark/internal/backend/bls12-377/groth16" - "github.com/consensys/gnark/std/algebra/sw_bls12377" + "github.com/consensys/gnark/std/algebra/native/sw_bls12377" "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/test" ) diff --git a/std/groth16_bls24315/verifier.go b/std/groth16_bls24315/verifier.go index 09487acbb3..836c20d33b 100644 --- a/std/groth16_bls24315/verifier.go +++ b/std/groth16_bls24315/verifier.go @@ -24,8 +24,8 @@ import ( "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/frontend" groth16_bls24315 "github.com/consensys/gnark/internal/backend/bls24-315/groth16" - "github.com/consensys/gnark/std/algebra/fields_bls24315" - "github.com/consensys/gnark/std/algebra/sw_bls24315" + "github.com/consensys/gnark/std/algebra/native/fields_bls24315" + "github.com/consensys/gnark/std/algebra/native/sw_bls24315" ) // Proof represents a Groth16 proof diff --git a/std/groth16_bls24315/verifier_test.go b/std/groth16_bls24315/verifier_test.go index 18da40b4b4..73bb075d19 100644 --- a/std/groth16_bls24315/verifier_test.go +++ b/std/groth16_bls24315/verifier_test.go @@ -27,7 +27,7 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" groth16_bls24315 "github.com/consensys/gnark/internal/backend/bls24-315/groth16" - "github.com/consensys/gnark/std/algebra/sw_bls24315" + "github.com/consensys/gnark/std/algebra/native/sw_bls24315" "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/test" ) diff --git a/std/hints.go b/std/hints.go index c3bdc3713b..f9b85d3266 100644 --- a/std/hints.go +++ b/std/hints.go @@ -4,8 +4,8 @@ import ( "sync" "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/std/algebra/sw_bls12377" - "github.com/consensys/gnark/std/algebra/sw_bls24315" + "github.com/consensys/gnark/std/algebra/native/sw_bls12377" + "github.com/consensys/gnark/std/algebra/native/sw_bls24315" "github.com/consensys/gnark/std/math/bits" "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/std/selector" diff --git a/std/math/emulated/field_test.go b/std/math/emulated/field_test.go index 927b23bc59..d1124f4e82 100644 --- a/std/math/emulated/field_test.go +++ b/std/math/emulated/field_test.go @@ -8,7 +8,7 @@ import ( bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/std/algebra/sw_bls12377" + "github.com/consensys/gnark/std/algebra/native/sw_bls12377" "github.com/consensys/gnark/test" ) diff --git a/std/signature/ecdsa/ecdsa.go b/std/signature/ecdsa/ecdsa.go index acf7286dcd..86bdb5bac7 100644 --- a/std/signature/ecdsa/ecdsa.go +++ b/std/signature/ecdsa/ecdsa.go @@ -1,7 +1,7 @@ /* Package ecdsa implements ECDSA signature verification over any elliptic curve. -The package depends on the [weierstrass] package for elliptic curve group +The package depends on the [emulated/sw_emulated] package for elliptic curve group operations using non-native arithmetic. Thus we can verify ECDSA signatures over any curve. The cost for a single secp256k1 signature verification is approximately 4M constraints in R1CS and 10M constraints in PLONKish. @@ -15,7 +15,7 @@ package ecdsa import ( "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/weierstrass" + "github.com/consensys/gnark/std/algebra/emulated/sw_emulated" "github.com/consensys/gnark/std/math/emulated" ) @@ -25,14 +25,14 @@ type Signature[Scalar emulated.FieldParams] struct { } // PublicKey represents the public key to verify the signature for. -type PublicKey[Base, Scalar emulated.FieldParams] weierstrass.AffinePoint[Base] +type PublicKey[Base, Scalar emulated.FieldParams] sw_emulated.AffinePoint[Base] // Verify asserts that the signature sig verifies for the message msg and public // key pk. The curve parameters params define the elliptic curve. // // We assume that the message msg is already hashed to the scalar field. -func (pk PublicKey[T, S]) Verify(api frontend.API, params weierstrass.CurveParams, msg *emulated.Element[S], sig *Signature[S]) { - cr, err := weierstrass.New[T, S](api, params) +func (pk PublicKey[T, S]) Verify(api frontend.API, params sw_emulated.CurveParams, msg *emulated.Element[S], sig *Signature[S]) { + cr, err := sw_emulated.New[T, S](api, params) if err != nil { // TODO: softer handling. panic(err) @@ -45,7 +45,7 @@ func (pk PublicKey[T, S]) Verify(api frontend.API, params weierstrass.CurveParam if err != nil { panic(err) } - pkpt := weierstrass.AffinePoint[T](pk) + pkpt := sw_emulated.AffinePoint[T](pk) sInv := scalarApi.Inverse(&sig.S) msInv := scalarApi.MulMod(msg, sInv) rsInv := scalarApi.MulMod(&sig.R, sInv) diff --git a/std/signature/ecdsa/ecdsa_test.go b/std/signature/ecdsa/ecdsa_test.go index 711ec69554..57ff1a4406 100644 --- a/std/signature/ecdsa/ecdsa_test.go +++ b/std/signature/ecdsa/ecdsa_test.go @@ -9,7 +9,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/secp256k1/ecdsa" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/weierstrass" + "github.com/consensys/gnark/std/algebra/emulated/sw_emulated" "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/test" ) @@ -21,7 +21,7 @@ type EcdsaCircuit[T, S emulated.FieldParams] struct { } func (c *EcdsaCircuit[T, S]) Define(api frontend.API) error { - c.Pub.Verify(api, weierstrass.GetCurveParams[T](), &c.Msg, &c.Sig) + c.Pub.Verify(api, sw_emulated.GetCurveParams[T](), &c.Msg, &c.Sig) return nil } @@ -134,7 +134,7 @@ func ExamplePublicKey_Verify() { Y: emulated.ValueOf[emulated.Secp256k1Fp](puby), } // signature verification assertion is done in-circuit - Pub.Verify(api, weierstrass.GetCurveParams[emulated.Secp256k1Fp](), &Msg, &Sig) + Pub.Verify(api, sw_emulated.GetCurveParams[emulated.Secp256k1Fp](), &Msg, &Sig) } // Example how to create a valid signature for secp256k1 diff --git a/std/signature/eddsa/eddsa.go b/std/signature/eddsa/eddsa.go index e285f00496..dcfcfc2870 100644 --- a/std/signature/eddsa/eddsa.go +++ b/std/signature/eddsa/eddsa.go @@ -24,7 +24,7 @@ import ( "github.com/consensys/gnark/std/hash" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/twistededwards" + "github.com/consensys/gnark/std/algebra/native/twistededwards" tedwards "github.com/consensys/gnark-crypto/ecc/twistededwards" diff --git a/std/signature/eddsa/eddsa_test.go b/std/signature/eddsa/eddsa_test.go index 657d337010..762bfb5ef0 100644 --- a/std/signature/eddsa/eddsa_test.go +++ b/std/signature/eddsa/eddsa_test.go @@ -27,7 +27,7 @@ import ( "github.com/consensys/gnark-crypto/signature/eddsa" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/internal/utils" - "github.com/consensys/gnark/std/algebra/twistededwards" + "github.com/consensys/gnark/std/algebra/native/twistededwards" "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/test" ) From c439508a05bc713377267e65fc827c5ebad7db46 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Wed, 8 Mar 2023 04:00:34 +0100 Subject: [PATCH 071/464] fix: allow unreplaced BSB22 commitment hint in solver (#507) --- frontend/cs/r1cs/api.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index 75d0d31326..063ec9eebe 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -20,6 +20,7 @@ import ( "errors" "fmt" "math/big" + "os" "path/filepath" "reflect" "runtime" @@ -27,9 +28,11 @@ import ( "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/debug" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/internal/expr" "github.com/consensys/gnark/frontend/schema" + "github.com/consensys/gnark/logger" "github.com/consensys/gnark/std/math/bits" ) @@ -756,6 +759,17 @@ func (builder *builder) getCommittedVariables(i *constraint.Commitment) []fronte return res } -func bsb22CommitmentComputePlaceholder(*big.Int, []*big.Int, []*big.Int) error { +func bsb22CommitmentComputePlaceholder(_ *big.Int, _ []*big.Int, output []*big.Int) error { + if (len(os.Args) > 0 && strings.HasSuffix(os.Args[0], ".test")) || debug.Debug { + // usually we only run solver without prover during testing + log := logger.Logger() + log.Error().Msg("Augmented groth16 commitment hint not replaced. Proof will not be sound!") + output[0].SetInt64(0) + return nil + } return fmt.Errorf("placeholder function: to be replaced by commitment computation") } + +func init() { + solver.RegisterHint(bsb22CommitmentComputePlaceholder) +} From 1ef6a1bf5d826ffb3e94baca9951caa58066ade5 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Tue, 7 Mar 2023 21:06:42 -0600 Subject: [PATCH 072/464] feat: gnark/profile now filter frontend private method for clarity and return a tree as txt repr (#538) --- go.sum | 2 -- profile/profile.go | 6 ++--- profile/profile_test.go | 27 +++++++++++++++++----- profile/profile_worker.go | 47 ++++++++++++++++++++++----------------- 4 files changed, 52 insertions(+), 30 deletions(-) diff --git a/go.sum b/go.sum index 83552db257..3c8602fd34 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,6 @@ github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.9.1 h1:mru55qKdWl3E035hAoh1jj9d7hVnYY5pfb6tmovSmII= -github.com/consensys/gnark-crypto v0.9.1/go.mod h1:a2DQL4+5ywF6safEeZFEPGRiiGbjzGFRUN2sg06VuU4= github.com/consensys/gnark-crypto v0.9.2-0.20230222154459-49b5c6cfd875 h1:FTOvlE+90hvp+XHi8i89xCejJ0627wfbP0RSWzmVFks= github.com/consensys/gnark-crypto v0.9.2-0.20230222154459-49b5c6cfd875/go.mod h1:a2DQL4+5ywF6safEeZFEPGRiiGbjzGFRUN2sg06VuU4= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= diff --git a/profile/profile.go b/profile/profile.go index 3d3778d995..fe3e58f3c2 100644 --- a/profile/profile.go +++ b/profile/profile.go @@ -92,7 +92,7 @@ func Start(options ...Option) *Profile { log := logger.Logger() if p.filePath == "" { - log.Warn().Msg("gnark profiling enabled [not writting to disk]") + log.Warn().Msg("gnark profiling enabled [not writing to disk]") } else { log.Info().Str("path", p.filePath).Msg("gnark profiling enabled") } @@ -131,7 +131,7 @@ func (p *Profile) Stop() { f.Close() log.Info().Str("path", p.filePath).Msg("gnark profiling disabled") } else { - log.Warn().Msg("gnark profiling disabled [not writting to disk]") + log.Warn().Msg("gnark profiling disabled [not writing to disk]") } } @@ -144,7 +144,7 @@ func (p *Profile) NbConstraints() int { // Top return a similar output than pprof top command func (p *Profile) Top() string { r := report.NewDefault(&p.pprof, report.Options{ - OutputFormat: report.Text, + OutputFormat: report.Tree, CompactLabels: true, NodeFraction: 0.005, EdgeFraction: 0.001, diff --git a/profile/profile_test.go b/profile/profile_test.go index 0505331a90..ea132b1161 100644 --- a/profile/profile_test.go +++ b/profile/profile_test.go @@ -4,11 +4,13 @@ package profile_test import ( "fmt" + "strings" "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/consensys/gnark/profile" + "golang.org/x/exp/slices" ) type Circuit struct { @@ -29,12 +31,27 @@ func Example() { _, _ = frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &Circuit{}) p.Stop() + const expectedOutput = `Showing nodes accounting for 2, 100% of 2 total +----------------------------------------------------------+------------- + flat flat% sum% cum cum% calls calls% + context +----------------------------------------------------------+------------- + 1 100% | profile_test.(*Circuit).Define profile/profile_test.go:21 + 1 50.00% 50.00% 1 50.00% | r1cs.(*builder).AssertIsEqual frontend/cs/r1cs/api_assertions.go:37 +----------------------------------------------------------+------------- + 1 100% | profile_test.(*Circuit).Define profile/profile_test.go:21 + 1 50.00% 100% 1 50.00% | r1cs.(*builder).Mul frontend/cs/r1cs/api.go:221 +----------------------------------------------------------+------------- + 0 0% 100% 2 100% | profile_test.(*Circuit).Define profile/profile_test.go:21 + 1 50.00% | r1cs.(*builder).AssertIsEqual frontend/cs/r1cs/api_assertions.go:37 + 1 50.00% | r1cs.(*builder).Mul frontend/cs/r1cs/api.go:221 +----------------------------------------------------------+-------------` + + a := strings.Fields(p.Top()) + b := strings.Fields(expectedOutput) + fmt.Println(p.NbConstraints()) - fmt.Println(p.Top()) + fmt.Println(slices.Equal(a, b)) // Output: // 2 - // Showing nodes accounting for 2, 100% of 2 total - // flat flat% sum% cum cum% - // 1 50.00% 50.00% 2 100% profile_test.(*Circuit).Define profile/profile_test.go:19 - // 1 50.00% 100% 1 50.00% r1cs.(*builder).AssertIsEqual frontend/cs/r1cs/api_assertions.go:37 + // true } diff --git a/profile/profile_worker.go b/profile/profile_worker.go index b63499475b..2465262459 100644 --- a/profile/profile_worker.go +++ b/profile/profile_worker.go @@ -5,6 +5,7 @@ import ( "strings" "sync" "sync/atomic" + "unicode" "github.com/google/pprof/profile" ) @@ -68,26 +69,8 @@ func collectSample(pc []uintptr) { continue } - // to avoid aving a location that concentrates 99% of the calls, we transfer the "addConstraint" - // occuring in Mul to the previous level in the stack - if strings.Contains(frame.Function, "github.com/consensys/gnark/frontend/cs/r1cs.(*builder).Mul") { - continue - } - - if strings.HasPrefix(frame.Function, "github.com/consensys/gnark/frontend/cs/scs.(*scs).Mul") { - continue - } - - if strings.HasPrefix(frame.Function, "github.com/consensys/gnark/frontend/cs/scs.(*scs).split") { - continue - } - - // with scs.Builder (Plonk) Add and Sub always add a constraint --> we record the caller as the constraint adder - // but in the future we may record a different type of sample for these - if strings.HasPrefix(frame.Function, "github.com/consensys/gnark/frontend/cs/scs.(*scs).Add") { - continue - } - if strings.HasPrefix(frame.Function, "github.com/consensys/gnark/frontend/cs/scs.(*scs).Sub") { + // filter internal builder functions + if filterSCSPrivateFunc(frame.Function) || filterR1CSPrivateFunc(frame.Function) { continue } @@ -123,3 +106,27 @@ func collectSample(pc []uintptr) { } } + +func filterSCSPrivateFunc(f string) bool { + const scsPrefix = "github.com/consensys/gnark/frontend/cs/scs.(*builder)." + if strings.HasPrefix(f, scsPrefix) && len(f) > len(scsPrefix) { + // filter plonk frontend private APIs from the trace. + c := []rune(f)[len(scsPrefix)] + if unicode.IsLower(c) { + return true + } + } + return false +} + +func filterR1CSPrivateFunc(f string) bool { + const r1csPrefix = "github.com/consensys/gnark/frontend/cs/r1cs.(*builder)." + if strings.HasPrefix(f, r1csPrefix) && len(f) > len(r1csPrefix) { + // filter r1cs frontend private APIs from the trace. + c := []rune(f)[len(r1csPrefix)] + if unicode.IsLower(c) { + return true + } + } + return false +} From a6e04012e1126abd6e3e151337f08e35f79a4ca0 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Tue, 7 Mar 2023 21:56:29 -0600 Subject: [PATCH 073/464] fix: fix profile example to not compare expected output with varying line numbers --- profile/profile_test.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/profile/profile_test.go b/profile/profile_test.go index ea132b1161..9f7d0fca0a 100644 --- a/profile/profile_test.go +++ b/profile/profile_test.go @@ -4,13 +4,11 @@ package profile_test import ( "fmt" - "strings" "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/consensys/gnark/profile" - "golang.org/x/exp/slices" ) type Circuit struct { @@ -31,7 +29,8 @@ func Example() { _, _ = frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &Circuit{}) p.Stop() - const expectedOutput = `Showing nodes accounting for 2, 100% of 2 total + // expected output + const _ = `Showing nodes accounting for 2, 100% of 2 total ----------------------------------------------------------+------------- flat flat% sum% cum cum% calls calls% + context ----------------------------------------------------------+------------- @@ -46,12 +45,7 @@ func Example() { 1 50.00% | r1cs.(*builder).Mul frontend/cs/r1cs/api.go:221 ----------------------------------------------------------+-------------` - a := strings.Fields(p.Top()) - b := strings.Fields(expectedOutput) - fmt.Println(p.NbConstraints()) - fmt.Println(slices.Equal(a, b)) // Output: // 2 - // true } From a57f017a0ad5cd726746bbcba161d33d4d35aaf5 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 8 Mar 2023 11:53:07 +0100 Subject: [PATCH 074/464] style: apply suggested edits --- std/algebra/emulated/fields_bn254/e12.go | 9 +- std/algebra/emulated/fields_bn254/e12_test.go | 80 ++++++++------- std/algebra/emulated/fields_bn254/e2.go | 9 +- std/algebra/emulated/fields_bn254/e2_test.go | 99 +++++++++++-------- std/algebra/emulated/fields_bn254/e6.go | 11 ++- std/algebra/emulated/fields_bn254/e6_test.go | 75 +++++++------- 6 files changed, 162 insertions(+), 121 deletions(-) diff --git a/std/algebra/emulated/fields_bn254/e12.go b/std/algebra/emulated/fields_bn254/e12.go index 77bd9727b7..b6b65daf6e 100644 --- a/std/algebra/emulated/fields_bn254/e12.go +++ b/std/algebra/emulated/fields_bn254/e12.go @@ -246,7 +246,10 @@ func (e Ext12) AssertIsEqual(x, y *E12) { e.Ext6.AssertIsEqual(&x.C1, &y.C1) } -func (x *E12) assign(y *bn254.E12) { - x.C0.assign(&y.C0) - x.C1.assign(&y.C1) +func FromE12(y *bn254.E12) E12 { + return E12{ + C0: FromE6(&y.C0), + C1: FromE6(&y.C1), + } + } diff --git a/std/algebra/emulated/fields_bn254/e12_test.go b/std/algebra/emulated/fields_bn254/e12_test.go index 040d3e16af..fced3de604 100644 --- a/std/algebra/emulated/fields_bn254/e12_test.go +++ b/std/algebra/emulated/fields_bn254/e12_test.go @@ -31,10 +31,11 @@ func TestAddFp12(t *testing.T) { _, _ = b.SetRandom() c.Add(&a, &b) - var witness e12Add - witness.A.assign(&a) - witness.B.assign(&b) - witness.C.assign(&c) + witness := e12Add{ + A: FromE12(&a), + B: FromE12(&b), + C: FromE12(&c), + } err := test.IsSolved(&e12Add{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) @@ -62,10 +63,11 @@ func TestSubFp12(t *testing.T) { _, _ = b.SetRandom() c.Sub(&a, &b) - var witness e12Sub - witness.A.assign(&a) - witness.B.assign(&b) - witness.C.assign(&c) + witness := e12Sub{ + A: FromE12(&a), + B: FromE12(&b), + C: FromE12(&c), + } err := test.IsSolved(&e12Sub{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) @@ -94,10 +96,11 @@ func TestMulFp12(t *testing.T) { _, _ = b.SetRandom() c.Mul(&a, &b) - var witness e12Mul - witness.A.assign(&a) - witness.B.assign(&b) - witness.C.assign(&c) + witness := e12Mul{ + A: FromE12(&a), + B: FromE12(&b), + C: FromE12(&c), + } err := test.IsSolved(&e12Mul{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) @@ -132,14 +135,16 @@ func TestMulFp12By034by034(t *testing.T) { _, _ = d3.SetRandom() _, _ = d4.SetRandom() c.Mul034by034(&c0, &c3, &c4, &d0, &d3, &d4) - var witness e12MulBy034by034 - witness.C0.assign(&c0) - witness.C3.assign(&c3) - witness.C4.assign(&c4) - witness.D0.assign(&d0) - witness.D3.assign(&d3) - witness.D4.assign(&d4) - witness.C.assign(&c) + + witness := e12MulBy034by034{ + C0: FromE2(&c0), + C3: FromE2(&c3), + C4: FromE2(&c4), + D0: FromE2(&d0), + D3: FromE2(&d3), + D4: FromE2(&d4), + C: FromE12(&c), + } err := test.IsSolved(&e12MulBy034by034{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) @@ -167,9 +172,10 @@ func TestSquareFp12(t *testing.T) { _, _ = a.SetRandom() c.Square(&a) - var witness e12Square - witness.A.assign(&a) - witness.C.assign(&c) + witness := e12Square{ + A: FromE12(&a), + C: FromE12(&c), + } err := test.IsSolved(&e12Square{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) @@ -207,9 +213,10 @@ func TestFp12CyclotomicSquare(t *testing.T) { a.FrobeniusSquare(&tmp).Mul(&a, &tmp) c.CyclotomicSquare(&a) - var witness e12Conjugate - witness.A.assign(&a) - witness.C.assign(&c) + witness := e12CycloSquare{ + A: FromE12(&a), + C: FromE12(&c), + } err := test.IsSolved(&e12CycloSquare{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) @@ -237,9 +244,10 @@ func TestConjugateFp12(t *testing.T) { _, _ = a.SetRandom() c.Conjugate(&a) - var witness e12Conjugate - witness.A.assign(&a) - witness.C.assign(&c) + witness := e12Conjugate{ + A: FromE12(&a), + C: FromE12(&c), + } err := test.IsSolved(&e12Conjugate{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) @@ -268,9 +276,10 @@ func TestInverseFp12(t *testing.T) { _, _ = a.SetRandom() c.Inverse(&a) - var witness e12Inverse - witness.A.assign(&a) - witness.C.assign(&c) + witness := e12Inverse{ + A: FromE12(&a), + C: FromE12(&c), + } err := test.IsSolved(&e12Inverse{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) @@ -307,9 +316,10 @@ func TestFp12Expt(t *testing.T) { c.Expt(&a) - var witness e12Expt - witness.A.assign(&a) - witness.C.assign(&c) + witness := e12Expt{ + A: FromE12(&a), + C: FromE12(&c), + } err := test.IsSolved(&e12Expt{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) diff --git a/std/algebra/emulated/fields_bn254/e2.go b/std/algebra/emulated/fields_bn254/e2.go index 0e81265933..63fdc6f78c 100644 --- a/std/algebra/emulated/fields_bn254/e2.go +++ b/std/algebra/emulated/fields_bn254/e2.go @@ -312,7 +312,10 @@ func (e Ext2) AssertIsEqual(x, y *E2) { e.fp.AssertIsEqual(&x.A1, &y.A1) } -func (x *E2) assign(y *bn254.E2) { - x.A0 = emulated.ValueOf[emulated.BN254Fp](y.A0) - x.A1 = emulated.ValueOf[emulated.BN254Fp](y.A1) +func FromE2(y *bn254.E2) E2 { + return E2{ + A0: emulated.ValueOf[emulated.BN254Fp](y.A0), + A1: emulated.ValueOf[emulated.BN254Fp](y.A1), + } + } diff --git a/std/algebra/emulated/fields_bn254/e2_test.go b/std/algebra/emulated/fields_bn254/e2_test.go index dcba17ff5c..99b2db5aa1 100644 --- a/std/algebra/emulated/fields_bn254/e2_test.go +++ b/std/algebra/emulated/fields_bn254/e2_test.go @@ -32,10 +32,11 @@ func TestAddFp2(t *testing.T) { _, _ = b.SetRandom() c.Add(&a, &b) - var witness e2Add - witness.A.assign(&a) - witness.B.assign(&b) - witness.C.assign(&c) + witness := e2Add{ + A: FromE2(&a), + B: FromE2(&b), + C: FromE2(&c), + } err := test.IsSolved(&e2Add{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) @@ -63,10 +64,11 @@ func TestSubFp2(t *testing.T) { _, _ = b.SetRandom() c.Sub(&a, &b) - var witness e2Sub - witness.A.assign(&a) - witness.B.assign(&b) - witness.C.assign(&c) + witness := e2Sub{ + A: FromE2(&a), + B: FromE2(&b), + C: FromE2(&c), + } err := test.IsSolved(&e2Sub{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) @@ -94,9 +96,10 @@ func TestDoubleFp2(t *testing.T) { _, _ = b.SetRandom() c.Double(&a) - var witness e2Double - witness.A.assign(&a) - witness.C.assign(&c) + witness := e2Double{ + A: FromE2(&a), + C: FromE2(&c), + } err := test.IsSolved(&e2Double{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) @@ -125,9 +128,10 @@ func TestHalveFp2(t *testing.T) { c = a c.Halve() - var witness e2Halve - witness.A.assign(&a) - witness.C.assign(&c) + witness := e2Halve{ + A: FromE2(&a), + C: FromE2(&c), + } err := test.IsSolved(&e2Halve{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) @@ -156,10 +160,11 @@ func TestMulFp2(t *testing.T) { _, _ = b.SetRandom() c.Mul(&a, &b) - var witness e2Mul - witness.A.assign(&a) - witness.B.assign(&b) - witness.C.assign(&c) + witness := e2Mul{ + A: FromE2(&a), + B: FromE2(&b), + C: FromE2(&c), + } err := test.IsSolved(&e2Mul{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) @@ -187,9 +192,10 @@ func TestSquareFp2(t *testing.T) { _, _ = a.SetRandom() c.Square(&a) - var witness e2Square - witness.A.assign(&a) - witness.C.assign(&c) + witness := e2Square{ + A: FromE2(&a), + C: FromE2(&c), + } err := test.IsSolved(&e2Square{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) @@ -221,10 +227,11 @@ func TestMulByElement(t *testing.T) { _, _ = b.SetRandom() c.MulByElement(&a, &b) - var witness e2MulByElement - witness.A.assign(&a) - witness.B = emulated.ValueOf[emulated.BN254Fp](b) - witness.C.assign(&c) + witness := e2MulByElement{ + A: FromE2(&a), + B: emulated.ValueOf[emulated.BN254Fp](b), + C: FromE2(&c), + } err := test.IsSolved(&e2MulByElement{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) @@ -253,9 +260,10 @@ func TestMulFp2BybTwistCurveCoeff(t *testing.T) { _, _ = a.SetRandom() c.MulBybTwistCurveCoeff(&a) - var witness e2MulBybTwistCurveCoeff - witness.A.assign(&a) - witness.C.assign(&c) + witness := e2MulBybTwistCurveCoeff{ + A: FromE2(&a), + C: FromE2(&c), + } err := test.IsSolved(&e2MulBybTwistCurveCoeff{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) @@ -284,9 +292,10 @@ func TestMulFp2ByNonResidue(t *testing.T) { _, _ = a.SetRandom() c.MulByNonResidue(&a) - var witness e2MulByNonResidue - witness.A.assign(&a) - witness.C.assign(&c) + witness := e2MulByNonResidue{ + A: FromE2(&a), + C: FromE2(&c), + } err := test.IsSolved(&e2MulByNonResidue{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) @@ -315,9 +324,10 @@ func TestMulFp2ByNonResidueInv(t *testing.T) { _, _ = a.SetRandom() c.MulByNonResidueInv(&a) - var witness e2MulByNonResidueInv - witness.A.assign(&a) - witness.C.assign(&c) + witness := e2MulByNonResidueInv{ + A: FromE2(&a), + C: FromE2(&c), + } err := test.IsSolved(&e2MulByNonResidueInv{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) @@ -346,9 +356,10 @@ func TestNegFp2(t *testing.T) { _, _ = a.SetRandom() c.Neg(&a) - var witness e2Neg - witness.A.assign(&a) - witness.C.assign(&c) + witness := e2Neg{ + A: FromE2(&a), + C: FromE2(&c), + } err := test.IsSolved(&e2Neg{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) @@ -376,9 +387,10 @@ func TestConjugateFp2(t *testing.T) { _, _ = a.SetRandom() c.Conjugate(&a) - var witness e2Conjugate - witness.A.assign(&a) - witness.C.assign(&c) + witness := e2Conjugate{ + A: FromE2(&a), + C: FromE2(&c), + } err := test.IsSolved(&e2Conjugate{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) @@ -407,9 +419,10 @@ func TestInverseFp2(t *testing.T) { _, _ = a.SetRandom() c.Inverse(&a) - var witness e2Inverse - witness.A.assign(&a) - witness.C.assign(&c) + witness := e2Inverse{ + A: FromE2(&a), + C: FromE2(&c), + } err := test.IsSolved(&e2Inverse{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) diff --git a/std/algebra/emulated/fields_bn254/e6.go b/std/algebra/emulated/fields_bn254/e6.go index ead7d8278f..9120a33f18 100644 --- a/std/algebra/emulated/fields_bn254/e6.go +++ b/std/algebra/emulated/fields_bn254/e6.go @@ -204,8 +204,11 @@ func (e Ext6) AssertIsEqual(x, y *E6) { e.Ext2.AssertIsEqual(&x.B2, &y.B2) } -func (x *E6) assign(y *bn254.E6) { - x.B0.assign(&y.B0) - x.B1.assign(&y.B1) - x.B2.assign(&y.B2) +func FromE6(y *bn254.E6) E6 { + return E6{ + B0: FromE2(&y.B0), + B1: FromE2(&y.B1), + B2: FromE2(&y.B2), + } + } diff --git a/std/algebra/emulated/fields_bn254/e6_test.go b/std/algebra/emulated/fields_bn254/e6_test.go index 5f6aebd0d9..f37c6ba24d 100644 --- a/std/algebra/emulated/fields_bn254/e6_test.go +++ b/std/algebra/emulated/fields_bn254/e6_test.go @@ -31,10 +31,11 @@ func TestAddFp6(t *testing.T) { _, _ = b.SetRandom() c.Add(&a, &b) - var witness e6Add - witness.A.assign(&a) - witness.B.assign(&b) - witness.C.assign(&c) + witness := e6Add{ + A: FromE6(&a), + B: FromE6(&b), + C: FromE6(&c), + } err := test.IsSolved(&e6Add{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) @@ -62,10 +63,11 @@ func TestSubFp6(t *testing.T) { _, _ = b.SetRandom() c.Sub(&a, &b) - var witness e6Sub - witness.A.assign(&a) - witness.B.assign(&b) - witness.C.assign(&c) + witness := e6Sub{ + A: FromE6(&a), + B: FromE6(&b), + C: FromE6(&c), + } err := test.IsSolved(&e6Sub{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) @@ -94,10 +96,11 @@ func TestMulFp6(t *testing.T) { _, _ = b.SetRandom() c.Mul(&a, &b) - var witness e6Mul - witness.A.assign(&a) - witness.B.assign(&b) - witness.C.assign(&c) + witness := e6Mul{ + A: FromE6(&a), + B: FromE6(&b), + C: FromE6(&c), + } err := test.IsSolved(&e6Mul{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) @@ -125,9 +128,10 @@ func TestSquareFp6(t *testing.T) { _, _ = a.SetRandom() c.Square(&a) - var witness e6Square - witness.A.assign(&a) - witness.C.assign(&c) + witness := e6Square{ + A: FromE6(&a), + C: FromE6(&c), + } err := test.IsSolved(&e6Square{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) @@ -156,9 +160,10 @@ func TestMulFp6ByNonResidue(t *testing.T) { _, _ = a.SetRandom() c.MulByNonResidue(&a) - var witness e6MulByNonResidue - witness.A.assign(&a) - witness.C.assign(&c) + witness := e6MulByNonResidue{ + A: FromE6(&a), + C: FromE6(&c), + } err := test.IsSolved(&e6MulByNonResidue{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) @@ -190,10 +195,11 @@ func TestMulFp6ByE2(t *testing.T) { _, _ = b.SetRandom() c.MulByE2(&a, &b) - var witness e6MulByE2 - witness.A.assign(&a) - witness.B.assign(&b) - witness.C.assign(&c) + witness := e6MulByE2{ + A: FromE6(&a), + B: FromE2(&b), + C: FromE6(&c), + } err := test.IsSolved(&e6MulByE2{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) @@ -227,11 +233,12 @@ func TestMulFp6By01(t *testing.T) { c.Set(&a) c.MulBy01(&C0, &C1) - var witness e6MulBy01 - witness.A.assign(&a) - witness.C0.assign(&C0) - witness.C1.assign(&C1) - witness.C.assign(&c) + witness := e6MulBy01{ + A: FromE6(&a), + C0: FromE2(&C0), + C1: FromE2(&C1), + C: FromE6(&c), + } err := test.IsSolved(&e6MulBy01{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) @@ -260,9 +267,10 @@ func TestNegFp6(t *testing.T) { _, _ = a.SetRandom() c.Neg(&a) - var witness e6Neg - witness.A.assign(&a) - witness.C.assign(&c) + witness := e6Neg{ + A: FromE6(&a), + C: FromE6(&c), + } err := test.IsSolved(&e6Neg{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) @@ -291,9 +299,10 @@ func TestInverseFp6(t *testing.T) { _, _ = a.SetRandom() c.Inverse(&a) - var witness e6Inverse - witness.A.assign(&a) - witness.C.assign(&c) + witness := e6Inverse{ + A: FromE6(&a), + C: FromE6(&c), + } err := test.IsSolved(&e6Inverse{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) From fd864f73904a918b746765e2598b42d4a649ab6f Mon Sep 17 00:00:00 2001 From: Hisham Galal <0xhgalal@gmail.com> Date: Wed, 8 Mar 2023 11:03:50 -0500 Subject: [PATCH 075/464] parallelize coefficients multiplication --- backend/groth16/setup/utils/lagrange.go | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/backend/groth16/setup/utils/lagrange.go b/backend/groth16/setup/utils/lagrange.go index 6fa1f657b8..a44f612aeb 100644 --- a/backend/groth16/setup/utils/lagrange.go +++ b/backend/groth16/setup/utils/lagrange.go @@ -9,6 +9,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" + "github.com/consensys/gnark/internal/utils" ) func butterflyG1(a *bn254.G1Affine, b *bn254.G1Affine) { @@ -193,10 +194,11 @@ func LagrangeCoeffsG1(powers []bn254.G1Affine, size int) []bn254.G1Affine { var invBigint big.Int domain.CardinalityInv.BigInt(&invBigint) - for i := 0; i < size; i++ { - coeffs[i].ScalarMultiplication(&coeffs[i], &invBigint) - } - + utils.Parallelize(size, func(start, end int) { + for i := start; i < end; i++ { + coeffs[i].ScalarMultiplication(&coeffs[i], &invBigint) + } + }) return coeffs } @@ -213,9 +215,10 @@ func LagrangeCoeffsG2(powers []bn254.G2Affine, size int) []bn254.G2Affine { var invBigint big.Int domain.CardinalityInv.BigInt(&invBigint) - for i := 0; i < size; i++ { - coeffs[i].ScalarMultiplication(&coeffs[i], &invBigint) - } - + utils.Parallelize(size, func(start, end int) { + for i := start; i < end; i++ { + coeffs[i].ScalarMultiplication(&coeffs[i], &invBigint) + } + }) return coeffs } From 0196057df738befc0b605d2cc248985bf0af1ae1 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 8 Mar 2023 13:31:15 -0500 Subject: [PATCH 076/464] refactor: take api.Commit to api.go --- constraint/commitment.go | 4 ++-- frontend/cs/scs/api.go | 29 ++++++++++++++++++++++++++- frontend/cs/scs/builder.go | 16 --------------- internal/backend/bn254/plonk/prove.go | 15 ++++++++------ internal/backend/bn254/plonk/setup.go | 2 +- 5 files changed, 40 insertions(+), 26 deletions(-) diff --git a/constraint/commitment.go b/constraint/commitment.go index bc6a0e8d0a..4a1189a540 100644 --- a/constraint/commitment.go +++ b/constraint/commitment.go @@ -12,8 +12,8 @@ type Commitment struct { Committed []int // sorted list of id's of committed variables NbPrivateCommitted int HintID hint.ID // TODO @gbotrel we probably don't need that here - CommitmentIndex int - CommittedAndCommitment []int // sorted list of id's of committed variables AND the commitment itself + CommitmentIndex int // in groth16, CommitmentIndex is the wire index. in plonk, it's the constraint defining it + CommittedAndCommitment []int // sorted list of id's of committed variables AND the commitment itself } func (i *Commitment) NbPublicCommitted() int { diff --git a/frontend/cs/scs/api.go b/frontend/cs/scs/api.go index 945c746a6d..763265c9b6 100644 --- a/frontend/cs/scs/api.go +++ b/frontend/cs/scs/api.go @@ -17,6 +17,7 @@ limitations under the License. package scs import ( + "errors" "fmt" "math/big" "path/filepath" @@ -178,7 +179,7 @@ func (builder *scs) Inverse(i1 frontend.Variable) frontend.Variable { // n is the number of bits to select (starting from lsb) // n default value is fr.Bits the number of bits needed to represent a field element // -// The result in in little endian (first bit= lsb) +// The result is in little endian (first bit= lsb) func (builder *scs) ToBinary(i1 frontend.Variable, n ...int) []frontend.Variable { // nbBits nbBits := builder.cs.FieldBitLen() @@ -499,3 +500,29 @@ func (builder *scs) printArg(log *constraint.LogEntry, sbb *strings.Builder, a f func (builder *scs) Compiler() frontend.Compiler { return builder } + +func scsBsb22CommitmentHintPlaceholder(*big.Int, []*big.Int, []*big.Int) error { + return errors.New("placeholder - should never be called") +} + +func (builder *scs) Commit(v ...frontend.Variable) (frontend.Variable, error) { + // NOT THREAD SAFE. It is important for these to be consecutive + for _, vI := range v { // TODO: Perf; If public, just hash it + builder.AssertIsEqual(vI, 0) // We need a constraint per committed value. Will be changed between solving and proof time + // Hacky and dangerous: assumes that trivial constraints will not be optimized away + } + outs, err := builder.NewHint(scsBsb22CommitmentHintPlaceholder, 1, v...) + if err != nil { + return nil, err + } + commitmentVar := outs[0] + + commitmentConstraintIndex := builder.cs.GetNbConstraints() + builder.AssertIsEqual(commitmentVar, 0) // value will be injected later + + return outs[0], builder.cs.AddCommitment(constraint.Commitment{ + HintID: hint.UUID(scsBsb22CommitmentHintPlaceholder), + CommitmentIndex: commitmentConstraintIndex, + Committed: make([]int, len(v)), // only recording the number of committed variables. TODO: Something less revolting + }) +} diff --git a/frontend/cs/scs/builder.go b/frontend/cs/scs/builder.go index 92f7878d64..194747efb7 100644 --- a/frontend/cs/scs/builder.go +++ b/frontend/cs/scs/builder.go @@ -17,7 +17,6 @@ limitations under the License. package scs import ( - "errors" "math/big" "reflect" "sort" @@ -362,21 +361,6 @@ func (builder *scs) splitProd(acc expr.TermToRefactor, r expr.LinearExpressionTo return builder.splitProd(o, r[1:]) } -func scsBsb22CommitmentHintPlaceholder(*big.Int, []*big.Int, []*big.Int) error { - return errors.New("placeholder - should never be called") -} - -func (builder *scs) Commit(v ...frontend.Variable) (frontend.Variable, error) { - for i, vI := range v { // Perf-TODO: If public, hash it - builder.addPlonkConstraint(vI.(expr.TermToRefactor), builder.zero(), builder.zero(), constraint.CoeffIdOne, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, i) - } - outs, err := builder.NewHint(scsBsb22CommitmentHintPlaceholder, 1, v...) - if err != nil { - return nil, err - } - return outs[0], builder.cs.AddCommitment(constraint.Commitment{HintID: hint.UUID(scsBsb22CommitmentHintPlaceholder)}) -} - // newDebugInfo this is temporary to restore debug logs // something more like builder.sprintf("my message %le %lv", l0, l1) // to build logs for both debug and println diff --git a/internal/backend/bn254/plonk/prove.go b/internal/backend/bn254/plonk/prove.go index 04e961ed04..484eac2936 100644 --- a/internal/backend/bn254/plonk/prove.go +++ b/internal/backend/bn254/plonk/prove.go @@ -78,11 +78,10 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen if id := spr.CommitmentInfo.HintID; id != 0 { opt.HintFunctions[id] = func(_ *big.Int, ins, outs []*big.Int) error { - pi2 = make(fr.Vector, len(spr.Constraints)) //TODO: Correct? Or fft.DomainSize etc? - for i, cI := range spr.Constraints { - if cI.C != -1 { - pi2[i].SetBigInt(ins[cI.C]) - } + pi2 = make(fr.Vector, pk.Domain[0].Cardinality) + committedConstraintOffset := spr.CommitmentInfo.CommitmentIndex - len(spr.CommitmentInfo.Committed) + for i := range ins { + pi2[i+committedConstraintOffset].SetBigInt(ins[i]) } var ( err error @@ -91,11 +90,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness fr.Vector, opt backen if proof.PI2, err = kzg.Commit(pi2, pk.Vk.KZGSRS); err != nil { return err } - if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } + commitmentConstIndex := len(spr.Coefficients) + spr.Coefficients = append(spr.Coefficients, fr.Element{}) + spr.Coefficients[commitmentConstIndex].Neg(&hashRes[0]) + spr.Constraints[spr.CommitmentInfo.CommitmentIndex].K = commitmentConstIndex + hashRes[0].BigInt(outs[0]) return nil } diff --git a/internal/backend/bn254/plonk/setup.go b/internal/backend/bn254/plonk/setup.go index 43b6754c24..929a44a8a2 100644 --- a/internal/backend/bn254/plonk/setup.go +++ b/internal/backend/bn254/plonk/setup.go @@ -383,7 +383,7 @@ func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { // This should be used after deserializing a VerifyingKey // as vk.KZG is NOT serialized // -// Note that this instantiate a new FFT domain using vk.Size +// Note that this instantiates a new FFT domain using vk.Size func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { _srs := srs.(*kzg.SRS) From 6fe12347ab73d9ebb7fde293c1a9344c78347af3 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 8 Mar 2023 14:11:36 -0500 Subject: [PATCH 077/464] refactor: SparceCS.CommitmentConstraint instead of C; more "honest" constraints --- constraint/r1cs_sparse.go | 18 +++++++++++----- frontend/cs/scs/api.go | 36 ++++++++++++++++++------------- frontend/cs/scs/api_assertions.go | 29 +++++-------------------- frontend/cs/scs/builder.go | 8 +++---- 4 files changed, 43 insertions(+), 48 deletions(-) diff --git a/constraint/r1cs_sparse.go b/constraint/r1cs_sparse.go index c65485cc03..8aab2f72c0 100644 --- a/constraint/r1cs_sparse.go +++ b/constraint/r1cs_sparse.go @@ -129,14 +129,22 @@ func (system *SparseR1CSCore) CheckUnconstrainedWires() error { return errors.New(sbb.String()) } +type CommitmentConstraint byte + +const ( + NOT CommitmentConstraint = 0 + COMMITTED CommitmentConstraint = 1 + COMMITMENT CommitmentConstraint = 2 +) + // SparseR1C used to compute the wires -// L+R+M[0]M[1]+O+k=0 +// L+R+M[0]M[1]+O+k-committed?*PI2-commitment?*commitmentValue=0 // if a Term is zero, it means the field doesn't exist (ex M=[0,0] means there is no multiplicative term) type SparseR1C struct { - L, R, O Term - M [2]Term - K int // stores only the ID of the constant term that is used - C int // index among commitment constraints. -1 if not a commitment. + L, R, O Term + M [2]Term + K int // stores only the ID of the constant term that is used + Commitment CommitmentConstraint } // WireIterator implements constraint.Iterable diff --git a/frontend/cs/scs/api.go b/frontend/cs/scs/api.go index 763265c9b6..fd420fa2ac 100644 --- a/frontend/cs/scs/api.go +++ b/frontend/cs/scs/api.go @@ -48,7 +48,7 @@ func (builder *scs) Add(i1, i2 frontend.Variable, in ...frontend.Variable) front cl, _ := vars[0].Unpack() kID := builder.st.CoeffID(&k) o := builder.newInternalVariable() - builder.addPlonkConstraint(vars[0], builder.zero(), o, cl, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdMinusOne, kID, -1) + builder.addPlonkConstraint(vars[0], builder.zero(), o, cl, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdMinusOne, kID) return builder.splitSum(o, vars[1:]) } @@ -145,7 +145,7 @@ func (builder *scs) DivUnchecked(i1, i2 frontend.Variable) frontend.Variable { o := builder.Neg(i1).(expr.TermToRefactor) cr, _ := r.Unpack() co, _ := o.Unpack() - builder.addPlonkConstraint(res, r, o, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdOne, cr, co, constraint.CoeffIdZero, -1) + builder.addPlonkConstraint(res, r, o, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdOne, cr, co, constraint.CoeffIdZero) return res } @@ -168,7 +168,7 @@ func (builder *scs) Inverse(i1 frontend.Variable) frontend.Variable { cr, _ := t.Unpack() debug := builder.newDebugInfo("inverse", "1/", i1, " < ∞") res := builder.newInternalVariable() - builder.addPlonkConstraint(res, t, builder.zero(), constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdOne, cr, constraint.CoeffIdZero, constraint.CoeffIdMinusOne, -1, debug) + builder.addPlonkConstraint(res, t, builder.zero(), constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdOne, cr, constraint.CoeffIdZero, constraint.CoeffIdMinusOne, debug) return res } @@ -224,12 +224,12 @@ func (builder *scs) Xor(a, b frontend.Variable) frontend.Variable { r := l oneMinusTwoB := big.NewInt(1) oneMinusTwoB.Sub(oneMinusTwoB, _b).Sub(oneMinusTwoB, _b) - builder.addPlonkConstraint(l, r, res, builder.st.CoeffID(oneMinusTwoB), constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdMinusOne, builder.st.CoeffID(_b), -1) + builder.addPlonkConstraint(l, r, res, builder.st.CoeffID(oneMinusTwoB), constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdMinusOne, builder.st.CoeffID(_b)) return res } l := a.(expr.TermToRefactor) r := b.(expr.TermToRefactor) - builder.addPlonkConstraint(l, r, res, constraint.CoeffIdMinusOne, constraint.CoeffIdMinusOne, constraint.CoeffIdTwo, constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdZero, -1) + builder.addPlonkConstraint(l, r, res, constraint.CoeffIdMinusOne, constraint.CoeffIdMinusOne, constraint.CoeffIdTwo, constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdZero) return res } @@ -261,12 +261,12 @@ func (builder *scs) Or(a, b frontend.Variable) frontend.Variable { one := big.NewInt(1) _b.Sub(_b, one) idl := builder.st.CoeffID(_b) - builder.addPlonkConstraint(l, r, res, idl, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdOne, constraint.CoeffIdZero, -1) + builder.addPlonkConstraint(l, r, res, idl, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdOne, constraint.CoeffIdZero) return res } l := a.(expr.TermToRefactor) r := b.(expr.TermToRefactor) - builder.addPlonkConstraint(l, r, res, constraint.CoeffIdMinusOne, constraint.CoeffIdMinusOne, constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdZero, -1) + builder.addPlonkConstraint(l, r, res, constraint.CoeffIdMinusOne, constraint.CoeffIdMinusOne, constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdZero) return res } @@ -393,10 +393,10 @@ func (builder *scs) IsZero(i1 frontend.Variable) frontend.Variable { constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdMinusOne, - -1) + ) // a * m = 0 // constrain m to be 0 if a != 0 - builder.addPlonkConstraint(a, m, builder.zero(), constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdZero, constraint.CoeffIdZero, -1) + builder.addPlonkConstraint(a, m, builder.zero(), constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdZero, constraint.CoeffIdZero) return m } @@ -506,10 +506,16 @@ func scsBsb22CommitmentHintPlaceholder(*big.Int, []*big.Int, []*big.Int) error { } func (builder *scs) Commit(v ...frontend.Variable) (frontend.Variable, error) { - // NOT THREAD SAFE. It is important for these to be consecutive - for _, vI := range v { // TODO: Perf; If public, just hash it - builder.AssertIsEqual(vI, 0) // We need a constraint per committed value. Will be changed between solving and proof time - // Hacky and dangerous: assumes that trivial constraints will not be optimized away + + committed := make([]int, len(v)) + // NOT THREAD SAFE. Recording constraint indexes + for i, vI := range v { // TODO: Perf; If public, just hash it + vIExpr := vI.(constraint.LinearExpression) + if len(vIExpr) != 1 { + return nil, errors.New("can only commit to single terms") // TODO: Create a wire in this case + } + committed[i] = builder.cs.GetNbConstraints() + builder.cs.AddConstraint(constraint.SparseR1C{L: vIExpr[0], Commitment: constraint.COMMITTED}) } outs, err := builder.NewHint(scsBsb22CommitmentHintPlaceholder, 1, v...) if err != nil { @@ -518,11 +524,11 @@ func (builder *scs) Commit(v ...frontend.Variable) (frontend.Variable, error) { commitmentVar := outs[0] commitmentConstraintIndex := builder.cs.GetNbConstraints() - builder.AssertIsEqual(commitmentVar, 0) // value will be injected later + builder.cs.AddConstraint(constraint.SparseR1C{L: commitmentVar.(constraint.LinearExpression)[0], Commitment: constraint.COMMITMENT}) // value will be injected later return outs[0], builder.cs.AddCommitment(constraint.Commitment{ HintID: hint.UUID(scsBsb22CommitmentHintPlaceholder), CommitmentIndex: commitmentConstraintIndex, - Committed: make([]int, len(v)), // only recording the number of committed variables. TODO: Something less revolting + Committed: committed, }) } diff --git a/frontend/cs/scs/api_assertions.go b/frontend/cs/scs/api_assertions.go index 381d5bafb5..72e315ec6e 100644 --- a/frontend/cs/scs/api_assertions.go +++ b/frontend/cs/scs/api_assertions.go @@ -51,7 +51,7 @@ func (builder *scs) AssertIsEqual(i1, i2 frontend.Variable) { debug := builder.newDebugInfo("assertIsEqual", l, "+", i2, " == 0") k.Neg(k) _k := builder.st.CoeffID(k) - builder.addPlonkConstraint(l, builder.zero(), builder.zero(), lc, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, _k, -1, debug) + builder.addPlonkConstraint(l, builder.zero(), builder.zero(), lc, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, _k, debug) return } l := i1.(expr.TermToRefactor) @@ -60,7 +60,7 @@ func (builder *scs) AssertIsEqual(i1, i2 frontend.Variable) { rc, _ := r.Unpack() debug := builder.newDebugInfo("assertIsEqual", l, " + ", r, " == 0") - builder.addPlonkConstraint(l, r, builder.zero(), lc, rc, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, -1, debug) + builder.addPlonkConstraint(l, r, builder.zero(), lc, rc, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdZero, debug) } // AssertIsDifferent fails if i1 == i2 @@ -87,7 +87,7 @@ func (builder *scs) AssertIsBoolean(i1 frontend.Variable) { var mCoef big.Int mCoef.Neg(&builder.st.Coeffs[cID]) mcID := builder.st.CoeffID(&mCoef) - builder.addPlonkConstraint(t, t, builder.zero(), cID, constraint.CoeffIdZero, mcID, cID, constraint.CoeffIdZero, constraint.CoeffIdZero, -1, debug) + builder.addPlonkConstraint(t, t, builder.zero(), cID, constraint.CoeffIdZero, mcID, cID, constraint.CoeffIdZero, constraint.CoeffIdZero, debug) } // AssertIsLessOrEqual fails if v > bound @@ -133,16 +133,7 @@ func (builder *scs) mustBeLessOrEqVar(a expr.TermToRefactor, bound expr.TermToRe // if bound[i] == 0, t must be 0 or 1, thus ai must be 0 or 1 too builder.MarkBoolean(aBits[i].(expr.TermToRefactor)) // this does not create a constraint - builder.addPlonkConstraint( - l.(expr.TermToRefactor), - aBits[i].(expr.TermToRefactor), - builder.zero(), - constraint.CoeffIdZero, - constraint.CoeffIdZero, - constraint.CoeffIdOne, - constraint.CoeffIdOne, - constraint.CoeffIdZero, - constraint.CoeffIdZero, -1, debug) + builder.addPlonkConstraint(l.(expr.TermToRefactor), aBits[i].(expr.TermToRefactor), builder.zero(), constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdZero, constraint.CoeffIdZero, debug) } } @@ -194,17 +185,7 @@ func (builder *scs) mustBeLessOrEqCst(a expr.TermToRefactor, bound big.Int) { l := builder.Sub(1, p[i+1], aBits[i]).(expr.TermToRefactor) //l = builder.Sub(l, ).(term) - builder.addPlonkConstraint( - l, - aBits[i].(expr.TermToRefactor), - builder.zero(), - constraint.CoeffIdZero, - constraint.CoeffIdZero, - constraint.CoeffIdOne, - constraint.CoeffIdOne, - constraint.CoeffIdZero, - constraint.CoeffIdZero, - -1, debug) + builder.addPlonkConstraint(l, aBits[i].(expr.TermToRefactor), builder.zero(), constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdZero, constraint.CoeffIdZero, debug) // builder.markBoolean(aBits[i].(term)) } else { builder.AssertIsBoolean(aBits[i]) diff --git a/frontend/cs/scs/builder.go b/frontend/cs/scs/builder.go index 194747efb7..6c7d7d2d26 100644 --- a/frontend/cs/scs/builder.go +++ b/frontend/cs/scs/builder.go @@ -115,7 +115,7 @@ func (builder *scs) FieldBitLen() int { // addPlonkConstraint creates a constraint of the for al+br+clr+k=0 // qL⋅xa + qR⋅xb + qO⋅xc + qM⋅(xaxb) + qC == 0 -func (builder *scs) addPlonkConstraint(xa, xb, xc expr.TermToRefactor, qL, qR, qM1, qM2, qO, qC int, cIndex int, debug ...constraint.DebugInfo) { +func (builder *scs) addPlonkConstraint(xa, xb, xc expr.TermToRefactor, qL, qR, qM1, qM2, qO, qC int, debug ...constraint.DebugInfo) { // TODO @gbotrel the signature of this function is odd.. and confusing. need refactor. // TODO @gbotrel restore debug info // if len(debugID) > 0 { @@ -139,7 +139,7 @@ func (builder *scs) addPlonkConstraint(xa, xb, xc expr.TermToRefactor, qL, qR, q V := builder.TOREFACTORMakeTerm(&builder.st.Coeffs[v.CID], v.VID) K := builder.TOREFACTORMakeTerm(&builder.st.Coeffs[qC], 0) K.MarkConstant() - builder.cs.AddConstraint(constraint.SparseR1C{L: L, R: R, O: O, M: [2]constraint.Term{U, V}, K: K.CoeffID(), C: cIndex}, debug...) + builder.cs.AddConstraint(constraint.SparseR1C{L: L, R: R, O: O, M: [2]constraint.Term{U, V}, K: K.CoeffID()}, debug...) } // newInternalVariable creates a new wire, appends it on the list of wires of the circuit, sets @@ -343,7 +343,7 @@ func (builder *scs) splitSum(acc expr.TermToRefactor, r expr.LinearExpressionToR cl, _ := acc.Unpack() cr, _ := r[0].Unpack() o := builder.newInternalVariable() - builder.addPlonkConstraint(acc, r[0], o, cl, cr, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdMinusOne, constraint.CoeffIdZero, -1) + builder.addPlonkConstraint(acc, r[0], o, cl, cr, constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdMinusOne, constraint.CoeffIdZero) return builder.splitSum(o, r[1:]) } @@ -357,7 +357,7 @@ func (builder *scs) splitProd(acc expr.TermToRefactor, r expr.LinearExpressionTo cl, _ := acc.Unpack() cr, _ := r[0].Unpack() o := builder.newInternalVariable() - builder.addPlonkConstraint(acc, r[0], o, constraint.CoeffIdZero, constraint.CoeffIdZero, cl, cr, constraint.CoeffIdMinusOne, constraint.CoeffIdZero, -1) + builder.addPlonkConstraint(acc, r[0], o, constraint.CoeffIdZero, constraint.CoeffIdZero, cl, cr, constraint.CoeffIdMinusOne, constraint.CoeffIdZero) return builder.splitProd(o, r[1:]) } From 6987aa83bffe527433350b4c59fae9756e7d5cad Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 8 Mar 2023 14:18:17 -0500 Subject: [PATCH 078/464] revert: unnecessary stylistic changes --- frontend/cs/scs/api.go | 3 +-- frontend/cs/scs/api_assertions.go | 24 +++++++++++++++++++++--- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/frontend/cs/scs/api.go b/frontend/cs/scs/api.go index fd420fa2ac..503ec09d03 100644 --- a/frontend/cs/scs/api.go +++ b/frontend/cs/scs/api.go @@ -392,8 +392,7 @@ func (builder *scs) IsZero(i1 frontend.Variable) frontend.Variable { constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdOne, - constraint.CoeffIdMinusOne, - ) + constraint.CoeffIdMinusOne) // a * m = 0 // constrain m to be 0 if a != 0 builder.addPlonkConstraint(a, m, builder.zero(), constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdZero, constraint.CoeffIdZero) diff --git a/frontend/cs/scs/api_assertions.go b/frontend/cs/scs/api_assertions.go index 72e315ec6e..108de4dc06 100644 --- a/frontend/cs/scs/api_assertions.go +++ b/frontend/cs/scs/api_assertions.go @@ -133,7 +133,16 @@ func (builder *scs) mustBeLessOrEqVar(a expr.TermToRefactor, bound expr.TermToRe // if bound[i] == 0, t must be 0 or 1, thus ai must be 0 or 1 too builder.MarkBoolean(aBits[i].(expr.TermToRefactor)) // this does not create a constraint - builder.addPlonkConstraint(l.(expr.TermToRefactor), aBits[i].(expr.TermToRefactor), builder.zero(), constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdZero, constraint.CoeffIdZero, debug) + builder.addPlonkConstraint( + l.(expr.TermToRefactor), + aBits[i].(expr.TermToRefactor), + builder.zero(), + constraint.CoeffIdZero, + constraint.CoeffIdZero, + constraint.CoeffIdOne, + constraint.CoeffIdOne, + constraint.CoeffIdZero, + constraint.CoeffIdZero, debug) } } @@ -185,8 +194,17 @@ func (builder *scs) mustBeLessOrEqCst(a expr.TermToRefactor, bound big.Int) { l := builder.Sub(1, p[i+1], aBits[i]).(expr.TermToRefactor) //l = builder.Sub(l, ).(term) - builder.addPlonkConstraint(l, aBits[i].(expr.TermToRefactor), builder.zero(), constraint.CoeffIdZero, constraint.CoeffIdZero, constraint.CoeffIdOne, constraint.CoeffIdOne, constraint.CoeffIdZero, constraint.CoeffIdZero, debug) - // builder.markBoolean(aBits[i].(term)) + builder.addPlonkConstraint( + l, + aBits[i].(expr.TermToRefactor), + builder.zero(), + constraint.CoeffIdZero, + constraint.CoeffIdZero, + constraint.CoeffIdOne, + constraint.CoeffIdOne, + constraint.CoeffIdZero, + constraint.CoeffIdZero, + debug) // builder.markBoolean(aBits[i].(term)) } else { builder.AssertIsBoolean(aBits[i]) } From 571464e97b6905407a6da937812643c1c4ee1e74 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 8 Mar 2023 14:38:34 -0500 Subject: [PATCH 079/464] revert: unnecessary stylistic change --- frontend/cs/scs/api_assertions.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/cs/scs/api_assertions.go b/frontend/cs/scs/api_assertions.go index 108de4dc06..f30b177666 100644 --- a/frontend/cs/scs/api_assertions.go +++ b/frontend/cs/scs/api_assertions.go @@ -204,7 +204,8 @@ func (builder *scs) mustBeLessOrEqCst(a expr.TermToRefactor, bound big.Int) { constraint.CoeffIdOne, constraint.CoeffIdZero, constraint.CoeffIdZero, - debug) // builder.markBoolean(aBits[i].(term)) + debug) + // builder.markBoolean(aBits[i].(term)) } else { builder.AssertIsBoolean(aBits[i]) } From 299424d26f429b7d1030285fce7142610428f7b6 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 8 Mar 2023 15:28:39 -0500 Subject: [PATCH 080/464] refactor: solving and compilation in accordance with commitmentInfo struct changes --- constraint/bn254/r1cs_sparse.go | 4 ++++ frontend/cs/r1cs/api.go | 2 +- frontend/cs/scs/api.go | 11 ++++++----- internal/backend/bn254/plonk/prove.go | 21 +++++++++------------ internal/backend/bn254/plonk/setup.go | 9 ++++----- 5 files changed, 24 insertions(+), 23 deletions(-) diff --git a/constraint/bn254/r1cs_sparse.go b/constraint/bn254/r1cs_sparse.go index afc57fe459..1cc20bd816 100644 --- a/constraint/bn254/r1cs_sparse.go +++ b/constraint/bn254/r1cs_sparse.go @@ -358,6 +358,10 @@ func (cs *SparseR1CS) computeHints(c constraint.SparseR1C, solution *solution) ( // if it doesn't, then this function returns and does nothing func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution, coefficientsNegInv fr.Vector) error { + if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. + return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time + } + lro, err := cs.computeHints(c, solution) if err != nil { return err diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index 063ec9eebe..2a2a983e4b 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -738,7 +738,7 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error commitment.CommitmentIndex = (cVar.(expr.LinearExpression))[0].WireID() - // TODO @Tabaie: Get rid of this field + // TODO @Tabaie Get rid of this field commitment.CommittedAndCommitment = append(commitment.Committed, commitment.CommitmentIndex) if commitment.CommitmentIndex <= commitment.Committed[len(commitment.Committed)-1] { return nil, fmt.Errorf("commitment variable index smaller than some committed variable indices") diff --git a/frontend/cs/scs/api.go b/frontend/cs/scs/api.go index 86d441c7dc..76c941f87d 100644 --- a/frontend/cs/scs/api.go +++ b/frontend/cs/scs/api.go @@ -19,6 +19,7 @@ package scs import ( "errors" "fmt" + "math/big" "path/filepath" "reflect" "runtime" @@ -563,14 +564,14 @@ func scsBsb22CommitmentHintPlaceholder(*big.Int, []*big.Int, []*big.Int) error { return errors.New("placeholder - should never be called") } -func (builder *scs) Commit(v ...frontend.Variable) (frontend.Variable, error) { +func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error) { committed := make([]int, len(v)) - // NOT THREAD SAFE. Recording constraint indexes - for i, vI := range v { // TODO: Perf; If public, just hash it + + for i, vI := range v { // TODO @Tabaie Perf; If public, just hash it vIExpr := vI.(constraint.LinearExpression) if len(vIExpr) != 1 { - return nil, errors.New("can only commit to single terms") // TODO: Create a wire in this case + return nil, errors.New("can only commit to single terms") // TODO @Tabaie Create a wire in this case } committed[i] = builder.cs.GetNbConstraints() builder.cs.AddConstraint(constraint.SparseR1C{L: vIExpr[0], Commitment: constraint.COMMITTED}) @@ -585,7 +586,7 @@ func (builder *scs) Commit(v ...frontend.Variable) (frontend.Variable, error) { builder.cs.AddConstraint(constraint.SparseR1C{L: commitmentVar.(constraint.LinearExpression)[0], Commitment: constraint.COMMITMENT}) // value will be injected later return outs[0], builder.cs.AddCommitment(constraint.Commitment{ - HintID: hint.UUID(scsBsb22CommitmentHintPlaceholder), + HintID: solver.GetHintID(scsBsb22CommitmentHintPlaceholder), CommitmentIndex: commitmentConstraintIndex, Committed: committed, }) diff --git a/internal/backend/bn254/plonk/prove.go b/internal/backend/bn254/plonk/prove.go index 8a3394e339..3734df278e 100644 --- a/internal/backend/bn254/plonk/prove.go +++ b/internal/backend/bn254/plonk/prove.go @@ -18,6 +18,7 @@ package plonk import ( "crypto/sha256" + "github.com/consensys/gnark/constraint/solver" "math/big" "runtime" "sync" @@ -82,18 +83,19 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // result proof := &Proof{} var pi2 fr.Vector - - if id := spr.CommitmentInfo.HintID; id != 0 { - opt.HintFunctions[id] = func(_ *big.Int, ins, outs []*big.Int) error { + if spr.CommitmentInfo.Is() { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo.HintID, func(_ *big.Int, ins, outs []*big.Int) error { pi2 = make(fr.Vector, pk.Domain[0].Cardinality) - committedConstraintOffset := spr.CommitmentInfo.CommitmentIndex - len(spr.CommitmentInfo.Committed) for i := range ins { - pi2[i+committedConstraintOffset].SetBigInt(ins[i]) + pi2[spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) + if _, err = pi2[spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { + return err + } if proof.PI2, err = kzg.Commit(pi2, pk.Vk.KZGSRS); err != nil { return err } @@ -101,14 +103,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return err } - commitmentConstIndex := len(spr.Coefficients) - spr.Coefficients = append(spr.Coefficients, fr.Element{}) - spr.Coefficients[commitmentConstIndex].Neg(&hashRes[0]) - spr.Constraints[spr.CommitmentInfo.CommitmentIndex].K = commitmentConstIndex - hashRes[0].BigInt(outs[0]) return nil - } + })) } // query l, r, o in Lagrange basis, not blinded @@ -152,7 +149,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)]); err != nil { return nil, err } - gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) + gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) // TODO @Tabaie @ThomasPiellard add BSB commitment here? if err != nil { return nil, err } diff --git a/internal/backend/bn254/plonk/setup.go b/internal/backend/bn254/plonk/setup.go index 929a44a8a2..5e6f19e210 100644 --- a/internal/backend/bn254/plonk/setup.go +++ b/internal/backend/bn254/plonk/setup.go @@ -22,6 +22,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" "github.com/consensys/gnark-crypto/ecc/bn254/fr/iop" "github.com/consensys/gnark-crypto/ecc/bn254/fr/kzg" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bn254" kzgg "github.com/consensys/gnark-crypto/kzg" @@ -154,12 +155,10 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) pk.Qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) pk.CQk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) pk.LQk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) + } - if spr.Constraints[i].C == -1 { - pk.QcPrime[i].SetZero() - } else { - pk.QcPrime[i].SetInt64(-1) - } + for _, committed := range spr.CommitmentInfo.Committed { + pk.QcPrime[committed] = spr.Coefficients[constraint.CoeffIdMinusOne] } pk.Domain[0].FFTInverse(pk.Ql, fft.DIF) From 700bfa33714c723d23c657bd89c1f2f361df1863 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 8 Mar 2023 16:24:19 -0500 Subject: [PATCH 081/464] feat: commitment verification - plonk bn254 --- internal/backend/bn254/plonk/prove.go | 2 +- internal/backend/bn254/plonk/setup.go | 3 ++ internal/backend/bn254/plonk/verify.go | 68 ++++++++++++++++++-------- 3 files changed, 52 insertions(+), 21 deletions(-) diff --git a/internal/backend/bn254/plonk/prove.go b/internal/backend/bn254/plonk/prove.go index 3734df278e..31ac26b80e 100644 --- a/internal/backend/bn254/plonk/prove.go +++ b/internal/backend/bn254/plonk/prove.go @@ -57,7 +57,7 @@ type Proof struct { // PI2, the BSB22 commitment PI2 kzg.Digest - // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2 + // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2, qCPrime BatchedProof kzg.BatchOpeningProof // Opening proof of Z at zeta*mu diff --git a/internal/backend/bn254/plonk/setup.go b/internal/backend/bn254/plonk/setup.go index 5e6f19e210..3ba4eb6ea5 100644 --- a/internal/backend/bn254/plonk/setup.go +++ b/internal/backend/bn254/plonk/setup.go @@ -93,6 +93,8 @@ type VerifyingKey struct { // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. Ql, Qr, Qm, Qo, Qk, QcPrime kzg.Digest + + CommitmentInfo constraint.Commitment } // Setup sets proving and verifying keys @@ -102,6 +104,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // The verifying key shares data with the proving key pk.Vk = &vk + vk.CommitmentInfo = spr.CommitmentInfo nbConstraints := len(spr.Constraints) diff --git a/internal/backend/bn254/plonk/verify.go b/internal/backend/bn254/plonk/verify.go index 74b56c5caf..8db03fb3fd 100644 --- a/internal/backend/bn254/plonk/verify.go +++ b/internal/backend/bn254/plonk/verify.go @@ -89,23 +89,48 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // ccompute PI = ∑_{i Date: Thu, 9 Mar 2023 01:09:00 +0100 Subject: [PATCH 082/464] feat: add calling hints to field emulation --- std/math/emulated/field_hint.go | 92 ++++++++++++++++++++++++++++ std/math/emulated/field_hint_test.go | 71 +++++++++++++++++++++ 2 files changed, 163 insertions(+) create mode 100644 std/math/emulated/field_hint.go create mode 100644 std/math/emulated/field_hint_test.go diff --git a/std/math/emulated/field_hint.go b/std/math/emulated/field_hint.go new file mode 100644 index 0000000000..b85c08cf42 --- /dev/null +++ b/std/math/emulated/field_hint.go @@ -0,0 +1,92 @@ +package emulated + +import ( + "fmt" + "math/big" + + "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/frontend" +) + +func (f *Field[T]) wrapHint(nonnativeInputs ...*Element[T]) []frontend.Variable { + res := []frontend.Variable{f.fParams.BitsPerLimb(), f.fParams.NbLimbs()} + res = append(res, f.Modulus().Limbs...) + res = append(res, len(nonnativeInputs)) + for i := range nonnativeInputs { + res = append(res, len(nonnativeInputs[i].Limbs)) + res = append(res, nonnativeInputs[i].Limbs...) + } + return res +} + +func UnwrapHint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int, nonNativeHint solver.Hint) error { + if len(nativeInputs) < 2 { + return fmt.Errorf("hint wrapper header is 2 elements") + } + if !nativeInputs[0].IsInt64() || !nativeInputs[1].IsInt64() { + return fmt.Errorf("header must be castable to int64") + } + nbBits := int(nativeInputs[0].Int64()) + nbLimbs := int(nativeInputs[1].Int64()) + if len(nativeInputs) < 2+nbLimbs { + return fmt.Errorf("hint wrapper header is 2+nbLimbs elements") + } + nonnativeMod := new(big.Int) + if err := recompose(nativeInputs[2:2+nbLimbs], uint(nbBits), nonnativeMod); err != nil { + return fmt.Errorf("cannot recover nonnative mod: %w", err) + } + if !nativeInputs[2+nbLimbs].IsInt64() { + return fmt.Errorf("number of nonnative elements must be castable to int64") + } + nbInputs := int(nativeInputs[2+nbLimbs].Int64()) + nonnativeInputs := make([]*big.Int, nbInputs) + readPtr := 3 + nbLimbs + for i := 0; i < nbInputs; i++ { + if len(nativeInputs) < readPtr+1 { + return fmt.Errorf("can not read %d-th native input", i) + } + if !nativeInputs[readPtr].IsInt64() { + return fmt.Errorf("corrupted %d-th native input", i) + } + currentInputLen := int(nativeInputs[readPtr].Int64()) + if len(nativeInputs) < (readPtr + 1 + currentInputLen) { + return fmt.Errorf("cannot read %d-th nonnative element", i) + } + nonnativeInputs[i] = new(big.Int) + if err := recompose(nativeInputs[readPtr+1:readPtr+1+currentInputLen], uint(nbBits), nonnativeInputs[i]); err != nil { + return fmt.Errorf("recompose %d-th element: %w", i, err) + } + readPtr += 1 + currentInputLen + } + if len(nativeOutputs)%nbLimbs != 0 { + return fmt.Errorf("output count doesn't divide limb count") + } + nonnativeOutputs := make([]*big.Int, len(nativeOutputs)/nbLimbs) + for i := range nonnativeOutputs { + nonnativeOutputs[i] = new(big.Int) + } + if err := nonNativeHint(nonnativeMod, nonnativeInputs, nonnativeOutputs); err != nil { + return fmt.Errorf("nonnative hint: %w", err) + } + for i := range nonnativeOutputs { + nonnativeOutputs[i].Mod(nonnativeOutputs[i], nonnativeMod) + if err := decompose(nonnativeOutputs[i], uint(nbBits), nativeOutputs[i*nbLimbs:(i+1)*nbLimbs]); err != nil { + return fmt.Errorf("decompose %d-th element: %w", i, err) + } + } + return nil +} + +func (f *Field[T]) NewHint(hf solver.Hint, nbOutputs int, inputs ...*Element[T]) ([]*Element[T], error) { + nativeInputs := f.wrapHint(inputs...) + nbNativeOutputs := int(f.fParams.NbLimbs()) * nbOutputs + nativeOutputs, err := f.api.Compiler().NewHint(hf, nbNativeOutputs, nativeInputs...) + if err != nil { + return nil, fmt.Errorf("call hint: %w", err) + } + outputs := make([]*Element[T], nbOutputs) + for i := 0; i < nbOutputs; i++ { + outputs[i] = f.packLimbs(nativeOutputs[i*int(f.fParams.NbLimbs()):(i+1)*int(f.fParams.NbLimbs())], true) + } + return outputs, nil +} diff --git a/std/math/emulated/field_hint_test.go b/std/math/emulated/field_hint_test.go new file mode 100644 index 0000000000..473cbea6b1 --- /dev/null +++ b/std/math/emulated/field_hint_test.go @@ -0,0 +1,71 @@ +package emulated_test + +import ( + "fmt" + "math/big" + "testing" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/math/emulated" + "github.com/consensys/gnark/test" +) + +func DivTestHint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeMod, nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + nominator := inputs[0] + denominator := inputs[1] + res := new(big.Int).ModInverse(denominator, mod) + if res == nil { + return fmt.Errorf("no modular inverse") + } + res.Mul(res, nominator) + res.Mod(res, mod) + outputs[0].Set(res) + return nil + }) +} + +type testDivHintCircuit[T emulated.FieldParams] struct { + Nominator emulated.Element[T] + Denominator emulated.Element[T] + Expected emulated.Element[T] +} + +func (c *testDivHintCircuit[T]) Define(api frontend.API) error { + field, err := emulated.NewField[T](api) + if err != nil { + return err + } + res, err := field.NewHint(DivTestHint, 1, &c.Nominator, &c.Denominator) + if err != nil { + return err + } + m := field.Mul(res[0], &c.Denominator) + field.AssertIsEqual(m, &c.Nominator) + field.AssertIsEqual(res[0], &c.Expected) + return nil +} + +func TestDivWithHInt(t *testing.T) { + var a, b, c fr.Element + a.SetRandom() + b.SetRandom() + c.Div(&a, &b) + + circuit := testDivHintCircuit[emulated.BN254Fr]{} + witness := testDivHintCircuit[emulated.BN254Fr]{ + Nominator: emulated.ValueOf[emulated.BN254Fr](a), + Denominator: emulated.ValueOf[emulated.BN254Fr](b), + Expected: emulated.ValueOf[emulated.BN254Fr](c), + } + assert := test.NewAssert(t) + assert.ProverSucceeded(&circuit, &witness, test.NoFuzzing(), test.NoSerialization(), test.WithCurves(ecc.BN254), + test.WithBackends(backend.PLONK), + test.WithSolverOpts(solver.WithHints(DivTestHint)), + ) +} From 9adb8326c2e0006810eded55c361dcd0610c243f Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 9 Mar 2023 01:09:39 +0100 Subject: [PATCH 083/464] fix: append solver options to prover options in tests Backend options were split into prover and solver options. Usually when running the prover we set the solver options using backend.WithSolverOptions. But in tests makes sense that if we set `test.WithSolverOptions` then these options are also applied to the solver when run by the prover. --- test/options.go | 1 + 1 file changed, 1 insertion(+) diff --git a/test/options.go b/test/options.go index c40104b886..00ca2924a2 100644 --- a/test/options.go +++ b/test/options.go @@ -89,6 +89,7 @@ func WithProverOpts(proverOpts ...backend.ProverOption) TestingOption { // calling constraint system solver. func WithSolverOpts(solverOpts ...solver.Option) TestingOption { return func(opt *testingConfig) error { + opt.proverOpts = append(opt.proverOpts, backend.WithSolverOptions(solverOpts...)) opt.solverOpts = solverOpts return nil } From 485fd702f05f1eb53299b28fac5fa371284ce0da Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 9 Mar 2023 01:22:14 +0100 Subject: [PATCH 084/464] refactor: dont need nativemod in emulated hint unwrapper --- std/math/emulated/field_hint.go | 2 +- std/math/emulated/field_hint_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/std/math/emulated/field_hint.go b/std/math/emulated/field_hint.go index b85c08cf42..6da209ec1f 100644 --- a/std/math/emulated/field_hint.go +++ b/std/math/emulated/field_hint.go @@ -19,7 +19,7 @@ func (f *Field[T]) wrapHint(nonnativeInputs ...*Element[T]) []frontend.Variable return res } -func UnwrapHint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int, nonNativeHint solver.Hint) error { +func UnwrapHint(nativeInputs, nativeOutputs []*big.Int, nonNativeHint solver.Hint) error { if len(nativeInputs) < 2 { return fmt.Errorf("hint wrapper header is 2 elements") } diff --git a/std/math/emulated/field_hint_test.go b/std/math/emulated/field_hint_test.go index 473cbea6b1..86f1dec322 100644 --- a/std/math/emulated/field_hint_test.go +++ b/std/math/emulated/field_hint_test.go @@ -15,7 +15,7 @@ import ( ) func DivTestHint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { - return emulated.UnwrapHint(nativeMod, nativeInputs, nativeOutputs, + return emulated.UnwrapHint(nativeInputs, nativeOutputs, func(mod *big.Int, inputs, outputs []*big.Int) error { nominator := inputs[0] denominator := inputs[1] From bd39e9fc1c6438da73a5d3f6473825a5ac0ef8e2 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Wed, 8 Mar 2023 21:20:29 -0600 Subject: [PATCH 085/464] feat: plonk frontend filter common cases of duplicate constraints (#539) * feat: check for common duplicate mul gate in plonk frontend * feat: scs detects duplicate add constraints * feat: update stats * checkpoint * feat: clean duplicate add and handle extra possible case * style: more cleaning + fix edge case where qC != 0 * test: added DuplicateMul test in scs * feat: regenerate stats * docs: update struct comment * test: add failing test for duplicate mul * test: fix failing test * style: code cleaning --- constraint/bls12-377/r1cs_sparse.go | 12 + constraint/bls12-381/r1cs_sparse.go | 12 + constraint/bls24-315/r1cs_sparse.go | 12 + constraint/bls24-317/r1cs_sparse.go | 12 + constraint/bn254/r1cs_sparse.go | 12 + constraint/bw6-633/r1cs_sparse.go | 12 + constraint/bw6-761/r1cs_sparse.go | 12 + constraint/r1cs_sparse.go | 7 + constraint/tinyfield/r1cs_sparse.go | 12 + frontend/cs/scs/builder.go | 253 ++++++++++++++++-- frontend/cs/scs/duplicate_test.go | 94 +++++++ .../representations/r1cs.sparse.go.tmpl | 12 + internal/stats/latest.stats | Bin 2803 -> 2803 bytes 13 files changed, 437 insertions(+), 25 deletions(-) create mode 100644 frontend/cs/scs/duplicate_test.go diff --git a/constraint/bls12-377/r1cs_sparse.go b/constraint/bls12-377/r1cs_sparse.go index 2fd9f5cd64..ff06c23efd 100644 --- a/constraint/bls12-377/r1cs_sparse.go +++ b/constraint/bls12-377/r1cs_sparse.go @@ -437,6 +437,18 @@ func (cs *SparseR1CS) GetConstraints() ([]constraint.SparseR1C, constraint.Resol return cs.Constraints, cs } +func (cs *SparseR1CS) GetConstraint(i int) *constraint.SparseR1C { + if i < 0 || i >= len(cs.Constraints) { + return nil + } + return &cs.Constraints[i] +} + +func (cs *SparseR1CS) GetCoefficient(i int) (r constraint.Coeff) { + copy(r[:], cs.Coefficients[i][:]) + return +} + // checkConstraint verifies that the constraint holds func (cs *SparseR1CS) checkConstraint(c constraint.SparseR1C, solution *solution) error { l := solution.computeTerm(c.L) diff --git a/constraint/bls12-381/r1cs_sparse.go b/constraint/bls12-381/r1cs_sparse.go index 63a023a9ff..e4aea25b0a 100644 --- a/constraint/bls12-381/r1cs_sparse.go +++ b/constraint/bls12-381/r1cs_sparse.go @@ -437,6 +437,18 @@ func (cs *SparseR1CS) GetConstraints() ([]constraint.SparseR1C, constraint.Resol return cs.Constraints, cs } +func (cs *SparseR1CS) GetConstraint(i int) *constraint.SparseR1C { + if i < 0 || i >= len(cs.Constraints) { + return nil + } + return &cs.Constraints[i] +} + +func (cs *SparseR1CS) GetCoefficient(i int) (r constraint.Coeff) { + copy(r[:], cs.Coefficients[i][:]) + return +} + // checkConstraint verifies that the constraint holds func (cs *SparseR1CS) checkConstraint(c constraint.SparseR1C, solution *solution) error { l := solution.computeTerm(c.L) diff --git a/constraint/bls24-315/r1cs_sparse.go b/constraint/bls24-315/r1cs_sparse.go index 827bd37fc3..794c9b06ee 100644 --- a/constraint/bls24-315/r1cs_sparse.go +++ b/constraint/bls24-315/r1cs_sparse.go @@ -437,6 +437,18 @@ func (cs *SparseR1CS) GetConstraints() ([]constraint.SparseR1C, constraint.Resol return cs.Constraints, cs } +func (cs *SparseR1CS) GetConstraint(i int) *constraint.SparseR1C { + if i < 0 || i >= len(cs.Constraints) { + return nil + } + return &cs.Constraints[i] +} + +func (cs *SparseR1CS) GetCoefficient(i int) (r constraint.Coeff) { + copy(r[:], cs.Coefficients[i][:]) + return +} + // checkConstraint verifies that the constraint holds func (cs *SparseR1CS) checkConstraint(c constraint.SparseR1C, solution *solution) error { l := solution.computeTerm(c.L) diff --git a/constraint/bls24-317/r1cs_sparse.go b/constraint/bls24-317/r1cs_sparse.go index c8503d0f54..6208f3deec 100644 --- a/constraint/bls24-317/r1cs_sparse.go +++ b/constraint/bls24-317/r1cs_sparse.go @@ -437,6 +437,18 @@ func (cs *SparseR1CS) GetConstraints() ([]constraint.SparseR1C, constraint.Resol return cs.Constraints, cs } +func (cs *SparseR1CS) GetConstraint(i int) *constraint.SparseR1C { + if i < 0 || i >= len(cs.Constraints) { + return nil + } + return &cs.Constraints[i] +} + +func (cs *SparseR1CS) GetCoefficient(i int) (r constraint.Coeff) { + copy(r[:], cs.Coefficients[i][:]) + return +} + // checkConstraint verifies that the constraint holds func (cs *SparseR1CS) checkConstraint(c constraint.SparseR1C, solution *solution) error { l := solution.computeTerm(c.L) diff --git a/constraint/bn254/r1cs_sparse.go b/constraint/bn254/r1cs_sparse.go index 4cf27221b9..a5529022f7 100644 --- a/constraint/bn254/r1cs_sparse.go +++ b/constraint/bn254/r1cs_sparse.go @@ -437,6 +437,18 @@ func (cs *SparseR1CS) GetConstraints() ([]constraint.SparseR1C, constraint.Resol return cs.Constraints, cs } +func (cs *SparseR1CS) GetConstraint(i int) *constraint.SparseR1C { + if i < 0 || i >= len(cs.Constraints) { + return nil + } + return &cs.Constraints[i] +} + +func (cs *SparseR1CS) GetCoefficient(i int) (r constraint.Coeff) { + copy(r[:], cs.Coefficients[i][:]) + return +} + // checkConstraint verifies that the constraint holds func (cs *SparseR1CS) checkConstraint(c constraint.SparseR1C, solution *solution) error { l := solution.computeTerm(c.L) diff --git a/constraint/bw6-633/r1cs_sparse.go b/constraint/bw6-633/r1cs_sparse.go index 80cdacb38c..ff12346a66 100644 --- a/constraint/bw6-633/r1cs_sparse.go +++ b/constraint/bw6-633/r1cs_sparse.go @@ -437,6 +437,18 @@ func (cs *SparseR1CS) GetConstraints() ([]constraint.SparseR1C, constraint.Resol return cs.Constraints, cs } +func (cs *SparseR1CS) GetConstraint(i int) *constraint.SparseR1C { + if i < 0 || i >= len(cs.Constraints) { + return nil + } + return &cs.Constraints[i] +} + +func (cs *SparseR1CS) GetCoefficient(i int) (r constraint.Coeff) { + copy(r[:], cs.Coefficients[i][:]) + return +} + // checkConstraint verifies that the constraint holds func (cs *SparseR1CS) checkConstraint(c constraint.SparseR1C, solution *solution) error { l := solution.computeTerm(c.L) diff --git a/constraint/bw6-761/r1cs_sparse.go b/constraint/bw6-761/r1cs_sparse.go index 09c22e4d48..eea553ba14 100644 --- a/constraint/bw6-761/r1cs_sparse.go +++ b/constraint/bw6-761/r1cs_sparse.go @@ -437,6 +437,18 @@ func (cs *SparseR1CS) GetConstraints() ([]constraint.SparseR1C, constraint.Resol return cs.Constraints, cs } +func (cs *SparseR1CS) GetConstraint(i int) *constraint.SparseR1C { + if i < 0 || i >= len(cs.Constraints) { + return nil + } + return &cs.Constraints[i] +} + +func (cs *SparseR1CS) GetCoefficient(i int) (r constraint.Coeff) { + copy(r[:], cs.Coefficients[i][:]) + return +} + // checkConstraint verifies that the constraint holds func (cs *SparseR1CS) checkConstraint(c constraint.SparseR1C, solution *solution) error { l := solution.computeTerm(c.L) diff --git a/constraint/r1cs_sparse.go b/constraint/r1cs_sparse.go index 4d99c82857..04b135298c 100644 --- a/constraint/r1cs_sparse.go +++ b/constraint/r1cs_sparse.go @@ -29,6 +29,13 @@ type SparseR1CS interface { // and will grow the memory usage of the constraint system. AddConstraint(c SparseR1C, debugInfo ...DebugInfo) int + // GetConstraint return a pointer to the constraint at index i, or nil if out of bounds. + GetConstraint(i int) *SparseR1C + + // GetCoefficient returns coefficient with given id in the coeff table. + // calls panic if i is out of bounds, because this is called in the hot path of the compiler. + GetCoefficient(i int) Coeff + // GetConstraints return the list of SparseR1C and a helper for pretty printing. // See StringBuilder for more info. // ! this is an experimental API. diff --git a/constraint/tinyfield/r1cs_sparse.go b/constraint/tinyfield/r1cs_sparse.go index b3fe2373a9..5a80ead238 100644 --- a/constraint/tinyfield/r1cs_sparse.go +++ b/constraint/tinyfield/r1cs_sparse.go @@ -437,6 +437,18 @@ func (cs *SparseR1CS) GetConstraints() ([]constraint.SparseR1C, constraint.Resol return cs.Constraints, cs } +func (cs *SparseR1CS) GetConstraint(i int) *constraint.SparseR1C { + if i < 0 || i >= len(cs.Constraints) { + return nil + } + return &cs.Constraints[i] +} + +func (cs *SparseR1CS) GetCoefficient(i int) (r constraint.Coeff) { + copy(r[:], cs.Coefficients[i][:]) + return +} + // checkConstraint verifies that the constraint holds func (cs *SparseR1CS) checkConstraint(c constraint.SparseR1C, solution *solution) error { l := solution.computeTerm(c.L) diff --git a/frontend/cs/scs/builder.go b/frontend/cs/scs/builder.go index 340e5fe0ab..11595cc7c8 100644 --- a/frontend/cs/scs/builder.go +++ b/frontend/cs/scs/builder.go @@ -55,6 +55,14 @@ type builder struct { // map for recording boolean constrained variables (to not constrain them twice) mtBooleans map[expr.Term]struct{} + // records multiplications constraint to avoid duplicate. + // see mulConstraintExist(...) + mMulConstraints map[uint64]int + + // same thing for addition gates + // see addConstraintExist(...) + mAddConstraints map[uint64]int + // frequently used coefficients tOne, tMinusOne constraint.Coeff } @@ -63,9 +71,11 @@ type builder struct { // we may want to add build tags to tune that func newBuilder(field *big.Int, config frontend.CompileConfig) *builder { b := builder{ - mtBooleans: make(map[expr.Term]struct{}), - config: config, - Store: kvstore.New(), + mtBooleans: make(map[expr.Term]struct{}), + mMulConstraints: make(map[uint64]int, config.Capacity/2), + mAddConstraints: make(map[uint64]int, config.Capacity/2), + config: config, + Store: kvstore.New(), } curve := utils.FieldToCurve(field) @@ -149,6 +159,7 @@ func (builder *builder) addPlonkConstraint(c sparseR1C, debug ...constraint.Debu V := builder.cs.MakeTerm(&builder.tOne, c.xb) K := builder.cs.MakeTerm(&c.qC, 0) K.MarkConstant() + builder.cs.AddConstraint(constraint.SparseR1C{L: L, R: R, O: O, M: [2]constraint.Term{U, V}, K: K.CoeffID()}, debug...) } @@ -331,48 +342,240 @@ func (builder *builder) splitSum(acc expr.Term, r expr.LinearExpression, k *cons if len(r) == 0 { if k != nil { // we need to return acc + k - o := builder.newInternalVariable() - builder.addPlonkConstraint(sparseR1C{ - xa: acc.VID, - xc: o.VID, - qL: acc.Coeff, - qO: builder.tMinusOne, - qC: *k, - }) + o, found := builder.addConstraintExist(acc, expr.Term{}, *k) + if !found { + o = builder.newInternalVariable() + builder.addPlonkConstraint(sparseR1C{ + xa: acc.VID, + xc: o.VID, + qL: acc.Coeff, + qO: builder.tMinusOne, + qC: *k, + }) + } + return o } return acc } // constraint to add: acc + r[0] (+ k) == o - o := builder.newInternalVariable() - qC := constraint.Coeff{} if k != nil { qC = *k } - builder.addPlonkConstraint(sparseR1C{ - xa: acc.VID, - xb: r[0].VID, - xc: o.VID, - qL: acc.Coeff, - qR: r[0].Coeff, - qO: builder.tMinusOne, - qC: qC, - }) + o, found := builder.addConstraintExist(acc, r[0], qC) + if !found { + o = builder.newInternalVariable() + + builder.addPlonkConstraint(sparseR1C{ + xa: acc.VID, + xb: r[0].VID, + xc: o.VID, + qL: acc.Coeff, + qR: r[0].Coeff, + qO: builder.tMinusOne, + qC: qC, + }) + } return builder.splitSum(o, r[1:], nil) } +// addConstraintExist check if we recorded a constraint in the form +// q1*xa + q2*xb + qC - xc == 0 +// +// if we find one, this function returns the xc wire with the correct coefficients. +// if we don't, and no previous addition was recorded with xa and xb, add an entry in the map +// (this assumes that the caller will add a constraint just after this call if it's not found!) +// +// idea: +// 1. take (xa | (xb << 32)) as a identifier of an addition that used wires xa and xb. +// 2. look for an entry in builder.mAddConstraints for a previously added constraint that matches. +// 3. if so, check that the coefficients matches and we can re-use xc wire. +// +// limitations: +// 1. for efficiency, we just store the first addition that occurred with with xa and xb; +// so if we do 2*xa + 3*xb == c, then want to compute xa + xb == d multiple times, the compiler is +// not going to catch these duplicates. +// 2. this piece of code assumes some behavior from constraint/ package (like coeffIDs, or append-style +// constraint management) +func (builder *builder) addConstraintExist(a, b expr.Term, k constraint.Coeff) (expr.Term, bool) { + // ensure deterministic combined identifier; + if a.VID < b.VID { + a, b = b, a + } + h := uint64(a.WireID()) | uint64(b.WireID()<<32) + + if cID, ok := builder.mAddConstraints[h]; ok { + // seems likely we have a fit, let's double check + if c := builder.cs.GetConstraint(cID); c != nil { + if c.M[0].CoeffID() != constraint.CoeffIdZero { + panic("sanity check failed; recorded a add constraint with qM set") + } + + if a.WireID() == c.R.WireID() { + a, b = b, a // ensure a is in qL + } + if (a.WireID() != c.L.WireID()) || (b.WireID() != c.R.WireID()) { + // that shouldn't happen; it means we added an entry in the duplicate add constraint + // map with a key that don't match the entries. + log := logger.Logger() + log.Error().Msg("mAddConstraints entry doesn't match key") + return expr.Term{}, false + } + + // qO == -1 + if c.O.CoeffID() != constraint.CoeffIdMinusOne { + // we could probably handle that case, but it shouldn't + // happen with our current APIs --> each time we record a add gate in the duplicate + // map qO == -1 + return expr.Term{}, false + } + + tk := builder.cs.MakeTerm(&k, 0) + if tk.CoeffID() != c.K { + // the constant part of the addition differs, no point going forward + // since we will need to add a new constraint anyway. + return expr.Term{}, false + } + + // check that the coeff matches + qL := a.Coeff + qR := b.Coeff + ta := builder.cs.MakeTerm(&qL, 0) + tb := builder.cs.MakeTerm(&qR, 0) + if c.L.CoeffID() != ta.CoeffID() || c.R.CoeffID() != tb.CoeffID() { + if !k.IsZero() { + // may be for some edge cases we could avoid adding a constraint here. + return expr.Term{}, false + } + // we recorded an addition in the form q1*a + q2*b == c + // we want to record a new one in the form q3*a + q4*b == n*c + // question is; can we re-use c to avoid introducing a new wire & new constraint + // this is possible only if n == q3/q1 == q4/q2, that is, q3q2 == q1q4 + q1 := builder.cs.GetCoefficient(c.L.CoeffID()) + q2 := builder.cs.GetCoefficient(c.R.CoeffID()) + q3 := qL + q4 := qR + builder.cs.Mul(&q3, &q2) + builder.cs.Mul(&q1, &q4) + if q1 == q3 { + // no need to introduce a new constraint; + // compute n, the coefficient for the output wire + builder.cs.Inverse(&q2) + builder.cs.Mul(&q2, &q4) + return expr.NewTerm(c.O.WireID(), q2), true + } + // we will need an additional constraint + return expr.Term{}, false + } + + // we found the same constraint! + return expr.NewTerm(c.O.WireID(), builder.tOne), true + } + } + // we are going to add this constraint, so we mark it. + // ! assumes the caller add a constraint immediately after the call to this function + builder.mAddConstraints[h] = builder.cs.GetNbConstraints() + return expr.Term{}, false +} + +// mulConstraintExist check if we recorded a constraint in the form +// qM*xa*xb - xc == 0 +// +// if we find one, this function returns the xc wire with the correct coefficients. +// if we don't, and no previous multiplication was recorded with xa and xb, add an entry in the map +// (this assumes that the caller will add a constraint just after this call if it's not found!) +// +// idea: +// 1. take (xa | (xb << 32)) as a identifier of a multiplication that used wires xa and xb. +// 2. look for an entry in builder.mMulConstraints for a previously added constraint that matches. +// 3. if so, compute correct coefficient N for xc wire that matches qM'*xa*xb - N*xc == 0 +// +// limitations: +// 1. this piece of code assumes some behavior from constraint/ package (like coeffIDs, or append-style +// constraint management) +func (builder *builder) mulConstraintExist(a, b expr.Term) (expr.Term, bool) { + // ensure deterministic combined identifier; + if a.VID < b.VID { + a, b = b, a + } + h := uint64(a.WireID()) | uint64(b.WireID()<<32) + if a.VID < b.VID { + a, b = b, a + } + + if cID, ok := builder.mMulConstraints[h]; ok { + // seems likely we have a fit, let's double check + if c := builder.cs.GetConstraint(cID); c != nil { + if !(c.K|c.L.CoeffID()|c.R.CoeffID() == constraint.CoeffIdZero) { + panic("sanity check failed; recorded a mul constraint with qL, qR or qC set") + } + + // qO == -1 + if c.O.CoeffID() != constraint.CoeffIdMinusOne { + // we could probably handle that case, but it shouldn't + // happen with our current APIs --> each time we record a mul gate in the duplicate + // map qO == -1 + return expr.Term{}, false + } + + if a.WireID() == c.R.WireID() { + a, b = b, a // ensure a is in qL + } + if (a.WireID() != c.L.WireID()) || (b.WireID() != c.R.WireID()) { + // that shouldn't happen; it means we added an entry in the duplicate mul constraint + // map with a key that don't match the entries. + log := logger.Logger() + log.Error().Msg("mMulConstraints entry doesn't match key") + return expr.Term{}, false + } + + // recompute the qM coeff and check that it matches; + qM := a.Coeff + builder.cs.Mul(&qM, &b.Coeff) + tm := builder.cs.MakeTerm(&qM, 0) + if c.M[0].CoeffID() != tm.CoeffID() { + // so we wanted to compute + // N * xC == qM*xA*xB + // but found a constraint + // xC == qM'*xA*xB + // the coefficient for our resulting wire is different; + // N = qM / qM' + N := builder.cs.GetCoefficient(c.M[0].CoeffID()) + builder.cs.Inverse(&N) + builder.cs.Mul(&N, &qM) + + return expr.NewTerm(c.O.WireID(), N), true + } + + // we found the exact same constraint + return expr.NewTerm(c.O.WireID(), builder.tOne), true + } + } + + // we are going to add this constraint, so we mark it. + // ! assumes the caller add a constraint immediately after the call to this function + builder.mMulConstraints[h] = builder.cs.GetNbConstraints() + return expr.Term{}, false +} + func (builder *builder) splitProd(acc expr.Term, r expr.LinearExpression) expr.Term { // floor case if len(r) == 0 { return acc } + // we want to add a constraint such that acc * r[0] == o + // let's check if we didn't already constrain a similar product + o, found := builder.mulConstraintExist(acc, r[0]) + + if !found { + // constraint to add: acc * r[0] == o + o = builder.newInternalVariable() + builder.addMulGate(acc, r[0], o) + } - // constraint to add: acc * r[0] == o - o := builder.newInternalVariable() - builder.addMulGate(acc, r[0], o) return builder.splitProd(o, r[1:]) } diff --git a/frontend/cs/scs/duplicate_test.go b/frontend/cs/scs/duplicate_test.go new file mode 100644 index 0000000000..e06051bb86 --- /dev/null +++ b/frontend/cs/scs/duplicate_test.go @@ -0,0 +1,94 @@ +package scs_test + +import ( + "testing" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/scs" + "github.com/stretchr/testify/require" +) + +type circuitDupAdd struct { + A, B frontend.Variable + R frontend.Variable +} + +func (c *circuitDupAdd) Define(api frontend.API) error { + + f := api.Add(c.A, c.B) // 1 constraint + f = api.Add(c.A, c.B, f) // 1 constraint + f = api.Add(c.A, c.B, f) // 1 constraint + + d := api.Add(api.Mul(c.A, 3), api.Mul(3, c.B)) // 3a + 3b --> 3 (a + b) shouldn't add a constraint. + e := api.Mul(api.Add(c.A, c.B), 3) // no constraints + + api.AssertIsEqual(f, e) // 1 constraint + api.AssertIsEqual(d, f) // 1 constraint + api.AssertIsEqual(c.R, e) // 1 constraint + + return nil +} + +func TestDuplicateAdd(t *testing.T) { + assert := require.New(t) + + ccs, err := frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, &circuitDupAdd{}) + assert.NoError(err) + + assert.Equal(6, ccs.GetNbConstraints(), "comparing expected number of constraints") + + w, err := frontend.NewWitness(&circuitDupAdd{ + A: 13, + B: 42, + R: 165, + }, ecc.BN254.ScalarField()) + assert.NoError(err) + + _, err = ccs.Solve(w) + assert.NoError(err, "solving failed") +} + +type circuitDupMul struct { + A, B frontend.Variable + R1, R2 frontend.Variable +} + +func (c *circuitDupMul) Define(api frontend.API) error { + + f := api.Mul(c.A, c.B) // 1 constraint + f = api.Mul(c.A, c.B, f) // 1 constraint + f = api.Mul(c.A, c.B, f) // 1 constraint + // f == (a*b)**3 + + d := api.Mul(api.Mul(c.A, 2), api.Mul(3, c.B)) // no constraints + e := api.Mul(api.Mul(c.A, c.B), 1) // no constraints + e = api.Mul(e, e) // e**2 (no constraints) + e = api.Mul(e, api.Mul(c.A, c.B), 1) // e**3 (no constraints) + + api.AssertIsEqual(f, e) // 1 constraint + api.AssertIsEqual(d, c.R1) // 1 constraint + api.AssertIsEqual(c.R2, e) // 1 constraint + + return nil +} + +func TestDuplicateMul(t *testing.T) { + assert := require.New(t) + + ccs, err := frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, &circuitDupMul{}) + assert.NoError(err) + + assert.Equal(6, ccs.GetNbConstraints(), "comparing expected number of constraints") + + w, err := frontend.NewWitness(&circuitDupMul{ + A: 13, + B: 42, + R1: (13 * 2) * (42 * 3), + R2: (13 * 42) * (13 * 42) * (13 * 42), + }, ecc.BN254.ScalarField()) + assert.NoError(err) + + _, err = ccs.Solve(w) + assert.NoError(err, "solving failed") +} diff --git a/internal/generator/backend/template/representations/r1cs.sparse.go.tmpl b/internal/generator/backend/template/representations/r1cs.sparse.go.tmpl index eec1fd8d58..84128a998a 100644 --- a/internal/generator/backend/template/representations/r1cs.sparse.go.tmpl +++ b/internal/generator/backend/template/representations/r1cs.sparse.go.tmpl @@ -427,6 +427,18 @@ func (cs *SparseR1CS) GetConstraints() ([]constraint.SparseR1C, constraint.Resol return cs.Constraints, cs } +func (cs *SparseR1CS) GetConstraint(i int) (*constraint.SparseR1C) { + if i < 0 ||i >= len(cs.Constraints) { + return nil + } + return &cs.Constraints[i] +} + +func (cs *SparseR1CS) GetCoefficient(i int) (r constraint.Coeff) { + copy(r[:], cs.Coefficients[i][:]) + return +} + // checkConstraint verifies that the constraint holds func (cs *SparseR1CS) checkConstraint(c constraint.SparseR1C, solution *solution) error { l := solution.computeTerm(c.L) diff --git a/internal/stats/latest.stats b/internal/stats/latest.stats index c846090f0ae1d77d0d5e4ac2e9b1f20ae4acc0f7..3d6d18dabdd36c14139e188342d94235a0d0a3a6 100644 GIT binary patch delta 243 zcmew?`dM^B*5qYOcPFQ?WY(8gG5#z2$H4dx4 Date: Thu, 9 Mar 2023 13:29:45 +0100 Subject: [PATCH 086/464] perf(bn254-pair): use hinted Div in tower instead of plain inv+mul --- std/algebra/emulated/fields_bn254/e12.go | 188 ++++++++++++++++-- .../emulated/fields_bn254/e12_pairing.go | 20 +- std/algebra/emulated/fields_bn254/e12_test.go | 39 +++- std/algebra/emulated/fields_bn254/e2.go | 107 ++++++++-- std/algebra/emulated/fields_bn254/e2_test.go | 35 +++- std/algebra/emulated/fields_bn254/e6.go | 171 +++++++++++++--- std/algebra/emulated/fields_bn254/e6_test.go | 35 +++- std/algebra/emulated/sw_bn254/doc_test.go | 2 +- std/algebra/emulated/sw_bn254/pairing.go | 17 +- std/algebra/emulated/sw_bn254/pairing_test.go | 18 +- 10 files changed, 542 insertions(+), 90 deletions(-) diff --git a/std/algebra/emulated/fields_bn254/e12.go b/std/algebra/emulated/fields_bn254/e12.go index f9b9b72b06..20cd949616 100644 --- a/std/algebra/emulated/fields_bn254/e12.go +++ b/std/algebra/emulated/fields_bn254/e12.go @@ -1,6 +1,13 @@ package fields_bn254 -import "github.com/consensys/gnark-crypto/ecc/bn254" +import ( + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/math/emulated" +) type E12 struct { C0, C1 E6 @@ -40,22 +47,6 @@ func (e Ext12) Conjugate(x *E12) *E12 { } } -func (e Ext12) Inverse(x *E12) *E12 { - // var t0, t1, tmp E6 - t0 := e.Ext6.Square(&x.C0) // t0.Square(&x.C0) - t1 := e.Ext6.Square(&x.C1) // t1.Square(&x.C1) - tmp := e.Ext6.MulByNonResidue(t1) // tmp.MulByNonResidue(&t1) - t0 = e.Ext6.Sub(t0, tmp) // t0.Sub(&t0, &tmp) - t1 = e.Ext6.Inverse(t0) // t1.Inverse(&t0) - z0 := e.Ext6.Mul(&x.C0, t1) // z.C0.Mul(&x.C0, &t1) - z1 := e.Ext6.Mul(&x.C1, t1) // z.C1.Mul(&x.C1, &t1). - z1 = e.Ext6.Neg(z1) // Neg(&z.C1) - return &E12{ // return z - C0: *z0, - C1: *z1, - } -} - func (e Ext12) Mul(x, y *E12) *E12 { // var a, b, c E6 a := e.Ext6.Add(&x.C0, &x.C1) // a.Add(&x.C0, &x.C1) @@ -234,7 +225,7 @@ func (e Ext12) NCycloSquareCompressed(z *E12, n int) *E12 { } // DecompressKarabina Karabina's cyclotomic square result -func (e Ext12) DecompressKarabina(x *E12) *E12 { +func (e Ext12) DecompressKarabina(api frontend.API, x *E12) *E12 { one := e.Ext6.Ext2.One() @@ -256,7 +247,7 @@ func (e Ext12) DecompressKarabina(x *E12) *E12 { // z4 = g4 // TODO: Div instead of Inv+Mul - C1B1 := e.Ext6.Ext2.Inverse(t1) + C1B1 := e.Ext6.Ext2.Inverse(api, t1) C1B1 = e.Ext6.Ext2.Mul(C1B1, t0) // t1 = g2 * g1 @@ -401,3 +392,162 @@ func FromE12(y *bn254.E12) E12 { } } + +func init() { + solver.RegisterHint(DivE12Hint) + solver.RegisterHint(InverseE12Hint) +} + +func InverseE12Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, c bn254.E12 + + a.C0.B0.A0.SetBigInt(inputs[0]) + a.C0.B0.A1.SetBigInt(inputs[1]) + a.C0.B1.A0.SetBigInt(inputs[2]) + a.C0.B1.A1.SetBigInt(inputs[3]) + a.C0.B2.A0.SetBigInt(inputs[4]) + a.C0.B2.A1.SetBigInt(inputs[5]) + a.C1.B0.A0.SetBigInt(inputs[6]) + a.C1.B0.A1.SetBigInt(inputs[7]) + a.C1.B1.A0.SetBigInt(inputs[8]) + a.C1.B1.A1.SetBigInt(inputs[9]) + a.C1.B2.A0.SetBigInt(inputs[10]) + a.C1.B2.A1.SetBigInt(inputs[11]) + + c.Inverse(&a) + + c.C0.B0.A0.BigInt(outputs[0]) + c.C0.B0.A1.BigInt(outputs[1]) + c.C0.B1.A0.BigInt(outputs[2]) + c.C0.B1.A1.BigInt(outputs[3]) + c.C0.B2.A0.BigInt(outputs[4]) + c.C0.B2.A1.BigInt(outputs[5]) + c.C1.B0.A0.BigInt(outputs[6]) + c.C1.B0.A1.BigInt(outputs[7]) + c.C1.B1.A0.BigInt(outputs[8]) + c.C1.B1.A1.BigInt(outputs[9]) + c.C1.B2.A0.BigInt(outputs[10]) + c.C1.B2.A1.BigInt(outputs[11]) + + return nil + }) +} + +func DivE12Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, b, c bn254.E12 + + a.C0.B0.A0.SetBigInt(inputs[0]) + a.C0.B0.A1.SetBigInt(inputs[1]) + a.C0.B1.A0.SetBigInt(inputs[2]) + a.C0.B1.A1.SetBigInt(inputs[3]) + a.C0.B2.A0.SetBigInt(inputs[4]) + a.C0.B2.A1.SetBigInt(inputs[5]) + a.C1.B0.A0.SetBigInt(inputs[6]) + a.C1.B0.A1.SetBigInt(inputs[7]) + a.C1.B1.A0.SetBigInt(inputs[8]) + a.C1.B1.A1.SetBigInt(inputs[9]) + a.C1.B2.A0.SetBigInt(inputs[10]) + a.C1.B2.A1.SetBigInt(inputs[11]) + + b.C0.B0.A0.SetBigInt(inputs[12]) + b.C0.B0.A1.SetBigInt(inputs[13]) + b.C0.B1.A0.SetBigInt(inputs[14]) + b.C0.B1.A1.SetBigInt(inputs[15]) + b.C0.B2.A0.SetBigInt(inputs[16]) + b.C0.B2.A1.SetBigInt(inputs[17]) + b.C1.B0.A0.SetBigInt(inputs[18]) + b.C1.B0.A1.SetBigInt(inputs[19]) + b.C1.B1.A0.SetBigInt(inputs[20]) + b.C1.B1.A1.SetBigInt(inputs[21]) + b.C1.B2.A0.SetBigInt(inputs[22]) + b.C1.B2.A1.SetBigInt(inputs[23]) + + c.Inverse(&b).Mul(&c, &a) + + c.C0.B0.A0.BigInt(outputs[0]) + c.C0.B0.A1.BigInt(outputs[1]) + c.C0.B1.A0.BigInt(outputs[2]) + c.C0.B1.A1.BigInt(outputs[3]) + c.C0.B2.A0.BigInt(outputs[4]) + c.C0.B2.A1.BigInt(outputs[5]) + c.C1.B0.A0.BigInt(outputs[6]) + c.C1.B0.A1.BigInt(outputs[7]) + c.C1.B1.A0.BigInt(outputs[8]) + c.C1.B1.A1.BigInt(outputs[9]) + c.C1.B2.A0.BigInt(outputs[10]) + c.C1.B2.A1.BigInt(outputs[11]) + + return nil + }) +} + +func (e Ext12) Inverse(api frontend.API, x *E12) *E12 { + field, err := emulated.NewField[emulated.BN254Fp](api) + if err != nil { + panic(err) + } + res, err := field.NewHint(InverseE12Hint, 12, &x.C0.B0.A0, &x.C0.B0.A1, &x.C0.B1.A0, &x.C0.B1.A1, &x.C0.B2.A0, &x.C0.B2.A1, &x.C1.B0.A0, &x.C1.B0.A1, &x.C1.B1.A0, &x.C1.B1.A1, &x.C1.B2.A0, &x.C1.B2.A1) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + inv := E12{ + C0: E6{ + B0: E2{A0: *res[0], A1: *res[1]}, + B1: E2{A0: *res[2], A1: *res[3]}, + B2: E2{A0: *res[4], A1: *res[5]}, + }, + C1: E6{ + B0: E2{A0: *res[6], A1: *res[7]}, + B1: E2{A0: *res[8], A1: *res[9]}, + B2: E2{A0: *res[10], A1: *res[11]}, + }, + } + + one := e.One() + + // 1 == inv * x + _one := *e.Mul(&inv, x) + e.AssertIsEqual(one, &_one) + + return &inv + +} + +// DivUnchecked e2 elmts +func (e Ext12) DivUnchecked(api frontend.API, x, y E12) *E12 { + field, err := emulated.NewField[emulated.BN254Fp](api) + if err != nil { + panic(err) + } + res, err := field.NewHint(DivE12Hint, 12, &x.C0.B0.A0, &x.C0.B0.A1, &x.C0.B1.A0, &x.C0.B1.A1, &x.C0.B2.A0, &x.C0.B2.A1, &x.C1.B0.A0, &x.C1.B0.A1, &x.C1.B1.A0, &x.C1.B1.A1, &x.C1.B2.A0, &x.C1.B2.A1, &y.C0.B0.A0, &y.C0.B0.A1, &y.C0.B1.A0, &y.C0.B1.A1, &y.C0.B2.A0, &y.C0.B2.A1, &y.C1.B0.A0, &y.C1.B0.A1, &y.C1.B1.A0, &y.C1.B1.A1, &y.C1.B2.A0, &y.C1.B2.A1) + + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + div := E12{ + C0: E6{ + B0: E2{A0: *res[0], A1: *res[1]}, + B1: E2{A0: *res[2], A1: *res[3]}, + B2: E2{A0: *res[4], A1: *res[5]}, + }, + C1: E6{ + B0: E2{A0: *res[6], A1: *res[7]}, + B1: E2{A0: *res[8], A1: *res[9]}, + B2: E2{A0: *res[10], A1: *res[11]}, + }, + } + + // x == div * y + _x := *e.Mul(&div, &y) + e.AssertIsEqual(&x, &_x) + + return &div +} diff --git a/std/algebra/emulated/fields_bn254/e12_pairing.go b/std/algebra/emulated/fields_bn254/e12_pairing.go index d6cf38494e..344be7d08f 100644 --- a/std/algebra/emulated/fields_bn254/e12_pairing.go +++ b/std/algebra/emulated/fields_bn254/e12_pairing.go @@ -1,6 +1,8 @@ package fields_bn254 -func (e Ext12) Expt(x *E12) *E12 { +import "github.com/consensys/gnark/frontend" + +func (e Ext12) Expt(api frontend.API, x *E12) *E12 { t3 := e.CyclotomicSquare(x) t5 := e.CyclotomicSquare(t3) result := e.CyclotomicSquare(t5) @@ -13,30 +15,30 @@ func (e Ext12) Expt(x *E12) *E12 { t1 = e.Mul(t0, t1) t0 = e.Mul(t3, t1) t6 = e.NCycloSquareCompressed(t6, 6) - t6 = e.DecompressKarabina(t6) + t6 = e.DecompressKarabina(api, t6) t5 = e.Mul(t5, t6) t5 = e.Mul(t4, t5) t5 = e.NCycloSquareCompressed(t5, 7) - t5 = e.DecompressKarabina(t5) + t5 = e.DecompressKarabina(api, t5) t4 = e.Mul(t4, t5) t4 = e.NCycloSquareCompressed(t4, 8) - t4 = e.DecompressKarabina(t4) + t4 = e.DecompressKarabina(api, t4) t4 = e.Mul(t0, t4) t3 = e.Mul(t3, t4) t3 = e.NCycloSquareCompressed(t3, 6) - t3 = e.DecompressKarabina(t3) + t3 = e.DecompressKarabina(api, t3) t2 = e.Mul(t2, t3) t2 = e.NCycloSquareCompressed(t2, 8) - t2 = e.DecompressKarabina(t2) + t2 = e.DecompressKarabina(api, t2) t2 = e.Mul(t0, t2) t2 = e.NCycloSquareCompressed(t2, 6) - t2 = e.DecompressKarabina(t2) + t2 = e.DecompressKarabina(api, t2) t2 = e.Mul(t0, t2) t2 = e.NCycloSquareCompressed(t2, 10) - t2 = e.DecompressKarabina(t2) + t2 = e.DecompressKarabina(api, t2) t1 = e.Mul(t1, t2) t1 = e.NCycloSquareCompressed(t1, 6) - t1 = e.DecompressKarabina(t1) + t1 = e.DecompressKarabina(api, t1) t0 = e.Mul(t0, t1) z := e.Mul(result, t0) return z diff --git a/std/algebra/emulated/fields_bn254/e12_test.go b/std/algebra/emulated/fields_bn254/e12_test.go index 0b218e4e26..2df2be5b14 100644 --- a/std/algebra/emulated/fields_bn254/e12_test.go +++ b/std/algebra/emulated/fields_bn254/e12_test.go @@ -107,6 +107,39 @@ func TestMulFp12(t *testing.T) { } +type e12Div struct { + A, B, C E12 +} + +func (circuit *e12Div) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt12(ba) + + expected := e.DivUnchecked(api, circuit.A, circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestDivFp12(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bn254.E12 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Div(&a, &b) + + witness := e12Div{ + A: FromE12(&a), + B: FromE12(&b), + C: FromE12(&c), + } + + err := test.IsSolved(&e12Div{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + type e12MulBy034by034 struct { C0, C3, C4 E2 D0, D3, D4 E2 @@ -232,7 +265,7 @@ func (circuit *e12CycloSquareKarabina) Define(api frontend.API) error { ba, _ := emulated.NewField[emulated.BN254Fp](api) e := NewExt12(ba) v := e.CyclotomicSquareCompressed(&circuit.A) - v = e.DecompressKarabina(v) + v = e.DecompressKarabina(api, v) e.AssertIsEqual(v, &circuit.C) return nil } @@ -302,7 +335,7 @@ func (circuit *e12Inverse) Define(api frontend.API) error { ba, _ := emulated.NewField[emulated.BN254Fp](api) e := NewExt12(ba) - expected := e.Inverse(&circuit.A) + expected := e.Inverse(api, &circuit.A) e.AssertIsEqual(expected, &circuit.C) return nil @@ -334,7 +367,7 @@ func (circuit *e12Expt) Define(api frontend.API) error { ba, _ := emulated.NewField[emulated.BN254Fp](api) e := NewExt12(ba) - expected := e.Expt(&circuit.A) + expected := e.Expt(api, &circuit.A) e.AssertIsEqual(expected, &circuit.C) return nil diff --git a/std/algebra/emulated/fields_bn254/e2.go b/std/algebra/emulated/fields_bn254/e2.go index 63fdc6f78c..38cb52ddf3 100644 --- a/std/algebra/emulated/fields_bn254/e2.go +++ b/std/algebra/emulated/fields_bn254/e2.go @@ -4,6 +4,8 @@ import ( "math/big" "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/math/emulated" ) @@ -292,21 +294,6 @@ func (e Ext2) MulBybTwistCurveCoeff(x *E2) *E2 { return z // return z } -func (e Ext2) Inverse(x *E2) *E2 { - // var t0, t1 fp.Element - t0 := e.fp.MulMod(&x.A0, &x.A0) // t0.Square(&x.A0) - t1 := e.fp.MulMod(&x.A1, &x.A1) // t1.Square(&x.A1) - t0 = e.fp.Add(t0, t1) // t0.Add(&t0, &t1) - t1 = e.fp.Inverse(t0) // t1.Inverse(&t0) - z0 := e.fp.MulMod(&x.A0, t1) // z.A0.Mul(&x.A0, &t1) - z1 := e.fp.MulMod(&x.A1, t1) // z.A1.Mul(&x.A1, &t1). - z1 = e.fp.Neg(z1) // Neg(&z.A1) - return &E2{ - A0: *z0, - A1: *z1, - } -} - func (e Ext2) AssertIsEqual(x, y *E2) { e.fp.AssertIsEqual(&x.A0, &y.A0) e.fp.AssertIsEqual(&x.A1, &y.A1) @@ -319,3 +306,93 @@ func FromE2(y *bn254.E2) E2 { } } + +func init() { + solver.RegisterHint(DivE2Hint) + solver.RegisterHint(InverseE2Hint) +} + +func InverseE2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, c bn254.E2 + + a.A0.SetBigInt(inputs[0]) + a.A1.SetBigInt(inputs[1]) + + c.Inverse(&a) + + c.A0.BigInt(outputs[0]) + c.A1.BigInt(outputs[1]) + + return nil + }) +} + +func DivE2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, b, c bn254.E2 + + a.A0.SetBigInt(inputs[0]) + a.A1.SetBigInt(inputs[1]) + b.A0.SetBigInt(inputs[2]) + b.A1.SetBigInt(inputs[3]) + + c.Inverse(&b).Mul(&c, &a) + + c.A0.BigInt(outputs[0]) + c.A1.BigInt(outputs[1]) + + return nil + }) +} + +func (e Ext2) Inverse(api frontend.API, x *E2) *E2 { + field, err := emulated.NewField[emulated.BN254Fp](api) + if err != nil { + panic(err) + } + res, err := field.NewHint(InverseE2Hint, 2, &x.A0, &x.A1) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + inv := E2{ + A0: *res[0], + A1: *res[1], + } + one := e.One() + + // 1 == inv * x + _one := *e.Mul(&inv, x) + e.AssertIsEqual(one, &_one) + + return &inv + +} + +// DivUnchecked e2 elmts +func (e Ext2) DivUnchecked(api frontend.API, x, y E2) *E2 { + field, err := emulated.NewField[emulated.BN254Fp](api) + if err != nil { + panic(err) + } + res, err := field.NewHint(DivE2Hint, 2, &x.A0, &x.A1, &y.A0, &y.A1) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + div := E2{ + A0: *res[0], + A1: *res[1], + } + + // x == div * y + _x := *e.Mul(&div, &y) + e.AssertIsEqual(&x, &_x) + + return &div +} diff --git a/std/algebra/emulated/fields_bn254/e2_test.go b/std/algebra/emulated/fields_bn254/e2_test.go index 99b2db5aa1..a37947b1fa 100644 --- a/std/algebra/emulated/fields_bn254/e2_test.go +++ b/std/algebra/emulated/fields_bn254/e2_test.go @@ -202,6 +202,39 @@ func TestSquareFp2(t *testing.T) { } +type e2Div struct { + A, B, C E2 +} + +func (circuit *e2Div) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt2(ba) + + expected := e.DivUnchecked(api, circuit.A, circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestDivFp2(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bn254.E2 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Div(&a, &b) + + witness := e2Div{ + A: FromE2(&a), + B: FromE2(&b), + C: FromE2(&c), + } + + err := test.IsSolved(&e2Div{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + type e2MulByElement struct { A E2 B baseEl @@ -405,7 +438,7 @@ func (circuit *e2Inverse) Define(api frontend.API) error { ba, _ := emulated.NewField[emulated.BN254Fp](api) e := NewExt2(ba) - expected := e.Inverse(&circuit.A) + expected := e.Inverse(api, &circuit.A) e.AssertIsEqual(expected, &circuit.C) return nil diff --git a/std/algebra/emulated/fields_bn254/e6.go b/std/algebra/emulated/fields_bn254/e6.go index 9120a33f18..85c1ec0d70 100644 --- a/std/algebra/emulated/fields_bn254/e6.go +++ b/std/algebra/emulated/fields_bn254/e6.go @@ -1,7 +1,12 @@ package fields_bn254 import ( + "math/big" + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/math/emulated" ) type E6 struct { @@ -16,6 +21,28 @@ func NewExt6(baseField *curveF) *Ext6 { return &Ext6{Ext2: NewExt2(baseField)} } +func (e Ext6) One() *E6 { + z0 := e.Ext2.One() + z1 := e.Ext2.Zero() + z2 := e.Ext2.Zero() + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Zero() *E6 { + z0 := e.Ext2.Zero() + z1 := e.Ext2.Zero() + z2 := e.Ext2.Zero() + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + func (e Ext6) Add(x, y *E6) *E6 { z0 := e.Ext2.Add(&x.B0, &y.B0) // z.B0.Add(&x.B0, &y.B0) z1 := e.Ext2.Add(&x.B1, &y.B1) // z.B1.Add(&x.B1, &y.B1) @@ -120,36 +147,6 @@ func (e Ext6) Square(x *E6) *E6 { } } -func (e Ext6) Inverse(x *E6) *E6 { - // var t0, t1, t2, t3, t4, t5, t6, c0, c1, c2, d1, d2 E2 - t0 := e.Ext2.Square(&x.B0) // t0.Square(&x.B0) - t1 := e.Ext2.Square(&x.B1) // t1.Square(&x.B1) - t2 := e.Ext2.Square(&x.B2) // t2.Square(&x.B2) - t3 := e.Ext2.Mul(&x.B0, &x.B1) // t3.Mul(&x.B0, &x.B1) - t4 := e.Ext2.Mul(&x.B0, &x.B2) // t4.Mul(&x.B0, &x.B2) - t5 := e.Ext2.Mul(&x.B1, &x.B2) // t5.Mul(&x.B1, &x.B2) - c0 := e.Ext2.MulByNonResidue(t5) // c0.MulByNonResidue(&t5). - c0 = e.Ext2.Neg(c0) // Neg(&c0). - c0 = e.Ext2.Add(c0, t0) // Add(&c0, &t0) - c1 := e.Ext2.MulByNonResidue(t2) // c1.MulByNonResidue(&t2). - c1 = e.Ext2.Sub(c1, t3) // Sub(&c1, &t3) - c2 := e.Ext2.Sub(t1, t4) // c2.Sub(&t1, &t4) - t6 := e.Ext2.Mul(&x.B0, c0) // t6.Mul(&x.B0, &c0) - d1 := e.Ext2.Mul(&x.B2, c1) // d1.Mul(&x.B2, &c1) - d2 := e.Ext2.Mul(&x.B1, c2) // d2.Mul(&x.B1, &c2) - d1 = e.Ext2.Add(d1, d2) // d1.Add(&d1, &d2). - d1 = e.Ext2.MulByNonResidue(d1) // MulByNonResidue(&d1) - t6 = e.Ext2.Add(t6, d1) // t6.Add(&t6, &d1) - t6 = e.Ext2.Inverse(t6) // t6.Inverse(&t6) - z0 := e.Ext2.Mul(c0, t6) // z.B0.Mul(&c0, &t6) - z1 := e.Ext2.Mul(c1, t6) // z.B1.Mul(&c1, &t6) - z2 := e.Ext2.Mul(c2, t6) // z.B2.Mul(&c2, &t6) - return &E6{ // return z - B0: *z0, - B1: *z1, - B2: *z2, - } -} func (e Ext6) MulByE2(x *E6, y *E2) *E6 { // var yCopy E2 // yCopy.Set(y) @@ -212,3 +209,117 @@ func FromE6(y *bn254.E6) E6 { } } + +func init() { + solver.RegisterHint(DivE6Hint) + solver.RegisterHint(InverseE6Hint) +} + +func InverseE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, c bn254.E6 + + a.B0.A0.SetBigInt(inputs[0]) + a.B0.A1.SetBigInt(inputs[1]) + a.B1.A0.SetBigInt(inputs[2]) + a.B1.A1.SetBigInt(inputs[3]) + a.B2.A0.SetBigInt(inputs[4]) + a.B2.A1.SetBigInt(inputs[5]) + + c.Inverse(&a) + + c.B0.A0.BigInt(outputs[0]) + c.B0.A1.BigInt(outputs[1]) + c.B1.A0.BigInt(outputs[2]) + c.B1.A1.BigInt(outputs[3]) + c.B2.A0.BigInt(outputs[4]) + c.B2.A1.BigInt(outputs[5]) + + return nil + }) +} + +func DivE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, b, c bn254.E6 + + a.B0.A0.SetBigInt(inputs[0]) + a.B0.A1.SetBigInt(inputs[1]) + a.B1.A0.SetBigInt(inputs[2]) + a.B1.A1.SetBigInt(inputs[3]) + a.B2.A0.SetBigInt(inputs[4]) + a.B2.A1.SetBigInt(inputs[5]) + + b.B0.A0.SetBigInt(inputs[6]) + b.B0.A1.SetBigInt(inputs[7]) + b.B1.A0.SetBigInt(inputs[8]) + b.B1.A1.SetBigInt(inputs[9]) + b.B2.A0.SetBigInt(inputs[10]) + b.B2.A1.SetBigInt(inputs[11]) + + c.Inverse(&b).Mul(&c, &a) + + c.B0.A0.BigInt(outputs[0]) + c.B0.A1.BigInt(outputs[1]) + c.B1.A0.BigInt(outputs[2]) + c.B1.A1.BigInt(outputs[3]) + c.B2.A0.BigInt(outputs[4]) + c.B2.A1.BigInt(outputs[5]) + + return nil + }) +} + +func (e Ext6) Inverse(api frontend.API, x *E6) *E6 { + field, err := emulated.NewField[emulated.BN254Fp](api) + if err != nil { + panic(err) + } + res, err := field.NewHint(InverseE6Hint, 6, &x.B0.A0, &x.B0.A1, &x.B1.A0, &x.B1.A1, &x.B2.A0, &x.B2.A1) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + inv := E6{ + B0: E2{A0: *res[0], A1: *res[1]}, + B1: E2{A0: *res[2], A1: *res[3]}, + B2: E2{A0: *res[4], A1: *res[5]}, + } + + one := e.One() + + // 1 == inv * x + _one := *e.Mul(&inv, x) + e.AssertIsEqual(one, &_one) + + return &inv + +} + +// DivUnchecked e2 elmts +func (e Ext6) DivUnchecked(api frontend.API, x, y E6) *E6 { + field, err := emulated.NewField[emulated.BN254Fp](api) + if err != nil { + panic(err) + } + res, err := field.NewHint(DivE6Hint, 6, &x.B0.A0, &x.B0.A1, &x.B1.A0, &x.B1.A1, &x.B2.A0, &x.B2.A1, &y.B0.A0, &y.B0.A1, &y.B1.A0, &y.B1.A1, &y.B2.A0, &y.B2.A1) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + div := E6{ + B0: E2{A0: *res[0], A1: *res[1]}, + B1: E2{A0: *res[2], A1: *res[3]}, + B2: E2{A0: *res[4], A1: *res[5]}, + } + + // x == div * y + _x := *e.Mul(&div, &y) + e.AssertIsEqual(&x, &_x) + + return &div +} diff --git a/std/algebra/emulated/fields_bn254/e6_test.go b/std/algebra/emulated/fields_bn254/e6_test.go index f37c6ba24d..4d3e96601d 100644 --- a/std/algebra/emulated/fields_bn254/e6_test.go +++ b/std/algebra/emulated/fields_bn254/e6_test.go @@ -138,6 +138,39 @@ func TestSquareFp6(t *testing.T) { } +type e6Div struct { + A, B, C E6 +} + +func (circuit *e6Div) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt6(ba) + + expected := e.DivUnchecked(api, circuit.A, circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestDivFp6(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bn254.E6 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Div(&a, &b) + + witness := e6Div{ + A: FromE6(&a), + B: FromE6(&b), + C: FromE6(&c), + } + + err := test.IsSolved(&e6Div{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + type e6MulByNonResidue struct { A E6 C E6 `gnark:",public"` @@ -285,7 +318,7 @@ func (circuit *e6Inverse) Define(api frontend.API) error { ba, _ := emulated.NewField[emulated.BN254Fp](api) e := NewExt6(ba) - expected := e.Inverse(&circuit.A) + expected := e.Inverse(api, &circuit.A) e.AssertIsEqual(expected, &circuit.C) return nil diff --git a/std/algebra/emulated/sw_bn254/doc_test.go b/std/algebra/emulated/sw_bn254/doc_test.go index db095a0210..f3d41bf4f8 100644 --- a/std/algebra/emulated/sw_bn254/doc_test.go +++ b/std/algebra/emulated/sw_bn254/doc_test.go @@ -23,7 +23,7 @@ func (c *PairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res, err := pairing.Pair([]*sw_bn254.G1Affine{&c.InG1}, []*sw_bn254.G2Affine{&c.InG2}) + res, err := pairing.Pair(api, []*sw_bn254.G1Affine{&c.InG1}, []*sw_bn254.G2Affine{&c.InG2}) if err != nil { return fmt.Errorf("pair: %w", err) } diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 3eb536345a..c5d2f2f344 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -261,28 +261,27 @@ func (pr Pairing) MillerLoop(p []*G1Affine, q []*G2Affine) (*GTEl, error) { return result, nil } -func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { +func (pr Pairing) FinalExponentiation(api frontend.API, e *GTEl) *GTEl { // var result GT // result.Set(z) var t [4]*GTEl // var t [4]GT // easy part t[0] = pr.Ext12.Conjugate(e) - result := pr.Ext12.Inverse(e) - t[0] = pr.Ext12.Mul(t[0], result) - result = pr.Ext12.FrobeniusSquare(t[0]) + t[0] = pr.Ext12.DivUnchecked(api, *t[0], *e) + result := pr.Ext12.FrobeniusSquare(t[0]) result = pr.Ext12.Mul(result, t[0]) //hard part - t[0] = pr.Ext12.Expt(result) + t[0] = pr.Ext12.Expt(api, result) t[0] = pr.Ext12.Conjugate(t[0]) t[0] = pr.Ext12.CyclotomicSquare(t[0]) - t[2] = pr.Ext12.Expt(t[0]) + t[2] = pr.Ext12.Expt(api, t[0]) t[2] = pr.Ext12.Conjugate(t[2]) t[1] = pr.Ext12.CyclotomicSquare(t[2]) t[2] = pr.Ext12.Mul(t[2], t[1]) t[2] = pr.Ext12.Mul(t[2], result) - t[1] = pr.Ext12.Expt(t[2]) + t[1] = pr.Ext12.Expt(api, t[2]) t[1] = pr.Ext12.CyclotomicSquare(t[1]) t[1] = pr.Ext12.Mul(t[1], t[2]) t[1] = pr.Ext12.Conjugate(t[1]) @@ -305,12 +304,12 @@ func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { return t[1] } -func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { +func (pr Pairing) Pair(api frontend.API, P []*G1Affine, Q []*G2Affine) (*GTEl, error) { res, err := pr.MillerLoop(P, Q) if err != nil { return nil, fmt.Errorf("miller loop: %w", err) } - res = pr.FinalExponentiation(res) + res = pr.FinalExponentiation(api, res) return res, nil } diff --git a/std/algebra/emulated/sw_bn254/pairing_test.go b/std/algebra/emulated/sw_bn254/pairing_test.go index 5de8a3bc89..2531474c99 100644 --- a/std/algebra/emulated/sw_bn254/pairing_test.go +++ b/std/algebra/emulated/sw_bn254/pairing_test.go @@ -7,7 +7,10 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/frontend/cs/scs" "github.com/consensys/gnark/test" ) @@ -68,7 +71,7 @@ func (c *FinalExponentiationCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res := pairing.FinalExponentiation(&c.InGt) + res := pairing.FinalExponentiation(api, &c.InGt) pairing.AssertIsEqual(res, &c.Res) return nil } @@ -97,7 +100,7 @@ func (c *PairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res, err := pairing.Pair([]*G1Affine{&c.InG1}, []*G2Affine{&c.InG2}) + res, err := pairing.Pair(api, []*G1Affine{&c.InG1}, []*G2Affine{&c.InG2}) if err != nil { return fmt.Errorf("pair: %w", err) } @@ -118,3 +121,14 @@ func TestPairTestSolve(t *testing.T) { err = test.IsSolved(&PairCircuit{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } + +// bench +var ccsBench constraint.ConstraintSystem + +func BenchmarkFinalExp(b *testing.B) { + var c FinalExponentiationCircuit + ccsBench, _ = frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &c) + b.Log("groth16", ccsBench.GetNbConstraints()) + ccsBench, _ = frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, &c) + b.Log("plonk", ccsBench.GetNbConstraints()) +} From a8af4f3bac57b77af4c76903e863212bfe7f3f28 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 9 Mar 2023 15:29:13 +0100 Subject: [PATCH 087/464] feat: range check gadget (#472) * feat: add external range checker interface * feat: add optional FrontendType method to the builders In range checking gadget we try to estimate the number of constraints given different parameters. But for estimating we need to know the costs of operations. And the costs of the operations depend on the way we arithmetize the circuit. Added an internal interface which allows to query the arithmetization method and implement this in existing builders. * feat: implement range checking * feat: use range checking in field emulation * test: update circuit statistics * test: update stats * test: update stats --- frontend/builder.go | 9 + frontend/cs/r1cs/builder.go | 5 + frontend/cs/scs/api.go | 5 + internal/frontendtype/frontendtype.go | 13 ++ internal/stats/latest.stats | Bin 2803 -> 2803 bytes std/hints.go | 2 + std/math/emulated/field.go | 3 + std/math/emulated/field_assert.go | 55 ++---- std/math/emulated/hints.go | 25 ++- std/rangecheck/rangecheck.go | 30 ++++ std/rangecheck/rangecheck_commit.go | 238 ++++++++++++++++++++++++++ std/rangecheck/rangecheck_plain.go | 14 ++ std/rangecheck/rangecheck_test.go | 50 ++++++ 13 files changed, 399 insertions(+), 50 deletions(-) create mode 100644 internal/frontendtype/frontendtype.go create mode 100644 std/rangecheck/rangecheck.go create mode 100644 std/rangecheck/rangecheck_commit.go create mode 100644 std/rangecheck/rangecheck_plain.go create mode 100644 std/rangecheck/rangecheck_test.go diff --git a/frontend/builder.go b/frontend/builder.go index 7dd1b6c488..cd52e71169 100644 --- a/frontend/builder.go +++ b/frontend/builder.go @@ -78,3 +78,12 @@ type Committer interface { // Commit commits to the variables and returns the commitment. Commit(toCommit ...Variable) (commitment Variable, err error) } + +// Rangechecker allows to externally range-check the variables to be of +// specified width. Not all compilers implement this interface. Users should +// instead use [github.com/consensys/gnark/std/rangecheck] package which +// automatically chooses most optimal method for range checking the variables. +type Rangechecker interface { + // Check checks that the given variable v has bit-length bits. + Check(v Variable, bits int) +} diff --git a/frontend/cs/r1cs/builder.go b/frontend/cs/r1cs/builder.go index 87ac36d348..6d085e41fc 100644 --- a/frontend/cs/r1cs/builder.go +++ b/frontend/cs/r1cs/builder.go @@ -29,6 +29,7 @@ import ( "github.com/consensys/gnark/frontend/internal/expr" "github.com/consensys/gnark/frontend/schema" "github.com/consensys/gnark/internal/circuitdefer" + "github.com/consensys/gnark/internal/frontendtype" "github.com/consensys/gnark/internal/kvstore" "github.com/consensys/gnark/internal/tinyfield" "github.com/consensys/gnark/internal/utils" @@ -452,3 +453,7 @@ func (builder *builder) compress(le expr.LinearExpression) expr.LinearExpression func (builder *builder) Defer(cb func(frontend.API) error) { circuitdefer.Put(builder, cb) } + +func (*builder) FrontendType() frontendtype.Type { + return frontendtype.R1CS +} diff --git a/frontend/cs/scs/api.go b/frontend/cs/scs/api.go index f9f379fcf5..fb1ecbf2d8 100644 --- a/frontend/cs/scs/api.go +++ b/frontend/cs/scs/api.go @@ -28,6 +28,7 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/internal/expr" "github.com/consensys/gnark/frontend/schema" + "github.com/consensys/gnark/internal/frontendtype" "github.com/consensys/gnark/std/math/bits" ) @@ -557,3 +558,7 @@ func (builder *builder) printArg(log *constraint.LogEntry, sbb *strings.Builder, func (builder *builder) Compiler() frontend.Compiler { return builder } + +func (*builder) FrontendType() frontendtype.Type { + return frontendtype.SCS +} diff --git a/internal/frontendtype/frontendtype.go b/internal/frontendtype/frontendtype.go new file mode 100644 index 0000000000..040af53c5b --- /dev/null +++ b/internal/frontendtype/frontendtype.go @@ -0,0 +1,13 @@ +// Package frontendtype allows to assert frontend type. +package frontendtype + +type Type int + +const ( + R1CS Type = iota + SCS +) + +type FrontendTyper interface { + FrontendType() Type +} diff --git a/internal/stats/latest.stats b/internal/stats/latest.stats index 3d6d18dabdd36c14139e188342d94235a0d0a3a6..0948135ddd60782be3462ac0fc7be1924cd8e438 100644 GIT binary patch delta 249 zcmew?`dM^B*5oCuEt88_9!%!rdOG<(ThL@fj)$AKFzsWUtig7Dav=MI$w90^ll7Te zCkt`@*_g%3STFL2@t;x#1LHqD3;`d;f07_If)$Maq*ovmGjK5eD_;e~dO$Hej1Vry Vf5Gd3YGOVCaUVi4gCoTz007S{V{!lh delta 246 zcmew?`dM^B)@D6UR>pdZZH)gctQdd b.overflow { - assertLimbsEqualitySlow(f.api, ca, cb, bitsPerLimb, a.overflow) + f.assertLimbsEqualitySlow(f.api, ca, cb, bitsPerLimb, a.overflow) } else { - assertLimbsEqualitySlow(f.api, cb, ca, bitsPerLimb, b.overflow) + f.assertLimbsEqualitySlow(f.api, cb, ca, bitsPerLimb, b.overflow) } } @@ -133,10 +109,7 @@ func (f *Field[T]) enforceWidth(a *Element[T], modWidth bool) { // take only required bits from the most significant limb limbNbBits = ((f.fParams.Modulus().BitLen() - 1) % int(f.fParams.BitsPerLimb())) + 1 } - // bits.ToBinary restricts the least significant NbDigits to be equal to - // the limb value. This is sufficient to restrict for the bitlength and - // we can discard the bits themselves. - bits.ToBinary(f.api, a.Limbs[i], bits.WithNbDigits(limbNbBits)) + f.checker.Check(a.Limbs[i], limbNbBits) } } diff --git a/std/math/emulated/hints.go b/std/math/emulated/hints.go index 9901aab49f..00ecd2d8f6 100644 --- a/std/math/emulated/hints.go +++ b/std/math/emulated/hints.go @@ -23,7 +23,7 @@ func GetHints() []solver.Hint { InverseHint, MultiplicationHint, RemHint, - NBitsShifted, + RightShift, } } @@ -287,13 +287,20 @@ func parseHintDivInputs(inputs []*big.Int) (uint, int, *big.Int, *big.Int, error return nbBits, nbLimbs, x, y, nil } -// NBitsShifted returns the first bits of the input, with a shift. The number of returned bits is -// defined by the length of the results slice. -func NBitsShifted(_ *big.Int, inputs []*big.Int, results []*big.Int) error { - n := inputs[0] - shift := inputs[1].Uint64() // TODO @gbotrel validate input vs perf in large circuits. - for i := 0; i < len(results); i++ { - results[i].SetUint64(uint64(n.Bit(i + int(shift)))) - } +// RightShift shifts input by the given number of bits. Expects two inputs: +// - first input is the shift, will be represented as uint64; +// - second input is the value to be shifted. +// +// Returns a single output which is the value shifted. Errors if number of +// inputs is not 2 and number of outputs is not 1. +func RightShift(_ *big.Int, inputs []*big.Int, outputs []*big.Int) error { + if len(inputs) != 2 { + return fmt.Errorf("expecting two inputs") + } + if len(outputs) != 1 { + return fmt.Errorf("expecting single output") + } + shift := inputs[0].Uint64() + outputs[0].Rsh(inputs[1], uint(shift)) return nil } diff --git a/std/rangecheck/rangecheck.go b/std/rangecheck/rangecheck.go new file mode 100644 index 0000000000..b3bf870690 --- /dev/null +++ b/std/rangecheck/rangecheck.go @@ -0,0 +1,30 @@ +// Package rangecheck implements range checking gadget +// +// This package chooses the most optimal path for performing range checks: +// - if the backend supports native range checking and the frontend exports the variables in the proprietary format by implementing [frontend.Rangechecker], then use it directly; +// - if the backend supports creating a commitment of variables by implementing [frontend.Committer], then we use the product argument as in [BCG+18]. [r1cs.NewBuilder] returns a builder which implements this interface; +// - lacking these, we perform binary decomposition of variable into bits. +// +// [BCG+18]: https://eprint.iacr.org/2018/380 +package rangecheck + +import ( + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" +) + +// only for documentation purposes. If we import the package then godoc knows +// how to refer to package r1cs and we get nice links in godoc. We import the +// package anyway in test. +var _ = r1cs.NewBuilder + +// New returns a new range checker depending on the frontend capabilities. +func New(api frontend.API) frontend.Rangechecker { + if rc, ok := api.(frontend.Rangechecker); ok { + return rc + } + if _, ok := api.(frontend.Committer); ok { + return newCommitRangechecker(api) + } + return plainChecker{api: api} +} diff --git a/std/rangecheck/rangecheck_commit.go b/std/rangecheck/rangecheck_commit.go new file mode 100644 index 0000000000..f5b6ddb30c --- /dev/null +++ b/std/rangecheck/rangecheck_commit.go @@ -0,0 +1,238 @@ +package rangecheck + +import ( + "fmt" + "math" + "math/big" + stdbits "math/bits" + + "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/internal/frontendtype" + "github.com/consensys/gnark/internal/kvstore" + "github.com/consensys/gnark/std/math/bits" +) + +type ctxCheckerKey struct{} + +func init() { + solver.RegisterHint(DecomposeHint, CountHint) +} + +type checkedVariable struct { + v frontend.Variable + bits int +} + +type commitChecker struct { + collected []checkedVariable + closed bool +} + +func newCommitRangechecker(api frontend.API) *commitChecker { + kv, ok := api.Compiler().(kvstore.Store) + if !ok { + panic("builder should implement key-value store") + } + ch := kv.GetKeyValue(ctxCheckerKey{}) + if ch != nil { + if cht, ok := ch.(*commitChecker); ok { + return cht + } else { + panic("stored rangechecker is not valid") + } + } + cht := &commitChecker{} + kv.SetKeyValue(ctxCheckerKey{}, cht) + api.Compiler().Defer(cht.commit) + return cht +} + +func (c *commitChecker) Check(in frontend.Variable, bits int) { + if c.closed { + panic("checker already closed") + } + c.collected = append(c.collected, checkedVariable{v: in, bits: bits}) +} + +func (c *commitChecker) commit(api frontend.API) error { + if c.closed { + return nil + } + defer func() { c.closed = true }() + if len(c.collected) == 0 { + return nil + } + committer, ok := api.(frontend.Committer) + if !ok { + panic("expected committer API") + } + baseLength := c.getOptimalBasewidth(api) + // decompose into smaller limbs + decomposed := make([]frontend.Variable, 0, len(c.collected)) + collected := make([]frontend.Variable, len(c.collected)) + base := new(big.Int).Lsh(big.NewInt(1), uint(baseLength)) + for i := range c.collected { + // collect all vars for commitment input + collected[i] = c.collected[i].v + // decompose value into limbs + nbLimbs := decompSize(c.collected[i].bits, baseLength) + limbs, err := api.Compiler().NewHint(DecomposeHint, int(nbLimbs), c.collected[i].bits, baseLength, c.collected[i].v) + if err != nil { + panic(fmt.Sprintf("decompose %v", err)) + } + // store all limbs for counting + decomposed = append(decomposed, limbs...) + // check that limbs are correct. We check the sizes of the limbs later + var composed frontend.Variable = 0 + for j := range limbs { + composed = api.Add(composed, api.Mul(limbs[j], new(big.Int).Exp(base, big.NewInt(int64(j)), nil))) + } + api.AssertIsEqual(composed, c.collected[i].v) + } + nbTable := 1 << baseLength + // compute the counts for every value in the range + exps, err := api.Compiler().NewHint(CountHint, nbTable, decomposed...) + if err != nil { + panic(fmt.Sprintf("count %v", err)) + } + // compute the poly \pi (X - s_i)^{e_i} + commitment, err := committer.Commit(collected...) + if err != nil { + panic(fmt.Sprintf("commit %v", err)) + } + logn := stdbits.Len(uint(len(decomposed))) + var lp frontend.Variable = 1 + for i := 0; i < nbTable; i++ { + expbits := bits.ToBinary(api, exps[i], bits.WithNbDigits(logn)) + var acc frontend.Variable = 1 + tmp := api.Sub(commitment, i) + for j := 0; j < logn; j++ { + curr := api.Select(expbits[j], tmp, 1) + acc = api.Mul(acc, curr) + tmp = api.Mul(tmp, tmp) + } + lp = api.Mul(lp, acc) + } + // compute the poly \pi (X - f_i) + var rp frontend.Variable = 1 + for i := range decomposed { + val := api.Sub(commitment, decomposed[i]) + rp = api.Mul(rp, val) + } + api.AssertIsEqual(lp, rp) + return nil +} + +func decompSize(varSize int, limbSize int) int { + return (varSize + limbSize - 1) / limbSize +} + +// DecomposeHint is a hint used for range checking with commitment. It +// decomposes large variables into chunks which can be individually range-check +// in the native range. +func DecomposeHint(m *big.Int, inputs []*big.Int, outputs []*big.Int) error { + if len(inputs) != 3 { + return fmt.Errorf("input must be 3 elements") + } + if !inputs[0].IsUint64() || !inputs[1].IsUint64() { + return fmt.Errorf("first two inputs have to be uint64") + } + varSize := int(inputs[0].Int64()) + limbSize := int(inputs[1].Int64()) + val := inputs[2] + nbLimbs := decompSize(varSize, limbSize) + if len(outputs) != nbLimbs { + return fmt.Errorf("need %d outputs instead to decompose", nbLimbs) + } + base := new(big.Int).Lsh(big.NewInt(1), uint(limbSize)) + tmp := new(big.Int).Set(val) + for i := 0; i < len(outputs); i++ { + outputs[i].Mod(tmp, base) + tmp.Rsh(tmp, uint(limbSize)) + } + return nil +} + +// CountHint is a hint function which is used in range checking using +// commitment. It counts the occurences of checked variables in the range and +// returns the counts. +func CountHint(m *big.Int, inputs []*big.Int, outputs []*big.Int) error { + nbVals := len(outputs) + if len(outputs) != nbVals { + return fmt.Errorf("output size %d does not match range size %d", len(outputs), nbVals) + } + counts := make(map[uint64]uint64, nbVals) + for i := 0; i < len(inputs); i++ { + if !inputs[i].IsUint64() { + return fmt.Errorf("input %d not uint64", i) + } + c := inputs[i].Uint64() + counts[c]++ + } + for i := 0; i < nbVals; i++ { + outputs[i].SetUint64(counts[uint64(i)]) + } + return nil +} + +func (c *commitChecker) getOptimalBasewidth(api frontend.API) int { + if ft, ok := api.(frontendtype.FrontendTyper); ok { + switch ft.FrontendType() { + case frontendtype.R1CS: + return optimalWidth(nbR1CSConstraints, c.collected) + case frontendtype.SCS: + return optimalWidth(nbPLONKConstraints, c.collected) + } + } + return optimalWidth(nbR1CSConstraints, c.collected) +} + +func optimalWidth(countFn func(baseLength int, collected []checkedVariable) int, collected []checkedVariable) int { + min := math.MaxInt64 + minVal := 0 + for j := 2; j < 18; j++ { + current := countFn(j, collected) + if current < min { + min = current + minVal = j + } + } + return minVal +} + +func nbR1CSConstraints(baseLength int, collected []checkedVariable) int { + nbDecomposed := 0 + for i := range collected { + nbDecomposed += int(decompSize(collected[i].bits, baseLength)) + } + eqs := len(collected) // single composition check per collected + logn := stdbits.Len(uint(nbDecomposed)) + nbTable := 1 << baseLength + nbLeft := nbTable * + (logn + // tobinary + logn + // select per exponent bit + logn + // mul per exponent bit + logn + // mul per exponent bit + 1) // final mul + nbRight := nbDecomposed // mul all decomposed + return nbLeft + nbRight + eqs + 1 // single for final equality +} + +func nbPLONKConstraints(baseLength int, collected []checkedVariable) int { + nbDecomposed := 0 + for i := range collected { + nbDecomposed += int(decompSize(collected[i].bits, baseLength)) + } + eqs := nbDecomposed // check correctness of every decomposition. this is nbDecomp adds + eq cost per collected + logn := stdbits.Len(uint(nbDecomposed)) + nbTable := 1 << baseLength + nbLeft := nbTable * + (3*logn + // tobinary. decomposition check + binary check + 2*logn + // select per exponent bit + logn + // mul per exponent bit + logn + // mul per exponent bit + 1) // final mul + nbRight := 2 * nbDecomposed // per decomposed sub and mul + return nbLeft + nbRight + eqs + 1 // single for final equality +} diff --git a/std/rangecheck/rangecheck_plain.go b/std/rangecheck/rangecheck_plain.go new file mode 100644 index 0000000000..6f20418f2d --- /dev/null +++ b/std/rangecheck/rangecheck_plain.go @@ -0,0 +1,14 @@ +package rangecheck + +import ( + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/math/bits" +) + +type plainChecker struct { + api frontend.API +} + +func (pl plainChecker) Check(v frontend.Variable, nbBits int) { + bits.ToBinary(pl.api, v, bits.WithNbDigits(nbBits)) +} diff --git a/std/rangecheck/rangecheck_test.go b/std/rangecheck/rangecheck_test.go new file mode 100644 index 0000000000..e135376afb --- /dev/null +++ b/std/rangecheck/rangecheck_test.go @@ -0,0 +1,50 @@ +package rangecheck + +import ( + "crypto/rand" + "math/big" + "testing" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/field/goldilocks" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/test" +) + +type CheckCircuit struct { + Vals []frontend.Variable + bits int + base int +} + +func (c *CheckCircuit) Define(api frontend.API) error { + r := newCommitRangechecker(api) + for i := range c.Vals { + r.Check(c.Vals[i], c.bits) + } + return nil +} + +func TestCheck(t *testing.T) { + assert := test.NewAssert(t) + var err error + bits := 64 + base := 11 + nbVals := 100000 + bound := new(big.Int).Lsh(big.NewInt(1), uint(bits)) + vals := make([]frontend.Variable, nbVals) + for i := range vals { + vals[i], err = rand.Int(rand.Reader, bound) + if err != nil { + t.Fatal(err) + } + } + witness := CheckCircuit{Vals: vals, bits: bits, base: base} + circuit := CheckCircuit{Vals: make([]frontend.Variable, len(vals)), bits: bits, base: base} + err = test.IsSolved(&circuit, &witness, goldilocks.Modulus()) + assert.NoError(err) + ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) + assert.NoError(err) + t.Log(ccs.GetNbConstraints()) +} From 28b29dea06185e723d266d5c0093648e24243256 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 9 Mar 2023 16:46:32 +0100 Subject: [PATCH 088/464] fix: do not pass limb width enforcement for consts in AssertIsEqual (#550) * fix: enforce emulated element width also in AssetIsEqual header Previously we didn't conditionally enforce the width in the method as it was done in the methods we called. However, there is a short path for constants and in that case the check was omitted. Add width enforcement to the header of the method to ensure it is also enforce for const inputs. * feat: display fuzzer input which fails test * fix: use given curve --- std/math/emulated/field_assert.go | 3 ++- test/assert.go | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/std/math/emulated/field_assert.go b/std/math/emulated/field_assert.go index af16d4e065..5e9f6e3902 100644 --- a/std/math/emulated/field_assert.go +++ b/std/math/emulated/field_assert.go @@ -115,7 +115,8 @@ func (f *Field[T]) enforceWidth(a *Element[T], modWidth bool) { // AssertIsEqual ensures that a is equal to b modulo the modulus. func (f *Field[T]) AssertIsEqual(a, b *Element[T]) { - // we omit width assertion as it is done in Sub below + f.enforceWidthConditional(a) + f.enforceWidthConditional(b) ba, aConst := f.constantValue(a) bb, bConst := f.constantValue(b) if aConst && bConst { diff --git a/test/assert.go b/test/assert.go index e15fc4aab5..0c916ee88d 100644 --- a/test/assert.go +++ b/test/assert.go @@ -369,8 +369,22 @@ func (assert *Assert) fuzzer(fuzzer filler, circuit, w frontend.Circuit, b backe errConsts := IsSolved(circuit, w, curve.ScalarField(), SetAllVariablesAsConstants()) if (errVars == nil) != (errConsts == nil) { + w, err := frontend.NewWitness(w, curve.ScalarField()) + if err != nil { + panic(err) + } + s, err := frontend.NewSchema(circuit) + if err != nil { + panic(err) + } + bb, err := w.ToJSON(s) + if err != nil { + panic(err) + } + assert.Log("errVars", errVars) assert.Log("errConsts", errConsts) + assert.Log("fuzzer witness", string(bb)) assert.FailNow("solving circuit with values as constants vs non-constants mismatched result") } From 43a9235c88336e4e180ca9f8f8994ef65f99ba9d Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Thu, 9 Mar 2023 09:58:18 -0600 Subject: [PATCH 089/464] fix #527 when fuzzer reports bug for inconsistency between bit decomposition with constant and with variable (#546) * fix: fix #527 when fuzzer reports bug for inconsistency between bit decomposition with constant and with variable * fix: std/math/bits same path for const and non-const --- std/math/bits/conversion_binary.go | 9 --------- std/math/bits/conversion_ternary.go | 16 ---------------- std/math/bits/naf.go | 16 ---------------- 3 files changed, 41 deletions(-) diff --git a/std/math/bits/conversion_binary.go b/std/math/bits/conversion_binary.go index 88edb6b504..6fb3cb8fcc 100644 --- a/std/math/bits/conversion_binary.go +++ b/std/math/bits/conversion_binary.go @@ -63,15 +63,6 @@ func toBinary(api frontend.API, v frontend.Variable, opts ...BaseConversionOptio } } - // if a is a constant, work with the big int value. - if c, ok := api.Compiler().ConstantValue(v); ok { - bits := make([]frontend.Variable, cfg.NbDigits) - for i := 0; i < len(bits); i++ { - bits[i] = c.Bit(i) - } - return bits - } - c := big.NewInt(1) bits, err := api.Compiler().NewHint(NBits, cfg.NbDigits, v) diff --git a/std/math/bits/conversion_ternary.go b/std/math/bits/conversion_ternary.go index f71cbf74fe..7e366eb1d9 100644 --- a/std/math/bits/conversion_ternary.go +++ b/std/math/bits/conversion_ternary.go @@ -67,22 +67,6 @@ func toTernary(api frontend.API, v frontend.Variable, opts ...BaseConversionOpti } } - // if a is a constant, work with the big int value. - if c, ok := api.Compiler().ConstantValue(v); ok { - trits := make([]frontend.Variable, cfg.NbDigits) - // TODO using big.Int Text is likely not cheap - base3 := c.Text(3) - i := 0 - for j := len(base3) - 1; j >= 0 && i < len(trits); j-- { - trits[i] = int(base3[j] - 48) - i++ - } - for ; i < len(trits); i++ { - trits[i] = 0 - } - return trits - } - c := big.NewInt(1) b := big.NewInt(3) diff --git a/std/math/bits/naf.go b/std/math/bits/naf.go index fdabb71bb6..cf62dc0183 100644 --- a/std/math/bits/naf.go +++ b/std/math/bits/naf.go @@ -32,22 +32,6 @@ func ToNAF(api frontend.API, v frontend.Variable, opts ...BaseConversionOption) } } - // if v is a constant, work with the big int value. - if c, ok := api.Compiler().ConstantValue(v); ok { - bits := make([]*big.Int, cfg.NbDigits) - for i := 0; i < len(bits); i++ { - bits[i] = big.NewInt(0) - } - if err := nafDecomposition(c, bits); err != nil { - panic(err) - } - res := make([]frontend.Variable, len(bits)) - for i := 0; i < len(bits); i++ { - res[i] = bits[i] - } - return res - } - c := big.NewInt(1) bits, err := api.Compiler().NewHint(NNAF, cfg.NbDigits, v) From 78bc582d19b96c3379c5838694c077f529cc7ce1 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Thu, 9 Mar 2023 17:44:03 +0100 Subject: [PATCH 090/464] perf(bn254-pair): optimize fields ops + cleaning --- std/algebra/emulated/fields_bn254/e12.go | 244 +++++++++++------------ std/algebra/emulated/fields_bn254/e2.go | 96 ++++----- std/algebra/emulated/fields_bn254/e6.go | 185 +++++++++-------- 3 files changed, 244 insertions(+), 281 deletions(-) diff --git a/std/algebra/emulated/fields_bn254/e12.go b/std/algebra/emulated/fields_bn254/e12.go index 20cd949616..37575bdb79 100644 --- a/std/algebra/emulated/fields_bn254/e12.go +++ b/std/algebra/emulated/fields_bn254/e12.go @@ -22,8 +22,8 @@ func NewExt12(baseField *curveF) *Ext12 { } func (e Ext12) Add(x, y *E12) *E12 { - z0 := e.Ext6.Add(&x.C0, &y.C0) // z.C0.Add(&x.A0, &y.A0) - z1 := e.Ext6.Add(&x.C1, &y.C1) // z.C1.Add(&x.A1, &y.A1) + z0 := e.Ext6.Add(&x.C0, &y.C0) + z1 := e.Ext6.Add(&x.C1, &y.C1) return &E12{ C0: *z0, C1: *z1, @@ -31,8 +31,8 @@ func (e Ext12) Add(x, y *E12) *E12 { } func (e Ext12) Sub(x, y *E12) *E12 { - z0 := e.Ext6.Sub(&x.C0, &y.C0) // z.C0.Sub(&x.A0, &y.A0) - z1 := e.Ext6.Sub(&x.C1, &y.C1) // z.C1.Sub(&x.A1, &y.A1) + z0 := e.Ext6.Sub(&x.C0, &y.C0) + z1 := e.Ext6.Sub(&x.C1, &y.C1) return &E12{ C0: *z0, C1: *z1, @@ -40,76 +40,74 @@ func (e Ext12) Sub(x, y *E12) *E12 { } func (e Ext12) Conjugate(x *E12) *E12 { - z1 := e.Ext6.Neg(&x.C1) // z.C1.Neg(&z.C1) - return &E12{ // return z + z1 := e.Ext6.Neg(&x.C1) + return &E12{ C0: x.C0, C1: *z1, } } func (e Ext12) Mul(x, y *E12) *E12 { - // var a, b, c E6 - a := e.Ext6.Add(&x.C0, &x.C1) // a.Add(&x.C0, &x.C1) - b := e.Ext6.Add(&y.C0, &y.C1) // b.Add(&y.C0, &y.C1) - a = e.Ext6.Mul(a, b) // a.Mul(&a, &b) - b = e.Ext6.Mul(&x.C0, &y.C0) // b.Mul(&x.C0, &y.C0) - c := e.Ext6.Mul(&x.C1, &y.C1) // c.Mul(&x.C1, &y.C1) - z1 := e.Ext6.Sub(a, b) // z.C1.Sub(&a, &b). - z1 = e.Ext6.Sub(z1, c) // Sub(&z.C1, &c) - z0 := e.Ext6.MulByNonResidue(c) // z.C0.MulByNonResidue(&c). - z0 = e.Ext6.Add(z0, b) // Add(&z.C0, &b) - return &E12{ // return z + a := e.Ext6.Add(&x.C0, &x.C1) + b := e.Ext6.Add(&y.C0, &y.C1) + a = e.Ext6.Mul(a, b) + b = e.Ext6.Mul(&x.C0, &y.C0) + c := e.Ext6.Mul(&x.C1, &y.C1) + z1 := e.Ext6.Sub(a, b) + z1 = e.Ext6.Sub(z1, c) + z0 := e.Ext6.MulByNonResidue(c) + z0 = e.Ext6.Add(z0, b) + return &E12{ C0: *z0, C1: *z1, } } func (e Ext12) CyclotomicSquare(x *E12) *E12 { - // var t [9]E2 - t0 := e.Ext2.Square(&x.C1.B1) // t[0].Square(&x.C1.B1) - t1 := e.Ext2.Square(&x.C0.B0) // t[1].Square(&x.C0.B0) - t6 := e.Ext2.Add(&x.C1.B1, &x.C0.B0) // t[6].Add(&x.C1.B1, &x.C0.B0). - t6 = e.Ext2.Square(t6) // Square(&t[6]). - t6 = e.Ext2.Sub(t6, t0) // Sub(&t[6], &t[0]). - t6 = e.Ext2.Sub(t6, t1) // Sub(&t[6], &t[1]) - t2 := e.Ext2.Square(&x.C0.B2) // t[2].Square(&x.C0.B2) - t3 := e.Ext2.Square(&x.C1.B0) // t[3].Square(&x.C1.B0) - t7 := e.Ext2.Add(&x.C0.B2, &x.C1.B0) // t[7].Add(&x.C0.B2, &x.C1.B0). - t7 = e.Ext2.Square(t7) // Square(&t[7]). - t7 = e.Ext2.Sub(t7, t2) // Sub(&t[7], &t[2]). - t7 = e.Ext2.Sub(t7, t3) // Sub(&t[7], &t[3]) - t4 := e.Ext2.Square(&x.C1.B2) // t[4].Square(&x.C1.B2) - t5 := e.Ext2.Square(&x.C0.B1) // t[5].Square(&x.C0.B1) - t8 := e.Ext2.Add(&x.C1.B2, &x.C0.B1) // t[8].Add(&x.C1.B2, &x.C0.B1). - t8 = e.Ext2.Square(t8) // Square(&t[8]). - t8 = e.Ext2.Sub(t8, t4) // Sub(&t[8], &t[4]). - t8 = e.Ext2.Sub(t8, t5) // Sub(&t[8], &t[5]). - t8 = e.Ext2.MulByNonResidue(t8) // MulByNonResidue(&t[8]) - t0 = e.Ext2.MulByNonResidue(t0) // t[0].MulByNonResidue(&t[0]). - t0 = e.Ext2.Add(t0, t1) // Add(&t[0], &t[1]) - t2 = e.Ext2.MulByNonResidue(t2) // t[2].MulByNonResidue(&t[2]). - t2 = e.Ext2.Add(t2, t3) // Add(&t[2], &t[3]) - t4 = e.Ext2.MulByNonResidue(t4) // t[4].MulByNonResidue(&t[4]). - t4 = e.Ext2.Add(t4, t5) // Add(&t[4], &t[5]) - z00 := e.Ext2.Sub(t0, &x.C0.B0) // z.C0.B0.Sub(&t[0], &x.C0.B0). - z00 = e.Ext2.Double(z00) // Double(&z.C0.B0). - z00 = e.Ext2.Add(z00, t0) // Add(&z.C0.B0, &t[0]) - z01 := e.Ext2.Sub(t2, &x.C0.B1) // z.C0.B1.Sub(&t[2], &x.C0.B1). - z01 = e.Ext2.Double(z01) // Double(&z.C0.B1). - z01 = e.Ext2.Add(z01, t2) // Add(&z.C0.B1, &t[2]) - z02 := e.Ext2.Sub(t4, &x.C0.B2) // z.C0.B2.Sub(&t[4], &x.C0.B2). - z02 = e.Ext2.Double(z02) // Double(&z.C0.B2). - z02 = e.Ext2.Add(z02, t4) // Add(&z.C0.B2, &t[4]) - z10 := e.Ext2.Add(t8, &x.C1.B0) // z.C1.B0.Add(&t[8], &x.C1.B0). - z10 = e.Ext2.Double(z10) // Double(&z.C1.B0). - z10 = e.Ext2.Add(z10, t8) // Add(&z.C1.B0, &t[8]) - z11 := e.Ext2.Add(t6, &x.C1.B1) // z.C1.B1.Add(&t[6], &x.C1.B1). - z11 = e.Ext2.Double(z11) // Double(&z.C1.B1). - z11 = e.Ext2.Add(z11, t6) // Add(&z.C1.B1, &t[6]) - z12 := e.Ext2.Add(t7, &x.C1.B2) // z.C1.B2.Add(&t[7], &x.C1.B2). - z12 = e.Ext2.Double(z12) // Double(&z.C1.B2). - z12 = e.Ext2.Add(z12, t7) // Add(&z.C1.B2, &t[7]) - return &E12{ // return z + t0 := e.Ext2.Square(&x.C1.B1) + t1 := e.Ext2.Square(&x.C0.B0) + t6 := e.Ext2.Add(&x.C1.B1, &x.C0.B0) + t6 = e.Ext2.Square(t6) + t6 = e.Ext2.Sub(t6, t0) + t6 = e.Ext2.Sub(t6, t1) + t2 := e.Ext2.Square(&x.C0.B2) + t3 := e.Ext2.Square(&x.C1.B0) + t7 := e.Ext2.Add(&x.C0.B2, &x.C1.B0) + t7 = e.Ext2.Square(t7) + t7 = e.Ext2.Sub(t7, t2) + t7 = e.Ext2.Sub(t7, t3) + t4 := e.Ext2.Square(&x.C1.B2) + t5 := e.Ext2.Square(&x.C0.B1) + t8 := e.Ext2.Add(&x.C1.B2, &x.C0.B1) + t8 = e.Ext2.Square(t8) + t8 = e.Ext2.Sub(t8, t4) + t8 = e.Ext2.Sub(t8, t5) + t8 = e.Ext2.MulByNonResidue(t8) + t0 = e.Ext2.MulByNonResidue(t0) + t0 = e.Ext2.Add(t0, t1) + t2 = e.Ext2.MulByNonResidue(t2) + t2 = e.Ext2.Add(t2, t3) + t4 = e.Ext2.MulByNonResidue(t4) + t4 = e.Ext2.Add(t4, t5) + z00 := e.Ext2.Sub(t0, &x.C0.B0) + z00 = e.Ext2.Double(z00) + z00 = e.Ext2.Add(z00, t0) + z01 := e.Ext2.Sub(t2, &x.C0.B1) + z01 = e.Ext2.Double(z01) + z01 = e.Ext2.Add(z01, t2) + z02 := e.Ext2.Sub(t4, &x.C0.B2) + z02 = e.Ext2.Double(z02) + z02 = e.Ext2.Add(z02, t4) + z10 := e.Ext2.Add(t8, &x.C1.B0) + z10 = e.Ext2.Double(z10) + z10 = e.Ext2.Add(z10, t8) + z11 := e.Ext2.Add(t6, &x.C1.B1) + z11 = e.Ext2.Double(z11) + z11 = e.Ext2.Add(z11, t6) + z12 := e.Ext2.Add(t7, &x.C1.B2) + z12 = e.Ext2.Double(z12) + z12 = e.Ext2.Add(z12, t7) + return &E12{ C0: E6{ B0: *z00, B1: *z01, @@ -123,13 +121,6 @@ func (e Ext12) CyclotomicSquare(x *E12) *E12 { } } -func (e Ext12) NCycloSquare(z *E12, n int) *E12 { - for i := 0; i < n; i++ { - z = e.CyclotomicSquare(z) - } - return z -} - // Karabina's compressed cyclotomic square // https://eprint.iacr.org/2010/542.pdf // Th. 3.2 with minor modifications to fit our tower @@ -246,9 +237,7 @@ func (e Ext12) DecompressKarabina(api frontend.API, x *E12) *E12 { t1 = e.Ext6.Ext2.Double(t1) // z4 = g4 - // TODO: Div instead of Inv+Mul - C1B1 := e.Ext6.Ext2.Inverse(api, t1) - C1B1 = e.Ext6.Ext2.Mul(C1B1, t0) + C1B1 := e.Ext6.Ext2.DivUnchecked(api, *t0, *t1) // t1 = g2 * g1 t1 = e.Ext6.Ext2.Mul(&x.C0.B2, &x.C0.B1) @@ -279,68 +268,66 @@ func (e Ext12) DecompressKarabina(api frontend.API, x *E12) *E12 { } func (e Ext12) Frobenius(x *E12) *E12 { - // var t [6]E2 - t0 := e.Ext2.Conjugate(&x.C0.B0) // t[0].Conjugate(&x.C0.B0) - t1 := e.Ext2.Conjugate(&x.C0.B1) // t[1].Conjugate(&x.C0.B1) - t2 := e.Ext2.Conjugate(&x.C0.B2) // t[2].Conjugate(&x.C0.B2) - t3 := e.Ext2.Conjugate(&x.C1.B0) // t[3].Conjugate(&x.C1.B0) - t4 := e.Ext2.Conjugate(&x.C1.B1) // t[4].Conjugate(&x.C1.B1) - t5 := e.Ext2.Conjugate(&x.C1.B2) // t[5].Conjugate(&x.C1.B2) - t1 = e.Ext2.MulByNonResidue1Power2(t1) // t[1].MulByNonResidue1Power2(&t[1]) - t2 = e.Ext2.MulByNonResidue1Power4(t2) // t[2].MulByNonResidue1Power4(&t[2]) - t3 = e.Ext2.MulByNonResidue1Power1(t3) // t[3].MulByNonResidue1Power1(&t[3]) - t4 = e.Ext2.MulByNonResidue1Power3(t4) // t[4].MulByNonResidue1Power3(&t[4]) - t5 = e.Ext2.MulByNonResidue1Power5(t5) // t[5].MulByNonResidue1Power5(&t[5]) - return &E12{ // return z + t0 := e.Ext2.Conjugate(&x.C0.B0) + t1 := e.Ext2.Conjugate(&x.C0.B1) + t2 := e.Ext2.Conjugate(&x.C0.B2) + t3 := e.Ext2.Conjugate(&x.C1.B0) + t4 := e.Ext2.Conjugate(&x.C1.B1) + t5 := e.Ext2.Conjugate(&x.C1.B2) + t1 = e.Ext2.MulByNonResidue1Power2(t1) + t2 = e.Ext2.MulByNonResidue1Power4(t2) + t3 = e.Ext2.MulByNonResidue1Power1(t3) + t4 = e.Ext2.MulByNonResidue1Power3(t4) + t5 = e.Ext2.MulByNonResidue1Power5(t5) + return &E12{ C0: E6{ - B0: *t0, // z.C0.B0 = t[0] - B1: *t1, // z.C0.B1 = t[1] - B2: *t2, // z.C0.B2 = t[2] + B0: *t0, + B1: *t1, + B2: *t2, }, C1: E6{ - B0: *t3, // z.C1.B0 = t[3] - B1: *t4, // z.C1.B1 = t[4] - B2: *t5, // z.C1.B2 = t[5] + B0: *t3, + B1: *t4, + B2: *t5, }, } } func (e Ext12) FrobeniusSquare(x *E12) *E12 { - z00 := &x.C0.B0 // z.C0.B0 = x.C0.B0 - z01 := e.Ext2.MulByNonResidue2Power2(&x.C0.B1) // z.C0.B1.MulByNonResidue2Power2(&x.C0.B1) - z02 := e.Ext2.MulByNonResidue2Power4(&x.C0.B2) // z.C0.B2.MulByNonResidue2Power4(&x.C0.B2) - z10 := e.Ext2.MulByNonResidue2Power1(&x.C1.B0) // z.C1.B0.MulByNonResidue2Power1(&x.C1.B0) - z11 := e.Ext2.MulByNonResidue2Power3(&x.C1.B1) // z.C1.B1.MulByNonResidue2Power3(&x.C1.B1) - z12 := e.Ext2.MulByNonResidue2Power5(&x.C1.B2) // z.C1.B2.MulByNonResidue2Power5(&x.C1.B2) - return &E12{ // return z + z00 := &x.C0.B0 + z01 := e.Ext2.MulByNonResidue2Power2(&x.C0.B1) + z02 := e.Ext2.MulByNonResidue2Power4(&x.C0.B2) + z10 := e.Ext2.MulByNonResidue2Power1(&x.C1.B0) + z11 := e.Ext2.MulByNonResidue2Power3(&x.C1.B1) + z12 := e.Ext2.MulByNonResidue2Power5(&x.C1.B2) + return &E12{ C0: E6{B0: *z00, B1: *z01, B2: *z02}, C1: E6{B0: *z10, B1: *z11, B2: *z12}, } } func (e Ext12) FrobeniusCube(x *E12) *E12 { - // var t [6]E2 - t0 := e.Ext2.Conjugate(&x.C0.B0) // t[0].Conjugate(&x.C0.B0) - t1 := e.Ext2.Conjugate(&x.C0.B1) // t[1].Conjugate(&x.C0.B1) - t2 := e.Ext2.Conjugate(&x.C0.B2) // t[2].Conjugate(&x.C0.B2) - t3 := e.Ext2.Conjugate(&x.C1.B0) // t[3].Conjugate(&x.C1.B0) - t4 := e.Ext2.Conjugate(&x.C1.B1) // t[4].Conjugate(&x.C1.B1) - t5 := e.Ext2.Conjugate(&x.C1.B2) // t[5].Conjugate(&x.C1.B2) - t1 = e.Ext2.MulByNonResidue3Power2(t1) // t[1].MulByNonResidue3Power2(&t[1]) - t2 = e.Ext2.MulByNonResidue3Power4(t2) // t[2].MulByNonResidue3Power4(&t[2]) - t3 = e.Ext2.MulByNonResidue3Power1(t3) // t[3].MulByNonResidue3Power1(&t[3]) - t4 = e.Ext2.MulByNonResidue3Power3(t4) // t[4].MulByNonResidue3Power3(&t[4]) - t5 = e.Ext2.MulByNonResidue3Power5(t5) // t[5].MulByNonResidue3Power5(&t[5]) - return &E12{ // return z + t0 := e.Ext2.Conjugate(&x.C0.B0) + t1 := e.Ext2.Conjugate(&x.C0.B1) + t2 := e.Ext2.Conjugate(&x.C0.B2) + t3 := e.Ext2.Conjugate(&x.C1.B0) + t4 := e.Ext2.Conjugate(&x.C1.B1) + t5 := e.Ext2.Conjugate(&x.C1.B2) + t1 = e.Ext2.MulByNonResidue3Power2(t1) + t2 = e.Ext2.MulByNonResidue3Power4(t2) + t3 = e.Ext2.MulByNonResidue3Power1(t3) + t4 = e.Ext2.MulByNonResidue3Power3(t4) + t5 = e.Ext2.MulByNonResidue3Power5(t5) + return &E12{ C0: E6{ - B0: *t0, // z.C0.B0 = t[0] - B1: *t1, // z.C0.B1 = t[1] - B2: *t2, // z.C0.B2 = t[2] + B0: *t0, + B1: *t1, + B2: *t2, }, C1: E6{ - B0: *t3, // z.C1.B0 = t[3] - B1: *t4, // z.C1.B1 = t[4] - B2: *t5, // z.C1.B2 = t[5] + B0: *t3, + B1: *t4, + B2: *t5, }, } } @@ -363,18 +350,17 @@ func (e Ext12) One() *E12 { } func (e Ext12) Square(x *E12) *E12 { - // var c0, c2, c3 E6 - c0 := e.Ext6.Sub(&x.C0, &x.C1) // c0.Sub(&x.C0, &x.C1) - c3 := e.Ext6.MulByNonResidue(&x.C1) // c3.MulByNonResidue(&x.C1). - c3 = e.Ext6.Neg(c3) // Neg(&c3). - c3 = e.Ext6.Add(&x.C0, c3) // Add(&x.C0, &c3) - c2 := e.Ext6.Mul(&x.C0, &x.C1) // c2.Mul(&x.C0, &x.C1) - c0 = e.Ext6.Mul(c0, c3) // c0.Mul(&c0, &c3). - c0 = e.Ext6.Add(c0, c2) // Add(&c0, &c2) - z1 := e.Ext6.double(c2) // z.C1.Double(&c2) - c2 = e.Ext6.MulByNonResidue(c2) // c2.MulByNonResidue(&c2) - z0 := e.Ext6.Add(c0, c2) // z.C0.Add(&c0, &c2) - return &E12{ // return z + c0 := e.Ext6.Sub(&x.C0, &x.C1) + c3 := e.Ext6.MulByNonResidue(&x.C1) + c3 = e.Ext6.Neg(c3) + c3 = e.Ext6.Add(&x.C0, c3) + c2 := e.Ext6.Mul(&x.C0, &x.C1) + c0 = e.Ext6.Mul(c0, c3) + c0 = e.Ext6.Add(c0, c2) + z1 := e.Ext6.double(c2) + c2 = e.Ext6.MulByNonResidue(c2) + z0 := e.Ext6.Add(c0, c2) + return &E12{ C0: *z0, C1: *z1, } diff --git a/std/algebra/emulated/fields_bn254/e2.go b/std/algebra/emulated/fields_bn254/e2.go index 38cb52ddf3..5241adadce 100644 --- a/std/algebra/emulated/fields_bn254/e2.go +++ b/std/algebra/emulated/fields_bn254/e2.go @@ -94,33 +94,18 @@ func (e Ext2) MulByNonResidueGeneric(x *E2, power, coef int) *E2 { } func (e Ext2) MulByNonResidue(x *E2) *E2 { - /* - // below is the direct transliteration of the gnark-crypto code. Now only, - // for simplicity and debugging purposes, we do the non residue operations - // without optimisations. - - nine := big.NewInt(9) - // var a, b fp.Element - a := e.fp.MulConst(&x.A0, nine) // a.Double(&x.A0).Double(&a).Double(&a).Add(&a, &x.A0). - a = e.fp.Sub(a, &x.A1) // Sub(&a, &x.A1) - b := e.fp.MulConst(&x.A1, nine) // b.Double(&x.A1).Double(&b).Double(&b).Add(&b, &x.A1). - b = e.fp.Add(b, &x.A0) // Add(&b, &x.A0) - return &E2{ - A0: *a, // z.A0.Set(&a) - A1: *b, // z.A1.Set(&b) - } // return z - */ - // TODO: inline non-residue Multiplication - return e.MulByNonResidueGeneric(x, 0, 1) + nine := big.NewInt(9) + a := e.fp.MulConst(&x.A0, nine) + a = e.fp.Sub(a, &x.A1) + b := e.fp.MulConst(&x.A1, nine) + b = e.fp.Add(b, &x.A0) + return &E2{ + A0: *a, + A1: *b, + } } func (e Ext2) MulByNonResidueInv(x *E2) *E2 { - // TODO: to optimise with constant non-residue inverse - /* - // from gnark-crypto - // z.Mul(x, &nonResInverse) - // return z - */ return e.MulByNonResidueGeneric(x, 0, -1) } @@ -189,15 +174,14 @@ func (e Ext2) MulByNonResidue3Power5(x *E2) *E2 { } func (e Ext2) Mul(x, y *E2) *E2 { - // var a, b, c fp.Element - a := e.fp.Add(&x.A0, &x.A1) // a.Add(&x.A0, &x.A1) - b := e.fp.Add(&y.A0, &y.A1) // b.Add(&y.A0, &y.A1) - a = e.fp.MulMod(a, b) // a.Mul(&a, &b) - b = e.fp.MulMod(&x.A0, &y.A0) // b.Mul(&x.A0, &y.A0) - c := e.fp.MulMod(&x.A1, &y.A1) // c.Mul(&x.A1, &y.A1) - z1 := e.fp.Sub(a, b) // z.A1.Sub(&a, &b). - z1 = e.fp.Sub(z1, c) // Sub(&z.A1, &c) - z0 := e.fp.Sub(b, c) // z.A0.Sub(&b, &c) + a := e.fp.Add(&x.A0, &x.A1) + b := e.fp.Add(&y.A0, &y.A1) + a = e.fp.MulMod(a, b) + b = e.fp.MulMod(&x.A0, &y.A0) + c := e.fp.MulMod(&x.A1, &y.A1) + z1 := e.fp.Sub(a, b) + z1 = e.fp.Sub(z1, c) + z0 := e.fp.Sub(b, c) return &E2{ A0: *z0, A1: *z1, @@ -205,8 +189,8 @@ func (e Ext2) Mul(x, y *E2) *E2 { } func (e Ext2) Add(x, y *E2) *E2 { - z0 := e.fp.Add(&x.A0, &y.A0) // z.A0.Add(&x.A0, &y.A0) - z1 := e.fp.Add(&x.A1, &y.A1) // z.A1.Add(&x.A1, &y.A1) + z0 := e.fp.Add(&x.A0, &y.A0) + z1 := e.fp.Add(&x.A1, &y.A1) return &E2{ A0: *z0, A1: *z1, @@ -214,8 +198,8 @@ func (e Ext2) Add(x, y *E2) *E2 { } func (e Ext2) Sub(x, y *E2) *E2 { - z0 := e.fp.Sub(&x.A0, &y.A0) // z.A0.Sub(&x.A0, &y.A0) - z1 := e.fp.Sub(&x.A1, &y.A1) // z.A1.Sub(&x.A1, &y.A1) + z0 := e.fp.Sub(&x.A0, &y.A0) + z1 := e.fp.Sub(&x.A1, &y.A1) return &E2{ A0: *z0, A1: *z1, @@ -223,8 +207,8 @@ func (e Ext2) Sub(x, y *E2) *E2 { } func (e Ext2) Neg(x *E2) *E2 { - z0 := e.fp.Neg(&x.A0) // z.A0.Neg(&x.A0) - z1 := e.fp.Neg(&x.A1) // z.A1.Neg(&x.A1) + z0 := e.fp.Neg(&x.A0) + z1 := e.fp.Neg(&x.A1) return &E2{ A0: *z0, A1: *z1, @@ -232,9 +216,9 @@ func (e Ext2) Neg(x *E2) *E2 { } func (e Ext2) One() *E2 { - z0 := e.fp.One() // z.A0.SetOne() - z1 := e.fp.Zero() // z.A1.SetZero() - return &E2{ // return z + z0 := e.fp.One() + z1 := e.fp.Zero() + return &E2{ A0: *z0, A1: *z1, } @@ -250,22 +234,21 @@ func (e Ext2) Zero() *E2 { } func (e Ext2) Square(x *E2) *E2 { - // var a, b fp.Element - a := e.fp.Add(&x.A0, &x.A1) // a.Add(&x.A0, &x.A1) - b := e.fp.Sub(&x.A0, &x.A1) // b.Sub(&x.A0, &x.A1) - a = e.fp.MulMod(a, b) // a.Mul(&a, &b) - b = e.fp.MulMod(&x.A0, &x.A1) // b.Mul(&x.A0, &x.A1). - b = e.fp.MulConst(b, big.NewInt(2)) // Double(&b) + a := e.fp.Add(&x.A0, &x.A1) + b := e.fp.Sub(&x.A0, &x.A1) + a = e.fp.MulMod(a, b) + b = e.fp.MulMod(&x.A0, &x.A1) + b = e.fp.MulConst(b, big.NewInt(2)) return &E2{ - A0: *a, // z.A0.Set(&a) - A1: *b, // z.A1.Set(&b) + A0: *a, + A1: *b, } } func (e Ext2) Double(x *E2) *E2 { two := big.NewInt(2) - z0 := e.fp.MulConst(&x.A0, two) // z.A0.Double(&x.A0) - z1 := e.fp.MulConst(&x.A1, two) // z.A1.Double(&x.A1) + z0 := e.fp.MulConst(&x.A0, two) + z1 := e.fp.MulConst(&x.A1, two) return &E2{ A0: *z0, A1: *z1, @@ -287,11 +270,10 @@ func (e Ext2) Halve(x *E2) *E2 { } func (e Ext2) MulBybTwistCurveCoeff(x *E2) *E2 { - // var res E2 - res := e.MulByNonResidueInv(x) // res.MulByNonResidueInv(x) - z := e.Double(res) // z.Double(&res). - z = e.Add(z, res) // Add(&res, z) - return z // return z + res := e.MulByNonResidueInv(x) + z := e.Double(res) + z = e.Add(z, res) + return z } func (e Ext2) AssertIsEqual(x, y *E2) { diff --git a/std/algebra/emulated/fields_bn254/e6.go b/std/algebra/emulated/fields_bn254/e6.go index 85c1ec0d70..511968da40 100644 --- a/std/algebra/emulated/fields_bn254/e6.go +++ b/std/algebra/emulated/fields_bn254/e6.go @@ -44,10 +44,10 @@ func (e Ext6) Zero() *E6 { } func (e Ext6) Add(x, y *E6) *E6 { - z0 := e.Ext2.Add(&x.B0, &y.B0) // z.B0.Add(&x.B0, &y.B0) - z1 := e.Ext2.Add(&x.B1, &y.B1) // z.B1.Add(&x.B1, &y.B1) - z2 := e.Ext2.Add(&x.B2, &y.B2) // z.B2.Add(&x.B2, &y.B2) - return &E6{ // return z + z0 := e.Ext2.Add(&x.B0, &y.B0) + z1 := e.Ext2.Add(&x.B1, &y.B1) + z2 := e.Ext2.Add(&x.B2, &y.B2) + return &E6{ B0: *z0, B1: *z1, B2: *z2, @@ -55,10 +55,10 @@ func (e Ext6) Add(x, y *E6) *E6 { } func (e Ext6) Neg(x *E6) *E6 { - z0 := e.Ext2.Neg(&x.B0) // z.B0.Neg(&x.B0) - z1 := e.Ext2.Neg(&x.B1) // z.B1.Neg(&x.B1) - z2 := e.Ext2.Neg(&x.B2) // z.B2.Neg(&x.B2) - return &E6{ // return z + z0 := e.Ext2.Neg(&x.B0) + z1 := e.Ext2.Neg(&x.B1) + z2 := e.Ext2.Neg(&x.B2) + return &E6{ B0: *z0, B1: *z1, B2: *z2, @@ -66,10 +66,10 @@ func (e Ext6) Neg(x *E6) *E6 { } func (e Ext6) Sub(x, y *E6) *E6 { - z0 := e.Ext2.Sub(&x.B0, &y.B0) // z.B0.Sub(&x.B0, &y.B0) - z1 := e.Ext2.Sub(&x.B1, &y.B1) // z.B1.Sub(&x.B1, &y.B1) - z2 := e.Ext2.Sub(&x.B2, &y.B2) // z.B2.Sub(&x.B2, &y.B2) - return &E6{ // return z + z0 := e.Ext2.Sub(&x.B0, &y.B0) + z1 := e.Ext2.Sub(&x.B1, &y.B1) + z2 := e.Ext2.Sub(&x.B2, &y.B2) + return &E6{ B0: *z0, B1: *z1, B2: *z2, @@ -77,42 +77,41 @@ func (e Ext6) Sub(x, y *E6) *E6 { } func (e Ext6) Mul(x, y *E6) *E6 { - // var t0, t1, t2, c0, c1, c2, tmp E2 - t0 := e.Ext2.Mul(&x.B0, &y.B0) // t0.Mul(&x.B0, &y.B0) - t1 := e.Ext2.Mul(&x.B1, &y.B1) // t1.Mul(&x.B1, &y.B1) - t2 := e.Ext2.Mul(&x.B2, &y.B2) // t2.Mul(&x.B2, &y.B2) - c0 := e.Ext2.Add(&x.B1, &x.B2) // c0.Add(&x.B1, &x.B2) - tmp := e.Ext2.Add(&y.B1, &y.B2) // tmp.Add(&y.B1, &y.B2) - c0 = e.Ext2.Mul(c0, tmp) // c0.Mul(&c0, &tmp). - c0 = e.Ext2.Sub(c0, t1) // Sub(&c0, &t1). - c0 = e.Ext2.Sub(c0, t2) // Sub(&c0, &t2). - c0 = e.Ext2.MulByNonResidue(c0) // MulByNonResidue(&c0). - c0 = e.Ext2.Add(c0, t0) // Add(&c0, &t0) - c1 := e.Ext2.Add(&x.B0, &x.B1) // c1.Add(&x.B0, &x.B1) - tmp = e.Ext2.Add(&y.B0, &y.B1) // tmp.Add(&y.B0, &y.B1) - c1 = e.Ext2.Mul(c1, tmp) // c1.Mul(&c1, &tmp). - c1 = e.Ext2.Sub(c1, t0) // Sub(&c1, &t0). - c1 = e.Ext2.Sub(c1, t1) // Sub(&c1, &t1) - tmp = e.Ext2.MulByNonResidue(t2) // tmp.MulByNonResidue(&t2) - c1 = e.Ext2.Add(c1, tmp) // c1.Add(&c1, &tmp) - tmp = e.Ext2.Add(&x.B0, &x.B2) // tmp.Add(&x.B0, &x.B2) - c2 := e.Ext2.Add(&y.B0, &y.B2) // c2.Add(&y.B0, &y.B2). - c2 = e.Ext2.Mul(c2, tmp) // Mul(&c2, &tmp). - c2 = e.Ext2.Sub(c2, t0) // Sub(&c2, &t0). - c2 = e.Ext2.Sub(c2, t2) // Sub(&c2, &t2). - c2 = e.Ext2.Add(c2, t1) // Add(&c2, &t1) + t0 := e.Ext2.Mul(&x.B0, &y.B0) + t1 := e.Ext2.Mul(&x.B1, &y.B1) + t2 := e.Ext2.Mul(&x.B2, &y.B2) + c0 := e.Ext2.Add(&x.B1, &x.B2) + tmp := e.Ext2.Add(&y.B1, &y.B2) + c0 = e.Ext2.Mul(c0, tmp) + c0 = e.Ext2.Sub(c0, t1) + c0 = e.Ext2.Sub(c0, t2) + c0 = e.Ext2.MulByNonResidue(c0) + c0 = e.Ext2.Add(c0, t0) + c1 := e.Ext2.Add(&x.B0, &x.B1) + tmp = e.Ext2.Add(&y.B0, &y.B1) + c1 = e.Ext2.Mul(c1, tmp) + c1 = e.Ext2.Sub(c1, t0) + c1 = e.Ext2.Sub(c1, t1) + tmp = e.Ext2.MulByNonResidue(t2) + c1 = e.Ext2.Add(c1, tmp) + tmp = e.Ext2.Add(&x.B0, &x.B2) + c2 := e.Ext2.Add(&y.B0, &y.B2) + c2 = e.Ext2.Mul(c2, tmp) + c2 = e.Ext2.Sub(c2, t0) + c2 = e.Ext2.Sub(c2, t2) + c2 = e.Ext2.Add(c2, t1) return &E6{ - B0: *c0, // z.B0.Set(&c0) - B1: *c1, // z.B1.Set(&c1) - B2: *c2, // z.B2.Set(&c2) - } // return z + B0: *c0, + B1: *c1, + B2: *c2, + } } func (e Ext6) double(x *E6) *E6 { - z0 := e.Ext2.Double(&x.B0) // z.B0.Double(&x.B0) - z1 := e.Ext2.Double(&x.B1) // z.B1.Double(&x.B1) - z2 := e.Ext2.Double(&x.B2) // z.B2.Double(&x.B2) - return &E6{ // return z + z0 := e.Ext2.Double(&x.B0) + z1 := e.Ext2.Double(&x.B1) + z2 := e.Ext2.Double(&x.B2) + return &E6{ B0: *z0, B1: *z1, B2: *z2, @@ -120,27 +119,26 @@ func (e Ext6) double(x *E6) *E6 { } func (e Ext6) Square(x *E6) *E6 { - // var c4, c5, c1, c2, c3, c0 E2 - c4 := e.Ext2.Mul(&x.B0, &x.B1) // c4.Mul(&x.B0, &x.B1). - c4 = e.Ext2.Double(c4) // Double(&c4) - c5 := e.Ext2.Square(&x.B2) // c5.Square(&x.B2) - c1 := e.Ext2.MulByNonResidue(c5) // c1.MulByNonResidue(&c5). - c1 = e.Ext2.Add(c1, c4) // Add(&c1, &c4) - c2 := e.Ext2.Sub(c4, c5) // c2.Sub(&c4, &c5) - c3 := e.Ext2.Square(&x.B0) // c3.Square(&x.B0) - c4 = e.Ext2.Sub(&x.B0, &x.B1) // c4.Sub(&x.B0, &x.B1). - c4 = e.Ext2.Add(c4, &x.B2) // Add(&c4, &x.B2) - c5 = e.Ext2.Mul(&x.B1, &x.B2) // c5.Mul(&x.B1, &x.B2). - c5 = e.Ext2.Double(c5) // Double(&c5) - c4 = e.Ext2.Square(c4) // c4.Square(&c4) - c0 := e.Ext2.MulByNonResidue(c5) // c0.MulByNonResidue(&c5). - c0 = e.Ext2.Add(c0, c3) // Add(&c0, &c3) - z2 := e.Ext2.Add(c2, c4) // z.B2.Add(&c2, &c4). - z2 = e.Ext2.Add(z2, c5) // Add(&z.B2, &c5). - z2 = e.Ext2.Sub(z2, c3) // Sub(&z.B2, &c3) - z0 := c0 // z.B0.Set(&c0) - z1 := c1 // z.B1.Set(&c1) - return &E6{ // return z + c4 := e.Ext2.Mul(&x.B0, &x.B1) + c4 = e.Ext2.Double(c4) + c5 := e.Ext2.Square(&x.B2) + c1 := e.Ext2.MulByNonResidue(c5) + c1 = e.Ext2.Add(c1, c4) + c2 := e.Ext2.Sub(c4, c5) + c3 := e.Ext2.Square(&x.B0) + c4 = e.Ext2.Sub(&x.B0, &x.B1) + c4 = e.Ext2.Add(c4, &x.B2) + c5 = e.Ext2.Mul(&x.B1, &x.B2) + c5 = e.Ext2.Double(c5) + c4 = e.Ext2.Square(c4) + c0 := e.Ext2.MulByNonResidue(c5) + c0 = e.Ext2.Add(c0, c3) + z2 := e.Ext2.Add(c2, c4) + z2 = e.Ext2.Add(z2, c5) + z2 = e.Ext2.Sub(z2, c3) + z0 := c0 + z1 := c1 + return &E6{ B0: *z0, B1: *z1, B2: *z2, @@ -148,12 +146,10 @@ func (e Ext6) Square(x *E6) *E6 { } func (e Ext6) MulByE2(x *E6, y *E2) *E6 { - // var yCopy E2 - // yCopy.Set(y) - z0 := e.Ext2.Mul(&x.B0, y) // z.B0.Mul(&x.B0, &yCopy) - z1 := e.Ext2.Mul(&x.B1, y) // z.B1.Mul(&x.B1, &yCopy) - z2 := e.Ext2.Mul(&x.B2, y) // z.B2.Mul(&x.B2, &yCopy) - return &E6{ // return z + z0 := e.Ext2.Mul(&x.B0, y) + z1 := e.Ext2.Mul(&x.B1, y) + z2 := e.Ext2.Mul(&x.B2, y) + return &E6{ B0: *z0, B1: *z1, B2: *z2, @@ -161,34 +157,33 @@ func (e Ext6) MulByE2(x *E6, y *E2) *E6 { } func (e Ext6) MulBy01(z *E6, c0, c1 *E2) *E6 { - // var a, b, tmp, t0, t1, t2 E2 - a := e.Ext2.Mul(&z.B0, c0) // a.Mul(&z.B0, c0) - b := e.Ext2.Mul(&z.B1, c1) // b.Mul(&z.B1, c1) - tmp := e.Ext2.Add(&z.B1, &z.B2) // tmp.Add(&z.B1, &z.B2) - t0 := e.Ext2.Mul(c1, tmp) // t0.Mul(c1, &tmp) - t0 = e.Ext2.Sub(t0, b) // t0.Sub(&t0, &b) - t0 = e.Ext2.MulByNonResidue(t0) // t0.MulByNonResidue(&t0) - t0 = e.Ext2.Add(t0, a) // t0.Add(&t0, &a) - tmp = e.Ext2.Add(&z.B0, &z.B2) // tmp.Add(&z.B0, &z.B2) - t2 := e.Ext2.Mul(c0, tmp) // t2.Mul(c0, &tmp) - t2 = e.Ext2.Sub(t2, a) // t2.Sub(&t2, &a) - t2 = e.Ext2.Add(t2, b) // t2.Add(&t2, &b) - t1 := e.Ext2.Add(c0, c1) // t1.Add(c0, c1) - tmp = e.Ext2.Add(&z.B0, &z.B1) // tmp.Add(&z.B0, &z.B1) - t1 = e.Ext2.Mul(t1, tmp) // t1.Mul(&t1, &tmp) - t1 = e.Ext2.Sub(t1, a) // t1.Sub(&t1, &a) - t1 = e.Ext2.Sub(t1, b) // t1.Sub(&t1, &b) + a := e.Ext2.Mul(&z.B0, c0) + b := e.Ext2.Mul(&z.B1, c1) + tmp := e.Ext2.Add(&z.B1, &z.B2) + t0 := e.Ext2.Mul(c1, tmp) + t0 = e.Ext2.Sub(t0, b) + t0 = e.Ext2.MulByNonResidue(t0) + t0 = e.Ext2.Add(t0, a) + tmp = e.Ext2.Add(&z.B0, &z.B2) + t2 := e.Ext2.Mul(c0, tmp) + t2 = e.Ext2.Sub(t2, a) + t2 = e.Ext2.Add(t2, b) + t1 := e.Ext2.Add(c0, c1) + tmp = e.Ext2.Add(&z.B0, &z.B1) + t1 = e.Ext2.Mul(t1, tmp) + t1 = e.Ext2.Sub(t1, a) + t1 = e.Ext2.Sub(t1, b) return &E6{ - B0: *t0, // z.B0.Set(&t0) - B1: *t1, // z.B1.Set(&t1) - B2: *t2, // z.B2.Set(&t2) - } // return z + B0: *t0, + B1: *t1, + B2: *t2, + } } func (e Ext6) MulByNonResidue(x *E6) *E6 { - z2, z1, z0 := &x.B1, &x.B0, &x.B2 // z.B2, z.B1, z.B0 = x.B1, x.B0, x.B2 - z0 = e.Ext2.MulByNonResidue(z0) // z.B0.MulByNonResidue(&z.B0) - return &E6{ // return z + z2, z1, z0 := &x.B1, &x.B0, &x.B2 + z0 = e.Ext2.MulByNonResidue(z0) + return &E6{ B0: *z0, B1: *z1, B2: *z2, From ddff89b1653a764fe9ea686d468662d2e4d90c03 Mon Sep 17 00:00:00 2001 From: Behrouz Date: Thu, 9 Mar 2023 20:15:06 +0330 Subject: [PATCH 091/464] docs: correct `WithNbDigits` description (#522) * docs: correct `WithNbDigits` description This commit corrects the description of the behaviour of conversion functions when `nbDigits` is lower than the length of the full decomposition. Some tests are also added to test this behaviour. * docs: improve readability --- std/math/bits/conversion.go | 8 ++++---- std/math/bits/conversion_test.go | 7 +++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/std/math/bits/conversion.go b/std/math/bits/conversion.go index 20040b82d8..ca82c2773e 100644 --- a/std/math/bits/conversion.go +++ b/std/math/bits/conversion.go @@ -56,10 +56,10 @@ type baseConversionConfig struct { // BaseConversionOption configures the behaviour of scalar decomposition. type BaseConversionOption func(opt *baseConversionConfig) error -// WithNbDigits set the resulting number of digits to be used in the base conversion. -// nbDigits must be > 0. If nbDigits is lower than the length of full -// decomposition, then nbDigits least significant digits are returned. If the -// option is not set, then the full decomposition is returned. +// WithNbDigits sets the resulting number of digits (nbDigits) to be used in the base conversion. +// nbDigits must be > 0. If nbDigits is lower than the length of full decomposition and +// WithUnconstrainedOutputs option is not used, then this function generates an unsatisfiable +// constraint. If WithNbDigits option is not set, then the full decomposition is returned. func WithNbDigits(nbDigits int) BaseConversionOption { return func(opt *baseConversionConfig) error { if nbDigits <= 0 { diff --git a/std/math/bits/conversion_test.go b/std/math/bits/conversion_test.go index a43ae6489d..47455b236d 100644 --- a/std/math/bits/conversion_test.go +++ b/std/math/bits/conversion_test.go @@ -31,6 +31,13 @@ func (c *toBinaryCircuit) Define(api frontend.API) error { func TestToBinary(t *testing.T) { assert := test.NewAssert(t) assert.ProverSucceeded(&toBinaryCircuit{}, &toBinaryCircuit{A: 5, B0: 1, B1: 0, B2: 1}) + + assert.ProverSucceeded(&toBinaryCircuit{}, &toBinaryCircuit{A: 3, B0: 1, B1: 1, B2: 0}) + + // prover fails when the binary representation of A has more than 3 bits + assert.ProverFailed(&toBinaryCircuit{}, &toBinaryCircuit{A: 8, B0: 0, B1: 0, B2: 0}) + + assert.ProverFailed(&toBinaryCircuit{}, &toBinaryCircuit{A: 10, B0: 0, B1: 1, B2: 0}) } type toTernaryCircuit struct { From 7b0d25c8f9d887c0588a170a2e7886812172a44f Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Thu, 9 Mar 2023 10:47:24 -0600 Subject: [PATCH 092/464] fix: fix #516 compiler detects api.AssertIsDifferent(x,x) with better error (#552) --- frontend/cs/r1cs/api_assertions.go | 7 ++++++- frontend/cs/scs/api_assertions.go | 8 +++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/frontend/cs/r1cs/api_assertions.go b/frontend/cs/r1cs/api_assertions.go index ec7351b4af..dd1d155aa3 100644 --- a/frontend/cs/r1cs/api_assertions.go +++ b/frontend/cs/r1cs/api_assertions.go @@ -39,7 +39,12 @@ func (builder *builder) AssertIsEqual(i1, i2 frontend.Variable) { // AssertIsDifferent constrain i1 and i2 to be different func (builder *builder) AssertIsDifferent(i1, i2 frontend.Variable) { - builder.Inverse(builder.Sub(i1, i2)) + s := builder.Sub(i1, i2).(expr.LinearExpression) + if len(s) == 1 && s[0].Coeff.IsZero() { + panic("AssertIsDifferent(x,x) will never be satisfied") + } + + builder.Inverse(s) } // AssertIsBoolean adds an assertion in the constraint builder (v == 0 ∥ v == 1) diff --git a/frontend/cs/scs/api_assertions.go b/frontend/cs/scs/api_assertions.go index 27b5962420..698a139402 100644 --- a/frontend/cs/scs/api_assertions.go +++ b/frontend/cs/scs/api_assertions.go @@ -73,7 +73,13 @@ func (builder *builder) AssertIsEqual(i1, i2 frontend.Variable) { // AssertIsDifferent fails if i1 == i2 func (builder *builder) AssertIsDifferent(i1, i2 frontend.Variable) { - builder.Inverse(builder.Sub(i1, i2)) + s := builder.Sub(i1, i2) + if c, ok := builder.constantValue(s); ok && c.IsZero() { + panic("AssertIsDifferent(x,x) will never be satisfied") + } else if t := s.(expr.Term); t.Coeff.IsZero() { + panic("AssertIsDifferent(x,x) will never be satisfied") + } + builder.Inverse(s) } // AssertIsBoolean fails if v != 0 ∥ v != 1 From f32bcd0aec3d6e4a36054c1ae5146f434c089bc7 Mon Sep 17 00:00:00 2001 From: Hisham Galal <0xhgalal@gmail.com> Date: Thu, 9 Mar 2023 11:51:36 -0500 Subject: [PATCH 093/464] parallelize scalar multiplication --- backend/groth16/setup/test/example_test.go | 13 +++---- backend/groth16/setup/utils/utils.go | 45 ++++++++-------------- 2 files changed, 20 insertions(+), 38 deletions(-) diff --git a/backend/groth16/setup/test/example_test.go b/backend/groth16/setup/test/example_test.go index 8cdd8416f5..a1ad64d95c 100644 --- a/backend/groth16/setup/test/example_test.go +++ b/backend/groth16/setup/test/example_test.go @@ -61,13 +61,10 @@ func TestSetupCircuit(t *testing.T) { nContributionsPhase2 := 3 var evals phase2.Evaluations contributionsPhase2 := make([]phase2.Contribution, nContributionsPhase2) - switch r1cs := ccs.(type) { - case *cs_bn254.R1CS: - // Prepare for phase-2 - evals = contributionsPhase2[0].PreparePhase2(&contributionsPhase1[nContributionsPhase1-1], r1cs) - default: - panic("Unsupported curve") - } + r1cs := ccs.(*cs_bn254.R1CS) + + // Prepare for phase-2 + evals = contributionsPhase2[0].PreparePhase2(&contributionsPhase1[nContributionsPhase1-1], r1cs) // Make and verify contributions for phase1 for i := 1; i < nContributionsPhase2; i++ { @@ -80,12 +77,12 @@ func TestSetupCircuit(t *testing.T) { pk, vk := keys.ExtractKeys(&contributionsPhase1[nContributionsPhase1-1], &contributionsPhase2[nContributionsPhase2-1], &evals, ccs.GetNbConstraints()) var bufPK, bufVK bytes.Buffer + // Write PK and VK pk.WriteTo(&bufPK, false) vk.WriteTo(&bufVK, false) // Read PK and VK - pkk := groth16.NewProvingKey(ecc.BN254) pkk.ReadFrom(&bufPK) vkk := groth16.NewVerifyingKey(ecc.BN254) diff --git a/backend/groth16/setup/utils/utils.go b/backend/groth16/setup/utils/utils.go index 18f4fc0313..d7bf149eb3 100644 --- a/backend/groth16/setup/utils/utils.go +++ b/backend/groth16/setup/utils/utils.go @@ -7,6 +7,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark/internal/utils" ) type PublicKey struct { @@ -27,46 +28,30 @@ func Powers(a fr.Element, n int) []fr.Element { // Returns [aᵢAᵢ, ...] in G1 func ScaleG1(A []bn254.G1Affine, a []fr.Element) []bn254.G1Affine { - var tmp big.Int result := make([]bn254.G1Affine, len(A)) - for i := 0; i < len(A); i++ { - a[i].BigInt(&tmp) - result[i].ScalarMultiplication(&A[i], &tmp) - } + utils.Parallelize(len(A), func(start, end int) { + for i := start; i < end; i++ { + var tmp big.Int + a[i].BigInt(&tmp) + result[i].ScalarMultiplication(&A[i], &tmp) + } + }) return result } // Returns [aᵢAᵢ, ...] in G2 func ScaleG2(A []bn254.G2Affine, a []fr.Element) []bn254.G2Affine { - var tmp big.Int result := make([]bn254.G2Affine, len(A)) - for i := 0; i < len(A); i++ { - a[i].BigInt(&tmp) - result[i].ScalarMultiplication(&A[i], &tmp) - } + utils.Parallelize(len(A), func(start, end int) { + for i := start; i < end; i++ { + var tmp big.Int + a[i].BigInt(&tmp) + result[i].ScalarMultiplication(&A[i], &tmp) + } + }) return result } -func EvalG1(scalars []fr.Element, points []bn254.G1Affine) *bn254.G1Jac { - nc := runtime.NumCPU() - - var result bn254.G1Jac - if _, err := result.MultiExp(points, scalars, ecc.MultiExpConfig{NbTasks: nc / 2}); err != nil { - panic("Failed to MultiExp") - } - return &result -} - -func EvalG2(scalars []fr.Element, points []bn254.G2Affine) *bn254.G2Jac { - nc := runtime.NumCPU() - - var result bn254.G2Jac - if _, err := result.MultiExp(points, scalars, ecc.MultiExpConfig{NbTasks: nc / 2}); err != nil { - panic("Failed to MultiExp") - } - return &result -} - // Check e(a₁, a₂) = e(b₁, b₂) func SameRatio(a1, b1 bn254.G1Affine, a2, b2 bn254.G2Affine) bool { if !a1.IsInSubGroup() || !b1.IsInSubGroup() || !a2.IsInSubGroup() || !b2.IsInSubGroup() { From b9ce5aec26b0a3c20dcbf84c8c070bd8c4344c24 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Thu, 9 Mar 2023 14:58:41 -0600 Subject: [PATCH 094/464] build: upgraded github.com/stretchr/testify v1.8.1 => v1.8.2 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 19402a2ed5..b7c7eb4612 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/google/pprof v0.0.0-20230207041349-798e818bf904 github.com/leanovate/gopter v0.2.9 github.com/rs/zerolog v1.29.0 - github.com/stretchr/testify v1.8.1 + github.com/stretchr/testify v1.8.2 golang.org/x/crypto v0.6.0 golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb ) diff --git a/go.sum b/go.sum index 3c8602fd34..d12a06113f 100644 --- a/go.sum +++ b/go.sum @@ -47,8 +47,8 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= From 95ab3d65e7c59abb1fbd901ef30d887e82780b69 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 10 Mar 2023 11:16:32 +0100 Subject: [PATCH 095/464] perf(bn254-pair): MulByNonResidueInverse using hints --- std/algebra/emulated/fields_bn254/e2.go | 52 ++++++++++++-- std/algebra/emulated/fields_bn254/e2_test.go | 19 +++++- std/algebra/emulated/sw_bn254/pairing.go | 68 +++++++++---------- std/algebra/emulated/sw_bn254/pairing_test.go | 14 ++-- 4 files changed, 104 insertions(+), 49 deletions(-) diff --git a/std/algebra/emulated/fields_bn254/e2.go b/std/algebra/emulated/fields_bn254/e2.go index 5241adadce..eef0bd810a 100644 --- a/std/algebra/emulated/fields_bn254/e2.go +++ b/std/algebra/emulated/fields_bn254/e2.go @@ -105,10 +105,6 @@ func (e Ext2) MulByNonResidue(x *E2) *E2 { } } -func (e Ext2) MulByNonResidueInv(x *E2) *E2 { - return e.MulByNonResidueGeneric(x, 0, -1) -} - func (e Ext2) MulByNonResidue1Power1(x *E2) *E2 { return e.MulByNonResidueGeneric(x, 1, 1) } @@ -269,8 +265,8 @@ func (e Ext2) Halve(x *E2) *E2 { } } -func (e Ext2) MulBybTwistCurveCoeff(x *E2) *E2 { - res := e.MulByNonResidueInv(x) +func (e Ext2) MulBybTwistCurveCoeff(api frontend.API, x *E2) *E2 { + res := e.MulByNonResidueInv(api, x) z := e.Double(res) z = e.Add(z, res) return z @@ -292,6 +288,50 @@ func FromE2(y *bn254.E2) E2 { func init() { solver.RegisterHint(DivE2Hint) solver.RegisterHint(InverseE2Hint) + solver.RegisterHint(MulByNonResidueInvHint) +} + +func MulByNonResidueInvHint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, c bn254.E2 + + a.A0.SetBigInt(inputs[0]) + a.A1.SetBigInt(inputs[1]) + + c.MulByNonResidueInv(&a) + + c.A0.BigInt(outputs[0]) + c.A1.BigInt(outputs[1]) + + return nil + + }) +} + +func (e Ext2) MulByNonResidueInv(api frontend.API, x *E2) *E2 { + field, err := emulated.NewField[emulated.BN254Fp](api) + if err != nil { + panic(err) + } + res, err := field.NewHint(MulByNonResidueInvHint, 2, &x.A0, &x.A1) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + // r <-- x * (1/(9+u)) + r := E2{ + A0: *res[0], + A1: *res[1], + } + + // x == r * (9+u) + _x := e.MulByNonResidue(&r) + e.AssertIsEqual(x, _x) + + return &r + } func InverseE2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { diff --git a/std/algebra/emulated/fields_bn254/e2_test.go b/std/algebra/emulated/fields_bn254/e2_test.go index a37947b1fa..560e3e2f5c 100644 --- a/std/algebra/emulated/fields_bn254/e2_test.go +++ b/std/algebra/emulated/fields_bn254/e2_test.go @@ -1,12 +1,16 @@ package fields_bn254 import ( + "fmt" "testing" "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fp" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/profile" "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/test" ) @@ -279,7 +283,7 @@ type e2MulBybTwistCurveCoeff struct { func (circuit *e2MulBybTwistCurveCoeff) Define(api frontend.API) error { ba, _ := emulated.NewField[emulated.BN254Fp](api) e := NewExt2(ba) - expected := e.MulBybTwistCurveCoeff(&circuit.A) + expected := e.MulBybTwistCurveCoeff(api, &circuit.A) e.AssertIsEqual(expected, &circuit.C) return nil @@ -343,7 +347,7 @@ type e2MulByNonResidueInv struct { func (circuit *e2MulByNonResidueInv) Define(api frontend.API) error { ba, _ := emulated.NewField[emulated.BN254Fp](api) e := NewExt2(ba) - expected := e.MulByNonResidueInv(&circuit.A) + expected := e.MulByNonResidueInv(api, &circuit.A) e.AssertIsEqual(expected, &circuit.C) return nil @@ -460,3 +464,14 @@ func TestInverseFp2(t *testing.T) { err := test.IsSolved(&e2Inverse{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } + +// bench +var ccsBench constraint.ConstraintSystem + +func BenchmarkPairing(b *testing.B) { + var c e2MulByNonResidueInv + p := profile.Start() + ccsBench, _ = frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &c) + p.Stop() + fmt.Println(p.NbConstraints()) +} diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index c5d2f2f344..e8ed1fb62e 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -58,37 +58,37 @@ func NewPairing(api frontend.API) (*Pairing, error) { }, nil } -func (pr Pairing) DoubleStep(p *g2Projective) (*g2Projective, *lineEvaluation) { +func (pr Pairing) DoubleStep(api frontend.API, p *g2Projective) (*g2Projective, *lineEvaluation) { // var t1, A, B, C, D, E, EE, F, G, H, I, J, K fptower.E2 - A := pr.Ext2.Mul(&p.X, &p.Y) // A.Mul(&p.x, &p.y) - A = pr.Ext2.Halve(A) // A.Halve() - B := pr.Ext2.Square(&p.Y) // B.Square(&p.y) - C := pr.Ext2.Square(&p.Z) // C.Square(&p.z) - D := pr.Ext2.Double(C) // D.Double(&C). - D = pr.Ext2.Add(D, C) // Add(&D, &C) - E := pr.Ext2.MulBybTwistCurveCoeff(D) // E.MulBybTwistCurveCoeff(&D) - F := pr.Ext2.Double(E) // F.Double(&E). - F = pr.Ext2.Add(F, E) // Add(&F, &E) - G := pr.Ext2.Add(B, F) // G.Add(&B, &F) - G = pr.Ext2.Halve(G) // G.Halve() - H := pr.Ext2.Add(&p.Y, &p.Z) // H.Add(&p.y, &p.z). - H = pr.Ext2.Square(H) // Square(&H) - t1 := pr.Ext2.Add(B, C) // t1.Add(&B, &C) - H = pr.Ext2.Sub(H, t1) // H.Sub(&H, &t1) - I := pr.Ext2.Sub(E, B) // I.Sub(&E, &B) - J := pr.Ext2.Square(&p.X) // J.Square(&p.x) - EE := pr.Ext2.Square(E) // EE.Square(&E) - K := pr.Ext2.Double(EE) // K.Double(&EE). - K = pr.Ext2.Add(K, EE) // Add(&K, &EE) - px := pr.Ext2.Sub(B, F) // p.x.Sub(&B, &F). - px = pr.Ext2.Mul(px, A) // Mul(&p.x, &A) - py := pr.Ext2.Square(G) // p.y.Square(&G). - py = pr.Ext2.Sub(py, K) // Sub(&p.y, &K) - pz := pr.Ext2.Mul(B, H) // p.z.Mul(&B, &H) - ev0 := pr.Ext2.Neg(H) // evaluations.r0.Neg(&H) - ev1 := pr.Ext2.Double(J) // evaluations.r1.Double(&J). - ev1 = pr.Ext2.Add(ev1, J) // Add(&evaluations.r1, &J) - ev2 := I // evaluations.r2.Set(&I) + A := pr.Ext2.Mul(&p.X, &p.Y) // A.Mul(&p.x, &p.y) + A = pr.Ext2.Halve(A) // A.Halve() + B := pr.Ext2.Square(&p.Y) // B.Square(&p.y) + C := pr.Ext2.Square(&p.Z) // C.Square(&p.z) + D := pr.Ext2.Double(C) // D.Double(&C). + D = pr.Ext2.Add(D, C) // Add(&D, &C) + E := pr.Ext2.MulBybTwistCurveCoeff(api, D) // E.MulBybTwistCurveCoeff(&D) + F := pr.Ext2.Double(E) // F.Double(&E). + F = pr.Ext2.Add(F, E) // Add(&F, &E) + G := pr.Ext2.Add(B, F) // G.Add(&B, &F) + G = pr.Ext2.Halve(G) // G.Halve() + H := pr.Ext2.Add(&p.Y, &p.Z) // H.Add(&p.y, &p.z). + H = pr.Ext2.Square(H) // Square(&H) + t1 := pr.Ext2.Add(B, C) // t1.Add(&B, &C) + H = pr.Ext2.Sub(H, t1) // H.Sub(&H, &t1) + I := pr.Ext2.Sub(E, B) // I.Sub(&E, &B) + J := pr.Ext2.Square(&p.X) // J.Square(&p.x) + EE := pr.Ext2.Square(E) // EE.Square(&E) + K := pr.Ext2.Double(EE) // K.Double(&EE). + K = pr.Ext2.Add(K, EE) // Add(&K, &EE) + px := pr.Ext2.Sub(B, F) // p.x.Sub(&B, &F). + px = pr.Ext2.Mul(px, A) // Mul(&p.x, &A) + py := pr.Ext2.Square(G) // p.y.Square(&G). + py = pr.Ext2.Sub(py, K) // Sub(&p.y, &K) + pz := pr.Ext2.Mul(B, H) // p.z.Mul(&B, &H) + ev0 := pr.Ext2.Neg(H) // evaluations.r0.Neg(&H) + ev1 := pr.Ext2.Double(J) // evaluations.r1.Double(&J). + ev1 = pr.Ext2.Add(ev1, J) // Add(&evaluations.r1, &J) + ev2 := I // evaluations.r2.Set(&I) return &g2Projective{ X: *px, Y: *py, @@ -180,7 +180,7 @@ var loopCounter = [66]int8{ -1, 0, -1, 0, 0, 0, 1, 0, -1, 0, 1, } -func (pr Pairing) MillerLoop(p []*G1Affine, q []*G2Affine) (*GTEl, error) { +func (pr Pairing) MillerLoop(api frontend.API, p []*G1Affine, q []*G2Affine) (*GTEl, error) { n := len(p) if n == 0 || n != len(q) { return nil, fmt.Errorf("invalid inputs sizes") @@ -201,7 +201,7 @@ func (pr Pairing) MillerLoop(p []*G1Affine, q []*G2Affine) (*GTEl, error) { // i == len(loopCounter) - 2 for k := 0; k < n; k++ { - qProj[k], l = pr.DoubleStep(qProj[k]) // qProj[k].DoubleStep(&l) + qProj[k], l = pr.DoubleStep(api, qProj[k]) // qProj[k].DoubleStep(&l) l.r0 = *pr.Ext12.Ext2.MulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) l.r1 = *pr.Ext12.Ext2.MulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) result = pr.Ext12.MulBy034(result, &l.r0, &l.r1, &l.r2) // result.MulBy034(&l.r0, &l.r1, &l.r2) @@ -211,7 +211,7 @@ func (pr Pairing) MillerLoop(p []*G1Affine, q []*G2Affine) (*GTEl, error) { result = pr.Ext12.Square(result) // result.Square(&result) for k := 0; k < n; k++ { - qProj[k], l = pr.DoubleStep(qProj[k]) // qProj[k].DoubleStep(&l) + qProj[k], l = pr.DoubleStep(api, qProj[k]) // qProj[k].DoubleStep(&l) l.r0 = *pr.Ext12.Ext2.MulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) l.r1 = *pr.Ext12.Ext2.MulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) @@ -305,7 +305,7 @@ func (pr Pairing) FinalExponentiation(api frontend.API, e *GTEl) *GTEl { } func (pr Pairing) Pair(api frontend.API, P []*G1Affine, Q []*G2Affine) (*GTEl, error) { - res, err := pr.MillerLoop(P, Q) + res, err := pr.MillerLoop(api, P, Q) if err != nil { return nil, fmt.Errorf("miller loop: %w", err) } diff --git a/std/algebra/emulated/sw_bn254/pairing_test.go b/std/algebra/emulated/sw_bn254/pairing_test.go index 2531474c99..763d18bd48 100644 --- a/std/algebra/emulated/sw_bn254/pairing_test.go +++ b/std/algebra/emulated/sw_bn254/pairing_test.go @@ -10,7 +10,7 @@ import ( "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/frontend/cs/scs" + "github.com/consensys/gnark/profile" "github.com/consensys/gnark/test" ) @@ -39,7 +39,7 @@ func (c *MillerLoopCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res, err := pairing.MillerLoop([]*G1Affine{&c.InG1}, []*G2Affine{&c.InG2}) + res, err := pairing.MillerLoop(api, []*G1Affine{&c.InG1}, []*G2Affine{&c.InG2}) if err != nil { return fmt.Errorf("pair: %w", err) } @@ -125,10 +125,10 @@ func TestPairTestSolve(t *testing.T) { // bench var ccsBench constraint.ConstraintSystem -func BenchmarkFinalExp(b *testing.B) { - var c FinalExponentiationCircuit +func BenchmarkPairing(b *testing.B) { + var c PairCircuit + p := profile.Start() ccsBench, _ = frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &c) - b.Log("groth16", ccsBench.GetNbConstraints()) - ccsBench, _ = frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, &c) - b.Log("plonk", ccsBench.GetNbConstraints()) + p.Stop() + fmt.Println(p.NbConstraints()) } From 4b05ec5ceb59c152535007737b87bce44d39693f Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 10 Mar 2023 11:25:14 +0100 Subject: [PATCH 096/464] style(fields_bn254): clean hints --- std/algebra/emulated/fields_bn254/e12.go | 95 --------- std/algebra/emulated/fields_bn254/e2.go | 125 +++-------- std/algebra/emulated/fields_bn254/e6.go | 65 ------ std/algebra/emulated/fields_bn254/hints.go | 230 +++++++++++++++++++++ 4 files changed, 261 insertions(+), 254 deletions(-) create mode 100644 std/algebra/emulated/fields_bn254/hints.go diff --git a/std/algebra/emulated/fields_bn254/e12.go b/std/algebra/emulated/fields_bn254/e12.go index 37575bdb79..4f52741272 100644 --- a/std/algebra/emulated/fields_bn254/e12.go +++ b/std/algebra/emulated/fields_bn254/e12.go @@ -1,10 +1,7 @@ package fields_bn254 import ( - "math/big" - "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/math/emulated" ) @@ -379,98 +376,6 @@ func FromE12(y *bn254.E12) E12 { } -func init() { - solver.RegisterHint(DivE12Hint) - solver.RegisterHint(InverseE12Hint) -} - -func InverseE12Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { - return emulated.UnwrapHint(nativeInputs, nativeOutputs, - func(mod *big.Int, inputs, outputs []*big.Int) error { - var a, c bn254.E12 - - a.C0.B0.A0.SetBigInt(inputs[0]) - a.C0.B0.A1.SetBigInt(inputs[1]) - a.C0.B1.A0.SetBigInt(inputs[2]) - a.C0.B1.A1.SetBigInt(inputs[3]) - a.C0.B2.A0.SetBigInt(inputs[4]) - a.C0.B2.A1.SetBigInt(inputs[5]) - a.C1.B0.A0.SetBigInt(inputs[6]) - a.C1.B0.A1.SetBigInt(inputs[7]) - a.C1.B1.A0.SetBigInt(inputs[8]) - a.C1.B1.A1.SetBigInt(inputs[9]) - a.C1.B2.A0.SetBigInt(inputs[10]) - a.C1.B2.A1.SetBigInt(inputs[11]) - - c.Inverse(&a) - - c.C0.B0.A0.BigInt(outputs[0]) - c.C0.B0.A1.BigInt(outputs[1]) - c.C0.B1.A0.BigInt(outputs[2]) - c.C0.B1.A1.BigInt(outputs[3]) - c.C0.B2.A0.BigInt(outputs[4]) - c.C0.B2.A1.BigInt(outputs[5]) - c.C1.B0.A0.BigInt(outputs[6]) - c.C1.B0.A1.BigInt(outputs[7]) - c.C1.B1.A0.BigInt(outputs[8]) - c.C1.B1.A1.BigInt(outputs[9]) - c.C1.B2.A0.BigInt(outputs[10]) - c.C1.B2.A1.BigInt(outputs[11]) - - return nil - }) -} - -func DivE12Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { - return emulated.UnwrapHint(nativeInputs, nativeOutputs, - func(mod *big.Int, inputs, outputs []*big.Int) error { - var a, b, c bn254.E12 - - a.C0.B0.A0.SetBigInt(inputs[0]) - a.C0.B0.A1.SetBigInt(inputs[1]) - a.C0.B1.A0.SetBigInt(inputs[2]) - a.C0.B1.A1.SetBigInt(inputs[3]) - a.C0.B2.A0.SetBigInt(inputs[4]) - a.C0.B2.A1.SetBigInt(inputs[5]) - a.C1.B0.A0.SetBigInt(inputs[6]) - a.C1.B0.A1.SetBigInt(inputs[7]) - a.C1.B1.A0.SetBigInt(inputs[8]) - a.C1.B1.A1.SetBigInt(inputs[9]) - a.C1.B2.A0.SetBigInt(inputs[10]) - a.C1.B2.A1.SetBigInt(inputs[11]) - - b.C0.B0.A0.SetBigInt(inputs[12]) - b.C0.B0.A1.SetBigInt(inputs[13]) - b.C0.B1.A0.SetBigInt(inputs[14]) - b.C0.B1.A1.SetBigInt(inputs[15]) - b.C0.B2.A0.SetBigInt(inputs[16]) - b.C0.B2.A1.SetBigInt(inputs[17]) - b.C1.B0.A0.SetBigInt(inputs[18]) - b.C1.B0.A1.SetBigInt(inputs[19]) - b.C1.B1.A0.SetBigInt(inputs[20]) - b.C1.B1.A1.SetBigInt(inputs[21]) - b.C1.B2.A0.SetBigInt(inputs[22]) - b.C1.B2.A1.SetBigInt(inputs[23]) - - c.Inverse(&b).Mul(&c, &a) - - c.C0.B0.A0.BigInt(outputs[0]) - c.C0.B0.A1.BigInt(outputs[1]) - c.C0.B1.A0.BigInt(outputs[2]) - c.C0.B1.A1.BigInt(outputs[3]) - c.C0.B2.A0.BigInt(outputs[4]) - c.C0.B2.A1.BigInt(outputs[5]) - c.C1.B0.A0.BigInt(outputs[6]) - c.C1.B0.A1.BigInt(outputs[7]) - c.C1.B1.A0.BigInt(outputs[8]) - c.C1.B1.A1.BigInt(outputs[9]) - c.C1.B2.A0.BigInt(outputs[10]) - c.C1.B2.A1.BigInt(outputs[11]) - - return nil - }) -} - func (e Ext12) Inverse(api frontend.API, x *E12) *E12 { field, err := emulated.NewField[emulated.BN254Fp](api) if err != nil { diff --git a/std/algebra/emulated/fields_bn254/e2.go b/std/algebra/emulated/fields_bn254/e2.go index eef0bd810a..1f7def3dab 100644 --- a/std/algebra/emulated/fields_bn254/e2.go +++ b/std/algebra/emulated/fields_bn254/e2.go @@ -4,7 +4,6 @@ import ( "math/big" "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/math/emulated" ) @@ -68,20 +67,18 @@ func NewExt2(baseField *curveF) *Ext2 { // TODO: check where to use Mod and where ModMul. func (e Ext2) MulByElement(x *E2, y *baseEl) *E2 { - // var yCopy fp.Element - // yCopy.Set(y) - z0 := e.fp.MulMod(&x.A0, y) // z.A0.Mul(&x.A0, &yCopy) - z1 := e.fp.MulMod(&x.A1, y) // z.A1.Mul(&x.A1, &yCopy) - return &E2{ // return z + z0 := e.fp.MulMod(&x.A0, y) + z1 := e.fp.MulMod(&x.A1, y) + return &E2{ A0: *z0, A1: *z1, } } func (e Ext2) Conjugate(x *E2) *E2 { - z0 := x.A0 // z.A0 = x.A0 - z1 := e.fp.Neg(&x.A1) // z.A1.Neg(&x.A1) - return &E2{ // return z + z0 := x.A0 + z1 := e.fp.Neg(&x.A1) + return &E2{ A0: z0, A1: *z1, } @@ -285,91 +282,6 @@ func FromE2(y *bn254.E2) E2 { } -func init() { - solver.RegisterHint(DivE2Hint) - solver.RegisterHint(InverseE2Hint) - solver.RegisterHint(MulByNonResidueInvHint) -} - -func MulByNonResidueInvHint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { - return emulated.UnwrapHint(nativeInputs, nativeOutputs, - func(mod *big.Int, inputs, outputs []*big.Int) error { - var a, c bn254.E2 - - a.A0.SetBigInt(inputs[0]) - a.A1.SetBigInt(inputs[1]) - - c.MulByNonResidueInv(&a) - - c.A0.BigInt(outputs[0]) - c.A1.BigInt(outputs[1]) - - return nil - - }) -} - -func (e Ext2) MulByNonResidueInv(api frontend.API, x *E2) *E2 { - field, err := emulated.NewField[emulated.BN254Fp](api) - if err != nil { - panic(err) - } - res, err := field.NewHint(MulByNonResidueInvHint, 2, &x.A0, &x.A1) - if err != nil { - // err is non-nil only for invalid number of inputs - panic(err) - } - - // r <-- x * (1/(9+u)) - r := E2{ - A0: *res[0], - A1: *res[1], - } - - // x == r * (9+u) - _x := e.MulByNonResidue(&r) - e.AssertIsEqual(x, _x) - - return &r - -} - -func InverseE2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { - return emulated.UnwrapHint(nativeInputs, nativeOutputs, - func(mod *big.Int, inputs, outputs []*big.Int) error { - var a, c bn254.E2 - - a.A0.SetBigInt(inputs[0]) - a.A1.SetBigInt(inputs[1]) - - c.Inverse(&a) - - c.A0.BigInt(outputs[0]) - c.A1.BigInt(outputs[1]) - - return nil - }) -} - -func DivE2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { - return emulated.UnwrapHint(nativeInputs, nativeOutputs, - func(mod *big.Int, inputs, outputs []*big.Int) error { - var a, b, c bn254.E2 - - a.A0.SetBigInt(inputs[0]) - a.A1.SetBigInt(inputs[1]) - b.A0.SetBigInt(inputs[2]) - b.A1.SetBigInt(inputs[3]) - - c.Inverse(&b).Mul(&c, &a) - - c.A0.BigInt(outputs[0]) - c.A1.BigInt(outputs[1]) - - return nil - }) -} - func (e Ext2) Inverse(api frontend.API, x *E2) *E2 { field, err := emulated.NewField[emulated.BN254Fp](api) if err != nil { @@ -418,3 +330,28 @@ func (e Ext2) DivUnchecked(api frontend.API, x, y E2) *E2 { return &div } + +func (e Ext2) MulByNonResidueInv(api frontend.API, x *E2) *E2 { + field, err := emulated.NewField[emulated.BN254Fp](api) + if err != nil { + panic(err) + } + res, err := field.NewHint(MulByNonResidueInvHint, 2, &x.A0, &x.A1) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + // r <-- x * (1/(9+u)) + r := E2{ + A0: *res[0], + A1: *res[1], + } + + // x == r * (9+u) + _x := e.MulByNonResidue(&r) + e.AssertIsEqual(x, _x) + + return &r + +} diff --git a/std/algebra/emulated/fields_bn254/e6.go b/std/algebra/emulated/fields_bn254/e6.go index 511968da40..fa0fbf1cf3 100644 --- a/std/algebra/emulated/fields_bn254/e6.go +++ b/std/algebra/emulated/fields_bn254/e6.go @@ -1,10 +1,7 @@ package fields_bn254 import ( - "math/big" - "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/math/emulated" ) @@ -205,68 +202,6 @@ func FromE6(y *bn254.E6) E6 { } -func init() { - solver.RegisterHint(DivE6Hint) - solver.RegisterHint(InverseE6Hint) -} - -func InverseE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { - return emulated.UnwrapHint(nativeInputs, nativeOutputs, - func(mod *big.Int, inputs, outputs []*big.Int) error { - var a, c bn254.E6 - - a.B0.A0.SetBigInt(inputs[0]) - a.B0.A1.SetBigInt(inputs[1]) - a.B1.A0.SetBigInt(inputs[2]) - a.B1.A1.SetBigInt(inputs[3]) - a.B2.A0.SetBigInt(inputs[4]) - a.B2.A1.SetBigInt(inputs[5]) - - c.Inverse(&a) - - c.B0.A0.BigInt(outputs[0]) - c.B0.A1.BigInt(outputs[1]) - c.B1.A0.BigInt(outputs[2]) - c.B1.A1.BigInt(outputs[3]) - c.B2.A0.BigInt(outputs[4]) - c.B2.A1.BigInt(outputs[5]) - - return nil - }) -} - -func DivE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { - return emulated.UnwrapHint(nativeInputs, nativeOutputs, - func(mod *big.Int, inputs, outputs []*big.Int) error { - var a, b, c bn254.E6 - - a.B0.A0.SetBigInt(inputs[0]) - a.B0.A1.SetBigInt(inputs[1]) - a.B1.A0.SetBigInt(inputs[2]) - a.B1.A1.SetBigInt(inputs[3]) - a.B2.A0.SetBigInt(inputs[4]) - a.B2.A1.SetBigInt(inputs[5]) - - b.B0.A0.SetBigInt(inputs[6]) - b.B0.A1.SetBigInt(inputs[7]) - b.B1.A0.SetBigInt(inputs[8]) - b.B1.A1.SetBigInt(inputs[9]) - b.B2.A0.SetBigInt(inputs[10]) - b.B2.A1.SetBigInt(inputs[11]) - - c.Inverse(&b).Mul(&c, &a) - - c.B0.A0.BigInt(outputs[0]) - c.B0.A1.BigInt(outputs[1]) - c.B1.A0.BigInt(outputs[2]) - c.B1.A1.BigInt(outputs[3]) - c.B2.A0.BigInt(outputs[4]) - c.B2.A1.BigInt(outputs[5]) - - return nil - }) -} - func (e Ext6) Inverse(api frontend.API, x *E6) *E6 { field, err := emulated.NewField[emulated.BN254Fp](api) if err != nil { diff --git a/std/algebra/emulated/fields_bn254/hints.go b/std/algebra/emulated/fields_bn254/hints.go new file mode 100644 index 0000000000..1387940966 --- /dev/null +++ b/std/algebra/emulated/fields_bn254/hints.go @@ -0,0 +1,230 @@ +package fields_bn254 + +import ( + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/std/math/emulated" +) + +func init() { + solver.RegisterHint(GetHints()...) +} + +// GetHints returns all hint functions used in the package. +func GetHints() []solver.Hint { + return []solver.Hint{ + // E2 + DivE2Hint, + InverseE2Hint, + MulByNonResidueInvHint, + // E6 + DivE6Hint, + InverseE6Hint, + // E12 + DivE12Hint, + InverseE12Hint, + } +} + +// E2 hints +func MulByNonResidueInvHint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, c bn254.E2 + + a.A0.SetBigInt(inputs[0]) + a.A1.SetBigInt(inputs[1]) + + c.MulByNonResidueInv(&a) + + c.A0.BigInt(outputs[0]) + c.A1.BigInt(outputs[1]) + + return nil + + }) +} + +func InverseE2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, c bn254.E2 + + a.A0.SetBigInt(inputs[0]) + a.A1.SetBigInt(inputs[1]) + + c.Inverse(&a) + + c.A0.BigInt(outputs[0]) + c.A1.BigInt(outputs[1]) + + return nil + }) +} + +func DivE2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, b, c bn254.E2 + + a.A0.SetBigInt(inputs[0]) + a.A1.SetBigInt(inputs[1]) + b.A0.SetBigInt(inputs[2]) + b.A1.SetBigInt(inputs[3]) + + c.Inverse(&b).Mul(&c, &a) + + c.A0.BigInt(outputs[0]) + c.A1.BigInt(outputs[1]) + + return nil + }) +} + +// E6 hints +func InverseE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, c bn254.E6 + + a.B0.A0.SetBigInt(inputs[0]) + a.B0.A1.SetBigInt(inputs[1]) + a.B1.A0.SetBigInt(inputs[2]) + a.B1.A1.SetBigInt(inputs[3]) + a.B2.A0.SetBigInt(inputs[4]) + a.B2.A1.SetBigInt(inputs[5]) + + c.Inverse(&a) + + c.B0.A0.BigInt(outputs[0]) + c.B0.A1.BigInt(outputs[1]) + c.B1.A0.BigInt(outputs[2]) + c.B1.A1.BigInt(outputs[3]) + c.B2.A0.BigInt(outputs[4]) + c.B2.A1.BigInt(outputs[5]) + + return nil + }) +} + +func DivE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, b, c bn254.E6 + + a.B0.A0.SetBigInt(inputs[0]) + a.B0.A1.SetBigInt(inputs[1]) + a.B1.A0.SetBigInt(inputs[2]) + a.B1.A1.SetBigInt(inputs[3]) + a.B2.A0.SetBigInt(inputs[4]) + a.B2.A1.SetBigInt(inputs[5]) + + b.B0.A0.SetBigInt(inputs[6]) + b.B0.A1.SetBigInt(inputs[7]) + b.B1.A0.SetBigInt(inputs[8]) + b.B1.A1.SetBigInt(inputs[9]) + b.B2.A0.SetBigInt(inputs[10]) + b.B2.A1.SetBigInt(inputs[11]) + + c.Inverse(&b).Mul(&c, &a) + + c.B0.A0.BigInt(outputs[0]) + c.B0.A1.BigInt(outputs[1]) + c.B1.A0.BigInt(outputs[2]) + c.B1.A1.BigInt(outputs[3]) + c.B2.A0.BigInt(outputs[4]) + c.B2.A1.BigInt(outputs[5]) + + return nil + }) +} + +// E12 hints +func InverseE12Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, c bn254.E12 + + a.C0.B0.A0.SetBigInt(inputs[0]) + a.C0.B0.A1.SetBigInt(inputs[1]) + a.C0.B1.A0.SetBigInt(inputs[2]) + a.C0.B1.A1.SetBigInt(inputs[3]) + a.C0.B2.A0.SetBigInt(inputs[4]) + a.C0.B2.A1.SetBigInt(inputs[5]) + a.C1.B0.A0.SetBigInt(inputs[6]) + a.C1.B0.A1.SetBigInt(inputs[7]) + a.C1.B1.A0.SetBigInt(inputs[8]) + a.C1.B1.A1.SetBigInt(inputs[9]) + a.C1.B2.A0.SetBigInt(inputs[10]) + a.C1.B2.A1.SetBigInt(inputs[11]) + + c.Inverse(&a) + + c.C0.B0.A0.BigInt(outputs[0]) + c.C0.B0.A1.BigInt(outputs[1]) + c.C0.B1.A0.BigInt(outputs[2]) + c.C0.B1.A1.BigInt(outputs[3]) + c.C0.B2.A0.BigInt(outputs[4]) + c.C0.B2.A1.BigInt(outputs[5]) + c.C1.B0.A0.BigInt(outputs[6]) + c.C1.B0.A1.BigInt(outputs[7]) + c.C1.B1.A0.BigInt(outputs[8]) + c.C1.B1.A1.BigInt(outputs[9]) + c.C1.B2.A0.BigInt(outputs[10]) + c.C1.B2.A1.BigInt(outputs[11]) + + return nil + }) +} + +func DivE12Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, b, c bn254.E12 + + a.C0.B0.A0.SetBigInt(inputs[0]) + a.C0.B0.A1.SetBigInt(inputs[1]) + a.C0.B1.A0.SetBigInt(inputs[2]) + a.C0.B1.A1.SetBigInt(inputs[3]) + a.C0.B2.A0.SetBigInt(inputs[4]) + a.C0.B2.A1.SetBigInt(inputs[5]) + a.C1.B0.A0.SetBigInt(inputs[6]) + a.C1.B0.A1.SetBigInt(inputs[7]) + a.C1.B1.A0.SetBigInt(inputs[8]) + a.C1.B1.A1.SetBigInt(inputs[9]) + a.C1.B2.A0.SetBigInt(inputs[10]) + a.C1.B2.A1.SetBigInt(inputs[11]) + + b.C0.B0.A0.SetBigInt(inputs[12]) + b.C0.B0.A1.SetBigInt(inputs[13]) + b.C0.B1.A0.SetBigInt(inputs[14]) + b.C0.B1.A1.SetBigInt(inputs[15]) + b.C0.B2.A0.SetBigInt(inputs[16]) + b.C0.B2.A1.SetBigInt(inputs[17]) + b.C1.B0.A0.SetBigInt(inputs[18]) + b.C1.B0.A1.SetBigInt(inputs[19]) + b.C1.B1.A0.SetBigInt(inputs[20]) + b.C1.B1.A1.SetBigInt(inputs[21]) + b.C1.B2.A0.SetBigInt(inputs[22]) + b.C1.B2.A1.SetBigInt(inputs[23]) + + c.Inverse(&b).Mul(&c, &a) + + c.C0.B0.A0.BigInt(outputs[0]) + c.C0.B0.A1.BigInt(outputs[1]) + c.C0.B1.A0.BigInt(outputs[2]) + c.C0.B1.A1.BigInt(outputs[3]) + c.C0.B2.A0.BigInt(outputs[4]) + c.C0.B2.A1.BigInt(outputs[5]) + c.C1.B0.A0.BigInt(outputs[6]) + c.C1.B0.A1.BigInt(outputs[7]) + c.C1.B1.A0.BigInt(outputs[8]) + c.C1.B1.A1.BigInt(outputs[9]) + c.C1.B2.A0.BigInt(outputs[10]) + c.C1.B2.A1.BigInt(outputs[11]) + + return nil + }) +} From bc5e40d543b969a9247f979d4dc31ba4325883cb Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 10 Mar 2023 12:35:00 +0100 Subject: [PATCH 097/464] perf(bn254-pair): optimize FrobeniusSquare computations --- std/algebra/emulated/fields_bn254/e12_test.go | 93 +++++++++++++++++++ std/algebra/emulated/fields_bn254/e2.go | 52 +++++++++-- std/algebra/emulated/fields_bn254/e2_test.go | 15 --- 3 files changed, 135 insertions(+), 25 deletions(-) diff --git a/std/algebra/emulated/fields_bn254/e12_test.go b/std/algebra/emulated/fields_bn254/e12_test.go index 2df2be5b14..9e5f632270 100644 --- a/std/algebra/emulated/fields_bn254/e12_test.go +++ b/std/algebra/emulated/fields_bn254/e12_test.go @@ -397,3 +397,96 @@ func TestFp12Expt(t *testing.T) { err := test.IsSolved(&e12Expt{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } + +type e12Frobenius struct { + A, C E12 +} + +func (circuit *e12Frobenius) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt12(ba) + + expected := e.Frobenius(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestFrobeniusFp12(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E12 + _, _ = a.SetRandom() + c.Frobenius(&a) + + witness := e12Frobenius{ + A: FromE12(&a), + C: FromE12(&c), + } + + err := test.IsSolved(&e12Frobenius{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e12FrobeniusSquare struct { + A, C E12 +} + +func (circuit *e12FrobeniusSquare) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt12(ba) + + expected := e.FrobeniusSquare(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestFrobeniusSquareFp12(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E12 + _, _ = a.SetRandom() + c.FrobeniusSquare(&a) + + witness := e12FrobeniusSquare{ + A: FromE12(&a), + C: FromE12(&c), + } + + err := test.IsSolved(&e12FrobeniusSquare{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +type e12FrobeniusCube struct { + A, C E12 +} + +func (circuit *e12FrobeniusCube) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt12(ba) + + expected := e.FrobeniusCube(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestFrobeniusCubeFp12(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E12 + _, _ = a.SetRandom() + c.FrobeniusCube(&a) + + witness := e12FrobeniusCube{ + A: FromE12(&a), + C: FromE12(&c), + } + + err := test.IsSolved(&e12FrobeniusCube{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} diff --git a/std/algebra/emulated/fields_bn254/e2.go b/std/algebra/emulated/fields_bn254/e2.go index 1f7def3dab..2eb8a91192 100644 --- a/std/algebra/emulated/fields_bn254/e2.go +++ b/std/algebra/emulated/fields_bn254/e2.go @@ -90,6 +90,7 @@ func (e Ext2) MulByNonResidueGeneric(x *E2, power, coef int) *E2 { return z } +// MulByNonResidue1Power1 return x*(9+u) func (e Ext2) MulByNonResidue(x *E2) *E2 { nine := big.NewInt(9) a := e.fp.MulConst(&x.A0, nine) @@ -102,66 +103,97 @@ func (e Ext2) MulByNonResidue(x *E2) *E2 { } } +// MulByNonResidue1Power1 returns x*(9+u)^(1*(p^1-1)/6) func (e Ext2) MulByNonResidue1Power1(x *E2) *E2 { return e.MulByNonResidueGeneric(x, 1, 1) } +// MulByNonResidue1Power2 returns x*(9+u)^(2*(p^1-1)/6) func (e Ext2) MulByNonResidue1Power2(x *E2) *E2 { return e.MulByNonResidueGeneric(x, 1, 2) } +// MulByNonResidue1Power3 returns x*(9+u)^(3*(p^1-1)/6) func (e Ext2) MulByNonResidue1Power3(x *E2) *E2 { return e.MulByNonResidueGeneric(x, 1, 3) } +// MulByNonResidue1Power4 returns x*(9+u)^(4*(p^1-1)/6) func (e Ext2) MulByNonResidue1Power4(x *E2) *E2 { return e.MulByNonResidueGeneric(x, 1, 4) } +// MulByNonResidue1Power5 returns x*(9+u)^(5*(p^1-1)/6) func (e Ext2) MulByNonResidue1Power5(x *E2) *E2 { return e.MulByNonResidueGeneric(x, 1, 5) } +// MulByNonResidue2Power1 returns x*(9+u)^(1*(p^2-1)/6) func (e Ext2) MulByNonResidue2Power1(x *E2) *E2 { - // TODO: A1 is 0, we can optimize for it - return e.MulByNonResidueGeneric(x, 2, 1) + element := emulated.ValueOf[emulated.BN254Fp]("21888242871839275220042445260109153167277707414472061641714758635765020556617") + return &E2{ + A0: *e.fp.MulMod(&x.A0, &element), + A1: *e.fp.MulMod(&x.A1, &element), + } } + +// MulByNonResidue2Power2 returns x*(9+u)^(2*(p^2-1)/6) func (e Ext2) MulByNonResidue2Power2(x *E2) *E2 { - // TODO: A1 is 0, we can optimize for it - return e.MulByNonResidueGeneric(x, 2, 2) + element := emulated.ValueOf[emulated.BN254Fp]("21888242871839275220042445260109153167277707414472061641714758635765020556616") + return &E2{ + A0: *e.fp.MulMod(&x.A0, &element), + A1: *e.fp.MulMod(&x.A1, &element), + } } +// MulByNonResidue2Power3 returns x*(9+u)^(3*(p^2-1)/6) func (e Ext2) MulByNonResidue2Power3(x *E2) *E2 { - // TODO: A1 is 0, we can optimize for it - return e.MulByNonResidueGeneric(x, 2, 3) + element := emulated.ValueOf[emulated.BN254Fp]("21888242871839275222246405745257275088696311157297823662689037894645226208582") + return &E2{ + A0: *e.fp.MulMod(&x.A0, &element), + A1: *e.fp.MulMod(&x.A1, &element), + } } +// MulByNonResidue2Power4 returns x*(9+u)^(4*(p^2-1)/6) func (e Ext2) MulByNonResidue2Power4(x *E2) *E2 { - // TODO: A1 is 0, we can optimize for it - return e.MulByNonResidueGeneric(x, 2, 4) + element := emulated.ValueOf[emulated.BN254Fp]("2203960485148121921418603742825762020974279258880205651966") + return &E2{ + A0: *e.fp.MulMod(&x.A0, &element), + A1: *e.fp.MulMod(&x.A1, &element), + } } +// MulByNonResidue2Power5 returns x*(9+u)^(5*(p^2-1)/6) func (e Ext2) MulByNonResidue2Power5(x *E2) *E2 { - // TODO: A1 is 0, we can optimize for it - return e.MulByNonResidueGeneric(x, 2, 5) + element := emulated.ValueOf[emulated.BN254Fp]("2203960485148121921418603742825762020974279258880205651967") + return &E2{ + A0: *e.fp.MulMod(&x.A0, &element), + A1: *e.fp.MulMod(&x.A1, &element), + } } +// MulByNonResidue3Power1 returns x*(9+u)^(1*(p^3-1)/6) func (e Ext2) MulByNonResidue3Power1(x *E2) *E2 { return e.MulByNonResidueGeneric(x, 3, 1) } +// MulByNonResidue3Power2 returns x*(9+u)^(2*(p^3-1)/6) func (e Ext2) MulByNonResidue3Power2(x *E2) *E2 { return e.MulByNonResidueGeneric(x, 3, 2) } +// MulByNonResidue3Power3 returns x*(9+u)^(3*(p^3-1)/6) func (e Ext2) MulByNonResidue3Power3(x *E2) *E2 { return e.MulByNonResidueGeneric(x, 3, 3) } +// MulByNonResidue3Power4 returns x*(9+u)^(4*(p^3-1)/6) func (e Ext2) MulByNonResidue3Power4(x *E2) *E2 { return e.MulByNonResidueGeneric(x, 3, 4) } +// MulByNonResidue3Power5 returns x*(9+u)^(5*(p^3-1)/6) func (e Ext2) MulByNonResidue3Power5(x *E2) *E2 { return e.MulByNonResidueGeneric(x, 3, 5) } diff --git a/std/algebra/emulated/fields_bn254/e2_test.go b/std/algebra/emulated/fields_bn254/e2_test.go index 560e3e2f5c..bcad7750a7 100644 --- a/std/algebra/emulated/fields_bn254/e2_test.go +++ b/std/algebra/emulated/fields_bn254/e2_test.go @@ -1,16 +1,12 @@ package fields_bn254 import ( - "fmt" "testing" "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fp" - "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/profile" "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/test" ) @@ -464,14 +460,3 @@ func TestInverseFp2(t *testing.T) { err := test.IsSolved(&e2Inverse{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } - -// bench -var ccsBench constraint.ConstraintSystem - -func BenchmarkPairing(b *testing.B) { - var c e2MulByNonResidueInv - p := profile.Start() - ccsBench, _ = frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &c) - p.Stop() - fmt.Println(p.NbConstraints()) -} From 39a181bef80c0794ce84b387723daffec0116b75 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 10 Mar 2023 12:46:02 +0100 Subject: [PATCH 098/464] perf(bn254-pair): optimize Halve using hints --- std/algebra/emulated/fields_bn254/e2.go | 33 +++++++++++++------- std/algebra/emulated/fields_bn254/e2_test.go | 17 +++++++++- std/algebra/emulated/fields_bn254/hints.go | 18 +++++++++++ std/algebra/emulated/sw_bn254/pairing.go | 4 +-- 4 files changed, 58 insertions(+), 14 deletions(-) diff --git a/std/algebra/emulated/fields_bn254/e2.go b/std/algebra/emulated/fields_bn254/e2.go index 2eb8a91192..52f3ffb35c 100644 --- a/std/algebra/emulated/fields_bn254/e2.go +++ b/std/algebra/emulated/fields_bn254/e2.go @@ -280,18 +280,29 @@ func (e Ext2) Double(x *E2) *E2 { } } -func (e Ext2) Halve(x *E2) *E2 { - // I'm trying to avoid hard-coding modulus here in case want to make generic - // for different curves. - // TODO: if implemented Half in field emulation, then replace with it. - one := e.fp.One() - two := e.fp.MulConst(one, big.NewInt(2)) - z0 := e.fp.Div(&x.A0, two) - z1 := e.fp.Div(&x.A1, two) - return &E2{ - A0: *z0, - A1: *z1, +func (e Ext2) Halve(api frontend.API, x *E2) *E2 { + field, err := emulated.NewField[emulated.BN254Fp](api) + if err != nil { + panic(err) } + res, err := field.NewHint(HalveE2Hint, 2, &x.A0, &x.A1) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + // half = x/2 + half := E2{ + A0: *res[0], + A1: *res[1], + } + + // x == 2*half + _x := *e.Double(&half) + e.AssertIsEqual(x, &_x) + + return &half + } func (e Ext2) MulBybTwistCurveCoeff(api frontend.API, x *E2) *E2 { diff --git a/std/algebra/emulated/fields_bn254/e2_test.go b/std/algebra/emulated/fields_bn254/e2_test.go index bcad7750a7..fe228116ee 100644 --- a/std/algebra/emulated/fields_bn254/e2_test.go +++ b/std/algebra/emulated/fields_bn254/e2_test.go @@ -1,12 +1,16 @@ package fields_bn254 import ( + "fmt" "testing" "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fp" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/profile" "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/test" ) @@ -113,7 +117,7 @@ type e2Halve struct { func (circuit *e2Halve) Define(api frontend.API) error { ba, _ := emulated.NewField[emulated.BN254Fp](api) e := NewExt2(ba) - expected := e.Halve(&circuit.A) + expected := e.Halve(api, &circuit.A) e.AssertIsEqual(expected, &circuit.C) return nil } @@ -460,3 +464,14 @@ func TestInverseFp2(t *testing.T) { err := test.IsSolved(&e2Inverse{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } + +// bench +var ccsBench constraint.ConstraintSystem + +func BenchmarkHalve(b *testing.B) { + var c e2Halve + p := profile.Start() + ccsBench, _ = frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &c) + p.Stop() + fmt.Println(p.NbConstraints()) +} diff --git a/std/algebra/emulated/fields_bn254/hints.go b/std/algebra/emulated/fields_bn254/hints.go index 1387940966..6272b925bd 100644 --- a/std/algebra/emulated/fields_bn254/hints.go +++ b/std/algebra/emulated/fields_bn254/hints.go @@ -19,6 +19,7 @@ func GetHints() []solver.Hint { DivE2Hint, InverseE2Hint, MulByNonResidueInvHint, + HalveE2Hint, // E6 DivE6Hint, InverseE6Hint, @@ -83,6 +84,23 @@ func DivE2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error }) } +func HalveE2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, c bn254.E2 + + a.A0.SetBigInt(inputs[0]) + a.A1.SetBigInt(inputs[1]) + + c.Set(&a).Halve() + + c.A0.BigInt(outputs[0]) + c.A1.BigInt(outputs[1]) + + return nil + }) +} + // E6 hints func InverseE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { return emulated.UnwrapHint(nativeInputs, nativeOutputs, diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index e8ed1fb62e..85d1e3a33e 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -61,7 +61,7 @@ func NewPairing(api frontend.API) (*Pairing, error) { func (pr Pairing) DoubleStep(api frontend.API, p *g2Projective) (*g2Projective, *lineEvaluation) { // var t1, A, B, C, D, E, EE, F, G, H, I, J, K fptower.E2 A := pr.Ext2.Mul(&p.X, &p.Y) // A.Mul(&p.x, &p.y) - A = pr.Ext2.Halve(A) // A.Halve() + A = pr.Ext2.Halve(api, A) // A.Halve() B := pr.Ext2.Square(&p.Y) // B.Square(&p.y) C := pr.Ext2.Square(&p.Z) // C.Square(&p.z) D := pr.Ext2.Double(C) // D.Double(&C). @@ -70,7 +70,7 @@ func (pr Pairing) DoubleStep(api frontend.API, p *g2Projective) (*g2Projective, F := pr.Ext2.Double(E) // F.Double(&E). F = pr.Ext2.Add(F, E) // Add(&F, &E) G := pr.Ext2.Add(B, F) // G.Add(&B, &F) - G = pr.Ext2.Halve(G) // G.Halve() + G = pr.Ext2.Halve(api, G) // G.Halve() H := pr.Ext2.Add(&p.Y, &p.Z) // H.Add(&p.y, &p.z). H = pr.Ext2.Square(H) // Square(&H) t1 := pr.Ext2.Add(B, C) // t1.Add(&B, &C) From 86d843645822548b4c80bf48138c1abe291a6003 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 10 Mar 2023 17:48:31 +0100 Subject: [PATCH 099/464] test(fields_bn254): clean tests --- .../emulated/fields_bn254/e12_pairing.go | 77 +++++++++---------- std/algebra/emulated/fields_bn254/e12_test.go | 52 +++++++++++-- std/algebra/emulated/fields_bn254/e2_test.go | 15 ---- std/algebra/emulated/sw_bn254/pairing.go | 17 ++-- 4 files changed, 93 insertions(+), 68 deletions(-) diff --git a/std/algebra/emulated/fields_bn254/e12_pairing.go b/std/algebra/emulated/fields_bn254/e12_pairing.go index 344be7d08f..f0d7931d36 100644 --- a/std/algebra/emulated/fields_bn254/e12_pairing.go +++ b/std/algebra/emulated/fields_bn254/e12_pairing.go @@ -45,52 +45,49 @@ func (e Ext12) Expt(api frontend.API, x *E12) *E12 { } func (e Ext12) MulBy034(z *E12, c0, c3, c4 *E2) *E12 { - // var a, b, d E6 - a := e.Ext6.MulByE2(&z.C0, c0) // a.MulByE2(&z.C0, c0) - // b.Set(&z.C1) - b := e.Ext6.MulBy01(&z.C1, c3, c4) // b.MulBy01(c3, c4) - c0 = e.Ext2.Add(c0, c3) // c0.Add(c0, c3) - d := e.Ext6.Add(&z.C0, &z.C1) // d.Add(&z.C0, &z.C1) - d = e.Ext6.MulBy01(d, c0, c4) // d.MulBy01(c0, c4) - z1 := e.Ext6.Add(a, b) // z.C1.Add(&a, &b). - z1 = e.Neg(z1) // Neg(&z.C1). - z1 = e.Ext6.Add(z1, d) // Add(&z.C1, &d) - z0 := e.MulByNonResidue(b) // z.C0.MulByNonResidue(&b). - z0 = e.Ext6.Add(z0, a) // Add(&z.C0, &a) - return &E12{ // return z + a := e.Ext6.MulByE2(&z.C0, c0) + b := e.Ext6.MulBy01(&z.C1, c3, c4) + c0 = e.Ext2.Add(c0, c3) + d := e.Ext6.Add(&z.C0, &z.C1) + d = e.Ext6.MulBy01(d, c0, c4) + z1 := e.Ext6.Add(a, b) + z1 = e.Neg(z1) + z1 = e.Ext6.Add(z1, d) + z0 := e.MulByNonResidue(b) + z0 = e.Ext6.Add(z0, a) + return &E12{ C0: *z0, C1: *z1, } } func (e Ext12) MulBy034by034(d0, d3, d4, c0, c3, c4 *E2) *E12 { - // var tmp, x0, x3, x4, x04, x03, x34 E2 - x0 := e.Ext2.Mul(c0, d0) // x0.Mul(c0, d0) - x3 := e.Ext2.Mul(c3, d3) // x3.Mul(c3, d3) - x4 := e.Ext2.Mul(c4, d4) // x4.Mul(c4, d4) - tmp := e.Ext2.Add(c0, c4) // tmp.Add(c0, c4) - x04 := e.Ext2.Add(d0, d4) // x04.Add(d0, d4). - x04 = e.Ext2.Mul(x04, tmp) // Mul(&x04, &tmp). - x04 = e.Ext2.Sub(x04, x0) // Sub(&x04, &x0). - x04 = e.Ext2.Sub(x04, x4) // Sub(&x04, &x4) - tmp = e.Ext2.Add(c0, c3) // tmp.Add(c0, c3) - x03 := e.Ext2.Add(d0, d3) // x03.Add(d0, d3). - x03 = e.Ext2.Mul(x03, tmp) // Mul(&x03, &tmp). - x03 = e.Ext2.Sub(x03, x0) // Sub(&x03, &x0). - x03 = e.Ext2.Sub(x03, x3) // Sub(&x03, &x3) - tmp = e.Ext2.Add(c3, c4) // tmp.Add(c3, c4) - x34 := e.Ext2.Add(d3, d4) // x34.Add(d3, d4). - x34 = e.Ext2.Mul(x34, tmp) // Mul(&x34, &tmp). - x34 = e.Ext2.Sub(x34, x3) // Sub(&x34, &x3). - x34 = e.Ext2.Sub(x34, x4) // Sub(&x34, &x4) - z00 := e.Ext2.MulByNonResidue(x4) // z.C0.B0.MulByNonResidue(&x4). - z00 = e.Ext2.Add(z00, x0) // Add(&z.C0.B0, &x0) - z01 := x3 // z.C0.B1.Set(&x3) - z02 := x34 // z.C0.B2.Set(&x34) - z10 := x03 // z.C1.B0.Set(&x03) - z11 := x04 // z.C1.B1.Set(&x04) - z12 := e.Ext2.Zero() // z.C1.B2.SetZero() - return &E12{ // return z + x0 := e.Ext2.Mul(c0, d0) + x3 := e.Ext2.Mul(c3, d3) + x4 := e.Ext2.Mul(c4, d4) + tmp := e.Ext2.Add(c0, c4) + x04 := e.Ext2.Add(d0, d4) + x04 = e.Ext2.Mul(x04, tmp) + x04 = e.Ext2.Sub(x04, x0) + x04 = e.Ext2.Sub(x04, x4) + tmp = e.Ext2.Add(c0, c3) + x03 := e.Ext2.Add(d0, d3) + x03 = e.Ext2.Mul(x03, tmp) + x03 = e.Ext2.Sub(x03, x0) + x03 = e.Ext2.Sub(x03, x3) + tmp = e.Ext2.Add(c3, c4) + x34 := e.Ext2.Add(d3, d4) + x34 = e.Ext2.Mul(x34, tmp) + x34 = e.Ext2.Sub(x34, x3) + x34 = e.Ext2.Sub(x34, x4) + z00 := e.Ext2.MulByNonResidue(x4) + z00 = e.Ext2.Add(z00, x0) + z01 := x3 + z02 := x34 + z10 := x03 + z11 := x04 + z12 := e.Ext2.Zero() + return &E12{ C0: E6{ B0: *z00, B1: *z01, diff --git a/std/algebra/emulated/fields_bn254/e12_test.go b/std/algebra/emulated/fields_bn254/e12_test.go index 9e5f632270..96470e3099 100644 --- a/std/algebra/emulated/fields_bn254/e12_test.go +++ b/std/algebra/emulated/fields_bn254/e12_test.go @@ -224,10 +224,8 @@ func (circuit *e12CycloSquare) Define(api frontend.API) error { ba, _ := emulated.NewField[emulated.BN254Fp](api) e := NewExt12(ba) - u := e.Square(&circuit.A) - v := e.CyclotomicSquare(&circuit.A) - e.AssertIsEqual(u, v) - e.AssertIsEqual(u, &circuit.C) + expected := e.CyclotomicSquare(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) return nil } @@ -264,9 +262,8 @@ func (circuit *e12CycloSquareKarabina) Define(api frontend.API) error { ba, _ := emulated.NewField[emulated.BN254Fp](api) e := NewExt12(ba) - v := e.CyclotomicSquareCompressed(&circuit.A) - v = e.DecompressKarabina(api, v) - e.AssertIsEqual(v, &circuit.C) + expected := e.CyclotomicSquareCompressed(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) return nil } @@ -284,7 +281,6 @@ func TestFp12CyclotomicSquareKarabina(t *testing.T) { tmp.Mul(&tmp, &a) a.FrobeniusSquare(&tmp).Mul(&a, &tmp) c.CyclotomicSquareCompressed(&a) - c.DecompressKarabina(&c) witness := e12CycloSquareKarabina{ A: FromE12(&a), @@ -295,6 +291,46 @@ func TestFp12CyclotomicSquareKarabina(t *testing.T) { assert.NoError(err) } +type e12CycloSquareKarabinaAndDecompress struct { + A E12 + C E12 `gnark:",public"` +} + +func (circuit *e12CycloSquareKarabinaAndDecompress) Define(api frontend.API) error { + + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt12(ba) + expected := e.CyclotomicSquareCompressed(&circuit.A) + expected = e.DecompressKarabina(api, expected) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestFp12CyclotomicSquareKarabinaAndDecompress(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E12 + _, _ = a.SetRandom() + + // put a in the cyclotomic subgroup + var tmp bn254.E12 + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + c.CyclotomicSquareCompressed(&a) + c.DecompressKarabina(&c) + + witness := e12CycloSquareKarabina{ + A: FromE12(&a), + C: FromE12(&c), + } + + err := test.IsSolved(&e12CycloSquareKarabinaAndDecompress{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + type e12Conjugate struct { A E12 C E12 `gnark:",public"` diff --git a/std/algebra/emulated/fields_bn254/e2_test.go b/std/algebra/emulated/fields_bn254/e2_test.go index fe228116ee..224492cffb 100644 --- a/std/algebra/emulated/fields_bn254/e2_test.go +++ b/std/algebra/emulated/fields_bn254/e2_test.go @@ -1,16 +1,12 @@ package fields_bn254 import ( - "fmt" "testing" "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fp" - "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/profile" "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/test" ) @@ -464,14 +460,3 @@ func TestInverseFp2(t *testing.T) { err := test.IsSolved(&e2Inverse{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } - -// bench -var ccsBench constraint.ConstraintSystem - -func BenchmarkHalve(b *testing.B) { - var c e2Halve - p := profile.Start() - ccsBench, _ = frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &c) - p.Stop() - fmt.Println(p.NbConstraints()) -} diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 85d1e3a33e..9ff8311e9b 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -261,18 +261,25 @@ func (pr Pairing) MillerLoop(api frontend.API, p []*G1Affine, q []*G2Affine) (*G return result, nil } +// FinalExponentiation computes the exponentiation eᵈ +// where d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r +// we use instead d'= s ⋅ d, where s is the cofactor 2x₀(6x₀²+3x₀+1) +// and r does NOT divide d' func (pr Pairing) FinalExponentiation(api frontend.API, e *GTEl) *GTEl { - // var result GT - // result.Set(z) - var t [4]*GTEl // var t [4]GT + var t [4]*GTEl - // easy part + // Easy part + // (p⁶-1)(p²+1) t[0] = pr.Ext12.Conjugate(e) t[0] = pr.Ext12.DivUnchecked(api, *t[0], *e) result := pr.Ext12.FrobeniusSquare(t[0]) result = pr.Ext12.Mul(result, t[0]) - //hard part + // Hard part (up to permutation) + // 2x₀(6x₀²+3x₀+1)(p⁴-p²+1)/r + // Duquesne and Ghammam + // https://eprint.iacr.org/2015/192.pdf + // Fuentes et al. variant (alg. 10) t[0] = pr.Ext12.Expt(api, result) t[0] = pr.Ext12.Conjugate(t[0]) t[0] = pr.Ext12.CyclotomicSquare(t[0]) From 9f74ad791b8c5103d73e239013b8f6457042d1df Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Fri, 10 Mar 2023 11:28:33 -0600 Subject: [PATCH 100/464] perf: plonk ccs serialization (#557) * perf: don't add debug info for each bool unless debug tag is set * feat,perf: remove *HintMapping from System struct, use int id instead --- constraint/bls12-377/r1cs.go | 2 +- constraint/bls12-377/r1cs_sparse.go | 2 +- constraint/bls12-377/solution.go | 19 +++++++++++-------- constraint/bls12-381/r1cs.go | 2 +- constraint/bls12-381/r1cs_sparse.go | 2 +- constraint/bls12-381/solution.go | 19 +++++++++++-------- constraint/bls24-315/r1cs.go | 2 +- constraint/bls24-315/r1cs_sparse.go | 2 +- constraint/bls24-315/solution.go | 19 +++++++++++-------- constraint/bls24-317/r1cs.go | 2 +- constraint/bls24-317/r1cs_sparse.go | 2 +- constraint/bls24-317/solution.go | 19 +++++++++++-------- constraint/bn254/r1cs.go | 2 +- constraint/bn254/r1cs_sparse.go | 2 +- constraint/bn254/solution.go | 19 +++++++++++-------- constraint/bw6-633/r1cs.go | 2 +- constraint/bw6-633/r1cs_sparse.go | 2 +- constraint/bw6-633/solution.go | 19 +++++++++++-------- constraint/bw6-761/r1cs.go | 2 +- constraint/bw6-761/r1cs_sparse.go | 2 +- constraint/bw6-761/solution.go | 19 +++++++++++-------- constraint/level_builder.go | 9 +++++---- constraint/system.go | 19 +++++++++++-------- constraint/tinyfield/r1cs.go | 2 +- constraint/tinyfield/r1cs_sparse.go | 2 +- constraint/tinyfield/solution.go | 19 +++++++++++-------- frontend/cs/scs/api_assertions.go | 13 ++++++++++--- .../template/representations/r1cs.go.tmpl | 2 +- .../representations/r1cs.sparse.go.tmpl | 2 +- .../template/representations/solution.go.tmpl | 17 ++++++++++------- 30 files changed, 142 insertions(+), 104 deletions(-) diff --git a/constraint/bls12-377/r1cs.go b/constraint/bls12-377/r1cs.go index 40c9af537f..dc3797887c 100644 --- a/constraint/bls12-377/r1cs.go +++ b/constraint/bls12-377/r1cs.go @@ -107,7 +107,7 @@ func (cs *R1CS) solve(witness, a, b, c fr.Vector, opt solver.Config) (fr.Vector, log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - solution, err := newSolution(nbWires, opt.HintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients, &cs.System.SymbolTable) + solution, err := newSolution(&cs.System, nbWires, opt.HintFunctions, cs.Coefficients) if err != nil { return make(fr.Vector, nbWires), err } diff --git a/constraint/bls12-377/r1cs_sparse.go b/constraint/bls12-377/r1cs_sparse.go index ff06c23efd..1d9cbc1b75 100644 --- a/constraint/bls12-377/r1cs_sparse.go +++ b/constraint/bls12-377/r1cs_sparse.go @@ -150,7 +150,7 @@ func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, er } // keep track of wire that have a value - solution, err := newSolution(nbVariables, opt.HintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients, &cs.System.SymbolTable) + solution, err := newSolution(&cs.System, nbVariables, opt.HintFunctions, cs.Coefficients) if err != nil { return solution.values, err } diff --git a/constraint/bls12-377/solution.go b/constraint/bls12-377/solution.go index e93dc7bfa1..112682fafe 100644 --- a/constraint/bls12-377/solution.go +++ b/constraint/bls12-377/solution.go @@ -38,25 +38,25 @@ type solution struct { values, coefficients []fr.Element solved []bool nbSolved uint64 - mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function - mHints map[int]*constraint.HintMapping // maps wireID to hint + mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function st *debug.SymbolTable + cs *constraint.System } -func newSolution(nbWires int, hintFunctions map[solver.HintID]solver.Hint, hintsDependencies map[solver.HintID]string, mHints map[int]*constraint.HintMapping, coefficients []fr.Element, st *debug.SymbolTable) (solution, error) { +func newSolution(cs *constraint.System, nbWires int, hintFunctions map[solver.HintID]solver.Hint, coefficients []fr.Element) (solution, error) { s := solution{ - st: st, + cs: cs, + st: &cs.SymbolTable, values: make([]fr.Element, nbWires), coefficients: coefficients, solved: make([]bool, nbWires), mHintsFunctions: hintFunctions, - mHints: mHints, } // hintsDependencies is from compile time; it contains the list of hints the solver **needs** var missing []string - for hintUUID, hintID := range hintsDependencies { + for hintUUID, hintID := range cs.MHintsDependencies { if _, ok := s.mHintsFunctions[hintUUID]; !ok { missing = append(missing, hintID) } @@ -140,12 +140,15 @@ func (s *solution) accumulateInto(t constraint.Term, r *fr.Element) { } // solveHint compute solution.values[vID] using provided solver hint -func (s *solution) solveWithHint(vID int, h *constraint.HintMapping) error { +func (s *solution) solveWithHint(vID int, hID int) error { // skip if the wire is already solved by a call to the same hint // function on the same inputs if s.solved[vID] { return nil } + + h := &s.cs.HintMappings[hID] + // ensure hint function was provided f, ok := s.mHintsFunctions[h.HintID] if !ok { @@ -177,7 +180,7 @@ func (s *solution) solveWithHint(vID int, h *constraint.HintMapping) error { return nil } // unsolved dependency - if h, ok := s.mHints[wID]; ok { + if h, ok := s.cs.MHints[wID]; ok { // solve recursively. return s.solveWithHint(wID, h) } diff --git a/constraint/bls12-381/r1cs.go b/constraint/bls12-381/r1cs.go index f007cee3de..063c5462fd 100644 --- a/constraint/bls12-381/r1cs.go +++ b/constraint/bls12-381/r1cs.go @@ -107,7 +107,7 @@ func (cs *R1CS) solve(witness, a, b, c fr.Vector, opt solver.Config) (fr.Vector, log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - solution, err := newSolution(nbWires, opt.HintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients, &cs.System.SymbolTable) + solution, err := newSolution(&cs.System, nbWires, opt.HintFunctions, cs.Coefficients) if err != nil { return make(fr.Vector, nbWires), err } diff --git a/constraint/bls12-381/r1cs_sparse.go b/constraint/bls12-381/r1cs_sparse.go index e4aea25b0a..333ef0bb6d 100644 --- a/constraint/bls12-381/r1cs_sparse.go +++ b/constraint/bls12-381/r1cs_sparse.go @@ -150,7 +150,7 @@ func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, er } // keep track of wire that have a value - solution, err := newSolution(nbVariables, opt.HintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients, &cs.System.SymbolTable) + solution, err := newSolution(&cs.System, nbVariables, opt.HintFunctions, cs.Coefficients) if err != nil { return solution.values, err } diff --git a/constraint/bls12-381/solution.go b/constraint/bls12-381/solution.go index 2e0d32172c..b267734702 100644 --- a/constraint/bls12-381/solution.go +++ b/constraint/bls12-381/solution.go @@ -38,25 +38,25 @@ type solution struct { values, coefficients []fr.Element solved []bool nbSolved uint64 - mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function - mHints map[int]*constraint.HintMapping // maps wireID to hint + mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function st *debug.SymbolTable + cs *constraint.System } -func newSolution(nbWires int, hintFunctions map[solver.HintID]solver.Hint, hintsDependencies map[solver.HintID]string, mHints map[int]*constraint.HintMapping, coefficients []fr.Element, st *debug.SymbolTable) (solution, error) { +func newSolution(cs *constraint.System, nbWires int, hintFunctions map[solver.HintID]solver.Hint, coefficients []fr.Element) (solution, error) { s := solution{ - st: st, + cs: cs, + st: &cs.SymbolTable, values: make([]fr.Element, nbWires), coefficients: coefficients, solved: make([]bool, nbWires), mHintsFunctions: hintFunctions, - mHints: mHints, } // hintsDependencies is from compile time; it contains the list of hints the solver **needs** var missing []string - for hintUUID, hintID := range hintsDependencies { + for hintUUID, hintID := range cs.MHintsDependencies { if _, ok := s.mHintsFunctions[hintUUID]; !ok { missing = append(missing, hintID) } @@ -140,12 +140,15 @@ func (s *solution) accumulateInto(t constraint.Term, r *fr.Element) { } // solveHint compute solution.values[vID] using provided solver hint -func (s *solution) solveWithHint(vID int, h *constraint.HintMapping) error { +func (s *solution) solveWithHint(vID int, hID int) error { // skip if the wire is already solved by a call to the same hint // function on the same inputs if s.solved[vID] { return nil } + + h := &s.cs.HintMappings[hID] + // ensure hint function was provided f, ok := s.mHintsFunctions[h.HintID] if !ok { @@ -177,7 +180,7 @@ func (s *solution) solveWithHint(vID int, h *constraint.HintMapping) error { return nil } // unsolved dependency - if h, ok := s.mHints[wID]; ok { + if h, ok := s.cs.MHints[wID]; ok { // solve recursively. return s.solveWithHint(wID, h) } diff --git a/constraint/bls24-315/r1cs.go b/constraint/bls24-315/r1cs.go index 64925c8a5b..3c42462419 100644 --- a/constraint/bls24-315/r1cs.go +++ b/constraint/bls24-315/r1cs.go @@ -107,7 +107,7 @@ func (cs *R1CS) solve(witness, a, b, c fr.Vector, opt solver.Config) (fr.Vector, log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - solution, err := newSolution(nbWires, opt.HintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients, &cs.System.SymbolTable) + solution, err := newSolution(&cs.System, nbWires, opt.HintFunctions, cs.Coefficients) if err != nil { return make(fr.Vector, nbWires), err } diff --git a/constraint/bls24-315/r1cs_sparse.go b/constraint/bls24-315/r1cs_sparse.go index 794c9b06ee..4789d82329 100644 --- a/constraint/bls24-315/r1cs_sparse.go +++ b/constraint/bls24-315/r1cs_sparse.go @@ -150,7 +150,7 @@ func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, er } // keep track of wire that have a value - solution, err := newSolution(nbVariables, opt.HintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients, &cs.System.SymbolTable) + solution, err := newSolution(&cs.System, nbVariables, opt.HintFunctions, cs.Coefficients) if err != nil { return solution.values, err } diff --git a/constraint/bls24-315/solution.go b/constraint/bls24-315/solution.go index 4efab5606e..cacdc58211 100644 --- a/constraint/bls24-315/solution.go +++ b/constraint/bls24-315/solution.go @@ -38,25 +38,25 @@ type solution struct { values, coefficients []fr.Element solved []bool nbSolved uint64 - mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function - mHints map[int]*constraint.HintMapping // maps wireID to hint + mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function st *debug.SymbolTable + cs *constraint.System } -func newSolution(nbWires int, hintFunctions map[solver.HintID]solver.Hint, hintsDependencies map[solver.HintID]string, mHints map[int]*constraint.HintMapping, coefficients []fr.Element, st *debug.SymbolTable) (solution, error) { +func newSolution(cs *constraint.System, nbWires int, hintFunctions map[solver.HintID]solver.Hint, coefficients []fr.Element) (solution, error) { s := solution{ - st: st, + cs: cs, + st: &cs.SymbolTable, values: make([]fr.Element, nbWires), coefficients: coefficients, solved: make([]bool, nbWires), mHintsFunctions: hintFunctions, - mHints: mHints, } // hintsDependencies is from compile time; it contains the list of hints the solver **needs** var missing []string - for hintUUID, hintID := range hintsDependencies { + for hintUUID, hintID := range cs.MHintsDependencies { if _, ok := s.mHintsFunctions[hintUUID]; !ok { missing = append(missing, hintID) } @@ -140,12 +140,15 @@ func (s *solution) accumulateInto(t constraint.Term, r *fr.Element) { } // solveHint compute solution.values[vID] using provided solver hint -func (s *solution) solveWithHint(vID int, h *constraint.HintMapping) error { +func (s *solution) solveWithHint(vID int, hID int) error { // skip if the wire is already solved by a call to the same hint // function on the same inputs if s.solved[vID] { return nil } + + h := &s.cs.HintMappings[hID] + // ensure hint function was provided f, ok := s.mHintsFunctions[h.HintID] if !ok { @@ -177,7 +180,7 @@ func (s *solution) solveWithHint(vID int, h *constraint.HintMapping) error { return nil } // unsolved dependency - if h, ok := s.mHints[wID]; ok { + if h, ok := s.cs.MHints[wID]; ok { // solve recursively. return s.solveWithHint(wID, h) } diff --git a/constraint/bls24-317/r1cs.go b/constraint/bls24-317/r1cs.go index 2c6eb08acd..e397fb5073 100644 --- a/constraint/bls24-317/r1cs.go +++ b/constraint/bls24-317/r1cs.go @@ -107,7 +107,7 @@ func (cs *R1CS) solve(witness, a, b, c fr.Vector, opt solver.Config) (fr.Vector, log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - solution, err := newSolution(nbWires, opt.HintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients, &cs.System.SymbolTable) + solution, err := newSolution(&cs.System, nbWires, opt.HintFunctions, cs.Coefficients) if err != nil { return make(fr.Vector, nbWires), err } diff --git a/constraint/bls24-317/r1cs_sparse.go b/constraint/bls24-317/r1cs_sparse.go index 6208f3deec..dbad078e57 100644 --- a/constraint/bls24-317/r1cs_sparse.go +++ b/constraint/bls24-317/r1cs_sparse.go @@ -150,7 +150,7 @@ func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, er } // keep track of wire that have a value - solution, err := newSolution(nbVariables, opt.HintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients, &cs.System.SymbolTable) + solution, err := newSolution(&cs.System, nbVariables, opt.HintFunctions, cs.Coefficients) if err != nil { return solution.values, err } diff --git a/constraint/bls24-317/solution.go b/constraint/bls24-317/solution.go index a3628fc04b..789d74ac9b 100644 --- a/constraint/bls24-317/solution.go +++ b/constraint/bls24-317/solution.go @@ -38,25 +38,25 @@ type solution struct { values, coefficients []fr.Element solved []bool nbSolved uint64 - mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function - mHints map[int]*constraint.HintMapping // maps wireID to hint + mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function st *debug.SymbolTable + cs *constraint.System } -func newSolution(nbWires int, hintFunctions map[solver.HintID]solver.Hint, hintsDependencies map[solver.HintID]string, mHints map[int]*constraint.HintMapping, coefficients []fr.Element, st *debug.SymbolTable) (solution, error) { +func newSolution(cs *constraint.System, nbWires int, hintFunctions map[solver.HintID]solver.Hint, coefficients []fr.Element) (solution, error) { s := solution{ - st: st, + cs: cs, + st: &cs.SymbolTable, values: make([]fr.Element, nbWires), coefficients: coefficients, solved: make([]bool, nbWires), mHintsFunctions: hintFunctions, - mHints: mHints, } // hintsDependencies is from compile time; it contains the list of hints the solver **needs** var missing []string - for hintUUID, hintID := range hintsDependencies { + for hintUUID, hintID := range cs.MHintsDependencies { if _, ok := s.mHintsFunctions[hintUUID]; !ok { missing = append(missing, hintID) } @@ -140,12 +140,15 @@ func (s *solution) accumulateInto(t constraint.Term, r *fr.Element) { } // solveHint compute solution.values[vID] using provided solver hint -func (s *solution) solveWithHint(vID int, h *constraint.HintMapping) error { +func (s *solution) solveWithHint(vID int, hID int) error { // skip if the wire is already solved by a call to the same hint // function on the same inputs if s.solved[vID] { return nil } + + h := &s.cs.HintMappings[hID] + // ensure hint function was provided f, ok := s.mHintsFunctions[h.HintID] if !ok { @@ -177,7 +180,7 @@ func (s *solution) solveWithHint(vID int, h *constraint.HintMapping) error { return nil } // unsolved dependency - if h, ok := s.mHints[wID]; ok { + if h, ok := s.cs.MHints[wID]; ok { // solve recursively. return s.solveWithHint(wID, h) } diff --git a/constraint/bn254/r1cs.go b/constraint/bn254/r1cs.go index 8a80571d90..36a9fa2b28 100644 --- a/constraint/bn254/r1cs.go +++ b/constraint/bn254/r1cs.go @@ -107,7 +107,7 @@ func (cs *R1CS) solve(witness, a, b, c fr.Vector, opt solver.Config) (fr.Vector, log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - solution, err := newSolution(nbWires, opt.HintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients, &cs.System.SymbolTable) + solution, err := newSolution(&cs.System, nbWires, opt.HintFunctions, cs.Coefficients) if err != nil { return make(fr.Vector, nbWires), err } diff --git a/constraint/bn254/r1cs_sparse.go b/constraint/bn254/r1cs_sparse.go index a5529022f7..44863105fd 100644 --- a/constraint/bn254/r1cs_sparse.go +++ b/constraint/bn254/r1cs_sparse.go @@ -150,7 +150,7 @@ func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, er } // keep track of wire that have a value - solution, err := newSolution(nbVariables, opt.HintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients, &cs.System.SymbolTable) + solution, err := newSolution(&cs.System, nbVariables, opt.HintFunctions, cs.Coefficients) if err != nil { return solution.values, err } diff --git a/constraint/bn254/solution.go b/constraint/bn254/solution.go index 24a5d94396..bc1ea454c4 100644 --- a/constraint/bn254/solution.go +++ b/constraint/bn254/solution.go @@ -38,25 +38,25 @@ type solution struct { values, coefficients []fr.Element solved []bool nbSolved uint64 - mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function - mHints map[int]*constraint.HintMapping // maps wireID to hint + mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function st *debug.SymbolTable + cs *constraint.System } -func newSolution(nbWires int, hintFunctions map[solver.HintID]solver.Hint, hintsDependencies map[solver.HintID]string, mHints map[int]*constraint.HintMapping, coefficients []fr.Element, st *debug.SymbolTable) (solution, error) { +func newSolution(cs *constraint.System, nbWires int, hintFunctions map[solver.HintID]solver.Hint, coefficients []fr.Element) (solution, error) { s := solution{ - st: st, + cs: cs, + st: &cs.SymbolTable, values: make([]fr.Element, nbWires), coefficients: coefficients, solved: make([]bool, nbWires), mHintsFunctions: hintFunctions, - mHints: mHints, } // hintsDependencies is from compile time; it contains the list of hints the solver **needs** var missing []string - for hintUUID, hintID := range hintsDependencies { + for hintUUID, hintID := range cs.MHintsDependencies { if _, ok := s.mHintsFunctions[hintUUID]; !ok { missing = append(missing, hintID) } @@ -140,12 +140,15 @@ func (s *solution) accumulateInto(t constraint.Term, r *fr.Element) { } // solveHint compute solution.values[vID] using provided solver hint -func (s *solution) solveWithHint(vID int, h *constraint.HintMapping) error { +func (s *solution) solveWithHint(vID int, hID int) error { // skip if the wire is already solved by a call to the same hint // function on the same inputs if s.solved[vID] { return nil } + + h := &s.cs.HintMappings[hID] + // ensure hint function was provided f, ok := s.mHintsFunctions[h.HintID] if !ok { @@ -177,7 +180,7 @@ func (s *solution) solveWithHint(vID int, h *constraint.HintMapping) error { return nil } // unsolved dependency - if h, ok := s.mHints[wID]; ok { + if h, ok := s.cs.MHints[wID]; ok { // solve recursively. return s.solveWithHint(wID, h) } diff --git a/constraint/bw6-633/r1cs.go b/constraint/bw6-633/r1cs.go index 6bd0f697c1..52500bfea7 100644 --- a/constraint/bw6-633/r1cs.go +++ b/constraint/bw6-633/r1cs.go @@ -107,7 +107,7 @@ func (cs *R1CS) solve(witness, a, b, c fr.Vector, opt solver.Config) (fr.Vector, log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - solution, err := newSolution(nbWires, opt.HintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients, &cs.System.SymbolTable) + solution, err := newSolution(&cs.System, nbWires, opt.HintFunctions, cs.Coefficients) if err != nil { return make(fr.Vector, nbWires), err } diff --git a/constraint/bw6-633/r1cs_sparse.go b/constraint/bw6-633/r1cs_sparse.go index ff12346a66..d43f172185 100644 --- a/constraint/bw6-633/r1cs_sparse.go +++ b/constraint/bw6-633/r1cs_sparse.go @@ -150,7 +150,7 @@ func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, er } // keep track of wire that have a value - solution, err := newSolution(nbVariables, opt.HintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients, &cs.System.SymbolTable) + solution, err := newSolution(&cs.System, nbVariables, opt.HintFunctions, cs.Coefficients) if err != nil { return solution.values, err } diff --git a/constraint/bw6-633/solution.go b/constraint/bw6-633/solution.go index 7b403823f2..fb47c98e41 100644 --- a/constraint/bw6-633/solution.go +++ b/constraint/bw6-633/solution.go @@ -38,25 +38,25 @@ type solution struct { values, coefficients []fr.Element solved []bool nbSolved uint64 - mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function - mHints map[int]*constraint.HintMapping // maps wireID to hint + mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function st *debug.SymbolTable + cs *constraint.System } -func newSolution(nbWires int, hintFunctions map[solver.HintID]solver.Hint, hintsDependencies map[solver.HintID]string, mHints map[int]*constraint.HintMapping, coefficients []fr.Element, st *debug.SymbolTable) (solution, error) { +func newSolution(cs *constraint.System, nbWires int, hintFunctions map[solver.HintID]solver.Hint, coefficients []fr.Element) (solution, error) { s := solution{ - st: st, + cs: cs, + st: &cs.SymbolTable, values: make([]fr.Element, nbWires), coefficients: coefficients, solved: make([]bool, nbWires), mHintsFunctions: hintFunctions, - mHints: mHints, } // hintsDependencies is from compile time; it contains the list of hints the solver **needs** var missing []string - for hintUUID, hintID := range hintsDependencies { + for hintUUID, hintID := range cs.MHintsDependencies { if _, ok := s.mHintsFunctions[hintUUID]; !ok { missing = append(missing, hintID) } @@ -140,12 +140,15 @@ func (s *solution) accumulateInto(t constraint.Term, r *fr.Element) { } // solveHint compute solution.values[vID] using provided solver hint -func (s *solution) solveWithHint(vID int, h *constraint.HintMapping) error { +func (s *solution) solveWithHint(vID int, hID int) error { // skip if the wire is already solved by a call to the same hint // function on the same inputs if s.solved[vID] { return nil } + + h := &s.cs.HintMappings[hID] + // ensure hint function was provided f, ok := s.mHintsFunctions[h.HintID] if !ok { @@ -177,7 +180,7 @@ func (s *solution) solveWithHint(vID int, h *constraint.HintMapping) error { return nil } // unsolved dependency - if h, ok := s.mHints[wID]; ok { + if h, ok := s.cs.MHints[wID]; ok { // solve recursively. return s.solveWithHint(wID, h) } diff --git a/constraint/bw6-761/r1cs.go b/constraint/bw6-761/r1cs.go index 12dec7e3a0..eaa080c67b 100644 --- a/constraint/bw6-761/r1cs.go +++ b/constraint/bw6-761/r1cs.go @@ -107,7 +107,7 @@ func (cs *R1CS) solve(witness, a, b, c fr.Vector, opt solver.Config) (fr.Vector, log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - solution, err := newSolution(nbWires, opt.HintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients, &cs.System.SymbolTable) + solution, err := newSolution(&cs.System, nbWires, opt.HintFunctions, cs.Coefficients) if err != nil { return make(fr.Vector, nbWires), err } diff --git a/constraint/bw6-761/r1cs_sparse.go b/constraint/bw6-761/r1cs_sparse.go index eea553ba14..c40aecc8d4 100644 --- a/constraint/bw6-761/r1cs_sparse.go +++ b/constraint/bw6-761/r1cs_sparse.go @@ -150,7 +150,7 @@ func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, er } // keep track of wire that have a value - solution, err := newSolution(nbVariables, opt.HintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients, &cs.System.SymbolTable) + solution, err := newSolution(&cs.System, nbVariables, opt.HintFunctions, cs.Coefficients) if err != nil { return solution.values, err } diff --git a/constraint/bw6-761/solution.go b/constraint/bw6-761/solution.go index 139b58737d..68d019734e 100644 --- a/constraint/bw6-761/solution.go +++ b/constraint/bw6-761/solution.go @@ -38,25 +38,25 @@ type solution struct { values, coefficients []fr.Element solved []bool nbSolved uint64 - mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function - mHints map[int]*constraint.HintMapping // maps wireID to hint + mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function st *debug.SymbolTable + cs *constraint.System } -func newSolution(nbWires int, hintFunctions map[solver.HintID]solver.Hint, hintsDependencies map[solver.HintID]string, mHints map[int]*constraint.HintMapping, coefficients []fr.Element, st *debug.SymbolTable) (solution, error) { +func newSolution(cs *constraint.System, nbWires int, hintFunctions map[solver.HintID]solver.Hint, coefficients []fr.Element) (solution, error) { s := solution{ - st: st, + cs: cs, + st: &cs.SymbolTable, values: make([]fr.Element, nbWires), coefficients: coefficients, solved: make([]bool, nbWires), mHintsFunctions: hintFunctions, - mHints: mHints, } // hintsDependencies is from compile time; it contains the list of hints the solver **needs** var missing []string - for hintUUID, hintID := range hintsDependencies { + for hintUUID, hintID := range cs.MHintsDependencies { if _, ok := s.mHintsFunctions[hintUUID]; !ok { missing = append(missing, hintID) } @@ -140,12 +140,15 @@ func (s *solution) accumulateInto(t constraint.Term, r *fr.Element) { } // solveHint compute solution.values[vID] using provided solver hint -func (s *solution) solveWithHint(vID int, h *constraint.HintMapping) error { +func (s *solution) solveWithHint(vID int, hID int) error { // skip if the wire is already solved by a call to the same hint // function on the same inputs if s.solved[vID] { return nil } + + h := &s.cs.HintMappings[hID] + // ensure hint function was provided f, ok := s.mHintsFunctions[h.HintID] if !ok { @@ -177,7 +180,7 @@ func (s *solution) solveWithHint(vID int, h *constraint.HintMapping) error { return nil } // unsolved dependency - if h, ok := s.mHints[wID]; ok { + if h, ok := s.cs.MHints[wID]; ok { // solve recursively. return s.solveWithHint(wID, h) } diff --git a/constraint/level_builder.go b/constraint/level_builder.go index 562cd0a930..e558477cad 100644 --- a/constraint/level_builder.go +++ b/constraint/level_builder.go @@ -38,7 +38,7 @@ func (system *System) updateLevel(cID int, c Iterable) { // clean the table. NB! Do not remove or move, this is required to make the // compilation deterministic. system.lbOutputs = system.lbOutputs[:0] - system.lbHints = map[*HintMapping]struct{}{} + system.lbHints = map[int]struct{}{} } func (system *System) processWire(wireID uint32, maxLevel *int) { @@ -57,16 +57,17 @@ func (system *System) processWire(wireID uint32, maxLevel *int) { return } // we don't know how to solve this wire; it's either THE wire we have to solve or a hint. - if h, ok := system.MHints[int(wireID)]; ok { + if hID, ok := system.MHints[int(wireID)]; ok { // check that we didn't process that hint already; performance wise, if many wires in a // constraint are the output of the same hint, and input to parent hint are themselves // computed with a hint, we can suffer. // (nominal case: not too many different hints involved for a single constraint) - if _, ok := system.lbHints[h]; ok { + if _, ok := system.lbHints[hID]; ok { // skip return } - system.lbHints[h] = struct{}{} + system.lbHints[hID] = struct{}{} + h := &system.HintMappings[hID] for _, hwid := range h.Outputs { system.lbOutputs = append(system.lbOutputs, uint32(hwid)) diff --git a/constraint/system.go b/constraint/system.go index fc7e0eea67..2b3ada4a60 100644 --- a/constraint/system.go +++ b/constraint/system.go @@ -110,7 +110,8 @@ type System struct { // several constraints may point to the same debug info MDebug map[int]int - MHints map[int]*HintMapping // maps wireID to hint + HintMappings []HintMapping + MHints map[int]int // maps wireID to hint MHintsDependencies map[solver.HintID]string // maps hintID to hint string identifier // each level contains independent constraints and can be parallelized @@ -126,9 +127,9 @@ type System struct { bitLen int `cbor:"-"` // level builder - lbWireLevel []int `cbor:"-"` // at which level we solve a wire. init at -1. - lbOutputs []uint32 `cbor:"-"` // wire outputs for current constraint. - lbHints map[*HintMapping]struct{} `cbor:"-"` // hints we processed in current round + lbWireLevel []int `cbor:"-"` // at which level we solve a wire. init at -1. + lbOutputs []uint32 `cbor:"-"` // wire outputs for current constraint. + lbHints map[int]struct{} `cbor:"-"` // hints we processed in current round CommitmentInfo Commitment } @@ -140,11 +141,11 @@ func NewSystem(scalarField *big.Int) System { MDebug: map[int]int{}, GnarkVersion: gnark.Version.String(), ScalarField: scalarField.Text(16), - MHints: make(map[int]*HintMapping), + MHints: make(map[int]int), MHintsDependencies: make(map[solver.HintID]string), q: new(big.Int).Set(scalarField), bitLen: scalarField.BitLen(), - lbHints: map[*HintMapping]struct{}{}, + lbHints: map[int]struct{}{}, } } @@ -246,9 +247,11 @@ func (system *System) AddSolverHint(f solver.Hint, input []LinearExpression, nbO } // associate these wires with the solver hint - ch := &HintMapping{HintID: hintUUID, Inputs: input, Outputs: internalVariables} + hm := HintMapping{HintID: hintUUID, Inputs: input, Outputs: internalVariables} + system.HintMappings = append(system.HintMappings, hm) + n := len(system.HintMappings) - 1 for _, vID := range internalVariables { - system.MHints[vID] = ch + system.MHints[vID] = n } return diff --git a/constraint/tinyfield/r1cs.go b/constraint/tinyfield/r1cs.go index a38085f0fb..21af84a24a 100644 --- a/constraint/tinyfield/r1cs.go +++ b/constraint/tinyfield/r1cs.go @@ -107,7 +107,7 @@ func (cs *R1CS) solve(witness, a, b, c fr.Vector, opt solver.Config) (fr.Vector, log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - solution, err := newSolution(nbWires, opt.HintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients, &cs.System.SymbolTable) + solution, err := newSolution(&cs.System, nbWires, opt.HintFunctions, cs.Coefficients) if err != nil { return make(fr.Vector, nbWires), err } diff --git a/constraint/tinyfield/r1cs_sparse.go b/constraint/tinyfield/r1cs_sparse.go index 5a80ead238..4317dcc8e9 100644 --- a/constraint/tinyfield/r1cs_sparse.go +++ b/constraint/tinyfield/r1cs_sparse.go @@ -150,7 +150,7 @@ func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, er } // keep track of wire that have a value - solution, err := newSolution(nbVariables, opt.HintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients, &cs.System.SymbolTable) + solution, err := newSolution(&cs.System, nbVariables, opt.HintFunctions, cs.Coefficients) if err != nil { return solution.values, err } diff --git a/constraint/tinyfield/solution.go b/constraint/tinyfield/solution.go index 090b97f78d..b514905da4 100644 --- a/constraint/tinyfield/solution.go +++ b/constraint/tinyfield/solution.go @@ -38,25 +38,25 @@ type solution struct { values, coefficients []fr.Element solved []bool nbSolved uint64 - mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function - mHints map[int]*constraint.HintMapping // maps wireID to hint + mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function st *debug.SymbolTable + cs *constraint.System } -func newSolution(nbWires int, hintFunctions map[solver.HintID]solver.Hint, hintsDependencies map[solver.HintID]string, mHints map[int]*constraint.HintMapping, coefficients []fr.Element, st *debug.SymbolTable) (solution, error) { +func newSolution(cs *constraint.System, nbWires int, hintFunctions map[solver.HintID]solver.Hint, coefficients []fr.Element) (solution, error) { s := solution{ - st: st, + cs: cs, + st: &cs.SymbolTable, values: make([]fr.Element, nbWires), coefficients: coefficients, solved: make([]bool, nbWires), mHintsFunctions: hintFunctions, - mHints: mHints, } // hintsDependencies is from compile time; it contains the list of hints the solver **needs** var missing []string - for hintUUID, hintID := range hintsDependencies { + for hintUUID, hintID := range cs.MHintsDependencies { if _, ok := s.mHintsFunctions[hintUUID]; !ok { missing = append(missing, hintID) } @@ -140,12 +140,15 @@ func (s *solution) accumulateInto(t constraint.Term, r *fr.Element) { } // solveHint compute solution.values[vID] using provided solver hint -func (s *solution) solveWithHint(vID int, h *constraint.HintMapping) error { +func (s *solution) solveWithHint(vID int, hID int) error { // skip if the wire is already solved by a call to the same hint // function on the same inputs if s.solved[vID] { return nil } + + h := &s.cs.HintMappings[hID] + // ensure hint function was provided f, ok := s.mHintsFunctions[h.HintID] if !ok { @@ -177,7 +180,7 @@ func (s *solution) solveWithHint(vID int, h *constraint.HintMapping) error { return nil } // unsolved dependency - if h, ok := s.mHints[wID]; ok { + if h, ok := s.cs.MHints[wID]; ok { // solve recursively. return s.solveWithHint(wID, h) } diff --git a/frontend/cs/scs/api_assertions.go b/frontend/cs/scs/api_assertions.go index 698a139402..2137d5da0b 100644 --- a/frontend/cs/scs/api_assertions.go +++ b/frontend/cs/scs/api_assertions.go @@ -20,6 +20,7 @@ import ( "fmt" "math/big" + "github.com/consensys/gnark/debug" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/internal/expr" "github.com/consensys/gnark/internal/utils" @@ -96,7 +97,6 @@ func (builder *builder) AssertIsBoolean(i1 frontend.Variable) { return } builder.MarkBoolean(v) - debug := builder.newDebugInfo("assertIsBoolean", v, " == (0|1)") // ensure v * (1 - v) == 0 // that is v + -v*v == 0 @@ -104,12 +104,19 @@ func (builder *builder) AssertIsBoolean(i1 frontend.Variable) { qM := v.Coeff builder.cs.Neg(&qM) builder.cs.Mul(&qM, &v.Coeff) - builder.addPlonkConstraint(sparseR1C{ + toAdd := sparseR1C{ xa: v.VID, xb: v.VID, qL: v.Coeff, qM: qM, - }, debug) + } + if debug.Debug { + debug := builder.newDebugInfo("assertIsBoolean", v, " == (0|1)") + builder.addPlonkConstraint(toAdd, debug) + } else { + builder.addPlonkConstraint(toAdd) + } + } // AssertIsLessOrEqual fails if v > bound diff --git a/internal/generator/backend/template/representations/r1cs.go.tmpl b/internal/generator/backend/template/representations/r1cs.go.tmpl index 0d91c7f299..d481bd0e18 100644 --- a/internal/generator/backend/template/representations/r1cs.go.tmpl +++ b/internal/generator/backend/template/representations/r1cs.go.tmpl @@ -91,7 +91,7 @@ func (cs *R1CS) solve(witness, a, b, c fr.Vector, opt solver.Config) (fr.Vector, log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - solution, err := newSolution(nbWires, opt.HintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients, &cs.System.SymbolTable) + solution, err := newSolution(&cs.System, nbWires, opt.HintFunctions, cs.Coefficients) if err != nil { return make(fr.Vector, nbWires), err } diff --git a/internal/generator/backend/template/representations/r1cs.sparse.go.tmpl b/internal/generator/backend/template/representations/r1cs.sparse.go.tmpl index 84128a998a..55b4163781 100644 --- a/internal/generator/backend/template/representations/r1cs.sparse.go.tmpl +++ b/internal/generator/backend/template/representations/r1cs.sparse.go.tmpl @@ -134,7 +134,7 @@ func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, er } // keep track of wire that have a value - solution, err := newSolution( nbVariables, opt.HintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients, &cs.System.SymbolTable) + solution, err := newSolution(&cs.System, nbVariables, opt.HintFunctions, cs.Coefficients) if err != nil { return solution.values, err } diff --git a/internal/generator/backend/template/representations/solution.go.tmpl b/internal/generator/backend/template/representations/solution.go.tmpl index 43835d3786..f083181786 100644 --- a/internal/generator/backend/template/representations/solution.go.tmpl +++ b/internal/generator/backend/template/representations/solution.go.tmpl @@ -20,24 +20,24 @@ type solution struct { solved []bool nbSolved uint64 mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function - mHints map[int]*constraint.HintMapping // maps wireID to hint st *debug.SymbolTable + cs *constraint.System } -func newSolution( nbWires int, hintFunctions map[solver.HintID]solver.Hint, hintsDependencies map[solver.HintID]string, mHints map[int]*constraint.HintMapping, coefficients []fr.Element, st *debug.SymbolTable) (solution, error) { +func newSolution(cs *constraint.System, nbWires int, hintFunctions map[solver.HintID]solver.Hint, coefficients []fr.Element) (solution, error) { s := solution{ - st: st, + cs: cs, + st: &cs.SymbolTable, values: make([]fr.Element, nbWires), coefficients: coefficients, solved: make([]bool, nbWires), mHintsFunctions: hintFunctions, - mHints: mHints, } // hintsDependencies is from compile time; it contains the list of hints the solver **needs** var missing []string - for hintUUID, hintID := range hintsDependencies { + for hintUUID, hintID := range cs.MHintsDependencies { if _, ok := s.mHintsFunctions[hintUUID]; !ok { missing = append(missing, hintID) } @@ -121,12 +121,15 @@ func (s *solution) accumulateInto(t constraint.Term, r *fr.Element) { } // solveHint compute solution.values[vID] using provided solver hint -func (s *solution) solveWithHint(vID int, h *constraint.HintMapping) error { +func (s *solution) solveWithHint(vID int, hID int) error { // skip if the wire is already solved by a call to the same hint // function on the same inputs if s.solved[vID] { return nil } + + h := &s.cs.HintMappings[hID] + // ensure hint function was provided f, ok := s.mHintsFunctions[h.HintID] if !ok { @@ -158,7 +161,7 @@ func (s *solution) solveWithHint(vID int, h *constraint.HintMapping) error { return nil } // unsolved dependency - if h, ok := s.mHints[wID]; ok { + if h, ok := s.cs.MHints[wID]; ok { // solve recursively. return s.solveWithHint(wID, h) } From 1bb583ae2337f2879c35e71054023399412ea8ef Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 10 Mar 2023 13:04:59 -0500 Subject: [PATCH 101/464] feat: some bsb22 proving in plonk --- internal/backend/bn254/plonk/prove.go | 28 ++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/internal/backend/bn254/plonk/prove.go b/internal/backend/bn254/plonk/prove.go index 31ac26b80e..16472567d5 100644 --- a/internal/backend/bn254/plonk/prove.go +++ b/internal/backend/bn254/plonk/prove.go @@ -82,7 +82,10 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // result proof := &Proof{} - var pi2 fr.Vector + var ( + pi2 fr.Vector + commitmentVal fr.Element // TODO @Tabaie get rid of this + ) if spr.CommitmentInfo.Is() { opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo.HintID, func(_ *big.Int, ins, outs []*big.Int) error { pi2 = make(fr.Vector, pk.Domain[0].Cardinality) @@ -102,8 +105,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } - - hashRes[0].BigInt(outs[0]) + commitmentVal = hashRes[0] // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses + commitmentVal.BigInt(outs[0]) return nil })) } @@ -200,6 +203,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, pk.Domain[0].Cardinality) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], pk.LQk[len(spr.Public):]) + if spr.CommitmentInfo.Is() { + qkCompletedCanonical[spr.CommitmentInfo.CommitmentIndex] = commitmentVal // TODO @Tabaie no need to negate? + } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -249,7 +255,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ToLagrangeCoset(&pk.Domain[1]) // Full capture using latest gnark crypto... - fic := func(fql, fqr, fqm, fqo, fqk, l, r, o fr.Element) fr.Element { + fic := func(fql, fqr, fqm, fqo, fqk, fqCPrime, l, r, o, pi2 fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary var ic, tmp fr.Element @@ -260,6 +266,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ic.Add(&ic, &tmp) tmp.Mul(&fqo, &o) ic.Add(&ic, &tmp).Add(&ic, &fqk) + tmp.Mul(&fqCPrime, &pi2) + ic.Add(&ic, &tmp) return ic } @@ -293,13 +301,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return one } - // 0 , 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 - // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk,lone + // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15 , 16 + // l , r , o, id, s1, s2, s3, z, zs, PI2, ql, qr, qm, qo, qk, qCPrime, lone fm := func(x ...fr.Element) fr.Element { - a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2]) + a := fic(x[10], x[11], x[12], x[13], x[14], x[15], x[0], x[1], x[2], x[9]) b := fo(x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8]) - c := fone(x[7], x[14]) + c := fone(x[7], x[16]) c.Mul(&c, &alpha).Add(&c, &b).Mul(&c, &alpha).Add(&c, &a) @@ -315,17 +323,19 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ws3, bwziop, bwsziop, + pi2, // TODO @Tabaie correct format wqliop, wqriop, wqmiop, wqoiop, wqkiop, + qCPrime, // TODO @Tabaie correct format wloneiop, ) if err != nil { return nil, err } - h, err := iop.DivideByXMinusOne(testEval, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) + h, err := iop.DivideByXMinusOne(testEval, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) // TODO @Tabaie not x^n - 1? if err != nil { return nil, err } From 263e8ca2da4c62677333e1a9bff952d6885af8b5 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 10 Mar 2023 15:47:20 -0500 Subject: [PATCH 102/464] style: public-value-defining constraints as -x + c = 0 for consistency --- frontend/cs/scs/api.go | 4 ++-- internal/backend/bn254/plonk/setup.go | 2 +- internal/backend/bn254/plonk/verify.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/cs/scs/api.go b/frontend/cs/scs/api.go index 76c941f87d..a08a27def2 100644 --- a/frontend/cs/scs/api.go +++ b/frontend/cs/scs/api.go @@ -569,7 +569,7 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error committed := make([]int, len(v)) for i, vI := range v { // TODO @Tabaie Perf; If public, just hash it - vIExpr := vI.(constraint.LinearExpression) + vIExpr := builder.Neg(vI).(constraint.LinearExpression) if len(vIExpr) != 1 { return nil, errors.New("can only commit to single terms") // TODO @Tabaie Create a wire in this case } @@ -583,7 +583,7 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error commitmentVar := outs[0] commitmentConstraintIndex := builder.cs.GetNbConstraints() - builder.cs.AddConstraint(constraint.SparseR1C{L: commitmentVar.(constraint.LinearExpression)[0], Commitment: constraint.COMMITMENT}) // value will be injected later + builder.cs.AddConstraint(constraint.SparseR1C{L: builder.Neg(commitmentVar).(constraint.LinearExpression)[0], Commitment: constraint.COMMITMENT}) // value will be injected later return outs[0], builder.cs.AddCommitment(constraint.Commitment{ HintID: solver.GetHintID(scsBsb22CommitmentHintPlaceholder), diff --git a/internal/backend/bn254/plonk/setup.go b/internal/backend/bn254/plonk/setup.go index 3ba4eb6ea5..edadc5e3bb 100644 --- a/internal/backend/bn254/plonk/setup.go +++ b/internal/backend/bn254/plonk/setup.go @@ -161,7 +161,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) } for _, committed := range spr.CommitmentInfo.Committed { - pk.QcPrime[committed] = spr.Coefficients[constraint.CoeffIdMinusOne] + pk.QcPrime[committed] = spr.Coefficients[constraint.CoeffIdOne] } pk.Domain[0].FFTInverse(pk.Ql, fft.DIF) diff --git a/internal/backend/bn254/plonk/verify.go b/internal/backend/bn254/plonk/verify.go index 8db03fb3fd..770e66c8db 100644 --- a/internal/backend/bn254/plonk/verify.go +++ b/internal/backend/bn254/plonk/verify.go @@ -129,7 +129,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { lagrange.Div(&lagrange, &den) xiLi.Mul(&lagrange, &hashRes[0]) - pi.Sub(&pi, &xiLi) + pi.Add(&pi, &xiLi) } } From 42d4af3001f87639e5c03aa5193a3e32a58f1dfd Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 10 Mar 2023 16:31:11 -0500 Subject: [PATCH 103/464] refactor: compute lagrange basis from scratch --- internal/backend/bn254/plonk/verify.go | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/internal/backend/bn254/plonk/verify.go b/internal/backend/bn254/plonk/verify.go index 770e66c8db..ca30399988 100644 --- a/internal/backend/bn254/plonk/verify.go +++ b/internal/backend/bn254/plonk/verify.go @@ -87,7 +87,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zetaPowerM.Exp(zeta, &bExpo) zzeta.Sub(&zetaPowerM, &one) - // ccompute PI = ∑_{i Date: Mon, 13 Mar 2023 17:05:32 +0100 Subject: [PATCH 104/464] fix: use mocked api.Commit also in Windows tests (#560) --- frontend/cs/r1cs/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index 063ec9eebe..ebc7c96c08 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -760,7 +760,7 @@ func (builder *builder) getCommittedVariables(i *constraint.Commitment) []fronte } func bsb22CommitmentComputePlaceholder(_ *big.Int, _ []*big.Int, output []*big.Int) error { - if (len(os.Args) > 0 && strings.HasSuffix(os.Args[0], ".test")) || debug.Debug { + if (len(os.Args) > 0 && (strings.HasSuffix(os.Args[0], ".test") || strings.HasSuffix(os.Args[0], ".test.exe"))) || debug.Debug { // usually we only run solver without prover during testing log := logger.Logger() log.Error().Msg("Augmented groth16 commitment hint not replaced. Proof will not be sound!") From 792600457ed3d96cba93063d31b6c50d685b7e97 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Mon, 13 Mar 2023 14:33:49 -0500 Subject: [PATCH 105/464] refactor: expose all typed backends in gnark/backend (moved from internal/) --- .../groth16/bls12-377}/commitment.go | 0 .../groth16/bls12-377}/commitment_test.go | 0 .../groth16/bls12-377}/marshal.go | 0 .../groth16/bls12-377}/marshal_test.go | 0 .../groth16/bls12-377}/prove.go | 0 .../groth16/bls12-377}/setup.go | 0 .../groth16/bls12-377}/verify.go | 0 .../groth16/bls12-381}/commitment.go | 0 .../groth16/bls12-381}/commitment_test.go | 0 .../groth16/bls12-381}/marshal.go | 0 .../groth16/bls12-381}/marshal_test.go | 0 .../groth16/bls12-381}/prove.go | 0 .../groth16/bls12-381}/setup.go | 0 .../groth16/bls12-381}/verify.go | 0 .../groth16/bls24-315}/commitment.go | 0 .../groth16/bls24-315}/commitment_test.go | 0 .../groth16/bls24-315}/marshal.go | 0 .../groth16/bls24-315}/marshal_test.go | 0 .../groth16/bls24-315}/prove.go | 0 .../groth16/bls24-315}/setup.go | 0 .../groth16/bls24-315}/verify.go | 0 .../groth16/bls24-317}/commitment.go | 0 .../groth16/bls24-317}/commitment_test.go | 0 .../groth16/bls24-317}/marshal.go | 0 .../groth16/bls24-317}/marshal_test.go | 0 .../groth16/bls24-317}/prove.go | 0 .../groth16/bls24-317}/setup.go | 0 .../groth16/bls24-317}/verify.go | 0 .../groth16/bn254}/commitment.go | 0 .../groth16/bn254}/commitment_test.go | 0 .../groth16/bn254}/marshal.go | 0 .../groth16/bn254}/marshal_test.go | 0 .../groth16/bn254}/prove.go | 0 .../groth16/bn254}/setup.go | 0 .../groth16/bn254}/solidity.go | 0 .../groth16/bn254}/utils_test.go | 0 .../groth16/bn254}/verify.go | 0 .../groth16/bw6-633}/commitment.go | 0 .../groth16/bw6-633}/commitment_test.go | 0 .../groth16/bw6-633}/marshal.go | 0 .../groth16/bw6-633}/marshal_test.go | 0 .../groth16/bw6-633}/prove.go | 0 .../groth16/bw6-633}/setup.go | 0 .../groth16/bw6-633}/verify.go | 0 .../groth16/bw6-761}/commitment.go | 0 .../groth16/bw6-761}/commitment_test.go | 0 .../groth16/bw6-761}/marshal.go | 0 .../groth16/bw6-761}/marshal_test.go | 0 .../groth16/bw6-761}/prove.go | 0 .../groth16/bw6-761}/setup.go | 0 .../groth16/bw6-761}/verify.go | 0 backend/groth16/groth16.go | 14 ++++---- .../plonk/bls12-377}/marshal.go | 0 .../plonk/bls12-377}/marshal_test.go | 0 .../plonk/bls12-377}/prove.go | 0 .../plonk/bls12-377}/setup.go | 0 .../plonk/bls12-377}/verify.go | 0 .../plonk/bls12-381}/marshal.go | 0 .../plonk/bls12-381}/marshal_test.go | 0 .../plonk/bls12-381}/prove.go | 0 .../plonk/bls12-381}/setup.go | 0 .../plonk/bls12-381}/verify.go | 0 .../plonk/bls24-315}/marshal.go | 0 .../plonk/bls24-315}/marshal_test.go | 0 .../plonk/bls24-315}/prove.go | 0 .../plonk/bls24-315}/setup.go | 0 .../plonk/bls24-315}/verify.go | 0 .../plonk/bls24-317}/marshal.go | 0 .../plonk/bls24-317}/marshal_test.go | 0 .../plonk/bls24-317}/prove.go | 0 .../plonk/bls24-317}/setup.go | 0 .../plonk/bls24-317}/verify.go | 0 .../plonk => backend/plonk/bn254}/marshal.go | 0 .../plonk/bn254}/marshal_test.go | 0 .../plonk => backend/plonk/bn254}/prove.go | 0 .../plonk => backend/plonk/bn254}/setup.go | 0 .../plonk => backend/plonk/bn254}/solidity.go | 0 .../plonk => backend/plonk/bn254}/verify.go | 0 .../plonk/bw6-633}/marshal.go | 0 .../plonk/bw6-633}/marshal_test.go | 0 .../plonk => backend/plonk/bw6-633}/prove.go | 0 .../plonk => backend/plonk/bw6-633}/setup.go | 0 .../plonk => backend/plonk/bw6-633}/verify.go | 0 .../plonk/bw6-761}/marshal.go | 0 .../plonk/bw6-761}/marshal_test.go | 0 .../plonk => backend/plonk/bw6-761}/prove.go | 0 .../plonk => backend/plonk/bw6-761}/setup.go | 0 .../plonk => backend/plonk/bw6-761}/verify.go | 0 backend/plonk/plonk.go | 14 ++++---- .../plonkfri/bls12-377}/prove.go | 0 .../plonkfri/bls12-377}/setup.go | 0 .../plonkfri/bls12-377}/verify.go | 0 .../plonkfri/bls12-381}/prove.go | 0 .../plonkfri/bls12-381}/setup.go | 0 .../plonkfri/bls12-381}/verify.go | 0 .../plonkfri/bls24-315}/prove.go | 0 .../plonkfri/bls24-315}/setup.go | 0 .../plonkfri/bls24-315}/verify.go | 0 .../plonkfri/bls24-317}/prove.go | 0 .../plonkfri/bls24-317}/setup.go | 0 .../plonkfri/bls24-317}/verify.go | 0 .../plonkfri/bn254}/prove.go | 0 .../plonkfri/bn254}/setup.go | 0 .../plonkfri/bn254}/verify.go | 0 .../plonkfri/bw6-633}/prove.go | 0 .../plonkfri/bw6-633}/setup.go | 0 .../plonkfri/bw6-633}/verify.go | 0 .../plonkfri/bw6-761}/prove.go | 0 .../plonkfri/bw6-761}/setup.go | 0 .../plonkfri/bw6-761}/verify.go | 0 backend/plonkfri/plonkfri.go | 15 ++++----- internal/generator/backend/main.go | 32 ++++++++++--------- std/groth16_bls12377/verifier.go | 2 +- std/groth16_bls12377/verifier_test.go | 2 +- std/groth16_bls24315/verifier.go | 2 +- std/groth16_bls24315/verifier_test.go | 2 +- 116 files changed, 42 insertions(+), 41 deletions(-) rename {internal/backend/bls12-377/groth16 => backend/groth16/bls12-377}/commitment.go (100%) rename {internal/backend/bls12-377/groth16 => backend/groth16/bls12-377}/commitment_test.go (100%) rename {internal/backend/bls12-377/groth16 => backend/groth16/bls12-377}/marshal.go (100%) rename {internal/backend/bls12-377/groth16 => backend/groth16/bls12-377}/marshal_test.go (100%) rename {internal/backend/bls12-377/groth16 => backend/groth16/bls12-377}/prove.go (100%) rename {internal/backend/bls12-377/groth16 => backend/groth16/bls12-377}/setup.go (100%) rename {internal/backend/bls12-377/groth16 => backend/groth16/bls12-377}/verify.go (100%) rename {internal/backend/bls12-381/groth16 => backend/groth16/bls12-381}/commitment.go (100%) rename {internal/backend/bls12-381/groth16 => backend/groth16/bls12-381}/commitment_test.go (100%) rename {internal/backend/bls12-381/groth16 => backend/groth16/bls12-381}/marshal.go (100%) rename {internal/backend/bls12-381/groth16 => backend/groth16/bls12-381}/marshal_test.go (100%) rename {internal/backend/bls12-381/groth16 => backend/groth16/bls12-381}/prove.go (100%) rename {internal/backend/bls12-381/groth16 => backend/groth16/bls12-381}/setup.go (100%) rename {internal/backend/bls12-381/groth16 => backend/groth16/bls12-381}/verify.go (100%) rename {internal/backend/bls24-315/groth16 => backend/groth16/bls24-315}/commitment.go (100%) rename {internal/backend/bls24-315/groth16 => backend/groth16/bls24-315}/commitment_test.go (100%) rename {internal/backend/bls24-315/groth16 => backend/groth16/bls24-315}/marshal.go (100%) rename {internal/backend/bls24-315/groth16 => backend/groth16/bls24-315}/marshal_test.go (100%) rename {internal/backend/bls24-315/groth16 => backend/groth16/bls24-315}/prove.go (100%) rename {internal/backend/bls24-315/groth16 => backend/groth16/bls24-315}/setup.go (100%) rename {internal/backend/bls24-315/groth16 => backend/groth16/bls24-315}/verify.go (100%) rename {internal/backend/bls24-317/groth16 => backend/groth16/bls24-317}/commitment.go (100%) rename {internal/backend/bls24-317/groth16 => backend/groth16/bls24-317}/commitment_test.go (100%) rename {internal/backend/bls24-317/groth16 => backend/groth16/bls24-317}/marshal.go (100%) rename {internal/backend/bls24-317/groth16 => backend/groth16/bls24-317}/marshal_test.go (100%) rename {internal/backend/bls24-317/groth16 => backend/groth16/bls24-317}/prove.go (100%) rename {internal/backend/bls24-317/groth16 => backend/groth16/bls24-317}/setup.go (100%) rename {internal/backend/bls24-317/groth16 => backend/groth16/bls24-317}/verify.go (100%) rename {internal/backend/bn254/groth16 => backend/groth16/bn254}/commitment.go (100%) rename {internal/backend/bn254/groth16 => backend/groth16/bn254}/commitment_test.go (100%) rename {internal/backend/bn254/groth16 => backend/groth16/bn254}/marshal.go (100%) rename {internal/backend/bn254/groth16 => backend/groth16/bn254}/marshal_test.go (100%) rename {internal/backend/bn254/groth16 => backend/groth16/bn254}/prove.go (100%) rename {internal/backend/bn254/groth16 => backend/groth16/bn254}/setup.go (100%) rename {internal/backend/bn254/groth16 => backend/groth16/bn254}/solidity.go (100%) rename {internal/backend/bn254/groth16 => backend/groth16/bn254}/utils_test.go (100%) rename {internal/backend/bn254/groth16 => backend/groth16/bn254}/verify.go (100%) rename {internal/backend/bw6-633/groth16 => backend/groth16/bw6-633}/commitment.go (100%) rename {internal/backend/bw6-633/groth16 => backend/groth16/bw6-633}/commitment_test.go (100%) rename {internal/backend/bw6-633/groth16 => backend/groth16/bw6-633}/marshal.go (100%) rename {internal/backend/bw6-633/groth16 => backend/groth16/bw6-633}/marshal_test.go (100%) rename {internal/backend/bw6-633/groth16 => backend/groth16/bw6-633}/prove.go (100%) rename {internal/backend/bw6-633/groth16 => backend/groth16/bw6-633}/setup.go (100%) rename {internal/backend/bw6-633/groth16 => backend/groth16/bw6-633}/verify.go (100%) rename {internal/backend/bw6-761/groth16 => backend/groth16/bw6-761}/commitment.go (100%) rename {internal/backend/bw6-761/groth16 => backend/groth16/bw6-761}/commitment_test.go (100%) rename {internal/backend/bw6-761/groth16 => backend/groth16/bw6-761}/marshal.go (100%) rename {internal/backend/bw6-761/groth16 => backend/groth16/bw6-761}/marshal_test.go (100%) rename {internal/backend/bw6-761/groth16 => backend/groth16/bw6-761}/prove.go (100%) rename {internal/backend/bw6-761/groth16 => backend/groth16/bw6-761}/setup.go (100%) rename {internal/backend/bw6-761/groth16 => backend/groth16/bw6-761}/verify.go (100%) rename {internal/backend/bls12-377/plonk => backend/plonk/bls12-377}/marshal.go (100%) rename {internal/backend/bls12-377/plonk => backend/plonk/bls12-377}/marshal_test.go (100%) rename {internal/backend/bls12-377/plonk => backend/plonk/bls12-377}/prove.go (100%) rename {internal/backend/bls12-377/plonk => backend/plonk/bls12-377}/setup.go (100%) rename {internal/backend/bls12-377/plonk => backend/plonk/bls12-377}/verify.go (100%) rename {internal/backend/bls12-381/plonk => backend/plonk/bls12-381}/marshal.go (100%) rename {internal/backend/bls12-381/plonk => backend/plonk/bls12-381}/marshal_test.go (100%) rename {internal/backend/bls12-381/plonk => backend/plonk/bls12-381}/prove.go (100%) rename {internal/backend/bls12-381/plonk => backend/plonk/bls12-381}/setup.go (100%) rename {internal/backend/bls12-381/plonk => backend/plonk/bls12-381}/verify.go (100%) rename {internal/backend/bls24-315/plonk => backend/plonk/bls24-315}/marshal.go (100%) rename {internal/backend/bls24-315/plonk => backend/plonk/bls24-315}/marshal_test.go (100%) rename {internal/backend/bls24-315/plonk => backend/plonk/bls24-315}/prove.go (100%) rename {internal/backend/bls24-315/plonk => backend/plonk/bls24-315}/setup.go (100%) rename {internal/backend/bls24-315/plonk => backend/plonk/bls24-315}/verify.go (100%) rename {internal/backend/bls24-317/plonk => backend/plonk/bls24-317}/marshal.go (100%) rename {internal/backend/bls24-317/plonk => backend/plonk/bls24-317}/marshal_test.go (100%) rename {internal/backend/bls24-317/plonk => backend/plonk/bls24-317}/prove.go (100%) rename {internal/backend/bls24-317/plonk => backend/plonk/bls24-317}/setup.go (100%) rename {internal/backend/bls24-317/plonk => backend/plonk/bls24-317}/verify.go (100%) rename {internal/backend/bn254/plonk => backend/plonk/bn254}/marshal.go (100%) rename {internal/backend/bn254/plonk => backend/plonk/bn254}/marshal_test.go (100%) rename {internal/backend/bn254/plonk => backend/plonk/bn254}/prove.go (100%) rename {internal/backend/bn254/plonk => backend/plonk/bn254}/setup.go (100%) rename {internal/backend/bn254/plonk => backend/plonk/bn254}/solidity.go (100%) rename {internal/backend/bn254/plonk => backend/plonk/bn254}/verify.go (100%) rename {internal/backend/bw6-633/plonk => backend/plonk/bw6-633}/marshal.go (100%) rename {internal/backend/bw6-633/plonk => backend/plonk/bw6-633}/marshal_test.go (100%) rename {internal/backend/bw6-633/plonk => backend/plonk/bw6-633}/prove.go (100%) rename {internal/backend/bw6-633/plonk => backend/plonk/bw6-633}/setup.go (100%) rename {internal/backend/bw6-633/plonk => backend/plonk/bw6-633}/verify.go (100%) rename {internal/backend/bw6-761/plonk => backend/plonk/bw6-761}/marshal.go (100%) rename {internal/backend/bw6-761/plonk => backend/plonk/bw6-761}/marshal_test.go (100%) rename {internal/backend/bw6-761/plonk => backend/plonk/bw6-761}/prove.go (100%) rename {internal/backend/bw6-761/plonk => backend/plonk/bw6-761}/setup.go (100%) rename {internal/backend/bw6-761/plonk => backend/plonk/bw6-761}/verify.go (100%) rename {internal/backend/bls12-377/plonkfri => backend/plonkfri/bls12-377}/prove.go (100%) rename {internal/backend/bls12-377/plonkfri => backend/plonkfri/bls12-377}/setup.go (100%) rename {internal/backend/bls12-377/plonkfri => backend/plonkfri/bls12-377}/verify.go (100%) rename {internal/backend/bls12-381/plonkfri => backend/plonkfri/bls12-381}/prove.go (100%) rename {internal/backend/bls12-381/plonkfri => backend/plonkfri/bls12-381}/setup.go (100%) rename {internal/backend/bls12-381/plonkfri => backend/plonkfri/bls12-381}/verify.go (100%) rename {internal/backend/bls24-315/plonkfri => backend/plonkfri/bls24-315}/prove.go (100%) rename {internal/backend/bls24-315/plonkfri => backend/plonkfri/bls24-315}/setup.go (100%) rename {internal/backend/bls24-315/plonkfri => backend/plonkfri/bls24-315}/verify.go (100%) rename {internal/backend/bls24-317/plonkfri => backend/plonkfri/bls24-317}/prove.go (100%) rename {internal/backend/bls24-317/plonkfri => backend/plonkfri/bls24-317}/setup.go (100%) rename {internal/backend/bls24-317/plonkfri => backend/plonkfri/bls24-317}/verify.go (100%) rename {internal/backend/bn254/plonkfri => backend/plonkfri/bn254}/prove.go (100%) rename {internal/backend/bn254/plonkfri => backend/plonkfri/bn254}/setup.go (100%) rename {internal/backend/bn254/plonkfri => backend/plonkfri/bn254}/verify.go (100%) rename {internal/backend/bw6-633/plonkfri => backend/plonkfri/bw6-633}/prove.go (100%) rename {internal/backend/bw6-633/plonkfri => backend/plonkfri/bw6-633}/setup.go (100%) rename {internal/backend/bw6-633/plonkfri => backend/plonkfri/bw6-633}/verify.go (100%) rename {internal/backend/bw6-761/plonkfri => backend/plonkfri/bw6-761}/prove.go (100%) rename {internal/backend/bw6-761/plonkfri => backend/plonkfri/bw6-761}/setup.go (100%) rename {internal/backend/bw6-761/plonkfri => backend/plonkfri/bw6-761}/verify.go (100%) diff --git a/internal/backend/bls12-377/groth16/commitment.go b/backend/groth16/bls12-377/commitment.go similarity index 100% rename from internal/backend/bls12-377/groth16/commitment.go rename to backend/groth16/bls12-377/commitment.go diff --git a/internal/backend/bls12-377/groth16/commitment_test.go b/backend/groth16/bls12-377/commitment_test.go similarity index 100% rename from internal/backend/bls12-377/groth16/commitment_test.go rename to backend/groth16/bls12-377/commitment_test.go diff --git a/internal/backend/bls12-377/groth16/marshal.go b/backend/groth16/bls12-377/marshal.go similarity index 100% rename from internal/backend/bls12-377/groth16/marshal.go rename to backend/groth16/bls12-377/marshal.go diff --git a/internal/backend/bls12-377/groth16/marshal_test.go b/backend/groth16/bls12-377/marshal_test.go similarity index 100% rename from internal/backend/bls12-377/groth16/marshal_test.go rename to backend/groth16/bls12-377/marshal_test.go diff --git a/internal/backend/bls12-377/groth16/prove.go b/backend/groth16/bls12-377/prove.go similarity index 100% rename from internal/backend/bls12-377/groth16/prove.go rename to backend/groth16/bls12-377/prove.go diff --git a/internal/backend/bls12-377/groth16/setup.go b/backend/groth16/bls12-377/setup.go similarity index 100% rename from internal/backend/bls12-377/groth16/setup.go rename to backend/groth16/bls12-377/setup.go diff --git a/internal/backend/bls12-377/groth16/verify.go b/backend/groth16/bls12-377/verify.go similarity index 100% rename from internal/backend/bls12-377/groth16/verify.go rename to backend/groth16/bls12-377/verify.go diff --git a/internal/backend/bls12-381/groth16/commitment.go b/backend/groth16/bls12-381/commitment.go similarity index 100% rename from internal/backend/bls12-381/groth16/commitment.go rename to backend/groth16/bls12-381/commitment.go diff --git a/internal/backend/bls12-381/groth16/commitment_test.go b/backend/groth16/bls12-381/commitment_test.go similarity index 100% rename from internal/backend/bls12-381/groth16/commitment_test.go rename to backend/groth16/bls12-381/commitment_test.go diff --git a/internal/backend/bls12-381/groth16/marshal.go b/backend/groth16/bls12-381/marshal.go similarity index 100% rename from internal/backend/bls12-381/groth16/marshal.go rename to backend/groth16/bls12-381/marshal.go diff --git a/internal/backend/bls12-381/groth16/marshal_test.go b/backend/groth16/bls12-381/marshal_test.go similarity index 100% rename from internal/backend/bls12-381/groth16/marshal_test.go rename to backend/groth16/bls12-381/marshal_test.go diff --git a/internal/backend/bls12-381/groth16/prove.go b/backend/groth16/bls12-381/prove.go similarity index 100% rename from internal/backend/bls12-381/groth16/prove.go rename to backend/groth16/bls12-381/prove.go diff --git a/internal/backend/bls12-381/groth16/setup.go b/backend/groth16/bls12-381/setup.go similarity index 100% rename from internal/backend/bls12-381/groth16/setup.go rename to backend/groth16/bls12-381/setup.go diff --git a/internal/backend/bls12-381/groth16/verify.go b/backend/groth16/bls12-381/verify.go similarity index 100% rename from internal/backend/bls12-381/groth16/verify.go rename to backend/groth16/bls12-381/verify.go diff --git a/internal/backend/bls24-315/groth16/commitment.go b/backend/groth16/bls24-315/commitment.go similarity index 100% rename from internal/backend/bls24-315/groth16/commitment.go rename to backend/groth16/bls24-315/commitment.go diff --git a/internal/backend/bls24-315/groth16/commitment_test.go b/backend/groth16/bls24-315/commitment_test.go similarity index 100% rename from internal/backend/bls24-315/groth16/commitment_test.go rename to backend/groth16/bls24-315/commitment_test.go diff --git a/internal/backend/bls24-315/groth16/marshal.go b/backend/groth16/bls24-315/marshal.go similarity index 100% rename from internal/backend/bls24-315/groth16/marshal.go rename to backend/groth16/bls24-315/marshal.go diff --git a/internal/backend/bls24-315/groth16/marshal_test.go b/backend/groth16/bls24-315/marshal_test.go similarity index 100% rename from internal/backend/bls24-315/groth16/marshal_test.go rename to backend/groth16/bls24-315/marshal_test.go diff --git a/internal/backend/bls24-315/groth16/prove.go b/backend/groth16/bls24-315/prove.go similarity index 100% rename from internal/backend/bls24-315/groth16/prove.go rename to backend/groth16/bls24-315/prove.go diff --git a/internal/backend/bls24-315/groth16/setup.go b/backend/groth16/bls24-315/setup.go similarity index 100% rename from internal/backend/bls24-315/groth16/setup.go rename to backend/groth16/bls24-315/setup.go diff --git a/internal/backend/bls24-315/groth16/verify.go b/backend/groth16/bls24-315/verify.go similarity index 100% rename from internal/backend/bls24-315/groth16/verify.go rename to backend/groth16/bls24-315/verify.go diff --git a/internal/backend/bls24-317/groth16/commitment.go b/backend/groth16/bls24-317/commitment.go similarity index 100% rename from internal/backend/bls24-317/groth16/commitment.go rename to backend/groth16/bls24-317/commitment.go diff --git a/internal/backend/bls24-317/groth16/commitment_test.go b/backend/groth16/bls24-317/commitment_test.go similarity index 100% rename from internal/backend/bls24-317/groth16/commitment_test.go rename to backend/groth16/bls24-317/commitment_test.go diff --git a/internal/backend/bls24-317/groth16/marshal.go b/backend/groth16/bls24-317/marshal.go similarity index 100% rename from internal/backend/bls24-317/groth16/marshal.go rename to backend/groth16/bls24-317/marshal.go diff --git a/internal/backend/bls24-317/groth16/marshal_test.go b/backend/groth16/bls24-317/marshal_test.go similarity index 100% rename from internal/backend/bls24-317/groth16/marshal_test.go rename to backend/groth16/bls24-317/marshal_test.go diff --git a/internal/backend/bls24-317/groth16/prove.go b/backend/groth16/bls24-317/prove.go similarity index 100% rename from internal/backend/bls24-317/groth16/prove.go rename to backend/groth16/bls24-317/prove.go diff --git a/internal/backend/bls24-317/groth16/setup.go b/backend/groth16/bls24-317/setup.go similarity index 100% rename from internal/backend/bls24-317/groth16/setup.go rename to backend/groth16/bls24-317/setup.go diff --git a/internal/backend/bls24-317/groth16/verify.go b/backend/groth16/bls24-317/verify.go similarity index 100% rename from internal/backend/bls24-317/groth16/verify.go rename to backend/groth16/bls24-317/verify.go diff --git a/internal/backend/bn254/groth16/commitment.go b/backend/groth16/bn254/commitment.go similarity index 100% rename from internal/backend/bn254/groth16/commitment.go rename to backend/groth16/bn254/commitment.go diff --git a/internal/backend/bn254/groth16/commitment_test.go b/backend/groth16/bn254/commitment_test.go similarity index 100% rename from internal/backend/bn254/groth16/commitment_test.go rename to backend/groth16/bn254/commitment_test.go diff --git a/internal/backend/bn254/groth16/marshal.go b/backend/groth16/bn254/marshal.go similarity index 100% rename from internal/backend/bn254/groth16/marshal.go rename to backend/groth16/bn254/marshal.go diff --git a/internal/backend/bn254/groth16/marshal_test.go b/backend/groth16/bn254/marshal_test.go similarity index 100% rename from internal/backend/bn254/groth16/marshal_test.go rename to backend/groth16/bn254/marshal_test.go diff --git a/internal/backend/bn254/groth16/prove.go b/backend/groth16/bn254/prove.go similarity index 100% rename from internal/backend/bn254/groth16/prove.go rename to backend/groth16/bn254/prove.go diff --git a/internal/backend/bn254/groth16/setup.go b/backend/groth16/bn254/setup.go similarity index 100% rename from internal/backend/bn254/groth16/setup.go rename to backend/groth16/bn254/setup.go diff --git a/internal/backend/bn254/groth16/solidity.go b/backend/groth16/bn254/solidity.go similarity index 100% rename from internal/backend/bn254/groth16/solidity.go rename to backend/groth16/bn254/solidity.go diff --git a/internal/backend/bn254/groth16/utils_test.go b/backend/groth16/bn254/utils_test.go similarity index 100% rename from internal/backend/bn254/groth16/utils_test.go rename to backend/groth16/bn254/utils_test.go diff --git a/internal/backend/bn254/groth16/verify.go b/backend/groth16/bn254/verify.go similarity index 100% rename from internal/backend/bn254/groth16/verify.go rename to backend/groth16/bn254/verify.go diff --git a/internal/backend/bw6-633/groth16/commitment.go b/backend/groth16/bw6-633/commitment.go similarity index 100% rename from internal/backend/bw6-633/groth16/commitment.go rename to backend/groth16/bw6-633/commitment.go diff --git a/internal/backend/bw6-633/groth16/commitment_test.go b/backend/groth16/bw6-633/commitment_test.go similarity index 100% rename from internal/backend/bw6-633/groth16/commitment_test.go rename to backend/groth16/bw6-633/commitment_test.go diff --git a/internal/backend/bw6-633/groth16/marshal.go b/backend/groth16/bw6-633/marshal.go similarity index 100% rename from internal/backend/bw6-633/groth16/marshal.go rename to backend/groth16/bw6-633/marshal.go diff --git a/internal/backend/bw6-633/groth16/marshal_test.go b/backend/groth16/bw6-633/marshal_test.go similarity index 100% rename from internal/backend/bw6-633/groth16/marshal_test.go rename to backend/groth16/bw6-633/marshal_test.go diff --git a/internal/backend/bw6-633/groth16/prove.go b/backend/groth16/bw6-633/prove.go similarity index 100% rename from internal/backend/bw6-633/groth16/prove.go rename to backend/groth16/bw6-633/prove.go diff --git a/internal/backend/bw6-633/groth16/setup.go b/backend/groth16/bw6-633/setup.go similarity index 100% rename from internal/backend/bw6-633/groth16/setup.go rename to backend/groth16/bw6-633/setup.go diff --git a/internal/backend/bw6-633/groth16/verify.go b/backend/groth16/bw6-633/verify.go similarity index 100% rename from internal/backend/bw6-633/groth16/verify.go rename to backend/groth16/bw6-633/verify.go diff --git a/internal/backend/bw6-761/groth16/commitment.go b/backend/groth16/bw6-761/commitment.go similarity index 100% rename from internal/backend/bw6-761/groth16/commitment.go rename to backend/groth16/bw6-761/commitment.go diff --git a/internal/backend/bw6-761/groth16/commitment_test.go b/backend/groth16/bw6-761/commitment_test.go similarity index 100% rename from internal/backend/bw6-761/groth16/commitment_test.go rename to backend/groth16/bw6-761/commitment_test.go diff --git a/internal/backend/bw6-761/groth16/marshal.go b/backend/groth16/bw6-761/marshal.go similarity index 100% rename from internal/backend/bw6-761/groth16/marshal.go rename to backend/groth16/bw6-761/marshal.go diff --git a/internal/backend/bw6-761/groth16/marshal_test.go b/backend/groth16/bw6-761/marshal_test.go similarity index 100% rename from internal/backend/bw6-761/groth16/marshal_test.go rename to backend/groth16/bw6-761/marshal_test.go diff --git a/internal/backend/bw6-761/groth16/prove.go b/backend/groth16/bw6-761/prove.go similarity index 100% rename from internal/backend/bw6-761/groth16/prove.go rename to backend/groth16/bw6-761/prove.go diff --git a/internal/backend/bw6-761/groth16/setup.go b/backend/groth16/bw6-761/setup.go similarity index 100% rename from internal/backend/bw6-761/groth16/setup.go rename to backend/groth16/bw6-761/setup.go diff --git a/internal/backend/bw6-761/groth16/verify.go b/backend/groth16/bw6-761/verify.go similarity index 100% rename from internal/backend/bw6-761/groth16/verify.go rename to backend/groth16/bw6-761/verify.go diff --git a/backend/groth16/groth16.go b/backend/groth16/groth16.go index 9e4bf92150..41e0f63c7e 100644 --- a/backend/groth16/groth16.go +++ b/backend/groth16/groth16.go @@ -44,13 +44,13 @@ import ( gnarkio "github.com/consensys/gnark/io" - groth16_bls12377 "github.com/consensys/gnark/internal/backend/bls12-377/groth16" - groth16_bls12381 "github.com/consensys/gnark/internal/backend/bls12-381/groth16" - groth16_bls24315 "github.com/consensys/gnark/internal/backend/bls24-315/groth16" - groth16_bls24317 "github.com/consensys/gnark/internal/backend/bls24-317/groth16" - groth16_bn254 "github.com/consensys/gnark/internal/backend/bn254/groth16" - groth16_bw6633 "github.com/consensys/gnark/internal/backend/bw6-633/groth16" - groth16_bw6761 "github.com/consensys/gnark/internal/backend/bw6-761/groth16" + groth16_bls12377 "github.com/consensys/gnark/backend/groth16/bls12-377" + groth16_bls12381 "github.com/consensys/gnark/backend/groth16/bls12-381" + groth16_bls24315 "github.com/consensys/gnark/backend/groth16/bls24-315" + groth16_bls24317 "github.com/consensys/gnark/backend/groth16/bls24-317" + groth16_bn254 "github.com/consensys/gnark/backend/groth16/bn254" + groth16_bw6633 "github.com/consensys/gnark/backend/groth16/bw6-633" + groth16_bw6761 "github.com/consensys/gnark/backend/groth16/bw6-761" ) type groth16Object interface { diff --git a/internal/backend/bls12-377/plonk/marshal.go b/backend/plonk/bls12-377/marshal.go similarity index 100% rename from internal/backend/bls12-377/plonk/marshal.go rename to backend/plonk/bls12-377/marshal.go diff --git a/internal/backend/bls12-377/plonk/marshal_test.go b/backend/plonk/bls12-377/marshal_test.go similarity index 100% rename from internal/backend/bls12-377/plonk/marshal_test.go rename to backend/plonk/bls12-377/marshal_test.go diff --git a/internal/backend/bls12-377/plonk/prove.go b/backend/plonk/bls12-377/prove.go similarity index 100% rename from internal/backend/bls12-377/plonk/prove.go rename to backend/plonk/bls12-377/prove.go diff --git a/internal/backend/bls12-377/plonk/setup.go b/backend/plonk/bls12-377/setup.go similarity index 100% rename from internal/backend/bls12-377/plonk/setup.go rename to backend/plonk/bls12-377/setup.go diff --git a/internal/backend/bls12-377/plonk/verify.go b/backend/plonk/bls12-377/verify.go similarity index 100% rename from internal/backend/bls12-377/plonk/verify.go rename to backend/plonk/bls12-377/verify.go diff --git a/internal/backend/bls12-381/plonk/marshal.go b/backend/plonk/bls12-381/marshal.go similarity index 100% rename from internal/backend/bls12-381/plonk/marshal.go rename to backend/plonk/bls12-381/marshal.go diff --git a/internal/backend/bls12-381/plonk/marshal_test.go b/backend/plonk/bls12-381/marshal_test.go similarity index 100% rename from internal/backend/bls12-381/plonk/marshal_test.go rename to backend/plonk/bls12-381/marshal_test.go diff --git a/internal/backend/bls12-381/plonk/prove.go b/backend/plonk/bls12-381/prove.go similarity index 100% rename from internal/backend/bls12-381/plonk/prove.go rename to backend/plonk/bls12-381/prove.go diff --git a/internal/backend/bls12-381/plonk/setup.go b/backend/plonk/bls12-381/setup.go similarity index 100% rename from internal/backend/bls12-381/plonk/setup.go rename to backend/plonk/bls12-381/setup.go diff --git a/internal/backend/bls12-381/plonk/verify.go b/backend/plonk/bls12-381/verify.go similarity index 100% rename from internal/backend/bls12-381/plonk/verify.go rename to backend/plonk/bls12-381/verify.go diff --git a/internal/backend/bls24-315/plonk/marshal.go b/backend/plonk/bls24-315/marshal.go similarity index 100% rename from internal/backend/bls24-315/plonk/marshal.go rename to backend/plonk/bls24-315/marshal.go diff --git a/internal/backend/bls24-315/plonk/marshal_test.go b/backend/plonk/bls24-315/marshal_test.go similarity index 100% rename from internal/backend/bls24-315/plonk/marshal_test.go rename to backend/plonk/bls24-315/marshal_test.go diff --git a/internal/backend/bls24-315/plonk/prove.go b/backend/plonk/bls24-315/prove.go similarity index 100% rename from internal/backend/bls24-315/plonk/prove.go rename to backend/plonk/bls24-315/prove.go diff --git a/internal/backend/bls24-315/plonk/setup.go b/backend/plonk/bls24-315/setup.go similarity index 100% rename from internal/backend/bls24-315/plonk/setup.go rename to backend/plonk/bls24-315/setup.go diff --git a/internal/backend/bls24-315/plonk/verify.go b/backend/plonk/bls24-315/verify.go similarity index 100% rename from internal/backend/bls24-315/plonk/verify.go rename to backend/plonk/bls24-315/verify.go diff --git a/internal/backend/bls24-317/plonk/marshal.go b/backend/plonk/bls24-317/marshal.go similarity index 100% rename from internal/backend/bls24-317/plonk/marshal.go rename to backend/plonk/bls24-317/marshal.go diff --git a/internal/backend/bls24-317/plonk/marshal_test.go b/backend/plonk/bls24-317/marshal_test.go similarity index 100% rename from internal/backend/bls24-317/plonk/marshal_test.go rename to backend/plonk/bls24-317/marshal_test.go diff --git a/internal/backend/bls24-317/plonk/prove.go b/backend/plonk/bls24-317/prove.go similarity index 100% rename from internal/backend/bls24-317/plonk/prove.go rename to backend/plonk/bls24-317/prove.go diff --git a/internal/backend/bls24-317/plonk/setup.go b/backend/plonk/bls24-317/setup.go similarity index 100% rename from internal/backend/bls24-317/plonk/setup.go rename to backend/plonk/bls24-317/setup.go diff --git a/internal/backend/bls24-317/plonk/verify.go b/backend/plonk/bls24-317/verify.go similarity index 100% rename from internal/backend/bls24-317/plonk/verify.go rename to backend/plonk/bls24-317/verify.go diff --git a/internal/backend/bn254/plonk/marshal.go b/backend/plonk/bn254/marshal.go similarity index 100% rename from internal/backend/bn254/plonk/marshal.go rename to backend/plonk/bn254/marshal.go diff --git a/internal/backend/bn254/plonk/marshal_test.go b/backend/plonk/bn254/marshal_test.go similarity index 100% rename from internal/backend/bn254/plonk/marshal_test.go rename to backend/plonk/bn254/marshal_test.go diff --git a/internal/backend/bn254/plonk/prove.go b/backend/plonk/bn254/prove.go similarity index 100% rename from internal/backend/bn254/plonk/prove.go rename to backend/plonk/bn254/prove.go diff --git a/internal/backend/bn254/plonk/setup.go b/backend/plonk/bn254/setup.go similarity index 100% rename from internal/backend/bn254/plonk/setup.go rename to backend/plonk/bn254/setup.go diff --git a/internal/backend/bn254/plonk/solidity.go b/backend/plonk/bn254/solidity.go similarity index 100% rename from internal/backend/bn254/plonk/solidity.go rename to backend/plonk/bn254/solidity.go diff --git a/internal/backend/bn254/plonk/verify.go b/backend/plonk/bn254/verify.go similarity index 100% rename from internal/backend/bn254/plonk/verify.go rename to backend/plonk/bn254/verify.go diff --git a/internal/backend/bw6-633/plonk/marshal.go b/backend/plonk/bw6-633/marshal.go similarity index 100% rename from internal/backend/bw6-633/plonk/marshal.go rename to backend/plonk/bw6-633/marshal.go diff --git a/internal/backend/bw6-633/plonk/marshal_test.go b/backend/plonk/bw6-633/marshal_test.go similarity index 100% rename from internal/backend/bw6-633/plonk/marshal_test.go rename to backend/plonk/bw6-633/marshal_test.go diff --git a/internal/backend/bw6-633/plonk/prove.go b/backend/plonk/bw6-633/prove.go similarity index 100% rename from internal/backend/bw6-633/plonk/prove.go rename to backend/plonk/bw6-633/prove.go diff --git a/internal/backend/bw6-633/plonk/setup.go b/backend/plonk/bw6-633/setup.go similarity index 100% rename from internal/backend/bw6-633/plonk/setup.go rename to backend/plonk/bw6-633/setup.go diff --git a/internal/backend/bw6-633/plonk/verify.go b/backend/plonk/bw6-633/verify.go similarity index 100% rename from internal/backend/bw6-633/plonk/verify.go rename to backend/plonk/bw6-633/verify.go diff --git a/internal/backend/bw6-761/plonk/marshal.go b/backend/plonk/bw6-761/marshal.go similarity index 100% rename from internal/backend/bw6-761/plonk/marshal.go rename to backend/plonk/bw6-761/marshal.go diff --git a/internal/backend/bw6-761/plonk/marshal_test.go b/backend/plonk/bw6-761/marshal_test.go similarity index 100% rename from internal/backend/bw6-761/plonk/marshal_test.go rename to backend/plonk/bw6-761/marshal_test.go diff --git a/internal/backend/bw6-761/plonk/prove.go b/backend/plonk/bw6-761/prove.go similarity index 100% rename from internal/backend/bw6-761/plonk/prove.go rename to backend/plonk/bw6-761/prove.go diff --git a/internal/backend/bw6-761/plonk/setup.go b/backend/plonk/bw6-761/setup.go similarity index 100% rename from internal/backend/bw6-761/plonk/setup.go rename to backend/plonk/bw6-761/setup.go diff --git a/internal/backend/bw6-761/plonk/verify.go b/backend/plonk/bw6-761/verify.go similarity index 100% rename from internal/backend/bw6-761/plonk/verify.go rename to backend/plonk/bw6-761/verify.go diff --git a/backend/plonk/plonk.go b/backend/plonk/plonk.go index 22fb4a84e6..c74e14363b 100644 --- a/backend/plonk/plonk.go +++ b/backend/plonk/plonk.go @@ -36,13 +36,13 @@ import ( cs_bw6633 "github.com/consensys/gnark/constraint/bw6-633" cs_bw6761 "github.com/consensys/gnark/constraint/bw6-761" - plonk_bls12377 "github.com/consensys/gnark/internal/backend/bls12-377/plonk" - plonk_bls12381 "github.com/consensys/gnark/internal/backend/bls12-381/plonk" - plonk_bls24315 "github.com/consensys/gnark/internal/backend/bls24-315/plonk" - plonk_bls24317 "github.com/consensys/gnark/internal/backend/bls24-317/plonk" - plonk_bn254 "github.com/consensys/gnark/internal/backend/bn254/plonk" - plonk_bw6633 "github.com/consensys/gnark/internal/backend/bw6-633/plonk" - plonk_bw6761 "github.com/consensys/gnark/internal/backend/bw6-761/plonk" + plonk_bls12377 "github.com/consensys/gnark/backend/plonk/bls12-377" + plonk_bls12381 "github.com/consensys/gnark/backend/plonk/bls12-381" + plonk_bls24315 "github.com/consensys/gnark/backend/plonk/bls24-315" + plonk_bls24317 "github.com/consensys/gnark/backend/plonk/bls24-317" + plonk_bn254 "github.com/consensys/gnark/backend/plonk/bn254" + plonk_bw6633 "github.com/consensys/gnark/backend/plonk/bw6-633" + plonk_bw6761 "github.com/consensys/gnark/backend/plonk/bw6-761" fr_bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" fr_bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" diff --git a/internal/backend/bls12-377/plonkfri/prove.go b/backend/plonkfri/bls12-377/prove.go similarity index 100% rename from internal/backend/bls12-377/plonkfri/prove.go rename to backend/plonkfri/bls12-377/prove.go diff --git a/internal/backend/bls12-377/plonkfri/setup.go b/backend/plonkfri/bls12-377/setup.go similarity index 100% rename from internal/backend/bls12-377/plonkfri/setup.go rename to backend/plonkfri/bls12-377/setup.go diff --git a/internal/backend/bls12-377/plonkfri/verify.go b/backend/plonkfri/bls12-377/verify.go similarity index 100% rename from internal/backend/bls12-377/plonkfri/verify.go rename to backend/plonkfri/bls12-377/verify.go diff --git a/internal/backend/bls12-381/plonkfri/prove.go b/backend/plonkfri/bls12-381/prove.go similarity index 100% rename from internal/backend/bls12-381/plonkfri/prove.go rename to backend/plonkfri/bls12-381/prove.go diff --git a/internal/backend/bls12-381/plonkfri/setup.go b/backend/plonkfri/bls12-381/setup.go similarity index 100% rename from internal/backend/bls12-381/plonkfri/setup.go rename to backend/plonkfri/bls12-381/setup.go diff --git a/internal/backend/bls12-381/plonkfri/verify.go b/backend/plonkfri/bls12-381/verify.go similarity index 100% rename from internal/backend/bls12-381/plonkfri/verify.go rename to backend/plonkfri/bls12-381/verify.go diff --git a/internal/backend/bls24-315/plonkfri/prove.go b/backend/plonkfri/bls24-315/prove.go similarity index 100% rename from internal/backend/bls24-315/plonkfri/prove.go rename to backend/plonkfri/bls24-315/prove.go diff --git a/internal/backend/bls24-315/plonkfri/setup.go b/backend/plonkfri/bls24-315/setup.go similarity index 100% rename from internal/backend/bls24-315/plonkfri/setup.go rename to backend/plonkfri/bls24-315/setup.go diff --git a/internal/backend/bls24-315/plonkfri/verify.go b/backend/plonkfri/bls24-315/verify.go similarity index 100% rename from internal/backend/bls24-315/plonkfri/verify.go rename to backend/plonkfri/bls24-315/verify.go diff --git a/internal/backend/bls24-317/plonkfri/prove.go b/backend/plonkfri/bls24-317/prove.go similarity index 100% rename from internal/backend/bls24-317/plonkfri/prove.go rename to backend/plonkfri/bls24-317/prove.go diff --git a/internal/backend/bls24-317/plonkfri/setup.go b/backend/plonkfri/bls24-317/setup.go similarity index 100% rename from internal/backend/bls24-317/plonkfri/setup.go rename to backend/plonkfri/bls24-317/setup.go diff --git a/internal/backend/bls24-317/plonkfri/verify.go b/backend/plonkfri/bls24-317/verify.go similarity index 100% rename from internal/backend/bls24-317/plonkfri/verify.go rename to backend/plonkfri/bls24-317/verify.go diff --git a/internal/backend/bn254/plonkfri/prove.go b/backend/plonkfri/bn254/prove.go similarity index 100% rename from internal/backend/bn254/plonkfri/prove.go rename to backend/plonkfri/bn254/prove.go diff --git a/internal/backend/bn254/plonkfri/setup.go b/backend/plonkfri/bn254/setup.go similarity index 100% rename from internal/backend/bn254/plonkfri/setup.go rename to backend/plonkfri/bn254/setup.go diff --git a/internal/backend/bn254/plonkfri/verify.go b/backend/plonkfri/bn254/verify.go similarity index 100% rename from internal/backend/bn254/plonkfri/verify.go rename to backend/plonkfri/bn254/verify.go diff --git a/internal/backend/bw6-633/plonkfri/prove.go b/backend/plonkfri/bw6-633/prove.go similarity index 100% rename from internal/backend/bw6-633/plonkfri/prove.go rename to backend/plonkfri/bw6-633/prove.go diff --git a/internal/backend/bw6-633/plonkfri/setup.go b/backend/plonkfri/bw6-633/setup.go similarity index 100% rename from internal/backend/bw6-633/plonkfri/setup.go rename to backend/plonkfri/bw6-633/setup.go diff --git a/internal/backend/bw6-633/plonkfri/verify.go b/backend/plonkfri/bw6-633/verify.go similarity index 100% rename from internal/backend/bw6-633/plonkfri/verify.go rename to backend/plonkfri/bw6-633/verify.go diff --git a/internal/backend/bw6-761/plonkfri/prove.go b/backend/plonkfri/bw6-761/prove.go similarity index 100% rename from internal/backend/bw6-761/plonkfri/prove.go rename to backend/plonkfri/bw6-761/prove.go diff --git a/internal/backend/bw6-761/plonkfri/setup.go b/backend/plonkfri/bw6-761/setup.go similarity index 100% rename from internal/backend/bw6-761/plonkfri/setup.go rename to backend/plonkfri/bw6-761/setup.go diff --git a/internal/backend/bw6-761/plonkfri/verify.go b/backend/plonkfri/bw6-761/verify.go similarity index 100% rename from internal/backend/bw6-761/plonkfri/verify.go rename to backend/plonkfri/bw6-761/verify.go diff --git a/backend/plonkfri/plonkfri.go b/backend/plonkfri/plonkfri.go index 54954f89a8..5fcb3760eb 100644 --- a/backend/plonkfri/plonkfri.go +++ b/backend/plonkfri/plonkfri.go @@ -29,12 +29,13 @@ import ( cs_bw6633 "github.com/consensys/gnark/constraint/bw6-633" cs_bw6761 "github.com/consensys/gnark/constraint/bw6-761" - plonk_bls12377 "github.com/consensys/gnark/internal/backend/bls12-377/plonkfri" - plonk_bls12381 "github.com/consensys/gnark/internal/backend/bls12-381/plonkfri" - plonk_bls24315 "github.com/consensys/gnark/internal/backend/bls24-315/plonkfri" - plonk_bn254 "github.com/consensys/gnark/internal/backend/bn254/plonkfri" - plonk_bw6633 "github.com/consensys/gnark/internal/backend/bw6-633/plonkfri" - plonk_bw6761 "github.com/consensys/gnark/internal/backend/bw6-761/plonkfri" + plonk_bls12377 "github.com/consensys/gnark/backend/plonkfri/bls12-377" + plonk_bls12381 "github.com/consensys/gnark/backend/plonkfri/bls12-381" + plonk_bls24315 "github.com/consensys/gnark/backend/plonkfri/bls24-315" + plonk_bls24317 "github.com/consensys/gnark/backend/plonkfri/bls24-317" + plonk_bn254 "github.com/consensys/gnark/backend/plonkfri/bn254" + plonk_bw6633 "github.com/consensys/gnark/backend/plonkfri/bw6-633" + plonk_bw6761 "github.com/consensys/gnark/backend/plonkfri/bw6-761" fr_bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" fr_bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" @@ -43,8 +44,6 @@ import ( fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" fr_bw6633 "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" fr_bw6761 "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" - - plonk_bls24317 "github.com/consensys/gnark/internal/backend/bls24-317/plonkfri" ) // Proof represents a Plonk proof generated by plonk.Prove diff --git a/internal/generator/backend/main.go b/internal/generator/backend/main.go index df801f8650..5face84ed8 100644 --- a/internal/generator/backend/main.go +++ b/internal/generator/backend/main.go @@ -4,6 +4,7 @@ import ( "os" "os/exec" "path/filepath" + "strings" "sync" "github.com/consensys/bavard" @@ -19,43 +20,43 @@ var bgen = bavard.NewBatchGenerator(copyrightHolder, 2020, "gnark") func main() { bls12_377 := templateData{ - RootPath: "../../../internal/backend/bls12-377/", + RootPath: "../../../backend/{?}/bls12-377/", CSPath: "../../../constraint/bls12-377/", Curve: "BLS12-377", CurveID: "BLS12_377", } bls12_381 := templateData{ - RootPath: "../../../internal/backend/bls12-381/", + RootPath: "../../../backend/{?}/bls12-381/", CSPath: "../../../constraint/bls12-381/", Curve: "BLS12-381", CurveID: "BLS12_381", } bn254 := templateData{ - RootPath: "../../../internal/backend/bn254/", + RootPath: "../../../backend/{?}/bn254/", CSPath: "../../../constraint/bn254/", Curve: "BN254", CurveID: "BN254", } bw6_761 := templateData{ - RootPath: "../../../internal/backend/bw6-761/", + RootPath: "../../../backend/{?}/bw6-761/", CSPath: "../../../constraint/bw6-761/", Curve: "BW6-761", CurveID: "BW6_761", } bls24_315 := templateData{ - RootPath: "../../../internal/backend/bls24-315/", + RootPath: "../../../backend/{?}/bls24-315/", CSPath: "../../../constraint/bls24-315/", Curve: "BLS24-315", CurveID: "BLS24_315", } bls24_317 := templateData{ - RootPath: "../../../internal/backend/bls24-317/", + RootPath: "../../../backend/{?}/bls24-317/", CSPath: "../../../constraint/bls24-317/", Curve: "BLS24-317", CurveID: "BLS24_317", } bw6_633 := templateData{ - RootPath: "../../../internal/backend/bw6-633/", + RootPath: "../../../backend/{?}/bw6-633/", CSPath: "../../../constraint/bw6-633/", Curve: "BW6-633", CurveID: "BW6_633", @@ -97,16 +98,21 @@ func main() { wg.Add(1) go func(d templateData) { - defer wg.Done() - if err := os.MkdirAll(d.RootPath+"groth16", 0700); err != nil { + var ( + groth16Dir = strings.Replace(d.RootPath, "{?}", "groth16", 1) + plonkDir = strings.Replace(d.RootPath, "{?}", "plonk", 1) + plonkFriDir = strings.Replace(d.RootPath, "{?}", "plonkfri", 1) + ) + + if err := os.MkdirAll(groth16Dir, 0700); err != nil { panic(err) } - if err := os.MkdirAll(d.RootPath+"plonk", 0700); err != nil { + if err := os.MkdirAll(plonkDir, 0700); err != nil { panic(err) } - if err := os.MkdirAll(d.RootPath+"plonkfri", 0700); err != nil { + if err := os.MkdirAll(plonkFriDir, 0700); err != nil { panic(err) } @@ -136,10 +142,6 @@ func main() { return } - plonkFriDir := filepath.Join(d.RootPath, "plonkfri") - groth16Dir := filepath.Join(d.RootPath, "groth16") - plonkDir := filepath.Join(d.RootPath, "plonk") - if err := os.MkdirAll(groth16Dir, 0700); err != nil { panic(err) } diff --git a/std/groth16_bls12377/verifier.go b/std/groth16_bls12377/verifier.go index 8316d20479..7d6f561dde 100644 --- a/std/groth16_bls12377/verifier.go +++ b/std/groth16_bls12377/verifier.go @@ -22,8 +22,8 @@ import ( bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377" "github.com/consensys/gnark/backend/groth16" + groth16_bls12377 "github.com/consensys/gnark/backend/groth16/bls12-377" "github.com/consensys/gnark/frontend" - groth16_bls12377 "github.com/consensys/gnark/internal/backend/bls12-377/groth16" "github.com/consensys/gnark/std/algebra/native/fields_bls12377" "github.com/consensys/gnark/std/algebra/native/sw_bls12377" ) diff --git a/std/groth16_bls12377/verifier_test.go b/std/groth16_bls12377/verifier_test.go index beab2de62b..40397b507a 100644 --- a/std/groth16_bls12377/verifier_test.go +++ b/std/groth16_bls12377/verifier_test.go @@ -22,11 +22,11 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + groth16_bls12377 "github.com/consensys/gnark/backend/groth16/bls12-377" "github.com/consensys/gnark/constraint" cs_bls12377 "github.com/consensys/gnark/constraint/bls12-377" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" - groth16_bls12377 "github.com/consensys/gnark/internal/backend/bls12-377/groth16" "github.com/consensys/gnark/std/algebra/native/sw_bls12377" "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/test" diff --git a/std/groth16_bls24315/verifier.go b/std/groth16_bls24315/verifier.go index 836c20d33b..8da0f6c0b0 100644 --- a/std/groth16_bls24315/verifier.go +++ b/std/groth16_bls24315/verifier.go @@ -22,8 +22,8 @@ import ( bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315" "github.com/consensys/gnark/backend/groth16" + groth16_bls24315 "github.com/consensys/gnark/backend/groth16/bls24-315" "github.com/consensys/gnark/frontend" - groth16_bls24315 "github.com/consensys/gnark/internal/backend/bls24-315/groth16" "github.com/consensys/gnark/std/algebra/native/fields_bls24315" "github.com/consensys/gnark/std/algebra/native/sw_bls24315" ) diff --git a/std/groth16_bls24315/verifier_test.go b/std/groth16_bls24315/verifier_test.go index 73bb075d19..9af446d8bf 100644 --- a/std/groth16_bls24315/verifier_test.go +++ b/std/groth16_bls24315/verifier_test.go @@ -22,11 +22,11 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" + groth16_bls24315 "github.com/consensys/gnark/backend/groth16/bls24-315" "github.com/consensys/gnark/constraint" cs_bls24315 "github.com/consensys/gnark/constraint/bls24-315" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" - groth16_bls24315 "github.com/consensys/gnark/internal/backend/bls24-315/groth16" "github.com/consensys/gnark/std/algebra/native/sw_bls24315" "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/test" From 71fca45adc6a1fbdee8d866f082dc273d3637e85 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Mon, 13 Mar 2023 15:58:04 -0400 Subject: [PATCH 106/464] fix: pass canonical version of pi2 to computeLinearizedPolynomial --- internal/backend/bn254/plonk/prove.go | 63 +++++++++++++++------------ internal/backend/bn254/plonk/setup.go | 2 +- 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/internal/backend/bn254/plonk/prove.go b/internal/backend/bn254/plonk/prove.go index 16472567d5..b3d6528fb4 100644 --- a/internal/backend/bn254/plonk/prove.go +++ b/internal/backend/bn254/plonk/prove.go @@ -120,17 +120,26 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts evaluationLDomainSmall := []fr.Element(solution.L) evaluationRDomainSmall := []fr.Element(solution.R) evaluationODomainSmall := []fr.Element(solution.O) + evaluationPI2DomainSmall := []fr.Element(pi2) lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} liop := iop.NewPolynomial(&evaluationLDomainSmall, lagReg) riop := iop.NewPolynomial(&evaluationRDomainSmall, lagReg) oiop := iop.NewPolynomial(&evaluationODomainSmall, lagReg) + pi2iop := iop.NewPolynomial(&evaluationPI2DomainSmall, lagReg) + qcpiop := iop.NewPolynomial(&pk.QcPrime, lagReg) wliop := liop.ShallowClone() wriop := riop.ShallowClone() woiop := oiop.ShallowClone() + wpi2iop := pi2iop.ShallowClone() + wqciop := qcpiop.ShallowClone() wliop.ToCanonical(&pk.Domain[0]).ToRegular() wriop.ToCanonical(&pk.Domain[0]).ToRegular() woiop.ToCanonical(&pk.Domain[0]).ToRegular() + wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + wqciop.ToCanonical(&pk.Domain[0]).ToRegular() + + wpi2iop.Coefficients() // Blind l, r, o before committing // we set the underlying slice capacity to domain[1].Cardinality to minimize mem moves. @@ -204,7 +213,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], pk.LQk[len(spr.Public):]) if spr.CommitmentInfo.Is() { - qkCompletedCanonical[spr.CommitmentInfo.CommitmentIndex] = commitmentVal // TODO @Tabaie no need to negate? + qkCompletedCanonical[spr.CommitmentInfo.CommitmentIndex] = commitmentVal } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -323,13 +332,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ws3, bwziop, bwsziop, - pi2, // TODO @Tabaie correct format + wpi2iop, // TODO @Tabaie correct format wqliop, wqriop, wqmiop, wqoiop, wqkiop, - qCPrime, // TODO @Tabaie correct format + qcpiop, // TODO @Tabaie correct format wloneiop, ) if err != nil { @@ -355,29 +364,20 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } - // compute evaluations of (blinded version of) l, r, o, z at zeta - var blzeta, brzeta, bozeta fr.Element + // compute evaluations of (blinded version of) l, r, o, z, qCPrime at zeta + var blzeta, brzeta, bozeta, qcpzeta fr.Element var wgEvals sync.WaitGroup - wgEvals.Add(3) - - go func() { - bwliop.ToCanonical(&pk.Domain[1]).ToRegular() - blzeta = bwliop.Evaluate(zeta) - wgEvals.Done() - }() - - go func() { - bwriop.ToCanonical(&pk.Domain[1]).ToRegular() - brzeta = bwriop.Evaluate(zeta) - wgEvals.Done() - }() - - go func() { - bwoiop.ToCanonical(&pk.Domain[1]).ToRegular() - bozeta = bwoiop.Evaluate(zeta) + wgEvals.Add(4) + evalAtZeta := func(poly *iop.Polynomial, res *fr.Element) { + poly.ToCanonical(&pk.Domain[1]).ToRegular() + *res = poly.Evaluate(zeta) wgEvals.Done() - }() + } + go evalAtZeta(bwliop, &blzeta) + go evalAtZeta(bwriop, &brzeta) + go evalAtZeta(bwoiop, &bozeta) + go evalAtZeta(wqciop, &qcpzeta) // open blinded Z at zeta*z bwziop.ToCanonical(&pk.Domain[1]).ToRegular() @@ -414,7 +414,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts gamma, zeta, bzuzeta, + qcpzeta, bwziop.Coefficients()[:bwziop.BlindedSize()], + wpi2iop.Coefficients(), pk, ) @@ -539,6 +541,8 @@ func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error return err1 } +// Discuss whether there is a benefit to opening pi2 instead + // computeLinearizedPolynomial computes the linearized polynomial in canonical basis. // The purpose is to commit and open all in one ql, qr, qm, qo, qk. // * lZeta, rZeta, oZeta are the evaluation of l, r, o at zeta @@ -550,7 +554,7 @@ func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error // α²*L₁(ζ)*Z(X) // + α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*id1(ζ)+γ)*(r(ζ)+β*id2(ζ)+γ)*(o(ζ)+β*id3(ζ)+γ)) // + l(ζ)*Ql(X) + l(ζ)r(ζ)*Qm(X) + r(ζ)*Qr(X) + o(ζ)*Qo(X) + Qk(X) -func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu fr.Element, blindedZCanonical []fr.Element, pk *ProvingKey) []fr.Element { +func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu, qcpZeta fr.Element, blindedZCanonical []fr.Element, pi2Canonical []fr.Element, pk *ProvingKey) []fr.Element { // first part: individual constraints var rl fr.Element @@ -559,7 +563,7 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, // second part: // Z(μζ)(l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*β*s3(X)-Z(X)(l(ζ)+β*id1(ζ)+γ)*(r(ζ)+β*id2(ζ)+γ)*(o(ζ)+β*id3(ζ)+γ) var s1, s2 fr.Element - chS1 := make(chan struct{}, 1) + chS1 := make(chan struct{}, 1) // TODO @Tabaie wait group? go func() { ps1 := iop.NewPolynomial(&pk.S1Canonical, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) s1 = ps1.Evaluate(zeta) // s1(ζ) @@ -594,9 +598,9 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, den.Sub(&zeta, &one). Inverse(&den) lagrangeZeta.Mul(&lagrangeZeta, &den). // L₁ = (ζⁿ⁻¹)/(ζ-1) - Mul(&lagrangeZeta, &alpha). - Mul(&lagrangeZeta, &alpha). - Mul(&lagrangeZeta, &pk.Domain[0].CardinalityInv) // (1/n)*α²*L₁(ζ) + Mul(&lagrangeZeta, &alpha). + Mul(&lagrangeZeta, &alpha). + Mul(&lagrangeZeta, &pk.Domain[0].CardinalityInv) // (1/n)*α²*L₁(ζ) linPol := make([]fr.Element, len(blindedZCanonical)) copy(linPol, blindedZCanonical) @@ -630,6 +634,9 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, t0.Mul(&pk.Qo[i], &oZeta).Add(&t0, &pk.CQk[i]) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) + + t0.Mul(&pi2Canonical[i], &qcpZeta) + linPol[i].Add(&linPol[i], &t0) } t0.Mul(&blindedZCanonical[i], &lagrangeZeta) diff --git a/internal/backend/bn254/plonk/setup.go b/internal/backend/bn254/plonk/setup.go index edadc5e3bb..d3926f7307 100644 --- a/internal/backend/bn254/plonk/setup.go +++ b/internal/backend/bn254/plonk/setup.go @@ -161,7 +161,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) } for _, committed := range spr.CommitmentInfo.Committed { - pk.QcPrime[committed] = spr.Coefficients[constraint.CoeffIdOne] + pk.QcPrime[committed].SetOne() } pk.Domain[0].FFTInverse(pk.Ql, fft.DIF) From 8b151d2d1135a041a397ec80ea91aad706872cc0 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Mon, 13 Mar 2023 18:07:37 -0500 Subject: [PATCH 107/464] refactor: flatten mpc structure, idomify APIs --- backend/groth16/bls12-377/marshal.go | 6 +- backend/groth16/bls12-377/setup.go | 21 +- backend/groth16/bls12-381/marshal.go | 6 +- backend/groth16/bls12-381/setup.go | 21 +- backend/groth16/bls24-315/marshal.go | 6 +- backend/groth16/bls24-315/setup.go | 21 +- backend/groth16/bls24-317/marshal.go | 6 +- backend/groth16/bls24-317/setup.go | 21 +- backend/groth16/bn254/marshal.go | 6 +- backend/groth16/bn254/setup.go | 21 +- backend/groth16/bw6-633/marshal.go | 6 +- backend/groth16/bw6-633/setup.go | 21 +- backend/groth16/bw6-761/marshal.go | 6 +- backend/groth16/bw6-761/setup.go | 21 +- backend/groth16/setup/keys/marshal.go | 86 -------- backend/groth16/setup/marshal.go | 159 +++++++++++++++ backend/groth16/setup/marshal_test.go | 38 ++++ backend/groth16/setup/phase1.go | 188 ++++++++++++++++++ backend/groth16/setup/phase1/contribution.go | 125 ------------ backend/groth16/setup/phase1/marshal.go | 64 ------ backend/groth16/setup/phase1/verifier.go | 72 ------- .../{phase2/contribution.go => phase2.go} | 90 +++++++-- backend/groth16/setup/phase2/marshal.go | 87 -------- backend/groth16/setup/phase2/verifier.go | 45 ----- .../groth16/setup/{keys/keys.go => setup.go} | 45 +---- backend/groth16/setup/setup_test.go | 118 +++++++++++ backend/groth16/setup/test/example_test.go | 108 ---------- backend/groth16/setup/test/phase1_test.go | 45 ----- backend/groth16/setup/utils/lagrange.go | 8 +- .../groth16/groth16.marshal.go.tmpl | 8 +- .../zkpschemes/groth16/groth16.setup.go.tmpl | 23 ++- 31 files changed, 722 insertions(+), 776 deletions(-) delete mode 100644 backend/groth16/setup/keys/marshal.go create mode 100644 backend/groth16/setup/marshal.go create mode 100644 backend/groth16/setup/marshal_test.go create mode 100644 backend/groth16/setup/phase1.go delete mode 100644 backend/groth16/setup/phase1/contribution.go delete mode 100644 backend/groth16/setup/phase1/marshal.go delete mode 100644 backend/groth16/setup/phase1/verifier.go rename backend/groth16/setup/{phase2/contribution.go => phase2.go} (63%) delete mode 100644 backend/groth16/setup/phase2/marshal.go delete mode 100644 backend/groth16/setup/phase2/verifier.go rename backend/groth16/setup/{keys/keys.go => setup.go} (62%) create mode 100644 backend/groth16/setup/setup_test.go delete mode 100644 backend/groth16/setup/test/example_test.go delete mode 100644 backend/groth16/setup/test/phase1_test.go diff --git a/backend/groth16/bls12-377/marshal.go b/backend/groth16/bls12-377/marshal.go index 787d450165..e4fdff1a48 100644 --- a/backend/groth16/bls12-377/marshal.go +++ b/backend/groth16/bls12-377/marshal.go @@ -171,13 +171,9 @@ func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder) } // recompute vk.e (e(α, β)) and -[δ]2, -[γ]2 - var err error - vk.e, err = curve.Pair([]curve.G1Affine{vk.G1.Alpha}, []curve.G2Affine{vk.G2.Beta}) - if err != nil { + if err := vk.Precompute(); err != nil { return dec.BytesRead(), err } - vk.G2.deltaNeg.Neg(&vk.G2.Delta) - vk.G2.gammaNeg.Neg(&vk.G2.Gamma) return dec.BytesRead(), nil } diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index 2665004ce3..c1e7a22c9e 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -284,11 +284,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pk.G2.Beta = g2PointsAff[len(B)+0] pk.G2.Delta = g2PointsAff[len(B)+1] - // sets vk: [δ]2, [γ]2, -[δ]2, -[γ]2 + // sets vk: [δ]2, [γ]2 vk.G2.Delta = g2PointsAff[len(B)+1] vk.G2.Gamma = g2PointsAff[len(B)+2] - vk.G2.deltaNeg.Neg(&vk.G2.Delta) - vk.G2.gammaNeg.Neg(&vk.G2.Gamma) // --------------------------------------------------------------------------------------------- // Pairing: vk.e @@ -299,16 +297,29 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vk.G1.Beta = pk.G1.Beta vk.G1.Delta = pk.G1.Delta - vk.e, err = curve.Pair([]curve.G1Affine{pk.G1.Alpha}, []curve.G2Affine{pk.G2.Beta}) - if err != nil { + if err := vk.Precompute(); err != nil { return err } + // set domain pk.Domain = *domain return nil } +// Precompute sets e, -[δ]2, -[γ]2 +// This is meant to be called internally during setup or deserialization. +func (vk *VerifyingKey) Precompute() error { + var err error + vk.e, err = curve.Pair([]curve.G1Affine{vk.G1.Alpha}, []curve.G2Affine{vk.G2.Beta}) + if err != nil { + return err + } + vk.G2.deltaNeg.Neg(&vk.G2.Delta) + vk.G2.gammaNeg.Neg(&vk.G2.Gamma) + return nil +} + func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr.Element, B []fr.Element, C []fr.Element) { nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() diff --git a/backend/groth16/bls12-381/marshal.go b/backend/groth16/bls12-381/marshal.go index 8f1cf81f4a..bb544afd21 100644 --- a/backend/groth16/bls12-381/marshal.go +++ b/backend/groth16/bls12-381/marshal.go @@ -171,13 +171,9 @@ func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder) } // recompute vk.e (e(α, β)) and -[δ]2, -[γ]2 - var err error - vk.e, err = curve.Pair([]curve.G1Affine{vk.G1.Alpha}, []curve.G2Affine{vk.G2.Beta}) - if err != nil { + if err := vk.Precompute(); err != nil { return dec.BytesRead(), err } - vk.G2.deltaNeg.Neg(&vk.G2.Delta) - vk.G2.gammaNeg.Neg(&vk.G2.Gamma) return dec.BytesRead(), nil } diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index b5878333f6..dc23ffa75a 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -284,11 +284,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pk.G2.Beta = g2PointsAff[len(B)+0] pk.G2.Delta = g2PointsAff[len(B)+1] - // sets vk: [δ]2, [γ]2, -[δ]2, -[γ]2 + // sets vk: [δ]2, [γ]2 vk.G2.Delta = g2PointsAff[len(B)+1] vk.G2.Gamma = g2PointsAff[len(B)+2] - vk.G2.deltaNeg.Neg(&vk.G2.Delta) - vk.G2.gammaNeg.Neg(&vk.G2.Gamma) // --------------------------------------------------------------------------------------------- // Pairing: vk.e @@ -299,16 +297,29 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vk.G1.Beta = pk.G1.Beta vk.G1.Delta = pk.G1.Delta - vk.e, err = curve.Pair([]curve.G1Affine{pk.G1.Alpha}, []curve.G2Affine{pk.G2.Beta}) - if err != nil { + if err := vk.Precompute(); err != nil { return err } + // set domain pk.Domain = *domain return nil } +// Precompute sets e, -[δ]2, -[γ]2 +// This is meant to be called internally during setup or deserialization. +func (vk *VerifyingKey) Precompute() error { + var err error + vk.e, err = curve.Pair([]curve.G1Affine{vk.G1.Alpha}, []curve.G2Affine{vk.G2.Beta}) + if err != nil { + return err + } + vk.G2.deltaNeg.Neg(&vk.G2.Delta) + vk.G2.gammaNeg.Neg(&vk.G2.Gamma) + return nil +} + func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr.Element, B []fr.Element, C []fr.Element) { nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() diff --git a/backend/groth16/bls24-315/marshal.go b/backend/groth16/bls24-315/marshal.go index ede9181c06..6a53616cd7 100644 --- a/backend/groth16/bls24-315/marshal.go +++ b/backend/groth16/bls24-315/marshal.go @@ -171,13 +171,9 @@ func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder) } // recompute vk.e (e(α, β)) and -[δ]2, -[γ]2 - var err error - vk.e, err = curve.Pair([]curve.G1Affine{vk.G1.Alpha}, []curve.G2Affine{vk.G2.Beta}) - if err != nil { + if err := vk.Precompute(); err != nil { return dec.BytesRead(), err } - vk.G2.deltaNeg.Neg(&vk.G2.Delta) - vk.G2.gammaNeg.Neg(&vk.G2.Gamma) return dec.BytesRead(), nil } diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index 414a6743f4..6a4bf19a6f 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -284,11 +284,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pk.G2.Beta = g2PointsAff[len(B)+0] pk.G2.Delta = g2PointsAff[len(B)+1] - // sets vk: [δ]2, [γ]2, -[δ]2, -[γ]2 + // sets vk: [δ]2, [γ]2 vk.G2.Delta = g2PointsAff[len(B)+1] vk.G2.Gamma = g2PointsAff[len(B)+2] - vk.G2.deltaNeg.Neg(&vk.G2.Delta) - vk.G2.gammaNeg.Neg(&vk.G2.Gamma) // --------------------------------------------------------------------------------------------- // Pairing: vk.e @@ -299,16 +297,29 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vk.G1.Beta = pk.G1.Beta vk.G1.Delta = pk.G1.Delta - vk.e, err = curve.Pair([]curve.G1Affine{pk.G1.Alpha}, []curve.G2Affine{pk.G2.Beta}) - if err != nil { + if err := vk.Precompute(); err != nil { return err } + // set domain pk.Domain = *domain return nil } +// Precompute sets e, -[δ]2, -[γ]2 +// This is meant to be called internally during setup or deserialization. +func (vk *VerifyingKey) Precompute() error { + var err error + vk.e, err = curve.Pair([]curve.G1Affine{vk.G1.Alpha}, []curve.G2Affine{vk.G2.Beta}) + if err != nil { + return err + } + vk.G2.deltaNeg.Neg(&vk.G2.Delta) + vk.G2.gammaNeg.Neg(&vk.G2.Gamma) + return nil +} + func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr.Element, B []fr.Element, C []fr.Element) { nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() diff --git a/backend/groth16/bls24-317/marshal.go b/backend/groth16/bls24-317/marshal.go index 3b0ec45426..6aeab91292 100644 --- a/backend/groth16/bls24-317/marshal.go +++ b/backend/groth16/bls24-317/marshal.go @@ -171,13 +171,9 @@ func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder) } // recompute vk.e (e(α, β)) and -[δ]2, -[γ]2 - var err error - vk.e, err = curve.Pair([]curve.G1Affine{vk.G1.Alpha}, []curve.G2Affine{vk.G2.Beta}) - if err != nil { + if err := vk.Precompute(); err != nil { return dec.BytesRead(), err } - vk.G2.deltaNeg.Neg(&vk.G2.Delta) - vk.G2.gammaNeg.Neg(&vk.G2.Gamma) return dec.BytesRead(), nil } diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index cddbac53ae..cd21b8dde9 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -284,11 +284,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pk.G2.Beta = g2PointsAff[len(B)+0] pk.G2.Delta = g2PointsAff[len(B)+1] - // sets vk: [δ]2, [γ]2, -[δ]2, -[γ]2 + // sets vk: [δ]2, [γ]2 vk.G2.Delta = g2PointsAff[len(B)+1] vk.G2.Gamma = g2PointsAff[len(B)+2] - vk.G2.deltaNeg.Neg(&vk.G2.Delta) - vk.G2.gammaNeg.Neg(&vk.G2.Gamma) // --------------------------------------------------------------------------------------------- // Pairing: vk.e @@ -299,16 +297,29 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vk.G1.Beta = pk.G1.Beta vk.G1.Delta = pk.G1.Delta - vk.e, err = curve.Pair([]curve.G1Affine{pk.G1.Alpha}, []curve.G2Affine{pk.G2.Beta}) - if err != nil { + if err := vk.Precompute(); err != nil { return err } + // set domain pk.Domain = *domain return nil } +// Precompute sets e, -[δ]2, -[γ]2 +// This is meant to be called internally during setup or deserialization. +func (vk *VerifyingKey) Precompute() error { + var err error + vk.e, err = curve.Pair([]curve.G1Affine{vk.G1.Alpha}, []curve.G2Affine{vk.G2.Beta}) + if err != nil { + return err + } + vk.G2.deltaNeg.Neg(&vk.G2.Delta) + vk.G2.gammaNeg.Neg(&vk.G2.Gamma) + return nil +} + func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr.Element, B []fr.Element, C []fr.Element) { nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() diff --git a/backend/groth16/bn254/marshal.go b/backend/groth16/bn254/marshal.go index 66e3c144a1..f906599f75 100644 --- a/backend/groth16/bn254/marshal.go +++ b/backend/groth16/bn254/marshal.go @@ -171,13 +171,9 @@ func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder) } // recompute vk.e (e(α, β)) and -[δ]2, -[γ]2 - var err error - vk.e, err = curve.Pair([]curve.G1Affine{vk.G1.Alpha}, []curve.G2Affine{vk.G2.Beta}) - if err != nil { + if err := vk.Precompute(); err != nil { return dec.BytesRead(), err } - vk.G2.deltaNeg.Neg(&vk.G2.Delta) - vk.G2.gammaNeg.Neg(&vk.G2.Gamma) return dec.BytesRead(), nil } diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index 0ddf89346a..e65295ebec 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -284,11 +284,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pk.G2.Beta = g2PointsAff[len(B)+0] pk.G2.Delta = g2PointsAff[len(B)+1] - // sets vk: [δ]2, [γ]2, -[δ]2, -[γ]2 + // sets vk: [δ]2, [γ]2 vk.G2.Delta = g2PointsAff[len(B)+1] vk.G2.Gamma = g2PointsAff[len(B)+2] - vk.G2.deltaNeg.Neg(&vk.G2.Delta) - vk.G2.gammaNeg.Neg(&vk.G2.Gamma) // --------------------------------------------------------------------------------------------- // Pairing: vk.e @@ -299,16 +297,29 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vk.G1.Beta = pk.G1.Beta vk.G1.Delta = pk.G1.Delta - vk.e, err = curve.Pair([]curve.G1Affine{pk.G1.Alpha}, []curve.G2Affine{pk.G2.Beta}) - if err != nil { + if err := vk.Precompute(); err != nil { return err } + // set domain pk.Domain = *domain return nil } +// Precompute sets e, -[δ]2, -[γ]2 +// This is meant to be called internally during setup or deserialization. +func (vk *VerifyingKey) Precompute() error { + var err error + vk.e, err = curve.Pair([]curve.G1Affine{vk.G1.Alpha}, []curve.G2Affine{vk.G2.Beta}) + if err != nil { + return err + } + vk.G2.deltaNeg.Neg(&vk.G2.Delta) + vk.G2.gammaNeg.Neg(&vk.G2.Gamma) + return nil +} + func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr.Element, B []fr.Element, C []fr.Element) { nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() diff --git a/backend/groth16/bw6-633/marshal.go b/backend/groth16/bw6-633/marshal.go index 8c09e3a403..cb7e234fc5 100644 --- a/backend/groth16/bw6-633/marshal.go +++ b/backend/groth16/bw6-633/marshal.go @@ -171,13 +171,9 @@ func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder) } // recompute vk.e (e(α, β)) and -[δ]2, -[γ]2 - var err error - vk.e, err = curve.Pair([]curve.G1Affine{vk.G1.Alpha}, []curve.G2Affine{vk.G2.Beta}) - if err != nil { + if err := vk.Precompute(); err != nil { return dec.BytesRead(), err } - vk.G2.deltaNeg.Neg(&vk.G2.Delta) - vk.G2.gammaNeg.Neg(&vk.G2.Gamma) return dec.BytesRead(), nil } diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index 1a80792363..7118c2fa44 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -284,11 +284,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pk.G2.Beta = g2PointsAff[len(B)+0] pk.G2.Delta = g2PointsAff[len(B)+1] - // sets vk: [δ]2, [γ]2, -[δ]2, -[γ]2 + // sets vk: [δ]2, [γ]2 vk.G2.Delta = g2PointsAff[len(B)+1] vk.G2.Gamma = g2PointsAff[len(B)+2] - vk.G2.deltaNeg.Neg(&vk.G2.Delta) - vk.G2.gammaNeg.Neg(&vk.G2.Gamma) // --------------------------------------------------------------------------------------------- // Pairing: vk.e @@ -299,16 +297,29 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vk.G1.Beta = pk.G1.Beta vk.G1.Delta = pk.G1.Delta - vk.e, err = curve.Pair([]curve.G1Affine{pk.G1.Alpha}, []curve.G2Affine{pk.G2.Beta}) - if err != nil { + if err := vk.Precompute(); err != nil { return err } + // set domain pk.Domain = *domain return nil } +// Precompute sets e, -[δ]2, -[γ]2 +// This is meant to be called internally during setup or deserialization. +func (vk *VerifyingKey) Precompute() error { + var err error + vk.e, err = curve.Pair([]curve.G1Affine{vk.G1.Alpha}, []curve.G2Affine{vk.G2.Beta}) + if err != nil { + return err + } + vk.G2.deltaNeg.Neg(&vk.G2.Delta) + vk.G2.gammaNeg.Neg(&vk.G2.Gamma) + return nil +} + func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr.Element, B []fr.Element, C []fr.Element) { nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() diff --git a/backend/groth16/bw6-761/marshal.go b/backend/groth16/bw6-761/marshal.go index 0a18c29463..662ece22be 100644 --- a/backend/groth16/bw6-761/marshal.go +++ b/backend/groth16/bw6-761/marshal.go @@ -171,13 +171,9 @@ func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder) } // recompute vk.e (e(α, β)) and -[δ]2, -[γ]2 - var err error - vk.e, err = curve.Pair([]curve.G1Affine{vk.G1.Alpha}, []curve.G2Affine{vk.G2.Beta}) - if err != nil { + if err := vk.Precompute(); err != nil { return dec.BytesRead(), err } - vk.G2.deltaNeg.Neg(&vk.G2.Delta) - vk.G2.gammaNeg.Neg(&vk.G2.Gamma) return dec.BytesRead(), nil } diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index 9fb10e6cb4..5cc22cbfa5 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -284,11 +284,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pk.G2.Beta = g2PointsAff[len(B)+0] pk.G2.Delta = g2PointsAff[len(B)+1] - // sets vk: [δ]2, [γ]2, -[δ]2, -[γ]2 + // sets vk: [δ]2, [γ]2 vk.G2.Delta = g2PointsAff[len(B)+1] vk.G2.Gamma = g2PointsAff[len(B)+2] - vk.G2.deltaNeg.Neg(&vk.G2.Delta) - vk.G2.gammaNeg.Neg(&vk.G2.Gamma) // --------------------------------------------------------------------------------------------- // Pairing: vk.e @@ -299,16 +297,29 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vk.G1.Beta = pk.G1.Beta vk.G1.Delta = pk.G1.Delta - vk.e, err = curve.Pair([]curve.G1Affine{pk.G1.Alpha}, []curve.G2Affine{pk.G2.Beta}) - if err != nil { + if err := vk.Precompute(); err != nil { return err } + // set domain pk.Domain = *domain return nil } +// Precompute sets e, -[δ]2, -[γ]2 +// This is meant to be called internally during setup or deserialization. +func (vk *VerifyingKey) Precompute() error { + var err error + vk.e, err = curve.Pair([]curve.G1Affine{vk.G1.Alpha}, []curve.G2Affine{vk.G2.Beta}) + if err != nil { + return err + } + vk.G2.deltaNeg.Neg(&vk.G2.Delta) + vk.G2.gammaNeg.Neg(&vk.G2.Gamma) + return nil +} + func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr.Element, B []fr.Element, C []fr.Element) { nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() diff --git a/backend/groth16/setup/keys/marshal.go b/backend/groth16/setup/keys/marshal.go deleted file mode 100644 index b02021030b..0000000000 --- a/backend/groth16/setup/keys/marshal.go +++ /dev/null @@ -1,86 +0,0 @@ -package keys - -import ( - "io" - - "github.com/consensys/gnark-crypto/ecc/bn254" -) -func (pk *ProvingKey) WriteTo(w io.Writer, raw bool) (int64, error) { - n, err := pk.Domain.WriteTo(w) - if err != nil { - return n, err - } - - var enc *bn254.Encoder - if raw { - enc = bn254.NewEncoder(w, bn254.RawEncoding()) - } else { - enc = bn254.NewEncoder(w) - } - nbWires := uint64(len(pk.InfinityA)) - - toEncode := []interface{}{ - &pk.G1.Alpha, - &pk.G1.Beta, - &pk.G1.Delta, - pk.G1.A, - pk.G1.B, - pk.G1.Z, - pk.G1.K, - &pk.G2.Beta, - &pk.G2.Delta, - pk.G2.B, - nbWires, - pk.NbInfinityA, - pk.NbInfinityB, - pk.InfinityA, - pk.InfinityB, - } - - for _, v := range toEncode { - if err := enc.Encode(v); err != nil { - return n + enc.BytesWritten(), err - } - } - - return n + enc.BytesWritten(), nil - -} - -// follows bellman format: -// https://github.com/zkcrypto/bellman/blob/fa9be45588227a8c6ec34957de3f68705f07bd92/src/groth16/mod.rs#L143 -// [α]1,[β]1,[β]2,[γ]2,[δ]1,[δ]2,uint32(len(Kvk)),[Kvk]1 -func (vk *VerifyingKey) WriteTo(w io.Writer, raw bool) (int64, error) { - var enc *bn254.Encoder - if raw { - enc = bn254.NewEncoder(w, bn254.RawEncoding()) - } else { - enc = bn254.NewEncoder(w) - } - - // [α]1,[β]1,[β]2,[γ]2,[δ]1,[δ]2 - if err := enc.Encode(&vk.G1.Alpha); err != nil { - return enc.BytesWritten(), err - } - if err := enc.Encode(&vk.G1.Beta); err != nil { - return enc.BytesWritten(), err - } - if err := enc.Encode(&vk.G2.Beta); err != nil { - return enc.BytesWritten(), err - } - if err := enc.Encode(&vk.G2.Gamma); err != nil { - return enc.BytesWritten(), err - } - if err := enc.Encode(&vk.G1.Delta); err != nil { - return enc.BytesWritten(), err - } - if err := enc.Encode(&vk.G2.Delta); err != nil { - return enc.BytesWritten(), err - } - - // uint32(len(Kvk)),[Kvk]1 - if err := enc.Encode(vk.G1.K); err != nil { - return enc.BytesWritten(), err - } - return enc.BytesWritten(), nil -} \ No newline at end of file diff --git a/backend/groth16/setup/marshal.go b/backend/groth16/setup/marshal.go new file mode 100644 index 0000000000..84278a4fe8 --- /dev/null +++ b/backend/groth16/setup/marshal.go @@ -0,0 +1,159 @@ +package setup + +import ( + "io" + + "github.com/consensys/gnark-crypto/ecc/bn254" +) + +// WriteTo implements io.WriterTo +func (phase1 *Phase1) WriteTo(writer io.Writer) (int64, error) { + n, err := phase1.writeTo(writer) + if err != nil { + return n, err + } + nBytes, err := writer.Write(phase1.Hash) + return int64(nBytes) + n, err +} + +func (phase1 *Phase1) writeTo(writer io.Writer) (int64, error) { + toEncode := []interface{}{ + &phase1.PublicKeys.Tau.SG, + &phase1.PublicKeys.Tau.SXG, + &phase1.PublicKeys.Tau.XR, + &phase1.PublicKeys.Alpha.SG, + &phase1.PublicKeys.Alpha.SXG, + &phase1.PublicKeys.Alpha.XR, + &phase1.PublicKeys.Beta.SG, + &phase1.PublicKeys.Beta.SXG, + &phase1.PublicKeys.Beta.XR, + phase1.Parameters.G1.Tau, + phase1.Parameters.G1.AlphaTau, + phase1.Parameters.G1.BetaTau, + phase1.Parameters.G2.Tau, + &phase1.Parameters.G2.Beta, + } + + enc := bn254.NewEncoder(writer) + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + return enc.BytesWritten(), nil +} + +// ReadFrom implements io.ReaderFrom +func (phase1 *Phase1) ReadFrom(reader io.Reader) (int64, error) { + toEncode := []interface{}{ + &phase1.PublicKeys.Tau.SG, + &phase1.PublicKeys.Tau.SXG, + &phase1.PublicKeys.Tau.XR, + &phase1.PublicKeys.Alpha.SG, + &phase1.PublicKeys.Alpha.SXG, + &phase1.PublicKeys.Alpha.XR, + &phase1.PublicKeys.Beta.SG, + &phase1.PublicKeys.Beta.SXG, + &phase1.PublicKeys.Beta.XR, + &phase1.Parameters.G1.Tau, + &phase1.Parameters.G1.AlphaTau, + &phase1.Parameters.G1.BetaTau, + &phase1.Parameters.G2.Tau, + &phase1.Parameters.G2.Beta, + } + + dec := bn254.NewDecoder(reader) + for _, v := range toEncode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + phase1.Hash = make([]byte, 32) + nBytes, err := reader.Read(phase1.Hash) + return dec.BytesRead() + int64(nBytes), err +} + +// WriteTo implements io.WriterTo +func (c *Phase2) WriteTo(writer io.Writer) (int64, error) { + enc := bn254.NewEncoder(writer) + toEncode := []interface{}{ + &c.PublicKey.SG, + &c.PublicKey.SXG, + &c.PublicKey.XR, + &c.Parameters.G1.Delta, + c.Parameters.G1.L, + c.Parameters.G1.Z, + &c.Parameters.G2.Delta, + } + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + + n, err := writer.Write(c.Hash) + return int64(n), err + +} + +// ReadFrom implements io.ReaderFrom +func (c *Phase2) ReadFrom(reader io.Reader) (int64, error) { + dec := bn254.NewDecoder(reader) + toEncode := []interface{}{ + &c.PublicKey.SG, + &c.PublicKey.SXG, + &c.PublicKey.XR, + &c.Parameters.G1.Delta, + &c.Parameters.G1.L, + &c.Parameters.G1.Z, + &c.Parameters.G2.Delta, + } + + for _, v := range toEncode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + + c.Hash = make([]byte, 32) + n, err := reader.Read(c.Hash) + return int64(n), err + +} + +// WriteTo implements io.WriterTo +func (c *Phase2Evaluations) WriteTo(writer io.Writer) (int64, error) { + enc := bn254.NewEncoder(writer) + toEncode := []interface{}{ + c.G1.A, + c.G1.B, + c.G2.B, + } + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + + return enc.BytesWritten(), nil +} + +// ReadFrom implements io.ReaderFrom +func (c *Phase2Evaluations) ReadFrom(reader io.Reader) (int64, error) { + dec := bn254.NewDecoder(reader) + toEncode := []interface{}{ + &c.G1.A, + &c.G1.B, + &c.G2.B, + } + + for _, v := range toEncode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + + return dec.BytesRead(), nil +} diff --git a/backend/groth16/setup/marshal_test.go b/backend/groth16/setup/marshal_test.go new file mode 100644 index 0000000000..3af7002f0e --- /dev/null +++ b/backend/groth16/setup/marshal_test.go @@ -0,0 +1,38 @@ +package setup + +import ( + "bytes" + "io" + "reflect" + "testing" +) + +func TestPhase1Serialization(t *testing.T) { + var phase1, reconstructed Phase1 + phase1 = NewPhase1(8) + + roundTripCheck(t, &phase1, &reconstructed) +} + +func roundTripCheck(t *testing.T, from io.WriterTo, reconstructed io.ReaderFrom) { + t.Helper() + + var buf bytes.Buffer + written, err := from.WriteTo(&buf) + if err != nil { + t.Fatal("couldn't serialize", err) + } + + read, err := reconstructed.ReadFrom(&buf) + if err != nil { + t.Fatal("couldn't deserialize", err) + } + + if !reflect.DeepEqual(from, reconstructed) { + t.Fatal("reconstructed object don't match original") + } + + if written != read { + t.Fatal("bytes written / read don't match") + } +} diff --git a/backend/groth16/setup/phase1.go b/backend/groth16/setup/phase1.go new file mode 100644 index 0000000000..56d6a9e186 --- /dev/null +++ b/backend/groth16/setup/phase1.go @@ -0,0 +1,188 @@ +package setup + +import ( + "crypto/sha256" + "errors" + "math" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark/backend/groth16/setup/utils" +) + +// Phase1 represents the Phase1 of the MPC described in +// https://eprint.iacr.org/2017/1050.pdf +// +// Also known as "Powers of Tau" +type Phase1 struct { + Parameters struct { + G1 struct { + Tau []bn254.G1Affine // {[τ⁰]₁, [τ¹]₁, [τ²]₁, …, [τ²ⁿ⁻²]₁} + AlphaTau []bn254.G1Affine // {α[τ⁰]₁, α[τ¹]₁, α[τ²]₁, …, α[τⁿ⁻¹]₁} + BetaTau []bn254.G1Affine // {β[τ⁰]₁, β[τ¹]₁, β[τ²]₁, …, β[τⁿ⁻¹]₁} + } + G2 struct { + Tau []bn254.G2Affine // {[τ⁰]₂, [τ¹]₂, [τ²]₂, …, [τⁿ⁻¹]₂} + Beta bn254.G2Affine // [β]₂ + } + } + PublicKeys struct { + Tau, Alpha, Beta utils.PublicKey + } + Hash []byte // sha256 hash +} + +// NewPhase1 initialize phase 1 of the MPC. This is called once before any randomness contribution +// is made (see Contribute()). +func NewPhase1(power int) (phase1 Phase1) { + N := int(math.Pow(2, float64(power))) + + // Generate key pairs + var tau, alpha, beta fr.Element + tau.SetOne() + alpha.SetOne() + beta.SetOne() + phase1.PublicKeys.Tau = utils.GenPublicKey(tau, nil, 1) + phase1.PublicKeys.Alpha = utils.GenPublicKey(alpha, nil, 2) + phase1.PublicKeys.Beta = utils.GenPublicKey(beta, nil, 3) + + // First contribution use generators + _, _, g1, g2 := bn254.Generators() + phase1.Parameters.G2.Beta.Set(&g2) + phase1.Parameters.G1.Tau = make([]bn254.G1Affine, 2*N-1) + phase1.Parameters.G2.Tau = make([]bn254.G2Affine, N) + phase1.Parameters.G1.AlphaTau = make([]bn254.G1Affine, N) + phase1.Parameters.G1.BetaTau = make([]bn254.G1Affine, N) + for i := 0; i < len(phase1.Parameters.G1.Tau); i++ { + phase1.Parameters.G1.Tau[i].Set(&g1) + } + for i := 0; i < len(phase1.Parameters.G2.Tau); i++ { + phase1.Parameters.G2.Tau[i].Set(&g2) + phase1.Parameters.G1.AlphaTau[i].Set(&g1) + phase1.Parameters.G1.BetaTau[i].Set(&g1) + } + + phase1.Parameters.G2.Beta.Set(&g2) + + // Compute hash of Contribution + phase1.Hash = phase1.hash() + + return +} + +// Contribute contributes randomness to the phase1 object. This mutates phase1. +func (phase1 *Phase1) Contribute() { + N := len(phase1.Parameters.G2.Tau) + + // Generate key pairs + var tau, alpha, beta fr.Element + tau.SetRandom() + alpha.SetRandom() + beta.SetRandom() + phase1.PublicKeys.Tau = utils.GenPublicKey(tau, phase1.Hash[:], 1) + phase1.PublicKeys.Alpha = utils.GenPublicKey(alpha, phase1.Hash[:], 2) + phase1.PublicKeys.Beta = utils.GenPublicKey(beta, phase1.Hash[:], 3) + + // Compute powers of τ, ατ, and βτ + taus := utils.Powers(tau, 2*N-1) + alphaTau := make([]fr.Element, N) + betaTau := make([]fr.Element, N) + for i := 0; i < N; i++ { + alphaTau[i].Mul(&taus[i], &alpha) + betaTau[i].Mul(&taus[i], &beta) + } + + // Update using previous parameters + phase1.Parameters.G1.Tau = utils.ScaleG1(phase1.Parameters.G1.Tau, taus) + phase1.Parameters.G2.Tau = utils.ScaleG2(phase1.Parameters.G2.Tau, taus[0:N]) + phase1.Parameters.G1.AlphaTau = utils.ScaleG1(phase1.Parameters.G1.AlphaTau, alphaTau) + phase1.Parameters.G1.BetaTau = utils.ScaleG1(phase1.Parameters.G1.BetaTau, betaTau) + var betaBI big.Int + beta.BigInt(&betaBI) + phase1.Parameters.G2.Beta.ScalarMultiplication(&phase1.Parameters.G2.Beta, &betaBI) + + // Compute hash of Contribution + phase1.Hash = phase1.hash() +} + +func VerifyPhase1(c0, c1 *Phase1, c ...*Phase1) error { + contribs := append([]*Phase1{c0, c1}, c...) + for i := 0; i < len(contribs)-1; i++ { + if err := verifyPhase1(contribs[i], contribs[i+1]); err != nil { + return err + } + } + return nil +} + +// verifyPhase1 checks that a contribution is based on a known previous Phase1 state. +func verifyPhase1(current, contribution *Phase1) error { + // Compute R for τ, α, β + tauR := utils.GenR(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, current.Hash[:], 1) + alphaR := utils.GenR(contribution.PublicKeys.Alpha.SG, contribution.PublicKeys.Alpha.SXG, current.Hash[:], 2) + betaR := utils.GenR(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, current.Hash[:], 3) + + // Check for knowledge of toxic parameters + if !utils.SameRatio(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, contribution.PublicKeys.Tau.XR, tauR) { + return errors.New("couldn't verify public key of τ") + } + if !utils.SameRatio(contribution.PublicKeys.Alpha.SG, contribution.PublicKeys.Alpha.SXG, contribution.PublicKeys.Alpha.XR, alphaR) { + return errors.New("couldn't verify public key of α") + } + if !utils.SameRatio(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, contribution.PublicKeys.Beta.XR, betaR) { + return errors.New("couldn't verify public key of β") + } + + // Check for valid updates using previous parameters + if !utils.SameRatio(contribution.Parameters.G1.Tau[1], current.Parameters.G1.Tau[1], tauR, contribution.PublicKeys.Tau.XR) { + return errors.New("couldn't verify that [τ]₁ is based on previous contribution") + } + if !utils.SameRatio(contribution.Parameters.G1.AlphaTau[0], current.Parameters.G1.AlphaTau[0], alphaR, contribution.PublicKeys.Alpha.XR) { + return errors.New("couldn't verify that [α]₁ is based on previous contribution") + } + if !utils.SameRatio(contribution.Parameters.G1.BetaTau[0], current.Parameters.G1.BetaTau[0], betaR, contribution.PublicKeys.Beta.XR) { + return errors.New("couldn't verify that [β]₁ is based on previous contribution") + } + if !utils.SameRatio(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, contribution.Parameters.G2.Tau[1], current.Parameters.G2.Tau[1]) { + return errors.New("couldn't verify that [τ]₂ is based on previous contribution") + } + if !utils.SameRatio(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, contribution.Parameters.G2.Beta, current.Parameters.G2.Beta) { + return errors.New("couldn't verify that [β]₂ is based on previous contribution") + } + + // Check for valid updates using powers of τ + _, _, g1, g2 := bn254.Generators() + tauL1, tauL2 := utils.LinearCombinationG1(contribution.Parameters.G1.Tau) + if !utils.SameRatio(tauL1, tauL2, contribution.Parameters.G2.Tau[1], g2) { + return errors.New("couldn't verify valid powers of τ in G₁") + } + alphaL1, alphaL2 := utils.LinearCombinationG1(contribution.Parameters.G1.AlphaTau) + if !utils.SameRatio(alphaL1, alphaL2, contribution.Parameters.G2.Tau[1], g2) { + return errors.New("couldn't verify valid powers of α(τ) in G₁") + } + betaL1, betaL2 := utils.LinearCombinationG1(contribution.Parameters.G1.BetaTau) + if !utils.SameRatio(betaL1, betaL2, contribution.Parameters.G2.Tau[1], g2) { + return errors.New("couldn't verify valid powers of α(τ) in G₁") + } + tau2L1, tau2L2 := utils.LinearCombinationG2(contribution.Parameters.G2.Tau) + if !utils.SameRatio(contribution.Parameters.G1.Tau[1], g1, tau2L1, tau2L2) { + return errors.New("couldn't verify valid powers of τ in G₂") + } + + // Check hash of the contribution + h := contribution.hash() + for i := 0; i < len(h); i++ { + if h[i] != contribution.Hash[i] { + return errors.New("couldn't verify hash of contribution") + } + } + + return nil +} + +func (phase1 *Phase1) hash() []byte { + sha := sha256.New() + phase1.writeTo(sha) + return sha.Sum(nil) +} diff --git a/backend/groth16/setup/phase1/contribution.go b/backend/groth16/setup/phase1/contribution.go deleted file mode 100644 index aec82a8352..0000000000 --- a/backend/groth16/setup/phase1/contribution.go +++ /dev/null @@ -1,125 +0,0 @@ -package phase1 - -import ( - "crypto/sha256" - "math" - "math/big" - - "github.com/consensys/gnark/backend/groth16/setup/utils" - "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark-crypto/ecc/bn254/fr" -) - -type Contribution struct { - Parameters struct { - G1 struct { - Tau []bn254.G1Affine // {[τ⁰]₁, [τ¹]₁, [τ²]₁, …, [τ²ⁿ⁻²]₁} - AlphaTau []bn254.G1Affine // {α[τ⁰]₁, α[τ¹]₁, α[τ²]₁, …, α[τⁿ⁻¹]₁} - BetaTau []bn254.G1Affine // {β[τ⁰]₁, β[τ¹]₁, β[τ²]₁, …, β[τⁿ⁻¹]₁} - } - G2 struct { - Tau []bn254.G2Affine // {[τ⁰]₂, [τ¹]₂, [τ²]₂, …, [τⁿ⁻¹]₂} - Beta bn254.G2Affine // [β]₂ - } - } - PublicKeys struct { - Tau, Alpha, Beta utils.PublicKey - } - Hash []byte // sha256 hash -} - -func (c *Contribution) Initialize(power int) { - N := int(math.Pow(2, float64(power))) - - // Generate key pairs - var tau, alpha, beta fr.Element - tau.SetOne() - alpha.SetOne() - beta.SetOne() - c.PublicKeys.Tau = utils.GenPublicKey(tau, nil, 1) - c.PublicKeys.Alpha = utils.GenPublicKey(alpha, nil, 2) - c.PublicKeys.Beta = utils.GenPublicKey(beta, nil, 3) - - // First contribution use generators - _, _, g1, g2 := bn254.Generators() - c.Parameters.G2.Beta.Set(&g2) - c.Parameters.G1.Tau = make([]bn254.G1Affine, 2*N-1) - c.Parameters.G2.Tau = make([]bn254.G2Affine, N) - c.Parameters.G1.AlphaTau = make([]bn254.G1Affine, N) - c.Parameters.G1.BetaTau = make([]bn254.G1Affine, N) - for i := 0; i < len(c.Parameters.G1.Tau); i++ { - c.Parameters.G1.Tau[i].Set(&g1) - } - for i := 0; i < len(c.Parameters.G2.Tau); i++ { - c.Parameters.G2.Tau[i].Set(&g2) - c.Parameters.G1.AlphaTau[i].Set(&g1) - c.Parameters.G1.BetaTau[i].Set(&g1) - } - - c.Parameters.G2.Beta.Set(&g2) - - // Compute hash of Contribution - c.Hash = HashContribution(c) -} - -func (c *Contribution) Contribute(prev *Contribution) { - N := len(prev.Parameters.G2.Tau) - - // Generate key pairs - var tau, alpha, beta fr.Element - tau.SetRandom() - alpha.SetRandom() - beta.SetRandom() - c.PublicKeys.Tau = utils.GenPublicKey(tau, prev.Hash[:], 1) - c.PublicKeys.Alpha = utils.GenPublicKey(alpha, prev.Hash[:], 2) - c.PublicKeys.Beta = utils.GenPublicKey(beta, prev.Hash[:], 3) - - // Compute powers of τ, ατ, and βτ - taus := utils.Powers(tau, 2*N-1) - alphaTau := make([]fr.Element, N) - betaTau := make([]fr.Element, N) - for i := 0; i < N; i++ { - alphaTau[i].Mul(&taus[i], &alpha) - betaTau[i].Mul(&taus[i], &beta) - } - - // Update using previous parameters - c.Parameters.G1.Tau = utils.ScaleG1(prev.Parameters.G1.Tau, taus) - c.Parameters.G2.Tau = utils.ScaleG2(prev.Parameters.G2.Tau, taus[0:N]) - c.Parameters.G1.AlphaTau = utils.ScaleG1(prev.Parameters.G1.AlphaTau, alphaTau) - c.Parameters.G1.BetaTau = utils.ScaleG1(prev.Parameters.G1.BetaTau, betaTau) - var betaBI big.Int - beta.BigInt(&betaBI) - c.Parameters.G2.Beta.ScalarMultiplication(&prev.Parameters.G2.Beta, &betaBI) - - // Compute hash of Contribution - c.Hash = HashContribution(c) -} - -func HashContribution(c *Contribution) []byte { - sha := sha256.New() - toEncode := []interface{}{ - &c.PublicKeys.Tau.SG, - &c.PublicKeys.Tau.SXG, - &c.PublicKeys.Tau.XR, - &c.PublicKeys.Alpha.SG, - &c.PublicKeys.Alpha.SXG, - &c.PublicKeys.Alpha.XR, - &c.PublicKeys.Beta.SG, - &c.PublicKeys.Beta.SXG, - &c.PublicKeys.Beta.XR, - c.Parameters.G1.Tau, - c.Parameters.G1.AlphaTau, - c.Parameters.G1.BetaTau, - c.Parameters.G2.Tau, - &c.Parameters.G2.Beta, - } - - enc := bn254.NewEncoder(sha) - for _, v := range toEncode { - if err := enc.Encode(v); err != nil { - panic(err) - } - } - return sha.Sum(nil) -} diff --git a/backend/groth16/setup/phase1/marshal.go b/backend/groth16/setup/phase1/marshal.go deleted file mode 100644 index 23557a2379..0000000000 --- a/backend/groth16/setup/phase1/marshal.go +++ /dev/null @@ -1,64 +0,0 @@ -package phase1 - -import ( - "io" - - "github.com/consensys/gnark-crypto/ecc/bn254" -) - -func (c *Contribution) WriteTo(writer io.Writer) (int64, error) { - toEncode := []interface{}{ - &c.PublicKeys.Tau.SG, - &c.PublicKeys.Tau.SXG, - &c.PublicKeys.Tau.XR, - &c.PublicKeys.Alpha.SG, - &c.PublicKeys.Alpha.SXG, - &c.PublicKeys.Alpha.XR, - &c.PublicKeys.Beta.SG, - &c.PublicKeys.Beta.SXG, - &c.PublicKeys.Beta.XR, - c.Parameters.G1.Tau, - c.Parameters.G1.AlphaTau, - c.Parameters.G1.BetaTau, - c.Parameters.G2.Tau, - &c.Parameters.G2.Beta, - } - - enc := bn254.NewEncoder(writer) - for _, v := range toEncode { - if err := enc.Encode(v); err != nil { - return enc.BytesWritten(), err - } - } - nBytes, err := writer.Write(c.Hash) - return int64(nBytes), err -} - -func (c *Contribution) ReadFrom(reader io.Reader) (int64, error) { - toEncode := []interface{}{ - &c.PublicKeys.Tau.SG, - &c.PublicKeys.Tau.SXG, - &c.PublicKeys.Tau.XR, - &c.PublicKeys.Alpha.SG, - &c.PublicKeys.Alpha.SXG, - &c.PublicKeys.Alpha.XR, - &c.PublicKeys.Beta.SG, - &c.PublicKeys.Beta.SXG, - &c.PublicKeys.Beta.XR, - &c.Parameters.G1.Tau, - &c.Parameters.G1.AlphaTau, - &c.Parameters.G1.BetaTau, - &c.Parameters.G2.Tau, - &c.Parameters.G2.Beta, - } - - dec := bn254.NewDecoder(reader) - for _, v := range toEncode { - if err := dec.Decode(v); err != nil { - return dec.BytesRead(), err - } - } - c.Hash = make([]byte, 32) - nBytes, err := reader.Read(c.Hash) - return int64(nBytes), err -} diff --git a/backend/groth16/setup/phase1/verifier.go b/backend/groth16/setup/phase1/verifier.go deleted file mode 100644 index 08e4d504be..0000000000 --- a/backend/groth16/setup/phase1/verifier.go +++ /dev/null @@ -1,72 +0,0 @@ -package phase1 - -import ( - "errors" - - "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark/backend/groth16/setup/utils" -) - -func (c *Contribution) Verify(prev *Contribution) error { - // Compute R for τ, α, β - tauR := utils.GenR(c.PublicKeys.Tau.SG, c.PublicKeys.Tau.SXG, prev.Hash[:], 1) - alphaR := utils.GenR(c.PublicKeys.Alpha.SG, c.PublicKeys.Alpha.SXG, prev.Hash[:], 2) - betaR := utils.GenR(c.PublicKeys.Beta.SG, c.PublicKeys.Beta.SXG, prev.Hash[:], 3) - - // Check for knowledge of toxic parameters - if !utils.SameRatio(c.PublicKeys.Tau.SG, c.PublicKeys.Tau.SXG, c.PublicKeys.Tau.XR, tauR) { - return errors.New("couldn't verify public key of τ") - } - if !utils.SameRatio(c.PublicKeys.Alpha.SG, c.PublicKeys.Alpha.SXG, c.PublicKeys.Alpha.XR, alphaR) { - return errors.New("couldn't verify public key of α") - } - if !utils.SameRatio(c.PublicKeys.Beta.SG, c.PublicKeys.Beta.SXG, c.PublicKeys.Beta.XR, betaR) { - return errors.New("couldn't verify public key of β") - } - - // Check for valid updates using previous parameters - if !utils.SameRatio(c.Parameters.G1.Tau[1], prev.Parameters.G1.Tau[1], tauR, c.PublicKeys.Tau.XR) { - return errors.New("couldn't verify that [τ]₁ is based on previous contribution") - } - if !utils.SameRatio(c.Parameters.G1.AlphaTau[0], prev.Parameters.G1.AlphaTau[0], alphaR, c.PublicKeys.Alpha.XR) { - return errors.New("couldn't verify that [α]₁ is based on previous contribution") - } - if !utils.SameRatio(c.Parameters.G1.BetaTau[0], prev.Parameters.G1.BetaTau[0], betaR, c.PublicKeys.Beta.XR) { - return errors.New("couldn't verify that [β]₁ is based on previous contribution") - } - if !utils.SameRatio(c.PublicKeys.Tau.SG, c.PublicKeys.Tau.SXG, c.Parameters.G2.Tau[1], prev.Parameters.G2.Tau[1]) { - return errors.New("couldn't verify that [τ]₂ is based on previous contribution") - } - if !utils.SameRatio(c.PublicKeys.Beta.SG, c.PublicKeys.Beta.SXG, c.Parameters.G2.Beta, prev.Parameters.G2.Beta) { - return errors.New("couldn't verify that [β]₂ is based on previous contribution") - } - - // Check for valid updates using powers of τ - _, _, g1, g2 := bn254.Generators() - tauL1, tauL2 := utils.LinearCombinationG1(c.Parameters.G1.Tau) - if !utils.SameRatio(tauL1, tauL2, c.Parameters.G2.Tau[1], g2) { - return errors.New("couldn't verify valid powers of τ in G₁") - } - alphaL1, alphaL2 := utils.LinearCombinationG1(c.Parameters.G1.AlphaTau) - if !utils.SameRatio(alphaL1, alphaL2, c.Parameters.G2.Tau[1], g2) { - return errors.New("couldn't verify valid powers of α(τ) in G₁") - } - betaL1, betaL2 := utils.LinearCombinationG1(c.Parameters.G1.BetaTau) - if !utils.SameRatio(betaL1, betaL2, c.Parameters.G2.Tau[1], g2) { - return errors.New("couldn't verify valid powers of α(τ) in G₁") - } - tau2L1, tau2L2 := utils.LinearCombinationG2(c.Parameters.G2.Tau) - if !utils.SameRatio(c.Parameters.G1.Tau[1], g1, tau2L1, tau2L2) { - return errors.New("couldn't verify valid powers of τ in G₂") - } - - // Check hash of the contribution - h := HashContribution(c) - for i := 0; i < len(h); i++ { - if h[i] != c.Hash[i] { - return errors.New("couldn't verify hash of contribution") - } - } - - return nil -} diff --git a/backend/groth16/setup/phase2/contribution.go b/backend/groth16/setup/phase2.go similarity index 63% rename from backend/groth16/setup/phase2/contribution.go rename to backend/groth16/setup/phase2.go index 9bd43b5108..16defcf143 100644 --- a/backend/groth16/setup/phase2/contribution.go +++ b/backend/groth16/setup/phase2.go @@ -1,18 +1,18 @@ -package phase2 +package setup import ( "crypto/sha256" + "errors" "math/big" "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr" - "github.com/consensys/gnark/backend/groth16/setup/phase1" utils "github.com/consensys/gnark/backend/groth16/setup/utils" "github.com/consensys/gnark/constraint" cs_bn254 "github.com/consensys/gnark/constraint/bn254" ) -type Evaluations struct { +type Phase2Evaluations struct { G1 struct { A, B, VKK []bn254.G1Affine } @@ -21,7 +21,7 @@ type Evaluations struct { } } -type Contribution struct { +type Phase2 struct { Parameters struct { G1 struct { Delta bn254.G1Affine @@ -35,13 +35,15 @@ type Contribution struct { Hash []byte } -func (c2 *Contribution) PreparePhase2(c1 *phase1.Contribution, r1cs *cs_bn254.R1CS) Evaluations { - srs := c1.Parameters +func NewPhase2(r1cs *cs_bn254.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { + srs := srs1.Parameters size := len(srs.G1.AlphaTau) if size < r1cs.GetNbConstraints() { panic("Number of constraints is larger than expected") } + c2 := Phase2{} + accumulateG1 := func(res *bn254.G1Affine, t constraint.Term, value *bn254.G1Affine) { cID := t.CoeffID() switch cID { @@ -90,7 +92,7 @@ func (c2 *Contribution) PreparePhase2(c1 *phase1.Contribution, r1cs *cs_bn254.R1 internal, secret, public := r1cs.GetNbVariables() nWires := internal + secret + public - var evals Evaluations + var evals Phase2Evaluations evals.G1.A = make([]bn254.G1Affine, nWires) evals.G1.B = make([]bn254.G1Affine, nWires) evals.G2.B = make([]bn254.G2Affine, nWires) @@ -151,11 +153,11 @@ func (c2 *Contribution) PreparePhase2(c1 *phase1.Contribution, r1cs *cs_bn254.R1 c2.PublicKey = utils.GenPublicKey(delta, nil, 1) // Hash initial contribution - c2.Hash = HashContribution(c2) - return evals + c2.Hash = c2.hash() + return c2, evals } -func (c *Contribution) Contribute(prev *Contribution) { +func (c *Phase2) Contribute() { // Sample toxic δ var delta, deltaInv fr.Element var deltaBI, deltaInvBI big.Int @@ -166,29 +168,75 @@ func (c *Contribution) Contribute(prev *Contribution) { deltaInv.BigInt(&deltaInvBI) // Set δ public key - c.PublicKey = utils.GenPublicKey(delta, prev.Hash, 1) + c.PublicKey = utils.GenPublicKey(delta, c.Hash, 1) // Update δ - c.Parameters.G1.Delta.ScalarMultiplication(&prev.Parameters.G1.Delta, &deltaBI) - c.Parameters.G2.Delta.ScalarMultiplication(&prev.Parameters.G2.Delta, &deltaBI) + c.Parameters.G1.Delta.ScalarMultiplication(&c.Parameters.G1.Delta, &deltaBI) + c.Parameters.G2.Delta.ScalarMultiplication(&c.Parameters.G2.Delta, &deltaBI) // Update Z using δ⁻¹ - c.Parameters.G1.Z = make([]bn254.G1Affine, len(prev.Parameters.G1.Z)) - for i := 0; i < len(prev.Parameters.G1.Z); i++ { - c.Parameters.G1.Z[i].ScalarMultiplication(&prev.Parameters.G1.Z[i], &deltaInvBI) + for i := 0; i < len(c.Parameters.G1.Z); i++ { + c.Parameters.G1.Z[i].ScalarMultiplication(&c.Parameters.G1.Z[i], &deltaInvBI) } // Update L using δ⁻¹ - c.Parameters.G1.L = make([]bn254.G1Affine, len(prev.Parameters.G1.L)) - for i := 0; i < len(prev.Parameters.G1.L); i++ { - c.Parameters.G1.L[i].ScalarMultiplication(&prev.Parameters.G1.L[i], &deltaInvBI) + for i := 0; i < len(c.Parameters.G1.L); i++ { + c.Parameters.G1.L[i].ScalarMultiplication(&c.Parameters.G1.L[i], &deltaInvBI) } // 4. Hash contribution - c.Hash = HashContribution(c) + c.Hash = c.hash() +} + +func VerifyPhase2(c0, c1 *Phase2, c ...*Phase2) error { + contribs := append([]*Phase2{c0, c1}, c...) + for i := 0; i < len(contribs)-1; i++ { + if err := verifyPhase2(contribs[i], contribs[i+1]); err != nil { + return err + } + } + return nil +} + +func verifyPhase2(current, contribution *Phase2) error { + // Compute R for δ + deltaR := utils.GenR(contribution.PublicKey.SG, contribution.PublicKey.SXG, current.Hash[:], 1) + + // Check for knowledge of δ + if !utils.SameRatio(contribution.PublicKey.SG, contribution.PublicKey.SXG, contribution.PublicKey.XR, deltaR) { + return errors.New("couldn't verify knowledge of δ") + } + + // Check for valid updates using previous parameters + if !utils.SameRatio(contribution.Parameters.G1.Delta, current.Parameters.G1.Delta, deltaR, contribution.PublicKey.XR) { + return errors.New("couldn't verify that [δ]₁ is based on previous contribution") + } + if !utils.SameRatio(contribution.PublicKey.SG, contribution.PublicKey.SXG, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { + return errors.New("couldn't verify that [δ]₂ is based on previous contribution") + } + + // Check for valid updates of L and Z using + L, prevL := utils.Merge(contribution.Parameters.G1.L, current.Parameters.G1.L) + if !utils.SameRatio(L, prevL, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { + return errors.New("couldn't verify valid updates of L using δ⁻¹") + } + Z, prevZ := utils.Merge(contribution.Parameters.G1.Z, current.Parameters.G1.Z) + if !utils.SameRatio(Z, prevZ, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { + return errors.New("couldn't verify valid updates of L using δ⁻¹") + } + + // Check hash of the contribution + h := contribution.hash() + for i := 0; i < len(h); i++ { + if h[i] != contribution.Hash[i] { + return errors.New("couldn't verify hash of contribution") + } + } + + return nil } -func HashContribution(c *Contribution) []byte { +func (c *Phase2) hash() []byte { sha := sha256.New() // Hash contribution toEncode := []interface{}{ diff --git a/backend/groth16/setup/phase2/marshal.go b/backend/groth16/setup/phase2/marshal.go deleted file mode 100644 index 3bc6c51dfa..0000000000 --- a/backend/groth16/setup/phase2/marshal.go +++ /dev/null @@ -1,87 +0,0 @@ -package phase2 - -import ( - "io" - - "github.com/consensys/gnark-crypto/ecc/bn254" -) - -func (c *Contribution) WriteTo(writer io.Writer) (int64, error) { - enc := bn254.NewEncoder(writer) - toEncode := []interface{}{ - &c.PublicKey.SG, - &c.PublicKey.SXG, - &c.PublicKey.XR, - &c.Parameters.G1.Delta, - c.Parameters.G1.L, - c.Parameters.G1.Z, - &c.Parameters.G2.Delta, - } - - for _, v := range toEncode { - if err := enc.Encode(v); err != nil { - return enc.BytesWritten(), err - } - } - - n, err := writer.Write(c.Hash) - return int64(n), err - -} -func (c *Contribution) ReadFrom(reader io.Reader) (int64, error) { - dec := bn254.NewDecoder(reader) - toEncode := []interface{}{ - &c.PublicKey.SG, - &c.PublicKey.SXG, - &c.PublicKey.XR, - &c.Parameters.G1.Delta, - &c.Parameters.G1.L, - &c.Parameters.G1.Z, - &c.Parameters.G2.Delta, - } - - for _, v := range toEncode { - if err := dec.Decode(v); err != nil { - return dec.BytesRead(), err - } - } - - c.Hash = make([]byte, 32) - n, err := reader.Read(c.Hash) - return int64(n), err - -} - -func (c *Evaluations) WriteTo(writer io.Writer) (int64, error) { - enc := bn254.NewEncoder(writer) - toEncode := []interface{}{ - c.G1.A, - c.G1.B, - c.G2.B, - } - - for _, v := range toEncode { - if err := enc.Encode(v); err != nil { - return enc.BytesWritten(), err - } - } - - return enc.BytesWritten(), nil -} - -func (c *Evaluations) ReadFrom(reader io.Reader) (int64, error) { - dec := bn254.NewDecoder(reader) - toEncode := []interface{}{ - &c.G1.A, - &c.G1.B, - &c.G2.B, - } - - for _, v := range toEncode { - if err := dec.Decode(v); err != nil { - return dec.BytesRead(), err - } - } - - return dec.BytesRead(), nil -} diff --git a/backend/groth16/setup/phase2/verifier.go b/backend/groth16/setup/phase2/verifier.go deleted file mode 100644 index 8017ff3ef7..0000000000 --- a/backend/groth16/setup/phase2/verifier.go +++ /dev/null @@ -1,45 +0,0 @@ -package phase2 - -import ( - "errors" - - "github.com/consensys/gnark/backend/groth16/setup/utils" -) - -func (c *Contribution) Verify(prev *Contribution) error { - // Compute R for δ - deltaR := utils.GenR(c.PublicKey.SG, c.PublicKey.SXG, prev.Hash[:], 1) - - // Check for knowledge of δ - if !utils.SameRatio(c.PublicKey.SG, c.PublicKey.SXG, c.PublicKey.XR, deltaR) { - return errors.New("couldn't verify knowledge of δ") - } - - // Check for valid updates using previous parameters - if !utils.SameRatio(c.Parameters.G1.Delta, prev.Parameters.G1.Delta, deltaR, c.PublicKey.XR) { - return errors.New("couldn't verify that [δ]₁ is based on previous contribution") - } - if !utils.SameRatio(c.PublicKey.SG, c.PublicKey.SXG, c.Parameters.G2.Delta, prev.Parameters.G2.Delta) { - return errors.New("couldn't verify that [δ]₂ is based on previous contribution") - } - - // Check for valid updates of L and Z using - L, prevL := utils.Merge(c.Parameters.G1.L, prev.Parameters.G1.L) - if !utils.SameRatio(L, prevL, c.Parameters.G2.Delta, prev.Parameters.G2.Delta) { - return errors.New("couldn't verify valid updates of L using δ⁻¹") - } - Z, prevZ := utils.Merge(c.Parameters.G1.Z, prev.Parameters.G1.Z) - if !utils.SameRatio(Z, prevZ, c.Parameters.G2.Delta, prev.Parameters.G2.Delta) { - return errors.New("couldn't verify valid updates of L using δ⁻¹") - } - - // Check hash of the contribution - h := HashContribution(c) - for i := 0; i < len(h); i++ { - if h[i] != c.Hash[i] { - return errors.New("couldn't verify hash of contribution") - } - } - - return nil -} diff --git a/backend/groth16/setup/keys/keys.go b/backend/groth16/setup/setup.go similarity index 62% rename from backend/groth16/setup/keys/keys.go rename to backend/groth16/setup/setup.go index 9fc7a08892..e719bef36c 100644 --- a/backend/groth16/setup/keys/keys.go +++ b/backend/groth16/setup/setup.go @@ -1,47 +1,13 @@ -package keys +package setup import ( - "github.com/consensys/gnark/backend/groth16/setup/phase1" - "github.com/consensys/gnark/backend/groth16/setup/phase2" "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" + groth16 "github.com/consensys/gnark/backend/groth16/bn254" "github.com/consensys/gnark/backend/groth16/setup/utils" ) -type ProvingKey struct { - Domain fft.Domain - // [α]₁ , [β]₁, [δ]₁, [A(t)]₁, [B(t)]₁, [Kpk(t)]₁, [Z(t)]₁ - G1 struct { - Alpha, Beta, Delta bn254.G1Affine - A, B, Z []bn254.G1Affine - K []bn254.G1Affine // the indexes correspond to the private wires - } - - // [β]₂ , [δ]₂, [B(t)]₂ - G2 struct { - Beta, Delta bn254.G2Affine - B []bn254.G2Affine - } - - // if InfinityA[i] == true, the point G1.A[i] == infinity - InfinityA, InfinityB []bool - NbInfinityA, NbInfinityB uint64 -} - -type VerifyingKey struct { - // [α]₁, [Kvk]₁ - G1 struct { - Alpha, Beta, Delta bn254.G1Affine - K []bn254.G1Affine - } - - // [β]₂, [δ]₂, [γ]₂, - G2 struct { - Beta, Delta, Gamma bn254.G2Affine - } -} - -func ExtractKeys(srs1 *phase1.Contribution, srs2 *phase2.Contribution, evals *phase2.Evaluations, nConstraints int) (pk ProvingKey, vk VerifyingKey) { +func ExtractKeys(srs1 *Phase1, srs2 *Phase2, evals *Phase2Evaluations, nConstraints int) (pk groth16.ProvingKey, vk groth16.VerifyingKey) { _, _, _, g2 := bn254.Generators() // Initialize PK @@ -107,5 +73,10 @@ func ExtractKeys(srs1 *phase1.Contribution, srs2 *phase2.Contribution, evals *ph vk.G2.Gamma.Set(&g2) vk.G1.K = evals.G1.VKK + // sets e, -[δ]2, -[γ]2 + if err := vk.Precompute(); err != nil { + panic(err) + } + return pk, vk } diff --git a/backend/groth16/setup/setup_test.go b/backend/groth16/setup/setup_test.go new file mode 100644 index 0000000000..992df91216 --- /dev/null +++ b/backend/groth16/setup/setup_test.go @@ -0,0 +1,118 @@ +package setup + +import ( + "testing" + + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/backend/groth16" + cs_bn254 "github.com/consensys/gnark/constraint/bn254" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/std/hash/mimc" + "github.com/stretchr/testify/require" +) + +// Circuit defines a pre-image knowledge proof +// mimc(secret preImage) = public hash +type Circuit struct { + PreImage frontend.Variable + Hash frontend.Variable `gnark:",public"` +} + +// Define declares the circuit's constraints +// Hash = mimc(PreImage) +func (circuit *Circuit) Define(api frontend.API) error { + // hash function + mimc, _ := mimc.NewMiMC(api) + + // specify constraints + mimc.Write(circuit.PreImage) + api.AssertIsEqual(circuit.Hash, mimc.Sum()) + + return nil +} + +func TestSetupCircuit(t *testing.T) { + const ( + nContributionsPhase1 = 3 + nContributionsPhase2 = 3 + power = 9 + ) + + assert := require.New(t) + + srs1 := NewPhase1(power) + + // Make and verify contributions for phase1 + for i := 1; i < nContributionsPhase1; i++ { + prev := srs1.clone() + srs1.Contribute() + assert.NoError(VerifyPhase1(&prev, &srs1)) + } + + // Compile the circuit + var myCircuit Circuit + ccs, err := frontend.Compile(bn254.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) + assert.NoError(err) + + var evals Phase2Evaluations + r1cs := ccs.(*cs_bn254.R1CS) + + // Prepare for phase-2 + srs2, evals := NewPhase2(r1cs, &srs1) + + // Make and verify contributions for phase1 + for i := 1; i < nContributionsPhase2; i++ { + prev := srs2.clone() + srs2.Contribute() + assert.NoError(VerifyPhase2(&prev, &srs2)) + } + + // Extract the proving and verifying keys + pk, vk := ExtractKeys(&srs1, &srs2, &evals, ccs.GetNbConstraints()) + + // Build the witness + assignment := &Circuit{ + PreImage: "16130099170765464552823636852555369511329944820189892919423002775646948828469", + Hash: "12886436712380113721405259596386800092738845035233065858332878701083870690753", + } + witness, err := frontend.NewWitness(assignment, bn254.ID.ScalarField()) + assert.NoError(err) + + pubWitness, err := witness.Public() + assert.NoError(err) + + // groth16: ensure proof is verified + proof, err := groth16.Prove(ccs, &pk, witness) + assert.NoError(err) + + err = groth16.Verify(proof, &vk, pubWitness) + assert.NoError(err) +} + +func (phase2 *Phase2) clone() Phase2 { + r := Phase2{} + r.Parameters.G1.Delta = phase2.Parameters.G1.Delta + r.Parameters.G1.L = append(r.Parameters.G1.L, phase2.Parameters.G1.L...) + r.Parameters.G1.Z = append(r.Parameters.G1.Z, phase2.Parameters.G1.Z...) + r.Parameters.G2.Delta = phase2.Parameters.G2.Delta + r.PublicKey = phase2.PublicKey + r.Hash = append(r.Hash, phase2.Hash...) + + return r +} + +func (phase1 *Phase1) clone() Phase1 { + r := Phase1{} + r.Parameters.G1.Tau = append(r.Parameters.G1.Tau, phase1.Parameters.G1.Tau...) + r.Parameters.G1.AlphaTau = append(r.Parameters.G1.AlphaTau, phase1.Parameters.G1.AlphaTau...) + r.Parameters.G1.BetaTau = append(r.Parameters.G1.BetaTau, phase1.Parameters.G1.BetaTau...) + + r.Parameters.G2.Tau = append(r.Parameters.G2.Tau, phase1.Parameters.G2.Tau...) + r.Parameters.G2.Beta = phase1.Parameters.G2.Beta + + r.PublicKeys = phase1.PublicKeys + r.Hash = append(r.Hash, phase1.Hash...) + + return r +} diff --git a/backend/groth16/setup/test/example_test.go b/backend/groth16/setup/test/example_test.go deleted file mode 100644 index a1ad64d95c..0000000000 --- a/backend/groth16/setup/test/example_test.go +++ /dev/null @@ -1,108 +0,0 @@ -package test - -import ( - "bytes" - "testing" - - "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark/backend/groth16" - "github.com/consensys/gnark/backend/groth16/setup/keys" - "github.com/consensys/gnark/backend/groth16/setup/phase1" - "github.com/consensys/gnark/backend/groth16/setup/phase2" - cs_bn254 "github.com/consensys/gnark/constraint/bn254" - "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/std/hash/mimc" -) - -// Circuit defines a pre-image knowledge proof -// mimc(secret preImage) = public hash -type Circuit struct { - // struct tag on a variable is optional - // default uses variable name and secret visibility. - PreImage frontend.Variable - Hash frontend.Variable `gnark:",public"` -} - -// Define declares the circuit's constraints -// Hash = mimc(PreImage) -func (circuit *Circuit) Define(api frontend.API) error { - // hash function - mimc, _ := mimc.NewMiMC(api) - - // specify constraints - // mimc(preImage) == hash - mimc.Write(circuit.PreImage) - api.AssertIsEqual(circuit.Hash, mimc.Sum()) - - return nil -} - -func TestSetupCircuit(t *testing.T) { - nContributionsPhase1 := 3 - power := 9 - contributionsPhase1 := make([]phase1.Contribution, nContributionsPhase1) - contributionsPhase1[0].Initialize(power) - - // Make and verify contributions for phase1 - for i := 1; i < nContributionsPhase1; i++ { - contributionsPhase1[i].Contribute(&contributionsPhase1[i-1]) - err := contributionsPhase1[i].Verify(&contributionsPhase1[i-1]) - if err != nil { - t.Error(err) - } - } - - // Compile the circuit - var myCircuit Circuit - ccs, _ := frontend.Compile(bn254.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) - - nContributionsPhase2 := 3 - var evals phase2.Evaluations - contributionsPhase2 := make([]phase2.Contribution, nContributionsPhase2) - r1cs := ccs.(*cs_bn254.R1CS) - - // Prepare for phase-2 - evals = contributionsPhase2[0].PreparePhase2(&contributionsPhase1[nContributionsPhase1-1], r1cs) - - // Make and verify contributions for phase1 - for i := 1; i < nContributionsPhase2; i++ { - contributionsPhase2[i].Contribute(&contributionsPhase2[i-1]) - err := contributionsPhase2[i].Verify(&contributionsPhase2[i-1]) - if err != nil { - t.Error(err) - } - } - - pk, vk := keys.ExtractKeys(&contributionsPhase1[nContributionsPhase1-1], &contributionsPhase2[nContributionsPhase2-1], &evals, ccs.GetNbConstraints()) - var bufPK, bufVK bytes.Buffer - - // Write PK and VK - pk.WriteTo(&bufPK, false) - vk.WriteTo(&bufVK, false) - - // Read PK and VK - pkk := groth16.NewProvingKey(ecc.BN254) - pkk.ReadFrom(&bufPK) - vkk := groth16.NewVerifyingKey(ecc.BN254) - vkk.ReadFrom(&bufVK) - - assignment := &Circuit{ - PreImage: "16130099170765464552823636852555369511329944820189892919423002775646948828469", - Hash: "12886436712380113721405259596386800092738845035233065858332878701083870690753", - } - witness, _ := frontend.NewWitness(assignment, bn254.ID.ScalarField()) - prf, err := groth16.Prove(ccs, pkk, witness) - if err != nil { - panic(err) - } - pubWitness, err := witness.Public() - if err != nil { - panic(err) - } - err = groth16.Verify(prf, vkk, pubWitness) - if err != nil { - panic(err) - } -} diff --git a/backend/groth16/setup/test/phase1_test.go b/backend/groth16/setup/test/phase1_test.go deleted file mode 100644 index 50f03c8c84..0000000000 --- a/backend/groth16/setup/test/phase1_test.go +++ /dev/null @@ -1,45 +0,0 @@ -package test - -import ( - "github.com/consensys/gnark/backend/groth16/setup/phase1" - "bytes" - "testing" -) - -func TestContributeVerify(t *testing.T) { - // Contribute 10 times - nContributions := 10 - power := 8 - contributions := make([]phase1.Contribution, nContributions) - contributions[0].Initialize(power) - - // Make contributions - for i := 1; i < nContributions; i++ { - contributions[i].Contribute(&contributions[i-1]) - } - - // Verify contributions - for i := 1; i < nContributions; i++ { - err := contributions[i].Verify(&contributions[i-1]) - if err != nil { - t.Error(err) - } - } -} - -func TestContributionMarshal(t *testing.T) { - power := 8 - var c1, c2 phase1.Contribution - c1.Initialize(power) - var buf bytes.Buffer - if _, err := c1.WriteTo(&buf); err != nil { - t.Error(err) - } - if _, err := c2.ReadFrom(&buf); err != nil { - t.Error(err) - } - - if !bytes.Equal(phase1.HashContribution(&c1), phase1.HashContribution(&c2)) { - t.Error("failed to correctly marshal contribution") - } -} diff --git a/backend/groth16/setup/utils/lagrange.go b/backend/groth16/setup/utils/lagrange.go index a44f612aeb..0987adf609 100644 --- a/backend/groth16/setup/utils/lagrange.go +++ b/backend/groth16/setup/utils/lagrange.go @@ -196,9 +196,9 @@ func LagrangeCoeffsG1(powers []bn254.G1Affine, size int) []bn254.G1Affine { utils.Parallelize(size, func(start, end int) { for i := start; i < end; i++ { - coeffs[i].ScalarMultiplication(&coeffs[i], &invBigint) + coeffs[i].ScalarMultiplication(&coeffs[i], &invBigint) } - }) + }) return coeffs } @@ -217,8 +217,8 @@ func LagrangeCoeffsG2(powers []bn254.G2Affine, size int) []bn254.G2Affine { utils.Parallelize(size, func(start, end int) { for i := start; i < end; i++ { - coeffs[i].ScalarMultiplication(&coeffs[i], &invBigint) + coeffs[i].ScalarMultiplication(&coeffs[i], &invBigint) } - }) + }) return coeffs } diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl index 7414dab596..e29c0f451e 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl @@ -155,13 +155,9 @@ func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder) } // recompute vk.e (e(α, β)) and -[δ]2, -[γ]2 - var err error - vk.e, err = curve.Pair([]curve.G1Affine{vk.G1.Alpha}, []curve.G2Affine{vk.G2.Beta}) - if err != nil { - return dec.BytesRead(), err + if err := vk.Precompute(); err != nil { + return dec.BytesRead(), err } - vk.G2.deltaNeg.Neg(&vk.G2.Delta) - vk.G2.gammaNeg.Neg(&vk.G2.Gamma) return dec.BytesRead(), nil } diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl index d10adb10b2..ee62876564 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl @@ -266,11 +266,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pk.G2.Beta = g2PointsAff[len(B)+0] pk.G2.Delta = g2PointsAff[len(B)+1] - // sets vk: [δ]2, [γ]2, -[δ]2, -[γ]2 + // sets vk: [δ]2, [γ]2 vk.G2.Delta = g2PointsAff[len(B)+1] vk.G2.Gamma = g2PointsAff[len(B)+2] - vk.G2.deltaNeg.Neg(&vk.G2.Delta) - vk.G2.gammaNeg.Neg(&vk.G2.Gamma) // --------------------------------------------------------------------------------------------- // Pairing: vk.e @@ -281,16 +279,29 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vk.G1.Beta = pk.G1.Beta vk.G1.Delta = pk.G1.Delta - vk.e, err = curve.Pair([]curve.G1Affine{pk.G1.Alpha}, []curve.G2Affine{pk.G2.Beta}) - if err != nil { - return err + if err := vk.Precompute(); err != nil { + return err } + // set domain pk.Domain = *domain return nil } +// Precompute sets e, -[δ]2, -[γ]2 +// This is meant to be called internally during setup or deserialization. +func (vk *VerifyingKey) Precompute() error { + var err error + vk.e, err = curve.Pair([]curve.G1Affine{vk.G1.Alpha}, []curve.G2Affine{vk.G2.Beta}) + if err != nil { + return err + } + vk.G2.deltaNeg.Neg(&vk.G2.Delta) + vk.G2.gammaNeg.Neg(&vk.G2.Gamma) + return nil +} + func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr.Element, B []fr.Element, C []fr.Element) { nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() From 6d826ff8721b3518fc4f811b0c682c7c9b2683fc Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Mon, 13 Mar 2023 18:15:28 -0500 Subject: [PATCH 108/464] test: ensure phase2 serialization is tested --- backend/groth16/setup/marshal.go | 17 ++++++++++---- backend/groth16/setup/marshal_test.go | 34 +++++++++++++++++++++++---- backend/groth16/setup/phase2.go | 18 +------------- 3 files changed, 43 insertions(+), 26 deletions(-) diff --git a/backend/groth16/setup/marshal.go b/backend/groth16/setup/marshal.go index 84278a4fe8..1adb74e960 100644 --- a/backend/groth16/setup/marshal.go +++ b/backend/groth16/setup/marshal.go @@ -74,7 +74,16 @@ func (phase1 *Phase1) ReadFrom(reader io.Reader) (int64, error) { } // WriteTo implements io.WriterTo -func (c *Phase2) WriteTo(writer io.Writer) (int64, error) { +func (phase2 *Phase2) WriteTo(writer io.Writer) (int64, error) { + n, err := phase2.writeTo(writer) + if err != nil { + return n, err + } + nBytes, err := writer.Write(phase2.Hash) + return int64(nBytes) + n, err +} + +func (c *Phase2) writeTo(writer io.Writer) (int64, error) { enc := bn254.NewEncoder(writer) toEncode := []interface{}{ &c.PublicKey.SG, @@ -92,9 +101,7 @@ func (c *Phase2) WriteTo(writer io.Writer) (int64, error) { } } - n, err := writer.Write(c.Hash) - return int64(n), err - + return enc.BytesWritten(), nil } // ReadFrom implements io.ReaderFrom @@ -118,7 +125,7 @@ func (c *Phase2) ReadFrom(reader io.Reader) (int64, error) { c.Hash = make([]byte, 32) n, err := reader.Read(c.Hash) - return int64(n), err + return int64(n) + dec.BytesRead(), err } diff --git a/backend/groth16/setup/marshal_test.go b/backend/groth16/setup/marshal_test.go index 3af7002f0e..58140fe97f 100644 --- a/backend/groth16/setup/marshal_test.go +++ b/backend/groth16/setup/marshal_test.go @@ -5,13 +5,39 @@ import ( "io" "reflect" "testing" + + "github.com/consensys/gnark-crypto/ecc/bn254" + cs_bn254 "github.com/consensys/gnark/constraint/bn254" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/stretchr/testify/require" ) -func TestPhase1Serialization(t *testing.T) { - var phase1, reconstructed Phase1 - phase1 = NewPhase1(8) +func TestContributionSerialization(t *testing.T) { + assert := require.New(t) + + // Phase 1 + srs1 := NewPhase1(9) + srs1.Contribute() + { + var reconstructed Phase1 + roundTripCheck(t, &srs1, &reconstructed) + } + + var myCircuit Circuit + ccs, err := frontend.Compile(bn254.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) + assert.NoError(err) - roundTripCheck(t, &phase1, &reconstructed) + r1cs := ccs.(*cs_bn254.R1CS) + + // Phase 2 + srs2, _ := NewPhase2(r1cs, &srs1) + srs2.Contribute() + + { + var reconstructed Phase2 + roundTripCheck(t, &srs2, &reconstructed) + } } func roundTripCheck(t *testing.T, from io.WriterTo, reconstructed io.ReaderFrom) { diff --git a/backend/groth16/setup/phase2.go b/backend/groth16/setup/phase2.go index 16defcf143..a88c2f7d65 100644 --- a/backend/groth16/setup/phase2.go +++ b/backend/groth16/setup/phase2.go @@ -238,22 +238,6 @@ func verifyPhase2(current, contribution *Phase2) error { func (c *Phase2) hash() []byte { sha := sha256.New() - // Hash contribution - toEncode := []interface{}{ - &c.PublicKey.SG, - &c.PublicKey.SXG, - &c.PublicKey.XR, - &c.Parameters.G1.Delta, - c.Parameters.G1.L, - c.Parameters.G1.Z, - &c.Parameters.G2.Delta, - } - - enc := bn254.NewEncoder(sha) - for _, v := range toEncode { - if err := enc.Encode(v); err != nil { - panic(err) - } - } + c.writeTo(sha) return sha.Sum(nil) } From 790c51b94c84bba20d89ebfdd6b70c81e5d4ac54 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Mon, 13 Mar 2023 21:53:23 -0500 Subject: [PATCH 109/464] test: added reference benchmark --- backend/groth16/setup/marshal_test.go | 4 +- backend/groth16/setup/phase1.go | 6 +- backend/groth16/setup/phase2.go | 4 +- backend/groth16/setup/setup_test.go | 107 ++++++++++++++++++-------- 4 files changed, 81 insertions(+), 40 deletions(-) diff --git a/backend/groth16/setup/marshal_test.go b/backend/groth16/setup/marshal_test.go index 58140fe97f..eee6948b72 100644 --- a/backend/groth16/setup/marshal_test.go +++ b/backend/groth16/setup/marshal_test.go @@ -17,7 +17,7 @@ func TestContributionSerialization(t *testing.T) { assert := require.New(t) // Phase 1 - srs1 := NewPhase1(9) + srs1 := InitPhase1(9) srs1.Contribute() { var reconstructed Phase1 @@ -31,7 +31,7 @@ func TestContributionSerialization(t *testing.T) { r1cs := ccs.(*cs_bn254.R1CS) // Phase 2 - srs2, _ := NewPhase2(r1cs, &srs1) + srs2, _ := InitPhase2(r1cs, &srs1) srs2.Contribute() { diff --git a/backend/groth16/setup/phase1.go b/backend/groth16/setup/phase1.go index 56d6a9e186..0736d08573 100644 --- a/backend/groth16/setup/phase1.go +++ b/backend/groth16/setup/phase1.go @@ -33,9 +33,9 @@ type Phase1 struct { Hash []byte // sha256 hash } -// NewPhase1 initialize phase 1 of the MPC. This is called once before any randomness contribution -// is made (see Contribute()). -func NewPhase1(power int) (phase1 Phase1) { +// InitPhase1 initialize phase 1 of the MPC. This is called once by the coordinator before +// any randomness contribution is made (see Contribute()). +func InitPhase1(power int) (phase1 Phase1) { N := int(math.Pow(2, float64(power))) // Generate key pairs diff --git a/backend/groth16/setup/phase2.go b/backend/groth16/setup/phase2.go index a88c2f7d65..48f8309b18 100644 --- a/backend/groth16/setup/phase2.go +++ b/backend/groth16/setup/phase2.go @@ -9,7 +9,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr" utils "github.com/consensys/gnark/backend/groth16/setup/utils" "github.com/consensys/gnark/constraint" - cs_bn254 "github.com/consensys/gnark/constraint/bn254" + cs "github.com/consensys/gnark/constraint/bn254" ) type Phase2Evaluations struct { @@ -35,7 +35,7 @@ type Phase2 struct { Hash []byte } -func NewPhase2(r1cs *cs_bn254.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { +func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { srs := srs1.Parameters size := len(srs.G1.AlphaTau) if size < r1cs.GetNbConstraints() { diff --git a/backend/groth16/setup/setup_test.go b/backend/groth16/setup/setup_test.go index 992df91216..93786b0d14 100644 --- a/backend/groth16/setup/setup_test.go +++ b/backend/groth16/setup/setup_test.go @@ -5,33 +5,13 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark/backend/groth16" - cs_bn254 "github.com/consensys/gnark/constraint/bn254" + cs "github.com/consensys/gnark/constraint/bn254" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/consensys/gnark/std/hash/mimc" "github.com/stretchr/testify/require" ) -// Circuit defines a pre-image knowledge proof -// mimc(secret preImage) = public hash -type Circuit struct { - PreImage frontend.Variable - Hash frontend.Variable `gnark:",public"` -} - -// Define declares the circuit's constraints -// Hash = mimc(PreImage) -func (circuit *Circuit) Define(api frontend.API) error { - // hash function - mimc, _ := mimc.NewMiMC(api) - - // specify constraints - mimc.Write(circuit.PreImage) - api.AssertIsEqual(circuit.Hash, mimc.Sum()) - - return nil -} - func TestSetupCircuit(t *testing.T) { const ( nContributionsPhase1 = 3 @@ -41,7 +21,7 @@ func TestSetupCircuit(t *testing.T) { assert := require.New(t) - srs1 := NewPhase1(power) + srs1 := InitPhase1(power) // Make and verify contributions for phase1 for i := 1; i < nContributionsPhase1; i++ { @@ -56,10 +36,10 @@ func TestSetupCircuit(t *testing.T) { assert.NoError(err) var evals Phase2Evaluations - r1cs := ccs.(*cs_bn254.R1CS) + r1cs := ccs.(*cs.R1CS) // Prepare for phase-2 - srs2, evals := NewPhase2(r1cs, &srs1) + srs2, evals := InitPhase2(r1cs, &srs1) // Make and verify contributions for phase1 for i := 1; i < nContributionsPhase2; i++ { @@ -90,16 +70,65 @@ func TestSetupCircuit(t *testing.T) { assert.NoError(err) } -func (phase2 *Phase2) clone() Phase2 { - r := Phase2{} - r.Parameters.G1.Delta = phase2.Parameters.G1.Delta - r.Parameters.G1.L = append(r.Parameters.G1.L, phase2.Parameters.G1.L...) - r.Parameters.G1.Z = append(r.Parameters.G1.Z, phase2.Parameters.G1.Z...) - r.Parameters.G2.Delta = phase2.Parameters.G2.Delta - r.PublicKey = phase2.PublicKey - r.Hash = append(r.Hash, phase2.Hash...) +func BenchmarkPhase1Contribution(b *testing.B) { + const power = 16 + srs1 := InitPhase1(power) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + srs1.Contribute() + } + +} + +func BenchmarkPhase2Contribution(b *testing.B) { + const power = 16 + srs1 := InitPhase1(power) + srs1.Contribute() + + var myCircuit Circuit + ccs, err := frontend.Compile(bn254.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) + if err != nil { + b.Fatal(err) + } + + r1cs := ccs.(*cs.R1CS) + + b.Run("init", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, _ = InitPhase2(r1cs, &srs1) + } + }) + + b.Run("contrib", func(b *testing.B) { + srs2, _ := InitPhase2(r1cs, &srs1) + b.ResetTimer() + for i := 0; i < b.N; i++ { + srs2.Contribute() + } + }) - return r +} + +// Circuit defines a pre-image knowledge proof +// mimc(secret preImage) = public hash +type Circuit struct { + PreImage frontend.Variable + Hash frontend.Variable `gnark:",public"` +} + +// Define declares the circuit's constraints +// Hash = mimc(PreImage) +func (circuit *Circuit) Define(api frontend.API) error { + // hash function + mimc, _ := mimc.NewMiMC(api) + + // specify constraints + mimc.Write(circuit.PreImage) + api.AssertIsEqual(circuit.Hash, mimc.Sum()) + + return nil } func (phase1 *Phase1) clone() Phase1 { @@ -116,3 +145,15 @@ func (phase1 *Phase1) clone() Phase1 { return r } + +func (phase2 *Phase2) clone() Phase2 { + r := Phase2{} + r.Parameters.G1.Delta = phase2.Parameters.G1.Delta + r.Parameters.G1.L = append(r.Parameters.G1.L, phase2.Parameters.G1.L...) + r.Parameters.G1.Z = append(r.Parameters.G1.Z, phase2.Parameters.G1.Z...) + r.Parameters.G2.Delta = phase2.Parameters.G2.Delta + r.PublicKey = phase2.PublicKey + r.Hash = append(r.Hash, phase2.Hash...) + + return r +} From c7c718a56da2bd2a43ec51f0ae54732224deeb39 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Mon, 13 Mar 2023 21:54:25 -0500 Subject: [PATCH 110/464] refactor: setup -> mpcsetup --- backend/groth16/{setup => mpcsetup}/marshal.go | 2 +- backend/groth16/{setup => mpcsetup}/marshal_test.go | 2 +- backend/groth16/{setup => mpcsetup}/phase1.go | 4 ++-- backend/groth16/{setup => mpcsetup}/phase2.go | 4 ++-- backend/groth16/{setup => mpcsetup}/setup.go | 4 ++-- backend/groth16/{setup => mpcsetup}/setup_test.go | 2 +- backend/groth16/{setup => mpcsetup}/utils/lagrange.go | 0 backend/groth16/{setup => mpcsetup}/utils/utils.go | 0 8 files changed, 9 insertions(+), 9 deletions(-) rename backend/groth16/{setup => mpcsetup}/marshal.go (99%) rename backend/groth16/{setup => mpcsetup}/marshal_test.go (98%) rename backend/groth16/{setup => mpcsetup}/phase1.go (98%) rename backend/groth16/{setup => mpcsetup}/phase2.go (98%) rename backend/groth16/{setup => mpcsetup}/setup.go (96%) rename backend/groth16/{setup => mpcsetup}/setup_test.go (99%) rename backend/groth16/{setup => mpcsetup}/utils/lagrange.go (100%) rename backend/groth16/{setup => mpcsetup}/utils/utils.go (100%) diff --git a/backend/groth16/setup/marshal.go b/backend/groth16/mpcsetup/marshal.go similarity index 99% rename from backend/groth16/setup/marshal.go rename to backend/groth16/mpcsetup/marshal.go index 1adb74e960..f0545585b9 100644 --- a/backend/groth16/setup/marshal.go +++ b/backend/groth16/mpcsetup/marshal.go @@ -1,4 +1,4 @@ -package setup +package mpcsetup import ( "io" diff --git a/backend/groth16/setup/marshal_test.go b/backend/groth16/mpcsetup/marshal_test.go similarity index 98% rename from backend/groth16/setup/marshal_test.go rename to backend/groth16/mpcsetup/marshal_test.go index eee6948b72..9bb13c2e5d 100644 --- a/backend/groth16/setup/marshal_test.go +++ b/backend/groth16/mpcsetup/marshal_test.go @@ -1,4 +1,4 @@ -package setup +package mpcsetup import ( "bytes" diff --git a/backend/groth16/setup/phase1.go b/backend/groth16/mpcsetup/phase1.go similarity index 98% rename from backend/groth16/setup/phase1.go rename to backend/groth16/mpcsetup/phase1.go index 0736d08573..d0ee9ba2da 100644 --- a/backend/groth16/setup/phase1.go +++ b/backend/groth16/mpcsetup/phase1.go @@ -1,4 +1,4 @@ -package setup +package mpcsetup import ( "crypto/sha256" @@ -8,7 +8,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr" - "github.com/consensys/gnark/backend/groth16/setup/utils" + "github.com/consensys/gnark/backend/groth16/mpcsetup/utils" ) // Phase1 represents the Phase1 of the MPC described in diff --git a/backend/groth16/setup/phase2.go b/backend/groth16/mpcsetup/phase2.go similarity index 98% rename from backend/groth16/setup/phase2.go rename to backend/groth16/mpcsetup/phase2.go index 48f8309b18..0905ae00f9 100644 --- a/backend/groth16/setup/phase2.go +++ b/backend/groth16/mpcsetup/phase2.go @@ -1,4 +1,4 @@ -package setup +package mpcsetup import ( "crypto/sha256" @@ -7,7 +7,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr" - utils "github.com/consensys/gnark/backend/groth16/setup/utils" + utils "github.com/consensys/gnark/backend/groth16/mpcsetup/utils" "github.com/consensys/gnark/constraint" cs "github.com/consensys/gnark/constraint/bn254" ) diff --git a/backend/groth16/setup/setup.go b/backend/groth16/mpcsetup/setup.go similarity index 96% rename from backend/groth16/setup/setup.go rename to backend/groth16/mpcsetup/setup.go index e719bef36c..06e5be2d0e 100644 --- a/backend/groth16/setup/setup.go +++ b/backend/groth16/mpcsetup/setup.go @@ -1,10 +1,10 @@ -package setup +package mpcsetup import ( "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" groth16 "github.com/consensys/gnark/backend/groth16/bn254" - "github.com/consensys/gnark/backend/groth16/setup/utils" + "github.com/consensys/gnark/backend/groth16/mpcsetup/utils" ) func ExtractKeys(srs1 *Phase1, srs2 *Phase2, evals *Phase2Evaluations, nConstraints int) (pk groth16.ProvingKey, vk groth16.VerifyingKey) { diff --git a/backend/groth16/setup/setup_test.go b/backend/groth16/mpcsetup/setup_test.go similarity index 99% rename from backend/groth16/setup/setup_test.go rename to backend/groth16/mpcsetup/setup_test.go index 93786b0d14..e79e284a0c 100644 --- a/backend/groth16/setup/setup_test.go +++ b/backend/groth16/mpcsetup/setup_test.go @@ -1,4 +1,4 @@ -package setup +package mpcsetup import ( "testing" diff --git a/backend/groth16/setup/utils/lagrange.go b/backend/groth16/mpcsetup/utils/lagrange.go similarity index 100% rename from backend/groth16/setup/utils/lagrange.go rename to backend/groth16/mpcsetup/utils/lagrange.go diff --git a/backend/groth16/setup/utils/utils.go b/backend/groth16/mpcsetup/utils/utils.go similarity index 100% rename from backend/groth16/setup/utils/utils.go rename to backend/groth16/mpcsetup/utils/utils.go From d96e6bc59bde4e77151fe6fc5a2f2a3e45fe5d15 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Mon, 13 Mar 2023 22:08:45 -0500 Subject: [PATCH 111/464] refactor: move utils in mpcsetup; limit api surface --- backend/groth16/mpcsetup/doc.go | 2 + .../groth16/mpcsetup/{utils => }/lagrange.go | 110 +++++++----------- backend/groth16/mpcsetup/phase1.go | 63 +++++----- backend/groth16/mpcsetup/phase2.go | 33 +++--- backend/groth16/mpcsetup/setup.go | 3 +- backend/groth16/mpcsetup/setup_test.go | 25 +++- backend/groth16/mpcsetup/{utils => }/utils.go | 81 +++++++------ 7 files changed, 160 insertions(+), 157 deletions(-) create mode 100644 backend/groth16/mpcsetup/doc.go rename backend/groth16/mpcsetup/{utils => }/lagrange.go (90%) rename backend/groth16/mpcsetup/{utils => }/utils.go (75%) diff --git a/backend/groth16/mpcsetup/doc.go b/backend/groth16/mpcsetup/doc.go new file mode 100644 index 0000000000..786398d32a --- /dev/null +++ b/backend/groth16/mpcsetup/doc.go @@ -0,0 +1,2 @@ +// Package mpcsetup implements https://eprint.iacr.org/2017/1050.pdf +package mpcsetup diff --git a/backend/groth16/mpcsetup/utils/lagrange.go b/backend/groth16/mpcsetup/lagrange.go similarity index 90% rename from backend/groth16/mpcsetup/utils/lagrange.go rename to backend/groth16/mpcsetup/lagrange.go index 0987adf609..a0d3d463be 100644 --- a/backend/groth16/mpcsetup/utils/lagrange.go +++ b/backend/groth16/mpcsetup/lagrange.go @@ -1,4 +1,4 @@ -package utils +package mpcsetup import ( "math/big" @@ -12,6 +12,48 @@ import ( "github.com/consensys/gnark/internal/utils" ) +func LagrangeCoeffsG1(powers []bn254.G1Affine, size int) []bn254.G1Affine { + coeffs := make([]bn254.G1Affine, size) + copy(coeffs, powers[:size]) + domain := fft.NewDomain(uint64(size)) + numCPU := uint64(runtime.NumCPU()) + maxSplits := bits.TrailingZeros64(ecc.NextPowerOfTwo(numCPU)) + + difFFTG1(coeffs, domain.TwiddlesInv, 0, maxSplits, nil) + bitReverse(coeffs) + + var invBigint big.Int + domain.CardinalityInv.BigInt(&invBigint) + + utils.Parallelize(size, func(start, end int) { + for i := start; i < end; i++ { + coeffs[i].ScalarMultiplication(&coeffs[i], &invBigint) + } + }) + return coeffs +} + +func LagrangeCoeffsG2(powers []bn254.G2Affine, size int) []bn254.G2Affine { + coeffs := make([]bn254.G2Affine, size) + copy(coeffs, powers[:size]) + domain := fft.NewDomain(uint64(size)) + numCPU := uint64(runtime.NumCPU()) + maxSplits := bits.TrailingZeros64(ecc.NextPowerOfTwo(numCPU)) + + difFFTG2(coeffs, domain.TwiddlesInv, 0, maxSplits, nil) + bitReverse(coeffs) + + var invBigint big.Int + domain.CardinalityInv.BigInt(&invBigint) + + utils.Parallelize(size, func(start, end int) { + for i := start; i < end; i++ { + coeffs[i].ScalarMultiplication(&coeffs[i], &invBigint) + } + }) + return coeffs +} + func butterflyG1(a *bn254.G1Affine, b *bn254.G1Affine) { t := *a a.Add(a, b) @@ -156,69 +198,3 @@ func difFFTG2(a []bn254.G2Affine, twiddles [][]fr.Element, stage, maxSplits int, difFFTG2(a[m:n], twiddles, nextStage, maxSplits, nil) } } - -func BitReverseG1(a []bn254.G1Affine) { - n := uint64(len(a)) - nn := uint64(64 - bits.TrailingZeros64(n)) - - for i := uint64(0); i < n; i++ { - irev := bits.Reverse64(i) >> nn - if irev > i { - a[i], a[irev] = a[irev], a[i] - } - } -} - -func BitReverseG2(a []bn254.G2Affine) { - n := uint64(len(a)) - nn := uint64(64 - bits.TrailingZeros64(n)) - - for i := uint64(0); i < n; i++ { - irev := bits.Reverse64(i) >> nn - if irev > i { - a[i], a[irev] = a[irev], a[i] - } - } -} - -func LagrangeCoeffsG1(powers []bn254.G1Affine, size int) []bn254.G1Affine { - coeffs := make([]bn254.G1Affine, size) - copy(coeffs, powers[:size]) - domain := fft.NewDomain(uint64(size)) - numCPU := uint64(runtime.NumCPU()) - maxSplits := bits.TrailingZeros64(ecc.NextPowerOfTwo(numCPU)) - - difFFTG1(coeffs, domain.TwiddlesInv, 0, maxSplits, nil) - BitReverseG1(coeffs) - - var invBigint big.Int - domain.CardinalityInv.BigInt(&invBigint) - - utils.Parallelize(size, func(start, end int) { - for i := start; i < end; i++ { - coeffs[i].ScalarMultiplication(&coeffs[i], &invBigint) - } - }) - return coeffs -} - -func LagrangeCoeffsG2(powers []bn254.G2Affine, size int) []bn254.G2Affine { - coeffs := make([]bn254.G2Affine, size) - copy(coeffs, powers[:size]) - domain := fft.NewDomain(uint64(size)) - numCPU := uint64(runtime.NumCPU()) - maxSplits := bits.TrailingZeros64(ecc.NextPowerOfTwo(numCPU)) - - difFFTG2(coeffs, domain.TwiddlesInv, 0, maxSplits, nil) - BitReverseG2(coeffs) - - var invBigint big.Int - domain.CardinalityInv.BigInt(&invBigint) - - utils.Parallelize(size, func(start, end int) { - for i := start; i < end; i++ { - coeffs[i].ScalarMultiplication(&coeffs[i], &invBigint) - } - }) - return coeffs -} diff --git a/backend/groth16/mpcsetup/phase1.go b/backend/groth16/mpcsetup/phase1.go index d0ee9ba2da..8e7d6742d2 100644 --- a/backend/groth16/mpcsetup/phase1.go +++ b/backend/groth16/mpcsetup/phase1.go @@ -8,7 +8,6 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr" - "github.com/consensys/gnark/backend/groth16/mpcsetup/utils" ) // Phase1 represents the Phase1 of the MPC described in @@ -28,7 +27,7 @@ type Phase1 struct { } } PublicKeys struct { - Tau, Alpha, Beta utils.PublicKey + Tau, Alpha, Beta publicKey } Hash []byte // sha256 hash } @@ -43,9 +42,9 @@ func InitPhase1(power int) (phase1 Phase1) { tau.SetOne() alpha.SetOne() beta.SetOne() - phase1.PublicKeys.Tau = utils.GenPublicKey(tau, nil, 1) - phase1.PublicKeys.Alpha = utils.GenPublicKey(alpha, nil, 2) - phase1.PublicKeys.Beta = utils.GenPublicKey(beta, nil, 3) + phase1.PublicKeys.Tau = newPublicKey(tau, nil, 1) + phase1.PublicKeys.Alpha = newPublicKey(alpha, nil, 2) + phase1.PublicKeys.Beta = newPublicKey(beta, nil, 3) // First contribution use generators _, _, g1, g2 := bn254.Generators() @@ -80,12 +79,12 @@ func (phase1 *Phase1) Contribute() { tau.SetRandom() alpha.SetRandom() beta.SetRandom() - phase1.PublicKeys.Tau = utils.GenPublicKey(tau, phase1.Hash[:], 1) - phase1.PublicKeys.Alpha = utils.GenPublicKey(alpha, phase1.Hash[:], 2) - phase1.PublicKeys.Beta = utils.GenPublicKey(beta, phase1.Hash[:], 3) + phase1.PublicKeys.Tau = newPublicKey(tau, phase1.Hash[:], 1) + phase1.PublicKeys.Alpha = newPublicKey(alpha, phase1.Hash[:], 2) + phase1.PublicKeys.Beta = newPublicKey(beta, phase1.Hash[:], 3) // Compute powers of τ, ατ, and βτ - taus := utils.Powers(tau, 2*N-1) + taus := powers(tau, 2*N-1) alphaTau := make([]fr.Element, N) betaTau := make([]fr.Element, N) for i := 0; i < N; i++ { @@ -94,10 +93,10 @@ func (phase1 *Phase1) Contribute() { } // Update using previous parameters - phase1.Parameters.G1.Tau = utils.ScaleG1(phase1.Parameters.G1.Tau, taus) - phase1.Parameters.G2.Tau = utils.ScaleG2(phase1.Parameters.G2.Tau, taus[0:N]) - phase1.Parameters.G1.AlphaTau = utils.ScaleG1(phase1.Parameters.G1.AlphaTau, alphaTau) - phase1.Parameters.G1.BetaTau = utils.ScaleG1(phase1.Parameters.G1.BetaTau, betaTau) + phase1.Parameters.G1.Tau = scaleG1(phase1.Parameters.G1.Tau, taus) + phase1.Parameters.G2.Tau = scaleG2(phase1.Parameters.G2.Tau, taus[0:N]) + phase1.Parameters.G1.AlphaTau = scaleG1(phase1.Parameters.G1.AlphaTau, alphaTau) + phase1.Parameters.G1.BetaTau = scaleG1(phase1.Parameters.G1.BetaTau, betaTau) var betaBI big.Int beta.BigInt(&betaBI) phase1.Parameters.G2.Beta.ScalarMultiplication(&phase1.Parameters.G2.Beta, &betaBI) @@ -119,54 +118,54 @@ func VerifyPhase1(c0, c1 *Phase1, c ...*Phase1) error { // verifyPhase1 checks that a contribution is based on a known previous Phase1 state. func verifyPhase1(current, contribution *Phase1) error { // Compute R for τ, α, β - tauR := utils.GenR(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, current.Hash[:], 1) - alphaR := utils.GenR(contribution.PublicKeys.Alpha.SG, contribution.PublicKeys.Alpha.SXG, current.Hash[:], 2) - betaR := utils.GenR(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, current.Hash[:], 3) + tauR := genR(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, current.Hash[:], 1) + alphaR := genR(contribution.PublicKeys.Alpha.SG, contribution.PublicKeys.Alpha.SXG, current.Hash[:], 2) + betaR := genR(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, current.Hash[:], 3) // Check for knowledge of toxic parameters - if !utils.SameRatio(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, contribution.PublicKeys.Tau.XR, tauR) { + if !sameRatio(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, contribution.PublicKeys.Tau.XR, tauR) { return errors.New("couldn't verify public key of τ") } - if !utils.SameRatio(contribution.PublicKeys.Alpha.SG, contribution.PublicKeys.Alpha.SXG, contribution.PublicKeys.Alpha.XR, alphaR) { + if !sameRatio(contribution.PublicKeys.Alpha.SG, contribution.PublicKeys.Alpha.SXG, contribution.PublicKeys.Alpha.XR, alphaR) { return errors.New("couldn't verify public key of α") } - if !utils.SameRatio(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, contribution.PublicKeys.Beta.XR, betaR) { + if !sameRatio(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, contribution.PublicKeys.Beta.XR, betaR) { return errors.New("couldn't verify public key of β") } // Check for valid updates using previous parameters - if !utils.SameRatio(contribution.Parameters.G1.Tau[1], current.Parameters.G1.Tau[1], tauR, contribution.PublicKeys.Tau.XR) { + if !sameRatio(contribution.Parameters.G1.Tau[1], current.Parameters.G1.Tau[1], tauR, contribution.PublicKeys.Tau.XR) { return errors.New("couldn't verify that [τ]₁ is based on previous contribution") } - if !utils.SameRatio(contribution.Parameters.G1.AlphaTau[0], current.Parameters.G1.AlphaTau[0], alphaR, contribution.PublicKeys.Alpha.XR) { + if !sameRatio(contribution.Parameters.G1.AlphaTau[0], current.Parameters.G1.AlphaTau[0], alphaR, contribution.PublicKeys.Alpha.XR) { return errors.New("couldn't verify that [α]₁ is based on previous contribution") } - if !utils.SameRatio(contribution.Parameters.G1.BetaTau[0], current.Parameters.G1.BetaTau[0], betaR, contribution.PublicKeys.Beta.XR) { + if !sameRatio(contribution.Parameters.G1.BetaTau[0], current.Parameters.G1.BetaTau[0], betaR, contribution.PublicKeys.Beta.XR) { return errors.New("couldn't verify that [β]₁ is based on previous contribution") } - if !utils.SameRatio(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, contribution.Parameters.G2.Tau[1], current.Parameters.G2.Tau[1]) { + if !sameRatio(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, contribution.Parameters.G2.Tau[1], current.Parameters.G2.Tau[1]) { return errors.New("couldn't verify that [τ]₂ is based on previous contribution") } - if !utils.SameRatio(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, contribution.Parameters.G2.Beta, current.Parameters.G2.Beta) { + if !sameRatio(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, contribution.Parameters.G2.Beta, current.Parameters.G2.Beta) { return errors.New("couldn't verify that [β]₂ is based on previous contribution") } // Check for valid updates using powers of τ _, _, g1, g2 := bn254.Generators() - tauL1, tauL2 := utils.LinearCombinationG1(contribution.Parameters.G1.Tau) - if !utils.SameRatio(tauL1, tauL2, contribution.Parameters.G2.Tau[1], g2) { + tauL1, tauL2 := linearCombinationG1(contribution.Parameters.G1.Tau) + if !sameRatio(tauL1, tauL2, contribution.Parameters.G2.Tau[1], g2) { return errors.New("couldn't verify valid powers of τ in G₁") } - alphaL1, alphaL2 := utils.LinearCombinationG1(contribution.Parameters.G1.AlphaTau) - if !utils.SameRatio(alphaL1, alphaL2, contribution.Parameters.G2.Tau[1], g2) { + alphaL1, alphaL2 := linearCombinationG1(contribution.Parameters.G1.AlphaTau) + if !sameRatio(alphaL1, alphaL2, contribution.Parameters.G2.Tau[1], g2) { return errors.New("couldn't verify valid powers of α(τ) in G₁") } - betaL1, betaL2 := utils.LinearCombinationG1(contribution.Parameters.G1.BetaTau) - if !utils.SameRatio(betaL1, betaL2, contribution.Parameters.G2.Tau[1], g2) { + betaL1, betaL2 := linearCombinationG1(contribution.Parameters.G1.BetaTau) + if !sameRatio(betaL1, betaL2, contribution.Parameters.G2.Tau[1], g2) { return errors.New("couldn't verify valid powers of α(τ) in G₁") } - tau2L1, tau2L2 := utils.LinearCombinationG2(contribution.Parameters.G2.Tau) - if !utils.SameRatio(contribution.Parameters.G1.Tau[1], g1, tau2L1, tau2L2) { + tau2L1, tau2L2 := linearCombinationG2(contribution.Parameters.G2.Tau) + if !sameRatio(contribution.Parameters.G1.Tau[1], g1, tau2L1, tau2L2) { return errors.New("couldn't verify valid powers of τ in G₂") } diff --git a/backend/groth16/mpcsetup/phase2.go b/backend/groth16/mpcsetup/phase2.go index 0905ae00f9..53cccf839c 100644 --- a/backend/groth16/mpcsetup/phase2.go +++ b/backend/groth16/mpcsetup/phase2.go @@ -7,7 +7,6 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr" - utils "github.com/consensys/gnark/backend/groth16/mpcsetup/utils" "github.com/consensys/gnark/constraint" cs "github.com/consensys/gnark/constraint/bn254" ) @@ -31,7 +30,7 @@ type Phase2 struct { Delta bn254.G2Affine } } - PublicKey utils.PublicKey + PublicKey publicKey Hash []byte } @@ -85,10 +84,10 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { } // Prepare Lagrange coefficients of [τ...]₁, [τ...]₂, [ατ...]₁, [βτ...]₁ - coeffTau1 := utils.LagrangeCoeffsG1(srs.G1.Tau, size) - coeffTau2 := utils.LagrangeCoeffsG2(srs.G2.Tau, size) - coeffAlphaTau1 := utils.LagrangeCoeffsG1(srs.G1.AlphaTau, size) - coeffBetaTau1 := utils.LagrangeCoeffsG1(srs.G1.BetaTau, size) + coeffTau1 := LagrangeCoeffsG1(srs.G1.Tau, size) + coeffTau2 := LagrangeCoeffsG2(srs.G2.Tau, size) + coeffAlphaTau1 := LagrangeCoeffsG1(srs.G1.AlphaTau, size) + coeffBetaTau1 := LagrangeCoeffsG1(srs.G1.BetaTau, size) internal, secret, public := r1cs.GetNbVariables() nWires := internal + secret + public @@ -129,7 +128,7 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { for i := 0; i < n-1; i++ { c2.Parameters.G1.Z[i].Sub(&srs.G1.Tau[i+n], &srs.G1.Tau[i]) } - utils.BitReverseG1(c2.Parameters.G1.Z) + bitReverse(c2.Parameters.G1.Z) c2.Parameters.G1.Z = c2.Parameters.G1.Z[:n-1] // Evaluate L @@ -150,7 +149,7 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { // Set δ public key var delta fr.Element delta.SetOne() - c2.PublicKey = utils.GenPublicKey(delta, nil, 1) + c2.PublicKey = newPublicKey(delta, nil, 1) // Hash initial contribution c2.Hash = c2.hash() @@ -168,7 +167,7 @@ func (c *Phase2) Contribute() { deltaInv.BigInt(&deltaInvBI) // Set δ public key - c.PublicKey = utils.GenPublicKey(delta, c.Hash, 1) + c.PublicKey = newPublicKey(delta, c.Hash, 1) // Update δ c.Parameters.G1.Delta.ScalarMultiplication(&c.Parameters.G1.Delta, &deltaBI) @@ -200,28 +199,28 @@ func VerifyPhase2(c0, c1 *Phase2, c ...*Phase2) error { func verifyPhase2(current, contribution *Phase2) error { // Compute R for δ - deltaR := utils.GenR(contribution.PublicKey.SG, contribution.PublicKey.SXG, current.Hash[:], 1) + deltaR := genR(contribution.PublicKey.SG, contribution.PublicKey.SXG, current.Hash[:], 1) // Check for knowledge of δ - if !utils.SameRatio(contribution.PublicKey.SG, contribution.PublicKey.SXG, contribution.PublicKey.XR, deltaR) { + if !sameRatio(contribution.PublicKey.SG, contribution.PublicKey.SXG, contribution.PublicKey.XR, deltaR) { return errors.New("couldn't verify knowledge of δ") } // Check for valid updates using previous parameters - if !utils.SameRatio(contribution.Parameters.G1.Delta, current.Parameters.G1.Delta, deltaR, contribution.PublicKey.XR) { + if !sameRatio(contribution.Parameters.G1.Delta, current.Parameters.G1.Delta, deltaR, contribution.PublicKey.XR) { return errors.New("couldn't verify that [δ]₁ is based on previous contribution") } - if !utils.SameRatio(contribution.PublicKey.SG, contribution.PublicKey.SXG, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { + if !sameRatio(contribution.PublicKey.SG, contribution.PublicKey.SXG, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { return errors.New("couldn't verify that [δ]₂ is based on previous contribution") } // Check for valid updates of L and Z using - L, prevL := utils.Merge(contribution.Parameters.G1.L, current.Parameters.G1.L) - if !utils.SameRatio(L, prevL, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { + L, prevL := merge(contribution.Parameters.G1.L, current.Parameters.G1.L) + if !sameRatio(L, prevL, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { return errors.New("couldn't verify valid updates of L using δ⁻¹") } - Z, prevZ := utils.Merge(contribution.Parameters.G1.Z, current.Parameters.G1.Z) - if !utils.SameRatio(Z, prevZ, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { + Z, prevZ := merge(contribution.Parameters.G1.Z, current.Parameters.G1.Z) + if !sameRatio(Z, prevZ, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { return errors.New("couldn't verify valid updates of L using δ⁻¹") } diff --git a/backend/groth16/mpcsetup/setup.go b/backend/groth16/mpcsetup/setup.go index 06e5be2d0e..b0d439aa32 100644 --- a/backend/groth16/mpcsetup/setup.go +++ b/backend/groth16/mpcsetup/setup.go @@ -4,7 +4,6 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" groth16 "github.com/consensys/gnark/backend/groth16/bn254" - "github.com/consensys/gnark/backend/groth16/mpcsetup/utils" ) func ExtractKeys(srs1 *Phase1, srs2 *Phase2, evals *Phase2Evaluations, nConstraints int) (pk groth16.ProvingKey, vk groth16.VerifyingKey) { @@ -16,7 +15,7 @@ func ExtractKeys(srs1 *Phase1, srs2 *Phase2, evals *Phase2Evaluations, nConstrai pk.G1.Beta.Set(&srs1.Parameters.G1.BetaTau[0]) pk.G1.Delta.Set(&srs2.Parameters.G1.Delta) pk.G1.Z = srs2.Parameters.G1.Z - utils.BitReverseG1(pk.G1.Z) + bitReverse(pk.G1.Z) pk.G1.K = srs2.Parameters.G1.L pk.G2.Beta.Set(&srs1.Parameters.G2.Beta) diff --git a/backend/groth16/mpcsetup/setup_test.go b/backend/groth16/mpcsetup/setup_test.go index e79e284a0c..3cfb742e39 100644 --- a/backend/groth16/mpcsetup/setup_test.go +++ b/backend/groth16/mpcsetup/setup_test.go @@ -25,7 +25,10 @@ func TestSetupCircuit(t *testing.T) { // Make and verify contributions for phase1 for i := 1; i < nContributionsPhase1; i++ { + // we clone test purposes; but in practice, participant will receive a []byte, deserialize it, + // add his contribution and send back to coordinator. prev := srs1.clone() + srs1.Contribute() assert.NoError(VerifyPhase1(&prev, &srs1)) } @@ -43,7 +46,10 @@ func TestSetupCircuit(t *testing.T) { // Make and verify contributions for phase1 for i := 1; i < nContributionsPhase2; i++ { + // we clone for test purposes; but in practice, participant will receive a []byte, deserialize it, + // add his contribution and send back to coordinator. prev := srs2.clone() + srs2.Contribute() assert.NoError(VerifyPhase2(&prev, &srs2)) } @@ -72,12 +78,21 @@ func TestSetupCircuit(t *testing.T) { func BenchmarkPhase1Contribution(b *testing.B) { const power = 16 - srs1 := InitPhase1(power) - b.ResetTimer() - for i := 0; i < b.N; i++ { - srs1.Contribute() - } + b.Run("init", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = InitPhase1(power) + } + }) + + b.Run("contrib", func(b *testing.B) { + srs1 := InitPhase1(power) + b.ResetTimer() + for i := 0; i < b.N; i++ { + srs1.Contribute() + } + }) } diff --git a/backend/groth16/mpcsetup/utils/utils.go b/backend/groth16/mpcsetup/utils.go similarity index 75% rename from backend/groth16/mpcsetup/utils/utils.go rename to backend/groth16/mpcsetup/utils.go index d7bf149eb3..5469fdb815 100644 --- a/backend/groth16/mpcsetup/utils/utils.go +++ b/backend/groth16/mpcsetup/utils.go @@ -1,7 +1,8 @@ -package utils +package mpcsetup import ( "math/big" + "math/bits" "runtime" "github.com/consensys/gnark-crypto/ecc" @@ -10,14 +11,49 @@ import ( "github.com/consensys/gnark/internal/utils" ) -type PublicKey struct { +type publicKey struct { SG bn254.G1Affine SXG bn254.G1Affine XR bn254.G2Affine } +func newPublicKey(x fr.Element, challenge []byte, dst byte) publicKey { + var pk publicKey + _, _, g1, _ := bn254.Generators() + + var s fr.Element + var sBi big.Int + s.SetRandom() + s.BigInt(&sBi) + pk.SG.ScalarMultiplication(&g1, &sBi) + + // compute x*sG1 + var xBi big.Int + x.BigInt(&xBi) + pk.SXG.ScalarMultiplication(&pk.SG, &xBi) + + // generate R based on sG1, sxG1, challenge, and domain separation tag (tau, alpha or beta) + R := genR(pk.SG, pk.SXG, challenge, dst) + + // compute x*spG2 + pk.XR.ScalarMultiplication(&R, &xBi) + return pk +} + +func bitReverse[T any](a []T) { + n := uint64(len(a)) + nn := uint64(64 - bits.TrailingZeros64(n)) + + for i := uint64(0); i < n; i++ { + irev := bits.Reverse64(i) >> nn + if irev > i { + a[i], a[irev] = a[irev], a[i] + } + } +} + // Returns [1, a, a², ..., aⁿ⁻¹ ] in Montgomery form -func Powers(a fr.Element, n int) []fr.Element { +func powers(a fr.Element, n int) []fr.Element { result := make([]fr.Element, n) result[0] = fr.NewElement(1) for i := 1; i < n; i++ { @@ -27,7 +63,7 @@ func Powers(a fr.Element, n int) []fr.Element { } // Returns [aᵢAᵢ, ...] in G1 -func ScaleG1(A []bn254.G1Affine, a []fr.Element) []bn254.G1Affine { +func scaleG1(A []bn254.G1Affine, a []fr.Element) []bn254.G1Affine { result := make([]bn254.G1Affine, len(A)) utils.Parallelize(len(A), func(start, end int) { for i := start; i < end; i++ { @@ -40,7 +76,7 @@ func ScaleG1(A []bn254.G1Affine, a []fr.Element) []bn254.G1Affine { } // Returns [aᵢAᵢ, ...] in G2 -func ScaleG2(A []bn254.G2Affine, a []fr.Element) []bn254.G2Affine { +func scaleG2(A []bn254.G2Affine, a []fr.Element) []bn254.G2Affine { result := make([]bn254.G2Affine, len(A)) utils.Parallelize(len(A), func(start, end int) { for i := start; i < end; i++ { @@ -53,7 +89,7 @@ func ScaleG2(A []bn254.G2Affine, a []fr.Element) []bn254.G2Affine { } // Check e(a₁, a₂) = e(b₁, b₂) -func SameRatio(a1, b1 bn254.G1Affine, a2, b2 bn254.G2Affine) bool { +func sameRatio(a1, b1 bn254.G1Affine, a2, b2 bn254.G2Affine) bool { if !a1.IsInSubGroup() || !b1.IsInSubGroup() || !a2.IsInSubGroup() || !b2.IsInSubGroup() { panic("invalid point not in subgroup") } @@ -68,8 +104,8 @@ func SameRatio(a1, b1 bn254.G1Affine, a2, b2 bn254.G2Affine) bool { return res } -// returnsa = ∑ rᵢAᵢ, b = ∑ rᵢBᵢ -func Merge(A, B []bn254.G1Affine) (a, b bn254.G1Affine) { +// returns a = ∑ rᵢAᵢ, b = ∑ rᵢBᵢ +func merge(A, B []bn254.G1Affine) (a, b bn254.G1Affine) { nc := runtime.NumCPU() r := make([]fr.Element, len(A)) for i := 0; i < len(A); i++ { @@ -81,7 +117,7 @@ func Merge(A, B []bn254.G1Affine) (a, b bn254.G1Affine) { } // L1 = ∑ rᵢAᵢ, L2 = ∑ rᵢAᵢ₊₁ in G1 -func LinearCombinationG1(A []bn254.G1Affine) (L1, L2 bn254.G1Affine) { +func linearCombinationG1(A []bn254.G1Affine) (L1, L2 bn254.G1Affine) { nc := runtime.NumCPU() n := len(A) r := make([]fr.Element, n-1) @@ -94,7 +130,7 @@ func LinearCombinationG1(A []bn254.G1Affine) (L1, L2 bn254.G1Affine) { } // L1 = ∑ rᵢAᵢ, L2 = ∑ rᵢAᵢ₊₁ in G2 -func LinearCombinationG2(A []bn254.G2Affine) (L1, L2 bn254.G2Affine) { +func linearCombinationG2(A []bn254.G2Affine) (L1, L2 bn254.G2Affine) { nc := runtime.NumCPU() n := len(A) r := make([]fr.Element, n-1) @@ -107,7 +143,7 @@ func LinearCombinationG2(A []bn254.G2Affine) (L1, L2 bn254.G2Affine) { } // Generate R in G₂ as Hash(gˢ, gˢˣ, challenge, dst) -func GenR(sG1, sxG1 bn254.G1Affine, challenge []byte, dst byte) bn254.G2Affine { +func genR(sG1, sxG1 bn254.G1Affine, challenge []byte, dst byte) bn254.G2Affine { buffer := append(sG1.Marshal()[:], sxG1.Marshal()...) buffer = append(buffer, challenge...) spG2, err := bn254.HashToG2(buffer, []byte{dst}) @@ -116,26 +152,3 @@ func GenR(sG1, sxG1 bn254.G1Affine, challenge []byte, dst byte) bn254.G2Affine { } return spG2 } - -func GenPublicKey(x fr.Element, challenge []byte, dst byte) PublicKey { - var pk PublicKey - _, _, g1, _ := bn254.Generators() - - var s fr.Element - var sBi big.Int - s.SetRandom() - s.BigInt(&sBi) - pk.SG.ScalarMultiplication(&g1, &sBi) - - // compute x*sG1 - var xBi big.Int - x.BigInt(&xBi) - pk.SXG.ScalarMultiplication(&pk.SG, &xBi) - - // generate R based on sG1, sxG1, challenge, and domain separation tag (tau, alpha or beta) - R := GenR(pk.SG, pk.SXG, challenge, dst) - - // compute x*spG2 - pk.XR.ScalarMultiplication(&R, &xBi) - return pk -} From 7ca6bc388ff4b4913e6f1f38393e780a500d24df Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Mon, 13 Mar 2023 22:28:40 -0500 Subject: [PATCH 112/464] refactor: minor code cleaning --- backend/groth16/mpcsetup/phase1.go | 11 +++++---- backend/groth16/mpcsetup/phase2.go | 2 +- backend/groth16/mpcsetup/setup_test.go | 8 +++---- backend/groth16/mpcsetup/utils.go | 32 +++++++++++++------------- 4 files changed, 27 insertions(+), 26 deletions(-) diff --git a/backend/groth16/mpcsetup/phase1.go b/backend/groth16/mpcsetup/phase1.go index 8e7d6742d2..a49c2be0a1 100644 --- a/backend/groth16/mpcsetup/phase1.go +++ b/backend/groth16/mpcsetup/phase1.go @@ -27,7 +27,7 @@ type Phase1 struct { } } PublicKeys struct { - Tau, Alpha, Beta publicKey + Tau, Alpha, Beta PublicKey } Hash []byte // sha256 hash } @@ -93,10 +93,11 @@ func (phase1 *Phase1) Contribute() { } // Update using previous parameters - phase1.Parameters.G1.Tau = scaleG1(phase1.Parameters.G1.Tau, taus) - phase1.Parameters.G2.Tau = scaleG2(phase1.Parameters.G2.Tau, taus[0:N]) - phase1.Parameters.G1.AlphaTau = scaleG1(phase1.Parameters.G1.AlphaTau, alphaTau) - phase1.Parameters.G1.BetaTau = scaleG1(phase1.Parameters.G1.BetaTau, betaTau) + // TODO @gbotrel working with jacobian points here will help with perf. + scaleG1InPlace(phase1.Parameters.G1.Tau, taus) + scaleG2InPlace(phase1.Parameters.G2.Tau, taus[0:N]) + scaleG1InPlace(phase1.Parameters.G1.AlphaTau, alphaTau) + scaleG1InPlace(phase1.Parameters.G1.BetaTau, betaTau) var betaBI big.Int beta.BigInt(&betaBI) phase1.Parameters.G2.Beta.ScalarMultiplication(&phase1.Parameters.G2.Beta, &betaBI) diff --git a/backend/groth16/mpcsetup/phase2.go b/backend/groth16/mpcsetup/phase2.go index 53cccf839c..b6792a9c1b 100644 --- a/backend/groth16/mpcsetup/phase2.go +++ b/backend/groth16/mpcsetup/phase2.go @@ -30,7 +30,7 @@ type Phase2 struct { Delta bn254.G2Affine } } - PublicKey publicKey + PublicKey PublicKey Hash []byte } diff --git a/backend/groth16/mpcsetup/setup_test.go b/backend/groth16/mpcsetup/setup_test.go index 3cfb742e39..e816c147a6 100644 --- a/backend/groth16/mpcsetup/setup_test.go +++ b/backend/groth16/mpcsetup/setup_test.go @@ -76,8 +76,8 @@ func TestSetupCircuit(t *testing.T) { assert.NoError(err) } -func BenchmarkPhase1Contribution(b *testing.B) { - const power = 16 +func BenchmarkPhase1(b *testing.B) { + const power = 14 b.Run("init", func(b *testing.B) { b.ResetTimer() @@ -96,8 +96,8 @@ func BenchmarkPhase1Contribution(b *testing.B) { } -func BenchmarkPhase2Contribution(b *testing.B) { - const power = 16 +func BenchmarkPhase2(b *testing.B) { + const power = 14 srs1 := InitPhase1(power) srs1.Contribute() diff --git a/backend/groth16/mpcsetup/utils.go b/backend/groth16/mpcsetup/utils.go index 5469fdb815..a4ee4eafc8 100644 --- a/backend/groth16/mpcsetup/utils.go +++ b/backend/groth16/mpcsetup/utils.go @@ -1,6 +1,7 @@ package mpcsetup import ( + "bytes" "math/big" "math/bits" "runtime" @@ -11,14 +12,14 @@ import ( "github.com/consensys/gnark/internal/utils" ) -type publicKey struct { +type PublicKey struct { SG bn254.G1Affine SXG bn254.G1Affine XR bn254.G2Affine } -func newPublicKey(x fr.Element, challenge []byte, dst byte) publicKey { - var pk publicKey +func newPublicKey(x fr.Element, challenge []byte, dst byte) PublicKey { + var pk PublicKey _, _, g1, _ := bn254.Generators() var s fr.Element @@ -63,29 +64,25 @@ func powers(a fr.Element, n int) []fr.Element { } // Returns [aᵢAᵢ, ...] in G1 -func scaleG1(A []bn254.G1Affine, a []fr.Element) []bn254.G1Affine { - result := make([]bn254.G1Affine, len(A)) +func scaleG1InPlace(A []bn254.G1Affine, a []fr.Element) { utils.Parallelize(len(A), func(start, end int) { + var tmp big.Int for i := start; i < end; i++ { - var tmp big.Int a[i].BigInt(&tmp) - result[i].ScalarMultiplication(&A[i], &tmp) + A[i].ScalarMultiplication(&A[i], &tmp) } }) - return result } // Returns [aᵢAᵢ, ...] in G2 -func scaleG2(A []bn254.G2Affine, a []fr.Element) []bn254.G2Affine { - result := make([]bn254.G2Affine, len(A)) +func scaleG2InPlace(A []bn254.G2Affine, a []fr.Element) { utils.Parallelize(len(A), func(start, end int) { + var tmp big.Int for i := start; i < end; i++ { - var tmp big.Int a[i].BigInt(&tmp) - result[i].ScalarMultiplication(&A[i], &tmp) + A[i].ScalarMultiplication(&A[i], &tmp) } }) - return result } // Check e(a₁, a₂) = e(b₁, b₂) @@ -144,9 +141,12 @@ func linearCombinationG2(A []bn254.G2Affine) (L1, L2 bn254.G2Affine) { // Generate R in G₂ as Hash(gˢ, gˢˣ, challenge, dst) func genR(sG1, sxG1 bn254.G1Affine, challenge []byte, dst byte) bn254.G2Affine { - buffer := append(sG1.Marshal()[:], sxG1.Marshal()...) - buffer = append(buffer, challenge...) - spG2, err := bn254.HashToG2(buffer, []byte{dst}) + var buf bytes.Buffer + buf.Grow(len(challenge) + bn254.SizeOfG1AffineUncompressed*2) + buf.Write(sG1.Marshal()) + buf.Write(sxG1.Marshal()) + buf.Write(challenge) + spG2, err := bn254.HashToG2(buf.Bytes(), []byte{dst}) if err != nil { panic(err) } From 3f068a3b160b08f9c45ec0d5c77caed958e4c20b Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Mon, 13 Mar 2023 22:54:42 -0500 Subject: [PATCH 113/464] build: generify mpcsetup for all curves --- .../groth16/bls12-377/mpcsetup/lagrange.go | 216 +++++++++++++++ backend/groth16/bls12-377/mpcsetup/marshal.go | 181 ++++++++++++ .../bls12-377/mpcsetup/marshal_test.go | 79 ++++++ backend/groth16/bls12-377/mpcsetup/phase1.go | 203 ++++++++++++++ backend/groth16/bls12-377/mpcsetup/phase2.go | 258 ++++++++++++++++++ backend/groth16/bls12-377/mpcsetup/setup.go | 97 +++++++ .../groth16/bls12-377/mpcsetup/setup_test.go | 199 ++++++++++++++ backend/groth16/bls12-377/mpcsetup/utils.go | 170 ++++++++++++ .../groth16/bls12-381/mpcsetup/lagrange.go | 216 +++++++++++++++ backend/groth16/bls12-381/mpcsetup/marshal.go | 181 ++++++++++++ .../bls12-381/mpcsetup/marshal_test.go | 79 ++++++ backend/groth16/bls12-381/mpcsetup/phase1.go | 203 ++++++++++++++ backend/groth16/bls12-381/mpcsetup/phase2.go | 258 ++++++++++++++++++ backend/groth16/bls12-381/mpcsetup/setup.go | 97 +++++++ .../groth16/bls12-381/mpcsetup/setup_test.go | 199 ++++++++++++++ backend/groth16/bls12-381/mpcsetup/utils.go | 170 ++++++++++++ .../groth16/bls24-315/mpcsetup/lagrange.go | 216 +++++++++++++++ backend/groth16/bls24-315/mpcsetup/marshal.go | 181 ++++++++++++ .../bls24-315/mpcsetup/marshal_test.go | 79 ++++++ backend/groth16/bls24-315/mpcsetup/phase1.go | 203 ++++++++++++++ backend/groth16/bls24-315/mpcsetup/phase2.go | 258 ++++++++++++++++++ backend/groth16/bls24-315/mpcsetup/setup.go | 97 +++++++ .../groth16/bls24-315/mpcsetup/setup_test.go | 199 ++++++++++++++ backend/groth16/bls24-315/mpcsetup/utils.go | 170 ++++++++++++ .../groth16/bls24-317/mpcsetup/lagrange.go | 216 +++++++++++++++ backend/groth16/bls24-317/mpcsetup/marshal.go | 181 ++++++++++++ .../bls24-317/mpcsetup/marshal_test.go | 79 ++++++ backend/groth16/bls24-317/mpcsetup/phase1.go | 203 ++++++++++++++ backend/groth16/bls24-317/mpcsetup/phase2.go | 258 ++++++++++++++++++ backend/groth16/bls24-317/mpcsetup/setup.go | 97 +++++++ .../groth16/bls24-317/mpcsetup/setup_test.go | 199 ++++++++++++++ backend/groth16/bls24-317/mpcsetup/utils.go | 170 ++++++++++++ backend/groth16/bn254/mpcsetup/lagrange.go | 216 +++++++++++++++ backend/groth16/bn254/mpcsetup/marshal.go | 181 ++++++++++++ .../groth16/bn254/mpcsetup/marshal_test.go | 79 ++++++ backend/groth16/bn254/mpcsetup/phase1.go | 203 ++++++++++++++ backend/groth16/bn254/mpcsetup/phase2.go | 258 ++++++++++++++++++ backend/groth16/bn254/mpcsetup/setup.go | 97 +++++++ backend/groth16/bn254/mpcsetup/setup_test.go | 196 +++++++++++++ backend/groth16/bn254/mpcsetup/utils.go | 170 ++++++++++++ backend/groth16/bw6-633/mpcsetup/lagrange.go | 216 +++++++++++++++ backend/groth16/bw6-633/mpcsetup/marshal.go | 181 ++++++++++++ .../groth16/bw6-633/mpcsetup/marshal_test.go | 79 ++++++ backend/groth16/bw6-633/mpcsetup/phase1.go | 203 ++++++++++++++ backend/groth16/bw6-633/mpcsetup/phase2.go | 258 ++++++++++++++++++ backend/groth16/bw6-633/mpcsetup/setup.go | 97 +++++++ .../groth16/bw6-633/mpcsetup/setup_test.go | 199 ++++++++++++++ backend/groth16/bw6-633/mpcsetup/utils.go | 170 ++++++++++++ backend/groth16/bw6-761/mpcsetup/lagrange.go | 216 +++++++++++++++ backend/groth16/bw6-761/mpcsetup/marshal.go | 181 ++++++++++++ .../groth16/bw6-761/mpcsetup/marshal_test.go | 79 ++++++ backend/groth16/bw6-761/mpcsetup/phase1.go | 203 ++++++++++++++ backend/groth16/bw6-761/mpcsetup/phase2.go | 258 ++++++++++++++++++ backend/groth16/bw6-761/mpcsetup/setup.go | 97 +++++++ .../groth16/bw6-761/mpcsetup/setup_test.go | 199 ++++++++++++++ backend/groth16/bw6-761/mpcsetup/utils.go | 170 ++++++++++++ backend/groth16/mpcsetup/doc.go | 2 - internal/generator/backend/main.go | 23 +- .../groth16/mpcsetup/lagrange.go.tmpl | 31 ++- .../groth16/mpcsetup/marshal.go.tmpl | 17 +- .../groth16/mpcsetup/marshal_test.go.tmpl | 11 +- .../groth16/mpcsetup/phase1.go.tmpl | 29 +- .../groth16/mpcsetup/phase2.go.tmpl | 50 ++-- .../zkpschemes/groth16/mpcsetup/setup.go.tmpl | 17 +- .../groth16/mpcsetup/setup_test.go.tmpl | 30 +- .../zkpschemes/groth16/mpcsetup/utils.go.tmpl | 41 ++- 66 files changed, 9954 insertions(+), 115 deletions(-) create mode 100644 backend/groth16/bls12-377/mpcsetup/lagrange.go create mode 100644 backend/groth16/bls12-377/mpcsetup/marshal.go create mode 100644 backend/groth16/bls12-377/mpcsetup/marshal_test.go create mode 100644 backend/groth16/bls12-377/mpcsetup/phase1.go create mode 100644 backend/groth16/bls12-377/mpcsetup/phase2.go create mode 100644 backend/groth16/bls12-377/mpcsetup/setup.go create mode 100644 backend/groth16/bls12-377/mpcsetup/setup_test.go create mode 100644 backend/groth16/bls12-377/mpcsetup/utils.go create mode 100644 backend/groth16/bls12-381/mpcsetup/lagrange.go create mode 100644 backend/groth16/bls12-381/mpcsetup/marshal.go create mode 100644 backend/groth16/bls12-381/mpcsetup/marshal_test.go create mode 100644 backend/groth16/bls12-381/mpcsetup/phase1.go create mode 100644 backend/groth16/bls12-381/mpcsetup/phase2.go create mode 100644 backend/groth16/bls12-381/mpcsetup/setup.go create mode 100644 backend/groth16/bls12-381/mpcsetup/setup_test.go create mode 100644 backend/groth16/bls12-381/mpcsetup/utils.go create mode 100644 backend/groth16/bls24-315/mpcsetup/lagrange.go create mode 100644 backend/groth16/bls24-315/mpcsetup/marshal.go create mode 100644 backend/groth16/bls24-315/mpcsetup/marshal_test.go create mode 100644 backend/groth16/bls24-315/mpcsetup/phase1.go create mode 100644 backend/groth16/bls24-315/mpcsetup/phase2.go create mode 100644 backend/groth16/bls24-315/mpcsetup/setup.go create mode 100644 backend/groth16/bls24-315/mpcsetup/setup_test.go create mode 100644 backend/groth16/bls24-315/mpcsetup/utils.go create mode 100644 backend/groth16/bls24-317/mpcsetup/lagrange.go create mode 100644 backend/groth16/bls24-317/mpcsetup/marshal.go create mode 100644 backend/groth16/bls24-317/mpcsetup/marshal_test.go create mode 100644 backend/groth16/bls24-317/mpcsetup/phase1.go create mode 100644 backend/groth16/bls24-317/mpcsetup/phase2.go create mode 100644 backend/groth16/bls24-317/mpcsetup/setup.go create mode 100644 backend/groth16/bls24-317/mpcsetup/setup_test.go create mode 100644 backend/groth16/bls24-317/mpcsetup/utils.go create mode 100644 backend/groth16/bn254/mpcsetup/lagrange.go create mode 100644 backend/groth16/bn254/mpcsetup/marshal.go create mode 100644 backend/groth16/bn254/mpcsetup/marshal_test.go create mode 100644 backend/groth16/bn254/mpcsetup/phase1.go create mode 100644 backend/groth16/bn254/mpcsetup/phase2.go create mode 100644 backend/groth16/bn254/mpcsetup/setup.go create mode 100644 backend/groth16/bn254/mpcsetup/setup_test.go create mode 100644 backend/groth16/bn254/mpcsetup/utils.go create mode 100644 backend/groth16/bw6-633/mpcsetup/lagrange.go create mode 100644 backend/groth16/bw6-633/mpcsetup/marshal.go create mode 100644 backend/groth16/bw6-633/mpcsetup/marshal_test.go create mode 100644 backend/groth16/bw6-633/mpcsetup/phase1.go create mode 100644 backend/groth16/bw6-633/mpcsetup/phase2.go create mode 100644 backend/groth16/bw6-633/mpcsetup/setup.go create mode 100644 backend/groth16/bw6-633/mpcsetup/setup_test.go create mode 100644 backend/groth16/bw6-633/mpcsetup/utils.go create mode 100644 backend/groth16/bw6-761/mpcsetup/lagrange.go create mode 100644 backend/groth16/bw6-761/mpcsetup/marshal.go create mode 100644 backend/groth16/bw6-761/mpcsetup/marshal_test.go create mode 100644 backend/groth16/bw6-761/mpcsetup/phase1.go create mode 100644 backend/groth16/bw6-761/mpcsetup/phase2.go create mode 100644 backend/groth16/bw6-761/mpcsetup/setup.go create mode 100644 backend/groth16/bw6-761/mpcsetup/setup_test.go create mode 100644 backend/groth16/bw6-761/mpcsetup/utils.go delete mode 100644 backend/groth16/mpcsetup/doc.go rename backend/groth16/mpcsetup/lagrange.go => internal/generator/backend/template/zkpschemes/groth16/mpcsetup/lagrange.go.tmpl (85%) rename backend/groth16/mpcsetup/marshal.go => internal/generator/backend/template/zkpschemes/groth16/mpcsetup/marshal.go.tmpl (92%) rename backend/groth16/mpcsetup/marshal_test.go => internal/generator/backend/template/zkpschemes/groth16/mpcsetup/marshal_test.go.tmpl (83%) rename backend/groth16/mpcsetup/phase1.go => internal/generator/backend/template/zkpschemes/groth16/mpcsetup/phase1.go.tmpl (89%) rename backend/groth16/mpcsetup/phase2.go => internal/generator/backend/template/zkpschemes/groth16/mpcsetup/phase2.go.tmpl (85%) rename backend/groth16/mpcsetup/setup.go => internal/generator/backend/template/zkpschemes/groth16/mpcsetup/setup.go.tmpl (83%) rename backend/groth16/mpcsetup/setup_test.go => internal/generator/backend/template/zkpschemes/groth16/mpcsetup/setup_test.go.tmpl (86%) rename backend/groth16/mpcsetup/utils.go => internal/generator/backend/template/zkpschemes/groth16/mpcsetup/utils.go.tmpl (76%) diff --git a/backend/groth16/bls12-377/mpcsetup/lagrange.go b/backend/groth16/bls12-377/mpcsetup/lagrange.go new file mode 100644 index 0000000000..190a4f804a --- /dev/null +++ b/backend/groth16/bls12-377/mpcsetup/lagrange.go @@ -0,0 +1,216 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "math/big" + "math/bits" + "runtime" + + "github.com/consensys/gnark-crypto/ecc" + curve "github.com/consensys/gnark-crypto/ecc/bls12-377" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft" + "github.com/consensys/gnark/internal/utils" +) + +func LagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { + coeffs := make([]curve.G1Affine, size) + copy(coeffs, powers[:size]) + domain := fft.NewDomain(uint64(size)) + numCPU := uint64(runtime.NumCPU()) + maxSplits := bits.TrailingZeros64(ecc.NextPowerOfTwo(numCPU)) + + difFFTG1(coeffs, domain.TwiddlesInv, 0, maxSplits, nil) + bitReverse(coeffs) + + var invBigint big.Int + domain.CardinalityInv.BigInt(&invBigint) + + utils.Parallelize(size, func(start, end int) { + for i := start; i < end; i++ { + coeffs[i].ScalarMultiplication(&coeffs[i], &invBigint) + } + }) + return coeffs +} + +func LagrangeCoeffsG2(powers []curve.G2Affine, size int) []curve.G2Affine { + coeffs := make([]curve.G2Affine, size) + copy(coeffs, powers[:size]) + domain := fft.NewDomain(uint64(size)) + numCPU := uint64(runtime.NumCPU()) + maxSplits := bits.TrailingZeros64(ecc.NextPowerOfTwo(numCPU)) + + difFFTG2(coeffs, domain.TwiddlesInv, 0, maxSplits, nil) + bitReverse(coeffs) + + var invBigint big.Int + domain.CardinalityInv.BigInt(&invBigint) + + utils.Parallelize(size, func(start, end int) { + for i := start; i < end; i++ { + coeffs[i].ScalarMultiplication(&coeffs[i], &invBigint) + } + }) + return coeffs +} + +func butterflyG1(a *curve.G1Affine, b *curve.G1Affine) { + t := *a + a.Add(a, b) + b.Sub(&t, b) +} + +func butterflyG2(a *curve.G2Affine, b *curve.G2Affine) { + t := *a + a.Add(a, b) + b.Sub(&t, b) +} + +// kerDIF8 is a kernel that process a FFT of size 8 +func kerDIF8G1(a []curve.G1Affine, twiddles [][]fr.Element, stage int) { + butterflyG1(&a[0], &a[4]) + butterflyG1(&a[1], &a[5]) + butterflyG1(&a[2], &a[6]) + butterflyG1(&a[3], &a[7]) + + var twiddle big.Int + twiddles[stage+0][1].BigInt(&twiddle) + a[5].ScalarMultiplication(&a[5], &twiddle) + twiddles[stage+0][2].BigInt(&twiddle) + a[6].ScalarMultiplication(&a[6], &twiddle) + twiddles[stage+0][3].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG1(&a[0], &a[2]) + butterflyG1(&a[1], &a[3]) + butterflyG1(&a[4], &a[6]) + butterflyG1(&a[5], &a[7]) + twiddles[stage+1][1].BigInt(&twiddle) + a[3].ScalarMultiplication(&a[3], &twiddle) + twiddles[stage+1][1].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG1(&a[0], &a[1]) + butterflyG1(&a[2], &a[3]) + butterflyG1(&a[4], &a[5]) + butterflyG1(&a[6], &a[7]) +} + +// kerDIF8 is a kernel that process a FFT of size 8 +func kerDIF8G2(a []curve.G2Affine, twiddles [][]fr.Element, stage int) { + butterflyG2(&a[0], &a[4]) + butterflyG2(&a[1], &a[5]) + butterflyG2(&a[2], &a[6]) + butterflyG2(&a[3], &a[7]) + + var twiddle big.Int + twiddles[stage+0][1].BigInt(&twiddle) + a[5].ScalarMultiplication(&a[5], &twiddle) + twiddles[stage+0][2].BigInt(&twiddle) + a[6].ScalarMultiplication(&a[6], &twiddle) + twiddles[stage+0][3].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG2(&a[0], &a[2]) + butterflyG2(&a[1], &a[3]) + butterflyG2(&a[4], &a[6]) + butterflyG2(&a[5], &a[7]) + twiddles[stage+1][1].BigInt(&twiddle) + a[3].ScalarMultiplication(&a[3], &twiddle) + twiddles[stage+1][1].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG2(&a[0], &a[1]) + butterflyG2(&a[2], &a[3]) + butterflyG2(&a[4], &a[5]) + butterflyG2(&a[6], &a[7]) +} + +func difFFTG1(a []curve.G1Affine, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { + if chDone != nil { + defer close(chDone) + } + + n := len(a) + if n == 1 { + return + } else if n == 8 { + kerDIF8G1(a, twiddles, stage) + return + } + m := n >> 1 + + butterflyG1(&a[0], &a[m]) + + var twiddle big.Int + for i := 1; i < m; i++ { + butterflyG1(&a[i], &a[i+m]) + twiddles[stage][i].BigInt(&twiddle) + a[i+m].ScalarMultiplication(&a[i+m], &twiddle) + } + + if m == 1 { + return + } + + nextStage := stage + 1 + if stage < maxSplits { + chDone := make(chan struct{}, 1) + go difFFTG1(a[m:n], twiddles, nextStage, maxSplits, chDone) + difFFTG1(a[0:m], twiddles, nextStage, maxSplits, nil) + <-chDone + } else { + difFFTG1(a[0:m], twiddles, nextStage, maxSplits, nil) + difFFTG1(a[m:n], twiddles, nextStage, maxSplits, nil) + } +} +func difFFTG2(a []curve.G2Affine, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { + if chDone != nil { + defer close(chDone) + } + + n := len(a) + if n == 1 { + return + } else if n == 8 { + kerDIF8G2(a, twiddles, stage) + return + } + m := n >> 1 + + butterflyG2(&a[0], &a[m]) + + var twiddle big.Int + for i := 1; i < m; i++ { + butterflyG2(&a[i], &a[i+m]) + twiddles[stage][i].BigInt(&twiddle) + a[i+m].ScalarMultiplication(&a[i+m], &twiddle) + } + + if m == 1 { + return + } + + nextStage := stage + 1 + if stage < maxSplits { + chDone := make(chan struct{}, 1) + go difFFTG2(a[m:n], twiddles, nextStage, maxSplits, chDone) + difFFTG2(a[0:m], twiddles, nextStage, maxSplits, nil) + <-chDone + } else { + difFFTG2(a[0:m], twiddles, nextStage, maxSplits, nil) + difFFTG2(a[m:n], twiddles, nextStage, maxSplits, nil) + } +} diff --git a/backend/groth16/bls12-377/mpcsetup/marshal.go b/backend/groth16/bls12-377/mpcsetup/marshal.go new file mode 100644 index 0000000000..35ceece58f --- /dev/null +++ b/backend/groth16/bls12-377/mpcsetup/marshal.go @@ -0,0 +1,181 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + curve "github.com/consensys/gnark-crypto/ecc/bls12-377" + "io" +) + +// WriteTo implements io.WriterTo +func (phase1 *Phase1) WriteTo(writer io.Writer) (int64, error) { + n, err := phase1.writeTo(writer) + if err != nil { + return n, err + } + nBytes, err := writer.Write(phase1.Hash) + return int64(nBytes) + n, err +} + +func (phase1 *Phase1) writeTo(writer io.Writer) (int64, error) { + toEncode := []interface{}{ + &phase1.PublicKeys.Tau.SG, + &phase1.PublicKeys.Tau.SXG, + &phase1.PublicKeys.Tau.XR, + &phase1.PublicKeys.Alpha.SG, + &phase1.PublicKeys.Alpha.SXG, + &phase1.PublicKeys.Alpha.XR, + &phase1.PublicKeys.Beta.SG, + &phase1.PublicKeys.Beta.SXG, + &phase1.PublicKeys.Beta.XR, + phase1.Parameters.G1.Tau, + phase1.Parameters.G1.AlphaTau, + phase1.Parameters.G1.BetaTau, + phase1.Parameters.G2.Tau, + &phase1.Parameters.G2.Beta, + } + + enc := curve.NewEncoder(writer) + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + return enc.BytesWritten(), nil +} + +// ReadFrom implements io.ReaderFrom +func (phase1 *Phase1) ReadFrom(reader io.Reader) (int64, error) { + toEncode := []interface{}{ + &phase1.PublicKeys.Tau.SG, + &phase1.PublicKeys.Tau.SXG, + &phase1.PublicKeys.Tau.XR, + &phase1.PublicKeys.Alpha.SG, + &phase1.PublicKeys.Alpha.SXG, + &phase1.PublicKeys.Alpha.XR, + &phase1.PublicKeys.Beta.SG, + &phase1.PublicKeys.Beta.SXG, + &phase1.PublicKeys.Beta.XR, + &phase1.Parameters.G1.Tau, + &phase1.Parameters.G1.AlphaTau, + &phase1.Parameters.G1.BetaTau, + &phase1.Parameters.G2.Tau, + &phase1.Parameters.G2.Beta, + } + + dec := curve.NewDecoder(reader) + for _, v := range toEncode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + phase1.Hash = make([]byte, 32) + nBytes, err := reader.Read(phase1.Hash) + return dec.BytesRead() + int64(nBytes), err +} + +// WriteTo implements io.WriterTo +func (phase2 *Phase2) WriteTo(writer io.Writer) (int64, error) { + n, err := phase2.writeTo(writer) + if err != nil { + return n, err + } + nBytes, err := writer.Write(phase2.Hash) + return int64(nBytes) + n, err +} + +func (c *Phase2) writeTo(writer io.Writer) (int64, error) { + enc := curve.NewEncoder(writer) + toEncode := []interface{}{ + &c.PublicKey.SG, + &c.PublicKey.SXG, + &c.PublicKey.XR, + &c.Parameters.G1.Delta, + c.Parameters.G1.L, + c.Parameters.G1.Z, + &c.Parameters.G2.Delta, + } + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + + return enc.BytesWritten(), nil +} + +// ReadFrom implements io.ReaderFrom +func (c *Phase2) ReadFrom(reader io.Reader) (int64, error) { + dec := curve.NewDecoder(reader) + toEncode := []interface{}{ + &c.PublicKey.SG, + &c.PublicKey.SXG, + &c.PublicKey.XR, + &c.Parameters.G1.Delta, + &c.Parameters.G1.L, + &c.Parameters.G1.Z, + &c.Parameters.G2.Delta, + } + + for _, v := range toEncode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + + c.Hash = make([]byte, 32) + n, err := reader.Read(c.Hash) + return int64(n) + dec.BytesRead(), err + +} + +// WriteTo implements io.WriterTo +func (c *Phase2Evaluations) WriteTo(writer io.Writer) (int64, error) { + enc := curve.NewEncoder(writer) + toEncode := []interface{}{ + c.G1.A, + c.G1.B, + c.G2.B, + } + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + + return enc.BytesWritten(), nil +} + +// ReadFrom implements io.ReaderFrom +func (c *Phase2Evaluations) ReadFrom(reader io.Reader) (int64, error) { + dec := curve.NewDecoder(reader) + toEncode := []interface{}{ + &c.G1.A, + &c.G1.B, + &c.G2.B, + } + + for _, v := range toEncode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + + return dec.BytesRead(), nil +} diff --git a/backend/groth16/bls12-377/mpcsetup/marshal_test.go b/backend/groth16/bls12-377/mpcsetup/marshal_test.go new file mode 100644 index 0000000000..fafeac27ca --- /dev/null +++ b/backend/groth16/bls12-377/mpcsetup/marshal_test.go @@ -0,0 +1,79 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "bytes" + curve "github.com/consensys/gnark-crypto/ecc/bls12-377" + "github.com/consensys/gnark/constraint/bls12-377" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/stretchr/testify/require" + "io" + "reflect" + "testing" +) + +func TestContributionSerialization(t *testing.T) { + assert := require.New(t) + + // Phase 1 + srs1 := InitPhase1(9) + srs1.Contribute() + { + var reconstructed Phase1 + roundTripCheck(t, &srs1, &reconstructed) + } + + var myCircuit Circuit + ccs, err := frontend.Compile(curve.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) + assert.NoError(err) + + r1cs := ccs.(*cs.R1CS) + + // Phase 2 + srs2, _ := InitPhase2(r1cs, &srs1) + srs2.Contribute() + + { + var reconstructed Phase2 + roundTripCheck(t, &srs2, &reconstructed) + } +} + +func roundTripCheck(t *testing.T, from io.WriterTo, reconstructed io.ReaderFrom) { + t.Helper() + + var buf bytes.Buffer + written, err := from.WriteTo(&buf) + if err != nil { + t.Fatal("couldn't serialize", err) + } + + read, err := reconstructed.ReadFrom(&buf) + if err != nil { + t.Fatal("couldn't deserialize", err) + } + + if !reflect.DeepEqual(from, reconstructed) { + t.Fatal("reconstructed object don't match original") + } + + if written != read { + t.Fatal("bytes written / read don't match") + } +} diff --git a/backend/groth16/bls12-377/mpcsetup/phase1.go b/backend/groth16/bls12-377/mpcsetup/phase1.go new file mode 100644 index 0000000000..573aaec996 --- /dev/null +++ b/backend/groth16/bls12-377/mpcsetup/phase1.go @@ -0,0 +1,203 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "crypto/sha256" + "errors" + curve "github.com/consensys/gnark-crypto/ecc/bls12-377" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "math" + "math/big" +) + +// Phase1 represents the Phase1 of the MPC described in +// https://eprint.iacr.org/2017/1050.pdf +// +// Also known as "Powers of Tau" +type Phase1 struct { + Parameters struct { + G1 struct { + Tau []curve.G1Affine // {[τ⁰]₁, [τ¹]₁, [τ²]₁, …, [τ²ⁿ⁻²]₁} + AlphaTau []curve.G1Affine // {α[τ⁰]₁, α[τ¹]₁, α[τ²]₁, …, α[τⁿ⁻¹]₁} + BetaTau []curve.G1Affine // {β[τ⁰]₁, β[τ¹]₁, β[τ²]₁, …, β[τⁿ⁻¹]₁} + } + G2 struct { + Tau []curve.G2Affine // {[τ⁰]₂, [τ¹]₂, [τ²]₂, …, [τⁿ⁻¹]₂} + Beta curve.G2Affine // [β]₂ + } + } + PublicKeys struct { + Tau, Alpha, Beta PublicKey + } + Hash []byte // sha256 hash +} + +// InitPhase1 initialize phase 1 of the MPC. This is called once by the coordinator before +// any randomness contribution is made (see Contribute()). +func InitPhase1(power int) (phase1 Phase1) { + N := int(math.Pow(2, float64(power))) + + // Generate key pairs + var tau, alpha, beta fr.Element + tau.SetOne() + alpha.SetOne() + beta.SetOne() + phase1.PublicKeys.Tau = newPublicKey(tau, nil, 1) + phase1.PublicKeys.Alpha = newPublicKey(alpha, nil, 2) + phase1.PublicKeys.Beta = newPublicKey(beta, nil, 3) + + // First contribution use generators + _, _, g1, g2 := curve.Generators() + phase1.Parameters.G2.Beta.Set(&g2) + phase1.Parameters.G1.Tau = make([]curve.G1Affine, 2*N-1) + phase1.Parameters.G2.Tau = make([]curve.G2Affine, N) + phase1.Parameters.G1.AlphaTau = make([]curve.G1Affine, N) + phase1.Parameters.G1.BetaTau = make([]curve.G1Affine, N) + for i := 0; i < len(phase1.Parameters.G1.Tau); i++ { + phase1.Parameters.G1.Tau[i].Set(&g1) + } + for i := 0; i < len(phase1.Parameters.G2.Tau); i++ { + phase1.Parameters.G2.Tau[i].Set(&g2) + phase1.Parameters.G1.AlphaTau[i].Set(&g1) + phase1.Parameters.G1.BetaTau[i].Set(&g1) + } + + phase1.Parameters.G2.Beta.Set(&g2) + + // Compute hash of Contribution + phase1.Hash = phase1.hash() + + return +} + +// Contribute contributes randomness to the phase1 object. This mutates phase1. +func (phase1 *Phase1) Contribute() { + N := len(phase1.Parameters.G2.Tau) + + // Generate key pairs + var tau, alpha, beta fr.Element + tau.SetRandom() + alpha.SetRandom() + beta.SetRandom() + phase1.PublicKeys.Tau = newPublicKey(tau, phase1.Hash[:], 1) + phase1.PublicKeys.Alpha = newPublicKey(alpha, phase1.Hash[:], 2) + phase1.PublicKeys.Beta = newPublicKey(beta, phase1.Hash[:], 3) + + // Compute powers of τ, ατ, and βτ + taus := powers(tau, 2*N-1) + alphaTau := make([]fr.Element, N) + betaTau := make([]fr.Element, N) + for i := 0; i < N; i++ { + alphaTau[i].Mul(&taus[i], &alpha) + betaTau[i].Mul(&taus[i], &beta) + } + + // Update using previous parameters + // TODO @gbotrel working with jacobian points here will help with perf. + scaleG1InPlace(phase1.Parameters.G1.Tau, taus) + scaleG2InPlace(phase1.Parameters.G2.Tau, taus[0:N]) + scaleG1InPlace(phase1.Parameters.G1.AlphaTau, alphaTau) + scaleG1InPlace(phase1.Parameters.G1.BetaTau, betaTau) + var betaBI big.Int + beta.BigInt(&betaBI) + phase1.Parameters.G2.Beta.ScalarMultiplication(&phase1.Parameters.G2.Beta, &betaBI) + + // Compute hash of Contribution + phase1.Hash = phase1.hash() +} + +func VerifyPhase1(c0, c1 *Phase1, c ...*Phase1) error { + contribs := append([]*Phase1{c0, c1}, c...) + for i := 0; i < len(contribs)-1; i++ { + if err := verifyPhase1(contribs[i], contribs[i+1]); err != nil { + return err + } + } + return nil +} + +// verifyPhase1 checks that a contribution is based on a known previous Phase1 state. +func verifyPhase1(current, contribution *Phase1) error { + // Compute R for τ, α, β + tauR := genR(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, current.Hash[:], 1) + alphaR := genR(contribution.PublicKeys.Alpha.SG, contribution.PublicKeys.Alpha.SXG, current.Hash[:], 2) + betaR := genR(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, current.Hash[:], 3) + + // Check for knowledge of toxic parameters + if !sameRatio(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, contribution.PublicKeys.Tau.XR, tauR) { + return errors.New("couldn't verify public key of τ") + } + if !sameRatio(contribution.PublicKeys.Alpha.SG, contribution.PublicKeys.Alpha.SXG, contribution.PublicKeys.Alpha.XR, alphaR) { + return errors.New("couldn't verify public key of α") + } + if !sameRatio(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, contribution.PublicKeys.Beta.XR, betaR) { + return errors.New("couldn't verify public key of β") + } + + // Check for valid updates using previous parameters + if !sameRatio(contribution.Parameters.G1.Tau[1], current.Parameters.G1.Tau[1], tauR, contribution.PublicKeys.Tau.XR) { + return errors.New("couldn't verify that [τ]₁ is based on previous contribution") + } + if !sameRatio(contribution.Parameters.G1.AlphaTau[0], current.Parameters.G1.AlphaTau[0], alphaR, contribution.PublicKeys.Alpha.XR) { + return errors.New("couldn't verify that [α]₁ is based on previous contribution") + } + if !sameRatio(contribution.Parameters.G1.BetaTau[0], current.Parameters.G1.BetaTau[0], betaR, contribution.PublicKeys.Beta.XR) { + return errors.New("couldn't verify that [β]₁ is based on previous contribution") + } + if !sameRatio(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, contribution.Parameters.G2.Tau[1], current.Parameters.G2.Tau[1]) { + return errors.New("couldn't verify that [τ]₂ is based on previous contribution") + } + if !sameRatio(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, contribution.Parameters.G2.Beta, current.Parameters.G2.Beta) { + return errors.New("couldn't verify that [β]₂ is based on previous contribution") + } + + // Check for valid updates using powers of τ + _, _, g1, g2 := curve.Generators() + tauL1, tauL2 := linearCombinationG1(contribution.Parameters.G1.Tau) + if !sameRatio(tauL1, tauL2, contribution.Parameters.G2.Tau[1], g2) { + return errors.New("couldn't verify valid powers of τ in G₁") + } + alphaL1, alphaL2 := linearCombinationG1(contribution.Parameters.G1.AlphaTau) + if !sameRatio(alphaL1, alphaL2, contribution.Parameters.G2.Tau[1], g2) { + return errors.New("couldn't verify valid powers of α(τ) in G₁") + } + betaL1, betaL2 := linearCombinationG1(contribution.Parameters.G1.BetaTau) + if !sameRatio(betaL1, betaL2, contribution.Parameters.G2.Tau[1], g2) { + return errors.New("couldn't verify valid powers of α(τ) in G₁") + } + tau2L1, tau2L2 := linearCombinationG2(contribution.Parameters.G2.Tau) + if !sameRatio(contribution.Parameters.G1.Tau[1], g1, tau2L1, tau2L2) { + return errors.New("couldn't verify valid powers of τ in G₂") + } + + // Check hash of the contribution + h := contribution.hash() + for i := 0; i < len(h); i++ { + if h[i] != contribution.Hash[i] { + return errors.New("couldn't verify hash of contribution") + } + } + + return nil +} + +func (phase1 *Phase1) hash() []byte { + sha := sha256.New() + phase1.writeTo(sha) + return sha.Sum(nil) +} diff --git a/backend/groth16/bls12-377/mpcsetup/phase2.go b/backend/groth16/bls12-377/mpcsetup/phase2.go new file mode 100644 index 0000000000..5fde08d2c6 --- /dev/null +++ b/backend/groth16/bls12-377/mpcsetup/phase2.go @@ -0,0 +1,258 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "crypto/sha256" + "errors" + "math/big" + + curve "github.com/consensys/gnark-crypto/ecc/bls12-377" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/bls12-377" +) + +type Phase2Evaluations struct { + G1 struct { + A, B, VKK []curve.G1Affine + } + G2 struct { + B []curve.G2Affine + } +} + +type Phase2 struct { + Parameters struct { + G1 struct { + Delta curve.G1Affine + L, Z []curve.G1Affine + } + G2 struct { + Delta curve.G2Affine + } + } + PublicKey PublicKey + Hash []byte +} + +func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { + srs := srs1.Parameters + size := len(srs.G1.AlphaTau) + if size < r1cs.GetNbConstraints() { + panic("Number of constraints is larger than expected") + } + + c2 := Phase2{} + + accumulateG1 := func(res *curve.G1Affine, t constraint.Term, value *curve.G1Affine) { + cID := t.CoeffID() + switch cID { + case constraint.CoeffIdZero: + return + case constraint.CoeffIdOne: + res.Add(res, value) + case constraint.CoeffIdMinusOne: + res.Sub(res, value) + case constraint.CoeffIdTwo: + res.Add(res, value).Add(res, value) + default: + var tmp curve.G1Affine + var vBi big.Int + r1cs.Coefficients[cID].BigInt(&vBi) + tmp.ScalarMultiplication(value, &vBi) + res.Add(res, &tmp) + } + } + + accumulateG2 := func(res *curve.G2Affine, t constraint.Term, value *curve.G2Affine) { + cID := t.CoeffID() + switch cID { + case constraint.CoeffIdZero: + return + case constraint.CoeffIdOne: + res.Add(res, value) + case constraint.CoeffIdMinusOne: + res.Sub(res, value) + case constraint.CoeffIdTwo: + res.Add(res, value).Add(res, value) + default: + var tmp curve.G2Affine + var vBi big.Int + r1cs.Coefficients[cID].BigInt(&vBi) + tmp.ScalarMultiplication(value, &vBi) + res.Add(res, &tmp) + } + } + + // Prepare Lagrange coefficients of [τ...]₁, [τ...]₂, [ατ...]₁, [βτ...]₁ + coeffTau1 := LagrangeCoeffsG1(srs.G1.Tau, size) + coeffTau2 := LagrangeCoeffsG2(srs.G2.Tau, size) + coeffAlphaTau1 := LagrangeCoeffsG1(srs.G1.AlphaTau, size) + coeffBetaTau1 := LagrangeCoeffsG1(srs.G1.BetaTau, size) + + internal, secret, public := r1cs.GetNbVariables() + nWires := internal + secret + public + var evals Phase2Evaluations + evals.G1.A = make([]curve.G1Affine, nWires) + evals.G1.B = make([]curve.G1Affine, nWires) + evals.G2.B = make([]curve.G2Affine, nWires) + bA := make([]curve.G1Affine, nWires) + aB := make([]curve.G1Affine, nWires) + C := make([]curve.G1Affine, nWires) + for i, c := range r1cs.Constraints { + // A + for _, t := range c.L { + accumulateG1(&evals.G1.A[t.WireID()], t, &coeffTau1[i]) + accumulateG1(&bA[t.WireID()], t, &coeffBetaTau1[i]) + } + // B + for _, t := range c.R { + accumulateG1(&evals.G1.B[t.WireID()], t, &coeffTau1[i]) + accumulateG2(&evals.G2.B[t.WireID()], t, &coeffTau2[i]) + accumulateG1(&aB[t.WireID()], t, &coeffAlphaTau1[i]) + } + // C + for _, t := range c.O { + accumulateG1(&C[t.WireID()], t, &coeffTau1[i]) + } + } + + // Prepare default contribution + _, _, g1, g2 := curve.Generators() + c2.Parameters.G1.Delta = g1 + c2.Parameters.G2.Delta = g2 + + // Build Z in PK as τⁱ(τⁿ - 1) = τ⁽ⁱ⁺ⁿ⁾ - τⁱ for i ∈ [0, n-2] + // τⁱ(τⁿ - 1) = τ⁽ⁱ⁺ⁿ⁾ - τⁱ for i ∈ [0, n-2] + n := len(srs.G1.AlphaTau) + c2.Parameters.G1.Z = make([]curve.G1Affine, n) + for i := 0; i < n-1; i++ { + c2.Parameters.G1.Z[i].Sub(&srs.G1.Tau[i+n], &srs.G1.Tau[i]) + } + bitReverse(c2.Parameters.G1.Z) + c2.Parameters.G1.Z = c2.Parameters.G1.Z[:n-1] + + // Evaluate L + nPrivate := internal + secret + c2.Parameters.G1.L = make([]curve.G1Affine, nPrivate) + evals.G1.VKK = make([]curve.G1Affine, public) + offset := public + for i := 0; i < nWires; i++ { + var tmp curve.G1Affine + tmp.Add(&bA[i], &aB[i]) + tmp.Add(&tmp, &C[i]) + if i < public { + evals.G1.VKK[i].Set(&tmp) + } else { + c2.Parameters.G1.L[i-offset].Set(&tmp) + } + } + // Set δ public key + var delta fr.Element + delta.SetOne() + c2.PublicKey = newPublicKey(delta, nil, 1) + + // Hash initial contribution + c2.Hash = c2.hash() + return c2, evals +} + +func (c *Phase2) Contribute() { + // Sample toxic δ + var delta, deltaInv fr.Element + var deltaBI, deltaInvBI big.Int + delta.SetRandom() + deltaInv.Inverse(&delta) + + delta.BigInt(&deltaBI) + deltaInv.BigInt(&deltaInvBI) + + // Set δ public key + c.PublicKey = newPublicKey(delta, c.Hash, 1) + + // Update δ + c.Parameters.G1.Delta.ScalarMultiplication(&c.Parameters.G1.Delta, &deltaBI) + c.Parameters.G2.Delta.ScalarMultiplication(&c.Parameters.G2.Delta, &deltaBI) + + // Update Z using δ⁻¹ + for i := 0; i < len(c.Parameters.G1.Z); i++ { + c.Parameters.G1.Z[i].ScalarMultiplication(&c.Parameters.G1.Z[i], &deltaInvBI) + } + + // Update L using δ⁻¹ + for i := 0; i < len(c.Parameters.G1.L); i++ { + c.Parameters.G1.L[i].ScalarMultiplication(&c.Parameters.G1.L[i], &deltaInvBI) + } + + // 4. Hash contribution + c.Hash = c.hash() +} + +func VerifyPhase2(c0, c1 *Phase2, c ...*Phase2) error { + contribs := append([]*Phase2{c0, c1}, c...) + for i := 0; i < len(contribs)-1; i++ { + if err := verifyPhase2(contribs[i], contribs[i+1]); err != nil { + return err + } + } + return nil +} + +func verifyPhase2(current, contribution *Phase2) error { + // Compute R for δ + deltaR := genR(contribution.PublicKey.SG, contribution.PublicKey.SXG, current.Hash[:], 1) + + // Check for knowledge of δ + if !sameRatio(contribution.PublicKey.SG, contribution.PublicKey.SXG, contribution.PublicKey.XR, deltaR) { + return errors.New("couldn't verify knowledge of δ") + } + + // Check for valid updates using previous parameters + if !sameRatio(contribution.Parameters.G1.Delta, current.Parameters.G1.Delta, deltaR, contribution.PublicKey.XR) { + return errors.New("couldn't verify that [δ]₁ is based on previous contribution") + } + if !sameRatio(contribution.PublicKey.SG, contribution.PublicKey.SXG, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { + return errors.New("couldn't verify that [δ]₂ is based on previous contribution") + } + + // Check for valid updates of L and Z using + L, prevL := merge(contribution.Parameters.G1.L, current.Parameters.G1.L) + if !sameRatio(L, prevL, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { + return errors.New("couldn't verify valid updates of L using δ⁻¹") + } + Z, prevZ := merge(contribution.Parameters.G1.Z, current.Parameters.G1.Z) + if !sameRatio(Z, prevZ, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { + return errors.New("couldn't verify valid updates of L using δ⁻¹") + } + + // Check hash of the contribution + h := contribution.hash() + for i := 0; i < len(h); i++ { + if h[i] != contribution.Hash[i] { + return errors.New("couldn't verify hash of contribution") + } + } + + return nil +} + +func (c *Phase2) hash() []byte { + sha := sha256.New() + c.writeTo(sha) + return sha.Sum(nil) +} diff --git a/backend/groth16/bls12-377/mpcsetup/setup.go b/backend/groth16/bls12-377/mpcsetup/setup.go new file mode 100644 index 0000000000..683369c871 --- /dev/null +++ b/backend/groth16/bls12-377/mpcsetup/setup.go @@ -0,0 +1,97 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + curve "github.com/consensys/gnark-crypto/ecc/bls12-377" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft" + groth16 "github.com/consensys/gnark/backend/groth16/bls12-377" +) + +func ExtractKeys(srs1 *Phase1, srs2 *Phase2, evals *Phase2Evaluations, nConstraints int) (pk groth16.ProvingKey, vk groth16.VerifyingKey) { + _, _, _, g2 := curve.Generators() + + // Initialize PK + pk.Domain = *fft.NewDomain(uint64(nConstraints)) + pk.G1.Alpha.Set(&srs1.Parameters.G1.AlphaTau[0]) + pk.G1.Beta.Set(&srs1.Parameters.G1.BetaTau[0]) + pk.G1.Delta.Set(&srs2.Parameters.G1.Delta) + pk.G1.Z = srs2.Parameters.G1.Z + bitReverse(pk.G1.Z) + + pk.G1.K = srs2.Parameters.G1.L + pk.G2.Beta.Set(&srs1.Parameters.G2.Beta) + pk.G2.Delta.Set(&srs2.Parameters.G2.Delta) + + // Filter out infinity points + nWires := len(evals.G1.A) + pk.InfinityA = make([]bool, nWires) + A := make([]curve.G1Affine, nWires) + j := 0 + for i, e := range evals.G1.A { + if e.IsInfinity() { + pk.InfinityA[i] = true + continue + } + A[j] = evals.G1.A[i] + j++ + } + pk.G1.A = A[:j] + pk.NbInfinityA = uint64(nWires - j) + + pk.InfinityB = make([]bool, nWires) + B := make([]curve.G1Affine, nWires) + j = 0 + for i, e := range evals.G1.B { + if e.IsInfinity() { + pk.InfinityB[i] = true + continue + } + B[j] = evals.G1.B[i] + j++ + } + pk.G1.B = B[:j] + pk.NbInfinityB = uint64(nWires - j) + + B2 := make([]curve.G2Affine, nWires) + j = 0 + for i, e := range evals.G2.B { + if e.IsInfinity() { + // pk.InfinityB[i] = true should be the same as in B + continue + } + B2[j] = evals.G2.B[i] + j++ + } + pk.G2.B = B2[:j] + + // Initialize VK + vk.G1.Alpha.Set(&srs1.Parameters.G1.AlphaTau[0]) + vk.G1.Beta.Set(&srs1.Parameters.G1.BetaTau[0]) + vk.G1.Delta.Set(&srs2.Parameters.G1.Delta) + vk.G2.Beta.Set(&srs1.Parameters.G2.Beta) + vk.G2.Delta.Set(&srs2.Parameters.G2.Delta) + vk.G2.Gamma.Set(&g2) + vk.G1.K = evals.G1.VKK + + // sets e, -[δ]2, -[γ]2 + if err := vk.Precompute(); err != nil { + panic(err) + } + + return pk, vk +} diff --git a/backend/groth16/bls12-377/mpcsetup/setup_test.go b/backend/groth16/bls12-377/mpcsetup/setup_test.go new file mode 100644 index 0000000000..6cfb710888 --- /dev/null +++ b/backend/groth16/bls12-377/mpcsetup/setup_test.go @@ -0,0 +1,199 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + curve "github.com/consensys/gnark-crypto/ecc/bls12-377" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/consensys/gnark/constraint/bls12-377" + "testing" + + "github.com/consensys/gnark/backend/groth16" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/std/hash/mimc" + "github.com/stretchr/testify/require" + + native_mimc "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/mimc" +) + +func TestSetupCircuit(t *testing.T) { + if testing.Short() { + t.Skip() + } + const ( + nContributionsPhase1 = 3 + nContributionsPhase2 = 3 + power = 9 + ) + + assert := require.New(t) + + srs1 := InitPhase1(power) + + // Make and verify contributions for phase1 + for i := 1; i < nContributionsPhase1; i++ { + // we clone test purposes; but in practice, participant will receive a []byte, deserialize it, + // add his contribution and send back to coordinator. + prev := srs1.clone() + + srs1.Contribute() + assert.NoError(VerifyPhase1(&prev, &srs1)) + } + + // Compile the circuit + var myCircuit Circuit + ccs, err := frontend.Compile(curve.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) + assert.NoError(err) + + var evals Phase2Evaluations + r1cs := ccs.(*cs.R1CS) + + // Prepare for phase-2 + srs2, evals := InitPhase2(r1cs, &srs1) + + // Make and verify contributions for phase1 + for i := 1; i < nContributionsPhase2; i++ { + // we clone for test purposes; but in practice, participant will receive a []byte, deserialize it, + // add his contribution and send back to coordinator. + prev := srs2.clone() + + srs2.Contribute() + assert.NoError(VerifyPhase2(&prev, &srs2)) + } + + // Extract the proving and verifying keys + pk, vk := ExtractKeys(&srs1, &srs2, &evals, ccs.GetNbConstraints()) + + // Build the witness + var preImage, hash fr.Element + { + m := native_mimc.NewMiMC() + m.Write(preImage.Marshal()) + hash.SetBytes(m.Sum(nil)) + } + + witness, err := frontend.NewWitness(&Circuit{PreImage: preImage, Hash: hash}, curve.ID.ScalarField()) + assert.NoError(err) + + pubWitness, err := witness.Public() + assert.NoError(err) + + // groth16: ensure proof is verified + proof, err := groth16.Prove(ccs, &pk, witness) + assert.NoError(err) + + err = groth16.Verify(proof, &vk, pubWitness) + assert.NoError(err) +} + +func BenchmarkPhase1(b *testing.B) { + const power = 14 + + b.Run("init", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = InitPhase1(power) + } + }) + + b.Run("contrib", func(b *testing.B) { + srs1 := InitPhase1(power) + b.ResetTimer() + for i := 0; i < b.N; i++ { + srs1.Contribute() + } + }) + +} + +func BenchmarkPhase2(b *testing.B) { + const power = 14 + srs1 := InitPhase1(power) + srs1.Contribute() + + var myCircuit Circuit + ccs, err := frontend.Compile(curve.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) + if err != nil { + b.Fatal(err) + } + + r1cs := ccs.(*cs.R1CS) + + b.Run("init", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, _ = InitPhase2(r1cs, &srs1) + } + }) + + b.Run("contrib", func(b *testing.B) { + srs2, _ := InitPhase2(r1cs, &srs1) + b.ResetTimer() + for i := 0; i < b.N; i++ { + srs2.Contribute() + } + }) + +} + +// Circuit defines a pre-image knowledge proof +// mimc(secret preImage) = public hash +type Circuit struct { + PreImage frontend.Variable + Hash frontend.Variable `gnark:",public"` +} + +// Define declares the circuit's constraints +// Hash = mimc(PreImage) +func (circuit *Circuit) Define(api frontend.API) error { + // hash function + mimc, _ := mimc.NewMiMC(api) + + // specify constraints + mimc.Write(circuit.PreImage) + api.AssertIsEqual(circuit.Hash, mimc.Sum()) + + return nil +} + +func (phase1 *Phase1) clone() Phase1 { + r := Phase1{} + r.Parameters.G1.Tau = append(r.Parameters.G1.Tau, phase1.Parameters.G1.Tau...) + r.Parameters.G1.AlphaTau = append(r.Parameters.G1.AlphaTau, phase1.Parameters.G1.AlphaTau...) + r.Parameters.G1.BetaTau = append(r.Parameters.G1.BetaTau, phase1.Parameters.G1.BetaTau...) + + r.Parameters.G2.Tau = append(r.Parameters.G2.Tau, phase1.Parameters.G2.Tau...) + r.Parameters.G2.Beta = phase1.Parameters.G2.Beta + + r.PublicKeys = phase1.PublicKeys + r.Hash = append(r.Hash, phase1.Hash...) + + return r +} + +func (phase2 *Phase2) clone() Phase2 { + r := Phase2{} + r.Parameters.G1.Delta = phase2.Parameters.G1.Delta + r.Parameters.G1.L = append(r.Parameters.G1.L, phase2.Parameters.G1.L...) + r.Parameters.G1.Z = append(r.Parameters.G1.Z, phase2.Parameters.G1.Z...) + r.Parameters.G2.Delta = phase2.Parameters.G2.Delta + r.PublicKey = phase2.PublicKey + r.Hash = append(r.Hash, phase2.Hash...) + + return r +} diff --git a/backend/groth16/bls12-377/mpcsetup/utils.go b/backend/groth16/bls12-377/mpcsetup/utils.go new file mode 100644 index 0000000000..978b2ecbde --- /dev/null +++ b/backend/groth16/bls12-377/mpcsetup/utils.go @@ -0,0 +1,170 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "bytes" + "math/big" + "math/bits" + "runtime" + + "github.com/consensys/gnark-crypto/ecc" + curve "github.com/consensys/gnark-crypto/ecc/bls12-377" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/consensys/gnark/internal/utils" +) + +type PublicKey struct { + SG curve.G1Affine + SXG curve.G1Affine + XR curve.G2Affine +} + +func newPublicKey(x fr.Element, challenge []byte, dst byte) PublicKey { + var pk PublicKey + _, _, g1, _ := curve.Generators() + + var s fr.Element + var sBi big.Int + s.SetRandom() + s.BigInt(&sBi) + pk.SG.ScalarMultiplication(&g1, &sBi) + + // compute x*sG1 + var xBi big.Int + x.BigInt(&xBi) + pk.SXG.ScalarMultiplication(&pk.SG, &xBi) + + // generate R based on sG1, sxG1, challenge, and domain separation tag (tau, alpha or beta) + R := genR(pk.SG, pk.SXG, challenge, dst) + + // compute x*spG2 + pk.XR.ScalarMultiplication(&R, &xBi) + return pk +} + +func bitReverse[T any](a []T) { + n := uint64(len(a)) + nn := uint64(64 - bits.TrailingZeros64(n)) + + for i := uint64(0); i < n; i++ { + irev := bits.Reverse64(i) >> nn + if irev > i { + a[i], a[irev] = a[irev], a[i] + } + } +} + +// Returns [1, a, a², ..., aⁿ⁻¹ ] in Montgomery form +func powers(a fr.Element, n int) []fr.Element { + result := make([]fr.Element, n) + result[0] = fr.NewElement(1) + for i := 1; i < n; i++ { + result[i].Mul(&result[i-1], &a) + } + return result +} + +// Returns [aᵢAᵢ, ...] in G1 +func scaleG1InPlace(A []curve.G1Affine, a []fr.Element) { + utils.Parallelize(len(A), func(start, end int) { + var tmp big.Int + for i := start; i < end; i++ { + a[i].BigInt(&tmp) + A[i].ScalarMultiplication(&A[i], &tmp) + } + }) +} + +// Returns [aᵢAᵢ, ...] in G2 +func scaleG2InPlace(A []curve.G2Affine, a []fr.Element) { + utils.Parallelize(len(A), func(start, end int) { + var tmp big.Int + for i := start; i < end; i++ { + a[i].BigInt(&tmp) + A[i].ScalarMultiplication(&A[i], &tmp) + } + }) +} + +// Check e(a₁, a₂) = e(b₁, b₂) +func sameRatio(a1, b1 curve.G1Affine, a2, b2 curve.G2Affine) bool { + if !a1.IsInSubGroup() || !b1.IsInSubGroup() || !a2.IsInSubGroup() || !b2.IsInSubGroup() { + panic("invalid point not in subgroup") + } + var na2 curve.G2Affine + na2.Neg(&a2) + res, err := curve.PairingCheck( + []curve.G1Affine{a1, b1}, + []curve.G2Affine{na2, b2}) + if err != nil { + panic(err) + } + return res +} + +// returns a = ∑ rᵢAᵢ, b = ∑ rᵢBᵢ +func merge(A, B []curve.G1Affine) (a, b curve.G1Affine) { + nc := runtime.NumCPU() + r := make([]fr.Element, len(A)) + for i := 0; i < len(A); i++ { + r[i].SetRandom() + } + a.MultiExp(A, r, ecc.MultiExpConfig{NbTasks: nc / 2}) + b.MultiExp(B, r, ecc.MultiExpConfig{NbTasks: nc / 2}) + return +} + +// L1 = ∑ rᵢAᵢ, L2 = ∑ rᵢAᵢ₊₁ in G1 +func linearCombinationG1(A []curve.G1Affine) (L1, L2 curve.G1Affine) { + nc := runtime.NumCPU() + n := len(A) + r := make([]fr.Element, n-1) + for i := 0; i < n-1; i++ { + r[i].SetRandom() + } + L1.MultiExp(A[:n-1], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + L2.MultiExp(A[1:], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + return +} + +// L1 = ∑ rᵢAᵢ, L2 = ∑ rᵢAᵢ₊₁ in G2 +func linearCombinationG2(A []curve.G2Affine) (L1, L2 curve.G2Affine) { + nc := runtime.NumCPU() + n := len(A) + r := make([]fr.Element, n-1) + for i := 0; i < n-1; i++ { + r[i].SetRandom() + } + L1.MultiExp(A[:n-1], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + L2.MultiExp(A[1:], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + return +} + +// Generate R in G₂ as Hash(gˢ, gˢˣ, challenge, dst) +func genR(sG1, sxG1 curve.G1Affine, challenge []byte, dst byte) curve.G2Affine { + var buf bytes.Buffer + buf.Grow(len(challenge) + curve.SizeOfG1AffineUncompressed*2) + buf.Write(sG1.Marshal()) + buf.Write(sxG1.Marshal()) + buf.Write(challenge) + spG2, err := curve.HashToG2(buf.Bytes(), []byte{dst}) + if err != nil { + panic(err) + } + return spG2 +} diff --git a/backend/groth16/bls12-381/mpcsetup/lagrange.go b/backend/groth16/bls12-381/mpcsetup/lagrange.go new file mode 100644 index 0000000000..48c60bee7d --- /dev/null +++ b/backend/groth16/bls12-381/mpcsetup/lagrange.go @@ -0,0 +1,216 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "math/big" + "math/bits" + "runtime" + + "github.com/consensys/gnark-crypto/ecc" + curve "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/fft" + "github.com/consensys/gnark/internal/utils" +) + +func LagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { + coeffs := make([]curve.G1Affine, size) + copy(coeffs, powers[:size]) + domain := fft.NewDomain(uint64(size)) + numCPU := uint64(runtime.NumCPU()) + maxSplits := bits.TrailingZeros64(ecc.NextPowerOfTwo(numCPU)) + + difFFTG1(coeffs, domain.TwiddlesInv, 0, maxSplits, nil) + bitReverse(coeffs) + + var invBigint big.Int + domain.CardinalityInv.BigInt(&invBigint) + + utils.Parallelize(size, func(start, end int) { + for i := start; i < end; i++ { + coeffs[i].ScalarMultiplication(&coeffs[i], &invBigint) + } + }) + return coeffs +} + +func LagrangeCoeffsG2(powers []curve.G2Affine, size int) []curve.G2Affine { + coeffs := make([]curve.G2Affine, size) + copy(coeffs, powers[:size]) + domain := fft.NewDomain(uint64(size)) + numCPU := uint64(runtime.NumCPU()) + maxSplits := bits.TrailingZeros64(ecc.NextPowerOfTwo(numCPU)) + + difFFTG2(coeffs, domain.TwiddlesInv, 0, maxSplits, nil) + bitReverse(coeffs) + + var invBigint big.Int + domain.CardinalityInv.BigInt(&invBigint) + + utils.Parallelize(size, func(start, end int) { + for i := start; i < end; i++ { + coeffs[i].ScalarMultiplication(&coeffs[i], &invBigint) + } + }) + return coeffs +} + +func butterflyG1(a *curve.G1Affine, b *curve.G1Affine) { + t := *a + a.Add(a, b) + b.Sub(&t, b) +} + +func butterflyG2(a *curve.G2Affine, b *curve.G2Affine) { + t := *a + a.Add(a, b) + b.Sub(&t, b) +} + +// kerDIF8 is a kernel that process a FFT of size 8 +func kerDIF8G1(a []curve.G1Affine, twiddles [][]fr.Element, stage int) { + butterflyG1(&a[0], &a[4]) + butterflyG1(&a[1], &a[5]) + butterflyG1(&a[2], &a[6]) + butterflyG1(&a[3], &a[7]) + + var twiddle big.Int + twiddles[stage+0][1].BigInt(&twiddle) + a[5].ScalarMultiplication(&a[5], &twiddle) + twiddles[stage+0][2].BigInt(&twiddle) + a[6].ScalarMultiplication(&a[6], &twiddle) + twiddles[stage+0][3].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG1(&a[0], &a[2]) + butterflyG1(&a[1], &a[3]) + butterflyG1(&a[4], &a[6]) + butterflyG1(&a[5], &a[7]) + twiddles[stage+1][1].BigInt(&twiddle) + a[3].ScalarMultiplication(&a[3], &twiddle) + twiddles[stage+1][1].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG1(&a[0], &a[1]) + butterflyG1(&a[2], &a[3]) + butterflyG1(&a[4], &a[5]) + butterflyG1(&a[6], &a[7]) +} + +// kerDIF8 is a kernel that process a FFT of size 8 +func kerDIF8G2(a []curve.G2Affine, twiddles [][]fr.Element, stage int) { + butterflyG2(&a[0], &a[4]) + butterflyG2(&a[1], &a[5]) + butterflyG2(&a[2], &a[6]) + butterflyG2(&a[3], &a[7]) + + var twiddle big.Int + twiddles[stage+0][1].BigInt(&twiddle) + a[5].ScalarMultiplication(&a[5], &twiddle) + twiddles[stage+0][2].BigInt(&twiddle) + a[6].ScalarMultiplication(&a[6], &twiddle) + twiddles[stage+0][3].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG2(&a[0], &a[2]) + butterflyG2(&a[1], &a[3]) + butterflyG2(&a[4], &a[6]) + butterflyG2(&a[5], &a[7]) + twiddles[stage+1][1].BigInt(&twiddle) + a[3].ScalarMultiplication(&a[3], &twiddle) + twiddles[stage+1][1].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG2(&a[0], &a[1]) + butterflyG2(&a[2], &a[3]) + butterflyG2(&a[4], &a[5]) + butterflyG2(&a[6], &a[7]) +} + +func difFFTG1(a []curve.G1Affine, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { + if chDone != nil { + defer close(chDone) + } + + n := len(a) + if n == 1 { + return + } else if n == 8 { + kerDIF8G1(a, twiddles, stage) + return + } + m := n >> 1 + + butterflyG1(&a[0], &a[m]) + + var twiddle big.Int + for i := 1; i < m; i++ { + butterflyG1(&a[i], &a[i+m]) + twiddles[stage][i].BigInt(&twiddle) + a[i+m].ScalarMultiplication(&a[i+m], &twiddle) + } + + if m == 1 { + return + } + + nextStage := stage + 1 + if stage < maxSplits { + chDone := make(chan struct{}, 1) + go difFFTG1(a[m:n], twiddles, nextStage, maxSplits, chDone) + difFFTG1(a[0:m], twiddles, nextStage, maxSplits, nil) + <-chDone + } else { + difFFTG1(a[0:m], twiddles, nextStage, maxSplits, nil) + difFFTG1(a[m:n], twiddles, nextStage, maxSplits, nil) + } +} +func difFFTG2(a []curve.G2Affine, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { + if chDone != nil { + defer close(chDone) + } + + n := len(a) + if n == 1 { + return + } else if n == 8 { + kerDIF8G2(a, twiddles, stage) + return + } + m := n >> 1 + + butterflyG2(&a[0], &a[m]) + + var twiddle big.Int + for i := 1; i < m; i++ { + butterflyG2(&a[i], &a[i+m]) + twiddles[stage][i].BigInt(&twiddle) + a[i+m].ScalarMultiplication(&a[i+m], &twiddle) + } + + if m == 1 { + return + } + + nextStage := stage + 1 + if stage < maxSplits { + chDone := make(chan struct{}, 1) + go difFFTG2(a[m:n], twiddles, nextStage, maxSplits, chDone) + difFFTG2(a[0:m], twiddles, nextStage, maxSplits, nil) + <-chDone + } else { + difFFTG2(a[0:m], twiddles, nextStage, maxSplits, nil) + difFFTG2(a[m:n], twiddles, nextStage, maxSplits, nil) + } +} diff --git a/backend/groth16/bls12-381/mpcsetup/marshal.go b/backend/groth16/bls12-381/mpcsetup/marshal.go new file mode 100644 index 0000000000..0aa64ea1f0 --- /dev/null +++ b/backend/groth16/bls12-381/mpcsetup/marshal.go @@ -0,0 +1,181 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + curve "github.com/consensys/gnark-crypto/ecc/bls12-381" + "io" +) + +// WriteTo implements io.WriterTo +func (phase1 *Phase1) WriteTo(writer io.Writer) (int64, error) { + n, err := phase1.writeTo(writer) + if err != nil { + return n, err + } + nBytes, err := writer.Write(phase1.Hash) + return int64(nBytes) + n, err +} + +func (phase1 *Phase1) writeTo(writer io.Writer) (int64, error) { + toEncode := []interface{}{ + &phase1.PublicKeys.Tau.SG, + &phase1.PublicKeys.Tau.SXG, + &phase1.PublicKeys.Tau.XR, + &phase1.PublicKeys.Alpha.SG, + &phase1.PublicKeys.Alpha.SXG, + &phase1.PublicKeys.Alpha.XR, + &phase1.PublicKeys.Beta.SG, + &phase1.PublicKeys.Beta.SXG, + &phase1.PublicKeys.Beta.XR, + phase1.Parameters.G1.Tau, + phase1.Parameters.G1.AlphaTau, + phase1.Parameters.G1.BetaTau, + phase1.Parameters.G2.Tau, + &phase1.Parameters.G2.Beta, + } + + enc := curve.NewEncoder(writer) + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + return enc.BytesWritten(), nil +} + +// ReadFrom implements io.ReaderFrom +func (phase1 *Phase1) ReadFrom(reader io.Reader) (int64, error) { + toEncode := []interface{}{ + &phase1.PublicKeys.Tau.SG, + &phase1.PublicKeys.Tau.SXG, + &phase1.PublicKeys.Tau.XR, + &phase1.PublicKeys.Alpha.SG, + &phase1.PublicKeys.Alpha.SXG, + &phase1.PublicKeys.Alpha.XR, + &phase1.PublicKeys.Beta.SG, + &phase1.PublicKeys.Beta.SXG, + &phase1.PublicKeys.Beta.XR, + &phase1.Parameters.G1.Tau, + &phase1.Parameters.G1.AlphaTau, + &phase1.Parameters.G1.BetaTau, + &phase1.Parameters.G2.Tau, + &phase1.Parameters.G2.Beta, + } + + dec := curve.NewDecoder(reader) + for _, v := range toEncode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + phase1.Hash = make([]byte, 32) + nBytes, err := reader.Read(phase1.Hash) + return dec.BytesRead() + int64(nBytes), err +} + +// WriteTo implements io.WriterTo +func (phase2 *Phase2) WriteTo(writer io.Writer) (int64, error) { + n, err := phase2.writeTo(writer) + if err != nil { + return n, err + } + nBytes, err := writer.Write(phase2.Hash) + return int64(nBytes) + n, err +} + +func (c *Phase2) writeTo(writer io.Writer) (int64, error) { + enc := curve.NewEncoder(writer) + toEncode := []interface{}{ + &c.PublicKey.SG, + &c.PublicKey.SXG, + &c.PublicKey.XR, + &c.Parameters.G1.Delta, + c.Parameters.G1.L, + c.Parameters.G1.Z, + &c.Parameters.G2.Delta, + } + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + + return enc.BytesWritten(), nil +} + +// ReadFrom implements io.ReaderFrom +func (c *Phase2) ReadFrom(reader io.Reader) (int64, error) { + dec := curve.NewDecoder(reader) + toEncode := []interface{}{ + &c.PublicKey.SG, + &c.PublicKey.SXG, + &c.PublicKey.XR, + &c.Parameters.G1.Delta, + &c.Parameters.G1.L, + &c.Parameters.G1.Z, + &c.Parameters.G2.Delta, + } + + for _, v := range toEncode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + + c.Hash = make([]byte, 32) + n, err := reader.Read(c.Hash) + return int64(n) + dec.BytesRead(), err + +} + +// WriteTo implements io.WriterTo +func (c *Phase2Evaluations) WriteTo(writer io.Writer) (int64, error) { + enc := curve.NewEncoder(writer) + toEncode := []interface{}{ + c.G1.A, + c.G1.B, + c.G2.B, + } + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + + return enc.BytesWritten(), nil +} + +// ReadFrom implements io.ReaderFrom +func (c *Phase2Evaluations) ReadFrom(reader io.Reader) (int64, error) { + dec := curve.NewDecoder(reader) + toEncode := []interface{}{ + &c.G1.A, + &c.G1.B, + &c.G2.B, + } + + for _, v := range toEncode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + + return dec.BytesRead(), nil +} diff --git a/backend/groth16/bls12-381/mpcsetup/marshal_test.go b/backend/groth16/bls12-381/mpcsetup/marshal_test.go new file mode 100644 index 0000000000..9432d50a6a --- /dev/null +++ b/backend/groth16/bls12-381/mpcsetup/marshal_test.go @@ -0,0 +1,79 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "bytes" + curve "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark/constraint/bls12-381" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/stretchr/testify/require" + "io" + "reflect" + "testing" +) + +func TestContributionSerialization(t *testing.T) { + assert := require.New(t) + + // Phase 1 + srs1 := InitPhase1(9) + srs1.Contribute() + { + var reconstructed Phase1 + roundTripCheck(t, &srs1, &reconstructed) + } + + var myCircuit Circuit + ccs, err := frontend.Compile(curve.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) + assert.NoError(err) + + r1cs := ccs.(*cs.R1CS) + + // Phase 2 + srs2, _ := InitPhase2(r1cs, &srs1) + srs2.Contribute() + + { + var reconstructed Phase2 + roundTripCheck(t, &srs2, &reconstructed) + } +} + +func roundTripCheck(t *testing.T, from io.WriterTo, reconstructed io.ReaderFrom) { + t.Helper() + + var buf bytes.Buffer + written, err := from.WriteTo(&buf) + if err != nil { + t.Fatal("couldn't serialize", err) + } + + read, err := reconstructed.ReadFrom(&buf) + if err != nil { + t.Fatal("couldn't deserialize", err) + } + + if !reflect.DeepEqual(from, reconstructed) { + t.Fatal("reconstructed object don't match original") + } + + if written != read { + t.Fatal("bytes written / read don't match") + } +} diff --git a/backend/groth16/bls12-381/mpcsetup/phase1.go b/backend/groth16/bls12-381/mpcsetup/phase1.go new file mode 100644 index 0000000000..14cef5f605 --- /dev/null +++ b/backend/groth16/bls12-381/mpcsetup/phase1.go @@ -0,0 +1,203 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "crypto/sha256" + "errors" + curve "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + "math" + "math/big" +) + +// Phase1 represents the Phase1 of the MPC described in +// https://eprint.iacr.org/2017/1050.pdf +// +// Also known as "Powers of Tau" +type Phase1 struct { + Parameters struct { + G1 struct { + Tau []curve.G1Affine // {[τ⁰]₁, [τ¹]₁, [τ²]₁, …, [τ²ⁿ⁻²]₁} + AlphaTau []curve.G1Affine // {α[τ⁰]₁, α[τ¹]₁, α[τ²]₁, …, α[τⁿ⁻¹]₁} + BetaTau []curve.G1Affine // {β[τ⁰]₁, β[τ¹]₁, β[τ²]₁, …, β[τⁿ⁻¹]₁} + } + G2 struct { + Tau []curve.G2Affine // {[τ⁰]₂, [τ¹]₂, [τ²]₂, …, [τⁿ⁻¹]₂} + Beta curve.G2Affine // [β]₂ + } + } + PublicKeys struct { + Tau, Alpha, Beta PublicKey + } + Hash []byte // sha256 hash +} + +// InitPhase1 initialize phase 1 of the MPC. This is called once by the coordinator before +// any randomness contribution is made (see Contribute()). +func InitPhase1(power int) (phase1 Phase1) { + N := int(math.Pow(2, float64(power))) + + // Generate key pairs + var tau, alpha, beta fr.Element + tau.SetOne() + alpha.SetOne() + beta.SetOne() + phase1.PublicKeys.Tau = newPublicKey(tau, nil, 1) + phase1.PublicKeys.Alpha = newPublicKey(alpha, nil, 2) + phase1.PublicKeys.Beta = newPublicKey(beta, nil, 3) + + // First contribution use generators + _, _, g1, g2 := curve.Generators() + phase1.Parameters.G2.Beta.Set(&g2) + phase1.Parameters.G1.Tau = make([]curve.G1Affine, 2*N-1) + phase1.Parameters.G2.Tau = make([]curve.G2Affine, N) + phase1.Parameters.G1.AlphaTau = make([]curve.G1Affine, N) + phase1.Parameters.G1.BetaTau = make([]curve.G1Affine, N) + for i := 0; i < len(phase1.Parameters.G1.Tau); i++ { + phase1.Parameters.G1.Tau[i].Set(&g1) + } + for i := 0; i < len(phase1.Parameters.G2.Tau); i++ { + phase1.Parameters.G2.Tau[i].Set(&g2) + phase1.Parameters.G1.AlphaTau[i].Set(&g1) + phase1.Parameters.G1.BetaTau[i].Set(&g1) + } + + phase1.Parameters.G2.Beta.Set(&g2) + + // Compute hash of Contribution + phase1.Hash = phase1.hash() + + return +} + +// Contribute contributes randomness to the phase1 object. This mutates phase1. +func (phase1 *Phase1) Contribute() { + N := len(phase1.Parameters.G2.Tau) + + // Generate key pairs + var tau, alpha, beta fr.Element + tau.SetRandom() + alpha.SetRandom() + beta.SetRandom() + phase1.PublicKeys.Tau = newPublicKey(tau, phase1.Hash[:], 1) + phase1.PublicKeys.Alpha = newPublicKey(alpha, phase1.Hash[:], 2) + phase1.PublicKeys.Beta = newPublicKey(beta, phase1.Hash[:], 3) + + // Compute powers of τ, ατ, and βτ + taus := powers(tau, 2*N-1) + alphaTau := make([]fr.Element, N) + betaTau := make([]fr.Element, N) + for i := 0; i < N; i++ { + alphaTau[i].Mul(&taus[i], &alpha) + betaTau[i].Mul(&taus[i], &beta) + } + + // Update using previous parameters + // TODO @gbotrel working with jacobian points here will help with perf. + scaleG1InPlace(phase1.Parameters.G1.Tau, taus) + scaleG2InPlace(phase1.Parameters.G2.Tau, taus[0:N]) + scaleG1InPlace(phase1.Parameters.G1.AlphaTau, alphaTau) + scaleG1InPlace(phase1.Parameters.G1.BetaTau, betaTau) + var betaBI big.Int + beta.BigInt(&betaBI) + phase1.Parameters.G2.Beta.ScalarMultiplication(&phase1.Parameters.G2.Beta, &betaBI) + + // Compute hash of Contribution + phase1.Hash = phase1.hash() +} + +func VerifyPhase1(c0, c1 *Phase1, c ...*Phase1) error { + contribs := append([]*Phase1{c0, c1}, c...) + for i := 0; i < len(contribs)-1; i++ { + if err := verifyPhase1(contribs[i], contribs[i+1]); err != nil { + return err + } + } + return nil +} + +// verifyPhase1 checks that a contribution is based on a known previous Phase1 state. +func verifyPhase1(current, contribution *Phase1) error { + // Compute R for τ, α, β + tauR := genR(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, current.Hash[:], 1) + alphaR := genR(contribution.PublicKeys.Alpha.SG, contribution.PublicKeys.Alpha.SXG, current.Hash[:], 2) + betaR := genR(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, current.Hash[:], 3) + + // Check for knowledge of toxic parameters + if !sameRatio(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, contribution.PublicKeys.Tau.XR, tauR) { + return errors.New("couldn't verify public key of τ") + } + if !sameRatio(contribution.PublicKeys.Alpha.SG, contribution.PublicKeys.Alpha.SXG, contribution.PublicKeys.Alpha.XR, alphaR) { + return errors.New("couldn't verify public key of α") + } + if !sameRatio(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, contribution.PublicKeys.Beta.XR, betaR) { + return errors.New("couldn't verify public key of β") + } + + // Check for valid updates using previous parameters + if !sameRatio(contribution.Parameters.G1.Tau[1], current.Parameters.G1.Tau[1], tauR, contribution.PublicKeys.Tau.XR) { + return errors.New("couldn't verify that [τ]₁ is based on previous contribution") + } + if !sameRatio(contribution.Parameters.G1.AlphaTau[0], current.Parameters.G1.AlphaTau[0], alphaR, contribution.PublicKeys.Alpha.XR) { + return errors.New("couldn't verify that [α]₁ is based on previous contribution") + } + if !sameRatio(contribution.Parameters.G1.BetaTau[0], current.Parameters.G1.BetaTau[0], betaR, contribution.PublicKeys.Beta.XR) { + return errors.New("couldn't verify that [β]₁ is based on previous contribution") + } + if !sameRatio(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, contribution.Parameters.G2.Tau[1], current.Parameters.G2.Tau[1]) { + return errors.New("couldn't verify that [τ]₂ is based on previous contribution") + } + if !sameRatio(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, contribution.Parameters.G2.Beta, current.Parameters.G2.Beta) { + return errors.New("couldn't verify that [β]₂ is based on previous contribution") + } + + // Check for valid updates using powers of τ + _, _, g1, g2 := curve.Generators() + tauL1, tauL2 := linearCombinationG1(contribution.Parameters.G1.Tau) + if !sameRatio(tauL1, tauL2, contribution.Parameters.G2.Tau[1], g2) { + return errors.New("couldn't verify valid powers of τ in G₁") + } + alphaL1, alphaL2 := linearCombinationG1(contribution.Parameters.G1.AlphaTau) + if !sameRatio(alphaL1, alphaL2, contribution.Parameters.G2.Tau[1], g2) { + return errors.New("couldn't verify valid powers of α(τ) in G₁") + } + betaL1, betaL2 := linearCombinationG1(contribution.Parameters.G1.BetaTau) + if !sameRatio(betaL1, betaL2, contribution.Parameters.G2.Tau[1], g2) { + return errors.New("couldn't verify valid powers of α(τ) in G₁") + } + tau2L1, tau2L2 := linearCombinationG2(contribution.Parameters.G2.Tau) + if !sameRatio(contribution.Parameters.G1.Tau[1], g1, tau2L1, tau2L2) { + return errors.New("couldn't verify valid powers of τ in G₂") + } + + // Check hash of the contribution + h := contribution.hash() + for i := 0; i < len(h); i++ { + if h[i] != contribution.Hash[i] { + return errors.New("couldn't verify hash of contribution") + } + } + + return nil +} + +func (phase1 *Phase1) hash() []byte { + sha := sha256.New() + phase1.writeTo(sha) + return sha.Sum(nil) +} diff --git a/backend/groth16/bls12-381/mpcsetup/phase2.go b/backend/groth16/bls12-381/mpcsetup/phase2.go new file mode 100644 index 0000000000..1d585aac1d --- /dev/null +++ b/backend/groth16/bls12-381/mpcsetup/phase2.go @@ -0,0 +1,258 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "crypto/sha256" + "errors" + "math/big" + + curve "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/bls12-381" +) + +type Phase2Evaluations struct { + G1 struct { + A, B, VKK []curve.G1Affine + } + G2 struct { + B []curve.G2Affine + } +} + +type Phase2 struct { + Parameters struct { + G1 struct { + Delta curve.G1Affine + L, Z []curve.G1Affine + } + G2 struct { + Delta curve.G2Affine + } + } + PublicKey PublicKey + Hash []byte +} + +func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { + srs := srs1.Parameters + size := len(srs.G1.AlphaTau) + if size < r1cs.GetNbConstraints() { + panic("Number of constraints is larger than expected") + } + + c2 := Phase2{} + + accumulateG1 := func(res *curve.G1Affine, t constraint.Term, value *curve.G1Affine) { + cID := t.CoeffID() + switch cID { + case constraint.CoeffIdZero: + return + case constraint.CoeffIdOne: + res.Add(res, value) + case constraint.CoeffIdMinusOne: + res.Sub(res, value) + case constraint.CoeffIdTwo: + res.Add(res, value).Add(res, value) + default: + var tmp curve.G1Affine + var vBi big.Int + r1cs.Coefficients[cID].BigInt(&vBi) + tmp.ScalarMultiplication(value, &vBi) + res.Add(res, &tmp) + } + } + + accumulateG2 := func(res *curve.G2Affine, t constraint.Term, value *curve.G2Affine) { + cID := t.CoeffID() + switch cID { + case constraint.CoeffIdZero: + return + case constraint.CoeffIdOne: + res.Add(res, value) + case constraint.CoeffIdMinusOne: + res.Sub(res, value) + case constraint.CoeffIdTwo: + res.Add(res, value).Add(res, value) + default: + var tmp curve.G2Affine + var vBi big.Int + r1cs.Coefficients[cID].BigInt(&vBi) + tmp.ScalarMultiplication(value, &vBi) + res.Add(res, &tmp) + } + } + + // Prepare Lagrange coefficients of [τ...]₁, [τ...]₂, [ατ...]₁, [βτ...]₁ + coeffTau1 := LagrangeCoeffsG1(srs.G1.Tau, size) + coeffTau2 := LagrangeCoeffsG2(srs.G2.Tau, size) + coeffAlphaTau1 := LagrangeCoeffsG1(srs.G1.AlphaTau, size) + coeffBetaTau1 := LagrangeCoeffsG1(srs.G1.BetaTau, size) + + internal, secret, public := r1cs.GetNbVariables() + nWires := internal + secret + public + var evals Phase2Evaluations + evals.G1.A = make([]curve.G1Affine, nWires) + evals.G1.B = make([]curve.G1Affine, nWires) + evals.G2.B = make([]curve.G2Affine, nWires) + bA := make([]curve.G1Affine, nWires) + aB := make([]curve.G1Affine, nWires) + C := make([]curve.G1Affine, nWires) + for i, c := range r1cs.Constraints { + // A + for _, t := range c.L { + accumulateG1(&evals.G1.A[t.WireID()], t, &coeffTau1[i]) + accumulateG1(&bA[t.WireID()], t, &coeffBetaTau1[i]) + } + // B + for _, t := range c.R { + accumulateG1(&evals.G1.B[t.WireID()], t, &coeffTau1[i]) + accumulateG2(&evals.G2.B[t.WireID()], t, &coeffTau2[i]) + accumulateG1(&aB[t.WireID()], t, &coeffAlphaTau1[i]) + } + // C + for _, t := range c.O { + accumulateG1(&C[t.WireID()], t, &coeffTau1[i]) + } + } + + // Prepare default contribution + _, _, g1, g2 := curve.Generators() + c2.Parameters.G1.Delta = g1 + c2.Parameters.G2.Delta = g2 + + // Build Z in PK as τⁱ(τⁿ - 1) = τ⁽ⁱ⁺ⁿ⁾ - τⁱ for i ∈ [0, n-2] + // τⁱ(τⁿ - 1) = τ⁽ⁱ⁺ⁿ⁾ - τⁱ for i ∈ [0, n-2] + n := len(srs.G1.AlphaTau) + c2.Parameters.G1.Z = make([]curve.G1Affine, n) + for i := 0; i < n-1; i++ { + c2.Parameters.G1.Z[i].Sub(&srs.G1.Tau[i+n], &srs.G1.Tau[i]) + } + bitReverse(c2.Parameters.G1.Z) + c2.Parameters.G1.Z = c2.Parameters.G1.Z[:n-1] + + // Evaluate L + nPrivate := internal + secret + c2.Parameters.G1.L = make([]curve.G1Affine, nPrivate) + evals.G1.VKK = make([]curve.G1Affine, public) + offset := public + for i := 0; i < nWires; i++ { + var tmp curve.G1Affine + tmp.Add(&bA[i], &aB[i]) + tmp.Add(&tmp, &C[i]) + if i < public { + evals.G1.VKK[i].Set(&tmp) + } else { + c2.Parameters.G1.L[i-offset].Set(&tmp) + } + } + // Set δ public key + var delta fr.Element + delta.SetOne() + c2.PublicKey = newPublicKey(delta, nil, 1) + + // Hash initial contribution + c2.Hash = c2.hash() + return c2, evals +} + +func (c *Phase2) Contribute() { + // Sample toxic δ + var delta, deltaInv fr.Element + var deltaBI, deltaInvBI big.Int + delta.SetRandom() + deltaInv.Inverse(&delta) + + delta.BigInt(&deltaBI) + deltaInv.BigInt(&deltaInvBI) + + // Set δ public key + c.PublicKey = newPublicKey(delta, c.Hash, 1) + + // Update δ + c.Parameters.G1.Delta.ScalarMultiplication(&c.Parameters.G1.Delta, &deltaBI) + c.Parameters.G2.Delta.ScalarMultiplication(&c.Parameters.G2.Delta, &deltaBI) + + // Update Z using δ⁻¹ + for i := 0; i < len(c.Parameters.G1.Z); i++ { + c.Parameters.G1.Z[i].ScalarMultiplication(&c.Parameters.G1.Z[i], &deltaInvBI) + } + + // Update L using δ⁻¹ + for i := 0; i < len(c.Parameters.G1.L); i++ { + c.Parameters.G1.L[i].ScalarMultiplication(&c.Parameters.G1.L[i], &deltaInvBI) + } + + // 4. Hash contribution + c.Hash = c.hash() +} + +func VerifyPhase2(c0, c1 *Phase2, c ...*Phase2) error { + contribs := append([]*Phase2{c0, c1}, c...) + for i := 0; i < len(contribs)-1; i++ { + if err := verifyPhase2(contribs[i], contribs[i+1]); err != nil { + return err + } + } + return nil +} + +func verifyPhase2(current, contribution *Phase2) error { + // Compute R for δ + deltaR := genR(contribution.PublicKey.SG, contribution.PublicKey.SXG, current.Hash[:], 1) + + // Check for knowledge of δ + if !sameRatio(contribution.PublicKey.SG, contribution.PublicKey.SXG, contribution.PublicKey.XR, deltaR) { + return errors.New("couldn't verify knowledge of δ") + } + + // Check for valid updates using previous parameters + if !sameRatio(contribution.Parameters.G1.Delta, current.Parameters.G1.Delta, deltaR, contribution.PublicKey.XR) { + return errors.New("couldn't verify that [δ]₁ is based on previous contribution") + } + if !sameRatio(contribution.PublicKey.SG, contribution.PublicKey.SXG, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { + return errors.New("couldn't verify that [δ]₂ is based on previous contribution") + } + + // Check for valid updates of L and Z using + L, prevL := merge(contribution.Parameters.G1.L, current.Parameters.G1.L) + if !sameRatio(L, prevL, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { + return errors.New("couldn't verify valid updates of L using δ⁻¹") + } + Z, prevZ := merge(contribution.Parameters.G1.Z, current.Parameters.G1.Z) + if !sameRatio(Z, prevZ, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { + return errors.New("couldn't verify valid updates of L using δ⁻¹") + } + + // Check hash of the contribution + h := contribution.hash() + for i := 0; i < len(h); i++ { + if h[i] != contribution.Hash[i] { + return errors.New("couldn't verify hash of contribution") + } + } + + return nil +} + +func (c *Phase2) hash() []byte { + sha := sha256.New() + c.writeTo(sha) + return sha.Sum(nil) +} diff --git a/backend/groth16/bls12-381/mpcsetup/setup.go b/backend/groth16/bls12-381/mpcsetup/setup.go new file mode 100644 index 0000000000..dd568aa21e --- /dev/null +++ b/backend/groth16/bls12-381/mpcsetup/setup.go @@ -0,0 +1,97 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + curve "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/fft" + groth16 "github.com/consensys/gnark/backend/groth16/bls12-381" +) + +func ExtractKeys(srs1 *Phase1, srs2 *Phase2, evals *Phase2Evaluations, nConstraints int) (pk groth16.ProvingKey, vk groth16.VerifyingKey) { + _, _, _, g2 := curve.Generators() + + // Initialize PK + pk.Domain = *fft.NewDomain(uint64(nConstraints)) + pk.G1.Alpha.Set(&srs1.Parameters.G1.AlphaTau[0]) + pk.G1.Beta.Set(&srs1.Parameters.G1.BetaTau[0]) + pk.G1.Delta.Set(&srs2.Parameters.G1.Delta) + pk.G1.Z = srs2.Parameters.G1.Z + bitReverse(pk.G1.Z) + + pk.G1.K = srs2.Parameters.G1.L + pk.G2.Beta.Set(&srs1.Parameters.G2.Beta) + pk.G2.Delta.Set(&srs2.Parameters.G2.Delta) + + // Filter out infinity points + nWires := len(evals.G1.A) + pk.InfinityA = make([]bool, nWires) + A := make([]curve.G1Affine, nWires) + j := 0 + for i, e := range evals.G1.A { + if e.IsInfinity() { + pk.InfinityA[i] = true + continue + } + A[j] = evals.G1.A[i] + j++ + } + pk.G1.A = A[:j] + pk.NbInfinityA = uint64(nWires - j) + + pk.InfinityB = make([]bool, nWires) + B := make([]curve.G1Affine, nWires) + j = 0 + for i, e := range evals.G1.B { + if e.IsInfinity() { + pk.InfinityB[i] = true + continue + } + B[j] = evals.G1.B[i] + j++ + } + pk.G1.B = B[:j] + pk.NbInfinityB = uint64(nWires - j) + + B2 := make([]curve.G2Affine, nWires) + j = 0 + for i, e := range evals.G2.B { + if e.IsInfinity() { + // pk.InfinityB[i] = true should be the same as in B + continue + } + B2[j] = evals.G2.B[i] + j++ + } + pk.G2.B = B2[:j] + + // Initialize VK + vk.G1.Alpha.Set(&srs1.Parameters.G1.AlphaTau[0]) + vk.G1.Beta.Set(&srs1.Parameters.G1.BetaTau[0]) + vk.G1.Delta.Set(&srs2.Parameters.G1.Delta) + vk.G2.Beta.Set(&srs1.Parameters.G2.Beta) + vk.G2.Delta.Set(&srs2.Parameters.G2.Delta) + vk.G2.Gamma.Set(&g2) + vk.G1.K = evals.G1.VKK + + // sets e, -[δ]2, -[γ]2 + if err := vk.Precompute(); err != nil { + panic(err) + } + + return pk, vk +} diff --git a/backend/groth16/bls12-381/mpcsetup/setup_test.go b/backend/groth16/bls12-381/mpcsetup/setup_test.go new file mode 100644 index 0000000000..e801821bea --- /dev/null +++ b/backend/groth16/bls12-381/mpcsetup/setup_test.go @@ -0,0 +1,199 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + curve "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + "github.com/consensys/gnark/constraint/bls12-381" + "testing" + + "github.com/consensys/gnark/backend/groth16" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/std/hash/mimc" + "github.com/stretchr/testify/require" + + native_mimc "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/mimc" +) + +func TestSetupCircuit(t *testing.T) { + if testing.Short() { + t.Skip() + } + const ( + nContributionsPhase1 = 3 + nContributionsPhase2 = 3 + power = 9 + ) + + assert := require.New(t) + + srs1 := InitPhase1(power) + + // Make and verify contributions for phase1 + for i := 1; i < nContributionsPhase1; i++ { + // we clone test purposes; but in practice, participant will receive a []byte, deserialize it, + // add his contribution and send back to coordinator. + prev := srs1.clone() + + srs1.Contribute() + assert.NoError(VerifyPhase1(&prev, &srs1)) + } + + // Compile the circuit + var myCircuit Circuit + ccs, err := frontend.Compile(curve.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) + assert.NoError(err) + + var evals Phase2Evaluations + r1cs := ccs.(*cs.R1CS) + + // Prepare for phase-2 + srs2, evals := InitPhase2(r1cs, &srs1) + + // Make and verify contributions for phase1 + for i := 1; i < nContributionsPhase2; i++ { + // we clone for test purposes; but in practice, participant will receive a []byte, deserialize it, + // add his contribution and send back to coordinator. + prev := srs2.clone() + + srs2.Contribute() + assert.NoError(VerifyPhase2(&prev, &srs2)) + } + + // Extract the proving and verifying keys + pk, vk := ExtractKeys(&srs1, &srs2, &evals, ccs.GetNbConstraints()) + + // Build the witness + var preImage, hash fr.Element + { + m := native_mimc.NewMiMC() + m.Write(preImage.Marshal()) + hash.SetBytes(m.Sum(nil)) + } + + witness, err := frontend.NewWitness(&Circuit{PreImage: preImage, Hash: hash}, curve.ID.ScalarField()) + assert.NoError(err) + + pubWitness, err := witness.Public() + assert.NoError(err) + + // groth16: ensure proof is verified + proof, err := groth16.Prove(ccs, &pk, witness) + assert.NoError(err) + + err = groth16.Verify(proof, &vk, pubWitness) + assert.NoError(err) +} + +func BenchmarkPhase1(b *testing.B) { + const power = 14 + + b.Run("init", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = InitPhase1(power) + } + }) + + b.Run("contrib", func(b *testing.B) { + srs1 := InitPhase1(power) + b.ResetTimer() + for i := 0; i < b.N; i++ { + srs1.Contribute() + } + }) + +} + +func BenchmarkPhase2(b *testing.B) { + const power = 14 + srs1 := InitPhase1(power) + srs1.Contribute() + + var myCircuit Circuit + ccs, err := frontend.Compile(curve.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) + if err != nil { + b.Fatal(err) + } + + r1cs := ccs.(*cs.R1CS) + + b.Run("init", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, _ = InitPhase2(r1cs, &srs1) + } + }) + + b.Run("contrib", func(b *testing.B) { + srs2, _ := InitPhase2(r1cs, &srs1) + b.ResetTimer() + for i := 0; i < b.N; i++ { + srs2.Contribute() + } + }) + +} + +// Circuit defines a pre-image knowledge proof +// mimc(secret preImage) = public hash +type Circuit struct { + PreImage frontend.Variable + Hash frontend.Variable `gnark:",public"` +} + +// Define declares the circuit's constraints +// Hash = mimc(PreImage) +func (circuit *Circuit) Define(api frontend.API) error { + // hash function + mimc, _ := mimc.NewMiMC(api) + + // specify constraints + mimc.Write(circuit.PreImage) + api.AssertIsEqual(circuit.Hash, mimc.Sum()) + + return nil +} + +func (phase1 *Phase1) clone() Phase1 { + r := Phase1{} + r.Parameters.G1.Tau = append(r.Parameters.G1.Tau, phase1.Parameters.G1.Tau...) + r.Parameters.G1.AlphaTau = append(r.Parameters.G1.AlphaTau, phase1.Parameters.G1.AlphaTau...) + r.Parameters.G1.BetaTau = append(r.Parameters.G1.BetaTau, phase1.Parameters.G1.BetaTau...) + + r.Parameters.G2.Tau = append(r.Parameters.G2.Tau, phase1.Parameters.G2.Tau...) + r.Parameters.G2.Beta = phase1.Parameters.G2.Beta + + r.PublicKeys = phase1.PublicKeys + r.Hash = append(r.Hash, phase1.Hash...) + + return r +} + +func (phase2 *Phase2) clone() Phase2 { + r := Phase2{} + r.Parameters.G1.Delta = phase2.Parameters.G1.Delta + r.Parameters.G1.L = append(r.Parameters.G1.L, phase2.Parameters.G1.L...) + r.Parameters.G1.Z = append(r.Parameters.G1.Z, phase2.Parameters.G1.Z...) + r.Parameters.G2.Delta = phase2.Parameters.G2.Delta + r.PublicKey = phase2.PublicKey + r.Hash = append(r.Hash, phase2.Hash...) + + return r +} diff --git a/backend/groth16/bls12-381/mpcsetup/utils.go b/backend/groth16/bls12-381/mpcsetup/utils.go new file mode 100644 index 0000000000..e29ec7ae32 --- /dev/null +++ b/backend/groth16/bls12-381/mpcsetup/utils.go @@ -0,0 +1,170 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "bytes" + "math/big" + "math/bits" + "runtime" + + "github.com/consensys/gnark-crypto/ecc" + curve "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + "github.com/consensys/gnark/internal/utils" +) + +type PublicKey struct { + SG curve.G1Affine + SXG curve.G1Affine + XR curve.G2Affine +} + +func newPublicKey(x fr.Element, challenge []byte, dst byte) PublicKey { + var pk PublicKey + _, _, g1, _ := curve.Generators() + + var s fr.Element + var sBi big.Int + s.SetRandom() + s.BigInt(&sBi) + pk.SG.ScalarMultiplication(&g1, &sBi) + + // compute x*sG1 + var xBi big.Int + x.BigInt(&xBi) + pk.SXG.ScalarMultiplication(&pk.SG, &xBi) + + // generate R based on sG1, sxG1, challenge, and domain separation tag (tau, alpha or beta) + R := genR(pk.SG, pk.SXG, challenge, dst) + + // compute x*spG2 + pk.XR.ScalarMultiplication(&R, &xBi) + return pk +} + +func bitReverse[T any](a []T) { + n := uint64(len(a)) + nn := uint64(64 - bits.TrailingZeros64(n)) + + for i := uint64(0); i < n; i++ { + irev := bits.Reverse64(i) >> nn + if irev > i { + a[i], a[irev] = a[irev], a[i] + } + } +} + +// Returns [1, a, a², ..., aⁿ⁻¹ ] in Montgomery form +func powers(a fr.Element, n int) []fr.Element { + result := make([]fr.Element, n) + result[0] = fr.NewElement(1) + for i := 1; i < n; i++ { + result[i].Mul(&result[i-1], &a) + } + return result +} + +// Returns [aᵢAᵢ, ...] in G1 +func scaleG1InPlace(A []curve.G1Affine, a []fr.Element) { + utils.Parallelize(len(A), func(start, end int) { + var tmp big.Int + for i := start; i < end; i++ { + a[i].BigInt(&tmp) + A[i].ScalarMultiplication(&A[i], &tmp) + } + }) +} + +// Returns [aᵢAᵢ, ...] in G2 +func scaleG2InPlace(A []curve.G2Affine, a []fr.Element) { + utils.Parallelize(len(A), func(start, end int) { + var tmp big.Int + for i := start; i < end; i++ { + a[i].BigInt(&tmp) + A[i].ScalarMultiplication(&A[i], &tmp) + } + }) +} + +// Check e(a₁, a₂) = e(b₁, b₂) +func sameRatio(a1, b1 curve.G1Affine, a2, b2 curve.G2Affine) bool { + if !a1.IsInSubGroup() || !b1.IsInSubGroup() || !a2.IsInSubGroup() || !b2.IsInSubGroup() { + panic("invalid point not in subgroup") + } + var na2 curve.G2Affine + na2.Neg(&a2) + res, err := curve.PairingCheck( + []curve.G1Affine{a1, b1}, + []curve.G2Affine{na2, b2}) + if err != nil { + panic(err) + } + return res +} + +// returns a = ∑ rᵢAᵢ, b = ∑ rᵢBᵢ +func merge(A, B []curve.G1Affine) (a, b curve.G1Affine) { + nc := runtime.NumCPU() + r := make([]fr.Element, len(A)) + for i := 0; i < len(A); i++ { + r[i].SetRandom() + } + a.MultiExp(A, r, ecc.MultiExpConfig{NbTasks: nc / 2}) + b.MultiExp(B, r, ecc.MultiExpConfig{NbTasks: nc / 2}) + return +} + +// L1 = ∑ rᵢAᵢ, L2 = ∑ rᵢAᵢ₊₁ in G1 +func linearCombinationG1(A []curve.G1Affine) (L1, L2 curve.G1Affine) { + nc := runtime.NumCPU() + n := len(A) + r := make([]fr.Element, n-1) + for i := 0; i < n-1; i++ { + r[i].SetRandom() + } + L1.MultiExp(A[:n-1], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + L2.MultiExp(A[1:], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + return +} + +// L1 = ∑ rᵢAᵢ, L2 = ∑ rᵢAᵢ₊₁ in G2 +func linearCombinationG2(A []curve.G2Affine) (L1, L2 curve.G2Affine) { + nc := runtime.NumCPU() + n := len(A) + r := make([]fr.Element, n-1) + for i := 0; i < n-1; i++ { + r[i].SetRandom() + } + L1.MultiExp(A[:n-1], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + L2.MultiExp(A[1:], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + return +} + +// Generate R in G₂ as Hash(gˢ, gˢˣ, challenge, dst) +func genR(sG1, sxG1 curve.G1Affine, challenge []byte, dst byte) curve.G2Affine { + var buf bytes.Buffer + buf.Grow(len(challenge) + curve.SizeOfG1AffineUncompressed*2) + buf.Write(sG1.Marshal()) + buf.Write(sxG1.Marshal()) + buf.Write(challenge) + spG2, err := curve.HashToG2(buf.Bytes(), []byte{dst}) + if err != nil { + panic(err) + } + return spG2 +} diff --git a/backend/groth16/bls24-315/mpcsetup/lagrange.go b/backend/groth16/bls24-315/mpcsetup/lagrange.go new file mode 100644 index 0000000000..aeef03cdfd --- /dev/null +++ b/backend/groth16/bls24-315/mpcsetup/lagrange.go @@ -0,0 +1,216 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "math/big" + "math/bits" + "runtime" + + "github.com/consensys/gnark-crypto/ecc" + curve "github.com/consensys/gnark-crypto/ecc/bls24-315" + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/fft" + "github.com/consensys/gnark/internal/utils" +) + +func LagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { + coeffs := make([]curve.G1Affine, size) + copy(coeffs, powers[:size]) + domain := fft.NewDomain(uint64(size)) + numCPU := uint64(runtime.NumCPU()) + maxSplits := bits.TrailingZeros64(ecc.NextPowerOfTwo(numCPU)) + + difFFTG1(coeffs, domain.TwiddlesInv, 0, maxSplits, nil) + bitReverse(coeffs) + + var invBigint big.Int + domain.CardinalityInv.BigInt(&invBigint) + + utils.Parallelize(size, func(start, end int) { + for i := start; i < end; i++ { + coeffs[i].ScalarMultiplication(&coeffs[i], &invBigint) + } + }) + return coeffs +} + +func LagrangeCoeffsG2(powers []curve.G2Affine, size int) []curve.G2Affine { + coeffs := make([]curve.G2Affine, size) + copy(coeffs, powers[:size]) + domain := fft.NewDomain(uint64(size)) + numCPU := uint64(runtime.NumCPU()) + maxSplits := bits.TrailingZeros64(ecc.NextPowerOfTwo(numCPU)) + + difFFTG2(coeffs, domain.TwiddlesInv, 0, maxSplits, nil) + bitReverse(coeffs) + + var invBigint big.Int + domain.CardinalityInv.BigInt(&invBigint) + + utils.Parallelize(size, func(start, end int) { + for i := start; i < end; i++ { + coeffs[i].ScalarMultiplication(&coeffs[i], &invBigint) + } + }) + return coeffs +} + +func butterflyG1(a *curve.G1Affine, b *curve.G1Affine) { + t := *a + a.Add(a, b) + b.Sub(&t, b) +} + +func butterflyG2(a *curve.G2Affine, b *curve.G2Affine) { + t := *a + a.Add(a, b) + b.Sub(&t, b) +} + +// kerDIF8 is a kernel that process a FFT of size 8 +func kerDIF8G1(a []curve.G1Affine, twiddles [][]fr.Element, stage int) { + butterflyG1(&a[0], &a[4]) + butterflyG1(&a[1], &a[5]) + butterflyG1(&a[2], &a[6]) + butterflyG1(&a[3], &a[7]) + + var twiddle big.Int + twiddles[stage+0][1].BigInt(&twiddle) + a[5].ScalarMultiplication(&a[5], &twiddle) + twiddles[stage+0][2].BigInt(&twiddle) + a[6].ScalarMultiplication(&a[6], &twiddle) + twiddles[stage+0][3].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG1(&a[0], &a[2]) + butterflyG1(&a[1], &a[3]) + butterflyG1(&a[4], &a[6]) + butterflyG1(&a[5], &a[7]) + twiddles[stage+1][1].BigInt(&twiddle) + a[3].ScalarMultiplication(&a[3], &twiddle) + twiddles[stage+1][1].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG1(&a[0], &a[1]) + butterflyG1(&a[2], &a[3]) + butterflyG1(&a[4], &a[5]) + butterflyG1(&a[6], &a[7]) +} + +// kerDIF8 is a kernel that process a FFT of size 8 +func kerDIF8G2(a []curve.G2Affine, twiddles [][]fr.Element, stage int) { + butterflyG2(&a[0], &a[4]) + butterflyG2(&a[1], &a[5]) + butterflyG2(&a[2], &a[6]) + butterflyG2(&a[3], &a[7]) + + var twiddle big.Int + twiddles[stage+0][1].BigInt(&twiddle) + a[5].ScalarMultiplication(&a[5], &twiddle) + twiddles[stage+0][2].BigInt(&twiddle) + a[6].ScalarMultiplication(&a[6], &twiddle) + twiddles[stage+0][3].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG2(&a[0], &a[2]) + butterflyG2(&a[1], &a[3]) + butterflyG2(&a[4], &a[6]) + butterflyG2(&a[5], &a[7]) + twiddles[stage+1][1].BigInt(&twiddle) + a[3].ScalarMultiplication(&a[3], &twiddle) + twiddles[stage+1][1].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG2(&a[0], &a[1]) + butterflyG2(&a[2], &a[3]) + butterflyG2(&a[4], &a[5]) + butterflyG2(&a[6], &a[7]) +} + +func difFFTG1(a []curve.G1Affine, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { + if chDone != nil { + defer close(chDone) + } + + n := len(a) + if n == 1 { + return + } else if n == 8 { + kerDIF8G1(a, twiddles, stage) + return + } + m := n >> 1 + + butterflyG1(&a[0], &a[m]) + + var twiddle big.Int + for i := 1; i < m; i++ { + butterflyG1(&a[i], &a[i+m]) + twiddles[stage][i].BigInt(&twiddle) + a[i+m].ScalarMultiplication(&a[i+m], &twiddle) + } + + if m == 1 { + return + } + + nextStage := stage + 1 + if stage < maxSplits { + chDone := make(chan struct{}, 1) + go difFFTG1(a[m:n], twiddles, nextStage, maxSplits, chDone) + difFFTG1(a[0:m], twiddles, nextStage, maxSplits, nil) + <-chDone + } else { + difFFTG1(a[0:m], twiddles, nextStage, maxSplits, nil) + difFFTG1(a[m:n], twiddles, nextStage, maxSplits, nil) + } +} +func difFFTG2(a []curve.G2Affine, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { + if chDone != nil { + defer close(chDone) + } + + n := len(a) + if n == 1 { + return + } else if n == 8 { + kerDIF8G2(a, twiddles, stage) + return + } + m := n >> 1 + + butterflyG2(&a[0], &a[m]) + + var twiddle big.Int + for i := 1; i < m; i++ { + butterflyG2(&a[i], &a[i+m]) + twiddles[stage][i].BigInt(&twiddle) + a[i+m].ScalarMultiplication(&a[i+m], &twiddle) + } + + if m == 1 { + return + } + + nextStage := stage + 1 + if stage < maxSplits { + chDone := make(chan struct{}, 1) + go difFFTG2(a[m:n], twiddles, nextStage, maxSplits, chDone) + difFFTG2(a[0:m], twiddles, nextStage, maxSplits, nil) + <-chDone + } else { + difFFTG2(a[0:m], twiddles, nextStage, maxSplits, nil) + difFFTG2(a[m:n], twiddles, nextStage, maxSplits, nil) + } +} diff --git a/backend/groth16/bls24-315/mpcsetup/marshal.go b/backend/groth16/bls24-315/mpcsetup/marshal.go new file mode 100644 index 0000000000..f670a7af74 --- /dev/null +++ b/backend/groth16/bls24-315/mpcsetup/marshal.go @@ -0,0 +1,181 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + curve "github.com/consensys/gnark-crypto/ecc/bls24-315" + "io" +) + +// WriteTo implements io.WriterTo +func (phase1 *Phase1) WriteTo(writer io.Writer) (int64, error) { + n, err := phase1.writeTo(writer) + if err != nil { + return n, err + } + nBytes, err := writer.Write(phase1.Hash) + return int64(nBytes) + n, err +} + +func (phase1 *Phase1) writeTo(writer io.Writer) (int64, error) { + toEncode := []interface{}{ + &phase1.PublicKeys.Tau.SG, + &phase1.PublicKeys.Tau.SXG, + &phase1.PublicKeys.Tau.XR, + &phase1.PublicKeys.Alpha.SG, + &phase1.PublicKeys.Alpha.SXG, + &phase1.PublicKeys.Alpha.XR, + &phase1.PublicKeys.Beta.SG, + &phase1.PublicKeys.Beta.SXG, + &phase1.PublicKeys.Beta.XR, + phase1.Parameters.G1.Tau, + phase1.Parameters.G1.AlphaTau, + phase1.Parameters.G1.BetaTau, + phase1.Parameters.G2.Tau, + &phase1.Parameters.G2.Beta, + } + + enc := curve.NewEncoder(writer) + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + return enc.BytesWritten(), nil +} + +// ReadFrom implements io.ReaderFrom +func (phase1 *Phase1) ReadFrom(reader io.Reader) (int64, error) { + toEncode := []interface{}{ + &phase1.PublicKeys.Tau.SG, + &phase1.PublicKeys.Tau.SXG, + &phase1.PublicKeys.Tau.XR, + &phase1.PublicKeys.Alpha.SG, + &phase1.PublicKeys.Alpha.SXG, + &phase1.PublicKeys.Alpha.XR, + &phase1.PublicKeys.Beta.SG, + &phase1.PublicKeys.Beta.SXG, + &phase1.PublicKeys.Beta.XR, + &phase1.Parameters.G1.Tau, + &phase1.Parameters.G1.AlphaTau, + &phase1.Parameters.G1.BetaTau, + &phase1.Parameters.G2.Tau, + &phase1.Parameters.G2.Beta, + } + + dec := curve.NewDecoder(reader) + for _, v := range toEncode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + phase1.Hash = make([]byte, 32) + nBytes, err := reader.Read(phase1.Hash) + return dec.BytesRead() + int64(nBytes), err +} + +// WriteTo implements io.WriterTo +func (phase2 *Phase2) WriteTo(writer io.Writer) (int64, error) { + n, err := phase2.writeTo(writer) + if err != nil { + return n, err + } + nBytes, err := writer.Write(phase2.Hash) + return int64(nBytes) + n, err +} + +func (c *Phase2) writeTo(writer io.Writer) (int64, error) { + enc := curve.NewEncoder(writer) + toEncode := []interface{}{ + &c.PublicKey.SG, + &c.PublicKey.SXG, + &c.PublicKey.XR, + &c.Parameters.G1.Delta, + c.Parameters.G1.L, + c.Parameters.G1.Z, + &c.Parameters.G2.Delta, + } + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + + return enc.BytesWritten(), nil +} + +// ReadFrom implements io.ReaderFrom +func (c *Phase2) ReadFrom(reader io.Reader) (int64, error) { + dec := curve.NewDecoder(reader) + toEncode := []interface{}{ + &c.PublicKey.SG, + &c.PublicKey.SXG, + &c.PublicKey.XR, + &c.Parameters.G1.Delta, + &c.Parameters.G1.L, + &c.Parameters.G1.Z, + &c.Parameters.G2.Delta, + } + + for _, v := range toEncode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + + c.Hash = make([]byte, 32) + n, err := reader.Read(c.Hash) + return int64(n) + dec.BytesRead(), err + +} + +// WriteTo implements io.WriterTo +func (c *Phase2Evaluations) WriteTo(writer io.Writer) (int64, error) { + enc := curve.NewEncoder(writer) + toEncode := []interface{}{ + c.G1.A, + c.G1.B, + c.G2.B, + } + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + + return enc.BytesWritten(), nil +} + +// ReadFrom implements io.ReaderFrom +func (c *Phase2Evaluations) ReadFrom(reader io.Reader) (int64, error) { + dec := curve.NewDecoder(reader) + toEncode := []interface{}{ + &c.G1.A, + &c.G1.B, + &c.G2.B, + } + + for _, v := range toEncode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + + return dec.BytesRead(), nil +} diff --git a/backend/groth16/bls24-315/mpcsetup/marshal_test.go b/backend/groth16/bls24-315/mpcsetup/marshal_test.go new file mode 100644 index 0000000000..9ca32105de --- /dev/null +++ b/backend/groth16/bls24-315/mpcsetup/marshal_test.go @@ -0,0 +1,79 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "bytes" + curve "github.com/consensys/gnark-crypto/ecc/bls24-315" + "github.com/consensys/gnark/constraint/bls24-315" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/stretchr/testify/require" + "io" + "reflect" + "testing" +) + +func TestContributionSerialization(t *testing.T) { + assert := require.New(t) + + // Phase 1 + srs1 := InitPhase1(9) + srs1.Contribute() + { + var reconstructed Phase1 + roundTripCheck(t, &srs1, &reconstructed) + } + + var myCircuit Circuit + ccs, err := frontend.Compile(curve.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) + assert.NoError(err) + + r1cs := ccs.(*cs.R1CS) + + // Phase 2 + srs2, _ := InitPhase2(r1cs, &srs1) + srs2.Contribute() + + { + var reconstructed Phase2 + roundTripCheck(t, &srs2, &reconstructed) + } +} + +func roundTripCheck(t *testing.T, from io.WriterTo, reconstructed io.ReaderFrom) { + t.Helper() + + var buf bytes.Buffer + written, err := from.WriteTo(&buf) + if err != nil { + t.Fatal("couldn't serialize", err) + } + + read, err := reconstructed.ReadFrom(&buf) + if err != nil { + t.Fatal("couldn't deserialize", err) + } + + if !reflect.DeepEqual(from, reconstructed) { + t.Fatal("reconstructed object don't match original") + } + + if written != read { + t.Fatal("bytes written / read don't match") + } +} diff --git a/backend/groth16/bls24-315/mpcsetup/phase1.go b/backend/groth16/bls24-315/mpcsetup/phase1.go new file mode 100644 index 0000000000..cefde6c90f --- /dev/null +++ b/backend/groth16/bls24-315/mpcsetup/phase1.go @@ -0,0 +1,203 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "crypto/sha256" + "errors" + curve "github.com/consensys/gnark-crypto/ecc/bls24-315" + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" + "math" + "math/big" +) + +// Phase1 represents the Phase1 of the MPC described in +// https://eprint.iacr.org/2017/1050.pdf +// +// Also known as "Powers of Tau" +type Phase1 struct { + Parameters struct { + G1 struct { + Tau []curve.G1Affine // {[τ⁰]₁, [τ¹]₁, [τ²]₁, …, [τ²ⁿ⁻²]₁} + AlphaTau []curve.G1Affine // {α[τ⁰]₁, α[τ¹]₁, α[τ²]₁, …, α[τⁿ⁻¹]₁} + BetaTau []curve.G1Affine // {β[τ⁰]₁, β[τ¹]₁, β[τ²]₁, …, β[τⁿ⁻¹]₁} + } + G2 struct { + Tau []curve.G2Affine // {[τ⁰]₂, [τ¹]₂, [τ²]₂, …, [τⁿ⁻¹]₂} + Beta curve.G2Affine // [β]₂ + } + } + PublicKeys struct { + Tau, Alpha, Beta PublicKey + } + Hash []byte // sha256 hash +} + +// InitPhase1 initialize phase 1 of the MPC. This is called once by the coordinator before +// any randomness contribution is made (see Contribute()). +func InitPhase1(power int) (phase1 Phase1) { + N := int(math.Pow(2, float64(power))) + + // Generate key pairs + var tau, alpha, beta fr.Element + tau.SetOne() + alpha.SetOne() + beta.SetOne() + phase1.PublicKeys.Tau = newPublicKey(tau, nil, 1) + phase1.PublicKeys.Alpha = newPublicKey(alpha, nil, 2) + phase1.PublicKeys.Beta = newPublicKey(beta, nil, 3) + + // First contribution use generators + _, _, g1, g2 := curve.Generators() + phase1.Parameters.G2.Beta.Set(&g2) + phase1.Parameters.G1.Tau = make([]curve.G1Affine, 2*N-1) + phase1.Parameters.G2.Tau = make([]curve.G2Affine, N) + phase1.Parameters.G1.AlphaTau = make([]curve.G1Affine, N) + phase1.Parameters.G1.BetaTau = make([]curve.G1Affine, N) + for i := 0; i < len(phase1.Parameters.G1.Tau); i++ { + phase1.Parameters.G1.Tau[i].Set(&g1) + } + for i := 0; i < len(phase1.Parameters.G2.Tau); i++ { + phase1.Parameters.G2.Tau[i].Set(&g2) + phase1.Parameters.G1.AlphaTau[i].Set(&g1) + phase1.Parameters.G1.BetaTau[i].Set(&g1) + } + + phase1.Parameters.G2.Beta.Set(&g2) + + // Compute hash of Contribution + phase1.Hash = phase1.hash() + + return +} + +// Contribute contributes randomness to the phase1 object. This mutates phase1. +func (phase1 *Phase1) Contribute() { + N := len(phase1.Parameters.G2.Tau) + + // Generate key pairs + var tau, alpha, beta fr.Element + tau.SetRandom() + alpha.SetRandom() + beta.SetRandom() + phase1.PublicKeys.Tau = newPublicKey(tau, phase1.Hash[:], 1) + phase1.PublicKeys.Alpha = newPublicKey(alpha, phase1.Hash[:], 2) + phase1.PublicKeys.Beta = newPublicKey(beta, phase1.Hash[:], 3) + + // Compute powers of τ, ατ, and βτ + taus := powers(tau, 2*N-1) + alphaTau := make([]fr.Element, N) + betaTau := make([]fr.Element, N) + for i := 0; i < N; i++ { + alphaTau[i].Mul(&taus[i], &alpha) + betaTau[i].Mul(&taus[i], &beta) + } + + // Update using previous parameters + // TODO @gbotrel working with jacobian points here will help with perf. + scaleG1InPlace(phase1.Parameters.G1.Tau, taus) + scaleG2InPlace(phase1.Parameters.G2.Tau, taus[0:N]) + scaleG1InPlace(phase1.Parameters.G1.AlphaTau, alphaTau) + scaleG1InPlace(phase1.Parameters.G1.BetaTau, betaTau) + var betaBI big.Int + beta.BigInt(&betaBI) + phase1.Parameters.G2.Beta.ScalarMultiplication(&phase1.Parameters.G2.Beta, &betaBI) + + // Compute hash of Contribution + phase1.Hash = phase1.hash() +} + +func VerifyPhase1(c0, c1 *Phase1, c ...*Phase1) error { + contribs := append([]*Phase1{c0, c1}, c...) + for i := 0; i < len(contribs)-1; i++ { + if err := verifyPhase1(contribs[i], contribs[i+1]); err != nil { + return err + } + } + return nil +} + +// verifyPhase1 checks that a contribution is based on a known previous Phase1 state. +func verifyPhase1(current, contribution *Phase1) error { + // Compute R for τ, α, β + tauR := genR(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, current.Hash[:], 1) + alphaR := genR(contribution.PublicKeys.Alpha.SG, contribution.PublicKeys.Alpha.SXG, current.Hash[:], 2) + betaR := genR(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, current.Hash[:], 3) + + // Check for knowledge of toxic parameters + if !sameRatio(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, contribution.PublicKeys.Tau.XR, tauR) { + return errors.New("couldn't verify public key of τ") + } + if !sameRatio(contribution.PublicKeys.Alpha.SG, contribution.PublicKeys.Alpha.SXG, contribution.PublicKeys.Alpha.XR, alphaR) { + return errors.New("couldn't verify public key of α") + } + if !sameRatio(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, contribution.PublicKeys.Beta.XR, betaR) { + return errors.New("couldn't verify public key of β") + } + + // Check for valid updates using previous parameters + if !sameRatio(contribution.Parameters.G1.Tau[1], current.Parameters.G1.Tau[1], tauR, contribution.PublicKeys.Tau.XR) { + return errors.New("couldn't verify that [τ]₁ is based on previous contribution") + } + if !sameRatio(contribution.Parameters.G1.AlphaTau[0], current.Parameters.G1.AlphaTau[0], alphaR, contribution.PublicKeys.Alpha.XR) { + return errors.New("couldn't verify that [α]₁ is based on previous contribution") + } + if !sameRatio(contribution.Parameters.G1.BetaTau[0], current.Parameters.G1.BetaTau[0], betaR, contribution.PublicKeys.Beta.XR) { + return errors.New("couldn't verify that [β]₁ is based on previous contribution") + } + if !sameRatio(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, contribution.Parameters.G2.Tau[1], current.Parameters.G2.Tau[1]) { + return errors.New("couldn't verify that [τ]₂ is based on previous contribution") + } + if !sameRatio(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, contribution.Parameters.G2.Beta, current.Parameters.G2.Beta) { + return errors.New("couldn't verify that [β]₂ is based on previous contribution") + } + + // Check for valid updates using powers of τ + _, _, g1, g2 := curve.Generators() + tauL1, tauL2 := linearCombinationG1(contribution.Parameters.G1.Tau) + if !sameRatio(tauL1, tauL2, contribution.Parameters.G2.Tau[1], g2) { + return errors.New("couldn't verify valid powers of τ in G₁") + } + alphaL1, alphaL2 := linearCombinationG1(contribution.Parameters.G1.AlphaTau) + if !sameRatio(alphaL1, alphaL2, contribution.Parameters.G2.Tau[1], g2) { + return errors.New("couldn't verify valid powers of α(τ) in G₁") + } + betaL1, betaL2 := linearCombinationG1(contribution.Parameters.G1.BetaTau) + if !sameRatio(betaL1, betaL2, contribution.Parameters.G2.Tau[1], g2) { + return errors.New("couldn't verify valid powers of α(τ) in G₁") + } + tau2L1, tau2L2 := linearCombinationG2(contribution.Parameters.G2.Tau) + if !sameRatio(contribution.Parameters.G1.Tau[1], g1, tau2L1, tau2L2) { + return errors.New("couldn't verify valid powers of τ in G₂") + } + + // Check hash of the contribution + h := contribution.hash() + for i := 0; i < len(h); i++ { + if h[i] != contribution.Hash[i] { + return errors.New("couldn't verify hash of contribution") + } + } + + return nil +} + +func (phase1 *Phase1) hash() []byte { + sha := sha256.New() + phase1.writeTo(sha) + return sha.Sum(nil) +} diff --git a/backend/groth16/bls24-315/mpcsetup/phase2.go b/backend/groth16/bls24-315/mpcsetup/phase2.go new file mode 100644 index 0000000000..445a6952d3 --- /dev/null +++ b/backend/groth16/bls24-315/mpcsetup/phase2.go @@ -0,0 +1,258 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "crypto/sha256" + "errors" + "math/big" + + curve "github.com/consensys/gnark-crypto/ecc/bls24-315" + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" + "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/bls24-315" +) + +type Phase2Evaluations struct { + G1 struct { + A, B, VKK []curve.G1Affine + } + G2 struct { + B []curve.G2Affine + } +} + +type Phase2 struct { + Parameters struct { + G1 struct { + Delta curve.G1Affine + L, Z []curve.G1Affine + } + G2 struct { + Delta curve.G2Affine + } + } + PublicKey PublicKey + Hash []byte +} + +func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { + srs := srs1.Parameters + size := len(srs.G1.AlphaTau) + if size < r1cs.GetNbConstraints() { + panic("Number of constraints is larger than expected") + } + + c2 := Phase2{} + + accumulateG1 := func(res *curve.G1Affine, t constraint.Term, value *curve.G1Affine) { + cID := t.CoeffID() + switch cID { + case constraint.CoeffIdZero: + return + case constraint.CoeffIdOne: + res.Add(res, value) + case constraint.CoeffIdMinusOne: + res.Sub(res, value) + case constraint.CoeffIdTwo: + res.Add(res, value).Add(res, value) + default: + var tmp curve.G1Affine + var vBi big.Int + r1cs.Coefficients[cID].BigInt(&vBi) + tmp.ScalarMultiplication(value, &vBi) + res.Add(res, &tmp) + } + } + + accumulateG2 := func(res *curve.G2Affine, t constraint.Term, value *curve.G2Affine) { + cID := t.CoeffID() + switch cID { + case constraint.CoeffIdZero: + return + case constraint.CoeffIdOne: + res.Add(res, value) + case constraint.CoeffIdMinusOne: + res.Sub(res, value) + case constraint.CoeffIdTwo: + res.Add(res, value).Add(res, value) + default: + var tmp curve.G2Affine + var vBi big.Int + r1cs.Coefficients[cID].BigInt(&vBi) + tmp.ScalarMultiplication(value, &vBi) + res.Add(res, &tmp) + } + } + + // Prepare Lagrange coefficients of [τ...]₁, [τ...]₂, [ατ...]₁, [βτ...]₁ + coeffTau1 := LagrangeCoeffsG1(srs.G1.Tau, size) + coeffTau2 := LagrangeCoeffsG2(srs.G2.Tau, size) + coeffAlphaTau1 := LagrangeCoeffsG1(srs.G1.AlphaTau, size) + coeffBetaTau1 := LagrangeCoeffsG1(srs.G1.BetaTau, size) + + internal, secret, public := r1cs.GetNbVariables() + nWires := internal + secret + public + var evals Phase2Evaluations + evals.G1.A = make([]curve.G1Affine, nWires) + evals.G1.B = make([]curve.G1Affine, nWires) + evals.G2.B = make([]curve.G2Affine, nWires) + bA := make([]curve.G1Affine, nWires) + aB := make([]curve.G1Affine, nWires) + C := make([]curve.G1Affine, nWires) + for i, c := range r1cs.Constraints { + // A + for _, t := range c.L { + accumulateG1(&evals.G1.A[t.WireID()], t, &coeffTau1[i]) + accumulateG1(&bA[t.WireID()], t, &coeffBetaTau1[i]) + } + // B + for _, t := range c.R { + accumulateG1(&evals.G1.B[t.WireID()], t, &coeffTau1[i]) + accumulateG2(&evals.G2.B[t.WireID()], t, &coeffTau2[i]) + accumulateG1(&aB[t.WireID()], t, &coeffAlphaTau1[i]) + } + // C + for _, t := range c.O { + accumulateG1(&C[t.WireID()], t, &coeffTau1[i]) + } + } + + // Prepare default contribution + _, _, g1, g2 := curve.Generators() + c2.Parameters.G1.Delta = g1 + c2.Parameters.G2.Delta = g2 + + // Build Z in PK as τⁱ(τⁿ - 1) = τ⁽ⁱ⁺ⁿ⁾ - τⁱ for i ∈ [0, n-2] + // τⁱ(τⁿ - 1) = τ⁽ⁱ⁺ⁿ⁾ - τⁱ for i ∈ [0, n-2] + n := len(srs.G1.AlphaTau) + c2.Parameters.G1.Z = make([]curve.G1Affine, n) + for i := 0; i < n-1; i++ { + c2.Parameters.G1.Z[i].Sub(&srs.G1.Tau[i+n], &srs.G1.Tau[i]) + } + bitReverse(c2.Parameters.G1.Z) + c2.Parameters.G1.Z = c2.Parameters.G1.Z[:n-1] + + // Evaluate L + nPrivate := internal + secret + c2.Parameters.G1.L = make([]curve.G1Affine, nPrivate) + evals.G1.VKK = make([]curve.G1Affine, public) + offset := public + for i := 0; i < nWires; i++ { + var tmp curve.G1Affine + tmp.Add(&bA[i], &aB[i]) + tmp.Add(&tmp, &C[i]) + if i < public { + evals.G1.VKK[i].Set(&tmp) + } else { + c2.Parameters.G1.L[i-offset].Set(&tmp) + } + } + // Set δ public key + var delta fr.Element + delta.SetOne() + c2.PublicKey = newPublicKey(delta, nil, 1) + + // Hash initial contribution + c2.Hash = c2.hash() + return c2, evals +} + +func (c *Phase2) Contribute() { + // Sample toxic δ + var delta, deltaInv fr.Element + var deltaBI, deltaInvBI big.Int + delta.SetRandom() + deltaInv.Inverse(&delta) + + delta.BigInt(&deltaBI) + deltaInv.BigInt(&deltaInvBI) + + // Set δ public key + c.PublicKey = newPublicKey(delta, c.Hash, 1) + + // Update δ + c.Parameters.G1.Delta.ScalarMultiplication(&c.Parameters.G1.Delta, &deltaBI) + c.Parameters.G2.Delta.ScalarMultiplication(&c.Parameters.G2.Delta, &deltaBI) + + // Update Z using δ⁻¹ + for i := 0; i < len(c.Parameters.G1.Z); i++ { + c.Parameters.G1.Z[i].ScalarMultiplication(&c.Parameters.G1.Z[i], &deltaInvBI) + } + + // Update L using δ⁻¹ + for i := 0; i < len(c.Parameters.G1.L); i++ { + c.Parameters.G1.L[i].ScalarMultiplication(&c.Parameters.G1.L[i], &deltaInvBI) + } + + // 4. Hash contribution + c.Hash = c.hash() +} + +func VerifyPhase2(c0, c1 *Phase2, c ...*Phase2) error { + contribs := append([]*Phase2{c0, c1}, c...) + for i := 0; i < len(contribs)-1; i++ { + if err := verifyPhase2(contribs[i], contribs[i+1]); err != nil { + return err + } + } + return nil +} + +func verifyPhase2(current, contribution *Phase2) error { + // Compute R for δ + deltaR := genR(contribution.PublicKey.SG, contribution.PublicKey.SXG, current.Hash[:], 1) + + // Check for knowledge of δ + if !sameRatio(contribution.PublicKey.SG, contribution.PublicKey.SXG, contribution.PublicKey.XR, deltaR) { + return errors.New("couldn't verify knowledge of δ") + } + + // Check for valid updates using previous parameters + if !sameRatio(contribution.Parameters.G1.Delta, current.Parameters.G1.Delta, deltaR, contribution.PublicKey.XR) { + return errors.New("couldn't verify that [δ]₁ is based on previous contribution") + } + if !sameRatio(contribution.PublicKey.SG, contribution.PublicKey.SXG, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { + return errors.New("couldn't verify that [δ]₂ is based on previous contribution") + } + + // Check for valid updates of L and Z using + L, prevL := merge(contribution.Parameters.G1.L, current.Parameters.G1.L) + if !sameRatio(L, prevL, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { + return errors.New("couldn't verify valid updates of L using δ⁻¹") + } + Z, prevZ := merge(contribution.Parameters.G1.Z, current.Parameters.G1.Z) + if !sameRatio(Z, prevZ, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { + return errors.New("couldn't verify valid updates of L using δ⁻¹") + } + + // Check hash of the contribution + h := contribution.hash() + for i := 0; i < len(h); i++ { + if h[i] != contribution.Hash[i] { + return errors.New("couldn't verify hash of contribution") + } + } + + return nil +} + +func (c *Phase2) hash() []byte { + sha := sha256.New() + c.writeTo(sha) + return sha.Sum(nil) +} diff --git a/backend/groth16/bls24-315/mpcsetup/setup.go b/backend/groth16/bls24-315/mpcsetup/setup.go new file mode 100644 index 0000000000..98fc63f1ad --- /dev/null +++ b/backend/groth16/bls24-315/mpcsetup/setup.go @@ -0,0 +1,97 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + curve "github.com/consensys/gnark-crypto/ecc/bls24-315" + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/fft" + groth16 "github.com/consensys/gnark/backend/groth16/bls24-315" +) + +func ExtractKeys(srs1 *Phase1, srs2 *Phase2, evals *Phase2Evaluations, nConstraints int) (pk groth16.ProvingKey, vk groth16.VerifyingKey) { + _, _, _, g2 := curve.Generators() + + // Initialize PK + pk.Domain = *fft.NewDomain(uint64(nConstraints)) + pk.G1.Alpha.Set(&srs1.Parameters.G1.AlphaTau[0]) + pk.G1.Beta.Set(&srs1.Parameters.G1.BetaTau[0]) + pk.G1.Delta.Set(&srs2.Parameters.G1.Delta) + pk.G1.Z = srs2.Parameters.G1.Z + bitReverse(pk.G1.Z) + + pk.G1.K = srs2.Parameters.G1.L + pk.G2.Beta.Set(&srs1.Parameters.G2.Beta) + pk.G2.Delta.Set(&srs2.Parameters.G2.Delta) + + // Filter out infinity points + nWires := len(evals.G1.A) + pk.InfinityA = make([]bool, nWires) + A := make([]curve.G1Affine, nWires) + j := 0 + for i, e := range evals.G1.A { + if e.IsInfinity() { + pk.InfinityA[i] = true + continue + } + A[j] = evals.G1.A[i] + j++ + } + pk.G1.A = A[:j] + pk.NbInfinityA = uint64(nWires - j) + + pk.InfinityB = make([]bool, nWires) + B := make([]curve.G1Affine, nWires) + j = 0 + for i, e := range evals.G1.B { + if e.IsInfinity() { + pk.InfinityB[i] = true + continue + } + B[j] = evals.G1.B[i] + j++ + } + pk.G1.B = B[:j] + pk.NbInfinityB = uint64(nWires - j) + + B2 := make([]curve.G2Affine, nWires) + j = 0 + for i, e := range evals.G2.B { + if e.IsInfinity() { + // pk.InfinityB[i] = true should be the same as in B + continue + } + B2[j] = evals.G2.B[i] + j++ + } + pk.G2.B = B2[:j] + + // Initialize VK + vk.G1.Alpha.Set(&srs1.Parameters.G1.AlphaTau[0]) + vk.G1.Beta.Set(&srs1.Parameters.G1.BetaTau[0]) + vk.G1.Delta.Set(&srs2.Parameters.G1.Delta) + vk.G2.Beta.Set(&srs1.Parameters.G2.Beta) + vk.G2.Delta.Set(&srs2.Parameters.G2.Delta) + vk.G2.Gamma.Set(&g2) + vk.G1.K = evals.G1.VKK + + // sets e, -[δ]2, -[γ]2 + if err := vk.Precompute(); err != nil { + panic(err) + } + + return pk, vk +} diff --git a/backend/groth16/bls24-315/mpcsetup/setup_test.go b/backend/groth16/bls24-315/mpcsetup/setup_test.go new file mode 100644 index 0000000000..c640467623 --- /dev/null +++ b/backend/groth16/bls24-315/mpcsetup/setup_test.go @@ -0,0 +1,199 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + curve "github.com/consensys/gnark-crypto/ecc/bls24-315" + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" + "github.com/consensys/gnark/constraint/bls24-315" + "testing" + + "github.com/consensys/gnark/backend/groth16" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/std/hash/mimc" + "github.com/stretchr/testify/require" + + native_mimc "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/mimc" +) + +func TestSetupCircuit(t *testing.T) { + if testing.Short() { + t.Skip() + } + const ( + nContributionsPhase1 = 3 + nContributionsPhase2 = 3 + power = 9 + ) + + assert := require.New(t) + + srs1 := InitPhase1(power) + + // Make and verify contributions for phase1 + for i := 1; i < nContributionsPhase1; i++ { + // we clone test purposes; but in practice, participant will receive a []byte, deserialize it, + // add his contribution and send back to coordinator. + prev := srs1.clone() + + srs1.Contribute() + assert.NoError(VerifyPhase1(&prev, &srs1)) + } + + // Compile the circuit + var myCircuit Circuit + ccs, err := frontend.Compile(curve.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) + assert.NoError(err) + + var evals Phase2Evaluations + r1cs := ccs.(*cs.R1CS) + + // Prepare for phase-2 + srs2, evals := InitPhase2(r1cs, &srs1) + + // Make and verify contributions for phase1 + for i := 1; i < nContributionsPhase2; i++ { + // we clone for test purposes; but in practice, participant will receive a []byte, deserialize it, + // add his contribution and send back to coordinator. + prev := srs2.clone() + + srs2.Contribute() + assert.NoError(VerifyPhase2(&prev, &srs2)) + } + + // Extract the proving and verifying keys + pk, vk := ExtractKeys(&srs1, &srs2, &evals, ccs.GetNbConstraints()) + + // Build the witness + var preImage, hash fr.Element + { + m := native_mimc.NewMiMC() + m.Write(preImage.Marshal()) + hash.SetBytes(m.Sum(nil)) + } + + witness, err := frontend.NewWitness(&Circuit{PreImage: preImage, Hash: hash}, curve.ID.ScalarField()) + assert.NoError(err) + + pubWitness, err := witness.Public() + assert.NoError(err) + + // groth16: ensure proof is verified + proof, err := groth16.Prove(ccs, &pk, witness) + assert.NoError(err) + + err = groth16.Verify(proof, &vk, pubWitness) + assert.NoError(err) +} + +func BenchmarkPhase1(b *testing.B) { + const power = 14 + + b.Run("init", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = InitPhase1(power) + } + }) + + b.Run("contrib", func(b *testing.B) { + srs1 := InitPhase1(power) + b.ResetTimer() + for i := 0; i < b.N; i++ { + srs1.Contribute() + } + }) + +} + +func BenchmarkPhase2(b *testing.B) { + const power = 14 + srs1 := InitPhase1(power) + srs1.Contribute() + + var myCircuit Circuit + ccs, err := frontend.Compile(curve.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) + if err != nil { + b.Fatal(err) + } + + r1cs := ccs.(*cs.R1CS) + + b.Run("init", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, _ = InitPhase2(r1cs, &srs1) + } + }) + + b.Run("contrib", func(b *testing.B) { + srs2, _ := InitPhase2(r1cs, &srs1) + b.ResetTimer() + for i := 0; i < b.N; i++ { + srs2.Contribute() + } + }) + +} + +// Circuit defines a pre-image knowledge proof +// mimc(secret preImage) = public hash +type Circuit struct { + PreImage frontend.Variable + Hash frontend.Variable `gnark:",public"` +} + +// Define declares the circuit's constraints +// Hash = mimc(PreImage) +func (circuit *Circuit) Define(api frontend.API) error { + // hash function + mimc, _ := mimc.NewMiMC(api) + + // specify constraints + mimc.Write(circuit.PreImage) + api.AssertIsEqual(circuit.Hash, mimc.Sum()) + + return nil +} + +func (phase1 *Phase1) clone() Phase1 { + r := Phase1{} + r.Parameters.G1.Tau = append(r.Parameters.G1.Tau, phase1.Parameters.G1.Tau...) + r.Parameters.G1.AlphaTau = append(r.Parameters.G1.AlphaTau, phase1.Parameters.G1.AlphaTau...) + r.Parameters.G1.BetaTau = append(r.Parameters.G1.BetaTau, phase1.Parameters.G1.BetaTau...) + + r.Parameters.G2.Tau = append(r.Parameters.G2.Tau, phase1.Parameters.G2.Tau...) + r.Parameters.G2.Beta = phase1.Parameters.G2.Beta + + r.PublicKeys = phase1.PublicKeys + r.Hash = append(r.Hash, phase1.Hash...) + + return r +} + +func (phase2 *Phase2) clone() Phase2 { + r := Phase2{} + r.Parameters.G1.Delta = phase2.Parameters.G1.Delta + r.Parameters.G1.L = append(r.Parameters.G1.L, phase2.Parameters.G1.L...) + r.Parameters.G1.Z = append(r.Parameters.G1.Z, phase2.Parameters.G1.Z...) + r.Parameters.G2.Delta = phase2.Parameters.G2.Delta + r.PublicKey = phase2.PublicKey + r.Hash = append(r.Hash, phase2.Hash...) + + return r +} diff --git a/backend/groth16/bls24-315/mpcsetup/utils.go b/backend/groth16/bls24-315/mpcsetup/utils.go new file mode 100644 index 0000000000..c86248ac16 --- /dev/null +++ b/backend/groth16/bls24-315/mpcsetup/utils.go @@ -0,0 +1,170 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "bytes" + "math/big" + "math/bits" + "runtime" + + "github.com/consensys/gnark-crypto/ecc" + curve "github.com/consensys/gnark-crypto/ecc/bls24-315" + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" + "github.com/consensys/gnark/internal/utils" +) + +type PublicKey struct { + SG curve.G1Affine + SXG curve.G1Affine + XR curve.G2Affine +} + +func newPublicKey(x fr.Element, challenge []byte, dst byte) PublicKey { + var pk PublicKey + _, _, g1, _ := curve.Generators() + + var s fr.Element + var sBi big.Int + s.SetRandom() + s.BigInt(&sBi) + pk.SG.ScalarMultiplication(&g1, &sBi) + + // compute x*sG1 + var xBi big.Int + x.BigInt(&xBi) + pk.SXG.ScalarMultiplication(&pk.SG, &xBi) + + // generate R based on sG1, sxG1, challenge, and domain separation tag (tau, alpha or beta) + R := genR(pk.SG, pk.SXG, challenge, dst) + + // compute x*spG2 + pk.XR.ScalarMultiplication(&R, &xBi) + return pk +} + +func bitReverse[T any](a []T) { + n := uint64(len(a)) + nn := uint64(64 - bits.TrailingZeros64(n)) + + for i := uint64(0); i < n; i++ { + irev := bits.Reverse64(i) >> nn + if irev > i { + a[i], a[irev] = a[irev], a[i] + } + } +} + +// Returns [1, a, a², ..., aⁿ⁻¹ ] in Montgomery form +func powers(a fr.Element, n int) []fr.Element { + result := make([]fr.Element, n) + result[0] = fr.NewElement(1) + for i := 1; i < n; i++ { + result[i].Mul(&result[i-1], &a) + } + return result +} + +// Returns [aᵢAᵢ, ...] in G1 +func scaleG1InPlace(A []curve.G1Affine, a []fr.Element) { + utils.Parallelize(len(A), func(start, end int) { + var tmp big.Int + for i := start; i < end; i++ { + a[i].BigInt(&tmp) + A[i].ScalarMultiplication(&A[i], &tmp) + } + }) +} + +// Returns [aᵢAᵢ, ...] in G2 +func scaleG2InPlace(A []curve.G2Affine, a []fr.Element) { + utils.Parallelize(len(A), func(start, end int) { + var tmp big.Int + for i := start; i < end; i++ { + a[i].BigInt(&tmp) + A[i].ScalarMultiplication(&A[i], &tmp) + } + }) +} + +// Check e(a₁, a₂) = e(b₁, b₂) +func sameRatio(a1, b1 curve.G1Affine, a2, b2 curve.G2Affine) bool { + if !a1.IsInSubGroup() || !b1.IsInSubGroup() || !a2.IsInSubGroup() || !b2.IsInSubGroup() { + panic("invalid point not in subgroup") + } + var na2 curve.G2Affine + na2.Neg(&a2) + res, err := curve.PairingCheck( + []curve.G1Affine{a1, b1}, + []curve.G2Affine{na2, b2}) + if err != nil { + panic(err) + } + return res +} + +// returns a = ∑ rᵢAᵢ, b = ∑ rᵢBᵢ +func merge(A, B []curve.G1Affine) (a, b curve.G1Affine) { + nc := runtime.NumCPU() + r := make([]fr.Element, len(A)) + for i := 0; i < len(A); i++ { + r[i].SetRandom() + } + a.MultiExp(A, r, ecc.MultiExpConfig{NbTasks: nc / 2}) + b.MultiExp(B, r, ecc.MultiExpConfig{NbTasks: nc / 2}) + return +} + +// L1 = ∑ rᵢAᵢ, L2 = ∑ rᵢAᵢ₊₁ in G1 +func linearCombinationG1(A []curve.G1Affine) (L1, L2 curve.G1Affine) { + nc := runtime.NumCPU() + n := len(A) + r := make([]fr.Element, n-1) + for i := 0; i < n-1; i++ { + r[i].SetRandom() + } + L1.MultiExp(A[:n-1], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + L2.MultiExp(A[1:], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + return +} + +// L1 = ∑ rᵢAᵢ, L2 = ∑ rᵢAᵢ₊₁ in G2 +func linearCombinationG2(A []curve.G2Affine) (L1, L2 curve.G2Affine) { + nc := runtime.NumCPU() + n := len(A) + r := make([]fr.Element, n-1) + for i := 0; i < n-1; i++ { + r[i].SetRandom() + } + L1.MultiExp(A[:n-1], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + L2.MultiExp(A[1:], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + return +} + +// Generate R in G₂ as Hash(gˢ, gˢˣ, challenge, dst) +func genR(sG1, sxG1 curve.G1Affine, challenge []byte, dst byte) curve.G2Affine { + var buf bytes.Buffer + buf.Grow(len(challenge) + curve.SizeOfG1AffineUncompressed*2) + buf.Write(sG1.Marshal()) + buf.Write(sxG1.Marshal()) + buf.Write(challenge) + spG2, err := curve.HashToG2(buf.Bytes(), []byte{dst}) + if err != nil { + panic(err) + } + return spG2 +} diff --git a/backend/groth16/bls24-317/mpcsetup/lagrange.go b/backend/groth16/bls24-317/mpcsetup/lagrange.go new file mode 100644 index 0000000000..ab3dc5706a --- /dev/null +++ b/backend/groth16/bls24-317/mpcsetup/lagrange.go @@ -0,0 +1,216 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "math/big" + "math/bits" + "runtime" + + "github.com/consensys/gnark-crypto/ecc" + curve "github.com/consensys/gnark-crypto/ecc/bls24-317" + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/fft" + "github.com/consensys/gnark/internal/utils" +) + +func LagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { + coeffs := make([]curve.G1Affine, size) + copy(coeffs, powers[:size]) + domain := fft.NewDomain(uint64(size)) + numCPU := uint64(runtime.NumCPU()) + maxSplits := bits.TrailingZeros64(ecc.NextPowerOfTwo(numCPU)) + + difFFTG1(coeffs, domain.TwiddlesInv, 0, maxSplits, nil) + bitReverse(coeffs) + + var invBigint big.Int + domain.CardinalityInv.BigInt(&invBigint) + + utils.Parallelize(size, func(start, end int) { + for i := start; i < end; i++ { + coeffs[i].ScalarMultiplication(&coeffs[i], &invBigint) + } + }) + return coeffs +} + +func LagrangeCoeffsG2(powers []curve.G2Affine, size int) []curve.G2Affine { + coeffs := make([]curve.G2Affine, size) + copy(coeffs, powers[:size]) + domain := fft.NewDomain(uint64(size)) + numCPU := uint64(runtime.NumCPU()) + maxSplits := bits.TrailingZeros64(ecc.NextPowerOfTwo(numCPU)) + + difFFTG2(coeffs, domain.TwiddlesInv, 0, maxSplits, nil) + bitReverse(coeffs) + + var invBigint big.Int + domain.CardinalityInv.BigInt(&invBigint) + + utils.Parallelize(size, func(start, end int) { + for i := start; i < end; i++ { + coeffs[i].ScalarMultiplication(&coeffs[i], &invBigint) + } + }) + return coeffs +} + +func butterflyG1(a *curve.G1Affine, b *curve.G1Affine) { + t := *a + a.Add(a, b) + b.Sub(&t, b) +} + +func butterflyG2(a *curve.G2Affine, b *curve.G2Affine) { + t := *a + a.Add(a, b) + b.Sub(&t, b) +} + +// kerDIF8 is a kernel that process a FFT of size 8 +func kerDIF8G1(a []curve.G1Affine, twiddles [][]fr.Element, stage int) { + butterflyG1(&a[0], &a[4]) + butterflyG1(&a[1], &a[5]) + butterflyG1(&a[2], &a[6]) + butterflyG1(&a[3], &a[7]) + + var twiddle big.Int + twiddles[stage+0][1].BigInt(&twiddle) + a[5].ScalarMultiplication(&a[5], &twiddle) + twiddles[stage+0][2].BigInt(&twiddle) + a[6].ScalarMultiplication(&a[6], &twiddle) + twiddles[stage+0][3].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG1(&a[0], &a[2]) + butterflyG1(&a[1], &a[3]) + butterflyG1(&a[4], &a[6]) + butterflyG1(&a[5], &a[7]) + twiddles[stage+1][1].BigInt(&twiddle) + a[3].ScalarMultiplication(&a[3], &twiddle) + twiddles[stage+1][1].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG1(&a[0], &a[1]) + butterflyG1(&a[2], &a[3]) + butterflyG1(&a[4], &a[5]) + butterflyG1(&a[6], &a[7]) +} + +// kerDIF8 is a kernel that process a FFT of size 8 +func kerDIF8G2(a []curve.G2Affine, twiddles [][]fr.Element, stage int) { + butterflyG2(&a[0], &a[4]) + butterflyG2(&a[1], &a[5]) + butterflyG2(&a[2], &a[6]) + butterflyG2(&a[3], &a[7]) + + var twiddle big.Int + twiddles[stage+0][1].BigInt(&twiddle) + a[5].ScalarMultiplication(&a[5], &twiddle) + twiddles[stage+0][2].BigInt(&twiddle) + a[6].ScalarMultiplication(&a[6], &twiddle) + twiddles[stage+0][3].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG2(&a[0], &a[2]) + butterflyG2(&a[1], &a[3]) + butterflyG2(&a[4], &a[6]) + butterflyG2(&a[5], &a[7]) + twiddles[stage+1][1].BigInt(&twiddle) + a[3].ScalarMultiplication(&a[3], &twiddle) + twiddles[stage+1][1].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG2(&a[0], &a[1]) + butterflyG2(&a[2], &a[3]) + butterflyG2(&a[4], &a[5]) + butterflyG2(&a[6], &a[7]) +} + +func difFFTG1(a []curve.G1Affine, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { + if chDone != nil { + defer close(chDone) + } + + n := len(a) + if n == 1 { + return + } else if n == 8 { + kerDIF8G1(a, twiddles, stage) + return + } + m := n >> 1 + + butterflyG1(&a[0], &a[m]) + + var twiddle big.Int + for i := 1; i < m; i++ { + butterflyG1(&a[i], &a[i+m]) + twiddles[stage][i].BigInt(&twiddle) + a[i+m].ScalarMultiplication(&a[i+m], &twiddle) + } + + if m == 1 { + return + } + + nextStage := stage + 1 + if stage < maxSplits { + chDone := make(chan struct{}, 1) + go difFFTG1(a[m:n], twiddles, nextStage, maxSplits, chDone) + difFFTG1(a[0:m], twiddles, nextStage, maxSplits, nil) + <-chDone + } else { + difFFTG1(a[0:m], twiddles, nextStage, maxSplits, nil) + difFFTG1(a[m:n], twiddles, nextStage, maxSplits, nil) + } +} +func difFFTG2(a []curve.G2Affine, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { + if chDone != nil { + defer close(chDone) + } + + n := len(a) + if n == 1 { + return + } else if n == 8 { + kerDIF8G2(a, twiddles, stage) + return + } + m := n >> 1 + + butterflyG2(&a[0], &a[m]) + + var twiddle big.Int + for i := 1; i < m; i++ { + butterflyG2(&a[i], &a[i+m]) + twiddles[stage][i].BigInt(&twiddle) + a[i+m].ScalarMultiplication(&a[i+m], &twiddle) + } + + if m == 1 { + return + } + + nextStage := stage + 1 + if stage < maxSplits { + chDone := make(chan struct{}, 1) + go difFFTG2(a[m:n], twiddles, nextStage, maxSplits, chDone) + difFFTG2(a[0:m], twiddles, nextStage, maxSplits, nil) + <-chDone + } else { + difFFTG2(a[0:m], twiddles, nextStage, maxSplits, nil) + difFFTG2(a[m:n], twiddles, nextStage, maxSplits, nil) + } +} diff --git a/backend/groth16/bls24-317/mpcsetup/marshal.go b/backend/groth16/bls24-317/mpcsetup/marshal.go new file mode 100644 index 0000000000..6e1ebfc02c --- /dev/null +++ b/backend/groth16/bls24-317/mpcsetup/marshal.go @@ -0,0 +1,181 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + curve "github.com/consensys/gnark-crypto/ecc/bls24-317" + "io" +) + +// WriteTo implements io.WriterTo +func (phase1 *Phase1) WriteTo(writer io.Writer) (int64, error) { + n, err := phase1.writeTo(writer) + if err != nil { + return n, err + } + nBytes, err := writer.Write(phase1.Hash) + return int64(nBytes) + n, err +} + +func (phase1 *Phase1) writeTo(writer io.Writer) (int64, error) { + toEncode := []interface{}{ + &phase1.PublicKeys.Tau.SG, + &phase1.PublicKeys.Tau.SXG, + &phase1.PublicKeys.Tau.XR, + &phase1.PublicKeys.Alpha.SG, + &phase1.PublicKeys.Alpha.SXG, + &phase1.PublicKeys.Alpha.XR, + &phase1.PublicKeys.Beta.SG, + &phase1.PublicKeys.Beta.SXG, + &phase1.PublicKeys.Beta.XR, + phase1.Parameters.G1.Tau, + phase1.Parameters.G1.AlphaTau, + phase1.Parameters.G1.BetaTau, + phase1.Parameters.G2.Tau, + &phase1.Parameters.G2.Beta, + } + + enc := curve.NewEncoder(writer) + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + return enc.BytesWritten(), nil +} + +// ReadFrom implements io.ReaderFrom +func (phase1 *Phase1) ReadFrom(reader io.Reader) (int64, error) { + toEncode := []interface{}{ + &phase1.PublicKeys.Tau.SG, + &phase1.PublicKeys.Tau.SXG, + &phase1.PublicKeys.Tau.XR, + &phase1.PublicKeys.Alpha.SG, + &phase1.PublicKeys.Alpha.SXG, + &phase1.PublicKeys.Alpha.XR, + &phase1.PublicKeys.Beta.SG, + &phase1.PublicKeys.Beta.SXG, + &phase1.PublicKeys.Beta.XR, + &phase1.Parameters.G1.Tau, + &phase1.Parameters.G1.AlphaTau, + &phase1.Parameters.G1.BetaTau, + &phase1.Parameters.G2.Tau, + &phase1.Parameters.G2.Beta, + } + + dec := curve.NewDecoder(reader) + for _, v := range toEncode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + phase1.Hash = make([]byte, 32) + nBytes, err := reader.Read(phase1.Hash) + return dec.BytesRead() + int64(nBytes), err +} + +// WriteTo implements io.WriterTo +func (phase2 *Phase2) WriteTo(writer io.Writer) (int64, error) { + n, err := phase2.writeTo(writer) + if err != nil { + return n, err + } + nBytes, err := writer.Write(phase2.Hash) + return int64(nBytes) + n, err +} + +func (c *Phase2) writeTo(writer io.Writer) (int64, error) { + enc := curve.NewEncoder(writer) + toEncode := []interface{}{ + &c.PublicKey.SG, + &c.PublicKey.SXG, + &c.PublicKey.XR, + &c.Parameters.G1.Delta, + c.Parameters.G1.L, + c.Parameters.G1.Z, + &c.Parameters.G2.Delta, + } + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + + return enc.BytesWritten(), nil +} + +// ReadFrom implements io.ReaderFrom +func (c *Phase2) ReadFrom(reader io.Reader) (int64, error) { + dec := curve.NewDecoder(reader) + toEncode := []interface{}{ + &c.PublicKey.SG, + &c.PublicKey.SXG, + &c.PublicKey.XR, + &c.Parameters.G1.Delta, + &c.Parameters.G1.L, + &c.Parameters.G1.Z, + &c.Parameters.G2.Delta, + } + + for _, v := range toEncode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + + c.Hash = make([]byte, 32) + n, err := reader.Read(c.Hash) + return int64(n) + dec.BytesRead(), err + +} + +// WriteTo implements io.WriterTo +func (c *Phase2Evaluations) WriteTo(writer io.Writer) (int64, error) { + enc := curve.NewEncoder(writer) + toEncode := []interface{}{ + c.G1.A, + c.G1.B, + c.G2.B, + } + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + + return enc.BytesWritten(), nil +} + +// ReadFrom implements io.ReaderFrom +func (c *Phase2Evaluations) ReadFrom(reader io.Reader) (int64, error) { + dec := curve.NewDecoder(reader) + toEncode := []interface{}{ + &c.G1.A, + &c.G1.B, + &c.G2.B, + } + + for _, v := range toEncode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + + return dec.BytesRead(), nil +} diff --git a/backend/groth16/bls24-317/mpcsetup/marshal_test.go b/backend/groth16/bls24-317/mpcsetup/marshal_test.go new file mode 100644 index 0000000000..6fc34b923c --- /dev/null +++ b/backend/groth16/bls24-317/mpcsetup/marshal_test.go @@ -0,0 +1,79 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "bytes" + curve "github.com/consensys/gnark-crypto/ecc/bls24-317" + "github.com/consensys/gnark/constraint/bls24-317" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/stretchr/testify/require" + "io" + "reflect" + "testing" +) + +func TestContributionSerialization(t *testing.T) { + assert := require.New(t) + + // Phase 1 + srs1 := InitPhase1(9) + srs1.Contribute() + { + var reconstructed Phase1 + roundTripCheck(t, &srs1, &reconstructed) + } + + var myCircuit Circuit + ccs, err := frontend.Compile(curve.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) + assert.NoError(err) + + r1cs := ccs.(*cs.R1CS) + + // Phase 2 + srs2, _ := InitPhase2(r1cs, &srs1) + srs2.Contribute() + + { + var reconstructed Phase2 + roundTripCheck(t, &srs2, &reconstructed) + } +} + +func roundTripCheck(t *testing.T, from io.WriterTo, reconstructed io.ReaderFrom) { + t.Helper() + + var buf bytes.Buffer + written, err := from.WriteTo(&buf) + if err != nil { + t.Fatal("couldn't serialize", err) + } + + read, err := reconstructed.ReadFrom(&buf) + if err != nil { + t.Fatal("couldn't deserialize", err) + } + + if !reflect.DeepEqual(from, reconstructed) { + t.Fatal("reconstructed object don't match original") + } + + if written != read { + t.Fatal("bytes written / read don't match") + } +} diff --git a/backend/groth16/bls24-317/mpcsetup/phase1.go b/backend/groth16/bls24-317/mpcsetup/phase1.go new file mode 100644 index 0000000000..72e61e9977 --- /dev/null +++ b/backend/groth16/bls24-317/mpcsetup/phase1.go @@ -0,0 +1,203 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "crypto/sha256" + "errors" + curve "github.com/consensys/gnark-crypto/ecc/bls24-317" + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" + "math" + "math/big" +) + +// Phase1 represents the Phase1 of the MPC described in +// https://eprint.iacr.org/2017/1050.pdf +// +// Also known as "Powers of Tau" +type Phase1 struct { + Parameters struct { + G1 struct { + Tau []curve.G1Affine // {[τ⁰]₁, [τ¹]₁, [τ²]₁, …, [τ²ⁿ⁻²]₁} + AlphaTau []curve.G1Affine // {α[τ⁰]₁, α[τ¹]₁, α[τ²]₁, …, α[τⁿ⁻¹]₁} + BetaTau []curve.G1Affine // {β[τ⁰]₁, β[τ¹]₁, β[τ²]₁, …, β[τⁿ⁻¹]₁} + } + G2 struct { + Tau []curve.G2Affine // {[τ⁰]₂, [τ¹]₂, [τ²]₂, …, [τⁿ⁻¹]₂} + Beta curve.G2Affine // [β]₂ + } + } + PublicKeys struct { + Tau, Alpha, Beta PublicKey + } + Hash []byte // sha256 hash +} + +// InitPhase1 initialize phase 1 of the MPC. This is called once by the coordinator before +// any randomness contribution is made (see Contribute()). +func InitPhase1(power int) (phase1 Phase1) { + N := int(math.Pow(2, float64(power))) + + // Generate key pairs + var tau, alpha, beta fr.Element + tau.SetOne() + alpha.SetOne() + beta.SetOne() + phase1.PublicKeys.Tau = newPublicKey(tau, nil, 1) + phase1.PublicKeys.Alpha = newPublicKey(alpha, nil, 2) + phase1.PublicKeys.Beta = newPublicKey(beta, nil, 3) + + // First contribution use generators + _, _, g1, g2 := curve.Generators() + phase1.Parameters.G2.Beta.Set(&g2) + phase1.Parameters.G1.Tau = make([]curve.G1Affine, 2*N-1) + phase1.Parameters.G2.Tau = make([]curve.G2Affine, N) + phase1.Parameters.G1.AlphaTau = make([]curve.G1Affine, N) + phase1.Parameters.G1.BetaTau = make([]curve.G1Affine, N) + for i := 0; i < len(phase1.Parameters.G1.Tau); i++ { + phase1.Parameters.G1.Tau[i].Set(&g1) + } + for i := 0; i < len(phase1.Parameters.G2.Tau); i++ { + phase1.Parameters.G2.Tau[i].Set(&g2) + phase1.Parameters.G1.AlphaTau[i].Set(&g1) + phase1.Parameters.G1.BetaTau[i].Set(&g1) + } + + phase1.Parameters.G2.Beta.Set(&g2) + + // Compute hash of Contribution + phase1.Hash = phase1.hash() + + return +} + +// Contribute contributes randomness to the phase1 object. This mutates phase1. +func (phase1 *Phase1) Contribute() { + N := len(phase1.Parameters.G2.Tau) + + // Generate key pairs + var tau, alpha, beta fr.Element + tau.SetRandom() + alpha.SetRandom() + beta.SetRandom() + phase1.PublicKeys.Tau = newPublicKey(tau, phase1.Hash[:], 1) + phase1.PublicKeys.Alpha = newPublicKey(alpha, phase1.Hash[:], 2) + phase1.PublicKeys.Beta = newPublicKey(beta, phase1.Hash[:], 3) + + // Compute powers of τ, ατ, and βτ + taus := powers(tau, 2*N-1) + alphaTau := make([]fr.Element, N) + betaTau := make([]fr.Element, N) + for i := 0; i < N; i++ { + alphaTau[i].Mul(&taus[i], &alpha) + betaTau[i].Mul(&taus[i], &beta) + } + + // Update using previous parameters + // TODO @gbotrel working with jacobian points here will help with perf. + scaleG1InPlace(phase1.Parameters.G1.Tau, taus) + scaleG2InPlace(phase1.Parameters.G2.Tau, taus[0:N]) + scaleG1InPlace(phase1.Parameters.G1.AlphaTau, alphaTau) + scaleG1InPlace(phase1.Parameters.G1.BetaTau, betaTau) + var betaBI big.Int + beta.BigInt(&betaBI) + phase1.Parameters.G2.Beta.ScalarMultiplication(&phase1.Parameters.G2.Beta, &betaBI) + + // Compute hash of Contribution + phase1.Hash = phase1.hash() +} + +func VerifyPhase1(c0, c1 *Phase1, c ...*Phase1) error { + contribs := append([]*Phase1{c0, c1}, c...) + for i := 0; i < len(contribs)-1; i++ { + if err := verifyPhase1(contribs[i], contribs[i+1]); err != nil { + return err + } + } + return nil +} + +// verifyPhase1 checks that a contribution is based on a known previous Phase1 state. +func verifyPhase1(current, contribution *Phase1) error { + // Compute R for τ, α, β + tauR := genR(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, current.Hash[:], 1) + alphaR := genR(contribution.PublicKeys.Alpha.SG, contribution.PublicKeys.Alpha.SXG, current.Hash[:], 2) + betaR := genR(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, current.Hash[:], 3) + + // Check for knowledge of toxic parameters + if !sameRatio(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, contribution.PublicKeys.Tau.XR, tauR) { + return errors.New("couldn't verify public key of τ") + } + if !sameRatio(contribution.PublicKeys.Alpha.SG, contribution.PublicKeys.Alpha.SXG, contribution.PublicKeys.Alpha.XR, alphaR) { + return errors.New("couldn't verify public key of α") + } + if !sameRatio(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, contribution.PublicKeys.Beta.XR, betaR) { + return errors.New("couldn't verify public key of β") + } + + // Check for valid updates using previous parameters + if !sameRatio(contribution.Parameters.G1.Tau[1], current.Parameters.G1.Tau[1], tauR, contribution.PublicKeys.Tau.XR) { + return errors.New("couldn't verify that [τ]₁ is based on previous contribution") + } + if !sameRatio(contribution.Parameters.G1.AlphaTau[0], current.Parameters.G1.AlphaTau[0], alphaR, contribution.PublicKeys.Alpha.XR) { + return errors.New("couldn't verify that [α]₁ is based on previous contribution") + } + if !sameRatio(contribution.Parameters.G1.BetaTau[0], current.Parameters.G1.BetaTau[0], betaR, contribution.PublicKeys.Beta.XR) { + return errors.New("couldn't verify that [β]₁ is based on previous contribution") + } + if !sameRatio(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, contribution.Parameters.G2.Tau[1], current.Parameters.G2.Tau[1]) { + return errors.New("couldn't verify that [τ]₂ is based on previous contribution") + } + if !sameRatio(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, contribution.Parameters.G2.Beta, current.Parameters.G2.Beta) { + return errors.New("couldn't verify that [β]₂ is based on previous contribution") + } + + // Check for valid updates using powers of τ + _, _, g1, g2 := curve.Generators() + tauL1, tauL2 := linearCombinationG1(contribution.Parameters.G1.Tau) + if !sameRatio(tauL1, tauL2, contribution.Parameters.G2.Tau[1], g2) { + return errors.New("couldn't verify valid powers of τ in G₁") + } + alphaL1, alphaL2 := linearCombinationG1(contribution.Parameters.G1.AlphaTau) + if !sameRatio(alphaL1, alphaL2, contribution.Parameters.G2.Tau[1], g2) { + return errors.New("couldn't verify valid powers of α(τ) in G₁") + } + betaL1, betaL2 := linearCombinationG1(contribution.Parameters.G1.BetaTau) + if !sameRatio(betaL1, betaL2, contribution.Parameters.G2.Tau[1], g2) { + return errors.New("couldn't verify valid powers of α(τ) in G₁") + } + tau2L1, tau2L2 := linearCombinationG2(contribution.Parameters.G2.Tau) + if !sameRatio(contribution.Parameters.G1.Tau[1], g1, tau2L1, tau2L2) { + return errors.New("couldn't verify valid powers of τ in G₂") + } + + // Check hash of the contribution + h := contribution.hash() + for i := 0; i < len(h); i++ { + if h[i] != contribution.Hash[i] { + return errors.New("couldn't verify hash of contribution") + } + } + + return nil +} + +func (phase1 *Phase1) hash() []byte { + sha := sha256.New() + phase1.writeTo(sha) + return sha.Sum(nil) +} diff --git a/backend/groth16/bls24-317/mpcsetup/phase2.go b/backend/groth16/bls24-317/mpcsetup/phase2.go new file mode 100644 index 0000000000..bfbbdbddc1 --- /dev/null +++ b/backend/groth16/bls24-317/mpcsetup/phase2.go @@ -0,0 +1,258 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "crypto/sha256" + "errors" + "math/big" + + curve "github.com/consensys/gnark-crypto/ecc/bls24-317" + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" + "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/bls24-317" +) + +type Phase2Evaluations struct { + G1 struct { + A, B, VKK []curve.G1Affine + } + G2 struct { + B []curve.G2Affine + } +} + +type Phase2 struct { + Parameters struct { + G1 struct { + Delta curve.G1Affine + L, Z []curve.G1Affine + } + G2 struct { + Delta curve.G2Affine + } + } + PublicKey PublicKey + Hash []byte +} + +func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { + srs := srs1.Parameters + size := len(srs.G1.AlphaTau) + if size < r1cs.GetNbConstraints() { + panic("Number of constraints is larger than expected") + } + + c2 := Phase2{} + + accumulateG1 := func(res *curve.G1Affine, t constraint.Term, value *curve.G1Affine) { + cID := t.CoeffID() + switch cID { + case constraint.CoeffIdZero: + return + case constraint.CoeffIdOne: + res.Add(res, value) + case constraint.CoeffIdMinusOne: + res.Sub(res, value) + case constraint.CoeffIdTwo: + res.Add(res, value).Add(res, value) + default: + var tmp curve.G1Affine + var vBi big.Int + r1cs.Coefficients[cID].BigInt(&vBi) + tmp.ScalarMultiplication(value, &vBi) + res.Add(res, &tmp) + } + } + + accumulateG2 := func(res *curve.G2Affine, t constraint.Term, value *curve.G2Affine) { + cID := t.CoeffID() + switch cID { + case constraint.CoeffIdZero: + return + case constraint.CoeffIdOne: + res.Add(res, value) + case constraint.CoeffIdMinusOne: + res.Sub(res, value) + case constraint.CoeffIdTwo: + res.Add(res, value).Add(res, value) + default: + var tmp curve.G2Affine + var vBi big.Int + r1cs.Coefficients[cID].BigInt(&vBi) + tmp.ScalarMultiplication(value, &vBi) + res.Add(res, &tmp) + } + } + + // Prepare Lagrange coefficients of [τ...]₁, [τ...]₂, [ατ...]₁, [βτ...]₁ + coeffTau1 := LagrangeCoeffsG1(srs.G1.Tau, size) + coeffTau2 := LagrangeCoeffsG2(srs.G2.Tau, size) + coeffAlphaTau1 := LagrangeCoeffsG1(srs.G1.AlphaTau, size) + coeffBetaTau1 := LagrangeCoeffsG1(srs.G1.BetaTau, size) + + internal, secret, public := r1cs.GetNbVariables() + nWires := internal + secret + public + var evals Phase2Evaluations + evals.G1.A = make([]curve.G1Affine, nWires) + evals.G1.B = make([]curve.G1Affine, nWires) + evals.G2.B = make([]curve.G2Affine, nWires) + bA := make([]curve.G1Affine, nWires) + aB := make([]curve.G1Affine, nWires) + C := make([]curve.G1Affine, nWires) + for i, c := range r1cs.Constraints { + // A + for _, t := range c.L { + accumulateG1(&evals.G1.A[t.WireID()], t, &coeffTau1[i]) + accumulateG1(&bA[t.WireID()], t, &coeffBetaTau1[i]) + } + // B + for _, t := range c.R { + accumulateG1(&evals.G1.B[t.WireID()], t, &coeffTau1[i]) + accumulateG2(&evals.G2.B[t.WireID()], t, &coeffTau2[i]) + accumulateG1(&aB[t.WireID()], t, &coeffAlphaTau1[i]) + } + // C + for _, t := range c.O { + accumulateG1(&C[t.WireID()], t, &coeffTau1[i]) + } + } + + // Prepare default contribution + _, _, g1, g2 := curve.Generators() + c2.Parameters.G1.Delta = g1 + c2.Parameters.G2.Delta = g2 + + // Build Z in PK as τⁱ(τⁿ - 1) = τ⁽ⁱ⁺ⁿ⁾ - τⁱ for i ∈ [0, n-2] + // τⁱ(τⁿ - 1) = τ⁽ⁱ⁺ⁿ⁾ - τⁱ for i ∈ [0, n-2] + n := len(srs.G1.AlphaTau) + c2.Parameters.G1.Z = make([]curve.G1Affine, n) + for i := 0; i < n-1; i++ { + c2.Parameters.G1.Z[i].Sub(&srs.G1.Tau[i+n], &srs.G1.Tau[i]) + } + bitReverse(c2.Parameters.G1.Z) + c2.Parameters.G1.Z = c2.Parameters.G1.Z[:n-1] + + // Evaluate L + nPrivate := internal + secret + c2.Parameters.G1.L = make([]curve.G1Affine, nPrivate) + evals.G1.VKK = make([]curve.G1Affine, public) + offset := public + for i := 0; i < nWires; i++ { + var tmp curve.G1Affine + tmp.Add(&bA[i], &aB[i]) + tmp.Add(&tmp, &C[i]) + if i < public { + evals.G1.VKK[i].Set(&tmp) + } else { + c2.Parameters.G1.L[i-offset].Set(&tmp) + } + } + // Set δ public key + var delta fr.Element + delta.SetOne() + c2.PublicKey = newPublicKey(delta, nil, 1) + + // Hash initial contribution + c2.Hash = c2.hash() + return c2, evals +} + +func (c *Phase2) Contribute() { + // Sample toxic δ + var delta, deltaInv fr.Element + var deltaBI, deltaInvBI big.Int + delta.SetRandom() + deltaInv.Inverse(&delta) + + delta.BigInt(&deltaBI) + deltaInv.BigInt(&deltaInvBI) + + // Set δ public key + c.PublicKey = newPublicKey(delta, c.Hash, 1) + + // Update δ + c.Parameters.G1.Delta.ScalarMultiplication(&c.Parameters.G1.Delta, &deltaBI) + c.Parameters.G2.Delta.ScalarMultiplication(&c.Parameters.G2.Delta, &deltaBI) + + // Update Z using δ⁻¹ + for i := 0; i < len(c.Parameters.G1.Z); i++ { + c.Parameters.G1.Z[i].ScalarMultiplication(&c.Parameters.G1.Z[i], &deltaInvBI) + } + + // Update L using δ⁻¹ + for i := 0; i < len(c.Parameters.G1.L); i++ { + c.Parameters.G1.L[i].ScalarMultiplication(&c.Parameters.G1.L[i], &deltaInvBI) + } + + // 4. Hash contribution + c.Hash = c.hash() +} + +func VerifyPhase2(c0, c1 *Phase2, c ...*Phase2) error { + contribs := append([]*Phase2{c0, c1}, c...) + for i := 0; i < len(contribs)-1; i++ { + if err := verifyPhase2(contribs[i], contribs[i+1]); err != nil { + return err + } + } + return nil +} + +func verifyPhase2(current, contribution *Phase2) error { + // Compute R for δ + deltaR := genR(contribution.PublicKey.SG, contribution.PublicKey.SXG, current.Hash[:], 1) + + // Check for knowledge of δ + if !sameRatio(contribution.PublicKey.SG, contribution.PublicKey.SXG, contribution.PublicKey.XR, deltaR) { + return errors.New("couldn't verify knowledge of δ") + } + + // Check for valid updates using previous parameters + if !sameRatio(contribution.Parameters.G1.Delta, current.Parameters.G1.Delta, deltaR, contribution.PublicKey.XR) { + return errors.New("couldn't verify that [δ]₁ is based on previous contribution") + } + if !sameRatio(contribution.PublicKey.SG, contribution.PublicKey.SXG, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { + return errors.New("couldn't verify that [δ]₂ is based on previous contribution") + } + + // Check for valid updates of L and Z using + L, prevL := merge(contribution.Parameters.G1.L, current.Parameters.G1.L) + if !sameRatio(L, prevL, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { + return errors.New("couldn't verify valid updates of L using δ⁻¹") + } + Z, prevZ := merge(contribution.Parameters.G1.Z, current.Parameters.G1.Z) + if !sameRatio(Z, prevZ, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { + return errors.New("couldn't verify valid updates of L using δ⁻¹") + } + + // Check hash of the contribution + h := contribution.hash() + for i := 0; i < len(h); i++ { + if h[i] != contribution.Hash[i] { + return errors.New("couldn't verify hash of contribution") + } + } + + return nil +} + +func (c *Phase2) hash() []byte { + sha := sha256.New() + c.writeTo(sha) + return sha.Sum(nil) +} diff --git a/backend/groth16/bls24-317/mpcsetup/setup.go b/backend/groth16/bls24-317/mpcsetup/setup.go new file mode 100644 index 0000000000..f90fea816c --- /dev/null +++ b/backend/groth16/bls24-317/mpcsetup/setup.go @@ -0,0 +1,97 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + curve "github.com/consensys/gnark-crypto/ecc/bls24-317" + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/fft" + groth16 "github.com/consensys/gnark/backend/groth16/bls24-317" +) + +func ExtractKeys(srs1 *Phase1, srs2 *Phase2, evals *Phase2Evaluations, nConstraints int) (pk groth16.ProvingKey, vk groth16.VerifyingKey) { + _, _, _, g2 := curve.Generators() + + // Initialize PK + pk.Domain = *fft.NewDomain(uint64(nConstraints)) + pk.G1.Alpha.Set(&srs1.Parameters.G1.AlphaTau[0]) + pk.G1.Beta.Set(&srs1.Parameters.G1.BetaTau[0]) + pk.G1.Delta.Set(&srs2.Parameters.G1.Delta) + pk.G1.Z = srs2.Parameters.G1.Z + bitReverse(pk.G1.Z) + + pk.G1.K = srs2.Parameters.G1.L + pk.G2.Beta.Set(&srs1.Parameters.G2.Beta) + pk.G2.Delta.Set(&srs2.Parameters.G2.Delta) + + // Filter out infinity points + nWires := len(evals.G1.A) + pk.InfinityA = make([]bool, nWires) + A := make([]curve.G1Affine, nWires) + j := 0 + for i, e := range evals.G1.A { + if e.IsInfinity() { + pk.InfinityA[i] = true + continue + } + A[j] = evals.G1.A[i] + j++ + } + pk.G1.A = A[:j] + pk.NbInfinityA = uint64(nWires - j) + + pk.InfinityB = make([]bool, nWires) + B := make([]curve.G1Affine, nWires) + j = 0 + for i, e := range evals.G1.B { + if e.IsInfinity() { + pk.InfinityB[i] = true + continue + } + B[j] = evals.G1.B[i] + j++ + } + pk.G1.B = B[:j] + pk.NbInfinityB = uint64(nWires - j) + + B2 := make([]curve.G2Affine, nWires) + j = 0 + for i, e := range evals.G2.B { + if e.IsInfinity() { + // pk.InfinityB[i] = true should be the same as in B + continue + } + B2[j] = evals.G2.B[i] + j++ + } + pk.G2.B = B2[:j] + + // Initialize VK + vk.G1.Alpha.Set(&srs1.Parameters.G1.AlphaTau[0]) + vk.G1.Beta.Set(&srs1.Parameters.G1.BetaTau[0]) + vk.G1.Delta.Set(&srs2.Parameters.G1.Delta) + vk.G2.Beta.Set(&srs1.Parameters.G2.Beta) + vk.G2.Delta.Set(&srs2.Parameters.G2.Delta) + vk.G2.Gamma.Set(&g2) + vk.G1.K = evals.G1.VKK + + // sets e, -[δ]2, -[γ]2 + if err := vk.Precompute(); err != nil { + panic(err) + } + + return pk, vk +} diff --git a/backend/groth16/bls24-317/mpcsetup/setup_test.go b/backend/groth16/bls24-317/mpcsetup/setup_test.go new file mode 100644 index 0000000000..8332441b27 --- /dev/null +++ b/backend/groth16/bls24-317/mpcsetup/setup_test.go @@ -0,0 +1,199 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + curve "github.com/consensys/gnark-crypto/ecc/bls24-317" + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" + "github.com/consensys/gnark/constraint/bls24-317" + "testing" + + "github.com/consensys/gnark/backend/groth16" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/std/hash/mimc" + "github.com/stretchr/testify/require" + + native_mimc "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/mimc" +) + +func TestSetupCircuit(t *testing.T) { + if testing.Short() { + t.Skip() + } + const ( + nContributionsPhase1 = 3 + nContributionsPhase2 = 3 + power = 9 + ) + + assert := require.New(t) + + srs1 := InitPhase1(power) + + // Make and verify contributions for phase1 + for i := 1; i < nContributionsPhase1; i++ { + // we clone test purposes; but in practice, participant will receive a []byte, deserialize it, + // add his contribution and send back to coordinator. + prev := srs1.clone() + + srs1.Contribute() + assert.NoError(VerifyPhase1(&prev, &srs1)) + } + + // Compile the circuit + var myCircuit Circuit + ccs, err := frontend.Compile(curve.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) + assert.NoError(err) + + var evals Phase2Evaluations + r1cs := ccs.(*cs.R1CS) + + // Prepare for phase-2 + srs2, evals := InitPhase2(r1cs, &srs1) + + // Make and verify contributions for phase1 + for i := 1; i < nContributionsPhase2; i++ { + // we clone for test purposes; but in practice, participant will receive a []byte, deserialize it, + // add his contribution and send back to coordinator. + prev := srs2.clone() + + srs2.Contribute() + assert.NoError(VerifyPhase2(&prev, &srs2)) + } + + // Extract the proving and verifying keys + pk, vk := ExtractKeys(&srs1, &srs2, &evals, ccs.GetNbConstraints()) + + // Build the witness + var preImage, hash fr.Element + { + m := native_mimc.NewMiMC() + m.Write(preImage.Marshal()) + hash.SetBytes(m.Sum(nil)) + } + + witness, err := frontend.NewWitness(&Circuit{PreImage: preImage, Hash: hash}, curve.ID.ScalarField()) + assert.NoError(err) + + pubWitness, err := witness.Public() + assert.NoError(err) + + // groth16: ensure proof is verified + proof, err := groth16.Prove(ccs, &pk, witness) + assert.NoError(err) + + err = groth16.Verify(proof, &vk, pubWitness) + assert.NoError(err) +} + +func BenchmarkPhase1(b *testing.B) { + const power = 14 + + b.Run("init", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = InitPhase1(power) + } + }) + + b.Run("contrib", func(b *testing.B) { + srs1 := InitPhase1(power) + b.ResetTimer() + for i := 0; i < b.N; i++ { + srs1.Contribute() + } + }) + +} + +func BenchmarkPhase2(b *testing.B) { + const power = 14 + srs1 := InitPhase1(power) + srs1.Contribute() + + var myCircuit Circuit + ccs, err := frontend.Compile(curve.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) + if err != nil { + b.Fatal(err) + } + + r1cs := ccs.(*cs.R1CS) + + b.Run("init", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, _ = InitPhase2(r1cs, &srs1) + } + }) + + b.Run("contrib", func(b *testing.B) { + srs2, _ := InitPhase2(r1cs, &srs1) + b.ResetTimer() + for i := 0; i < b.N; i++ { + srs2.Contribute() + } + }) + +} + +// Circuit defines a pre-image knowledge proof +// mimc(secret preImage) = public hash +type Circuit struct { + PreImage frontend.Variable + Hash frontend.Variable `gnark:",public"` +} + +// Define declares the circuit's constraints +// Hash = mimc(PreImage) +func (circuit *Circuit) Define(api frontend.API) error { + // hash function + mimc, _ := mimc.NewMiMC(api) + + // specify constraints + mimc.Write(circuit.PreImage) + api.AssertIsEqual(circuit.Hash, mimc.Sum()) + + return nil +} + +func (phase1 *Phase1) clone() Phase1 { + r := Phase1{} + r.Parameters.G1.Tau = append(r.Parameters.G1.Tau, phase1.Parameters.G1.Tau...) + r.Parameters.G1.AlphaTau = append(r.Parameters.G1.AlphaTau, phase1.Parameters.G1.AlphaTau...) + r.Parameters.G1.BetaTau = append(r.Parameters.G1.BetaTau, phase1.Parameters.G1.BetaTau...) + + r.Parameters.G2.Tau = append(r.Parameters.G2.Tau, phase1.Parameters.G2.Tau...) + r.Parameters.G2.Beta = phase1.Parameters.G2.Beta + + r.PublicKeys = phase1.PublicKeys + r.Hash = append(r.Hash, phase1.Hash...) + + return r +} + +func (phase2 *Phase2) clone() Phase2 { + r := Phase2{} + r.Parameters.G1.Delta = phase2.Parameters.G1.Delta + r.Parameters.G1.L = append(r.Parameters.G1.L, phase2.Parameters.G1.L...) + r.Parameters.G1.Z = append(r.Parameters.G1.Z, phase2.Parameters.G1.Z...) + r.Parameters.G2.Delta = phase2.Parameters.G2.Delta + r.PublicKey = phase2.PublicKey + r.Hash = append(r.Hash, phase2.Hash...) + + return r +} diff --git a/backend/groth16/bls24-317/mpcsetup/utils.go b/backend/groth16/bls24-317/mpcsetup/utils.go new file mode 100644 index 0000000000..877fef7fad --- /dev/null +++ b/backend/groth16/bls24-317/mpcsetup/utils.go @@ -0,0 +1,170 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "bytes" + "math/big" + "math/bits" + "runtime" + + "github.com/consensys/gnark-crypto/ecc" + curve "github.com/consensys/gnark-crypto/ecc/bls24-317" + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" + "github.com/consensys/gnark/internal/utils" +) + +type PublicKey struct { + SG curve.G1Affine + SXG curve.G1Affine + XR curve.G2Affine +} + +func newPublicKey(x fr.Element, challenge []byte, dst byte) PublicKey { + var pk PublicKey + _, _, g1, _ := curve.Generators() + + var s fr.Element + var sBi big.Int + s.SetRandom() + s.BigInt(&sBi) + pk.SG.ScalarMultiplication(&g1, &sBi) + + // compute x*sG1 + var xBi big.Int + x.BigInt(&xBi) + pk.SXG.ScalarMultiplication(&pk.SG, &xBi) + + // generate R based on sG1, sxG1, challenge, and domain separation tag (tau, alpha or beta) + R := genR(pk.SG, pk.SXG, challenge, dst) + + // compute x*spG2 + pk.XR.ScalarMultiplication(&R, &xBi) + return pk +} + +func bitReverse[T any](a []T) { + n := uint64(len(a)) + nn := uint64(64 - bits.TrailingZeros64(n)) + + for i := uint64(0); i < n; i++ { + irev := bits.Reverse64(i) >> nn + if irev > i { + a[i], a[irev] = a[irev], a[i] + } + } +} + +// Returns [1, a, a², ..., aⁿ⁻¹ ] in Montgomery form +func powers(a fr.Element, n int) []fr.Element { + result := make([]fr.Element, n) + result[0] = fr.NewElement(1) + for i := 1; i < n; i++ { + result[i].Mul(&result[i-1], &a) + } + return result +} + +// Returns [aᵢAᵢ, ...] in G1 +func scaleG1InPlace(A []curve.G1Affine, a []fr.Element) { + utils.Parallelize(len(A), func(start, end int) { + var tmp big.Int + for i := start; i < end; i++ { + a[i].BigInt(&tmp) + A[i].ScalarMultiplication(&A[i], &tmp) + } + }) +} + +// Returns [aᵢAᵢ, ...] in G2 +func scaleG2InPlace(A []curve.G2Affine, a []fr.Element) { + utils.Parallelize(len(A), func(start, end int) { + var tmp big.Int + for i := start; i < end; i++ { + a[i].BigInt(&tmp) + A[i].ScalarMultiplication(&A[i], &tmp) + } + }) +} + +// Check e(a₁, a₂) = e(b₁, b₂) +func sameRatio(a1, b1 curve.G1Affine, a2, b2 curve.G2Affine) bool { + if !a1.IsInSubGroup() || !b1.IsInSubGroup() || !a2.IsInSubGroup() || !b2.IsInSubGroup() { + panic("invalid point not in subgroup") + } + var na2 curve.G2Affine + na2.Neg(&a2) + res, err := curve.PairingCheck( + []curve.G1Affine{a1, b1}, + []curve.G2Affine{na2, b2}) + if err != nil { + panic(err) + } + return res +} + +// returns a = ∑ rᵢAᵢ, b = ∑ rᵢBᵢ +func merge(A, B []curve.G1Affine) (a, b curve.G1Affine) { + nc := runtime.NumCPU() + r := make([]fr.Element, len(A)) + for i := 0; i < len(A); i++ { + r[i].SetRandom() + } + a.MultiExp(A, r, ecc.MultiExpConfig{NbTasks: nc / 2}) + b.MultiExp(B, r, ecc.MultiExpConfig{NbTasks: nc / 2}) + return +} + +// L1 = ∑ rᵢAᵢ, L2 = ∑ rᵢAᵢ₊₁ in G1 +func linearCombinationG1(A []curve.G1Affine) (L1, L2 curve.G1Affine) { + nc := runtime.NumCPU() + n := len(A) + r := make([]fr.Element, n-1) + for i := 0; i < n-1; i++ { + r[i].SetRandom() + } + L1.MultiExp(A[:n-1], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + L2.MultiExp(A[1:], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + return +} + +// L1 = ∑ rᵢAᵢ, L2 = ∑ rᵢAᵢ₊₁ in G2 +func linearCombinationG2(A []curve.G2Affine) (L1, L2 curve.G2Affine) { + nc := runtime.NumCPU() + n := len(A) + r := make([]fr.Element, n-1) + for i := 0; i < n-1; i++ { + r[i].SetRandom() + } + L1.MultiExp(A[:n-1], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + L2.MultiExp(A[1:], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + return +} + +// Generate R in G₂ as Hash(gˢ, gˢˣ, challenge, dst) +func genR(sG1, sxG1 curve.G1Affine, challenge []byte, dst byte) curve.G2Affine { + var buf bytes.Buffer + buf.Grow(len(challenge) + curve.SizeOfG1AffineUncompressed*2) + buf.Write(sG1.Marshal()) + buf.Write(sxG1.Marshal()) + buf.Write(challenge) + spG2, err := curve.HashToG2(buf.Bytes(), []byte{dst}) + if err != nil { + panic(err) + } + return spG2 +} diff --git a/backend/groth16/bn254/mpcsetup/lagrange.go b/backend/groth16/bn254/mpcsetup/lagrange.go new file mode 100644 index 0000000000..eb8ddedc06 --- /dev/null +++ b/backend/groth16/bn254/mpcsetup/lagrange.go @@ -0,0 +1,216 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "math/big" + "math/bits" + "runtime" + + "github.com/consensys/gnark-crypto/ecc" + curve "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" + "github.com/consensys/gnark/internal/utils" +) + +func LagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { + coeffs := make([]curve.G1Affine, size) + copy(coeffs, powers[:size]) + domain := fft.NewDomain(uint64(size)) + numCPU := uint64(runtime.NumCPU()) + maxSplits := bits.TrailingZeros64(ecc.NextPowerOfTwo(numCPU)) + + difFFTG1(coeffs, domain.TwiddlesInv, 0, maxSplits, nil) + bitReverse(coeffs) + + var invBigint big.Int + domain.CardinalityInv.BigInt(&invBigint) + + utils.Parallelize(size, func(start, end int) { + for i := start; i < end; i++ { + coeffs[i].ScalarMultiplication(&coeffs[i], &invBigint) + } + }) + return coeffs +} + +func LagrangeCoeffsG2(powers []curve.G2Affine, size int) []curve.G2Affine { + coeffs := make([]curve.G2Affine, size) + copy(coeffs, powers[:size]) + domain := fft.NewDomain(uint64(size)) + numCPU := uint64(runtime.NumCPU()) + maxSplits := bits.TrailingZeros64(ecc.NextPowerOfTwo(numCPU)) + + difFFTG2(coeffs, domain.TwiddlesInv, 0, maxSplits, nil) + bitReverse(coeffs) + + var invBigint big.Int + domain.CardinalityInv.BigInt(&invBigint) + + utils.Parallelize(size, func(start, end int) { + for i := start; i < end; i++ { + coeffs[i].ScalarMultiplication(&coeffs[i], &invBigint) + } + }) + return coeffs +} + +func butterflyG1(a *curve.G1Affine, b *curve.G1Affine) { + t := *a + a.Add(a, b) + b.Sub(&t, b) +} + +func butterflyG2(a *curve.G2Affine, b *curve.G2Affine) { + t := *a + a.Add(a, b) + b.Sub(&t, b) +} + +// kerDIF8 is a kernel that process a FFT of size 8 +func kerDIF8G1(a []curve.G1Affine, twiddles [][]fr.Element, stage int) { + butterflyG1(&a[0], &a[4]) + butterflyG1(&a[1], &a[5]) + butterflyG1(&a[2], &a[6]) + butterflyG1(&a[3], &a[7]) + + var twiddle big.Int + twiddles[stage+0][1].BigInt(&twiddle) + a[5].ScalarMultiplication(&a[5], &twiddle) + twiddles[stage+0][2].BigInt(&twiddle) + a[6].ScalarMultiplication(&a[6], &twiddle) + twiddles[stage+0][3].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG1(&a[0], &a[2]) + butterflyG1(&a[1], &a[3]) + butterflyG1(&a[4], &a[6]) + butterflyG1(&a[5], &a[7]) + twiddles[stage+1][1].BigInt(&twiddle) + a[3].ScalarMultiplication(&a[3], &twiddle) + twiddles[stage+1][1].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG1(&a[0], &a[1]) + butterflyG1(&a[2], &a[3]) + butterflyG1(&a[4], &a[5]) + butterflyG1(&a[6], &a[7]) +} + +// kerDIF8 is a kernel that process a FFT of size 8 +func kerDIF8G2(a []curve.G2Affine, twiddles [][]fr.Element, stage int) { + butterflyG2(&a[0], &a[4]) + butterflyG2(&a[1], &a[5]) + butterflyG2(&a[2], &a[6]) + butterflyG2(&a[3], &a[7]) + + var twiddle big.Int + twiddles[stage+0][1].BigInt(&twiddle) + a[5].ScalarMultiplication(&a[5], &twiddle) + twiddles[stage+0][2].BigInt(&twiddle) + a[6].ScalarMultiplication(&a[6], &twiddle) + twiddles[stage+0][3].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG2(&a[0], &a[2]) + butterflyG2(&a[1], &a[3]) + butterflyG2(&a[4], &a[6]) + butterflyG2(&a[5], &a[7]) + twiddles[stage+1][1].BigInt(&twiddle) + a[3].ScalarMultiplication(&a[3], &twiddle) + twiddles[stage+1][1].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG2(&a[0], &a[1]) + butterflyG2(&a[2], &a[3]) + butterflyG2(&a[4], &a[5]) + butterflyG2(&a[6], &a[7]) +} + +func difFFTG1(a []curve.G1Affine, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { + if chDone != nil { + defer close(chDone) + } + + n := len(a) + if n == 1 { + return + } else if n == 8 { + kerDIF8G1(a, twiddles, stage) + return + } + m := n >> 1 + + butterflyG1(&a[0], &a[m]) + + var twiddle big.Int + for i := 1; i < m; i++ { + butterflyG1(&a[i], &a[i+m]) + twiddles[stage][i].BigInt(&twiddle) + a[i+m].ScalarMultiplication(&a[i+m], &twiddle) + } + + if m == 1 { + return + } + + nextStage := stage + 1 + if stage < maxSplits { + chDone := make(chan struct{}, 1) + go difFFTG1(a[m:n], twiddles, nextStage, maxSplits, chDone) + difFFTG1(a[0:m], twiddles, nextStage, maxSplits, nil) + <-chDone + } else { + difFFTG1(a[0:m], twiddles, nextStage, maxSplits, nil) + difFFTG1(a[m:n], twiddles, nextStage, maxSplits, nil) + } +} +func difFFTG2(a []curve.G2Affine, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { + if chDone != nil { + defer close(chDone) + } + + n := len(a) + if n == 1 { + return + } else if n == 8 { + kerDIF8G2(a, twiddles, stage) + return + } + m := n >> 1 + + butterflyG2(&a[0], &a[m]) + + var twiddle big.Int + for i := 1; i < m; i++ { + butterflyG2(&a[i], &a[i+m]) + twiddles[stage][i].BigInt(&twiddle) + a[i+m].ScalarMultiplication(&a[i+m], &twiddle) + } + + if m == 1 { + return + } + + nextStage := stage + 1 + if stage < maxSplits { + chDone := make(chan struct{}, 1) + go difFFTG2(a[m:n], twiddles, nextStage, maxSplits, chDone) + difFFTG2(a[0:m], twiddles, nextStage, maxSplits, nil) + <-chDone + } else { + difFFTG2(a[0:m], twiddles, nextStage, maxSplits, nil) + difFFTG2(a[m:n], twiddles, nextStage, maxSplits, nil) + } +} diff --git a/backend/groth16/bn254/mpcsetup/marshal.go b/backend/groth16/bn254/mpcsetup/marshal.go new file mode 100644 index 0000000000..08cb2ae3d1 --- /dev/null +++ b/backend/groth16/bn254/mpcsetup/marshal.go @@ -0,0 +1,181 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + curve "github.com/consensys/gnark-crypto/ecc/bn254" + "io" +) + +// WriteTo implements io.WriterTo +func (phase1 *Phase1) WriteTo(writer io.Writer) (int64, error) { + n, err := phase1.writeTo(writer) + if err != nil { + return n, err + } + nBytes, err := writer.Write(phase1.Hash) + return int64(nBytes) + n, err +} + +func (phase1 *Phase1) writeTo(writer io.Writer) (int64, error) { + toEncode := []interface{}{ + &phase1.PublicKeys.Tau.SG, + &phase1.PublicKeys.Tau.SXG, + &phase1.PublicKeys.Tau.XR, + &phase1.PublicKeys.Alpha.SG, + &phase1.PublicKeys.Alpha.SXG, + &phase1.PublicKeys.Alpha.XR, + &phase1.PublicKeys.Beta.SG, + &phase1.PublicKeys.Beta.SXG, + &phase1.PublicKeys.Beta.XR, + phase1.Parameters.G1.Tau, + phase1.Parameters.G1.AlphaTau, + phase1.Parameters.G1.BetaTau, + phase1.Parameters.G2.Tau, + &phase1.Parameters.G2.Beta, + } + + enc := curve.NewEncoder(writer) + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + return enc.BytesWritten(), nil +} + +// ReadFrom implements io.ReaderFrom +func (phase1 *Phase1) ReadFrom(reader io.Reader) (int64, error) { + toEncode := []interface{}{ + &phase1.PublicKeys.Tau.SG, + &phase1.PublicKeys.Tau.SXG, + &phase1.PublicKeys.Tau.XR, + &phase1.PublicKeys.Alpha.SG, + &phase1.PublicKeys.Alpha.SXG, + &phase1.PublicKeys.Alpha.XR, + &phase1.PublicKeys.Beta.SG, + &phase1.PublicKeys.Beta.SXG, + &phase1.PublicKeys.Beta.XR, + &phase1.Parameters.G1.Tau, + &phase1.Parameters.G1.AlphaTau, + &phase1.Parameters.G1.BetaTau, + &phase1.Parameters.G2.Tau, + &phase1.Parameters.G2.Beta, + } + + dec := curve.NewDecoder(reader) + for _, v := range toEncode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + phase1.Hash = make([]byte, 32) + nBytes, err := reader.Read(phase1.Hash) + return dec.BytesRead() + int64(nBytes), err +} + +// WriteTo implements io.WriterTo +func (phase2 *Phase2) WriteTo(writer io.Writer) (int64, error) { + n, err := phase2.writeTo(writer) + if err != nil { + return n, err + } + nBytes, err := writer.Write(phase2.Hash) + return int64(nBytes) + n, err +} + +func (c *Phase2) writeTo(writer io.Writer) (int64, error) { + enc := curve.NewEncoder(writer) + toEncode := []interface{}{ + &c.PublicKey.SG, + &c.PublicKey.SXG, + &c.PublicKey.XR, + &c.Parameters.G1.Delta, + c.Parameters.G1.L, + c.Parameters.G1.Z, + &c.Parameters.G2.Delta, + } + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + + return enc.BytesWritten(), nil +} + +// ReadFrom implements io.ReaderFrom +func (c *Phase2) ReadFrom(reader io.Reader) (int64, error) { + dec := curve.NewDecoder(reader) + toEncode := []interface{}{ + &c.PublicKey.SG, + &c.PublicKey.SXG, + &c.PublicKey.XR, + &c.Parameters.G1.Delta, + &c.Parameters.G1.L, + &c.Parameters.G1.Z, + &c.Parameters.G2.Delta, + } + + for _, v := range toEncode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + + c.Hash = make([]byte, 32) + n, err := reader.Read(c.Hash) + return int64(n) + dec.BytesRead(), err + +} + +// WriteTo implements io.WriterTo +func (c *Phase2Evaluations) WriteTo(writer io.Writer) (int64, error) { + enc := curve.NewEncoder(writer) + toEncode := []interface{}{ + c.G1.A, + c.G1.B, + c.G2.B, + } + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + + return enc.BytesWritten(), nil +} + +// ReadFrom implements io.ReaderFrom +func (c *Phase2Evaluations) ReadFrom(reader io.Reader) (int64, error) { + dec := curve.NewDecoder(reader) + toEncode := []interface{}{ + &c.G1.A, + &c.G1.B, + &c.G2.B, + } + + for _, v := range toEncode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + + return dec.BytesRead(), nil +} diff --git a/backend/groth16/bn254/mpcsetup/marshal_test.go b/backend/groth16/bn254/mpcsetup/marshal_test.go new file mode 100644 index 0000000000..b56e2bfdce --- /dev/null +++ b/backend/groth16/bn254/mpcsetup/marshal_test.go @@ -0,0 +1,79 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "bytes" + curve "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/constraint/bn254" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/stretchr/testify/require" + "io" + "reflect" + "testing" +) + +func TestContributionSerialization(t *testing.T) { + assert := require.New(t) + + // Phase 1 + srs1 := InitPhase1(9) + srs1.Contribute() + { + var reconstructed Phase1 + roundTripCheck(t, &srs1, &reconstructed) + } + + var myCircuit Circuit + ccs, err := frontend.Compile(curve.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) + assert.NoError(err) + + r1cs := ccs.(*cs.R1CS) + + // Phase 2 + srs2, _ := InitPhase2(r1cs, &srs1) + srs2.Contribute() + + { + var reconstructed Phase2 + roundTripCheck(t, &srs2, &reconstructed) + } +} + +func roundTripCheck(t *testing.T, from io.WriterTo, reconstructed io.ReaderFrom) { + t.Helper() + + var buf bytes.Buffer + written, err := from.WriteTo(&buf) + if err != nil { + t.Fatal("couldn't serialize", err) + } + + read, err := reconstructed.ReadFrom(&buf) + if err != nil { + t.Fatal("couldn't deserialize", err) + } + + if !reflect.DeepEqual(from, reconstructed) { + t.Fatal("reconstructed object don't match original") + } + + if written != read { + t.Fatal("bytes written / read don't match") + } +} diff --git a/backend/groth16/bn254/mpcsetup/phase1.go b/backend/groth16/bn254/mpcsetup/phase1.go new file mode 100644 index 0000000000..a912a473aa --- /dev/null +++ b/backend/groth16/bn254/mpcsetup/phase1.go @@ -0,0 +1,203 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "crypto/sha256" + "errors" + curve "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "math" + "math/big" +) + +// Phase1 represents the Phase1 of the MPC described in +// https://eprint.iacr.org/2017/1050.pdf +// +// Also known as "Powers of Tau" +type Phase1 struct { + Parameters struct { + G1 struct { + Tau []curve.G1Affine // {[τ⁰]₁, [τ¹]₁, [τ²]₁, …, [τ²ⁿ⁻²]₁} + AlphaTau []curve.G1Affine // {α[τ⁰]₁, α[τ¹]₁, α[τ²]₁, …, α[τⁿ⁻¹]₁} + BetaTau []curve.G1Affine // {β[τ⁰]₁, β[τ¹]₁, β[τ²]₁, …, β[τⁿ⁻¹]₁} + } + G2 struct { + Tau []curve.G2Affine // {[τ⁰]₂, [τ¹]₂, [τ²]₂, …, [τⁿ⁻¹]₂} + Beta curve.G2Affine // [β]₂ + } + } + PublicKeys struct { + Tau, Alpha, Beta PublicKey + } + Hash []byte // sha256 hash +} + +// InitPhase1 initialize phase 1 of the MPC. This is called once by the coordinator before +// any randomness contribution is made (see Contribute()). +func InitPhase1(power int) (phase1 Phase1) { + N := int(math.Pow(2, float64(power))) + + // Generate key pairs + var tau, alpha, beta fr.Element + tau.SetOne() + alpha.SetOne() + beta.SetOne() + phase1.PublicKeys.Tau = newPublicKey(tau, nil, 1) + phase1.PublicKeys.Alpha = newPublicKey(alpha, nil, 2) + phase1.PublicKeys.Beta = newPublicKey(beta, nil, 3) + + // First contribution use generators + _, _, g1, g2 := curve.Generators() + phase1.Parameters.G2.Beta.Set(&g2) + phase1.Parameters.G1.Tau = make([]curve.G1Affine, 2*N-1) + phase1.Parameters.G2.Tau = make([]curve.G2Affine, N) + phase1.Parameters.G1.AlphaTau = make([]curve.G1Affine, N) + phase1.Parameters.G1.BetaTau = make([]curve.G1Affine, N) + for i := 0; i < len(phase1.Parameters.G1.Tau); i++ { + phase1.Parameters.G1.Tau[i].Set(&g1) + } + for i := 0; i < len(phase1.Parameters.G2.Tau); i++ { + phase1.Parameters.G2.Tau[i].Set(&g2) + phase1.Parameters.G1.AlphaTau[i].Set(&g1) + phase1.Parameters.G1.BetaTau[i].Set(&g1) + } + + phase1.Parameters.G2.Beta.Set(&g2) + + // Compute hash of Contribution + phase1.Hash = phase1.hash() + + return +} + +// Contribute contributes randomness to the phase1 object. This mutates phase1. +func (phase1 *Phase1) Contribute() { + N := len(phase1.Parameters.G2.Tau) + + // Generate key pairs + var tau, alpha, beta fr.Element + tau.SetRandom() + alpha.SetRandom() + beta.SetRandom() + phase1.PublicKeys.Tau = newPublicKey(tau, phase1.Hash[:], 1) + phase1.PublicKeys.Alpha = newPublicKey(alpha, phase1.Hash[:], 2) + phase1.PublicKeys.Beta = newPublicKey(beta, phase1.Hash[:], 3) + + // Compute powers of τ, ατ, and βτ + taus := powers(tau, 2*N-1) + alphaTau := make([]fr.Element, N) + betaTau := make([]fr.Element, N) + for i := 0; i < N; i++ { + alphaTau[i].Mul(&taus[i], &alpha) + betaTau[i].Mul(&taus[i], &beta) + } + + // Update using previous parameters + // TODO @gbotrel working with jacobian points here will help with perf. + scaleG1InPlace(phase1.Parameters.G1.Tau, taus) + scaleG2InPlace(phase1.Parameters.G2.Tau, taus[0:N]) + scaleG1InPlace(phase1.Parameters.G1.AlphaTau, alphaTau) + scaleG1InPlace(phase1.Parameters.G1.BetaTau, betaTau) + var betaBI big.Int + beta.BigInt(&betaBI) + phase1.Parameters.G2.Beta.ScalarMultiplication(&phase1.Parameters.G2.Beta, &betaBI) + + // Compute hash of Contribution + phase1.Hash = phase1.hash() +} + +func VerifyPhase1(c0, c1 *Phase1, c ...*Phase1) error { + contribs := append([]*Phase1{c0, c1}, c...) + for i := 0; i < len(contribs)-1; i++ { + if err := verifyPhase1(contribs[i], contribs[i+1]); err != nil { + return err + } + } + return nil +} + +// verifyPhase1 checks that a contribution is based on a known previous Phase1 state. +func verifyPhase1(current, contribution *Phase1) error { + // Compute R for τ, α, β + tauR := genR(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, current.Hash[:], 1) + alphaR := genR(contribution.PublicKeys.Alpha.SG, contribution.PublicKeys.Alpha.SXG, current.Hash[:], 2) + betaR := genR(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, current.Hash[:], 3) + + // Check for knowledge of toxic parameters + if !sameRatio(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, contribution.PublicKeys.Tau.XR, tauR) { + return errors.New("couldn't verify public key of τ") + } + if !sameRatio(contribution.PublicKeys.Alpha.SG, contribution.PublicKeys.Alpha.SXG, contribution.PublicKeys.Alpha.XR, alphaR) { + return errors.New("couldn't verify public key of α") + } + if !sameRatio(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, contribution.PublicKeys.Beta.XR, betaR) { + return errors.New("couldn't verify public key of β") + } + + // Check for valid updates using previous parameters + if !sameRatio(contribution.Parameters.G1.Tau[1], current.Parameters.G1.Tau[1], tauR, contribution.PublicKeys.Tau.XR) { + return errors.New("couldn't verify that [τ]₁ is based on previous contribution") + } + if !sameRatio(contribution.Parameters.G1.AlphaTau[0], current.Parameters.G1.AlphaTau[0], alphaR, contribution.PublicKeys.Alpha.XR) { + return errors.New("couldn't verify that [α]₁ is based on previous contribution") + } + if !sameRatio(contribution.Parameters.G1.BetaTau[0], current.Parameters.G1.BetaTau[0], betaR, contribution.PublicKeys.Beta.XR) { + return errors.New("couldn't verify that [β]₁ is based on previous contribution") + } + if !sameRatio(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, contribution.Parameters.G2.Tau[1], current.Parameters.G2.Tau[1]) { + return errors.New("couldn't verify that [τ]₂ is based on previous contribution") + } + if !sameRatio(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, contribution.Parameters.G2.Beta, current.Parameters.G2.Beta) { + return errors.New("couldn't verify that [β]₂ is based on previous contribution") + } + + // Check for valid updates using powers of τ + _, _, g1, g2 := curve.Generators() + tauL1, tauL2 := linearCombinationG1(contribution.Parameters.G1.Tau) + if !sameRatio(tauL1, tauL2, contribution.Parameters.G2.Tau[1], g2) { + return errors.New("couldn't verify valid powers of τ in G₁") + } + alphaL1, alphaL2 := linearCombinationG1(contribution.Parameters.G1.AlphaTau) + if !sameRatio(alphaL1, alphaL2, contribution.Parameters.G2.Tau[1], g2) { + return errors.New("couldn't verify valid powers of α(τ) in G₁") + } + betaL1, betaL2 := linearCombinationG1(contribution.Parameters.G1.BetaTau) + if !sameRatio(betaL1, betaL2, contribution.Parameters.G2.Tau[1], g2) { + return errors.New("couldn't verify valid powers of α(τ) in G₁") + } + tau2L1, tau2L2 := linearCombinationG2(contribution.Parameters.G2.Tau) + if !sameRatio(contribution.Parameters.G1.Tau[1], g1, tau2L1, tau2L2) { + return errors.New("couldn't verify valid powers of τ in G₂") + } + + // Check hash of the contribution + h := contribution.hash() + for i := 0; i < len(h); i++ { + if h[i] != contribution.Hash[i] { + return errors.New("couldn't verify hash of contribution") + } + } + + return nil +} + +func (phase1 *Phase1) hash() []byte { + sha := sha256.New() + phase1.writeTo(sha) + return sha.Sum(nil) +} diff --git a/backend/groth16/bn254/mpcsetup/phase2.go b/backend/groth16/bn254/mpcsetup/phase2.go new file mode 100644 index 0000000000..f2b1f4683f --- /dev/null +++ b/backend/groth16/bn254/mpcsetup/phase2.go @@ -0,0 +1,258 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "crypto/sha256" + "errors" + "math/big" + + curve "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/bn254" +) + +type Phase2Evaluations struct { + G1 struct { + A, B, VKK []curve.G1Affine + } + G2 struct { + B []curve.G2Affine + } +} + +type Phase2 struct { + Parameters struct { + G1 struct { + Delta curve.G1Affine + L, Z []curve.G1Affine + } + G2 struct { + Delta curve.G2Affine + } + } + PublicKey PublicKey + Hash []byte +} + +func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { + srs := srs1.Parameters + size := len(srs.G1.AlphaTau) + if size < r1cs.GetNbConstraints() { + panic("Number of constraints is larger than expected") + } + + c2 := Phase2{} + + accumulateG1 := func(res *curve.G1Affine, t constraint.Term, value *curve.G1Affine) { + cID := t.CoeffID() + switch cID { + case constraint.CoeffIdZero: + return + case constraint.CoeffIdOne: + res.Add(res, value) + case constraint.CoeffIdMinusOne: + res.Sub(res, value) + case constraint.CoeffIdTwo: + res.Add(res, value).Add(res, value) + default: + var tmp curve.G1Affine + var vBi big.Int + r1cs.Coefficients[cID].BigInt(&vBi) + tmp.ScalarMultiplication(value, &vBi) + res.Add(res, &tmp) + } + } + + accumulateG2 := func(res *curve.G2Affine, t constraint.Term, value *curve.G2Affine) { + cID := t.CoeffID() + switch cID { + case constraint.CoeffIdZero: + return + case constraint.CoeffIdOne: + res.Add(res, value) + case constraint.CoeffIdMinusOne: + res.Sub(res, value) + case constraint.CoeffIdTwo: + res.Add(res, value).Add(res, value) + default: + var tmp curve.G2Affine + var vBi big.Int + r1cs.Coefficients[cID].BigInt(&vBi) + tmp.ScalarMultiplication(value, &vBi) + res.Add(res, &tmp) + } + } + + // Prepare Lagrange coefficients of [τ...]₁, [τ...]₂, [ατ...]₁, [βτ...]₁ + coeffTau1 := LagrangeCoeffsG1(srs.G1.Tau, size) + coeffTau2 := LagrangeCoeffsG2(srs.G2.Tau, size) + coeffAlphaTau1 := LagrangeCoeffsG1(srs.G1.AlphaTau, size) + coeffBetaTau1 := LagrangeCoeffsG1(srs.G1.BetaTau, size) + + internal, secret, public := r1cs.GetNbVariables() + nWires := internal + secret + public + var evals Phase2Evaluations + evals.G1.A = make([]curve.G1Affine, nWires) + evals.G1.B = make([]curve.G1Affine, nWires) + evals.G2.B = make([]curve.G2Affine, nWires) + bA := make([]curve.G1Affine, nWires) + aB := make([]curve.G1Affine, nWires) + C := make([]curve.G1Affine, nWires) + for i, c := range r1cs.Constraints { + // A + for _, t := range c.L { + accumulateG1(&evals.G1.A[t.WireID()], t, &coeffTau1[i]) + accumulateG1(&bA[t.WireID()], t, &coeffBetaTau1[i]) + } + // B + for _, t := range c.R { + accumulateG1(&evals.G1.B[t.WireID()], t, &coeffTau1[i]) + accumulateG2(&evals.G2.B[t.WireID()], t, &coeffTau2[i]) + accumulateG1(&aB[t.WireID()], t, &coeffAlphaTau1[i]) + } + // C + for _, t := range c.O { + accumulateG1(&C[t.WireID()], t, &coeffTau1[i]) + } + } + + // Prepare default contribution + _, _, g1, g2 := curve.Generators() + c2.Parameters.G1.Delta = g1 + c2.Parameters.G2.Delta = g2 + + // Build Z in PK as τⁱ(τⁿ - 1) = τ⁽ⁱ⁺ⁿ⁾ - τⁱ for i ∈ [0, n-2] + // τⁱ(τⁿ - 1) = τ⁽ⁱ⁺ⁿ⁾ - τⁱ for i ∈ [0, n-2] + n := len(srs.G1.AlphaTau) + c2.Parameters.G1.Z = make([]curve.G1Affine, n) + for i := 0; i < n-1; i++ { + c2.Parameters.G1.Z[i].Sub(&srs.G1.Tau[i+n], &srs.G1.Tau[i]) + } + bitReverse(c2.Parameters.G1.Z) + c2.Parameters.G1.Z = c2.Parameters.G1.Z[:n-1] + + // Evaluate L + nPrivate := internal + secret + c2.Parameters.G1.L = make([]curve.G1Affine, nPrivate) + evals.G1.VKK = make([]curve.G1Affine, public) + offset := public + for i := 0; i < nWires; i++ { + var tmp curve.G1Affine + tmp.Add(&bA[i], &aB[i]) + tmp.Add(&tmp, &C[i]) + if i < public { + evals.G1.VKK[i].Set(&tmp) + } else { + c2.Parameters.G1.L[i-offset].Set(&tmp) + } + } + // Set δ public key + var delta fr.Element + delta.SetOne() + c2.PublicKey = newPublicKey(delta, nil, 1) + + // Hash initial contribution + c2.Hash = c2.hash() + return c2, evals +} + +func (c *Phase2) Contribute() { + // Sample toxic δ + var delta, deltaInv fr.Element + var deltaBI, deltaInvBI big.Int + delta.SetRandom() + deltaInv.Inverse(&delta) + + delta.BigInt(&deltaBI) + deltaInv.BigInt(&deltaInvBI) + + // Set δ public key + c.PublicKey = newPublicKey(delta, c.Hash, 1) + + // Update δ + c.Parameters.G1.Delta.ScalarMultiplication(&c.Parameters.G1.Delta, &deltaBI) + c.Parameters.G2.Delta.ScalarMultiplication(&c.Parameters.G2.Delta, &deltaBI) + + // Update Z using δ⁻¹ + for i := 0; i < len(c.Parameters.G1.Z); i++ { + c.Parameters.G1.Z[i].ScalarMultiplication(&c.Parameters.G1.Z[i], &deltaInvBI) + } + + // Update L using δ⁻¹ + for i := 0; i < len(c.Parameters.G1.L); i++ { + c.Parameters.G1.L[i].ScalarMultiplication(&c.Parameters.G1.L[i], &deltaInvBI) + } + + // 4. Hash contribution + c.Hash = c.hash() +} + +func VerifyPhase2(c0, c1 *Phase2, c ...*Phase2) error { + contribs := append([]*Phase2{c0, c1}, c...) + for i := 0; i < len(contribs)-1; i++ { + if err := verifyPhase2(contribs[i], contribs[i+1]); err != nil { + return err + } + } + return nil +} + +func verifyPhase2(current, contribution *Phase2) error { + // Compute R for δ + deltaR := genR(contribution.PublicKey.SG, contribution.PublicKey.SXG, current.Hash[:], 1) + + // Check for knowledge of δ + if !sameRatio(contribution.PublicKey.SG, contribution.PublicKey.SXG, contribution.PublicKey.XR, deltaR) { + return errors.New("couldn't verify knowledge of δ") + } + + // Check for valid updates using previous parameters + if !sameRatio(contribution.Parameters.G1.Delta, current.Parameters.G1.Delta, deltaR, contribution.PublicKey.XR) { + return errors.New("couldn't verify that [δ]₁ is based on previous contribution") + } + if !sameRatio(contribution.PublicKey.SG, contribution.PublicKey.SXG, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { + return errors.New("couldn't verify that [δ]₂ is based on previous contribution") + } + + // Check for valid updates of L and Z using + L, prevL := merge(contribution.Parameters.G1.L, current.Parameters.G1.L) + if !sameRatio(L, prevL, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { + return errors.New("couldn't verify valid updates of L using δ⁻¹") + } + Z, prevZ := merge(contribution.Parameters.G1.Z, current.Parameters.G1.Z) + if !sameRatio(Z, prevZ, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { + return errors.New("couldn't verify valid updates of L using δ⁻¹") + } + + // Check hash of the contribution + h := contribution.hash() + for i := 0; i < len(h); i++ { + if h[i] != contribution.Hash[i] { + return errors.New("couldn't verify hash of contribution") + } + } + + return nil +} + +func (c *Phase2) hash() []byte { + sha := sha256.New() + c.writeTo(sha) + return sha.Sum(nil) +} diff --git a/backend/groth16/bn254/mpcsetup/setup.go b/backend/groth16/bn254/mpcsetup/setup.go new file mode 100644 index 0000000000..4946e9f597 --- /dev/null +++ b/backend/groth16/bn254/mpcsetup/setup.go @@ -0,0 +1,97 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + curve "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" + groth16 "github.com/consensys/gnark/backend/groth16/bn254" +) + +func ExtractKeys(srs1 *Phase1, srs2 *Phase2, evals *Phase2Evaluations, nConstraints int) (pk groth16.ProvingKey, vk groth16.VerifyingKey) { + _, _, _, g2 := curve.Generators() + + // Initialize PK + pk.Domain = *fft.NewDomain(uint64(nConstraints)) + pk.G1.Alpha.Set(&srs1.Parameters.G1.AlphaTau[0]) + pk.G1.Beta.Set(&srs1.Parameters.G1.BetaTau[0]) + pk.G1.Delta.Set(&srs2.Parameters.G1.Delta) + pk.G1.Z = srs2.Parameters.G1.Z + bitReverse(pk.G1.Z) + + pk.G1.K = srs2.Parameters.G1.L + pk.G2.Beta.Set(&srs1.Parameters.G2.Beta) + pk.G2.Delta.Set(&srs2.Parameters.G2.Delta) + + // Filter out infinity points + nWires := len(evals.G1.A) + pk.InfinityA = make([]bool, nWires) + A := make([]curve.G1Affine, nWires) + j := 0 + for i, e := range evals.G1.A { + if e.IsInfinity() { + pk.InfinityA[i] = true + continue + } + A[j] = evals.G1.A[i] + j++ + } + pk.G1.A = A[:j] + pk.NbInfinityA = uint64(nWires - j) + + pk.InfinityB = make([]bool, nWires) + B := make([]curve.G1Affine, nWires) + j = 0 + for i, e := range evals.G1.B { + if e.IsInfinity() { + pk.InfinityB[i] = true + continue + } + B[j] = evals.G1.B[i] + j++ + } + pk.G1.B = B[:j] + pk.NbInfinityB = uint64(nWires - j) + + B2 := make([]curve.G2Affine, nWires) + j = 0 + for i, e := range evals.G2.B { + if e.IsInfinity() { + // pk.InfinityB[i] = true should be the same as in B + continue + } + B2[j] = evals.G2.B[i] + j++ + } + pk.G2.B = B2[:j] + + // Initialize VK + vk.G1.Alpha.Set(&srs1.Parameters.G1.AlphaTau[0]) + vk.G1.Beta.Set(&srs1.Parameters.G1.BetaTau[0]) + vk.G1.Delta.Set(&srs2.Parameters.G1.Delta) + vk.G2.Beta.Set(&srs1.Parameters.G2.Beta) + vk.G2.Delta.Set(&srs2.Parameters.G2.Delta) + vk.G2.Gamma.Set(&g2) + vk.G1.K = evals.G1.VKK + + // sets e, -[δ]2, -[γ]2 + if err := vk.Precompute(); err != nil { + panic(err) + } + + return pk, vk +} diff --git a/backend/groth16/bn254/mpcsetup/setup_test.go b/backend/groth16/bn254/mpcsetup/setup_test.go new file mode 100644 index 0000000000..e6644c664d --- /dev/null +++ b/backend/groth16/bn254/mpcsetup/setup_test.go @@ -0,0 +1,196 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + curve "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark/constraint/bn254" + "testing" + + "github.com/consensys/gnark/backend/groth16" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/std/hash/mimc" + "github.com/stretchr/testify/require" + + native_mimc "github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc" +) + +func TestSetupCircuit(t *testing.T) { + const ( + nContributionsPhase1 = 3 + nContributionsPhase2 = 3 + power = 9 + ) + + assert := require.New(t) + + srs1 := InitPhase1(power) + + // Make and verify contributions for phase1 + for i := 1; i < nContributionsPhase1; i++ { + // we clone test purposes; but in practice, participant will receive a []byte, deserialize it, + // add his contribution and send back to coordinator. + prev := srs1.clone() + + srs1.Contribute() + assert.NoError(VerifyPhase1(&prev, &srs1)) + } + + // Compile the circuit + var myCircuit Circuit + ccs, err := frontend.Compile(curve.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) + assert.NoError(err) + + var evals Phase2Evaluations + r1cs := ccs.(*cs.R1CS) + + // Prepare for phase-2 + srs2, evals := InitPhase2(r1cs, &srs1) + + // Make and verify contributions for phase1 + for i := 1; i < nContributionsPhase2; i++ { + // we clone for test purposes; but in practice, participant will receive a []byte, deserialize it, + // add his contribution and send back to coordinator. + prev := srs2.clone() + + srs2.Contribute() + assert.NoError(VerifyPhase2(&prev, &srs2)) + } + + // Extract the proving and verifying keys + pk, vk := ExtractKeys(&srs1, &srs2, &evals, ccs.GetNbConstraints()) + + // Build the witness + var preImage, hash fr.Element + { + m := native_mimc.NewMiMC() + m.Write(preImage.Marshal()) + hash.SetBytes(m.Sum(nil)) + } + + witness, err := frontend.NewWitness(&Circuit{PreImage: preImage, Hash: hash}, curve.ID.ScalarField()) + assert.NoError(err) + + pubWitness, err := witness.Public() + assert.NoError(err) + + // groth16: ensure proof is verified + proof, err := groth16.Prove(ccs, &pk, witness) + assert.NoError(err) + + err = groth16.Verify(proof, &vk, pubWitness) + assert.NoError(err) +} + +func BenchmarkPhase1(b *testing.B) { + const power = 14 + + b.Run("init", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = InitPhase1(power) + } + }) + + b.Run("contrib", func(b *testing.B) { + srs1 := InitPhase1(power) + b.ResetTimer() + for i := 0; i < b.N; i++ { + srs1.Contribute() + } + }) + +} + +func BenchmarkPhase2(b *testing.B) { + const power = 14 + srs1 := InitPhase1(power) + srs1.Contribute() + + var myCircuit Circuit + ccs, err := frontend.Compile(curve.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) + if err != nil { + b.Fatal(err) + } + + r1cs := ccs.(*cs.R1CS) + + b.Run("init", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, _ = InitPhase2(r1cs, &srs1) + } + }) + + b.Run("contrib", func(b *testing.B) { + srs2, _ := InitPhase2(r1cs, &srs1) + b.ResetTimer() + for i := 0; i < b.N; i++ { + srs2.Contribute() + } + }) + +} + +// Circuit defines a pre-image knowledge proof +// mimc(secret preImage) = public hash +type Circuit struct { + PreImage frontend.Variable + Hash frontend.Variable `gnark:",public"` +} + +// Define declares the circuit's constraints +// Hash = mimc(PreImage) +func (circuit *Circuit) Define(api frontend.API) error { + // hash function + mimc, _ := mimc.NewMiMC(api) + + // specify constraints + mimc.Write(circuit.PreImage) + api.AssertIsEqual(circuit.Hash, mimc.Sum()) + + return nil +} + +func (phase1 *Phase1) clone() Phase1 { + r := Phase1{} + r.Parameters.G1.Tau = append(r.Parameters.G1.Tau, phase1.Parameters.G1.Tau...) + r.Parameters.G1.AlphaTau = append(r.Parameters.G1.AlphaTau, phase1.Parameters.G1.AlphaTau...) + r.Parameters.G1.BetaTau = append(r.Parameters.G1.BetaTau, phase1.Parameters.G1.BetaTau...) + + r.Parameters.G2.Tau = append(r.Parameters.G2.Tau, phase1.Parameters.G2.Tau...) + r.Parameters.G2.Beta = phase1.Parameters.G2.Beta + + r.PublicKeys = phase1.PublicKeys + r.Hash = append(r.Hash, phase1.Hash...) + + return r +} + +func (phase2 *Phase2) clone() Phase2 { + r := Phase2{} + r.Parameters.G1.Delta = phase2.Parameters.G1.Delta + r.Parameters.G1.L = append(r.Parameters.G1.L, phase2.Parameters.G1.L...) + r.Parameters.G1.Z = append(r.Parameters.G1.Z, phase2.Parameters.G1.Z...) + r.Parameters.G2.Delta = phase2.Parameters.G2.Delta + r.PublicKey = phase2.PublicKey + r.Hash = append(r.Hash, phase2.Hash...) + + return r +} diff --git a/backend/groth16/bn254/mpcsetup/utils.go b/backend/groth16/bn254/mpcsetup/utils.go new file mode 100644 index 0000000000..e3b47d1121 --- /dev/null +++ b/backend/groth16/bn254/mpcsetup/utils.go @@ -0,0 +1,170 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "bytes" + "math/big" + "math/bits" + "runtime" + + "github.com/consensys/gnark-crypto/ecc" + curve "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark/internal/utils" +) + +type PublicKey struct { + SG curve.G1Affine + SXG curve.G1Affine + XR curve.G2Affine +} + +func newPublicKey(x fr.Element, challenge []byte, dst byte) PublicKey { + var pk PublicKey + _, _, g1, _ := curve.Generators() + + var s fr.Element + var sBi big.Int + s.SetRandom() + s.BigInt(&sBi) + pk.SG.ScalarMultiplication(&g1, &sBi) + + // compute x*sG1 + var xBi big.Int + x.BigInt(&xBi) + pk.SXG.ScalarMultiplication(&pk.SG, &xBi) + + // generate R based on sG1, sxG1, challenge, and domain separation tag (tau, alpha or beta) + R := genR(pk.SG, pk.SXG, challenge, dst) + + // compute x*spG2 + pk.XR.ScalarMultiplication(&R, &xBi) + return pk +} + +func bitReverse[T any](a []T) { + n := uint64(len(a)) + nn := uint64(64 - bits.TrailingZeros64(n)) + + for i := uint64(0); i < n; i++ { + irev := bits.Reverse64(i) >> nn + if irev > i { + a[i], a[irev] = a[irev], a[i] + } + } +} + +// Returns [1, a, a², ..., aⁿ⁻¹ ] in Montgomery form +func powers(a fr.Element, n int) []fr.Element { + result := make([]fr.Element, n) + result[0] = fr.NewElement(1) + for i := 1; i < n; i++ { + result[i].Mul(&result[i-1], &a) + } + return result +} + +// Returns [aᵢAᵢ, ...] in G1 +func scaleG1InPlace(A []curve.G1Affine, a []fr.Element) { + utils.Parallelize(len(A), func(start, end int) { + var tmp big.Int + for i := start; i < end; i++ { + a[i].BigInt(&tmp) + A[i].ScalarMultiplication(&A[i], &tmp) + } + }) +} + +// Returns [aᵢAᵢ, ...] in G2 +func scaleG2InPlace(A []curve.G2Affine, a []fr.Element) { + utils.Parallelize(len(A), func(start, end int) { + var tmp big.Int + for i := start; i < end; i++ { + a[i].BigInt(&tmp) + A[i].ScalarMultiplication(&A[i], &tmp) + } + }) +} + +// Check e(a₁, a₂) = e(b₁, b₂) +func sameRatio(a1, b1 curve.G1Affine, a2, b2 curve.G2Affine) bool { + if !a1.IsInSubGroup() || !b1.IsInSubGroup() || !a2.IsInSubGroup() || !b2.IsInSubGroup() { + panic("invalid point not in subgroup") + } + var na2 curve.G2Affine + na2.Neg(&a2) + res, err := curve.PairingCheck( + []curve.G1Affine{a1, b1}, + []curve.G2Affine{na2, b2}) + if err != nil { + panic(err) + } + return res +} + +// returns a = ∑ rᵢAᵢ, b = ∑ rᵢBᵢ +func merge(A, B []curve.G1Affine) (a, b curve.G1Affine) { + nc := runtime.NumCPU() + r := make([]fr.Element, len(A)) + for i := 0; i < len(A); i++ { + r[i].SetRandom() + } + a.MultiExp(A, r, ecc.MultiExpConfig{NbTasks: nc / 2}) + b.MultiExp(B, r, ecc.MultiExpConfig{NbTasks: nc / 2}) + return +} + +// L1 = ∑ rᵢAᵢ, L2 = ∑ rᵢAᵢ₊₁ in G1 +func linearCombinationG1(A []curve.G1Affine) (L1, L2 curve.G1Affine) { + nc := runtime.NumCPU() + n := len(A) + r := make([]fr.Element, n-1) + for i := 0; i < n-1; i++ { + r[i].SetRandom() + } + L1.MultiExp(A[:n-1], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + L2.MultiExp(A[1:], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + return +} + +// L1 = ∑ rᵢAᵢ, L2 = ∑ rᵢAᵢ₊₁ in G2 +func linearCombinationG2(A []curve.G2Affine) (L1, L2 curve.G2Affine) { + nc := runtime.NumCPU() + n := len(A) + r := make([]fr.Element, n-1) + for i := 0; i < n-1; i++ { + r[i].SetRandom() + } + L1.MultiExp(A[:n-1], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + L2.MultiExp(A[1:], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + return +} + +// Generate R in G₂ as Hash(gˢ, gˢˣ, challenge, dst) +func genR(sG1, sxG1 curve.G1Affine, challenge []byte, dst byte) curve.G2Affine { + var buf bytes.Buffer + buf.Grow(len(challenge) + curve.SizeOfG1AffineUncompressed*2) + buf.Write(sG1.Marshal()) + buf.Write(sxG1.Marshal()) + buf.Write(challenge) + spG2, err := curve.HashToG2(buf.Bytes(), []byte{dst}) + if err != nil { + panic(err) + } + return spG2 +} diff --git a/backend/groth16/bw6-633/mpcsetup/lagrange.go b/backend/groth16/bw6-633/mpcsetup/lagrange.go new file mode 100644 index 0000000000..40fecdefb6 --- /dev/null +++ b/backend/groth16/bw6-633/mpcsetup/lagrange.go @@ -0,0 +1,216 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "math/big" + "math/bits" + "runtime" + + "github.com/consensys/gnark-crypto/ecc" + curve "github.com/consensys/gnark-crypto/ecc/bw6-633" + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/fft" + "github.com/consensys/gnark/internal/utils" +) + +func LagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { + coeffs := make([]curve.G1Affine, size) + copy(coeffs, powers[:size]) + domain := fft.NewDomain(uint64(size)) + numCPU := uint64(runtime.NumCPU()) + maxSplits := bits.TrailingZeros64(ecc.NextPowerOfTwo(numCPU)) + + difFFTG1(coeffs, domain.TwiddlesInv, 0, maxSplits, nil) + bitReverse(coeffs) + + var invBigint big.Int + domain.CardinalityInv.BigInt(&invBigint) + + utils.Parallelize(size, func(start, end int) { + for i := start; i < end; i++ { + coeffs[i].ScalarMultiplication(&coeffs[i], &invBigint) + } + }) + return coeffs +} + +func LagrangeCoeffsG2(powers []curve.G2Affine, size int) []curve.G2Affine { + coeffs := make([]curve.G2Affine, size) + copy(coeffs, powers[:size]) + domain := fft.NewDomain(uint64(size)) + numCPU := uint64(runtime.NumCPU()) + maxSplits := bits.TrailingZeros64(ecc.NextPowerOfTwo(numCPU)) + + difFFTG2(coeffs, domain.TwiddlesInv, 0, maxSplits, nil) + bitReverse(coeffs) + + var invBigint big.Int + domain.CardinalityInv.BigInt(&invBigint) + + utils.Parallelize(size, func(start, end int) { + for i := start; i < end; i++ { + coeffs[i].ScalarMultiplication(&coeffs[i], &invBigint) + } + }) + return coeffs +} + +func butterflyG1(a *curve.G1Affine, b *curve.G1Affine) { + t := *a + a.Add(a, b) + b.Sub(&t, b) +} + +func butterflyG2(a *curve.G2Affine, b *curve.G2Affine) { + t := *a + a.Add(a, b) + b.Sub(&t, b) +} + +// kerDIF8 is a kernel that process a FFT of size 8 +func kerDIF8G1(a []curve.G1Affine, twiddles [][]fr.Element, stage int) { + butterflyG1(&a[0], &a[4]) + butterflyG1(&a[1], &a[5]) + butterflyG1(&a[2], &a[6]) + butterflyG1(&a[3], &a[7]) + + var twiddle big.Int + twiddles[stage+0][1].BigInt(&twiddle) + a[5].ScalarMultiplication(&a[5], &twiddle) + twiddles[stage+0][2].BigInt(&twiddle) + a[6].ScalarMultiplication(&a[6], &twiddle) + twiddles[stage+0][3].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG1(&a[0], &a[2]) + butterflyG1(&a[1], &a[3]) + butterflyG1(&a[4], &a[6]) + butterflyG1(&a[5], &a[7]) + twiddles[stage+1][1].BigInt(&twiddle) + a[3].ScalarMultiplication(&a[3], &twiddle) + twiddles[stage+1][1].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG1(&a[0], &a[1]) + butterflyG1(&a[2], &a[3]) + butterflyG1(&a[4], &a[5]) + butterflyG1(&a[6], &a[7]) +} + +// kerDIF8 is a kernel that process a FFT of size 8 +func kerDIF8G2(a []curve.G2Affine, twiddles [][]fr.Element, stage int) { + butterflyG2(&a[0], &a[4]) + butterflyG2(&a[1], &a[5]) + butterflyG2(&a[2], &a[6]) + butterflyG2(&a[3], &a[7]) + + var twiddle big.Int + twiddles[stage+0][1].BigInt(&twiddle) + a[5].ScalarMultiplication(&a[5], &twiddle) + twiddles[stage+0][2].BigInt(&twiddle) + a[6].ScalarMultiplication(&a[6], &twiddle) + twiddles[stage+0][3].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG2(&a[0], &a[2]) + butterflyG2(&a[1], &a[3]) + butterflyG2(&a[4], &a[6]) + butterflyG2(&a[5], &a[7]) + twiddles[stage+1][1].BigInt(&twiddle) + a[3].ScalarMultiplication(&a[3], &twiddle) + twiddles[stage+1][1].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG2(&a[0], &a[1]) + butterflyG2(&a[2], &a[3]) + butterflyG2(&a[4], &a[5]) + butterflyG2(&a[6], &a[7]) +} + +func difFFTG1(a []curve.G1Affine, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { + if chDone != nil { + defer close(chDone) + } + + n := len(a) + if n == 1 { + return + } else if n == 8 { + kerDIF8G1(a, twiddles, stage) + return + } + m := n >> 1 + + butterflyG1(&a[0], &a[m]) + + var twiddle big.Int + for i := 1; i < m; i++ { + butterflyG1(&a[i], &a[i+m]) + twiddles[stage][i].BigInt(&twiddle) + a[i+m].ScalarMultiplication(&a[i+m], &twiddle) + } + + if m == 1 { + return + } + + nextStage := stage + 1 + if stage < maxSplits { + chDone := make(chan struct{}, 1) + go difFFTG1(a[m:n], twiddles, nextStage, maxSplits, chDone) + difFFTG1(a[0:m], twiddles, nextStage, maxSplits, nil) + <-chDone + } else { + difFFTG1(a[0:m], twiddles, nextStage, maxSplits, nil) + difFFTG1(a[m:n], twiddles, nextStage, maxSplits, nil) + } +} +func difFFTG2(a []curve.G2Affine, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { + if chDone != nil { + defer close(chDone) + } + + n := len(a) + if n == 1 { + return + } else if n == 8 { + kerDIF8G2(a, twiddles, stage) + return + } + m := n >> 1 + + butterflyG2(&a[0], &a[m]) + + var twiddle big.Int + for i := 1; i < m; i++ { + butterflyG2(&a[i], &a[i+m]) + twiddles[stage][i].BigInt(&twiddle) + a[i+m].ScalarMultiplication(&a[i+m], &twiddle) + } + + if m == 1 { + return + } + + nextStage := stage + 1 + if stage < maxSplits { + chDone := make(chan struct{}, 1) + go difFFTG2(a[m:n], twiddles, nextStage, maxSplits, chDone) + difFFTG2(a[0:m], twiddles, nextStage, maxSplits, nil) + <-chDone + } else { + difFFTG2(a[0:m], twiddles, nextStage, maxSplits, nil) + difFFTG2(a[m:n], twiddles, nextStage, maxSplits, nil) + } +} diff --git a/backend/groth16/bw6-633/mpcsetup/marshal.go b/backend/groth16/bw6-633/mpcsetup/marshal.go new file mode 100644 index 0000000000..4955ec6d92 --- /dev/null +++ b/backend/groth16/bw6-633/mpcsetup/marshal.go @@ -0,0 +1,181 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + curve "github.com/consensys/gnark-crypto/ecc/bw6-633" + "io" +) + +// WriteTo implements io.WriterTo +func (phase1 *Phase1) WriteTo(writer io.Writer) (int64, error) { + n, err := phase1.writeTo(writer) + if err != nil { + return n, err + } + nBytes, err := writer.Write(phase1.Hash) + return int64(nBytes) + n, err +} + +func (phase1 *Phase1) writeTo(writer io.Writer) (int64, error) { + toEncode := []interface{}{ + &phase1.PublicKeys.Tau.SG, + &phase1.PublicKeys.Tau.SXG, + &phase1.PublicKeys.Tau.XR, + &phase1.PublicKeys.Alpha.SG, + &phase1.PublicKeys.Alpha.SXG, + &phase1.PublicKeys.Alpha.XR, + &phase1.PublicKeys.Beta.SG, + &phase1.PublicKeys.Beta.SXG, + &phase1.PublicKeys.Beta.XR, + phase1.Parameters.G1.Tau, + phase1.Parameters.G1.AlphaTau, + phase1.Parameters.G1.BetaTau, + phase1.Parameters.G2.Tau, + &phase1.Parameters.G2.Beta, + } + + enc := curve.NewEncoder(writer) + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + return enc.BytesWritten(), nil +} + +// ReadFrom implements io.ReaderFrom +func (phase1 *Phase1) ReadFrom(reader io.Reader) (int64, error) { + toEncode := []interface{}{ + &phase1.PublicKeys.Tau.SG, + &phase1.PublicKeys.Tau.SXG, + &phase1.PublicKeys.Tau.XR, + &phase1.PublicKeys.Alpha.SG, + &phase1.PublicKeys.Alpha.SXG, + &phase1.PublicKeys.Alpha.XR, + &phase1.PublicKeys.Beta.SG, + &phase1.PublicKeys.Beta.SXG, + &phase1.PublicKeys.Beta.XR, + &phase1.Parameters.G1.Tau, + &phase1.Parameters.G1.AlphaTau, + &phase1.Parameters.G1.BetaTau, + &phase1.Parameters.G2.Tau, + &phase1.Parameters.G2.Beta, + } + + dec := curve.NewDecoder(reader) + for _, v := range toEncode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + phase1.Hash = make([]byte, 32) + nBytes, err := reader.Read(phase1.Hash) + return dec.BytesRead() + int64(nBytes), err +} + +// WriteTo implements io.WriterTo +func (phase2 *Phase2) WriteTo(writer io.Writer) (int64, error) { + n, err := phase2.writeTo(writer) + if err != nil { + return n, err + } + nBytes, err := writer.Write(phase2.Hash) + return int64(nBytes) + n, err +} + +func (c *Phase2) writeTo(writer io.Writer) (int64, error) { + enc := curve.NewEncoder(writer) + toEncode := []interface{}{ + &c.PublicKey.SG, + &c.PublicKey.SXG, + &c.PublicKey.XR, + &c.Parameters.G1.Delta, + c.Parameters.G1.L, + c.Parameters.G1.Z, + &c.Parameters.G2.Delta, + } + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + + return enc.BytesWritten(), nil +} + +// ReadFrom implements io.ReaderFrom +func (c *Phase2) ReadFrom(reader io.Reader) (int64, error) { + dec := curve.NewDecoder(reader) + toEncode := []interface{}{ + &c.PublicKey.SG, + &c.PublicKey.SXG, + &c.PublicKey.XR, + &c.Parameters.G1.Delta, + &c.Parameters.G1.L, + &c.Parameters.G1.Z, + &c.Parameters.G2.Delta, + } + + for _, v := range toEncode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + + c.Hash = make([]byte, 32) + n, err := reader.Read(c.Hash) + return int64(n) + dec.BytesRead(), err + +} + +// WriteTo implements io.WriterTo +func (c *Phase2Evaluations) WriteTo(writer io.Writer) (int64, error) { + enc := curve.NewEncoder(writer) + toEncode := []interface{}{ + c.G1.A, + c.G1.B, + c.G2.B, + } + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + + return enc.BytesWritten(), nil +} + +// ReadFrom implements io.ReaderFrom +func (c *Phase2Evaluations) ReadFrom(reader io.Reader) (int64, error) { + dec := curve.NewDecoder(reader) + toEncode := []interface{}{ + &c.G1.A, + &c.G1.B, + &c.G2.B, + } + + for _, v := range toEncode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + + return dec.BytesRead(), nil +} diff --git a/backend/groth16/bw6-633/mpcsetup/marshal_test.go b/backend/groth16/bw6-633/mpcsetup/marshal_test.go new file mode 100644 index 0000000000..0c04d15934 --- /dev/null +++ b/backend/groth16/bw6-633/mpcsetup/marshal_test.go @@ -0,0 +1,79 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "bytes" + curve "github.com/consensys/gnark-crypto/ecc/bw6-633" + "github.com/consensys/gnark/constraint/bw6-633" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/stretchr/testify/require" + "io" + "reflect" + "testing" +) + +func TestContributionSerialization(t *testing.T) { + assert := require.New(t) + + // Phase 1 + srs1 := InitPhase1(9) + srs1.Contribute() + { + var reconstructed Phase1 + roundTripCheck(t, &srs1, &reconstructed) + } + + var myCircuit Circuit + ccs, err := frontend.Compile(curve.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) + assert.NoError(err) + + r1cs := ccs.(*cs.R1CS) + + // Phase 2 + srs2, _ := InitPhase2(r1cs, &srs1) + srs2.Contribute() + + { + var reconstructed Phase2 + roundTripCheck(t, &srs2, &reconstructed) + } +} + +func roundTripCheck(t *testing.T, from io.WriterTo, reconstructed io.ReaderFrom) { + t.Helper() + + var buf bytes.Buffer + written, err := from.WriteTo(&buf) + if err != nil { + t.Fatal("couldn't serialize", err) + } + + read, err := reconstructed.ReadFrom(&buf) + if err != nil { + t.Fatal("couldn't deserialize", err) + } + + if !reflect.DeepEqual(from, reconstructed) { + t.Fatal("reconstructed object don't match original") + } + + if written != read { + t.Fatal("bytes written / read don't match") + } +} diff --git a/backend/groth16/bw6-633/mpcsetup/phase1.go b/backend/groth16/bw6-633/mpcsetup/phase1.go new file mode 100644 index 0000000000..fa91cc5025 --- /dev/null +++ b/backend/groth16/bw6-633/mpcsetup/phase1.go @@ -0,0 +1,203 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "crypto/sha256" + "errors" + curve "github.com/consensys/gnark-crypto/ecc/bw6-633" + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" + "math" + "math/big" +) + +// Phase1 represents the Phase1 of the MPC described in +// https://eprint.iacr.org/2017/1050.pdf +// +// Also known as "Powers of Tau" +type Phase1 struct { + Parameters struct { + G1 struct { + Tau []curve.G1Affine // {[τ⁰]₁, [τ¹]₁, [τ²]₁, …, [τ²ⁿ⁻²]₁} + AlphaTau []curve.G1Affine // {α[τ⁰]₁, α[τ¹]₁, α[τ²]₁, …, α[τⁿ⁻¹]₁} + BetaTau []curve.G1Affine // {β[τ⁰]₁, β[τ¹]₁, β[τ²]₁, …, β[τⁿ⁻¹]₁} + } + G2 struct { + Tau []curve.G2Affine // {[τ⁰]₂, [τ¹]₂, [τ²]₂, …, [τⁿ⁻¹]₂} + Beta curve.G2Affine // [β]₂ + } + } + PublicKeys struct { + Tau, Alpha, Beta PublicKey + } + Hash []byte // sha256 hash +} + +// InitPhase1 initialize phase 1 of the MPC. This is called once by the coordinator before +// any randomness contribution is made (see Contribute()). +func InitPhase1(power int) (phase1 Phase1) { + N := int(math.Pow(2, float64(power))) + + // Generate key pairs + var tau, alpha, beta fr.Element + tau.SetOne() + alpha.SetOne() + beta.SetOne() + phase1.PublicKeys.Tau = newPublicKey(tau, nil, 1) + phase1.PublicKeys.Alpha = newPublicKey(alpha, nil, 2) + phase1.PublicKeys.Beta = newPublicKey(beta, nil, 3) + + // First contribution use generators + _, _, g1, g2 := curve.Generators() + phase1.Parameters.G2.Beta.Set(&g2) + phase1.Parameters.G1.Tau = make([]curve.G1Affine, 2*N-1) + phase1.Parameters.G2.Tau = make([]curve.G2Affine, N) + phase1.Parameters.G1.AlphaTau = make([]curve.G1Affine, N) + phase1.Parameters.G1.BetaTau = make([]curve.G1Affine, N) + for i := 0; i < len(phase1.Parameters.G1.Tau); i++ { + phase1.Parameters.G1.Tau[i].Set(&g1) + } + for i := 0; i < len(phase1.Parameters.G2.Tau); i++ { + phase1.Parameters.G2.Tau[i].Set(&g2) + phase1.Parameters.G1.AlphaTau[i].Set(&g1) + phase1.Parameters.G1.BetaTau[i].Set(&g1) + } + + phase1.Parameters.G2.Beta.Set(&g2) + + // Compute hash of Contribution + phase1.Hash = phase1.hash() + + return +} + +// Contribute contributes randomness to the phase1 object. This mutates phase1. +func (phase1 *Phase1) Contribute() { + N := len(phase1.Parameters.G2.Tau) + + // Generate key pairs + var tau, alpha, beta fr.Element + tau.SetRandom() + alpha.SetRandom() + beta.SetRandom() + phase1.PublicKeys.Tau = newPublicKey(tau, phase1.Hash[:], 1) + phase1.PublicKeys.Alpha = newPublicKey(alpha, phase1.Hash[:], 2) + phase1.PublicKeys.Beta = newPublicKey(beta, phase1.Hash[:], 3) + + // Compute powers of τ, ατ, and βτ + taus := powers(tau, 2*N-1) + alphaTau := make([]fr.Element, N) + betaTau := make([]fr.Element, N) + for i := 0; i < N; i++ { + alphaTau[i].Mul(&taus[i], &alpha) + betaTau[i].Mul(&taus[i], &beta) + } + + // Update using previous parameters + // TODO @gbotrel working with jacobian points here will help with perf. + scaleG1InPlace(phase1.Parameters.G1.Tau, taus) + scaleG2InPlace(phase1.Parameters.G2.Tau, taus[0:N]) + scaleG1InPlace(phase1.Parameters.G1.AlphaTau, alphaTau) + scaleG1InPlace(phase1.Parameters.G1.BetaTau, betaTau) + var betaBI big.Int + beta.BigInt(&betaBI) + phase1.Parameters.G2.Beta.ScalarMultiplication(&phase1.Parameters.G2.Beta, &betaBI) + + // Compute hash of Contribution + phase1.Hash = phase1.hash() +} + +func VerifyPhase1(c0, c1 *Phase1, c ...*Phase1) error { + contribs := append([]*Phase1{c0, c1}, c...) + for i := 0; i < len(contribs)-1; i++ { + if err := verifyPhase1(contribs[i], contribs[i+1]); err != nil { + return err + } + } + return nil +} + +// verifyPhase1 checks that a contribution is based on a known previous Phase1 state. +func verifyPhase1(current, contribution *Phase1) error { + // Compute R for τ, α, β + tauR := genR(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, current.Hash[:], 1) + alphaR := genR(contribution.PublicKeys.Alpha.SG, contribution.PublicKeys.Alpha.SXG, current.Hash[:], 2) + betaR := genR(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, current.Hash[:], 3) + + // Check for knowledge of toxic parameters + if !sameRatio(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, contribution.PublicKeys.Tau.XR, tauR) { + return errors.New("couldn't verify public key of τ") + } + if !sameRatio(contribution.PublicKeys.Alpha.SG, contribution.PublicKeys.Alpha.SXG, contribution.PublicKeys.Alpha.XR, alphaR) { + return errors.New("couldn't verify public key of α") + } + if !sameRatio(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, contribution.PublicKeys.Beta.XR, betaR) { + return errors.New("couldn't verify public key of β") + } + + // Check for valid updates using previous parameters + if !sameRatio(contribution.Parameters.G1.Tau[1], current.Parameters.G1.Tau[1], tauR, contribution.PublicKeys.Tau.XR) { + return errors.New("couldn't verify that [τ]₁ is based on previous contribution") + } + if !sameRatio(contribution.Parameters.G1.AlphaTau[0], current.Parameters.G1.AlphaTau[0], alphaR, contribution.PublicKeys.Alpha.XR) { + return errors.New("couldn't verify that [α]₁ is based on previous contribution") + } + if !sameRatio(contribution.Parameters.G1.BetaTau[0], current.Parameters.G1.BetaTau[0], betaR, contribution.PublicKeys.Beta.XR) { + return errors.New("couldn't verify that [β]₁ is based on previous contribution") + } + if !sameRatio(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, contribution.Parameters.G2.Tau[1], current.Parameters.G2.Tau[1]) { + return errors.New("couldn't verify that [τ]₂ is based on previous contribution") + } + if !sameRatio(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, contribution.Parameters.G2.Beta, current.Parameters.G2.Beta) { + return errors.New("couldn't verify that [β]₂ is based on previous contribution") + } + + // Check for valid updates using powers of τ + _, _, g1, g2 := curve.Generators() + tauL1, tauL2 := linearCombinationG1(contribution.Parameters.G1.Tau) + if !sameRatio(tauL1, tauL2, contribution.Parameters.G2.Tau[1], g2) { + return errors.New("couldn't verify valid powers of τ in G₁") + } + alphaL1, alphaL2 := linearCombinationG1(contribution.Parameters.G1.AlphaTau) + if !sameRatio(alphaL1, alphaL2, contribution.Parameters.G2.Tau[1], g2) { + return errors.New("couldn't verify valid powers of α(τ) in G₁") + } + betaL1, betaL2 := linearCombinationG1(contribution.Parameters.G1.BetaTau) + if !sameRatio(betaL1, betaL2, contribution.Parameters.G2.Tau[1], g2) { + return errors.New("couldn't verify valid powers of α(τ) in G₁") + } + tau2L1, tau2L2 := linearCombinationG2(contribution.Parameters.G2.Tau) + if !sameRatio(contribution.Parameters.G1.Tau[1], g1, tau2L1, tau2L2) { + return errors.New("couldn't verify valid powers of τ in G₂") + } + + // Check hash of the contribution + h := contribution.hash() + for i := 0; i < len(h); i++ { + if h[i] != contribution.Hash[i] { + return errors.New("couldn't verify hash of contribution") + } + } + + return nil +} + +func (phase1 *Phase1) hash() []byte { + sha := sha256.New() + phase1.writeTo(sha) + return sha.Sum(nil) +} diff --git a/backend/groth16/bw6-633/mpcsetup/phase2.go b/backend/groth16/bw6-633/mpcsetup/phase2.go new file mode 100644 index 0000000000..6951a53db5 --- /dev/null +++ b/backend/groth16/bw6-633/mpcsetup/phase2.go @@ -0,0 +1,258 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "crypto/sha256" + "errors" + "math/big" + + curve "github.com/consensys/gnark-crypto/ecc/bw6-633" + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" + "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/bw6-633" +) + +type Phase2Evaluations struct { + G1 struct { + A, B, VKK []curve.G1Affine + } + G2 struct { + B []curve.G2Affine + } +} + +type Phase2 struct { + Parameters struct { + G1 struct { + Delta curve.G1Affine + L, Z []curve.G1Affine + } + G2 struct { + Delta curve.G2Affine + } + } + PublicKey PublicKey + Hash []byte +} + +func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { + srs := srs1.Parameters + size := len(srs.G1.AlphaTau) + if size < r1cs.GetNbConstraints() { + panic("Number of constraints is larger than expected") + } + + c2 := Phase2{} + + accumulateG1 := func(res *curve.G1Affine, t constraint.Term, value *curve.G1Affine) { + cID := t.CoeffID() + switch cID { + case constraint.CoeffIdZero: + return + case constraint.CoeffIdOne: + res.Add(res, value) + case constraint.CoeffIdMinusOne: + res.Sub(res, value) + case constraint.CoeffIdTwo: + res.Add(res, value).Add(res, value) + default: + var tmp curve.G1Affine + var vBi big.Int + r1cs.Coefficients[cID].BigInt(&vBi) + tmp.ScalarMultiplication(value, &vBi) + res.Add(res, &tmp) + } + } + + accumulateG2 := func(res *curve.G2Affine, t constraint.Term, value *curve.G2Affine) { + cID := t.CoeffID() + switch cID { + case constraint.CoeffIdZero: + return + case constraint.CoeffIdOne: + res.Add(res, value) + case constraint.CoeffIdMinusOne: + res.Sub(res, value) + case constraint.CoeffIdTwo: + res.Add(res, value).Add(res, value) + default: + var tmp curve.G2Affine + var vBi big.Int + r1cs.Coefficients[cID].BigInt(&vBi) + tmp.ScalarMultiplication(value, &vBi) + res.Add(res, &tmp) + } + } + + // Prepare Lagrange coefficients of [τ...]₁, [τ...]₂, [ατ...]₁, [βτ...]₁ + coeffTau1 := LagrangeCoeffsG1(srs.G1.Tau, size) + coeffTau2 := LagrangeCoeffsG2(srs.G2.Tau, size) + coeffAlphaTau1 := LagrangeCoeffsG1(srs.G1.AlphaTau, size) + coeffBetaTau1 := LagrangeCoeffsG1(srs.G1.BetaTau, size) + + internal, secret, public := r1cs.GetNbVariables() + nWires := internal + secret + public + var evals Phase2Evaluations + evals.G1.A = make([]curve.G1Affine, nWires) + evals.G1.B = make([]curve.G1Affine, nWires) + evals.G2.B = make([]curve.G2Affine, nWires) + bA := make([]curve.G1Affine, nWires) + aB := make([]curve.G1Affine, nWires) + C := make([]curve.G1Affine, nWires) + for i, c := range r1cs.Constraints { + // A + for _, t := range c.L { + accumulateG1(&evals.G1.A[t.WireID()], t, &coeffTau1[i]) + accumulateG1(&bA[t.WireID()], t, &coeffBetaTau1[i]) + } + // B + for _, t := range c.R { + accumulateG1(&evals.G1.B[t.WireID()], t, &coeffTau1[i]) + accumulateG2(&evals.G2.B[t.WireID()], t, &coeffTau2[i]) + accumulateG1(&aB[t.WireID()], t, &coeffAlphaTau1[i]) + } + // C + for _, t := range c.O { + accumulateG1(&C[t.WireID()], t, &coeffTau1[i]) + } + } + + // Prepare default contribution + _, _, g1, g2 := curve.Generators() + c2.Parameters.G1.Delta = g1 + c2.Parameters.G2.Delta = g2 + + // Build Z in PK as τⁱ(τⁿ - 1) = τ⁽ⁱ⁺ⁿ⁾ - τⁱ for i ∈ [0, n-2] + // τⁱ(τⁿ - 1) = τ⁽ⁱ⁺ⁿ⁾ - τⁱ for i ∈ [0, n-2] + n := len(srs.G1.AlphaTau) + c2.Parameters.G1.Z = make([]curve.G1Affine, n) + for i := 0; i < n-1; i++ { + c2.Parameters.G1.Z[i].Sub(&srs.G1.Tau[i+n], &srs.G1.Tau[i]) + } + bitReverse(c2.Parameters.G1.Z) + c2.Parameters.G1.Z = c2.Parameters.G1.Z[:n-1] + + // Evaluate L + nPrivate := internal + secret + c2.Parameters.G1.L = make([]curve.G1Affine, nPrivate) + evals.G1.VKK = make([]curve.G1Affine, public) + offset := public + for i := 0; i < nWires; i++ { + var tmp curve.G1Affine + tmp.Add(&bA[i], &aB[i]) + tmp.Add(&tmp, &C[i]) + if i < public { + evals.G1.VKK[i].Set(&tmp) + } else { + c2.Parameters.G1.L[i-offset].Set(&tmp) + } + } + // Set δ public key + var delta fr.Element + delta.SetOne() + c2.PublicKey = newPublicKey(delta, nil, 1) + + // Hash initial contribution + c2.Hash = c2.hash() + return c2, evals +} + +func (c *Phase2) Contribute() { + // Sample toxic δ + var delta, deltaInv fr.Element + var deltaBI, deltaInvBI big.Int + delta.SetRandom() + deltaInv.Inverse(&delta) + + delta.BigInt(&deltaBI) + deltaInv.BigInt(&deltaInvBI) + + // Set δ public key + c.PublicKey = newPublicKey(delta, c.Hash, 1) + + // Update δ + c.Parameters.G1.Delta.ScalarMultiplication(&c.Parameters.G1.Delta, &deltaBI) + c.Parameters.G2.Delta.ScalarMultiplication(&c.Parameters.G2.Delta, &deltaBI) + + // Update Z using δ⁻¹ + for i := 0; i < len(c.Parameters.G1.Z); i++ { + c.Parameters.G1.Z[i].ScalarMultiplication(&c.Parameters.G1.Z[i], &deltaInvBI) + } + + // Update L using δ⁻¹ + for i := 0; i < len(c.Parameters.G1.L); i++ { + c.Parameters.G1.L[i].ScalarMultiplication(&c.Parameters.G1.L[i], &deltaInvBI) + } + + // 4. Hash contribution + c.Hash = c.hash() +} + +func VerifyPhase2(c0, c1 *Phase2, c ...*Phase2) error { + contribs := append([]*Phase2{c0, c1}, c...) + for i := 0; i < len(contribs)-1; i++ { + if err := verifyPhase2(contribs[i], contribs[i+1]); err != nil { + return err + } + } + return nil +} + +func verifyPhase2(current, contribution *Phase2) error { + // Compute R for δ + deltaR := genR(contribution.PublicKey.SG, contribution.PublicKey.SXG, current.Hash[:], 1) + + // Check for knowledge of δ + if !sameRatio(contribution.PublicKey.SG, contribution.PublicKey.SXG, contribution.PublicKey.XR, deltaR) { + return errors.New("couldn't verify knowledge of δ") + } + + // Check for valid updates using previous parameters + if !sameRatio(contribution.Parameters.G1.Delta, current.Parameters.G1.Delta, deltaR, contribution.PublicKey.XR) { + return errors.New("couldn't verify that [δ]₁ is based on previous contribution") + } + if !sameRatio(contribution.PublicKey.SG, contribution.PublicKey.SXG, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { + return errors.New("couldn't verify that [δ]₂ is based on previous contribution") + } + + // Check for valid updates of L and Z using + L, prevL := merge(contribution.Parameters.G1.L, current.Parameters.G1.L) + if !sameRatio(L, prevL, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { + return errors.New("couldn't verify valid updates of L using δ⁻¹") + } + Z, prevZ := merge(contribution.Parameters.G1.Z, current.Parameters.G1.Z) + if !sameRatio(Z, prevZ, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { + return errors.New("couldn't verify valid updates of L using δ⁻¹") + } + + // Check hash of the contribution + h := contribution.hash() + for i := 0; i < len(h); i++ { + if h[i] != contribution.Hash[i] { + return errors.New("couldn't verify hash of contribution") + } + } + + return nil +} + +func (c *Phase2) hash() []byte { + sha := sha256.New() + c.writeTo(sha) + return sha.Sum(nil) +} diff --git a/backend/groth16/bw6-633/mpcsetup/setup.go b/backend/groth16/bw6-633/mpcsetup/setup.go new file mode 100644 index 0000000000..35bfdca0e9 --- /dev/null +++ b/backend/groth16/bw6-633/mpcsetup/setup.go @@ -0,0 +1,97 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + curve "github.com/consensys/gnark-crypto/ecc/bw6-633" + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/fft" + groth16 "github.com/consensys/gnark/backend/groth16/bw6-633" +) + +func ExtractKeys(srs1 *Phase1, srs2 *Phase2, evals *Phase2Evaluations, nConstraints int) (pk groth16.ProvingKey, vk groth16.VerifyingKey) { + _, _, _, g2 := curve.Generators() + + // Initialize PK + pk.Domain = *fft.NewDomain(uint64(nConstraints)) + pk.G1.Alpha.Set(&srs1.Parameters.G1.AlphaTau[0]) + pk.G1.Beta.Set(&srs1.Parameters.G1.BetaTau[0]) + pk.G1.Delta.Set(&srs2.Parameters.G1.Delta) + pk.G1.Z = srs2.Parameters.G1.Z + bitReverse(pk.G1.Z) + + pk.G1.K = srs2.Parameters.G1.L + pk.G2.Beta.Set(&srs1.Parameters.G2.Beta) + pk.G2.Delta.Set(&srs2.Parameters.G2.Delta) + + // Filter out infinity points + nWires := len(evals.G1.A) + pk.InfinityA = make([]bool, nWires) + A := make([]curve.G1Affine, nWires) + j := 0 + for i, e := range evals.G1.A { + if e.IsInfinity() { + pk.InfinityA[i] = true + continue + } + A[j] = evals.G1.A[i] + j++ + } + pk.G1.A = A[:j] + pk.NbInfinityA = uint64(nWires - j) + + pk.InfinityB = make([]bool, nWires) + B := make([]curve.G1Affine, nWires) + j = 0 + for i, e := range evals.G1.B { + if e.IsInfinity() { + pk.InfinityB[i] = true + continue + } + B[j] = evals.G1.B[i] + j++ + } + pk.G1.B = B[:j] + pk.NbInfinityB = uint64(nWires - j) + + B2 := make([]curve.G2Affine, nWires) + j = 0 + for i, e := range evals.G2.B { + if e.IsInfinity() { + // pk.InfinityB[i] = true should be the same as in B + continue + } + B2[j] = evals.G2.B[i] + j++ + } + pk.G2.B = B2[:j] + + // Initialize VK + vk.G1.Alpha.Set(&srs1.Parameters.G1.AlphaTau[0]) + vk.G1.Beta.Set(&srs1.Parameters.G1.BetaTau[0]) + vk.G1.Delta.Set(&srs2.Parameters.G1.Delta) + vk.G2.Beta.Set(&srs1.Parameters.G2.Beta) + vk.G2.Delta.Set(&srs2.Parameters.G2.Delta) + vk.G2.Gamma.Set(&g2) + vk.G1.K = evals.G1.VKK + + // sets e, -[δ]2, -[γ]2 + if err := vk.Precompute(); err != nil { + panic(err) + } + + return pk, vk +} diff --git a/backend/groth16/bw6-633/mpcsetup/setup_test.go b/backend/groth16/bw6-633/mpcsetup/setup_test.go new file mode 100644 index 0000000000..6933f11050 --- /dev/null +++ b/backend/groth16/bw6-633/mpcsetup/setup_test.go @@ -0,0 +1,199 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + curve "github.com/consensys/gnark-crypto/ecc/bw6-633" + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" + "github.com/consensys/gnark/constraint/bw6-633" + "testing" + + "github.com/consensys/gnark/backend/groth16" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/std/hash/mimc" + "github.com/stretchr/testify/require" + + native_mimc "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/mimc" +) + +func TestSetupCircuit(t *testing.T) { + if testing.Short() { + t.Skip() + } + const ( + nContributionsPhase1 = 3 + nContributionsPhase2 = 3 + power = 9 + ) + + assert := require.New(t) + + srs1 := InitPhase1(power) + + // Make and verify contributions for phase1 + for i := 1; i < nContributionsPhase1; i++ { + // we clone test purposes; but in practice, participant will receive a []byte, deserialize it, + // add his contribution and send back to coordinator. + prev := srs1.clone() + + srs1.Contribute() + assert.NoError(VerifyPhase1(&prev, &srs1)) + } + + // Compile the circuit + var myCircuit Circuit + ccs, err := frontend.Compile(curve.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) + assert.NoError(err) + + var evals Phase2Evaluations + r1cs := ccs.(*cs.R1CS) + + // Prepare for phase-2 + srs2, evals := InitPhase2(r1cs, &srs1) + + // Make and verify contributions for phase1 + for i := 1; i < nContributionsPhase2; i++ { + // we clone for test purposes; but in practice, participant will receive a []byte, deserialize it, + // add his contribution and send back to coordinator. + prev := srs2.clone() + + srs2.Contribute() + assert.NoError(VerifyPhase2(&prev, &srs2)) + } + + // Extract the proving and verifying keys + pk, vk := ExtractKeys(&srs1, &srs2, &evals, ccs.GetNbConstraints()) + + // Build the witness + var preImage, hash fr.Element + { + m := native_mimc.NewMiMC() + m.Write(preImage.Marshal()) + hash.SetBytes(m.Sum(nil)) + } + + witness, err := frontend.NewWitness(&Circuit{PreImage: preImage, Hash: hash}, curve.ID.ScalarField()) + assert.NoError(err) + + pubWitness, err := witness.Public() + assert.NoError(err) + + // groth16: ensure proof is verified + proof, err := groth16.Prove(ccs, &pk, witness) + assert.NoError(err) + + err = groth16.Verify(proof, &vk, pubWitness) + assert.NoError(err) +} + +func BenchmarkPhase1(b *testing.B) { + const power = 14 + + b.Run("init", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = InitPhase1(power) + } + }) + + b.Run("contrib", func(b *testing.B) { + srs1 := InitPhase1(power) + b.ResetTimer() + for i := 0; i < b.N; i++ { + srs1.Contribute() + } + }) + +} + +func BenchmarkPhase2(b *testing.B) { + const power = 14 + srs1 := InitPhase1(power) + srs1.Contribute() + + var myCircuit Circuit + ccs, err := frontend.Compile(curve.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) + if err != nil { + b.Fatal(err) + } + + r1cs := ccs.(*cs.R1CS) + + b.Run("init", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, _ = InitPhase2(r1cs, &srs1) + } + }) + + b.Run("contrib", func(b *testing.B) { + srs2, _ := InitPhase2(r1cs, &srs1) + b.ResetTimer() + for i := 0; i < b.N; i++ { + srs2.Contribute() + } + }) + +} + +// Circuit defines a pre-image knowledge proof +// mimc(secret preImage) = public hash +type Circuit struct { + PreImage frontend.Variable + Hash frontend.Variable `gnark:",public"` +} + +// Define declares the circuit's constraints +// Hash = mimc(PreImage) +func (circuit *Circuit) Define(api frontend.API) error { + // hash function + mimc, _ := mimc.NewMiMC(api) + + // specify constraints + mimc.Write(circuit.PreImage) + api.AssertIsEqual(circuit.Hash, mimc.Sum()) + + return nil +} + +func (phase1 *Phase1) clone() Phase1 { + r := Phase1{} + r.Parameters.G1.Tau = append(r.Parameters.G1.Tau, phase1.Parameters.G1.Tau...) + r.Parameters.G1.AlphaTau = append(r.Parameters.G1.AlphaTau, phase1.Parameters.G1.AlphaTau...) + r.Parameters.G1.BetaTau = append(r.Parameters.G1.BetaTau, phase1.Parameters.G1.BetaTau...) + + r.Parameters.G2.Tau = append(r.Parameters.G2.Tau, phase1.Parameters.G2.Tau...) + r.Parameters.G2.Beta = phase1.Parameters.G2.Beta + + r.PublicKeys = phase1.PublicKeys + r.Hash = append(r.Hash, phase1.Hash...) + + return r +} + +func (phase2 *Phase2) clone() Phase2 { + r := Phase2{} + r.Parameters.G1.Delta = phase2.Parameters.G1.Delta + r.Parameters.G1.L = append(r.Parameters.G1.L, phase2.Parameters.G1.L...) + r.Parameters.G1.Z = append(r.Parameters.G1.Z, phase2.Parameters.G1.Z...) + r.Parameters.G2.Delta = phase2.Parameters.G2.Delta + r.PublicKey = phase2.PublicKey + r.Hash = append(r.Hash, phase2.Hash...) + + return r +} diff --git a/backend/groth16/bw6-633/mpcsetup/utils.go b/backend/groth16/bw6-633/mpcsetup/utils.go new file mode 100644 index 0000000000..7a2979c53c --- /dev/null +++ b/backend/groth16/bw6-633/mpcsetup/utils.go @@ -0,0 +1,170 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "bytes" + "math/big" + "math/bits" + "runtime" + + "github.com/consensys/gnark-crypto/ecc" + curve "github.com/consensys/gnark-crypto/ecc/bw6-633" + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" + "github.com/consensys/gnark/internal/utils" +) + +type PublicKey struct { + SG curve.G1Affine + SXG curve.G1Affine + XR curve.G2Affine +} + +func newPublicKey(x fr.Element, challenge []byte, dst byte) PublicKey { + var pk PublicKey + _, _, g1, _ := curve.Generators() + + var s fr.Element + var sBi big.Int + s.SetRandom() + s.BigInt(&sBi) + pk.SG.ScalarMultiplication(&g1, &sBi) + + // compute x*sG1 + var xBi big.Int + x.BigInt(&xBi) + pk.SXG.ScalarMultiplication(&pk.SG, &xBi) + + // generate R based on sG1, sxG1, challenge, and domain separation tag (tau, alpha or beta) + R := genR(pk.SG, pk.SXG, challenge, dst) + + // compute x*spG2 + pk.XR.ScalarMultiplication(&R, &xBi) + return pk +} + +func bitReverse[T any](a []T) { + n := uint64(len(a)) + nn := uint64(64 - bits.TrailingZeros64(n)) + + for i := uint64(0); i < n; i++ { + irev := bits.Reverse64(i) >> nn + if irev > i { + a[i], a[irev] = a[irev], a[i] + } + } +} + +// Returns [1, a, a², ..., aⁿ⁻¹ ] in Montgomery form +func powers(a fr.Element, n int) []fr.Element { + result := make([]fr.Element, n) + result[0] = fr.NewElement(1) + for i := 1; i < n; i++ { + result[i].Mul(&result[i-1], &a) + } + return result +} + +// Returns [aᵢAᵢ, ...] in G1 +func scaleG1InPlace(A []curve.G1Affine, a []fr.Element) { + utils.Parallelize(len(A), func(start, end int) { + var tmp big.Int + for i := start; i < end; i++ { + a[i].BigInt(&tmp) + A[i].ScalarMultiplication(&A[i], &tmp) + } + }) +} + +// Returns [aᵢAᵢ, ...] in G2 +func scaleG2InPlace(A []curve.G2Affine, a []fr.Element) { + utils.Parallelize(len(A), func(start, end int) { + var tmp big.Int + for i := start; i < end; i++ { + a[i].BigInt(&tmp) + A[i].ScalarMultiplication(&A[i], &tmp) + } + }) +} + +// Check e(a₁, a₂) = e(b₁, b₂) +func sameRatio(a1, b1 curve.G1Affine, a2, b2 curve.G2Affine) bool { + if !a1.IsInSubGroup() || !b1.IsInSubGroup() || !a2.IsInSubGroup() || !b2.IsInSubGroup() { + panic("invalid point not in subgroup") + } + var na2 curve.G2Affine + na2.Neg(&a2) + res, err := curve.PairingCheck( + []curve.G1Affine{a1, b1}, + []curve.G2Affine{na2, b2}) + if err != nil { + panic(err) + } + return res +} + +// returns a = ∑ rᵢAᵢ, b = ∑ rᵢBᵢ +func merge(A, B []curve.G1Affine) (a, b curve.G1Affine) { + nc := runtime.NumCPU() + r := make([]fr.Element, len(A)) + for i := 0; i < len(A); i++ { + r[i].SetRandom() + } + a.MultiExp(A, r, ecc.MultiExpConfig{NbTasks: nc / 2}) + b.MultiExp(B, r, ecc.MultiExpConfig{NbTasks: nc / 2}) + return +} + +// L1 = ∑ rᵢAᵢ, L2 = ∑ rᵢAᵢ₊₁ in G1 +func linearCombinationG1(A []curve.G1Affine) (L1, L2 curve.G1Affine) { + nc := runtime.NumCPU() + n := len(A) + r := make([]fr.Element, n-1) + for i := 0; i < n-1; i++ { + r[i].SetRandom() + } + L1.MultiExp(A[:n-1], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + L2.MultiExp(A[1:], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + return +} + +// L1 = ∑ rᵢAᵢ, L2 = ∑ rᵢAᵢ₊₁ in G2 +func linearCombinationG2(A []curve.G2Affine) (L1, L2 curve.G2Affine) { + nc := runtime.NumCPU() + n := len(A) + r := make([]fr.Element, n-1) + for i := 0; i < n-1; i++ { + r[i].SetRandom() + } + L1.MultiExp(A[:n-1], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + L2.MultiExp(A[1:], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + return +} + +// Generate R in G₂ as Hash(gˢ, gˢˣ, challenge, dst) +func genR(sG1, sxG1 curve.G1Affine, challenge []byte, dst byte) curve.G2Affine { + var buf bytes.Buffer + buf.Grow(len(challenge) + curve.SizeOfG1AffineUncompressed*2) + buf.Write(sG1.Marshal()) + buf.Write(sxG1.Marshal()) + buf.Write(challenge) + spG2, err := curve.HashToG2(buf.Bytes(), []byte{dst}) + if err != nil { + panic(err) + } + return spG2 +} diff --git a/backend/groth16/bw6-761/mpcsetup/lagrange.go b/backend/groth16/bw6-761/mpcsetup/lagrange.go new file mode 100644 index 0000000000..b2d05ccea4 --- /dev/null +++ b/backend/groth16/bw6-761/mpcsetup/lagrange.go @@ -0,0 +1,216 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "math/big" + "math/bits" + "runtime" + + "github.com/consensys/gnark-crypto/ecc" + curve "github.com/consensys/gnark-crypto/ecc/bw6-761" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/fft" + "github.com/consensys/gnark/internal/utils" +) + +func LagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { + coeffs := make([]curve.G1Affine, size) + copy(coeffs, powers[:size]) + domain := fft.NewDomain(uint64(size)) + numCPU := uint64(runtime.NumCPU()) + maxSplits := bits.TrailingZeros64(ecc.NextPowerOfTwo(numCPU)) + + difFFTG1(coeffs, domain.TwiddlesInv, 0, maxSplits, nil) + bitReverse(coeffs) + + var invBigint big.Int + domain.CardinalityInv.BigInt(&invBigint) + + utils.Parallelize(size, func(start, end int) { + for i := start; i < end; i++ { + coeffs[i].ScalarMultiplication(&coeffs[i], &invBigint) + } + }) + return coeffs +} + +func LagrangeCoeffsG2(powers []curve.G2Affine, size int) []curve.G2Affine { + coeffs := make([]curve.G2Affine, size) + copy(coeffs, powers[:size]) + domain := fft.NewDomain(uint64(size)) + numCPU := uint64(runtime.NumCPU()) + maxSplits := bits.TrailingZeros64(ecc.NextPowerOfTwo(numCPU)) + + difFFTG2(coeffs, domain.TwiddlesInv, 0, maxSplits, nil) + bitReverse(coeffs) + + var invBigint big.Int + domain.CardinalityInv.BigInt(&invBigint) + + utils.Parallelize(size, func(start, end int) { + for i := start; i < end; i++ { + coeffs[i].ScalarMultiplication(&coeffs[i], &invBigint) + } + }) + return coeffs +} + +func butterflyG1(a *curve.G1Affine, b *curve.G1Affine) { + t := *a + a.Add(a, b) + b.Sub(&t, b) +} + +func butterflyG2(a *curve.G2Affine, b *curve.G2Affine) { + t := *a + a.Add(a, b) + b.Sub(&t, b) +} + +// kerDIF8 is a kernel that process a FFT of size 8 +func kerDIF8G1(a []curve.G1Affine, twiddles [][]fr.Element, stage int) { + butterflyG1(&a[0], &a[4]) + butterflyG1(&a[1], &a[5]) + butterflyG1(&a[2], &a[6]) + butterflyG1(&a[3], &a[7]) + + var twiddle big.Int + twiddles[stage+0][1].BigInt(&twiddle) + a[5].ScalarMultiplication(&a[5], &twiddle) + twiddles[stage+0][2].BigInt(&twiddle) + a[6].ScalarMultiplication(&a[6], &twiddle) + twiddles[stage+0][3].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG1(&a[0], &a[2]) + butterflyG1(&a[1], &a[3]) + butterflyG1(&a[4], &a[6]) + butterflyG1(&a[5], &a[7]) + twiddles[stage+1][1].BigInt(&twiddle) + a[3].ScalarMultiplication(&a[3], &twiddle) + twiddles[stage+1][1].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG1(&a[0], &a[1]) + butterflyG1(&a[2], &a[3]) + butterflyG1(&a[4], &a[5]) + butterflyG1(&a[6], &a[7]) +} + +// kerDIF8 is a kernel that process a FFT of size 8 +func kerDIF8G2(a []curve.G2Affine, twiddles [][]fr.Element, stage int) { + butterflyG2(&a[0], &a[4]) + butterflyG2(&a[1], &a[5]) + butterflyG2(&a[2], &a[6]) + butterflyG2(&a[3], &a[7]) + + var twiddle big.Int + twiddles[stage+0][1].BigInt(&twiddle) + a[5].ScalarMultiplication(&a[5], &twiddle) + twiddles[stage+0][2].BigInt(&twiddle) + a[6].ScalarMultiplication(&a[6], &twiddle) + twiddles[stage+0][3].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG2(&a[0], &a[2]) + butterflyG2(&a[1], &a[3]) + butterflyG2(&a[4], &a[6]) + butterflyG2(&a[5], &a[7]) + twiddles[stage+1][1].BigInt(&twiddle) + a[3].ScalarMultiplication(&a[3], &twiddle) + twiddles[stage+1][1].BigInt(&twiddle) + a[7].ScalarMultiplication(&a[7], &twiddle) + butterflyG2(&a[0], &a[1]) + butterflyG2(&a[2], &a[3]) + butterflyG2(&a[4], &a[5]) + butterflyG2(&a[6], &a[7]) +} + +func difFFTG1(a []curve.G1Affine, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { + if chDone != nil { + defer close(chDone) + } + + n := len(a) + if n == 1 { + return + } else if n == 8 { + kerDIF8G1(a, twiddles, stage) + return + } + m := n >> 1 + + butterflyG1(&a[0], &a[m]) + + var twiddle big.Int + for i := 1; i < m; i++ { + butterflyG1(&a[i], &a[i+m]) + twiddles[stage][i].BigInt(&twiddle) + a[i+m].ScalarMultiplication(&a[i+m], &twiddle) + } + + if m == 1 { + return + } + + nextStage := stage + 1 + if stage < maxSplits { + chDone := make(chan struct{}, 1) + go difFFTG1(a[m:n], twiddles, nextStage, maxSplits, chDone) + difFFTG1(a[0:m], twiddles, nextStage, maxSplits, nil) + <-chDone + } else { + difFFTG1(a[0:m], twiddles, nextStage, maxSplits, nil) + difFFTG1(a[m:n], twiddles, nextStage, maxSplits, nil) + } +} +func difFFTG2(a []curve.G2Affine, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { + if chDone != nil { + defer close(chDone) + } + + n := len(a) + if n == 1 { + return + } else if n == 8 { + kerDIF8G2(a, twiddles, stage) + return + } + m := n >> 1 + + butterflyG2(&a[0], &a[m]) + + var twiddle big.Int + for i := 1; i < m; i++ { + butterflyG2(&a[i], &a[i+m]) + twiddles[stage][i].BigInt(&twiddle) + a[i+m].ScalarMultiplication(&a[i+m], &twiddle) + } + + if m == 1 { + return + } + + nextStage := stage + 1 + if stage < maxSplits { + chDone := make(chan struct{}, 1) + go difFFTG2(a[m:n], twiddles, nextStage, maxSplits, chDone) + difFFTG2(a[0:m], twiddles, nextStage, maxSplits, nil) + <-chDone + } else { + difFFTG2(a[0:m], twiddles, nextStage, maxSplits, nil) + difFFTG2(a[m:n], twiddles, nextStage, maxSplits, nil) + } +} diff --git a/backend/groth16/bw6-761/mpcsetup/marshal.go b/backend/groth16/bw6-761/mpcsetup/marshal.go new file mode 100644 index 0000000000..d1a071aa5d --- /dev/null +++ b/backend/groth16/bw6-761/mpcsetup/marshal.go @@ -0,0 +1,181 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + curve "github.com/consensys/gnark-crypto/ecc/bw6-761" + "io" +) + +// WriteTo implements io.WriterTo +func (phase1 *Phase1) WriteTo(writer io.Writer) (int64, error) { + n, err := phase1.writeTo(writer) + if err != nil { + return n, err + } + nBytes, err := writer.Write(phase1.Hash) + return int64(nBytes) + n, err +} + +func (phase1 *Phase1) writeTo(writer io.Writer) (int64, error) { + toEncode := []interface{}{ + &phase1.PublicKeys.Tau.SG, + &phase1.PublicKeys.Tau.SXG, + &phase1.PublicKeys.Tau.XR, + &phase1.PublicKeys.Alpha.SG, + &phase1.PublicKeys.Alpha.SXG, + &phase1.PublicKeys.Alpha.XR, + &phase1.PublicKeys.Beta.SG, + &phase1.PublicKeys.Beta.SXG, + &phase1.PublicKeys.Beta.XR, + phase1.Parameters.G1.Tau, + phase1.Parameters.G1.AlphaTau, + phase1.Parameters.G1.BetaTau, + phase1.Parameters.G2.Tau, + &phase1.Parameters.G2.Beta, + } + + enc := curve.NewEncoder(writer) + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + return enc.BytesWritten(), nil +} + +// ReadFrom implements io.ReaderFrom +func (phase1 *Phase1) ReadFrom(reader io.Reader) (int64, error) { + toEncode := []interface{}{ + &phase1.PublicKeys.Tau.SG, + &phase1.PublicKeys.Tau.SXG, + &phase1.PublicKeys.Tau.XR, + &phase1.PublicKeys.Alpha.SG, + &phase1.PublicKeys.Alpha.SXG, + &phase1.PublicKeys.Alpha.XR, + &phase1.PublicKeys.Beta.SG, + &phase1.PublicKeys.Beta.SXG, + &phase1.PublicKeys.Beta.XR, + &phase1.Parameters.G1.Tau, + &phase1.Parameters.G1.AlphaTau, + &phase1.Parameters.G1.BetaTau, + &phase1.Parameters.G2.Tau, + &phase1.Parameters.G2.Beta, + } + + dec := curve.NewDecoder(reader) + for _, v := range toEncode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + phase1.Hash = make([]byte, 32) + nBytes, err := reader.Read(phase1.Hash) + return dec.BytesRead() + int64(nBytes), err +} + +// WriteTo implements io.WriterTo +func (phase2 *Phase2) WriteTo(writer io.Writer) (int64, error) { + n, err := phase2.writeTo(writer) + if err != nil { + return n, err + } + nBytes, err := writer.Write(phase2.Hash) + return int64(nBytes) + n, err +} + +func (c *Phase2) writeTo(writer io.Writer) (int64, error) { + enc := curve.NewEncoder(writer) + toEncode := []interface{}{ + &c.PublicKey.SG, + &c.PublicKey.SXG, + &c.PublicKey.XR, + &c.Parameters.G1.Delta, + c.Parameters.G1.L, + c.Parameters.G1.Z, + &c.Parameters.G2.Delta, + } + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + + return enc.BytesWritten(), nil +} + +// ReadFrom implements io.ReaderFrom +func (c *Phase2) ReadFrom(reader io.Reader) (int64, error) { + dec := curve.NewDecoder(reader) + toEncode := []interface{}{ + &c.PublicKey.SG, + &c.PublicKey.SXG, + &c.PublicKey.XR, + &c.Parameters.G1.Delta, + &c.Parameters.G1.L, + &c.Parameters.G1.Z, + &c.Parameters.G2.Delta, + } + + for _, v := range toEncode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + + c.Hash = make([]byte, 32) + n, err := reader.Read(c.Hash) + return int64(n) + dec.BytesRead(), err + +} + +// WriteTo implements io.WriterTo +func (c *Phase2Evaluations) WriteTo(writer io.Writer) (int64, error) { + enc := curve.NewEncoder(writer) + toEncode := []interface{}{ + c.G1.A, + c.G1.B, + c.G2.B, + } + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + + return enc.BytesWritten(), nil +} + +// ReadFrom implements io.ReaderFrom +func (c *Phase2Evaluations) ReadFrom(reader io.Reader) (int64, error) { + dec := curve.NewDecoder(reader) + toEncode := []interface{}{ + &c.G1.A, + &c.G1.B, + &c.G2.B, + } + + for _, v := range toEncode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + + return dec.BytesRead(), nil +} diff --git a/backend/groth16/bw6-761/mpcsetup/marshal_test.go b/backend/groth16/bw6-761/mpcsetup/marshal_test.go new file mode 100644 index 0000000000..46913c86b5 --- /dev/null +++ b/backend/groth16/bw6-761/mpcsetup/marshal_test.go @@ -0,0 +1,79 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "bytes" + curve "github.com/consensys/gnark-crypto/ecc/bw6-761" + "github.com/consensys/gnark/constraint/bw6-761" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/stretchr/testify/require" + "io" + "reflect" + "testing" +) + +func TestContributionSerialization(t *testing.T) { + assert := require.New(t) + + // Phase 1 + srs1 := InitPhase1(9) + srs1.Contribute() + { + var reconstructed Phase1 + roundTripCheck(t, &srs1, &reconstructed) + } + + var myCircuit Circuit + ccs, err := frontend.Compile(curve.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) + assert.NoError(err) + + r1cs := ccs.(*cs.R1CS) + + // Phase 2 + srs2, _ := InitPhase2(r1cs, &srs1) + srs2.Contribute() + + { + var reconstructed Phase2 + roundTripCheck(t, &srs2, &reconstructed) + } +} + +func roundTripCheck(t *testing.T, from io.WriterTo, reconstructed io.ReaderFrom) { + t.Helper() + + var buf bytes.Buffer + written, err := from.WriteTo(&buf) + if err != nil { + t.Fatal("couldn't serialize", err) + } + + read, err := reconstructed.ReadFrom(&buf) + if err != nil { + t.Fatal("couldn't deserialize", err) + } + + if !reflect.DeepEqual(from, reconstructed) { + t.Fatal("reconstructed object don't match original") + } + + if written != read { + t.Fatal("bytes written / read don't match") + } +} diff --git a/backend/groth16/bw6-761/mpcsetup/phase1.go b/backend/groth16/bw6-761/mpcsetup/phase1.go new file mode 100644 index 0000000000..07af196d3f --- /dev/null +++ b/backend/groth16/bw6-761/mpcsetup/phase1.go @@ -0,0 +1,203 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "crypto/sha256" + "errors" + curve "github.com/consensys/gnark-crypto/ecc/bw6-761" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" + "math" + "math/big" +) + +// Phase1 represents the Phase1 of the MPC described in +// https://eprint.iacr.org/2017/1050.pdf +// +// Also known as "Powers of Tau" +type Phase1 struct { + Parameters struct { + G1 struct { + Tau []curve.G1Affine // {[τ⁰]₁, [τ¹]₁, [τ²]₁, …, [τ²ⁿ⁻²]₁} + AlphaTau []curve.G1Affine // {α[τ⁰]₁, α[τ¹]₁, α[τ²]₁, …, α[τⁿ⁻¹]₁} + BetaTau []curve.G1Affine // {β[τ⁰]₁, β[τ¹]₁, β[τ²]₁, …, β[τⁿ⁻¹]₁} + } + G2 struct { + Tau []curve.G2Affine // {[τ⁰]₂, [τ¹]₂, [τ²]₂, …, [τⁿ⁻¹]₂} + Beta curve.G2Affine // [β]₂ + } + } + PublicKeys struct { + Tau, Alpha, Beta PublicKey + } + Hash []byte // sha256 hash +} + +// InitPhase1 initialize phase 1 of the MPC. This is called once by the coordinator before +// any randomness contribution is made (see Contribute()). +func InitPhase1(power int) (phase1 Phase1) { + N := int(math.Pow(2, float64(power))) + + // Generate key pairs + var tau, alpha, beta fr.Element + tau.SetOne() + alpha.SetOne() + beta.SetOne() + phase1.PublicKeys.Tau = newPublicKey(tau, nil, 1) + phase1.PublicKeys.Alpha = newPublicKey(alpha, nil, 2) + phase1.PublicKeys.Beta = newPublicKey(beta, nil, 3) + + // First contribution use generators + _, _, g1, g2 := curve.Generators() + phase1.Parameters.G2.Beta.Set(&g2) + phase1.Parameters.G1.Tau = make([]curve.G1Affine, 2*N-1) + phase1.Parameters.G2.Tau = make([]curve.G2Affine, N) + phase1.Parameters.G1.AlphaTau = make([]curve.G1Affine, N) + phase1.Parameters.G1.BetaTau = make([]curve.G1Affine, N) + for i := 0; i < len(phase1.Parameters.G1.Tau); i++ { + phase1.Parameters.G1.Tau[i].Set(&g1) + } + for i := 0; i < len(phase1.Parameters.G2.Tau); i++ { + phase1.Parameters.G2.Tau[i].Set(&g2) + phase1.Parameters.G1.AlphaTau[i].Set(&g1) + phase1.Parameters.G1.BetaTau[i].Set(&g1) + } + + phase1.Parameters.G2.Beta.Set(&g2) + + // Compute hash of Contribution + phase1.Hash = phase1.hash() + + return +} + +// Contribute contributes randomness to the phase1 object. This mutates phase1. +func (phase1 *Phase1) Contribute() { + N := len(phase1.Parameters.G2.Tau) + + // Generate key pairs + var tau, alpha, beta fr.Element + tau.SetRandom() + alpha.SetRandom() + beta.SetRandom() + phase1.PublicKeys.Tau = newPublicKey(tau, phase1.Hash[:], 1) + phase1.PublicKeys.Alpha = newPublicKey(alpha, phase1.Hash[:], 2) + phase1.PublicKeys.Beta = newPublicKey(beta, phase1.Hash[:], 3) + + // Compute powers of τ, ατ, and βτ + taus := powers(tau, 2*N-1) + alphaTau := make([]fr.Element, N) + betaTau := make([]fr.Element, N) + for i := 0; i < N; i++ { + alphaTau[i].Mul(&taus[i], &alpha) + betaTau[i].Mul(&taus[i], &beta) + } + + // Update using previous parameters + // TODO @gbotrel working with jacobian points here will help with perf. + scaleG1InPlace(phase1.Parameters.G1.Tau, taus) + scaleG2InPlace(phase1.Parameters.G2.Tau, taus[0:N]) + scaleG1InPlace(phase1.Parameters.G1.AlphaTau, alphaTau) + scaleG1InPlace(phase1.Parameters.G1.BetaTau, betaTau) + var betaBI big.Int + beta.BigInt(&betaBI) + phase1.Parameters.G2.Beta.ScalarMultiplication(&phase1.Parameters.G2.Beta, &betaBI) + + // Compute hash of Contribution + phase1.Hash = phase1.hash() +} + +func VerifyPhase1(c0, c1 *Phase1, c ...*Phase1) error { + contribs := append([]*Phase1{c0, c1}, c...) + for i := 0; i < len(contribs)-1; i++ { + if err := verifyPhase1(contribs[i], contribs[i+1]); err != nil { + return err + } + } + return nil +} + +// verifyPhase1 checks that a contribution is based on a known previous Phase1 state. +func verifyPhase1(current, contribution *Phase1) error { + // Compute R for τ, α, β + tauR := genR(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, current.Hash[:], 1) + alphaR := genR(contribution.PublicKeys.Alpha.SG, contribution.PublicKeys.Alpha.SXG, current.Hash[:], 2) + betaR := genR(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, current.Hash[:], 3) + + // Check for knowledge of toxic parameters + if !sameRatio(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, contribution.PublicKeys.Tau.XR, tauR) { + return errors.New("couldn't verify public key of τ") + } + if !sameRatio(contribution.PublicKeys.Alpha.SG, contribution.PublicKeys.Alpha.SXG, contribution.PublicKeys.Alpha.XR, alphaR) { + return errors.New("couldn't verify public key of α") + } + if !sameRatio(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, contribution.PublicKeys.Beta.XR, betaR) { + return errors.New("couldn't verify public key of β") + } + + // Check for valid updates using previous parameters + if !sameRatio(contribution.Parameters.G1.Tau[1], current.Parameters.G1.Tau[1], tauR, contribution.PublicKeys.Tau.XR) { + return errors.New("couldn't verify that [τ]₁ is based on previous contribution") + } + if !sameRatio(contribution.Parameters.G1.AlphaTau[0], current.Parameters.G1.AlphaTau[0], alphaR, contribution.PublicKeys.Alpha.XR) { + return errors.New("couldn't verify that [α]₁ is based on previous contribution") + } + if !sameRatio(contribution.Parameters.G1.BetaTau[0], current.Parameters.G1.BetaTau[0], betaR, contribution.PublicKeys.Beta.XR) { + return errors.New("couldn't verify that [β]₁ is based on previous contribution") + } + if !sameRatio(contribution.PublicKeys.Tau.SG, contribution.PublicKeys.Tau.SXG, contribution.Parameters.G2.Tau[1], current.Parameters.G2.Tau[1]) { + return errors.New("couldn't verify that [τ]₂ is based on previous contribution") + } + if !sameRatio(contribution.PublicKeys.Beta.SG, contribution.PublicKeys.Beta.SXG, contribution.Parameters.G2.Beta, current.Parameters.G2.Beta) { + return errors.New("couldn't verify that [β]₂ is based on previous contribution") + } + + // Check for valid updates using powers of τ + _, _, g1, g2 := curve.Generators() + tauL1, tauL2 := linearCombinationG1(contribution.Parameters.G1.Tau) + if !sameRatio(tauL1, tauL2, contribution.Parameters.G2.Tau[1], g2) { + return errors.New("couldn't verify valid powers of τ in G₁") + } + alphaL1, alphaL2 := linearCombinationG1(contribution.Parameters.G1.AlphaTau) + if !sameRatio(alphaL1, alphaL2, contribution.Parameters.G2.Tau[1], g2) { + return errors.New("couldn't verify valid powers of α(τ) in G₁") + } + betaL1, betaL2 := linearCombinationG1(contribution.Parameters.G1.BetaTau) + if !sameRatio(betaL1, betaL2, contribution.Parameters.G2.Tau[1], g2) { + return errors.New("couldn't verify valid powers of α(τ) in G₁") + } + tau2L1, tau2L2 := linearCombinationG2(contribution.Parameters.G2.Tau) + if !sameRatio(contribution.Parameters.G1.Tau[1], g1, tau2L1, tau2L2) { + return errors.New("couldn't verify valid powers of τ in G₂") + } + + // Check hash of the contribution + h := contribution.hash() + for i := 0; i < len(h); i++ { + if h[i] != contribution.Hash[i] { + return errors.New("couldn't verify hash of contribution") + } + } + + return nil +} + +func (phase1 *Phase1) hash() []byte { + sha := sha256.New() + phase1.writeTo(sha) + return sha.Sum(nil) +} diff --git a/backend/groth16/bw6-761/mpcsetup/phase2.go b/backend/groth16/bw6-761/mpcsetup/phase2.go new file mode 100644 index 0000000000..c53621f17e --- /dev/null +++ b/backend/groth16/bw6-761/mpcsetup/phase2.go @@ -0,0 +1,258 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "crypto/sha256" + "errors" + "math/big" + + curve "github.com/consensys/gnark-crypto/ecc/bw6-761" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" + "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/bw6-761" +) + +type Phase2Evaluations struct { + G1 struct { + A, B, VKK []curve.G1Affine + } + G2 struct { + B []curve.G2Affine + } +} + +type Phase2 struct { + Parameters struct { + G1 struct { + Delta curve.G1Affine + L, Z []curve.G1Affine + } + G2 struct { + Delta curve.G2Affine + } + } + PublicKey PublicKey + Hash []byte +} + +func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { + srs := srs1.Parameters + size := len(srs.G1.AlphaTau) + if size < r1cs.GetNbConstraints() { + panic("Number of constraints is larger than expected") + } + + c2 := Phase2{} + + accumulateG1 := func(res *curve.G1Affine, t constraint.Term, value *curve.G1Affine) { + cID := t.CoeffID() + switch cID { + case constraint.CoeffIdZero: + return + case constraint.CoeffIdOne: + res.Add(res, value) + case constraint.CoeffIdMinusOne: + res.Sub(res, value) + case constraint.CoeffIdTwo: + res.Add(res, value).Add(res, value) + default: + var tmp curve.G1Affine + var vBi big.Int + r1cs.Coefficients[cID].BigInt(&vBi) + tmp.ScalarMultiplication(value, &vBi) + res.Add(res, &tmp) + } + } + + accumulateG2 := func(res *curve.G2Affine, t constraint.Term, value *curve.G2Affine) { + cID := t.CoeffID() + switch cID { + case constraint.CoeffIdZero: + return + case constraint.CoeffIdOne: + res.Add(res, value) + case constraint.CoeffIdMinusOne: + res.Sub(res, value) + case constraint.CoeffIdTwo: + res.Add(res, value).Add(res, value) + default: + var tmp curve.G2Affine + var vBi big.Int + r1cs.Coefficients[cID].BigInt(&vBi) + tmp.ScalarMultiplication(value, &vBi) + res.Add(res, &tmp) + } + } + + // Prepare Lagrange coefficients of [τ...]₁, [τ...]₂, [ατ...]₁, [βτ...]₁ + coeffTau1 := LagrangeCoeffsG1(srs.G1.Tau, size) + coeffTau2 := LagrangeCoeffsG2(srs.G2.Tau, size) + coeffAlphaTau1 := LagrangeCoeffsG1(srs.G1.AlphaTau, size) + coeffBetaTau1 := LagrangeCoeffsG1(srs.G1.BetaTau, size) + + internal, secret, public := r1cs.GetNbVariables() + nWires := internal + secret + public + var evals Phase2Evaluations + evals.G1.A = make([]curve.G1Affine, nWires) + evals.G1.B = make([]curve.G1Affine, nWires) + evals.G2.B = make([]curve.G2Affine, nWires) + bA := make([]curve.G1Affine, nWires) + aB := make([]curve.G1Affine, nWires) + C := make([]curve.G1Affine, nWires) + for i, c := range r1cs.Constraints { + // A + for _, t := range c.L { + accumulateG1(&evals.G1.A[t.WireID()], t, &coeffTau1[i]) + accumulateG1(&bA[t.WireID()], t, &coeffBetaTau1[i]) + } + // B + for _, t := range c.R { + accumulateG1(&evals.G1.B[t.WireID()], t, &coeffTau1[i]) + accumulateG2(&evals.G2.B[t.WireID()], t, &coeffTau2[i]) + accumulateG1(&aB[t.WireID()], t, &coeffAlphaTau1[i]) + } + // C + for _, t := range c.O { + accumulateG1(&C[t.WireID()], t, &coeffTau1[i]) + } + } + + // Prepare default contribution + _, _, g1, g2 := curve.Generators() + c2.Parameters.G1.Delta = g1 + c2.Parameters.G2.Delta = g2 + + // Build Z in PK as τⁱ(τⁿ - 1) = τ⁽ⁱ⁺ⁿ⁾ - τⁱ for i ∈ [0, n-2] + // τⁱ(τⁿ - 1) = τ⁽ⁱ⁺ⁿ⁾ - τⁱ for i ∈ [0, n-2] + n := len(srs.G1.AlphaTau) + c2.Parameters.G1.Z = make([]curve.G1Affine, n) + for i := 0; i < n-1; i++ { + c2.Parameters.G1.Z[i].Sub(&srs.G1.Tau[i+n], &srs.G1.Tau[i]) + } + bitReverse(c2.Parameters.G1.Z) + c2.Parameters.G1.Z = c2.Parameters.G1.Z[:n-1] + + // Evaluate L + nPrivate := internal + secret + c2.Parameters.G1.L = make([]curve.G1Affine, nPrivate) + evals.G1.VKK = make([]curve.G1Affine, public) + offset := public + for i := 0; i < nWires; i++ { + var tmp curve.G1Affine + tmp.Add(&bA[i], &aB[i]) + tmp.Add(&tmp, &C[i]) + if i < public { + evals.G1.VKK[i].Set(&tmp) + } else { + c2.Parameters.G1.L[i-offset].Set(&tmp) + } + } + // Set δ public key + var delta fr.Element + delta.SetOne() + c2.PublicKey = newPublicKey(delta, nil, 1) + + // Hash initial contribution + c2.Hash = c2.hash() + return c2, evals +} + +func (c *Phase2) Contribute() { + // Sample toxic δ + var delta, deltaInv fr.Element + var deltaBI, deltaInvBI big.Int + delta.SetRandom() + deltaInv.Inverse(&delta) + + delta.BigInt(&deltaBI) + deltaInv.BigInt(&deltaInvBI) + + // Set δ public key + c.PublicKey = newPublicKey(delta, c.Hash, 1) + + // Update δ + c.Parameters.G1.Delta.ScalarMultiplication(&c.Parameters.G1.Delta, &deltaBI) + c.Parameters.G2.Delta.ScalarMultiplication(&c.Parameters.G2.Delta, &deltaBI) + + // Update Z using δ⁻¹ + for i := 0; i < len(c.Parameters.G1.Z); i++ { + c.Parameters.G1.Z[i].ScalarMultiplication(&c.Parameters.G1.Z[i], &deltaInvBI) + } + + // Update L using δ⁻¹ + for i := 0; i < len(c.Parameters.G1.L); i++ { + c.Parameters.G1.L[i].ScalarMultiplication(&c.Parameters.G1.L[i], &deltaInvBI) + } + + // 4. Hash contribution + c.Hash = c.hash() +} + +func VerifyPhase2(c0, c1 *Phase2, c ...*Phase2) error { + contribs := append([]*Phase2{c0, c1}, c...) + for i := 0; i < len(contribs)-1; i++ { + if err := verifyPhase2(contribs[i], contribs[i+1]); err != nil { + return err + } + } + return nil +} + +func verifyPhase2(current, contribution *Phase2) error { + // Compute R for δ + deltaR := genR(contribution.PublicKey.SG, contribution.PublicKey.SXG, current.Hash[:], 1) + + // Check for knowledge of δ + if !sameRatio(contribution.PublicKey.SG, contribution.PublicKey.SXG, contribution.PublicKey.XR, deltaR) { + return errors.New("couldn't verify knowledge of δ") + } + + // Check for valid updates using previous parameters + if !sameRatio(contribution.Parameters.G1.Delta, current.Parameters.G1.Delta, deltaR, contribution.PublicKey.XR) { + return errors.New("couldn't verify that [δ]₁ is based on previous contribution") + } + if !sameRatio(contribution.PublicKey.SG, contribution.PublicKey.SXG, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { + return errors.New("couldn't verify that [δ]₂ is based on previous contribution") + } + + // Check for valid updates of L and Z using + L, prevL := merge(contribution.Parameters.G1.L, current.Parameters.G1.L) + if !sameRatio(L, prevL, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { + return errors.New("couldn't verify valid updates of L using δ⁻¹") + } + Z, prevZ := merge(contribution.Parameters.G1.Z, current.Parameters.G1.Z) + if !sameRatio(Z, prevZ, contribution.Parameters.G2.Delta, current.Parameters.G2.Delta) { + return errors.New("couldn't verify valid updates of L using δ⁻¹") + } + + // Check hash of the contribution + h := contribution.hash() + for i := 0; i < len(h); i++ { + if h[i] != contribution.Hash[i] { + return errors.New("couldn't verify hash of contribution") + } + } + + return nil +} + +func (c *Phase2) hash() []byte { + sha := sha256.New() + c.writeTo(sha) + return sha.Sum(nil) +} diff --git a/backend/groth16/bw6-761/mpcsetup/setup.go b/backend/groth16/bw6-761/mpcsetup/setup.go new file mode 100644 index 0000000000..9008fd26b0 --- /dev/null +++ b/backend/groth16/bw6-761/mpcsetup/setup.go @@ -0,0 +1,97 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + curve "github.com/consensys/gnark-crypto/ecc/bw6-761" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/fft" + groth16 "github.com/consensys/gnark/backend/groth16/bw6-761" +) + +func ExtractKeys(srs1 *Phase1, srs2 *Phase2, evals *Phase2Evaluations, nConstraints int) (pk groth16.ProvingKey, vk groth16.VerifyingKey) { + _, _, _, g2 := curve.Generators() + + // Initialize PK + pk.Domain = *fft.NewDomain(uint64(nConstraints)) + pk.G1.Alpha.Set(&srs1.Parameters.G1.AlphaTau[0]) + pk.G1.Beta.Set(&srs1.Parameters.G1.BetaTau[0]) + pk.G1.Delta.Set(&srs2.Parameters.G1.Delta) + pk.G1.Z = srs2.Parameters.G1.Z + bitReverse(pk.G1.Z) + + pk.G1.K = srs2.Parameters.G1.L + pk.G2.Beta.Set(&srs1.Parameters.G2.Beta) + pk.G2.Delta.Set(&srs2.Parameters.G2.Delta) + + // Filter out infinity points + nWires := len(evals.G1.A) + pk.InfinityA = make([]bool, nWires) + A := make([]curve.G1Affine, nWires) + j := 0 + for i, e := range evals.G1.A { + if e.IsInfinity() { + pk.InfinityA[i] = true + continue + } + A[j] = evals.G1.A[i] + j++ + } + pk.G1.A = A[:j] + pk.NbInfinityA = uint64(nWires - j) + + pk.InfinityB = make([]bool, nWires) + B := make([]curve.G1Affine, nWires) + j = 0 + for i, e := range evals.G1.B { + if e.IsInfinity() { + pk.InfinityB[i] = true + continue + } + B[j] = evals.G1.B[i] + j++ + } + pk.G1.B = B[:j] + pk.NbInfinityB = uint64(nWires - j) + + B2 := make([]curve.G2Affine, nWires) + j = 0 + for i, e := range evals.G2.B { + if e.IsInfinity() { + // pk.InfinityB[i] = true should be the same as in B + continue + } + B2[j] = evals.G2.B[i] + j++ + } + pk.G2.B = B2[:j] + + // Initialize VK + vk.G1.Alpha.Set(&srs1.Parameters.G1.AlphaTau[0]) + vk.G1.Beta.Set(&srs1.Parameters.G1.BetaTau[0]) + vk.G1.Delta.Set(&srs2.Parameters.G1.Delta) + vk.G2.Beta.Set(&srs1.Parameters.G2.Beta) + vk.G2.Delta.Set(&srs2.Parameters.G2.Delta) + vk.G2.Gamma.Set(&g2) + vk.G1.K = evals.G1.VKK + + // sets e, -[δ]2, -[γ]2 + if err := vk.Precompute(); err != nil { + panic(err) + } + + return pk, vk +} diff --git a/backend/groth16/bw6-761/mpcsetup/setup_test.go b/backend/groth16/bw6-761/mpcsetup/setup_test.go new file mode 100644 index 0000000000..28e4c7a768 --- /dev/null +++ b/backend/groth16/bw6-761/mpcsetup/setup_test.go @@ -0,0 +1,199 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + curve "github.com/consensys/gnark-crypto/ecc/bw6-761" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" + "github.com/consensys/gnark/constraint/bw6-761" + "testing" + + "github.com/consensys/gnark/backend/groth16" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/std/hash/mimc" + "github.com/stretchr/testify/require" + + native_mimc "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/mimc" +) + +func TestSetupCircuit(t *testing.T) { + if testing.Short() { + t.Skip() + } + const ( + nContributionsPhase1 = 3 + nContributionsPhase2 = 3 + power = 9 + ) + + assert := require.New(t) + + srs1 := InitPhase1(power) + + // Make and verify contributions for phase1 + for i := 1; i < nContributionsPhase1; i++ { + // we clone test purposes; but in practice, participant will receive a []byte, deserialize it, + // add his contribution and send back to coordinator. + prev := srs1.clone() + + srs1.Contribute() + assert.NoError(VerifyPhase1(&prev, &srs1)) + } + + // Compile the circuit + var myCircuit Circuit + ccs, err := frontend.Compile(curve.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) + assert.NoError(err) + + var evals Phase2Evaluations + r1cs := ccs.(*cs.R1CS) + + // Prepare for phase-2 + srs2, evals := InitPhase2(r1cs, &srs1) + + // Make and verify contributions for phase1 + for i := 1; i < nContributionsPhase2; i++ { + // we clone for test purposes; but in practice, participant will receive a []byte, deserialize it, + // add his contribution and send back to coordinator. + prev := srs2.clone() + + srs2.Contribute() + assert.NoError(VerifyPhase2(&prev, &srs2)) + } + + // Extract the proving and verifying keys + pk, vk := ExtractKeys(&srs1, &srs2, &evals, ccs.GetNbConstraints()) + + // Build the witness + var preImage, hash fr.Element + { + m := native_mimc.NewMiMC() + m.Write(preImage.Marshal()) + hash.SetBytes(m.Sum(nil)) + } + + witness, err := frontend.NewWitness(&Circuit{PreImage: preImage, Hash: hash}, curve.ID.ScalarField()) + assert.NoError(err) + + pubWitness, err := witness.Public() + assert.NoError(err) + + // groth16: ensure proof is verified + proof, err := groth16.Prove(ccs, &pk, witness) + assert.NoError(err) + + err = groth16.Verify(proof, &vk, pubWitness) + assert.NoError(err) +} + +func BenchmarkPhase1(b *testing.B) { + const power = 14 + + b.Run("init", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = InitPhase1(power) + } + }) + + b.Run("contrib", func(b *testing.B) { + srs1 := InitPhase1(power) + b.ResetTimer() + for i := 0; i < b.N; i++ { + srs1.Contribute() + } + }) + +} + +func BenchmarkPhase2(b *testing.B) { + const power = 14 + srs1 := InitPhase1(power) + srs1.Contribute() + + var myCircuit Circuit + ccs, err := frontend.Compile(curve.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) + if err != nil { + b.Fatal(err) + } + + r1cs := ccs.(*cs.R1CS) + + b.Run("init", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, _ = InitPhase2(r1cs, &srs1) + } + }) + + b.Run("contrib", func(b *testing.B) { + srs2, _ := InitPhase2(r1cs, &srs1) + b.ResetTimer() + for i := 0; i < b.N; i++ { + srs2.Contribute() + } + }) + +} + +// Circuit defines a pre-image knowledge proof +// mimc(secret preImage) = public hash +type Circuit struct { + PreImage frontend.Variable + Hash frontend.Variable `gnark:",public"` +} + +// Define declares the circuit's constraints +// Hash = mimc(PreImage) +func (circuit *Circuit) Define(api frontend.API) error { + // hash function + mimc, _ := mimc.NewMiMC(api) + + // specify constraints + mimc.Write(circuit.PreImage) + api.AssertIsEqual(circuit.Hash, mimc.Sum()) + + return nil +} + +func (phase1 *Phase1) clone() Phase1 { + r := Phase1{} + r.Parameters.G1.Tau = append(r.Parameters.G1.Tau, phase1.Parameters.G1.Tau...) + r.Parameters.G1.AlphaTau = append(r.Parameters.G1.AlphaTau, phase1.Parameters.G1.AlphaTau...) + r.Parameters.G1.BetaTau = append(r.Parameters.G1.BetaTau, phase1.Parameters.G1.BetaTau...) + + r.Parameters.G2.Tau = append(r.Parameters.G2.Tau, phase1.Parameters.G2.Tau...) + r.Parameters.G2.Beta = phase1.Parameters.G2.Beta + + r.PublicKeys = phase1.PublicKeys + r.Hash = append(r.Hash, phase1.Hash...) + + return r +} + +func (phase2 *Phase2) clone() Phase2 { + r := Phase2{} + r.Parameters.G1.Delta = phase2.Parameters.G1.Delta + r.Parameters.G1.L = append(r.Parameters.G1.L, phase2.Parameters.G1.L...) + r.Parameters.G1.Z = append(r.Parameters.G1.Z, phase2.Parameters.G1.Z...) + r.Parameters.G2.Delta = phase2.Parameters.G2.Delta + r.PublicKey = phase2.PublicKey + r.Hash = append(r.Hash, phase2.Hash...) + + return r +} diff --git a/backend/groth16/bw6-761/mpcsetup/utils.go b/backend/groth16/bw6-761/mpcsetup/utils.go new file mode 100644 index 0000000000..dfdd1e8a97 --- /dev/null +++ b/backend/groth16/bw6-761/mpcsetup/utils.go @@ -0,0 +1,170 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package mpcsetup + +import ( + "bytes" + "math/big" + "math/bits" + "runtime" + + "github.com/consensys/gnark-crypto/ecc" + curve "github.com/consensys/gnark-crypto/ecc/bw6-761" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" + "github.com/consensys/gnark/internal/utils" +) + +type PublicKey struct { + SG curve.G1Affine + SXG curve.G1Affine + XR curve.G2Affine +} + +func newPublicKey(x fr.Element, challenge []byte, dst byte) PublicKey { + var pk PublicKey + _, _, g1, _ := curve.Generators() + + var s fr.Element + var sBi big.Int + s.SetRandom() + s.BigInt(&sBi) + pk.SG.ScalarMultiplication(&g1, &sBi) + + // compute x*sG1 + var xBi big.Int + x.BigInt(&xBi) + pk.SXG.ScalarMultiplication(&pk.SG, &xBi) + + // generate R based on sG1, sxG1, challenge, and domain separation tag (tau, alpha or beta) + R := genR(pk.SG, pk.SXG, challenge, dst) + + // compute x*spG2 + pk.XR.ScalarMultiplication(&R, &xBi) + return pk +} + +func bitReverse[T any](a []T) { + n := uint64(len(a)) + nn := uint64(64 - bits.TrailingZeros64(n)) + + for i := uint64(0); i < n; i++ { + irev := bits.Reverse64(i) >> nn + if irev > i { + a[i], a[irev] = a[irev], a[i] + } + } +} + +// Returns [1, a, a², ..., aⁿ⁻¹ ] in Montgomery form +func powers(a fr.Element, n int) []fr.Element { + result := make([]fr.Element, n) + result[0] = fr.NewElement(1) + for i := 1; i < n; i++ { + result[i].Mul(&result[i-1], &a) + } + return result +} + +// Returns [aᵢAᵢ, ...] in G1 +func scaleG1InPlace(A []curve.G1Affine, a []fr.Element) { + utils.Parallelize(len(A), func(start, end int) { + var tmp big.Int + for i := start; i < end; i++ { + a[i].BigInt(&tmp) + A[i].ScalarMultiplication(&A[i], &tmp) + } + }) +} + +// Returns [aᵢAᵢ, ...] in G2 +func scaleG2InPlace(A []curve.G2Affine, a []fr.Element) { + utils.Parallelize(len(A), func(start, end int) { + var tmp big.Int + for i := start; i < end; i++ { + a[i].BigInt(&tmp) + A[i].ScalarMultiplication(&A[i], &tmp) + } + }) +} + +// Check e(a₁, a₂) = e(b₁, b₂) +func sameRatio(a1, b1 curve.G1Affine, a2, b2 curve.G2Affine) bool { + if !a1.IsInSubGroup() || !b1.IsInSubGroup() || !a2.IsInSubGroup() || !b2.IsInSubGroup() { + panic("invalid point not in subgroup") + } + var na2 curve.G2Affine + na2.Neg(&a2) + res, err := curve.PairingCheck( + []curve.G1Affine{a1, b1}, + []curve.G2Affine{na2, b2}) + if err != nil { + panic(err) + } + return res +} + +// returns a = ∑ rᵢAᵢ, b = ∑ rᵢBᵢ +func merge(A, B []curve.G1Affine) (a, b curve.G1Affine) { + nc := runtime.NumCPU() + r := make([]fr.Element, len(A)) + for i := 0; i < len(A); i++ { + r[i].SetRandom() + } + a.MultiExp(A, r, ecc.MultiExpConfig{NbTasks: nc / 2}) + b.MultiExp(B, r, ecc.MultiExpConfig{NbTasks: nc / 2}) + return +} + +// L1 = ∑ rᵢAᵢ, L2 = ∑ rᵢAᵢ₊₁ in G1 +func linearCombinationG1(A []curve.G1Affine) (L1, L2 curve.G1Affine) { + nc := runtime.NumCPU() + n := len(A) + r := make([]fr.Element, n-1) + for i := 0; i < n-1; i++ { + r[i].SetRandom() + } + L1.MultiExp(A[:n-1], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + L2.MultiExp(A[1:], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + return +} + +// L1 = ∑ rᵢAᵢ, L2 = ∑ rᵢAᵢ₊₁ in G2 +func linearCombinationG2(A []curve.G2Affine) (L1, L2 curve.G2Affine) { + nc := runtime.NumCPU() + n := len(A) + r := make([]fr.Element, n-1) + for i := 0; i < n-1; i++ { + r[i].SetRandom() + } + L1.MultiExp(A[:n-1], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + L2.MultiExp(A[1:], r, ecc.MultiExpConfig{NbTasks: nc / 2}) + return +} + +// Generate R in G₂ as Hash(gˢ, gˢˣ, challenge, dst) +func genR(sG1, sxG1 curve.G1Affine, challenge []byte, dst byte) curve.G2Affine { + var buf bytes.Buffer + buf.Grow(len(challenge) + curve.SizeOfG1AffineUncompressed*2) + buf.Write(sG1.Marshal()) + buf.Write(sxG1.Marshal()) + buf.Write(challenge) + spG2, err := curve.HashToG2(buf.Bytes(), []byte{dst}) + if err != nil { + panic(err) + } + return spG2 +} diff --git a/backend/groth16/mpcsetup/doc.go b/backend/groth16/mpcsetup/doc.go deleted file mode 100644 index 786398d32a..0000000000 --- a/backend/groth16/mpcsetup/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package mpcsetup implements https://eprint.iacr.org/2017/1050.pdf -package mpcsetup diff --git a/internal/generator/backend/main.go b/internal/generator/backend/main.go index 5face84ed8..5b59be8e69 100644 --- a/internal/generator/backend/main.go +++ b/internal/generator/backend/main.go @@ -101,9 +101,10 @@ func main() { defer wg.Done() var ( - groth16Dir = strings.Replace(d.RootPath, "{?}", "groth16", 1) - plonkDir = strings.Replace(d.RootPath, "{?}", "plonk", 1) - plonkFriDir = strings.Replace(d.RootPath, "{?}", "plonkfri", 1) + groth16Dir = strings.Replace(d.RootPath, "{?}", "groth16", 1) + groth16MpcSetupDir = filepath.Join(groth16Dir, "mpcsetup") + plonkDir = strings.Replace(d.RootPath, "{?}", "plonk", 1) + plonkFriDir = strings.Replace(d.RootPath, "{?}", "plonkfri", 1) ) if err := os.MkdirAll(groth16Dir, 0700); err != nil { @@ -168,6 +169,22 @@ func main() { panic(err) // TODO handle } + // groth16 mpcsetup + entries = []bavard.Entry{ + {File: filepath.Join(groth16MpcSetupDir, "lagrange.go"), Templates: []string{"groth16/mpcsetup/lagrange.go.tmpl", importCurve}}, + {File: filepath.Join(groth16MpcSetupDir, "marshal.go"), Templates: []string{"groth16/mpcsetup/marshal.go.tmpl", importCurve}}, + {File: filepath.Join(groth16MpcSetupDir, "marshal_test.go"), Templates: []string{"groth16/mpcsetup/marshal_test.go.tmpl", importCurve}}, + {File: filepath.Join(groth16MpcSetupDir, "phase1.go"), Templates: []string{"groth16/mpcsetup/phase1.go.tmpl", importCurve}}, + {File: filepath.Join(groth16MpcSetupDir, "phase2.go"), Templates: []string{"groth16/mpcsetup/phase2.go.tmpl", importCurve}}, + {File: filepath.Join(groth16MpcSetupDir, "setup.go"), Templates: []string{"groth16/mpcsetup/setup.go.tmpl", importCurve}}, + {File: filepath.Join(groth16MpcSetupDir, "setup_test.go"), Templates: []string{"groth16/mpcsetup/setup_test.go.tmpl", importCurve}}, + {File: filepath.Join(groth16MpcSetupDir, "utils.go"), Templates: []string{"groth16/mpcsetup/utils.go.tmpl", importCurve}}, + } + + if err := bgen.Generate(d, "mpcsetup", "./template/zkpschemes/", entries...); err != nil { + panic(err) // TODO handle + } + // plonk entries = []bavard.Entry{ {File: filepath.Join(plonkDir, "verify.go"), Templates: []string{"plonk/plonk.verify.go.tmpl", importCurve}}, diff --git a/backend/groth16/mpcsetup/lagrange.go b/internal/generator/backend/template/zkpschemes/groth16/mpcsetup/lagrange.go.tmpl similarity index 85% rename from backend/groth16/mpcsetup/lagrange.go rename to internal/generator/backend/template/zkpschemes/groth16/mpcsetup/lagrange.go.tmpl index a0d3d463be..ade1c628ad 100644 --- a/backend/groth16/mpcsetup/lagrange.go +++ b/internal/generator/backend/template/zkpschemes/groth16/mpcsetup/lagrange.go.tmpl @@ -1,19 +1,20 @@ -package mpcsetup - import ( "math/big" "math/bits" "runtime" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark-crypto/ecc/bn254/fr" - "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" + + {{- template "import_fr" . }} + {{- template "import_curve" . }} + {{- template "import_fft" . }} "github.com/consensys/gnark/internal/utils" ) -func LagrangeCoeffsG1(powers []bn254.G1Affine, size int) []bn254.G1Affine { - coeffs := make([]bn254.G1Affine, size) + + +func LagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { + coeffs := make([]curve.G1Affine, size) copy(coeffs, powers[:size]) domain := fft.NewDomain(uint64(size)) numCPU := uint64(runtime.NumCPU()) @@ -33,8 +34,8 @@ func LagrangeCoeffsG1(powers []bn254.G1Affine, size int) []bn254.G1Affine { return coeffs } -func LagrangeCoeffsG2(powers []bn254.G2Affine, size int) []bn254.G2Affine { - coeffs := make([]bn254.G2Affine, size) +func LagrangeCoeffsG2(powers []curve.G2Affine, size int) []curve.G2Affine { + coeffs := make([]curve.G2Affine, size) copy(coeffs, powers[:size]) domain := fft.NewDomain(uint64(size)) numCPU := uint64(runtime.NumCPU()) @@ -54,20 +55,20 @@ func LagrangeCoeffsG2(powers []bn254.G2Affine, size int) []bn254.G2Affine { return coeffs } -func butterflyG1(a *bn254.G1Affine, b *bn254.G1Affine) { +func butterflyG1(a *curve.G1Affine, b *curve.G1Affine) { t := *a a.Add(a, b) b.Sub(&t, b) } -func butterflyG2(a *bn254.G2Affine, b *bn254.G2Affine) { +func butterflyG2(a *curve.G2Affine, b *curve.G2Affine) { t := *a a.Add(a, b) b.Sub(&t, b) } // kerDIF8 is a kernel that process a FFT of size 8 -func kerDIF8G1(a []bn254.G1Affine, twiddles [][]fr.Element, stage int) { +func kerDIF8G1(a []curve.G1Affine, twiddles [][]fr.Element, stage int) { butterflyG1(&a[0], &a[4]) butterflyG1(&a[1], &a[5]) butterflyG1(&a[2], &a[6]) @@ -95,7 +96,7 @@ func kerDIF8G1(a []bn254.G1Affine, twiddles [][]fr.Element, stage int) { } // kerDIF8 is a kernel that process a FFT of size 8 -func kerDIF8G2(a []bn254.G2Affine, twiddles [][]fr.Element, stage int) { +func kerDIF8G2(a []curve.G2Affine, twiddles [][]fr.Element, stage int) { butterflyG2(&a[0], &a[4]) butterflyG2(&a[1], &a[5]) butterflyG2(&a[2], &a[6]) @@ -122,7 +123,7 @@ func kerDIF8G2(a []bn254.G2Affine, twiddles [][]fr.Element, stage int) { butterflyG2(&a[6], &a[7]) } -func difFFTG1(a []bn254.G1Affine, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { +func difFFTG1(a []curve.G1Affine, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { if chDone != nil { defer close(chDone) } @@ -160,7 +161,7 @@ func difFFTG1(a []bn254.G1Affine, twiddles [][]fr.Element, stage, maxSplits int, difFFTG1(a[m:n], twiddles, nextStage, maxSplits, nil) } } -func difFFTG2(a []bn254.G2Affine, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { +func difFFTG2(a []curve.G2Affine, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { if chDone != nil { defer close(chDone) } diff --git a/backend/groth16/mpcsetup/marshal.go b/internal/generator/backend/template/zkpschemes/groth16/mpcsetup/marshal.go.tmpl similarity index 92% rename from backend/groth16/mpcsetup/marshal.go rename to internal/generator/backend/template/zkpschemes/groth16/mpcsetup/marshal.go.tmpl index f0545585b9..3af994ae04 100644 --- a/backend/groth16/mpcsetup/marshal.go +++ b/internal/generator/backend/template/zkpschemes/groth16/mpcsetup/marshal.go.tmpl @@ -1,9 +1,8 @@ -package mpcsetup - import ( "io" - "github.com/consensys/gnark-crypto/ecc/bn254" + + {{- template "import_curve" . }} ) // WriteTo implements io.WriterTo @@ -34,7 +33,7 @@ func (phase1 *Phase1) writeTo(writer io.Writer) (int64, error) { &phase1.Parameters.G2.Beta, } - enc := bn254.NewEncoder(writer) + enc := curve.NewEncoder(writer) for _, v := range toEncode { if err := enc.Encode(v); err != nil { return enc.BytesWritten(), err @@ -62,7 +61,7 @@ func (phase1 *Phase1) ReadFrom(reader io.Reader) (int64, error) { &phase1.Parameters.G2.Beta, } - dec := bn254.NewDecoder(reader) + dec := curve.NewDecoder(reader) for _, v := range toEncode { if err := dec.Decode(v); err != nil { return dec.BytesRead(), err @@ -84,7 +83,7 @@ func (phase2 *Phase2) WriteTo(writer io.Writer) (int64, error) { } func (c *Phase2) writeTo(writer io.Writer) (int64, error) { - enc := bn254.NewEncoder(writer) + enc := curve.NewEncoder(writer) toEncode := []interface{}{ &c.PublicKey.SG, &c.PublicKey.SXG, @@ -106,7 +105,7 @@ func (c *Phase2) writeTo(writer io.Writer) (int64, error) { // ReadFrom implements io.ReaderFrom func (c *Phase2) ReadFrom(reader io.Reader) (int64, error) { - dec := bn254.NewDecoder(reader) + dec := curve.NewDecoder(reader) toEncode := []interface{}{ &c.PublicKey.SG, &c.PublicKey.SXG, @@ -131,7 +130,7 @@ func (c *Phase2) ReadFrom(reader io.Reader) (int64, error) { // WriteTo implements io.WriterTo func (c *Phase2Evaluations) WriteTo(writer io.Writer) (int64, error) { - enc := bn254.NewEncoder(writer) + enc := curve.NewEncoder(writer) toEncode := []interface{}{ c.G1.A, c.G1.B, @@ -149,7 +148,7 @@ func (c *Phase2Evaluations) WriteTo(writer io.Writer) (int64, error) { // ReadFrom implements io.ReaderFrom func (c *Phase2Evaluations) ReadFrom(reader io.Reader) (int64, error) { - dec := bn254.NewDecoder(reader) + dec := curve.NewDecoder(reader) toEncode := []interface{}{ &c.G1.A, &c.G1.B, diff --git a/backend/groth16/mpcsetup/marshal_test.go b/internal/generator/backend/template/zkpschemes/groth16/mpcsetup/marshal_test.go.tmpl similarity index 83% rename from backend/groth16/mpcsetup/marshal_test.go rename to internal/generator/backend/template/zkpschemes/groth16/mpcsetup/marshal_test.go.tmpl index 9bb13c2e5d..803b1863d9 100644 --- a/backend/groth16/mpcsetup/marshal_test.go +++ b/internal/generator/backend/template/zkpschemes/groth16/mpcsetup/marshal_test.go.tmpl @@ -1,13 +1,12 @@ -package mpcsetup - import ( "bytes" "io" "reflect" "testing" - "github.com/consensys/gnark-crypto/ecc/bn254" - cs_bn254 "github.com/consensys/gnark/constraint/bn254" + + {{- template "import_curve" . }} + {{- template "import_backend_cs" . }} "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/stretchr/testify/require" @@ -25,10 +24,10 @@ func TestContributionSerialization(t *testing.T) { } var myCircuit Circuit - ccs, err := frontend.Compile(bn254.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) + ccs, err := frontend.Compile(curve.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) assert.NoError(err) - r1cs := ccs.(*cs_bn254.R1CS) + r1cs := ccs.(*cs.R1CS) // Phase 2 srs2, _ := InitPhase2(r1cs, &srs1) diff --git a/backend/groth16/mpcsetup/phase1.go b/internal/generator/backend/template/zkpschemes/groth16/mpcsetup/phase1.go.tmpl similarity index 89% rename from backend/groth16/mpcsetup/phase1.go rename to internal/generator/backend/template/zkpschemes/groth16/mpcsetup/phase1.go.tmpl index a49c2be0a1..7c8c6fa540 100644 --- a/backend/groth16/mpcsetup/phase1.go +++ b/internal/generator/backend/template/zkpschemes/groth16/mpcsetup/phase1.go.tmpl @@ -1,13 +1,12 @@ -package mpcsetup - import ( "crypto/sha256" "errors" "math" "math/big" - "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark-crypto/ecc/bn254/fr" + + {{- template "import_fr" . }} + {{- template "import_curve" . }} ) // Phase1 represents the Phase1 of the MPC described in @@ -17,13 +16,13 @@ import ( type Phase1 struct { Parameters struct { G1 struct { - Tau []bn254.G1Affine // {[τ⁰]₁, [τ¹]₁, [τ²]₁, …, [τ²ⁿ⁻²]₁} - AlphaTau []bn254.G1Affine // {α[τ⁰]₁, α[τ¹]₁, α[τ²]₁, …, α[τⁿ⁻¹]₁} - BetaTau []bn254.G1Affine // {β[τ⁰]₁, β[τ¹]₁, β[τ²]₁, …, β[τⁿ⁻¹]₁} + Tau []curve.G1Affine // {[τ⁰]₁, [τ¹]₁, [τ²]₁, …, [τ²ⁿ⁻²]₁} + AlphaTau []curve.G1Affine // {α[τ⁰]₁, α[τ¹]₁, α[τ²]₁, …, α[τⁿ⁻¹]₁} + BetaTau []curve.G1Affine // {β[τ⁰]₁, β[τ¹]₁, β[τ²]₁, …, β[τⁿ⁻¹]₁} } G2 struct { - Tau []bn254.G2Affine // {[τ⁰]₂, [τ¹]₂, [τ²]₂, …, [τⁿ⁻¹]₂} - Beta bn254.G2Affine // [β]₂ + Tau []curve.G2Affine // {[τ⁰]₂, [τ¹]₂, [τ²]₂, …, [τⁿ⁻¹]₂} + Beta curve.G2Affine // [β]₂ } } PublicKeys struct { @@ -47,12 +46,12 @@ func InitPhase1(power int) (phase1 Phase1) { phase1.PublicKeys.Beta = newPublicKey(beta, nil, 3) // First contribution use generators - _, _, g1, g2 := bn254.Generators() + _, _, g1, g2 := curve.Generators() phase1.Parameters.G2.Beta.Set(&g2) - phase1.Parameters.G1.Tau = make([]bn254.G1Affine, 2*N-1) - phase1.Parameters.G2.Tau = make([]bn254.G2Affine, N) - phase1.Parameters.G1.AlphaTau = make([]bn254.G1Affine, N) - phase1.Parameters.G1.BetaTau = make([]bn254.G1Affine, N) + phase1.Parameters.G1.Tau = make([]curve.G1Affine, 2*N-1) + phase1.Parameters.G2.Tau = make([]curve.G2Affine, N) + phase1.Parameters.G1.AlphaTau = make([]curve.G1Affine, N) + phase1.Parameters.G1.BetaTau = make([]curve.G1Affine, N) for i := 0; i < len(phase1.Parameters.G1.Tau); i++ { phase1.Parameters.G1.Tau[i].Set(&g1) } @@ -152,7 +151,7 @@ func verifyPhase1(current, contribution *Phase1) error { } // Check for valid updates using powers of τ - _, _, g1, g2 := bn254.Generators() + _, _, g1, g2 := curve.Generators() tauL1, tauL2 := linearCombinationG1(contribution.Parameters.G1.Tau) if !sameRatio(tauL1, tauL2, contribution.Parameters.G2.Tau[1], g2) { return errors.New("couldn't verify valid powers of τ in G₁") diff --git a/backend/groth16/mpcsetup/phase2.go b/internal/generator/backend/template/zkpschemes/groth16/mpcsetup/phase2.go.tmpl similarity index 85% rename from backend/groth16/mpcsetup/phase2.go rename to internal/generator/backend/template/zkpschemes/groth16/mpcsetup/phase2.go.tmpl index b6792a9c1b..af16b6d8fa 100644 --- a/backend/groth16/mpcsetup/phase2.go +++ b/internal/generator/backend/template/zkpschemes/groth16/mpcsetup/phase2.go.tmpl @@ -1,33 +1,33 @@ -package mpcsetup - import ( "crypto/sha256" "errors" "math/big" - "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark/constraint" - cs "github.com/consensys/gnark/constraint/bn254" + + + {{- template "import_fr" . }} + {{- template "import_curve" . }} + {{- template "import_backend_cs" . }} ) type Phase2Evaluations struct { G1 struct { - A, B, VKK []bn254.G1Affine + A, B, VKK []curve.G1Affine } G2 struct { - B []bn254.G2Affine + B []curve.G2Affine } } type Phase2 struct { Parameters struct { G1 struct { - Delta bn254.G1Affine - L, Z []bn254.G1Affine + Delta curve.G1Affine + L, Z []curve.G1Affine } G2 struct { - Delta bn254.G2Affine + Delta curve.G2Affine } } PublicKey PublicKey @@ -43,7 +43,7 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { c2 := Phase2{} - accumulateG1 := func(res *bn254.G1Affine, t constraint.Term, value *bn254.G1Affine) { + accumulateG1 := func(res *curve.G1Affine, t constraint.Term, value *curve.G1Affine) { cID := t.CoeffID() switch cID { case constraint.CoeffIdZero: @@ -55,7 +55,7 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { case constraint.CoeffIdTwo: res.Add(res, value).Add(res, value) default: - var tmp bn254.G1Affine + var tmp curve.G1Affine var vBi big.Int r1cs.Coefficients[cID].BigInt(&vBi) tmp.ScalarMultiplication(value, &vBi) @@ -63,7 +63,7 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { } } - accumulateG2 := func(res *bn254.G2Affine, t constraint.Term, value *bn254.G2Affine) { + accumulateG2 := func(res *curve.G2Affine, t constraint.Term, value *curve.G2Affine) { cID := t.CoeffID() switch cID { case constraint.CoeffIdZero: @@ -75,7 +75,7 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { case constraint.CoeffIdTwo: res.Add(res, value).Add(res, value) default: - var tmp bn254.G2Affine + var tmp curve.G2Affine var vBi big.Int r1cs.Coefficients[cID].BigInt(&vBi) tmp.ScalarMultiplication(value, &vBi) @@ -92,12 +92,12 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { internal, secret, public := r1cs.GetNbVariables() nWires := internal + secret + public var evals Phase2Evaluations - evals.G1.A = make([]bn254.G1Affine, nWires) - evals.G1.B = make([]bn254.G1Affine, nWires) - evals.G2.B = make([]bn254.G2Affine, nWires) - bA := make([]bn254.G1Affine, nWires) - aB := make([]bn254.G1Affine, nWires) - C := make([]bn254.G1Affine, nWires) + evals.G1.A = make([]curve.G1Affine, nWires) + evals.G1.B = make([]curve.G1Affine, nWires) + evals.G2.B = make([]curve.G2Affine, nWires) + bA := make([]curve.G1Affine, nWires) + aB := make([]curve.G1Affine, nWires) + C := make([]curve.G1Affine, nWires) for i, c := range r1cs.Constraints { // A for _, t := range c.L { @@ -117,14 +117,14 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { } // Prepare default contribution - _, _, g1, g2 := bn254.Generators() + _, _, g1, g2 := curve.Generators() c2.Parameters.G1.Delta = g1 c2.Parameters.G2.Delta = g2 // Build Z in PK as τⁱ(τⁿ - 1) = τ⁽ⁱ⁺ⁿ⁾ - τⁱ for i ∈ [0, n-2] // τⁱ(τⁿ - 1) = τ⁽ⁱ⁺ⁿ⁾ - τⁱ for i ∈ [0, n-2] n := len(srs.G1.AlphaTau) - c2.Parameters.G1.Z = make([]bn254.G1Affine, n) + c2.Parameters.G1.Z = make([]curve.G1Affine, n) for i := 0; i < n-1; i++ { c2.Parameters.G1.Z[i].Sub(&srs.G1.Tau[i+n], &srs.G1.Tau[i]) } @@ -133,11 +133,11 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { // Evaluate L nPrivate := internal + secret - c2.Parameters.G1.L = make([]bn254.G1Affine, nPrivate) - evals.G1.VKK = make([]bn254.G1Affine, public) + c2.Parameters.G1.L = make([]curve.G1Affine, nPrivate) + evals.G1.VKK = make([]curve.G1Affine, public) offset := public for i := 0; i < nWires; i++ { - var tmp bn254.G1Affine + var tmp curve.G1Affine tmp.Add(&bA[i], &aB[i]) tmp.Add(&tmp, &C[i]) if i < public { diff --git a/backend/groth16/mpcsetup/setup.go b/internal/generator/backend/template/zkpschemes/groth16/mpcsetup/setup.go.tmpl similarity index 83% rename from backend/groth16/mpcsetup/setup.go rename to internal/generator/backend/template/zkpschemes/groth16/mpcsetup/setup.go.tmpl index b0d439aa32..e60410b467 100644 --- a/backend/groth16/mpcsetup/setup.go +++ b/internal/generator/backend/template/zkpschemes/groth16/mpcsetup/setup.go.tmpl @@ -1,13 +1,12 @@ -package mpcsetup - import ( - "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" - groth16 "github.com/consensys/gnark/backend/groth16/bn254" + groth16 "github.com/consensys/gnark/backend/groth16/{{toLower .Curve}}" + + {{- template "import_curve" . }} + {{- template "import_fft" . }} ) func ExtractKeys(srs1 *Phase1, srs2 *Phase2, evals *Phase2Evaluations, nConstraints int) (pk groth16.ProvingKey, vk groth16.VerifyingKey) { - _, _, _, g2 := bn254.Generators() + _, _, _, g2 := curve.Generators() // Initialize PK pk.Domain = *fft.NewDomain(uint64(nConstraints)) @@ -24,7 +23,7 @@ func ExtractKeys(srs1 *Phase1, srs2 *Phase2, evals *Phase2Evaluations, nConstrai // Filter out infinity points nWires := len(evals.G1.A) pk.InfinityA = make([]bool, nWires) - A := make([]bn254.G1Affine, nWires) + A := make([]curve.G1Affine, nWires) j := 0 for i, e := range evals.G1.A { if e.IsInfinity() { @@ -38,7 +37,7 @@ func ExtractKeys(srs1 *Phase1, srs2 *Phase2, evals *Phase2Evaluations, nConstrai pk.NbInfinityA = uint64(nWires - j) pk.InfinityB = make([]bool, nWires) - B := make([]bn254.G1Affine, nWires) + B := make([]curve.G1Affine, nWires) j = 0 for i, e := range evals.G1.B { if e.IsInfinity() { @@ -51,7 +50,7 @@ func ExtractKeys(srs1 *Phase1, srs2 *Phase2, evals *Phase2Evaluations, nConstrai pk.G1.B = B[:j] pk.NbInfinityB = uint64(nWires - j) - B2 := make([]bn254.G2Affine, nWires) + B2 := make([]curve.G2Affine, nWires) j = 0 for i, e := range evals.G2.B { if e.IsInfinity() { diff --git a/backend/groth16/mpcsetup/setup_test.go b/internal/generator/backend/template/zkpschemes/groth16/mpcsetup/setup_test.go.tmpl similarity index 86% rename from backend/groth16/mpcsetup/setup_test.go rename to internal/generator/backend/template/zkpschemes/groth16/mpcsetup/setup_test.go.tmpl index e816c147a6..a36c0c1b9d 100644 --- a/backend/groth16/mpcsetup/setup_test.go +++ b/internal/generator/backend/template/zkpschemes/groth16/mpcsetup/setup_test.go.tmpl @@ -1,18 +1,25 @@ -package mpcsetup - import ( "testing" - "github.com/consensys/gnark-crypto/ecc/bn254" + {{- template "import_fr" . }} + {{- template "import_curve" . }} + {{- template "import_backend_cs" . }} + "github.com/consensys/gnark/backend/groth16" - cs "github.com/consensys/gnark/constraint/bn254" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/consensys/gnark/std/hash/mimc" "github.com/stretchr/testify/require" + + native_mimc "github.com/consensys/gnark-crypto/ecc/{{toLower .Curve}}/fr/mimc" ) func TestSetupCircuit(t *testing.T) { + {{- if ne (toLower .Curve) "bn254" }} + if testing.Short() { + t.Skip() + } + {{- end}} const ( nContributionsPhase1 = 3 nContributionsPhase2 = 3 @@ -35,7 +42,7 @@ func TestSetupCircuit(t *testing.T) { // Compile the circuit var myCircuit Circuit - ccs, err := frontend.Compile(bn254.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) + ccs, err := frontend.Compile(curve.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) assert.NoError(err) var evals Phase2Evaluations @@ -58,11 +65,14 @@ func TestSetupCircuit(t *testing.T) { pk, vk := ExtractKeys(&srs1, &srs2, &evals, ccs.GetNbConstraints()) // Build the witness - assignment := &Circuit{ - PreImage: "16130099170765464552823636852555369511329944820189892919423002775646948828469", - Hash: "12886436712380113721405259596386800092738845035233065858332878701083870690753", + var preImage, hash fr.Element + { + m := native_mimc.NewMiMC() + m.Write(preImage.Marshal()) + hash.SetBytes(m.Sum(nil)) } - witness, err := frontend.NewWitness(assignment, bn254.ID.ScalarField()) + + witness, err := frontend.NewWitness(&Circuit{PreImage: preImage, Hash: hash}, curve.ID.ScalarField()) assert.NoError(err) pubWitness, err := witness.Public() @@ -102,7 +112,7 @@ func BenchmarkPhase2(b *testing.B) { srs1.Contribute() var myCircuit Circuit - ccs, err := frontend.Compile(bn254.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) + ccs, err := frontend.Compile(curve.ID.ScalarField(), r1cs.NewBuilder, &myCircuit) if err != nil { b.Fatal(err) } diff --git a/backend/groth16/mpcsetup/utils.go b/internal/generator/backend/template/zkpschemes/groth16/mpcsetup/utils.go.tmpl similarity index 76% rename from backend/groth16/mpcsetup/utils.go rename to internal/generator/backend/template/zkpschemes/groth16/mpcsetup/utils.go.tmpl index a4ee4eafc8..f7c67c036d 100644 --- a/backend/groth16/mpcsetup/utils.go +++ b/internal/generator/backend/template/zkpschemes/groth16/mpcsetup/utils.go.tmpl @@ -1,5 +1,3 @@ -package mpcsetup - import ( "bytes" "math/big" @@ -7,20 +5,21 @@ import ( "runtime" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark-crypto/ecc/bn254/fr" + + {{- template "import_fr" . }} + {{- template "import_curve" . }} "github.com/consensys/gnark/internal/utils" ) type PublicKey struct { - SG bn254.G1Affine - SXG bn254.G1Affine - XR bn254.G2Affine + SG curve.G1Affine + SXG curve.G1Affine + XR curve.G2Affine } func newPublicKey(x fr.Element, challenge []byte, dst byte) PublicKey { var pk PublicKey - _, _, g1, _ := bn254.Generators() + _, _, g1, _ := curve.Generators() var s fr.Element var sBi big.Int @@ -64,7 +63,7 @@ func powers(a fr.Element, n int) []fr.Element { } // Returns [aᵢAᵢ, ...] in G1 -func scaleG1InPlace(A []bn254.G1Affine, a []fr.Element) { +func scaleG1InPlace(A []curve.G1Affine, a []fr.Element) { utils.Parallelize(len(A), func(start, end int) { var tmp big.Int for i := start; i < end; i++ { @@ -75,7 +74,7 @@ func scaleG1InPlace(A []bn254.G1Affine, a []fr.Element) { } // Returns [aᵢAᵢ, ...] in G2 -func scaleG2InPlace(A []bn254.G2Affine, a []fr.Element) { +func scaleG2InPlace(A []curve.G2Affine, a []fr.Element) { utils.Parallelize(len(A), func(start, end int) { var tmp big.Int for i := start; i < end; i++ { @@ -86,15 +85,15 @@ func scaleG2InPlace(A []bn254.G2Affine, a []fr.Element) { } // Check e(a₁, a₂) = e(b₁, b₂) -func sameRatio(a1, b1 bn254.G1Affine, a2, b2 bn254.G2Affine) bool { +func sameRatio(a1, b1 curve.G1Affine, a2, b2 curve.G2Affine) bool { if !a1.IsInSubGroup() || !b1.IsInSubGroup() || !a2.IsInSubGroup() || !b2.IsInSubGroup() { panic("invalid point not in subgroup") } - var na2 bn254.G2Affine + var na2 curve.G2Affine na2.Neg(&a2) - res, err := bn254.PairingCheck( - []bn254.G1Affine{a1, b1}, - []bn254.G2Affine{na2, b2}) + res, err := curve.PairingCheck( + []curve.G1Affine{a1, b1}, + []curve.G2Affine{na2, b2}) if err != nil { panic(err) } @@ -102,7 +101,7 @@ func sameRatio(a1, b1 bn254.G1Affine, a2, b2 bn254.G2Affine) bool { } // returns a = ∑ rᵢAᵢ, b = ∑ rᵢBᵢ -func merge(A, B []bn254.G1Affine) (a, b bn254.G1Affine) { +func merge(A, B []curve.G1Affine) (a, b curve.G1Affine) { nc := runtime.NumCPU() r := make([]fr.Element, len(A)) for i := 0; i < len(A); i++ { @@ -114,7 +113,7 @@ func merge(A, B []bn254.G1Affine) (a, b bn254.G1Affine) { } // L1 = ∑ rᵢAᵢ, L2 = ∑ rᵢAᵢ₊₁ in G1 -func linearCombinationG1(A []bn254.G1Affine) (L1, L2 bn254.G1Affine) { +func linearCombinationG1(A []curve.G1Affine) (L1, L2 curve.G1Affine) { nc := runtime.NumCPU() n := len(A) r := make([]fr.Element, n-1) @@ -127,7 +126,7 @@ func linearCombinationG1(A []bn254.G1Affine) (L1, L2 bn254.G1Affine) { } // L1 = ∑ rᵢAᵢ, L2 = ∑ rᵢAᵢ₊₁ in G2 -func linearCombinationG2(A []bn254.G2Affine) (L1, L2 bn254.G2Affine) { +func linearCombinationG2(A []curve.G2Affine) (L1, L2 curve.G2Affine) { nc := runtime.NumCPU() n := len(A) r := make([]fr.Element, n-1) @@ -140,13 +139,13 @@ func linearCombinationG2(A []bn254.G2Affine) (L1, L2 bn254.G2Affine) { } // Generate R in G₂ as Hash(gˢ, gˢˣ, challenge, dst) -func genR(sG1, sxG1 bn254.G1Affine, challenge []byte, dst byte) bn254.G2Affine { +func genR(sG1, sxG1 curve.G1Affine, challenge []byte, dst byte) curve.G2Affine { var buf bytes.Buffer - buf.Grow(len(challenge) + bn254.SizeOfG1AffineUncompressed*2) + buf.Grow(len(challenge) + curve.SizeOfG1AffineUncompressed*2) buf.Write(sG1.Marshal()) buf.Write(sxG1.Marshal()) buf.Write(challenge) - spG2, err := bn254.HashToG2(buf.Bytes(), []byte{dst}) + spG2, err := curve.HashToG2(buf.Bytes(), []byte{dst}) if err != nil { panic(err) } From cccdc3536cec54fcc19f5a5e66ffd2d17d72d761 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 14 Mar 2023 12:05:38 +0100 Subject: [PATCH 114/464] feat: reintroduce hints for field emulation (#547) * feat: add calling hints to field emulation * fix: append solver options to prover options in tests Backend options were split into prover and solver options. Usually when running the prover we set the solver options using backend.WithSolverOptions. But in tests makes sense that if we set `test.WithSolverOptions` then these options are also applied to the solver when run by the prover. * refactor: dont need nativemod in emulated hint unwrapper * docs: add package documentation for emulation hints --- std/math/emulated/field_hint.go | 109 +++++++++++++++++++++++++ std/math/emulated/field_hint_test.go | 116 +++++++++++++++++++++++++++ test/options.go | 1 + 3 files changed, 226 insertions(+) create mode 100644 std/math/emulated/field_hint.go create mode 100644 std/math/emulated/field_hint_test.go diff --git a/std/math/emulated/field_hint.go b/std/math/emulated/field_hint.go new file mode 100644 index 0000000000..52b8e9ddfc --- /dev/null +++ b/std/math/emulated/field_hint.go @@ -0,0 +1,109 @@ +package emulated + +import ( + "fmt" + "math/big" + + "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/frontend" +) + +func (f *Field[T]) wrapHint(nonnativeInputs ...*Element[T]) []frontend.Variable { + res := []frontend.Variable{f.fParams.BitsPerLimb(), f.fParams.NbLimbs()} + res = append(res, f.Modulus().Limbs...) + res = append(res, len(nonnativeInputs)) + for i := range nonnativeInputs { + res = append(res, len(nonnativeInputs[i].Limbs)) + res = append(res, nonnativeInputs[i].Limbs...) + } + return res +} + +// UnwrapHint unwraps the native inputs into nonnative inputs. Then it calls +// nonnativeHint function with nonnative inputs. After nonnativeHint returns, it +// decomposes the outputs into limbs. +func UnwrapHint(nativeInputs, nativeOutputs []*big.Int, nonnativeHint solver.Hint) error { + if len(nativeInputs) < 2 { + return fmt.Errorf("hint wrapper header is 2 elements") + } + if !nativeInputs[0].IsInt64() || !nativeInputs[1].IsInt64() { + return fmt.Errorf("header must be castable to int64") + } + nbBits := int(nativeInputs[0].Int64()) + nbLimbs := int(nativeInputs[1].Int64()) + if len(nativeInputs) < 2+nbLimbs { + return fmt.Errorf("hint wrapper header is 2+nbLimbs elements") + } + nonnativeMod := new(big.Int) + if err := recompose(nativeInputs[2:2+nbLimbs], uint(nbBits), nonnativeMod); err != nil { + return fmt.Errorf("cannot recover nonnative mod: %w", err) + } + if !nativeInputs[2+nbLimbs].IsInt64() { + return fmt.Errorf("number of nonnative elements must be castable to int64") + } + nbInputs := int(nativeInputs[2+nbLimbs].Int64()) + nonnativeInputs := make([]*big.Int, nbInputs) + readPtr := 3 + nbLimbs + for i := 0; i < nbInputs; i++ { + if len(nativeInputs) < readPtr+1 { + return fmt.Errorf("can not read %d-th native input", i) + } + if !nativeInputs[readPtr].IsInt64() { + return fmt.Errorf("corrupted %d-th native input", i) + } + currentInputLen := int(nativeInputs[readPtr].Int64()) + if len(nativeInputs) < (readPtr + 1 + currentInputLen) { + return fmt.Errorf("cannot read %d-th nonnative element", i) + } + nonnativeInputs[i] = new(big.Int) + if err := recompose(nativeInputs[readPtr+1:readPtr+1+currentInputLen], uint(nbBits), nonnativeInputs[i]); err != nil { + return fmt.Errorf("recompose %d-th element: %w", i, err) + } + readPtr += 1 + currentInputLen + } + if len(nativeOutputs)%nbLimbs != 0 { + return fmt.Errorf("output count doesn't divide limb count") + } + nonnativeOutputs := make([]*big.Int, len(nativeOutputs)/nbLimbs) + for i := range nonnativeOutputs { + nonnativeOutputs[i] = new(big.Int) + } + if err := nonnativeHint(nonnativeMod, nonnativeInputs, nonnativeOutputs); err != nil { + return fmt.Errorf("nonnative hint: %w", err) + } + for i := range nonnativeOutputs { + nonnativeOutputs[i].Mod(nonnativeOutputs[i], nonnativeMod) + if err := decompose(nonnativeOutputs[i], uint(nbBits), nativeOutputs[i*nbLimbs:(i+1)*nbLimbs]); err != nil { + return fmt.Errorf("decompose %d-th element: %w", i, err) + } + } + return nil +} + +// NewHint allows to call the emulation hint function hf on inputs, expecting +// nbOutputs results. This function splits internally the emulated element into +// limbs and passes these to the hint function. There is [UnwrapHint] function +// which performs corresponding recomposition of limbs into integer values (and +// vice verse for output). +// +// The hint function for this method is defined as: +// +// func HintFn(mod *big.Int, inputs, outputs []*big.Int) error { +// return emulated.UnwrapHint(inputs, outputs, func(mod *big.Int, inputs, outputs []*big.Int) error { // NB we shadow initial input, output, mod to avoid accidental overwrite! +// // here all inputs and outputs are modulo nonnative mod. we decompose them automatically +// })} +// +// See the example for full written example. +func (f *Field[T]) NewHint(hf solver.Hint, nbOutputs int, inputs ...*Element[T]) ([]*Element[T], error) { + nativeInputs := f.wrapHint(inputs...) + nbNativeOutputs := int(f.fParams.NbLimbs()) * nbOutputs + nativeOutputs, err := f.api.Compiler().NewHint(hf, nbNativeOutputs, nativeInputs...) + if err != nil { + return nil, fmt.Errorf("call hint: %w", err) + } + outputs := make([]*Element[T], nbOutputs) + for i := 0; i < nbOutputs; i++ { + outputs[i] = f.packLimbs(nativeOutputs[i*int(f.fParams.NbLimbs()):(i+1)*int(f.fParams.NbLimbs())], true) + } + return outputs, nil +} diff --git a/std/math/emulated/field_hint_test.go b/std/math/emulated/field_hint_test.go new file mode 100644 index 0000000000..9f2d286ec8 --- /dev/null +++ b/std/math/emulated/field_hint_test.go @@ -0,0 +1,116 @@ +package emulated_test + +import ( + "fmt" + "math/big" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/groth16" + "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/std/math/emulated" +) + +// HintExample is a hint for field emulation which returns the division of the +// first and second input. +func HintExample(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + // nativeInputs are the limbs of the input non-native elements. We wrap the + // actual hint function with [emulated.UnwrapHint] to get actual [*big.Int] + // values of the non-native elements. + return emulated.UnwrapHint(nativeInputs, nativeOutputs, func(mod *big.Int, inputs, outputs []*big.Int) error { + // this hint computes the division of first and second input and returns it. + nominator := inputs[0] + denominator := inputs[1] + res := new(big.Int).ModInverse(denominator, mod) + if res == nil { + return fmt.Errorf("no modular inverse") + } + res.Mul(res, nominator) + res.Mod(res, mod) + outputs[0].Set(res) + return nil + }) + // when the internal hint function returns, the UnwrapHint function + // decomposes the non-native value into limbs. +} + +type emulationHintCircuit[T emulated.FieldParams] struct { + Nominator emulated.Element[T] + Denominator emulated.Element[T] + Expected emulated.Element[T] +} + +func (c *emulationHintCircuit[T]) Define(api frontend.API) error { + field, err := emulated.NewField[T](api) + if err != nil { + return err + } + res, err := field.NewHint(HintExample, 1, &c.Nominator, &c.Denominator) + if err != nil { + return err + } + m := field.Mul(res[0], &c.Denominator) + field.AssertIsEqual(m, &c.Nominator) + field.AssertIsEqual(res[0], &c.Expected) + return nil +} + +// Example of using hints with emulated elements. +func ExampleField_NewHint() { + var a, b, c fr.Element + a.SetRandom() + b.SetRandom() + c.Div(&a, &b) + + circuit := emulationHintCircuit[emulated.BN254Fr]{} + witness := emulationHintCircuit[emulated.BN254Fr]{ + Nominator: emulated.ValueOf[emulated.BN254Fr](a), + Denominator: emulated.ValueOf[emulated.BN254Fr](b), + Expected: emulated.ValueOf[emulated.BN254Fr](c), + } + ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) + if err != nil { + panic(err) + } else { + fmt.Println("compiled") + } + witnessData, err := frontend.NewWitness(&witness, ecc.BN254.ScalarField()) + if err != nil { + panic(err) + } else { + fmt.Println("secret witness parsed") + } + publicWitnessData, err := witnessData.Public() + if err != nil { + panic(err) + } else { + fmt.Println("public witness parsed") + } + pk, vk, err := groth16.Setup(ccs) + if err != nil { + panic(err) + } else { + fmt.Println("setup done") + } + proof, err := groth16.Prove(ccs, pk, witnessData, backend.WithSolverOptions(solver.WithHints(HintExample))) + if err != nil { + panic(err) + } else { + fmt.Println("proved") + } + err = groth16.Verify(proof, vk, publicWitnessData) + if err != nil { + panic(err) + } else { + fmt.Println("verified") + } + // Output: compiled + // secret witness parsed + // public witness parsed + // setup done + // proved + // verified +} diff --git a/test/options.go b/test/options.go index c40104b886..00ca2924a2 100644 --- a/test/options.go +++ b/test/options.go @@ -89,6 +89,7 @@ func WithProverOpts(proverOpts ...backend.ProverOption) TestingOption { // calling constraint system solver. func WithSolverOpts(solverOpts ...solver.Option) TestingOption { return func(opt *testingConfig) error { + opt.proverOpts = append(opt.proverOpts, backend.WithSolverOptions(solverOpts...)) opt.solverOpts = solverOpts return nil } From 0814ececd22bc2b3e709d4b4ad934c650d19ff90 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Tue, 14 Mar 2023 08:37:59 -0500 Subject: [PATCH 115/464] refactor: expose all typed backends in gnark/backend (moved from internal/) (#561) --- .../groth16/bls12-377}/commitment.go | 0 .../groth16/bls12-377}/commitment_test.go | 0 .../groth16/bls12-377}/marshal.go | 0 .../groth16/bls12-377}/marshal_test.go | 0 .../groth16/bls12-377}/prove.go | 0 .../groth16/bls12-377}/setup.go | 0 .../groth16/bls12-377}/verify.go | 0 .../groth16/bls12-381}/commitment.go | 0 .../groth16/bls12-381}/commitment_test.go | 0 .../groth16/bls12-381}/marshal.go | 0 .../groth16/bls12-381}/marshal_test.go | 0 .../groth16/bls12-381}/prove.go | 0 .../groth16/bls12-381}/setup.go | 0 .../groth16/bls12-381}/verify.go | 0 .../groth16/bls24-315}/commitment.go | 0 .../groth16/bls24-315}/commitment_test.go | 0 .../groth16/bls24-315}/marshal.go | 0 .../groth16/bls24-315}/marshal_test.go | 0 .../groth16/bls24-315}/prove.go | 0 .../groth16/bls24-315}/setup.go | 0 .../groth16/bls24-315}/verify.go | 0 .../groth16/bls24-317}/commitment.go | 0 .../groth16/bls24-317}/commitment_test.go | 0 .../groth16/bls24-317}/marshal.go | 0 .../groth16/bls24-317}/marshal_test.go | 0 .../groth16/bls24-317}/prove.go | 0 .../groth16/bls24-317}/setup.go | 0 .../groth16/bls24-317}/verify.go | 0 .../groth16/bn254}/commitment.go | 0 .../groth16/bn254}/commitment_test.go | 0 .../groth16/bn254}/marshal.go | 0 .../groth16/bn254}/marshal_test.go | 0 .../groth16/bn254}/prove.go | 0 .../groth16/bn254}/setup.go | 0 .../groth16/bn254}/solidity.go | 0 .../groth16/bn254}/utils_test.go | 0 .../groth16/bn254}/verify.go | 0 .../groth16/bw6-633}/commitment.go | 0 .../groth16/bw6-633}/commitment_test.go | 0 .../groth16/bw6-633}/marshal.go | 0 .../groth16/bw6-633}/marshal_test.go | 0 .../groth16/bw6-633}/prove.go | 0 .../groth16/bw6-633}/setup.go | 0 .../groth16/bw6-633}/verify.go | 0 .../groth16/bw6-761}/commitment.go | 0 .../groth16/bw6-761}/commitment_test.go | 0 .../groth16/bw6-761}/marshal.go | 0 .../groth16/bw6-761}/marshal_test.go | 0 .../groth16/bw6-761}/prove.go | 0 .../groth16/bw6-761}/setup.go | 0 .../groth16/bw6-761}/verify.go | 0 backend/groth16/groth16.go | 14 ++++---- .../plonk/bls12-377}/marshal.go | 0 .../plonk/bls12-377}/marshal_test.go | 0 .../plonk/bls12-377}/prove.go | 0 .../plonk/bls12-377}/setup.go | 0 .../plonk/bls12-377}/verify.go | 0 .../plonk/bls12-381}/marshal.go | 0 .../plonk/bls12-381}/marshal_test.go | 0 .../plonk/bls12-381}/prove.go | 0 .../plonk/bls12-381}/setup.go | 0 .../plonk/bls12-381}/verify.go | 0 .../plonk/bls24-315}/marshal.go | 0 .../plonk/bls24-315}/marshal_test.go | 0 .../plonk/bls24-315}/prove.go | 0 .../plonk/bls24-315}/setup.go | 0 .../plonk/bls24-315}/verify.go | 0 .../plonk/bls24-317}/marshal.go | 0 .../plonk/bls24-317}/marshal_test.go | 0 .../plonk/bls24-317}/prove.go | 0 .../plonk/bls24-317}/setup.go | 0 .../plonk/bls24-317}/verify.go | 0 .../plonk => backend/plonk/bn254}/marshal.go | 0 .../plonk/bn254}/marshal_test.go | 0 .../plonk => backend/plonk/bn254}/prove.go | 0 .../plonk => backend/plonk/bn254}/setup.go | 0 .../plonk => backend/plonk/bn254}/solidity.go | 0 .../plonk => backend/plonk/bn254}/verify.go | 0 .../plonk/bw6-633}/marshal.go | 0 .../plonk/bw6-633}/marshal_test.go | 0 .../plonk => backend/plonk/bw6-633}/prove.go | 0 .../plonk => backend/plonk/bw6-633}/setup.go | 0 .../plonk => backend/plonk/bw6-633}/verify.go | 0 .../plonk/bw6-761}/marshal.go | 0 .../plonk/bw6-761}/marshal_test.go | 0 .../plonk => backend/plonk/bw6-761}/prove.go | 0 .../plonk => backend/plonk/bw6-761}/setup.go | 0 .../plonk => backend/plonk/bw6-761}/verify.go | 0 backend/plonk/plonk.go | 14 ++++---- .../plonkfri/bls12-377}/prove.go | 0 .../plonkfri/bls12-377}/setup.go | 0 .../plonkfri/bls12-377}/verify.go | 0 .../plonkfri/bls12-381}/prove.go | 0 .../plonkfri/bls12-381}/setup.go | 0 .../plonkfri/bls12-381}/verify.go | 0 .../plonkfri/bls24-315}/prove.go | 0 .../plonkfri/bls24-315}/setup.go | 0 .../plonkfri/bls24-315}/verify.go | 0 .../plonkfri/bls24-317}/prove.go | 0 .../plonkfri/bls24-317}/setup.go | 0 .../plonkfri/bls24-317}/verify.go | 0 .../plonkfri/bn254}/prove.go | 0 .../plonkfri/bn254}/setup.go | 0 .../plonkfri/bn254}/verify.go | 0 .../plonkfri/bw6-633}/prove.go | 0 .../plonkfri/bw6-633}/setup.go | 0 .../plonkfri/bw6-633}/verify.go | 0 .../plonkfri/bw6-761}/prove.go | 0 .../plonkfri/bw6-761}/setup.go | 0 .../plonkfri/bw6-761}/verify.go | 0 backend/plonkfri/plonkfri.go | 15 ++++----- internal/generator/backend/main.go | 32 ++++++++++--------- std/groth16_bls12377/verifier.go | 2 +- std/groth16_bls12377/verifier_test.go | 2 +- std/groth16_bls24315/verifier.go | 2 +- std/groth16_bls24315/verifier_test.go | 2 +- 116 files changed, 42 insertions(+), 41 deletions(-) rename {internal/backend/bls12-377/groth16 => backend/groth16/bls12-377}/commitment.go (100%) rename {internal/backend/bls12-377/groth16 => backend/groth16/bls12-377}/commitment_test.go (100%) rename {internal/backend/bls12-377/groth16 => backend/groth16/bls12-377}/marshal.go (100%) rename {internal/backend/bls12-377/groth16 => backend/groth16/bls12-377}/marshal_test.go (100%) rename {internal/backend/bls12-377/groth16 => backend/groth16/bls12-377}/prove.go (100%) rename {internal/backend/bls12-377/groth16 => backend/groth16/bls12-377}/setup.go (100%) rename {internal/backend/bls12-377/groth16 => backend/groth16/bls12-377}/verify.go (100%) rename {internal/backend/bls12-381/groth16 => backend/groth16/bls12-381}/commitment.go (100%) rename {internal/backend/bls12-381/groth16 => backend/groth16/bls12-381}/commitment_test.go (100%) rename {internal/backend/bls12-381/groth16 => backend/groth16/bls12-381}/marshal.go (100%) rename {internal/backend/bls12-381/groth16 => backend/groth16/bls12-381}/marshal_test.go (100%) rename {internal/backend/bls12-381/groth16 => backend/groth16/bls12-381}/prove.go (100%) rename {internal/backend/bls12-381/groth16 => backend/groth16/bls12-381}/setup.go (100%) rename {internal/backend/bls12-381/groth16 => backend/groth16/bls12-381}/verify.go (100%) rename {internal/backend/bls24-315/groth16 => backend/groth16/bls24-315}/commitment.go (100%) rename {internal/backend/bls24-315/groth16 => backend/groth16/bls24-315}/commitment_test.go (100%) rename {internal/backend/bls24-315/groth16 => backend/groth16/bls24-315}/marshal.go (100%) rename {internal/backend/bls24-315/groth16 => backend/groth16/bls24-315}/marshal_test.go (100%) rename {internal/backend/bls24-315/groth16 => backend/groth16/bls24-315}/prove.go (100%) rename {internal/backend/bls24-315/groth16 => backend/groth16/bls24-315}/setup.go (100%) rename {internal/backend/bls24-315/groth16 => backend/groth16/bls24-315}/verify.go (100%) rename {internal/backend/bls24-317/groth16 => backend/groth16/bls24-317}/commitment.go (100%) rename {internal/backend/bls24-317/groth16 => backend/groth16/bls24-317}/commitment_test.go (100%) rename {internal/backend/bls24-317/groth16 => backend/groth16/bls24-317}/marshal.go (100%) rename {internal/backend/bls24-317/groth16 => backend/groth16/bls24-317}/marshal_test.go (100%) rename {internal/backend/bls24-317/groth16 => backend/groth16/bls24-317}/prove.go (100%) rename {internal/backend/bls24-317/groth16 => backend/groth16/bls24-317}/setup.go (100%) rename {internal/backend/bls24-317/groth16 => backend/groth16/bls24-317}/verify.go (100%) rename {internal/backend/bn254/groth16 => backend/groth16/bn254}/commitment.go (100%) rename {internal/backend/bn254/groth16 => backend/groth16/bn254}/commitment_test.go (100%) rename {internal/backend/bn254/groth16 => backend/groth16/bn254}/marshal.go (100%) rename {internal/backend/bn254/groth16 => backend/groth16/bn254}/marshal_test.go (100%) rename {internal/backend/bn254/groth16 => backend/groth16/bn254}/prove.go (100%) rename {internal/backend/bn254/groth16 => backend/groth16/bn254}/setup.go (100%) rename {internal/backend/bn254/groth16 => backend/groth16/bn254}/solidity.go (100%) rename {internal/backend/bn254/groth16 => backend/groth16/bn254}/utils_test.go (100%) rename {internal/backend/bn254/groth16 => backend/groth16/bn254}/verify.go (100%) rename {internal/backend/bw6-633/groth16 => backend/groth16/bw6-633}/commitment.go (100%) rename {internal/backend/bw6-633/groth16 => backend/groth16/bw6-633}/commitment_test.go (100%) rename {internal/backend/bw6-633/groth16 => backend/groth16/bw6-633}/marshal.go (100%) rename {internal/backend/bw6-633/groth16 => backend/groth16/bw6-633}/marshal_test.go (100%) rename {internal/backend/bw6-633/groth16 => backend/groth16/bw6-633}/prove.go (100%) rename {internal/backend/bw6-633/groth16 => backend/groth16/bw6-633}/setup.go (100%) rename {internal/backend/bw6-633/groth16 => backend/groth16/bw6-633}/verify.go (100%) rename {internal/backend/bw6-761/groth16 => backend/groth16/bw6-761}/commitment.go (100%) rename {internal/backend/bw6-761/groth16 => backend/groth16/bw6-761}/commitment_test.go (100%) rename {internal/backend/bw6-761/groth16 => backend/groth16/bw6-761}/marshal.go (100%) rename {internal/backend/bw6-761/groth16 => backend/groth16/bw6-761}/marshal_test.go (100%) rename {internal/backend/bw6-761/groth16 => backend/groth16/bw6-761}/prove.go (100%) rename {internal/backend/bw6-761/groth16 => backend/groth16/bw6-761}/setup.go (100%) rename {internal/backend/bw6-761/groth16 => backend/groth16/bw6-761}/verify.go (100%) rename {internal/backend/bls12-377/plonk => backend/plonk/bls12-377}/marshal.go (100%) rename {internal/backend/bls12-377/plonk => backend/plonk/bls12-377}/marshal_test.go (100%) rename {internal/backend/bls12-377/plonk => backend/plonk/bls12-377}/prove.go (100%) rename {internal/backend/bls12-377/plonk => backend/plonk/bls12-377}/setup.go (100%) rename {internal/backend/bls12-377/plonk => backend/plonk/bls12-377}/verify.go (100%) rename {internal/backend/bls12-381/plonk => backend/plonk/bls12-381}/marshal.go (100%) rename {internal/backend/bls12-381/plonk => backend/plonk/bls12-381}/marshal_test.go (100%) rename {internal/backend/bls12-381/plonk => backend/plonk/bls12-381}/prove.go (100%) rename {internal/backend/bls12-381/plonk => backend/plonk/bls12-381}/setup.go (100%) rename {internal/backend/bls12-381/plonk => backend/plonk/bls12-381}/verify.go (100%) rename {internal/backend/bls24-315/plonk => backend/plonk/bls24-315}/marshal.go (100%) rename {internal/backend/bls24-315/plonk => backend/plonk/bls24-315}/marshal_test.go (100%) rename {internal/backend/bls24-315/plonk => backend/plonk/bls24-315}/prove.go (100%) rename {internal/backend/bls24-315/plonk => backend/plonk/bls24-315}/setup.go (100%) rename {internal/backend/bls24-315/plonk => backend/plonk/bls24-315}/verify.go (100%) rename {internal/backend/bls24-317/plonk => backend/plonk/bls24-317}/marshal.go (100%) rename {internal/backend/bls24-317/plonk => backend/plonk/bls24-317}/marshal_test.go (100%) rename {internal/backend/bls24-317/plonk => backend/plonk/bls24-317}/prove.go (100%) rename {internal/backend/bls24-317/plonk => backend/plonk/bls24-317}/setup.go (100%) rename {internal/backend/bls24-317/plonk => backend/plonk/bls24-317}/verify.go (100%) rename {internal/backend/bn254/plonk => backend/plonk/bn254}/marshal.go (100%) rename {internal/backend/bn254/plonk => backend/plonk/bn254}/marshal_test.go (100%) rename {internal/backend/bn254/plonk => backend/plonk/bn254}/prove.go (100%) rename {internal/backend/bn254/plonk => backend/plonk/bn254}/setup.go (100%) rename {internal/backend/bn254/plonk => backend/plonk/bn254}/solidity.go (100%) rename {internal/backend/bn254/plonk => backend/plonk/bn254}/verify.go (100%) rename {internal/backend/bw6-633/plonk => backend/plonk/bw6-633}/marshal.go (100%) rename {internal/backend/bw6-633/plonk => backend/plonk/bw6-633}/marshal_test.go (100%) rename {internal/backend/bw6-633/plonk => backend/plonk/bw6-633}/prove.go (100%) rename {internal/backend/bw6-633/plonk => backend/plonk/bw6-633}/setup.go (100%) rename {internal/backend/bw6-633/plonk => backend/plonk/bw6-633}/verify.go (100%) rename {internal/backend/bw6-761/plonk => backend/plonk/bw6-761}/marshal.go (100%) rename {internal/backend/bw6-761/plonk => backend/plonk/bw6-761}/marshal_test.go (100%) rename {internal/backend/bw6-761/plonk => backend/plonk/bw6-761}/prove.go (100%) rename {internal/backend/bw6-761/plonk => backend/plonk/bw6-761}/setup.go (100%) rename {internal/backend/bw6-761/plonk => backend/plonk/bw6-761}/verify.go (100%) rename {internal/backend/bls12-377/plonkfri => backend/plonkfri/bls12-377}/prove.go (100%) rename {internal/backend/bls12-377/plonkfri => backend/plonkfri/bls12-377}/setup.go (100%) rename {internal/backend/bls12-377/plonkfri => backend/plonkfri/bls12-377}/verify.go (100%) rename {internal/backend/bls12-381/plonkfri => backend/plonkfri/bls12-381}/prove.go (100%) rename {internal/backend/bls12-381/plonkfri => backend/plonkfri/bls12-381}/setup.go (100%) rename {internal/backend/bls12-381/plonkfri => backend/plonkfri/bls12-381}/verify.go (100%) rename {internal/backend/bls24-315/plonkfri => backend/plonkfri/bls24-315}/prove.go (100%) rename {internal/backend/bls24-315/plonkfri => backend/plonkfri/bls24-315}/setup.go (100%) rename {internal/backend/bls24-315/plonkfri => backend/plonkfri/bls24-315}/verify.go (100%) rename {internal/backend/bls24-317/plonkfri => backend/plonkfri/bls24-317}/prove.go (100%) rename {internal/backend/bls24-317/plonkfri => backend/plonkfri/bls24-317}/setup.go (100%) rename {internal/backend/bls24-317/plonkfri => backend/plonkfri/bls24-317}/verify.go (100%) rename {internal/backend/bn254/plonkfri => backend/plonkfri/bn254}/prove.go (100%) rename {internal/backend/bn254/plonkfri => backend/plonkfri/bn254}/setup.go (100%) rename {internal/backend/bn254/plonkfri => backend/plonkfri/bn254}/verify.go (100%) rename {internal/backend/bw6-633/plonkfri => backend/plonkfri/bw6-633}/prove.go (100%) rename {internal/backend/bw6-633/plonkfri => backend/plonkfri/bw6-633}/setup.go (100%) rename {internal/backend/bw6-633/plonkfri => backend/plonkfri/bw6-633}/verify.go (100%) rename {internal/backend/bw6-761/plonkfri => backend/plonkfri/bw6-761}/prove.go (100%) rename {internal/backend/bw6-761/plonkfri => backend/plonkfri/bw6-761}/setup.go (100%) rename {internal/backend/bw6-761/plonkfri => backend/plonkfri/bw6-761}/verify.go (100%) diff --git a/internal/backend/bls12-377/groth16/commitment.go b/backend/groth16/bls12-377/commitment.go similarity index 100% rename from internal/backend/bls12-377/groth16/commitment.go rename to backend/groth16/bls12-377/commitment.go diff --git a/internal/backend/bls12-377/groth16/commitment_test.go b/backend/groth16/bls12-377/commitment_test.go similarity index 100% rename from internal/backend/bls12-377/groth16/commitment_test.go rename to backend/groth16/bls12-377/commitment_test.go diff --git a/internal/backend/bls12-377/groth16/marshal.go b/backend/groth16/bls12-377/marshal.go similarity index 100% rename from internal/backend/bls12-377/groth16/marshal.go rename to backend/groth16/bls12-377/marshal.go diff --git a/internal/backend/bls12-377/groth16/marshal_test.go b/backend/groth16/bls12-377/marshal_test.go similarity index 100% rename from internal/backend/bls12-377/groth16/marshal_test.go rename to backend/groth16/bls12-377/marshal_test.go diff --git a/internal/backend/bls12-377/groth16/prove.go b/backend/groth16/bls12-377/prove.go similarity index 100% rename from internal/backend/bls12-377/groth16/prove.go rename to backend/groth16/bls12-377/prove.go diff --git a/internal/backend/bls12-377/groth16/setup.go b/backend/groth16/bls12-377/setup.go similarity index 100% rename from internal/backend/bls12-377/groth16/setup.go rename to backend/groth16/bls12-377/setup.go diff --git a/internal/backend/bls12-377/groth16/verify.go b/backend/groth16/bls12-377/verify.go similarity index 100% rename from internal/backend/bls12-377/groth16/verify.go rename to backend/groth16/bls12-377/verify.go diff --git a/internal/backend/bls12-381/groth16/commitment.go b/backend/groth16/bls12-381/commitment.go similarity index 100% rename from internal/backend/bls12-381/groth16/commitment.go rename to backend/groth16/bls12-381/commitment.go diff --git a/internal/backend/bls12-381/groth16/commitment_test.go b/backend/groth16/bls12-381/commitment_test.go similarity index 100% rename from internal/backend/bls12-381/groth16/commitment_test.go rename to backend/groth16/bls12-381/commitment_test.go diff --git a/internal/backend/bls12-381/groth16/marshal.go b/backend/groth16/bls12-381/marshal.go similarity index 100% rename from internal/backend/bls12-381/groth16/marshal.go rename to backend/groth16/bls12-381/marshal.go diff --git a/internal/backend/bls12-381/groth16/marshal_test.go b/backend/groth16/bls12-381/marshal_test.go similarity index 100% rename from internal/backend/bls12-381/groth16/marshal_test.go rename to backend/groth16/bls12-381/marshal_test.go diff --git a/internal/backend/bls12-381/groth16/prove.go b/backend/groth16/bls12-381/prove.go similarity index 100% rename from internal/backend/bls12-381/groth16/prove.go rename to backend/groth16/bls12-381/prove.go diff --git a/internal/backend/bls12-381/groth16/setup.go b/backend/groth16/bls12-381/setup.go similarity index 100% rename from internal/backend/bls12-381/groth16/setup.go rename to backend/groth16/bls12-381/setup.go diff --git a/internal/backend/bls12-381/groth16/verify.go b/backend/groth16/bls12-381/verify.go similarity index 100% rename from internal/backend/bls12-381/groth16/verify.go rename to backend/groth16/bls12-381/verify.go diff --git a/internal/backend/bls24-315/groth16/commitment.go b/backend/groth16/bls24-315/commitment.go similarity index 100% rename from internal/backend/bls24-315/groth16/commitment.go rename to backend/groth16/bls24-315/commitment.go diff --git a/internal/backend/bls24-315/groth16/commitment_test.go b/backend/groth16/bls24-315/commitment_test.go similarity index 100% rename from internal/backend/bls24-315/groth16/commitment_test.go rename to backend/groth16/bls24-315/commitment_test.go diff --git a/internal/backend/bls24-315/groth16/marshal.go b/backend/groth16/bls24-315/marshal.go similarity index 100% rename from internal/backend/bls24-315/groth16/marshal.go rename to backend/groth16/bls24-315/marshal.go diff --git a/internal/backend/bls24-315/groth16/marshal_test.go b/backend/groth16/bls24-315/marshal_test.go similarity index 100% rename from internal/backend/bls24-315/groth16/marshal_test.go rename to backend/groth16/bls24-315/marshal_test.go diff --git a/internal/backend/bls24-315/groth16/prove.go b/backend/groth16/bls24-315/prove.go similarity index 100% rename from internal/backend/bls24-315/groth16/prove.go rename to backend/groth16/bls24-315/prove.go diff --git a/internal/backend/bls24-315/groth16/setup.go b/backend/groth16/bls24-315/setup.go similarity index 100% rename from internal/backend/bls24-315/groth16/setup.go rename to backend/groth16/bls24-315/setup.go diff --git a/internal/backend/bls24-315/groth16/verify.go b/backend/groth16/bls24-315/verify.go similarity index 100% rename from internal/backend/bls24-315/groth16/verify.go rename to backend/groth16/bls24-315/verify.go diff --git a/internal/backend/bls24-317/groth16/commitment.go b/backend/groth16/bls24-317/commitment.go similarity index 100% rename from internal/backend/bls24-317/groth16/commitment.go rename to backend/groth16/bls24-317/commitment.go diff --git a/internal/backend/bls24-317/groth16/commitment_test.go b/backend/groth16/bls24-317/commitment_test.go similarity index 100% rename from internal/backend/bls24-317/groth16/commitment_test.go rename to backend/groth16/bls24-317/commitment_test.go diff --git a/internal/backend/bls24-317/groth16/marshal.go b/backend/groth16/bls24-317/marshal.go similarity index 100% rename from internal/backend/bls24-317/groth16/marshal.go rename to backend/groth16/bls24-317/marshal.go diff --git a/internal/backend/bls24-317/groth16/marshal_test.go b/backend/groth16/bls24-317/marshal_test.go similarity index 100% rename from internal/backend/bls24-317/groth16/marshal_test.go rename to backend/groth16/bls24-317/marshal_test.go diff --git a/internal/backend/bls24-317/groth16/prove.go b/backend/groth16/bls24-317/prove.go similarity index 100% rename from internal/backend/bls24-317/groth16/prove.go rename to backend/groth16/bls24-317/prove.go diff --git a/internal/backend/bls24-317/groth16/setup.go b/backend/groth16/bls24-317/setup.go similarity index 100% rename from internal/backend/bls24-317/groth16/setup.go rename to backend/groth16/bls24-317/setup.go diff --git a/internal/backend/bls24-317/groth16/verify.go b/backend/groth16/bls24-317/verify.go similarity index 100% rename from internal/backend/bls24-317/groth16/verify.go rename to backend/groth16/bls24-317/verify.go diff --git a/internal/backend/bn254/groth16/commitment.go b/backend/groth16/bn254/commitment.go similarity index 100% rename from internal/backend/bn254/groth16/commitment.go rename to backend/groth16/bn254/commitment.go diff --git a/internal/backend/bn254/groth16/commitment_test.go b/backend/groth16/bn254/commitment_test.go similarity index 100% rename from internal/backend/bn254/groth16/commitment_test.go rename to backend/groth16/bn254/commitment_test.go diff --git a/internal/backend/bn254/groth16/marshal.go b/backend/groth16/bn254/marshal.go similarity index 100% rename from internal/backend/bn254/groth16/marshal.go rename to backend/groth16/bn254/marshal.go diff --git a/internal/backend/bn254/groth16/marshal_test.go b/backend/groth16/bn254/marshal_test.go similarity index 100% rename from internal/backend/bn254/groth16/marshal_test.go rename to backend/groth16/bn254/marshal_test.go diff --git a/internal/backend/bn254/groth16/prove.go b/backend/groth16/bn254/prove.go similarity index 100% rename from internal/backend/bn254/groth16/prove.go rename to backend/groth16/bn254/prove.go diff --git a/internal/backend/bn254/groth16/setup.go b/backend/groth16/bn254/setup.go similarity index 100% rename from internal/backend/bn254/groth16/setup.go rename to backend/groth16/bn254/setup.go diff --git a/internal/backend/bn254/groth16/solidity.go b/backend/groth16/bn254/solidity.go similarity index 100% rename from internal/backend/bn254/groth16/solidity.go rename to backend/groth16/bn254/solidity.go diff --git a/internal/backend/bn254/groth16/utils_test.go b/backend/groth16/bn254/utils_test.go similarity index 100% rename from internal/backend/bn254/groth16/utils_test.go rename to backend/groth16/bn254/utils_test.go diff --git a/internal/backend/bn254/groth16/verify.go b/backend/groth16/bn254/verify.go similarity index 100% rename from internal/backend/bn254/groth16/verify.go rename to backend/groth16/bn254/verify.go diff --git a/internal/backend/bw6-633/groth16/commitment.go b/backend/groth16/bw6-633/commitment.go similarity index 100% rename from internal/backend/bw6-633/groth16/commitment.go rename to backend/groth16/bw6-633/commitment.go diff --git a/internal/backend/bw6-633/groth16/commitment_test.go b/backend/groth16/bw6-633/commitment_test.go similarity index 100% rename from internal/backend/bw6-633/groth16/commitment_test.go rename to backend/groth16/bw6-633/commitment_test.go diff --git a/internal/backend/bw6-633/groth16/marshal.go b/backend/groth16/bw6-633/marshal.go similarity index 100% rename from internal/backend/bw6-633/groth16/marshal.go rename to backend/groth16/bw6-633/marshal.go diff --git a/internal/backend/bw6-633/groth16/marshal_test.go b/backend/groth16/bw6-633/marshal_test.go similarity index 100% rename from internal/backend/bw6-633/groth16/marshal_test.go rename to backend/groth16/bw6-633/marshal_test.go diff --git a/internal/backend/bw6-633/groth16/prove.go b/backend/groth16/bw6-633/prove.go similarity index 100% rename from internal/backend/bw6-633/groth16/prove.go rename to backend/groth16/bw6-633/prove.go diff --git a/internal/backend/bw6-633/groth16/setup.go b/backend/groth16/bw6-633/setup.go similarity index 100% rename from internal/backend/bw6-633/groth16/setup.go rename to backend/groth16/bw6-633/setup.go diff --git a/internal/backend/bw6-633/groth16/verify.go b/backend/groth16/bw6-633/verify.go similarity index 100% rename from internal/backend/bw6-633/groth16/verify.go rename to backend/groth16/bw6-633/verify.go diff --git a/internal/backend/bw6-761/groth16/commitment.go b/backend/groth16/bw6-761/commitment.go similarity index 100% rename from internal/backend/bw6-761/groth16/commitment.go rename to backend/groth16/bw6-761/commitment.go diff --git a/internal/backend/bw6-761/groth16/commitment_test.go b/backend/groth16/bw6-761/commitment_test.go similarity index 100% rename from internal/backend/bw6-761/groth16/commitment_test.go rename to backend/groth16/bw6-761/commitment_test.go diff --git a/internal/backend/bw6-761/groth16/marshal.go b/backend/groth16/bw6-761/marshal.go similarity index 100% rename from internal/backend/bw6-761/groth16/marshal.go rename to backend/groth16/bw6-761/marshal.go diff --git a/internal/backend/bw6-761/groth16/marshal_test.go b/backend/groth16/bw6-761/marshal_test.go similarity index 100% rename from internal/backend/bw6-761/groth16/marshal_test.go rename to backend/groth16/bw6-761/marshal_test.go diff --git a/internal/backend/bw6-761/groth16/prove.go b/backend/groth16/bw6-761/prove.go similarity index 100% rename from internal/backend/bw6-761/groth16/prove.go rename to backend/groth16/bw6-761/prove.go diff --git a/internal/backend/bw6-761/groth16/setup.go b/backend/groth16/bw6-761/setup.go similarity index 100% rename from internal/backend/bw6-761/groth16/setup.go rename to backend/groth16/bw6-761/setup.go diff --git a/internal/backend/bw6-761/groth16/verify.go b/backend/groth16/bw6-761/verify.go similarity index 100% rename from internal/backend/bw6-761/groth16/verify.go rename to backend/groth16/bw6-761/verify.go diff --git a/backend/groth16/groth16.go b/backend/groth16/groth16.go index 9e4bf92150..41e0f63c7e 100644 --- a/backend/groth16/groth16.go +++ b/backend/groth16/groth16.go @@ -44,13 +44,13 @@ import ( gnarkio "github.com/consensys/gnark/io" - groth16_bls12377 "github.com/consensys/gnark/internal/backend/bls12-377/groth16" - groth16_bls12381 "github.com/consensys/gnark/internal/backend/bls12-381/groth16" - groth16_bls24315 "github.com/consensys/gnark/internal/backend/bls24-315/groth16" - groth16_bls24317 "github.com/consensys/gnark/internal/backend/bls24-317/groth16" - groth16_bn254 "github.com/consensys/gnark/internal/backend/bn254/groth16" - groth16_bw6633 "github.com/consensys/gnark/internal/backend/bw6-633/groth16" - groth16_bw6761 "github.com/consensys/gnark/internal/backend/bw6-761/groth16" + groth16_bls12377 "github.com/consensys/gnark/backend/groth16/bls12-377" + groth16_bls12381 "github.com/consensys/gnark/backend/groth16/bls12-381" + groth16_bls24315 "github.com/consensys/gnark/backend/groth16/bls24-315" + groth16_bls24317 "github.com/consensys/gnark/backend/groth16/bls24-317" + groth16_bn254 "github.com/consensys/gnark/backend/groth16/bn254" + groth16_bw6633 "github.com/consensys/gnark/backend/groth16/bw6-633" + groth16_bw6761 "github.com/consensys/gnark/backend/groth16/bw6-761" ) type groth16Object interface { diff --git a/internal/backend/bls12-377/plonk/marshal.go b/backend/plonk/bls12-377/marshal.go similarity index 100% rename from internal/backend/bls12-377/plonk/marshal.go rename to backend/plonk/bls12-377/marshal.go diff --git a/internal/backend/bls12-377/plonk/marshal_test.go b/backend/plonk/bls12-377/marshal_test.go similarity index 100% rename from internal/backend/bls12-377/plonk/marshal_test.go rename to backend/plonk/bls12-377/marshal_test.go diff --git a/internal/backend/bls12-377/plonk/prove.go b/backend/plonk/bls12-377/prove.go similarity index 100% rename from internal/backend/bls12-377/plonk/prove.go rename to backend/plonk/bls12-377/prove.go diff --git a/internal/backend/bls12-377/plonk/setup.go b/backend/plonk/bls12-377/setup.go similarity index 100% rename from internal/backend/bls12-377/plonk/setup.go rename to backend/plonk/bls12-377/setup.go diff --git a/internal/backend/bls12-377/plonk/verify.go b/backend/plonk/bls12-377/verify.go similarity index 100% rename from internal/backend/bls12-377/plonk/verify.go rename to backend/plonk/bls12-377/verify.go diff --git a/internal/backend/bls12-381/plonk/marshal.go b/backend/plonk/bls12-381/marshal.go similarity index 100% rename from internal/backend/bls12-381/plonk/marshal.go rename to backend/plonk/bls12-381/marshal.go diff --git a/internal/backend/bls12-381/plonk/marshal_test.go b/backend/plonk/bls12-381/marshal_test.go similarity index 100% rename from internal/backend/bls12-381/plonk/marshal_test.go rename to backend/plonk/bls12-381/marshal_test.go diff --git a/internal/backend/bls12-381/plonk/prove.go b/backend/plonk/bls12-381/prove.go similarity index 100% rename from internal/backend/bls12-381/plonk/prove.go rename to backend/plonk/bls12-381/prove.go diff --git a/internal/backend/bls12-381/plonk/setup.go b/backend/plonk/bls12-381/setup.go similarity index 100% rename from internal/backend/bls12-381/plonk/setup.go rename to backend/plonk/bls12-381/setup.go diff --git a/internal/backend/bls12-381/plonk/verify.go b/backend/plonk/bls12-381/verify.go similarity index 100% rename from internal/backend/bls12-381/plonk/verify.go rename to backend/plonk/bls12-381/verify.go diff --git a/internal/backend/bls24-315/plonk/marshal.go b/backend/plonk/bls24-315/marshal.go similarity index 100% rename from internal/backend/bls24-315/plonk/marshal.go rename to backend/plonk/bls24-315/marshal.go diff --git a/internal/backend/bls24-315/plonk/marshal_test.go b/backend/plonk/bls24-315/marshal_test.go similarity index 100% rename from internal/backend/bls24-315/plonk/marshal_test.go rename to backend/plonk/bls24-315/marshal_test.go diff --git a/internal/backend/bls24-315/plonk/prove.go b/backend/plonk/bls24-315/prove.go similarity index 100% rename from internal/backend/bls24-315/plonk/prove.go rename to backend/plonk/bls24-315/prove.go diff --git a/internal/backend/bls24-315/plonk/setup.go b/backend/plonk/bls24-315/setup.go similarity index 100% rename from internal/backend/bls24-315/plonk/setup.go rename to backend/plonk/bls24-315/setup.go diff --git a/internal/backend/bls24-315/plonk/verify.go b/backend/plonk/bls24-315/verify.go similarity index 100% rename from internal/backend/bls24-315/plonk/verify.go rename to backend/plonk/bls24-315/verify.go diff --git a/internal/backend/bls24-317/plonk/marshal.go b/backend/plonk/bls24-317/marshal.go similarity index 100% rename from internal/backend/bls24-317/plonk/marshal.go rename to backend/plonk/bls24-317/marshal.go diff --git a/internal/backend/bls24-317/plonk/marshal_test.go b/backend/plonk/bls24-317/marshal_test.go similarity index 100% rename from internal/backend/bls24-317/plonk/marshal_test.go rename to backend/plonk/bls24-317/marshal_test.go diff --git a/internal/backend/bls24-317/plonk/prove.go b/backend/plonk/bls24-317/prove.go similarity index 100% rename from internal/backend/bls24-317/plonk/prove.go rename to backend/plonk/bls24-317/prove.go diff --git a/internal/backend/bls24-317/plonk/setup.go b/backend/plonk/bls24-317/setup.go similarity index 100% rename from internal/backend/bls24-317/plonk/setup.go rename to backend/plonk/bls24-317/setup.go diff --git a/internal/backend/bls24-317/plonk/verify.go b/backend/plonk/bls24-317/verify.go similarity index 100% rename from internal/backend/bls24-317/plonk/verify.go rename to backend/plonk/bls24-317/verify.go diff --git a/internal/backend/bn254/plonk/marshal.go b/backend/plonk/bn254/marshal.go similarity index 100% rename from internal/backend/bn254/plonk/marshal.go rename to backend/plonk/bn254/marshal.go diff --git a/internal/backend/bn254/plonk/marshal_test.go b/backend/plonk/bn254/marshal_test.go similarity index 100% rename from internal/backend/bn254/plonk/marshal_test.go rename to backend/plonk/bn254/marshal_test.go diff --git a/internal/backend/bn254/plonk/prove.go b/backend/plonk/bn254/prove.go similarity index 100% rename from internal/backend/bn254/plonk/prove.go rename to backend/plonk/bn254/prove.go diff --git a/internal/backend/bn254/plonk/setup.go b/backend/plonk/bn254/setup.go similarity index 100% rename from internal/backend/bn254/plonk/setup.go rename to backend/plonk/bn254/setup.go diff --git a/internal/backend/bn254/plonk/solidity.go b/backend/plonk/bn254/solidity.go similarity index 100% rename from internal/backend/bn254/plonk/solidity.go rename to backend/plonk/bn254/solidity.go diff --git a/internal/backend/bn254/plonk/verify.go b/backend/plonk/bn254/verify.go similarity index 100% rename from internal/backend/bn254/plonk/verify.go rename to backend/plonk/bn254/verify.go diff --git a/internal/backend/bw6-633/plonk/marshal.go b/backend/plonk/bw6-633/marshal.go similarity index 100% rename from internal/backend/bw6-633/plonk/marshal.go rename to backend/plonk/bw6-633/marshal.go diff --git a/internal/backend/bw6-633/plonk/marshal_test.go b/backend/plonk/bw6-633/marshal_test.go similarity index 100% rename from internal/backend/bw6-633/plonk/marshal_test.go rename to backend/plonk/bw6-633/marshal_test.go diff --git a/internal/backend/bw6-633/plonk/prove.go b/backend/plonk/bw6-633/prove.go similarity index 100% rename from internal/backend/bw6-633/plonk/prove.go rename to backend/plonk/bw6-633/prove.go diff --git a/internal/backend/bw6-633/plonk/setup.go b/backend/plonk/bw6-633/setup.go similarity index 100% rename from internal/backend/bw6-633/plonk/setup.go rename to backend/plonk/bw6-633/setup.go diff --git a/internal/backend/bw6-633/plonk/verify.go b/backend/plonk/bw6-633/verify.go similarity index 100% rename from internal/backend/bw6-633/plonk/verify.go rename to backend/plonk/bw6-633/verify.go diff --git a/internal/backend/bw6-761/plonk/marshal.go b/backend/plonk/bw6-761/marshal.go similarity index 100% rename from internal/backend/bw6-761/plonk/marshal.go rename to backend/plonk/bw6-761/marshal.go diff --git a/internal/backend/bw6-761/plonk/marshal_test.go b/backend/plonk/bw6-761/marshal_test.go similarity index 100% rename from internal/backend/bw6-761/plonk/marshal_test.go rename to backend/plonk/bw6-761/marshal_test.go diff --git a/internal/backend/bw6-761/plonk/prove.go b/backend/plonk/bw6-761/prove.go similarity index 100% rename from internal/backend/bw6-761/plonk/prove.go rename to backend/plonk/bw6-761/prove.go diff --git a/internal/backend/bw6-761/plonk/setup.go b/backend/plonk/bw6-761/setup.go similarity index 100% rename from internal/backend/bw6-761/plonk/setup.go rename to backend/plonk/bw6-761/setup.go diff --git a/internal/backend/bw6-761/plonk/verify.go b/backend/plonk/bw6-761/verify.go similarity index 100% rename from internal/backend/bw6-761/plonk/verify.go rename to backend/plonk/bw6-761/verify.go diff --git a/backend/plonk/plonk.go b/backend/plonk/plonk.go index 22fb4a84e6..c74e14363b 100644 --- a/backend/plonk/plonk.go +++ b/backend/plonk/plonk.go @@ -36,13 +36,13 @@ import ( cs_bw6633 "github.com/consensys/gnark/constraint/bw6-633" cs_bw6761 "github.com/consensys/gnark/constraint/bw6-761" - plonk_bls12377 "github.com/consensys/gnark/internal/backend/bls12-377/plonk" - plonk_bls12381 "github.com/consensys/gnark/internal/backend/bls12-381/plonk" - plonk_bls24315 "github.com/consensys/gnark/internal/backend/bls24-315/plonk" - plonk_bls24317 "github.com/consensys/gnark/internal/backend/bls24-317/plonk" - plonk_bn254 "github.com/consensys/gnark/internal/backend/bn254/plonk" - plonk_bw6633 "github.com/consensys/gnark/internal/backend/bw6-633/plonk" - plonk_bw6761 "github.com/consensys/gnark/internal/backend/bw6-761/plonk" + plonk_bls12377 "github.com/consensys/gnark/backend/plonk/bls12-377" + plonk_bls12381 "github.com/consensys/gnark/backend/plonk/bls12-381" + plonk_bls24315 "github.com/consensys/gnark/backend/plonk/bls24-315" + plonk_bls24317 "github.com/consensys/gnark/backend/plonk/bls24-317" + plonk_bn254 "github.com/consensys/gnark/backend/plonk/bn254" + plonk_bw6633 "github.com/consensys/gnark/backend/plonk/bw6-633" + plonk_bw6761 "github.com/consensys/gnark/backend/plonk/bw6-761" fr_bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" fr_bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" diff --git a/internal/backend/bls12-377/plonkfri/prove.go b/backend/plonkfri/bls12-377/prove.go similarity index 100% rename from internal/backend/bls12-377/plonkfri/prove.go rename to backend/plonkfri/bls12-377/prove.go diff --git a/internal/backend/bls12-377/plonkfri/setup.go b/backend/plonkfri/bls12-377/setup.go similarity index 100% rename from internal/backend/bls12-377/plonkfri/setup.go rename to backend/plonkfri/bls12-377/setup.go diff --git a/internal/backend/bls12-377/plonkfri/verify.go b/backend/plonkfri/bls12-377/verify.go similarity index 100% rename from internal/backend/bls12-377/plonkfri/verify.go rename to backend/plonkfri/bls12-377/verify.go diff --git a/internal/backend/bls12-381/plonkfri/prove.go b/backend/plonkfri/bls12-381/prove.go similarity index 100% rename from internal/backend/bls12-381/plonkfri/prove.go rename to backend/plonkfri/bls12-381/prove.go diff --git a/internal/backend/bls12-381/plonkfri/setup.go b/backend/plonkfri/bls12-381/setup.go similarity index 100% rename from internal/backend/bls12-381/plonkfri/setup.go rename to backend/plonkfri/bls12-381/setup.go diff --git a/internal/backend/bls12-381/plonkfri/verify.go b/backend/plonkfri/bls12-381/verify.go similarity index 100% rename from internal/backend/bls12-381/plonkfri/verify.go rename to backend/plonkfri/bls12-381/verify.go diff --git a/internal/backend/bls24-315/plonkfri/prove.go b/backend/plonkfri/bls24-315/prove.go similarity index 100% rename from internal/backend/bls24-315/plonkfri/prove.go rename to backend/plonkfri/bls24-315/prove.go diff --git a/internal/backend/bls24-315/plonkfri/setup.go b/backend/plonkfri/bls24-315/setup.go similarity index 100% rename from internal/backend/bls24-315/plonkfri/setup.go rename to backend/plonkfri/bls24-315/setup.go diff --git a/internal/backend/bls24-315/plonkfri/verify.go b/backend/plonkfri/bls24-315/verify.go similarity index 100% rename from internal/backend/bls24-315/plonkfri/verify.go rename to backend/plonkfri/bls24-315/verify.go diff --git a/internal/backend/bls24-317/plonkfri/prove.go b/backend/plonkfri/bls24-317/prove.go similarity index 100% rename from internal/backend/bls24-317/plonkfri/prove.go rename to backend/plonkfri/bls24-317/prove.go diff --git a/internal/backend/bls24-317/plonkfri/setup.go b/backend/plonkfri/bls24-317/setup.go similarity index 100% rename from internal/backend/bls24-317/plonkfri/setup.go rename to backend/plonkfri/bls24-317/setup.go diff --git a/internal/backend/bls24-317/plonkfri/verify.go b/backend/plonkfri/bls24-317/verify.go similarity index 100% rename from internal/backend/bls24-317/plonkfri/verify.go rename to backend/plonkfri/bls24-317/verify.go diff --git a/internal/backend/bn254/plonkfri/prove.go b/backend/plonkfri/bn254/prove.go similarity index 100% rename from internal/backend/bn254/plonkfri/prove.go rename to backend/plonkfri/bn254/prove.go diff --git a/internal/backend/bn254/plonkfri/setup.go b/backend/plonkfri/bn254/setup.go similarity index 100% rename from internal/backend/bn254/plonkfri/setup.go rename to backend/plonkfri/bn254/setup.go diff --git a/internal/backend/bn254/plonkfri/verify.go b/backend/plonkfri/bn254/verify.go similarity index 100% rename from internal/backend/bn254/plonkfri/verify.go rename to backend/plonkfri/bn254/verify.go diff --git a/internal/backend/bw6-633/plonkfri/prove.go b/backend/plonkfri/bw6-633/prove.go similarity index 100% rename from internal/backend/bw6-633/plonkfri/prove.go rename to backend/plonkfri/bw6-633/prove.go diff --git a/internal/backend/bw6-633/plonkfri/setup.go b/backend/plonkfri/bw6-633/setup.go similarity index 100% rename from internal/backend/bw6-633/plonkfri/setup.go rename to backend/plonkfri/bw6-633/setup.go diff --git a/internal/backend/bw6-633/plonkfri/verify.go b/backend/plonkfri/bw6-633/verify.go similarity index 100% rename from internal/backend/bw6-633/plonkfri/verify.go rename to backend/plonkfri/bw6-633/verify.go diff --git a/internal/backend/bw6-761/plonkfri/prove.go b/backend/plonkfri/bw6-761/prove.go similarity index 100% rename from internal/backend/bw6-761/plonkfri/prove.go rename to backend/plonkfri/bw6-761/prove.go diff --git a/internal/backend/bw6-761/plonkfri/setup.go b/backend/plonkfri/bw6-761/setup.go similarity index 100% rename from internal/backend/bw6-761/plonkfri/setup.go rename to backend/plonkfri/bw6-761/setup.go diff --git a/internal/backend/bw6-761/plonkfri/verify.go b/backend/plonkfri/bw6-761/verify.go similarity index 100% rename from internal/backend/bw6-761/plonkfri/verify.go rename to backend/plonkfri/bw6-761/verify.go diff --git a/backend/plonkfri/plonkfri.go b/backend/plonkfri/plonkfri.go index 54954f89a8..5fcb3760eb 100644 --- a/backend/plonkfri/plonkfri.go +++ b/backend/plonkfri/plonkfri.go @@ -29,12 +29,13 @@ import ( cs_bw6633 "github.com/consensys/gnark/constraint/bw6-633" cs_bw6761 "github.com/consensys/gnark/constraint/bw6-761" - plonk_bls12377 "github.com/consensys/gnark/internal/backend/bls12-377/plonkfri" - plonk_bls12381 "github.com/consensys/gnark/internal/backend/bls12-381/plonkfri" - plonk_bls24315 "github.com/consensys/gnark/internal/backend/bls24-315/plonkfri" - plonk_bn254 "github.com/consensys/gnark/internal/backend/bn254/plonkfri" - plonk_bw6633 "github.com/consensys/gnark/internal/backend/bw6-633/plonkfri" - plonk_bw6761 "github.com/consensys/gnark/internal/backend/bw6-761/plonkfri" + plonk_bls12377 "github.com/consensys/gnark/backend/plonkfri/bls12-377" + plonk_bls12381 "github.com/consensys/gnark/backend/plonkfri/bls12-381" + plonk_bls24315 "github.com/consensys/gnark/backend/plonkfri/bls24-315" + plonk_bls24317 "github.com/consensys/gnark/backend/plonkfri/bls24-317" + plonk_bn254 "github.com/consensys/gnark/backend/plonkfri/bn254" + plonk_bw6633 "github.com/consensys/gnark/backend/plonkfri/bw6-633" + plonk_bw6761 "github.com/consensys/gnark/backend/plonkfri/bw6-761" fr_bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" fr_bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" @@ -43,8 +44,6 @@ import ( fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" fr_bw6633 "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" fr_bw6761 "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" - - plonk_bls24317 "github.com/consensys/gnark/internal/backend/bls24-317/plonkfri" ) // Proof represents a Plonk proof generated by plonk.Prove diff --git a/internal/generator/backend/main.go b/internal/generator/backend/main.go index df801f8650..5face84ed8 100644 --- a/internal/generator/backend/main.go +++ b/internal/generator/backend/main.go @@ -4,6 +4,7 @@ import ( "os" "os/exec" "path/filepath" + "strings" "sync" "github.com/consensys/bavard" @@ -19,43 +20,43 @@ var bgen = bavard.NewBatchGenerator(copyrightHolder, 2020, "gnark") func main() { bls12_377 := templateData{ - RootPath: "../../../internal/backend/bls12-377/", + RootPath: "../../../backend/{?}/bls12-377/", CSPath: "../../../constraint/bls12-377/", Curve: "BLS12-377", CurveID: "BLS12_377", } bls12_381 := templateData{ - RootPath: "../../../internal/backend/bls12-381/", + RootPath: "../../../backend/{?}/bls12-381/", CSPath: "../../../constraint/bls12-381/", Curve: "BLS12-381", CurveID: "BLS12_381", } bn254 := templateData{ - RootPath: "../../../internal/backend/bn254/", + RootPath: "../../../backend/{?}/bn254/", CSPath: "../../../constraint/bn254/", Curve: "BN254", CurveID: "BN254", } bw6_761 := templateData{ - RootPath: "../../../internal/backend/bw6-761/", + RootPath: "../../../backend/{?}/bw6-761/", CSPath: "../../../constraint/bw6-761/", Curve: "BW6-761", CurveID: "BW6_761", } bls24_315 := templateData{ - RootPath: "../../../internal/backend/bls24-315/", + RootPath: "../../../backend/{?}/bls24-315/", CSPath: "../../../constraint/bls24-315/", Curve: "BLS24-315", CurveID: "BLS24_315", } bls24_317 := templateData{ - RootPath: "../../../internal/backend/bls24-317/", + RootPath: "../../../backend/{?}/bls24-317/", CSPath: "../../../constraint/bls24-317/", Curve: "BLS24-317", CurveID: "BLS24_317", } bw6_633 := templateData{ - RootPath: "../../../internal/backend/bw6-633/", + RootPath: "../../../backend/{?}/bw6-633/", CSPath: "../../../constraint/bw6-633/", Curve: "BW6-633", CurveID: "BW6_633", @@ -97,16 +98,21 @@ func main() { wg.Add(1) go func(d templateData) { - defer wg.Done() - if err := os.MkdirAll(d.RootPath+"groth16", 0700); err != nil { + var ( + groth16Dir = strings.Replace(d.RootPath, "{?}", "groth16", 1) + plonkDir = strings.Replace(d.RootPath, "{?}", "plonk", 1) + plonkFriDir = strings.Replace(d.RootPath, "{?}", "plonkfri", 1) + ) + + if err := os.MkdirAll(groth16Dir, 0700); err != nil { panic(err) } - if err := os.MkdirAll(d.RootPath+"plonk", 0700); err != nil { + if err := os.MkdirAll(plonkDir, 0700); err != nil { panic(err) } - if err := os.MkdirAll(d.RootPath+"plonkfri", 0700); err != nil { + if err := os.MkdirAll(plonkFriDir, 0700); err != nil { panic(err) } @@ -136,10 +142,6 @@ func main() { return } - plonkFriDir := filepath.Join(d.RootPath, "plonkfri") - groth16Dir := filepath.Join(d.RootPath, "groth16") - plonkDir := filepath.Join(d.RootPath, "plonk") - if err := os.MkdirAll(groth16Dir, 0700); err != nil { panic(err) } diff --git a/std/groth16_bls12377/verifier.go b/std/groth16_bls12377/verifier.go index 8316d20479..7d6f561dde 100644 --- a/std/groth16_bls12377/verifier.go +++ b/std/groth16_bls12377/verifier.go @@ -22,8 +22,8 @@ import ( bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377" "github.com/consensys/gnark/backend/groth16" + groth16_bls12377 "github.com/consensys/gnark/backend/groth16/bls12-377" "github.com/consensys/gnark/frontend" - groth16_bls12377 "github.com/consensys/gnark/internal/backend/bls12-377/groth16" "github.com/consensys/gnark/std/algebra/native/fields_bls12377" "github.com/consensys/gnark/std/algebra/native/sw_bls12377" ) diff --git a/std/groth16_bls12377/verifier_test.go b/std/groth16_bls12377/verifier_test.go index beab2de62b..40397b507a 100644 --- a/std/groth16_bls12377/verifier_test.go +++ b/std/groth16_bls12377/verifier_test.go @@ -22,11 +22,11 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + groth16_bls12377 "github.com/consensys/gnark/backend/groth16/bls12-377" "github.com/consensys/gnark/constraint" cs_bls12377 "github.com/consensys/gnark/constraint/bls12-377" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" - groth16_bls12377 "github.com/consensys/gnark/internal/backend/bls12-377/groth16" "github.com/consensys/gnark/std/algebra/native/sw_bls12377" "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/test" diff --git a/std/groth16_bls24315/verifier.go b/std/groth16_bls24315/verifier.go index 836c20d33b..8da0f6c0b0 100644 --- a/std/groth16_bls24315/verifier.go +++ b/std/groth16_bls24315/verifier.go @@ -22,8 +22,8 @@ import ( bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315" "github.com/consensys/gnark/backend/groth16" + groth16_bls24315 "github.com/consensys/gnark/backend/groth16/bls24-315" "github.com/consensys/gnark/frontend" - groth16_bls24315 "github.com/consensys/gnark/internal/backend/bls24-315/groth16" "github.com/consensys/gnark/std/algebra/native/fields_bls24315" "github.com/consensys/gnark/std/algebra/native/sw_bls24315" ) diff --git a/std/groth16_bls24315/verifier_test.go b/std/groth16_bls24315/verifier_test.go index 73bb075d19..9af446d8bf 100644 --- a/std/groth16_bls24315/verifier_test.go +++ b/std/groth16_bls24315/verifier_test.go @@ -22,11 +22,11 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" + groth16_bls24315 "github.com/consensys/gnark/backend/groth16/bls24-315" "github.com/consensys/gnark/constraint" cs_bls24315 "github.com/consensys/gnark/constraint/bls24-315" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" - groth16_bls24315 "github.com/consensys/gnark/internal/backend/bls24-315/groth16" "github.com/consensys/gnark/std/algebra/native/sw_bls24315" "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/test" From fd75160229d7381914a38836d04d716200ead275 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Tue, 14 Mar 2023 08:40:31 -0500 Subject: [PATCH 116/464] refactor: made some util func private --- backend/groth16/bls12-377/mpcsetup/lagrange.go | 4 ++-- backend/groth16/bls12-377/mpcsetup/phase2.go | 8 ++++---- backend/groth16/bls12-381/mpcsetup/lagrange.go | 4 ++-- backend/groth16/bls12-381/mpcsetup/phase2.go | 8 ++++---- backend/groth16/bls24-315/mpcsetup/lagrange.go | 4 ++-- backend/groth16/bls24-315/mpcsetup/phase2.go | 8 ++++---- backend/groth16/bls24-317/mpcsetup/lagrange.go | 4 ++-- backend/groth16/bls24-317/mpcsetup/phase2.go | 8 ++++---- backend/groth16/bn254/mpcsetup/lagrange.go | 4 ++-- backend/groth16/bn254/mpcsetup/phase2.go | 8 ++++---- backend/groth16/bw6-633/mpcsetup/lagrange.go | 4 ++-- backend/groth16/bw6-633/mpcsetup/phase2.go | 8 ++++---- backend/groth16/bw6-761/mpcsetup/lagrange.go | 4 ++-- backend/groth16/bw6-761/mpcsetup/phase2.go | 8 ++++---- .../template/zkpschemes/groth16/mpcsetup/lagrange.go.tmpl | 4 ++-- .../template/zkpschemes/groth16/mpcsetup/phase2.go.tmpl | 8 ++++---- 16 files changed, 48 insertions(+), 48 deletions(-) diff --git a/backend/groth16/bls12-377/mpcsetup/lagrange.go b/backend/groth16/bls12-377/mpcsetup/lagrange.go index 190a4f804a..92b6acb948 100644 --- a/backend/groth16/bls12-377/mpcsetup/lagrange.go +++ b/backend/groth16/bls12-377/mpcsetup/lagrange.go @@ -28,7 +28,7 @@ import ( "github.com/consensys/gnark/internal/utils" ) -func LagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { +func lagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { coeffs := make([]curve.G1Affine, size) copy(coeffs, powers[:size]) domain := fft.NewDomain(uint64(size)) @@ -49,7 +49,7 @@ func LagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { return coeffs } -func LagrangeCoeffsG2(powers []curve.G2Affine, size int) []curve.G2Affine { +func lagrangeCoeffsG2(powers []curve.G2Affine, size int) []curve.G2Affine { coeffs := make([]curve.G2Affine, size) copy(coeffs, powers[:size]) domain := fft.NewDomain(uint64(size)) diff --git a/backend/groth16/bls12-377/mpcsetup/phase2.go b/backend/groth16/bls12-377/mpcsetup/phase2.go index 5fde08d2c6..a43efe3fcc 100644 --- a/backend/groth16/bls12-377/mpcsetup/phase2.go +++ b/backend/groth16/bls12-377/mpcsetup/phase2.go @@ -100,10 +100,10 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { } // Prepare Lagrange coefficients of [τ...]₁, [τ...]₂, [ατ...]₁, [βτ...]₁ - coeffTau1 := LagrangeCoeffsG1(srs.G1.Tau, size) - coeffTau2 := LagrangeCoeffsG2(srs.G2.Tau, size) - coeffAlphaTau1 := LagrangeCoeffsG1(srs.G1.AlphaTau, size) - coeffBetaTau1 := LagrangeCoeffsG1(srs.G1.BetaTau, size) + coeffTau1 := lagrangeCoeffsG1(srs.G1.Tau, size) + coeffTau2 := lagrangeCoeffsG2(srs.G2.Tau, size) + coeffAlphaTau1 := lagrangeCoeffsG1(srs.G1.AlphaTau, size) + coeffBetaTau1 := lagrangeCoeffsG1(srs.G1.BetaTau, size) internal, secret, public := r1cs.GetNbVariables() nWires := internal + secret + public diff --git a/backend/groth16/bls12-381/mpcsetup/lagrange.go b/backend/groth16/bls12-381/mpcsetup/lagrange.go index 48c60bee7d..8da7a42f2b 100644 --- a/backend/groth16/bls12-381/mpcsetup/lagrange.go +++ b/backend/groth16/bls12-381/mpcsetup/lagrange.go @@ -28,7 +28,7 @@ import ( "github.com/consensys/gnark/internal/utils" ) -func LagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { +func lagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { coeffs := make([]curve.G1Affine, size) copy(coeffs, powers[:size]) domain := fft.NewDomain(uint64(size)) @@ -49,7 +49,7 @@ func LagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { return coeffs } -func LagrangeCoeffsG2(powers []curve.G2Affine, size int) []curve.G2Affine { +func lagrangeCoeffsG2(powers []curve.G2Affine, size int) []curve.G2Affine { coeffs := make([]curve.G2Affine, size) copy(coeffs, powers[:size]) domain := fft.NewDomain(uint64(size)) diff --git a/backend/groth16/bls12-381/mpcsetup/phase2.go b/backend/groth16/bls12-381/mpcsetup/phase2.go index 1d585aac1d..38066c8c7b 100644 --- a/backend/groth16/bls12-381/mpcsetup/phase2.go +++ b/backend/groth16/bls12-381/mpcsetup/phase2.go @@ -100,10 +100,10 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { } // Prepare Lagrange coefficients of [τ...]₁, [τ...]₂, [ατ...]₁, [βτ...]₁ - coeffTau1 := LagrangeCoeffsG1(srs.G1.Tau, size) - coeffTau2 := LagrangeCoeffsG2(srs.G2.Tau, size) - coeffAlphaTau1 := LagrangeCoeffsG1(srs.G1.AlphaTau, size) - coeffBetaTau1 := LagrangeCoeffsG1(srs.G1.BetaTau, size) + coeffTau1 := lagrangeCoeffsG1(srs.G1.Tau, size) + coeffTau2 := lagrangeCoeffsG2(srs.G2.Tau, size) + coeffAlphaTau1 := lagrangeCoeffsG1(srs.G1.AlphaTau, size) + coeffBetaTau1 := lagrangeCoeffsG1(srs.G1.BetaTau, size) internal, secret, public := r1cs.GetNbVariables() nWires := internal + secret + public diff --git a/backend/groth16/bls24-315/mpcsetup/lagrange.go b/backend/groth16/bls24-315/mpcsetup/lagrange.go index aeef03cdfd..6fb61f2c68 100644 --- a/backend/groth16/bls24-315/mpcsetup/lagrange.go +++ b/backend/groth16/bls24-315/mpcsetup/lagrange.go @@ -28,7 +28,7 @@ import ( "github.com/consensys/gnark/internal/utils" ) -func LagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { +func lagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { coeffs := make([]curve.G1Affine, size) copy(coeffs, powers[:size]) domain := fft.NewDomain(uint64(size)) @@ -49,7 +49,7 @@ func LagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { return coeffs } -func LagrangeCoeffsG2(powers []curve.G2Affine, size int) []curve.G2Affine { +func lagrangeCoeffsG2(powers []curve.G2Affine, size int) []curve.G2Affine { coeffs := make([]curve.G2Affine, size) copy(coeffs, powers[:size]) domain := fft.NewDomain(uint64(size)) diff --git a/backend/groth16/bls24-315/mpcsetup/phase2.go b/backend/groth16/bls24-315/mpcsetup/phase2.go index 445a6952d3..a6da12a24a 100644 --- a/backend/groth16/bls24-315/mpcsetup/phase2.go +++ b/backend/groth16/bls24-315/mpcsetup/phase2.go @@ -100,10 +100,10 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { } // Prepare Lagrange coefficients of [τ...]₁, [τ...]₂, [ατ...]₁, [βτ...]₁ - coeffTau1 := LagrangeCoeffsG1(srs.G1.Tau, size) - coeffTau2 := LagrangeCoeffsG2(srs.G2.Tau, size) - coeffAlphaTau1 := LagrangeCoeffsG1(srs.G1.AlphaTau, size) - coeffBetaTau1 := LagrangeCoeffsG1(srs.G1.BetaTau, size) + coeffTau1 := lagrangeCoeffsG1(srs.G1.Tau, size) + coeffTau2 := lagrangeCoeffsG2(srs.G2.Tau, size) + coeffAlphaTau1 := lagrangeCoeffsG1(srs.G1.AlphaTau, size) + coeffBetaTau1 := lagrangeCoeffsG1(srs.G1.BetaTau, size) internal, secret, public := r1cs.GetNbVariables() nWires := internal + secret + public diff --git a/backend/groth16/bls24-317/mpcsetup/lagrange.go b/backend/groth16/bls24-317/mpcsetup/lagrange.go index ab3dc5706a..9d0ba07367 100644 --- a/backend/groth16/bls24-317/mpcsetup/lagrange.go +++ b/backend/groth16/bls24-317/mpcsetup/lagrange.go @@ -28,7 +28,7 @@ import ( "github.com/consensys/gnark/internal/utils" ) -func LagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { +func lagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { coeffs := make([]curve.G1Affine, size) copy(coeffs, powers[:size]) domain := fft.NewDomain(uint64(size)) @@ -49,7 +49,7 @@ func LagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { return coeffs } -func LagrangeCoeffsG2(powers []curve.G2Affine, size int) []curve.G2Affine { +func lagrangeCoeffsG2(powers []curve.G2Affine, size int) []curve.G2Affine { coeffs := make([]curve.G2Affine, size) copy(coeffs, powers[:size]) domain := fft.NewDomain(uint64(size)) diff --git a/backend/groth16/bls24-317/mpcsetup/phase2.go b/backend/groth16/bls24-317/mpcsetup/phase2.go index bfbbdbddc1..15772e84c5 100644 --- a/backend/groth16/bls24-317/mpcsetup/phase2.go +++ b/backend/groth16/bls24-317/mpcsetup/phase2.go @@ -100,10 +100,10 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { } // Prepare Lagrange coefficients of [τ...]₁, [τ...]₂, [ατ...]₁, [βτ...]₁ - coeffTau1 := LagrangeCoeffsG1(srs.G1.Tau, size) - coeffTau2 := LagrangeCoeffsG2(srs.G2.Tau, size) - coeffAlphaTau1 := LagrangeCoeffsG1(srs.G1.AlphaTau, size) - coeffBetaTau1 := LagrangeCoeffsG1(srs.G1.BetaTau, size) + coeffTau1 := lagrangeCoeffsG1(srs.G1.Tau, size) + coeffTau2 := lagrangeCoeffsG2(srs.G2.Tau, size) + coeffAlphaTau1 := lagrangeCoeffsG1(srs.G1.AlphaTau, size) + coeffBetaTau1 := lagrangeCoeffsG1(srs.G1.BetaTau, size) internal, secret, public := r1cs.GetNbVariables() nWires := internal + secret + public diff --git a/backend/groth16/bn254/mpcsetup/lagrange.go b/backend/groth16/bn254/mpcsetup/lagrange.go index eb8ddedc06..cbf377dc25 100644 --- a/backend/groth16/bn254/mpcsetup/lagrange.go +++ b/backend/groth16/bn254/mpcsetup/lagrange.go @@ -28,7 +28,7 @@ import ( "github.com/consensys/gnark/internal/utils" ) -func LagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { +func lagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { coeffs := make([]curve.G1Affine, size) copy(coeffs, powers[:size]) domain := fft.NewDomain(uint64(size)) @@ -49,7 +49,7 @@ func LagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { return coeffs } -func LagrangeCoeffsG2(powers []curve.G2Affine, size int) []curve.G2Affine { +func lagrangeCoeffsG2(powers []curve.G2Affine, size int) []curve.G2Affine { coeffs := make([]curve.G2Affine, size) copy(coeffs, powers[:size]) domain := fft.NewDomain(uint64(size)) diff --git a/backend/groth16/bn254/mpcsetup/phase2.go b/backend/groth16/bn254/mpcsetup/phase2.go index f2b1f4683f..5ead8e8dd4 100644 --- a/backend/groth16/bn254/mpcsetup/phase2.go +++ b/backend/groth16/bn254/mpcsetup/phase2.go @@ -100,10 +100,10 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { } // Prepare Lagrange coefficients of [τ...]₁, [τ...]₂, [ατ...]₁, [βτ...]₁ - coeffTau1 := LagrangeCoeffsG1(srs.G1.Tau, size) - coeffTau2 := LagrangeCoeffsG2(srs.G2.Tau, size) - coeffAlphaTau1 := LagrangeCoeffsG1(srs.G1.AlphaTau, size) - coeffBetaTau1 := LagrangeCoeffsG1(srs.G1.BetaTau, size) + coeffTau1 := lagrangeCoeffsG1(srs.G1.Tau, size) + coeffTau2 := lagrangeCoeffsG2(srs.G2.Tau, size) + coeffAlphaTau1 := lagrangeCoeffsG1(srs.G1.AlphaTau, size) + coeffBetaTau1 := lagrangeCoeffsG1(srs.G1.BetaTau, size) internal, secret, public := r1cs.GetNbVariables() nWires := internal + secret + public diff --git a/backend/groth16/bw6-633/mpcsetup/lagrange.go b/backend/groth16/bw6-633/mpcsetup/lagrange.go index 40fecdefb6..563daf9891 100644 --- a/backend/groth16/bw6-633/mpcsetup/lagrange.go +++ b/backend/groth16/bw6-633/mpcsetup/lagrange.go @@ -28,7 +28,7 @@ import ( "github.com/consensys/gnark/internal/utils" ) -func LagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { +func lagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { coeffs := make([]curve.G1Affine, size) copy(coeffs, powers[:size]) domain := fft.NewDomain(uint64(size)) @@ -49,7 +49,7 @@ func LagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { return coeffs } -func LagrangeCoeffsG2(powers []curve.G2Affine, size int) []curve.G2Affine { +func lagrangeCoeffsG2(powers []curve.G2Affine, size int) []curve.G2Affine { coeffs := make([]curve.G2Affine, size) copy(coeffs, powers[:size]) domain := fft.NewDomain(uint64(size)) diff --git a/backend/groth16/bw6-633/mpcsetup/phase2.go b/backend/groth16/bw6-633/mpcsetup/phase2.go index 6951a53db5..2b9aff3529 100644 --- a/backend/groth16/bw6-633/mpcsetup/phase2.go +++ b/backend/groth16/bw6-633/mpcsetup/phase2.go @@ -100,10 +100,10 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { } // Prepare Lagrange coefficients of [τ...]₁, [τ...]₂, [ατ...]₁, [βτ...]₁ - coeffTau1 := LagrangeCoeffsG1(srs.G1.Tau, size) - coeffTau2 := LagrangeCoeffsG2(srs.G2.Tau, size) - coeffAlphaTau1 := LagrangeCoeffsG1(srs.G1.AlphaTau, size) - coeffBetaTau1 := LagrangeCoeffsG1(srs.G1.BetaTau, size) + coeffTau1 := lagrangeCoeffsG1(srs.G1.Tau, size) + coeffTau2 := lagrangeCoeffsG2(srs.G2.Tau, size) + coeffAlphaTau1 := lagrangeCoeffsG1(srs.G1.AlphaTau, size) + coeffBetaTau1 := lagrangeCoeffsG1(srs.G1.BetaTau, size) internal, secret, public := r1cs.GetNbVariables() nWires := internal + secret + public diff --git a/backend/groth16/bw6-761/mpcsetup/lagrange.go b/backend/groth16/bw6-761/mpcsetup/lagrange.go index b2d05ccea4..3b8aaa3b7c 100644 --- a/backend/groth16/bw6-761/mpcsetup/lagrange.go +++ b/backend/groth16/bw6-761/mpcsetup/lagrange.go @@ -28,7 +28,7 @@ import ( "github.com/consensys/gnark/internal/utils" ) -func LagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { +func lagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { coeffs := make([]curve.G1Affine, size) copy(coeffs, powers[:size]) domain := fft.NewDomain(uint64(size)) @@ -49,7 +49,7 @@ func LagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { return coeffs } -func LagrangeCoeffsG2(powers []curve.G2Affine, size int) []curve.G2Affine { +func lagrangeCoeffsG2(powers []curve.G2Affine, size int) []curve.G2Affine { coeffs := make([]curve.G2Affine, size) copy(coeffs, powers[:size]) domain := fft.NewDomain(uint64(size)) diff --git a/backend/groth16/bw6-761/mpcsetup/phase2.go b/backend/groth16/bw6-761/mpcsetup/phase2.go index c53621f17e..b9bfb5b8ac 100644 --- a/backend/groth16/bw6-761/mpcsetup/phase2.go +++ b/backend/groth16/bw6-761/mpcsetup/phase2.go @@ -100,10 +100,10 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { } // Prepare Lagrange coefficients of [τ...]₁, [τ...]₂, [ατ...]₁, [βτ...]₁ - coeffTau1 := LagrangeCoeffsG1(srs.G1.Tau, size) - coeffTau2 := LagrangeCoeffsG2(srs.G2.Tau, size) - coeffAlphaTau1 := LagrangeCoeffsG1(srs.G1.AlphaTau, size) - coeffBetaTau1 := LagrangeCoeffsG1(srs.G1.BetaTau, size) + coeffTau1 := lagrangeCoeffsG1(srs.G1.Tau, size) + coeffTau2 := lagrangeCoeffsG2(srs.G2.Tau, size) + coeffAlphaTau1 := lagrangeCoeffsG1(srs.G1.AlphaTau, size) + coeffBetaTau1 := lagrangeCoeffsG1(srs.G1.BetaTau, size) internal, secret, public := r1cs.GetNbVariables() nWires := internal + secret + public diff --git a/internal/generator/backend/template/zkpschemes/groth16/mpcsetup/lagrange.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/mpcsetup/lagrange.go.tmpl index ade1c628ad..89b75eb44f 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/mpcsetup/lagrange.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/mpcsetup/lagrange.go.tmpl @@ -13,7 +13,7 @@ import ( -func LagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { +func lagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { coeffs := make([]curve.G1Affine, size) copy(coeffs, powers[:size]) domain := fft.NewDomain(uint64(size)) @@ -34,7 +34,7 @@ func LagrangeCoeffsG1(powers []curve.G1Affine, size int) []curve.G1Affine { return coeffs } -func LagrangeCoeffsG2(powers []curve.G2Affine, size int) []curve.G2Affine { +func lagrangeCoeffsG2(powers []curve.G2Affine, size int) []curve.G2Affine { coeffs := make([]curve.G2Affine, size) copy(coeffs, powers[:size]) domain := fft.NewDomain(uint64(size)) diff --git a/internal/generator/backend/template/zkpschemes/groth16/mpcsetup/phase2.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/mpcsetup/phase2.go.tmpl index af16b6d8fa..ba43428580 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/mpcsetup/phase2.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/mpcsetup/phase2.go.tmpl @@ -84,10 +84,10 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { } // Prepare Lagrange coefficients of [τ...]₁, [τ...]₂, [ατ...]₁, [βτ...]₁ - coeffTau1 := LagrangeCoeffsG1(srs.G1.Tau, size) - coeffTau2 := LagrangeCoeffsG2(srs.G2.Tau, size) - coeffAlphaTau1 := LagrangeCoeffsG1(srs.G1.AlphaTau, size) - coeffBetaTau1 := LagrangeCoeffsG1(srs.G1.BetaTau, size) + coeffTau1 := lagrangeCoeffsG1(srs.G1.Tau, size) + coeffTau2 := lagrangeCoeffsG2(srs.G2.Tau, size) + coeffAlphaTau1 := lagrangeCoeffsG1(srs.G1.AlphaTau, size) + coeffBetaTau1 := lagrangeCoeffsG1(srs.G1.BetaTau, size) internal, secret, public := r1cs.GetNbVariables() nWires := internal + secret + public From b6616a1398ef438972aa7deebcb93ecf0a216628 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 14 Mar 2023 19:36:06 +0100 Subject: [PATCH 117/464] perf(pairing-bn254): optimize emulated pairing over BN254 --- .../emulated/fields_bn254/e12_pairing.go | 120 +++-- std/algebra/emulated/fields_bn254/e12_test.go | 84 ++-- std/algebra/emulated/sw_bn254/doc.go | 6 +- std/algebra/emulated/sw_bn254/g2.go | 8 - std/algebra/emulated/sw_bn254/pairing.go | 463 ++++++++++-------- std/algebra/emulated/sw_bn254/pairing_test.go | 33 -- 6 files changed, 379 insertions(+), 335 deletions(-) diff --git a/std/algebra/emulated/fields_bn254/e12_pairing.go b/std/algebra/emulated/fields_bn254/e12_pairing.go index f0d7931d36..3a28fbfe03 100644 --- a/std/algebra/emulated/fields_bn254/e12_pairing.go +++ b/std/algebra/emulated/fields_bn254/e12_pairing.go @@ -3,6 +3,28 @@ package fields_bn254 import "github.com/consensys/gnark/frontend" func (e Ext12) Expt(api frontend.API, x *E12) *E12 { + // Expt computation is derived from the addition chain: + // + // _10 = 2*1 + // _100 = 2*_10 + // _1000 = 2*_100 + // _10000 = 2*_1000 + // _10001 = 1 + _10000 + // _10011 = _10 + _10001 + // _10100 = 1 + _10011 + // _11001 = _1000 + _10001 + // _100010 = 2*_10001 + // _100111 = _10011 + _10100 + // _101001 = _10 + _100111 + // i27 = (_100010 << 6 + _100 + _11001) << 7 + _11001 + // i44 = (i27 << 8 + _101001 + _10) << 6 + _10001 + // i70 = ((i44 << 8 + _101001) << 6 + _101001) << 10 + // return (_100111 + i70) << 6 + _101001 + _1000 + // + // Operations: 62 squares 17 multiplies + // + // Generated by github.com/mmcloughlin/addchain v0.4.0. + t3 := e.CyclotomicSquare(x) t5 := e.CyclotomicSquare(t3) result := e.CyclotomicSquare(t5) @@ -44,59 +66,75 @@ func (e Ext12) Expt(api frontend.API, x *E12) *E12 { return z } -func (e Ext12) MulBy034(z *E12, c0, c3, c4 *E2) *E12 { - a := e.Ext6.MulByE2(&z.C0, c0) - b := e.Ext6.MulBy01(&z.C1, c3, c4) - c0 = e.Ext2.Add(c0, c3) +// MulBy034 multiplies z by an E12 sparse element of the form +// +// E12{ +// C0: E6{B0: 1, B1: 0, B2: 0}, +// C1: E6{B0: c3, B1: c4, B2: 0}, +// } +func (e *Ext12) MulBy034(z *E12, c3, c4 E2) *E12 { + + a := z.C0 + b := z.C1 + + b = *e.MulBy01(&b, &c3, &c4) + one := e.Ext2.One() + + c3 = *e.Ext2.Add(one, &c3) d := e.Ext6.Add(&z.C0, &z.C1) - d = e.Ext6.MulBy01(d, c0, c4) - z1 := e.Ext6.Add(a, b) - z1 = e.Neg(z1) - z1 = e.Ext6.Add(z1, d) - z0 := e.MulByNonResidue(b) - z0 = e.Ext6.Add(z0, a) + d = e.MulBy01(d, &c3, &c4) + + zC1 := *e.Ext6.Add(&a, &b) + zC1 = *e.Ext6.Neg(&zC1) + zC1 = *e.Ext6.Add(&zC1, d) + zC0 := *e.Ext6.MulByNonResidue(&b) + zC0 = *e.Ext6.Add(&zC0, &a) + return &E12{ - C0: *z0, - C1: *z1, + C0: zC0, + C1: zC1, } } -func (e Ext12) MulBy034by034(d0, d3, d4, c0, c3, c4 *E2) *E12 { - x0 := e.Ext2.Mul(c0, d0) - x3 := e.Ext2.Mul(c3, d3) - x4 := e.Ext2.Mul(c4, d4) - tmp := e.Ext2.Add(c0, c4) - x04 := e.Ext2.Add(d0, d4) - x04 = e.Ext2.Mul(x04, tmp) - x04 = e.Ext2.Sub(x04, x0) - x04 = e.Ext2.Sub(x04, x4) - tmp = e.Ext2.Add(c0, c3) - x03 := e.Ext2.Add(d0, d3) - x03 = e.Ext2.Mul(x03, tmp) - x03 = e.Ext2.Sub(x03, x0) - x03 = e.Ext2.Sub(x03, x3) - tmp = e.Ext2.Add(c3, c4) - x34 := e.Ext2.Add(d3, d4) +// multipliies two E12 sparse element of the form: +// +// E12{ +// C0: E6{B0: 1, B1: 0, B2: 0}, +// C1: E6{B0: c3, B1: c4, B2: 0}, +// } +// +// and +// +// E12{ +// C0: E6{B0: 1, B1: 0, B2: 0}, +// C1: E6{B0: d3, B1: d4, B2: 0}, +// } +func (e *Ext12) Mul034By034(d3, d4, c3, c4 E2) *E12 { + one := e.Ext2.One() + x3 := e.Ext2.Mul(&c3, &d3) + x4 := e.Ext2.Mul(&c4, &d4) + x04 := e.Ext2.Add(&c4, &d4) + x03 := e.Ext2.Add(&c3, &d3) + tmp := e.Ext2.Add(&c3, &c4) + x34 := e.Ext2.Add(&d3, &d4) x34 = e.Ext2.Mul(x34, tmp) x34 = e.Ext2.Sub(x34, x3) x34 = e.Ext2.Sub(x34, x4) - z00 := e.Ext2.MulByNonResidue(x4) - z00 = e.Ext2.Add(z00, x0) - z01 := x3 - z02 := x34 - z10 := x03 - z11 := x04 - z12 := e.Ext2.Zero() + + zC0B0 := *e.Ext2.MulByNonResidue(x4) + zC0B0 = *e.Ext2.Add(&zC0B0, one) + zC0B1 := *x3 + zC0B2 := *x34 + zC1B0 := *x03 + zC1B1 := *x04 + zC1B2 := *e.Ext2.Zero() + return &E12{ C0: E6{ - B0: *z00, - B1: *z01, - B2: *z02, + B0: zC0B0, B1: zC0B1, B2: zC0B2, }, C1: E6{ - B0: *z10, - B1: *z11, - B2: *z12, + B0: zC1B0, B1: zC1B1, B2: zC1B2, }, } } diff --git a/std/algebra/emulated/fields_bn254/e12_test.go b/std/algebra/emulated/fields_bn254/e12_test.go index 96470e3099..3f17ba4756 100644 --- a/std/algebra/emulated/fields_bn254/e12_test.go +++ b/std/algebra/emulated/fields_bn254/e12_test.go @@ -140,50 +140,6 @@ func TestDivFp12(t *testing.T) { } -type e12MulBy034by034 struct { - C0, C3, C4 E2 - D0, D3, D4 E2 - C E12 `gnark:",public"` -} - -func (circuit *e12MulBy034by034) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt12(ba) - expected := e.MulBy034by034(&circuit.C0, &circuit.C3, &circuit.C4, &circuit.D0, &circuit.D3, &circuit.D4) - e.AssertIsEqual(expected, &circuit.C) - - return nil -} - -func TestMulFp12By034by034(t *testing.T) { - - assert := test.NewAssert(t) - // witness values - var c bn254.E12 - var c0, c3, c4, d0, d3, d4 bn254.E2 - _, _ = c0.SetRandom() - _, _ = c3.SetRandom() - _, _ = c4.SetRandom() - _, _ = d0.SetRandom() - _, _ = d3.SetRandom() - _, _ = d4.SetRandom() - c.Mul034by034(&c0, &c3, &c4, &d0, &d3, &d4) - - witness := e12MulBy034by034{ - C0: FromE2(&c0), - C3: FromE2(&c3), - C4: FromE2(&c4), - D0: FromE2(&d0), - D3: FromE2(&d3), - D4: FromE2(&d4), - C: FromE12(&c), - } - - err := test.IsSolved(&e12MulBy034by034{}, &witness, ecc.BN254.ScalarField()) - assert.NoError(err) - -} - type e12Square struct { A, C E12 } @@ -526,3 +482,43 @@ func TestFrobeniusCubeFp12(t *testing.T) { assert.NoError(err) } + +type e12MulBy034 struct { + A E12 `gnark:",public"` + W E12 + B, C E2 +} + +func (circuit *e12MulBy034) Define(api frontend.API) error { + + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt12(ba) + circuit.A = *e.MulBy034(&circuit.A, circuit.B, circuit.C) + e.AssertIsEqual(&circuit.A, &circuit.W) + return nil +} + +func TestFp12MulBy034(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, w bn254.E12 + _, _ = a.SetRandom() + var one, b, c bn254.E2 + one.SetOne() + _, _ = b.SetRandom() + _, _ = c.SetRandom() + w.Set(&a) + w.MulBy034(&one, &b, &c) + + witness := e12MulBy034{ + A: FromE12(&a), + B: FromE2(&b), + C: FromE2(&c), + W: FromE12(&w), + } + + err := test.IsSolved(&e12MulBy034{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} diff --git a/std/algebra/emulated/sw_bn254/doc.go b/std/algebra/emulated/sw_bn254/doc.go index 60bfca6876..7d0561c146 100644 --- a/std/algebra/emulated/sw_bn254/doc.go +++ b/std/algebra/emulated/sw_bn254/doc.go @@ -1,7 +1,5 @@ // Package sw_bn254 implements G1 and G2 arithmetics and pairing computation over BN254 curve. // -// The implementation follows very closely the implementation of its out-circuit -// counterpart in [gnark-crypto]. -// -// [gnark-crypto]: https://github.com/ConsenSys/gnark-crypto/tree/master/ecc/bn254 +// The implementation follows [Housni22]: "Pairings in Rank-1 Constraint Systems". +// [Housni22] https://eprint.iacr.org/2022/1162 package sw_bn254 diff --git a/std/algebra/emulated/sw_bn254/g2.go b/std/algebra/emulated/sw_bn254/g2.go index 1ba7d154a6..9fd94325c5 100644 --- a/std/algebra/emulated/sw_bn254/g2.go +++ b/std/algebra/emulated/sw_bn254/g2.go @@ -10,14 +10,6 @@ type G2Affine struct { X, Y fields_bn254.E2 } -type g2Jacobian struct { - X, Y, Z fields_bn254.E2 -} - -type g2Projective struct { - X, Y, Z fields_bn254.E2 -} - func NewG2Affine(v bn254.G2Affine) G2Affine { return G2Affine{ X: fields_bn254.E2{ diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 9ff8311e9b..d21d821ffe 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -1,6 +1,7 @@ package sw_bn254 import ( + "errors" "fmt" "github.com/consensys/gnark-crypto/ecc/bn254" @@ -58,209 +59,6 @@ func NewPairing(api frontend.API) (*Pairing, error) { }, nil } -func (pr Pairing) DoubleStep(api frontend.API, p *g2Projective) (*g2Projective, *lineEvaluation) { - // var t1, A, B, C, D, E, EE, F, G, H, I, J, K fptower.E2 - A := pr.Ext2.Mul(&p.X, &p.Y) // A.Mul(&p.x, &p.y) - A = pr.Ext2.Halve(api, A) // A.Halve() - B := pr.Ext2.Square(&p.Y) // B.Square(&p.y) - C := pr.Ext2.Square(&p.Z) // C.Square(&p.z) - D := pr.Ext2.Double(C) // D.Double(&C). - D = pr.Ext2.Add(D, C) // Add(&D, &C) - E := pr.Ext2.MulBybTwistCurveCoeff(api, D) // E.MulBybTwistCurveCoeff(&D) - F := pr.Ext2.Double(E) // F.Double(&E). - F = pr.Ext2.Add(F, E) // Add(&F, &E) - G := pr.Ext2.Add(B, F) // G.Add(&B, &F) - G = pr.Ext2.Halve(api, G) // G.Halve() - H := pr.Ext2.Add(&p.Y, &p.Z) // H.Add(&p.y, &p.z). - H = pr.Ext2.Square(H) // Square(&H) - t1 := pr.Ext2.Add(B, C) // t1.Add(&B, &C) - H = pr.Ext2.Sub(H, t1) // H.Sub(&H, &t1) - I := pr.Ext2.Sub(E, B) // I.Sub(&E, &B) - J := pr.Ext2.Square(&p.X) // J.Square(&p.x) - EE := pr.Ext2.Square(E) // EE.Square(&E) - K := pr.Ext2.Double(EE) // K.Double(&EE). - K = pr.Ext2.Add(K, EE) // Add(&K, &EE) - px := pr.Ext2.Sub(B, F) // p.x.Sub(&B, &F). - px = pr.Ext2.Mul(px, A) // Mul(&p.x, &A) - py := pr.Ext2.Square(G) // p.y.Square(&G). - py = pr.Ext2.Sub(py, K) // Sub(&p.y, &K) - pz := pr.Ext2.Mul(B, H) // p.z.Mul(&B, &H) - ev0 := pr.Ext2.Neg(H) // evaluations.r0.Neg(&H) - ev1 := pr.Ext2.Double(J) // evaluations.r1.Double(&J). - ev1 = pr.Ext2.Add(ev1, J) // Add(&evaluations.r1, &J) - ev2 := I // evaluations.r2.Set(&I) - return &g2Projective{ - X: *px, - Y: *py, - Z: *pz, - }, - &lineEvaluation{ - r0: *ev0, - r1: *ev1, - r2: *ev2, - } -} - -func (pr Pairing) affineToProjective(Q *G2Affine) *g2Projective { - // TODO: check point at infinity? We do not filter them in the Miller Loop neither. - // if Q.X.IsZero() && Q.Y.IsZero() { - // p.z.SetZero() - // p.x.SetOne() - // p.y.SetOne() - // return p - // } - pz := pr.Ext2.One() // p.z.SetOne() - px := &Q.X // p.x.Set(&Q.X) - py := &Q.Y // p.y.Set(&Q.Y) - return &g2Projective{ // return p - X: *px, - Y: *py, - Z: *pz, - } -} - -func (pr Pairing) NegAffine(a *G2Affine) *G2Affine { - px := &a.X // p.X = a.X - py := pr.Ext2.Neg(&a.Y) // p.Y.Neg(&a.Y) - return &G2Affine{ // return p - X: *px, - Y: *py, - } -} - -func (pr Pairing) AddStep(p *g2Projective, a *G2Affine) (*g2Projective, *lineEvaluation) { - // var Y2Z1, X2Z1, O, L, C, D, E, F, G, H, t0, t1, t2, J fptower.E2 - Y2Z1 := pr.Ext2.Mul(&a.Y, &p.Z) // Y2Z1.Mul(&a.Y, &p.z) - O := pr.Ext2.Sub(&p.Y, Y2Z1) // O.Sub(&p.y, &Y2Z1) - X2Z1 := pr.Ext2.Mul(&a.X, &p.Z) // X2Z1.Mul(&a.X, &p.z) - L := pr.Ext2.Sub(&p.X, X2Z1) // L.Sub(&p.x, &X2Z1) - C := pr.Ext2.Square(O) // C.Square(&O) - D := pr.Ext2.Square(L) // D.Square(&L) - E := pr.Ext2.Mul(L, D) // E.Mul(&L, &D) - F := pr.Ext2.Mul(&p.Z, C) // F.Mul(&p.z, &C) - G := pr.Ext2.Mul(&p.X, D) // G.Mul(&p.x, &D) - t0 := pr.Ext2.Double(G) // t0.Double(&G) - H := pr.Ext2.Add(E, F) // H.Add(&E, &F). - H = pr.Ext2.Sub(H, t0) // Sub(&H, &t0) - t1 := pr.Ext2.Mul(&p.Y, E) // t1.Mul(&p.y, &E) - px := pr.Ext2.Mul(L, H) // p.x.Mul(&L, &H) - py := pr.Ext2.Sub(G, H) // p.y.Sub(&G, &H). - py = pr.Ext2.Mul(py, O) // Mul(&p.y, &O). - py = pr.Ext2.Sub(py, t1) // Sub(&p.y, &t1) - pz := pr.Ext2.Mul(E, &p.Z) // p.z.Mul(&E, &p.z) - t2 := pr.Ext2.Mul(L, &a.Y) // t2.Mul(&L, &a.Y) - J := pr.Ext2.Mul(&a.X, O) // J.Mul(&a.X, &O). - J = pr.Ext2.Sub(J, t2) // Sub(&J, &t2) - ev0 := L // evaluations.r0.Set(&L) - ev1 := pr.Ext2.Neg(O) // evaluations.r1.Neg(&O) - ev2 := J // evaluations.r2.Set(&J) - return &g2Projective{ - X: *px, - Y: *py, - Z: *pz, - }, &lineEvaluation{ - r0: *ev0, - r1: *ev1, - r2: *ev2, - } -} - -type lineEvaluation struct { - r0 fields_bn254.E2 - r1 fields_bn254.E2 - r2 fields_bn254.E2 -} - -var loopCounter = [66]int8{ - 0, 0, 0, 1, 0, 1, 0, -1, 0, 0, -1, - 0, 0, 0, 1, 0, 0, -1, 0, -1, 0, 0, - 0, 1, 0, -1, 0, 0, 0, 0, -1, 0, 0, - 1, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, - -1, 0, 0, -1, 0, 1, 0, -1, 0, 0, 0, - -1, 0, -1, 0, 0, 0, 1, 0, -1, 0, 1, -} - -func (pr Pairing) MillerLoop(api frontend.API, p []*G1Affine, q []*G2Affine) (*GTEl, error) { - n := len(p) - if n == 0 || n != len(q) { - return nil, fmt.Errorf("invalid inputs sizes") - } - - // TODO: we have omitted filtering for infinity points. - - // projective points for Q - qProj := make([]*g2Projective, n) // qProj := make([]g2Proj, n) - qNeg := make([]*G2Affine, n) // qNeg := make([]G2Affine, n) - for k := 0; k < n; k++ { - qProj[k] = pr.affineToProjective(q[k]) // qProj[k].FromAffine(&q[k]) - qNeg[k] = pr.NegAffine(q[k]) // qNeg[k].Neg(&q[k]) - } - - var l, l0 *lineEvaluation - result := pr.Ext12.One() // var tmp, result GTEl - - // i == len(loopCounter) - 2 - for k := 0; k < n; k++ { - qProj[k], l = pr.DoubleStep(api, qProj[k]) // qProj[k].DoubleStep(&l) - l.r0 = *pr.Ext12.Ext2.MulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1 = *pr.Ext12.Ext2.MulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) - result = pr.Ext12.MulBy034(result, &l.r0, &l.r1, &l.r2) // result.MulBy034(&l.r0, &l.r1, &l.r2) - } - - for i := len(loopCounter) - 3; i >= 0; i-- { - result = pr.Ext12.Square(result) // result.Square(&result) - - for k := 0; k < n; k++ { - qProj[k], l = pr.DoubleStep(api, qProj[k]) // qProj[k].DoubleStep(&l) - l.r0 = *pr.Ext12.Ext2.MulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1 = *pr.Ext12.Ext2.MulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) - - if loopCounter[i] == 1 { - qProj[k], l0 = pr.AddStep(qProj[k], q[k]) // qProj[k].AddMixedStep(&l0, &q[k]) - l0.r0 = *pr.Ext12.Ext2.MulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) - l0.r1 = *pr.Ext12.Ext2.MulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) - tmp := pr.Ext12.MulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result = pr.Ext12.Mul(result, tmp) // result.Mul(&result, &tmp) - } else if loopCounter[i] == -1 { - qProj[k], l0 = pr.AddStep(qProj[k], qNeg[k]) // qProj[k].AddMixedStep(&l0, &qNeg[k]) - l0.r0 = *pr.Ext12.Ext2.MulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) - l0.r1 = *pr.Ext12.Ext2.MulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) - tmp := pr.Ext12.MulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result = pr.Ext12.Mul(result, tmp) //result.Mul(&result, &tmp) - } else { - result = pr.Ext12.MulBy034(result, &l.r0, &l.r1, &l.r2) // result.MulBy034(&l.r0, &l.r1, &l.r2) - } - } - } - - Q1, Q2 := new(G2Affine), new(G2Affine) // var Q1, Q2 G2Affine - for k := 0; k < n; k++ { - //Q1 = π(Q) - // TODO(ivokub): define phi(Q) in G2 instead of doing manually? - Q1.X = *pr.Ext12.Ext2.Conjugate(&q[k].X) // Q1.X.Conjugate(&q[k].X).MulByNonResidue1Power2(&Q1.X) - Q1.X = *pr.Ext12.Ext2.MulByNonResidue1Power2(&Q1.X) // Q1.X.Conjugate(&q[k].X).MulByNonResidue1Power2(&Q1.X) - Q1.Y = *pr.Ext12.Ext2.Conjugate(&q[k].Y) // Q1.Y.Conjugate(&q[k].Y).MulByNonResidue1Power3(&Q1.Y) - Q1.Y = *pr.Ext12.Ext2.MulByNonResidue1Power3(&Q1.Y) // Q1.Y.Conjugate(&q[k].Y).MulByNonResidue1Power3(&Q1.Y) - - // Q2 = -π²(Q) - Q2.X = *pr.Ext12.Ext2.MulByNonResidue2Power2(&q[k].X) // Q2.X.MulByNonResidufields_bn254.E2Power2(&q[k].X) - Q2.Y = *pr.Ext12.Ext2.MulByNonResidue2Power3(&q[k].Y) // Q2.Y.MulByNonResidufields_bn254.E2Power3(&q[k].Y).Neg(&Q2.Y) - Q2.Y = *pr.Ext12.Ext2.Neg(&Q2.Y) // Q2.Y.MulByNonResidufields_bn254.E2Power3(&q[k].Y).Neg(&Q2.Y) - - qProj[k], l0 = pr.AddStep(qProj[k], Q1) // qProj[k].AddMixedStep(&l0, &Q1) - l0.r0 = *pr.Ext12.Ext2.MulByElement(&l0.r0, &p[k].Y) // l0.r0.MulByElement(&l0.r0, &p[k].Y) - l0.r1 = *pr.Ext12.Ext2.MulByElement(&l0.r1, &p[k].X) // l0.r1.MulByElement(&l0.r1, &p[k].X) - - qProj[k], l = pr.AddStep(qProj[k], Q2) // qProj[k].AddMixedStep(&l, &Q2) - l.r0 = *pr.Ext12.Ext2.MulByElement(&l.r0, &p[k].Y) // l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1 = *pr.Ext12.Ext2.MulByElement(&l.r1, &p[k].X) // l.r1.MulByElement(&l.r1, &p[k].X) - tmp := pr.Ext12.MulBy034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) // tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result = pr.Ext12.Mul(result, tmp) // result.Mul(&result, &tmp) - } - - return result, nil -} - // FinalExponentiation computes the exponentiation eᵈ // where d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r // we use instead d'= s ⋅ d, where s is the cofactor 2x₀(6x₀²+3x₀+1) @@ -316,10 +114,265 @@ func (pr Pairing) Pair(api frontend.API, P []*G1Affine, Q []*G2Affine) (*GTEl, e if err != nil { return nil, fmt.Errorf("miller loop: %w", err) } - res = pr.FinalExponentiation(api, res) - return res, nil + res = *pr.FinalExponentiation(api, &res) + return &res, nil } func (pr Pairing) AssertIsEqual(x, y *GTEl) { pr.Ext12.AssertIsEqual(x, y) } + +// loopCounter = 6*seed+2 in 2-NAF +var loopCounter = [66]int8{ + 0, 0, 0, 1, 0, 1, 0, -1, 0, 0, -1, + 0, 0, 0, 1, 0, 0, -1, 0, -1, 0, 0, + 0, 1, 0, -1, 0, 0, 0, 0, -1, 0, 0, + 1, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, + -1, 0, 0, -1, 0, 1, 0, -1, 0, 0, 0, + -1, 0, -1, 0, 0, 0, 1, 0, -1, 0, 1, +} + +// LineEvaluation represents a sparse Fp12 Elmt (result of the line evaluation) +// line: 1 - R0*(x/y) - R1*(1/y) = 0 instead of R0'*y - R1'*x - R2' = 0 +// This makes the multiplication by lines (MulBy034) circuit-efficient. +type LineEvaluation struct { + R0, R1 fields_bn254.E2 +} + +// MillerLoop computes the multi-Miller loop +func (pr Pairing) MillerLoop(api frontend.API, P []*G1Affine, Q []*G2Affine) (GTEl, error) { + ba, err := emulated.NewField[emulated.BN254Fp](api) + if err != nil { + return GTEl{}, fmt.Errorf("new base api: %w", err) + } + // check input size match + n := len(P) + if n == 0 || n != len(Q) { + return GTEl{}, errors.New("invalid inputs sizes") + } + + res := pr.Ext12.One() + + var l1, l2 LineEvaluation + Qacc := make([]G2Affine, n) + QNeg := make([]G2Affine, n) + yInv := make([]emulated.Element[emulated.BN254Fp], n) + xOverY := make([]emulated.Element[emulated.BN254Fp], n) + + for k := 0; k < n; k++ { + Qacc[k] = *Q[k] + QNeg[k].X = Q[k].X + QNeg[k].Y = *pr.Ext2.Neg(&Q[k].Y) + yInv[k] = *ba.Inverse(&P[k].Y) + xOverY[k] = *ba.Div(&P[k].X, &P[k].Y) + } + + // k = 0 + Qacc[0], l1 = pr.doubleStep(api, &Qacc[0]) + res.C1.B0 = *pr.MulByElement(&l1.R0, &xOverY[0]) + res.C1.B1 = *pr.MulByElement(&l1.R1, &yInv[0]) + + if n >= 2 { + // k = 1 + Qacc[1], l1 = pr.doubleStep(api, &Qacc[1]) + l1.R0 = *pr.MulByElement(&l1.R0, &xOverY[1]) + l1.R1 = *pr.MulByElement(&l1.R1, &yInv[1]) + res = pr.Mul034By034(l1.R0, l1.R1, res.C1.B0, res.C1.B1) + } + + if n >= 3 { + // k >= 2 + for k := 2; k < n; k++ { + Qacc[k], l1 = pr.doubleStep(api, &Qacc[k]) + l1.R0 = *pr.MulByElement(&l1.R0, &xOverY[k]) + l1.R1 = *pr.MulByElement(&l1.R1, &yInv[k]) + res = pr.MulBy034(res, l1.R0, l1.R1) + } + } + + for i := len(loopCounter) - 3; i >= 0; i-- { + res = pr.Square(res) + + switch loopCounter[i] { + + case 0: + for k := 0; k < n; k++ { + Qacc[k], l1 = pr.doubleStep(api, &Qacc[k]) + l1.R0 = *pr.MulByElement(&l1.R0, &xOverY[k]) + l1.R1 = *pr.MulByElement(&l1.R1, &yInv[k]) + res = pr.MulBy034(res, l1.R0, l1.R1) + } + + case 1: + for k := 0; k < n; k++ { + Qacc[k], l1, l2 = pr.doubleAndAddStep(api, &Qacc[k], Q[k]) + l1.R0 = *pr.MulByElement(&l1.R0, &xOverY[k]) + l1.R1 = *pr.MulByElement(&l1.R1, &yInv[k]) + res = pr.MulBy034(res, l1.R0, l1.R1) + l2.R0 = *pr.MulByElement(&l2.R0, &xOverY[k]) + l2.R1 = *pr.MulByElement(&l2.R1, &yInv[k]) + res = pr.MulBy034(res, l2.R0, l2.R1) + } + + case -1: + for k := 0; k < n; k++ { + Qacc[k], l1, l2 = pr.doubleAndAddStep(api, &Qacc[k], &QNeg[k]) + l1.R0 = *pr.MulByElement(&l1.R0, &xOverY[k]) + l1.R1 = *pr.MulByElement(&l1.R1, &yInv[k]) + res = pr.MulBy034(res, l1.R0, l1.R1) + l2.R0 = *pr.MulByElement(&l2.R0, &xOverY[k]) + l2.R1 = *pr.MulByElement(&l2.R1, &yInv[k]) + res = pr.MulBy034(res, l2.R0, l2.R1) + } + + default: + return GTEl{}, errors.New("invalid loopCounter") + } + } + + Q1, Q2 := new(G2Affine), new(G2Affine) + for k := 0; k < n; k++ { + //Q1 = π(Q) + Q1.X = *pr.Ext12.Ext2.Conjugate(&Q[k].X) + Q1.X = *pr.Ext12.Ext2.MulByNonResidue1Power2(&Q1.X) + Q1.Y = *pr.Ext12.Ext2.Conjugate(&Q[k].Y) + Q1.Y = *pr.Ext12.Ext2.MulByNonResidue1Power3(&Q1.Y) + + // Q2 = -π²(Q) + Q2.X = *pr.Ext12.Ext2.MulByNonResidue2Power2(&Q[k].X) + Q2.Y = *pr.Ext12.Ext2.MulByNonResidue2Power3(&Q[k].Y) + Q2.Y = *pr.Ext12.Ext2.Neg(&Q2.Y) + + Qacc[k], l1 = pr.addStep(api, &Qacc[k], Q1) + l1.R0 = *pr.Ext2.MulByElement(&l1.R0, &xOverY[k]) + l1.R1 = *pr.Ext2.MulByElement(&l1.R1, &yInv[k]) + res = pr.MulBy034(res, l1.R0, l1.R1) + + Qacc[k], l2 = pr.addStep(api, &Qacc[k], Q2) + l2.R0 = *pr.MulByElement(&l2.R0, &xOverY[k]) + l2.R1 = *pr.MulByElement(&l2.R1, &yInv[k]) + res = pr.MulBy034(res, l2.R0, l2.R1) + + } + + return *res, nil +} + +// doubleAndAddStep doubles p1 and adds p2 to the result in affine coordinates, and evaluates the line in Miller loop +// https://eprint.iacr.org/2022/1162 (Section 6.1) +func (pr Pairing) doubleAndAddStep(api frontend.API, p1, p2 *G2Affine) (G2Affine, LineEvaluation, LineEvaluation) { + + var line1, line2 LineEvaluation + var p G2Affine + + // compute lambda1 = (y2-y1)/(x2-x1) + n := pr.Ext2.Sub(&p1.Y, &p2.Y) + d := pr.Ext2.Sub(&p1.X, &p2.X) + l1 := pr.Ext2.DivUnchecked(api, *n, *d) + + // x3 =lambda1**2-p1.x-p2.x + x3 := pr.Ext2.Square(l1) + x3 = pr.Ext2.Sub(x3, &p1.X) + x3 = pr.Ext2.Sub(x3, &p2.X) + + // omit y3 computation + + // compute line1 + line1.R0 = *pr.Ext2.Neg(l1) + line1.R1 = *pr.Ext2.Mul(l1, &p1.X) + line1.R1 = *pr.Ext2.Sub(&line1.R1, &p1.Y) + + // compute lambda2 = -lambda1-2*y1/(x3-x1) + n = pr.Ext2.Double(&p1.Y) + d = pr.Ext2.Sub(x3, &p1.X) + l2 := pr.Ext2.DivUnchecked(api, *n, *d) + l2 = pr.Ext2.Add(l2, l1) + l2 = pr.Ext2.Neg(l2) + + // compute x4 = lambda2**2-x1-x3 + x4 := pr.Ext2.Square(l2) + x4 = pr.Ext2.Sub(x4, &p1.X) + x4 = pr.Ext2.Sub(x4, x3) + + // compute y4 = lambda2*(x1 - x4)-y1 + y4 := pr.Ext2.Sub(&p1.X, x4) + y4 = pr.Ext2.Mul(l2, y4) + y4 = pr.Ext2.Sub(y4, &p1.Y) + + p.X = *x4 + p.Y = *y4 + + // compute line2 + line2.R0 = *pr.Ext2.Neg(l2) + line2.R1 = *pr.Ext2.Mul(l2, &p1.X) + line2.R1 = *pr.Ext2.Sub(&line2.R1, &p1.Y) + + return p, line1, line2 +} + +// doubleStep doubles a point in affine coordinates, and evaluates the line in Miller loop +// https://eprint.iacr.org/2022/1162 (Section 6.1) +func (pr Pairing) doubleStep(api frontend.API, p1 *G2Affine) (G2Affine, LineEvaluation) { + + var p G2Affine + var line LineEvaluation + + // lambda = 3*p1.x**2/2*p.y + n := pr.Ext2.Square(&p1.X) + three := emulated.ValueOf[emulated.BN254Fp](3) + n = pr.Ext2.MulByElement(n, &three) + d := pr.Ext2.Double(&p1.Y) + l := pr.Ext2.DivUnchecked(api, *n, *d) + + // xr = lambda**2-2*p1.x + xr := pr.Ext2.Square(l) + xr = pr.Ext2.Sub(xr, &p1.X) + xr = pr.Ext2.Sub(xr, &p1.X) + + // yr = lambda*(p.x-xr)-p.y + yr := pr.Ext2.Sub(&p1.X, xr) + yr = pr.Ext2.Mul(l, yr) + yr = pr.Ext2.Sub(yr, &p1.Y) + + p.X = *xr + p.Y = *yr + + line.R0 = *pr.Ext2.Neg(l) + line.R1 = *pr.Ext2.Mul(l, &p1.X) + line.R1 = *pr.Ext2.Sub(&line.R1, &p1.Y) + + return p, line + +} + +// addStep adds two points in affine coordinates, and evaluates the line in Miller loop +// https://eprint.iacr.org/2022/1162 (Section 6.1) +func (pr Pairing) addStep(api frontend.API, p, q *G2Affine) (G2Affine, LineEvaluation) { + + // compute λ = (q.y-p.y)/(q.x-p.x) + qypy := pr.Ext2.Sub(&q.Y, &p.Y) + qxpx := pr.Ext2.Sub(&q.X, &p.X) + λ := pr.Ext2.DivUnchecked(api, *qypy, *qxpx) + + // xr = λ²-p.x-q.x + λλ := pr.Ext2.Square(λ) + qxpx = pr.Ext2.Add(&p.X, &q.X) + xr := pr.Ext2.Sub(λλ, qxpx) + + // p.y = λ(p.x-r.x) - p.y + pxrx := pr.Ext2.Sub(&p.X, xr) + λpxrx := pr.Ext2.Mul(λ, pxrx) + yr := pr.Ext2.Sub(λpxrx, &p.Y) + + var res G2Affine + res.X = *xr + res.Y = *yr + + var line LineEvaluation + line.R0 = *pr.Ext2.Neg(λ) + line.R1 = *pr.Ext2.Mul(λ, &p.X) + line.R1 = *pr.Ext2.Sub(&line.R1, &p.Y) + + return res, line + +} diff --git a/std/algebra/emulated/sw_bn254/pairing_test.go b/std/algebra/emulated/sw_bn254/pairing_test.go index 763d18bd48..e21e578db7 100644 --- a/std/algebra/emulated/sw_bn254/pairing_test.go +++ b/std/algebra/emulated/sw_bn254/pairing_test.go @@ -28,39 +28,6 @@ func randomG1G2Affines(assert *test.Assert) (bn254.G1Affine, bn254.G2Affine) { return p, q } -type MillerLoopCircuit struct { - InG1 G1Affine - InG2 G2Affine - Res GTEl -} - -func (c *MillerLoopCircuit) Define(api frontend.API) error { - pairing, err := NewPairing(api) - if err != nil { - return fmt.Errorf("new pairing: %w", err) - } - res, err := pairing.MillerLoop(api, []*G1Affine{&c.InG1}, []*G2Affine{&c.InG2}) - if err != nil { - return fmt.Errorf("pair: %w", err) - } - pairing.AssertIsEqual(res, &c.Res) - return nil -} - -func TestMillerLoopTestSolve(t *testing.T) { - assert := test.NewAssert(t) - p, q := randomG1G2Affines(assert) - res, err := bn254.MillerLoop([]bn254.G1Affine{p}, []bn254.G2Affine{q}) - assert.NoError(err) - witness := MillerLoopCircuit{ - InG1: NewG1Affine(p), - InG2: NewG2Affine(q), - Res: NewGTEl(res), - } - err = test.IsSolved(&MillerLoopCircuit{}, &witness, ecc.BN254.ScalarField()) - assert.NoError(err) -} - type FinalExponentiationCircuit struct { InGt GTEl Res GTEl From 2d2254a1047be5046eda4099845399bb3eeab932 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 14 Mar 2023 20:09:11 +0100 Subject: [PATCH 118/464] refactor(pairing-bn254): remove dead code --- std/algebra/emulated/fields_bn254/e2.go | 32 ---------- std/algebra/emulated/fields_bn254/e2_test.go | 64 ------------------- std/algebra/emulated/fields_bn254/hints.go | 20 ------ std/algebra/emulated/sw_bn254/pairing_test.go | 14 ---- 4 files changed, 130 deletions(-) diff --git a/std/algebra/emulated/fields_bn254/e2.go b/std/algebra/emulated/fields_bn254/e2.go index 52f3ffb35c..e208424538 100644 --- a/std/algebra/emulated/fields_bn254/e2.go +++ b/std/algebra/emulated/fields_bn254/e2.go @@ -305,13 +305,6 @@ func (e Ext2) Halve(api frontend.API, x *E2) *E2 { } -func (e Ext2) MulBybTwistCurveCoeff(api frontend.API, x *E2) *E2 { - res := e.MulByNonResidueInv(api, x) - z := e.Double(res) - z = e.Add(z, res) - return z -} - func (e Ext2) AssertIsEqual(x, y *E2) { e.fp.AssertIsEqual(&x.A0, &y.A0) e.fp.AssertIsEqual(&x.A1, &y.A1) @@ -373,28 +366,3 @@ func (e Ext2) DivUnchecked(api frontend.API, x, y E2) *E2 { return &div } - -func (e Ext2) MulByNonResidueInv(api frontend.API, x *E2) *E2 { - field, err := emulated.NewField[emulated.BN254Fp](api) - if err != nil { - panic(err) - } - res, err := field.NewHint(MulByNonResidueInvHint, 2, &x.A0, &x.A1) - if err != nil { - // err is non-nil only for invalid number of inputs - panic(err) - } - - // r <-- x * (1/(9+u)) - r := E2{ - A0: *res[0], - A1: *res[1], - } - - // x == r * (9+u) - _x := e.MulByNonResidue(&r) - e.AssertIsEqual(x, _x) - - return &r - -} diff --git a/std/algebra/emulated/fields_bn254/e2_test.go b/std/algebra/emulated/fields_bn254/e2_test.go index 224492cffb..9139392bbf 100644 --- a/std/algebra/emulated/fields_bn254/e2_test.go +++ b/std/algebra/emulated/fields_bn254/e2_test.go @@ -271,38 +271,6 @@ func TestMulByElement(t *testing.T) { } -type e2MulBybTwistCurveCoeff struct { - A E2 - C E2 `gnark:",public"` -} - -func (circuit *e2MulBybTwistCurveCoeff) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt2(ba) - expected := e.MulBybTwistCurveCoeff(api, &circuit.A) - e.AssertIsEqual(expected, &circuit.C) - - return nil -} - -func TestMulFp2BybTwistCurveCoeff(t *testing.T) { - - assert := test.NewAssert(t) - // witness values - var a, c bn254.E2 - _, _ = a.SetRandom() - c.MulBybTwistCurveCoeff(&a) - - witness := e2MulBybTwistCurveCoeff{ - A: FromE2(&a), - C: FromE2(&c), - } - - err := test.IsSolved(&e2MulBybTwistCurveCoeff{}, &witness, ecc.BN254.ScalarField()) - assert.NoError(err) - -} - type e2MulByNonResidue struct { A E2 C E2 `gnark:",public"` @@ -335,38 +303,6 @@ func TestMulFp2ByNonResidue(t *testing.T) { } -type e2MulByNonResidueInv struct { - A E2 - C E2 `gnark:",public"` -} - -func (circuit *e2MulByNonResidueInv) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt2(ba) - expected := e.MulByNonResidueInv(api, &circuit.A) - e.AssertIsEqual(expected, &circuit.C) - - return nil -} - -func TestMulFp2ByNonResidueInv(t *testing.T) { - - assert := test.NewAssert(t) - // witness values - var a, c bn254.E2 - _, _ = a.SetRandom() - c.MulByNonResidueInv(&a) - - witness := e2MulByNonResidueInv{ - A: FromE2(&a), - C: FromE2(&c), - } - - err := test.IsSolved(&e2MulByNonResidueInv{}, &witness, ecc.BN254.ScalarField()) - assert.NoError(err) - -} - type e2Neg struct { A E2 C E2 `gnark:",public"` diff --git a/std/algebra/emulated/fields_bn254/hints.go b/std/algebra/emulated/fields_bn254/hints.go index 6272b925bd..e04c95751c 100644 --- a/std/algebra/emulated/fields_bn254/hints.go +++ b/std/algebra/emulated/fields_bn254/hints.go @@ -18,7 +18,6 @@ func GetHints() []solver.Hint { // E2 DivE2Hint, InverseE2Hint, - MulByNonResidueInvHint, HalveE2Hint, // E6 DivE6Hint, @@ -29,25 +28,6 @@ func GetHints() []solver.Hint { } } -// E2 hints -func MulByNonResidueInvHint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { - return emulated.UnwrapHint(nativeInputs, nativeOutputs, - func(mod *big.Int, inputs, outputs []*big.Int) error { - var a, c bn254.E2 - - a.A0.SetBigInt(inputs[0]) - a.A1.SetBigInt(inputs[1]) - - c.MulByNonResidueInv(&a) - - c.A0.BigInt(outputs[0]) - c.A1.BigInt(outputs[1]) - - return nil - - }) -} - func InverseE2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { return emulated.UnwrapHint(nativeInputs, nativeOutputs, func(mod *big.Int, inputs, outputs []*big.Int) error { diff --git a/std/algebra/emulated/sw_bn254/pairing_test.go b/std/algebra/emulated/sw_bn254/pairing_test.go index e21e578db7..23eea2a01b 100644 --- a/std/algebra/emulated/sw_bn254/pairing_test.go +++ b/std/algebra/emulated/sw_bn254/pairing_test.go @@ -7,10 +7,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/profile" "github.com/consensys/gnark/test" ) @@ -88,14 +85,3 @@ func TestPairTestSolve(t *testing.T) { err = test.IsSolved(&PairCircuit{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } - -// bench -var ccsBench constraint.ConstraintSystem - -func BenchmarkPairing(b *testing.B) { - var c PairCircuit - p := profile.Start() - ccsBench, _ = frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &c) - p.Stop() - fmt.Println(p.NbConstraints()) -} From b5d3d24108a67a30d0588f00eccc69ba1f2cd5a4 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Tue, 14 Mar 2023 15:00:56 -0500 Subject: [PATCH 119/464] fix: handle nested Define signature in call stack for profile --- profile/profile_test.go | 12 +++++++++++- profile/profile_worker.go | 8 +++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/profile/profile_test.go b/profile/profile_test.go index 9f7d0fca0a..04d5c3ebc7 100644 --- a/profile/profile_test.go +++ b/profile/profile_test.go @@ -15,8 +15,18 @@ type Circuit struct { A frontend.Variable } +type obj struct { +} + func (circuit *Circuit) Define(api frontend.API) error { - api.AssertIsEqual(api.Mul(circuit.A, circuit.A), circuit.A) + var o obj + o.Define(api, circuit.A) + // api.AssertIsEqual(api.Mul(circuit.A, circuit.A), circuit.A) + return nil +} + +func (o *obj) Define(api frontend.API, A frontend.Variable) error { + api.AssertIsEqual(api.Mul(A, A), A) return nil } diff --git a/profile/profile_worker.go b/profile/profile_worker.go index 2465262459..97817fe898 100644 --- a/profile/profile_worker.go +++ b/profile/profile_worker.go @@ -64,6 +64,11 @@ func collectSample(pc []uintptr) { for { frame, more := frames.Next() + if strings.Contains(frame.Function, "frontend.parseCircuit") { + // we stop; previous frame was the .Define definition of the circuit + break + } + if strings.HasSuffix(frame.Function, ".func1") { // TODO @gbotrel filter anonymous func better continue @@ -90,6 +95,7 @@ func collectSample(pc []uintptr) { sessions[i].onceSetName.Do(func() { // once per profile session, we set the "name of the binary" // here we grep the struct name where "Define" exist: hopefully the circuit Name + // note: this won't work well for nested Define calls. fe := strings.Split(frame.Function, "/") circuitName := strings.TrimSuffix(fe[len(fe)-1], ".Define") sessions[i].pprof.Mapping = []*profile.Mapping{ @@ -97,7 +103,7 @@ func collectSample(pc []uintptr) { } }) } - break + // break --> we break when we hit frontend.parseCircuit; in case we have nested Define calls in the stack. } } From 43b03167885b7b479f980ce513cc44da75837cb4 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 14 Mar 2023 21:20:59 +0100 Subject: [PATCH 120/464] perf(pairing-bn254): optimize Miller loop (last line out of loop) --- std/algebra/emulated/sw_bn254/pairing.go | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index d21d821ffe..685c996356 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -248,7 +248,7 @@ func (pr Pairing) MillerLoop(api frontend.API, P []*G1Affine, Q []*G2Affine) (GT l1.R1 = *pr.Ext2.MulByElement(&l1.R1, &yInv[k]) res = pr.MulBy034(res, l1.R0, l1.R1) - Qacc[k], l2 = pr.addStep(api, &Qacc[k], Q2) + l2 = pr.addStepLineOnly(api, &Qacc[k], Q2) l2.R0 = *pr.MulByElement(&l2.R0, &xOverY[k]) l2.R1 = *pr.MulByElement(&l2.R1, &yInv[k]) res = pr.MulBy034(res, l2.R0, l2.R1) @@ -376,3 +376,20 @@ func (pr Pairing) addStep(api frontend.API, p, q *G2Affine) (G2Affine, LineEvalu return res, line } + +// addStepLineOnly computes the line that goes through p and q but does not compute p+q +func (pr Pairing) addStepLineOnly(api frontend.API, p, q *G2Affine) LineEvaluation { + + // compute λ = (q.y-p.y)/(q.x-p.x) + qypy := pr.Ext2.Sub(&q.Y, &p.Y) + qxpx := pr.Ext2.Sub(&q.X, &p.X) + λ := pr.Ext2.DivUnchecked(api, *qypy, *qxpx) + + var line LineEvaluation + line.R0 = *pr.Ext2.Neg(λ) + line.R1 = *pr.Ext2.Mul(λ, &p.X) + line.R1 = *pr.Ext2.Sub(&line.R1, &p.Y) + + return line + +} From 06633e39efbb452d665c707aa1ae2f557410d313 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Wed, 15 Mar 2023 00:59:45 +0100 Subject: [PATCH 121/464] chore: update gnark-crypto dependency for exported towers --- go.mod | 2 +- go.sum | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index b7c7eb4612..2e0673510b 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 - github.com/consensys/gnark-crypto v0.9.2-0.20230222154459-49b5c6cfd875 + github.com/consensys/gnark-crypto v0.9.2-0.20230314094804-5185eb8c3978 github.com/fxamacker/cbor/v2 v2.4.0 github.com/google/go-cmp v0.5.9 github.com/google/pprof v0.0.0-20230207041349-798e818bf904 diff --git a/go.sum b/go.sum index e0f19ca991..9665af65f9 100644 --- a/go.sum +++ b/go.sum @@ -2,10 +2,8 @@ github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.9.1 h1:mru55qKdWl3E035hAoh1jj9d7hVnYY5pfb6tmovSmII= -github.com/consensys/gnark-crypto v0.9.1/go.mod h1:a2DQL4+5ywF6safEeZFEPGRiiGbjzGFRUN2sg06VuU4= -github.com/consensys/gnark-crypto v0.9.2-0.20230222154459-49b5c6cfd875 h1:FTOvlE+90hvp+XHi8i89xCejJ0627wfbP0RSWzmVFks= -github.com/consensys/gnark-crypto v0.9.2-0.20230222154459-49b5c6cfd875/go.mod h1:a2DQL4+5ywF6safEeZFEPGRiiGbjzGFRUN2sg06VuU4= +github.com/consensys/gnark-crypto v0.9.2-0.20230314094804-5185eb8c3978 h1:jMmg1FkGd5+Fv1jWNTwSIGVz5qkabvPvbfFb5v1mmIA= +github.com/consensys/gnark-crypto v0.9.2-0.20230314094804-5185eb8c3978/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= From ff24422fb678bf97b0ecbff0fc31a9b29885625b Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Wed, 15 Mar 2023 01:58:40 +0100 Subject: [PATCH 122/464] refactor: unify calling interfaces Unify the interfaces: * everywhere work with pointers to avoid unnecessary copies (Elements may be large) * do not pass frontend.API when necessary, use existing stored field emulation --- std/algebra/emulated/fields_bn254/e12.go | 136 ++++++++-------- .../emulated/fields_bn254/e12_pairing.go | 74 +++++---- std/algebra/emulated/fields_bn254/e12_test.go | 17 +- std/algebra/emulated/fields_bn254/e2.go | 38 ++--- std/algebra/emulated/fields_bn254/e2_test.go | 7 +- std/algebra/emulated/fields_bn254/e6.go | 26 +-- std/algebra/emulated/fields_bn254/e6_test.go | 4 +- std/algebra/emulated/sw_bn254/doc_test.go | 2 +- std/algebra/emulated/sw_bn254/pairing.go | 153 +++++++++--------- std/algebra/emulated/sw_bn254/pairing_test.go | 4 +- 10 files changed, 208 insertions(+), 253 deletions(-) diff --git a/std/algebra/emulated/fields_bn254/e12.go b/std/algebra/emulated/fields_bn254/e12.go index 4f52741272..e81c8b0078 100644 --- a/std/algebra/emulated/fields_bn254/e12.go +++ b/std/algebra/emulated/fields_bn254/e12.go @@ -2,8 +2,6 @@ package fields_bn254 import ( "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/math/emulated" ) type E12 struct { @@ -124,83 +122,83 @@ func (e Ext12) CyclotomicSquare(x *E12) *E12 { func (e Ext12) CyclotomicSquareCompressed(x *E12) *E12 { // t0 = g1^2 - t0 := e.Ext6.Ext2.Square(&x.C0.B1) + t0 := e.Ext2.Square(&x.C0.B1) // t1 = g5^2 - t1 := e.Ext6.Ext2.Square(&x.C1.B2) + t1 := e.Ext2.Square(&x.C1.B2) // t5 = g1 + g5 - t5 := e.Ext6.Ext2.Add(&x.C0.B1, &x.C1.B2) + t5 := e.Ext2.Add(&x.C0.B1, &x.C1.B2) // t2 = (g1 + g5)^2 - t2 := e.Ext6.Ext2.Square(t5) + t2 := e.Ext2.Square(t5) // t3 = g1^2 + g5^2 - t3 := e.Ext6.Ext2.Add(t0, t1) + t3 := e.Ext2.Add(t0, t1) // t5 = 2 * g1 * g5 - t5 = e.Ext6.Ext2.Sub(t2, t3) + t5 = e.Ext2.Sub(t2, t3) // t6 = g3 + g2 - t6 := e.Ext6.Ext2.Add(&x.C1.B0, &x.C0.B2) + t6 := e.Ext2.Add(&x.C1.B0, &x.C0.B2) // t3 = (g3 + g2)^2 - t3 = e.Ext6.Ext2.Square(t6) + t3 = e.Ext2.Square(t6) // t2 = g3^2 - t2 = e.Ext6.Ext2.Square(&x.C1.B0) + t2 = e.Ext2.Square(&x.C1.B0) // t6 = 2 * nr * g1 * g5 - t6 = e.Ext6.Ext2.MulByNonResidue(t5) + t6 = e.Ext2.MulByNonResidue(t5) // t5 = 4 * nr * g1 * g5 + 2 * g3 - t5 = e.Ext6.Ext2.Add(t6, &x.C1.B0) - t5 = e.Ext6.Ext2.Double(t5) + t5 = e.Ext2.Add(t6, &x.C1.B0) + t5 = e.Ext2.Double(t5) // z3 = 6 * nr * g1 * g5 + 2 * g3 - C1B0 := *e.Ext6.Ext2.Add(t5, t6) + C1B0 := e.Ext2.Add(t5, t6) // t4 = nr * g5^2 - t4 := e.Ext6.Ext2.MulByNonResidue(t1) + t4 := e.Ext2.MulByNonResidue(t1) // t5 = nr * g5^2 + g1^2 - t5 = e.Ext6.Ext2.Add(t0, t4) + t5 = e.Ext2.Add(t0, t4) // t6 = nr * g5^2 + g1^2 - g2 - t6 = e.Ext6.Ext2.Sub(t5, &x.C0.B2) + t6 = e.Ext2.Sub(t5, &x.C0.B2) // t1 = g2^2 - t1 = e.Ext6.Ext2.Square(&x.C0.B2) + t1 = e.Ext2.Square(&x.C0.B2) // t6 = 2 * nr * g5^2 + 2 * g1^2 - 2*g2 - t6 = e.Ext6.Ext2.Double(t6) + t6 = e.Ext2.Double(t6) // z2 = 3 * nr * g5^2 + 3 * g1^2 - 2*g2 - C0B2 := *e.Ext6.Ext2.Add(t6, t5) + C0B2 := e.Ext2.Add(t6, t5) // t4 = nr * g2^2 - t4 = e.Ext6.Ext2.MulByNonResidue(t1) + t4 = e.Ext2.MulByNonResidue(t1) // t5 = g3^2 + nr * g2^2 - t5 = e.Ext6.Ext2.Add(t2, t4) + t5 = e.Ext2.Add(t2, t4) // t6 = g3^2 + nr * g2^2 - g1 - t6 = e.Ext6.Ext2.Sub(t5, &x.C0.B1) + t6 = e.Ext2.Sub(t5, &x.C0.B1) // t6 = 2 * g3^2 + 2 * nr * g2^2 - 2 * g1 - t6 = e.Ext6.Ext2.Double(t6) + t6 = e.Ext2.Double(t6) // z1 = 3 * g3^2 + 3 * nr * g2^2 - 2 * g1 - C0B1 := *e.Ext6.Ext2.Add(t6, t5) + C0B1 := e.Ext2.Add(t6, t5) // t0 = g2^2 + g3^2 - t0 = e.Ext6.Ext2.Add(t2, t1) + t0 = e.Ext2.Add(t2, t1) // t5 = 2 * g3 * g2 - t5 = e.Ext6.Ext2.Sub(t3, t0) + t5 = e.Ext2.Sub(t3, t0) // t6 = 2 * g3 * g2 + g5 - t6 = e.Ext6.Ext2.Add(t5, &x.C1.B2) + t6 = e.Ext2.Add(t5, &x.C1.B2) // t6 = 4 * g3 * g2 + 2 * g5 - t6 = e.Ext6.Ext2.Double(t6) + t6 = e.Ext2.Double(t6) // z5 = 6 * g3 * g2 + 2 * g5 - C1B2 := *e.Ext6.Ext2.Add(t5, t6) + C1B2 := e.Ext2.Add(t5, t6) - zero := e.Ext6.Ext2.Zero() + zero := e.Ext2.Zero() return &E12{ C0: E6{ B0: *zero, - B1: C0B1, - B2: C0B2, + B1: *C0B1, + B2: *C0B2, }, C1: E6{ - B0: C1B0, + B0: *C1B0, B1: *zero, - B2: C1B2, + B2: *C1B2, }, } } @@ -213,42 +211,42 @@ func (e Ext12) NCycloSquareCompressed(z *E12, n int) *E12 { } // DecompressKarabina Karabina's cyclotomic square result -func (e Ext12) DecompressKarabina(api frontend.API, x *E12) *E12 { +func (e Ext12) DecompressKarabina(x *E12) *E12 { - one := e.Ext6.Ext2.One() + one := e.Ext2.One() // TODO: hadle the g3==0 case with MUX // t0 = g1^2 - t0 := e.Ext6.Ext2.Square(&x.C0.B1) + t0 := e.Ext2.Square(&x.C0.B1) // t1 = 3 * g1^2 - 2 * g2 - t1 := e.Ext6.Ext2.Sub(t0, &x.C0.B2) - t1 = e.Ext6.Ext2.Double(t1) - t1 = e.Ext6.Ext2.Add(t1, t0) + t1 := e.Ext2.Sub(t0, &x.C0.B2) + t1 = e.Ext2.Double(t1) + t1 = e.Ext2.Add(t1, t0) // t0 = E * g5^2 + t1 - t2 := e.Ext6.Ext2.Square(&x.C1.B2) - t0 = e.Ext6.Ext2.MulByNonResidue(t2) - t0 = e.Ext6.Ext2.Add(t0, t1) + t2 := e.Ext2.Square(&x.C1.B2) + t0 = e.Ext2.MulByNonResidue(t2) + t0 = e.Ext2.Add(t0, t1) // t1 = 4 * g3 - t1 = e.Ext6.Ext2.Double(&x.C1.B0) - t1 = e.Ext6.Ext2.Double(t1) + t1 = e.Ext2.Double(&x.C1.B0) + t1 = e.Ext2.Double(t1) // z4 = g4 - C1B1 := e.Ext6.Ext2.DivUnchecked(api, *t0, *t1) + C1B1 := e.Ext2.DivUnchecked(t0, t1) // t1 = g2 * g1 - t1 = e.Ext6.Ext2.Mul(&x.C0.B2, &x.C0.B1) + t1 = e.Ext2.Mul(&x.C0.B2, &x.C0.B1) // t2 = 2 * g4^2 - 3 * g2 * g1 - t2 = e.Ext6.Ext2.Square(C1B1) - t2 = e.Ext6.Ext2.Sub(t2, t1) - t2 = e.Ext6.Ext2.Double(t2) - t2 = e.Ext6.Ext2.Sub(t2, t1) + t2 = e.Ext2.Square(C1B1) + t2 = e.Ext2.Sub(t2, t1) + t2 = e.Ext2.Double(t2) + t2 = e.Ext2.Sub(t2, t1) // t1 = g3 * g5 (g3 can be 0) - t1 = e.Ext6.Ext2.Mul(&x.C1.B0, &x.C1.B2) + t1 = e.Ext2.Mul(&x.C1.B0, &x.C1.B2) // c_0 = E * (2 * g4^2 + g3 * g5 - 3 * g2 * g1) + 1 - t2 = e.Ext6.Ext2.Add(t2, t1) - C0B0 := e.Ext6.Ext2.MulByNonResidue(t2) - C0B0 = e.Ext6.Ext2.Add(C0B0, one) + t2 = e.Ext2.Add(t2, t1) + C0B0 := e.Ext2.MulByNonResidue(t2) + C0B0 = e.Ext2.Add(C0B0, one) return &E12{ C0: E6{ @@ -376,12 +374,8 @@ func FromE12(y *bn254.E12) E12 { } -func (e Ext12) Inverse(api frontend.API, x *E12) *E12 { - field, err := emulated.NewField[emulated.BN254Fp](api) - if err != nil { - panic(err) - } - res, err := field.NewHint(InverseE12Hint, 12, &x.C0.B0.A0, &x.C0.B0.A1, &x.C0.B1.A0, &x.C0.B1.A1, &x.C0.B2.A0, &x.C0.B2.A1, &x.C1.B0.A0, &x.C1.B0.A1, &x.C1.B1.A0, &x.C1.B1.A1, &x.C1.B2.A0, &x.C1.B2.A1) +func (e Ext12) Inverse(x *E12) *E12 { + res, err := e.fp.NewHint(InverseE12Hint, 12, &x.C0.B0.A0, &x.C0.B0.A1, &x.C0.B1.A0, &x.C0.B1.A1, &x.C0.B2.A0, &x.C0.B2.A1, &x.C1.B0.A0, &x.C1.B0.A1, &x.C1.B1.A0, &x.C1.B1.A1, &x.C1.B2.A0, &x.C1.B2.A1) if err != nil { // err is non-nil only for invalid number of inputs panic(err) @@ -403,20 +397,16 @@ func (e Ext12) Inverse(api frontend.API, x *E12) *E12 { one := e.One() // 1 == inv * x - _one := *e.Mul(&inv, x) - e.AssertIsEqual(one, &_one) + _one := e.Mul(&inv, x) + e.AssertIsEqual(one, _one) return &inv } // DivUnchecked e2 elmts -func (e Ext12) DivUnchecked(api frontend.API, x, y E12) *E12 { - field, err := emulated.NewField[emulated.BN254Fp](api) - if err != nil { - panic(err) - } - res, err := field.NewHint(DivE12Hint, 12, &x.C0.B0.A0, &x.C0.B0.A1, &x.C0.B1.A0, &x.C0.B1.A1, &x.C0.B2.A0, &x.C0.B2.A1, &x.C1.B0.A0, &x.C1.B0.A1, &x.C1.B1.A0, &x.C1.B1.A1, &x.C1.B2.A0, &x.C1.B2.A1, &y.C0.B0.A0, &y.C0.B0.A1, &y.C0.B1.A0, &y.C0.B1.A1, &y.C0.B2.A0, &y.C0.B2.A1, &y.C1.B0.A0, &y.C1.B0.A1, &y.C1.B1.A0, &y.C1.B1.A1, &y.C1.B2.A0, &y.C1.B2.A1) +func (e Ext12) DivUnchecked(x, y *E12) *E12 { + res, err := e.fp.NewHint(DivE12Hint, 12, &x.C0.B0.A0, &x.C0.B0.A1, &x.C0.B1.A0, &x.C0.B1.A1, &x.C0.B2.A0, &x.C0.B2.A1, &x.C1.B0.A0, &x.C1.B0.A1, &x.C1.B1.A0, &x.C1.B1.A1, &x.C1.B2.A0, &x.C1.B2.A1, &y.C0.B0.A0, &y.C0.B0.A1, &y.C0.B1.A0, &y.C0.B1.A1, &y.C0.B2.A0, &y.C0.B2.A1, &y.C1.B0.A0, &y.C1.B0.A1, &y.C1.B1.A0, &y.C1.B1.A1, &y.C1.B2.A0, &y.C1.B2.A1) if err != nil { // err is non-nil only for invalid number of inputs @@ -437,8 +427,8 @@ func (e Ext12) DivUnchecked(api frontend.API, x, y E12) *E12 { } // x == div * y - _x := *e.Mul(&div, &y) - e.AssertIsEqual(&x, &_x) + _x := e.Mul(&div, y) + e.AssertIsEqual(x, _x) return &div } diff --git a/std/algebra/emulated/fields_bn254/e12_pairing.go b/std/algebra/emulated/fields_bn254/e12_pairing.go index 3a28fbfe03..f2aa7c0c83 100644 --- a/std/algebra/emulated/fields_bn254/e12_pairing.go +++ b/std/algebra/emulated/fields_bn254/e12_pairing.go @@ -1,8 +1,6 @@ package fields_bn254 -import "github.com/consensys/gnark/frontend" - -func (e Ext12) Expt(api frontend.API, x *E12) *E12 { +func (e Ext12) Expt(x *E12) *E12 { // Expt computation is derived from the addition chain: // // _10 = 2*1 @@ -37,30 +35,30 @@ func (e Ext12) Expt(api frontend.API, x *E12) *E12 { t1 = e.Mul(t0, t1) t0 = e.Mul(t3, t1) t6 = e.NCycloSquareCompressed(t6, 6) - t6 = e.DecompressKarabina(api, t6) + t6 = e.DecompressKarabina(t6) t5 = e.Mul(t5, t6) t5 = e.Mul(t4, t5) t5 = e.NCycloSquareCompressed(t5, 7) - t5 = e.DecompressKarabina(api, t5) + t5 = e.DecompressKarabina(t5) t4 = e.Mul(t4, t5) t4 = e.NCycloSquareCompressed(t4, 8) - t4 = e.DecompressKarabina(api, t4) + t4 = e.DecompressKarabina(t4) t4 = e.Mul(t0, t4) t3 = e.Mul(t3, t4) t3 = e.NCycloSquareCompressed(t3, 6) - t3 = e.DecompressKarabina(api, t3) + t3 = e.DecompressKarabina(t3) t2 = e.Mul(t2, t3) t2 = e.NCycloSquareCompressed(t2, 8) - t2 = e.DecompressKarabina(api, t2) + t2 = e.DecompressKarabina(t2) t2 = e.Mul(t0, t2) t2 = e.NCycloSquareCompressed(t2, 6) - t2 = e.DecompressKarabina(api, t2) + t2 = e.DecompressKarabina(t2) t2 = e.Mul(t0, t2) t2 = e.NCycloSquareCompressed(t2, 10) - t2 = e.DecompressKarabina(api, t2) + t2 = e.DecompressKarabina(t2) t1 = e.Mul(t1, t2) t1 = e.NCycloSquareCompressed(t1, 6) - t1 = e.DecompressKarabina(api, t1) + t1 = e.DecompressKarabina(t1) t0 = e.Mul(t0, t1) z := e.Mul(result, t0) return z @@ -72,27 +70,27 @@ func (e Ext12) Expt(api frontend.API, x *E12) *E12 { // C0: E6{B0: 1, B1: 0, B2: 0}, // C1: E6{B0: c3, B1: c4, B2: 0}, // } -func (e *Ext12) MulBy034(z *E12, c3, c4 E2) *E12 { +func (e *Ext12) MulBy034(z *E12, c3, c4 *E2) *E12 { a := z.C0 b := z.C1 - b = *e.MulBy01(&b, &c3, &c4) + b = *e.MulBy01(&b, c3, c4) one := e.Ext2.One() - c3 = *e.Ext2.Add(one, &c3) + c3 = e.Ext2.Add(one, c3) d := e.Ext6.Add(&z.C0, &z.C1) - d = e.MulBy01(d, &c3, &c4) + d = e.MulBy01(d, c3, c4) - zC1 := *e.Ext6.Add(&a, &b) - zC1 = *e.Ext6.Neg(&zC1) - zC1 = *e.Ext6.Add(&zC1, d) - zC0 := *e.Ext6.MulByNonResidue(&b) - zC0 = *e.Ext6.Add(&zC0, &a) + zC1 := e.Ext6.Add(&a, &b) + zC1 = e.Ext6.Neg(zC1) + zC1 = e.Ext6.Add(zC1, d) + zC0 := e.Ext6.MulByNonResidue(&b) + zC0 = e.Ext6.Add(zC0, &a) return &E12{ - C0: zC0, - C1: zC1, + C0: *zC0, + C1: *zC1, } } @@ -109,32 +107,32 @@ func (e *Ext12) MulBy034(z *E12, c3, c4 E2) *E12 { // C0: E6{B0: 1, B1: 0, B2: 0}, // C1: E6{B0: d3, B1: d4, B2: 0}, // } -func (e *Ext12) Mul034By034(d3, d4, c3, c4 E2) *E12 { +func (e *Ext12) Mul034By034(d3, d4, c3, c4 *E2) *E12 { one := e.Ext2.One() - x3 := e.Ext2.Mul(&c3, &d3) - x4 := e.Ext2.Mul(&c4, &d4) - x04 := e.Ext2.Add(&c4, &d4) - x03 := e.Ext2.Add(&c3, &d3) - tmp := e.Ext2.Add(&c3, &c4) - x34 := e.Ext2.Add(&d3, &d4) + x3 := e.Ext2.Mul(c3, d3) + x4 := e.Ext2.Mul(c4, d4) + x04 := e.Ext2.Add(c4, d4) + x03 := e.Ext2.Add(c3, d3) + tmp := e.Ext2.Add(c3, c4) + x34 := e.Ext2.Add(d3, d4) x34 = e.Ext2.Mul(x34, tmp) x34 = e.Ext2.Sub(x34, x3) x34 = e.Ext2.Sub(x34, x4) - zC0B0 := *e.Ext2.MulByNonResidue(x4) - zC0B0 = *e.Ext2.Add(&zC0B0, one) - zC0B1 := *x3 - zC0B2 := *x34 - zC1B0 := *x03 - zC1B1 := *x04 - zC1B2 := *e.Ext2.Zero() + zC0B0 := e.Ext2.MulByNonResidue(x4) + zC0B0 = e.Ext2.Add(zC0B0, one) + zC0B1 := x3 + zC0B2 := x34 + zC1B0 := x03 + zC1B1 := x04 + zC1B2 := e.Ext2.Zero() return &E12{ C0: E6{ - B0: zC0B0, B1: zC0B1, B2: zC0B2, + B0: *zC0B0, B1: *zC0B1, B2: *zC0B2, }, C1: E6{ - B0: zC1B0, B1: zC1B1, B2: zC1B2, + B0: *zC1B0, B1: *zC1B1, B2: *zC1B2, }, } } diff --git a/std/algebra/emulated/fields_bn254/e12_test.go b/std/algebra/emulated/fields_bn254/e12_test.go index 3f17ba4756..f8c31760a8 100644 --- a/std/algebra/emulated/fields_bn254/e12_test.go +++ b/std/algebra/emulated/fields_bn254/e12_test.go @@ -115,7 +115,7 @@ func (circuit *e12Div) Define(api frontend.API) error { ba, _ := emulated.NewField[emulated.BN254Fp](api) e := NewExt12(ba) - expected := e.DivUnchecked(api, circuit.A, circuit.B) + expected := e.DivUnchecked(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) return nil } @@ -177,7 +177,6 @@ type e12CycloSquare struct { } func (circuit *e12CycloSquare) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) e := NewExt12(ba) expected := e.CyclotomicSquare(&circuit.A) @@ -215,7 +214,6 @@ type e12CycloSquareKarabina struct { } func (circuit *e12CycloSquareKarabina) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) e := NewExt12(ba) expected := e.CyclotomicSquareCompressed(&circuit.A) @@ -253,11 +251,10 @@ type e12CycloSquareKarabinaAndDecompress struct { } func (circuit *e12CycloSquareKarabinaAndDecompress) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) e := NewExt12(ba) expected := e.CyclotomicSquareCompressed(&circuit.A) - expected = e.DecompressKarabina(api, expected) + expected = e.DecompressKarabina(expected) e.AssertIsEqual(expected, &circuit.C) return nil } @@ -324,10 +321,9 @@ type e12Inverse struct { } func (circuit *e12Inverse) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) e := NewExt12(ba) - expected := e.Inverse(api, &circuit.A) + expected := e.Inverse(&circuit.A) e.AssertIsEqual(expected, &circuit.C) return nil @@ -356,10 +352,9 @@ type e12Expt struct { } func (circuit *e12Expt) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) e := NewExt12(ba) - expected := e.Expt(api, &circuit.A) + expected := e.Expt(&circuit.A) e.AssertIsEqual(expected, &circuit.C) return nil @@ -493,8 +488,8 @@ func (circuit *e12MulBy034) Define(api frontend.API) error { ba, _ := emulated.NewField[emulated.BN254Fp](api) e := NewExt12(ba) - circuit.A = *e.MulBy034(&circuit.A, circuit.B, circuit.C) - e.AssertIsEqual(&circuit.A, &circuit.W) + res := e.MulBy034(&circuit.A, &circuit.B, &circuit.C) + e.AssertIsEqual(res, &circuit.W) return nil } diff --git a/std/algebra/emulated/fields_bn254/e2.go b/std/algebra/emulated/fields_bn254/e2.go index e208424538..b66f22c9ee 100644 --- a/std/algebra/emulated/fields_bn254/e2.go +++ b/std/algebra/emulated/fields_bn254/e2.go @@ -4,7 +4,6 @@ import ( "math/big" "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/math/emulated" ) @@ -280,12 +279,8 @@ func (e Ext2) Double(x *E2) *E2 { } } -func (e Ext2) Halve(api frontend.API, x *E2) *E2 { - field, err := emulated.NewField[emulated.BN254Fp](api) - if err != nil { - panic(err) - } - res, err := field.NewHint(HalveE2Hint, 2, &x.A0, &x.A1) +func (e Ext2) Halve(x *E2) *E2 { + res, err := e.fp.NewHint(HalveE2Hint, 2, &x.A0, &x.A1) if err != nil { // err is non-nil only for invalid number of inputs panic(err) @@ -298,8 +293,8 @@ func (e Ext2) Halve(api frontend.API, x *E2) *E2 { } // x == 2*half - _x := *e.Double(&half) - e.AssertIsEqual(x, &_x) + _x := e.Double(&half) + e.AssertIsEqual(x, _x) return &half @@ -315,15 +310,10 @@ func FromE2(y *bn254.E2) E2 { A0: emulated.ValueOf[emulated.BN254Fp](y.A0), A1: emulated.ValueOf[emulated.BN254Fp](y.A1), } - } -func (e Ext2) Inverse(api frontend.API, x *E2) *E2 { - field, err := emulated.NewField[emulated.BN254Fp](api) - if err != nil { - panic(err) - } - res, err := field.NewHint(InverseE2Hint, 2, &x.A0, &x.A1) +func (e Ext2) Inverse(x *E2) *E2 { + res, err := e.fp.NewHint(InverseE2Hint, 2, &x.A0, &x.A1) if err != nil { // err is non-nil only for invalid number of inputs panic(err) @@ -336,20 +326,16 @@ func (e Ext2) Inverse(api frontend.API, x *E2) *E2 { one := e.One() // 1 == inv * x - _one := *e.Mul(&inv, x) - e.AssertIsEqual(one, &_one) + _one := e.Mul(&inv, x) + e.AssertIsEqual(one, _one) return &inv } // DivUnchecked e2 elmts -func (e Ext2) DivUnchecked(api frontend.API, x, y E2) *E2 { - field, err := emulated.NewField[emulated.BN254Fp](api) - if err != nil { - panic(err) - } - res, err := field.NewHint(DivE2Hint, 2, &x.A0, &x.A1, &y.A0, &y.A1) +func (e Ext2) DivUnchecked(x, y *E2) *E2 { + res, err := e.fp.NewHint(DivE2Hint, 2, &x.A0, &x.A1, &y.A0, &y.A1) if err != nil { // err is non-nil only for invalid number of inputs panic(err) @@ -361,8 +347,8 @@ func (e Ext2) DivUnchecked(api frontend.API, x, y E2) *E2 { } // x == div * y - _x := *e.Mul(&div, &y) - e.AssertIsEqual(&x, &_x) + _x := e.Mul(&div, y) + e.AssertIsEqual(x, _x) return &div } diff --git a/std/algebra/emulated/fields_bn254/e2_test.go b/std/algebra/emulated/fields_bn254/e2_test.go index 9139392bbf..6285e525a1 100644 --- a/std/algebra/emulated/fields_bn254/e2_test.go +++ b/std/algebra/emulated/fields_bn254/e2_test.go @@ -113,7 +113,7 @@ type e2Halve struct { func (circuit *e2Halve) Define(api frontend.API) error { ba, _ := emulated.NewField[emulated.BN254Fp](api) e := NewExt2(ba) - expected := e.Halve(api, &circuit.A) + expected := e.Halve(&circuit.A) e.AssertIsEqual(expected, &circuit.C) return nil } @@ -210,7 +210,7 @@ func (circuit *e2Div) Define(api frontend.API) error { ba, _ := emulated.NewField[emulated.BN254Fp](api) e := NewExt2(ba) - expected := e.DivUnchecked(api, circuit.A, circuit.B) + expected := e.DivUnchecked(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) return nil } @@ -371,10 +371,9 @@ type e2Inverse struct { } func (circuit *e2Inverse) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) e := NewExt2(ba) - expected := e.Inverse(api, &circuit.A) + expected := e.Inverse(&circuit.A) e.AssertIsEqual(expected, &circuit.C) return nil diff --git a/std/algebra/emulated/fields_bn254/e6.go b/std/algebra/emulated/fields_bn254/e6.go index fa0fbf1cf3..5555253d52 100644 --- a/std/algebra/emulated/fields_bn254/e6.go +++ b/std/algebra/emulated/fields_bn254/e6.go @@ -2,8 +2,6 @@ package fields_bn254 import ( "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/math/emulated" ) type E6 struct { @@ -202,12 +200,8 @@ func FromE6(y *bn254.E6) E6 { } -func (e Ext6) Inverse(api frontend.API, x *E6) *E6 { - field, err := emulated.NewField[emulated.BN254Fp](api) - if err != nil { - panic(err) - } - res, err := field.NewHint(InverseE6Hint, 6, &x.B0.A0, &x.B0.A1, &x.B1.A0, &x.B1.A1, &x.B2.A0, &x.B2.A1) +func (e Ext6) Inverse(x *E6) *E6 { + res, err := e.fp.NewHint(InverseE6Hint, 6, &x.B0.A0, &x.B0.A1, &x.B1.A0, &x.B1.A1, &x.B2.A0, &x.B2.A1) if err != nil { // err is non-nil only for invalid number of inputs panic(err) @@ -222,20 +216,16 @@ func (e Ext6) Inverse(api frontend.API, x *E6) *E6 { one := e.One() // 1 == inv * x - _one := *e.Mul(&inv, x) - e.AssertIsEqual(one, &_one) + _one := e.Mul(&inv, x) + e.AssertIsEqual(one, _one) return &inv } // DivUnchecked e2 elmts -func (e Ext6) DivUnchecked(api frontend.API, x, y E6) *E6 { - field, err := emulated.NewField[emulated.BN254Fp](api) - if err != nil { - panic(err) - } - res, err := field.NewHint(DivE6Hint, 6, &x.B0.A0, &x.B0.A1, &x.B1.A0, &x.B1.A1, &x.B2.A0, &x.B2.A1, &y.B0.A0, &y.B0.A1, &y.B1.A0, &y.B1.A1, &y.B2.A0, &y.B2.A1) +func (e Ext6) DivUnchecked(x, y *E6) *E6 { + res, err := e.fp.NewHint(DivE6Hint, 6, &x.B0.A0, &x.B0.A1, &x.B1.A0, &x.B1.A1, &x.B2.A0, &x.B2.A1, &y.B0.A0, &y.B0.A1, &y.B1.A0, &y.B1.A1, &y.B2.A0, &y.B2.A1) if err != nil { // err is non-nil only for invalid number of inputs panic(err) @@ -248,8 +238,8 @@ func (e Ext6) DivUnchecked(api frontend.API, x, y E6) *E6 { } // x == div * y - _x := *e.Mul(&div, &y) - e.AssertIsEqual(&x, &_x) + _x := e.Mul(&div, y) + e.AssertIsEqual(x, _x) return &div } diff --git a/std/algebra/emulated/fields_bn254/e6_test.go b/std/algebra/emulated/fields_bn254/e6_test.go index 4d3e96601d..a3fbfebd6f 100644 --- a/std/algebra/emulated/fields_bn254/e6_test.go +++ b/std/algebra/emulated/fields_bn254/e6_test.go @@ -146,7 +146,7 @@ func (circuit *e6Div) Define(api frontend.API) error { ba, _ := emulated.NewField[emulated.BN254Fp](api) e := NewExt6(ba) - expected := e.DivUnchecked(api, circuit.A, circuit.B) + expected := e.DivUnchecked(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) return nil } @@ -318,7 +318,7 @@ func (circuit *e6Inverse) Define(api frontend.API) error { ba, _ := emulated.NewField[emulated.BN254Fp](api) e := NewExt6(ba) - expected := e.Inverse(api, &circuit.A) + expected := e.Inverse(&circuit.A) e.AssertIsEqual(expected, &circuit.C) return nil diff --git a/std/algebra/emulated/sw_bn254/doc_test.go b/std/algebra/emulated/sw_bn254/doc_test.go index f3d41bf4f8..db095a0210 100644 --- a/std/algebra/emulated/sw_bn254/doc_test.go +++ b/std/algebra/emulated/sw_bn254/doc_test.go @@ -23,7 +23,7 @@ func (c *PairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res, err := pairing.Pair(api, []*sw_bn254.G1Affine{&c.InG1}, []*sw_bn254.G2Affine{&c.InG2}) + res, err := pairing.Pair([]*sw_bn254.G1Affine{&c.InG1}, []*sw_bn254.G2Affine{&c.InG2}) if err != nil { return fmt.Errorf("pair: %w", err) } diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 685c996356..cd511c92d2 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -12,6 +12,7 @@ import ( type Pairing struct { *fields_bn254.Ext12 + curveF *emulated.Field[emulated.BN254Fp] } type GTEl = fields_bn254.E12 @@ -55,7 +56,8 @@ func NewPairing(api frontend.API) (*Pairing, error) { return nil, fmt.Errorf("new base api: %w", err) } return &Pairing{ - Ext12: fields_bn254.NewExt12(ba), + Ext12: fields_bn254.NewExt12(ba), + curveF: ba, }, nil } @@ -63,13 +65,13 @@ func NewPairing(api frontend.API) (*Pairing, error) { // where d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r // we use instead d'= s ⋅ d, where s is the cofactor 2x₀(6x₀²+3x₀+1) // and r does NOT divide d' -func (pr Pairing) FinalExponentiation(api frontend.API, e *GTEl) *GTEl { +func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { var t [4]*GTEl // Easy part // (p⁶-1)(p²+1) t[0] = pr.Ext12.Conjugate(e) - t[0] = pr.Ext12.DivUnchecked(api, *t[0], *e) + t[0] = pr.Ext12.DivUnchecked(t[0], e) result := pr.Ext12.FrobeniusSquare(t[0]) result = pr.Ext12.Mul(result, t[0]) @@ -78,15 +80,15 @@ func (pr Pairing) FinalExponentiation(api frontend.API, e *GTEl) *GTEl { // Duquesne and Ghammam // https://eprint.iacr.org/2015/192.pdf // Fuentes et al. variant (alg. 10) - t[0] = pr.Ext12.Expt(api, result) + t[0] = pr.Ext12.Expt(result) t[0] = pr.Ext12.Conjugate(t[0]) t[0] = pr.Ext12.CyclotomicSquare(t[0]) - t[2] = pr.Ext12.Expt(api, t[0]) + t[2] = pr.Ext12.Expt(t[0]) t[2] = pr.Ext12.Conjugate(t[2]) t[1] = pr.Ext12.CyclotomicSquare(t[2]) t[2] = pr.Ext12.Mul(t[2], t[1]) t[2] = pr.Ext12.Mul(t[2], result) - t[1] = pr.Ext12.Expt(api, t[2]) + t[1] = pr.Ext12.Expt(t[2]) t[1] = pr.Ext12.CyclotomicSquare(t[1]) t[1] = pr.Ext12.Mul(t[1], t[2]) t[1] = pr.Ext12.Conjugate(t[1]) @@ -109,13 +111,13 @@ func (pr Pairing) FinalExponentiation(api frontend.API, e *GTEl) *GTEl { return t[1] } -func (pr Pairing) Pair(api frontend.API, P []*G1Affine, Q []*G2Affine) (*GTEl, error) { - res, err := pr.MillerLoop(api, P, Q) +func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { + res, err := pr.MillerLoop(P, Q) if err != nil { return nil, fmt.Errorf("miller loop: %w", err) } - res = *pr.FinalExponentiation(api, &res) - return &res, nil + res = pr.FinalExponentiation(res) + return res, nil } func (pr Pairing) AssertIsEqual(x, y *GTEl) { @@ -140,53 +142,48 @@ type LineEvaluation struct { } // MillerLoop computes the multi-Miller loop -func (pr Pairing) MillerLoop(api frontend.API, P []*G1Affine, Q []*G2Affine) (GTEl, error) { - ba, err := emulated.NewField[emulated.BN254Fp](api) - if err != nil { - return GTEl{}, fmt.Errorf("new base api: %w", err) - } +func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { // check input size match n := len(P) if n == 0 || n != len(Q) { - return GTEl{}, errors.New("invalid inputs sizes") + return nil, errors.New("invalid inputs sizes") } res := pr.Ext12.One() - var l1, l2 LineEvaluation - Qacc := make([]G2Affine, n) - QNeg := make([]G2Affine, n) - yInv := make([]emulated.Element[emulated.BN254Fp], n) - xOverY := make([]emulated.Element[emulated.BN254Fp], n) + var l1, l2 *LineEvaluation + Qacc := make([]*G2Affine, n) + QNeg := make([]*G2Affine, n) + yInv := make([]*emulated.Element[emulated.BN254Fp], n) + xOverY := make([]*emulated.Element[emulated.BN254Fp], n) for k := 0; k < n; k++ { - Qacc[k] = *Q[k] - QNeg[k].X = Q[k].X - QNeg[k].Y = *pr.Ext2.Neg(&Q[k].Y) - yInv[k] = *ba.Inverse(&P[k].Y) - xOverY[k] = *ba.Div(&P[k].X, &P[k].Y) + Qacc[k] = Q[k] + QNeg[k] = &G2Affine{X: Q[k].X, Y: *pr.Ext2.Neg(&Q[k].Y)} + yInv[k] = pr.curveF.Inverse(&P[k].Y) + xOverY[k] = pr.curveF.Div(&P[k].X, &P[k].Y) } // k = 0 - Qacc[0], l1 = pr.doubleStep(api, &Qacc[0]) - res.C1.B0 = *pr.MulByElement(&l1.R0, &xOverY[0]) - res.C1.B1 = *pr.MulByElement(&l1.R1, &yInv[0]) + Qacc[0], l1 = pr.doubleStep(Qacc[0]) + res.C1.B0 = *pr.MulByElement(&l1.R0, xOverY[0]) + res.C1.B1 = *pr.MulByElement(&l1.R1, yInv[0]) if n >= 2 { // k = 1 - Qacc[1], l1 = pr.doubleStep(api, &Qacc[1]) - l1.R0 = *pr.MulByElement(&l1.R0, &xOverY[1]) - l1.R1 = *pr.MulByElement(&l1.R1, &yInv[1]) - res = pr.Mul034By034(l1.R0, l1.R1, res.C1.B0, res.C1.B1) + Qacc[1], l1 = pr.doubleStep(Qacc[1]) + l1.R0 = *pr.MulByElement(&l1.R0, xOverY[1]) + l1.R1 = *pr.MulByElement(&l1.R1, yInv[1]) + res = pr.Mul034By034(&l1.R0, &l1.R1, &res.C1.B0, &res.C1.B1) } if n >= 3 { // k >= 2 for k := 2; k < n; k++ { - Qacc[k], l1 = pr.doubleStep(api, &Qacc[k]) - l1.R0 = *pr.MulByElement(&l1.R0, &xOverY[k]) - l1.R1 = *pr.MulByElement(&l1.R1, &yInv[k]) - res = pr.MulBy034(res, l1.R0, l1.R1) + Qacc[k], l1 = pr.doubleStep(Qacc[k]) + l1.R0 = *pr.MulByElement(&l1.R0, xOverY[k]) + l1.R1 = *pr.MulByElement(&l1.R1, yInv[k]) + res = pr.MulBy034(res, &l1.R0, &l1.R1) } } @@ -197,36 +194,36 @@ func (pr Pairing) MillerLoop(api frontend.API, P []*G1Affine, Q []*G2Affine) (GT case 0: for k := 0; k < n; k++ { - Qacc[k], l1 = pr.doubleStep(api, &Qacc[k]) - l1.R0 = *pr.MulByElement(&l1.R0, &xOverY[k]) - l1.R1 = *pr.MulByElement(&l1.R1, &yInv[k]) - res = pr.MulBy034(res, l1.R0, l1.R1) + Qacc[k], l1 = pr.doubleStep(Qacc[k]) + l1.R0 = *pr.MulByElement(&l1.R0, xOverY[k]) + l1.R1 = *pr.MulByElement(&l1.R1, yInv[k]) + res = pr.MulBy034(res, &l1.R0, &l1.R1) } case 1: for k := 0; k < n; k++ { - Qacc[k], l1, l2 = pr.doubleAndAddStep(api, &Qacc[k], Q[k]) - l1.R0 = *pr.MulByElement(&l1.R0, &xOverY[k]) - l1.R1 = *pr.MulByElement(&l1.R1, &yInv[k]) - res = pr.MulBy034(res, l1.R0, l1.R1) - l2.R0 = *pr.MulByElement(&l2.R0, &xOverY[k]) - l2.R1 = *pr.MulByElement(&l2.R1, &yInv[k]) - res = pr.MulBy034(res, l2.R0, l2.R1) + Qacc[k], l1, l2 = pr.doubleAndAddStep(Qacc[k], Q[k]) + l1.R0 = *pr.MulByElement(&l1.R0, xOverY[k]) + l1.R1 = *pr.MulByElement(&l1.R1, yInv[k]) + res = pr.MulBy034(res, &l1.R0, &l1.R1) + l2.R0 = *pr.MulByElement(&l2.R0, xOverY[k]) + l2.R1 = *pr.MulByElement(&l2.R1, yInv[k]) + res = pr.MulBy034(res, &l2.R0, &l2.R1) } case -1: for k := 0; k < n; k++ { - Qacc[k], l1, l2 = pr.doubleAndAddStep(api, &Qacc[k], &QNeg[k]) - l1.R0 = *pr.MulByElement(&l1.R0, &xOverY[k]) - l1.R1 = *pr.MulByElement(&l1.R1, &yInv[k]) - res = pr.MulBy034(res, l1.R0, l1.R1) - l2.R0 = *pr.MulByElement(&l2.R0, &xOverY[k]) - l2.R1 = *pr.MulByElement(&l2.R1, &yInv[k]) - res = pr.MulBy034(res, l2.R0, l2.R1) + Qacc[k], l1, l2 = pr.doubleAndAddStep(Qacc[k], QNeg[k]) + l1.R0 = *pr.MulByElement(&l1.R0, xOverY[k]) + l1.R1 = *pr.MulByElement(&l1.R1, yInv[k]) + res = pr.MulBy034(res, &l1.R0, &l1.R1) + l2.R0 = *pr.MulByElement(&l2.R0, xOverY[k]) + l2.R1 = *pr.MulByElement(&l2.R1, yInv[k]) + res = pr.MulBy034(res, &l2.R0, &l2.R1) } default: - return GTEl{}, errors.New("invalid loopCounter") + return nil, errors.New("invalid loopCounter") } } @@ -243,24 +240,24 @@ func (pr Pairing) MillerLoop(api frontend.API, P []*G1Affine, Q []*G2Affine) (GT Q2.Y = *pr.Ext12.Ext2.MulByNonResidue2Power3(&Q[k].Y) Q2.Y = *pr.Ext12.Ext2.Neg(&Q2.Y) - Qacc[k], l1 = pr.addStep(api, &Qacc[k], Q1) - l1.R0 = *pr.Ext2.MulByElement(&l1.R0, &xOverY[k]) - l1.R1 = *pr.Ext2.MulByElement(&l1.R1, &yInv[k]) - res = pr.MulBy034(res, l1.R0, l1.R1) + Qacc[k], l1 = pr.addStep(Qacc[k], Q1) + l1.R0 = *pr.Ext2.MulByElement(&l1.R0, xOverY[k]) + l1.R1 = *pr.Ext2.MulByElement(&l1.R1, yInv[k]) + res = pr.MulBy034(res, &l1.R0, &l1.R1) - l2 = pr.addStepLineOnly(api, &Qacc[k], Q2) - l2.R0 = *pr.MulByElement(&l2.R0, &xOverY[k]) - l2.R1 = *pr.MulByElement(&l2.R1, &yInv[k]) - res = pr.MulBy034(res, l2.R0, l2.R1) + l2 = pr.addStepLineOnly(Qacc[k], Q2) + l2.R0 = *pr.MulByElement(&l2.R0, xOverY[k]) + l2.R1 = *pr.MulByElement(&l2.R1, yInv[k]) + res = pr.MulBy034(res, &l2.R0, &l2.R1) } - return *res, nil + return res, nil } // doubleAndAddStep doubles p1 and adds p2 to the result in affine coordinates, and evaluates the line in Miller loop // https://eprint.iacr.org/2022/1162 (Section 6.1) -func (pr Pairing) doubleAndAddStep(api frontend.API, p1, p2 *G2Affine) (G2Affine, LineEvaluation, LineEvaluation) { +func (pr Pairing) doubleAndAddStep(p1, p2 *G2Affine) (*G2Affine, *LineEvaluation, *LineEvaluation) { var line1, line2 LineEvaluation var p G2Affine @@ -268,7 +265,7 @@ func (pr Pairing) doubleAndAddStep(api frontend.API, p1, p2 *G2Affine) (G2Affine // compute lambda1 = (y2-y1)/(x2-x1) n := pr.Ext2.Sub(&p1.Y, &p2.Y) d := pr.Ext2.Sub(&p1.X, &p2.X) - l1 := pr.Ext2.DivUnchecked(api, *n, *d) + l1 := pr.Ext2.DivUnchecked(n, d) // x3 =lambda1**2-p1.x-p2.x x3 := pr.Ext2.Square(l1) @@ -285,7 +282,7 @@ func (pr Pairing) doubleAndAddStep(api frontend.API, p1, p2 *G2Affine) (G2Affine // compute lambda2 = -lambda1-2*y1/(x3-x1) n = pr.Ext2.Double(&p1.Y) d = pr.Ext2.Sub(x3, &p1.X) - l2 := pr.Ext2.DivUnchecked(api, *n, *d) + l2 := pr.Ext2.DivUnchecked(n, d) l2 = pr.Ext2.Add(l2, l1) l2 = pr.Ext2.Neg(l2) @@ -307,12 +304,12 @@ func (pr Pairing) doubleAndAddStep(api frontend.API, p1, p2 *G2Affine) (G2Affine line2.R1 = *pr.Ext2.Mul(l2, &p1.X) line2.R1 = *pr.Ext2.Sub(&line2.R1, &p1.Y) - return p, line1, line2 + return &p, &line1, &line2 } // doubleStep doubles a point in affine coordinates, and evaluates the line in Miller loop // https://eprint.iacr.org/2022/1162 (Section 6.1) -func (pr Pairing) doubleStep(api frontend.API, p1 *G2Affine) (G2Affine, LineEvaluation) { +func (pr Pairing) doubleStep(p1 *G2Affine) (*G2Affine, *LineEvaluation) { var p G2Affine var line LineEvaluation @@ -322,7 +319,7 @@ func (pr Pairing) doubleStep(api frontend.API, p1 *G2Affine) (G2Affine, LineEval three := emulated.ValueOf[emulated.BN254Fp](3) n = pr.Ext2.MulByElement(n, &three) d := pr.Ext2.Double(&p1.Y) - l := pr.Ext2.DivUnchecked(api, *n, *d) + l := pr.Ext2.DivUnchecked(n, d) // xr = lambda**2-2*p1.x xr := pr.Ext2.Square(l) @@ -341,18 +338,18 @@ func (pr Pairing) doubleStep(api frontend.API, p1 *G2Affine) (G2Affine, LineEval line.R1 = *pr.Ext2.Mul(l, &p1.X) line.R1 = *pr.Ext2.Sub(&line.R1, &p1.Y) - return p, line + return &p, &line } // addStep adds two points in affine coordinates, and evaluates the line in Miller loop // https://eprint.iacr.org/2022/1162 (Section 6.1) -func (pr Pairing) addStep(api frontend.API, p, q *G2Affine) (G2Affine, LineEvaluation) { +func (pr Pairing) addStep(p, q *G2Affine) (*G2Affine, *LineEvaluation) { // compute λ = (q.y-p.y)/(q.x-p.x) qypy := pr.Ext2.Sub(&q.Y, &p.Y) qxpx := pr.Ext2.Sub(&q.X, &p.X) - λ := pr.Ext2.DivUnchecked(api, *qypy, *qxpx) + λ := pr.Ext2.DivUnchecked(qypy, qxpx) // xr = λ²-p.x-q.x λλ := pr.Ext2.Square(λ) @@ -373,23 +370,23 @@ func (pr Pairing) addStep(api frontend.API, p, q *G2Affine) (G2Affine, LineEvalu line.R1 = *pr.Ext2.Mul(λ, &p.X) line.R1 = *pr.Ext2.Sub(&line.R1, &p.Y) - return res, line + return &res, &line } // addStepLineOnly computes the line that goes through p and q but does not compute p+q -func (pr Pairing) addStepLineOnly(api frontend.API, p, q *G2Affine) LineEvaluation { +func (pr Pairing) addStepLineOnly(p, q *G2Affine) *LineEvaluation { // compute λ = (q.y-p.y)/(q.x-p.x) qypy := pr.Ext2.Sub(&q.Y, &p.Y) qxpx := pr.Ext2.Sub(&q.X, &p.X) - λ := pr.Ext2.DivUnchecked(api, *qypy, *qxpx) + λ := pr.Ext2.DivUnchecked(qypy, qxpx) var line LineEvaluation line.R0 = *pr.Ext2.Neg(λ) line.R1 = *pr.Ext2.Mul(λ, &p.X) line.R1 = *pr.Ext2.Sub(&line.R1, &p.Y) - return line + return &line } diff --git a/std/algebra/emulated/sw_bn254/pairing_test.go b/std/algebra/emulated/sw_bn254/pairing_test.go index 23eea2a01b..4fbb831b2d 100644 --- a/std/algebra/emulated/sw_bn254/pairing_test.go +++ b/std/algebra/emulated/sw_bn254/pairing_test.go @@ -35,7 +35,7 @@ func (c *FinalExponentiationCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res := pairing.FinalExponentiation(api, &c.InGt) + res := pairing.FinalExponentiation(&c.InGt) pairing.AssertIsEqual(res, &c.Res) return nil } @@ -64,7 +64,7 @@ func (c *PairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res, err := pairing.Pair(api, []*G1Affine{&c.InG1}, []*G2Affine{&c.InG2}) + res, err := pairing.Pair([]*G1Affine{&c.InG1}, []*G2Affine{&c.InG2}) if err != nil { return fmt.Errorf("pair: %w", err) } From a469808a8765d41eb69ef7fe115aeea68917c03a Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Wed, 15 Mar 2023 02:04:58 +0100 Subject: [PATCH 123/464] docs: make href in godoc --- std/algebra/emulated/sw_bn254/doc.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/std/algebra/emulated/sw_bn254/doc.go b/std/algebra/emulated/sw_bn254/doc.go index 7d0561c146..e66e237ee9 100644 --- a/std/algebra/emulated/sw_bn254/doc.go +++ b/std/algebra/emulated/sw_bn254/doc.go @@ -1,5 +1,6 @@ // Package sw_bn254 implements G1 and G2 arithmetics and pairing computation over BN254 curve. // -// The implementation follows [Housni22]: "Pairings in Rank-1 Constraint Systems". -// [Housni22] https://eprint.iacr.org/2022/1162 +// The implementation follows [[Housni22]]: "Pairings in Rank-1 Constraint Systems". +// +// [Housni22]: https://eprint.iacr.org/2022/1162 package sw_bn254 From 824812eb34e6c8140c462a6df7097f89cde3349b Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Wed, 15 Mar 2023 02:05:20 +0100 Subject: [PATCH 124/464] docs: make long equation codeblock --- std/algebra/emulated/sw_bn254/pairing.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index cd511c92d2..4eb792ee42 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -61,9 +61,14 @@ func NewPairing(api frontend.API) (*Pairing, error) { }, nil } -// FinalExponentiation computes the exponentiation eᵈ -// where d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r -// we use instead d'= s ⋅ d, where s is the cofactor 2x₀(6x₀²+3x₀+1) +// FinalExponentiation computes the exponentiation eᵈ where +// +// d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r. +// +// We use instead d'= s ⋅ d, where s is the cofactor +// +// 2x₀(6x₀²+3x₀+1) +// // and r does NOT divide d' func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { var t [4]*GTEl From 1b6e5c16c4bd5ad1faa10543f5624c65217160a9 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Wed, 15 Mar 2023 02:07:16 +0100 Subject: [PATCH 125/464] refactor: make all hints private There are a lot of hints in the package. The preferred way of accessing all the hints is using GetHints() --- std/algebra/emulated/fields_bn254/e12.go | 4 ++-- std/algebra/emulated/fields_bn254/e2.go | 6 ++--- std/algebra/emulated/fields_bn254/e6.go | 4 ++-- std/algebra/emulated/fields_bn254/hints.go | 28 +++++++++++----------- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/std/algebra/emulated/fields_bn254/e12.go b/std/algebra/emulated/fields_bn254/e12.go index e81c8b0078..68231299d7 100644 --- a/std/algebra/emulated/fields_bn254/e12.go +++ b/std/algebra/emulated/fields_bn254/e12.go @@ -375,7 +375,7 @@ func FromE12(y *bn254.E12) E12 { } func (e Ext12) Inverse(x *E12) *E12 { - res, err := e.fp.NewHint(InverseE12Hint, 12, &x.C0.B0.A0, &x.C0.B0.A1, &x.C0.B1.A0, &x.C0.B1.A1, &x.C0.B2.A0, &x.C0.B2.A1, &x.C1.B0.A0, &x.C1.B0.A1, &x.C1.B1.A0, &x.C1.B1.A1, &x.C1.B2.A0, &x.C1.B2.A1) + res, err := e.fp.NewHint(inverseE12Hint, 12, &x.C0.B0.A0, &x.C0.B0.A1, &x.C0.B1.A0, &x.C0.B1.A1, &x.C0.B2.A0, &x.C0.B2.A1, &x.C1.B0.A0, &x.C1.B0.A1, &x.C1.B1.A0, &x.C1.B1.A1, &x.C1.B2.A0, &x.C1.B2.A1) if err != nil { // err is non-nil only for invalid number of inputs panic(err) @@ -406,7 +406,7 @@ func (e Ext12) Inverse(x *E12) *E12 { // DivUnchecked e2 elmts func (e Ext12) DivUnchecked(x, y *E12) *E12 { - res, err := e.fp.NewHint(DivE12Hint, 12, &x.C0.B0.A0, &x.C0.B0.A1, &x.C0.B1.A0, &x.C0.B1.A1, &x.C0.B2.A0, &x.C0.B2.A1, &x.C1.B0.A0, &x.C1.B0.A1, &x.C1.B1.A0, &x.C1.B1.A1, &x.C1.B2.A0, &x.C1.B2.A1, &y.C0.B0.A0, &y.C0.B0.A1, &y.C0.B1.A0, &y.C0.B1.A1, &y.C0.B2.A0, &y.C0.B2.A1, &y.C1.B0.A0, &y.C1.B0.A1, &y.C1.B1.A0, &y.C1.B1.A1, &y.C1.B2.A0, &y.C1.B2.A1) + res, err := e.fp.NewHint(divE12Hint, 12, &x.C0.B0.A0, &x.C0.B0.A1, &x.C0.B1.A0, &x.C0.B1.A1, &x.C0.B2.A0, &x.C0.B2.A1, &x.C1.B0.A0, &x.C1.B0.A1, &x.C1.B1.A0, &x.C1.B1.A1, &x.C1.B2.A0, &x.C1.B2.A1, &y.C0.B0.A0, &y.C0.B0.A1, &y.C0.B1.A0, &y.C0.B1.A1, &y.C0.B2.A0, &y.C0.B2.A1, &y.C1.B0.A0, &y.C1.B0.A1, &y.C1.B1.A0, &y.C1.B1.A1, &y.C1.B2.A0, &y.C1.B2.A1) if err != nil { // err is non-nil only for invalid number of inputs diff --git a/std/algebra/emulated/fields_bn254/e2.go b/std/algebra/emulated/fields_bn254/e2.go index b66f22c9ee..a30ee7b0dd 100644 --- a/std/algebra/emulated/fields_bn254/e2.go +++ b/std/algebra/emulated/fields_bn254/e2.go @@ -280,7 +280,7 @@ func (e Ext2) Double(x *E2) *E2 { } func (e Ext2) Halve(x *E2) *E2 { - res, err := e.fp.NewHint(HalveE2Hint, 2, &x.A0, &x.A1) + res, err := e.fp.NewHint(halveE2Hint, 2, &x.A0, &x.A1) if err != nil { // err is non-nil only for invalid number of inputs panic(err) @@ -313,7 +313,7 @@ func FromE2(y *bn254.E2) E2 { } func (e Ext2) Inverse(x *E2) *E2 { - res, err := e.fp.NewHint(InverseE2Hint, 2, &x.A0, &x.A1) + res, err := e.fp.NewHint(inverseE2Hint, 2, &x.A0, &x.A1) if err != nil { // err is non-nil only for invalid number of inputs panic(err) @@ -335,7 +335,7 @@ func (e Ext2) Inverse(x *E2) *E2 { // DivUnchecked e2 elmts func (e Ext2) DivUnchecked(x, y *E2) *E2 { - res, err := e.fp.NewHint(DivE2Hint, 2, &x.A0, &x.A1, &y.A0, &y.A1) + res, err := e.fp.NewHint(divE2Hint, 2, &x.A0, &x.A1, &y.A0, &y.A1) if err != nil { // err is non-nil only for invalid number of inputs panic(err) diff --git a/std/algebra/emulated/fields_bn254/e6.go b/std/algebra/emulated/fields_bn254/e6.go index 5555253d52..98341aa3b7 100644 --- a/std/algebra/emulated/fields_bn254/e6.go +++ b/std/algebra/emulated/fields_bn254/e6.go @@ -201,7 +201,7 @@ func FromE6(y *bn254.E6) E6 { } func (e Ext6) Inverse(x *E6) *E6 { - res, err := e.fp.NewHint(InverseE6Hint, 6, &x.B0.A0, &x.B0.A1, &x.B1.A0, &x.B1.A1, &x.B2.A0, &x.B2.A1) + res, err := e.fp.NewHint(inverseE6Hint, 6, &x.B0.A0, &x.B0.A1, &x.B1.A0, &x.B1.A1, &x.B2.A0, &x.B2.A1) if err != nil { // err is non-nil only for invalid number of inputs panic(err) @@ -225,7 +225,7 @@ func (e Ext6) Inverse(x *E6) *E6 { // DivUnchecked e2 elmts func (e Ext6) DivUnchecked(x, y *E6) *E6 { - res, err := e.fp.NewHint(DivE6Hint, 6, &x.B0.A0, &x.B0.A1, &x.B1.A0, &x.B1.A1, &x.B2.A0, &x.B2.A1, &y.B0.A0, &y.B0.A1, &y.B1.A0, &y.B1.A1, &y.B2.A0, &y.B2.A1) + res, err := e.fp.NewHint(divE6Hint, 6, &x.B0.A0, &x.B0.A1, &x.B1.A0, &x.B1.A1, &x.B2.A0, &x.B2.A1, &y.B0.A0, &y.B0.A1, &y.B1.A0, &y.B1.A1, &y.B2.A0, &y.B2.A1) if err != nil { // err is non-nil only for invalid number of inputs panic(err) diff --git a/std/algebra/emulated/fields_bn254/hints.go b/std/algebra/emulated/fields_bn254/hints.go index e04c95751c..9dd3727b04 100644 --- a/std/algebra/emulated/fields_bn254/hints.go +++ b/std/algebra/emulated/fields_bn254/hints.go @@ -16,19 +16,19 @@ func init() { func GetHints() []solver.Hint { return []solver.Hint{ // E2 - DivE2Hint, - InverseE2Hint, - HalveE2Hint, + divE2Hint, + inverseE2Hint, + halveE2Hint, // E6 - DivE6Hint, - InverseE6Hint, + divE6Hint, + inverseE6Hint, // E12 - DivE12Hint, - InverseE12Hint, + divE12Hint, + inverseE12Hint, } } -func InverseE2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { +func inverseE2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { return emulated.UnwrapHint(nativeInputs, nativeOutputs, func(mod *big.Int, inputs, outputs []*big.Int) error { var a, c bn254.E2 @@ -45,7 +45,7 @@ func InverseE2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) e }) } -func DivE2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { +func divE2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { return emulated.UnwrapHint(nativeInputs, nativeOutputs, func(mod *big.Int, inputs, outputs []*big.Int) error { var a, b, c bn254.E2 @@ -64,7 +64,7 @@ func DivE2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error }) } -func HalveE2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { +func halveE2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { return emulated.UnwrapHint(nativeInputs, nativeOutputs, func(mod *big.Int, inputs, outputs []*big.Int) error { var a, c bn254.E2 @@ -82,7 +82,7 @@ func HalveE2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) err } // E6 hints -func InverseE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { +func inverseE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { return emulated.UnwrapHint(nativeInputs, nativeOutputs, func(mod *big.Int, inputs, outputs []*big.Int) error { var a, c bn254.E6 @@ -107,7 +107,7 @@ func InverseE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) e }) } -func DivE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { +func divE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { return emulated.UnwrapHint(nativeInputs, nativeOutputs, func(mod *big.Int, inputs, outputs []*big.Int) error { var a, b, c bn254.E6 @@ -140,7 +140,7 @@ func DivE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error } // E12 hints -func InverseE12Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { +func inverseE12Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { return emulated.UnwrapHint(nativeInputs, nativeOutputs, func(mod *big.Int, inputs, outputs []*big.Int) error { var a, c bn254.E12 @@ -177,7 +177,7 @@ func InverseE12Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) }) } -func DivE12Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { +func divE12Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { return emulated.UnwrapHint(nativeInputs, nativeOutputs, func(mod *big.Int, inputs, outputs []*big.Int) error { var a, b, c bn254.E12 From 65a1d654fab304809a295a808fc0a6589ee5e241 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Wed, 15 Mar 2023 02:08:29 +0100 Subject: [PATCH 126/464] refactor: make lineEvaluation private --- std/algebra/emulated/sw_bn254/pairing.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 4eb792ee42..233860e025 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -139,10 +139,10 @@ var loopCounter = [66]int8{ -1, 0, -1, 0, 0, 0, 1, 0, -1, 0, 1, } -// LineEvaluation represents a sparse Fp12 Elmt (result of the line evaluation) +// lineEvaluation represents a sparse Fp12 Elmt (result of the line evaluation) // line: 1 - R0*(x/y) - R1*(1/y) = 0 instead of R0'*y - R1'*x - R2' = 0 // This makes the multiplication by lines (MulBy034) circuit-efficient. -type LineEvaluation struct { +type lineEvaluation struct { R0, R1 fields_bn254.E2 } @@ -156,7 +156,7 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { res := pr.Ext12.One() - var l1, l2 *LineEvaluation + var l1, l2 *lineEvaluation Qacc := make([]*G2Affine, n) QNeg := make([]*G2Affine, n) yInv := make([]*emulated.Element[emulated.BN254Fp], n) @@ -262,9 +262,9 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { // doubleAndAddStep doubles p1 and adds p2 to the result in affine coordinates, and evaluates the line in Miller loop // https://eprint.iacr.org/2022/1162 (Section 6.1) -func (pr Pairing) doubleAndAddStep(p1, p2 *G2Affine) (*G2Affine, *LineEvaluation, *LineEvaluation) { +func (pr Pairing) doubleAndAddStep(p1, p2 *G2Affine) (*G2Affine, *lineEvaluation, *lineEvaluation) { - var line1, line2 LineEvaluation + var line1, line2 lineEvaluation var p G2Affine // compute lambda1 = (y2-y1)/(x2-x1) @@ -314,10 +314,10 @@ func (pr Pairing) doubleAndAddStep(p1, p2 *G2Affine) (*G2Affine, *LineEvaluation // doubleStep doubles a point in affine coordinates, and evaluates the line in Miller loop // https://eprint.iacr.org/2022/1162 (Section 6.1) -func (pr Pairing) doubleStep(p1 *G2Affine) (*G2Affine, *LineEvaluation) { +func (pr Pairing) doubleStep(p1 *G2Affine) (*G2Affine, *lineEvaluation) { var p G2Affine - var line LineEvaluation + var line lineEvaluation // lambda = 3*p1.x**2/2*p.y n := pr.Ext2.Square(&p1.X) @@ -349,7 +349,7 @@ func (pr Pairing) doubleStep(p1 *G2Affine) (*G2Affine, *LineEvaluation) { // addStep adds two points in affine coordinates, and evaluates the line in Miller loop // https://eprint.iacr.org/2022/1162 (Section 6.1) -func (pr Pairing) addStep(p, q *G2Affine) (*G2Affine, *LineEvaluation) { +func (pr Pairing) addStep(p, q *G2Affine) (*G2Affine, *lineEvaluation) { // compute λ = (q.y-p.y)/(q.x-p.x) qypy := pr.Ext2.Sub(&q.Y, &p.Y) @@ -370,7 +370,7 @@ func (pr Pairing) addStep(p, q *G2Affine) (*G2Affine, *LineEvaluation) { res.X = *xr res.Y = *yr - var line LineEvaluation + var line lineEvaluation line.R0 = *pr.Ext2.Neg(λ) line.R1 = *pr.Ext2.Mul(λ, &p.X) line.R1 = *pr.Ext2.Sub(&line.R1, &p.Y) @@ -380,14 +380,14 @@ func (pr Pairing) addStep(p, q *G2Affine) (*G2Affine, *LineEvaluation) { } // addStepLineOnly computes the line that goes through p and q but does not compute p+q -func (pr Pairing) addStepLineOnly(p, q *G2Affine) *LineEvaluation { +func (pr Pairing) addStepLineOnly(p, q *G2Affine) *lineEvaluation { // compute λ = (q.y-p.y)/(q.x-p.x) qypy := pr.Ext2.Sub(&q.Y, &p.Y) qxpx := pr.Ext2.Sub(&q.X, &p.X) λ := pr.Ext2.DivUnchecked(qypy, qxpx) - var line LineEvaluation + var line lineEvaluation line.R0 = *pr.Ext2.Neg(λ) line.R1 = *pr.Ext2.Mul(λ, &p.X) line.R1 = *pr.Ext2.Sub(&line.R1, &p.Y) From 8699eba5710dca5a4551fb56ed361ead4408f94f Mon Sep 17 00:00:00 2001 From: Behrouz Date: Wed, 15 Mar 2023 05:27:30 +0330 Subject: [PATCH 127/464] feat: add a partition selector (#486) * feat: add a partition selector * fix: handle pivot points at the end of input We want to handle the case when `Partition` needs to select the whole input. * docs: add missing docs * test: add more tests * fix: reduce mask size It seems that handling pivot points at the end of the array was not a good idea. That will introduce the overhead of one more nonlinear constraint, while in many cased it is not needed. * docs: fix some comments * fix: use the new hint registration Also removes a todo about a failing test, since that test is not failing anymore. * fix: handle errors when calling hints * refactor: make hints unexported * docs: add a missing doc Signed-off-by: aybehrouz * refactor: use per file hint registration * refactor: use one `init` per package Apparently, Go runs all the init functions of a package when the package is imported. So, there is no point in having multiple init functions in different source files. * refactor: add GetHints for getting all hints * chore: remove empty line in import * feat: add `Slice` function This commit adds a `Slice` function which is a wrapper for a cascade of two `Partition` calls. It also makes StepMask unexported. * feat: handle full array selection Now we handle the case when pivotPosition is at the start or end of the input array. Signed-off-by: aybehrouz --------- Signed-off-by: aybehrouz Co-authored-by: Ivo Kubjas --- std/hints.go | 3 +- std/selector/doc_partition_test.go | 80 +++++++++++ std/selector/multiplexer.go | 26 ++-- std/selector/slice.go | 105 +++++++++++++++ std/selector/slice_test.go | 205 +++++++++++++++++++++++++++++ 5 files changed, 409 insertions(+), 10 deletions(-) create mode 100644 std/selector/doc_partition_test.go create mode 100644 std/selector/slice.go create mode 100644 std/selector/slice_test.go diff --git a/std/hints.go b/std/hints.go index c566ccaad8..cb061cd72d 100644 --- a/std/hints.go +++ b/std/hints.go @@ -32,8 +32,7 @@ func registerHints() { solver.RegisterHint(bits.NNAF) solver.RegisterHint(bits.IthBit) solver.RegisterHint(bits.NBits) - solver.RegisterHint(selector.MuxIndicators) - solver.RegisterHint(selector.MapIndicators) + solver.RegisterHint(selector.GetHints()...) solver.RegisterHint(emulated.GetHints()...) solver.RegisterHint(rangecheck.CountHint, rangecheck.DecomposeHint) } diff --git a/std/selector/doc_partition_test.go b/std/selector/doc_partition_test.go new file mode 100644 index 0000000000..2a9b4ea548 --- /dev/null +++ b/std/selector/doc_partition_test.go @@ -0,0 +1,80 @@ +package selector_test + +import "github.com/consensys/gnark/frontend" + +import ( + "fmt" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/backend/groth16" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/std/selector" +) + +// adderCircuit adds first Count number of its input array In. +type adderCircuit struct { + Count frontend.Variable + In [10]frontend.Variable + ExpectedSum frontend.Variable +} + +// Define defines the arithmetic circuit. +func (c *adderCircuit) Define(api frontend.API) error { + selectedPart := selector.Partition(api, c.Count, false, c.In[:]) + sum := api.Add(selectedPart[0], selectedPart[1], selectedPart[2:]...) + api.AssertIsEqual(sum, c.ExpectedSum) + return nil +} + +// ExamplePartition gives an example on how to use selector.Partition to make a circuit that accepts a Count and an +// input array In, and then calculates the sum of first Count numbers of the input array. +func ExamplePartition() { + circuit := adderCircuit{} + witness := adderCircuit{ + Count: 6, + In: [10]frontend.Variable{0, 2, 4, 6, 8, 10, 12, 14, 16, 18}, + ExpectedSum: 30, + } + ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) + if err != nil { + panic(err) + } else { + fmt.Println("compiled") + } + pk, vk, err := groth16.Setup(ccs) + if err != nil { + panic(err) + } else { + fmt.Println("setup done") + } + secretWitness, err := frontend.NewWitness(&witness, ecc.BN254.ScalarField()) + if err != nil { + panic(err) + } else { + fmt.Println("secret witness") + } + publicWitness, err := secretWitness.Public() + if err != nil { + panic(err) + } else { + fmt.Println("public witness") + } + proof, err := groth16.Prove(ccs, pk, secretWitness) + if err != nil { + panic(err) + } else { + fmt.Println("proof") + } + err = groth16.Verify(proof, vk, publicWitness) + if err != nil { + panic(err) + } else { + fmt.Println("verify") + } + // Output: compiled + // setup done + // secret witness + // public witness + // proof + // verify +} diff --git a/std/selector/multiplexer.go b/std/selector/multiplexer.go index d76e291e4f..af3b3e99f1 100644 --- a/std/selector/multiplexer.go +++ b/std/selector/multiplexer.go @@ -13,6 +13,7 @@ package selector import ( + "fmt" "math/big" "github.com/consensys/gnark/constraint/solver" @@ -21,8 +22,13 @@ import ( func init() { // register hints - solver.RegisterHint(MuxIndicators) - solver.RegisterHint(MapIndicators) + solver.RegisterHint(GetHints()...) +} + +// GetHints returns all hint functions used in this package. This method is +// useful for registering all hints in the solver. +func GetHints() []solver.Hint { + return []solver.Hint{stepOutput, muxIndicators, mapIndicators} } // Map is a key value associative array: the output will be values[i] such that keys[i] == queryKey. If keys does not @@ -55,10 +61,14 @@ func generateSelector(api frontend.API, wantMux bool, sel frontend.Variable, keys []frontend.Variable, values []frontend.Variable) (out frontend.Variable) { var indicators []frontend.Variable + var err error if wantMux { - indicators, _ = api.Compiler().NewHint(MuxIndicators, len(values), sel) + indicators, err = api.Compiler().NewHint(muxIndicators, len(values), sel) } else { - indicators, _ = api.Compiler().NewHint(MapIndicators, len(keys), append(keys, sel)...) + indicators, err = api.Compiler().NewHint(mapIndicators, len(keys), append(keys, sel)...) + } + if err != nil { + panic(fmt.Sprintf("error in calling Mux/Map hint: %v", err)) } out = 0 @@ -82,9 +92,9 @@ func generateSelector(api frontend.API, wantMux bool, sel frontend.Variable, return out } -// MuxIndicators is a hint function used within [Mux] function. It must be +// muxIndicators is a hint function used within [Mux] function. It must be // provided to the prover when circuit uses it. -func MuxIndicators(_ *big.Int, inputs []*big.Int, results []*big.Int) error { +func muxIndicators(_ *big.Int, inputs []*big.Int, results []*big.Int) error { sel := inputs[0] for i := 0; i < len(results); i++ { // i is an int which can be int32 or int64. We convert i to int64 then to bigInt, which is safe. We should @@ -98,9 +108,9 @@ func MuxIndicators(_ *big.Int, inputs []*big.Int, results []*big.Int) error { return nil } -// MapIndicators is a hint function used within [Map] function. It must be +// mapIndicators is a hint function used within [Map] function. It must be // provided to the prover when circuit uses it. -func MapIndicators(_ *big.Int, inputs []*big.Int, results []*big.Int) error { +func mapIndicators(_ *big.Int, inputs []*big.Int, results []*big.Int) error { key := inputs[len(inputs)-1] // We must make sure that we are initializing all elements of results for i := 0; i < len(results); i++ { diff --git a/std/selector/slice.go b/std/selector/slice.go new file mode 100644 index 0000000000..b21be6059a --- /dev/null +++ b/std/selector/slice.go @@ -0,0 +1,105 @@ +package selector + +import ( + "fmt" + "github.com/consensys/gnark/frontend" + "math/big" +) + +// Slice selects a slice of the input array at indices [start, end), and zeroes the array at other +// indices. More precisely, for each i we have: +// +// if i >= start and i < end +// out[i] = input[i] +// else +// out[i] = 0 +// +// We must have start >= 0 and end <= len(input), otherwise a proof cannot be generated. +func Slice(api frontend.API, start, end frontend.Variable, input []frontend.Variable) []frontend.Variable { + // it appears that this is the most efficient implementation. There is also another implementation + // which creates the mask by adding two stepMask outputs, however that would not work correctly when + // end < start. + out := Partition(api, end, false, input) + out = Partition(api, start, true, out) + return out +} + +// Partition selects left or right side of the input array, with respect to the pivotPosition. +// More precisely when rightSide is false, for each i we have: +// +// if i < pivotPosition +// out[i] = input[i] +// else +// out[i] = 0 +// +// and when rightSide is true, for each i we have: +// +// if i >= pivotPosition +// out[i] = input[i] +// else +// out[i] = 0 +// +// We must have pivotPosition >= 0 and pivotPosition <= len(input), otherwise a proof cannot be generated. +func Partition(api frontend.API, pivotPosition frontend.Variable, rightSide bool, + input []frontend.Variable) (out []frontend.Variable) { + out = make([]frontend.Variable, len(input)) + var mask []frontend.Variable + // we create a bit mask to multiply with the input. + if rightSide { + mask = stepMask(api, len(input), pivotPosition, 0, 1) + } else { + mask = stepMask(api, len(input), pivotPosition, 1, 0) + } + for i := 0; i < len(out); i++ { + out[i] = api.Mul(mask[i], input[i]) + } + return +} + +// stepMask generates a step like function into an output array of a given length. +// The output is an array of length outputLen, +// such that its first stepPosition elements are equal to startValue and the remaining elements are equal to +// endValue. Note that outputLen cannot be a circuit variable. +// +// We must have stepPosition >= 0 and stepPosition <= outputLen, otherwise a proof cannot be generated. +// This function panics when outputLen is less than 2. +func stepMask(api frontend.API, outputLen int, + stepPosition, startValue, endValue frontend.Variable) []frontend.Variable { + if outputLen < 2 { + panic("the output len of StepMask must be >= 2") + } + // get the output as a hint + out, err := api.Compiler().NewHint(stepOutput, outputLen, stepPosition, startValue, endValue) + if err != nil { + panic(fmt.Sprintf("error in calling StepMask hint: %v", err)) + } + + // add the boundary constraints: + // (out[0] - startValue) * stepPosition == 0 + api.AssertIsEqual(api.Mul(api.Sub(out[0], startValue), stepPosition), 0) + // (out[len(out)-1] - endValue) * (len(out) - stepPosition) == 0 + api.AssertIsEqual(api.Mul(api.Sub(out[len(out)-1], endValue), api.Sub(len(out), stepPosition)), 0) + + // add constraints for the correct form of a step function that steps at the stepPosition + for i := 1; i < len(out); i++ { + // (out[i] - out[i-1]) * (i - stepPosition) == 0 + api.AssertIsEqual(api.Mul(api.Sub(out[i], out[i-1]), api.Sub(i, stepPosition)), 0) + } + return out +} + +// stepOutput is a hint function used within [StepMask] function. It must be +// provided to the prover when circuit uses it. +func stepOutput(_ *big.Int, inputs, results []*big.Int) error { + stepPos := inputs[0] + startValue := inputs[1] + endValue := inputs[2] + for i := 0; i < len(results); i++ { + if i < int(stepPos.Int64()) { + results[i].Set(startValue) + } else { + results[i].Set(endValue) + } + } + return nil +} diff --git a/std/selector/slice_test.go b/std/selector/slice_test.go new file mode 100644 index 0000000000..35715c886e --- /dev/null +++ b/std/selector/slice_test.go @@ -0,0 +1,205 @@ +package selector_test + +import ( + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/selector" + "github.com/consensys/gnark/test" + "testing" +) + +type partitionerCircuit struct { + Pivot frontend.Variable `gnark:",public"` + In [6]frontend.Variable `gnark:",public"` + WantLeft [6]frontend.Variable `gnark:",public"` + WantRight [6]frontend.Variable `gnark:",public"` +} + +func (c *partitionerCircuit) Define(api frontend.API) error { + gotLeft := selector.Partition(api, c.Pivot, false, c.In[:]) + for i, want := range c.WantLeft { + api.AssertIsEqual(gotLeft[i], want) + } + + gotRight := selector.Partition(api, c.Pivot, true, c.In[:]) + for i, want := range c.WantRight { + api.AssertIsEqual(gotRight[i], want) + } + + return nil +} + +type ignoredOutputPartitionerCircuit struct { + Pivot frontend.Variable `gnark:",public"` + In [2]frontend.Variable `gnark:",public"` +} + +func (c *ignoredOutputPartitionerCircuit) Define(api frontend.API) error { + _ = selector.Partition(api, c.Pivot, false, c.In[:]) + _ = selector.Partition(api, c.Pivot, true, c.In[:]) + return nil +} + +func TestPartition(t *testing.T) { + assert := test.NewAssert(t) + + assert.ProverSucceeded(&partitionerCircuit{}, &partitionerCircuit{ + Pivot: 3, + In: [6]frontend.Variable{10, 20, 30, 40, 50, 60}, + WantLeft: [6]frontend.Variable{10, 20, 30, 0, 0, 0}, + WantRight: [6]frontend.Variable{0, 0, 0, 40, 50, 60}, + }) + + assert.ProverSucceeded(&partitionerCircuit{}, &partitionerCircuit{ + Pivot: 1, + In: [6]frontend.Variable{10, 20, 30, 40, 50, 60}, + WantLeft: [6]frontend.Variable{10, 0, 0, 0, 0, 0}, + WantRight: [6]frontend.Variable{0, 20, 30, 40, 50, 60}, + }) + + assert.ProverSucceeded(&partitionerCircuit{}, &partitionerCircuit{ + Pivot: 5, + In: [6]frontend.Variable{10, 20, 30, 40, 50, 60}, + WantLeft: [6]frontend.Variable{10, 20, 30, 40, 50, 0}, + WantRight: [6]frontend.Variable{0, 0, 0, 0, 0, 60}, + }) + + assert.ProverFailed(&partitionerCircuit{}, &partitionerCircuit{ + Pivot: 5, + In: [6]frontend.Variable{10, 20, 30, 40, 50, 60}, + WantLeft: [6]frontend.Variable{10, 20, 30, 40, 0, 0}, + WantRight: [6]frontend.Variable{0, 0, 0, 0, 0, 0}, + }) + + assert.ProverSucceeded(&partitionerCircuit{}, &partitionerCircuit{ + Pivot: 6, + In: [6]frontend.Variable{10, 20, 30, 40, 50, 60}, + WantLeft: [6]frontend.Variable{10, 20, 30, 40, 50, 60}, + WantRight: [6]frontend.Variable{0, 0, 0, 0, 0, 0}, + }) + + assert.ProverSucceeded(&partitionerCircuit{}, &partitionerCircuit{ + Pivot: 0, + In: [6]frontend.Variable{10, 20, 30, 40, 50, 60}, + WantLeft: [6]frontend.Variable{0, 0, 0, 0, 0, 0}, + WantRight: [6]frontend.Variable{10, 20, 30, 40, 50, 60}, + }) + + // Pivot is outside and the prover fails: + assert.ProverFailed(&partitionerCircuit{}, &partitionerCircuit{ + Pivot: 7, + In: [6]frontend.Variable{10, 20, 30, 40, 50, 60}, + WantLeft: [6]frontend.Variable{10, 20, 30, 40, 50, 60}, + WantRight: [6]frontend.Variable{0, 0, 0, 0, 0, 0}, + }) + + assert.ProverFailed(&partitionerCircuit{}, &partitionerCircuit{ + Pivot: -1, + In: [6]frontend.Variable{10, 20, 30, 40, 50, 60}, + WantLeft: [6]frontend.Variable{0, 0, 0, 0, 0, 0}, + WantRight: [6]frontend.Variable{10, 20, 30, 40, 50, 60}, + }) + + // tests by ignoring the output: + assert.ProverSucceeded(&ignoredOutputPartitionerCircuit{}, &ignoredOutputPartitionerCircuit{ + Pivot: 1, + In: [2]frontend.Variable{10, 20}, + }) + + assert.ProverFailed(&ignoredOutputPartitionerCircuit{}, &ignoredOutputPartitionerCircuit{ + Pivot: -1, + In: [2]frontend.Variable{10, 20}, + }) + + assert.ProverFailed(&ignoredOutputPartitionerCircuit{}, &ignoredOutputPartitionerCircuit{ + Pivot: 3, + In: [2]frontend.Variable{10, 20}, + }) +} + +type slicerCircuit struct { + Start, End frontend.Variable `gnark:",public"` + In [7]frontend.Variable `gnark:",public"` + WantSlice [7]frontend.Variable `gnark:",public"` +} + +func (c *slicerCircuit) Define(api frontend.API) error { + gotSlice := selector.Slice(api, c.Start, c.End, c.In[:]) + for i, want := range c.WantSlice { + api.AssertIsEqual(gotSlice[i], want) + } + return nil +} + +func TestSlice(t *testing.T) { + assert := test.NewAssert(t) + + assert.ProverSucceeded(&slicerCircuit{}, &slicerCircuit{ + Start: 2, + End: 5, + In: [7]frontend.Variable{0, 1, 2, 3, 4, 5, 6}, + WantSlice: [7]frontend.Variable{0, 0, 2, 3, 4, 0, 0}, + }) + + assert.ProverSucceeded(&slicerCircuit{}, &slicerCircuit{ + Start: 3, + End: 4, + In: [7]frontend.Variable{0, 1, 2, 3, 4, 5, 6}, + WantSlice: [7]frontend.Variable{0, 0, 0, 3, 0, 0, 0}, + }) + + assert.ProverSucceeded(&slicerCircuit{}, &slicerCircuit{ + Start: 3, + End: 3, + In: [7]frontend.Variable{0, 1, 2, 3, 4, 5, 6}, + WantSlice: [7]frontend.Variable{0, 0, 0, 0, 0, 0, 0}, + }) + + assert.ProverSucceeded(&slicerCircuit{}, &slicerCircuit{ + Start: 3, + End: 1, + In: [7]frontend.Variable{0, 1, 2, 3, 4, 5, 6}, + WantSlice: [7]frontend.Variable{0, 0, 0, 0, 0, 0, 0}, + }) + + assert.ProverSucceeded(&slicerCircuit{}, &slicerCircuit{ + Start: 3, + End: 6, + In: [7]frontend.Variable{0, 1, 2, 3, 4, 5, 6}, + WantSlice: [7]frontend.Variable{0, 0, 0, 3, 4, 5, 0}, + }) + + assert.ProverSucceeded(&slicerCircuit{}, &slicerCircuit{ + Start: 3, + End: 7, + In: [7]frontend.Variable{0, 1, 2, 3, 4, 5, 6}, + WantSlice: [7]frontend.Variable{0, 0, 0, 3, 4, 5, 6}, + }) + + assert.ProverSucceeded(&slicerCircuit{}, &slicerCircuit{ + Start: 0, + End: 2, + In: [7]frontend.Variable{0, 1, 2, 3, 4, 5, 6}, + WantSlice: [7]frontend.Variable{0, 1, 0, 0, 0, 0, 0}, + }) + + assert.ProverSucceeded(&slicerCircuit{}, &slicerCircuit{ + Start: 0, + End: 7, + In: [7]frontend.Variable{0, 1, 2, 3, 4, 5, 6}, + WantSlice: [7]frontend.Variable{0, 1, 2, 3, 4, 5, 6}, + }) + + assert.ProverFailed(&slicerCircuit{}, &slicerCircuit{ + Start: 3, + End: 8, + In: [7]frontend.Variable{0, 1, 2, 3, 4, 5, 6}, + WantSlice: [7]frontend.Variable{0, 0, 0, 3, 4, 5, 6}, + }) + + assert.ProverFailed(&slicerCircuit{}, &slicerCircuit{ + Start: -1, + End: 2, + In: [7]frontend.Variable{0, 1, 2, 3, 4, 5, 6}, + WantSlice: [7]frontend.Variable{0, 1, 0, 0, 0, 0, 0}, + }) +} From dd3143dca7e9f85836a8e59f8daec918533d0269 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 15 Mar 2023 08:07:28 +0100 Subject: [PATCH 128/464] refactor(pairing-bn254): remove dead code (E2 Halve) --- std/algebra/emulated/fields_bn254/e2.go | 21 ------------- std/algebra/emulated/fields_bn254/e2_test.go | 32 -------------------- std/algebra/emulated/fields_bn254/hints.go | 18 ----------- 3 files changed, 71 deletions(-) diff --git a/std/algebra/emulated/fields_bn254/e2.go b/std/algebra/emulated/fields_bn254/e2.go index a30ee7b0dd..5633e83502 100644 --- a/std/algebra/emulated/fields_bn254/e2.go +++ b/std/algebra/emulated/fields_bn254/e2.go @@ -279,27 +279,6 @@ func (e Ext2) Double(x *E2) *E2 { } } -func (e Ext2) Halve(x *E2) *E2 { - res, err := e.fp.NewHint(halveE2Hint, 2, &x.A0, &x.A1) - if err != nil { - // err is non-nil only for invalid number of inputs - panic(err) - } - - // half = x/2 - half := E2{ - A0: *res[0], - A1: *res[1], - } - - // x == 2*half - _x := e.Double(&half) - e.AssertIsEqual(x, _x) - - return &half - -} - func (e Ext2) AssertIsEqual(x, y *E2) { e.fp.AssertIsEqual(&x.A0, &y.A0) e.fp.AssertIsEqual(&x.A1, &y.A1) diff --git a/std/algebra/emulated/fields_bn254/e2_test.go b/std/algebra/emulated/fields_bn254/e2_test.go index 6285e525a1..a7721a5b94 100644 --- a/std/algebra/emulated/fields_bn254/e2_test.go +++ b/std/algebra/emulated/fields_bn254/e2_test.go @@ -106,38 +106,6 @@ func TestDoubleFp2(t *testing.T) { } -type e2Halve struct { - A, C E2 -} - -func (circuit *e2Halve) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt2(ba) - expected := e.Halve(&circuit.A) - e.AssertIsEqual(expected, &circuit.C) - return nil -} - -func TestHalveFp2(t *testing.T) { - - assert := test.NewAssert(t) - // witness values - var a, b, c bn254.E2 - _, _ = a.SetRandom() - _, _ = b.SetRandom() - c = a - c.Halve() - - witness := e2Halve{ - A: FromE2(&a), - C: FromE2(&c), - } - - err := test.IsSolved(&e2Halve{}, &witness, ecc.BN254.ScalarField()) - assert.NoError(err) - -} - type e2Mul struct { A, B, C E2 } diff --git a/std/algebra/emulated/fields_bn254/hints.go b/std/algebra/emulated/fields_bn254/hints.go index 9dd3727b04..b69e5012fc 100644 --- a/std/algebra/emulated/fields_bn254/hints.go +++ b/std/algebra/emulated/fields_bn254/hints.go @@ -18,7 +18,6 @@ func GetHints() []solver.Hint { // E2 divE2Hint, inverseE2Hint, - halveE2Hint, // E6 divE6Hint, inverseE6Hint, @@ -64,23 +63,6 @@ func divE2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error }) } -func halveE2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { - return emulated.UnwrapHint(nativeInputs, nativeOutputs, - func(mod *big.Int, inputs, outputs []*big.Int) error { - var a, c bn254.E2 - - a.A0.SetBigInt(inputs[0]) - a.A1.SetBigInt(inputs[1]) - - c.Set(&a).Halve() - - c.A0.BigInt(outputs[0]) - c.A1.BigInt(outputs[1]) - - return nil - }) -} - // E6 hints func inverseE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { return emulated.UnwrapHint(nativeInputs, nativeOutputs, From fb8c36f385493377299d2c3707fce7ed80f68ae4 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 15 Mar 2023 08:26:27 +0100 Subject: [PATCH 129/464] perf(pairing-bn254): optimize doubleStep (mulByConst 3) --- std/algebra/emulated/fields_bn254/e2.go | 9 +++++++++ std/algebra/emulated/sw_bn254/pairing.go | 5 +++-- std/algebra/emulated/sw_bn254/pairing_test.go | 14 ++++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/std/algebra/emulated/fields_bn254/e2.go b/std/algebra/emulated/fields_bn254/e2.go index 5633e83502..33ce019222 100644 --- a/std/algebra/emulated/fields_bn254/e2.go +++ b/std/algebra/emulated/fields_bn254/e2.go @@ -74,6 +74,15 @@ func (e Ext2) MulByElement(x *E2, y *baseEl) *E2 { } } +func (e Ext2) MulByConstElement(x *E2, y *big.Int) *E2 { + z0 := e.fp.MulConst(&x.A0, y) + z1 := e.fp.MulConst(&x.A1, y) + return &E2{ + A0: *z0, + A1: *z1, + } +} + func (e Ext2) Conjugate(x *E2) *E2 { z0 := x.A0 z1 := e.fp.Neg(&x.A1) diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 233860e025..dbc72d0618 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -3,6 +3,7 @@ package sw_bn254 import ( "errors" "fmt" + "math/big" "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark/frontend" @@ -321,8 +322,8 @@ func (pr Pairing) doubleStep(p1 *G2Affine) (*G2Affine, *lineEvaluation) { // lambda = 3*p1.x**2/2*p.y n := pr.Ext2.Square(&p1.X) - three := emulated.ValueOf[emulated.BN254Fp](3) - n = pr.Ext2.MulByElement(n, &three) + three := big.NewInt(3) + n = pr.Ext2.MulByConstElement(n, three) d := pr.Ext2.Double(&p1.Y) l := pr.Ext2.DivUnchecked(n, d) diff --git a/std/algebra/emulated/sw_bn254/pairing_test.go b/std/algebra/emulated/sw_bn254/pairing_test.go index 4fbb831b2d..3a062f795a 100644 --- a/std/algebra/emulated/sw_bn254/pairing_test.go +++ b/std/algebra/emulated/sw_bn254/pairing_test.go @@ -7,7 +7,10 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/profile" "github.com/consensys/gnark/test" ) @@ -85,3 +88,14 @@ func TestPairTestSolve(t *testing.T) { err = test.IsSolved(&PairCircuit{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } + +// bench +var ccsBench constraint.ConstraintSystem + +func BenchmarkPairing(b *testing.B) { + var c PairCircuit + p := profile.Start() + ccsBench, _ = frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &c) + p.Stop() + fmt.Println(p.NbConstraints()) +} From f009036559c6abe320e290dbe4f9e71fa4573b86 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 15 Mar 2023 12:23:27 +0100 Subject: [PATCH 130/464] style(pairing-bn254): add comments --- std/algebra/emulated/fields_bn254/e2.go | 2 - std/algebra/emulated/sw_bn254/pairing.go | 119 +++++++++++++++-------- 2 files changed, 81 insertions(+), 40 deletions(-) diff --git a/std/algebra/emulated/fields_bn254/e2.go b/std/algebra/emulated/fields_bn254/e2.go index 33ce019222..95b866be1a 100644 --- a/std/algebra/emulated/fields_bn254/e2.go +++ b/std/algebra/emulated/fields_bn254/e2.go @@ -63,8 +63,6 @@ func NewExt2(baseField *curveF) *Ext2 { return &Ext2{fp: baseField, nonResidues: nonResidues} } -// TODO: check where to use Mod and where ModMul. - func (e Ext2) MulByElement(x *E2, y *baseEl) *E2 { z0 := e.fp.MulMod(&x.A0, y) z1 := e.fp.MulMod(&x.A1, y) diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index dbc72d0618..54a4525765 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -131,6 +131,7 @@ func (pr Pairing) AssertIsEqual(x, y *GTEl) { } // loopCounter = 6*seed+2 in 2-NAF +// loopCounter = 29793968203157093288 var loopCounter = [66]int8{ 0, 0, 0, 1, 0, 1, 0, -1, 0, 0, -1, 0, 0, 0, 1, 0, 0, -1, 0, -1, 0, 0, @@ -141,13 +142,15 @@ var loopCounter = [66]int8{ } // lineEvaluation represents a sparse Fp12 Elmt (result of the line evaluation) -// line: 1 - R0*(x/y) - R1*(1/y) = 0 instead of R0'*y - R1'*x - R2' = 0 -// This makes the multiplication by lines (MulBy034) circuit-efficient. +// line: 1 - R0(x/y) - R1(1/y) = 0 instead of R0'*y - R1'*x - R2' = 0 This +// makes the multiplication by lines (MulBy034) and between lines (Mul034By034) +// circuit-efficient. type lineEvaluation struct { R0, R1 fields_bn254.E2 } // MillerLoop computes the multi-Miller loop +// ∏ᵢ { fᵢ_{ℓ,Q}(P) · ℓᵢ_{Q,π(Q)}(P) · ℓᵢ_{Q,-π²(Q)}(P) } func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { // check input size match n := len(P) @@ -166,18 +169,28 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { for k := 0; k < n; k++ { Qacc[k] = Q[k] QNeg[k] = &G2Affine{X: Q[k].X, Y: *pr.Ext2.Neg(&Q[k].Y)} + // (x,0) cannot be on BN254 because -3 is a cubic non-residue in Fp + // so, 1/y is well defined for all points P's yInv[k] = pr.curveF.Inverse(&P[k].Y) - xOverY[k] = pr.curveF.Div(&P[k].X, &P[k].Y) + xOverY[k] = pr.curveF.MulMod(&P[k].X, yInv[k]) } - // k = 0 + // Compute ∏ᵢ { fᵢ_{ℓ,Q}(P) } + // i = len(loopCounter) - 2, separately to avoid E12 Square + // (Square(res) = 1² = 1) + + // k = 0, separately to avoid MulBy034 (res × ℓ) + // (assign line to res) Qacc[0], l1 = pr.doubleStep(Qacc[0]) + // line evaluation at P[0] res.C1.B0 = *pr.MulByElement(&l1.R0, xOverY[0]) res.C1.B1 = *pr.MulByElement(&l1.R1, yInv[0]) if n >= 2 { - // k = 1 + // k = 1, separately to avoid MulBy034 (res × ℓ) + // (res is also a line at this point, so we use Mul034By034 ℓ × ℓ) Qacc[1], l1 = pr.doubleStep(Qacc[1]) + // line evaluation at P[1] l1.R0 = *pr.MulByElement(&l1.R0, xOverY[1]) l1.R1 = *pr.MulByElement(&l1.R1, yInv[1]) res = pr.Mul034By034(&l1.R0, &l1.R1, &res.C1.B0, &res.C1.B1) @@ -186,45 +199,67 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { if n >= 3 { // k >= 2 for k := 2; k < n; k++ { + // Qacc[k] ← 2Qacc[k] and l1 the tangent ℓ passing 2Qacc[k] Qacc[k], l1 = pr.doubleStep(Qacc[k]) + // line evaluation at P[k] l1.R0 = *pr.MulByElement(&l1.R0, xOverY[k]) l1.R1 = *pr.MulByElement(&l1.R1, yInv[k]) + // ℓ × res res = pr.MulBy034(res, &l1.R0, &l1.R1) } } for i := len(loopCounter) - 3; i >= 0; i-- { + // mutualize the square among n Miller loops + // (∏ᵢfᵢ)² res = pr.Square(res) switch loopCounter[i] { case 0: for k := 0; k < n; k++ { + // Qacc[k] ← 2Qacc[k] and l1 the tangent ℓ passing 2Qacc[k] Qacc[k], l1 = pr.doubleStep(Qacc[k]) + // line evaluation at P[k] l1.R0 = *pr.MulByElement(&l1.R0, xOverY[k]) l1.R1 = *pr.MulByElement(&l1.R1, yInv[k]) + // ℓ × res res = pr.MulBy034(res, &l1.R0, &l1.R1) } case 1: for k := 0; k < n; k++ { + // Qacc[k] ← 2Qacc[k]+Q[k], + // l1 the line ℓ passing Qacc[k] and Q[k] + // l2 the line ℓ passing (Qacc[k]+Q[k]) and Qacc[k] Qacc[k], l1, l2 = pr.doubleAndAddStep(Qacc[k], Q[k]) + // line evaluation at P[k] l1.R0 = *pr.MulByElement(&l1.R0, xOverY[k]) l1.R1 = *pr.MulByElement(&l1.R1, yInv[k]) + // ℓ × res res = pr.MulBy034(res, &l1.R0, &l1.R1) + // line evaluation at P[k] l2.R0 = *pr.MulByElement(&l2.R0, xOverY[k]) l2.R1 = *pr.MulByElement(&l2.R1, yInv[k]) + // ℓ × res res = pr.MulBy034(res, &l2.R0, &l2.R1) } case -1: for k := 0; k < n; k++ { + // Qacc[k] ← 2Qacc[k]-Q[k], + // l1 the line ℓ passing Qacc[k] and -Q[k] + // l2 the line ℓ passing (Qacc[k]-Q[k]) and Qacc[k] Qacc[k], l1, l2 = pr.doubleAndAddStep(Qacc[k], QNeg[k]) + // line evaluation at P[k] l1.R0 = *pr.MulByElement(&l1.R0, xOverY[k]) l1.R1 = *pr.MulByElement(&l1.R1, yInv[k]) + // ℓ × res res = pr.MulBy034(res, &l1.R0, &l1.R1) + // line evaluation at P[k] l2.R0 = *pr.MulByElement(&l2.R0, xOverY[k]) l2.R1 = *pr.MulByElement(&l2.R1, yInv[k]) + // ℓ × res res = pr.MulBy034(res, &l2.R0, &l2.R1) } @@ -233,6 +268,7 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { } } + // Compute ∏ᵢ { ℓᵢ_{Q,π(Q)}(P) · ℓᵢ_{Q,-π²(Q)}(P) } Q1, Q2 := new(G2Affine), new(G2Affine) for k := 0; k < n; k++ { //Q1 = π(Q) @@ -246,14 +282,21 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { Q2.Y = *pr.Ext12.Ext2.MulByNonResidue2Power3(&Q[k].Y) Q2.Y = *pr.Ext12.Ext2.Neg(&Q2.Y) + // Qacc[k] ← Qacc[k]+π(Q) and + // l1 the line passing Qacc[k] and π(Q) Qacc[k], l1 = pr.addStep(Qacc[k], Q1) + // line evaluation at P[k] l1.R0 = *pr.Ext2.MulByElement(&l1.R0, xOverY[k]) l1.R1 = *pr.Ext2.MulByElement(&l1.R1, yInv[k]) + // ℓ × res res = pr.MulBy034(res, &l1.R0, &l1.R1) + // l2 the line passing Qacc[k] and -π²(Q) l2 = pr.addStepLineOnly(Qacc[k], Q2) + // line evaluation at P[k] l2.R0 = *pr.MulByElement(&l2.R0, xOverY[k]) l2.R1 = *pr.MulByElement(&l2.R1, yInv[k]) + // ℓ × res res = pr.MulBy034(res, &l2.R0, &l2.R1) } @@ -268,12 +311,12 @@ func (pr Pairing) doubleAndAddStep(p1, p2 *G2Affine) (*G2Affine, *lineEvaluation var line1, line2 lineEvaluation var p G2Affine - // compute lambda1 = (y2-y1)/(x2-x1) + // compute λ1 = (y2-y1)/(x2-x1) n := pr.Ext2.Sub(&p1.Y, &p2.Y) d := pr.Ext2.Sub(&p1.X, &p2.X) l1 := pr.Ext2.DivUnchecked(n, d) - // x3 =lambda1**2-p1.x-p2.x + // compute x3 =λ1²-x1-x2 x3 := pr.Ext2.Square(l1) x3 = pr.Ext2.Sub(x3, &p1.X) x3 = pr.Ext2.Sub(x3, &p2.X) @@ -285,19 +328,19 @@ func (pr Pairing) doubleAndAddStep(p1, p2 *G2Affine) (*G2Affine, *lineEvaluation line1.R1 = *pr.Ext2.Mul(l1, &p1.X) line1.R1 = *pr.Ext2.Sub(&line1.R1, &p1.Y) - // compute lambda2 = -lambda1-2*y1/(x3-x1) + // compute λ2 = -λ1-2y1/(x3-x1) n = pr.Ext2.Double(&p1.Y) d = pr.Ext2.Sub(x3, &p1.X) l2 := pr.Ext2.DivUnchecked(n, d) l2 = pr.Ext2.Add(l2, l1) l2 = pr.Ext2.Neg(l2) - // compute x4 = lambda2**2-x1-x3 + // compute x4 = λ2²-x1-x3 x4 := pr.Ext2.Square(l2) x4 = pr.Ext2.Sub(x4, &p1.X) x4 = pr.Ext2.Sub(x4, x3) - // compute y4 = lambda2*(x1 - x4)-y1 + // compute y4 = λ2(x1 - x4)-y1 y4 := pr.Ext2.Sub(&p1.X, x4) y4 = pr.Ext2.Mul(l2, y4) y4 = pr.Ext2.Sub(y4, &p1.Y) @@ -320,28 +363,28 @@ func (pr Pairing) doubleStep(p1 *G2Affine) (*G2Affine, *lineEvaluation) { var p G2Affine var line lineEvaluation - // lambda = 3*p1.x**2/2*p.y + // λ = 3x²/2y n := pr.Ext2.Square(&p1.X) three := big.NewInt(3) n = pr.Ext2.MulByConstElement(n, three) d := pr.Ext2.Double(&p1.Y) - l := pr.Ext2.DivUnchecked(n, d) + λ := pr.Ext2.DivUnchecked(n, d) - // xr = lambda**2-2*p1.x - xr := pr.Ext2.Square(l) + // xr = λ²-2x + xr := pr.Ext2.Square(λ) xr = pr.Ext2.Sub(xr, &p1.X) xr = pr.Ext2.Sub(xr, &p1.X) - // yr = lambda*(p.x-xr)-p.y + // yr = λ(x-xr)-y yr := pr.Ext2.Sub(&p1.X, xr) - yr = pr.Ext2.Mul(l, yr) + yr = pr.Ext2.Mul(λ, yr) yr = pr.Ext2.Sub(yr, &p1.Y) p.X = *xr p.Y = *yr - line.R0 = *pr.Ext2.Neg(l) - line.R1 = *pr.Ext2.Mul(l, &p1.X) + line.R0 = *pr.Ext2.Neg(λ) + line.R1 = *pr.Ext2.Mul(λ, &p1.X) line.R1 = *pr.Ext2.Sub(&line.R1, &p1.Y) return &p, &line @@ -350,22 +393,22 @@ func (pr Pairing) doubleStep(p1 *G2Affine) (*G2Affine, *lineEvaluation) { // addStep adds two points in affine coordinates, and evaluates the line in Miller loop // https://eprint.iacr.org/2022/1162 (Section 6.1) -func (pr Pairing) addStep(p, q *G2Affine) (*G2Affine, *lineEvaluation) { +func (pr Pairing) addStep(p1, p2 *G2Affine) (*G2Affine, *lineEvaluation) { - // compute λ = (q.y-p.y)/(q.x-p.x) - qypy := pr.Ext2.Sub(&q.Y, &p.Y) - qxpx := pr.Ext2.Sub(&q.X, &p.X) - λ := pr.Ext2.DivUnchecked(qypy, qxpx) + // compute λ = (y2-y1)/(x2-x1) + p2ypy := pr.Ext2.Sub(&p2.Y, &p1.Y) + p2xpx := pr.Ext2.Sub(&p2.X, &p1.X) + λ := pr.Ext2.DivUnchecked(p2ypy, p2xpx) - // xr = λ²-p.x-q.x + // xr = λ²-x1-x2 λλ := pr.Ext2.Square(λ) - qxpx = pr.Ext2.Add(&p.X, &q.X) - xr := pr.Ext2.Sub(λλ, qxpx) + p2xpx = pr.Ext2.Add(&p1.X, &p2.X) + xr := pr.Ext2.Sub(λλ, p2xpx) - // p.y = λ(p.x-r.x) - p.y - pxrx := pr.Ext2.Sub(&p.X, xr) + // yr = λ(x1-xr) - y1 + pxrx := pr.Ext2.Sub(&p1.X, xr) λpxrx := pr.Ext2.Mul(λ, pxrx) - yr := pr.Ext2.Sub(λpxrx, &p.Y) + yr := pr.Ext2.Sub(λpxrx, &p1.Y) var res G2Affine res.X = *xr @@ -373,25 +416,25 @@ func (pr Pairing) addStep(p, q *G2Affine) (*G2Affine, *lineEvaluation) { var line lineEvaluation line.R0 = *pr.Ext2.Neg(λ) - line.R1 = *pr.Ext2.Mul(λ, &p.X) - line.R1 = *pr.Ext2.Sub(&line.R1, &p.Y) + line.R1 = *pr.Ext2.Mul(λ, &p1.X) + line.R1 = *pr.Ext2.Sub(&line.R1, &p1.Y) return &res, &line } -// addStepLineOnly computes the line that goes through p and q but does not compute p+q -func (pr Pairing) addStepLineOnly(p, q *G2Affine) *lineEvaluation { +// addStepLineOnly computes the line that goes through p1 and p2 but does not compute p1+p2 +func (pr Pairing) addStepLineOnly(p1, p2 *G2Affine) *lineEvaluation { - // compute λ = (q.y-p.y)/(q.x-p.x) - qypy := pr.Ext2.Sub(&q.Y, &p.Y) - qxpx := pr.Ext2.Sub(&q.X, &p.X) + // compute λ = (y2-y1)/(x2-x1) + qypy := pr.Ext2.Sub(&p2.Y, &p1.Y) + qxpx := pr.Ext2.Sub(&p2.X, &p1.X) λ := pr.Ext2.DivUnchecked(qypy, qxpx) var line lineEvaluation line.R0 = *pr.Ext2.Neg(λ) - line.R1 = *pr.Ext2.Mul(λ, &p.X) - line.R1 = *pr.Ext2.Sub(&line.R1, &p.Y) + line.R1 = *pr.Ext2.Mul(λ, &p1.X) + line.R1 = *pr.Ext2.Sub(&line.R1, &p1.Y) return &line From 3aa0dd6412b95e659088ffa0f5f00a047665558c Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 15 Mar 2023 12:52:41 +0100 Subject: [PATCH 131/464] style(pairing-bn254): add comments --- std/algebra/emulated/fields_bn254/e12.go | 46 ++++++++++++------------ std/algebra/emulated/sw_bn254/pairing.go | 4 +-- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/std/algebra/emulated/fields_bn254/e12.go b/std/algebra/emulated/fields_bn254/e12.go index 68231299d7..8cf514aca3 100644 --- a/std/algebra/emulated/fields_bn254/e12.go +++ b/std/algebra/emulated/fields_bn254/e12.go @@ -121,25 +121,25 @@ func (e Ext12) CyclotomicSquare(x *E12) *E12 { // Th. 3.2 with minor modifications to fit our tower func (e Ext12) CyclotomicSquareCompressed(x *E12) *E12 { - // t0 = g1^2 + // t0 = g1² t0 := e.Ext2.Square(&x.C0.B1) - // t1 = g5^2 + // t1 = g5² t1 := e.Ext2.Square(&x.C1.B2) // t5 = g1 + g5 t5 := e.Ext2.Add(&x.C0.B1, &x.C1.B2) - // t2 = (g1 + g5)^2 + // t2 = (g1 + g5)² t2 := e.Ext2.Square(t5) - // t3 = g1^2 + g5^2 + // t3 = g1² + g5² t3 := e.Ext2.Add(t0, t1) // t5 = 2 * g1 * g5 t5 = e.Ext2.Sub(t2, t3) // t6 = g3 + g2 t6 := e.Ext2.Add(&x.C1.B0, &x.C0.B2) - // t3 = (g3 + g2)^2 + // t3 = (g3 + g2)² t3 = e.Ext2.Square(t6) - // t2 = g3^2 + // t2 = g3² t2 = e.Ext2.Square(&x.C1.B0) // t6 = 2 * nr * g1 * g5 @@ -150,33 +150,33 @@ func (e Ext12) CyclotomicSquareCompressed(x *E12) *E12 { // z3 = 6 * nr * g1 * g5 + 2 * g3 C1B0 := e.Ext2.Add(t5, t6) - // t4 = nr * g5^2 + // t4 = nr * g5² t4 := e.Ext2.MulByNonResidue(t1) - // t5 = nr * g5^2 + g1^2 + // t5 = nr * g5² + g1² t5 = e.Ext2.Add(t0, t4) - // t6 = nr * g5^2 + g1^2 - g2 + // t6 = nr * g5² + g1² - g2 t6 = e.Ext2.Sub(t5, &x.C0.B2) - // t1 = g2^2 + // t1 = g2² t1 = e.Ext2.Square(&x.C0.B2) - // t6 = 2 * nr * g5^2 + 2 * g1^2 - 2*g2 + // t6 = 2 * nr * g5² + 2 * g1² - 2*g2 t6 = e.Ext2.Double(t6) - // z2 = 3 * nr * g5^2 + 3 * g1^2 - 2*g2 + // z2 = 3 * nr * g5² + 3 * g1² - 2*g2 C0B2 := e.Ext2.Add(t6, t5) - // t4 = nr * g2^2 + // t4 = nr * g2² t4 = e.Ext2.MulByNonResidue(t1) - // t5 = g3^2 + nr * g2^2 + // t5 = g3² + nr * g2² t5 = e.Ext2.Add(t2, t4) - // t6 = g3^2 + nr * g2^2 - g1 + // t6 = g3² + nr * g2² - g1 t6 = e.Ext2.Sub(t5, &x.C0.B1) - // t6 = 2 * g3^2 + 2 * nr * g2^2 - 2 * g1 + // t6 = 2 * g3² + 2 * nr * g2² - 2 * g1 t6 = e.Ext2.Double(t6) - // z1 = 3 * g3^2 + 3 * nr * g2^2 - 2 * g1 + // z1 = 3 * g3² + 3 * nr * g2² - 2 * g1 C0B1 := e.Ext2.Add(t6, t5) - // t0 = g2^2 + g3^2 + // t0 = g2² + g3² t0 = e.Ext2.Add(t2, t1) // t5 = 2 * g3 * g2 t5 = e.Ext2.Sub(t3, t0) @@ -217,13 +217,13 @@ func (e Ext12) DecompressKarabina(x *E12) *E12 { // TODO: hadle the g3==0 case with MUX - // t0 = g1^2 + // t0 = g1² t0 := e.Ext2.Square(&x.C0.B1) - // t1 = 3 * g1^2 - 2 * g2 + // t1 = 3 * g1² - 2 * g2 t1 := e.Ext2.Sub(t0, &x.C0.B2) t1 = e.Ext2.Double(t1) t1 = e.Ext2.Add(t1, t0) - // t0 = E * g5^2 + t1 + // t0 = E * g5² + t1 t2 := e.Ext2.Square(&x.C1.B2) t0 = e.Ext2.MulByNonResidue(t2) t0 = e.Ext2.Add(t0, t1) @@ -236,14 +236,14 @@ func (e Ext12) DecompressKarabina(x *E12) *E12 { // t1 = g2 * g1 t1 = e.Ext2.Mul(&x.C0.B2, &x.C0.B1) - // t2 = 2 * g4^2 - 3 * g2 * g1 + // t2 = 2 * g4² - 3 * g2 * g1 t2 = e.Ext2.Square(C1B1) t2 = e.Ext2.Sub(t2, t1) t2 = e.Ext2.Double(t2) t2 = e.Ext2.Sub(t2, t1) // t1 = g3 * g5 (g3 can be 0) t1 = e.Ext2.Mul(&x.C1.B0, &x.C1.B2) - // c_0 = E * (2 * g4^2 + g3 * g5 - 3 * g2 * g1) + 1 + // c₀ = E * (2 * g4² + g3 * g5 - 3 * g2 * g1) + 1 t2 = e.Ext2.Add(t2, t1) C0B0 := e.Ext2.MulByNonResidue(t2) C0B0 = e.Ext2.Add(C0B0, one) diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 54a4525765..c9e495c164 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -150,7 +150,7 @@ type lineEvaluation struct { } // MillerLoop computes the multi-Miller loop -// ∏ᵢ { fᵢ_{ℓ,Q}(P) · ℓᵢ_{Q,π(Q)}(P) · ℓᵢ_{Q,-π²(Q)}(P) } +// ∏ᵢ { fᵢ_{ℓ,Q}(P) · ℓᵢ_{[ℓ]q,π(q)}(p) · ℓᵢ_{[ℓ]q+π(q),-π²(q)}(p) } func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { // check input size match n := len(P) @@ -268,7 +268,7 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { } } - // Compute ∏ᵢ { ℓᵢ_{Q,π(Q)}(P) · ℓᵢ_{Q,-π²(Q)}(P) } + // Compute ∏ᵢ { ℓᵢ_{[ℓ]q,π(q)}(p) · ℓᵢ_{[ℓ]q+π(q),-π²(q)}(p) } Q1, Q2 := new(G2Affine), new(G2Affine) for k := 0; k < n; k++ { //Q1 = π(Q) From 39758a3423c14a78bafae3478fd178a96f8f446a Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 15 Mar 2023 12:55:10 -0400 Subject: [PATCH 132/464] fix: computing t(X) requires lagrange coset input --- constraint/bn254/r1cs_sparse.go | 5 ++++ frontend/api.go | 1 + frontend/cs/scs/api.go | 12 ++++------ frontend/cs/scs/builder.go | 3 ++- internal/backend/bn254/plonk/prove.go | 34 +++++++++++++-------------- internal/backend/bn254/plonk/setup.go | 9 ++++--- test/commitments_test.go | 2 +- 7 files changed, 35 insertions(+), 31 deletions(-) diff --git a/constraint/bn254/r1cs_sparse.go b/constraint/bn254/r1cs_sparse.go index 1cc20bd816..b481f232a5 100644 --- a/constraint/bn254/r1cs_sparse.go +++ b/constraint/bn254/r1cs_sparse.go @@ -443,6 +443,11 @@ func (cs *SparseR1CS) GetConstraints() ([]constraint.SparseR1C, constraint.Resol // checkConstraint verifies that the constraint holds func (cs *SparseR1CS) checkConstraint(c constraint.SparseR1C, solution *solution) error { + + if c.Commitment != constraint.NOT { + return nil + } + l := solution.computeTerm(c.L) r := solution.computeTerm(c.R) m0 := solution.computeTerm(c.M[0]) diff --git a/frontend/api.go b/frontend/api.go index a54e2ec3c0..3e7e97c475 100644 --- a/frontend/api.go +++ b/frontend/api.go @@ -24,6 +24,7 @@ import ( // API represents the available functions to circuit developers type API interface { + Committer // TODO: Remove and find out how we're supposed to call api.Commit now // --------------------------------------------------------------------------------------------- // Arithmetic diff --git a/frontend/cs/scs/api.go b/frontend/cs/scs/api.go index a08a27def2..6a84b3c9a6 100644 --- a/frontend/cs/scs/api.go +++ b/frontend/cs/scs/api.go @@ -569,21 +569,17 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error committed := make([]int, len(v)) for i, vI := range v { // TODO @Tabaie Perf; If public, just hash it - vIExpr := builder.Neg(vI).(constraint.LinearExpression) - if len(vIExpr) != 1 { - return nil, errors.New("can only commit to single terms") // TODO @Tabaie Create a wire in this case - } + vINeg := builder.Neg(vI).(expr.Term) committed[i] = builder.cs.GetNbConstraints() - builder.cs.AddConstraint(constraint.SparseR1C{L: vIExpr[0], Commitment: constraint.COMMITTED}) + builder.addPlonkConstraint(sparseR1C{xa: vINeg.VID, qL: vINeg.Coeff, commitment: constraint.COMMITTED}) } outs, err := builder.NewHint(scsBsb22CommitmentHintPlaceholder, 1, v...) if err != nil { return nil, err } - commitmentVar := outs[0] - + commitmentVar := builder.Neg(outs[0]).(expr.Term) commitmentConstraintIndex := builder.cs.GetNbConstraints() - builder.cs.AddConstraint(constraint.SparseR1C{L: builder.Neg(commitmentVar).(constraint.LinearExpression)[0], Commitment: constraint.COMMITMENT}) // value will be injected later + builder.addPlonkConstraint(sparseR1C{xa: commitmentVar.VID, qL: commitmentVar.Coeff, commitment: constraint.COMMITMENT}) // value will be injected later return outs[0], builder.cs.AddCommitment(constraint.Commitment{ HintID: solver.GetHintID(scsBsb22CommitmentHintPlaceholder), diff --git a/frontend/cs/scs/builder.go b/frontend/cs/scs/builder.go index 340e5fe0ab..90a44e3312 100644 --- a/frontend/cs/scs/builder.go +++ b/frontend/cs/scs/builder.go @@ -112,6 +112,7 @@ func (builder *builder) FieldBitLen() int { type sparseR1C struct { xa, xb, xc int // wires qL, qR, qO, qM, qC constraint.Coeff // coefficients + commitment constraint.CommitmentConstraint } // a * b == c @@ -149,7 +150,7 @@ func (builder *builder) addPlonkConstraint(c sparseR1C, debug ...constraint.Debu V := builder.cs.MakeTerm(&builder.tOne, c.xb) K := builder.cs.MakeTerm(&c.qC, 0) K.MarkConstant() - builder.cs.AddConstraint(constraint.SparseR1C{L: L, R: R, O: O, M: [2]constraint.Term{U, V}, K: K.CoeffID()}, debug...) + builder.cs.AddConstraint(constraint.SparseR1C{L: L, R: R, O: O, M: [2]constraint.Term{U, V}, K: K.CoeffID(), Commitment: c.commitment}, debug...) } // newInternalVariable creates a new wire, appends it on the list of wires of the circuit, sets diff --git a/internal/backend/bn254/plonk/prove.go b/internal/backend/bn254/plonk/prove.go index b3d6528fb4..402789655d 100644 --- a/internal/backend/bn254/plonk/prove.go +++ b/internal/backend/bn254/plonk/prove.go @@ -82,13 +82,14 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // result proof := &Proof{} + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} var ( - pi2 fr.Vector - commitmentVal fr.Element // TODO @Tabaie get rid of this + wpi2iop *iop.Polynomial // canonical + commitmentVal fr.Element // TODO @Tabaie get rid of this ) if spr.CommitmentInfo.Is() { opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo.HintID, func(_ *big.Int, ins, outs []*big.Int) error { - pi2 = make(fr.Vector, pk.Domain[0].Cardinality) + pi2 := make([]fr.Element, pk.Domain[0].Cardinality) for i := range ins { pi2[spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) } @@ -99,7 +100,10 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if _, err = pi2[spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { return err } - if proof.PI2, err = kzg.Commit(pi2, pk.Vk.KZGSRS); err != nil { + pi2iop := iop.NewPolynomial(&pi2, lagReg) + wpi2iop = pi2iop.ShallowClone() + wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Vk.KZGSRS); err != nil { return err } if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { @@ -120,27 +124,20 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts evaluationLDomainSmall := []fr.Element(solution.L) evaluationRDomainSmall := []fr.Element(solution.R) evaluationODomainSmall := []fr.Element(solution.O) - evaluationPI2DomainSmall := []fr.Element(pi2) - lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} liop := iop.NewPolynomial(&evaluationLDomainSmall, lagReg) riop := iop.NewPolynomial(&evaluationRDomainSmall, lagReg) oiop := iop.NewPolynomial(&evaluationODomainSmall, lagReg) - pi2iop := iop.NewPolynomial(&evaluationPI2DomainSmall, lagReg) - qcpiop := iop.NewPolynomial(&pk.QcPrime, lagReg) + qcpiop := iop.NewPolynomial(&pk.lQcPrime, lagReg) wliop := liop.ShallowClone() wriop := riop.ShallowClone() woiop := oiop.ShallowClone() - wpi2iop := pi2iop.ShallowClone() wqciop := qcpiop.ShallowClone() wliop.ToCanonical(&pk.Domain[0]).ToRegular() wriop.ToCanonical(&pk.Domain[0]).ToRegular() woiop.ToCanonical(&pk.Domain[0]).ToRegular() - wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() wqciop.ToCanonical(&pk.Domain[0]).ToRegular() - wpi2iop.Coefficients() - // Blind l, r, o before committing // we set the underlying slice capacity to domain[1].Cardinality to minimize mem moves. bwliop := wliop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) @@ -218,10 +215,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) - // l, r, o are blinded here + // l, r, o are already blinded bwliop.ToLagrangeCoset(&pk.Domain[1]) bwriop.ToLagrangeCoset(&pk.Domain[1]) bwoiop.ToLagrangeCoset(&pk.Domain[1]) + pi2iop := wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) lagrangeCosetBitReversed := iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse} @@ -332,7 +330,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ws3, bwziop, bwsziop, - wpi2iop, // TODO @Tabaie correct format + pi2iop, // TODO @Tabaie correct format wqliop, wqriop, wqmiop, @@ -492,7 +490,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { n := runtime.NumCPU() / 2 var err0, err1, err2 error - chCommit0 := make(chan struct{}, 1) + chCommit0 := make(chan struct{}, 1) // TODO @Tabaie use wait group? chCommit1 := make(chan struct{}, 1) go func() { proof.LRO[0], err0 = kzg.Commit(bcl, srs, n) @@ -598,9 +596,9 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, den.Sub(&zeta, &one). Inverse(&den) lagrangeZeta.Mul(&lagrangeZeta, &den). // L₁ = (ζⁿ⁻¹)/(ζ-1) - Mul(&lagrangeZeta, &alpha). - Mul(&lagrangeZeta, &alpha). - Mul(&lagrangeZeta, &pk.Domain[0].CardinalityInv) // (1/n)*α²*L₁(ζ) + Mul(&lagrangeZeta, &alpha). + Mul(&lagrangeZeta, &alpha). + Mul(&lagrangeZeta, &pk.Domain[0].CardinalityInv) // (1/n)*α²*L₁(ζ) linPol := make([]fr.Element, len(blindedZCanonical)) copy(linPol, blindedZCanonical) diff --git a/internal/backend/bn254/plonk/setup.go b/internal/backend/bn254/plonk/setup.go index d3926f7307..248b9644e2 100644 --- a/internal/backend/bn254/plonk/setup.go +++ b/internal/backend/bn254/plonk/setup.go @@ -43,11 +43,11 @@ type ProvingKey struct { // TODO store iop.Polynomial here, not []fr.Element for more "type safety" // qr,ql,qm,qo (in canonical basis). - // QcPrime denotes the constraints defining committed variables - Ql, Qr, Qm, Qo, QcPrime []fr.Element + // lQcPrime denotes the constraints defining committed variables + Ql, Qr, Qm, Qo, QcPrime []fr.Element // TODO @Tabaie QcPrime is not used by the prover; remove it // qr,ql,qm,qo (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. - lQl, lQr, lQm, lQo []fr.Element + lQl, lQr, lQm, lQo, lQcPrime []fr.Element // LQk (CQk) qk in Lagrange basis (canonical basis), prepended with as many zeroes as public inputs. // Storing LQk in Lagrange basis saves a fft... @@ -286,6 +286,7 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { wqriop := iop.NewPolynomial(clone(pk.Qr, pk.Domain[1].Cardinality), canReg) wqmiop := iop.NewPolynomial(clone(pk.Qm, pk.Domain[1].Cardinality), canReg) wqoiop := iop.NewPolynomial(clone(pk.Qo, pk.Domain[1].Cardinality), canReg) + wqcpiop := iop.NewPolynomial(clone(pk.QcPrime, pk.Domain[1].Cardinality), canReg) ws1 := iop.NewPolynomial(clone(pk.S1Canonical, pk.Domain[1].Cardinality), canReg) ws2 := iop.NewPolynomial(clone(pk.S2Canonical, pk.Domain[1].Cardinality), canReg) @@ -295,6 +296,7 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { wqriop.ToLagrangeCoset(&pk.Domain[1]) wqmiop.ToLagrangeCoset(&pk.Domain[1]) wqoiop.ToLagrangeCoset(&pk.Domain[1]) + wqcpiop.ToLagrangeCoset(&pk.Domain[1]) ws1.ToLagrangeCoset(&pk.Domain[1]) ws2.ToLagrangeCoset(&pk.Domain[1]) @@ -304,6 +306,7 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { pk.lQr = wqriop.Coefficients() pk.lQm = wqmiop.Coefficients() pk.lQo = wqoiop.Coefficients() + pk.lQcPrime = wqoiop.Coefficients() pk.lS1LagrangeCoset = ws1.Coefficients() pk.lS2LagrangeCoset = ws2.Coefficients() diff --git a/test/commitments_test.go b/test/commitments_test.go index a1407caffc..5e920ba236 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -16,7 +16,7 @@ type commitmentCircuit struct { } func (c *commitmentCircuit) Define(api frontend.API) error { - commitment, err := api.Compiler().Commit(c.X...) + commitment, err := api.Commit(c.X...) if err == nil { api.AssertIsDifferent(commitment, 0) } From e62844aa542faab254e6a1437d53a38c26878449 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 15 Mar 2023 18:36:53 +0100 Subject: [PATCH 133/464] style: rename addStepLineOnly to lineCompute --- std/algebra/emulated/sw_bn254/pairing.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index c9e495c164..07fb08a386 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -292,7 +292,7 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { res = pr.MulBy034(res, &l1.R0, &l1.R1) // l2 the line passing Qacc[k] and -π²(Q) - l2 = pr.addStepLineOnly(Qacc[k], Q2) + l2 = pr.lineCompute(Qacc[k], Q2) // line evaluation at P[k] l2.R0 = *pr.MulByElement(&l2.R0, xOverY[k]) l2.R1 = *pr.MulByElement(&l2.R1, yInv[k]) @@ -423,8 +423,8 @@ func (pr Pairing) addStep(p1, p2 *G2Affine) (*G2Affine, *lineEvaluation) { } -// addStepLineOnly computes the line that goes through p1 and p2 but does not compute p1+p2 -func (pr Pairing) addStepLineOnly(p1, p2 *G2Affine) *lineEvaluation { +// lineCompute computes the line that goes through p1 and p2 but does not compute p1+p2 +func (pr Pairing) lineCompute(p1, p2 *G2Affine) *lineEvaluation { // compute λ = (y2-y1)/(x2-x1) qypy := pr.Ext2.Sub(&p2.Y, &p1.Y) From 796adf40c801c16e241b49474f25bb86125219ac Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 15 Mar 2023 13:42:12 -0400 Subject: [PATCH 134/464] fix: qcp formats --- internal/backend/bn254/plonk/prove.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/internal/backend/bn254/plonk/prove.go b/internal/backend/bn254/plonk/prove.go index 402789655d..72d83b1418 100644 --- a/internal/backend/bn254/plonk/prove.go +++ b/internal/backend/bn254/plonk/prove.go @@ -128,15 +128,12 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts liop := iop.NewPolynomial(&evaluationLDomainSmall, lagReg) riop := iop.NewPolynomial(&evaluationRDomainSmall, lagReg) oiop := iop.NewPolynomial(&evaluationODomainSmall, lagReg) - qcpiop := iop.NewPolynomial(&pk.lQcPrime, lagReg) wliop := liop.ShallowClone() wriop := riop.ShallowClone() woiop := oiop.ShallowClone() - wqciop := qcpiop.ShallowClone() wliop.ToCanonical(&pk.Domain[0]).ToRegular() wriop.ToCanonical(&pk.Domain[0]).ToRegular() woiop.ToCanonical(&pk.Domain[0]).ToRegular() - wqciop.ToCanonical(&pk.Domain[0]).ToRegular() // Blind l, r, o before committing // we set the underlying slice capacity to domain[1].Cardinality to minimize mem moves. @@ -219,7 +216,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwliop.ToLagrangeCoset(&pk.Domain[1]) bwriop.ToLagrangeCoset(&pk.Domain[1]) bwoiop.ToLagrangeCoset(&pk.Domain[1]) - pi2iop := wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) + pi2iop := wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form lagrangeCosetBitReversed := iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse} @@ -228,6 +225,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wqriop := iop.NewPolynomial(&pk.lQr, lagrangeCosetBitReversed) wqmiop := iop.NewPolynomial(&pk.lQm, lagrangeCosetBitReversed) wqoiop := iop.NewPolynomial(&pk.lQo, lagrangeCosetBitReversed) + wqcpiop := iop.NewPolynomial(&pk.lQcPrime, lagrangeCosetBitReversed) // lagrange coset form canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} wqkiop := iop.NewPolynomial(&qkCompletedCanonical, canReg) @@ -336,7 +334,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wqmiop, wqoiop, wqkiop, - qcpiop, // TODO @Tabaie correct format + wqcpiop, // TODO @Tabaie correct format wloneiop, ) if err != nil { @@ -375,7 +373,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts go evalAtZeta(bwliop, &blzeta) go evalAtZeta(bwriop, &brzeta) go evalAtZeta(bwoiop, &bozeta) - go evalAtZeta(wqciop, &qcpzeta) + go func() { + qcpiop := iop.NewPolynomial(&pk.QcPrime, canReg) // TODO @Tabaie canReg correct? + qcpzeta = qcpiop.Evaluate(zeta) + wgEvals.Done() + }() // open blinded Z at zeta*z bwziop.ToCanonical(&pk.Domain[1]).ToRegular() From e377a51a2d6a5f58760617936d8c61f8fc83c05e Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 15 Mar 2023 14:04:18 -0400 Subject: [PATCH 135/464] fix: open qcp commitment --- internal/backend/bn254/plonk/prove.go | 2 ++ internal/backend/bn254/plonk/setup.go | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/internal/backend/bn254/plonk/prove.go b/internal/backend/bn254/plonk/prove.go index 72d83b1418..673cf0e130 100644 --- a/internal/backend/bn254/plonk/prove.go +++ b/internal/backend/bn254/plonk/prove.go @@ -463,6 +463,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.Coefficients()[:bwoiop.BlindedSize()], pk.S1Canonical, pk.S2Canonical, + pk.QcPrime, }, []kzg.Digest{ foldedHDigest, @@ -472,6 +473,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.LRO[2], pk.Vk.S[0], pk.Vk.S[1], + pk.Vk.QcPrime, }, zeta, hFunc, diff --git a/internal/backend/bn254/plonk/setup.go b/internal/backend/bn254/plonk/setup.go index 248b9644e2..aae6bca848 100644 --- a/internal/backend/bn254/plonk/setup.go +++ b/internal/backend/bn254/plonk/setup.go @@ -42,11 +42,11 @@ type ProvingKey struct { // TODO store iop.Polynomial here, not []fr.Element for more "type safety" - // qr,ql,qm,qo (in canonical basis). - // lQcPrime denotes the constraints defining committed variables - Ql, Qr, Qm, Qo, QcPrime []fr.Element // TODO @Tabaie QcPrime is not used by the prover; remove it + // qr,ql,qm,qo,qcp (in canonical basis). + // QcPrime denotes the constraints defining committed variables + Ql, Qr, Qm, Qo, QcPrime []fr.Element - // qr,ql,qm,qo (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. + // qr,ql,qm,qo,qcp (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. lQl, lQr, lQm, lQo, lQcPrime []fr.Element // LQk (CQk) qk in Lagrange basis (canonical basis), prepended with as many zeroes as public inputs. From f744f9c4a74133da731a441f2e428a53f517adf2 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 15 Mar 2023 19:30:09 +0100 Subject: [PATCH 136/464] refactor(pairing-bn254): remove dead code (fields_e2) --- std/algebra/emulated/fields_bn254/e2.go | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/std/algebra/emulated/fields_bn254/e2.go b/std/algebra/emulated/fields_bn254/e2.go index 95b866be1a..008d259eab 100644 --- a/std/algebra/emulated/fields_bn254/e2.go +++ b/std/algebra/emulated/fields_bn254/e2.go @@ -24,10 +24,6 @@ func NewExt2(baseField *curveF) *Ext2 { A0 string A1 string }{ - 0: { - -1: {"21087453498479301738505683583845423561061080261299122796980902361914303298513", "14681138511599513868579906292550611339979233093309515871315818100066920017952"}, - 1: {"9", "1"}, - }, 1: { 1: {"8376118865763821496583973867626364092589906065868298776909617916018768340080", "16469823323077808223889137241176536799009286646108169935659301613961712198316"}, 2: {"21575463638280843010398324269430826099269044274347216827212613867836435027261", "10307601595873709700152284273816112264069230130616436755625194854815875713954"}, @@ -35,13 +31,6 @@ func NewExt2(baseField *curveF) *Ext2 { 4: {"2581911344467009335267311115468803099551665605076196740867805258568234346338", "19937756971775647987995932169929341994314640652964949448313374472400716661030"}, 5: {"685108087231508774477564247770172212460312782337200605669322048753928464687", "8447204650696766136447902020341177575205426561248465145919723016860428151883"}, }, - 2: { - 1: {"21888242871839275220042445260109153167277707414472061641714758635765020556617", "0"}, - 2: {"21888242871839275220042445260109153167277707414472061641714758635765020556616", "0"}, - 3: {"21888242871839275222246405745257275088696311157297823662689037894645226208582", "0"}, - 4: {"2203960485148121921418603742825762020974279258880205651966", "0"}, - 5: {"2203960485148121921418603742825762020974279258880205651967", "0"}, - }, 3: { 1: {"11697423496358154304825782922584725312912383441159505038794027105778954184319", "303847389135065887422783454877609941456349188919719272345083954437860409601"}, 2: {"3772000881919853776433695186713858239009073593817195771773381919316419345261", "2236595495967245188281701248203181795121068902605861227855261137820944008926"}, @@ -96,7 +85,7 @@ func (e Ext2) MulByNonResidueGeneric(x *E2, power, coef int) *E2 { return z } -// MulByNonResidue1Power1 return x*(9+u) +// MulByNonResidue return x*(9+u) func (e Ext2) MulByNonResidue(x *E2) *E2 { nine := big.NewInt(9) a := e.fp.MulConst(&x.A0, nine) From ceb87275ea2333c2d0e9060654d259b3b3513378 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 15 Mar 2023 15:07:30 -0400 Subject: [PATCH 137/464] test: remove blindings and hashes, simplest no-commitment test that fails --- internal/backend/bn254/plonk/prove.go | 35 ++++++++++++++++++++------ internal/backend/bn254/plonk/verify.go | 3 +-- test/commitments_test.go | 26 ++++++++++++++----- 3 files changed, 48 insertions(+), 16 deletions(-) diff --git a/internal/backend/bn254/plonk/prove.go b/internal/backend/bn254/plonk/prove.go index 673cf0e130..fc62d2c143 100644 --- a/internal/backend/bn254/plonk/prove.go +++ b/internal/backend/bn254/plonk/prove.go @@ -17,7 +17,6 @@ package plonk import ( - "crypto/sha256" "github.com/consensys/gnark/constraint/solver" "math/big" "runtime" @@ -64,6 +63,26 @@ type Proof struct { ZShiftedOpening kzg.OpeningProof } +type zeroHash struct{} + +func (h zeroHash) Write(p []byte) (n int, err error) { + return len(p), nil +} + +func (h zeroHash) Sum([]byte) []byte { + return make([]byte, fr.Bytes) +} + +func (h zeroHash) Reset() {} + +func (h zeroHash) Size() int { + return fr.Bytes +} + +func (h zeroHash) BlockSize() int { + return fr.Bytes +} + func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", len(spr.Constraints)).Str("backend", "plonk").Logger() @@ -75,7 +94,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts start := time.Now() // pick a hash function that will be used to derive the challenges - hFunc := sha256.New() + hFunc := zeroHash{} // TODO Remove // create a transcript manager to apply Fiat Shamir fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") @@ -97,9 +116,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts err error hashRes []fr.Element ) - if _, err = pi2[spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { + /*if _, err = pi2[spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { return err - } + }*/ pi2iop := iop.NewPolynomial(&pi2, lagReg) wpi2iop = pi2iop.ShallowClone() wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() @@ -137,9 +156,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // Blind l, r, o before committing // we set the underlying slice capacity to domain[1].Cardinality to minimize mem moves. - bwliop := wliop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) - bwriop := wriop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) - bwoiop := woiop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) + bwliop := wliop.Clone(int(pk.Domain[1].Cardinality)) //.Blind(1) + bwriop := wriop.Clone(int(pk.Domain[1].Cardinality)) //.Blind(1) + bwoiop := woiop.Clone(int(pk.Domain[1].Cardinality)) //.Blind(1) if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Vk.KZGSRS); err != nil { return nil, err } @@ -190,7 +209,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // commit to the blinded version of z bwziop := ziop // iop.NewWrappedPolynomial(&ziop) - bwziop.Blind(2) + //bwziop.Blind(2) proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Vk.KZGSRS, runtime.NumCPU()*2) if err != nil { return proof, err diff --git a/internal/backend/bn254/plonk/verify.go b/internal/backend/bn254/plonk/verify.go index ca30399988..a205ec8b23 100644 --- a/internal/backend/bn254/plonk/verify.go +++ b/internal/backend/bn254/plonk/verify.go @@ -17,7 +17,6 @@ package plonk import ( - "crypto/sha256" "errors" "io" "math/big" @@ -45,7 +44,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { start := time.Now() // pick a hash function to derive the challenge (the same as in the prover) - hFunc := sha256.New() + hFunc := zeroHash{} // transcript to derive the challenge fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") diff --git a/test/commitments_test.go b/test/commitments_test.go index 5e920ba236..d547953134 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -23,10 +23,7 @@ func (c *commitmentCircuit) Define(api frontend.API) error { return err } -func TestSingleCommitmentPlonkBn254(t *testing.T) { - - assignment := commitmentCircuit{[]frontend.Variable{1}} - +func plonkTestBn254(t *testing.T, assignment frontend.Circuit) { // // building the circuit... ccs, err := frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, &commitmentCircuit{make([]frontend.Variable, 1)}) assert.NoError(t, err) @@ -38,10 +35,10 @@ func TestSingleCommitmentPlonkBn254(t *testing.T) { // Witnesses instantiation. Witness is known only by the prover, // while public w is a public data known by the verifier. - witnessFull, err := frontend.NewWitness(&assignment, ecc.BN254.ScalarField()) + witnessFull, err := frontend.NewWitness(assignment, ecc.BN254.ScalarField()) assert.NoError(t, err) - witnessPublic, err := frontend.NewWitness(&assignment, ecc.BN254.ScalarField(), frontend.PublicOnly()) + witnessPublic, err := frontend.NewWitness(assignment, ecc.BN254.ScalarField(), frontend.PublicOnly()) assert.NoError(t, err) // public data consists the polynomials describing the constants involved @@ -58,3 +55,20 @@ func TestSingleCommitmentPlonkBn254(t *testing.T) { assert.NoError(t, err) } + +func TestSingleCommitmentPlonkBn254(t *testing.T) { + plonkTestBn254(t, &commitmentCircuit{[]frontend.Variable{1}}) +} + +type noCommitmentCircuit struct { + X frontend.Variable +} + +func (c *noCommitmentCircuit) Define(api frontend.API) error { + api.AssertIsEqual(c.X, 1) + return nil +} + +func TestNoCommitmentCircuit(t *testing.T) { + plonkTestBn254(t, &noCommitmentCircuit{1}) +} From 578ff38450e2b6caa8d0f3e8ddedf7fd554980a0 Mon Sep 17 00:00:00 2001 From: ThomasPiellard Date: Wed, 15 Mar 2023 22:25:54 +0100 Subject: [PATCH 138/464] Refactor/plonk setup (#556) * feat: setup bis (temporary) * feat: s1, s2, s3 computed on lagrange coset * feat: expose buildTrace * feat: init pk, vk * feat: fix marshalling keys * fix: added Verifyingkey, NbPublicWitness methods * fix: fixed marshalling tests * feat: restored setup * feat: code gen ok * fix: pk is no longer mutated when proving (plonk) * fix: fixed proving key serialisation * refactor: PlonkTrace -> Trace * style: removed dead code * refactor: buildDomains -> initDomains * fix: fixed template + code gen * clean: remove setup.tmp --------- Co-authored-by: Gautam Botrel --- backend/plonk/bls12-377/marshal.go | 60 ++- backend/plonk/bls12-377/marshal_test.go | 41 +- backend/plonk/bls12-377/prove.go | 77 ++- backend/plonk/bls12-377/setup.go | 468 +++++++++-------- backend/plonk/bls12-381/marshal.go | 60 ++- backend/plonk/bls12-381/marshal_test.go | 41 +- backend/plonk/bls12-381/prove.go | 77 ++- backend/plonk/bls12-381/setup.go | 468 +++++++++-------- backend/plonk/bls24-315/marshal.go | 60 ++- backend/plonk/bls24-315/marshal_test.go | 41 +- backend/plonk/bls24-315/prove.go | 77 ++- backend/plonk/bls24-315/setup.go | 468 +++++++++-------- backend/plonk/bls24-317/marshal.go | 60 ++- backend/plonk/bls24-317/marshal_test.go | 41 +- backend/plonk/bls24-317/prove.go | 77 ++- backend/plonk/bls24-317/setup.go | 468 +++++++++-------- backend/plonk/bn254/marshal.go | 60 ++- backend/plonk/bn254/marshal_test.go | 41 +- backend/plonk/bn254/prove.go | 77 ++- backend/plonk/bn254/setup.go | 468 +++++++++-------- backend/plonk/bw6-633/marshal.go | 60 ++- backend/plonk/bw6-633/marshal_test.go | 41 +- backend/plonk/bw6-633/prove.go | 77 ++- backend/plonk/bw6-633/setup.go | 468 +++++++++-------- backend/plonk/bw6-761/marshal.go | 60 ++- backend/plonk/bw6-761/marshal_test.go | 41 +- backend/plonk/bw6-761/prove.go | 77 ++- backend/plonk/bw6-761/setup.go | 468 +++++++++-------- go.mod | 2 +- go.sum | 2 + .../zkpschemes/plonk/plonk.marshal.go.tmpl | 64 ++- .../zkpschemes/plonk/plonk.prove.go.tmpl | 79 ++- .../zkpschemes/plonk/plonk.setup.go.tmpl | 471 ++++++++++-------- .../zkpschemes/plonk/tests/marshal.go.tmpl | 58 ++- 34 files changed, 2807 insertions(+), 2391 deletions(-) diff --git a/backend/plonk/bls12-377/marshal.go b/backend/plonk/bls12-377/marshal.go index 64daa4c899..8194875d8b 100644 --- a/backend/plonk/bls12-377/marshal.go +++ b/backend/plonk/bls12-377/marshal.go @@ -21,6 +21,7 @@ import ( "errors" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/iop" "io" ) @@ -108,7 +109,7 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { n += n2 // sanity check len(Permutation) == 3*int(pk.Domain[0].Cardinality) - if len(pk.Permutation) != (3 * int(pk.Domain[0].Cardinality)) { + if len(pk.trace.S) != (3 * int(pk.Domain[0].Cardinality)) { return n, errors.New("invalid permutation size, expected 3*domain cardinality") } @@ -117,16 +118,16 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { // encode the size (nor does it convert from Montgomery to Regular form) // so we explicitly transmit []fr.Element toEncode := []interface{}{ - ([]fr.Element)(pk.Ql), - ([]fr.Element)(pk.Qr), - ([]fr.Element)(pk.Qm), - ([]fr.Element)(pk.Qo), - ([]fr.Element)(pk.CQk), - ([]fr.Element)(pk.LQk), - ([]fr.Element)(pk.S1Canonical), - ([]fr.Element)(pk.S2Canonical), - ([]fr.Element)(pk.S3Canonical), - pk.Permutation, + ([]fr.Element)(pk.trace.Ql.Coefficients()), + ([]fr.Element)(pk.trace.Qr.Coefficients()), + ([]fr.Element)(pk.trace.Qm.Coefficients()), + ([]fr.Element)(pk.trace.Qo.Coefficients()), + ([]fr.Element)(pk.trace.Qk.Coefficients()), + ([]fr.Element)(pk.lQk.Coefficients()), + ([]fr.Element)(pk.trace.S1.Coefficients()), + ([]fr.Element)(pk.trace.S2.Coefficients()), + ([]fr.Element)(pk.trace.S3.Coefficients()), + pk.trace.S, } for _, v := range toEncode { @@ -158,20 +159,22 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { return n, err } - pk.Permutation = make([]int64, 3*pk.Domain[0].Cardinality) + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) dec := curve.NewDecoder(r) + + var ql, qr, qm, qo, qk, lqk, s1, s2, s3 []fr.Element toDecode := []interface{}{ - (*[]fr.Element)(&pk.Ql), - (*[]fr.Element)(&pk.Qr), - (*[]fr.Element)(&pk.Qm), - (*[]fr.Element)(&pk.Qo), - (*[]fr.Element)(&pk.CQk), - (*[]fr.Element)(&pk.LQk), - (*[]fr.Element)(&pk.S1Canonical), - (*[]fr.Element)(&pk.S2Canonical), - (*[]fr.Element)(&pk.S3Canonical), - &pk.Permutation, + &ql, + &qr, + &qm, + &qo, + &qk, + &lqk, + &s1, + &s2, + &s3, + &pk.trace.S, } for _, v := range toDecode { @@ -180,6 +183,19 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { } } + canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} + pk.trace.Ql = iop.NewPolynomial(&ql, canReg) + pk.trace.Qr = iop.NewPolynomial(&qr, canReg) + pk.trace.Qm = iop.NewPolynomial(&qm, canReg) + pk.trace.Qo = iop.NewPolynomial(&qo, canReg) + pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.S1 = iop.NewPolynomial(&s1, canReg) + pk.trace.S2 = iop.NewPolynomial(&s2, canReg) + pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + pk.lQk = iop.NewPolynomial(&lqk, lagReg) + pk.computeLagrangeCosetPolys() return n + dec.BytesRead(), nil diff --git a/backend/plonk/bls12-377/marshal_test.go b/backend/plonk/bls12-377/marshal_test.go index 94a69f6295..b9033af3af 100644 --- a/backend/plonk/bls12-377/marshal_test.go +++ b/backend/plonk/bls12-377/marshal_test.go @@ -23,6 +23,7 @@ import ( "bytes" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/iop" gnarkio "github.com/consensys/gnark/io" "io" "math/big" @@ -106,6 +107,7 @@ func roundTripCheckRaw(t *testing.T, from gnarkio.WriterRawTo, reconstructed io. } func (pk *ProvingKey) randomize() { + var vk VerifyingKey vk.randomize() pk.Vk = &vk @@ -113,19 +115,32 @@ func (pk *ProvingKey) randomize() { pk.Domain[1] = *fft.NewDomain(4 * 42) n := int(pk.Domain[0].Cardinality) - pk.Ql = randomScalars(n) - pk.Qr = randomScalars(n) - pk.Qm = randomScalars(n) - pk.Qo = randomScalars(n) - pk.CQk = randomScalars(n) - pk.LQk = randomScalars(n) - pk.S1Canonical = randomScalars(n) - pk.S2Canonical = randomScalars(n) - pk.S3Canonical = randomScalars(n) - - pk.Permutation = make([]int64, 3*pk.Domain[0].Cardinality) - pk.Permutation[0] = -12 - pk.Permutation[len(pk.Permutation)-1] = 8888 + ql := randomScalars(n) + qr := randomScalars(n) + qm := randomScalars(n) + qo := randomScalars(n) + qk := randomScalars(n) + lqk := randomScalars(n) + s1 := randomScalars(n) + s2 := randomScalars(n) + s3 := randomScalars(n) + + canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} + pk.trace.Ql = iop.NewPolynomial(&ql, canReg) + pk.trace.Qr = iop.NewPolynomial(&qr, canReg) + pk.trace.Qm = iop.NewPolynomial(&qm, canReg) + pk.trace.Qo = iop.NewPolynomial(&qo, canReg) + pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.S1 = iop.NewPolynomial(&s1, canReg) + pk.trace.S2 = iop.NewPolynomial(&s2, canReg) + pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) + pk.trace.S[0] = -12 + pk.trace.S[len(pk.trace.S)-1] = 8888 + + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + pk.lQk = iop.NewPolynomial(&lqk, lagReg) pk.computeLagrangeCosetPolys() } diff --git a/backend/plonk/bls12-377/prove.go b/backend/plonk/bls12-377/prove.go index 7347d6f861..54ceaa5870 100644 --- a/backend/plonk/bls12-377/prove.go +++ b/backend/plonk/bls12-377/prove.go @@ -143,7 +143,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts riop.Clone(), oiop.Clone(), }, - pk.Permutation, + pk.trace.S, beta, gamma, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}, @@ -168,9 +168,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // compute qk in canonical basis, completed with the public inputs - qkCompletedCanonical := make([]fr.Element, pk.Domain[0].Cardinality) + // We copy the coeffs of qk to pk is not mutated + lqkcoef := pk.lQk.Coefficients() + qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) + copy(qkCompletedCanonical, lqkcoef) copy(qkCompletedCanonical, fw[:len(spr.Public)]) - copy(qkCompletedCanonical[len(spr.Public):], pk.LQk[len(spr.Public):]) pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -179,17 +181,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwriop.ToLagrangeCoset(&pk.Domain[1]) bwoiop.ToLagrangeCoset(&pk.Domain[1]) - lagrangeCosetBitReversed := iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse} - - // we don't mutate so no need to clone the coefficients from the proving key. - wqliop := iop.NewPolynomial(&pk.lQl, lagrangeCosetBitReversed) - wqriop := iop.NewPolynomial(&pk.lQr, lagrangeCosetBitReversed) - wqmiop := iop.NewPolynomial(&pk.lQm, lagrangeCosetBitReversed) - wqoiop := iop.NewPolynomial(&pk.lQo, lagrangeCosetBitReversed) - canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} - wqkiop := iop.NewPolynomial(&qkCompletedCanonical, canReg) - wqkiop.ToLagrangeCoset(&pk.Domain[1]) + lcqk := iop.NewPolynomial(&qkCompletedCanonical, canReg) + lcqk.ToLagrangeCoset(&pk.Domain[1]) // storing Id id := make([]fr.Element, pk.Domain[1].Cardinality) @@ -197,12 +191,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts widiop := iop.NewPolynomial(&id, canReg) widiop.ToLagrangeCoset(&pk.Domain[1]) - // permutations in LagrangeCoset: we don't mutate so no need to clone the coefficients from the - // proving key. - ws1 := iop.NewPolynomial(&pk.lS1LagrangeCoset, lagrangeCosetBitReversed) - ws2 := iop.NewPolynomial(&pk.lS2LagrangeCoset, lagrangeCosetBitReversed) - ws3 := iop.NewPolynomial(&pk.lS3LagrangeCoset, lagrangeCosetBitReversed) - // Store z(g*x), without reallocating a slice bwsziop := bwziop.ShallowClone().Shift(1) bwsziop.ToLagrangeCoset(&pk.Domain[1]) @@ -276,27 +264,27 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return c } - testEval, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, + systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, bwliop, bwriop, bwoiop, widiop, - ws1, - ws2, - ws3, + pk.lcS1, + pk.lcS2, + pk.lcS3, bwziop, bwsziop, - wqliop, - wqriop, - wqmiop, - wqoiop, - wqkiop, + pk.lcQl, + pk.lcQr, + pk.lcQm, + pk.lcQo, + lcqk, wloneiop, ) if err != nil { return nil, err } - h, err := iop.DivideByXMinusOne(testEval, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) + h, err := iop.DivideByXMinusOne(systemEvaluation, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) if err != nil { return nil, err } @@ -420,8 +408,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwliop.Coefficients()[:bwliop.BlindedSize()], bwriop.Coefficients()[:bwriop.BlindedSize()], bwoiop.Coefficients()[:bwoiop.BlindedSize()], - pk.S1Canonical, - pk.S2Canonical, + pk.trace.S1.Coefficients(), + pk.trace.S2.Coefficients(), }, []kzg.Digest{ foldedHDigest, @@ -522,13 +510,12 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, var s1, s2 fr.Element chS1 := make(chan struct{}, 1) go func() { - ps1 := iop.NewPolynomial(&pk.S1Canonical, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) - s1 = ps1.Evaluate(zeta) // s1(ζ) + s1 = pk.trace.S1.Evaluate(zeta) // s1(ζ) s1.Mul(&s1, &beta).Add(&s1, &lZeta).Add(&s1, &gamma) // (l(ζ)+β*s1(ζ)+γ) close(chS1) }() - ps2 := iop.NewPolynomial(&pk.S2Canonical, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) - tmp := ps2.Evaluate(zeta) // s2(ζ) + // ps2 := iop.NewPolynomial(&pk.S2Canonical, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) + tmp := pk.trace.S2.Evaluate(zeta) // s2(ζ) tmp.Mul(&tmp, &beta).Add(&tmp, &rZeta).Add(&tmp, &gamma) // (r(ζ)+β*s2(ζ)+γ) <-chS1 s1.Mul(&s1, &tmp).Mul(&s1, &zu).Mul(&s1, &beta) // (l(ζ)+β*s1(β)+γ)*(r(ζ)+β*s2(β)+γ)*β*Z(μζ) @@ -562,6 +549,7 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, linPol := make([]fr.Element, len(blindedZCanonical)) copy(linPol, blindedZCanonical) + s3canonical := pk.trace.S3.Coefficients() utils.Parallelize(len(linPol), func(start, end int) { var t0, t1 fr.Element @@ -570,26 +558,31 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, linPol[i].Mul(&linPol[i], &s2) // -Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) - if i < len(pk.S3Canonical) { + if i < len(s3canonical) { - t0.Mul(&pk.S3Canonical[i], &s1) // (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*β*s3(X) + t0.Mul(&s3canonical[i], &s1) // (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*β*s3(X) linPol[i].Add(&linPol[i], &t0) } linPol[i].Mul(&linPol[i], &alpha) // α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ)) - if i < len(pk.Qm) { + cql := pk.trace.Ql.Coefficients() + cqr := pk.trace.Qr.Coefficients() + cqm := pk.trace.Qm.Coefficients() + cqo := pk.trace.Qo.Coefficients() + cqk := pk.trace.Qk.Coefficients() + if i < len(cqm) { - t1.Mul(&pk.Qm[i], &rl) // linPol = linPol + l(ζ)r(ζ)*Qm(X) - t0.Mul(&pk.Ql[i], &lZeta) + t1.Mul(&cqm[i], &rl) // linPol = linPol + l(ζ)r(ζ)*Qm(X) + t0.Mul(&cql[i], &lZeta) t0.Add(&t0, &t1) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + l(ζ)*Ql(X) - t0.Mul(&pk.Qr[i], &rZeta) + t0.Mul(&cqr[i], &rZeta) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + r(ζ)*Qr(X) - t0.Mul(&pk.Qo[i], &oZeta).Add(&t0, &pk.CQk[i]) + t0.Mul(&cqo[i], &oZeta).Add(&t0, &cqk[i]) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) } diff --git a/backend/plonk/bls12-377/setup.go b/backend/plonk/bls12-377/setup.go index e7f0b7a553..92cfa3f071 100644 --- a/backend/plonk/bls12-377/setup.go +++ b/backend/plonk/bls12-377/setup.go @@ -18,6 +18,7 @@ package plonk import ( "errors" + "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/iop" @@ -27,44 +28,25 @@ import ( kzgg "github.com/consensys/gnark-crypto/kzg" ) -// ProvingKey stores the data needed to generate a proof: -// * the commitment scheme -// * ql, prepended with as many ones as they are public inputs -// * qr, qm, qo prepended with as many zeroes as there are public inputs. -// * qk, prepended with as many zeroes as public inputs, to be completed by the prover -// with the list of public inputs. -// * sigma_1, sigma_2, sigma_3 in both basis -// * the copy constraint permutation -type ProvingKey struct { - // Verifying Key is embedded into the proving key (needed by Prove) - Vk *VerifyingKey - - // TODO store iop.Polynomial here, not []fr.Element for more "type safety" - - // qr,ql,qm,qo (in canonical basis). - Ql, Qr, Qm, Qo []fr.Element - - // qr,ql,qm,qo (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. - lQl, lQr, lQm, lQo []fr.Element - - // LQk (CQk) qk in Lagrange basis (canonical basis), prepended with as many zeroes as public inputs. - // Storing LQk in Lagrange basis saves a fft... - CQk, LQk []fr.Element - - // Domains used for the FFTs. - // Domain[0] = small Domain - // Domain[1] = big Domain - Domain [2]fft.Domain - // Domain[0], Domain[1] fft.Domain - - // Permutation polynomials - S1Canonical, S2Canonical, S3Canonical []fr.Element - - // in lagrange coset basis --> these are not serialized, but computed from S1Canonical, S2Canonical, S3Canonical once. - lS1LagrangeCoset, lS2LagrangeCoset, lS3LagrangeCoset []fr.Element - - // position -> permuted position (position in [0,3*sizeSystem-1]) - Permutation []int64 +// Trace stores a plonk trace as columns +type Trace struct { + + // Constants describing a plonk circuit. The first entries + // of LQk (whose index correspond to the public inputs) are set to 0, and are to be + // completed by the prover. At those indices i (so from 0 to nb_public_variables), LQl[i]=-1 + // so the first nb_public_variables constraints look like this: + // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. + Ql, Qr, Qm, Qo, Qk *iop.Polynomial + + // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. + // The set of interpolation is of size N, so to represent the permutation S we let S acts on the + // set A=(, u*, u^{2}*) of size 3*N, where u is outside (its use is to shift the set ). + // We obtain a permutation of A, A'. We split A' in 3 (A'_{1}, A'_{2}, A'_{3}), and S1, S2, S3 are + // respectively the interpolation of A'_{1}, A'_{2}, A'_{3} on . + S1, S2, S3 *iop.Polynomial + + // S full permutation, i -> S[i] + S []int64 } // VerifyingKey stores the data needed to verify a proof: @@ -73,6 +55,7 @@ type ProvingKey struct { // * Commitments of qr, qm, qo, qk prepended with as many zeroes as there are public inputs // * Commitments to S1, S2, S3 type VerifyingKey struct { + // Size circuit Size uint64 SizeInv fr.Element @@ -93,115 +76,235 @@ type VerifyingKey struct { Ql, Qr, Qm, Qo, Qk kzg.Digest } -// Setup sets proving and verifying keys +// ProvingKey stores the data needed to generate a proof: +// * the commitment scheme +// * ql, prepended with as many ones as they are public inputs +// * qr, qm, qo prepended with as many zeroes as there are public inputs. +// * qk, prepended with as many zeroes as public inputs, to be completed by the prover +// with the list of public inputs. +// * sigma_1, sigma_2, sigma_3 in both basis +// * the copy constraint permutation +type ProvingKey struct { + + // stores ql, qr, qm, qo, qk (-> to be completed by the prover) + // and s1, s2, s3. They are set in canonical basis before generating the proof, they will be used + // for computing the opening proofs (hence the canonical form). The canonical version + // of qk incompleted is used in the linearisation polynomial. + // The polynomials in trace are in canonical basis. + trace Trace + + // Verifying Key is embedded into the proving key (needed by Prove) + Vk *VerifyingKey + + // qr,ql,qm,qo in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. + lcQl, lcQr, lcQm, lcQo *iop.Polynomial + + // LQk qk in Lagrange form -> to be completed by the prover. After being completed, + lQk *iop.Polynomial + + // Domains used for the FFTs. + // Domain[0] = small Domain + // Domain[1] = big Domain + Domain [2]fft.Domain + + // in lagrange coset basis --> these are not serialized, but computed from S1Canonical, S2Canonical, S3Canonical once. + lcS1, lcS2, lcS3 *iop.Polynomial +} + func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) { + var pk ProvingKey var vk VerifyingKey - - // The verifying key shares data with the proving key pk.Vk = &vk + // nbConstraints := len(spr.Constraints) - nbConstraints := len(spr.Constraints) + // step 0: set the fft domains + pk.initDomains(spr) - // fft domains - sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints - pk.Domain[0] = *fft.NewDomain(sizeSystem) + // step 1: set the verifying key pk.Vk.CosetShift.Set(&pk.Domain[0].FrMultiplicativeGen) - - // h, the quotient polynomial is of degree 3(n+1)+2, so it's in a 3(n+2) dim vector space, - // the domain is the next power of 2 superior to 3(n+2). 4*domainNum is enough in all cases - // except when n<6. - if sizeSystem < 6 { - pk.Domain[1] = *fft.NewDomain(8 * sizeSystem) - } else { - pk.Domain[1] = *fft.NewDomain(4 * sizeSystem) - } - vk.Size = pk.Domain[0].Cardinality vk.SizeInv.SetUint64(vk.Size).Inverse(&vk.SizeInv) vk.Generator.Set(&pk.Domain[0].Generator) vk.NbPublicVariables = uint64(len(spr.Public)) - if err := pk.InitKZG(srs); err != nil { return nil, nil, err } - // public polynomials corresponding to constraints: [ placholders | constraints | assertions ] - pk.Ql = make([]fr.Element, pk.Domain[0].Cardinality) - pk.Qr = make([]fr.Element, pk.Domain[0].Cardinality) - pk.Qm = make([]fr.Element, pk.Domain[0].Cardinality) - pk.Qo = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQk = make([]fr.Element, pk.Domain[0].Cardinality) - pk.LQk = make([]fr.Element, pk.Domain[0].Cardinality) + // step 2: ql, qr, qm, qo, qk in Lagrange Basis + BuildTrace(spr, &pk.trace) + + // step 3: build the permutation and build the polynomials S1, S2, S3 to encode the permutation. + // Note: at this stage, the permutation takes in account the placeholders + nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) + buildPermutation(spr, &pk.trace, nbVariables) + s := computePermutationPolynomials(&pk.trace, &pk.Domain[0]) + pk.trace.S1 = s[0] + pk.trace.S2 = s[1] + pk.trace.S3 = s[2] + + // step 4: commit to s1, s2, s3, ql, qr, qm, qo, and (the incomplete version of) qk. + // All the above polynomials are expressed in canonical basis afterwards. This is why + // we save lqk before, because the prover needs to complete it in Lagrange form, and + // then express it on the Lagrange coset basis. + pk.lQk = pk.trace.Qk.Clone() // it will be completed by the prover, and the evaluated on the coset + err := commitTrace(&pk.trace, &pk) + if err != nil { + return nil, nil, err + } + + // step 5: evaluate ql, qr, qm, qo, s1, s2, s3 on LagrangeCoset (NOT qk) + // we clone them, because the canonical versions are going to be used in + // the opening proof + pk.computeLagrangeCosetPolys() + + return &pk, &vk, nil +} + +// computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset +// basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. +func (pk *ProvingKey) computeLagrangeCosetPolys() { + pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQo = pk.trace.Qo.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcS1 = pk.trace.S1.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcS2 = pk.trace.S2.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcS3 = pk.trace.S3.Clone().ToLagrangeCoset(&pk.Domain[1]) +} + +// NbPublicWitness returns the expected public witness size (number of field elements) +func (vk *VerifyingKey) NbPublicWitness() int { + return int(vk.NbPublicVariables) +} + +// VerifyingKey returns pk.Vk +func (pk *ProvingKey) VerifyingKey() interface{} { + return pk.Vk +} + +// InitKZG inits pk.Vk.KZG using pk.Domain[0] cardinality and provided SRS +// +// This should be used after deserializing a ProvingKey +// as pk.Vk.KZG is NOT serialized +func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { + return pk.Vk.InitKZG(srs) +} + +// InitKZG inits vk.KZG using provided SRS +// +// This should be used after deserializing a VerifyingKey +// as vk.KZG is NOT serialized +// +// Note that this instantiate a new FFT domain using vk.Size +func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { + _srs := srs.(*kzg.SRS) + + if len(_srs.G1) < int(vk.Size) { + return errors.New("kzg srs is too small") + } + vk.KZGSRS = _srs + + return nil +} + +// BuildTrace fills the constatn columns ql, qr, qm, qo, qk from the sparser1cs. +// Size is the size of the system that is nb_constraints+nb_public_variables +func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { + + nbConstraints := len(spr.Constraints) + sizeSystem := uint64(nbConstraints + len(spr.Public)) + size := ecc.NextPowerOfTwo(uint64(sizeSystem)) + + ql := make([]fr.Element, size) + qr := make([]fr.Element, size) + qm := make([]fr.Element, size) + qo := make([]fr.Element, size) + qk := make([]fr.Element, size) for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistant - pk.Ql[i].SetOne().Neg(&pk.Ql[i]) - pk.Qr[i].SetZero() - pk.Qm[i].SetZero() - pk.Qo[i].SetZero() - pk.CQk[i].SetZero() - pk.LQk[i].SetZero() // → to be completed by the prover + ql[i].SetOne().Neg(&ql[i]) + qr[i].SetZero() + qm[i].SetZero() + qo[i].SetZero() + qk[i].SetZero() // → to be completed by the prover } offset := len(spr.Public) for i := 0; i < nbConstraints; i++ { // constraints - pk.Ql[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) - pk.Qr[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) - pk.Qm[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). - Mul(&pk.Qm[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) - pk.Qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) - pk.CQk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) - pk.LQk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) + ql[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) + qr[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) + qm[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). + Mul(&qm[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) + qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) + qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } - pk.Domain[0].FFTInverse(pk.Ql, fft.DIF) - pk.Domain[0].FFTInverse(pk.Qr, fft.DIF) - pk.Domain[0].FFTInverse(pk.Qm, fft.DIF) - pk.Domain[0].FFTInverse(pk.Qo, fft.DIF) - pk.Domain[0].FFTInverse(pk.CQk, fft.DIF) - fft.BitReverse(pk.Ql) - fft.BitReverse(pk.Qr) - fft.BitReverse(pk.Qm) - fft.BitReverse(pk.Qo) - fft.BitReverse(pk.CQk) + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} - // build permutation. Note: at this stage, the permutation takes in account the placeholders - buildPermutation(spr, &pk) + pt.Ql = iop.NewPolynomial(&ql, lagReg) + pt.Qr = iop.NewPolynomial(&qr, lagReg) + pt.Qm = iop.NewPolynomial(&qm, lagReg) + pt.Qo = iop.NewPolynomial(&qo, lagReg) + pt.Qk = iop.NewPolynomial(&qk, lagReg) - // set s1, s2, s3 - ccomputePermutationPolynomials(&pk) +} - // compute the lagrange coset basis versions (not serialized) - pk.computeLagrangeCosetPolys() +// commitTrace commits to every polynomials in the trace, and put +// the commitments int the verifying key. +func commitTrace(trace *Trace, pk *ProvingKey) error { + + trace.Ql.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qr.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qm.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qo.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qk.ToCanonical(&pk.Domain[0]).ToRegular() // -> qk is not complete + trace.S1.ToCanonical(&pk.Domain[0]).ToRegular() + trace.S2.ToCanonical(&pk.Domain[0]).ToRegular() + trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() - // Commit to the polynomials to set up the verifying key var err error - if vk.Ql, err = kzg.Commit(pk.Ql, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qr, err = kzg.Commit(pk.Qr, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qr, err = kzg.Commit(pk.trace.Qr.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qm, err = kzg.Commit(pk.Qm, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qm, err = kzg.Commit(pk.trace.Qm.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qo, err = kzg.Commit(pk.Qo, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qo, err = kzg.Commit(pk.trace.Qo.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qk, err = kzg.Commit(pk.CQk, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.S[0], err = kzg.Commit(pk.S1Canonical, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.S[1], err = kzg.Commit(pk.S2Canonical, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.S[1], err = kzg.Commit(pk.trace.S2.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.S[2], err = kzg.Commit(pk.S3Canonical, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.S[2], err = kzg.Commit(pk.trace.S3.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } + return nil +} - return &pk, &vk, nil +func (pk *ProvingKey) initDomains(spr *cs.SparseR1CS) { + + nbConstraints := len(spr.Constraints) + sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints + pk.Domain[0] = *fft.NewDomain(sizeSystem) + + // h, the quotient polynomial is of degree 3(n+1)+2, so it's in a 3(n+2) dim vector space, + // the domain is the next power of 2 superior to 3(n+2). 4*domainNum is enough in all cases + // except when n<6. + if sizeSystem < 6 { + pk.Domain[1] = *fft.NewDomain(8 * sizeSystem) + } else { + pk.Domain[1] = *fft.NewDomain(4 * sizeSystem) + } } @@ -217,19 +320,20 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // The permutation is encoded as a slice s of size 3*size(l), where the // i-th entry of l∥r∥o is sent to the s[i]-th entry, so it acts on a tab // like this: for i in tab: tab[i] = tab[permutation[i]] -func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { +func buildPermutation(spr *cs.SparseR1CS, pt *Trace, nbVariables int) { - nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) - sizeSolution := int(pk.Domain[0].Cardinality) + // nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) + sizeSolution := len(pt.Ql.Coefficients()) + sizePermutation := 3 * sizeSolution // init permutation - pk.Permutation = make([]int64, 3*sizeSolution) - for i := 0; i < len(pk.Permutation); i++ { - pk.Permutation[i] = -1 + permutation := make([]int64, sizePermutation) + for i := 0; i < len(permutation); i++ { + permutation[i] = -1 } // init LRO position -> variable_ID - lro := make([]int, 3*sizeSolution) // position -> variable_ID + lro := make([]int, sizePermutation) // position -> variable_ID for i := 0; i < len(spr.Public); i++ { lro[i] = i // IDs of LRO associated to placeholders (only L needs to be taken care of) } @@ -252,95 +356,54 @@ func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { if cycle[lro[i]] != -1 { // if != -1, it means we already encountered this value // so we need to set the corresponding permutation index. - pk.Permutation[i] = cycle[lro[i]] + permutation[i] = cycle[lro[i]] } cycle[lro[i]] = int64(i) } // complete the Permutation by filling the first IDs encountered - for i := 0; i < len(pk.Permutation); i++ { - if pk.Permutation[i] == -1 { - pk.Permutation[i] = cycle[lro[i]] + for i := 0; i < sizePermutation; i++ { + if permutation[i] == -1 { + permutation[i] = cycle[lro[i]] } } -} -func (pk *ProvingKey) computeLagrangeCosetPolys() { - canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} - wqliop := iop.NewPolynomial(clone(pk.Ql, pk.Domain[1].Cardinality), canReg) - wqriop := iop.NewPolynomial(clone(pk.Qr, pk.Domain[1].Cardinality), canReg) - wqmiop := iop.NewPolynomial(clone(pk.Qm, pk.Domain[1].Cardinality), canReg) - wqoiop := iop.NewPolynomial(clone(pk.Qo, pk.Domain[1].Cardinality), canReg) - - ws1 := iop.NewPolynomial(clone(pk.S1Canonical, pk.Domain[1].Cardinality), canReg) - ws2 := iop.NewPolynomial(clone(pk.S2Canonical, pk.Domain[1].Cardinality), canReg) - ws3 := iop.NewPolynomial(clone(pk.S3Canonical, pk.Domain[1].Cardinality), canReg) - - wqliop.ToLagrangeCoset(&pk.Domain[1]) - wqriop.ToLagrangeCoset(&pk.Domain[1]) - wqmiop.ToLagrangeCoset(&pk.Domain[1]) - wqoiop.ToLagrangeCoset(&pk.Domain[1]) - - ws1.ToLagrangeCoset(&pk.Domain[1]) - ws2.ToLagrangeCoset(&pk.Domain[1]) - ws3.ToLagrangeCoset(&pk.Domain[1]) - - pk.lQl = wqliop.Coefficients() - pk.lQr = wqriop.Coefficients() - pk.lQm = wqmiop.Coefficients() - pk.lQo = wqoiop.Coefficients() - - pk.lS1LagrangeCoset = ws1.Coefficients() - pk.lS2LagrangeCoset = ws2.Coefficients() - pk.lS3LagrangeCoset = ws3.Coefficients() + pt.S = permutation } -func clone(input []fr.Element, capacity uint64) *[]fr.Element { - res := make([]fr.Element, len(input), capacity) - copy(res, input) - return &res -} +// computePermutationPolynomials computes the LDE (Lagrange basis) of the permutation. +// We let the permutation act on || u || u^{2}, split the result in 3 parts, +// and interpolate each of the 3 parts on . +func computePermutationPolynomials(pt *Trace, domain *fft.Domain) [3]*iop.Polynomial { -// ccomputePermutationPolynomials computes the LDE (Lagrange basis) of the permutations -// s1, s2, s3. -// -// 1 z .. z**n-1 | u uz .. u*z**n-1 | u**2 u**2*z .. u**2*z**n-1 | -// -// | -// | Permutation -// -// s11 s12 .. s1n s21 s22 .. s2n s31 s32 .. s3n v -// \---------------/ \--------------------/ \------------------------/ -// -// s1 (LDE) s2 (LDE) s3 (LDE) -func ccomputePermutationPolynomials(pk *ProvingKey) { + nbElmts := int(domain.Cardinality) - nbElmts := int(pk.Domain[0].Cardinality) + var res [3]*iop.Polynomial // Lagrange form of ID - evaluationIDSmallDomain := getIDSmallDomain(&pk.Domain[0]) + evaluationIDSmallDomain := getSupportPermutation(domain) // Lagrange form of S1, S2, S3 - pk.S1Canonical = make([]fr.Element, nbElmts) - pk.S2Canonical = make([]fr.Element, nbElmts) - pk.S3Canonical = make([]fr.Element, nbElmts) + s1Canonical := make([]fr.Element, nbElmts) + s2Canonical := make([]fr.Element, nbElmts) + s3Canonical := make([]fr.Element, nbElmts) for i := 0; i < nbElmts; i++ { - pk.S1Canonical[i].Set(&evaluationIDSmallDomain[pk.Permutation[i]]) - pk.S2Canonical[i].Set(&evaluationIDSmallDomain[pk.Permutation[nbElmts+i]]) - pk.S3Canonical[i].Set(&evaluationIDSmallDomain[pk.Permutation[2*nbElmts+i]]) + s1Canonical[i].Set(&evaluationIDSmallDomain[pt.S[i]]) + s2Canonical[i].Set(&evaluationIDSmallDomain[pt.S[nbElmts+i]]) + s3Canonical[i].Set(&evaluationIDSmallDomain[pt.S[2*nbElmts+i]]) } - // Canonical form of S1, S2, S3 - pk.Domain[0].FFTInverse(pk.S1Canonical, fft.DIF) - pk.Domain[0].FFTInverse(pk.S2Canonical, fft.DIF) - pk.Domain[0].FFTInverse(pk.S3Canonical, fft.DIF) - fft.BitReverse(pk.S1Canonical) - fft.BitReverse(pk.S2Canonical) - fft.BitReverse(pk.S3Canonical) + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + res[0] = iop.NewPolynomial(&s1Canonical, lagReg) + res[1] = iop.NewPolynomial(&s2Canonical, lagReg) + res[2] = iop.NewPolynomial(&s3Canonical, lagReg) + + return res } -// getIDSmallDomain returns the Lagrange form of ID on the small domain -func getIDSmallDomain(domain *fft.Domain) []fr.Element { +// getSupportPermutation returns the support on which the permutation acts, it is +// || u || u^{2} +func getSupportPermutation(domain *fft.Domain) []fr.Element { res := make([]fr.Element, 3*domain.Cardinality) @@ -356,38 +419,3 @@ func getIDSmallDomain(domain *fft.Domain) []fr.Element { return res } - -// InitKZG inits pk.Vk.KZG using pk.Domain[0] cardinality and provided SRS -// -// This should be used after deserializing a ProvingKey -// as pk.Vk.KZG is NOT serialized -func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { - return pk.Vk.InitKZG(srs) -} - -// InitKZG inits vk.KZG using provided SRS -// -// This should be used after deserializing a VerifyingKey -// as vk.KZG is NOT serialized -// -// Note that this instantiate a new FFT domain using vk.Size -func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { - _srs := srs.(*kzg.SRS) - - if len(_srs.G1) < int(vk.Size) { - return errors.New("kzg srs is too small") - } - vk.KZGSRS = _srs - - return nil -} - -// NbPublicWitness returns the expected public witness size (number of field elements) -func (vk *VerifyingKey) NbPublicWitness() int { - return int(vk.NbPublicVariables) -} - -// VerifyingKey returns pk.Vk -func (pk *ProvingKey) VerifyingKey() interface{} { - return pk.Vk -} diff --git a/backend/plonk/bls12-381/marshal.go b/backend/plonk/bls12-381/marshal.go index cdb2e18749..b40458990f 100644 --- a/backend/plonk/bls12-381/marshal.go +++ b/backend/plonk/bls12-381/marshal.go @@ -21,6 +21,7 @@ import ( "errors" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/iop" "io" ) @@ -108,7 +109,7 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { n += n2 // sanity check len(Permutation) == 3*int(pk.Domain[0].Cardinality) - if len(pk.Permutation) != (3 * int(pk.Domain[0].Cardinality)) { + if len(pk.trace.S) != (3 * int(pk.Domain[0].Cardinality)) { return n, errors.New("invalid permutation size, expected 3*domain cardinality") } @@ -117,16 +118,16 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { // encode the size (nor does it convert from Montgomery to Regular form) // so we explicitly transmit []fr.Element toEncode := []interface{}{ - ([]fr.Element)(pk.Ql), - ([]fr.Element)(pk.Qr), - ([]fr.Element)(pk.Qm), - ([]fr.Element)(pk.Qo), - ([]fr.Element)(pk.CQk), - ([]fr.Element)(pk.LQk), - ([]fr.Element)(pk.S1Canonical), - ([]fr.Element)(pk.S2Canonical), - ([]fr.Element)(pk.S3Canonical), - pk.Permutation, + ([]fr.Element)(pk.trace.Ql.Coefficients()), + ([]fr.Element)(pk.trace.Qr.Coefficients()), + ([]fr.Element)(pk.trace.Qm.Coefficients()), + ([]fr.Element)(pk.trace.Qo.Coefficients()), + ([]fr.Element)(pk.trace.Qk.Coefficients()), + ([]fr.Element)(pk.lQk.Coefficients()), + ([]fr.Element)(pk.trace.S1.Coefficients()), + ([]fr.Element)(pk.trace.S2.Coefficients()), + ([]fr.Element)(pk.trace.S3.Coefficients()), + pk.trace.S, } for _, v := range toEncode { @@ -158,20 +159,22 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { return n, err } - pk.Permutation = make([]int64, 3*pk.Domain[0].Cardinality) + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) dec := curve.NewDecoder(r) + + var ql, qr, qm, qo, qk, lqk, s1, s2, s3 []fr.Element toDecode := []interface{}{ - (*[]fr.Element)(&pk.Ql), - (*[]fr.Element)(&pk.Qr), - (*[]fr.Element)(&pk.Qm), - (*[]fr.Element)(&pk.Qo), - (*[]fr.Element)(&pk.CQk), - (*[]fr.Element)(&pk.LQk), - (*[]fr.Element)(&pk.S1Canonical), - (*[]fr.Element)(&pk.S2Canonical), - (*[]fr.Element)(&pk.S3Canonical), - &pk.Permutation, + &ql, + &qr, + &qm, + &qo, + &qk, + &lqk, + &s1, + &s2, + &s3, + &pk.trace.S, } for _, v := range toDecode { @@ -180,6 +183,19 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { } } + canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} + pk.trace.Ql = iop.NewPolynomial(&ql, canReg) + pk.trace.Qr = iop.NewPolynomial(&qr, canReg) + pk.trace.Qm = iop.NewPolynomial(&qm, canReg) + pk.trace.Qo = iop.NewPolynomial(&qo, canReg) + pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.S1 = iop.NewPolynomial(&s1, canReg) + pk.trace.S2 = iop.NewPolynomial(&s2, canReg) + pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + pk.lQk = iop.NewPolynomial(&lqk, lagReg) + pk.computeLagrangeCosetPolys() return n + dec.BytesRead(), nil diff --git a/backend/plonk/bls12-381/marshal_test.go b/backend/plonk/bls12-381/marshal_test.go index 0e0380208d..3727a97afc 100644 --- a/backend/plonk/bls12-381/marshal_test.go +++ b/backend/plonk/bls12-381/marshal_test.go @@ -23,6 +23,7 @@ import ( "bytes" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/fft" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/iop" gnarkio "github.com/consensys/gnark/io" "io" "math/big" @@ -106,6 +107,7 @@ func roundTripCheckRaw(t *testing.T, from gnarkio.WriterRawTo, reconstructed io. } func (pk *ProvingKey) randomize() { + var vk VerifyingKey vk.randomize() pk.Vk = &vk @@ -113,19 +115,32 @@ func (pk *ProvingKey) randomize() { pk.Domain[1] = *fft.NewDomain(4 * 42) n := int(pk.Domain[0].Cardinality) - pk.Ql = randomScalars(n) - pk.Qr = randomScalars(n) - pk.Qm = randomScalars(n) - pk.Qo = randomScalars(n) - pk.CQk = randomScalars(n) - pk.LQk = randomScalars(n) - pk.S1Canonical = randomScalars(n) - pk.S2Canonical = randomScalars(n) - pk.S3Canonical = randomScalars(n) - - pk.Permutation = make([]int64, 3*pk.Domain[0].Cardinality) - pk.Permutation[0] = -12 - pk.Permutation[len(pk.Permutation)-1] = 8888 + ql := randomScalars(n) + qr := randomScalars(n) + qm := randomScalars(n) + qo := randomScalars(n) + qk := randomScalars(n) + lqk := randomScalars(n) + s1 := randomScalars(n) + s2 := randomScalars(n) + s3 := randomScalars(n) + + canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} + pk.trace.Ql = iop.NewPolynomial(&ql, canReg) + pk.trace.Qr = iop.NewPolynomial(&qr, canReg) + pk.trace.Qm = iop.NewPolynomial(&qm, canReg) + pk.trace.Qo = iop.NewPolynomial(&qo, canReg) + pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.S1 = iop.NewPolynomial(&s1, canReg) + pk.trace.S2 = iop.NewPolynomial(&s2, canReg) + pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) + pk.trace.S[0] = -12 + pk.trace.S[len(pk.trace.S)-1] = 8888 + + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + pk.lQk = iop.NewPolynomial(&lqk, lagReg) pk.computeLagrangeCosetPolys() } diff --git a/backend/plonk/bls12-381/prove.go b/backend/plonk/bls12-381/prove.go index 98267ceee0..1fd5cf4edc 100644 --- a/backend/plonk/bls12-381/prove.go +++ b/backend/plonk/bls12-381/prove.go @@ -143,7 +143,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts riop.Clone(), oiop.Clone(), }, - pk.Permutation, + pk.trace.S, beta, gamma, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}, @@ -168,9 +168,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // compute qk in canonical basis, completed with the public inputs - qkCompletedCanonical := make([]fr.Element, pk.Domain[0].Cardinality) + // We copy the coeffs of qk to pk is not mutated + lqkcoef := pk.lQk.Coefficients() + qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) + copy(qkCompletedCanonical, lqkcoef) copy(qkCompletedCanonical, fw[:len(spr.Public)]) - copy(qkCompletedCanonical[len(spr.Public):], pk.LQk[len(spr.Public):]) pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -179,17 +181,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwriop.ToLagrangeCoset(&pk.Domain[1]) bwoiop.ToLagrangeCoset(&pk.Domain[1]) - lagrangeCosetBitReversed := iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse} - - // we don't mutate so no need to clone the coefficients from the proving key. - wqliop := iop.NewPolynomial(&pk.lQl, lagrangeCosetBitReversed) - wqriop := iop.NewPolynomial(&pk.lQr, lagrangeCosetBitReversed) - wqmiop := iop.NewPolynomial(&pk.lQm, lagrangeCosetBitReversed) - wqoiop := iop.NewPolynomial(&pk.lQo, lagrangeCosetBitReversed) - canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} - wqkiop := iop.NewPolynomial(&qkCompletedCanonical, canReg) - wqkiop.ToLagrangeCoset(&pk.Domain[1]) + lcqk := iop.NewPolynomial(&qkCompletedCanonical, canReg) + lcqk.ToLagrangeCoset(&pk.Domain[1]) // storing Id id := make([]fr.Element, pk.Domain[1].Cardinality) @@ -197,12 +191,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts widiop := iop.NewPolynomial(&id, canReg) widiop.ToLagrangeCoset(&pk.Domain[1]) - // permutations in LagrangeCoset: we don't mutate so no need to clone the coefficients from the - // proving key. - ws1 := iop.NewPolynomial(&pk.lS1LagrangeCoset, lagrangeCosetBitReversed) - ws2 := iop.NewPolynomial(&pk.lS2LagrangeCoset, lagrangeCosetBitReversed) - ws3 := iop.NewPolynomial(&pk.lS3LagrangeCoset, lagrangeCosetBitReversed) - // Store z(g*x), without reallocating a slice bwsziop := bwziop.ShallowClone().Shift(1) bwsziop.ToLagrangeCoset(&pk.Domain[1]) @@ -276,27 +264,27 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return c } - testEval, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, + systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, bwliop, bwriop, bwoiop, widiop, - ws1, - ws2, - ws3, + pk.lcS1, + pk.lcS2, + pk.lcS3, bwziop, bwsziop, - wqliop, - wqriop, - wqmiop, - wqoiop, - wqkiop, + pk.lcQl, + pk.lcQr, + pk.lcQm, + pk.lcQo, + lcqk, wloneiop, ) if err != nil { return nil, err } - h, err := iop.DivideByXMinusOne(testEval, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) + h, err := iop.DivideByXMinusOne(systemEvaluation, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) if err != nil { return nil, err } @@ -420,8 +408,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwliop.Coefficients()[:bwliop.BlindedSize()], bwriop.Coefficients()[:bwriop.BlindedSize()], bwoiop.Coefficients()[:bwoiop.BlindedSize()], - pk.S1Canonical, - pk.S2Canonical, + pk.trace.S1.Coefficients(), + pk.trace.S2.Coefficients(), }, []kzg.Digest{ foldedHDigest, @@ -522,13 +510,12 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, var s1, s2 fr.Element chS1 := make(chan struct{}, 1) go func() { - ps1 := iop.NewPolynomial(&pk.S1Canonical, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) - s1 = ps1.Evaluate(zeta) // s1(ζ) + s1 = pk.trace.S1.Evaluate(zeta) // s1(ζ) s1.Mul(&s1, &beta).Add(&s1, &lZeta).Add(&s1, &gamma) // (l(ζ)+β*s1(ζ)+γ) close(chS1) }() - ps2 := iop.NewPolynomial(&pk.S2Canonical, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) - tmp := ps2.Evaluate(zeta) // s2(ζ) + // ps2 := iop.NewPolynomial(&pk.S2Canonical, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) + tmp := pk.trace.S2.Evaluate(zeta) // s2(ζ) tmp.Mul(&tmp, &beta).Add(&tmp, &rZeta).Add(&tmp, &gamma) // (r(ζ)+β*s2(ζ)+γ) <-chS1 s1.Mul(&s1, &tmp).Mul(&s1, &zu).Mul(&s1, &beta) // (l(ζ)+β*s1(β)+γ)*(r(ζ)+β*s2(β)+γ)*β*Z(μζ) @@ -562,6 +549,7 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, linPol := make([]fr.Element, len(blindedZCanonical)) copy(linPol, blindedZCanonical) + s3canonical := pk.trace.S3.Coefficients() utils.Parallelize(len(linPol), func(start, end int) { var t0, t1 fr.Element @@ -570,26 +558,31 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, linPol[i].Mul(&linPol[i], &s2) // -Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) - if i < len(pk.S3Canonical) { + if i < len(s3canonical) { - t0.Mul(&pk.S3Canonical[i], &s1) // (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*β*s3(X) + t0.Mul(&s3canonical[i], &s1) // (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*β*s3(X) linPol[i].Add(&linPol[i], &t0) } linPol[i].Mul(&linPol[i], &alpha) // α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ)) - if i < len(pk.Qm) { + cql := pk.trace.Ql.Coefficients() + cqr := pk.trace.Qr.Coefficients() + cqm := pk.trace.Qm.Coefficients() + cqo := pk.trace.Qo.Coefficients() + cqk := pk.trace.Qk.Coefficients() + if i < len(cqm) { - t1.Mul(&pk.Qm[i], &rl) // linPol = linPol + l(ζ)r(ζ)*Qm(X) - t0.Mul(&pk.Ql[i], &lZeta) + t1.Mul(&cqm[i], &rl) // linPol = linPol + l(ζ)r(ζ)*Qm(X) + t0.Mul(&cql[i], &lZeta) t0.Add(&t0, &t1) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + l(ζ)*Ql(X) - t0.Mul(&pk.Qr[i], &rZeta) + t0.Mul(&cqr[i], &rZeta) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + r(ζ)*Qr(X) - t0.Mul(&pk.Qo[i], &oZeta).Add(&t0, &pk.CQk[i]) + t0.Mul(&cqo[i], &oZeta).Add(&t0, &cqk[i]) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) } diff --git a/backend/plonk/bls12-381/setup.go b/backend/plonk/bls12-381/setup.go index e86f945c71..4e06fd46d5 100644 --- a/backend/plonk/bls12-381/setup.go +++ b/backend/plonk/bls12-381/setup.go @@ -18,6 +18,7 @@ package plonk import ( "errors" + "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/iop" @@ -27,44 +28,25 @@ import ( kzgg "github.com/consensys/gnark-crypto/kzg" ) -// ProvingKey stores the data needed to generate a proof: -// * the commitment scheme -// * ql, prepended with as many ones as they are public inputs -// * qr, qm, qo prepended with as many zeroes as there are public inputs. -// * qk, prepended with as many zeroes as public inputs, to be completed by the prover -// with the list of public inputs. -// * sigma_1, sigma_2, sigma_3 in both basis -// * the copy constraint permutation -type ProvingKey struct { - // Verifying Key is embedded into the proving key (needed by Prove) - Vk *VerifyingKey - - // TODO store iop.Polynomial here, not []fr.Element for more "type safety" - - // qr,ql,qm,qo (in canonical basis). - Ql, Qr, Qm, Qo []fr.Element - - // qr,ql,qm,qo (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. - lQl, lQr, lQm, lQo []fr.Element - - // LQk (CQk) qk in Lagrange basis (canonical basis), prepended with as many zeroes as public inputs. - // Storing LQk in Lagrange basis saves a fft... - CQk, LQk []fr.Element - - // Domains used for the FFTs. - // Domain[0] = small Domain - // Domain[1] = big Domain - Domain [2]fft.Domain - // Domain[0], Domain[1] fft.Domain - - // Permutation polynomials - S1Canonical, S2Canonical, S3Canonical []fr.Element - - // in lagrange coset basis --> these are not serialized, but computed from S1Canonical, S2Canonical, S3Canonical once. - lS1LagrangeCoset, lS2LagrangeCoset, lS3LagrangeCoset []fr.Element - - // position -> permuted position (position in [0,3*sizeSystem-1]) - Permutation []int64 +// Trace stores a plonk trace as columns +type Trace struct { + + // Constants describing a plonk circuit. The first entries + // of LQk (whose index correspond to the public inputs) are set to 0, and are to be + // completed by the prover. At those indices i (so from 0 to nb_public_variables), LQl[i]=-1 + // so the first nb_public_variables constraints look like this: + // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. + Ql, Qr, Qm, Qo, Qk *iop.Polynomial + + // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. + // The set of interpolation is of size N, so to represent the permutation S we let S acts on the + // set A=(, u*, u^{2}*) of size 3*N, where u is outside (its use is to shift the set ). + // We obtain a permutation of A, A'. We split A' in 3 (A'_{1}, A'_{2}, A'_{3}), and S1, S2, S3 are + // respectively the interpolation of A'_{1}, A'_{2}, A'_{3} on . + S1, S2, S3 *iop.Polynomial + + // S full permutation, i -> S[i] + S []int64 } // VerifyingKey stores the data needed to verify a proof: @@ -73,6 +55,7 @@ type ProvingKey struct { // * Commitments of qr, qm, qo, qk prepended with as many zeroes as there are public inputs // * Commitments to S1, S2, S3 type VerifyingKey struct { + // Size circuit Size uint64 SizeInv fr.Element @@ -93,115 +76,235 @@ type VerifyingKey struct { Ql, Qr, Qm, Qo, Qk kzg.Digest } -// Setup sets proving and verifying keys +// ProvingKey stores the data needed to generate a proof: +// * the commitment scheme +// * ql, prepended with as many ones as they are public inputs +// * qr, qm, qo prepended with as many zeroes as there are public inputs. +// * qk, prepended with as many zeroes as public inputs, to be completed by the prover +// with the list of public inputs. +// * sigma_1, sigma_2, sigma_3 in both basis +// * the copy constraint permutation +type ProvingKey struct { + + // stores ql, qr, qm, qo, qk (-> to be completed by the prover) + // and s1, s2, s3. They are set in canonical basis before generating the proof, they will be used + // for computing the opening proofs (hence the canonical form). The canonical version + // of qk incompleted is used in the linearisation polynomial. + // The polynomials in trace are in canonical basis. + trace Trace + + // Verifying Key is embedded into the proving key (needed by Prove) + Vk *VerifyingKey + + // qr,ql,qm,qo in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. + lcQl, lcQr, lcQm, lcQo *iop.Polynomial + + // LQk qk in Lagrange form -> to be completed by the prover. After being completed, + lQk *iop.Polynomial + + // Domains used for the FFTs. + // Domain[0] = small Domain + // Domain[1] = big Domain + Domain [2]fft.Domain + + // in lagrange coset basis --> these are not serialized, but computed from S1Canonical, S2Canonical, S3Canonical once. + lcS1, lcS2, lcS3 *iop.Polynomial +} + func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) { + var pk ProvingKey var vk VerifyingKey - - // The verifying key shares data with the proving key pk.Vk = &vk + // nbConstraints := len(spr.Constraints) - nbConstraints := len(spr.Constraints) + // step 0: set the fft domains + pk.initDomains(spr) - // fft domains - sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints - pk.Domain[0] = *fft.NewDomain(sizeSystem) + // step 1: set the verifying key pk.Vk.CosetShift.Set(&pk.Domain[0].FrMultiplicativeGen) - - // h, the quotient polynomial is of degree 3(n+1)+2, so it's in a 3(n+2) dim vector space, - // the domain is the next power of 2 superior to 3(n+2). 4*domainNum is enough in all cases - // except when n<6. - if sizeSystem < 6 { - pk.Domain[1] = *fft.NewDomain(8 * sizeSystem) - } else { - pk.Domain[1] = *fft.NewDomain(4 * sizeSystem) - } - vk.Size = pk.Domain[0].Cardinality vk.SizeInv.SetUint64(vk.Size).Inverse(&vk.SizeInv) vk.Generator.Set(&pk.Domain[0].Generator) vk.NbPublicVariables = uint64(len(spr.Public)) - if err := pk.InitKZG(srs); err != nil { return nil, nil, err } - // public polynomials corresponding to constraints: [ placholders | constraints | assertions ] - pk.Ql = make([]fr.Element, pk.Domain[0].Cardinality) - pk.Qr = make([]fr.Element, pk.Domain[0].Cardinality) - pk.Qm = make([]fr.Element, pk.Domain[0].Cardinality) - pk.Qo = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQk = make([]fr.Element, pk.Domain[0].Cardinality) - pk.LQk = make([]fr.Element, pk.Domain[0].Cardinality) + // step 2: ql, qr, qm, qo, qk in Lagrange Basis + BuildTrace(spr, &pk.trace) + + // step 3: build the permutation and build the polynomials S1, S2, S3 to encode the permutation. + // Note: at this stage, the permutation takes in account the placeholders + nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) + buildPermutation(spr, &pk.trace, nbVariables) + s := computePermutationPolynomials(&pk.trace, &pk.Domain[0]) + pk.trace.S1 = s[0] + pk.trace.S2 = s[1] + pk.trace.S3 = s[2] + + // step 4: commit to s1, s2, s3, ql, qr, qm, qo, and (the incomplete version of) qk. + // All the above polynomials are expressed in canonical basis afterwards. This is why + // we save lqk before, because the prover needs to complete it in Lagrange form, and + // then express it on the Lagrange coset basis. + pk.lQk = pk.trace.Qk.Clone() // it will be completed by the prover, and the evaluated on the coset + err := commitTrace(&pk.trace, &pk) + if err != nil { + return nil, nil, err + } + + // step 5: evaluate ql, qr, qm, qo, s1, s2, s3 on LagrangeCoset (NOT qk) + // we clone them, because the canonical versions are going to be used in + // the opening proof + pk.computeLagrangeCosetPolys() + + return &pk, &vk, nil +} + +// computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset +// basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. +func (pk *ProvingKey) computeLagrangeCosetPolys() { + pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQo = pk.trace.Qo.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcS1 = pk.trace.S1.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcS2 = pk.trace.S2.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcS3 = pk.trace.S3.Clone().ToLagrangeCoset(&pk.Domain[1]) +} + +// NbPublicWitness returns the expected public witness size (number of field elements) +func (vk *VerifyingKey) NbPublicWitness() int { + return int(vk.NbPublicVariables) +} + +// VerifyingKey returns pk.Vk +func (pk *ProvingKey) VerifyingKey() interface{} { + return pk.Vk +} + +// InitKZG inits pk.Vk.KZG using pk.Domain[0] cardinality and provided SRS +// +// This should be used after deserializing a ProvingKey +// as pk.Vk.KZG is NOT serialized +func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { + return pk.Vk.InitKZG(srs) +} + +// InitKZG inits vk.KZG using provided SRS +// +// This should be used after deserializing a VerifyingKey +// as vk.KZG is NOT serialized +// +// Note that this instantiate a new FFT domain using vk.Size +func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { + _srs := srs.(*kzg.SRS) + + if len(_srs.G1) < int(vk.Size) { + return errors.New("kzg srs is too small") + } + vk.KZGSRS = _srs + + return nil +} + +// BuildTrace fills the constatn columns ql, qr, qm, qo, qk from the sparser1cs. +// Size is the size of the system that is nb_constraints+nb_public_variables +func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { + + nbConstraints := len(spr.Constraints) + sizeSystem := uint64(nbConstraints + len(spr.Public)) + size := ecc.NextPowerOfTwo(uint64(sizeSystem)) + + ql := make([]fr.Element, size) + qr := make([]fr.Element, size) + qm := make([]fr.Element, size) + qo := make([]fr.Element, size) + qk := make([]fr.Element, size) for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistant - pk.Ql[i].SetOne().Neg(&pk.Ql[i]) - pk.Qr[i].SetZero() - pk.Qm[i].SetZero() - pk.Qo[i].SetZero() - pk.CQk[i].SetZero() - pk.LQk[i].SetZero() // → to be completed by the prover + ql[i].SetOne().Neg(&ql[i]) + qr[i].SetZero() + qm[i].SetZero() + qo[i].SetZero() + qk[i].SetZero() // → to be completed by the prover } offset := len(spr.Public) for i := 0; i < nbConstraints; i++ { // constraints - pk.Ql[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) - pk.Qr[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) - pk.Qm[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). - Mul(&pk.Qm[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) - pk.Qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) - pk.CQk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) - pk.LQk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) + ql[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) + qr[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) + qm[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). + Mul(&qm[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) + qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) + qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } - pk.Domain[0].FFTInverse(pk.Ql, fft.DIF) - pk.Domain[0].FFTInverse(pk.Qr, fft.DIF) - pk.Domain[0].FFTInverse(pk.Qm, fft.DIF) - pk.Domain[0].FFTInverse(pk.Qo, fft.DIF) - pk.Domain[0].FFTInverse(pk.CQk, fft.DIF) - fft.BitReverse(pk.Ql) - fft.BitReverse(pk.Qr) - fft.BitReverse(pk.Qm) - fft.BitReverse(pk.Qo) - fft.BitReverse(pk.CQk) + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} - // build permutation. Note: at this stage, the permutation takes in account the placeholders - buildPermutation(spr, &pk) + pt.Ql = iop.NewPolynomial(&ql, lagReg) + pt.Qr = iop.NewPolynomial(&qr, lagReg) + pt.Qm = iop.NewPolynomial(&qm, lagReg) + pt.Qo = iop.NewPolynomial(&qo, lagReg) + pt.Qk = iop.NewPolynomial(&qk, lagReg) - // set s1, s2, s3 - ccomputePermutationPolynomials(&pk) +} - // compute the lagrange coset basis versions (not serialized) - pk.computeLagrangeCosetPolys() +// commitTrace commits to every polynomials in the trace, and put +// the commitments int the verifying key. +func commitTrace(trace *Trace, pk *ProvingKey) error { + + trace.Ql.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qr.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qm.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qo.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qk.ToCanonical(&pk.Domain[0]).ToRegular() // -> qk is not complete + trace.S1.ToCanonical(&pk.Domain[0]).ToRegular() + trace.S2.ToCanonical(&pk.Domain[0]).ToRegular() + trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() - // Commit to the polynomials to set up the verifying key var err error - if vk.Ql, err = kzg.Commit(pk.Ql, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qr, err = kzg.Commit(pk.Qr, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qr, err = kzg.Commit(pk.trace.Qr.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qm, err = kzg.Commit(pk.Qm, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qm, err = kzg.Commit(pk.trace.Qm.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qo, err = kzg.Commit(pk.Qo, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qo, err = kzg.Commit(pk.trace.Qo.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qk, err = kzg.Commit(pk.CQk, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.S[0], err = kzg.Commit(pk.S1Canonical, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.S[1], err = kzg.Commit(pk.S2Canonical, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.S[1], err = kzg.Commit(pk.trace.S2.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.S[2], err = kzg.Commit(pk.S3Canonical, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.S[2], err = kzg.Commit(pk.trace.S3.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } + return nil +} - return &pk, &vk, nil +func (pk *ProvingKey) initDomains(spr *cs.SparseR1CS) { + + nbConstraints := len(spr.Constraints) + sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints + pk.Domain[0] = *fft.NewDomain(sizeSystem) + + // h, the quotient polynomial is of degree 3(n+1)+2, so it's in a 3(n+2) dim vector space, + // the domain is the next power of 2 superior to 3(n+2). 4*domainNum is enough in all cases + // except when n<6. + if sizeSystem < 6 { + pk.Domain[1] = *fft.NewDomain(8 * sizeSystem) + } else { + pk.Domain[1] = *fft.NewDomain(4 * sizeSystem) + } } @@ -217,19 +320,20 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // The permutation is encoded as a slice s of size 3*size(l), where the // i-th entry of l∥r∥o is sent to the s[i]-th entry, so it acts on a tab // like this: for i in tab: tab[i] = tab[permutation[i]] -func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { +func buildPermutation(spr *cs.SparseR1CS, pt *Trace, nbVariables int) { - nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) - sizeSolution := int(pk.Domain[0].Cardinality) + // nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) + sizeSolution := len(pt.Ql.Coefficients()) + sizePermutation := 3 * sizeSolution // init permutation - pk.Permutation = make([]int64, 3*sizeSolution) - for i := 0; i < len(pk.Permutation); i++ { - pk.Permutation[i] = -1 + permutation := make([]int64, sizePermutation) + for i := 0; i < len(permutation); i++ { + permutation[i] = -1 } // init LRO position -> variable_ID - lro := make([]int, 3*sizeSolution) // position -> variable_ID + lro := make([]int, sizePermutation) // position -> variable_ID for i := 0; i < len(spr.Public); i++ { lro[i] = i // IDs of LRO associated to placeholders (only L needs to be taken care of) } @@ -252,95 +356,54 @@ func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { if cycle[lro[i]] != -1 { // if != -1, it means we already encountered this value // so we need to set the corresponding permutation index. - pk.Permutation[i] = cycle[lro[i]] + permutation[i] = cycle[lro[i]] } cycle[lro[i]] = int64(i) } // complete the Permutation by filling the first IDs encountered - for i := 0; i < len(pk.Permutation); i++ { - if pk.Permutation[i] == -1 { - pk.Permutation[i] = cycle[lro[i]] + for i := 0; i < sizePermutation; i++ { + if permutation[i] == -1 { + permutation[i] = cycle[lro[i]] } } -} -func (pk *ProvingKey) computeLagrangeCosetPolys() { - canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} - wqliop := iop.NewPolynomial(clone(pk.Ql, pk.Domain[1].Cardinality), canReg) - wqriop := iop.NewPolynomial(clone(pk.Qr, pk.Domain[1].Cardinality), canReg) - wqmiop := iop.NewPolynomial(clone(pk.Qm, pk.Domain[1].Cardinality), canReg) - wqoiop := iop.NewPolynomial(clone(pk.Qo, pk.Domain[1].Cardinality), canReg) - - ws1 := iop.NewPolynomial(clone(pk.S1Canonical, pk.Domain[1].Cardinality), canReg) - ws2 := iop.NewPolynomial(clone(pk.S2Canonical, pk.Domain[1].Cardinality), canReg) - ws3 := iop.NewPolynomial(clone(pk.S3Canonical, pk.Domain[1].Cardinality), canReg) - - wqliop.ToLagrangeCoset(&pk.Domain[1]) - wqriop.ToLagrangeCoset(&pk.Domain[1]) - wqmiop.ToLagrangeCoset(&pk.Domain[1]) - wqoiop.ToLagrangeCoset(&pk.Domain[1]) - - ws1.ToLagrangeCoset(&pk.Domain[1]) - ws2.ToLagrangeCoset(&pk.Domain[1]) - ws3.ToLagrangeCoset(&pk.Domain[1]) - - pk.lQl = wqliop.Coefficients() - pk.lQr = wqriop.Coefficients() - pk.lQm = wqmiop.Coefficients() - pk.lQo = wqoiop.Coefficients() - - pk.lS1LagrangeCoset = ws1.Coefficients() - pk.lS2LagrangeCoset = ws2.Coefficients() - pk.lS3LagrangeCoset = ws3.Coefficients() + pt.S = permutation } -func clone(input []fr.Element, capacity uint64) *[]fr.Element { - res := make([]fr.Element, len(input), capacity) - copy(res, input) - return &res -} +// computePermutationPolynomials computes the LDE (Lagrange basis) of the permutation. +// We let the permutation act on || u || u^{2}, split the result in 3 parts, +// and interpolate each of the 3 parts on . +func computePermutationPolynomials(pt *Trace, domain *fft.Domain) [3]*iop.Polynomial { -// ccomputePermutationPolynomials computes the LDE (Lagrange basis) of the permutations -// s1, s2, s3. -// -// 1 z .. z**n-1 | u uz .. u*z**n-1 | u**2 u**2*z .. u**2*z**n-1 | -// -// | -// | Permutation -// -// s11 s12 .. s1n s21 s22 .. s2n s31 s32 .. s3n v -// \---------------/ \--------------------/ \------------------------/ -// -// s1 (LDE) s2 (LDE) s3 (LDE) -func ccomputePermutationPolynomials(pk *ProvingKey) { + nbElmts := int(domain.Cardinality) - nbElmts := int(pk.Domain[0].Cardinality) + var res [3]*iop.Polynomial // Lagrange form of ID - evaluationIDSmallDomain := getIDSmallDomain(&pk.Domain[0]) + evaluationIDSmallDomain := getSupportPermutation(domain) // Lagrange form of S1, S2, S3 - pk.S1Canonical = make([]fr.Element, nbElmts) - pk.S2Canonical = make([]fr.Element, nbElmts) - pk.S3Canonical = make([]fr.Element, nbElmts) + s1Canonical := make([]fr.Element, nbElmts) + s2Canonical := make([]fr.Element, nbElmts) + s3Canonical := make([]fr.Element, nbElmts) for i := 0; i < nbElmts; i++ { - pk.S1Canonical[i].Set(&evaluationIDSmallDomain[pk.Permutation[i]]) - pk.S2Canonical[i].Set(&evaluationIDSmallDomain[pk.Permutation[nbElmts+i]]) - pk.S3Canonical[i].Set(&evaluationIDSmallDomain[pk.Permutation[2*nbElmts+i]]) + s1Canonical[i].Set(&evaluationIDSmallDomain[pt.S[i]]) + s2Canonical[i].Set(&evaluationIDSmallDomain[pt.S[nbElmts+i]]) + s3Canonical[i].Set(&evaluationIDSmallDomain[pt.S[2*nbElmts+i]]) } - // Canonical form of S1, S2, S3 - pk.Domain[0].FFTInverse(pk.S1Canonical, fft.DIF) - pk.Domain[0].FFTInverse(pk.S2Canonical, fft.DIF) - pk.Domain[0].FFTInverse(pk.S3Canonical, fft.DIF) - fft.BitReverse(pk.S1Canonical) - fft.BitReverse(pk.S2Canonical) - fft.BitReverse(pk.S3Canonical) + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + res[0] = iop.NewPolynomial(&s1Canonical, lagReg) + res[1] = iop.NewPolynomial(&s2Canonical, lagReg) + res[2] = iop.NewPolynomial(&s3Canonical, lagReg) + + return res } -// getIDSmallDomain returns the Lagrange form of ID on the small domain -func getIDSmallDomain(domain *fft.Domain) []fr.Element { +// getSupportPermutation returns the support on which the permutation acts, it is +// || u || u^{2} +func getSupportPermutation(domain *fft.Domain) []fr.Element { res := make([]fr.Element, 3*domain.Cardinality) @@ -356,38 +419,3 @@ func getIDSmallDomain(domain *fft.Domain) []fr.Element { return res } - -// InitKZG inits pk.Vk.KZG using pk.Domain[0] cardinality and provided SRS -// -// This should be used after deserializing a ProvingKey -// as pk.Vk.KZG is NOT serialized -func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { - return pk.Vk.InitKZG(srs) -} - -// InitKZG inits vk.KZG using provided SRS -// -// This should be used after deserializing a VerifyingKey -// as vk.KZG is NOT serialized -// -// Note that this instantiate a new FFT domain using vk.Size -func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { - _srs := srs.(*kzg.SRS) - - if len(_srs.G1) < int(vk.Size) { - return errors.New("kzg srs is too small") - } - vk.KZGSRS = _srs - - return nil -} - -// NbPublicWitness returns the expected public witness size (number of field elements) -func (vk *VerifyingKey) NbPublicWitness() int { - return int(vk.NbPublicVariables) -} - -// VerifyingKey returns pk.Vk -func (pk *ProvingKey) VerifyingKey() interface{} { - return pk.Vk -} diff --git a/backend/plonk/bls24-315/marshal.go b/backend/plonk/bls24-315/marshal.go index 69aad24641..0721e7a82b 100644 --- a/backend/plonk/bls24-315/marshal.go +++ b/backend/plonk/bls24-315/marshal.go @@ -21,6 +21,7 @@ import ( "errors" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/iop" "io" ) @@ -108,7 +109,7 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { n += n2 // sanity check len(Permutation) == 3*int(pk.Domain[0].Cardinality) - if len(pk.Permutation) != (3 * int(pk.Domain[0].Cardinality)) { + if len(pk.trace.S) != (3 * int(pk.Domain[0].Cardinality)) { return n, errors.New("invalid permutation size, expected 3*domain cardinality") } @@ -117,16 +118,16 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { // encode the size (nor does it convert from Montgomery to Regular form) // so we explicitly transmit []fr.Element toEncode := []interface{}{ - ([]fr.Element)(pk.Ql), - ([]fr.Element)(pk.Qr), - ([]fr.Element)(pk.Qm), - ([]fr.Element)(pk.Qo), - ([]fr.Element)(pk.CQk), - ([]fr.Element)(pk.LQk), - ([]fr.Element)(pk.S1Canonical), - ([]fr.Element)(pk.S2Canonical), - ([]fr.Element)(pk.S3Canonical), - pk.Permutation, + ([]fr.Element)(pk.trace.Ql.Coefficients()), + ([]fr.Element)(pk.trace.Qr.Coefficients()), + ([]fr.Element)(pk.trace.Qm.Coefficients()), + ([]fr.Element)(pk.trace.Qo.Coefficients()), + ([]fr.Element)(pk.trace.Qk.Coefficients()), + ([]fr.Element)(pk.lQk.Coefficients()), + ([]fr.Element)(pk.trace.S1.Coefficients()), + ([]fr.Element)(pk.trace.S2.Coefficients()), + ([]fr.Element)(pk.trace.S3.Coefficients()), + pk.trace.S, } for _, v := range toEncode { @@ -158,20 +159,22 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { return n, err } - pk.Permutation = make([]int64, 3*pk.Domain[0].Cardinality) + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) dec := curve.NewDecoder(r) + + var ql, qr, qm, qo, qk, lqk, s1, s2, s3 []fr.Element toDecode := []interface{}{ - (*[]fr.Element)(&pk.Ql), - (*[]fr.Element)(&pk.Qr), - (*[]fr.Element)(&pk.Qm), - (*[]fr.Element)(&pk.Qo), - (*[]fr.Element)(&pk.CQk), - (*[]fr.Element)(&pk.LQk), - (*[]fr.Element)(&pk.S1Canonical), - (*[]fr.Element)(&pk.S2Canonical), - (*[]fr.Element)(&pk.S3Canonical), - &pk.Permutation, + &ql, + &qr, + &qm, + &qo, + &qk, + &lqk, + &s1, + &s2, + &s3, + &pk.trace.S, } for _, v := range toDecode { @@ -180,6 +183,19 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { } } + canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} + pk.trace.Ql = iop.NewPolynomial(&ql, canReg) + pk.trace.Qr = iop.NewPolynomial(&qr, canReg) + pk.trace.Qm = iop.NewPolynomial(&qm, canReg) + pk.trace.Qo = iop.NewPolynomial(&qo, canReg) + pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.S1 = iop.NewPolynomial(&s1, canReg) + pk.trace.S2 = iop.NewPolynomial(&s2, canReg) + pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + pk.lQk = iop.NewPolynomial(&lqk, lagReg) + pk.computeLagrangeCosetPolys() return n + dec.BytesRead(), nil diff --git a/backend/plonk/bls24-315/marshal_test.go b/backend/plonk/bls24-315/marshal_test.go index 485366fd77..4fdf97dfdf 100644 --- a/backend/plonk/bls24-315/marshal_test.go +++ b/backend/plonk/bls24-315/marshal_test.go @@ -23,6 +23,7 @@ import ( "bytes" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/fft" + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/iop" gnarkio "github.com/consensys/gnark/io" "io" "math/big" @@ -106,6 +107,7 @@ func roundTripCheckRaw(t *testing.T, from gnarkio.WriterRawTo, reconstructed io. } func (pk *ProvingKey) randomize() { + var vk VerifyingKey vk.randomize() pk.Vk = &vk @@ -113,19 +115,32 @@ func (pk *ProvingKey) randomize() { pk.Domain[1] = *fft.NewDomain(4 * 42) n := int(pk.Domain[0].Cardinality) - pk.Ql = randomScalars(n) - pk.Qr = randomScalars(n) - pk.Qm = randomScalars(n) - pk.Qo = randomScalars(n) - pk.CQk = randomScalars(n) - pk.LQk = randomScalars(n) - pk.S1Canonical = randomScalars(n) - pk.S2Canonical = randomScalars(n) - pk.S3Canonical = randomScalars(n) - - pk.Permutation = make([]int64, 3*pk.Domain[0].Cardinality) - pk.Permutation[0] = -12 - pk.Permutation[len(pk.Permutation)-1] = 8888 + ql := randomScalars(n) + qr := randomScalars(n) + qm := randomScalars(n) + qo := randomScalars(n) + qk := randomScalars(n) + lqk := randomScalars(n) + s1 := randomScalars(n) + s2 := randomScalars(n) + s3 := randomScalars(n) + + canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} + pk.trace.Ql = iop.NewPolynomial(&ql, canReg) + pk.trace.Qr = iop.NewPolynomial(&qr, canReg) + pk.trace.Qm = iop.NewPolynomial(&qm, canReg) + pk.trace.Qo = iop.NewPolynomial(&qo, canReg) + pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.S1 = iop.NewPolynomial(&s1, canReg) + pk.trace.S2 = iop.NewPolynomial(&s2, canReg) + pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) + pk.trace.S[0] = -12 + pk.trace.S[len(pk.trace.S)-1] = 8888 + + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + pk.lQk = iop.NewPolynomial(&lqk, lagReg) pk.computeLagrangeCosetPolys() } diff --git a/backend/plonk/bls24-315/prove.go b/backend/plonk/bls24-315/prove.go index dcff52621b..3e2a5161ae 100644 --- a/backend/plonk/bls24-315/prove.go +++ b/backend/plonk/bls24-315/prove.go @@ -143,7 +143,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts riop.Clone(), oiop.Clone(), }, - pk.Permutation, + pk.trace.S, beta, gamma, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}, @@ -168,9 +168,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // compute qk in canonical basis, completed with the public inputs - qkCompletedCanonical := make([]fr.Element, pk.Domain[0].Cardinality) + // We copy the coeffs of qk to pk is not mutated + lqkcoef := pk.lQk.Coefficients() + qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) + copy(qkCompletedCanonical, lqkcoef) copy(qkCompletedCanonical, fw[:len(spr.Public)]) - copy(qkCompletedCanonical[len(spr.Public):], pk.LQk[len(spr.Public):]) pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -179,17 +181,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwriop.ToLagrangeCoset(&pk.Domain[1]) bwoiop.ToLagrangeCoset(&pk.Domain[1]) - lagrangeCosetBitReversed := iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse} - - // we don't mutate so no need to clone the coefficients from the proving key. - wqliop := iop.NewPolynomial(&pk.lQl, lagrangeCosetBitReversed) - wqriop := iop.NewPolynomial(&pk.lQr, lagrangeCosetBitReversed) - wqmiop := iop.NewPolynomial(&pk.lQm, lagrangeCosetBitReversed) - wqoiop := iop.NewPolynomial(&pk.lQo, lagrangeCosetBitReversed) - canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} - wqkiop := iop.NewPolynomial(&qkCompletedCanonical, canReg) - wqkiop.ToLagrangeCoset(&pk.Domain[1]) + lcqk := iop.NewPolynomial(&qkCompletedCanonical, canReg) + lcqk.ToLagrangeCoset(&pk.Domain[1]) // storing Id id := make([]fr.Element, pk.Domain[1].Cardinality) @@ -197,12 +191,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts widiop := iop.NewPolynomial(&id, canReg) widiop.ToLagrangeCoset(&pk.Domain[1]) - // permutations in LagrangeCoset: we don't mutate so no need to clone the coefficients from the - // proving key. - ws1 := iop.NewPolynomial(&pk.lS1LagrangeCoset, lagrangeCosetBitReversed) - ws2 := iop.NewPolynomial(&pk.lS2LagrangeCoset, lagrangeCosetBitReversed) - ws3 := iop.NewPolynomial(&pk.lS3LagrangeCoset, lagrangeCosetBitReversed) - // Store z(g*x), without reallocating a slice bwsziop := bwziop.ShallowClone().Shift(1) bwsziop.ToLagrangeCoset(&pk.Domain[1]) @@ -276,27 +264,27 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return c } - testEval, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, + systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, bwliop, bwriop, bwoiop, widiop, - ws1, - ws2, - ws3, + pk.lcS1, + pk.lcS2, + pk.lcS3, bwziop, bwsziop, - wqliop, - wqriop, - wqmiop, - wqoiop, - wqkiop, + pk.lcQl, + pk.lcQr, + pk.lcQm, + pk.lcQo, + lcqk, wloneiop, ) if err != nil { return nil, err } - h, err := iop.DivideByXMinusOne(testEval, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) + h, err := iop.DivideByXMinusOne(systemEvaluation, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) if err != nil { return nil, err } @@ -420,8 +408,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwliop.Coefficients()[:bwliop.BlindedSize()], bwriop.Coefficients()[:bwriop.BlindedSize()], bwoiop.Coefficients()[:bwoiop.BlindedSize()], - pk.S1Canonical, - pk.S2Canonical, + pk.trace.S1.Coefficients(), + pk.trace.S2.Coefficients(), }, []kzg.Digest{ foldedHDigest, @@ -522,13 +510,12 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, var s1, s2 fr.Element chS1 := make(chan struct{}, 1) go func() { - ps1 := iop.NewPolynomial(&pk.S1Canonical, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) - s1 = ps1.Evaluate(zeta) // s1(ζ) + s1 = pk.trace.S1.Evaluate(zeta) // s1(ζ) s1.Mul(&s1, &beta).Add(&s1, &lZeta).Add(&s1, &gamma) // (l(ζ)+β*s1(ζ)+γ) close(chS1) }() - ps2 := iop.NewPolynomial(&pk.S2Canonical, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) - tmp := ps2.Evaluate(zeta) // s2(ζ) + // ps2 := iop.NewPolynomial(&pk.S2Canonical, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) + tmp := pk.trace.S2.Evaluate(zeta) // s2(ζ) tmp.Mul(&tmp, &beta).Add(&tmp, &rZeta).Add(&tmp, &gamma) // (r(ζ)+β*s2(ζ)+γ) <-chS1 s1.Mul(&s1, &tmp).Mul(&s1, &zu).Mul(&s1, &beta) // (l(ζ)+β*s1(β)+γ)*(r(ζ)+β*s2(β)+γ)*β*Z(μζ) @@ -562,6 +549,7 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, linPol := make([]fr.Element, len(blindedZCanonical)) copy(linPol, blindedZCanonical) + s3canonical := pk.trace.S3.Coefficients() utils.Parallelize(len(linPol), func(start, end int) { var t0, t1 fr.Element @@ -570,26 +558,31 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, linPol[i].Mul(&linPol[i], &s2) // -Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) - if i < len(pk.S3Canonical) { + if i < len(s3canonical) { - t0.Mul(&pk.S3Canonical[i], &s1) // (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*β*s3(X) + t0.Mul(&s3canonical[i], &s1) // (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*β*s3(X) linPol[i].Add(&linPol[i], &t0) } linPol[i].Mul(&linPol[i], &alpha) // α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ)) - if i < len(pk.Qm) { + cql := pk.trace.Ql.Coefficients() + cqr := pk.trace.Qr.Coefficients() + cqm := pk.trace.Qm.Coefficients() + cqo := pk.trace.Qo.Coefficients() + cqk := pk.trace.Qk.Coefficients() + if i < len(cqm) { - t1.Mul(&pk.Qm[i], &rl) // linPol = linPol + l(ζ)r(ζ)*Qm(X) - t0.Mul(&pk.Ql[i], &lZeta) + t1.Mul(&cqm[i], &rl) // linPol = linPol + l(ζ)r(ζ)*Qm(X) + t0.Mul(&cql[i], &lZeta) t0.Add(&t0, &t1) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + l(ζ)*Ql(X) - t0.Mul(&pk.Qr[i], &rZeta) + t0.Mul(&cqr[i], &rZeta) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + r(ζ)*Qr(X) - t0.Mul(&pk.Qo[i], &oZeta).Add(&t0, &pk.CQk[i]) + t0.Mul(&cqo[i], &oZeta).Add(&t0, &cqk[i]) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) } diff --git a/backend/plonk/bls24-315/setup.go b/backend/plonk/bls24-315/setup.go index 0bdfcb2ff9..56aa9666e4 100644 --- a/backend/plonk/bls24-315/setup.go +++ b/backend/plonk/bls24-315/setup.go @@ -18,6 +18,7 @@ package plonk import ( "errors" + "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/iop" @@ -27,44 +28,25 @@ import ( kzgg "github.com/consensys/gnark-crypto/kzg" ) -// ProvingKey stores the data needed to generate a proof: -// * the commitment scheme -// * ql, prepended with as many ones as they are public inputs -// * qr, qm, qo prepended with as many zeroes as there are public inputs. -// * qk, prepended with as many zeroes as public inputs, to be completed by the prover -// with the list of public inputs. -// * sigma_1, sigma_2, sigma_3 in both basis -// * the copy constraint permutation -type ProvingKey struct { - // Verifying Key is embedded into the proving key (needed by Prove) - Vk *VerifyingKey - - // TODO store iop.Polynomial here, not []fr.Element for more "type safety" - - // qr,ql,qm,qo (in canonical basis). - Ql, Qr, Qm, Qo []fr.Element - - // qr,ql,qm,qo (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. - lQl, lQr, lQm, lQo []fr.Element - - // LQk (CQk) qk in Lagrange basis (canonical basis), prepended with as many zeroes as public inputs. - // Storing LQk in Lagrange basis saves a fft... - CQk, LQk []fr.Element - - // Domains used for the FFTs. - // Domain[0] = small Domain - // Domain[1] = big Domain - Domain [2]fft.Domain - // Domain[0], Domain[1] fft.Domain - - // Permutation polynomials - S1Canonical, S2Canonical, S3Canonical []fr.Element - - // in lagrange coset basis --> these are not serialized, but computed from S1Canonical, S2Canonical, S3Canonical once. - lS1LagrangeCoset, lS2LagrangeCoset, lS3LagrangeCoset []fr.Element - - // position -> permuted position (position in [0,3*sizeSystem-1]) - Permutation []int64 +// Trace stores a plonk trace as columns +type Trace struct { + + // Constants describing a plonk circuit. The first entries + // of LQk (whose index correspond to the public inputs) are set to 0, and are to be + // completed by the prover. At those indices i (so from 0 to nb_public_variables), LQl[i]=-1 + // so the first nb_public_variables constraints look like this: + // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. + Ql, Qr, Qm, Qo, Qk *iop.Polynomial + + // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. + // The set of interpolation is of size N, so to represent the permutation S we let S acts on the + // set A=(, u*, u^{2}*) of size 3*N, where u is outside (its use is to shift the set ). + // We obtain a permutation of A, A'. We split A' in 3 (A'_{1}, A'_{2}, A'_{3}), and S1, S2, S3 are + // respectively the interpolation of A'_{1}, A'_{2}, A'_{3} on . + S1, S2, S3 *iop.Polynomial + + // S full permutation, i -> S[i] + S []int64 } // VerifyingKey stores the data needed to verify a proof: @@ -73,6 +55,7 @@ type ProvingKey struct { // * Commitments of qr, qm, qo, qk prepended with as many zeroes as there are public inputs // * Commitments to S1, S2, S3 type VerifyingKey struct { + // Size circuit Size uint64 SizeInv fr.Element @@ -93,115 +76,235 @@ type VerifyingKey struct { Ql, Qr, Qm, Qo, Qk kzg.Digest } -// Setup sets proving and verifying keys +// ProvingKey stores the data needed to generate a proof: +// * the commitment scheme +// * ql, prepended with as many ones as they are public inputs +// * qr, qm, qo prepended with as many zeroes as there are public inputs. +// * qk, prepended with as many zeroes as public inputs, to be completed by the prover +// with the list of public inputs. +// * sigma_1, sigma_2, sigma_3 in both basis +// * the copy constraint permutation +type ProvingKey struct { + + // stores ql, qr, qm, qo, qk (-> to be completed by the prover) + // and s1, s2, s3. They are set in canonical basis before generating the proof, they will be used + // for computing the opening proofs (hence the canonical form). The canonical version + // of qk incompleted is used in the linearisation polynomial. + // The polynomials in trace are in canonical basis. + trace Trace + + // Verifying Key is embedded into the proving key (needed by Prove) + Vk *VerifyingKey + + // qr,ql,qm,qo in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. + lcQl, lcQr, lcQm, lcQo *iop.Polynomial + + // LQk qk in Lagrange form -> to be completed by the prover. After being completed, + lQk *iop.Polynomial + + // Domains used for the FFTs. + // Domain[0] = small Domain + // Domain[1] = big Domain + Domain [2]fft.Domain + + // in lagrange coset basis --> these are not serialized, but computed from S1Canonical, S2Canonical, S3Canonical once. + lcS1, lcS2, lcS3 *iop.Polynomial +} + func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) { + var pk ProvingKey var vk VerifyingKey - - // The verifying key shares data with the proving key pk.Vk = &vk + // nbConstraints := len(spr.Constraints) - nbConstraints := len(spr.Constraints) + // step 0: set the fft domains + pk.initDomains(spr) - // fft domains - sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints - pk.Domain[0] = *fft.NewDomain(sizeSystem) + // step 1: set the verifying key pk.Vk.CosetShift.Set(&pk.Domain[0].FrMultiplicativeGen) - - // h, the quotient polynomial is of degree 3(n+1)+2, so it's in a 3(n+2) dim vector space, - // the domain is the next power of 2 superior to 3(n+2). 4*domainNum is enough in all cases - // except when n<6. - if sizeSystem < 6 { - pk.Domain[1] = *fft.NewDomain(8 * sizeSystem) - } else { - pk.Domain[1] = *fft.NewDomain(4 * sizeSystem) - } - vk.Size = pk.Domain[0].Cardinality vk.SizeInv.SetUint64(vk.Size).Inverse(&vk.SizeInv) vk.Generator.Set(&pk.Domain[0].Generator) vk.NbPublicVariables = uint64(len(spr.Public)) - if err := pk.InitKZG(srs); err != nil { return nil, nil, err } - // public polynomials corresponding to constraints: [ placholders | constraints | assertions ] - pk.Ql = make([]fr.Element, pk.Domain[0].Cardinality) - pk.Qr = make([]fr.Element, pk.Domain[0].Cardinality) - pk.Qm = make([]fr.Element, pk.Domain[0].Cardinality) - pk.Qo = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQk = make([]fr.Element, pk.Domain[0].Cardinality) - pk.LQk = make([]fr.Element, pk.Domain[0].Cardinality) + // step 2: ql, qr, qm, qo, qk in Lagrange Basis + BuildTrace(spr, &pk.trace) + + // step 3: build the permutation and build the polynomials S1, S2, S3 to encode the permutation. + // Note: at this stage, the permutation takes in account the placeholders + nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) + buildPermutation(spr, &pk.trace, nbVariables) + s := computePermutationPolynomials(&pk.trace, &pk.Domain[0]) + pk.trace.S1 = s[0] + pk.trace.S2 = s[1] + pk.trace.S3 = s[2] + + // step 4: commit to s1, s2, s3, ql, qr, qm, qo, and (the incomplete version of) qk. + // All the above polynomials are expressed in canonical basis afterwards. This is why + // we save lqk before, because the prover needs to complete it in Lagrange form, and + // then express it on the Lagrange coset basis. + pk.lQk = pk.trace.Qk.Clone() // it will be completed by the prover, and the evaluated on the coset + err := commitTrace(&pk.trace, &pk) + if err != nil { + return nil, nil, err + } + + // step 5: evaluate ql, qr, qm, qo, s1, s2, s3 on LagrangeCoset (NOT qk) + // we clone them, because the canonical versions are going to be used in + // the opening proof + pk.computeLagrangeCosetPolys() + + return &pk, &vk, nil +} + +// computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset +// basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. +func (pk *ProvingKey) computeLagrangeCosetPolys() { + pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQo = pk.trace.Qo.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcS1 = pk.trace.S1.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcS2 = pk.trace.S2.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcS3 = pk.trace.S3.Clone().ToLagrangeCoset(&pk.Domain[1]) +} + +// NbPublicWitness returns the expected public witness size (number of field elements) +func (vk *VerifyingKey) NbPublicWitness() int { + return int(vk.NbPublicVariables) +} + +// VerifyingKey returns pk.Vk +func (pk *ProvingKey) VerifyingKey() interface{} { + return pk.Vk +} + +// InitKZG inits pk.Vk.KZG using pk.Domain[0] cardinality and provided SRS +// +// This should be used after deserializing a ProvingKey +// as pk.Vk.KZG is NOT serialized +func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { + return pk.Vk.InitKZG(srs) +} + +// InitKZG inits vk.KZG using provided SRS +// +// This should be used after deserializing a VerifyingKey +// as vk.KZG is NOT serialized +// +// Note that this instantiate a new FFT domain using vk.Size +func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { + _srs := srs.(*kzg.SRS) + + if len(_srs.G1) < int(vk.Size) { + return errors.New("kzg srs is too small") + } + vk.KZGSRS = _srs + + return nil +} + +// BuildTrace fills the constatn columns ql, qr, qm, qo, qk from the sparser1cs. +// Size is the size of the system that is nb_constraints+nb_public_variables +func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { + + nbConstraints := len(spr.Constraints) + sizeSystem := uint64(nbConstraints + len(spr.Public)) + size := ecc.NextPowerOfTwo(uint64(sizeSystem)) + + ql := make([]fr.Element, size) + qr := make([]fr.Element, size) + qm := make([]fr.Element, size) + qo := make([]fr.Element, size) + qk := make([]fr.Element, size) for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistant - pk.Ql[i].SetOne().Neg(&pk.Ql[i]) - pk.Qr[i].SetZero() - pk.Qm[i].SetZero() - pk.Qo[i].SetZero() - pk.CQk[i].SetZero() - pk.LQk[i].SetZero() // → to be completed by the prover + ql[i].SetOne().Neg(&ql[i]) + qr[i].SetZero() + qm[i].SetZero() + qo[i].SetZero() + qk[i].SetZero() // → to be completed by the prover } offset := len(spr.Public) for i := 0; i < nbConstraints; i++ { // constraints - pk.Ql[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) - pk.Qr[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) - pk.Qm[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). - Mul(&pk.Qm[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) - pk.Qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) - pk.CQk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) - pk.LQk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) + ql[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) + qr[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) + qm[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). + Mul(&qm[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) + qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) + qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } - pk.Domain[0].FFTInverse(pk.Ql, fft.DIF) - pk.Domain[0].FFTInverse(pk.Qr, fft.DIF) - pk.Domain[0].FFTInverse(pk.Qm, fft.DIF) - pk.Domain[0].FFTInverse(pk.Qo, fft.DIF) - pk.Domain[0].FFTInverse(pk.CQk, fft.DIF) - fft.BitReverse(pk.Ql) - fft.BitReverse(pk.Qr) - fft.BitReverse(pk.Qm) - fft.BitReverse(pk.Qo) - fft.BitReverse(pk.CQk) + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} - // build permutation. Note: at this stage, the permutation takes in account the placeholders - buildPermutation(spr, &pk) + pt.Ql = iop.NewPolynomial(&ql, lagReg) + pt.Qr = iop.NewPolynomial(&qr, lagReg) + pt.Qm = iop.NewPolynomial(&qm, lagReg) + pt.Qo = iop.NewPolynomial(&qo, lagReg) + pt.Qk = iop.NewPolynomial(&qk, lagReg) - // set s1, s2, s3 - ccomputePermutationPolynomials(&pk) +} - // compute the lagrange coset basis versions (not serialized) - pk.computeLagrangeCosetPolys() +// commitTrace commits to every polynomials in the trace, and put +// the commitments int the verifying key. +func commitTrace(trace *Trace, pk *ProvingKey) error { + + trace.Ql.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qr.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qm.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qo.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qk.ToCanonical(&pk.Domain[0]).ToRegular() // -> qk is not complete + trace.S1.ToCanonical(&pk.Domain[0]).ToRegular() + trace.S2.ToCanonical(&pk.Domain[0]).ToRegular() + trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() - // Commit to the polynomials to set up the verifying key var err error - if vk.Ql, err = kzg.Commit(pk.Ql, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qr, err = kzg.Commit(pk.Qr, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qr, err = kzg.Commit(pk.trace.Qr.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qm, err = kzg.Commit(pk.Qm, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qm, err = kzg.Commit(pk.trace.Qm.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qo, err = kzg.Commit(pk.Qo, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qo, err = kzg.Commit(pk.trace.Qo.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qk, err = kzg.Commit(pk.CQk, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.S[0], err = kzg.Commit(pk.S1Canonical, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.S[1], err = kzg.Commit(pk.S2Canonical, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.S[1], err = kzg.Commit(pk.trace.S2.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.S[2], err = kzg.Commit(pk.S3Canonical, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.S[2], err = kzg.Commit(pk.trace.S3.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } + return nil +} - return &pk, &vk, nil +func (pk *ProvingKey) initDomains(spr *cs.SparseR1CS) { + + nbConstraints := len(spr.Constraints) + sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints + pk.Domain[0] = *fft.NewDomain(sizeSystem) + + // h, the quotient polynomial is of degree 3(n+1)+2, so it's in a 3(n+2) dim vector space, + // the domain is the next power of 2 superior to 3(n+2). 4*domainNum is enough in all cases + // except when n<6. + if sizeSystem < 6 { + pk.Domain[1] = *fft.NewDomain(8 * sizeSystem) + } else { + pk.Domain[1] = *fft.NewDomain(4 * sizeSystem) + } } @@ -217,19 +320,20 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // The permutation is encoded as a slice s of size 3*size(l), where the // i-th entry of l∥r∥o is sent to the s[i]-th entry, so it acts on a tab // like this: for i in tab: tab[i] = tab[permutation[i]] -func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { +func buildPermutation(spr *cs.SparseR1CS, pt *Trace, nbVariables int) { - nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) - sizeSolution := int(pk.Domain[0].Cardinality) + // nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) + sizeSolution := len(pt.Ql.Coefficients()) + sizePermutation := 3 * sizeSolution // init permutation - pk.Permutation = make([]int64, 3*sizeSolution) - for i := 0; i < len(pk.Permutation); i++ { - pk.Permutation[i] = -1 + permutation := make([]int64, sizePermutation) + for i := 0; i < len(permutation); i++ { + permutation[i] = -1 } // init LRO position -> variable_ID - lro := make([]int, 3*sizeSolution) // position -> variable_ID + lro := make([]int, sizePermutation) // position -> variable_ID for i := 0; i < len(spr.Public); i++ { lro[i] = i // IDs of LRO associated to placeholders (only L needs to be taken care of) } @@ -252,95 +356,54 @@ func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { if cycle[lro[i]] != -1 { // if != -1, it means we already encountered this value // so we need to set the corresponding permutation index. - pk.Permutation[i] = cycle[lro[i]] + permutation[i] = cycle[lro[i]] } cycle[lro[i]] = int64(i) } // complete the Permutation by filling the first IDs encountered - for i := 0; i < len(pk.Permutation); i++ { - if pk.Permutation[i] == -1 { - pk.Permutation[i] = cycle[lro[i]] + for i := 0; i < sizePermutation; i++ { + if permutation[i] == -1 { + permutation[i] = cycle[lro[i]] } } -} -func (pk *ProvingKey) computeLagrangeCosetPolys() { - canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} - wqliop := iop.NewPolynomial(clone(pk.Ql, pk.Domain[1].Cardinality), canReg) - wqriop := iop.NewPolynomial(clone(pk.Qr, pk.Domain[1].Cardinality), canReg) - wqmiop := iop.NewPolynomial(clone(pk.Qm, pk.Domain[1].Cardinality), canReg) - wqoiop := iop.NewPolynomial(clone(pk.Qo, pk.Domain[1].Cardinality), canReg) - - ws1 := iop.NewPolynomial(clone(pk.S1Canonical, pk.Domain[1].Cardinality), canReg) - ws2 := iop.NewPolynomial(clone(pk.S2Canonical, pk.Domain[1].Cardinality), canReg) - ws3 := iop.NewPolynomial(clone(pk.S3Canonical, pk.Domain[1].Cardinality), canReg) - - wqliop.ToLagrangeCoset(&pk.Domain[1]) - wqriop.ToLagrangeCoset(&pk.Domain[1]) - wqmiop.ToLagrangeCoset(&pk.Domain[1]) - wqoiop.ToLagrangeCoset(&pk.Domain[1]) - - ws1.ToLagrangeCoset(&pk.Domain[1]) - ws2.ToLagrangeCoset(&pk.Domain[1]) - ws3.ToLagrangeCoset(&pk.Domain[1]) - - pk.lQl = wqliop.Coefficients() - pk.lQr = wqriop.Coefficients() - pk.lQm = wqmiop.Coefficients() - pk.lQo = wqoiop.Coefficients() - - pk.lS1LagrangeCoset = ws1.Coefficients() - pk.lS2LagrangeCoset = ws2.Coefficients() - pk.lS3LagrangeCoset = ws3.Coefficients() + pt.S = permutation } -func clone(input []fr.Element, capacity uint64) *[]fr.Element { - res := make([]fr.Element, len(input), capacity) - copy(res, input) - return &res -} +// computePermutationPolynomials computes the LDE (Lagrange basis) of the permutation. +// We let the permutation act on || u || u^{2}, split the result in 3 parts, +// and interpolate each of the 3 parts on . +func computePermutationPolynomials(pt *Trace, domain *fft.Domain) [3]*iop.Polynomial { -// ccomputePermutationPolynomials computes the LDE (Lagrange basis) of the permutations -// s1, s2, s3. -// -// 1 z .. z**n-1 | u uz .. u*z**n-1 | u**2 u**2*z .. u**2*z**n-1 | -// -// | -// | Permutation -// -// s11 s12 .. s1n s21 s22 .. s2n s31 s32 .. s3n v -// \---------------/ \--------------------/ \------------------------/ -// -// s1 (LDE) s2 (LDE) s3 (LDE) -func ccomputePermutationPolynomials(pk *ProvingKey) { + nbElmts := int(domain.Cardinality) - nbElmts := int(pk.Domain[0].Cardinality) + var res [3]*iop.Polynomial // Lagrange form of ID - evaluationIDSmallDomain := getIDSmallDomain(&pk.Domain[0]) + evaluationIDSmallDomain := getSupportPermutation(domain) // Lagrange form of S1, S2, S3 - pk.S1Canonical = make([]fr.Element, nbElmts) - pk.S2Canonical = make([]fr.Element, nbElmts) - pk.S3Canonical = make([]fr.Element, nbElmts) + s1Canonical := make([]fr.Element, nbElmts) + s2Canonical := make([]fr.Element, nbElmts) + s3Canonical := make([]fr.Element, nbElmts) for i := 0; i < nbElmts; i++ { - pk.S1Canonical[i].Set(&evaluationIDSmallDomain[pk.Permutation[i]]) - pk.S2Canonical[i].Set(&evaluationIDSmallDomain[pk.Permutation[nbElmts+i]]) - pk.S3Canonical[i].Set(&evaluationIDSmallDomain[pk.Permutation[2*nbElmts+i]]) + s1Canonical[i].Set(&evaluationIDSmallDomain[pt.S[i]]) + s2Canonical[i].Set(&evaluationIDSmallDomain[pt.S[nbElmts+i]]) + s3Canonical[i].Set(&evaluationIDSmallDomain[pt.S[2*nbElmts+i]]) } - // Canonical form of S1, S2, S3 - pk.Domain[0].FFTInverse(pk.S1Canonical, fft.DIF) - pk.Domain[0].FFTInverse(pk.S2Canonical, fft.DIF) - pk.Domain[0].FFTInverse(pk.S3Canonical, fft.DIF) - fft.BitReverse(pk.S1Canonical) - fft.BitReverse(pk.S2Canonical) - fft.BitReverse(pk.S3Canonical) + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + res[0] = iop.NewPolynomial(&s1Canonical, lagReg) + res[1] = iop.NewPolynomial(&s2Canonical, lagReg) + res[2] = iop.NewPolynomial(&s3Canonical, lagReg) + + return res } -// getIDSmallDomain returns the Lagrange form of ID on the small domain -func getIDSmallDomain(domain *fft.Domain) []fr.Element { +// getSupportPermutation returns the support on which the permutation acts, it is +// || u || u^{2} +func getSupportPermutation(domain *fft.Domain) []fr.Element { res := make([]fr.Element, 3*domain.Cardinality) @@ -356,38 +419,3 @@ func getIDSmallDomain(domain *fft.Domain) []fr.Element { return res } - -// InitKZG inits pk.Vk.KZG using pk.Domain[0] cardinality and provided SRS -// -// This should be used after deserializing a ProvingKey -// as pk.Vk.KZG is NOT serialized -func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { - return pk.Vk.InitKZG(srs) -} - -// InitKZG inits vk.KZG using provided SRS -// -// This should be used after deserializing a VerifyingKey -// as vk.KZG is NOT serialized -// -// Note that this instantiate a new FFT domain using vk.Size -func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { - _srs := srs.(*kzg.SRS) - - if len(_srs.G1) < int(vk.Size) { - return errors.New("kzg srs is too small") - } - vk.KZGSRS = _srs - - return nil -} - -// NbPublicWitness returns the expected public witness size (number of field elements) -func (vk *VerifyingKey) NbPublicWitness() int { - return int(vk.NbPublicVariables) -} - -// VerifyingKey returns pk.Vk -func (pk *ProvingKey) VerifyingKey() interface{} { - return pk.Vk -} diff --git a/backend/plonk/bls24-317/marshal.go b/backend/plonk/bls24-317/marshal.go index 5b9eb8b6f1..6d4d8b0fcd 100644 --- a/backend/plonk/bls24-317/marshal.go +++ b/backend/plonk/bls24-317/marshal.go @@ -21,6 +21,7 @@ import ( "errors" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/iop" "io" ) @@ -108,7 +109,7 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { n += n2 // sanity check len(Permutation) == 3*int(pk.Domain[0].Cardinality) - if len(pk.Permutation) != (3 * int(pk.Domain[0].Cardinality)) { + if len(pk.trace.S) != (3 * int(pk.Domain[0].Cardinality)) { return n, errors.New("invalid permutation size, expected 3*domain cardinality") } @@ -117,16 +118,16 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { // encode the size (nor does it convert from Montgomery to Regular form) // so we explicitly transmit []fr.Element toEncode := []interface{}{ - ([]fr.Element)(pk.Ql), - ([]fr.Element)(pk.Qr), - ([]fr.Element)(pk.Qm), - ([]fr.Element)(pk.Qo), - ([]fr.Element)(pk.CQk), - ([]fr.Element)(pk.LQk), - ([]fr.Element)(pk.S1Canonical), - ([]fr.Element)(pk.S2Canonical), - ([]fr.Element)(pk.S3Canonical), - pk.Permutation, + ([]fr.Element)(pk.trace.Ql.Coefficients()), + ([]fr.Element)(pk.trace.Qr.Coefficients()), + ([]fr.Element)(pk.trace.Qm.Coefficients()), + ([]fr.Element)(pk.trace.Qo.Coefficients()), + ([]fr.Element)(pk.trace.Qk.Coefficients()), + ([]fr.Element)(pk.lQk.Coefficients()), + ([]fr.Element)(pk.trace.S1.Coefficients()), + ([]fr.Element)(pk.trace.S2.Coefficients()), + ([]fr.Element)(pk.trace.S3.Coefficients()), + pk.trace.S, } for _, v := range toEncode { @@ -158,20 +159,22 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { return n, err } - pk.Permutation = make([]int64, 3*pk.Domain[0].Cardinality) + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) dec := curve.NewDecoder(r) + + var ql, qr, qm, qo, qk, lqk, s1, s2, s3 []fr.Element toDecode := []interface{}{ - (*[]fr.Element)(&pk.Ql), - (*[]fr.Element)(&pk.Qr), - (*[]fr.Element)(&pk.Qm), - (*[]fr.Element)(&pk.Qo), - (*[]fr.Element)(&pk.CQk), - (*[]fr.Element)(&pk.LQk), - (*[]fr.Element)(&pk.S1Canonical), - (*[]fr.Element)(&pk.S2Canonical), - (*[]fr.Element)(&pk.S3Canonical), - &pk.Permutation, + &ql, + &qr, + &qm, + &qo, + &qk, + &lqk, + &s1, + &s2, + &s3, + &pk.trace.S, } for _, v := range toDecode { @@ -180,6 +183,19 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { } } + canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} + pk.trace.Ql = iop.NewPolynomial(&ql, canReg) + pk.trace.Qr = iop.NewPolynomial(&qr, canReg) + pk.trace.Qm = iop.NewPolynomial(&qm, canReg) + pk.trace.Qo = iop.NewPolynomial(&qo, canReg) + pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.S1 = iop.NewPolynomial(&s1, canReg) + pk.trace.S2 = iop.NewPolynomial(&s2, canReg) + pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + pk.lQk = iop.NewPolynomial(&lqk, lagReg) + pk.computeLagrangeCosetPolys() return n + dec.BytesRead(), nil diff --git a/backend/plonk/bls24-317/marshal_test.go b/backend/plonk/bls24-317/marshal_test.go index 64618d989e..fa36ad1b3f 100644 --- a/backend/plonk/bls24-317/marshal_test.go +++ b/backend/plonk/bls24-317/marshal_test.go @@ -23,6 +23,7 @@ import ( "bytes" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/fft" + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/iop" gnarkio "github.com/consensys/gnark/io" "io" "math/big" @@ -106,6 +107,7 @@ func roundTripCheckRaw(t *testing.T, from gnarkio.WriterRawTo, reconstructed io. } func (pk *ProvingKey) randomize() { + var vk VerifyingKey vk.randomize() pk.Vk = &vk @@ -113,19 +115,32 @@ func (pk *ProvingKey) randomize() { pk.Domain[1] = *fft.NewDomain(4 * 42) n := int(pk.Domain[0].Cardinality) - pk.Ql = randomScalars(n) - pk.Qr = randomScalars(n) - pk.Qm = randomScalars(n) - pk.Qo = randomScalars(n) - pk.CQk = randomScalars(n) - pk.LQk = randomScalars(n) - pk.S1Canonical = randomScalars(n) - pk.S2Canonical = randomScalars(n) - pk.S3Canonical = randomScalars(n) - - pk.Permutation = make([]int64, 3*pk.Domain[0].Cardinality) - pk.Permutation[0] = -12 - pk.Permutation[len(pk.Permutation)-1] = 8888 + ql := randomScalars(n) + qr := randomScalars(n) + qm := randomScalars(n) + qo := randomScalars(n) + qk := randomScalars(n) + lqk := randomScalars(n) + s1 := randomScalars(n) + s2 := randomScalars(n) + s3 := randomScalars(n) + + canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} + pk.trace.Ql = iop.NewPolynomial(&ql, canReg) + pk.trace.Qr = iop.NewPolynomial(&qr, canReg) + pk.trace.Qm = iop.NewPolynomial(&qm, canReg) + pk.trace.Qo = iop.NewPolynomial(&qo, canReg) + pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.S1 = iop.NewPolynomial(&s1, canReg) + pk.trace.S2 = iop.NewPolynomial(&s2, canReg) + pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) + pk.trace.S[0] = -12 + pk.trace.S[len(pk.trace.S)-1] = 8888 + + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + pk.lQk = iop.NewPolynomial(&lqk, lagReg) pk.computeLagrangeCosetPolys() } diff --git a/backend/plonk/bls24-317/prove.go b/backend/plonk/bls24-317/prove.go index 400232aead..bcfd50a593 100644 --- a/backend/plonk/bls24-317/prove.go +++ b/backend/plonk/bls24-317/prove.go @@ -143,7 +143,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts riop.Clone(), oiop.Clone(), }, - pk.Permutation, + pk.trace.S, beta, gamma, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}, @@ -168,9 +168,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // compute qk in canonical basis, completed with the public inputs - qkCompletedCanonical := make([]fr.Element, pk.Domain[0].Cardinality) + // We copy the coeffs of qk to pk is not mutated + lqkcoef := pk.lQk.Coefficients() + qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) + copy(qkCompletedCanonical, lqkcoef) copy(qkCompletedCanonical, fw[:len(spr.Public)]) - copy(qkCompletedCanonical[len(spr.Public):], pk.LQk[len(spr.Public):]) pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -179,17 +181,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwriop.ToLagrangeCoset(&pk.Domain[1]) bwoiop.ToLagrangeCoset(&pk.Domain[1]) - lagrangeCosetBitReversed := iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse} - - // we don't mutate so no need to clone the coefficients from the proving key. - wqliop := iop.NewPolynomial(&pk.lQl, lagrangeCosetBitReversed) - wqriop := iop.NewPolynomial(&pk.lQr, lagrangeCosetBitReversed) - wqmiop := iop.NewPolynomial(&pk.lQm, lagrangeCosetBitReversed) - wqoiop := iop.NewPolynomial(&pk.lQo, lagrangeCosetBitReversed) - canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} - wqkiop := iop.NewPolynomial(&qkCompletedCanonical, canReg) - wqkiop.ToLagrangeCoset(&pk.Domain[1]) + lcqk := iop.NewPolynomial(&qkCompletedCanonical, canReg) + lcqk.ToLagrangeCoset(&pk.Domain[1]) // storing Id id := make([]fr.Element, pk.Domain[1].Cardinality) @@ -197,12 +191,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts widiop := iop.NewPolynomial(&id, canReg) widiop.ToLagrangeCoset(&pk.Domain[1]) - // permutations in LagrangeCoset: we don't mutate so no need to clone the coefficients from the - // proving key. - ws1 := iop.NewPolynomial(&pk.lS1LagrangeCoset, lagrangeCosetBitReversed) - ws2 := iop.NewPolynomial(&pk.lS2LagrangeCoset, lagrangeCosetBitReversed) - ws3 := iop.NewPolynomial(&pk.lS3LagrangeCoset, lagrangeCosetBitReversed) - // Store z(g*x), without reallocating a slice bwsziop := bwziop.ShallowClone().Shift(1) bwsziop.ToLagrangeCoset(&pk.Domain[1]) @@ -276,27 +264,27 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return c } - testEval, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, + systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, bwliop, bwriop, bwoiop, widiop, - ws1, - ws2, - ws3, + pk.lcS1, + pk.lcS2, + pk.lcS3, bwziop, bwsziop, - wqliop, - wqriop, - wqmiop, - wqoiop, - wqkiop, + pk.lcQl, + pk.lcQr, + pk.lcQm, + pk.lcQo, + lcqk, wloneiop, ) if err != nil { return nil, err } - h, err := iop.DivideByXMinusOne(testEval, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) + h, err := iop.DivideByXMinusOne(systemEvaluation, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) if err != nil { return nil, err } @@ -420,8 +408,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwliop.Coefficients()[:bwliop.BlindedSize()], bwriop.Coefficients()[:bwriop.BlindedSize()], bwoiop.Coefficients()[:bwoiop.BlindedSize()], - pk.S1Canonical, - pk.S2Canonical, + pk.trace.S1.Coefficients(), + pk.trace.S2.Coefficients(), }, []kzg.Digest{ foldedHDigest, @@ -522,13 +510,12 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, var s1, s2 fr.Element chS1 := make(chan struct{}, 1) go func() { - ps1 := iop.NewPolynomial(&pk.S1Canonical, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) - s1 = ps1.Evaluate(zeta) // s1(ζ) + s1 = pk.trace.S1.Evaluate(zeta) // s1(ζ) s1.Mul(&s1, &beta).Add(&s1, &lZeta).Add(&s1, &gamma) // (l(ζ)+β*s1(ζ)+γ) close(chS1) }() - ps2 := iop.NewPolynomial(&pk.S2Canonical, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) - tmp := ps2.Evaluate(zeta) // s2(ζ) + // ps2 := iop.NewPolynomial(&pk.S2Canonical, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) + tmp := pk.trace.S2.Evaluate(zeta) // s2(ζ) tmp.Mul(&tmp, &beta).Add(&tmp, &rZeta).Add(&tmp, &gamma) // (r(ζ)+β*s2(ζ)+γ) <-chS1 s1.Mul(&s1, &tmp).Mul(&s1, &zu).Mul(&s1, &beta) // (l(ζ)+β*s1(β)+γ)*(r(ζ)+β*s2(β)+γ)*β*Z(μζ) @@ -562,6 +549,7 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, linPol := make([]fr.Element, len(blindedZCanonical)) copy(linPol, blindedZCanonical) + s3canonical := pk.trace.S3.Coefficients() utils.Parallelize(len(linPol), func(start, end int) { var t0, t1 fr.Element @@ -570,26 +558,31 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, linPol[i].Mul(&linPol[i], &s2) // -Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) - if i < len(pk.S3Canonical) { + if i < len(s3canonical) { - t0.Mul(&pk.S3Canonical[i], &s1) // (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*β*s3(X) + t0.Mul(&s3canonical[i], &s1) // (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*β*s3(X) linPol[i].Add(&linPol[i], &t0) } linPol[i].Mul(&linPol[i], &alpha) // α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ)) - if i < len(pk.Qm) { + cql := pk.trace.Ql.Coefficients() + cqr := pk.trace.Qr.Coefficients() + cqm := pk.trace.Qm.Coefficients() + cqo := pk.trace.Qo.Coefficients() + cqk := pk.trace.Qk.Coefficients() + if i < len(cqm) { - t1.Mul(&pk.Qm[i], &rl) // linPol = linPol + l(ζ)r(ζ)*Qm(X) - t0.Mul(&pk.Ql[i], &lZeta) + t1.Mul(&cqm[i], &rl) // linPol = linPol + l(ζ)r(ζ)*Qm(X) + t0.Mul(&cql[i], &lZeta) t0.Add(&t0, &t1) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + l(ζ)*Ql(X) - t0.Mul(&pk.Qr[i], &rZeta) + t0.Mul(&cqr[i], &rZeta) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + r(ζ)*Qr(X) - t0.Mul(&pk.Qo[i], &oZeta).Add(&t0, &pk.CQk[i]) + t0.Mul(&cqo[i], &oZeta).Add(&t0, &cqk[i]) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) } diff --git a/backend/plonk/bls24-317/setup.go b/backend/plonk/bls24-317/setup.go index 08c3689967..dacb91b88f 100644 --- a/backend/plonk/bls24-317/setup.go +++ b/backend/plonk/bls24-317/setup.go @@ -18,6 +18,7 @@ package plonk import ( "errors" + "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/iop" @@ -27,44 +28,25 @@ import ( kzgg "github.com/consensys/gnark-crypto/kzg" ) -// ProvingKey stores the data needed to generate a proof: -// * the commitment scheme -// * ql, prepended with as many ones as they are public inputs -// * qr, qm, qo prepended with as many zeroes as there are public inputs. -// * qk, prepended with as many zeroes as public inputs, to be completed by the prover -// with the list of public inputs. -// * sigma_1, sigma_2, sigma_3 in both basis -// * the copy constraint permutation -type ProvingKey struct { - // Verifying Key is embedded into the proving key (needed by Prove) - Vk *VerifyingKey - - // TODO store iop.Polynomial here, not []fr.Element for more "type safety" - - // qr,ql,qm,qo (in canonical basis). - Ql, Qr, Qm, Qo []fr.Element - - // qr,ql,qm,qo (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. - lQl, lQr, lQm, lQo []fr.Element - - // LQk (CQk) qk in Lagrange basis (canonical basis), prepended with as many zeroes as public inputs. - // Storing LQk in Lagrange basis saves a fft... - CQk, LQk []fr.Element - - // Domains used for the FFTs. - // Domain[0] = small Domain - // Domain[1] = big Domain - Domain [2]fft.Domain - // Domain[0], Domain[1] fft.Domain - - // Permutation polynomials - S1Canonical, S2Canonical, S3Canonical []fr.Element - - // in lagrange coset basis --> these are not serialized, but computed from S1Canonical, S2Canonical, S3Canonical once. - lS1LagrangeCoset, lS2LagrangeCoset, lS3LagrangeCoset []fr.Element - - // position -> permuted position (position in [0,3*sizeSystem-1]) - Permutation []int64 +// Trace stores a plonk trace as columns +type Trace struct { + + // Constants describing a plonk circuit. The first entries + // of LQk (whose index correspond to the public inputs) are set to 0, and are to be + // completed by the prover. At those indices i (so from 0 to nb_public_variables), LQl[i]=-1 + // so the first nb_public_variables constraints look like this: + // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. + Ql, Qr, Qm, Qo, Qk *iop.Polynomial + + // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. + // The set of interpolation is of size N, so to represent the permutation S we let S acts on the + // set A=(, u*, u^{2}*) of size 3*N, where u is outside (its use is to shift the set ). + // We obtain a permutation of A, A'. We split A' in 3 (A'_{1}, A'_{2}, A'_{3}), and S1, S2, S3 are + // respectively the interpolation of A'_{1}, A'_{2}, A'_{3} on . + S1, S2, S3 *iop.Polynomial + + // S full permutation, i -> S[i] + S []int64 } // VerifyingKey stores the data needed to verify a proof: @@ -73,6 +55,7 @@ type ProvingKey struct { // * Commitments of qr, qm, qo, qk prepended with as many zeroes as there are public inputs // * Commitments to S1, S2, S3 type VerifyingKey struct { + // Size circuit Size uint64 SizeInv fr.Element @@ -93,115 +76,235 @@ type VerifyingKey struct { Ql, Qr, Qm, Qo, Qk kzg.Digest } -// Setup sets proving and verifying keys +// ProvingKey stores the data needed to generate a proof: +// * the commitment scheme +// * ql, prepended with as many ones as they are public inputs +// * qr, qm, qo prepended with as many zeroes as there are public inputs. +// * qk, prepended with as many zeroes as public inputs, to be completed by the prover +// with the list of public inputs. +// * sigma_1, sigma_2, sigma_3 in both basis +// * the copy constraint permutation +type ProvingKey struct { + + // stores ql, qr, qm, qo, qk (-> to be completed by the prover) + // and s1, s2, s3. They are set in canonical basis before generating the proof, they will be used + // for computing the opening proofs (hence the canonical form). The canonical version + // of qk incompleted is used in the linearisation polynomial. + // The polynomials in trace are in canonical basis. + trace Trace + + // Verifying Key is embedded into the proving key (needed by Prove) + Vk *VerifyingKey + + // qr,ql,qm,qo in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. + lcQl, lcQr, lcQm, lcQo *iop.Polynomial + + // LQk qk in Lagrange form -> to be completed by the prover. After being completed, + lQk *iop.Polynomial + + // Domains used for the FFTs. + // Domain[0] = small Domain + // Domain[1] = big Domain + Domain [2]fft.Domain + + // in lagrange coset basis --> these are not serialized, but computed from S1Canonical, S2Canonical, S3Canonical once. + lcS1, lcS2, lcS3 *iop.Polynomial +} + func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) { + var pk ProvingKey var vk VerifyingKey - - // The verifying key shares data with the proving key pk.Vk = &vk + // nbConstraints := len(spr.Constraints) - nbConstraints := len(spr.Constraints) + // step 0: set the fft domains + pk.initDomains(spr) - // fft domains - sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints - pk.Domain[0] = *fft.NewDomain(sizeSystem) + // step 1: set the verifying key pk.Vk.CosetShift.Set(&pk.Domain[0].FrMultiplicativeGen) - - // h, the quotient polynomial is of degree 3(n+1)+2, so it's in a 3(n+2) dim vector space, - // the domain is the next power of 2 superior to 3(n+2). 4*domainNum is enough in all cases - // except when n<6. - if sizeSystem < 6 { - pk.Domain[1] = *fft.NewDomain(8 * sizeSystem) - } else { - pk.Domain[1] = *fft.NewDomain(4 * sizeSystem) - } - vk.Size = pk.Domain[0].Cardinality vk.SizeInv.SetUint64(vk.Size).Inverse(&vk.SizeInv) vk.Generator.Set(&pk.Domain[0].Generator) vk.NbPublicVariables = uint64(len(spr.Public)) - if err := pk.InitKZG(srs); err != nil { return nil, nil, err } - // public polynomials corresponding to constraints: [ placholders | constraints | assertions ] - pk.Ql = make([]fr.Element, pk.Domain[0].Cardinality) - pk.Qr = make([]fr.Element, pk.Domain[0].Cardinality) - pk.Qm = make([]fr.Element, pk.Domain[0].Cardinality) - pk.Qo = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQk = make([]fr.Element, pk.Domain[0].Cardinality) - pk.LQk = make([]fr.Element, pk.Domain[0].Cardinality) + // step 2: ql, qr, qm, qo, qk in Lagrange Basis + BuildTrace(spr, &pk.trace) + + // step 3: build the permutation and build the polynomials S1, S2, S3 to encode the permutation. + // Note: at this stage, the permutation takes in account the placeholders + nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) + buildPermutation(spr, &pk.trace, nbVariables) + s := computePermutationPolynomials(&pk.trace, &pk.Domain[0]) + pk.trace.S1 = s[0] + pk.trace.S2 = s[1] + pk.trace.S3 = s[2] + + // step 4: commit to s1, s2, s3, ql, qr, qm, qo, and (the incomplete version of) qk. + // All the above polynomials are expressed in canonical basis afterwards. This is why + // we save lqk before, because the prover needs to complete it in Lagrange form, and + // then express it on the Lagrange coset basis. + pk.lQk = pk.trace.Qk.Clone() // it will be completed by the prover, and the evaluated on the coset + err := commitTrace(&pk.trace, &pk) + if err != nil { + return nil, nil, err + } + + // step 5: evaluate ql, qr, qm, qo, s1, s2, s3 on LagrangeCoset (NOT qk) + // we clone them, because the canonical versions are going to be used in + // the opening proof + pk.computeLagrangeCosetPolys() + + return &pk, &vk, nil +} + +// computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset +// basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. +func (pk *ProvingKey) computeLagrangeCosetPolys() { + pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQo = pk.trace.Qo.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcS1 = pk.trace.S1.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcS2 = pk.trace.S2.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcS3 = pk.trace.S3.Clone().ToLagrangeCoset(&pk.Domain[1]) +} + +// NbPublicWitness returns the expected public witness size (number of field elements) +func (vk *VerifyingKey) NbPublicWitness() int { + return int(vk.NbPublicVariables) +} + +// VerifyingKey returns pk.Vk +func (pk *ProvingKey) VerifyingKey() interface{} { + return pk.Vk +} + +// InitKZG inits pk.Vk.KZG using pk.Domain[0] cardinality and provided SRS +// +// This should be used after deserializing a ProvingKey +// as pk.Vk.KZG is NOT serialized +func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { + return pk.Vk.InitKZG(srs) +} + +// InitKZG inits vk.KZG using provided SRS +// +// This should be used after deserializing a VerifyingKey +// as vk.KZG is NOT serialized +// +// Note that this instantiate a new FFT domain using vk.Size +func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { + _srs := srs.(*kzg.SRS) + + if len(_srs.G1) < int(vk.Size) { + return errors.New("kzg srs is too small") + } + vk.KZGSRS = _srs + + return nil +} + +// BuildTrace fills the constatn columns ql, qr, qm, qo, qk from the sparser1cs. +// Size is the size of the system that is nb_constraints+nb_public_variables +func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { + + nbConstraints := len(spr.Constraints) + sizeSystem := uint64(nbConstraints + len(spr.Public)) + size := ecc.NextPowerOfTwo(uint64(sizeSystem)) + + ql := make([]fr.Element, size) + qr := make([]fr.Element, size) + qm := make([]fr.Element, size) + qo := make([]fr.Element, size) + qk := make([]fr.Element, size) for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistant - pk.Ql[i].SetOne().Neg(&pk.Ql[i]) - pk.Qr[i].SetZero() - pk.Qm[i].SetZero() - pk.Qo[i].SetZero() - pk.CQk[i].SetZero() - pk.LQk[i].SetZero() // → to be completed by the prover + ql[i].SetOne().Neg(&ql[i]) + qr[i].SetZero() + qm[i].SetZero() + qo[i].SetZero() + qk[i].SetZero() // → to be completed by the prover } offset := len(spr.Public) for i := 0; i < nbConstraints; i++ { // constraints - pk.Ql[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) - pk.Qr[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) - pk.Qm[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). - Mul(&pk.Qm[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) - pk.Qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) - pk.CQk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) - pk.LQk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) + ql[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) + qr[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) + qm[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). + Mul(&qm[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) + qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) + qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } - pk.Domain[0].FFTInverse(pk.Ql, fft.DIF) - pk.Domain[0].FFTInverse(pk.Qr, fft.DIF) - pk.Domain[0].FFTInverse(pk.Qm, fft.DIF) - pk.Domain[0].FFTInverse(pk.Qo, fft.DIF) - pk.Domain[0].FFTInverse(pk.CQk, fft.DIF) - fft.BitReverse(pk.Ql) - fft.BitReverse(pk.Qr) - fft.BitReverse(pk.Qm) - fft.BitReverse(pk.Qo) - fft.BitReverse(pk.CQk) + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} - // build permutation. Note: at this stage, the permutation takes in account the placeholders - buildPermutation(spr, &pk) + pt.Ql = iop.NewPolynomial(&ql, lagReg) + pt.Qr = iop.NewPolynomial(&qr, lagReg) + pt.Qm = iop.NewPolynomial(&qm, lagReg) + pt.Qo = iop.NewPolynomial(&qo, lagReg) + pt.Qk = iop.NewPolynomial(&qk, lagReg) - // set s1, s2, s3 - ccomputePermutationPolynomials(&pk) +} - // compute the lagrange coset basis versions (not serialized) - pk.computeLagrangeCosetPolys() +// commitTrace commits to every polynomials in the trace, and put +// the commitments int the verifying key. +func commitTrace(trace *Trace, pk *ProvingKey) error { + + trace.Ql.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qr.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qm.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qo.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qk.ToCanonical(&pk.Domain[0]).ToRegular() // -> qk is not complete + trace.S1.ToCanonical(&pk.Domain[0]).ToRegular() + trace.S2.ToCanonical(&pk.Domain[0]).ToRegular() + trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() - // Commit to the polynomials to set up the verifying key var err error - if vk.Ql, err = kzg.Commit(pk.Ql, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qr, err = kzg.Commit(pk.Qr, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qr, err = kzg.Commit(pk.trace.Qr.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qm, err = kzg.Commit(pk.Qm, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qm, err = kzg.Commit(pk.trace.Qm.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qo, err = kzg.Commit(pk.Qo, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qo, err = kzg.Commit(pk.trace.Qo.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qk, err = kzg.Commit(pk.CQk, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.S[0], err = kzg.Commit(pk.S1Canonical, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.S[1], err = kzg.Commit(pk.S2Canonical, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.S[1], err = kzg.Commit(pk.trace.S2.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.S[2], err = kzg.Commit(pk.S3Canonical, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.S[2], err = kzg.Commit(pk.trace.S3.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } + return nil +} - return &pk, &vk, nil +func (pk *ProvingKey) initDomains(spr *cs.SparseR1CS) { + + nbConstraints := len(spr.Constraints) + sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints + pk.Domain[0] = *fft.NewDomain(sizeSystem) + + // h, the quotient polynomial is of degree 3(n+1)+2, so it's in a 3(n+2) dim vector space, + // the domain is the next power of 2 superior to 3(n+2). 4*domainNum is enough in all cases + // except when n<6. + if sizeSystem < 6 { + pk.Domain[1] = *fft.NewDomain(8 * sizeSystem) + } else { + pk.Domain[1] = *fft.NewDomain(4 * sizeSystem) + } } @@ -217,19 +320,20 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // The permutation is encoded as a slice s of size 3*size(l), where the // i-th entry of l∥r∥o is sent to the s[i]-th entry, so it acts on a tab // like this: for i in tab: tab[i] = tab[permutation[i]] -func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { +func buildPermutation(spr *cs.SparseR1CS, pt *Trace, nbVariables int) { - nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) - sizeSolution := int(pk.Domain[0].Cardinality) + // nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) + sizeSolution := len(pt.Ql.Coefficients()) + sizePermutation := 3 * sizeSolution // init permutation - pk.Permutation = make([]int64, 3*sizeSolution) - for i := 0; i < len(pk.Permutation); i++ { - pk.Permutation[i] = -1 + permutation := make([]int64, sizePermutation) + for i := 0; i < len(permutation); i++ { + permutation[i] = -1 } // init LRO position -> variable_ID - lro := make([]int, 3*sizeSolution) // position -> variable_ID + lro := make([]int, sizePermutation) // position -> variable_ID for i := 0; i < len(spr.Public); i++ { lro[i] = i // IDs of LRO associated to placeholders (only L needs to be taken care of) } @@ -252,95 +356,54 @@ func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { if cycle[lro[i]] != -1 { // if != -1, it means we already encountered this value // so we need to set the corresponding permutation index. - pk.Permutation[i] = cycle[lro[i]] + permutation[i] = cycle[lro[i]] } cycle[lro[i]] = int64(i) } // complete the Permutation by filling the first IDs encountered - for i := 0; i < len(pk.Permutation); i++ { - if pk.Permutation[i] == -1 { - pk.Permutation[i] = cycle[lro[i]] + for i := 0; i < sizePermutation; i++ { + if permutation[i] == -1 { + permutation[i] = cycle[lro[i]] } } -} -func (pk *ProvingKey) computeLagrangeCosetPolys() { - canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} - wqliop := iop.NewPolynomial(clone(pk.Ql, pk.Domain[1].Cardinality), canReg) - wqriop := iop.NewPolynomial(clone(pk.Qr, pk.Domain[1].Cardinality), canReg) - wqmiop := iop.NewPolynomial(clone(pk.Qm, pk.Domain[1].Cardinality), canReg) - wqoiop := iop.NewPolynomial(clone(pk.Qo, pk.Domain[1].Cardinality), canReg) - - ws1 := iop.NewPolynomial(clone(pk.S1Canonical, pk.Domain[1].Cardinality), canReg) - ws2 := iop.NewPolynomial(clone(pk.S2Canonical, pk.Domain[1].Cardinality), canReg) - ws3 := iop.NewPolynomial(clone(pk.S3Canonical, pk.Domain[1].Cardinality), canReg) - - wqliop.ToLagrangeCoset(&pk.Domain[1]) - wqriop.ToLagrangeCoset(&pk.Domain[1]) - wqmiop.ToLagrangeCoset(&pk.Domain[1]) - wqoiop.ToLagrangeCoset(&pk.Domain[1]) - - ws1.ToLagrangeCoset(&pk.Domain[1]) - ws2.ToLagrangeCoset(&pk.Domain[1]) - ws3.ToLagrangeCoset(&pk.Domain[1]) - - pk.lQl = wqliop.Coefficients() - pk.lQr = wqriop.Coefficients() - pk.lQm = wqmiop.Coefficients() - pk.lQo = wqoiop.Coefficients() - - pk.lS1LagrangeCoset = ws1.Coefficients() - pk.lS2LagrangeCoset = ws2.Coefficients() - pk.lS3LagrangeCoset = ws3.Coefficients() + pt.S = permutation } -func clone(input []fr.Element, capacity uint64) *[]fr.Element { - res := make([]fr.Element, len(input), capacity) - copy(res, input) - return &res -} +// computePermutationPolynomials computes the LDE (Lagrange basis) of the permutation. +// We let the permutation act on || u || u^{2}, split the result in 3 parts, +// and interpolate each of the 3 parts on . +func computePermutationPolynomials(pt *Trace, domain *fft.Domain) [3]*iop.Polynomial { -// ccomputePermutationPolynomials computes the LDE (Lagrange basis) of the permutations -// s1, s2, s3. -// -// 1 z .. z**n-1 | u uz .. u*z**n-1 | u**2 u**2*z .. u**2*z**n-1 | -// -// | -// | Permutation -// -// s11 s12 .. s1n s21 s22 .. s2n s31 s32 .. s3n v -// \---------------/ \--------------------/ \------------------------/ -// -// s1 (LDE) s2 (LDE) s3 (LDE) -func ccomputePermutationPolynomials(pk *ProvingKey) { + nbElmts := int(domain.Cardinality) - nbElmts := int(pk.Domain[0].Cardinality) + var res [3]*iop.Polynomial // Lagrange form of ID - evaluationIDSmallDomain := getIDSmallDomain(&pk.Domain[0]) + evaluationIDSmallDomain := getSupportPermutation(domain) // Lagrange form of S1, S2, S3 - pk.S1Canonical = make([]fr.Element, nbElmts) - pk.S2Canonical = make([]fr.Element, nbElmts) - pk.S3Canonical = make([]fr.Element, nbElmts) + s1Canonical := make([]fr.Element, nbElmts) + s2Canonical := make([]fr.Element, nbElmts) + s3Canonical := make([]fr.Element, nbElmts) for i := 0; i < nbElmts; i++ { - pk.S1Canonical[i].Set(&evaluationIDSmallDomain[pk.Permutation[i]]) - pk.S2Canonical[i].Set(&evaluationIDSmallDomain[pk.Permutation[nbElmts+i]]) - pk.S3Canonical[i].Set(&evaluationIDSmallDomain[pk.Permutation[2*nbElmts+i]]) + s1Canonical[i].Set(&evaluationIDSmallDomain[pt.S[i]]) + s2Canonical[i].Set(&evaluationIDSmallDomain[pt.S[nbElmts+i]]) + s3Canonical[i].Set(&evaluationIDSmallDomain[pt.S[2*nbElmts+i]]) } - // Canonical form of S1, S2, S3 - pk.Domain[0].FFTInverse(pk.S1Canonical, fft.DIF) - pk.Domain[0].FFTInverse(pk.S2Canonical, fft.DIF) - pk.Domain[0].FFTInverse(pk.S3Canonical, fft.DIF) - fft.BitReverse(pk.S1Canonical) - fft.BitReverse(pk.S2Canonical) - fft.BitReverse(pk.S3Canonical) + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + res[0] = iop.NewPolynomial(&s1Canonical, lagReg) + res[1] = iop.NewPolynomial(&s2Canonical, lagReg) + res[2] = iop.NewPolynomial(&s3Canonical, lagReg) + + return res } -// getIDSmallDomain returns the Lagrange form of ID on the small domain -func getIDSmallDomain(domain *fft.Domain) []fr.Element { +// getSupportPermutation returns the support on which the permutation acts, it is +// || u || u^{2} +func getSupportPermutation(domain *fft.Domain) []fr.Element { res := make([]fr.Element, 3*domain.Cardinality) @@ -356,38 +419,3 @@ func getIDSmallDomain(domain *fft.Domain) []fr.Element { return res } - -// InitKZG inits pk.Vk.KZG using pk.Domain[0] cardinality and provided SRS -// -// This should be used after deserializing a ProvingKey -// as pk.Vk.KZG is NOT serialized -func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { - return pk.Vk.InitKZG(srs) -} - -// InitKZG inits vk.KZG using provided SRS -// -// This should be used after deserializing a VerifyingKey -// as vk.KZG is NOT serialized -// -// Note that this instantiate a new FFT domain using vk.Size -func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { - _srs := srs.(*kzg.SRS) - - if len(_srs.G1) < int(vk.Size) { - return errors.New("kzg srs is too small") - } - vk.KZGSRS = _srs - - return nil -} - -// NbPublicWitness returns the expected public witness size (number of field elements) -func (vk *VerifyingKey) NbPublicWitness() int { - return int(vk.NbPublicVariables) -} - -// VerifyingKey returns pk.Vk -func (pk *ProvingKey) VerifyingKey() interface{} { - return pk.Vk -} diff --git a/backend/plonk/bn254/marshal.go b/backend/plonk/bn254/marshal.go index 400e50e808..762065c319 100644 --- a/backend/plonk/bn254/marshal.go +++ b/backend/plonk/bn254/marshal.go @@ -21,6 +21,7 @@ import ( "errors" "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/iop" "io" ) @@ -108,7 +109,7 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { n += n2 // sanity check len(Permutation) == 3*int(pk.Domain[0].Cardinality) - if len(pk.Permutation) != (3 * int(pk.Domain[0].Cardinality)) { + if len(pk.trace.S) != (3 * int(pk.Domain[0].Cardinality)) { return n, errors.New("invalid permutation size, expected 3*domain cardinality") } @@ -117,16 +118,16 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { // encode the size (nor does it convert from Montgomery to Regular form) // so we explicitly transmit []fr.Element toEncode := []interface{}{ - ([]fr.Element)(pk.Ql), - ([]fr.Element)(pk.Qr), - ([]fr.Element)(pk.Qm), - ([]fr.Element)(pk.Qo), - ([]fr.Element)(pk.CQk), - ([]fr.Element)(pk.LQk), - ([]fr.Element)(pk.S1Canonical), - ([]fr.Element)(pk.S2Canonical), - ([]fr.Element)(pk.S3Canonical), - pk.Permutation, + ([]fr.Element)(pk.trace.Ql.Coefficients()), + ([]fr.Element)(pk.trace.Qr.Coefficients()), + ([]fr.Element)(pk.trace.Qm.Coefficients()), + ([]fr.Element)(pk.trace.Qo.Coefficients()), + ([]fr.Element)(pk.trace.Qk.Coefficients()), + ([]fr.Element)(pk.lQk.Coefficients()), + ([]fr.Element)(pk.trace.S1.Coefficients()), + ([]fr.Element)(pk.trace.S2.Coefficients()), + ([]fr.Element)(pk.trace.S3.Coefficients()), + pk.trace.S, } for _, v := range toEncode { @@ -158,20 +159,22 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { return n, err } - pk.Permutation = make([]int64, 3*pk.Domain[0].Cardinality) + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) dec := curve.NewDecoder(r) + + var ql, qr, qm, qo, qk, lqk, s1, s2, s3 []fr.Element toDecode := []interface{}{ - (*[]fr.Element)(&pk.Ql), - (*[]fr.Element)(&pk.Qr), - (*[]fr.Element)(&pk.Qm), - (*[]fr.Element)(&pk.Qo), - (*[]fr.Element)(&pk.CQk), - (*[]fr.Element)(&pk.LQk), - (*[]fr.Element)(&pk.S1Canonical), - (*[]fr.Element)(&pk.S2Canonical), - (*[]fr.Element)(&pk.S3Canonical), - &pk.Permutation, + &ql, + &qr, + &qm, + &qo, + &qk, + &lqk, + &s1, + &s2, + &s3, + &pk.trace.S, } for _, v := range toDecode { @@ -180,6 +183,19 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { } } + canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} + pk.trace.Ql = iop.NewPolynomial(&ql, canReg) + pk.trace.Qr = iop.NewPolynomial(&qr, canReg) + pk.trace.Qm = iop.NewPolynomial(&qm, canReg) + pk.trace.Qo = iop.NewPolynomial(&qo, canReg) + pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.S1 = iop.NewPolynomial(&s1, canReg) + pk.trace.S2 = iop.NewPolynomial(&s2, canReg) + pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + pk.lQk = iop.NewPolynomial(&lqk, lagReg) + pk.computeLagrangeCosetPolys() return n + dec.BytesRead(), nil diff --git a/backend/plonk/bn254/marshal_test.go b/backend/plonk/bn254/marshal_test.go index 8840ad242e..4feae1aad4 100644 --- a/backend/plonk/bn254/marshal_test.go +++ b/backend/plonk/bn254/marshal_test.go @@ -23,6 +23,7 @@ import ( "bytes" "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/iop" gnarkio "github.com/consensys/gnark/io" "io" "math/big" @@ -106,6 +107,7 @@ func roundTripCheckRaw(t *testing.T, from gnarkio.WriterRawTo, reconstructed io. } func (pk *ProvingKey) randomize() { + var vk VerifyingKey vk.randomize() pk.Vk = &vk @@ -113,19 +115,32 @@ func (pk *ProvingKey) randomize() { pk.Domain[1] = *fft.NewDomain(4 * 42) n := int(pk.Domain[0].Cardinality) - pk.Ql = randomScalars(n) - pk.Qr = randomScalars(n) - pk.Qm = randomScalars(n) - pk.Qo = randomScalars(n) - pk.CQk = randomScalars(n) - pk.LQk = randomScalars(n) - pk.S1Canonical = randomScalars(n) - pk.S2Canonical = randomScalars(n) - pk.S3Canonical = randomScalars(n) - - pk.Permutation = make([]int64, 3*pk.Domain[0].Cardinality) - pk.Permutation[0] = -12 - pk.Permutation[len(pk.Permutation)-1] = 8888 + ql := randomScalars(n) + qr := randomScalars(n) + qm := randomScalars(n) + qo := randomScalars(n) + qk := randomScalars(n) + lqk := randomScalars(n) + s1 := randomScalars(n) + s2 := randomScalars(n) + s3 := randomScalars(n) + + canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} + pk.trace.Ql = iop.NewPolynomial(&ql, canReg) + pk.trace.Qr = iop.NewPolynomial(&qr, canReg) + pk.trace.Qm = iop.NewPolynomial(&qm, canReg) + pk.trace.Qo = iop.NewPolynomial(&qo, canReg) + pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.S1 = iop.NewPolynomial(&s1, canReg) + pk.trace.S2 = iop.NewPolynomial(&s2, canReg) + pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) + pk.trace.S[0] = -12 + pk.trace.S[len(pk.trace.S)-1] = 8888 + + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + pk.lQk = iop.NewPolynomial(&lqk, lagReg) pk.computeLagrangeCosetPolys() } diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index d6e483487c..0e3620ffd8 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -143,7 +143,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts riop.Clone(), oiop.Clone(), }, - pk.Permutation, + pk.trace.S, beta, gamma, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}, @@ -168,9 +168,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // compute qk in canonical basis, completed with the public inputs - qkCompletedCanonical := make([]fr.Element, pk.Domain[0].Cardinality) + // We copy the coeffs of qk to pk is not mutated + lqkcoef := pk.lQk.Coefficients() + qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) + copy(qkCompletedCanonical, lqkcoef) copy(qkCompletedCanonical, fw[:len(spr.Public)]) - copy(qkCompletedCanonical[len(spr.Public):], pk.LQk[len(spr.Public):]) pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -179,17 +181,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwriop.ToLagrangeCoset(&pk.Domain[1]) bwoiop.ToLagrangeCoset(&pk.Domain[1]) - lagrangeCosetBitReversed := iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse} - - // we don't mutate so no need to clone the coefficients from the proving key. - wqliop := iop.NewPolynomial(&pk.lQl, lagrangeCosetBitReversed) - wqriop := iop.NewPolynomial(&pk.lQr, lagrangeCosetBitReversed) - wqmiop := iop.NewPolynomial(&pk.lQm, lagrangeCosetBitReversed) - wqoiop := iop.NewPolynomial(&pk.lQo, lagrangeCosetBitReversed) - canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} - wqkiop := iop.NewPolynomial(&qkCompletedCanonical, canReg) - wqkiop.ToLagrangeCoset(&pk.Domain[1]) + lcqk := iop.NewPolynomial(&qkCompletedCanonical, canReg) + lcqk.ToLagrangeCoset(&pk.Domain[1]) // storing Id id := make([]fr.Element, pk.Domain[1].Cardinality) @@ -197,12 +191,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts widiop := iop.NewPolynomial(&id, canReg) widiop.ToLagrangeCoset(&pk.Domain[1]) - // permutations in LagrangeCoset: we don't mutate so no need to clone the coefficients from the - // proving key. - ws1 := iop.NewPolynomial(&pk.lS1LagrangeCoset, lagrangeCosetBitReversed) - ws2 := iop.NewPolynomial(&pk.lS2LagrangeCoset, lagrangeCosetBitReversed) - ws3 := iop.NewPolynomial(&pk.lS3LagrangeCoset, lagrangeCosetBitReversed) - // Store z(g*x), without reallocating a slice bwsziop := bwziop.ShallowClone().Shift(1) bwsziop.ToLagrangeCoset(&pk.Domain[1]) @@ -276,27 +264,27 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return c } - testEval, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, + systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, bwliop, bwriop, bwoiop, widiop, - ws1, - ws2, - ws3, + pk.lcS1, + pk.lcS2, + pk.lcS3, bwziop, bwsziop, - wqliop, - wqriop, - wqmiop, - wqoiop, - wqkiop, + pk.lcQl, + pk.lcQr, + pk.lcQm, + pk.lcQo, + lcqk, wloneiop, ) if err != nil { return nil, err } - h, err := iop.DivideByXMinusOne(testEval, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) + h, err := iop.DivideByXMinusOne(systemEvaluation, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) if err != nil { return nil, err } @@ -420,8 +408,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwliop.Coefficients()[:bwliop.BlindedSize()], bwriop.Coefficients()[:bwriop.BlindedSize()], bwoiop.Coefficients()[:bwoiop.BlindedSize()], - pk.S1Canonical, - pk.S2Canonical, + pk.trace.S1.Coefficients(), + pk.trace.S2.Coefficients(), }, []kzg.Digest{ foldedHDigest, @@ -522,13 +510,12 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, var s1, s2 fr.Element chS1 := make(chan struct{}, 1) go func() { - ps1 := iop.NewPolynomial(&pk.S1Canonical, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) - s1 = ps1.Evaluate(zeta) // s1(ζ) + s1 = pk.trace.S1.Evaluate(zeta) // s1(ζ) s1.Mul(&s1, &beta).Add(&s1, &lZeta).Add(&s1, &gamma) // (l(ζ)+β*s1(ζ)+γ) close(chS1) }() - ps2 := iop.NewPolynomial(&pk.S2Canonical, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) - tmp := ps2.Evaluate(zeta) // s2(ζ) + // ps2 := iop.NewPolynomial(&pk.S2Canonical, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) + tmp := pk.trace.S2.Evaluate(zeta) // s2(ζ) tmp.Mul(&tmp, &beta).Add(&tmp, &rZeta).Add(&tmp, &gamma) // (r(ζ)+β*s2(ζ)+γ) <-chS1 s1.Mul(&s1, &tmp).Mul(&s1, &zu).Mul(&s1, &beta) // (l(ζ)+β*s1(β)+γ)*(r(ζ)+β*s2(β)+γ)*β*Z(μζ) @@ -562,6 +549,7 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, linPol := make([]fr.Element, len(blindedZCanonical)) copy(linPol, blindedZCanonical) + s3canonical := pk.trace.S3.Coefficients() utils.Parallelize(len(linPol), func(start, end int) { var t0, t1 fr.Element @@ -570,26 +558,31 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, linPol[i].Mul(&linPol[i], &s2) // -Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) - if i < len(pk.S3Canonical) { + if i < len(s3canonical) { - t0.Mul(&pk.S3Canonical[i], &s1) // (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*β*s3(X) + t0.Mul(&s3canonical[i], &s1) // (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*β*s3(X) linPol[i].Add(&linPol[i], &t0) } linPol[i].Mul(&linPol[i], &alpha) // α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ)) - if i < len(pk.Qm) { + cql := pk.trace.Ql.Coefficients() + cqr := pk.trace.Qr.Coefficients() + cqm := pk.trace.Qm.Coefficients() + cqo := pk.trace.Qo.Coefficients() + cqk := pk.trace.Qk.Coefficients() + if i < len(cqm) { - t1.Mul(&pk.Qm[i], &rl) // linPol = linPol + l(ζ)r(ζ)*Qm(X) - t0.Mul(&pk.Ql[i], &lZeta) + t1.Mul(&cqm[i], &rl) // linPol = linPol + l(ζ)r(ζ)*Qm(X) + t0.Mul(&cql[i], &lZeta) t0.Add(&t0, &t1) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + l(ζ)*Ql(X) - t0.Mul(&pk.Qr[i], &rZeta) + t0.Mul(&cqr[i], &rZeta) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + r(ζ)*Qr(X) - t0.Mul(&pk.Qo[i], &oZeta).Add(&t0, &pk.CQk[i]) + t0.Mul(&cqo[i], &oZeta).Add(&t0, &cqk[i]) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) } diff --git a/backend/plonk/bn254/setup.go b/backend/plonk/bn254/setup.go index 1cefa3c469..815de53b7d 100644 --- a/backend/plonk/bn254/setup.go +++ b/backend/plonk/bn254/setup.go @@ -18,6 +18,7 @@ package plonk import ( "errors" + "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" "github.com/consensys/gnark-crypto/ecc/bn254/fr/iop" @@ -27,44 +28,25 @@ import ( kzgg "github.com/consensys/gnark-crypto/kzg" ) -// ProvingKey stores the data needed to generate a proof: -// * the commitment scheme -// * ql, prepended with as many ones as they are public inputs -// * qr, qm, qo prepended with as many zeroes as there are public inputs. -// * qk, prepended with as many zeroes as public inputs, to be completed by the prover -// with the list of public inputs. -// * sigma_1, sigma_2, sigma_3 in both basis -// * the copy constraint permutation -type ProvingKey struct { - // Verifying Key is embedded into the proving key (needed by Prove) - Vk *VerifyingKey - - // TODO store iop.Polynomial here, not []fr.Element for more "type safety" - - // qr,ql,qm,qo (in canonical basis). - Ql, Qr, Qm, Qo []fr.Element - - // qr,ql,qm,qo (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. - lQl, lQr, lQm, lQo []fr.Element - - // LQk (CQk) qk in Lagrange basis (canonical basis), prepended with as many zeroes as public inputs. - // Storing LQk in Lagrange basis saves a fft... - CQk, LQk []fr.Element - - // Domains used for the FFTs. - // Domain[0] = small Domain - // Domain[1] = big Domain - Domain [2]fft.Domain - // Domain[0], Domain[1] fft.Domain - - // Permutation polynomials - S1Canonical, S2Canonical, S3Canonical []fr.Element - - // in lagrange coset basis --> these are not serialized, but computed from S1Canonical, S2Canonical, S3Canonical once. - lS1LagrangeCoset, lS2LagrangeCoset, lS3LagrangeCoset []fr.Element - - // position -> permuted position (position in [0,3*sizeSystem-1]) - Permutation []int64 +// Trace stores a plonk trace as columns +type Trace struct { + + // Constants describing a plonk circuit. The first entries + // of LQk (whose index correspond to the public inputs) are set to 0, and are to be + // completed by the prover. At those indices i (so from 0 to nb_public_variables), LQl[i]=-1 + // so the first nb_public_variables constraints look like this: + // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. + Ql, Qr, Qm, Qo, Qk *iop.Polynomial + + // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. + // The set of interpolation is of size N, so to represent the permutation S we let S acts on the + // set A=(, u*, u^{2}*) of size 3*N, where u is outside (its use is to shift the set ). + // We obtain a permutation of A, A'. We split A' in 3 (A'_{1}, A'_{2}, A'_{3}), and S1, S2, S3 are + // respectively the interpolation of A'_{1}, A'_{2}, A'_{3} on . + S1, S2, S3 *iop.Polynomial + + // S full permutation, i -> S[i] + S []int64 } // VerifyingKey stores the data needed to verify a proof: @@ -73,6 +55,7 @@ type ProvingKey struct { // * Commitments of qr, qm, qo, qk prepended with as many zeroes as there are public inputs // * Commitments to S1, S2, S3 type VerifyingKey struct { + // Size circuit Size uint64 SizeInv fr.Element @@ -93,115 +76,235 @@ type VerifyingKey struct { Ql, Qr, Qm, Qo, Qk kzg.Digest } -// Setup sets proving and verifying keys +// ProvingKey stores the data needed to generate a proof: +// * the commitment scheme +// * ql, prepended with as many ones as they are public inputs +// * qr, qm, qo prepended with as many zeroes as there are public inputs. +// * qk, prepended with as many zeroes as public inputs, to be completed by the prover +// with the list of public inputs. +// * sigma_1, sigma_2, sigma_3 in both basis +// * the copy constraint permutation +type ProvingKey struct { + + // stores ql, qr, qm, qo, qk (-> to be completed by the prover) + // and s1, s2, s3. They are set in canonical basis before generating the proof, they will be used + // for computing the opening proofs (hence the canonical form). The canonical version + // of qk incompleted is used in the linearisation polynomial. + // The polynomials in trace are in canonical basis. + trace Trace + + // Verifying Key is embedded into the proving key (needed by Prove) + Vk *VerifyingKey + + // qr,ql,qm,qo in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. + lcQl, lcQr, lcQm, lcQo *iop.Polynomial + + // LQk qk in Lagrange form -> to be completed by the prover. After being completed, + lQk *iop.Polynomial + + // Domains used for the FFTs. + // Domain[0] = small Domain + // Domain[1] = big Domain + Domain [2]fft.Domain + + // in lagrange coset basis --> these are not serialized, but computed from S1Canonical, S2Canonical, S3Canonical once. + lcS1, lcS2, lcS3 *iop.Polynomial +} + func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) { + var pk ProvingKey var vk VerifyingKey - - // The verifying key shares data with the proving key pk.Vk = &vk + // nbConstraints := len(spr.Constraints) - nbConstraints := len(spr.Constraints) + // step 0: set the fft domains + pk.initDomains(spr) - // fft domains - sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints - pk.Domain[0] = *fft.NewDomain(sizeSystem) + // step 1: set the verifying key pk.Vk.CosetShift.Set(&pk.Domain[0].FrMultiplicativeGen) - - // h, the quotient polynomial is of degree 3(n+1)+2, so it's in a 3(n+2) dim vector space, - // the domain is the next power of 2 superior to 3(n+2). 4*domainNum is enough in all cases - // except when n<6. - if sizeSystem < 6 { - pk.Domain[1] = *fft.NewDomain(8 * sizeSystem) - } else { - pk.Domain[1] = *fft.NewDomain(4 * sizeSystem) - } - vk.Size = pk.Domain[0].Cardinality vk.SizeInv.SetUint64(vk.Size).Inverse(&vk.SizeInv) vk.Generator.Set(&pk.Domain[0].Generator) vk.NbPublicVariables = uint64(len(spr.Public)) - if err := pk.InitKZG(srs); err != nil { return nil, nil, err } - // public polynomials corresponding to constraints: [ placholders | constraints | assertions ] - pk.Ql = make([]fr.Element, pk.Domain[0].Cardinality) - pk.Qr = make([]fr.Element, pk.Domain[0].Cardinality) - pk.Qm = make([]fr.Element, pk.Domain[0].Cardinality) - pk.Qo = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQk = make([]fr.Element, pk.Domain[0].Cardinality) - pk.LQk = make([]fr.Element, pk.Domain[0].Cardinality) + // step 2: ql, qr, qm, qo, qk in Lagrange Basis + BuildTrace(spr, &pk.trace) + + // step 3: build the permutation and build the polynomials S1, S2, S3 to encode the permutation. + // Note: at this stage, the permutation takes in account the placeholders + nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) + buildPermutation(spr, &pk.trace, nbVariables) + s := computePermutationPolynomials(&pk.trace, &pk.Domain[0]) + pk.trace.S1 = s[0] + pk.trace.S2 = s[1] + pk.trace.S3 = s[2] + + // step 4: commit to s1, s2, s3, ql, qr, qm, qo, and (the incomplete version of) qk. + // All the above polynomials are expressed in canonical basis afterwards. This is why + // we save lqk before, because the prover needs to complete it in Lagrange form, and + // then express it on the Lagrange coset basis. + pk.lQk = pk.trace.Qk.Clone() // it will be completed by the prover, and the evaluated on the coset + err := commitTrace(&pk.trace, &pk) + if err != nil { + return nil, nil, err + } + + // step 5: evaluate ql, qr, qm, qo, s1, s2, s3 on LagrangeCoset (NOT qk) + // we clone them, because the canonical versions are going to be used in + // the opening proof + pk.computeLagrangeCosetPolys() + + return &pk, &vk, nil +} + +// computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset +// basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. +func (pk *ProvingKey) computeLagrangeCosetPolys() { + pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQo = pk.trace.Qo.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcS1 = pk.trace.S1.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcS2 = pk.trace.S2.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcS3 = pk.trace.S3.Clone().ToLagrangeCoset(&pk.Domain[1]) +} + +// NbPublicWitness returns the expected public witness size (number of field elements) +func (vk *VerifyingKey) NbPublicWitness() int { + return int(vk.NbPublicVariables) +} + +// VerifyingKey returns pk.Vk +func (pk *ProvingKey) VerifyingKey() interface{} { + return pk.Vk +} + +// InitKZG inits pk.Vk.KZG using pk.Domain[0] cardinality and provided SRS +// +// This should be used after deserializing a ProvingKey +// as pk.Vk.KZG is NOT serialized +func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { + return pk.Vk.InitKZG(srs) +} + +// InitKZG inits vk.KZG using provided SRS +// +// This should be used after deserializing a VerifyingKey +// as vk.KZG is NOT serialized +// +// Note that this instantiate a new FFT domain using vk.Size +func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { + _srs := srs.(*kzg.SRS) + + if len(_srs.G1) < int(vk.Size) { + return errors.New("kzg srs is too small") + } + vk.KZGSRS = _srs + + return nil +} + +// BuildTrace fills the constatn columns ql, qr, qm, qo, qk from the sparser1cs. +// Size is the size of the system that is nb_constraints+nb_public_variables +func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { + + nbConstraints := len(spr.Constraints) + sizeSystem := uint64(nbConstraints + len(spr.Public)) + size := ecc.NextPowerOfTwo(uint64(sizeSystem)) + + ql := make([]fr.Element, size) + qr := make([]fr.Element, size) + qm := make([]fr.Element, size) + qo := make([]fr.Element, size) + qk := make([]fr.Element, size) for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistant - pk.Ql[i].SetOne().Neg(&pk.Ql[i]) - pk.Qr[i].SetZero() - pk.Qm[i].SetZero() - pk.Qo[i].SetZero() - pk.CQk[i].SetZero() - pk.LQk[i].SetZero() // → to be completed by the prover + ql[i].SetOne().Neg(&ql[i]) + qr[i].SetZero() + qm[i].SetZero() + qo[i].SetZero() + qk[i].SetZero() // → to be completed by the prover } offset := len(spr.Public) for i := 0; i < nbConstraints; i++ { // constraints - pk.Ql[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) - pk.Qr[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) - pk.Qm[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). - Mul(&pk.Qm[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) - pk.Qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) - pk.CQk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) - pk.LQk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) + ql[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) + qr[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) + qm[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). + Mul(&qm[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) + qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) + qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } - pk.Domain[0].FFTInverse(pk.Ql, fft.DIF) - pk.Domain[0].FFTInverse(pk.Qr, fft.DIF) - pk.Domain[0].FFTInverse(pk.Qm, fft.DIF) - pk.Domain[0].FFTInverse(pk.Qo, fft.DIF) - pk.Domain[0].FFTInverse(pk.CQk, fft.DIF) - fft.BitReverse(pk.Ql) - fft.BitReverse(pk.Qr) - fft.BitReverse(pk.Qm) - fft.BitReverse(pk.Qo) - fft.BitReverse(pk.CQk) + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} - // build permutation. Note: at this stage, the permutation takes in account the placeholders - buildPermutation(spr, &pk) + pt.Ql = iop.NewPolynomial(&ql, lagReg) + pt.Qr = iop.NewPolynomial(&qr, lagReg) + pt.Qm = iop.NewPolynomial(&qm, lagReg) + pt.Qo = iop.NewPolynomial(&qo, lagReg) + pt.Qk = iop.NewPolynomial(&qk, lagReg) - // set s1, s2, s3 - ccomputePermutationPolynomials(&pk) +} - // compute the lagrange coset basis versions (not serialized) - pk.computeLagrangeCosetPolys() +// commitTrace commits to every polynomials in the trace, and put +// the commitments int the verifying key. +func commitTrace(trace *Trace, pk *ProvingKey) error { + + trace.Ql.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qr.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qm.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qo.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qk.ToCanonical(&pk.Domain[0]).ToRegular() // -> qk is not complete + trace.S1.ToCanonical(&pk.Domain[0]).ToRegular() + trace.S2.ToCanonical(&pk.Domain[0]).ToRegular() + trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() - // Commit to the polynomials to set up the verifying key var err error - if vk.Ql, err = kzg.Commit(pk.Ql, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qr, err = kzg.Commit(pk.Qr, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qr, err = kzg.Commit(pk.trace.Qr.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qm, err = kzg.Commit(pk.Qm, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qm, err = kzg.Commit(pk.trace.Qm.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qo, err = kzg.Commit(pk.Qo, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qo, err = kzg.Commit(pk.trace.Qo.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qk, err = kzg.Commit(pk.CQk, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.S[0], err = kzg.Commit(pk.S1Canonical, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.S[1], err = kzg.Commit(pk.S2Canonical, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.S[1], err = kzg.Commit(pk.trace.S2.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.S[2], err = kzg.Commit(pk.S3Canonical, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.S[2], err = kzg.Commit(pk.trace.S3.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } + return nil +} - return &pk, &vk, nil +func (pk *ProvingKey) initDomains(spr *cs.SparseR1CS) { + + nbConstraints := len(spr.Constraints) + sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints + pk.Domain[0] = *fft.NewDomain(sizeSystem) + + // h, the quotient polynomial is of degree 3(n+1)+2, so it's in a 3(n+2) dim vector space, + // the domain is the next power of 2 superior to 3(n+2). 4*domainNum is enough in all cases + // except when n<6. + if sizeSystem < 6 { + pk.Domain[1] = *fft.NewDomain(8 * sizeSystem) + } else { + pk.Domain[1] = *fft.NewDomain(4 * sizeSystem) + } } @@ -217,19 +320,20 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // The permutation is encoded as a slice s of size 3*size(l), where the // i-th entry of l∥r∥o is sent to the s[i]-th entry, so it acts on a tab // like this: for i in tab: tab[i] = tab[permutation[i]] -func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { +func buildPermutation(spr *cs.SparseR1CS, pt *Trace, nbVariables int) { - nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) - sizeSolution := int(pk.Domain[0].Cardinality) + // nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) + sizeSolution := len(pt.Ql.Coefficients()) + sizePermutation := 3 * sizeSolution // init permutation - pk.Permutation = make([]int64, 3*sizeSolution) - for i := 0; i < len(pk.Permutation); i++ { - pk.Permutation[i] = -1 + permutation := make([]int64, sizePermutation) + for i := 0; i < len(permutation); i++ { + permutation[i] = -1 } // init LRO position -> variable_ID - lro := make([]int, 3*sizeSolution) // position -> variable_ID + lro := make([]int, sizePermutation) // position -> variable_ID for i := 0; i < len(spr.Public); i++ { lro[i] = i // IDs of LRO associated to placeholders (only L needs to be taken care of) } @@ -252,95 +356,54 @@ func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { if cycle[lro[i]] != -1 { // if != -1, it means we already encountered this value // so we need to set the corresponding permutation index. - pk.Permutation[i] = cycle[lro[i]] + permutation[i] = cycle[lro[i]] } cycle[lro[i]] = int64(i) } // complete the Permutation by filling the first IDs encountered - for i := 0; i < len(pk.Permutation); i++ { - if pk.Permutation[i] == -1 { - pk.Permutation[i] = cycle[lro[i]] + for i := 0; i < sizePermutation; i++ { + if permutation[i] == -1 { + permutation[i] = cycle[lro[i]] } } -} -func (pk *ProvingKey) computeLagrangeCosetPolys() { - canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} - wqliop := iop.NewPolynomial(clone(pk.Ql, pk.Domain[1].Cardinality), canReg) - wqriop := iop.NewPolynomial(clone(pk.Qr, pk.Domain[1].Cardinality), canReg) - wqmiop := iop.NewPolynomial(clone(pk.Qm, pk.Domain[1].Cardinality), canReg) - wqoiop := iop.NewPolynomial(clone(pk.Qo, pk.Domain[1].Cardinality), canReg) - - ws1 := iop.NewPolynomial(clone(pk.S1Canonical, pk.Domain[1].Cardinality), canReg) - ws2 := iop.NewPolynomial(clone(pk.S2Canonical, pk.Domain[1].Cardinality), canReg) - ws3 := iop.NewPolynomial(clone(pk.S3Canonical, pk.Domain[1].Cardinality), canReg) - - wqliop.ToLagrangeCoset(&pk.Domain[1]) - wqriop.ToLagrangeCoset(&pk.Domain[1]) - wqmiop.ToLagrangeCoset(&pk.Domain[1]) - wqoiop.ToLagrangeCoset(&pk.Domain[1]) - - ws1.ToLagrangeCoset(&pk.Domain[1]) - ws2.ToLagrangeCoset(&pk.Domain[1]) - ws3.ToLagrangeCoset(&pk.Domain[1]) - - pk.lQl = wqliop.Coefficients() - pk.lQr = wqriop.Coefficients() - pk.lQm = wqmiop.Coefficients() - pk.lQo = wqoiop.Coefficients() - - pk.lS1LagrangeCoset = ws1.Coefficients() - pk.lS2LagrangeCoset = ws2.Coefficients() - pk.lS3LagrangeCoset = ws3.Coefficients() + pt.S = permutation } -func clone(input []fr.Element, capacity uint64) *[]fr.Element { - res := make([]fr.Element, len(input), capacity) - copy(res, input) - return &res -} +// computePermutationPolynomials computes the LDE (Lagrange basis) of the permutation. +// We let the permutation act on || u || u^{2}, split the result in 3 parts, +// and interpolate each of the 3 parts on . +func computePermutationPolynomials(pt *Trace, domain *fft.Domain) [3]*iop.Polynomial { -// ccomputePermutationPolynomials computes the LDE (Lagrange basis) of the permutations -// s1, s2, s3. -// -// 1 z .. z**n-1 | u uz .. u*z**n-1 | u**2 u**2*z .. u**2*z**n-1 | -// -// | -// | Permutation -// -// s11 s12 .. s1n s21 s22 .. s2n s31 s32 .. s3n v -// \---------------/ \--------------------/ \------------------------/ -// -// s1 (LDE) s2 (LDE) s3 (LDE) -func ccomputePermutationPolynomials(pk *ProvingKey) { + nbElmts := int(domain.Cardinality) - nbElmts := int(pk.Domain[0].Cardinality) + var res [3]*iop.Polynomial // Lagrange form of ID - evaluationIDSmallDomain := getIDSmallDomain(&pk.Domain[0]) + evaluationIDSmallDomain := getSupportPermutation(domain) // Lagrange form of S1, S2, S3 - pk.S1Canonical = make([]fr.Element, nbElmts) - pk.S2Canonical = make([]fr.Element, nbElmts) - pk.S3Canonical = make([]fr.Element, nbElmts) + s1Canonical := make([]fr.Element, nbElmts) + s2Canonical := make([]fr.Element, nbElmts) + s3Canonical := make([]fr.Element, nbElmts) for i := 0; i < nbElmts; i++ { - pk.S1Canonical[i].Set(&evaluationIDSmallDomain[pk.Permutation[i]]) - pk.S2Canonical[i].Set(&evaluationIDSmallDomain[pk.Permutation[nbElmts+i]]) - pk.S3Canonical[i].Set(&evaluationIDSmallDomain[pk.Permutation[2*nbElmts+i]]) + s1Canonical[i].Set(&evaluationIDSmallDomain[pt.S[i]]) + s2Canonical[i].Set(&evaluationIDSmallDomain[pt.S[nbElmts+i]]) + s3Canonical[i].Set(&evaluationIDSmallDomain[pt.S[2*nbElmts+i]]) } - // Canonical form of S1, S2, S3 - pk.Domain[0].FFTInverse(pk.S1Canonical, fft.DIF) - pk.Domain[0].FFTInverse(pk.S2Canonical, fft.DIF) - pk.Domain[0].FFTInverse(pk.S3Canonical, fft.DIF) - fft.BitReverse(pk.S1Canonical) - fft.BitReverse(pk.S2Canonical) - fft.BitReverse(pk.S3Canonical) + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + res[0] = iop.NewPolynomial(&s1Canonical, lagReg) + res[1] = iop.NewPolynomial(&s2Canonical, lagReg) + res[2] = iop.NewPolynomial(&s3Canonical, lagReg) + + return res } -// getIDSmallDomain returns the Lagrange form of ID on the small domain -func getIDSmallDomain(domain *fft.Domain) []fr.Element { +// getSupportPermutation returns the support on which the permutation acts, it is +// || u || u^{2} +func getSupportPermutation(domain *fft.Domain) []fr.Element { res := make([]fr.Element, 3*domain.Cardinality) @@ -356,38 +419,3 @@ func getIDSmallDomain(domain *fft.Domain) []fr.Element { return res } - -// InitKZG inits pk.Vk.KZG using pk.Domain[0] cardinality and provided SRS -// -// This should be used after deserializing a ProvingKey -// as pk.Vk.KZG is NOT serialized -func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { - return pk.Vk.InitKZG(srs) -} - -// InitKZG inits vk.KZG using provided SRS -// -// This should be used after deserializing a VerifyingKey -// as vk.KZG is NOT serialized -// -// Note that this instantiate a new FFT domain using vk.Size -func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { - _srs := srs.(*kzg.SRS) - - if len(_srs.G1) < int(vk.Size) { - return errors.New("kzg srs is too small") - } - vk.KZGSRS = _srs - - return nil -} - -// NbPublicWitness returns the expected public witness size (number of field elements) -func (vk *VerifyingKey) NbPublicWitness() int { - return int(vk.NbPublicVariables) -} - -// VerifyingKey returns pk.Vk -func (pk *ProvingKey) VerifyingKey() interface{} { - return pk.Vk -} diff --git a/backend/plonk/bw6-633/marshal.go b/backend/plonk/bw6-633/marshal.go index 6ae656e777..6507039e1d 100644 --- a/backend/plonk/bw6-633/marshal.go +++ b/backend/plonk/bw6-633/marshal.go @@ -21,6 +21,7 @@ import ( "errors" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/iop" "io" ) @@ -108,7 +109,7 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { n += n2 // sanity check len(Permutation) == 3*int(pk.Domain[0].Cardinality) - if len(pk.Permutation) != (3 * int(pk.Domain[0].Cardinality)) { + if len(pk.trace.S) != (3 * int(pk.Domain[0].Cardinality)) { return n, errors.New("invalid permutation size, expected 3*domain cardinality") } @@ -117,16 +118,16 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { // encode the size (nor does it convert from Montgomery to Regular form) // so we explicitly transmit []fr.Element toEncode := []interface{}{ - ([]fr.Element)(pk.Ql), - ([]fr.Element)(pk.Qr), - ([]fr.Element)(pk.Qm), - ([]fr.Element)(pk.Qo), - ([]fr.Element)(pk.CQk), - ([]fr.Element)(pk.LQk), - ([]fr.Element)(pk.S1Canonical), - ([]fr.Element)(pk.S2Canonical), - ([]fr.Element)(pk.S3Canonical), - pk.Permutation, + ([]fr.Element)(pk.trace.Ql.Coefficients()), + ([]fr.Element)(pk.trace.Qr.Coefficients()), + ([]fr.Element)(pk.trace.Qm.Coefficients()), + ([]fr.Element)(pk.trace.Qo.Coefficients()), + ([]fr.Element)(pk.trace.Qk.Coefficients()), + ([]fr.Element)(pk.lQk.Coefficients()), + ([]fr.Element)(pk.trace.S1.Coefficients()), + ([]fr.Element)(pk.trace.S2.Coefficients()), + ([]fr.Element)(pk.trace.S3.Coefficients()), + pk.trace.S, } for _, v := range toEncode { @@ -158,20 +159,22 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { return n, err } - pk.Permutation = make([]int64, 3*pk.Domain[0].Cardinality) + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) dec := curve.NewDecoder(r) + + var ql, qr, qm, qo, qk, lqk, s1, s2, s3 []fr.Element toDecode := []interface{}{ - (*[]fr.Element)(&pk.Ql), - (*[]fr.Element)(&pk.Qr), - (*[]fr.Element)(&pk.Qm), - (*[]fr.Element)(&pk.Qo), - (*[]fr.Element)(&pk.CQk), - (*[]fr.Element)(&pk.LQk), - (*[]fr.Element)(&pk.S1Canonical), - (*[]fr.Element)(&pk.S2Canonical), - (*[]fr.Element)(&pk.S3Canonical), - &pk.Permutation, + &ql, + &qr, + &qm, + &qo, + &qk, + &lqk, + &s1, + &s2, + &s3, + &pk.trace.S, } for _, v := range toDecode { @@ -180,6 +183,19 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { } } + canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} + pk.trace.Ql = iop.NewPolynomial(&ql, canReg) + pk.trace.Qr = iop.NewPolynomial(&qr, canReg) + pk.trace.Qm = iop.NewPolynomial(&qm, canReg) + pk.trace.Qo = iop.NewPolynomial(&qo, canReg) + pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.S1 = iop.NewPolynomial(&s1, canReg) + pk.trace.S2 = iop.NewPolynomial(&s2, canReg) + pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + pk.lQk = iop.NewPolynomial(&lqk, lagReg) + pk.computeLagrangeCosetPolys() return n + dec.BytesRead(), nil diff --git a/backend/plonk/bw6-633/marshal_test.go b/backend/plonk/bw6-633/marshal_test.go index 09064a8900..9d1403112e 100644 --- a/backend/plonk/bw6-633/marshal_test.go +++ b/backend/plonk/bw6-633/marshal_test.go @@ -23,6 +23,7 @@ import ( "bytes" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/fft" + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/iop" gnarkio "github.com/consensys/gnark/io" "io" "math/big" @@ -106,6 +107,7 @@ func roundTripCheckRaw(t *testing.T, from gnarkio.WriterRawTo, reconstructed io. } func (pk *ProvingKey) randomize() { + var vk VerifyingKey vk.randomize() pk.Vk = &vk @@ -113,19 +115,32 @@ func (pk *ProvingKey) randomize() { pk.Domain[1] = *fft.NewDomain(4 * 42) n := int(pk.Domain[0].Cardinality) - pk.Ql = randomScalars(n) - pk.Qr = randomScalars(n) - pk.Qm = randomScalars(n) - pk.Qo = randomScalars(n) - pk.CQk = randomScalars(n) - pk.LQk = randomScalars(n) - pk.S1Canonical = randomScalars(n) - pk.S2Canonical = randomScalars(n) - pk.S3Canonical = randomScalars(n) - - pk.Permutation = make([]int64, 3*pk.Domain[0].Cardinality) - pk.Permutation[0] = -12 - pk.Permutation[len(pk.Permutation)-1] = 8888 + ql := randomScalars(n) + qr := randomScalars(n) + qm := randomScalars(n) + qo := randomScalars(n) + qk := randomScalars(n) + lqk := randomScalars(n) + s1 := randomScalars(n) + s2 := randomScalars(n) + s3 := randomScalars(n) + + canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} + pk.trace.Ql = iop.NewPolynomial(&ql, canReg) + pk.trace.Qr = iop.NewPolynomial(&qr, canReg) + pk.trace.Qm = iop.NewPolynomial(&qm, canReg) + pk.trace.Qo = iop.NewPolynomial(&qo, canReg) + pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.S1 = iop.NewPolynomial(&s1, canReg) + pk.trace.S2 = iop.NewPolynomial(&s2, canReg) + pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) + pk.trace.S[0] = -12 + pk.trace.S[len(pk.trace.S)-1] = 8888 + + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + pk.lQk = iop.NewPolynomial(&lqk, lagReg) pk.computeLagrangeCosetPolys() } diff --git a/backend/plonk/bw6-633/prove.go b/backend/plonk/bw6-633/prove.go index d19ff91d8a..94e73d4052 100644 --- a/backend/plonk/bw6-633/prove.go +++ b/backend/plonk/bw6-633/prove.go @@ -143,7 +143,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts riop.Clone(), oiop.Clone(), }, - pk.Permutation, + pk.trace.S, beta, gamma, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}, @@ -168,9 +168,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // compute qk in canonical basis, completed with the public inputs - qkCompletedCanonical := make([]fr.Element, pk.Domain[0].Cardinality) + // We copy the coeffs of qk to pk is not mutated + lqkcoef := pk.lQk.Coefficients() + qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) + copy(qkCompletedCanonical, lqkcoef) copy(qkCompletedCanonical, fw[:len(spr.Public)]) - copy(qkCompletedCanonical[len(spr.Public):], pk.LQk[len(spr.Public):]) pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -179,17 +181,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwriop.ToLagrangeCoset(&pk.Domain[1]) bwoiop.ToLagrangeCoset(&pk.Domain[1]) - lagrangeCosetBitReversed := iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse} - - // we don't mutate so no need to clone the coefficients from the proving key. - wqliop := iop.NewPolynomial(&pk.lQl, lagrangeCosetBitReversed) - wqriop := iop.NewPolynomial(&pk.lQr, lagrangeCosetBitReversed) - wqmiop := iop.NewPolynomial(&pk.lQm, lagrangeCosetBitReversed) - wqoiop := iop.NewPolynomial(&pk.lQo, lagrangeCosetBitReversed) - canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} - wqkiop := iop.NewPolynomial(&qkCompletedCanonical, canReg) - wqkiop.ToLagrangeCoset(&pk.Domain[1]) + lcqk := iop.NewPolynomial(&qkCompletedCanonical, canReg) + lcqk.ToLagrangeCoset(&pk.Domain[1]) // storing Id id := make([]fr.Element, pk.Domain[1].Cardinality) @@ -197,12 +191,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts widiop := iop.NewPolynomial(&id, canReg) widiop.ToLagrangeCoset(&pk.Domain[1]) - // permutations in LagrangeCoset: we don't mutate so no need to clone the coefficients from the - // proving key. - ws1 := iop.NewPolynomial(&pk.lS1LagrangeCoset, lagrangeCosetBitReversed) - ws2 := iop.NewPolynomial(&pk.lS2LagrangeCoset, lagrangeCosetBitReversed) - ws3 := iop.NewPolynomial(&pk.lS3LagrangeCoset, lagrangeCosetBitReversed) - // Store z(g*x), without reallocating a slice bwsziop := bwziop.ShallowClone().Shift(1) bwsziop.ToLagrangeCoset(&pk.Domain[1]) @@ -276,27 +264,27 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return c } - testEval, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, + systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, bwliop, bwriop, bwoiop, widiop, - ws1, - ws2, - ws3, + pk.lcS1, + pk.lcS2, + pk.lcS3, bwziop, bwsziop, - wqliop, - wqriop, - wqmiop, - wqoiop, - wqkiop, + pk.lcQl, + pk.lcQr, + pk.lcQm, + pk.lcQo, + lcqk, wloneiop, ) if err != nil { return nil, err } - h, err := iop.DivideByXMinusOne(testEval, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) + h, err := iop.DivideByXMinusOne(systemEvaluation, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) if err != nil { return nil, err } @@ -420,8 +408,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwliop.Coefficients()[:bwliop.BlindedSize()], bwriop.Coefficients()[:bwriop.BlindedSize()], bwoiop.Coefficients()[:bwoiop.BlindedSize()], - pk.S1Canonical, - pk.S2Canonical, + pk.trace.S1.Coefficients(), + pk.trace.S2.Coefficients(), }, []kzg.Digest{ foldedHDigest, @@ -522,13 +510,12 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, var s1, s2 fr.Element chS1 := make(chan struct{}, 1) go func() { - ps1 := iop.NewPolynomial(&pk.S1Canonical, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) - s1 = ps1.Evaluate(zeta) // s1(ζ) + s1 = pk.trace.S1.Evaluate(zeta) // s1(ζ) s1.Mul(&s1, &beta).Add(&s1, &lZeta).Add(&s1, &gamma) // (l(ζ)+β*s1(ζ)+γ) close(chS1) }() - ps2 := iop.NewPolynomial(&pk.S2Canonical, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) - tmp := ps2.Evaluate(zeta) // s2(ζ) + // ps2 := iop.NewPolynomial(&pk.S2Canonical, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) + tmp := pk.trace.S2.Evaluate(zeta) // s2(ζ) tmp.Mul(&tmp, &beta).Add(&tmp, &rZeta).Add(&tmp, &gamma) // (r(ζ)+β*s2(ζ)+γ) <-chS1 s1.Mul(&s1, &tmp).Mul(&s1, &zu).Mul(&s1, &beta) // (l(ζ)+β*s1(β)+γ)*(r(ζ)+β*s2(β)+γ)*β*Z(μζ) @@ -562,6 +549,7 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, linPol := make([]fr.Element, len(blindedZCanonical)) copy(linPol, blindedZCanonical) + s3canonical := pk.trace.S3.Coefficients() utils.Parallelize(len(linPol), func(start, end int) { var t0, t1 fr.Element @@ -570,26 +558,31 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, linPol[i].Mul(&linPol[i], &s2) // -Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) - if i < len(pk.S3Canonical) { + if i < len(s3canonical) { - t0.Mul(&pk.S3Canonical[i], &s1) // (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*β*s3(X) + t0.Mul(&s3canonical[i], &s1) // (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*β*s3(X) linPol[i].Add(&linPol[i], &t0) } linPol[i].Mul(&linPol[i], &alpha) // α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ)) - if i < len(pk.Qm) { + cql := pk.trace.Ql.Coefficients() + cqr := pk.trace.Qr.Coefficients() + cqm := pk.trace.Qm.Coefficients() + cqo := pk.trace.Qo.Coefficients() + cqk := pk.trace.Qk.Coefficients() + if i < len(cqm) { - t1.Mul(&pk.Qm[i], &rl) // linPol = linPol + l(ζ)r(ζ)*Qm(X) - t0.Mul(&pk.Ql[i], &lZeta) + t1.Mul(&cqm[i], &rl) // linPol = linPol + l(ζ)r(ζ)*Qm(X) + t0.Mul(&cql[i], &lZeta) t0.Add(&t0, &t1) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + l(ζ)*Ql(X) - t0.Mul(&pk.Qr[i], &rZeta) + t0.Mul(&cqr[i], &rZeta) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + r(ζ)*Qr(X) - t0.Mul(&pk.Qo[i], &oZeta).Add(&t0, &pk.CQk[i]) + t0.Mul(&cqo[i], &oZeta).Add(&t0, &cqk[i]) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) } diff --git a/backend/plonk/bw6-633/setup.go b/backend/plonk/bw6-633/setup.go index 4e6d650887..4bcf075b01 100644 --- a/backend/plonk/bw6-633/setup.go +++ b/backend/plonk/bw6-633/setup.go @@ -18,6 +18,7 @@ package plonk import ( "errors" + "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/fft" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/iop" @@ -27,44 +28,25 @@ import ( kzgg "github.com/consensys/gnark-crypto/kzg" ) -// ProvingKey stores the data needed to generate a proof: -// * the commitment scheme -// * ql, prepended with as many ones as they are public inputs -// * qr, qm, qo prepended with as many zeroes as there are public inputs. -// * qk, prepended with as many zeroes as public inputs, to be completed by the prover -// with the list of public inputs. -// * sigma_1, sigma_2, sigma_3 in both basis -// * the copy constraint permutation -type ProvingKey struct { - // Verifying Key is embedded into the proving key (needed by Prove) - Vk *VerifyingKey - - // TODO store iop.Polynomial here, not []fr.Element for more "type safety" - - // qr,ql,qm,qo (in canonical basis). - Ql, Qr, Qm, Qo []fr.Element - - // qr,ql,qm,qo (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. - lQl, lQr, lQm, lQo []fr.Element - - // LQk (CQk) qk in Lagrange basis (canonical basis), prepended with as many zeroes as public inputs. - // Storing LQk in Lagrange basis saves a fft... - CQk, LQk []fr.Element - - // Domains used for the FFTs. - // Domain[0] = small Domain - // Domain[1] = big Domain - Domain [2]fft.Domain - // Domain[0], Domain[1] fft.Domain - - // Permutation polynomials - S1Canonical, S2Canonical, S3Canonical []fr.Element - - // in lagrange coset basis --> these are not serialized, but computed from S1Canonical, S2Canonical, S3Canonical once. - lS1LagrangeCoset, lS2LagrangeCoset, lS3LagrangeCoset []fr.Element - - // position -> permuted position (position in [0,3*sizeSystem-1]) - Permutation []int64 +// Trace stores a plonk trace as columns +type Trace struct { + + // Constants describing a plonk circuit. The first entries + // of LQk (whose index correspond to the public inputs) are set to 0, and are to be + // completed by the prover. At those indices i (so from 0 to nb_public_variables), LQl[i]=-1 + // so the first nb_public_variables constraints look like this: + // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. + Ql, Qr, Qm, Qo, Qk *iop.Polynomial + + // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. + // The set of interpolation is of size N, so to represent the permutation S we let S acts on the + // set A=(, u*, u^{2}*) of size 3*N, where u is outside (its use is to shift the set ). + // We obtain a permutation of A, A'. We split A' in 3 (A'_{1}, A'_{2}, A'_{3}), and S1, S2, S3 are + // respectively the interpolation of A'_{1}, A'_{2}, A'_{3} on . + S1, S2, S3 *iop.Polynomial + + // S full permutation, i -> S[i] + S []int64 } // VerifyingKey stores the data needed to verify a proof: @@ -73,6 +55,7 @@ type ProvingKey struct { // * Commitments of qr, qm, qo, qk prepended with as many zeroes as there are public inputs // * Commitments to S1, S2, S3 type VerifyingKey struct { + // Size circuit Size uint64 SizeInv fr.Element @@ -93,115 +76,235 @@ type VerifyingKey struct { Ql, Qr, Qm, Qo, Qk kzg.Digest } -// Setup sets proving and verifying keys +// ProvingKey stores the data needed to generate a proof: +// * the commitment scheme +// * ql, prepended with as many ones as they are public inputs +// * qr, qm, qo prepended with as many zeroes as there are public inputs. +// * qk, prepended with as many zeroes as public inputs, to be completed by the prover +// with the list of public inputs. +// * sigma_1, sigma_2, sigma_3 in both basis +// * the copy constraint permutation +type ProvingKey struct { + + // stores ql, qr, qm, qo, qk (-> to be completed by the prover) + // and s1, s2, s3. They are set in canonical basis before generating the proof, they will be used + // for computing the opening proofs (hence the canonical form). The canonical version + // of qk incompleted is used in the linearisation polynomial. + // The polynomials in trace are in canonical basis. + trace Trace + + // Verifying Key is embedded into the proving key (needed by Prove) + Vk *VerifyingKey + + // qr,ql,qm,qo in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. + lcQl, lcQr, lcQm, lcQo *iop.Polynomial + + // LQk qk in Lagrange form -> to be completed by the prover. After being completed, + lQk *iop.Polynomial + + // Domains used for the FFTs. + // Domain[0] = small Domain + // Domain[1] = big Domain + Domain [2]fft.Domain + + // in lagrange coset basis --> these are not serialized, but computed from S1Canonical, S2Canonical, S3Canonical once. + lcS1, lcS2, lcS3 *iop.Polynomial +} + func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) { + var pk ProvingKey var vk VerifyingKey - - // The verifying key shares data with the proving key pk.Vk = &vk + // nbConstraints := len(spr.Constraints) - nbConstraints := len(spr.Constraints) + // step 0: set the fft domains + pk.initDomains(spr) - // fft domains - sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints - pk.Domain[0] = *fft.NewDomain(sizeSystem) + // step 1: set the verifying key pk.Vk.CosetShift.Set(&pk.Domain[0].FrMultiplicativeGen) - - // h, the quotient polynomial is of degree 3(n+1)+2, so it's in a 3(n+2) dim vector space, - // the domain is the next power of 2 superior to 3(n+2). 4*domainNum is enough in all cases - // except when n<6. - if sizeSystem < 6 { - pk.Domain[1] = *fft.NewDomain(8 * sizeSystem) - } else { - pk.Domain[1] = *fft.NewDomain(4 * sizeSystem) - } - vk.Size = pk.Domain[0].Cardinality vk.SizeInv.SetUint64(vk.Size).Inverse(&vk.SizeInv) vk.Generator.Set(&pk.Domain[0].Generator) vk.NbPublicVariables = uint64(len(spr.Public)) - if err := pk.InitKZG(srs); err != nil { return nil, nil, err } - // public polynomials corresponding to constraints: [ placholders | constraints | assertions ] - pk.Ql = make([]fr.Element, pk.Domain[0].Cardinality) - pk.Qr = make([]fr.Element, pk.Domain[0].Cardinality) - pk.Qm = make([]fr.Element, pk.Domain[0].Cardinality) - pk.Qo = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQk = make([]fr.Element, pk.Domain[0].Cardinality) - pk.LQk = make([]fr.Element, pk.Domain[0].Cardinality) + // step 2: ql, qr, qm, qo, qk in Lagrange Basis + BuildTrace(spr, &pk.trace) + + // step 3: build the permutation and build the polynomials S1, S2, S3 to encode the permutation. + // Note: at this stage, the permutation takes in account the placeholders + nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) + buildPermutation(spr, &pk.trace, nbVariables) + s := computePermutationPolynomials(&pk.trace, &pk.Domain[0]) + pk.trace.S1 = s[0] + pk.trace.S2 = s[1] + pk.trace.S3 = s[2] + + // step 4: commit to s1, s2, s3, ql, qr, qm, qo, and (the incomplete version of) qk. + // All the above polynomials are expressed in canonical basis afterwards. This is why + // we save lqk before, because the prover needs to complete it in Lagrange form, and + // then express it on the Lagrange coset basis. + pk.lQk = pk.trace.Qk.Clone() // it will be completed by the prover, and the evaluated on the coset + err := commitTrace(&pk.trace, &pk) + if err != nil { + return nil, nil, err + } + + // step 5: evaluate ql, qr, qm, qo, s1, s2, s3 on LagrangeCoset (NOT qk) + // we clone them, because the canonical versions are going to be used in + // the opening proof + pk.computeLagrangeCosetPolys() + + return &pk, &vk, nil +} + +// computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset +// basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. +func (pk *ProvingKey) computeLagrangeCosetPolys() { + pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQo = pk.trace.Qo.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcS1 = pk.trace.S1.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcS2 = pk.trace.S2.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcS3 = pk.trace.S3.Clone().ToLagrangeCoset(&pk.Domain[1]) +} + +// NbPublicWitness returns the expected public witness size (number of field elements) +func (vk *VerifyingKey) NbPublicWitness() int { + return int(vk.NbPublicVariables) +} + +// VerifyingKey returns pk.Vk +func (pk *ProvingKey) VerifyingKey() interface{} { + return pk.Vk +} + +// InitKZG inits pk.Vk.KZG using pk.Domain[0] cardinality and provided SRS +// +// This should be used after deserializing a ProvingKey +// as pk.Vk.KZG is NOT serialized +func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { + return pk.Vk.InitKZG(srs) +} + +// InitKZG inits vk.KZG using provided SRS +// +// This should be used after deserializing a VerifyingKey +// as vk.KZG is NOT serialized +// +// Note that this instantiate a new FFT domain using vk.Size +func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { + _srs := srs.(*kzg.SRS) + + if len(_srs.G1) < int(vk.Size) { + return errors.New("kzg srs is too small") + } + vk.KZGSRS = _srs + + return nil +} + +// BuildTrace fills the constatn columns ql, qr, qm, qo, qk from the sparser1cs. +// Size is the size of the system that is nb_constraints+nb_public_variables +func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { + + nbConstraints := len(spr.Constraints) + sizeSystem := uint64(nbConstraints + len(spr.Public)) + size := ecc.NextPowerOfTwo(uint64(sizeSystem)) + + ql := make([]fr.Element, size) + qr := make([]fr.Element, size) + qm := make([]fr.Element, size) + qo := make([]fr.Element, size) + qk := make([]fr.Element, size) for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistant - pk.Ql[i].SetOne().Neg(&pk.Ql[i]) - pk.Qr[i].SetZero() - pk.Qm[i].SetZero() - pk.Qo[i].SetZero() - pk.CQk[i].SetZero() - pk.LQk[i].SetZero() // → to be completed by the prover + ql[i].SetOne().Neg(&ql[i]) + qr[i].SetZero() + qm[i].SetZero() + qo[i].SetZero() + qk[i].SetZero() // → to be completed by the prover } offset := len(spr.Public) for i := 0; i < nbConstraints; i++ { // constraints - pk.Ql[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) - pk.Qr[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) - pk.Qm[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). - Mul(&pk.Qm[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) - pk.Qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) - pk.CQk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) - pk.LQk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) + ql[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) + qr[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) + qm[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). + Mul(&qm[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) + qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) + qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } - pk.Domain[0].FFTInverse(pk.Ql, fft.DIF) - pk.Domain[0].FFTInverse(pk.Qr, fft.DIF) - pk.Domain[0].FFTInverse(pk.Qm, fft.DIF) - pk.Domain[0].FFTInverse(pk.Qo, fft.DIF) - pk.Domain[0].FFTInverse(pk.CQk, fft.DIF) - fft.BitReverse(pk.Ql) - fft.BitReverse(pk.Qr) - fft.BitReverse(pk.Qm) - fft.BitReverse(pk.Qo) - fft.BitReverse(pk.CQk) + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} - // build permutation. Note: at this stage, the permutation takes in account the placeholders - buildPermutation(spr, &pk) + pt.Ql = iop.NewPolynomial(&ql, lagReg) + pt.Qr = iop.NewPolynomial(&qr, lagReg) + pt.Qm = iop.NewPolynomial(&qm, lagReg) + pt.Qo = iop.NewPolynomial(&qo, lagReg) + pt.Qk = iop.NewPolynomial(&qk, lagReg) - // set s1, s2, s3 - ccomputePermutationPolynomials(&pk) +} - // compute the lagrange coset basis versions (not serialized) - pk.computeLagrangeCosetPolys() +// commitTrace commits to every polynomials in the trace, and put +// the commitments int the verifying key. +func commitTrace(trace *Trace, pk *ProvingKey) error { + + trace.Ql.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qr.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qm.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qo.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qk.ToCanonical(&pk.Domain[0]).ToRegular() // -> qk is not complete + trace.S1.ToCanonical(&pk.Domain[0]).ToRegular() + trace.S2.ToCanonical(&pk.Domain[0]).ToRegular() + trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() - // Commit to the polynomials to set up the verifying key var err error - if vk.Ql, err = kzg.Commit(pk.Ql, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qr, err = kzg.Commit(pk.Qr, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qr, err = kzg.Commit(pk.trace.Qr.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qm, err = kzg.Commit(pk.Qm, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qm, err = kzg.Commit(pk.trace.Qm.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qo, err = kzg.Commit(pk.Qo, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qo, err = kzg.Commit(pk.trace.Qo.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qk, err = kzg.Commit(pk.CQk, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.S[0], err = kzg.Commit(pk.S1Canonical, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.S[1], err = kzg.Commit(pk.S2Canonical, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.S[1], err = kzg.Commit(pk.trace.S2.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.S[2], err = kzg.Commit(pk.S3Canonical, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.S[2], err = kzg.Commit(pk.trace.S3.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } + return nil +} - return &pk, &vk, nil +func (pk *ProvingKey) initDomains(spr *cs.SparseR1CS) { + + nbConstraints := len(spr.Constraints) + sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints + pk.Domain[0] = *fft.NewDomain(sizeSystem) + + // h, the quotient polynomial is of degree 3(n+1)+2, so it's in a 3(n+2) dim vector space, + // the domain is the next power of 2 superior to 3(n+2). 4*domainNum is enough in all cases + // except when n<6. + if sizeSystem < 6 { + pk.Domain[1] = *fft.NewDomain(8 * sizeSystem) + } else { + pk.Domain[1] = *fft.NewDomain(4 * sizeSystem) + } } @@ -217,19 +320,20 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // The permutation is encoded as a slice s of size 3*size(l), where the // i-th entry of l∥r∥o is sent to the s[i]-th entry, so it acts on a tab // like this: for i in tab: tab[i] = tab[permutation[i]] -func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { +func buildPermutation(spr *cs.SparseR1CS, pt *Trace, nbVariables int) { - nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) - sizeSolution := int(pk.Domain[0].Cardinality) + // nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) + sizeSolution := len(pt.Ql.Coefficients()) + sizePermutation := 3 * sizeSolution // init permutation - pk.Permutation = make([]int64, 3*sizeSolution) - for i := 0; i < len(pk.Permutation); i++ { - pk.Permutation[i] = -1 + permutation := make([]int64, sizePermutation) + for i := 0; i < len(permutation); i++ { + permutation[i] = -1 } // init LRO position -> variable_ID - lro := make([]int, 3*sizeSolution) // position -> variable_ID + lro := make([]int, sizePermutation) // position -> variable_ID for i := 0; i < len(spr.Public); i++ { lro[i] = i // IDs of LRO associated to placeholders (only L needs to be taken care of) } @@ -252,95 +356,54 @@ func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { if cycle[lro[i]] != -1 { // if != -1, it means we already encountered this value // so we need to set the corresponding permutation index. - pk.Permutation[i] = cycle[lro[i]] + permutation[i] = cycle[lro[i]] } cycle[lro[i]] = int64(i) } // complete the Permutation by filling the first IDs encountered - for i := 0; i < len(pk.Permutation); i++ { - if pk.Permutation[i] == -1 { - pk.Permutation[i] = cycle[lro[i]] + for i := 0; i < sizePermutation; i++ { + if permutation[i] == -1 { + permutation[i] = cycle[lro[i]] } } -} -func (pk *ProvingKey) computeLagrangeCosetPolys() { - canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} - wqliop := iop.NewPolynomial(clone(pk.Ql, pk.Domain[1].Cardinality), canReg) - wqriop := iop.NewPolynomial(clone(pk.Qr, pk.Domain[1].Cardinality), canReg) - wqmiop := iop.NewPolynomial(clone(pk.Qm, pk.Domain[1].Cardinality), canReg) - wqoiop := iop.NewPolynomial(clone(pk.Qo, pk.Domain[1].Cardinality), canReg) - - ws1 := iop.NewPolynomial(clone(pk.S1Canonical, pk.Domain[1].Cardinality), canReg) - ws2 := iop.NewPolynomial(clone(pk.S2Canonical, pk.Domain[1].Cardinality), canReg) - ws3 := iop.NewPolynomial(clone(pk.S3Canonical, pk.Domain[1].Cardinality), canReg) - - wqliop.ToLagrangeCoset(&pk.Domain[1]) - wqriop.ToLagrangeCoset(&pk.Domain[1]) - wqmiop.ToLagrangeCoset(&pk.Domain[1]) - wqoiop.ToLagrangeCoset(&pk.Domain[1]) - - ws1.ToLagrangeCoset(&pk.Domain[1]) - ws2.ToLagrangeCoset(&pk.Domain[1]) - ws3.ToLagrangeCoset(&pk.Domain[1]) - - pk.lQl = wqliop.Coefficients() - pk.lQr = wqriop.Coefficients() - pk.lQm = wqmiop.Coefficients() - pk.lQo = wqoiop.Coefficients() - - pk.lS1LagrangeCoset = ws1.Coefficients() - pk.lS2LagrangeCoset = ws2.Coefficients() - pk.lS3LagrangeCoset = ws3.Coefficients() + pt.S = permutation } -func clone(input []fr.Element, capacity uint64) *[]fr.Element { - res := make([]fr.Element, len(input), capacity) - copy(res, input) - return &res -} +// computePermutationPolynomials computes the LDE (Lagrange basis) of the permutation. +// We let the permutation act on || u || u^{2}, split the result in 3 parts, +// and interpolate each of the 3 parts on . +func computePermutationPolynomials(pt *Trace, domain *fft.Domain) [3]*iop.Polynomial { -// ccomputePermutationPolynomials computes the LDE (Lagrange basis) of the permutations -// s1, s2, s3. -// -// 1 z .. z**n-1 | u uz .. u*z**n-1 | u**2 u**2*z .. u**2*z**n-1 | -// -// | -// | Permutation -// -// s11 s12 .. s1n s21 s22 .. s2n s31 s32 .. s3n v -// \---------------/ \--------------------/ \------------------------/ -// -// s1 (LDE) s2 (LDE) s3 (LDE) -func ccomputePermutationPolynomials(pk *ProvingKey) { + nbElmts := int(domain.Cardinality) - nbElmts := int(pk.Domain[0].Cardinality) + var res [3]*iop.Polynomial // Lagrange form of ID - evaluationIDSmallDomain := getIDSmallDomain(&pk.Domain[0]) + evaluationIDSmallDomain := getSupportPermutation(domain) // Lagrange form of S1, S2, S3 - pk.S1Canonical = make([]fr.Element, nbElmts) - pk.S2Canonical = make([]fr.Element, nbElmts) - pk.S3Canonical = make([]fr.Element, nbElmts) + s1Canonical := make([]fr.Element, nbElmts) + s2Canonical := make([]fr.Element, nbElmts) + s3Canonical := make([]fr.Element, nbElmts) for i := 0; i < nbElmts; i++ { - pk.S1Canonical[i].Set(&evaluationIDSmallDomain[pk.Permutation[i]]) - pk.S2Canonical[i].Set(&evaluationIDSmallDomain[pk.Permutation[nbElmts+i]]) - pk.S3Canonical[i].Set(&evaluationIDSmallDomain[pk.Permutation[2*nbElmts+i]]) + s1Canonical[i].Set(&evaluationIDSmallDomain[pt.S[i]]) + s2Canonical[i].Set(&evaluationIDSmallDomain[pt.S[nbElmts+i]]) + s3Canonical[i].Set(&evaluationIDSmallDomain[pt.S[2*nbElmts+i]]) } - // Canonical form of S1, S2, S3 - pk.Domain[0].FFTInverse(pk.S1Canonical, fft.DIF) - pk.Domain[0].FFTInverse(pk.S2Canonical, fft.DIF) - pk.Domain[0].FFTInverse(pk.S3Canonical, fft.DIF) - fft.BitReverse(pk.S1Canonical) - fft.BitReverse(pk.S2Canonical) - fft.BitReverse(pk.S3Canonical) + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + res[0] = iop.NewPolynomial(&s1Canonical, lagReg) + res[1] = iop.NewPolynomial(&s2Canonical, lagReg) + res[2] = iop.NewPolynomial(&s3Canonical, lagReg) + + return res } -// getIDSmallDomain returns the Lagrange form of ID on the small domain -func getIDSmallDomain(domain *fft.Domain) []fr.Element { +// getSupportPermutation returns the support on which the permutation acts, it is +// || u || u^{2} +func getSupportPermutation(domain *fft.Domain) []fr.Element { res := make([]fr.Element, 3*domain.Cardinality) @@ -356,38 +419,3 @@ func getIDSmallDomain(domain *fft.Domain) []fr.Element { return res } - -// InitKZG inits pk.Vk.KZG using pk.Domain[0] cardinality and provided SRS -// -// This should be used after deserializing a ProvingKey -// as pk.Vk.KZG is NOT serialized -func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { - return pk.Vk.InitKZG(srs) -} - -// InitKZG inits vk.KZG using provided SRS -// -// This should be used after deserializing a VerifyingKey -// as vk.KZG is NOT serialized -// -// Note that this instantiate a new FFT domain using vk.Size -func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { - _srs := srs.(*kzg.SRS) - - if len(_srs.G1) < int(vk.Size) { - return errors.New("kzg srs is too small") - } - vk.KZGSRS = _srs - - return nil -} - -// NbPublicWitness returns the expected public witness size (number of field elements) -func (vk *VerifyingKey) NbPublicWitness() int { - return int(vk.NbPublicVariables) -} - -// VerifyingKey returns pk.Vk -func (pk *ProvingKey) VerifyingKey() interface{} { - return pk.Vk -} diff --git a/backend/plonk/bw6-761/marshal.go b/backend/plonk/bw6-761/marshal.go index d51e9ef211..110e046c3c 100644 --- a/backend/plonk/bw6-761/marshal.go +++ b/backend/plonk/bw6-761/marshal.go @@ -21,6 +21,7 @@ import ( "errors" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/iop" "io" ) @@ -108,7 +109,7 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { n += n2 // sanity check len(Permutation) == 3*int(pk.Domain[0].Cardinality) - if len(pk.Permutation) != (3 * int(pk.Domain[0].Cardinality)) { + if len(pk.trace.S) != (3 * int(pk.Domain[0].Cardinality)) { return n, errors.New("invalid permutation size, expected 3*domain cardinality") } @@ -117,16 +118,16 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { // encode the size (nor does it convert from Montgomery to Regular form) // so we explicitly transmit []fr.Element toEncode := []interface{}{ - ([]fr.Element)(pk.Ql), - ([]fr.Element)(pk.Qr), - ([]fr.Element)(pk.Qm), - ([]fr.Element)(pk.Qo), - ([]fr.Element)(pk.CQk), - ([]fr.Element)(pk.LQk), - ([]fr.Element)(pk.S1Canonical), - ([]fr.Element)(pk.S2Canonical), - ([]fr.Element)(pk.S3Canonical), - pk.Permutation, + ([]fr.Element)(pk.trace.Ql.Coefficients()), + ([]fr.Element)(pk.trace.Qr.Coefficients()), + ([]fr.Element)(pk.trace.Qm.Coefficients()), + ([]fr.Element)(pk.trace.Qo.Coefficients()), + ([]fr.Element)(pk.trace.Qk.Coefficients()), + ([]fr.Element)(pk.lQk.Coefficients()), + ([]fr.Element)(pk.trace.S1.Coefficients()), + ([]fr.Element)(pk.trace.S2.Coefficients()), + ([]fr.Element)(pk.trace.S3.Coefficients()), + pk.trace.S, } for _, v := range toEncode { @@ -158,20 +159,22 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { return n, err } - pk.Permutation = make([]int64, 3*pk.Domain[0].Cardinality) + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) dec := curve.NewDecoder(r) + + var ql, qr, qm, qo, qk, lqk, s1, s2, s3 []fr.Element toDecode := []interface{}{ - (*[]fr.Element)(&pk.Ql), - (*[]fr.Element)(&pk.Qr), - (*[]fr.Element)(&pk.Qm), - (*[]fr.Element)(&pk.Qo), - (*[]fr.Element)(&pk.CQk), - (*[]fr.Element)(&pk.LQk), - (*[]fr.Element)(&pk.S1Canonical), - (*[]fr.Element)(&pk.S2Canonical), - (*[]fr.Element)(&pk.S3Canonical), - &pk.Permutation, + &ql, + &qr, + &qm, + &qo, + &qk, + &lqk, + &s1, + &s2, + &s3, + &pk.trace.S, } for _, v := range toDecode { @@ -180,6 +183,19 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { } } + canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} + pk.trace.Ql = iop.NewPolynomial(&ql, canReg) + pk.trace.Qr = iop.NewPolynomial(&qr, canReg) + pk.trace.Qm = iop.NewPolynomial(&qm, canReg) + pk.trace.Qo = iop.NewPolynomial(&qo, canReg) + pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.S1 = iop.NewPolynomial(&s1, canReg) + pk.trace.S2 = iop.NewPolynomial(&s2, canReg) + pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + pk.lQk = iop.NewPolynomial(&lqk, lagReg) + pk.computeLagrangeCosetPolys() return n + dec.BytesRead(), nil diff --git a/backend/plonk/bw6-761/marshal_test.go b/backend/plonk/bw6-761/marshal_test.go index 548044159d..c53c256851 100644 --- a/backend/plonk/bw6-761/marshal_test.go +++ b/backend/plonk/bw6-761/marshal_test.go @@ -23,6 +23,7 @@ import ( "bytes" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/fft" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/iop" gnarkio "github.com/consensys/gnark/io" "io" "math/big" @@ -106,6 +107,7 @@ func roundTripCheckRaw(t *testing.T, from gnarkio.WriterRawTo, reconstructed io. } func (pk *ProvingKey) randomize() { + var vk VerifyingKey vk.randomize() pk.Vk = &vk @@ -113,19 +115,32 @@ func (pk *ProvingKey) randomize() { pk.Domain[1] = *fft.NewDomain(4 * 42) n := int(pk.Domain[0].Cardinality) - pk.Ql = randomScalars(n) - pk.Qr = randomScalars(n) - pk.Qm = randomScalars(n) - pk.Qo = randomScalars(n) - pk.CQk = randomScalars(n) - pk.LQk = randomScalars(n) - pk.S1Canonical = randomScalars(n) - pk.S2Canonical = randomScalars(n) - pk.S3Canonical = randomScalars(n) - - pk.Permutation = make([]int64, 3*pk.Domain[0].Cardinality) - pk.Permutation[0] = -12 - pk.Permutation[len(pk.Permutation)-1] = 8888 + ql := randomScalars(n) + qr := randomScalars(n) + qm := randomScalars(n) + qo := randomScalars(n) + qk := randomScalars(n) + lqk := randomScalars(n) + s1 := randomScalars(n) + s2 := randomScalars(n) + s3 := randomScalars(n) + + canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} + pk.trace.Ql = iop.NewPolynomial(&ql, canReg) + pk.trace.Qr = iop.NewPolynomial(&qr, canReg) + pk.trace.Qm = iop.NewPolynomial(&qm, canReg) + pk.trace.Qo = iop.NewPolynomial(&qo, canReg) + pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.S1 = iop.NewPolynomial(&s1, canReg) + pk.trace.S2 = iop.NewPolynomial(&s2, canReg) + pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) + pk.trace.S[0] = -12 + pk.trace.S[len(pk.trace.S)-1] = 8888 + + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + pk.lQk = iop.NewPolynomial(&lqk, lagReg) pk.computeLagrangeCosetPolys() } diff --git a/backend/plonk/bw6-761/prove.go b/backend/plonk/bw6-761/prove.go index c8854b1938..4c1bea3e41 100644 --- a/backend/plonk/bw6-761/prove.go +++ b/backend/plonk/bw6-761/prove.go @@ -143,7 +143,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts riop.Clone(), oiop.Clone(), }, - pk.Permutation, + pk.trace.S, beta, gamma, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}, @@ -168,9 +168,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // compute qk in canonical basis, completed with the public inputs - qkCompletedCanonical := make([]fr.Element, pk.Domain[0].Cardinality) + // We copy the coeffs of qk to pk is not mutated + lqkcoef := pk.lQk.Coefficients() + qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) + copy(qkCompletedCanonical, lqkcoef) copy(qkCompletedCanonical, fw[:len(spr.Public)]) - copy(qkCompletedCanonical[len(spr.Public):], pk.LQk[len(spr.Public):]) pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -179,17 +181,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwriop.ToLagrangeCoset(&pk.Domain[1]) bwoiop.ToLagrangeCoset(&pk.Domain[1]) - lagrangeCosetBitReversed := iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse} - - // we don't mutate so no need to clone the coefficients from the proving key. - wqliop := iop.NewPolynomial(&pk.lQl, lagrangeCosetBitReversed) - wqriop := iop.NewPolynomial(&pk.lQr, lagrangeCosetBitReversed) - wqmiop := iop.NewPolynomial(&pk.lQm, lagrangeCosetBitReversed) - wqoiop := iop.NewPolynomial(&pk.lQo, lagrangeCosetBitReversed) - canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} - wqkiop := iop.NewPolynomial(&qkCompletedCanonical, canReg) - wqkiop.ToLagrangeCoset(&pk.Domain[1]) + lcqk := iop.NewPolynomial(&qkCompletedCanonical, canReg) + lcqk.ToLagrangeCoset(&pk.Domain[1]) // storing Id id := make([]fr.Element, pk.Domain[1].Cardinality) @@ -197,12 +191,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts widiop := iop.NewPolynomial(&id, canReg) widiop.ToLagrangeCoset(&pk.Domain[1]) - // permutations in LagrangeCoset: we don't mutate so no need to clone the coefficients from the - // proving key. - ws1 := iop.NewPolynomial(&pk.lS1LagrangeCoset, lagrangeCosetBitReversed) - ws2 := iop.NewPolynomial(&pk.lS2LagrangeCoset, lagrangeCosetBitReversed) - ws3 := iop.NewPolynomial(&pk.lS3LagrangeCoset, lagrangeCosetBitReversed) - // Store z(g*x), without reallocating a slice bwsziop := bwziop.ShallowClone().Shift(1) bwsziop.ToLagrangeCoset(&pk.Domain[1]) @@ -276,27 +264,27 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return c } - testEval, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, + systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, bwliop, bwriop, bwoiop, widiop, - ws1, - ws2, - ws3, + pk.lcS1, + pk.lcS2, + pk.lcS3, bwziop, bwsziop, - wqliop, - wqriop, - wqmiop, - wqoiop, - wqkiop, + pk.lcQl, + pk.lcQr, + pk.lcQm, + pk.lcQo, + lcqk, wloneiop, ) if err != nil { return nil, err } - h, err := iop.DivideByXMinusOne(testEval, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) + h, err := iop.DivideByXMinusOne(systemEvaluation, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) if err != nil { return nil, err } @@ -420,8 +408,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwliop.Coefficients()[:bwliop.BlindedSize()], bwriop.Coefficients()[:bwriop.BlindedSize()], bwoiop.Coefficients()[:bwoiop.BlindedSize()], - pk.S1Canonical, - pk.S2Canonical, + pk.trace.S1.Coefficients(), + pk.trace.S2.Coefficients(), }, []kzg.Digest{ foldedHDigest, @@ -522,13 +510,12 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, var s1, s2 fr.Element chS1 := make(chan struct{}, 1) go func() { - ps1 := iop.NewPolynomial(&pk.S1Canonical, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) - s1 = ps1.Evaluate(zeta) // s1(ζ) + s1 = pk.trace.S1.Evaluate(zeta) // s1(ζ) s1.Mul(&s1, &beta).Add(&s1, &lZeta).Add(&s1, &gamma) // (l(ζ)+β*s1(ζ)+γ) close(chS1) }() - ps2 := iop.NewPolynomial(&pk.S2Canonical, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) - tmp := ps2.Evaluate(zeta) // s2(ζ) + // ps2 := iop.NewPolynomial(&pk.S2Canonical, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) + tmp := pk.trace.S2.Evaluate(zeta) // s2(ζ) tmp.Mul(&tmp, &beta).Add(&tmp, &rZeta).Add(&tmp, &gamma) // (r(ζ)+β*s2(ζ)+γ) <-chS1 s1.Mul(&s1, &tmp).Mul(&s1, &zu).Mul(&s1, &beta) // (l(ζ)+β*s1(β)+γ)*(r(ζ)+β*s2(β)+γ)*β*Z(μζ) @@ -562,6 +549,7 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, linPol := make([]fr.Element, len(blindedZCanonical)) copy(linPol, blindedZCanonical) + s3canonical := pk.trace.S3.Coefficients() utils.Parallelize(len(linPol), func(start, end int) { var t0, t1 fr.Element @@ -570,26 +558,31 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, linPol[i].Mul(&linPol[i], &s2) // -Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) - if i < len(pk.S3Canonical) { + if i < len(s3canonical) { - t0.Mul(&pk.S3Canonical[i], &s1) // (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*β*s3(X) + t0.Mul(&s3canonical[i], &s1) // (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*β*s3(X) linPol[i].Add(&linPol[i], &t0) } linPol[i].Mul(&linPol[i], &alpha) // α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ)) - if i < len(pk.Qm) { + cql := pk.trace.Ql.Coefficients() + cqr := pk.trace.Qr.Coefficients() + cqm := pk.trace.Qm.Coefficients() + cqo := pk.trace.Qo.Coefficients() + cqk := pk.trace.Qk.Coefficients() + if i < len(cqm) { - t1.Mul(&pk.Qm[i], &rl) // linPol = linPol + l(ζ)r(ζ)*Qm(X) - t0.Mul(&pk.Ql[i], &lZeta) + t1.Mul(&cqm[i], &rl) // linPol = linPol + l(ζ)r(ζ)*Qm(X) + t0.Mul(&cql[i], &lZeta) t0.Add(&t0, &t1) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + l(ζ)*Ql(X) - t0.Mul(&pk.Qr[i], &rZeta) + t0.Mul(&cqr[i], &rZeta) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + r(ζ)*Qr(X) - t0.Mul(&pk.Qo[i], &oZeta).Add(&t0, &pk.CQk[i]) + t0.Mul(&cqo[i], &oZeta).Add(&t0, &cqk[i]) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) } diff --git a/backend/plonk/bw6-761/setup.go b/backend/plonk/bw6-761/setup.go index 096aba6f95..ac49fe86aa 100644 --- a/backend/plonk/bw6-761/setup.go +++ b/backend/plonk/bw6-761/setup.go @@ -18,6 +18,7 @@ package plonk import ( "errors" + "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/fft" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/iop" @@ -27,44 +28,25 @@ import ( kzgg "github.com/consensys/gnark-crypto/kzg" ) -// ProvingKey stores the data needed to generate a proof: -// * the commitment scheme -// * ql, prepended with as many ones as they are public inputs -// * qr, qm, qo prepended with as many zeroes as there are public inputs. -// * qk, prepended with as many zeroes as public inputs, to be completed by the prover -// with the list of public inputs. -// * sigma_1, sigma_2, sigma_3 in both basis -// * the copy constraint permutation -type ProvingKey struct { - // Verifying Key is embedded into the proving key (needed by Prove) - Vk *VerifyingKey - - // TODO store iop.Polynomial here, not []fr.Element for more "type safety" - - // qr,ql,qm,qo (in canonical basis). - Ql, Qr, Qm, Qo []fr.Element - - // qr,ql,qm,qo (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. - lQl, lQr, lQm, lQo []fr.Element - - // LQk (CQk) qk in Lagrange basis (canonical basis), prepended with as many zeroes as public inputs. - // Storing LQk in Lagrange basis saves a fft... - CQk, LQk []fr.Element - - // Domains used for the FFTs. - // Domain[0] = small Domain - // Domain[1] = big Domain - Domain [2]fft.Domain - // Domain[0], Domain[1] fft.Domain - - // Permutation polynomials - S1Canonical, S2Canonical, S3Canonical []fr.Element - - // in lagrange coset basis --> these are not serialized, but computed from S1Canonical, S2Canonical, S3Canonical once. - lS1LagrangeCoset, lS2LagrangeCoset, lS3LagrangeCoset []fr.Element - - // position -> permuted position (position in [0,3*sizeSystem-1]) - Permutation []int64 +// Trace stores a plonk trace as columns +type Trace struct { + + // Constants describing a plonk circuit. The first entries + // of LQk (whose index correspond to the public inputs) are set to 0, and are to be + // completed by the prover. At those indices i (so from 0 to nb_public_variables), LQl[i]=-1 + // so the first nb_public_variables constraints look like this: + // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. + Ql, Qr, Qm, Qo, Qk *iop.Polynomial + + // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. + // The set of interpolation is of size N, so to represent the permutation S we let S acts on the + // set A=(, u*, u^{2}*) of size 3*N, where u is outside (its use is to shift the set ). + // We obtain a permutation of A, A'. We split A' in 3 (A'_{1}, A'_{2}, A'_{3}), and S1, S2, S3 are + // respectively the interpolation of A'_{1}, A'_{2}, A'_{3} on . + S1, S2, S3 *iop.Polynomial + + // S full permutation, i -> S[i] + S []int64 } // VerifyingKey stores the data needed to verify a proof: @@ -73,6 +55,7 @@ type ProvingKey struct { // * Commitments of qr, qm, qo, qk prepended with as many zeroes as there are public inputs // * Commitments to S1, S2, S3 type VerifyingKey struct { + // Size circuit Size uint64 SizeInv fr.Element @@ -93,115 +76,235 @@ type VerifyingKey struct { Ql, Qr, Qm, Qo, Qk kzg.Digest } -// Setup sets proving and verifying keys +// ProvingKey stores the data needed to generate a proof: +// * the commitment scheme +// * ql, prepended with as many ones as they are public inputs +// * qr, qm, qo prepended with as many zeroes as there are public inputs. +// * qk, prepended with as many zeroes as public inputs, to be completed by the prover +// with the list of public inputs. +// * sigma_1, sigma_2, sigma_3 in both basis +// * the copy constraint permutation +type ProvingKey struct { + + // stores ql, qr, qm, qo, qk (-> to be completed by the prover) + // and s1, s2, s3. They are set in canonical basis before generating the proof, they will be used + // for computing the opening proofs (hence the canonical form). The canonical version + // of qk incompleted is used in the linearisation polynomial. + // The polynomials in trace are in canonical basis. + trace Trace + + // Verifying Key is embedded into the proving key (needed by Prove) + Vk *VerifyingKey + + // qr,ql,qm,qo in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. + lcQl, lcQr, lcQm, lcQo *iop.Polynomial + + // LQk qk in Lagrange form -> to be completed by the prover. After being completed, + lQk *iop.Polynomial + + // Domains used for the FFTs. + // Domain[0] = small Domain + // Domain[1] = big Domain + Domain [2]fft.Domain + + // in lagrange coset basis --> these are not serialized, but computed from S1Canonical, S2Canonical, S3Canonical once. + lcS1, lcS2, lcS3 *iop.Polynomial +} + func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) { + var pk ProvingKey var vk VerifyingKey - - // The verifying key shares data with the proving key pk.Vk = &vk + // nbConstraints := len(spr.Constraints) - nbConstraints := len(spr.Constraints) + // step 0: set the fft domains + pk.initDomains(spr) - // fft domains - sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints - pk.Domain[0] = *fft.NewDomain(sizeSystem) + // step 1: set the verifying key pk.Vk.CosetShift.Set(&pk.Domain[0].FrMultiplicativeGen) - - // h, the quotient polynomial is of degree 3(n+1)+2, so it's in a 3(n+2) dim vector space, - // the domain is the next power of 2 superior to 3(n+2). 4*domainNum is enough in all cases - // except when n<6. - if sizeSystem < 6 { - pk.Domain[1] = *fft.NewDomain(8 * sizeSystem) - } else { - pk.Domain[1] = *fft.NewDomain(4 * sizeSystem) - } - vk.Size = pk.Domain[0].Cardinality vk.SizeInv.SetUint64(vk.Size).Inverse(&vk.SizeInv) vk.Generator.Set(&pk.Domain[0].Generator) vk.NbPublicVariables = uint64(len(spr.Public)) - if err := pk.InitKZG(srs); err != nil { return nil, nil, err } - // public polynomials corresponding to constraints: [ placholders | constraints | assertions ] - pk.Ql = make([]fr.Element, pk.Domain[0].Cardinality) - pk.Qr = make([]fr.Element, pk.Domain[0].Cardinality) - pk.Qm = make([]fr.Element, pk.Domain[0].Cardinality) - pk.Qo = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQk = make([]fr.Element, pk.Domain[0].Cardinality) - pk.LQk = make([]fr.Element, pk.Domain[0].Cardinality) + // step 2: ql, qr, qm, qo, qk in Lagrange Basis + BuildTrace(spr, &pk.trace) + + // step 3: build the permutation and build the polynomials S1, S2, S3 to encode the permutation. + // Note: at this stage, the permutation takes in account the placeholders + nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) + buildPermutation(spr, &pk.trace, nbVariables) + s := computePermutationPolynomials(&pk.trace, &pk.Domain[0]) + pk.trace.S1 = s[0] + pk.trace.S2 = s[1] + pk.trace.S3 = s[2] + + // step 4: commit to s1, s2, s3, ql, qr, qm, qo, and (the incomplete version of) qk. + // All the above polynomials are expressed in canonical basis afterwards. This is why + // we save lqk before, because the prover needs to complete it in Lagrange form, and + // then express it on the Lagrange coset basis. + pk.lQk = pk.trace.Qk.Clone() // it will be completed by the prover, and the evaluated on the coset + err := commitTrace(&pk.trace, &pk) + if err != nil { + return nil, nil, err + } + + // step 5: evaluate ql, qr, qm, qo, s1, s2, s3 on LagrangeCoset (NOT qk) + // we clone them, because the canonical versions are going to be used in + // the opening proof + pk.computeLagrangeCosetPolys() + + return &pk, &vk, nil +} + +// computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset +// basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. +func (pk *ProvingKey) computeLagrangeCosetPolys() { + pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQo = pk.trace.Qo.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcS1 = pk.trace.S1.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcS2 = pk.trace.S2.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcS3 = pk.trace.S3.Clone().ToLagrangeCoset(&pk.Domain[1]) +} + +// NbPublicWitness returns the expected public witness size (number of field elements) +func (vk *VerifyingKey) NbPublicWitness() int { + return int(vk.NbPublicVariables) +} + +// VerifyingKey returns pk.Vk +func (pk *ProvingKey) VerifyingKey() interface{} { + return pk.Vk +} + +// InitKZG inits pk.Vk.KZG using pk.Domain[0] cardinality and provided SRS +// +// This should be used after deserializing a ProvingKey +// as pk.Vk.KZG is NOT serialized +func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { + return pk.Vk.InitKZG(srs) +} + +// InitKZG inits vk.KZG using provided SRS +// +// This should be used after deserializing a VerifyingKey +// as vk.KZG is NOT serialized +// +// Note that this instantiate a new FFT domain using vk.Size +func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { + _srs := srs.(*kzg.SRS) + + if len(_srs.G1) < int(vk.Size) { + return errors.New("kzg srs is too small") + } + vk.KZGSRS = _srs + + return nil +} + +// BuildTrace fills the constatn columns ql, qr, qm, qo, qk from the sparser1cs. +// Size is the size of the system that is nb_constraints+nb_public_variables +func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { + + nbConstraints := len(spr.Constraints) + sizeSystem := uint64(nbConstraints + len(spr.Public)) + size := ecc.NextPowerOfTwo(uint64(sizeSystem)) + + ql := make([]fr.Element, size) + qr := make([]fr.Element, size) + qm := make([]fr.Element, size) + qo := make([]fr.Element, size) + qk := make([]fr.Element, size) for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistant - pk.Ql[i].SetOne().Neg(&pk.Ql[i]) - pk.Qr[i].SetZero() - pk.Qm[i].SetZero() - pk.Qo[i].SetZero() - pk.CQk[i].SetZero() - pk.LQk[i].SetZero() // → to be completed by the prover + ql[i].SetOne().Neg(&ql[i]) + qr[i].SetZero() + qm[i].SetZero() + qo[i].SetZero() + qk[i].SetZero() // → to be completed by the prover } offset := len(spr.Public) for i := 0; i < nbConstraints; i++ { // constraints - pk.Ql[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) - pk.Qr[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) - pk.Qm[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). - Mul(&pk.Qm[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) - pk.Qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) - pk.CQk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) - pk.LQk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) + ql[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) + qr[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) + qm[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). + Mul(&qm[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) + qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) + qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } - pk.Domain[0].FFTInverse(pk.Ql, fft.DIF) - pk.Domain[0].FFTInverse(pk.Qr, fft.DIF) - pk.Domain[0].FFTInverse(pk.Qm, fft.DIF) - pk.Domain[0].FFTInverse(pk.Qo, fft.DIF) - pk.Domain[0].FFTInverse(pk.CQk, fft.DIF) - fft.BitReverse(pk.Ql) - fft.BitReverse(pk.Qr) - fft.BitReverse(pk.Qm) - fft.BitReverse(pk.Qo) - fft.BitReverse(pk.CQk) + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} - // build permutation. Note: at this stage, the permutation takes in account the placeholders - buildPermutation(spr, &pk) + pt.Ql = iop.NewPolynomial(&ql, lagReg) + pt.Qr = iop.NewPolynomial(&qr, lagReg) + pt.Qm = iop.NewPolynomial(&qm, lagReg) + pt.Qo = iop.NewPolynomial(&qo, lagReg) + pt.Qk = iop.NewPolynomial(&qk, lagReg) - // set s1, s2, s3 - ccomputePermutationPolynomials(&pk) +} - // compute the lagrange coset basis versions (not serialized) - pk.computeLagrangeCosetPolys() +// commitTrace commits to every polynomials in the trace, and put +// the commitments int the verifying key. +func commitTrace(trace *Trace, pk *ProvingKey) error { + + trace.Ql.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qr.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qm.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qo.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qk.ToCanonical(&pk.Domain[0]).ToRegular() // -> qk is not complete + trace.S1.ToCanonical(&pk.Domain[0]).ToRegular() + trace.S2.ToCanonical(&pk.Domain[0]).ToRegular() + trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() - // Commit to the polynomials to set up the verifying key var err error - if vk.Ql, err = kzg.Commit(pk.Ql, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qr, err = kzg.Commit(pk.Qr, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qr, err = kzg.Commit(pk.trace.Qr.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qm, err = kzg.Commit(pk.Qm, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qm, err = kzg.Commit(pk.trace.Qm.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qo, err = kzg.Commit(pk.Qo, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qo, err = kzg.Commit(pk.trace.Qo.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qk, err = kzg.Commit(pk.CQk, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.S[0], err = kzg.Commit(pk.S1Canonical, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.S[1], err = kzg.Commit(pk.S2Canonical, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.S[1], err = kzg.Commit(pk.trace.S2.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.S[2], err = kzg.Commit(pk.S3Canonical, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.S[2], err = kzg.Commit(pk.trace.S3.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } + return nil +} - return &pk, &vk, nil +func (pk *ProvingKey) initDomains(spr *cs.SparseR1CS) { + + nbConstraints := len(spr.Constraints) + sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints + pk.Domain[0] = *fft.NewDomain(sizeSystem) + + // h, the quotient polynomial is of degree 3(n+1)+2, so it's in a 3(n+2) dim vector space, + // the domain is the next power of 2 superior to 3(n+2). 4*domainNum is enough in all cases + // except when n<6. + if sizeSystem < 6 { + pk.Domain[1] = *fft.NewDomain(8 * sizeSystem) + } else { + pk.Domain[1] = *fft.NewDomain(4 * sizeSystem) + } } @@ -217,19 +320,20 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // The permutation is encoded as a slice s of size 3*size(l), where the // i-th entry of l∥r∥o is sent to the s[i]-th entry, so it acts on a tab // like this: for i in tab: tab[i] = tab[permutation[i]] -func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { +func buildPermutation(spr *cs.SparseR1CS, pt *Trace, nbVariables int) { - nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) - sizeSolution := int(pk.Domain[0].Cardinality) + // nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) + sizeSolution := len(pt.Ql.Coefficients()) + sizePermutation := 3 * sizeSolution // init permutation - pk.Permutation = make([]int64, 3*sizeSolution) - for i := 0; i < len(pk.Permutation); i++ { - pk.Permutation[i] = -1 + permutation := make([]int64, sizePermutation) + for i := 0; i < len(permutation); i++ { + permutation[i] = -1 } // init LRO position -> variable_ID - lro := make([]int, 3*sizeSolution) // position -> variable_ID + lro := make([]int, sizePermutation) // position -> variable_ID for i := 0; i < len(spr.Public); i++ { lro[i] = i // IDs of LRO associated to placeholders (only L needs to be taken care of) } @@ -252,95 +356,54 @@ func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { if cycle[lro[i]] != -1 { // if != -1, it means we already encountered this value // so we need to set the corresponding permutation index. - pk.Permutation[i] = cycle[lro[i]] + permutation[i] = cycle[lro[i]] } cycle[lro[i]] = int64(i) } // complete the Permutation by filling the first IDs encountered - for i := 0; i < len(pk.Permutation); i++ { - if pk.Permutation[i] == -1 { - pk.Permutation[i] = cycle[lro[i]] + for i := 0; i < sizePermutation; i++ { + if permutation[i] == -1 { + permutation[i] = cycle[lro[i]] } } -} -func (pk *ProvingKey) computeLagrangeCosetPolys() { - canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} - wqliop := iop.NewPolynomial(clone(pk.Ql, pk.Domain[1].Cardinality), canReg) - wqriop := iop.NewPolynomial(clone(pk.Qr, pk.Domain[1].Cardinality), canReg) - wqmiop := iop.NewPolynomial(clone(pk.Qm, pk.Domain[1].Cardinality), canReg) - wqoiop := iop.NewPolynomial(clone(pk.Qo, pk.Domain[1].Cardinality), canReg) - - ws1 := iop.NewPolynomial(clone(pk.S1Canonical, pk.Domain[1].Cardinality), canReg) - ws2 := iop.NewPolynomial(clone(pk.S2Canonical, pk.Domain[1].Cardinality), canReg) - ws3 := iop.NewPolynomial(clone(pk.S3Canonical, pk.Domain[1].Cardinality), canReg) - - wqliop.ToLagrangeCoset(&pk.Domain[1]) - wqriop.ToLagrangeCoset(&pk.Domain[1]) - wqmiop.ToLagrangeCoset(&pk.Domain[1]) - wqoiop.ToLagrangeCoset(&pk.Domain[1]) - - ws1.ToLagrangeCoset(&pk.Domain[1]) - ws2.ToLagrangeCoset(&pk.Domain[1]) - ws3.ToLagrangeCoset(&pk.Domain[1]) - - pk.lQl = wqliop.Coefficients() - pk.lQr = wqriop.Coefficients() - pk.lQm = wqmiop.Coefficients() - pk.lQo = wqoiop.Coefficients() - - pk.lS1LagrangeCoset = ws1.Coefficients() - pk.lS2LagrangeCoset = ws2.Coefficients() - pk.lS3LagrangeCoset = ws3.Coefficients() + pt.S = permutation } -func clone(input []fr.Element, capacity uint64) *[]fr.Element { - res := make([]fr.Element, len(input), capacity) - copy(res, input) - return &res -} +// computePermutationPolynomials computes the LDE (Lagrange basis) of the permutation. +// We let the permutation act on || u || u^{2}, split the result in 3 parts, +// and interpolate each of the 3 parts on . +func computePermutationPolynomials(pt *Trace, domain *fft.Domain) [3]*iop.Polynomial { -// ccomputePermutationPolynomials computes the LDE (Lagrange basis) of the permutations -// s1, s2, s3. -// -// 1 z .. z**n-1 | u uz .. u*z**n-1 | u**2 u**2*z .. u**2*z**n-1 | -// -// | -// | Permutation -// -// s11 s12 .. s1n s21 s22 .. s2n s31 s32 .. s3n v -// \---------------/ \--------------------/ \------------------------/ -// -// s1 (LDE) s2 (LDE) s3 (LDE) -func ccomputePermutationPolynomials(pk *ProvingKey) { + nbElmts := int(domain.Cardinality) - nbElmts := int(pk.Domain[0].Cardinality) + var res [3]*iop.Polynomial // Lagrange form of ID - evaluationIDSmallDomain := getIDSmallDomain(&pk.Domain[0]) + evaluationIDSmallDomain := getSupportPermutation(domain) // Lagrange form of S1, S2, S3 - pk.S1Canonical = make([]fr.Element, nbElmts) - pk.S2Canonical = make([]fr.Element, nbElmts) - pk.S3Canonical = make([]fr.Element, nbElmts) + s1Canonical := make([]fr.Element, nbElmts) + s2Canonical := make([]fr.Element, nbElmts) + s3Canonical := make([]fr.Element, nbElmts) for i := 0; i < nbElmts; i++ { - pk.S1Canonical[i].Set(&evaluationIDSmallDomain[pk.Permutation[i]]) - pk.S2Canonical[i].Set(&evaluationIDSmallDomain[pk.Permutation[nbElmts+i]]) - pk.S3Canonical[i].Set(&evaluationIDSmallDomain[pk.Permutation[2*nbElmts+i]]) + s1Canonical[i].Set(&evaluationIDSmallDomain[pt.S[i]]) + s2Canonical[i].Set(&evaluationIDSmallDomain[pt.S[nbElmts+i]]) + s3Canonical[i].Set(&evaluationIDSmallDomain[pt.S[2*nbElmts+i]]) } - // Canonical form of S1, S2, S3 - pk.Domain[0].FFTInverse(pk.S1Canonical, fft.DIF) - pk.Domain[0].FFTInverse(pk.S2Canonical, fft.DIF) - pk.Domain[0].FFTInverse(pk.S3Canonical, fft.DIF) - fft.BitReverse(pk.S1Canonical) - fft.BitReverse(pk.S2Canonical) - fft.BitReverse(pk.S3Canonical) + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + res[0] = iop.NewPolynomial(&s1Canonical, lagReg) + res[1] = iop.NewPolynomial(&s2Canonical, lagReg) + res[2] = iop.NewPolynomial(&s3Canonical, lagReg) + + return res } -// getIDSmallDomain returns the Lagrange form of ID on the small domain -func getIDSmallDomain(domain *fft.Domain) []fr.Element { +// getSupportPermutation returns the support on which the permutation acts, it is +// || u || u^{2} +func getSupportPermutation(domain *fft.Domain) []fr.Element { res := make([]fr.Element, 3*domain.Cardinality) @@ -356,38 +419,3 @@ func getIDSmallDomain(domain *fft.Domain) []fr.Element { return res } - -// InitKZG inits pk.Vk.KZG using pk.Domain[0] cardinality and provided SRS -// -// This should be used after deserializing a ProvingKey -// as pk.Vk.KZG is NOT serialized -func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { - return pk.Vk.InitKZG(srs) -} - -// InitKZG inits vk.KZG using provided SRS -// -// This should be used after deserializing a VerifyingKey -// as vk.KZG is NOT serialized -// -// Note that this instantiate a new FFT domain using vk.Size -func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { - _srs := srs.(*kzg.SRS) - - if len(_srs.G1) < int(vk.Size) { - return errors.New("kzg srs is too small") - } - vk.KZGSRS = _srs - - return nil -} - -// NbPublicWitness returns the expected public witness size (number of field elements) -func (vk *VerifyingKey) NbPublicWitness() int { - return int(vk.NbPublicVariables) -} - -// VerifyingKey returns pk.Vk -func (pk *ProvingKey) VerifyingKey() interface{} { - return pk.Vk -} diff --git a/go.mod b/go.mod index b7c7eb4612..18bb2d0944 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 - github.com/consensys/gnark-crypto v0.9.2-0.20230222154459-49b5c6cfd875 + github.com/consensys/gnark-crypto v0.9.2-0.20230303095500-84be66f759b2 github.com/fxamacker/cbor/v2 v2.4.0 github.com/google/go-cmp v0.5.9 github.com/google/pprof v0.0.0-20230207041349-798e818bf904 diff --git a/go.sum b/go.sum index d12a06113f..aa64147881 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/Yj github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= github.com/consensys/gnark-crypto v0.9.2-0.20230222154459-49b5c6cfd875 h1:FTOvlE+90hvp+XHi8i89xCejJ0627wfbP0RSWzmVFks= github.com/consensys/gnark-crypto v0.9.2-0.20230222154459-49b5c6cfd875/go.mod h1:a2DQL4+5ywF6safEeZFEPGRiiGbjzGFRUN2sg06VuU4= +github.com/consensys/gnark-crypto v0.9.2-0.20230303095500-84be66f759b2 h1:AoLNGEIQLDhT2lIryd4xphtjappHJtAk6ouV2FYPHZY= +github.com/consensys/gnark-crypto v0.9.2-0.20230303095500-84be66f759b2/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl index 760f22b3d1..2b21e0978b 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl @@ -1,6 +1,7 @@ import ( {{ template "import_curve" . }} {{ template "import_fr" . }} + "github.com/consensys/gnark-crypto/ecc/{{toLower .Curve}}/fr/iop" "io" "errors" ) @@ -38,7 +39,7 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 } } - return enc.BytesWritten(), nil + return enc.BytesWritten(), nil } // ReadFrom reads binary representation of Proof from r @@ -64,7 +65,7 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { } } - return dec.BytesRead(), nil + return dec.BytesRead(), nil } // WriteTo writes binary encoding of ProvingKey to w @@ -89,7 +90,7 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { n += n2 // sanity check len(Permutation) == 3*int(pk.Domain[0].Cardinality) - if len(pk.Permutation) != (3 * int(pk.Domain[0].Cardinality)) { + if len(pk.trace.S) != (3 * int(pk.Domain[0].Cardinality)) { return n, errors.New("invalid permutation size, expected 3*domain cardinality") } @@ -98,16 +99,16 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { // encode the size (nor does it convert from Montgomery to Regular form) // so we explicitly transmit []fr.Element toEncode := []interface{}{ - ([]fr.Element)(pk.Ql), - ([]fr.Element)(pk.Qr), - ([]fr.Element)(pk.Qm), - ([]fr.Element)(pk.Qo), - ([]fr.Element)(pk.CQk), - ([]fr.Element)(pk.LQk), - ([]fr.Element)(pk.S1Canonical), - ([]fr.Element)(pk.S2Canonical), - ([]fr.Element)(pk.S3Canonical), - pk.Permutation, + ([]fr.Element)(pk.trace.Ql.Coefficients()), + ([]fr.Element)(pk.trace.Qr.Coefficients()), + ([]fr.Element)(pk.trace.Qm.Coefficients()), + ([]fr.Element)(pk.trace.Qo.Coefficients()), + ([]fr.Element)(pk.trace.Qk.Coefficients()), + ([]fr.Element)(pk.lQk.Coefficients()), + ([]fr.Element)(pk.trace.S1.Coefficients()), + ([]fr.Element)(pk.trace.S2.Coefficients()), + ([]fr.Element)(pk.trace.S3.Coefficients()), + pk.trace.S, } for _, v := range toEncode { @@ -139,20 +140,22 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { return n, err } - pk.Permutation = make([]int64, 3*pk.Domain[0].Cardinality) + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) dec := curve.NewDecoder(r) + + var ql, qr, qm, qo, qk, lqk, s1, s2, s3 []fr.Element toDecode := []interface{}{ - (*[]fr.Element)(&pk.Ql), - (*[]fr.Element)(&pk.Qr), - (*[]fr.Element)(&pk.Qm), - (*[]fr.Element)(&pk.Qo), - (*[]fr.Element)(&pk.CQk), - (*[]fr.Element)(&pk.LQk), - (*[]fr.Element)(&pk.S1Canonical), - (*[]fr.Element)(&pk.S2Canonical), - (*[]fr.Element)(&pk.S3Canonical), - &pk.Permutation, + &ql, + &qr, + &qm, + &qo, + &qk, + &lqk, + &s1, + &s2, + &s3, + &pk.trace.S, } for _, v := range toDecode { @@ -161,6 +164,19 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { } } + canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} + pk.trace.Ql = iop.NewPolynomial(&ql, canReg) + pk.trace.Qr = iop.NewPolynomial(&qr, canReg) + pk.trace.Qm = iop.NewPolynomial(&qm, canReg) + pk.trace.Qo = iop.NewPolynomial(&qo, canReg) + pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.S1 = iop.NewPolynomial(&s1, canReg) + pk.trace.S2 = iop.NewPolynomial(&s2, canReg) + pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + pk.lQk = iop.NewPolynomial(&lqk, lagReg) + pk.computeLagrangeCosetPolys() return n + dec.BytesRead(), nil diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl index 307ee05dbb..1b460c9451 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl @@ -121,7 +121,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts riop.Clone(), oiop.Clone(), }, - pk.Permutation, + pk.trace.S, beta, gamma, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}, @@ -146,9 +146,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // compute qk in canonical basis, completed with the public inputs - qkCompletedCanonical := make([]fr.Element, pk.Domain[0].Cardinality) + // We copy the coeffs of qk to pk is not mutated + lqkcoef := pk.lQk.Coefficients() + qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) + copy(qkCompletedCanonical, lqkcoef) copy(qkCompletedCanonical, fw[:len(spr.Public)]) - copy(qkCompletedCanonical[len(spr.Public):], pk.LQk[len(spr.Public):]) pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -157,17 +159,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwriop.ToLagrangeCoset(&pk.Domain[1]) bwoiop.ToLagrangeCoset(&pk.Domain[1]) - lagrangeCosetBitReversed := iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse} - - // we don't mutate so no need to clone the coefficients from the proving key. - wqliop := iop.NewPolynomial(&pk.lQl, lagrangeCosetBitReversed) - wqriop := iop.NewPolynomial(&pk.lQr, lagrangeCosetBitReversed) - wqmiop := iop.NewPolynomial(&pk.lQm, lagrangeCosetBitReversed) - wqoiop := iop.NewPolynomial(&pk.lQo, lagrangeCosetBitReversed) - canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} - wqkiop := iop.NewPolynomial(&qkCompletedCanonical, canReg) - wqkiop.ToLagrangeCoset(&pk.Domain[1]) + lcqk := iop.NewPolynomial(&qkCompletedCanonical, canReg) + lcqk.ToLagrangeCoset(&pk.Domain[1]) // storing Id id := make([]fr.Element, pk.Domain[1].Cardinality) @@ -175,12 +169,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts widiop := iop.NewPolynomial(&id, canReg) widiop.ToLagrangeCoset(&pk.Domain[1]) - // permutations in LagrangeCoset: we don't mutate so no need to clone the coefficients from the - // proving key. - ws1 := iop.NewPolynomial(&pk.lS1LagrangeCoset, lagrangeCosetBitReversed) - ws2 := iop.NewPolynomial(&pk.lS2LagrangeCoset, lagrangeCosetBitReversed) - ws3 := iop.NewPolynomial(&pk.lS3LagrangeCoset, lagrangeCosetBitReversed) - // Store z(g*x), without reallocating a slice bwsziop := bwziop.ShallowClone().Shift(1) bwsziop.ToLagrangeCoset(&pk.Domain[1]) @@ -254,27 +242,27 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return c } - testEval, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, + systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, bwliop, bwriop, bwoiop, widiop, - ws1, - ws2, - ws3, + pk.lcS1, + pk.lcS2, + pk.lcS3, bwziop, bwsziop, - wqliop, - wqriop, - wqmiop, - wqoiop, - wqkiop, + pk.lcQl, + pk.lcQr, + pk.lcQm, + pk.lcQo, + lcqk, wloneiop, ) if err != nil { return nil, err } - h, err := iop.DivideByXMinusOne(testEval, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) + h, err := iop.DivideByXMinusOne(systemEvaluation, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) if err != nil { return nil, err } @@ -398,8 +386,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwliop.Coefficients()[:bwliop.BlindedSize()], bwriop.Coefficients()[:bwriop.BlindedSize()], bwoiop.Coefficients()[:bwoiop.BlindedSize()], - pk.S1Canonical, - pk.S2Canonical, + pk.trace.S1.Coefficients(), + pk.trace.S2.Coefficients(), }, []kzg.Digest{ foldedHDigest, @@ -500,13 +488,12 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, var s1, s2 fr.Element chS1 := make(chan struct{}, 1) go func() { - ps1 := iop.NewPolynomial(&pk.S1Canonical, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) - s1 = ps1.Evaluate(zeta) // s1(ζ) + s1 = pk.trace.S1.Evaluate(zeta) // s1(ζ) s1.Mul(&s1, &beta).Add(&s1, &lZeta).Add(&s1, &gamma) // (l(ζ)+β*s1(ζ)+γ) close(chS1) }() - ps2 := iop.NewPolynomial(&pk.S2Canonical, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) - tmp := ps2.Evaluate(zeta) // s2(ζ) + // ps2 := iop.NewPolynomial(&pk.S2Canonical, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) + tmp := pk.trace.S2.Evaluate(zeta) // s2(ζ) tmp.Mul(&tmp, &beta).Add(&tmp, &rZeta).Add(&tmp, &gamma) // (r(ζ)+β*s2(ζ)+γ) <-chS1 s1.Mul(&s1, &tmp).Mul(&s1, &zu).Mul(&s1, &beta) // (l(ζ)+β*s1(β)+γ)*(r(ζ)+β*s2(β)+γ)*β*Z(μζ) @@ -540,6 +527,7 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, linPol := make([]fr.Element, len(blindedZCanonical)) copy(linPol, blindedZCanonical) + s3canonical := pk.trace.S3.Coefficients() utils.Parallelize(len(linPol), func(start, end int) { var t0, t1 fr.Element @@ -548,26 +536,31 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, linPol[i].Mul(&linPol[i], &s2) // -Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) - if i < len(pk.S3Canonical) { + if i < len(s3canonical) { - t0.Mul(&pk.S3Canonical[i], &s1) // (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*β*s3(X) + t0.Mul(&s3canonical[i], &s1) // (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*β*s3(X) linPol[i].Add(&linPol[i], &t0) } linPol[i].Mul(&linPol[i], &alpha) // α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ)) - if i < len(pk.Qm) { + cql := pk.trace.Ql.Coefficients() + cqr := pk.trace.Qr.Coefficients() + cqm := pk.trace.Qm.Coefficients() + cqo := pk.trace.Qo.Coefficients() + cqk := pk.trace.Qk.Coefficients() + if i < len(cqm) { - t1.Mul(&pk.Qm[i], &rl) // linPol = linPol + l(ζ)r(ζ)*Qm(X) - t0.Mul(&pk.Ql[i], &lZeta) + t1.Mul(&cqm[i], &rl) // linPol = linPol + l(ζ)r(ζ)*Qm(X) + t0.Mul(&cql[i], &lZeta) t0.Add(&t0, &t1) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + l(ζ)*Ql(X) - t0.Mul(&pk.Qr[i], &rZeta) + t0.Mul(&cqr[i], &rZeta) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + r(ζ)*Qr(X) - t0.Mul(&pk.Qo[i], &oZeta).Add(&t0, &pk.CQk[i]) + t0.Mul(&cqo[i], &oZeta).Add(&t0, &cqk[i]) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) } @@ -576,4 +569,4 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, } }) return linPol -} +} \ No newline at end of file diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl index 810078c132..7ed8f472c7 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl @@ -5,48 +5,30 @@ import ( {{- template "import_fft" . }} {{- template "import_backend_cs" . }} "github.com/consensys/gnark-crypto/ecc/{{toLower .Curve}}/fr/iop" + "github.com/consensys/gnark-crypto/ecc" kzgg "github.com/consensys/gnark-crypto/kzg" ) -// ProvingKey stores the data needed to generate a proof: -// * the commitment scheme -// * ql, prepended with as many ones as they are public inputs -// * qr, qm, qo prepended with as many zeroes as there are public inputs. -// * qk, prepended with as many zeroes as public inputs, to be completed by the prover -// with the list of public inputs. -// * sigma_1, sigma_2, sigma_3 in both basis -// * the copy constraint permutation -type ProvingKey struct { - // Verifying Key is embedded into the proving key (needed by Prove) - Vk *VerifyingKey - - // TODO store iop.Polynomial here, not []fr.Element for more "type safety" - - // qr,ql,qm,qo (in canonical basis). - Ql, Qr, Qm, Qo []fr.Element - - // qr,ql,qm,qo (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. - lQl, lQr, lQm, lQo []fr.Element - - // LQk (CQk) qk in Lagrange basis (canonical basis), prepended with as many zeroes as public inputs. - // Storing LQk in Lagrange basis saves a fft... - CQk, LQk []fr.Element - - // Domains used for the FFTs. - // Domain[0] = small Domain - // Domain[1] = big Domain - Domain [2]fft.Domain - // Domain[0], Domain[1] fft.Domain - - // Permutation polynomials - S1Canonical, S2Canonical, S3Canonical []fr.Element - - // in lagrange coset basis --> these are not serialized, but computed from S1Canonical, S2Canonical, S3Canonical once. - lS1LagrangeCoset, lS2LagrangeCoset, lS3LagrangeCoset []fr.Element - - // position -> permuted position (position in [0,3*sizeSystem-1]) - Permutation []int64 +// Trace stores a plonk trace as columns +type Trace struct { + + // Constants describing a plonk circuit. The first entries + // of LQk (whose index correspond to the public inputs) are set to 0, and are to be + // completed by the prover. At those indices i (so from 0 to nb_public_variables), LQl[i]=-1 + // so the first nb_public_variables constraints look like this: + // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. + Ql, Qr, Qm, Qo, Qk *iop.Polynomial + + // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. + // The set of interpolation is of size N, so to represent the permutation S we let S acts on the + // set A=(, u*, u^{2}*) of size 3*N, where u is outside (its use is to shift the set ). + // We obtain a permutation of A, A'. We split A' in 3 (A'_{1}, A'_{2}, A'_{3}), and S1, S2, S3 are + // respectively the interpolation of A'_{1}, A'_{2}, A'_{3} on . + S1, S2, S3 *iop.Polynomial + + // S full permutation, i -> S[i] + S []int64 } // VerifyingKey stores the data needed to verify a proof: @@ -55,6 +37,7 @@ type ProvingKey struct { // * Commitments of qr, qm, qo, qk prepended with as many zeroes as there are public inputs // * Commitments to S1, S2, S3 type VerifyingKey struct { + // Size circuit Size uint64 SizeInv fr.Element @@ -75,115 +58,235 @@ type VerifyingKey struct { Ql, Qr, Qm, Qo, Qk kzg.Digest } -// Setup sets proving and verifying keys +// ProvingKey stores the data needed to generate a proof: +// * the commitment scheme +// * ql, prepended with as many ones as they are public inputs +// * qr, qm, qo prepended with as many zeroes as there are public inputs. +// * qk, prepended with as many zeroes as public inputs, to be completed by the prover +// with the list of public inputs. +// * sigma_1, sigma_2, sigma_3 in both basis +// * the copy constraint permutation +type ProvingKey struct { + + // stores ql, qr, qm, qo, qk (-> to be completed by the prover) + // and s1, s2, s3. They are set in canonical basis before generating the proof, they will be used + // for computing the opening proofs (hence the canonical form). The canonical version + // of qk incompleted is used in the linearisation polynomial. + // The polynomials in trace are in canonical basis. + trace Trace + + // Verifying Key is embedded into the proving key (needed by Prove) + Vk *VerifyingKey + + // qr,ql,qm,qo in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. + lcQl, lcQr, lcQm, lcQo *iop.Polynomial + + // LQk qk in Lagrange form -> to be completed by the prover. After being completed, + lQk *iop.Polynomial + + // Domains used for the FFTs. + // Domain[0] = small Domain + // Domain[1] = big Domain + Domain [2]fft.Domain + + // in lagrange coset basis --> these are not serialized, but computed from S1Canonical, S2Canonical, S3Canonical once. + lcS1, lcS2, lcS3 *iop.Polynomial +} + func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) { + var pk ProvingKey var vk VerifyingKey - - // The verifying key shares data with the proving key pk.Vk = &vk + // nbConstraints := len(spr.Constraints) - nbConstraints := len(spr.Constraints) + // step 0: set the fft domains + pk.initDomains(spr) - // fft domains - sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints - pk.Domain[0] = *fft.NewDomain(sizeSystem) + // step 1: set the verifying key pk.Vk.CosetShift.Set(&pk.Domain[0].FrMultiplicativeGen) - - // h, the quotient polynomial is of degree 3(n+1)+2, so it's in a 3(n+2) dim vector space, - // the domain is the next power of 2 superior to 3(n+2). 4*domainNum is enough in all cases - // except when n<6. - if sizeSystem < 6 { - pk.Domain[1] = *fft.NewDomain(8 * sizeSystem) - } else { - pk.Domain[1] = *fft.NewDomain(4 * sizeSystem) - } - vk.Size = pk.Domain[0].Cardinality vk.SizeInv.SetUint64(vk.Size).Inverse(&vk.SizeInv) vk.Generator.Set(&pk.Domain[0].Generator) vk.NbPublicVariables = uint64(len(spr.Public)) - if err := pk.InitKZG(srs); err != nil { return nil, nil, err } - // public polynomials corresponding to constraints: [ placholders | constraints | assertions ] - pk.Ql = make([]fr.Element, pk.Domain[0].Cardinality) - pk.Qr = make([]fr.Element, pk.Domain[0].Cardinality) - pk.Qm = make([]fr.Element, pk.Domain[0].Cardinality) - pk.Qo = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQk = make([]fr.Element, pk.Domain[0].Cardinality) - pk.LQk = make([]fr.Element, pk.Domain[0].Cardinality) + // step 2: ql, qr, qm, qo, qk in Lagrange Basis + BuildTrace(spr, &pk.trace) + + // step 3: build the permutation and build the polynomials S1, S2, S3 to encode the permutation. + // Note: at this stage, the permutation takes in account the placeholders + nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) + buildPermutation(spr, &pk.trace, nbVariables) + s := computePermutationPolynomials(&pk.trace, &pk.Domain[0]) + pk.trace.S1 = s[0] + pk.trace.S2 = s[1] + pk.trace.S3 = s[2] + + // step 4: commit to s1, s2, s3, ql, qr, qm, qo, and (the incomplete version of) qk. + // All the above polynomials are expressed in canonical basis afterwards. This is why + // we save lqk before, because the prover needs to complete it in Lagrange form, and + // then express it on the Lagrange coset basis. + pk.lQk = pk.trace.Qk.Clone() // it will be completed by the prover, and the evaluated on the coset + err := commitTrace(&pk.trace, &pk) + if err != nil { + return nil, nil, err + } + + // step 5: evaluate ql, qr, qm, qo, s1, s2, s3 on LagrangeCoset (NOT qk) + // we clone them, because the canonical versions are going to be used in + // the opening proof + pk.computeLagrangeCosetPolys() + + return &pk, &vk, nil +} + +// computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset +// basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. +func (pk *ProvingKey) computeLagrangeCosetPolys() { + pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQo = pk.trace.Qo.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcS1 = pk.trace.S1.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcS2 = pk.trace.S2.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcS3 = pk.trace.S3.Clone().ToLagrangeCoset(&pk.Domain[1]) +} + +// NbPublicWitness returns the expected public witness size (number of field elements) +func (vk *VerifyingKey) NbPublicWitness() int { + return int(vk.NbPublicVariables) +} + +// VerifyingKey returns pk.Vk +func (pk *ProvingKey) VerifyingKey() interface{} { + return pk.Vk +} + +// InitKZG inits pk.Vk.KZG using pk.Domain[0] cardinality and provided SRS +// +// This should be used after deserializing a ProvingKey +// as pk.Vk.KZG is NOT serialized +func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { + return pk.Vk.InitKZG(srs) +} + +// InitKZG inits vk.KZG using provided SRS +// +// This should be used after deserializing a VerifyingKey +// as vk.KZG is NOT serialized +// +// Note that this instantiate a new FFT domain using vk.Size +func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { + _srs := srs.(*kzg.SRS) + + if len(_srs.G1) < int(vk.Size) { + return errors.New("kzg srs is too small") + } + vk.KZGSRS = _srs + + return nil +} + +// BuildTrace fills the constatn columns ql, qr, qm, qo, qk from the sparser1cs. +// Size is the size of the system that is nb_constraints+nb_public_variables +func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { + + nbConstraints := len(spr.Constraints) + sizeSystem := uint64(nbConstraints + len(spr.Public)) + size := ecc.NextPowerOfTwo(uint64(sizeSystem)) + + ql := make([]fr.Element, size) + qr := make([]fr.Element, size) + qm := make([]fr.Element, size) + qo := make([]fr.Element, size) + qk := make([]fr.Element, size) for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistant - pk.Ql[i].SetOne().Neg(&pk.Ql[i]) - pk.Qr[i].SetZero() - pk.Qm[i].SetZero() - pk.Qo[i].SetZero() - pk.CQk[i].SetZero() - pk.LQk[i].SetZero() // → to be completed by the prover + ql[i].SetOne().Neg(&ql[i]) + qr[i].SetZero() + qm[i].SetZero() + qo[i].SetZero() + qk[i].SetZero() // → to be completed by the prover } offset := len(spr.Public) for i := 0; i < nbConstraints; i++ { // constraints - pk.Ql[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) - pk.Qr[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) - pk.Qm[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). - Mul(&pk.Qm[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) - pk.Qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) - pk.CQk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) - pk.LQk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) + ql[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) + qr[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) + qm[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). + Mul(&qm[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) + qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) + qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } - pk.Domain[0].FFTInverse(pk.Ql, fft.DIF) - pk.Domain[0].FFTInverse(pk.Qr, fft.DIF) - pk.Domain[0].FFTInverse(pk.Qm, fft.DIF) - pk.Domain[0].FFTInverse(pk.Qo, fft.DIF) - pk.Domain[0].FFTInverse(pk.CQk, fft.DIF) - fft.BitReverse(pk.Ql) - fft.BitReverse(pk.Qr) - fft.BitReverse(pk.Qm) - fft.BitReverse(pk.Qo) - fft.BitReverse(pk.CQk) + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} - // build permutation. Note: at this stage, the permutation takes in account the placeholders - buildPermutation(spr, &pk) + pt.Ql = iop.NewPolynomial(&ql, lagReg) + pt.Qr = iop.NewPolynomial(&qr, lagReg) + pt.Qm = iop.NewPolynomial(&qm, lagReg) + pt.Qo = iop.NewPolynomial(&qo, lagReg) + pt.Qk = iop.NewPolynomial(&qk, lagReg) - // set s1, s2, s3 - ccomputePermutationPolynomials(&pk) +} - // compute the lagrange coset basis versions (not serialized) - pk.computeLagrangeCosetPolys() +// commitTrace commits to every polynomials in the trace, and put +// the commitments int the verifying key. +func commitTrace(trace *Trace, pk *ProvingKey) error { + + trace.Ql.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qr.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qm.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qo.ToCanonical(&pk.Domain[0]).ToRegular() + trace.Qk.ToCanonical(&pk.Domain[0]).ToRegular() // -> qk is not complete + trace.S1.ToCanonical(&pk.Domain[0]).ToRegular() + trace.S2.ToCanonical(&pk.Domain[0]).ToRegular() + trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() - // Commit to the polynomials to set up the verifying key var err error - if vk.Ql, err = kzg.Commit(pk.Ql, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qr, err = kzg.Commit(pk.Qr, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qr, err = kzg.Commit(pk.trace.Qr.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qm, err = kzg.Commit(pk.Qm, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qm, err = kzg.Commit(pk.trace.Qm.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qo, err = kzg.Commit(pk.Qo, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qo, err = kzg.Commit(pk.trace.Qo.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.Qk, err = kzg.Commit(pk.CQk, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.S[0], err = kzg.Commit(pk.S1Canonical, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.S[1], err = kzg.Commit(pk.S2Canonical, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.S[1], err = kzg.Commit(pk.trace.S2.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } - if vk.S[2], err = kzg.Commit(pk.S3Canonical, vk.KZGSRS); err != nil { - return nil, nil, err + if pk.Vk.S[2], err = kzg.Commit(pk.trace.S3.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err } + return nil +} - return &pk, &vk, nil +func (pk *ProvingKey) initDomains(spr *cs.SparseR1CS) { + + nbConstraints := len(spr.Constraints) + sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints + pk.Domain[0] = *fft.NewDomain(sizeSystem) + + // h, the quotient polynomial is of degree 3(n+1)+2, so it's in a 3(n+2) dim vector space, + // the domain is the next power of 2 superior to 3(n+2). 4*domainNum is enough in all cases + // except when n<6. + if sizeSystem < 6 { + pk.Domain[1] = *fft.NewDomain(8 * sizeSystem) + } else { + pk.Domain[1] = *fft.NewDomain(4 * sizeSystem) + } } @@ -191,27 +294,28 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // // The permutation s is composed of cycles of maximum length such that // -// s. (l∥r∥o) = (l∥r∥o) +// s. (l∥r∥o) = (l∥r∥o) // -//, where l∥r∥o is the concatenation of the indices of l, r, o in +// , where l∥r∥o is the concatenation of the indices of l, r, o in // ql.l+qr.r+qm.l.r+qo.O+k = 0. // // The permutation is encoded as a slice s of size 3*size(l), where the // i-th entry of l∥r∥o is sent to the s[i]-th entry, so it acts on a tab // like this: for i in tab: tab[i] = tab[permutation[i]] -func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { +func buildPermutation(spr *cs.SparseR1CS, pt *Trace, nbVariables int) { - nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) - sizeSolution := int(pk.Domain[0].Cardinality) + // nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) + sizeSolution := len(pt.Ql.Coefficients()) + sizePermutation := 3 * sizeSolution // init permutation - pk.Permutation = make([]int64, 3*sizeSolution) - for i := 0; i < len(pk.Permutation); i++ { - pk.Permutation[i] = -1 + permutation := make([]int64, sizePermutation) + for i := 0; i < len(permutation); i++ { + permutation[i] = -1 } // init LRO position -> variable_ID - lro := make([]int, 3*sizeSolution) // position -> variable_ID + lro := make([]int, sizePermutation) // position -> variable_ID for i := 0; i < len(spr.Public); i++ { lro[i] = i // IDs of LRO associated to placeholders (only L needs to be taken care of) } @@ -234,92 +338,54 @@ func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { if cycle[lro[i]] != -1 { // if != -1, it means we already encountered this value // so we need to set the corresponding permutation index. - pk.Permutation[i] = cycle[lro[i]] + permutation[i] = cycle[lro[i]] } cycle[lro[i]] = int64(i) } // complete the Permutation by filling the first IDs encountered - for i := 0; i < len(pk.Permutation); i++ { - if pk.Permutation[i] == -1 { - pk.Permutation[i] = cycle[lro[i]] + for i := 0; i < sizePermutation; i++ { + if permutation[i] == -1 { + permutation[i] = cycle[lro[i]] } } -} -func (pk *ProvingKey) computeLagrangeCosetPolys() { - canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} - wqliop := iop.NewPolynomial(clone(pk.Ql, pk.Domain[1].Cardinality), canReg) - wqriop := iop.NewPolynomial(clone(pk.Qr, pk.Domain[1].Cardinality), canReg) - wqmiop := iop.NewPolynomial(clone(pk.Qm, pk.Domain[1].Cardinality), canReg) - wqoiop := iop.NewPolynomial(clone(pk.Qo, pk.Domain[1].Cardinality), canReg) - - ws1 := iop.NewPolynomial(clone(pk.S1Canonical, pk.Domain[1].Cardinality), canReg) - ws2 := iop.NewPolynomial(clone(pk.S2Canonical, pk.Domain[1].Cardinality), canReg) - ws3 := iop.NewPolynomial(clone(pk.S3Canonical, pk.Domain[1].Cardinality), canReg) - - wqliop.ToLagrangeCoset(&pk.Domain[1]) - wqriop.ToLagrangeCoset(&pk.Domain[1]) - wqmiop.ToLagrangeCoset(&pk.Domain[1]) - wqoiop.ToLagrangeCoset(&pk.Domain[1]) - - ws1.ToLagrangeCoset(&pk.Domain[1]) - ws2.ToLagrangeCoset(&pk.Domain[1]) - ws3.ToLagrangeCoset(&pk.Domain[1]) - - pk.lQl = wqliop.Coefficients() - pk.lQr = wqriop.Coefficients() - pk.lQm = wqmiop.Coefficients() - pk.lQo = wqoiop.Coefficients() - - pk.lS1LagrangeCoset = ws1.Coefficients() - pk.lS2LagrangeCoset = ws2.Coefficients() - pk.lS3LagrangeCoset = ws3.Coefficients() + pt.S = permutation } -func clone(input []fr.Element, capacity uint64) *[]fr.Element { - res := make([]fr.Element, len(input), capacity) - copy(res, input) - return &res -} +// computePermutationPolynomials computes the LDE (Lagrange basis) of the permutation. +// We let the permutation act on || u || u^{2}, split the result in 3 parts, +// and interpolate each of the 3 parts on . +func computePermutationPolynomials(pt *Trace, domain *fft.Domain) [3]*iop.Polynomial { -// ccomputePermutationPolynomials computes the LDE (Lagrange basis) of the permutations -// s1, s2, s3. -// -// 1 z .. z**n-1 | u uz .. u*z**n-1 | u**2 u**2*z .. u**2*z**n-1 | -// | -// | Permutation -// s11 s12 .. s1n s21 s22 .. s2n s31 s32 .. s3n v -// \---------------/ \--------------------/ \------------------------/ -// s1 (LDE) s2 (LDE) s3 (LDE) -func ccomputePermutationPolynomials(pk *ProvingKey) { + nbElmts := int(domain.Cardinality) - nbElmts := int(pk.Domain[0].Cardinality) + var res [3]*iop.Polynomial // Lagrange form of ID - evaluationIDSmallDomain := getIDSmallDomain(&pk.Domain[0]) + evaluationIDSmallDomain := getSupportPermutation(domain) // Lagrange form of S1, S2, S3 - pk.S1Canonical = make([]fr.Element, nbElmts) - pk.S2Canonical = make([]fr.Element, nbElmts) - pk.S3Canonical = make([]fr.Element, nbElmts) + s1Canonical := make([]fr.Element, nbElmts) + s2Canonical := make([]fr.Element, nbElmts) + s3Canonical := make([]fr.Element, nbElmts) for i := 0; i < nbElmts; i++ { - pk.S1Canonical[i].Set(&evaluationIDSmallDomain[pk.Permutation[i]]) - pk.S2Canonical[i].Set(&evaluationIDSmallDomain[pk.Permutation[nbElmts+i]]) - pk.S3Canonical[i].Set(&evaluationIDSmallDomain[pk.Permutation[2*nbElmts+i]]) + s1Canonical[i].Set(&evaluationIDSmallDomain[pt.S[i]]) + s2Canonical[i].Set(&evaluationIDSmallDomain[pt.S[nbElmts+i]]) + s3Canonical[i].Set(&evaluationIDSmallDomain[pt.S[2*nbElmts+i]]) } - // Canonical form of S1, S2, S3 - pk.Domain[0].FFTInverse(pk.S1Canonical, fft.DIF) - pk.Domain[0].FFTInverse(pk.S2Canonical, fft.DIF) - pk.Domain[0].FFTInverse(pk.S3Canonical, fft.DIF) - fft.BitReverse(pk.S1Canonical) - fft.BitReverse(pk.S2Canonical) - fft.BitReverse(pk.S3Canonical) + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + res[0] = iop.NewPolynomial(&s1Canonical, lagReg) + res[1] = iop.NewPolynomial(&s2Canonical, lagReg) + res[2] = iop.NewPolynomial(&s3Canonical, lagReg) + + return res } -// getIDSmallDomain returns the Lagrange form of ID on the small domain -func getIDSmallDomain(domain *fft.Domain) []fr.Element { +// getSupportPermutation returns the support on which the permutation acts, it is +// || u || u^{2} +func getSupportPermutation(domain *fft.Domain) []fr.Element { res := make([]fr.Element, 3*domain.Cardinality) @@ -334,39 +400,4 @@ func getIDSmallDomain(domain *fft.Domain) []fr.Element { } return res -} - -// InitKZG inits pk.Vk.KZG using pk.Domain[0] cardinality and provided SRS -// -// This should be used after deserializing a ProvingKey -// as pk.Vk.KZG is NOT serialized -func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { - return pk.Vk.InitKZG(srs) -} - -// InitKZG inits vk.KZG using provided SRS -// -// This should be used after deserializing a VerifyingKey -// as vk.KZG is NOT serialized -// -// Note that this instantiate a new FFT domain using vk.Size -func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { - _srs := srs.(*kzg.SRS) - - if len(_srs.G1) < int(vk.Size) { - return errors.New("kzg srs is too small") - } - vk.KZGSRS = _srs - - return nil -} - -// NbPublicWitness returns the expected public witness size (number of field elements) -func (vk *VerifyingKey) NbPublicWitness() int { - return int(vk.NbPublicVariables) -} - -// VerifyingKey returns pk.Vk -func (pk *ProvingKey) VerifyingKey() interface{} { - return pk.Vk -} +} \ No newline at end of file diff --git a/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl index 2c5ed3824d..352a98012d 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl @@ -10,12 +10,12 @@ import ( "math/rand" "io" gnarkio "github.com/consensys/gnark/io" + "github.com/consensys/gnark-crypto/ecc/{{toLower .Curve}}/fr/iop" ) - func TestProofSerialization(t *testing.T) { // create a proof - var proof, reconstructed Proof + var proof, reconstructed Proof proof.randomize() roundTripCheck(t, &proof, &reconstructed) @@ -23,7 +23,7 @@ func TestProofSerialization(t *testing.T) { func TestProofSerializationRaw(t *testing.T) { // create a proof - var proof, reconstructed Proof + var proof, reconstructed Proof proof.randomize() roundTripCheckRaw(t, &proof, &reconstructed) @@ -45,8 +45,6 @@ func TestVerifyingKeySerialization(t *testing.T) { roundTripCheck(t, &vk, &reconstructed) } - - func roundTripCheck(t *testing.T, from io.WriterTo, reconstructed io.ReaderFrom) { var buf bytes.Buffer written, err := from.WriteTo(&buf) @@ -89,29 +87,41 @@ func roundTripCheckRaw(t *testing.T, from gnarkio.WriterRawTo, reconstructed io. } } - func (pk *ProvingKey) randomize() { + var vk VerifyingKey vk.randomize() pk.Vk = &vk pk.Domain[0] = *fft.NewDomain(42) pk.Domain[1] = *fft.NewDomain(4 * 42) - - n := int(pk.Domain[0].Cardinality) - pk.Ql = randomScalars(n) - pk.Qr = randomScalars(n) - pk.Qm = randomScalars(n) - pk.Qo = randomScalars(n) - pk.CQk = randomScalars(n) - pk.LQk = randomScalars(n) - pk.S1Canonical = randomScalars(n) - pk.S2Canonical = randomScalars(n) - pk.S3Canonical = randomScalars(n) - - pk.Permutation = make([]int64, 3*pk.Domain[0].Cardinality) - pk.Permutation[0] = -12 - pk.Permutation[len(pk.Permutation)-1] = 8888 + n := int(pk.Domain[0].Cardinality) + ql := randomScalars(n) + qr := randomScalars(n) + qm := randomScalars(n) + qo := randomScalars(n) + qk := randomScalars(n) + lqk := randomScalars(n) + s1 := randomScalars(n) + s2 := randomScalars(n) + s3 := randomScalars(n) + + canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} + pk.trace.Ql = iop.NewPolynomial(&ql, canReg) + pk.trace.Qr = iop.NewPolynomial(&qr, canReg) + pk.trace.Qm = iop.NewPolynomial(&qm, canReg) + pk.trace.Qo = iop.NewPolynomial(&qo, canReg) + pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.S1 = iop.NewPolynomial(&s1, canReg) + pk.trace.S2 = iop.NewPolynomial(&s2, canReg) + pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) + pk.trace.S[0] = -12 + pk.trace.S[len(pk.trace.S)-1] = 8888 + + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + pk.lQk = iop.NewPolynomial(&lqk, lagReg) pk.computeLagrangeCosetPolys() } @@ -153,7 +163,7 @@ func randomPoint() curve.G1Affine { return r } -func randomScalars( n int) []fr.Element { +func randomScalars(n int) []fr.Element { v := make([]fr.Element, n) one := fr.One() for i := 0; i < len(v); i++ { @@ -163,5 +173,5 @@ func randomScalars( n int) []fr.Element { v[i].Add(&v[i-1], &one) } } - return v -} + return v +} \ No newline at end of file From c4a129cb1c5e755ffb9887dcfa8815542f1daad8 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Thu, 16 Mar 2023 15:46:16 +0100 Subject: [PATCH 139/464] feat(emulated/bls12-381): adds Fp12 tower for bls12-381 --- std/algebra/emulated/fields_bls12381/doc.go | 7 + std/algebra/emulated/fields_bls12381/e12.go | 408 +++++++++++++++ .../emulated/fields_bls12381/e12_pairing.go | 99 ++++ .../emulated/fields_bls12381/e12_test.go | 492 ++++++++++++++++++ std/algebra/emulated/fields_bls12381/e2.go | 288 ++++++++++ .../emulated/fields_bls12381/e2_test.go | 365 +++++++++++++ std/algebra/emulated/fields_bls12381/e6.go | 245 +++++++++ .../emulated/fields_bls12381/e6_test.go | 342 ++++++++++++ std/algebra/emulated/fields_bls12381/hints.go | 210 ++++++++ std/math/emulated/params.go | 11 + 10 files changed, 2467 insertions(+) create mode 100644 std/algebra/emulated/fields_bls12381/doc.go create mode 100644 std/algebra/emulated/fields_bls12381/e12.go create mode 100644 std/algebra/emulated/fields_bls12381/e12_pairing.go create mode 100644 std/algebra/emulated/fields_bls12381/e12_test.go create mode 100644 std/algebra/emulated/fields_bls12381/e2.go create mode 100644 std/algebra/emulated/fields_bls12381/e2_test.go create mode 100644 std/algebra/emulated/fields_bls12381/e6.go create mode 100644 std/algebra/emulated/fields_bls12381/e6_test.go create mode 100644 std/algebra/emulated/fields_bls12381/hints.go diff --git a/std/algebra/emulated/fields_bls12381/doc.go b/std/algebra/emulated/fields_bls12381/doc.go new file mode 100644 index 0000000000..c94c08b683 --- /dev/null +++ b/std/algebra/emulated/fields_bls12381/doc.go @@ -0,0 +1,7 @@ +// Package fields_bls12381 implements the fields arithmetic of the Fp12 tower +// used to compute the pairing over the BLS12-381 curve. +// +// 𝔽p²[u] = 𝔽p/u²+1 +// 𝔽p⁶[v] = 𝔽p²/v³-1-u +// 𝔽p¹²[w] = 𝔽p⁶/w²-v +package fields_bls12381 diff --git a/std/algebra/emulated/fields_bls12381/e12.go b/std/algebra/emulated/fields_bls12381/e12.go new file mode 100644 index 0000000000..127daeb0e3 --- /dev/null +++ b/std/algebra/emulated/fields_bls12381/e12.go @@ -0,0 +1,408 @@ +package fields_bls12381 + +import ( + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" +) + +type E12 struct { + C0, C1 E6 +} + +type Ext12 struct { + *Ext6 +} + +func NewExt12(baseField *curveF) *Ext12 { + return &Ext12{Ext6: NewExt6(baseField)} +} + +func (e Ext12) Add(x, y *E12) *E12 { + z0 := e.Ext6.Add(&x.C0, &y.C0) + z1 := e.Ext6.Add(&x.C1, &y.C1) + return &E12{ + C0: *z0, + C1: *z1, + } +} + +func (e Ext12) Sub(x, y *E12) *E12 { + z0 := e.Ext6.Sub(&x.C0, &y.C0) + z1 := e.Ext6.Sub(&x.C1, &y.C1) + return &E12{ + C0: *z0, + C1: *z1, + } +} + +func (e Ext12) Conjugate(x *E12) *E12 { + z1 := e.Ext6.Neg(&x.C1) + return &E12{ + C0: x.C0, + C1: *z1, + } +} + +func (e Ext12) Mul(x, y *E12) *E12 { + a := e.Ext6.Add(&x.C0, &x.C1) + b := e.Ext6.Add(&y.C0, &y.C1) + a = e.Ext6.Mul(a, b) + b = e.Ext6.Mul(&x.C0, &y.C0) + c := e.Ext6.Mul(&x.C1, &y.C1) + z1 := e.Ext6.Sub(a, b) + z1 = e.Ext6.Sub(z1, c) + z0 := e.Ext6.MulByNonResidue(c) + z0 = e.Ext6.Add(z0, b) + return &E12{ + C0: *z0, + C1: *z1, + } +} + +func (e Ext12) CyclotomicSquare(x *E12) *E12 { + t0 := e.Ext2.Square(&x.C1.B1) + t1 := e.Ext2.Square(&x.C0.B0) + t6 := e.Ext2.Add(&x.C1.B1, &x.C0.B0) + t6 = e.Ext2.Square(t6) + t6 = e.Ext2.Sub(t6, t0) + t6 = e.Ext2.Sub(t6, t1) + t2 := e.Ext2.Square(&x.C0.B2) + t3 := e.Ext2.Square(&x.C1.B0) + t7 := e.Ext2.Add(&x.C0.B2, &x.C1.B0) + t7 = e.Ext2.Square(t7) + t7 = e.Ext2.Sub(t7, t2) + t7 = e.Ext2.Sub(t7, t3) + t4 := e.Ext2.Square(&x.C1.B2) + t5 := e.Ext2.Square(&x.C0.B1) + t8 := e.Ext2.Add(&x.C1.B2, &x.C0.B1) + t8 = e.Ext2.Square(t8) + t8 = e.Ext2.Sub(t8, t4) + t8 = e.Ext2.Sub(t8, t5) + t8 = e.Ext2.MulByNonResidue(t8) + t0 = e.Ext2.MulByNonResidue(t0) + t0 = e.Ext2.Add(t0, t1) + t2 = e.Ext2.MulByNonResidue(t2) + t2 = e.Ext2.Add(t2, t3) + t4 = e.Ext2.MulByNonResidue(t4) + t4 = e.Ext2.Add(t4, t5) + z00 := e.Ext2.Sub(t0, &x.C0.B0) + z00 = e.Ext2.Double(z00) + z00 = e.Ext2.Add(z00, t0) + z01 := e.Ext2.Sub(t2, &x.C0.B1) + z01 = e.Ext2.Double(z01) + z01 = e.Ext2.Add(z01, t2) + z02 := e.Ext2.Sub(t4, &x.C0.B2) + z02 = e.Ext2.Double(z02) + z02 = e.Ext2.Add(z02, t4) + z10 := e.Ext2.Add(t8, &x.C1.B0) + z10 = e.Ext2.Double(z10) + z10 = e.Ext2.Add(z10, t8) + z11 := e.Ext2.Add(t6, &x.C1.B1) + z11 = e.Ext2.Double(z11) + z11 = e.Ext2.Add(z11, t6) + z12 := e.Ext2.Add(t7, &x.C1.B2) + z12 = e.Ext2.Double(z12) + z12 = e.Ext2.Add(z12, t7) + return &E12{ + C0: E6{ + B0: *z00, + B1: *z01, + B2: *z02, + }, + C1: E6{ + B0: *z10, + B1: *z11, + B2: *z12, + }, + } +} + +// Karabina's compressed cyclotomic square +// https://eprint.iacr.org/2010/542.pdf +// Th. 3.2 with minor modifications to fit our tower +func (e Ext12) CyclotomicSquareCompressed(x *E12) *E12 { + + // t0 = g1² + t0 := e.Ext2.Square(&x.C0.B1) + // t1 = g5² + t1 := e.Ext2.Square(&x.C1.B2) + // t5 = g1 + g5 + t5 := e.Ext2.Add(&x.C0.B1, &x.C1.B2) + // t2 = (g1 + g5)² + t2 := e.Ext2.Square(t5) + + // t3 = g1² + g5² + t3 := e.Ext2.Add(t0, t1) + // t5 = 2 * g1 * g5 + t5 = e.Ext2.Sub(t2, t3) + + // t6 = g3 + g2 + t6 := e.Ext2.Add(&x.C1.B0, &x.C0.B2) + // t3 = (g3 + g2)² + t3 = e.Ext2.Square(t6) + // t2 = g3² + t2 = e.Ext2.Square(&x.C1.B0) + + // t6 = 2 * nr * g1 * g5 + t6 = e.Ext2.MulByNonResidue(t5) + // t5 = 4 * nr * g1 * g5 + 2 * g3 + t5 = e.Ext2.Add(t6, &x.C1.B0) + t5 = e.Ext2.Double(t5) + // z3 = 6 * nr * g1 * g5 + 2 * g3 + C1B0 := e.Ext2.Add(t5, t6) + + // t4 = nr * g5² + t4 := e.Ext2.MulByNonResidue(t1) + // t5 = nr * g5² + g1² + t5 = e.Ext2.Add(t0, t4) + // t6 = nr * g5² + g1² - g2 + t6 = e.Ext2.Sub(t5, &x.C0.B2) + + // t1 = g2² + t1 = e.Ext2.Square(&x.C0.B2) + + // t6 = 2 * nr * g5² + 2 * g1² - 2*g2 + t6 = e.Ext2.Double(t6) + // z2 = 3 * nr * g5² + 3 * g1² - 2*g2 + C0B2 := e.Ext2.Add(t6, t5) + + // t4 = nr * g2² + t4 = e.Ext2.MulByNonResidue(t1) + // t5 = g3² + nr * g2² + t5 = e.Ext2.Add(t2, t4) + // t6 = g3² + nr * g2² - g1 + t6 = e.Ext2.Sub(t5, &x.C0.B1) + // t6 = 2 * g3² + 2 * nr * g2² - 2 * g1 + t6 = e.Ext2.Double(t6) + // z1 = 3 * g3² + 3 * nr * g2² - 2 * g1 + C0B1 := e.Ext2.Add(t6, t5) + + // t0 = g2² + g3² + t0 = e.Ext2.Add(t2, t1) + // t5 = 2 * g3 * g2 + t5 = e.Ext2.Sub(t3, t0) + // t6 = 2 * g3 * g2 + g5 + t6 = e.Ext2.Add(t5, &x.C1.B2) + // t6 = 4 * g3 * g2 + 2 * g5 + t6 = e.Ext2.Double(t6) + // z5 = 6 * g3 * g2 + 2 * g5 + C1B2 := e.Ext2.Add(t5, t6) + + zero := e.Ext2.Zero() + + return &E12{ + C0: E6{ + B0: *zero, + B1: *C0B1, + B2: *C0B2, + }, + C1: E6{ + B0: *C1B0, + B1: *zero, + B2: *C1B2, + }, + } +} + +func (e Ext12) NCycloSquareCompressed(z *E12, n int) *E12 { + for i := 0; i < n; i++ { + z = e.CyclotomicSquareCompressed(z) + } + return z +} + +// DecompressKarabina Karabina's cyclotomic square result +func (e Ext12) DecompressKarabina(x *E12) *E12 { + + one := e.Ext2.One() + + // TODO: hadle the g3==0 case with MUX + + // t0 = g1² + t0 := e.Ext2.Square(&x.C0.B1) + // t1 = 3 * g1² - 2 * g2 + t1 := e.Ext2.Sub(t0, &x.C0.B2) + t1 = e.Ext2.Double(t1) + t1 = e.Ext2.Add(t1, t0) + // t0 = E * g5² + t1 + t2 := e.Ext2.Square(&x.C1.B2) + t0 = e.Ext2.MulByNonResidue(t2) + t0 = e.Ext2.Add(t0, t1) + // t1 = 4 * g3 + t1 = e.Ext2.Double(&x.C1.B0) + t1 = e.Ext2.Double(t1) + + // z4 = g4 + C1B1 := e.Ext2.DivUnchecked(t0, t1) + + // t1 = g2 * g1 + t1 = e.Ext2.Mul(&x.C0.B2, &x.C0.B1) + // t2 = 2 * g4² - 3 * g2 * g1 + t2 = e.Ext2.Square(C1B1) + t2 = e.Ext2.Sub(t2, t1) + t2 = e.Ext2.Double(t2) + t2 = e.Ext2.Sub(t2, t1) + // t1 = g3 * g5 (g3 can be 0) + t1 = e.Ext2.Mul(&x.C1.B0, &x.C1.B2) + // c₀ = E * (2 * g4² + g3 * g5 - 3 * g2 * g1) + 1 + t2 = e.Ext2.Add(t2, t1) + C0B0 := e.Ext2.MulByNonResidue(t2) + C0B0 = e.Ext2.Add(C0B0, one) + + return &E12{ + C0: E6{ + B0: *C0B0, + B1: x.C0.B1, + B2: x.C0.B2, + }, + C1: E6{ + B0: x.C1.B0, + B1: *C1B1, + B2: x.C1.B2, + }, + } +} + +func (e Ext12) Frobenius(x *E12) *E12 { + t0 := e.Ext2.Conjugate(&x.C0.B0) + t1 := e.Ext2.Conjugate(&x.C0.B1) + t2 := e.Ext2.Conjugate(&x.C0.B2) + t3 := e.Ext2.Conjugate(&x.C1.B0) + t4 := e.Ext2.Conjugate(&x.C1.B1) + t5 := e.Ext2.Conjugate(&x.C1.B2) + t1 = e.Ext2.MulByNonResidue1Power2(t1) + t2 = e.Ext2.MulByNonResidue1Power4(t2) + t3 = e.Ext2.MulByNonResidue1Power1(t3) + t4 = e.Ext2.MulByNonResidue1Power3(t4) + t5 = e.Ext2.MulByNonResidue1Power5(t5) + return &E12{ + C0: E6{ + B0: *t0, + B1: *t1, + B2: *t2, + }, + C1: E6{ + B0: *t3, + B1: *t4, + B2: *t5, + }, + } +} + +func (e Ext12) FrobeniusSquare(x *E12) *E12 { + z00 := &x.C0.B0 + z01 := e.Ext2.MulByNonResidue2Power2(&x.C0.B1) + z02 := e.Ext2.MulByNonResidue2Power4(&x.C0.B2) + z10 := e.Ext2.MulByNonResidue2Power1(&x.C1.B0) + z11 := e.Ext2.MulByNonResidue2Power3(&x.C1.B1) + z12 := e.Ext2.MulByNonResidue2Power5(&x.C1.B2) + return &E12{ + C0: E6{B0: *z00, B1: *z01, B2: *z02}, + C1: E6{B0: *z10, B1: *z11, B2: *z12}, + } +} + +func (e Ext12) One() *E12 { + z000 := e.fp.One() + zero := e.fp.Zero() + return &E12{ + C0: E6{ + B0: E2{A0: *z000, A1: *zero}, + B1: E2{A0: *zero, A1: *zero}, + B2: E2{A0: *zero, A1: *zero}, + }, + C1: E6{ + B0: E2{A0: *zero, A1: *zero}, + B1: E2{A0: *zero, A1: *zero}, + B2: E2{A0: *zero, A1: *zero}, + }, + } +} + +func (e Ext12) Square(x *E12) *E12 { + c0 := e.Ext6.Sub(&x.C0, &x.C1) + c3 := e.Ext6.MulByNonResidue(&x.C1) + c3 = e.Ext6.Neg(c3) + c3 = e.Ext6.Add(&x.C0, c3) + c2 := e.Ext6.Mul(&x.C0, &x.C1) + c0 = e.Ext6.Mul(c0, c3) + c0 = e.Ext6.Add(c0, c2) + z1 := e.Ext6.double(c2) + c2 = e.Ext6.MulByNonResidue(c2) + z0 := e.Ext6.Add(c0, c2) + return &E12{ + C0: *z0, + C1: *z1, + } +} + +func (e Ext12) AssertIsEqual(x, y *E12) { + e.Ext6.AssertIsEqual(&x.C0, &y.C0) + e.Ext6.AssertIsEqual(&x.C1, &y.C1) +} + +func FromE12(y *bls12381.E12) E12 { + return E12{ + C0: FromE6(&y.C0), + C1: FromE6(&y.C1), + } + +} + +func (e Ext12) Inverse(x *E12) *E12 { + res, err := e.fp.NewHint(inverseE12Hint, 12, &x.C0.B0.A0, &x.C0.B0.A1, &x.C0.B1.A0, &x.C0.B1.A1, &x.C0.B2.A0, &x.C0.B2.A1, &x.C1.B0.A0, &x.C1.B0.A1, &x.C1.B1.A0, &x.C1.B1.A1, &x.C1.B2.A0, &x.C1.B2.A1) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + inv := E12{ + C0: E6{ + B0: E2{A0: *res[0], A1: *res[1]}, + B1: E2{A0: *res[2], A1: *res[3]}, + B2: E2{A0: *res[4], A1: *res[5]}, + }, + C1: E6{ + B0: E2{A0: *res[6], A1: *res[7]}, + B1: E2{A0: *res[8], A1: *res[9]}, + B2: E2{A0: *res[10], A1: *res[11]}, + }, + } + + one := e.One() + + // 1 == inv * x + _one := e.Mul(&inv, x) + e.AssertIsEqual(one, _one) + + return &inv + +} + +// DivUnchecked e2 elmts +func (e Ext12) DivUnchecked(x, y *E12) *E12 { + res, err := e.fp.NewHint(divE12Hint, 12, &x.C0.B0.A0, &x.C0.B0.A1, &x.C0.B1.A0, &x.C0.B1.A1, &x.C0.B2.A0, &x.C0.B2.A1, &x.C1.B0.A0, &x.C1.B0.A1, &x.C1.B1.A0, &x.C1.B1.A1, &x.C1.B2.A0, &x.C1.B2.A1, &y.C0.B0.A0, &y.C0.B0.A1, &y.C0.B1.A0, &y.C0.B1.A1, &y.C0.B2.A0, &y.C0.B2.A1, &y.C1.B0.A0, &y.C1.B0.A1, &y.C1.B1.A0, &y.C1.B1.A1, &y.C1.B2.A0, &y.C1.B2.A1) + + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + div := E12{ + C0: E6{ + B0: E2{A0: *res[0], A1: *res[1]}, + B1: E2{A0: *res[2], A1: *res[3]}, + B2: E2{A0: *res[4], A1: *res[5]}, + }, + C1: E6{ + B0: E2{A0: *res[6], A1: *res[7]}, + B1: E2{A0: *res[8], A1: *res[9]}, + B2: E2{A0: *res[10], A1: *res[11]}, + }, + } + + // x == div * y + _x := e.Mul(&div, y) + e.AssertIsEqual(x, _x) + + return &div +} diff --git a/std/algebra/emulated/fields_bls12381/e12_pairing.go b/std/algebra/emulated/fields_bls12381/e12_pairing.go new file mode 100644 index 0000000000..2e8636652a --- /dev/null +++ b/std/algebra/emulated/fields_bls12381/e12_pairing.go @@ -0,0 +1,99 @@ +package fields_bls12381 + +// TODO: correct addchain to BLS12-381 seed + +func (e Ext12) Expt(x *E12) *E12 { + // Expt computation is derived from the addition chain: + // + // _10 = 2*1 + // _100 = 2*_10 + // _1000 = 2*_100 + // _10000 = 2*_1000 + // _10001 = 1 + _10000 + // _10011 = _10 + _10001 + // _10100 = 1 + _10011 + // _11001 = _1000 + _10001 + // _100010 = 2*_10001 + // _100111 = _10011 + _10100 + // _101001 = _10 + _100111 + // i27 = (_100010 << 6 + _100 + _11001) << 7 + _11001 + // i44 = (i27 << 8 + _101001 + _10) << 6 + _10001 + // i70 = ((i44 << 8 + _101001) << 6 + _101001) << 10 + // return (_100111 + i70) << 6 + _101001 + _1000 + // + // Operations: 62 squares 17 multiplies + // + // Generated by github.com/mmcloughlin/addchain v0.4.0. + + t3 := e.CyclotomicSquare(x) + t5 := e.CyclotomicSquare(t3) + result := e.CyclotomicSquare(t5) + t0 := e.CyclotomicSquare(result) + t2 := e.Mul(x, t0) + t0 = e.Mul(t3, t2) + t1 := e.Mul(x, t0) + t4 := e.Mul(result, t2) + t6 := e.CyclotomicSquare(t2) + t1 = e.Mul(t0, t1) + t0 = e.Mul(t3, t1) + t6 = e.NCycloSquareCompressed(t6, 6) + t6 = e.DecompressKarabina(t6) + t5 = e.Mul(t5, t6) + t5 = e.Mul(t4, t5) + t5 = e.NCycloSquareCompressed(t5, 7) + t5 = e.DecompressKarabina(t5) + t4 = e.Mul(t4, t5) + t4 = e.NCycloSquareCompressed(t4, 8) + t4 = e.DecompressKarabina(t4) + t4 = e.Mul(t0, t4) + t3 = e.Mul(t3, t4) + t3 = e.NCycloSquareCompressed(t3, 6) + t3 = e.DecompressKarabina(t3) + t2 = e.Mul(t2, t3) + t2 = e.NCycloSquareCompressed(t2, 8) + t2 = e.DecompressKarabina(t2) + t2 = e.Mul(t0, t2) + t2 = e.NCycloSquareCompressed(t2, 6) + t2 = e.DecompressKarabina(t2) + t2 = e.Mul(t0, t2) + t2 = e.NCycloSquareCompressed(t2, 10) + t2 = e.DecompressKarabina(t2) + t1 = e.Mul(t1, t2) + t1 = e.NCycloSquareCompressed(t1, 6) + t1 = e.DecompressKarabina(t1) + t0 = e.Mul(t0, t1) + z := e.Mul(result, t0) + return z +} + +// MulBy014 multiplies z by an E12 sparse element of the form +// +// E12{ +// C0: E6{B0: 1, B1: c1, B2: 0}, +// C1: E6{B0: 0, B1: c4, B2: 0}, +// } +// +// TODO : correct MulByO14 and not 034 +func (e *Ext12) MulBy014(z *E12, c1, c4 *E2) *E12 { + + a := z.C0 + b := z.C1 + + b = *e.MulBy01(&b, c1, c4) + one := e.Ext2.One() + + c1 = e.Ext2.Add(one, c1) + d := e.Ext6.Add(&z.C0, &z.C1) + d = e.MulBy01(d, c1, c4) + + zC1 := e.Ext6.Add(&a, &b) + zC1 = e.Ext6.Neg(zC1) + zC1 = e.Ext6.Add(zC1, d) + zC0 := e.Ext6.MulByNonResidue(&b) + zC0 = e.Ext6.Add(zC0, &a) + + return &E12{ + C0: *zC0, + C1: *zC1, + } +} diff --git a/std/algebra/emulated/fields_bls12381/e12_test.go b/std/algebra/emulated/fields_bls12381/e12_test.go new file mode 100644 index 0000000000..457dcd6c35 --- /dev/null +++ b/std/algebra/emulated/fields_bls12381/e12_test.go @@ -0,0 +1,492 @@ +package fields_bls12381 + +import ( + "testing" + + "github.com/consensys/gnark-crypto/ecc" + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/math/emulated" + "github.com/consensys/gnark/test" +) + +type e12Add struct { + A, B, C E12 +} + +func (circuit *e12Add) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt12(ba) + expected := e.Add(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestAddFp12(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bls12381.E12 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Add(&a, &b) + + witness := e12Add{ + A: FromE12(&a), + B: FromE12(&b), + C: FromE12(&c), + } + + err := test.IsSolved(&e12Add{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) + +} + +type e12Sub struct { + A, B, C E12 +} + +func (circuit *e12Sub) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt12(ba) + expected := e.Sub(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestSubFp12(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bls12381.E12 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Sub(&a, &b) + + witness := e12Sub{ + A: FromE12(&a), + B: FromE12(&b), + C: FromE12(&c), + } + + err := test.IsSolved(&e12Sub{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) + +} + +type e12Mul struct { + A, B, C E12 +} + +func (circuit *e12Mul) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt12(ba) + + expected := e.Mul(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestMulFp12(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bls12381.E12 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Mul(&a, &b) + + witness := e12Mul{ + A: FromE12(&a), + B: FromE12(&b), + C: FromE12(&c), + } + + err := test.IsSolved(&e12Mul{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) + +} + +type e12Div struct { + A, B, C E12 +} + +func (circuit *e12Div) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt12(ba) + + expected := e.DivUnchecked(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestDivFp12(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bls12381.E12 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Div(&a, &b) + + witness := e12Div{ + A: FromE12(&a), + B: FromE12(&b), + C: FromE12(&c), + } + + err := test.IsSolved(&e12Div{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) + +} + +type e12Square struct { + A, C E12 +} + +func (circuit *e12Square) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt12(ba) + + expected := e.Square(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestSquareFp12(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E12 + _, _ = a.SetRandom() + c.Square(&a) + + witness := e12Square{ + A: FromE12(&a), + C: FromE12(&c), + } + + err := test.IsSolved(&e12Square{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) + +} + +type e12CycloSquare struct { + A E12 + C E12 `gnark:",public"` +} + +func (circuit *e12CycloSquare) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt12(ba) + expected := e.CyclotomicSquare(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestFp12CyclotomicSquare(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E12 + _, _ = a.SetRandom() + + // put a in the cyclotomic subgroup + var tmp bls12381.E12 + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + c.CyclotomicSquare(&a) + + witness := e12CycloSquare{ + A: FromE12(&a), + C: FromE12(&c), + } + + err := test.IsSolved(&e12CycloSquare{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) +} + +type e12CycloSquareKarabina struct { + A E12 + C E12 `gnark:",public"` +} + +func (circuit *e12CycloSquareKarabina) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt12(ba) + expected := e.CyclotomicSquareCompressed(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestFp12CyclotomicSquareKarabina(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E12 + _, _ = a.SetRandom() + + // put a in the cyclotomic subgroup + var tmp bls12381.E12 + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + c.CyclotomicSquareCompressed(&a) + + witness := e12CycloSquareKarabina{ + A: FromE12(&a), + C: FromE12(&c), + } + + err := test.IsSolved(&e12CycloSquareKarabina{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) +} + +type e12CycloSquareKarabinaAndDecompress struct { + A E12 + C E12 `gnark:",public"` +} + +func (circuit *e12CycloSquareKarabinaAndDecompress) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt12(ba) + expected := e.CyclotomicSquareCompressed(&circuit.A) + expected = e.DecompressKarabina(expected) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestFp12CyclotomicSquareKarabinaAndDecompress(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E12 + _, _ = a.SetRandom() + + // put a in the cyclotomic subgroup + var tmp bls12381.E12 + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + c.CyclotomicSquareCompressed(&a) + c.DecompressKarabina(&c) + + witness := e12CycloSquareKarabina{ + A: FromE12(&a), + C: FromE12(&c), + } + + err := test.IsSolved(&e12CycloSquareKarabinaAndDecompress{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) +} + +type e12Conjugate struct { + A E12 + C E12 `gnark:",public"` +} + +func (circuit *e12Conjugate) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt12(ba) + expected := e.Conjugate(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestConjugateFp12(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E12 + _, _ = a.SetRandom() + c.Conjugate(&a) + + witness := e12Conjugate{ + A: FromE12(&a), + C: FromE12(&c), + } + + err := test.IsSolved(&e12Conjugate{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) +} + +type e12Inverse struct { + A E12 + C E12 `gnark:",public"` +} + +func (circuit *e12Inverse) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt12(ba) + expected := e.Inverse(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestInverseFp12(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E12 + _, _ = a.SetRandom() + c.Inverse(&a) + + witness := e12Inverse{ + A: FromE12(&a), + C: FromE12(&c), + } + + err := test.IsSolved(&e12Inverse{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) +} + +/* +type e12Expt struct { + A E12 + C E12 `gnark:",public"` +} + +func (circuit *e12Expt) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt12(ba) + expected := e.Expt(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestFp12Expt(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E12 + _, _ = a.SetRandom() + + // put a in the cyclotomic subgroup + var tmp bls12381.E12 + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + + c.Expt(&a) + + witness := e12Expt{ + A: FromE12(&a), + C: FromE12(&c), + } + + err := test.IsSolved(&e12Expt{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) +} +*/ + +type e12Frobenius struct { + A, C E12 +} + +func (circuit *e12Frobenius) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt12(ba) + + expected := e.Frobenius(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestFrobeniusFp12(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E12 + _, _ = a.SetRandom() + c.Frobenius(&a) + + witness := e12Frobenius{ + A: FromE12(&a), + C: FromE12(&c), + } + + err := test.IsSolved(&e12Frobenius{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) + +} + +type e12FrobeniusSquare struct { + A, C E12 +} + +func (circuit *e12FrobeniusSquare) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt12(ba) + + expected := e.FrobeniusSquare(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestFrobeniusSquareFp12(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E12 + _, _ = a.SetRandom() + c.FrobeniusSquare(&a) + + witness := e12FrobeniusSquare{ + A: FromE12(&a), + C: FromE12(&c), + } + + err := test.IsSolved(&e12FrobeniusSquare{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) + +} + +/* +type e12MulBy014 struct { + A E12 `gnark:",public"` + W E12 + B, C E2 +} + +func (circuit *e12MulBy014) Define(api frontend.API) error { + + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt12(ba) + res := e.MulBy014(&circuit.A, &circuit.B, &circuit.C) + e.AssertIsEqual(res, &circuit.W) + return nil +} + +func TestFp12MulBy014(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, w bls12381.E12 + _, _ = a.SetRandom() + var one, b, c bls12381.E2 + one.SetOne() + _, _ = b.SetRandom() + _, _ = c.SetRandom() + w.Set(&a) + w.MulBy014(&one, &b, &c) + + witness := e12MulBy014{ + A: FromE12(&a), + B: FromE2(&b), + C: FromE2(&c), + W: FromE12(&w), + } + + err := test.IsSolved(&e12MulBy014{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) + +} +*/ diff --git a/std/algebra/emulated/fields_bls12381/e2.go b/std/algebra/emulated/fields_bls12381/e2.go new file mode 100644 index 0000000000..750fd928ce --- /dev/null +++ b/std/algebra/emulated/fields_bls12381/e2.go @@ -0,0 +1,288 @@ +package fields_bls12381 + +import ( + "math/big" + + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark/std/math/emulated" +) + +type curveF = emulated.Field[emulated.BLS12381Fp] +type baseEl = emulated.Element[emulated.BLS12381Fp] + +type E2 struct { + A0, A1 baseEl +} + +type Ext2 struct { + fp *curveF + nonResidues map[int]map[int]*E2 +} + +func NewExt2(baseField *curveF) *Ext2 { + pwrs := map[int]map[int]struct { + A0 string + A1 string + }{ + 0: { + -1: {"2001204777610833696708894912867952078278441409969503942666029068062015825245418932221343814564507832018947136279894", "2001204777610833696708894912867952078278441409969503942666029068062015825245418932221343814564507832018947136279893"}, + 1: {"1", "1"}, + }, + 1: { + 1: {"3850754370037169011952147076051364057158807420970682438676050522613628423219637725072182697113062777891589506424760", "151655185184498381465642749684540099398075398968325446656007613510403227271200139370504932015952886146304766135027"}, + 2: {"0", "4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436"}, + 3: {"1028732146235106349975324479215795277384839936929757896155643118032610843298655225875571310552543014690878354869257", "1028732146235106349975324479215795277384839936929757896155643118032610843298655225875571310552543014690878354869257"}, + 4: {"4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437", "0"}, + 5: {"877076961050607968509681729531255177986764537961432449499635504522207616027455086505066378536590128544573588734230", "3125332594171059424908108096204648978570118281977575435832422631601824034463382777937621250592425535493320683825557"}, + }, + 2: { + 1: {"793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620351", "0"}, + 2: {"793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350", "0"}, + 3: {"4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559786", "0"}, + 4: {"4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436", "0"}, + 5: {"4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437", "0"}, + }, + } + nonResidues := make(map[int]map[int]*E2) + for pwr, v := range pwrs { + for coeff, v := range v { + el := E2{emulated.ValueOf[emulated.BLS12381Fp](v.A0), emulated.ValueOf[emulated.BLS12381Fp](v.A1)} + if nonResidues[pwr] == nil { + nonResidues[pwr] = make(map[int]*E2) + } + nonResidues[pwr][coeff] = &el + } + } + return &Ext2{fp: baseField, nonResidues: nonResidues} +} + +func (e Ext2) MulByElement(x *E2, y *baseEl) *E2 { + z0 := e.fp.MulMod(&x.A0, y) + z1 := e.fp.MulMod(&x.A1, y) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) MulByConstElement(x *E2, y *big.Int) *E2 { + z0 := e.fp.MulConst(&x.A0, y) + z1 := e.fp.MulConst(&x.A1, y) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) Conjugate(x *E2) *E2 { + z0 := x.A0 + z1 := e.fp.Neg(&x.A1) + return &E2{ + A0: z0, + A1: *z1, + } +} + +func (e Ext2) MulByNonResidueGeneric(x *E2, power, coef int) *E2 { + y := e.nonResidues[power][coef] + z := e.Mul(x, y) + return z +} + +// MulByNonResidue returns x*(1+u) +func (e Ext2) MulByNonResidue(x *E2) *E2 { + a := e.fp.Sub(&x.A0, &x.A1) + b := e.fp.Add(&x.A0, &x.A1) + + return &E2{ + A0: *a, + A1: *b, + } +} + +// TODO: optimize MulByNonResidue{i}Power{i} + +// MulByNonResidue1Power1 returns x*(9+u)^(1*(p^1-1)/6) +func (e Ext2) MulByNonResidue1Power1(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 1, 1) +} + +// MulByNonResidue1Power2 returns x*(9+u)^(2*(p^1-1)/6) +func (e Ext2) MulByNonResidue1Power2(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 1, 2) +} + +// MulByNonResidue1Power3 returns x*(9+u)^(3*(p^1-1)/6) +func (e Ext2) MulByNonResidue1Power3(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 1, 3) +} + +// MulByNonResidue1Power4 returns x*(9+u)^(4*(p^1-1)/6) +func (e Ext2) MulByNonResidue1Power4(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 1, 4) +} + +// MulByNonResidue1Power5 returns x*(9+u)^(5*(p^1-1)/6) +func (e Ext2) MulByNonResidue1Power5(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 1, 5) +} + +// MulByNonResidue2Power1 returns x*(9+u)^(1*(p^2-1)/6) +func (e Ext2) MulByNonResidue2Power1(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 2, 1) +} + +// MulByNonResidue2Power2 returns x*(9+u)^(2*(p^2-1)/6) +func (e Ext2) MulByNonResidue2Power2(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 2, 2) +} + +// MulByNonResidue2Power3 returns x*(9+u)^(3*(p^2-1)/6) +func (e Ext2) MulByNonResidue2Power3(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 2, 3) +} + +// MulByNonResidue2Power4 returns x*(9+u)^(4*(p^2-1)/6) +func (e Ext2) MulByNonResidue2Power4(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 2, 4) +} + +// MulByNonResidue2Power5 returns x*(9+u)^(5*(p^2-1)/6) +func (e Ext2) MulByNonResidue2Power5(x *E2) *E2 { + return e.MulByNonResidueGeneric(x, 2, 5) +} + +func (e Ext2) Mul(x, y *E2) *E2 { + a := e.fp.Add(&x.A0, &x.A1) + b := e.fp.Add(&y.A0, &y.A1) + a = e.fp.MulMod(a, b) + b = e.fp.MulMod(&x.A0, &y.A0) + c := e.fp.MulMod(&x.A1, &y.A1) + z1 := e.fp.Sub(a, b) + z1 = e.fp.Sub(z1, c) + z0 := e.fp.Sub(b, c) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) Add(x, y *E2) *E2 { + z0 := e.fp.Add(&x.A0, &y.A0) + z1 := e.fp.Add(&x.A1, &y.A1) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) Sub(x, y *E2) *E2 { + z0 := e.fp.Sub(&x.A0, &y.A0) + z1 := e.fp.Sub(&x.A1, &y.A1) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) Neg(x *E2) *E2 { + z0 := e.fp.Neg(&x.A0) + z1 := e.fp.Neg(&x.A1) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) One() *E2 { + z0 := e.fp.One() + z1 := e.fp.Zero() + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) Zero() *E2 { + z0 := e.fp.Zero() + z1 := e.fp.Zero() + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) Square(x *E2) *E2 { + a := e.fp.Add(&x.A0, &x.A1) + b := e.fp.Sub(&x.A0, &x.A1) + a = e.fp.MulMod(a, b) + b = e.fp.MulMod(&x.A0, &x.A1) + b = e.fp.MulConst(b, big.NewInt(2)) + return &E2{ + A0: *a, + A1: *b, + } +} + +func (e Ext2) Double(x *E2) *E2 { + two := big.NewInt(2) + z0 := e.fp.MulConst(&x.A0, two) + z1 := e.fp.MulConst(&x.A1, two) + return &E2{ + A0: *z0, + A1: *z1, + } +} + +func (e Ext2) AssertIsEqual(x, y *E2) { + e.fp.AssertIsEqual(&x.A0, &y.A0) + e.fp.AssertIsEqual(&x.A1, &y.A1) +} + +func FromE2(y *bls12381.E2) E2 { + return E2{ + A0: emulated.ValueOf[emulated.BLS12381Fp](y.A0), + A1: emulated.ValueOf[emulated.BLS12381Fp](y.A1), + } +} + +func (e Ext2) Inverse(x *E2) *E2 { + res, err := e.fp.NewHint(inverseE2Hint, 2, &x.A0, &x.A1) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + inv := E2{ + A0: *res[0], + A1: *res[1], + } + one := e.One() + + // 1 == inv * x + _one := e.Mul(&inv, x) + e.AssertIsEqual(one, _one) + + return &inv + +} + +// DivUnchecked e2 elmts +func (e Ext2) DivUnchecked(x, y *E2) *E2 { + res, err := e.fp.NewHint(divE2Hint, 2, &x.A0, &x.A1, &y.A0, &y.A1) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + div := E2{ + A0: *res[0], + A1: *res[1], + } + + // x == div * y + _x := e.Mul(&div, y) + e.AssertIsEqual(x, _x) + + return &div +} diff --git a/std/algebra/emulated/fields_bls12381/e2_test.go b/std/algebra/emulated/fields_bls12381/e2_test.go new file mode 100644 index 0000000000..7ea1aae73a --- /dev/null +++ b/std/algebra/emulated/fields_bls12381/e2_test.go @@ -0,0 +1,365 @@ +package fields_bls12381 + +import ( + "testing" + + "github.com/consensys/gnark-crypto/ecc" + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/math/emulated" + "github.com/consensys/gnark/test" +) + +type e2Add struct { + A, B, C E2 +} + +func (circuit *e2Add) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt2(ba) + expected := e.Add(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestAddFp2(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bls12381.E2 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Add(&a, &b) + + witness := e2Add{ + A: FromE2(&a), + B: FromE2(&b), + C: FromE2(&c), + } + + err := test.IsSolved(&e2Add{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) + +} + +type e2Sub struct { + A, B, C E2 +} + +func (circuit *e2Sub) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt2(ba) + expected := e.Sub(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestSubFp2(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bls12381.E2 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Sub(&a, &b) + + witness := e2Sub{ + A: FromE2(&a), + B: FromE2(&b), + C: FromE2(&c), + } + + err := test.IsSolved(&e2Sub{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) + +} + +type e2Double struct { + A, C E2 +} + +func (circuit *e2Double) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt2(ba) + expected := e.Double(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestDoubleFp2(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bls12381.E2 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Double(&a) + + witness := e2Double{ + A: FromE2(&a), + C: FromE2(&c), + } + + err := test.IsSolved(&e2Double{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) + +} + +type e2Mul struct { + A, B, C E2 +} + +func (circuit *e2Mul) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt2(ba) + + expected := e.Mul(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestMulFp2(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bls12381.E2 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Mul(&a, &b) + + witness := e2Mul{ + A: FromE2(&a), + B: FromE2(&b), + C: FromE2(&c), + } + + err := test.IsSolved(&e2Mul{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) + +} + +type e2Square struct { + A, C E2 +} + +func (circuit *e2Square) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt2(ba) + + expected := e.Square(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestSquareFp2(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E2 + _, _ = a.SetRandom() + c.Square(&a) + + witness := e2Square{ + A: FromE2(&a), + C: FromE2(&c), + } + + err := test.IsSolved(&e2Square{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) + +} + +type e2Div struct { + A, B, C E2 +} + +func (circuit *e2Div) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt2(ba) + + expected := e.DivUnchecked(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestDivFp2(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bls12381.E2 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Div(&a, &b) + + witness := e2Div{ + A: FromE2(&a), + B: FromE2(&b), + C: FromE2(&c), + } + + err := test.IsSolved(&e2Div{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) + +} + +type e2MulByElement struct { + A E2 + B baseEl + C E2 `gnark:",public"` +} + +func (circuit *e2MulByElement) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt2(ba) + expected := e.MulByElement(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestMulByElement(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E2 + var b fp.Element + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.MulByElement(&a, &b) + + witness := e2MulByElement{ + A: FromE2(&a), + B: emulated.ValueOf[emulated.BLS12381Fp](b), + C: FromE2(&c), + } + + err := test.IsSolved(&e2MulByElement{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) + +} + +type e2MulByNonResidue struct { + A E2 + C E2 `gnark:",public"` +} + +func (circuit *e2MulByNonResidue) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt2(ba) + expected := e.MulByNonResidue(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestMulFp2ByNonResidue(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E2 + _, _ = a.SetRandom() + c.MulByNonResidue(&a) + + witness := e2MulByNonResidue{ + A: FromE2(&a), + C: FromE2(&c), + } + + err := test.IsSolved(&e2MulByNonResidue{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) + +} + +type e2Neg struct { + A E2 + C E2 `gnark:",public"` +} + +func (circuit *e2Neg) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt2(ba) + expected := e.Neg(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestNegFp2(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E2 + _, _ = a.SetRandom() + c.Neg(&a) + + witness := e2Neg{ + A: FromE2(&a), + C: FromE2(&c), + } + + err := test.IsSolved(&e2Neg{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) +} + +type e2Conjugate struct { + A E2 + C E2 `gnark:",public"` +} + +func (circuit *e2Conjugate) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt2(ba) + expected := e.Conjugate(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestConjugateFp2(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E2 + _, _ = a.SetRandom() + c.Conjugate(&a) + + witness := e2Conjugate{ + A: FromE2(&a), + C: FromE2(&c), + } + + err := test.IsSolved(&e2Conjugate{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) +} + +type e2Inverse struct { + A E2 + C E2 `gnark:",public"` +} + +func (circuit *e2Inverse) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt2(ba) + expected := e.Inverse(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestInverseFp2(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E2 + _, _ = a.SetRandom() + c.Inverse(&a) + + witness := e2Inverse{ + A: FromE2(&a), + C: FromE2(&c), + } + + err := test.IsSolved(&e2Inverse{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) +} diff --git a/std/algebra/emulated/fields_bls12381/e6.go b/std/algebra/emulated/fields_bls12381/e6.go new file mode 100644 index 0000000000..206829025f --- /dev/null +++ b/std/algebra/emulated/fields_bls12381/e6.go @@ -0,0 +1,245 @@ +package fields_bls12381 + +import ( + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" +) + +type E6 struct { + B0, B1, B2 E2 +} + +type Ext6 struct { + *Ext2 +} + +func NewExt6(baseField *curveF) *Ext6 { + return &Ext6{Ext2: NewExt2(baseField)} +} + +func (e Ext6) One() *E6 { + z0 := e.Ext2.One() + z1 := e.Ext2.Zero() + z2 := e.Ext2.Zero() + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Zero() *E6 { + z0 := e.Ext2.Zero() + z1 := e.Ext2.Zero() + z2 := e.Ext2.Zero() + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Add(x, y *E6) *E6 { + z0 := e.Ext2.Add(&x.B0, &y.B0) + z1 := e.Ext2.Add(&x.B1, &y.B1) + z2 := e.Ext2.Add(&x.B2, &y.B2) + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Neg(x *E6) *E6 { + z0 := e.Ext2.Neg(&x.B0) + z1 := e.Ext2.Neg(&x.B1) + z2 := e.Ext2.Neg(&x.B2) + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Sub(x, y *E6) *E6 { + z0 := e.Ext2.Sub(&x.B0, &y.B0) + z1 := e.Ext2.Sub(&x.B1, &y.B1) + z2 := e.Ext2.Sub(&x.B2, &y.B2) + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Mul(x, y *E6) *E6 { + t0 := e.Ext2.Mul(&x.B0, &y.B0) + t1 := e.Ext2.Mul(&x.B1, &y.B1) + t2 := e.Ext2.Mul(&x.B2, &y.B2) + c0 := e.Ext2.Add(&x.B1, &x.B2) + tmp := e.Ext2.Add(&y.B1, &y.B2) + c0 = e.Ext2.Mul(c0, tmp) + c0 = e.Ext2.Sub(c0, t1) + c0 = e.Ext2.Sub(c0, t2) + c0 = e.Ext2.MulByNonResidue(c0) + c0 = e.Ext2.Add(c0, t0) + c1 := e.Ext2.Add(&x.B0, &x.B1) + tmp = e.Ext2.Add(&y.B0, &y.B1) + c1 = e.Ext2.Mul(c1, tmp) + c1 = e.Ext2.Sub(c1, t0) + c1 = e.Ext2.Sub(c1, t1) + tmp = e.Ext2.MulByNonResidue(t2) + c1 = e.Ext2.Add(c1, tmp) + tmp = e.Ext2.Add(&x.B0, &x.B2) + c2 := e.Ext2.Add(&y.B0, &y.B2) + c2 = e.Ext2.Mul(c2, tmp) + c2 = e.Ext2.Sub(c2, t0) + c2 = e.Ext2.Sub(c2, t2) + c2 = e.Ext2.Add(c2, t1) + return &E6{ + B0: *c0, + B1: *c1, + B2: *c2, + } +} + +func (e Ext6) double(x *E6) *E6 { + z0 := e.Ext2.Double(&x.B0) + z1 := e.Ext2.Double(&x.B1) + z2 := e.Ext2.Double(&x.B2) + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) Square(x *E6) *E6 { + c4 := e.Ext2.Mul(&x.B0, &x.B1) + c4 = e.Ext2.Double(c4) + c5 := e.Ext2.Square(&x.B2) + c1 := e.Ext2.MulByNonResidue(c5) + c1 = e.Ext2.Add(c1, c4) + c2 := e.Ext2.Sub(c4, c5) + c3 := e.Ext2.Square(&x.B0) + c4 = e.Ext2.Sub(&x.B0, &x.B1) + c4 = e.Ext2.Add(c4, &x.B2) + c5 = e.Ext2.Mul(&x.B1, &x.B2) + c5 = e.Ext2.Double(c5) + c4 = e.Ext2.Square(c4) + c0 := e.Ext2.MulByNonResidue(c5) + c0 = e.Ext2.Add(c0, c3) + z2 := e.Ext2.Add(c2, c4) + z2 = e.Ext2.Add(z2, c5) + z2 = e.Ext2.Sub(z2, c3) + z0 := c0 + z1 := c1 + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) MulByE2(x *E6, y *E2) *E6 { + z0 := e.Ext2.Mul(&x.B0, y) + z1 := e.Ext2.Mul(&x.B1, y) + z2 := e.Ext2.Mul(&x.B2, y) + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) MulBy01(z *E6, c0, c1 *E2) *E6 { + a := e.Ext2.Mul(&z.B0, c0) + b := e.Ext2.Mul(&z.B1, c1) + tmp := e.Ext2.Add(&z.B1, &z.B2) + t0 := e.Ext2.Mul(c1, tmp) + t0 = e.Ext2.Sub(t0, b) + t0 = e.Ext2.MulByNonResidue(t0) + t0 = e.Ext2.Add(t0, a) + tmp = e.Ext2.Add(&z.B0, &z.B2) + t2 := e.Ext2.Mul(c0, tmp) + t2 = e.Ext2.Sub(t2, a) + t2 = e.Ext2.Add(t2, b) + t1 := e.Ext2.Add(c0, c1) + tmp = e.Ext2.Add(&z.B0, &z.B1) + t1 = e.Ext2.Mul(t1, tmp) + t1 = e.Ext2.Sub(t1, a) + t1 = e.Ext2.Sub(t1, b) + return &E6{ + B0: *t0, + B1: *t1, + B2: *t2, + } +} + +func (e Ext6) MulByNonResidue(x *E6) *E6 { + z2, z1, z0 := &x.B1, &x.B0, &x.B2 + z0 = e.Ext2.MulByNonResidue(z0) + return &E6{ + B0: *z0, + B1: *z1, + B2: *z2, + } +} + +func (e Ext6) AssertIsEqual(x, y *E6) { + e.Ext2.AssertIsEqual(&x.B0, &y.B0) + e.Ext2.AssertIsEqual(&x.B1, &y.B1) + e.Ext2.AssertIsEqual(&x.B2, &y.B2) +} + +func FromE6(y *bls12381.E6) E6 { + return E6{ + B0: FromE2(&y.B0), + B1: FromE2(&y.B1), + B2: FromE2(&y.B2), + } + +} + +func (e Ext6) Inverse(x *E6) *E6 { + res, err := e.fp.NewHint(inverseE6Hint, 6, &x.B0.A0, &x.B0.A1, &x.B1.A0, &x.B1.A1, &x.B2.A0, &x.B2.A1) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + inv := E6{ + B0: E2{A0: *res[0], A1: *res[1]}, + B1: E2{A0: *res[2], A1: *res[3]}, + B2: E2{A0: *res[4], A1: *res[5]}, + } + + one := e.One() + + // 1 == inv * x + _one := e.Mul(&inv, x) + e.AssertIsEqual(one, _one) + + return &inv + +} + +// DivUnchecked e2 elmts +func (e Ext6) DivUnchecked(x, y *E6) *E6 { + res, err := e.fp.NewHint(divE6Hint, 6, &x.B0.A0, &x.B0.A1, &x.B1.A0, &x.B1.A1, &x.B2.A0, &x.B2.A1, &y.B0.A0, &y.B0.A1, &y.B1.A0, &y.B1.A1, &y.B2.A0, &y.B2.A1) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + div := E6{ + B0: E2{A0: *res[0], A1: *res[1]}, + B1: E2{A0: *res[2], A1: *res[3]}, + B2: E2{A0: *res[4], A1: *res[5]}, + } + + // x == div * y + _x := e.Mul(&div, y) + e.AssertIsEqual(x, _x) + + return &div +} diff --git a/std/algebra/emulated/fields_bls12381/e6_test.go b/std/algebra/emulated/fields_bls12381/e6_test.go new file mode 100644 index 0000000000..5c05d84401 --- /dev/null +++ b/std/algebra/emulated/fields_bls12381/e6_test.go @@ -0,0 +1,342 @@ +package fields_bls12381 + +import ( + "testing" + + "github.com/consensys/gnark-crypto/ecc" + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/math/emulated" + "github.com/consensys/gnark/test" +) + +type e6Add struct { + A, B, C E6 +} + +func (circuit *e6Add) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt6(ba) + expected := e.Add(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestAddFp6(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bls12381.E6 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Add(&a, &b) + + witness := e6Add{ + A: FromE6(&a), + B: FromE6(&b), + C: FromE6(&c), + } + + err := test.IsSolved(&e6Add{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) + +} + +type e6Sub struct { + A, B, C E6 +} + +func (circuit *e6Sub) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt6(ba) + expected := e.Sub(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestSubFp6(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bls12381.E6 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Sub(&a, &b) + + witness := e6Sub{ + A: FromE6(&a), + B: FromE6(&b), + C: FromE6(&c), + } + + err := test.IsSolved(&e6Sub{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) + +} + +type e6Mul struct { + A, B, C E6 +} + +func (circuit *e6Mul) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt6(ba) + + expected := e.Mul(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestMulFp6(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bls12381.E6 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Mul(&a, &b) + + witness := e6Mul{ + A: FromE6(&a), + B: FromE6(&b), + C: FromE6(&c), + } + + err := test.IsSolved(&e6Mul{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) + +} + +type e6Square struct { + A, C E6 +} + +func (circuit *e6Square) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt6(ba) + + expected := e.Square(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestSquareFp6(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E6 + _, _ = a.SetRandom() + c.Square(&a) + + witness := e6Square{ + A: FromE6(&a), + C: FromE6(&c), + } + + err := test.IsSolved(&e6Square{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) + +} + +type e6Div struct { + A, B, C E6 +} + +func (circuit *e6Div) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt6(ba) + + expected := e.DivUnchecked(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestDivFp6(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c bls12381.E6 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.Div(&a, &b) + + witness := e6Div{ + A: FromE6(&a), + B: FromE6(&b), + C: FromE6(&c), + } + + err := test.IsSolved(&e6Div{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) + +} + +type e6MulByNonResidue struct { + A E6 + C E6 `gnark:",public"` +} + +func (circuit *e6MulByNonResidue) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt6(ba) + expected := e.MulByNonResidue(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestMulFp6ByNonResidue(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E6 + _, _ = a.SetRandom() + c.MulByNonResidue(&a) + + witness := e6MulByNonResidue{ + A: FromE6(&a), + C: FromE6(&c), + } + + err := test.IsSolved(&e6MulByNonResidue{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) + +} + +type e6MulByE2 struct { + A E6 + B E2 + C E6 `gnark:",public"` +} + +func (circuit *e6MulByE2) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt6(ba) + expected := e.MulByE2(&circuit.A, &circuit.B) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestMulFp6ByE2(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E6 + var b bls12381.E2 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + c.MulByE2(&a, &b) + + witness := e6MulByE2{ + A: FromE6(&a), + B: FromE2(&b), + C: FromE6(&c), + } + + err := test.IsSolved(&e6MulByE2{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) + +} + +type e6MulBy01 struct { + A E6 + C0, C1 E2 + C E6 `gnark:",public"` +} + +func (circuit *e6MulBy01) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt6(ba) + expected := e.MulBy01(&circuit.A, &circuit.C0, &circuit.C1) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestMulFp6By01(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E6 + var C0, C1 bls12381.E2 + _, _ = a.SetRandom() + _, _ = C0.SetRandom() + _, _ = C1.SetRandom() + c.Set(&a) + c.MulBy01(&C0, &C1) + + witness := e6MulBy01{ + A: FromE6(&a), + C0: FromE2(&C0), + C1: FromE2(&C1), + C: FromE6(&c), + } + + err := test.IsSolved(&e6MulBy01{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) + +} + +type e6Neg struct { + A E6 + C E6 `gnark:",public"` +} + +func (circuit *e6Neg) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt6(ba) + expected := e.Neg(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestNegFp6(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E6 + _, _ = a.SetRandom() + c.Neg(&a) + + witness := e6Neg{ + A: FromE6(&a), + C: FromE6(&c), + } + + err := test.IsSolved(&e6Neg{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) +} + +type e6Inverse struct { + A E6 + C E6 `gnark:",public"` +} + +func (circuit *e6Inverse) Define(api frontend.API) error { + + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt6(ba) + expected := e.Inverse(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestInverseFp6(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E6 + _, _ = a.SetRandom() + c.Inverse(&a) + + witness := e6Inverse{ + A: FromE6(&a), + C: FromE6(&c), + } + + err := test.IsSolved(&e6Inverse{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) +} diff --git a/std/algebra/emulated/fields_bls12381/hints.go b/std/algebra/emulated/fields_bls12381/hints.go new file mode 100644 index 0000000000..320c7ffaa9 --- /dev/null +++ b/std/algebra/emulated/fields_bls12381/hints.go @@ -0,0 +1,210 @@ +package fields_bls12381 + +import ( + "math/big" + + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/std/math/emulated" +) + +func init() { + solver.RegisterHint(GetHints()...) +} + +// GetHints returns all hint functions used in the package. +func GetHints() []solver.Hint { + return []solver.Hint{ + // E2 + divE2Hint, + inverseE2Hint, + // E6 + divE6Hint, + inverseE6Hint, + // E12 + divE12Hint, + inverseE12Hint, + } +} + +func inverseE2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, c bls12381.E2 + + a.A0.SetBigInt(inputs[0]) + a.A1.SetBigInt(inputs[1]) + + c.Inverse(&a) + + c.A0.BigInt(outputs[0]) + c.A1.BigInt(outputs[1]) + + return nil + }) +} + +func divE2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, b, c bls12381.E2 + + a.A0.SetBigInt(inputs[0]) + a.A1.SetBigInt(inputs[1]) + b.A0.SetBigInt(inputs[2]) + b.A1.SetBigInt(inputs[3]) + + c.Inverse(&b).Mul(&c, &a) + + c.A0.BigInt(outputs[0]) + c.A1.BigInt(outputs[1]) + + return nil + }) +} + +// E6 hints +func inverseE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, c bls12381.E6 + + a.B0.A0.SetBigInt(inputs[0]) + a.B0.A1.SetBigInt(inputs[1]) + a.B1.A0.SetBigInt(inputs[2]) + a.B1.A1.SetBigInt(inputs[3]) + a.B2.A0.SetBigInt(inputs[4]) + a.B2.A1.SetBigInt(inputs[5]) + + c.Inverse(&a) + + c.B0.A0.BigInt(outputs[0]) + c.B0.A1.BigInt(outputs[1]) + c.B1.A0.BigInt(outputs[2]) + c.B1.A1.BigInt(outputs[3]) + c.B2.A0.BigInt(outputs[4]) + c.B2.A1.BigInt(outputs[5]) + + return nil + }) +} + +func divE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, b, c bls12381.E6 + + a.B0.A0.SetBigInt(inputs[0]) + a.B0.A1.SetBigInt(inputs[1]) + a.B1.A0.SetBigInt(inputs[2]) + a.B1.A1.SetBigInt(inputs[3]) + a.B2.A0.SetBigInt(inputs[4]) + a.B2.A1.SetBigInt(inputs[5]) + + b.B0.A0.SetBigInt(inputs[6]) + b.B0.A1.SetBigInt(inputs[7]) + b.B1.A0.SetBigInt(inputs[8]) + b.B1.A1.SetBigInt(inputs[9]) + b.B2.A0.SetBigInt(inputs[10]) + b.B2.A1.SetBigInt(inputs[11]) + + c.Inverse(&b).Mul(&c, &a) + + c.B0.A0.BigInt(outputs[0]) + c.B0.A1.BigInt(outputs[1]) + c.B1.A0.BigInt(outputs[2]) + c.B1.A1.BigInt(outputs[3]) + c.B2.A0.BigInt(outputs[4]) + c.B2.A1.BigInt(outputs[5]) + + return nil + }) +} + +// E12 hints +func inverseE12Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, c bls12381.E12 + + a.C0.B0.A0.SetBigInt(inputs[0]) + a.C0.B0.A1.SetBigInt(inputs[1]) + a.C0.B1.A0.SetBigInt(inputs[2]) + a.C0.B1.A1.SetBigInt(inputs[3]) + a.C0.B2.A0.SetBigInt(inputs[4]) + a.C0.B2.A1.SetBigInt(inputs[5]) + a.C1.B0.A0.SetBigInt(inputs[6]) + a.C1.B0.A1.SetBigInt(inputs[7]) + a.C1.B1.A0.SetBigInt(inputs[8]) + a.C1.B1.A1.SetBigInt(inputs[9]) + a.C1.B2.A0.SetBigInt(inputs[10]) + a.C1.B2.A1.SetBigInt(inputs[11]) + + c.Inverse(&a) + + c.C0.B0.A0.BigInt(outputs[0]) + c.C0.B0.A1.BigInt(outputs[1]) + c.C0.B1.A0.BigInt(outputs[2]) + c.C0.B1.A1.BigInt(outputs[3]) + c.C0.B2.A0.BigInt(outputs[4]) + c.C0.B2.A1.BigInt(outputs[5]) + c.C1.B0.A0.BigInt(outputs[6]) + c.C1.B0.A1.BigInt(outputs[7]) + c.C1.B1.A0.BigInt(outputs[8]) + c.C1.B1.A1.BigInt(outputs[9]) + c.C1.B2.A0.BigInt(outputs[10]) + c.C1.B2.A1.BigInt(outputs[11]) + + return nil + }) +} + +func divE12Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, b, c bls12381.E12 + + a.C0.B0.A0.SetBigInt(inputs[0]) + a.C0.B0.A1.SetBigInt(inputs[1]) + a.C0.B1.A0.SetBigInt(inputs[2]) + a.C0.B1.A1.SetBigInt(inputs[3]) + a.C0.B2.A0.SetBigInt(inputs[4]) + a.C0.B2.A1.SetBigInt(inputs[5]) + a.C1.B0.A0.SetBigInt(inputs[6]) + a.C1.B0.A1.SetBigInt(inputs[7]) + a.C1.B1.A0.SetBigInt(inputs[8]) + a.C1.B1.A1.SetBigInt(inputs[9]) + a.C1.B2.A0.SetBigInt(inputs[10]) + a.C1.B2.A1.SetBigInt(inputs[11]) + + b.C0.B0.A0.SetBigInt(inputs[12]) + b.C0.B0.A1.SetBigInt(inputs[13]) + b.C0.B1.A0.SetBigInt(inputs[14]) + b.C0.B1.A1.SetBigInt(inputs[15]) + b.C0.B2.A0.SetBigInt(inputs[16]) + b.C0.B2.A1.SetBigInt(inputs[17]) + b.C1.B0.A0.SetBigInt(inputs[18]) + b.C1.B0.A1.SetBigInt(inputs[19]) + b.C1.B1.A0.SetBigInt(inputs[20]) + b.C1.B1.A1.SetBigInt(inputs[21]) + b.C1.B2.A0.SetBigInt(inputs[22]) + b.C1.B2.A1.SetBigInt(inputs[23]) + + c.Inverse(&b).Mul(&c, &a) + + c.C0.B0.A0.BigInt(outputs[0]) + c.C0.B0.A1.BigInt(outputs[1]) + c.C0.B1.A0.BigInt(outputs[2]) + c.C0.B1.A1.BigInt(outputs[3]) + c.C0.B2.A0.BigInt(outputs[4]) + c.C0.B2.A1.BigInt(outputs[5]) + c.C1.B0.A0.BigInt(outputs[6]) + c.C1.B0.A1.BigInt(outputs[7]) + c.C1.B1.A0.BigInt(outputs[8]) + c.C1.B1.A1.BigInt(outputs[9]) + c.C1.B2.A0.BigInt(outputs[10]) + c.C1.B2.A1.BigInt(outputs[11]) + + return nil + }) +} diff --git a/std/math/emulated/params.go b/std/math/emulated/params.go index 9f89b0da09..eda8ebddc5 100644 --- a/std/math/emulated/params.go +++ b/std/math/emulated/params.go @@ -86,3 +86,14 @@ func (fp BLS12377Fp) NbLimbs() uint { return 6 } func (fp BLS12377Fp) BitsPerLimb() uint { return 64 } func (fp BLS12377Fp) IsPrime() bool { return true } func (fp BLS12377Fp) Modulus() *big.Int { return ecc.BLS12_377.BaseField() } + +// BLS12381Fp provide type parametrization for emulated field on 6 limb of width +// 64bits for modulus +// 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab. +// This is the base field of the BLS12-381 curve. +type BLS12381Fp struct{} + +func (fp BLS12381Fp) NbLimbs() uint { return 6 } +func (fp BLS12381Fp) BitsPerLimb() uint { return 64 } +func (fp BLS12381Fp) IsPrime() bool { return true } +func (fp BLS12381Fp) Modulus() *big.Int { return ecc.BLS12_381.BaseField() } From 5b6d13a70daa5af6b7623160d8ceb13e3bec23d9 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Thu, 16 Mar 2023 15:58:10 +0100 Subject: [PATCH 140/464] perf(bls381-pairing): optimize Frobenius and FrobeniusSquare --- std/algebra/emulated/fields_bls12381/e2.go | 71 +++++++++++++++------- 1 file changed, 48 insertions(+), 23 deletions(-) diff --git a/std/algebra/emulated/fields_bls12381/e2.go b/std/algebra/emulated/fields_bls12381/e2.go index 750fd928ce..4c2e6b8e2f 100644 --- a/std/algebra/emulated/fields_bls12381/e2.go +++ b/std/algebra/emulated/fields_bls12381/e2.go @@ -24,10 +24,6 @@ func NewExt2(baseField *curveF) *Ext2 { A0 string A1 string }{ - 0: { - -1: {"2001204777610833696708894912867952078278441409969503942666029068062015825245418932221343814564507832018947136279894", "2001204777610833696708894912867952078278441409969503942666029068062015825245418932221343814564507832018947136279893"}, - 1: {"1", "1"}, - }, 1: { 1: {"3850754370037169011952147076051364057158807420970682438676050522613628423219637725072182697113062777891589506424760", "151655185184498381465642749684540099398075398968325446656007613510403227271200139370504932015952886146304766135027"}, 2: {"0", "4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436"}, @@ -100,56 +96,85 @@ func (e Ext2) MulByNonResidue(x *E2) *E2 { } } -// TODO: optimize MulByNonResidue{i}Power{i} - -// MulByNonResidue1Power1 returns x*(9+u)^(1*(p^1-1)/6) +// MulByNonResidue1Power1 returns x*(1+u)^(1*(p^1-1)/6) func (e Ext2) MulByNonResidue1Power1(x *E2) *E2 { return e.MulByNonResidueGeneric(x, 1, 1) } -// MulByNonResidue1Power2 returns x*(9+u)^(2*(p^1-1)/6) +// MulByNonResidue1Power2 returns x*(1+u)^(2*(p^1-1)/6) func (e Ext2) MulByNonResidue1Power2(x *E2) *E2 { - return e.MulByNonResidueGeneric(x, 1, 2) + element := emulated.ValueOf[emulated.BLS12381Fp]("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436") + a := e.fp.MulMod(&x.A1, &element) + a = e.fp.Neg(a) + b := e.fp.MulMod(&x.A0, &element) + return &E2{ + A0: *a, + A1: *b, + } } -// MulByNonResidue1Power3 returns x*(9+u)^(3*(p^1-1)/6) +// MulByNonResidue1Power3 returns x*(1+u)^(3*(p^1-1)/6) func (e Ext2) MulByNonResidue1Power3(x *E2) *E2 { return e.MulByNonResidueGeneric(x, 1, 3) } -// MulByNonResidue1Power4 returns x*(9+u)^(4*(p^1-1)/6) +// MulByNonResidue1Power4 returns x*(1+u)^(4*(p^1-1)/6) func (e Ext2) MulByNonResidue1Power4(x *E2) *E2 { - return e.MulByNonResidueGeneric(x, 1, 4) + element := emulated.ValueOf[emulated.BLS12381Fp]("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437") + return &E2{ + A0: *e.fp.MulMod(&x.A0, &element), + A1: *e.fp.MulMod(&x.A1, &element), + } } -// MulByNonResidue1Power5 returns x*(9+u)^(5*(p^1-1)/6) +// MulByNonResidue1Power5 returns x*(1+u)^(5*(p^1-1)/6) func (e Ext2) MulByNonResidue1Power5(x *E2) *E2 { return e.MulByNonResidueGeneric(x, 1, 5) } -// MulByNonResidue2Power1 returns x*(9+u)^(1*(p^2-1)/6) +// MulByNonResidue2Power1 returns x*(1+u)^(1*(p^2-1)/6) func (e Ext2) MulByNonResidue2Power1(x *E2) *E2 { - return e.MulByNonResidueGeneric(x, 2, 1) + element := emulated.ValueOf[emulated.BLS12381Fp]("793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620351") + return &E2{ + A0: *e.fp.MulMod(&x.A0, &element), + A1: *e.fp.MulMod(&x.A1, &element), + } } -// MulByNonResidue2Power2 returns x*(9+u)^(2*(p^2-1)/6) +// MulByNonResidue2Power2 returns x*(1+u)^(2*(p^2-1)/6) func (e Ext2) MulByNonResidue2Power2(x *E2) *E2 { - return e.MulByNonResidueGeneric(x, 2, 2) + element := emulated.ValueOf[emulated.BLS12381Fp]("793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350") + return &E2{ + A0: *e.fp.MulMod(&x.A0, &element), + A1: *e.fp.MulMod(&x.A1, &element), + } } -// MulByNonResidue2Power3 returns x*(9+u)^(3*(p^2-1)/6) +// MulByNonResidue2Power3 returns x*(1+u)^(3*(p^2-1)/6) func (e Ext2) MulByNonResidue2Power3(x *E2) *E2 { - return e.MulByNonResidueGeneric(x, 2, 3) + element := emulated.ValueOf[emulated.BLS12381Fp]("4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559786") + return &E2{ + A0: *e.fp.MulMod(&x.A0, &element), + A1: *e.fp.MulMod(&x.A1, &element), + } } -// MulByNonResidue2Power4 returns x*(9+u)^(4*(p^2-1)/6) +// MulByNonResidue2Power4 returns x*(1+u)^(4*(p^2-1)/6) func (e Ext2) MulByNonResidue2Power4(x *E2) *E2 { - return e.MulByNonResidueGeneric(x, 2, 4) + element := emulated.ValueOf[emulated.BLS12381Fp]("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436") + return &E2{ + A0: *e.fp.MulMod(&x.A0, &element), + A1: *e.fp.MulMod(&x.A1, &element), + } } -// MulByNonResidue2Power5 returns x*(9+u)^(5*(p^2-1)/6) +// MulByNonResidue2Power5 returns x*(1+u)^(5*(p^2-1)/6) func (e Ext2) MulByNonResidue2Power5(x *E2) *E2 { - return e.MulByNonResidueGeneric(x, 2, 5) + element := emulated.ValueOf[emulated.BLS12381Fp]("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437") + return &E2{ + A0: *e.fp.MulMod(&x.A0, &element), + A1: *e.fp.MulMod(&x.A1, &element), + } } func (e Ext2) Mul(x, y *E2) *E2 { From 31e96ae48f1ddc43374f86ee288882ff336637c3 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Thu, 16 Mar 2023 16:24:49 +0100 Subject: [PATCH 141/464] fix: circuit-efficient Expt --- .../emulated/fields_bls12381/e12_pairing.go | 117 +++++++++--------- .../emulated/fields_bls12381/e12_test.go | 17 ++- 2 files changed, 74 insertions(+), 60 deletions(-) diff --git a/std/algebra/emulated/fields_bls12381/e12_pairing.go b/std/algebra/emulated/fields_bls12381/e12_pairing.go index 2e8636652a..631c0181fb 100644 --- a/std/algebra/emulated/fields_bls12381/e12_pairing.go +++ b/std/algebra/emulated/fields_bls12381/e12_pairing.go @@ -1,68 +1,69 @@ package fields_bls12381 -// TODO: correct addchain to BLS12-381 seed - -func (e Ext12) Expt(x *E12) *E12 { - // Expt computation is derived from the addition chain: +// ExptHalf set z to x^(t/2) in E12 and return z +// const t/2 uint64 = 7566188111470821376 // negative +func (e Ext12) ExptHalf(x *E12) *E12 { + // FixedExp computation is derived from the addition chain: // - // _10 = 2*1 - // _100 = 2*_10 - // _1000 = 2*_100 - // _10000 = 2*_1000 - // _10001 = 1 + _10000 - // _10011 = _10 + _10001 - // _10100 = 1 + _10011 - // _11001 = _1000 + _10001 - // _100010 = 2*_10001 - // _100111 = _10011 + _10100 - // _101001 = _10 + _100111 - // i27 = (_100010 << 6 + _100 + _11001) << 7 + _11001 - // i44 = (i27 << 8 + _101001 + _10) << 6 + _10001 - // i70 = ((i44 << 8 + _101001) << 6 + _101001) << 10 - // return (_100111 + i70) << 6 + _101001 + _1000 + // _10 = 2*1 + // _11 = 1 + _10 + // _1100 = _11 << 2 + // _1101 = 1 + _1100 + // _1101000 = _1101 << 3 + // _1101001 = 1 + _1101000 + // return ((_1101001 << 9 + 1) << 32 + 1) << 15 // - // Operations: 62 squares 17 multiplies + // Operations: 62 squares 5 multiplies // // Generated by github.com/mmcloughlin/addchain v0.4.0. - t3 := e.CyclotomicSquare(x) - t5 := e.CyclotomicSquare(t3) - result := e.CyclotomicSquare(t5) - t0 := e.CyclotomicSquare(result) - t2 := e.Mul(x, t0) - t0 = e.Mul(t3, t2) - t1 := e.Mul(x, t0) - t4 := e.Mul(result, t2) - t6 := e.CyclotomicSquare(t2) - t1 = e.Mul(t0, t1) - t0 = e.Mul(t3, t1) - t6 = e.NCycloSquareCompressed(t6, 6) - t6 = e.DecompressKarabina(t6) - t5 = e.Mul(t5, t6) - t5 = e.Mul(t4, t5) - t5 = e.NCycloSquareCompressed(t5, 7) - t5 = e.DecompressKarabina(t5) - t4 = e.Mul(t4, t5) - t4 = e.NCycloSquareCompressed(t4, 8) - t4 = e.DecompressKarabina(t4) - t4 = e.Mul(t0, t4) - t3 = e.Mul(t3, t4) - t3 = e.NCycloSquareCompressed(t3, 6) - t3 = e.DecompressKarabina(t3) - t2 = e.Mul(t2, t3) - t2 = e.NCycloSquareCompressed(t2, 8) - t2 = e.DecompressKarabina(t2) - t2 = e.Mul(t0, t2) - t2 = e.NCycloSquareCompressed(t2, 6) - t2 = e.DecompressKarabina(t2) - t2 = e.Mul(t0, t2) - t2 = e.NCycloSquareCompressed(t2, 10) - t2 = e.DecompressKarabina(t2) - t1 = e.Mul(t1, t2) - t1 = e.NCycloSquareCompressed(t1, 6) - t1 = e.DecompressKarabina(t1) - t0 = e.Mul(t0, t1) - z := e.Mul(result, t0) + // Step 1: z = x^0x2 + z := e.Square(x) + + // Step 2: z = x^0x3 + z = e.Mul(x, z) + + z = e.CyclotomicSquare(z) + z = e.CyclotomicSquare(z) + + // Step 5: z = x^0xd + z = e.Mul(x, z) + + // Step 8: z = x^0x68 + z = e.NCycloSquareCompressed(z, 3) + z = e.DecompressKarabina(z) + + // Step 9: z = x^0x69 + z = e.Mul(x, z) + + // Step 18: z = x^0xd200 + z = e.NCycloSquareCompressed(z, 9) + z = e.DecompressKarabina(z) + + // Step 19: z = x^0xd201 + z = e.Mul(x, z) + + // Step 51: z = x^0xd20100000000 + z = e.NCycloSquareCompressed(z, 32) + z = e.DecompressKarabina(z) + + // Step 52: z = x^0xd20100000001 + z = e.Mul(x, z) + + // Step 67: z = x^0x6900800000008000 + z = e.NCycloSquareCompressed(z, 15) + z = e.DecompressKarabina(z) + + z = e.Conjugate(z) // because tAbsVal is negative + + return z +} + +// Expt set z to xᵗ in E12 and return z +// const t uint64 = 15132376222941642752 // negative +func (e Ext12) Expt(x *E12) *E12 { + z := e.ExptHalf(x) + z = e.CyclotomicSquare(z) return z } diff --git a/std/algebra/emulated/fields_bls12381/e12_test.go b/std/algebra/emulated/fields_bls12381/e12_test.go index 457dcd6c35..478d2df1fd 100644 --- a/std/algebra/emulated/fields_bls12381/e12_test.go +++ b/std/algebra/emulated/fields_bls12381/e12_test.go @@ -1,11 +1,15 @@ package fields_bls12381 import ( + "fmt" "testing" "github.com/consensys/gnark-crypto/ecc" bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/profile" "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/test" ) @@ -346,7 +350,6 @@ func TestInverseFp12(t *testing.T) { assert.NoError(err) } -/* type e12Expt struct { A E12 C E12 `gnark:",public"` @@ -385,7 +388,6 @@ func TestFp12Expt(t *testing.T) { err := test.IsSolved(&e12Expt{}, &witness, ecc.BLS12_381.ScalarField()) assert.NoError(err) } -*/ type e12Frobenius struct { A, C E12 @@ -490,3 +492,14 @@ func TestFp12MulBy014(t *testing.T) { } */ + +// bench +var ccsBench constraint.ConstraintSystem + +func BenchmarkExpt(b *testing.B) { + var c e12Expt + p := profile.Start() + ccsBench, _ = frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &c) + p.Stop() + fmt.Println(p.NbConstraints()) +} From 49bf2e5163089740c5ea63afbb19ebe3ae9bc403 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Thu, 16 Mar 2023 17:47:34 +0100 Subject: [PATCH 142/464] fix(emulated/bls12-381): correct and optimize MulBy014 --- .../emulated/fields_bls12381/e12_pairing.go | 20 +++++------- .../emulated/fields_bls12381/e12_test.go | 2 -- std/algebra/emulated/fields_bls12381/e6.go | 32 ++++++++++++++++--- .../emulated/fields_bls12381/e6_test.go | 11 +++---- 4 files changed, 40 insertions(+), 25 deletions(-) diff --git a/std/algebra/emulated/fields_bls12381/e12_pairing.go b/std/algebra/emulated/fields_bls12381/e12_pairing.go index 631c0181fb..593c154000 100644 --- a/std/algebra/emulated/fields_bls12381/e12_pairing.go +++ b/std/algebra/emulated/fields_bls12381/e12_pairing.go @@ -73,23 +73,19 @@ func (e Ext12) Expt(x *E12) *E12 { // C0: E6{B0: 1, B1: c1, B2: 0}, // C1: E6{B0: 0, B1: c4, B2: 0}, // } -// -// TODO : correct MulByO14 and not 034 func (e *Ext12) MulBy014(z *E12, c1, c4 *E2) *E12 { a := z.C0 - b := z.C1 + a = *e.Ext6.MulBy01(&a, c1) - b = *e.MulBy01(&b, c1, c4) - one := e.Ext2.One() - - c1 = e.Ext2.Add(one, c1) - d := e.Ext6.Add(&z.C0, &z.C1) - d = e.MulBy01(d, c1, c4) + b := z.C1 + b = *e.Ext6.MulBy1(&b, c4) + d := e.Ext2.Add(c1, c4) - zC1 := e.Ext6.Add(&a, &b) - zC1 = e.Ext6.Neg(zC1) - zC1 = e.Ext6.Add(zC1, d) + zC1 := e.Ext6.Add(&z.C1, &z.C0) + zC1 = e.Ext6.MulBy01(zC1, d) + zC1 = e.Ext6.Sub(zC1, &a) + zC1 = e.Ext6.Sub(zC1, &b) zC0 := e.Ext6.MulByNonResidue(&b) zC0 = e.Ext6.Add(zC0, &a) diff --git a/std/algebra/emulated/fields_bls12381/e12_test.go b/std/algebra/emulated/fields_bls12381/e12_test.go index 478d2df1fd..eeccc23ead 100644 --- a/std/algebra/emulated/fields_bls12381/e12_test.go +++ b/std/algebra/emulated/fields_bls12381/e12_test.go @@ -451,7 +451,6 @@ func TestFrobeniusSquareFp12(t *testing.T) { } -/* type e12MulBy014 struct { A E12 `gnark:",public"` W E12 @@ -491,7 +490,6 @@ func TestFp12MulBy014(t *testing.T) { assert.NoError(err) } -*/ // bench var ccsBench constraint.ConstraintSystem diff --git a/std/algebra/emulated/fields_bls12381/e6.go b/std/algebra/emulated/fields_bls12381/e6.go index 206829025f..a9cb381ae8 100644 --- a/std/algebra/emulated/fields_bls12381/e6.go +++ b/std/algebra/emulated/fields_bls12381/e6.go @@ -151,8 +151,9 @@ func (e Ext6) MulByE2(x *E6, y *E2) *E6 { } } -func (e Ext6) MulBy01(z *E6, c0, c1 *E2) *E6 { - a := e.Ext2.Mul(&z.B0, c0) +// MulBy01 multiplication by sparse element (1,c1,0) +func (e Ext6) MulBy01(z *E6, c1 *E2) *E6 { + a := &z.B0 b := e.Ext2.Mul(&z.B1, c1) tmp := e.Ext2.Add(&z.B1, &z.B2) t0 := e.Ext2.Mul(c1, tmp) @@ -160,12 +161,12 @@ func (e Ext6) MulBy01(z *E6, c0, c1 *E2) *E6 { t0 = e.Ext2.MulByNonResidue(t0) t0 = e.Ext2.Add(t0, a) tmp = e.Ext2.Add(&z.B0, &z.B2) - t2 := e.Ext2.Mul(c0, tmp) + t2 := tmp t2 = e.Ext2.Sub(t2, a) t2 = e.Ext2.Add(t2, b) - t1 := e.Ext2.Add(c0, c1) tmp = e.Ext2.Add(&z.B0, &z.B1) - t1 = e.Ext2.Mul(t1, tmp) + t1 := e.Ext2.Mul(c1, tmp) + t1 = e.Ext2.Add(t1, tmp) t1 = e.Ext2.Sub(t1, a) t1 = e.Ext2.Sub(t1, b) return &E6{ @@ -175,6 +176,27 @@ func (e Ext6) MulBy01(z *E6, c0, c1 *E2) *E6 { } } +// MulBy1 multiplication of E6 by sparse element (0, c1, 0) +func (e Ext6) MulBy1(z *E6, c1 *E2) *E6 { + + b := e.Ext2.Mul(&z.B1, c1) + + tmp := e.Ext2.Add(&z.B1, &z.B2) + t0 := e.Ext2.Mul(c1, tmp) + t0 = e.Ext2.Sub(t0, b) + t0 = e.Ext2.MulByNonResidue(t0) + + tmp = e.Ext2.Add(&z.B0, &z.B1) + t1 := e.Ext2.Mul(c1, tmp) + t1 = e.Ext2.Sub(t1, b) + + return &E6{ + B0: *t0, + B1: *t1, + B2: *b, + } +} + func (e Ext6) MulByNonResidue(x *E6) *E6 { z2, z1, z0 := &x.B1, &x.B0, &x.B2 z0 = e.Ext2.MulByNonResidue(z0) diff --git a/std/algebra/emulated/fields_bls12381/e6_test.go b/std/algebra/emulated/fields_bls12381/e6_test.go index 5c05d84401..6d59231bc3 100644 --- a/std/algebra/emulated/fields_bls12381/e6_test.go +++ b/std/algebra/emulated/fields_bls12381/e6_test.go @@ -240,15 +240,15 @@ func TestMulFp6ByE2(t *testing.T) { } type e6MulBy01 struct { - A E6 - C0, C1 E2 - C E6 `gnark:",public"` + A E6 + C1 E2 + C E6 `gnark:",public"` } func (circuit *e6MulBy01) Define(api frontend.API) error { ba, _ := emulated.NewField[emulated.BLS12381Fp](api) e := NewExt6(ba) - expected := e.MulBy01(&circuit.A, &circuit.C0, &circuit.C1) + expected := e.MulBy01(&circuit.A, &circuit.C1) e.AssertIsEqual(expected, &circuit.C) return nil @@ -261,14 +261,13 @@ func TestMulFp6By01(t *testing.T) { var a, c bls12381.E6 var C0, C1 bls12381.E2 _, _ = a.SetRandom() - _, _ = C0.SetRandom() + C0.SetOne() _, _ = C1.SetRandom() c.Set(&a) c.MulBy01(&C0, &C1) witness := e6MulBy01{ A: FromE6(&a), - C0: FromE2(&C0), C1: FromE2(&C1), C: FromE6(&c), } From 1311ae22d1d327ece86224fbb693312cc12e12c1 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Thu, 16 Mar 2023 18:04:58 +0100 Subject: [PATCH 143/464] feat(emulated/bls12-381): add final exp (Hayashida et al.) --- std/algebra/emulated/sw_bls12381/doc.go | 6 + std/algebra/emulated/sw_bls12381/doc_test.go | 97 ++++ std/algebra/emulated/sw_bls12381/g1.go | 16 + std/algebra/emulated/sw_bls12381/g2.go | 24 + std/algebra/emulated/sw_bls12381/pairing.go | 426 ++++++++++++++++++ .../emulated/sw_bls12381/pairing_test.go | 100 ++++ 6 files changed, 669 insertions(+) create mode 100644 std/algebra/emulated/sw_bls12381/doc.go create mode 100644 std/algebra/emulated/sw_bls12381/doc_test.go create mode 100644 std/algebra/emulated/sw_bls12381/g1.go create mode 100644 std/algebra/emulated/sw_bls12381/g2.go create mode 100644 std/algebra/emulated/sw_bls12381/pairing.go create mode 100644 std/algebra/emulated/sw_bls12381/pairing_test.go diff --git a/std/algebra/emulated/sw_bls12381/doc.go b/std/algebra/emulated/sw_bls12381/doc.go new file mode 100644 index 0000000000..948f61e24f --- /dev/null +++ b/std/algebra/emulated/sw_bls12381/doc.go @@ -0,0 +1,6 @@ +// Package sw_bls12381 implements G1 and G2 arithmetics and pairing computation over BLS12-381 curve. +// +// The implementation follows [Housni22]: "Pairings in Rank-1 Constraint Systems". +// +// [Housni22]: https://eprint.iacr.org/2022/1162 +package sw_bls12381 diff --git a/std/algebra/emulated/sw_bls12381/doc_test.go b/std/algebra/emulated/sw_bls12381/doc_test.go new file mode 100644 index 0000000000..0e112a27c9 --- /dev/null +++ b/std/algebra/emulated/sw_bls12381/doc_test.go @@ -0,0 +1,97 @@ +package sw_bls12381_test + +import ( + "crypto/rand" + + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" +) + +/* +type PairCircuit struct { + InG1 sw_bls12381.G1Affine + InG2 sw_bls12381.G2Affine + Res sw_bls12381.GTEl +} + +func (c *PairCircuit) Define(api frontend.API) error { + pairing, err := sw_bls12381.NewPairing(api) + if err != nil { + return fmt.Errorf("new pairing: %w", err) + } + res, err := pairing.Pair([]*sw_bls12381.G1Affine{&c.InG1}, []*sw_bls12381.G2Affine{&c.InG2}) + if err != nil { + return fmt.Errorf("pair: %w", err) + } + pairing.AssertIsEqual(res, &c.Res) + return nil +} + +func ExamplePairing() { + p, q, err := randomG1G2Affines() + if err != nil { + panic(err) + } + res, err := bls12381.Pair([]bls12381.G1Affine{p}, []bls12381.G2Affine{q}) + if err != nil { + panic(err) + } + circuit := PairCircuit{} + witness := PairCircuit{ + InG1: sw_bls12381.NewG1Affine(p), + InG2: sw_bls12381.NewG2Affine(q), + Res: sw_bls12381.NewGTEl(res), + } + ccs, err := frontend.Compile(ecc.BLS12_381.ScalarField(), r1cs.NewBuilder, &circuit) + if err != nil { + panic(err) + } else { + fmt.Println("compiled") + } + pk, vk, err := groth16.Setup(ccs) + if err != nil { + panic(err) + } else { + fmt.Println("setup done") + } + secretWitness, err := frontend.NewWitness(&witness, ecc.BLS12_381.ScalarField()) + if err != nil { + panic(err) + } else { + fmt.Println("secret witness") + } + publicWitness, err := secretWitness.Public() + if err != nil { + panic(err) + } else { + fmt.Println("public witness") + } + proof, err := groth16.Prove(ccs, pk, secretWitness) + if err != nil { + panic(err) + } else { + fmt.Println("proof") + } + err = groth16.Verify(proof, vk, publicWitness) + if err != nil { + panic(err) + } else { + fmt.Println("verify") + } +} +*/ + +func randomG1G2Affines() (p bls12381.G1Affine, q bls12381.G2Affine, err error) { + _, _, G1AffGen, G2AffGen := bls12381.Generators() + mod := bls12381.ID.ScalarField() + s1, err := rand.Int(rand.Reader, mod) + if err != nil { + return p, q, err + } + s2, err := rand.Int(rand.Reader, mod) + if err != nil { + return p, q, err + } + p.ScalarMultiplication(&G1AffGen, s1) + q.ScalarMultiplication(&G2AffGen, s2) + return +} diff --git a/std/algebra/emulated/sw_bls12381/g1.go b/std/algebra/emulated/sw_bls12381/g1.go new file mode 100644 index 0000000000..fd95f4722b --- /dev/null +++ b/std/algebra/emulated/sw_bls12381/g1.go @@ -0,0 +1,16 @@ +package sw_bls12381 + +import ( + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark/std/algebra/emulated/sw_emulated" + "github.com/consensys/gnark/std/math/emulated" +) + +type G1Affine = sw_emulated.AffinePoint[emulated.BLS12381Fp] + +func NewG1Affine(v bls12381.G1Affine) G1Affine { + return G1Affine{ + X: emulated.ValueOf[emulated.BLS12381Fp](v.X), + Y: emulated.ValueOf[emulated.BLS12381Fp](v.Y), + } +} diff --git a/std/algebra/emulated/sw_bls12381/g2.go b/std/algebra/emulated/sw_bls12381/g2.go new file mode 100644 index 0000000000..f96ea4c354 --- /dev/null +++ b/std/algebra/emulated/sw_bls12381/g2.go @@ -0,0 +1,24 @@ +package sw_bls12381 + +import ( + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark/std/algebra/emulated/fields_bls12381" + "github.com/consensys/gnark/std/math/emulated" +) + +type G2Affine struct { + X, Y fields_bls12381.E2 +} + +func NewG2Affine(v bls12381.G2Affine) G2Affine { + return G2Affine{ + X: fields_bls12381.E2{ + A0: emulated.ValueOf[emulated.BLS12381Fp](v.X.A0), + A1: emulated.ValueOf[emulated.BLS12381Fp](v.X.A1), + }, + Y: fields_bls12381.E2{ + A0: emulated.ValueOf[emulated.BLS12381Fp](v.Y.A0), + A1: emulated.ValueOf[emulated.BLS12381Fp](v.Y.A1), + }, + } +} diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go new file mode 100644 index 0000000000..d739a74907 --- /dev/null +++ b/std/algebra/emulated/sw_bls12381/pairing.go @@ -0,0 +1,426 @@ +package sw_bls12381 + +import ( + "fmt" + "math/big" + + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/algebra/emulated/fields_bls12381" + "github.com/consensys/gnark/std/math/emulated" +) + +type Pairing struct { + *fields_bls12381.Ext12 + curveF *emulated.Field[emulated.BLS12381Fp] +} + +type GTEl = fields_bls12381.E12 + +func NewGTEl(v bls12381.GT) GTEl { + return GTEl{ + C0: fields_bls12381.E6{ + B0: fields_bls12381.E2{ + A0: emulated.ValueOf[emulated.BLS12381Fp](v.C0.B0.A0), + A1: emulated.ValueOf[emulated.BLS12381Fp](v.C0.B0.A1), + }, + B1: fields_bls12381.E2{ + A0: emulated.ValueOf[emulated.BLS12381Fp](v.C0.B1.A0), + A1: emulated.ValueOf[emulated.BLS12381Fp](v.C0.B1.A1), + }, + B2: fields_bls12381.E2{ + A0: emulated.ValueOf[emulated.BLS12381Fp](v.C0.B2.A0), + A1: emulated.ValueOf[emulated.BLS12381Fp](v.C0.B2.A1), + }, + }, + C1: fields_bls12381.E6{ + B0: fields_bls12381.E2{ + A0: emulated.ValueOf[emulated.BLS12381Fp](v.C1.B0.A0), + A1: emulated.ValueOf[emulated.BLS12381Fp](v.C1.B0.A1), + }, + B1: fields_bls12381.E2{ + A0: emulated.ValueOf[emulated.BLS12381Fp](v.C1.B1.A0), + A1: emulated.ValueOf[emulated.BLS12381Fp](v.C1.B1.A1), + }, + B2: fields_bls12381.E2{ + A0: emulated.ValueOf[emulated.BLS12381Fp](v.C1.B2.A0), + A1: emulated.ValueOf[emulated.BLS12381Fp](v.C1.B2.A1), + }, + }, + } +} + +func NewPairing(api frontend.API) (*Pairing, error) { + ba, err := emulated.NewField[emulated.BLS12381Fp](api) + if err != nil { + return nil, fmt.Errorf("new base api: %w", err) + } + return &Pairing{ + Ext12: fields_bls12381.NewExt12(ba), + curveF: ba, + }, nil +} + +// FinalExponentiation computes the exponentiation (∏ᵢ zᵢ)ᵈ +// where d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r +// we use instead d=s ⋅ (p⁶-1)(p²+1)(p⁴ - p² +1)/r +// where s is the cofactor 3 (Hayashida et al.) +func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { + var t [4]*GTEl + + // Easy part + // (p⁶-1)(p²+1) + t[0] = pr.Ext12.Conjugate(e) + t[0] = pr.Ext12.DivUnchecked(t[0], e) + result := pr.Ext12.FrobeniusSquare(t[0]) + result = pr.Ext12.Mul(result, t[0]) + + // Hard part (up to permutation) + // Daiki Hayashida, Kenichiro Hayasaka and Tadanori Teruya + // https://eprint.iacr.org/2020/875.pdf + t[0] = pr.CyclotomicSquare(result) + t[1] = pr.ExptHalf(t[0]) + t[2] = pr.Conjugate(result) + t[1] = pr.Mul(t[1], t[2]) + t[2] = pr.Expt(t[1]) + t[1] = pr.Conjugate(t[1]) + t[1] = pr.Mul(t[1], t[2]) + t[2] = pr.Expt(t[1]) + t[1] = pr.Frobenius(t[1]) + t[1] = pr.Mul(t[1], t[2]) + result = pr.Mul(result, t[0]) + t[0] = pr.Expt(t[1]) + t[2] = pr.Expt(t[0]) + t[0] = pr.FrobeniusSquare(t[1]) + t[1] = pr.Conjugate(t[1]) + t[1] = pr.Mul(t[1], t[2]) + t[1] = pr.Mul(t[1], t[0]) + result = pr.Mul(result, t[1]) + + return result +} + +// lineEvaluation represents a sparse Fp12 Elmt (result of the line evaluation) +// line: 1 - R0(x/y) - R1(1/y) = 0 instead of R0'*y - R1'*x - R2' = 0 This +// makes the multiplication by lines (MulBy034) and between lines (Mul034By034) +// circuit-efficient. +type lineEvaluation struct { + R0, R1 fields_bls12381.E2 +} + +/* +func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { + res, err := pr.MillerLoop(P, Q) + if err != nil { + return nil, fmt.Errorf("miller loop: %w", err) + } + res = pr.FinalExponentiation(res) + return res, nil +} + +func (pr Pairing) AssertIsEqual(x, y *GTEl) { + pr.Ext12.AssertIsEqual(x, y) +} + +// loopCounter = 6*seed+2 in 2-NAF +// loopCounter = 29793968203157093288 +var loopCounter = [66]int8{ + 0, 0, 0, 1, 0, 1, 0, -1, 0, 0, -1, + 0, 0, 0, 1, 0, 0, -1, 0, -1, 0, 0, + 0, 1, 0, -1, 0, 0, 0, 0, -1, 0, 0, + 1, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, + -1, 0, 0, -1, 0, 1, 0, -1, 0, 0, 0, + -1, 0, -1, 0, 0, 0, 1, 0, -1, 0, 1, +} + +// MillerLoop computes the multi-Miller loop +// ∏ᵢ { fᵢ_{ℓ,Q}(P) · ℓᵢ_{[ℓ]q,π(q)}(p) · ℓᵢ_{[ℓ]q+π(q),-π²(q)}(p) } +func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { + // check input size match + n := len(P) + if n == 0 || n != len(Q) { + return nil, errors.New("invalid inputs sizes") + } + + res := pr.Ext12.One() + + var l1, l2 *lineEvaluation + Qacc := make([]*G2Affine, n) + QNeg := make([]*G2Affine, n) + yInv := make([]*emulated.Element[emulated.BLS12381Fp], n) + xOverY := make([]*emulated.Element[emulated.BLS12381Fp], n) + + for k := 0; k < n; k++ { + Qacc[k] = Q[k] + QNeg[k] = &G2Affine{X: Q[k].X, Y: *pr.Ext2.Neg(&Q[k].Y)} + // (x,0) cannot be on BLS12381 because -3 is a cubic non-residue in Fp + // so, 1/y is well defined for all points P's + yInv[k] = pr.curveF.Inverse(&P[k].Y) + xOverY[k] = pr.curveF.MulMod(&P[k].X, yInv[k]) + } + + // Compute ∏ᵢ { fᵢ_{ℓ,Q}(P) } + // i = len(loopCounter) - 2, separately to avoid E12 Square + // (Square(res) = 1² = 1) + + // k = 0, separately to avoid MulBy034 (res × ℓ) + // (assign line to res) + Qacc[0], l1 = pr.doubleStep(Qacc[0]) + // line evaluation at P[0] + res.C1.B0 = *pr.MulByElement(&l1.R0, xOverY[0]) + res.C1.B1 = *pr.MulByElement(&l1.R1, yInv[0]) + + if n >= 2 { + // k = 1, separately to avoid MulBy034 (res × ℓ) + // (res is also a line at this point, so we use Mul034By034 ℓ × ℓ) + Qacc[1], l1 = pr.doubleStep(Qacc[1]) + // line evaluation at P[1] + l1.R0 = *pr.MulByElement(&l1.R0, xOverY[1]) + l1.R1 = *pr.MulByElement(&l1.R1, yInv[1]) + res = pr.Mul034By034(&l1.R0, &l1.R1, &res.C1.B0, &res.C1.B1) + } + + if n >= 3 { + // k >= 2 + for k := 2; k < n; k++ { + // Qacc[k] ← 2Qacc[k] and l1 the tangent ℓ passing 2Qacc[k] + Qacc[k], l1 = pr.doubleStep(Qacc[k]) + // line evaluation at P[k] + l1.R0 = *pr.MulByElement(&l1.R0, xOverY[k]) + l1.R1 = *pr.MulByElement(&l1.R1, yInv[k]) + // ℓ × res + res = pr.MulBy034(res, &l1.R0, &l1.R1) + } + } + + for i := len(loopCounter) - 3; i >= 0; i-- { + // mutualize the square among n Miller loops + // (∏ᵢfᵢ)² + res = pr.Square(res) + + switch loopCounter[i] { + + case 0: + for k := 0; k < n; k++ { + // Qacc[k] ← 2Qacc[k] and l1 the tangent ℓ passing 2Qacc[k] + Qacc[k], l1 = pr.doubleStep(Qacc[k]) + // line evaluation at P[k] + l1.R0 = *pr.MulByElement(&l1.R0, xOverY[k]) + l1.R1 = *pr.MulByElement(&l1.R1, yInv[k]) + // ℓ × res + res = pr.MulBy034(res, &l1.R0, &l1.R1) + } + + case 1: + for k := 0; k < n; k++ { + // Qacc[k] ← 2Qacc[k]+Q[k], + // l1 the line ℓ passing Qacc[k] and Q[k] + // l2 the line ℓ passing (Qacc[k]+Q[k]) and Qacc[k] + Qacc[k], l1, l2 = pr.doubleAndAddStep(Qacc[k], Q[k]) + // line evaluation at P[k] + l1.R0 = *pr.MulByElement(&l1.R0, xOverY[k]) + l1.R1 = *pr.MulByElement(&l1.R1, yInv[k]) + // ℓ × res + res = pr.MulBy034(res, &l1.R0, &l1.R1) + // line evaluation at P[k] + l2.R0 = *pr.MulByElement(&l2.R0, xOverY[k]) + l2.R1 = *pr.MulByElement(&l2.R1, yInv[k]) + // ℓ × res + res = pr.MulBy034(res, &l2.R0, &l2.R1) + } + + case -1: + for k := 0; k < n; k++ { + // Qacc[k] ← 2Qacc[k]-Q[k], + // l1 the line ℓ passing Qacc[k] and -Q[k] + // l2 the line ℓ passing (Qacc[k]-Q[k]) and Qacc[k] + Qacc[k], l1, l2 = pr.doubleAndAddStep(Qacc[k], QNeg[k]) + // line evaluation at P[k] + l1.R0 = *pr.MulByElement(&l1.R0, xOverY[k]) + l1.R1 = *pr.MulByElement(&l1.R1, yInv[k]) + // ℓ × res + res = pr.MulBy034(res, &l1.R0, &l1.R1) + // line evaluation at P[k] + l2.R0 = *pr.MulByElement(&l2.R0, xOverY[k]) + l2.R1 = *pr.MulByElement(&l2.R1, yInv[k]) + // ℓ × res + res = pr.MulBy034(res, &l2.R0, &l2.R1) + } + + default: + return nil, errors.New("invalid loopCounter") + } + } + + // Compute ∏ᵢ { ℓᵢ_{[ℓ]q,π(q)}(p) · ℓᵢ_{[ℓ]q+π(q),-π²(q)}(p) } + Q1, Q2 := new(G2Affine), new(G2Affine) + for k := 0; k < n; k++ { + //Q1 = π(Q) + Q1.X = *pr.Ext12.Ext2.Conjugate(&Q[k].X) + Q1.X = *pr.Ext12.Ext2.MulByNonResidue1Power2(&Q1.X) + Q1.Y = *pr.Ext12.Ext2.Conjugate(&Q[k].Y) + Q1.Y = *pr.Ext12.Ext2.MulByNonResidue1Power3(&Q1.Y) + + // Q2 = -π²(Q) + Q2.X = *pr.Ext12.Ext2.MulByNonResidue2Power2(&Q[k].X) + Q2.Y = *pr.Ext12.Ext2.MulByNonResidue2Power3(&Q[k].Y) + Q2.Y = *pr.Ext12.Ext2.Neg(&Q2.Y) + + // Qacc[k] ← Qacc[k]+π(Q) and + // l1 the line passing Qacc[k] and π(Q) + Qacc[k], l1 = pr.addStep(Qacc[k], Q1) + // line evaluation at P[k] + l1.R0 = *pr.Ext2.MulByElement(&l1.R0, xOverY[k]) + l1.R1 = *pr.Ext2.MulByElement(&l1.R1, yInv[k]) + // ℓ × res + res = pr.MulBy034(res, &l1.R0, &l1.R1) + + // l2 the line passing Qacc[k] and -π²(Q) + l2 = pr.lineCompute(Qacc[k], Q2) + // line evaluation at P[k] + l2.R0 = *pr.MulByElement(&l2.R0, xOverY[k]) + l2.R1 = *pr.MulByElement(&l2.R1, yInv[k]) + // ℓ × res + res = pr.MulBy034(res, &l2.R0, &l2.R1) + + } + + return res, nil +} +*/ + +// doubleAndAddStep doubles p1 and adds p2 to the result in affine coordinates, and evaluates the line in Miller loop +// https://eprint.iacr.org/2022/1162 (Section 6.1) +func (pr Pairing) doubleAndAddStep(p1, p2 *G2Affine) (*G2Affine, *lineEvaluation, *lineEvaluation) { + + var line1, line2 lineEvaluation + var p G2Affine + + // compute λ1 = (y2-y1)/(x2-x1) + n := pr.Ext2.Sub(&p1.Y, &p2.Y) + d := pr.Ext2.Sub(&p1.X, &p2.X) + l1 := pr.Ext2.DivUnchecked(n, d) + + // compute x3 =λ1²-x1-x2 + x3 := pr.Ext2.Square(l1) + x3 = pr.Ext2.Sub(x3, &p1.X) + x3 = pr.Ext2.Sub(x3, &p2.X) + + // omit y3 computation + + // compute line1 + line1.R0 = *pr.Ext2.Neg(l1) + line1.R1 = *pr.Ext2.Mul(l1, &p1.X) + line1.R1 = *pr.Ext2.Sub(&line1.R1, &p1.Y) + + // compute λ2 = -λ1-2y1/(x3-x1) + n = pr.Ext2.Double(&p1.Y) + d = pr.Ext2.Sub(x3, &p1.X) + l2 := pr.Ext2.DivUnchecked(n, d) + l2 = pr.Ext2.Add(l2, l1) + l2 = pr.Ext2.Neg(l2) + + // compute x4 = λ2²-x1-x3 + x4 := pr.Ext2.Square(l2) + x4 = pr.Ext2.Sub(x4, &p1.X) + x4 = pr.Ext2.Sub(x4, x3) + + // compute y4 = λ2(x1 - x4)-y1 + y4 := pr.Ext2.Sub(&p1.X, x4) + y4 = pr.Ext2.Mul(l2, y4) + y4 = pr.Ext2.Sub(y4, &p1.Y) + + p.X = *x4 + p.Y = *y4 + + // compute line2 + line2.R0 = *pr.Ext2.Neg(l2) + line2.R1 = *pr.Ext2.Mul(l2, &p1.X) + line2.R1 = *pr.Ext2.Sub(&line2.R1, &p1.Y) + + return &p, &line1, &line2 +} + +// doubleStep doubles a point in affine coordinates, and evaluates the line in Miller loop +// https://eprint.iacr.org/2022/1162 (Section 6.1) +func (pr Pairing) doubleStep(p1 *G2Affine) (*G2Affine, *lineEvaluation) { + + var p G2Affine + var line lineEvaluation + + // λ = 3x²/2y + n := pr.Ext2.Square(&p1.X) + three := big.NewInt(3) + n = pr.Ext2.MulByConstElement(n, three) + d := pr.Ext2.Double(&p1.Y) + λ := pr.Ext2.DivUnchecked(n, d) + + // xr = λ²-2x + xr := pr.Ext2.Square(λ) + xr = pr.Ext2.Sub(xr, &p1.X) + xr = pr.Ext2.Sub(xr, &p1.X) + + // yr = λ(x-xr)-y + yr := pr.Ext2.Sub(&p1.X, xr) + yr = pr.Ext2.Mul(λ, yr) + yr = pr.Ext2.Sub(yr, &p1.Y) + + p.X = *xr + p.Y = *yr + + line.R0 = *pr.Ext2.Neg(λ) + line.R1 = *pr.Ext2.Mul(λ, &p1.X) + line.R1 = *pr.Ext2.Sub(&line.R1, &p1.Y) + + return &p, &line + +} + +// addStep adds two points in affine coordinates, and evaluates the line in Miller loop +// https://eprint.iacr.org/2022/1162 (Section 6.1) +func (pr Pairing) addStep(p1, p2 *G2Affine) (*G2Affine, *lineEvaluation) { + + // compute λ = (y2-y1)/(x2-x1) + p2ypy := pr.Ext2.Sub(&p2.Y, &p1.Y) + p2xpx := pr.Ext2.Sub(&p2.X, &p1.X) + λ := pr.Ext2.DivUnchecked(p2ypy, p2xpx) + + // xr = λ²-x1-x2 + λλ := pr.Ext2.Square(λ) + p2xpx = pr.Ext2.Add(&p1.X, &p2.X) + xr := pr.Ext2.Sub(λλ, p2xpx) + + // yr = λ(x1-xr) - y1 + pxrx := pr.Ext2.Sub(&p1.X, xr) + λpxrx := pr.Ext2.Mul(λ, pxrx) + yr := pr.Ext2.Sub(λpxrx, &p1.Y) + + var res G2Affine + res.X = *xr + res.Y = *yr + + var line lineEvaluation + line.R0 = *pr.Ext2.Neg(λ) + line.R1 = *pr.Ext2.Mul(λ, &p1.X) + line.R1 = *pr.Ext2.Sub(&line.R1, &p1.Y) + + return &res, &line + +} + +// lineCompute computes the line that goes through p1 and p2 but does not compute p1+p2 +func (pr Pairing) lineCompute(p1, p2 *G2Affine) *lineEvaluation { + + // compute λ = (y2-y1)/(x2-x1) + qypy := pr.Ext2.Sub(&p2.Y, &p1.Y) + qxpx := pr.Ext2.Sub(&p2.X, &p1.X) + λ := pr.Ext2.DivUnchecked(qypy, qxpx) + + var line lineEvaluation + line.R0 = *pr.Ext2.Neg(λ) + line.R1 = *pr.Ext2.Mul(λ, &p1.X) + line.R1 = *pr.Ext2.Sub(&line.R1, &p1.Y) + + return &line + +} diff --git a/std/algebra/emulated/sw_bls12381/pairing_test.go b/std/algebra/emulated/sw_bls12381/pairing_test.go new file mode 100644 index 0000000000..63d32d14e8 --- /dev/null +++ b/std/algebra/emulated/sw_bls12381/pairing_test.go @@ -0,0 +1,100 @@ +package sw_bls12381 + +import ( + "crypto/rand" + "fmt" + "testing" + + "github.com/consensys/gnark-crypto/ecc" + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/test" +) + +func randomG1G2Affines(assert *test.Assert) (bls12381.G1Affine, bls12381.G2Affine) { + _, _, G1AffGen, G2AffGen := bls12381.Generators() + mod := bls12381.ID.ScalarField() + s1, err := rand.Int(rand.Reader, mod) + assert.NoError(err) + s2, err := rand.Int(rand.Reader, mod) + assert.NoError(err) + var p bls12381.G1Affine + p.ScalarMultiplication(&G1AffGen, s1) + var q bls12381.G2Affine + q.ScalarMultiplication(&G2AffGen, s2) + return p, q +} + +type FinalExponentiationCircuit struct { + InGt GTEl + Res GTEl +} + +func (c *FinalExponentiationCircuit) Define(api frontend.API) error { + pairing, err := NewPairing(api) + if err != nil { + return fmt.Errorf("new pairing: %w", err) + } + res := pairing.FinalExponentiation(&c.InGt) + pairing.AssertIsEqual(res, &c.Res) + return nil +} + +func TestFinalExponentiationTestSolve(t *testing.T) { + assert := test.NewAssert(t) + var gt bls12381.GT + gt.SetRandom() + res := bls12381.FinalExponentiation(>) + witness := FinalExponentiationCircuit{ + InGt: NewGTEl(gt), + Res: NewGTEl(res), + } + err := test.IsSolved(&FinalExponentiationCircuit{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) +} + +/* +type PairCircuit struct { + InG1 G1Affine + InG2 G2Affine + Res GTEl +} + +func (c *PairCircuit) Define(api frontend.API) error { + pairing, err := NewPairing(api) + if err != nil { + return fmt.Errorf("new pairing: %w", err) + } + res, err := pairing.Pair([]*G1Affine{&c.InG1}, []*G2Affine{&c.InG2}) + if err != nil { + return fmt.Errorf("pair: %w", err) + } + pairing.AssertIsEqual(res, &c.Res) + return nil +} + +func TestPairTestSolve(t *testing.T) { + assert := test.NewAssert(t) + p, q := randomG1G2Affines(assert) + res, err := bls12381.Pair([]bls12381.G1Affine{p}, []bls12381.G2Affine{q}) + assert.NoError(err) + witness := PairCircuit{ + InG1: NewG1Affine(p), + InG2: NewG2Affine(q), + Res: NewGTEl(res), + } + err = test.IsSolved(&PairCircuit{}, &witness, ecc.BLS12_381.ScalarField()) + assert.NoError(err) +} + +// bench +var ccsBench constraint.ConstraintSystem + +func BenchmarkPairing(b *testing.B) { + var c PairCircuit + p := profile.Start() + ccsBench, _ = frontend.Compile(ecc.BLS12_381.ScalarField(), r1cs.NewBuilder, &c) + p.Stop() + fmt.Println(p.NbConstraints()) +} +*/ From 0e81df4897a3d1617a559dccca7bfa959a23eb55 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 16 Mar 2023 22:45:30 +0100 Subject: [PATCH 144/464] fix: subtraction overflow computation bug (#579) * feat: add subtraction without inline reduction * fix: count possible overflow due to subtraction padding Previously when estimating the maximal overflow for subtraction we only considered the possible overflow caused by the subtraction padding and the subtrahend. But actually as the padding may overflow the minuend we have to also consider it. Due to this, we also had to decrease the maximal possible overflow by one as modular reduction uses subtraction as a subroutine. * test: update circuit statistics * fix: remove empty branch --- internal/stats/latest.stats | Bin 2803 -> 2803 bytes std/math/emulated/field.go | 2 +- std/math/emulated/field_assert.go | 2 +- std/math/emulated/field_ops.go | 15 +++++++++++++-- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/internal/stats/latest.stats b/internal/stats/latest.stats index 0948135ddd60782be3462ac0fc7be1924cd8e438..27e6782e0237df4bb959280fdee86aabc437f96a 100644 GIT binary patch delta 182 zcmew?`dM^B)@D6UcgFfE#(!o17#RPR<7Nc^V*D3852z;Q77&*q6fP^hGuEwQ{8z5W03>iTLbw?J1+N3DiTMP?eF()29C-D?jl^vL05yh6 AsQ>@~ diff --git a/std/math/emulated/field.go b/std/math/emulated/field.go index 3d47bf74be..240638d161 100644 --- a/std/math/emulated/field.go +++ b/std/math/emulated/field.go @@ -278,7 +278,7 @@ func (f *Field[T]) compactLimbs(e *Element[T], groupSize, bitsPerLimb uint) []fr // then the limbs may overflow the native field. func (f *Field[T]) maxOverflow() uint { f.maxOfOnce.Do(func() { - f.maxOf = uint(f.api.Compiler().FieldBitLen()-1) - f.fParams.BitsPerLimb() + f.maxOf = uint(f.api.Compiler().FieldBitLen()-2) - f.fParams.BitsPerLimb() }) return f.maxOf } diff --git a/std/math/emulated/field_assert.go b/std/math/emulated/field_assert.go index 5e9f6e3902..f988a7fcf0 100644 --- a/std/math/emulated/field_assert.go +++ b/std/math/emulated/field_assert.go @@ -128,7 +128,7 @@ func (f *Field[T]) AssertIsEqual(a, b *Element[T]) { return } - diff := f.Sub(b, a) + diff := f.subNoReduce(b, a) // we compute k such that diff / p == k // so essentially, we say "I know an element k such that k*p == diff" diff --git a/std/math/emulated/field_ops.go b/std/math/emulated/field_ops.go index 099b588d70..228106bcbf 100644 --- a/std/math/emulated/field_ops.go +++ b/std/math/emulated/field_ops.go @@ -225,9 +225,20 @@ func (f *Field[T]) Sub(a, b *Element[T]) *Element[T] { return f.reduceAndOp(f.sub, f.subPreCond, a, b) } +// subReduce returns a-b and returns it. Contrary to [Field[T].Sub] method this +// method does not reduce the inputs if the result would overflow. This method +// is currently only used as a subroutine in [Field[T].Reduce] method to avoid +// infinite recursion when we are working exactly on the overflow limits. +func (f *Field[T]) subNoReduce(a, b *Element[T]) *Element[T] { + nextOverflow, _ := f.subPreCond(a, b) + // we ignore error as it only indicates if we should reduce or not. But we + // are in non-reducing version of sub. + return f.sub(a, b, nextOverflow) +} + func (f *Field[T]) subPreCond(a, b *Element[T]) (nextOverflow uint, err error) { - reduceRight := a.overflow < b.overflow+2 - nextOverflow = max(b.overflow+2, a.overflow) + reduceRight := (a.overflow + 1) < (b.overflow + 1) + nextOverflow = max(b.overflow+1, a.overflow+1) if nextOverflow > f.maxOverflow() { err = overflowError{op: "sub", nextOverflow: nextOverflow, maxOverflow: f.maxOverflow(), reduceRight: reduceRight} } From 352f492cf99155d3e7eeaa402f234410f8f6fb2b Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 16 Mar 2023 19:27:39 -0400 Subject: [PATCH 145/464] fix: disastrous typo --- backend/witness/witness.go | 2 +- internal/backend/bn254/plonk/prove.go | 78 ++++++++++++++++++---- internal/backend/bn254/plonk/setup.go | 90 +++++++++++++++++++++++++- internal/backend/bn254/plonk/verify.go | 10 ++- test/commitments_test.go | 22 ++----- test/kzg_srs.go | 2 + 6 files changed, 175 insertions(+), 29 deletions(-) diff --git a/backend/witness/witness.go b/backend/witness/witness.go index 437ffcd35c..2db96aede3 100644 --- a/backend/witness/witness.go +++ b/backend/witness/witness.go @@ -113,7 +113,7 @@ func New(field *big.Int) (Witness, error) { } func (w *witness) Fill(nbPublic, nbSecret int, values <-chan any) error { - n := int(nbPublic + nbSecret) + n := nbPublic + nbSecret w.vector = resize(w.vector, n) w.nbPublic = uint32(nbPublic) w.nbSecret = uint32(nbSecret) diff --git a/internal/backend/bn254/plonk/prove.go b/internal/backend/bn254/plonk/prove.go index fc62d2c143..3223e7bb94 100644 --- a/internal/backend/bn254/plonk/prove.go +++ b/internal/backend/bn254/plonk/prove.go @@ -17,6 +17,8 @@ package plonk import ( + "crypto/sha256" + "fmt" "github.com/consensys/gnark/constraint/solver" "math/big" "runtime" @@ -63,28 +65,35 @@ type Proof struct { ZShiftedOpening kzg.OpeningProof } -type zeroHash struct{} +type oneHash struct{} -func (h zeroHash) Write(p []byte) (n int, err error) { +func (h oneHash) Write(p []byte) (n int, err error) { return len(p), nil } -func (h zeroHash) Sum([]byte) []byte { - return make([]byte, fr.Bytes) +func (h oneHash) Sum([]byte) []byte { + one := make([]byte, fr.Bytes) + one[0] = 1 + return one } -func (h zeroHash) Reset() {} +func (h oneHash) Reset() {} -func (h zeroHash) Size() int { +func (h oneHash) Size() int { return fr.Bytes } -func (h zeroHash) BlockSize() int { +func (h oneHash) BlockSize() int { return fr.Bytes } func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { + fmt.Println("qc(canonical) =", prints(pk.QcPrime)) + domGen = pk.Domain[1].Generator + fmt.Println("qc(coset) =", prints(pk.lQcPrime)) + domGen = pk.Domain[0].Generator + log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", len(spr.Constraints)).Str("backend", "plonk").Logger() opt, err := backend.NewProverConfig(opts...) @@ -94,7 +103,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts start := time.Now() // pick a hash function that will be used to derive the challenges - hFunc := zeroHash{} // TODO Remove + hFunc := sha256.New() // create a transcript manager to apply Fiat Shamir fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") @@ -120,18 +129,31 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return err }*/ pi2iop := iop.NewPolynomial(&pi2, lagReg) + fmt.Println("pi2 =", prints(pi2)) wpi2iop = pi2iop.ShallowClone() wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + fmt.Println("pi2 canonical =", prints(pi2)) if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Vk.KZGSRS); err != nil { return err } if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } + + // TODO Uncomment commitmentVal = hashRes[0] // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses + commitmentVal.SetZero() commitmentVal.BigInt(outs[0]) + fmt.Println("commitment computed as", hashRes[0].Text(10)) return nil })) + } else { + // TODO Leaving pi2 in for testing. In the future, bypass when no commitment present + pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + + pi2iop := iop.NewPolynomial(&pi2, lagReg) + wpi2iop = pi2iop.ShallowClone() + wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() } // query l, r, o in Lagrange basis, not blinded @@ -144,6 +166,10 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts evaluationRDomainSmall := []fr.Element(solution.R) evaluationODomainSmall := []fr.Element(solution.O) + fmt.Println("evaluationLDomainSmall =", prints(evaluationLDomainSmall)) + fmt.Println("evaluationRDomainSmall =", prints(evaluationRDomainSmall)) + fmt.Println("evaluationODomainSmall =", prints(evaluationODomainSmall)) + liop := iop.NewPolynomial(&evaluationLDomainSmall, lagReg) riop := iop.NewPolynomial(&evaluationRDomainSmall, lagReg) oiop := iop.NewPolynomial(&evaluationODomainSmall, lagReg) @@ -154,6 +180,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wriop.ToCanonical(&pk.Domain[0]).ToRegular() woiop.ToCanonical(&pk.Domain[0]).ToRegular() + fmt.Println("evaluationLDomainSmall =", prints(evaluationLDomainSmall)) + fmt.Println("liop =", prints(wliop.Coefficients())) + // Blind l, r, o before committing // we set the underlying slice capacity to domain[1].Cardinality to minimize mem moves. bwliop := wliop.Clone(int(pk.Domain[1].Cardinality)) //.Blind(1) @@ -175,10 +204,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) // TODO @Tabaie @ThomasPiellard add BSB commitment here? + gamma.SetOne() // TODO REMOVE if err != nil { return nil, err } + fmt.Println("gamma =", gamma.Text(10)) + // Fiat Shamir this bbeta, err := fs.ComputeChallenge("beta") if err != nil { @@ -186,6 +218,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } var beta fr.Element beta.SetBytes(bbeta) + beta.SetZero() + + fmt.Println("beta =", beta.Text(10)) // compute the copy constraint's ratio // We copy liop, riop, oiop because they are fft'ed in the process. @@ -217,9 +252,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // derive alpha from the Comm(l), Comm(r), Comm(o), Com(Z) alpha, err := deriveRandomness(&fs, "alpha", &proof.Z) + alpha.SetZero() if err != nil { return proof, err } + fmt.Println("alpha =", alpha.Text(10)) // compute qk in canonical basis, completed with the public inputs qkCompletedCanonical := make([]fr.Element, pk.Domain[0].Cardinality) @@ -237,6 +274,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.ToLagrangeCoset(&pk.Domain[1]) pi2iop := wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form + domGen = pk.Domain[1].Generator + fmt.Println("pi2 (lagrange coset) =", prints(pi2iop.Coefficients())) + lagrangeCosetBitReversed := iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse} // we don't mutate so no need to clone the coefficients from the proving key. @@ -337,6 +377,10 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return c } + + fmt.Println("bwliop evals =", prints(bwliop.Coefficients())) + fmt.Println("pi2iop evals =", prints(pi2iop.Coefficients())) + testEval, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, bwliop, bwriop, @@ -356,14 +400,24 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wqcpiop, // TODO @Tabaie correct format wloneiop, ) + if err != nil { return nil, err } + + cnum := testEval.Clone().ToRegular() + fmt.Println("testEval =", prints(cnum.Coefficients())) + + cnum = testEval.Clone().ToCanonical(&pk.Domain[1]).ToRegular() + fmt.Println("testEval(coeffs) =", prints(cnum.Coefficients())) + h, err := iop.DivideByXMinusOne(testEval, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) // TODO @Tabaie not x^n - 1? if err != nil { return nil, err } + fmt.Println("h =", prints(h.Coefficients())) + // compute kzg commitments of h1, h2 and h3 if err := commitToQuotient( h.Coefficients()[:pk.Domain[0].Cardinality+2], @@ -375,9 +429,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // derive zeta zeta, err := deriveRandomness(&fs, "zeta", &proof.H[0], &proof.H[1], &proof.H[2]) + zeta.SetZero() if err != nil { return nil, err } + fmt.Println("zeta = ", zeta.Text(10)) // compute evaluations of (blinded version of) l, r, o, z, qCPrime at zeta var blzeta, brzeta, bozeta, qcpzeta fr.Element @@ -619,9 +675,9 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, den.Sub(&zeta, &one). Inverse(&den) lagrangeZeta.Mul(&lagrangeZeta, &den). // L₁ = (ζⁿ⁻¹)/(ζ-1) - Mul(&lagrangeZeta, &alpha). - Mul(&lagrangeZeta, &alpha). - Mul(&lagrangeZeta, &pk.Domain[0].CardinalityInv) // (1/n)*α²*L₁(ζ) + Mul(&lagrangeZeta, &alpha). + Mul(&lagrangeZeta, &alpha). + Mul(&lagrangeZeta, &pk.Domain[0].CardinalityInv) // (1/n)*α²*L₁(ζ) linPol := make([]fr.Element, len(blindedZCanonical)) copy(linPol, blindedZCanonical) diff --git a/internal/backend/bn254/plonk/setup.go b/internal/backend/bn254/plonk/setup.go index aae6bca848..1fa99cd865 100644 --- a/internal/backend/bn254/plonk/setup.go +++ b/internal/backend/bn254/plonk/setup.go @@ -18,12 +18,15 @@ package plonk import ( "errors" + "fmt" "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" "github.com/consensys/gnark-crypto/ecc/bn254/fr/iop" "github.com/consensys/gnark-crypto/ecc/bn254/fr/kzg" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bn254" + "strconv" + "strings" kzgg "github.com/consensys/gnark-crypto/kzg" ) @@ -97,6 +100,77 @@ type VerifyingKey struct { CommitmentInfo constraint.Commitment } +var domGen fr.Element + +func isInt(v fr.Element) bool { + return v.IsUint64() || isNeg(v) +} + +func isNeg(v fr.Element) bool { + s := v.Text(10) + return s[0] == '-' +} + +func tryPrintElemAsIntComb(v fr.Element, sbb *strings.Builder) bool { + v.Sub(&v, &domGen) + if isInt(v) { + sbb.WriteString("(a") + if !isNeg(v) { + sbb.WriteByte('+') + } + sbb.WriteString(v.Text(10)) + sbb.WriteByte(')') + return true + } + v.Add(&v, &domGen) + if isInt(v) { + sbb.WriteString(v.Text(10)) + return true + } + v.Add(&v, &domGen) + if isInt(v) { + sbb.WriteString("(-a") + if !isNeg(v) { + sbb.WriteByte('+') + } + sbb.WriteString(v.Text(10)) + sbb.WriteByte(')') + return true + } + return false +} + +func printElem(v fr.Element, sbb *strings.Builder) { + if tryPrintElemAsIntComb(v, sbb) { + return + } + var tmp fr.Element + tmp.Double(&v) + for i := 1; i < 10; i++ { + if tryPrintElemAsIntComb(tmp, sbb) { + sbb.WriteByte('/') + sbb.WriteString(strconv.Itoa(1 << i)) + return + } + tmp.Double(&tmp) + } + sbb.WriteString(v.Text(10)) +} + +func prints(v []fr.Element) string { + + var sbb strings.Builder + sbb.WriteString("[") + for i := range v { + if i != 0 { + sbb.WriteString(", ") + } + printElem(v[i], &sbb) + } + sbb.WriteByte(']') + return sbb.String() +} + // Setup sets proving and verifying keys func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) { var pk ProvingKey @@ -111,6 +185,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // fft domains sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints pk.Domain[0] = *fft.NewDomain(sizeSystem) + domGen = pk.Domain[0].Generator pk.Vk.CosetShift.Set(&pk.Domain[0].FrMultiplicativeGen) // h, the quotient polynomial is of degree 3(n+1)+2, so it's in a 3(n+2) dim vector space, @@ -127,6 +202,9 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) vk.Generator.Set(&pk.Domain[0].Generator) vk.NbPublicVariables = uint64(len(spr.Public)) + fmt.Println("dom 0:", pk.Domain[0].Cardinality, pk.Domain[0].Generator.Text(10)) + fmt.Println("dom 1:", pk.Domain[1].Cardinality, pk.Domain[1].Generator.Text(10)) + if err := pk.InitKZG(srs); err != nil { return nil, nil, err } @@ -164,6 +242,12 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) pk.QcPrime[committed].SetOne() } + fmt.Println("ql:", prints(pk.Ql)) + fmt.Println("qr:", prints(pk.Qr)) + fmt.Println("qo:", prints(pk.Qo)) + fmt.Println("lqk:", prints(pk.CQk)) + fmt.Println("qcp:", prints(pk.QcPrime)) + pk.Domain[0].FFTInverse(pk.Ql, fft.DIF) pk.Domain[0].FFTInverse(pk.Qr, fft.DIF) pk.Domain[0].FFTInverse(pk.Qm, fft.DIF) @@ -306,7 +390,7 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { pk.lQr = wqriop.Coefficients() pk.lQm = wqmiop.Coefficients() pk.lQo = wqoiop.Coefficients() - pk.lQcPrime = wqoiop.Coefficients() + pk.lQcPrime = wqcpiop.Coefficients() pk.lS1LagrangeCoset = ws1.Coefficients() pk.lS2LagrangeCoset = ws2.Coefficients() @@ -348,6 +432,10 @@ func ccomputePermutationPolynomials(pk *ProvingKey) { pk.S3Canonical[i].Set(&evaluationIDSmallDomain[pk.Permutation[2*nbElmts+i]]) } + fmt.Println("ls1 =", prints(pk.S1Canonical)) + fmt.Println("ls2 =", prints(pk.S2Canonical)) + fmt.Println("ls3 =", prints(pk.S3Canonical)) + // Canonical form of S1, S2, S3 pk.Domain[0].FFTInverse(pk.S1Canonical, fft.DIF) pk.Domain[0].FFTInverse(pk.S2Canonical, fft.DIF) diff --git a/internal/backend/bn254/plonk/verify.go b/internal/backend/bn254/plonk/verify.go index a205ec8b23..dcd913896f 100644 --- a/internal/backend/bn254/plonk/verify.go +++ b/internal/backend/bn254/plonk/verify.go @@ -17,7 +17,9 @@ package plonk import ( + "crypto/sha256" "errors" + "fmt" "io" "math/big" "time" @@ -44,7 +46,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { start := time.Now() // pick a hash function to derive the challenge (the same as in the prover) - hFunc := zeroHash{} + hFunc := sha256.New() // transcript to derive the challenge fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") @@ -56,24 +58,28 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) + gamma.SetOne() if err != nil { return err } // derive beta from Comm(l), Comm(r), Comm(o) beta, err := deriveRandomness(&fs, "beta") + beta.SetZero() if err != nil { return err } // derive alpha from Comm(l), Comm(r), Comm(o), Com(Z) alpha, err := deriveRandomness(&fs, "alpha", &proof.Z) + alpha.SetZero() if err != nil { return err } // derive zeta, the point of evaluation zeta, err := deriveRandomness(&fs, "zeta", &proof.H[0], &proof.H[1], &proof.H[2]) + zeta.SetZero() if err != nil { return err } @@ -116,6 +122,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } + fmt.Println("commitment computed as", hashRes[0].Text(10)) + hashRes[0].SetZero() // TODO Remove // Computing L_{CommitmentIndex} diff --git a/test/commitments_test.go b/test/commitments_test.go index d547953134..adac414edb 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -18,34 +18,25 @@ type commitmentCircuit struct { func (c *commitmentCircuit) Define(api frontend.API) error { commitment, err := api.Commit(c.X...) if err == nil { - api.AssertIsDifferent(commitment, 0) + api.AssertIsEqual(commitment, 0) // TODO Change to AssertNotEqual(-, 0) } return err } func plonkTestBn254(t *testing.T, assignment frontend.Circuit) { - // // building the circuit... - ccs, err := frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, &commitmentCircuit{make([]frontend.Variable, 1)}) + witnessFull, err := frontend.NewWitness(assignment, ecc.BN254.ScalarField()) assert.NoError(t, err) - - _r1cs := ccs.(*cs.SparseR1CS) - srs, err := NewKZGSRS(_r1cs) + witnessPublic, err := witnessFull.Public() assert.NoError(t, err) - // Witnesses instantiation. Witness is known only by the prover, - // while public w is a public data known by the verifier. - - witnessFull, err := frontend.NewWitness(assignment, ecc.BN254.ScalarField()) + ccs, err := frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, assignment) assert.NoError(t, err) - witnessPublic, err := frontend.NewWitness(assignment, ecc.BN254.ScalarField(), frontend.PublicOnly()) + _r1cs := ccs.(*cs.SparseR1CS) + srs, err := NewKZGSRS(_r1cs) assert.NoError(t, err) - // public data consists the polynomials describing the constants involved - // in the constraints, the polynomial describing the permutation ("grand - // product argument"), and the FFT domains. pk, vk, err := plonk.Setup(ccs, srs) - //_, err := plonk.Setup(r1cs, kate, &publicWitness) assert.NoError(t, err) proof, err := plonk.Prove(ccs, pk, witnessFull) @@ -65,6 +56,7 @@ type noCommitmentCircuit struct { } func (c *noCommitmentCircuit) Define(api frontend.API) error { + api.AssertIsEqual(c.X, 1) api.AssertIsEqual(c.X, 1) return nil } diff --git a/test/kzg_srs.go b/test/kzg_srs.go index 4002762919..640169b6c5 100644 --- a/test/kzg_srs.go +++ b/test/kzg_srs.go @@ -18,6 +18,7 @@ package test import ( "crypto/rand" + "math/big" "sync" "github.com/consensys/gnark-crypto/ecc" @@ -84,6 +85,7 @@ func newKZGSRS(curve ecc.ID, kzgSize uint64) (kzg.SRS, error) { if err != nil { return nil, err } + alpha = big.NewInt(0) switch curve { case ecc.BN254: From 29eaaa596f27ed2e87caf26f984aa48ae5e32614 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 16 Mar 2023 19:36:49 -0400 Subject: [PATCH 146/464] chore: remove training wheels --- internal/backend/bn254/plonk/prove.go | 17 ++++++++--------- internal/backend/bn254/plonk/verify.go | 10 +++++----- test/commitments_test.go | 2 +- test/kzg_srs.go | 3 +-- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/internal/backend/bn254/plonk/prove.go b/internal/backend/bn254/plonk/prove.go index 3223e7bb94..0ebc2fe4eb 100644 --- a/internal/backend/bn254/plonk/prove.go +++ b/internal/backend/bn254/plonk/prove.go @@ -140,9 +140,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return err } - // TODO Uncomment commitmentVal = hashRes[0] // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses - commitmentVal.SetZero() + //commitmentVal.SetOne() commitmentVal.BigInt(outs[0]) fmt.Println("commitment computed as", hashRes[0].Text(10)) return nil @@ -204,7 +203,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) // TODO @Tabaie @ThomasPiellard add BSB commitment here? - gamma.SetOne() // TODO REMOVE + //gamma.SetOne() // TODO REMOVE if err != nil { return nil, err } @@ -218,7 +217,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } var beta fr.Element beta.SetBytes(bbeta) - beta.SetZero() + //beta.SetZero() fmt.Println("beta =", beta.Text(10)) @@ -252,7 +251,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // derive alpha from the Comm(l), Comm(r), Comm(o), Com(Z) alpha, err := deriveRandomness(&fs, "alpha", &proof.Z) - alpha.SetZero() + //alpha.SetZero() if err != nil { return proof, err } @@ -429,7 +428,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // derive zeta zeta, err := deriveRandomness(&fs, "zeta", &proof.H[0], &proof.H[1], &proof.H[2]) - zeta.SetZero() + //zeta.SetZero() if err != nil { return nil, err } @@ -675,9 +674,9 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, den.Sub(&zeta, &one). Inverse(&den) lagrangeZeta.Mul(&lagrangeZeta, &den). // L₁ = (ζⁿ⁻¹)/(ζ-1) - Mul(&lagrangeZeta, &alpha). - Mul(&lagrangeZeta, &alpha). - Mul(&lagrangeZeta, &pk.Domain[0].CardinalityInv) // (1/n)*α²*L₁(ζ) + Mul(&lagrangeZeta, &alpha). + Mul(&lagrangeZeta, &alpha). + Mul(&lagrangeZeta, &pk.Domain[0].CardinalityInv) // (1/n)*α²*L₁(ζ) linPol := make([]fr.Element, len(blindedZCanonical)) copy(linPol, blindedZCanonical) diff --git a/internal/backend/bn254/plonk/verify.go b/internal/backend/bn254/plonk/verify.go index dcd913896f..a488cab454 100644 --- a/internal/backend/bn254/plonk/verify.go +++ b/internal/backend/bn254/plonk/verify.go @@ -58,28 +58,28 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) - gamma.SetOne() + //gamma.SetOne() if err != nil { return err } // derive beta from Comm(l), Comm(r), Comm(o) beta, err := deriveRandomness(&fs, "beta") - beta.SetZero() + //beta.SetZero() if err != nil { return err } // derive alpha from Comm(l), Comm(r), Comm(o), Com(Z) alpha, err := deriveRandomness(&fs, "alpha", &proof.Z) - alpha.SetZero() + //alpha.SetZero() if err != nil { return err } // derive zeta, the point of evaluation zeta, err := deriveRandomness(&fs, "zeta", &proof.H[0], &proof.H[1], &proof.H[2]) - zeta.SetZero() + //zeta.SetZero() if err != nil { return err } @@ -123,7 +123,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } fmt.Println("commitment computed as", hashRes[0].Text(10)) - hashRes[0].SetZero() // TODO Remove + //hashRes[0].SetOne() // TODO Remove // Computing L_{CommitmentIndex} diff --git a/test/commitments_test.go b/test/commitments_test.go index adac414edb..707548860f 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -18,7 +18,7 @@ type commitmentCircuit struct { func (c *commitmentCircuit) Define(api frontend.API) error { commitment, err := api.Commit(c.X...) if err == nil { - api.AssertIsEqual(commitment, 0) // TODO Change to AssertNotEqual(-, 0) + api.AssertIsDifferent(commitment, 0) // TODO Change to AssertNotEqual(-, 0) } return err } diff --git a/test/kzg_srs.go b/test/kzg_srs.go index 640169b6c5..dff8fa3e75 100644 --- a/test/kzg_srs.go +++ b/test/kzg_srs.go @@ -18,7 +18,6 @@ package test import ( "crypto/rand" - "math/big" "sync" "github.com/consensys/gnark-crypto/ecc" @@ -85,7 +84,7 @@ func newKZGSRS(curve ecc.ID, kzgSize uint64) (kzg.SRS, error) { if err != nil { return nil, err } - alpha = big.NewInt(0) + //alpha = big.NewInt(0) switch curve { case ecc.BN254: From 5f6540ba375199eba7efd707d5cfff34c333bafd Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 16 Mar 2023 19:37:38 -0400 Subject: [PATCH 147/464] feat: blind commitment --- internal/backend/bn254/plonk/prove.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/backend/bn254/plonk/prove.go b/internal/backend/bn254/plonk/prove.go index 0ebc2fe4eb..7e4d952206 100644 --- a/internal/backend/bn254/plonk/prove.go +++ b/internal/backend/bn254/plonk/prove.go @@ -125,9 +125,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts err error hashRes []fr.Element ) - /*if _, err = pi2[spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { + if _, err = pi2[spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { return err - }*/ + } pi2iop := iop.NewPolynomial(&pi2, lagReg) fmt.Println("pi2 =", prints(pi2)) wpi2iop = pi2iop.ShallowClone() From a26d1479479d34de23658c557086d1a1cb813b80 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 16 Mar 2023 19:42:10 -0400 Subject: [PATCH 148/464] style: remove prints --- internal/backend/bn254/plonk/prove.go | 63 ------------------ internal/backend/bn254/plonk/setup.go | 92 +------------------------- internal/backend/bn254/plonk/verify.go | 3 - 3 files changed, 2 insertions(+), 156 deletions(-) diff --git a/internal/backend/bn254/plonk/prove.go b/internal/backend/bn254/plonk/prove.go index 7e4d952206..3a29a89ee7 100644 --- a/internal/backend/bn254/plonk/prove.go +++ b/internal/backend/bn254/plonk/prove.go @@ -18,7 +18,6 @@ package plonk import ( "crypto/sha256" - "fmt" "github.com/consensys/gnark/constraint/solver" "math/big" "runtime" @@ -65,35 +64,7 @@ type Proof struct { ZShiftedOpening kzg.OpeningProof } -type oneHash struct{} - -func (h oneHash) Write(p []byte) (n int, err error) { - return len(p), nil -} - -func (h oneHash) Sum([]byte) []byte { - one := make([]byte, fr.Bytes) - one[0] = 1 - return one -} - -func (h oneHash) Reset() {} - -func (h oneHash) Size() int { - return fr.Bytes -} - -func (h oneHash) BlockSize() int { - return fr.Bytes -} - func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { - - fmt.Println("qc(canonical) =", prints(pk.QcPrime)) - domGen = pk.Domain[1].Generator - fmt.Println("qc(coset) =", prints(pk.lQcPrime)) - domGen = pk.Domain[0].Generator - log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", len(spr.Constraints)).Str("backend", "plonk").Logger() opt, err := backend.NewProverConfig(opts...) @@ -129,10 +100,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return err } pi2iop := iop.NewPolynomial(&pi2, lagReg) - fmt.Println("pi2 =", prints(pi2)) wpi2iop = pi2iop.ShallowClone() wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() - fmt.Println("pi2 canonical =", prints(pi2)) if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Vk.KZGSRS); err != nil { return err } @@ -141,9 +110,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } commitmentVal = hashRes[0] // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses - //commitmentVal.SetOne() commitmentVal.BigInt(outs[0]) - fmt.Println("commitment computed as", hashRes[0].Text(10)) return nil })) } else { @@ -165,10 +132,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts evaluationRDomainSmall := []fr.Element(solution.R) evaluationODomainSmall := []fr.Element(solution.O) - fmt.Println("evaluationLDomainSmall =", prints(evaluationLDomainSmall)) - fmt.Println("evaluationRDomainSmall =", prints(evaluationRDomainSmall)) - fmt.Println("evaluationODomainSmall =", prints(evaluationODomainSmall)) - liop := iop.NewPolynomial(&evaluationLDomainSmall, lagReg) riop := iop.NewPolynomial(&evaluationRDomainSmall, lagReg) oiop := iop.NewPolynomial(&evaluationODomainSmall, lagReg) @@ -179,9 +142,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wriop.ToCanonical(&pk.Domain[0]).ToRegular() woiop.ToCanonical(&pk.Domain[0]).ToRegular() - fmt.Println("evaluationLDomainSmall =", prints(evaluationLDomainSmall)) - fmt.Println("liop =", prints(wliop.Coefficients())) - // Blind l, r, o before committing // we set the underlying slice capacity to domain[1].Cardinality to minimize mem moves. bwliop := wliop.Clone(int(pk.Domain[1].Cardinality)) //.Blind(1) @@ -203,13 +163,10 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) // TODO @Tabaie @ThomasPiellard add BSB commitment here? - //gamma.SetOne() // TODO REMOVE if err != nil { return nil, err } - fmt.Println("gamma =", gamma.Text(10)) - // Fiat Shamir this bbeta, err := fs.ComputeChallenge("beta") if err != nil { @@ -217,9 +174,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } var beta fr.Element beta.SetBytes(bbeta) - //beta.SetZero() - - fmt.Println("beta =", beta.Text(10)) // compute the copy constraint's ratio // We copy liop, riop, oiop because they are fft'ed in the process. @@ -251,11 +205,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // derive alpha from the Comm(l), Comm(r), Comm(o), Com(Z) alpha, err := deriveRandomness(&fs, "alpha", &proof.Z) - //alpha.SetZero() if err != nil { return proof, err } - fmt.Println("alpha =", alpha.Text(10)) // compute qk in canonical basis, completed with the public inputs qkCompletedCanonical := make([]fr.Element, pk.Domain[0].Cardinality) @@ -273,9 +225,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.ToLagrangeCoset(&pk.Domain[1]) pi2iop := wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form - domGen = pk.Domain[1].Generator - fmt.Println("pi2 (lagrange coset) =", prints(pi2iop.Coefficients())) - lagrangeCosetBitReversed := iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse} // we don't mutate so no need to clone the coefficients from the proving key. @@ -377,9 +326,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return c } - fmt.Println("bwliop evals =", prints(bwliop.Coefficients())) - fmt.Println("pi2iop evals =", prints(pi2iop.Coefficients())) - testEval, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, bwliop, bwriop, @@ -404,19 +350,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } - cnum := testEval.Clone().ToRegular() - fmt.Println("testEval =", prints(cnum.Coefficients())) - - cnum = testEval.Clone().ToCanonical(&pk.Domain[1]).ToRegular() - fmt.Println("testEval(coeffs) =", prints(cnum.Coefficients())) - h, err := iop.DivideByXMinusOne(testEval, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) // TODO @Tabaie not x^n - 1? if err != nil { return nil, err } - fmt.Println("h =", prints(h.Coefficients())) - // compute kzg commitments of h1, h2 and h3 if err := commitToQuotient( h.Coefficients()[:pk.Domain[0].Cardinality+2], @@ -432,7 +370,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if err != nil { return nil, err } - fmt.Println("zeta = ", zeta.Text(10)) // compute evaluations of (blinded version of) l, r, o, z, qCPrime at zeta var blzeta, brzeta, bozeta, qcpzeta fr.Element diff --git a/internal/backend/bn254/plonk/setup.go b/internal/backend/bn254/plonk/setup.go index 1fa99cd865..55966b5b91 100644 --- a/internal/backend/bn254/plonk/setup.go +++ b/internal/backend/bn254/plonk/setup.go @@ -18,17 +18,13 @@ package plonk import ( "errors" - "fmt" "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" "github.com/consensys/gnark-crypto/ecc/bn254/fr/iop" "github.com/consensys/gnark-crypto/ecc/bn254/fr/kzg" + kzgg "github.com/consensys/gnark-crypto/kzg" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bn254" - "strconv" - "strings" - - kzgg "github.com/consensys/gnark-crypto/kzg" ) // ProvingKey stores the data needed to generate a proof: @@ -100,77 +96,6 @@ type VerifyingKey struct { CommitmentInfo constraint.Commitment } -var domGen fr.Element - -func isInt(v fr.Element) bool { - return v.IsUint64() || isNeg(v) -} - -func isNeg(v fr.Element) bool { - s := v.Text(10) - return s[0] == '-' -} - -func tryPrintElemAsIntComb(v fr.Element, sbb *strings.Builder) bool { - v.Sub(&v, &domGen) - if isInt(v) { - sbb.WriteString("(a") - if !isNeg(v) { - sbb.WriteByte('+') - } - sbb.WriteString(v.Text(10)) - sbb.WriteByte(')') - return true - } - v.Add(&v, &domGen) - if isInt(v) { - sbb.WriteString(v.Text(10)) - return true - } - v.Add(&v, &domGen) - if isInt(v) { - sbb.WriteString("(-a") - if !isNeg(v) { - sbb.WriteByte('+') - } - sbb.WriteString(v.Text(10)) - sbb.WriteByte(')') - return true - } - return false -} - -func printElem(v fr.Element, sbb *strings.Builder) { - if tryPrintElemAsIntComb(v, sbb) { - return - } - var tmp fr.Element - tmp.Double(&v) - for i := 1; i < 10; i++ { - if tryPrintElemAsIntComb(tmp, sbb) { - sbb.WriteByte('/') - sbb.WriteString(strconv.Itoa(1 << i)) - return - } - tmp.Double(&tmp) - } - sbb.WriteString(v.Text(10)) -} - -func prints(v []fr.Element) string { - - var sbb strings.Builder - sbb.WriteString("[") - for i := range v { - if i != 0 { - sbb.WriteString(", ") - } - printElem(v[i], &sbb) - } - sbb.WriteByte(']') - return sbb.String() -} - // Setup sets proving and verifying keys func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) { var pk ProvingKey @@ -185,7 +110,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // fft domains sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints pk.Domain[0] = *fft.NewDomain(sizeSystem) - domGen = pk.Domain[0].Generator + _ = pk.Domain[0].Generator pk.Vk.CosetShift.Set(&pk.Domain[0].FrMultiplicativeGen) // h, the quotient polynomial is of degree 3(n+1)+2, so it's in a 3(n+2) dim vector space, @@ -202,9 +127,6 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) vk.Generator.Set(&pk.Domain[0].Generator) vk.NbPublicVariables = uint64(len(spr.Public)) - fmt.Println("dom 0:", pk.Domain[0].Cardinality, pk.Domain[0].Generator.Text(10)) - fmt.Println("dom 1:", pk.Domain[1].Cardinality, pk.Domain[1].Generator.Text(10)) - if err := pk.InitKZG(srs); err != nil { return nil, nil, err } @@ -242,12 +164,6 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) pk.QcPrime[committed].SetOne() } - fmt.Println("ql:", prints(pk.Ql)) - fmt.Println("qr:", prints(pk.Qr)) - fmt.Println("qo:", prints(pk.Qo)) - fmt.Println("lqk:", prints(pk.CQk)) - fmt.Println("qcp:", prints(pk.QcPrime)) - pk.Domain[0].FFTInverse(pk.Ql, fft.DIF) pk.Domain[0].FFTInverse(pk.Qr, fft.DIF) pk.Domain[0].FFTInverse(pk.Qm, fft.DIF) @@ -432,10 +348,6 @@ func ccomputePermutationPolynomials(pk *ProvingKey) { pk.S3Canonical[i].Set(&evaluationIDSmallDomain[pk.Permutation[2*nbElmts+i]]) } - fmt.Println("ls1 =", prints(pk.S1Canonical)) - fmt.Println("ls2 =", prints(pk.S2Canonical)) - fmt.Println("ls3 =", prints(pk.S3Canonical)) - // Canonical form of S1, S2, S3 pk.Domain[0].FFTInverse(pk.S1Canonical, fft.DIF) pk.Domain[0].FFTInverse(pk.S2Canonical, fft.DIF) diff --git a/internal/backend/bn254/plonk/verify.go b/internal/backend/bn254/plonk/verify.go index a488cab454..eb061f555d 100644 --- a/internal/backend/bn254/plonk/verify.go +++ b/internal/backend/bn254/plonk/verify.go @@ -19,7 +19,6 @@ package plonk import ( "crypto/sha256" "errors" - "fmt" "io" "math/big" "time" @@ -122,8 +121,6 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } - fmt.Println("commitment computed as", hashRes[0].Text(10)) - //hashRes[0].SetOne() // TODO Remove // Computing L_{CommitmentIndex} From 1a0166176ab19b79549d6f7431649b3d846cf1be Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 16 Mar 2023 19:46:58 -0400 Subject: [PATCH 149/464] style: remove unnecessary stylistic changes --- internal/backend/bn254/plonk/prove.go | 14 +++++--------- internal/backend/bn254/plonk/setup.go | 4 ++-- internal/backend/bn254/plonk/verify.go | 3 --- test/commitments_test.go | 2 +- test/kzg_srs.go | 1 - 5 files changed, 8 insertions(+), 16 deletions(-) diff --git a/internal/backend/bn254/plonk/prove.go b/internal/backend/bn254/plonk/prove.go index 3a29a89ee7..933032ff56 100644 --- a/internal/backend/bn254/plonk/prove.go +++ b/internal/backend/bn254/plonk/prove.go @@ -65,6 +65,7 @@ type Proof struct { } func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { + log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", len(spr.Constraints)).Str("backend", "plonk").Logger() opt, err := backend.NewProverConfig(opts...) @@ -108,7 +109,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } - commitmentVal = hashRes[0] // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses commitmentVal.BigInt(outs[0]) return nil @@ -144,9 +144,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // Blind l, r, o before committing // we set the underlying slice capacity to domain[1].Cardinality to minimize mem moves. - bwliop := wliop.Clone(int(pk.Domain[1].Cardinality)) //.Blind(1) - bwriop := wriop.Clone(int(pk.Domain[1].Cardinality)) //.Blind(1) - bwoiop := woiop.Clone(int(pk.Domain[1].Cardinality)) //.Blind(1) + bwliop := wliop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) + bwriop := wriop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) + bwoiop := woiop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Vk.KZGSRS); err != nil { return nil, err } @@ -197,7 +197,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // commit to the blinded version of z bwziop := ziop // iop.NewWrappedPolynomial(&ziop) - //bwziop.Blind(2) + bwziop.Blind(2) proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Vk.KZGSRS, runtime.NumCPU()*2) if err != nil { return proof, err @@ -325,7 +325,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return c } - testEval, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, bwliop, bwriop, @@ -345,11 +344,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wqcpiop, // TODO @Tabaie correct format wloneiop, ) - if err != nil { return nil, err } - h, err := iop.DivideByXMinusOne(testEval, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) // TODO @Tabaie not x^n - 1? if err != nil { return nil, err @@ -366,7 +363,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // derive zeta zeta, err := deriveRandomness(&fs, "zeta", &proof.H[0], &proof.H[1], &proof.H[2]) - //zeta.SetZero() if err != nil { return nil, err } diff --git a/internal/backend/bn254/plonk/setup.go b/internal/backend/bn254/plonk/setup.go index 55966b5b91..599dc953b3 100644 --- a/internal/backend/bn254/plonk/setup.go +++ b/internal/backend/bn254/plonk/setup.go @@ -22,9 +22,10 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" "github.com/consensys/gnark-crypto/ecc/bn254/fr/iop" "github.com/consensys/gnark-crypto/ecc/bn254/fr/kzg" - kzgg "github.com/consensys/gnark-crypto/kzg" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bn254" + + kzgg "github.com/consensys/gnark-crypto/kzg" ) // ProvingKey stores the data needed to generate a proof: @@ -110,7 +111,6 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // fft domains sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints pk.Domain[0] = *fft.NewDomain(sizeSystem) - _ = pk.Domain[0].Generator pk.Vk.CosetShift.Set(&pk.Domain[0].FrMultiplicativeGen) // h, the quotient polynomial is of degree 3(n+1)+2, so it's in a 3(n+2) dim vector space, diff --git a/internal/backend/bn254/plonk/verify.go b/internal/backend/bn254/plonk/verify.go index eb061f555d..00a8dd5759 100644 --- a/internal/backend/bn254/plonk/verify.go +++ b/internal/backend/bn254/plonk/verify.go @@ -57,21 +57,18 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) - //gamma.SetOne() if err != nil { return err } // derive beta from Comm(l), Comm(r), Comm(o) beta, err := deriveRandomness(&fs, "beta") - //beta.SetZero() if err != nil { return err } // derive alpha from Comm(l), Comm(r), Comm(o), Com(Z) alpha, err := deriveRandomness(&fs, "alpha", &proof.Z) - //alpha.SetZero() if err != nil { return err } diff --git a/test/commitments_test.go b/test/commitments_test.go index 707548860f..4ab58ba92f 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -18,7 +18,7 @@ type commitmentCircuit struct { func (c *commitmentCircuit) Define(api frontend.API) error { commitment, err := api.Commit(c.X...) if err == nil { - api.AssertIsDifferent(commitment, 0) // TODO Change to AssertNotEqual(-, 0) + api.AssertIsDifferent(commitment, 0) } return err } diff --git a/test/kzg_srs.go b/test/kzg_srs.go index dff8fa3e75..4002762919 100644 --- a/test/kzg_srs.go +++ b/test/kzg_srs.go @@ -84,7 +84,6 @@ func newKZGSRS(curve ecc.ID, kzgSize uint64) (kzg.SRS, error) { if err != nil { return nil, err } - //alpha = big.NewInt(0) switch curve { case ecc.BN254: From 9f060fdbc8ad9111bfd0114f208a97cc7bdd2dd0 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 16 Mar 2023 19:47:57 -0400 Subject: [PATCH 150/464] style: remove comment --- internal/backend/bn254/plonk/verify.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/backend/bn254/plonk/verify.go b/internal/backend/bn254/plonk/verify.go index 00a8dd5759..ca30399988 100644 --- a/internal/backend/bn254/plonk/verify.go +++ b/internal/backend/bn254/plonk/verify.go @@ -75,7 +75,6 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // derive zeta, the point of evaluation zeta, err := deriveRandomness(&fs, "zeta", &proof.H[0], &proof.H[1], &proof.H[2]) - //zeta.SetZero() if err != nil { return err } From 32a9a5647fb7b665c4f1d166bf6c59629b1944dc Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 17 Mar 2023 11:06:12 +0100 Subject: [PATCH 151/464] perf(bn254-pairing): isolate i=63 in MillerLoop to save a doubleStep --- .../emulated/fields_bn254/e12_pairing.go | 8 ++---- std/algebra/emulated/fields_bn254/e6.go | 7 +++++ std/algebra/emulated/sw_bn254/pairing.go | 27 +++++++++++++++++-- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/std/algebra/emulated/fields_bn254/e12_pairing.go b/std/algebra/emulated/fields_bn254/e12_pairing.go index f2aa7c0c83..f23f80c88f 100644 --- a/std/algebra/emulated/fields_bn254/e12_pairing.go +++ b/std/algebra/emulated/fields_bn254/e12_pairing.go @@ -74,11 +74,8 @@ func (e *Ext12) MulBy034(z *E12, c3, c4 *E2) *E12 { a := z.C0 b := z.C1 - b = *e.MulBy01(&b, c3, c4) - one := e.Ext2.One() - - c3 = e.Ext2.Add(one, c3) + c3 = e.Ext2.Add(e.Ext2.One(), c3) d := e.Ext6.Add(&z.C0, &z.C1) d = e.MulBy01(d, c3, c4) @@ -108,7 +105,6 @@ func (e *Ext12) MulBy034(z *E12, c3, c4 *E2) *E12 { // C1: E6{B0: d3, B1: d4, B2: 0}, // } func (e *Ext12) Mul034By034(d3, d4, c3, c4 *E2) *E12 { - one := e.Ext2.One() x3 := e.Ext2.Mul(c3, d3) x4 := e.Ext2.Mul(c4, d4) x04 := e.Ext2.Add(c4, d4) @@ -120,7 +116,7 @@ func (e *Ext12) Mul034By034(d3, d4, c3, c4 *E2) *E12 { x34 = e.Ext2.Sub(x34, x4) zC0B0 := e.Ext2.MulByNonResidue(x4) - zC0B0 = e.Ext2.Add(zC0B0, one) + zC0B0 = e.Ext2.Add(zC0B0, e.Ext2.One()) zC0B1 := x3 zC0B2 := x34 zC1B0 := x03 diff --git a/std/algebra/emulated/fields_bn254/e6.go b/std/algebra/emulated/fields_bn254/e6.go index 98341aa3b7..54d91805c7 100644 --- a/std/algebra/emulated/fields_bn254/e6.go +++ b/std/algebra/emulated/fields_bn254/e6.go @@ -151,6 +151,13 @@ func (e Ext6) MulByE2(x *E6, y *E2) *E6 { } } +// MulBy01 multiplies z by an E6 sparse element of the form +// +// E6{ +// B0: c0, +// B1: c1, +// B2: 0, +// } func (e Ext6) MulBy01(z *E6, c0, c1 *E2) *E6 { a := e.Ext2.Mul(&z.B0, c0) b := e.Ext2.Mul(&z.B1, c1) diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 07fb08a386..ba2a99345e 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -176,7 +176,7 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { } // Compute ∏ᵢ { fᵢ_{ℓ,Q}(P) } - // i = len(loopCounter) - 2, separately to avoid E12 Square + // i = 64, separately to avoid an E12 Square // (Square(res) = 1² = 1) // k = 0, separately to avoid MulBy034 (res × ℓ) @@ -209,7 +209,30 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { } } - for i := len(loopCounter) - 3; i >= 0; i-- { + // i = 63, separately to avoid a doubleStep + // (at this point Qacc = 2Q, so 2Qacc-Q=3Q is equivalent to Qacc+Q=3Q + // this means doubleAddStep is equivalent to addStep here) + res = pr.Square(res) + for k := 0; k < n; k++ { + // l2 the line passing Qacc[k] and -Q + l2 = pr.lineCompute(Qacc[k], QNeg[k]) + // line evaluation at P[k] + l2.R0 = *pr.MulByElement(&l2.R0, xOverY[k]) + l2.R1 = *pr.MulByElement(&l2.R1, yInv[k]) + // ℓ × res + res = pr.MulBy034(res, &l2.R0, &l2.R1) + + // Qacc[k] ← Qacc[k]+Q[k] and + // l1 the line ℓ passing Qacc[k] and Q[k] + Qacc[k], l1 = pr.addStep(Qacc[k], Q[k]) + // line evaluation at P[k] + l1.R0 = *pr.MulByElement(&l1.R0, xOverY[k]) + l1.R1 = *pr.MulByElement(&l1.R1, yInv[k]) + // ℓ × res + res = pr.MulBy034(res, &l1.R0, &l1.R1) + } + + for i := 62; i >= 0; i-- { // mutualize the square among n Miller loops // (∏ᵢfᵢ)² res = pr.Square(res) From 7d2f92e2153dd3569ea0d131974f344e4bea6a25 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 17 Mar 2023 12:02:05 +0100 Subject: [PATCH 152/464] perf(bn254-pairing): Mul lines between them before mul by accumulator --- std/algebra/emulated/fields_bn254/e12.go | 16 ++++++ .../emulated/fields_bn254/e12_pairing.go | 24 +++++++++ std/algebra/emulated/sw_bn254/pairing.go | 51 +++++++++++++------ 3 files changed, 75 insertions(+), 16 deletions(-) diff --git a/std/algebra/emulated/fields_bn254/e12.go b/std/algebra/emulated/fields_bn254/e12.go index 8cf514aca3..8f18867f98 100644 --- a/std/algebra/emulated/fields_bn254/e12.go +++ b/std/algebra/emulated/fields_bn254/e12.go @@ -327,6 +327,22 @@ func (e Ext12) FrobeniusCube(x *E12) *E12 { } } +func (e Ext12) Zero() *E12 { + zero := e.fp.Zero() + return &E12{ + C0: E6{ + B0: E2{A0: *zero, A1: *zero}, + B1: E2{A0: *zero, A1: *zero}, + B2: E2{A0: *zero, A1: *zero}, + }, + C1: E6{ + B0: E2{A0: *zero, A1: *zero}, + B1: E2{A0: *zero, A1: *zero}, + B2: E2{A0: *zero, A1: *zero}, + }, + } +} + func (e Ext12) One() *E12 { z000 := e.fp.One() zero := e.fp.Zero() diff --git a/std/algebra/emulated/fields_bn254/e12_pairing.go b/std/algebra/emulated/fields_bn254/e12_pairing.go index f23f80c88f..e81da4228f 100644 --- a/std/algebra/emulated/fields_bn254/e12_pairing.go +++ b/std/algebra/emulated/fields_bn254/e12_pairing.go @@ -132,3 +132,27 @@ func (e *Ext12) Mul034By034(d3, d4, c3, c4 *E2) *E12 { }, } } + +// MulBy01234 multiplies z by an E12 sparse element of the form +// +// E12{ +// C0: E6{B0: c0, B1: c1, B2: c2}, +// C1: E6{B0: c3, B1: c4, B2: 0}, +// } +func (e *Ext12) MulBy01234(z *E12, b0, b1, b2, b3, b4 *E2) *E12 { + c0 := &E6{B0: *b0, B1: *b1, B2: *b2} + c1 := &E6{B0: *b3, B1: *b4, B2: *e.Ext2.Zero()} + a := e.Ext6.Add(&z.C0, &z.C1) + b := e.Ext6.Add(c0, c1) + a = e.Ext6.Mul(a, b) + b = e.Ext6.Mul(&z.C0, c0) + c := e.Ext6.MulBy01(&z.C1, b3, b4) + z1 := e.Ext6.Sub(a, b) + z1 = e.Ext6.Sub(z1, c) + z0 := e.Ext6.MulByNonResidue(c) + z0 = e.Ext6.Add(z0, b) + return &E12{ + C0: *z0, + C1: *z1, + } +} diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index ba2a99345e..c7aa3b3ecb 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -159,6 +159,7 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { } res := pr.Ext12.One() + prodLines := pr.Ext12.Zero() var l1, l2 *lineEvaluation Qacc := make([]*G2Affine, n) @@ -190,6 +191,7 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { // k = 1, separately to avoid MulBy034 (res × ℓ) // (res is also a line at this point, so we use Mul034By034 ℓ × ℓ) Qacc[1], l1 = pr.doubleStep(Qacc[1]) + // line evaluation at P[1] l1.R0 = *pr.MulByElement(&l1.R0, xOverY[1]) l1.R1 = *pr.MulByElement(&l1.R1, yInv[1]) @@ -201,9 +203,11 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { for k := 2; k < n; k++ { // Qacc[k] ← 2Qacc[k] and l1 the tangent ℓ passing 2Qacc[k] Qacc[k], l1 = pr.doubleStep(Qacc[k]) + // line evaluation at P[k] l1.R0 = *pr.MulByElement(&l1.R0, xOverY[k]) l1.R1 = *pr.MulByElement(&l1.R1, yInv[k]) + // ℓ × res res = pr.MulBy034(res, &l1.R0, &l1.R1) } @@ -216,20 +220,23 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { for k := 0; k < n; k++ { // l2 the line passing Qacc[k] and -Q l2 = pr.lineCompute(Qacc[k], QNeg[k]) + // line evaluation at P[k] l2.R0 = *pr.MulByElement(&l2.R0, xOverY[k]) l2.R1 = *pr.MulByElement(&l2.R1, yInv[k]) - // ℓ × res - res = pr.MulBy034(res, &l2.R0, &l2.R1) // Qacc[k] ← Qacc[k]+Q[k] and // l1 the line ℓ passing Qacc[k] and Q[k] Qacc[k], l1 = pr.addStep(Qacc[k], Q[k]) + // line evaluation at P[k] l1.R0 = *pr.MulByElement(&l1.R0, xOverY[k]) l1.R1 = *pr.MulByElement(&l1.R1, yInv[k]) - // ℓ × res - res = pr.MulBy034(res, &l1.R0, &l1.R1) + + // ℓ × ℓ + prodLines = pr.Mul034By034(&l1.R0, &l1.R1, &l2.R0, &l2.R1) + // (ℓ × ℓ) × res + res = pr.MulBy01234(res, &prodLines.C0.B0, &prodLines.C0.B1, &prodLines.C0.B2, &prodLines.C1.B0, &prodLines.C1.B1) } for i := 62; i >= 0; i-- { @@ -243,9 +250,11 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { for k := 0; k < n; k++ { // Qacc[k] ← 2Qacc[k] and l1 the tangent ℓ passing 2Qacc[k] Qacc[k], l1 = pr.doubleStep(Qacc[k]) + // line evaluation at P[k] l1.R0 = *pr.MulByElement(&l1.R0, xOverY[k]) l1.R1 = *pr.MulByElement(&l1.R1, yInv[k]) + // ℓ × res res = pr.MulBy034(res, &l1.R0, &l1.R1) } @@ -256,16 +265,20 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { // l1 the line ℓ passing Qacc[k] and Q[k] // l2 the line ℓ passing (Qacc[k]+Q[k]) and Qacc[k] Qacc[k], l1, l2 = pr.doubleAndAddStep(Qacc[k], Q[k]) + // line evaluation at P[k] l1.R0 = *pr.MulByElement(&l1.R0, xOverY[k]) l1.R1 = *pr.MulByElement(&l1.R1, yInv[k]) - // ℓ × res - res = pr.MulBy034(res, &l1.R0, &l1.R1) + // line evaluation at P[k] l2.R0 = *pr.MulByElement(&l2.R0, xOverY[k]) l2.R1 = *pr.MulByElement(&l2.R1, yInv[k]) - // ℓ × res - res = pr.MulBy034(res, &l2.R0, &l2.R1) + + // ℓ × ℓ + prodLines = pr.Mul034By034(&l1.R0, &l1.R1, &l2.R0, &l2.R1) + // (ℓ × ℓ) × res + res = pr.MulBy01234(res, &prodLines.C0.B0, &prodLines.C0.B1, &prodLines.C0.B2, &prodLines.C1.B0, &prodLines.C1.B1) + } case -1: @@ -274,16 +287,20 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { // l1 the line ℓ passing Qacc[k] and -Q[k] // l2 the line ℓ passing (Qacc[k]-Q[k]) and Qacc[k] Qacc[k], l1, l2 = pr.doubleAndAddStep(Qacc[k], QNeg[k]) + // line evaluation at P[k] l1.R0 = *pr.MulByElement(&l1.R0, xOverY[k]) l1.R1 = *pr.MulByElement(&l1.R1, yInv[k]) - // ℓ × res - res = pr.MulBy034(res, &l1.R0, &l1.R1) + // line evaluation at P[k] l2.R0 = *pr.MulByElement(&l2.R0, xOverY[k]) l2.R1 = *pr.MulByElement(&l2.R1, yInv[k]) - // ℓ × res - res = pr.MulBy034(res, &l2.R0, &l2.R1) + + // ℓ × ℓ + prodLines = pr.Mul034By034(&l1.R0, &l1.R1, &l2.R0, &l2.R1) + // (ℓ × ℓ) × res + res = pr.MulBy01234(res, &prodLines.C0.B0, &prodLines.C0.B1, &prodLines.C0.B2, &prodLines.C1.B0, &prodLines.C1.B1) + } default: @@ -308,19 +325,21 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { // Qacc[k] ← Qacc[k]+π(Q) and // l1 the line passing Qacc[k] and π(Q) Qacc[k], l1 = pr.addStep(Qacc[k], Q1) + // line evaluation at P[k] l1.R0 = *pr.Ext2.MulByElement(&l1.R0, xOverY[k]) l1.R1 = *pr.Ext2.MulByElement(&l1.R1, yInv[k]) - // ℓ × res - res = pr.MulBy034(res, &l1.R0, &l1.R1) // l2 the line passing Qacc[k] and -π²(Q) l2 = pr.lineCompute(Qacc[k], Q2) // line evaluation at P[k] l2.R0 = *pr.MulByElement(&l2.R0, xOverY[k]) l2.R1 = *pr.MulByElement(&l2.R1, yInv[k]) - // ℓ × res - res = pr.MulBy034(res, &l2.R0, &l2.R1) + + // ℓ × ℓ + prodLines = pr.Mul034By034(&l1.R0, &l1.R1, &l2.R0, &l2.R1) + // (ℓ × ℓ) × res + res = pr.MulBy01234(res, &prodLines.C0.B0, &prodLines.C0.B1, &prodLines.C0.B2, &prodLines.C1.B0, &prodLines.C1.B1) } From fbcd628d0afa036fc86897355b2282ebf79d1352 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 17 Mar 2023 13:03:36 +0100 Subject: [PATCH 153/464] perf(bn254-pairing): test and optimize MultiMillerLoop --- .../emulated/fields_bn254/e12_pairing.go | 53 +++++++++++++------ std/algebra/emulated/fields_bn254/e6.go | 37 +++++++++++++ std/algebra/emulated/sw_bn254/pairing.go | 38 ++++++++----- std/algebra/emulated/sw_bn254/pairing_test.go | 38 +++++++++++++ 4 files changed, 139 insertions(+), 27 deletions(-) diff --git a/std/algebra/emulated/fields_bn254/e12_pairing.go b/std/algebra/emulated/fields_bn254/e12_pairing.go index e81da4228f..2fee792c60 100644 --- a/std/algebra/emulated/fields_bn254/e12_pairing.go +++ b/std/algebra/emulated/fields_bn254/e12_pairing.go @@ -91,7 +91,7 @@ func (e *Ext12) MulBy034(z *E12, c3, c4 *E2) *E12 { } } -// multipliies two E12 sparse element of the form: +// multiplies two E12 sparse element of the form: // // E12{ // C0: E6{B0: 1, B1: 0, B2: 0}, @@ -104,7 +104,7 @@ func (e *Ext12) MulBy034(z *E12, c3, c4 *E2) *E12 { // C0: E6{B0: 1, B1: 0, B2: 0}, // C1: E6{B0: d3, B1: d4, B2: 0}, // } -func (e *Ext12) Mul034By034(d3, d4, c3, c4 *E2) *E12 { +func (e *Ext12) Mul034By034(d3, d4, c3, c4 *E2) *[5]E2 { x3 := e.Ext2.Mul(c3, d3) x4 := e.Ext2.Mul(c4, d4) x04 := e.Ext2.Add(c4, d4) @@ -121,16 +121,8 @@ func (e *Ext12) Mul034By034(d3, d4, c3, c4 *E2) *E12 { zC0B2 := x34 zC1B0 := x03 zC1B1 := x04 - zC1B2 := e.Ext2.Zero() - return &E12{ - C0: E6{ - B0: *zC0B0, B1: *zC0B1, B2: *zC0B2, - }, - C1: E6{ - B0: *zC1B0, B1: *zC1B1, B2: *zC1B2, - }, - } + return &[5]E2{*zC0B0, *zC0B1, *zC0B2, *zC1B0, *zC1B1} } // MulBy01234 multiplies z by an E12 sparse element of the form @@ -139,14 +131,14 @@ func (e *Ext12) Mul034By034(d3, d4, c3, c4 *E2) *E12 { // C0: E6{B0: c0, B1: c1, B2: c2}, // C1: E6{B0: c3, B1: c4, B2: 0}, // } -func (e *Ext12) MulBy01234(z *E12, b0, b1, b2, b3, b4 *E2) *E12 { - c0 := &E6{B0: *b0, B1: *b1, B2: *b2} - c1 := &E6{B0: *b3, B1: *b4, B2: *e.Ext2.Zero()} +func (e *Ext12) MulBy01234(z *E12, x *[5]E2) *E12 { + c0 := &E6{B0: x[0], B1: x[1], B2: x[2]} + c1 := &E6{B0: x[3], B1: x[4], B2: *e.Ext2.Zero()} a := e.Ext6.Add(&z.C0, &z.C1) b := e.Ext6.Add(c0, c1) a = e.Ext6.Mul(a, b) b = e.Ext6.Mul(&z.C0, c0) - c := e.Ext6.MulBy01(&z.C1, b3, b4) + c := e.Ext6.MulBy01(&z.C1, &x[3], &x[4]) z1 := e.Ext6.Sub(a, b) z1 = e.Ext6.Sub(z1, c) z0 := e.Ext6.MulByNonResidue(c) @@ -156,3 +148,34 @@ func (e *Ext12) MulBy01234(z *E12, b0, b1, b2, b3, b4 *E2) *E12 { C1: *z1, } } + +// multiplies two E12 sparse element of the form: +// +// E12{ +// C0: E6{B0: x0, B1: x1, B2: x2}, +// C1: E6{B0: x3, B1: x4, B2: 0}, +// } +// +// and +// +// E12{ +// C0: E6{B0: 1, B1: 0, B2: 0}, +// C1: E6{B0: z3, B1: z4, B2: 0}, +// } +func (e *Ext12) Mul01234By034(x *[5]E2, z3, z4 *E2) *E12 { + c0 := &E6{B0: x[0], B1: x[1], B2: x[2]} + c1 := &E6{B0: x[3], B1: x[4], B2: *e.Ext2.Zero()} + a := e.Ext6.Add(e.Ext6.One(), &E6{B0: *z3, B1: *z4, B2: *e.Ext2.Zero()}) + b := e.Ext6.Add(c0, c1) + a = e.Ext6.Mul(a, b) + b = c0 + c := e.Ext6.Mul01By01(z3, z4, &x[3], &x[4]) + z1 := e.Ext6.Sub(a, c0) + z1 = e.Ext6.Sub(z1, c) + z0 := e.Ext6.MulByNonResidue(c) + z0 = e.Ext6.Add(z0, c0) + return &E12{ + C0: *z0, + C1: *z1, + } +} diff --git a/std/algebra/emulated/fields_bn254/e6.go b/std/algebra/emulated/fields_bn254/e6.go index 54d91805c7..b5ab693cd1 100644 --- a/std/algebra/emulated/fields_bn254/e6.go +++ b/std/algebra/emulated/fields_bn254/e6.go @@ -182,6 +182,43 @@ func (e Ext6) MulBy01(z *E6, c0, c1 *E2) *E6 { } } +// Mul01By01 multiplies two E6 sparse element of the form: +// +// E6{ +// B0: c0, +// B1: c1, +// B2: 0, +// } +// +// and +// +// E6{ +// B0: d0, +// B1: d1, +// B2: 0, +// } +func (e Ext6) Mul01By01(c0, c1, d0, d1 *E2) *E6 { + a := e.Ext2.Mul(d0, c0) + b := e.Ext2.Mul(d1, c1) + t0 := e.Ext2.Mul(c1, d1) + t0 = e.Ext2.Sub(t0, b) + t0 = e.Ext2.MulByNonResidue(t0) + t0 = e.Ext2.Add(t0, a) + t2 := e.Ext2.Mul(c0, d0) + t2 = e.Ext2.Sub(t2, a) + t2 = e.Ext2.Add(t2, b) + t1 := e.Ext2.Add(c0, c1) + tmp := e.Ext2.Add(d0, d1) + t1 = e.Ext2.Mul(t1, tmp) + t1 = e.Ext2.Sub(t1, a) + t1 = e.Ext2.Sub(t1, b) + return &E6{ + B0: *t0, + B1: *t1, + B2: *t2, + } +} + func (e Ext6) MulByNonResidue(x *E6) *E6 { z2, z1, z0 := &x.B1, &x.B0, &x.B2 z0 = e.Ext2.MulByNonResidue(z0) diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index c7aa3b3ecb..5b73a6d76d 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -159,7 +159,7 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { } res := pr.Ext12.One() - prodLines := pr.Ext12.Zero() + var prodLines [5]fields_bn254.E2 var l1, l2 *lineEvaluation Qacc := make([]*G2Affine, n) @@ -195,12 +195,26 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { // line evaluation at P[1] l1.R0 = *pr.MulByElement(&l1.R0, xOverY[1]) l1.R1 = *pr.MulByElement(&l1.R1, yInv[1]) - res = pr.Mul034By034(&l1.R0, &l1.R1, &res.C1.B0, &res.C1.B1) + prodLines = *pr.Mul034By034(&l1.R0, &l1.R1, &res.C1.B0, &res.C1.B1) + res.C0.B0 = prodLines[0] + res.C0.B1 = prodLines[1] + res.C0.B2 = prodLines[2] + res.C1.B0 = prodLines[3] + res.C1.B1 = prodLines[4] } if n >= 3 { - // k >= 2 - for k := 2; k < n; k++ { + // k = 2, separately to avoid MulBy034 (res × ℓ) + // (res has a zero E2 element, so we use Mul01234By034) + Qacc[2], l1 = pr.doubleStep(Qacc[2]) + + // line evaluation at P[1] + l1.R0 = *pr.MulByElement(&l1.R0, xOverY[2]) + l1.R1 = *pr.MulByElement(&l1.R1, yInv[2]) + res = pr.Mul01234By034(&prodLines, &l1.R0, &l1.R1) + + // k >= 3 + for k := 3; k < n; k++ { // Qacc[k] ← 2Qacc[k] and l1 the tangent ℓ passing 2Qacc[k] Qacc[k], l1 = pr.doubleStep(Qacc[k]) @@ -234,9 +248,9 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { l1.R1 = *pr.MulByElement(&l1.R1, yInv[k]) // ℓ × ℓ - prodLines = pr.Mul034By034(&l1.R0, &l1.R1, &l2.R0, &l2.R1) + prodLines = *pr.Mul034By034(&l1.R0, &l1.R1, &l2.R0, &l2.R1) // (ℓ × ℓ) × res - res = pr.MulBy01234(res, &prodLines.C0.B0, &prodLines.C0.B1, &prodLines.C0.B2, &prodLines.C1.B0, &prodLines.C1.B1) + res = pr.MulBy01234(res, &prodLines) } for i := 62; i >= 0; i-- { @@ -275,9 +289,9 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { l2.R1 = *pr.MulByElement(&l2.R1, yInv[k]) // ℓ × ℓ - prodLines = pr.Mul034By034(&l1.R0, &l1.R1, &l2.R0, &l2.R1) + prodLines = *pr.Mul034By034(&l1.R0, &l1.R1, &l2.R0, &l2.R1) // (ℓ × ℓ) × res - res = pr.MulBy01234(res, &prodLines.C0.B0, &prodLines.C0.B1, &prodLines.C0.B2, &prodLines.C1.B0, &prodLines.C1.B1) + res = pr.MulBy01234(res, &prodLines) } @@ -297,9 +311,9 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { l2.R1 = *pr.MulByElement(&l2.R1, yInv[k]) // ℓ × ℓ - prodLines = pr.Mul034By034(&l1.R0, &l1.R1, &l2.R0, &l2.R1) + prodLines = *pr.Mul034By034(&l1.R0, &l1.R1, &l2.R0, &l2.R1) // (ℓ × ℓ) × res - res = pr.MulBy01234(res, &prodLines.C0.B0, &prodLines.C0.B1, &prodLines.C0.B2, &prodLines.C1.B0, &prodLines.C1.B1) + res = pr.MulBy01234(res, &prodLines) } @@ -337,9 +351,9 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { l2.R1 = *pr.MulByElement(&l2.R1, yInv[k]) // ℓ × ℓ - prodLines = pr.Mul034By034(&l1.R0, &l1.R1, &l2.R0, &l2.R1) + prodLines = *pr.Mul034By034(&l1.R0, &l1.R1, &l2.R0, &l2.R1) // (ℓ × ℓ) × res - res = pr.MulBy01234(res, &prodLines.C0.B0, &prodLines.C0.B1, &prodLines.C0.B2, &prodLines.C1.B0, &prodLines.C1.B1) + res = pr.MulBy01234(res, &prodLines) } diff --git a/std/algebra/emulated/sw_bn254/pairing_test.go b/std/algebra/emulated/sw_bn254/pairing_test.go index 3a062f795a..4cb7ed26fc 100644 --- a/std/algebra/emulated/sw_bn254/pairing_test.go +++ b/std/algebra/emulated/sw_bn254/pairing_test.go @@ -89,6 +89,44 @@ func TestPairTestSolve(t *testing.T) { assert.NoError(err) } +type MultiPairCircuit struct { + In1G1 G1Affine + In2G1 G1Affine + In1G2 G2Affine + In2G2 G2Affine + Res GTEl +} + +func (c *MultiPairCircuit) Define(api frontend.API) error { + pairing, err := NewPairing(api) + if err != nil { + return fmt.Errorf("new pairing: %w", err) + } + res, err := pairing.Pair([]*G1Affine{&c.In1G1, &c.In1G1, &c.In2G1, &c.In2G1}, []*G2Affine{&c.In1G2, &c.In2G2, &c.In1G2, &c.In2G2}) + if err != nil { + return fmt.Errorf("pair: %w", err) + } + pairing.AssertIsEqual(res, &c.Res) + return nil +} + +func TestMultiPairTestSolve(t *testing.T) { + assert := test.NewAssert(t) + p1, q1 := randomG1G2Affines(assert) + p2, q2 := randomG1G2Affines(assert) + res, err := bn254.Pair([]bn254.G1Affine{p1, p1, p2, p2}, []bn254.G2Affine{q1, q2, q1, q2}) + assert.NoError(err) + witness := MultiPairCircuit{ + In1G1: NewG1Affine(p1), + In1G2: NewG2Affine(q1), + In2G1: NewG1Affine(p2), + In2G2: NewG2Affine(q2), + Res: NewGTEl(res), + } + err = test.IsSolved(&MultiPairCircuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + // bench var ccsBench constraint.ConstraintSystem From 87b51f51bc328a34236dfbfb9f90c50eb02c6302 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 17 Mar 2023 13:52:09 +0100 Subject: [PATCH 154/464] fix: make linter happy --- std/algebra/emulated/fields_bn254/e12_pairing.go | 1 - 1 file changed, 1 deletion(-) diff --git a/std/algebra/emulated/fields_bn254/e12_pairing.go b/std/algebra/emulated/fields_bn254/e12_pairing.go index 2fee792c60..0cfacc6355 100644 --- a/std/algebra/emulated/fields_bn254/e12_pairing.go +++ b/std/algebra/emulated/fields_bn254/e12_pairing.go @@ -168,7 +168,6 @@ func (e *Ext12) Mul01234By034(x *[5]E2, z3, z4 *E2) *E12 { a := e.Ext6.Add(e.Ext6.One(), &E6{B0: *z3, B1: *z4, B2: *e.Ext2.Zero()}) b := e.Ext6.Add(c0, c1) a = e.Ext6.Mul(a, b) - b = c0 c := e.Ext6.Mul01By01(z3, z4, &x[3], &x[4]) z1 := e.Ext6.Sub(a, c0) z1 = e.Ext6.Sub(z1, c) From bce018e5a7ca323f4ab0cd2c7cc797f793a8f6ab Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Fri, 17 Mar 2023 17:28:54 +0100 Subject: [PATCH 155/464] test: remove profiling test --- std/algebra/emulated/sw_bn254/pairing_test.go | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/std/algebra/emulated/sw_bn254/pairing_test.go b/std/algebra/emulated/sw_bn254/pairing_test.go index 4cb7ed26fc..7009a2a21f 100644 --- a/std/algebra/emulated/sw_bn254/pairing_test.go +++ b/std/algebra/emulated/sw_bn254/pairing_test.go @@ -7,10 +7,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/profile" "github.com/consensys/gnark/test" ) @@ -126,14 +123,3 @@ func TestMultiPairTestSolve(t *testing.T) { err = test.IsSolved(&MultiPairCircuit{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } - -// bench -var ccsBench constraint.ConstraintSystem - -func BenchmarkPairing(b *testing.B) { - var c PairCircuit - p := profile.Start() - ccsBench, _ = frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &c) - p.Stop() - fmt.Println(p.NbConstraints()) -} From 66dc78c47eb5679b4b09dead75d66e6555a28327 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 17 Mar 2023 17:55:21 +0100 Subject: [PATCH 156/464] style: correct some comments --- std/algebra/emulated/sw_bn254/doc.go | 2 +- std/algebra/emulated/sw_bn254/pairing.go | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/std/algebra/emulated/sw_bn254/doc.go b/std/algebra/emulated/sw_bn254/doc.go index e66e237ee9..a6639139e7 100644 --- a/std/algebra/emulated/sw_bn254/doc.go +++ b/std/algebra/emulated/sw_bn254/doc.go @@ -1,6 +1,6 @@ // Package sw_bn254 implements G1 and G2 arithmetics and pairing computation over BN254 curve. // -// The implementation follows [[Housni22]]: "Pairings in Rank-1 Constraint Systems". +// The implementation follows [Housni22]: "Pairings in Rank-1 Constraint Systems". // // [Housni22]: https://eprint.iacr.org/2022/1162 package sw_bn254 diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 5b73a6d76d..2aae15dc83 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -130,8 +130,9 @@ func (pr Pairing) AssertIsEqual(x, y *GTEl) { pr.Ext12.AssertIsEqual(x, y) } -// loopCounter = 6*seed+2 in 2-NAF -// loopCounter = 29793968203157093288 +// loopCounter = 6x₀+2 = 29793968203157093288 +// +// in 2-NAF var loopCounter = [66]int8{ 0, 0, 0, 1, 0, 1, 0, -1, 0, 0, -1, 0, 0, 0, 1, 0, 0, -1, 0, -1, 0, 0, @@ -142,7 +143,7 @@ var loopCounter = [66]int8{ } // lineEvaluation represents a sparse Fp12 Elmt (result of the line evaluation) -// line: 1 - R0(x/y) - R1(1/y) = 0 instead of R0'*y - R1'*x - R2' = 0 This +// line: 1 + R0(x/y) + R1(1/y) = 0 instead of R0'*y + R1'*x + R2' = 0 This // makes the multiplication by lines (MulBy034) and between lines (Mul034By034) // circuit-efficient. type lineEvaluation struct { @@ -150,7 +151,7 @@ type lineEvaluation struct { } // MillerLoop computes the multi-Miller loop -// ∏ᵢ { fᵢ_{ℓ,Q}(P) · ℓᵢ_{[ℓ]q,π(q)}(p) · ℓᵢ_{[ℓ]q+π(q),-π²(q)}(p) } +// ∏ᵢ { fᵢ_{6x₀+2,Q}(P) · ℓᵢ_{[6x₀+2]Q,π(Q)}(P) · ℓᵢ_{[6x₀+2]Q+π(Q),-π²(Q)}(P) } func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { // check input size match n := len(P) @@ -176,7 +177,7 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { xOverY[k] = pr.curveF.MulMod(&P[k].X, yInv[k]) } - // Compute ∏ᵢ { fᵢ_{ℓ,Q}(P) } + // Compute ∏ᵢ { fᵢ_{6x₀+2,Q}(P) } // i = 64, separately to avoid an E12 Square // (Square(res) = 1² = 1) @@ -195,6 +196,8 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { // line evaluation at P[1] l1.R0 = *pr.MulByElement(&l1.R0, xOverY[1]) l1.R1 = *pr.MulByElement(&l1.R1, yInv[1]) + + // ℓ × res prodLines = *pr.Mul034By034(&l1.R0, &l1.R1, &res.C1.B0, &res.C1.B1) res.C0.B0 = prodLines[0] res.C0.B1 = prodLines[1] @@ -211,6 +214,8 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { // line evaluation at P[1] l1.R0 = *pr.MulByElement(&l1.R0, xOverY[2]) l1.R1 = *pr.MulByElement(&l1.R1, yInv[2]) + + // ℓ × res res = pr.Mul01234By034(&prodLines, &l1.R0, &l1.R1) // k >= 3 @@ -229,7 +234,7 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { // i = 63, separately to avoid a doubleStep // (at this point Qacc = 2Q, so 2Qacc-Q=3Q is equivalent to Qacc+Q=3Q - // this means doubleAddStep is equivalent to addStep here) + // this means doubleAndAddStep is equivalent to addStep here) res = pr.Square(res) for k := 0; k < n; k++ { // l2 the line passing Qacc[k] and -Q @@ -322,7 +327,7 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { } } - // Compute ∏ᵢ { ℓᵢ_{[ℓ]q,π(q)}(p) · ℓᵢ_{[ℓ]q+π(q),-π²(q)}(p) } + // Compute ∏ᵢ { ℓᵢ_{[6x₀+2]Q,π(Q)}(P) · ℓᵢ_{[6x₀+2]Q+π(Q),-π²(Q)}(P) } Q1, Q2 := new(G2Affine), new(G2Affine) for k := 0; k < n; k++ { //Q1 = π(Q) From 2db2713c96d70ab903d1c7cead58e6cb3793a38e Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 17 Mar 2023 18:02:19 +0100 Subject: [PATCH 157/464] style: academic style reference for documentation --- std/algebra/emulated/sw_bn254/doc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/algebra/emulated/sw_bn254/doc.go b/std/algebra/emulated/sw_bn254/doc.go index a6639139e7..e66e237ee9 100644 --- a/std/algebra/emulated/sw_bn254/doc.go +++ b/std/algebra/emulated/sw_bn254/doc.go @@ -1,6 +1,6 @@ // Package sw_bn254 implements G1 and G2 arithmetics and pairing computation over BN254 curve. // -// The implementation follows [Housni22]: "Pairings in Rank-1 Constraint Systems". +// The implementation follows [[Housni22]]: "Pairings in Rank-1 Constraint Systems". // // [Housni22]: https://eprint.iacr.org/2022/1162 package sw_bn254 From 4e20b68ff1fc09343864340ee7ce981d27b4664f Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 17 Mar 2023 13:43:26 -0400 Subject: [PATCH 158/464] build: generify constraint changes --- constraint/bls12-377/r1cs_sparse.go | 11 ++++- constraint/bls12-381/r1cs_sparse.go | 11 ++++- constraint/bls24-315/r1cs_sparse.go | 11 ++++- constraint/bls24-317/r1cs_sparse.go | 11 ++++- constraint/bn254/r1cs_sparse.go | 4 +- constraint/bw6-633/r1cs_sparse.go | 11 ++++- constraint/bw6-761/r1cs_sparse.go | 11 ++++- constraint/commitment.go | 4 +- constraint/tinyfield/r1cs_sparse.go | 11 ++++- .../representations/r1cs.sparse.go.tmpl | 11 ++++- test/commitments_test.go | 40 ++++++++++--------- 11 files changed, 106 insertions(+), 30 deletions(-) diff --git a/constraint/bls12-377/r1cs_sparse.go b/constraint/bls12-377/r1cs_sparse.go index 2fd9f5cd64..d6cce3531f 100644 --- a/constraint/bls12-377/r1cs_sparse.go +++ b/constraint/bls12-377/r1cs_sparse.go @@ -138,7 +138,7 @@ func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, er start := time.Now() - expectedWitnessSize := int(len(cs.Public) + len(cs.Secret)) + expectedWitnessSize := len(cs.Public) + len(cs.Secret) if len(witness) != expectedWitnessSize { return make(fr.Vector, nbVariables), fmt.Errorf( "invalid witness size, got %d, expected %d = %d (public) + %d (secret)", @@ -358,6 +358,10 @@ func (cs *SparseR1CS) computeHints(c constraint.SparseR1C, solution *solution) ( // if it doesn't, then this function returns and does nothing func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution, coefficientsNegInv fr.Vector) error { + if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. + return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time + } + lro, err := cs.computeHints(c, solution) if err != nil { return err @@ -439,6 +443,11 @@ func (cs *SparseR1CS) GetConstraints() ([]constraint.SparseR1C, constraint.Resol // checkConstraint verifies that the constraint holds func (cs *SparseR1CS) checkConstraint(c constraint.SparseR1C, solution *solution) error { + + if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. + return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time + } + l := solution.computeTerm(c.L) r := solution.computeTerm(c.R) m0 := solution.computeTerm(c.M[0]) diff --git a/constraint/bls12-381/r1cs_sparse.go b/constraint/bls12-381/r1cs_sparse.go index 63a023a9ff..b26d9be6f4 100644 --- a/constraint/bls12-381/r1cs_sparse.go +++ b/constraint/bls12-381/r1cs_sparse.go @@ -138,7 +138,7 @@ func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, er start := time.Now() - expectedWitnessSize := int(len(cs.Public) + len(cs.Secret)) + expectedWitnessSize := len(cs.Public) + len(cs.Secret) if len(witness) != expectedWitnessSize { return make(fr.Vector, nbVariables), fmt.Errorf( "invalid witness size, got %d, expected %d = %d (public) + %d (secret)", @@ -358,6 +358,10 @@ func (cs *SparseR1CS) computeHints(c constraint.SparseR1C, solution *solution) ( // if it doesn't, then this function returns and does nothing func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution, coefficientsNegInv fr.Vector) error { + if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. + return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time + } + lro, err := cs.computeHints(c, solution) if err != nil { return err @@ -439,6 +443,11 @@ func (cs *SparseR1CS) GetConstraints() ([]constraint.SparseR1C, constraint.Resol // checkConstraint verifies that the constraint holds func (cs *SparseR1CS) checkConstraint(c constraint.SparseR1C, solution *solution) error { + + if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. + return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time + } + l := solution.computeTerm(c.L) r := solution.computeTerm(c.R) m0 := solution.computeTerm(c.M[0]) diff --git a/constraint/bls24-315/r1cs_sparse.go b/constraint/bls24-315/r1cs_sparse.go index 827bd37fc3..4fbb106359 100644 --- a/constraint/bls24-315/r1cs_sparse.go +++ b/constraint/bls24-315/r1cs_sparse.go @@ -138,7 +138,7 @@ func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, er start := time.Now() - expectedWitnessSize := int(len(cs.Public) + len(cs.Secret)) + expectedWitnessSize := len(cs.Public) + len(cs.Secret) if len(witness) != expectedWitnessSize { return make(fr.Vector, nbVariables), fmt.Errorf( "invalid witness size, got %d, expected %d = %d (public) + %d (secret)", @@ -358,6 +358,10 @@ func (cs *SparseR1CS) computeHints(c constraint.SparseR1C, solution *solution) ( // if it doesn't, then this function returns and does nothing func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution, coefficientsNegInv fr.Vector) error { + if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. + return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time + } + lro, err := cs.computeHints(c, solution) if err != nil { return err @@ -439,6 +443,11 @@ func (cs *SparseR1CS) GetConstraints() ([]constraint.SparseR1C, constraint.Resol // checkConstraint verifies that the constraint holds func (cs *SparseR1CS) checkConstraint(c constraint.SparseR1C, solution *solution) error { + + if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. + return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time + } + l := solution.computeTerm(c.L) r := solution.computeTerm(c.R) m0 := solution.computeTerm(c.M[0]) diff --git a/constraint/bls24-317/r1cs_sparse.go b/constraint/bls24-317/r1cs_sparse.go index c8503d0f54..fa13b420c9 100644 --- a/constraint/bls24-317/r1cs_sparse.go +++ b/constraint/bls24-317/r1cs_sparse.go @@ -138,7 +138,7 @@ func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, er start := time.Now() - expectedWitnessSize := int(len(cs.Public) + len(cs.Secret)) + expectedWitnessSize := len(cs.Public) + len(cs.Secret) if len(witness) != expectedWitnessSize { return make(fr.Vector, nbVariables), fmt.Errorf( "invalid witness size, got %d, expected %d = %d (public) + %d (secret)", @@ -358,6 +358,10 @@ func (cs *SparseR1CS) computeHints(c constraint.SparseR1C, solution *solution) ( // if it doesn't, then this function returns and does nothing func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution, coefficientsNegInv fr.Vector) error { + if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. + return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time + } + lro, err := cs.computeHints(c, solution) if err != nil { return err @@ -439,6 +443,11 @@ func (cs *SparseR1CS) GetConstraints() ([]constraint.SparseR1C, constraint.Resol // checkConstraint verifies that the constraint holds func (cs *SparseR1CS) checkConstraint(c constraint.SparseR1C, solution *solution) error { + + if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. + return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time + } + l := solution.computeTerm(c.L) r := solution.computeTerm(c.R) m0 := solution.computeTerm(c.M[0]) diff --git a/constraint/bn254/r1cs_sparse.go b/constraint/bn254/r1cs_sparse.go index b481f232a5..416c1e5ce0 100644 --- a/constraint/bn254/r1cs_sparse.go +++ b/constraint/bn254/r1cs_sparse.go @@ -444,8 +444,8 @@ func (cs *SparseR1CS) GetConstraints() ([]constraint.SparseR1C, constraint.Resol // checkConstraint verifies that the constraint holds func (cs *SparseR1CS) checkConstraint(c constraint.SparseR1C, solution *solution) error { - if c.Commitment != constraint.NOT { - return nil + if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. + return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time } l := solution.computeTerm(c.L) diff --git a/constraint/bw6-633/r1cs_sparse.go b/constraint/bw6-633/r1cs_sparse.go index 80cdacb38c..fffe3b65fd 100644 --- a/constraint/bw6-633/r1cs_sparse.go +++ b/constraint/bw6-633/r1cs_sparse.go @@ -138,7 +138,7 @@ func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, er start := time.Now() - expectedWitnessSize := int(len(cs.Public) + len(cs.Secret)) + expectedWitnessSize := len(cs.Public) + len(cs.Secret) if len(witness) != expectedWitnessSize { return make(fr.Vector, nbVariables), fmt.Errorf( "invalid witness size, got %d, expected %d = %d (public) + %d (secret)", @@ -358,6 +358,10 @@ func (cs *SparseR1CS) computeHints(c constraint.SparseR1C, solution *solution) ( // if it doesn't, then this function returns and does nothing func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution, coefficientsNegInv fr.Vector) error { + if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. + return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time + } + lro, err := cs.computeHints(c, solution) if err != nil { return err @@ -439,6 +443,11 @@ func (cs *SparseR1CS) GetConstraints() ([]constraint.SparseR1C, constraint.Resol // checkConstraint verifies that the constraint holds func (cs *SparseR1CS) checkConstraint(c constraint.SparseR1C, solution *solution) error { + + if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. + return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time + } + l := solution.computeTerm(c.L) r := solution.computeTerm(c.R) m0 := solution.computeTerm(c.M[0]) diff --git a/constraint/bw6-761/r1cs_sparse.go b/constraint/bw6-761/r1cs_sparse.go index 09c22e4d48..a00fac9c50 100644 --- a/constraint/bw6-761/r1cs_sparse.go +++ b/constraint/bw6-761/r1cs_sparse.go @@ -138,7 +138,7 @@ func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, er start := time.Now() - expectedWitnessSize := int(len(cs.Public) + len(cs.Secret)) + expectedWitnessSize := len(cs.Public) + len(cs.Secret) if len(witness) != expectedWitnessSize { return make(fr.Vector, nbVariables), fmt.Errorf( "invalid witness size, got %d, expected %d = %d (public) + %d (secret)", @@ -358,6 +358,10 @@ func (cs *SparseR1CS) computeHints(c constraint.SparseR1C, solution *solution) ( // if it doesn't, then this function returns and does nothing func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution, coefficientsNegInv fr.Vector) error { + if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. + return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time + } + lro, err := cs.computeHints(c, solution) if err != nil { return err @@ -439,6 +443,11 @@ func (cs *SparseR1CS) GetConstraints() ([]constraint.SparseR1C, constraint.Resol // checkConstraint verifies that the constraint holds func (cs *SparseR1CS) checkConstraint(c constraint.SparseR1C, solution *solution) error { + + if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. + return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time + } + l := solution.computeTerm(c.L) r := solution.computeTerm(c.R) m0 := solution.computeTerm(c.M[0]) diff --git a/constraint/commitment.go b/constraint/commitment.go index d43b5d3115..adc7ce65fc 100644 --- a/constraint/commitment.go +++ b/constraint/commitment.go @@ -12,8 +12,8 @@ type Commitment struct { Committed []int // sorted list of id's of committed variables in groth16. in plonk, list of indexes of constraints defining committed values NbPrivateCommitted int HintID solver.HintID // TODO @gbotrel we probably don't need that here - CommitmentIndex int // in groth16, CommitmentIndex is the wire index. in plonk, it's the constraint defining it - CommittedAndCommitment []int // sorted list of id's of committed variables AND the commitment itself + CommitmentIndex int // in groth16, CommitmentIndex is the wire index. in plonk, it's the constraint defining it + CommittedAndCommitment []int // sorted list of id's of committed variables AND the commitment itself } func (i *Commitment) NbPublicCommitted() int { diff --git a/constraint/tinyfield/r1cs_sparse.go b/constraint/tinyfield/r1cs_sparse.go index b3fe2373a9..6a18b3fa3f 100644 --- a/constraint/tinyfield/r1cs_sparse.go +++ b/constraint/tinyfield/r1cs_sparse.go @@ -138,7 +138,7 @@ func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, er start := time.Now() - expectedWitnessSize := int(len(cs.Public) + len(cs.Secret)) + expectedWitnessSize := len(cs.Public) + len(cs.Secret) if len(witness) != expectedWitnessSize { return make(fr.Vector, nbVariables), fmt.Errorf( "invalid witness size, got %d, expected %d = %d (public) + %d (secret)", @@ -358,6 +358,10 @@ func (cs *SparseR1CS) computeHints(c constraint.SparseR1C, solution *solution) ( // if it doesn't, then this function returns and does nothing func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution, coefficientsNegInv fr.Vector) error { + if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. + return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time + } + lro, err := cs.computeHints(c, solution) if err != nil { return err @@ -439,6 +443,11 @@ func (cs *SparseR1CS) GetConstraints() ([]constraint.SparseR1C, constraint.Resol // checkConstraint verifies that the constraint holds func (cs *SparseR1CS) checkConstraint(c constraint.SparseR1C, solution *solution) error { + + if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. + return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time + } + l := solution.computeTerm(c.L) r := solution.computeTerm(c.R) m0 := solution.computeTerm(c.M[0]) diff --git a/internal/generator/backend/template/representations/r1cs.sparse.go.tmpl b/internal/generator/backend/template/representations/r1cs.sparse.go.tmpl index eec1fd8d58..10d4184f28 100644 --- a/internal/generator/backend/template/representations/r1cs.sparse.go.tmpl +++ b/internal/generator/backend/template/representations/r1cs.sparse.go.tmpl @@ -122,7 +122,7 @@ func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, er start := time.Now() - expectedWitnessSize := int(len(cs.Public) + len(cs.Secret)) + expectedWitnessSize := len(cs.Public) + len(cs.Secret) if len(witness) != expectedWitnessSize { return make(fr.Vector, nbVariables), fmt.Errorf( "invalid witness size, got %d, expected %d = %d (public) + %d (secret)", @@ -348,6 +348,10 @@ func (cs *SparseR1CS) computeHints(c constraint.SparseR1C, solution *solution) ( // if it doesn't, then this function returns and does nothing func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution, coefficientsNegInv fr.Vector) error { + if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. + return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time + } + lro, err := cs.computeHints(c, solution) if err != nil { return err @@ -429,6 +433,11 @@ func (cs *SparseR1CS) GetConstraints() ([]constraint.SparseR1C, constraint.Resol // checkConstraint verifies that the constraint holds func (cs *SparseR1CS) checkConstraint(c constraint.SparseR1C, solution *solution) error { + + if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. + return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time + } + l := solution.computeTerm(c.L) r := solution.computeTerm(c.R) m0 := solution.computeTerm(c.M[0]) diff --git a/test/commitments_test.go b/test/commitments_test.go index 4ab58ba92f..592b9166ec 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -23,6 +23,28 @@ func (c *commitmentCircuit) Define(api frontend.API) error { return err } +func TestSingleCommitmentPlonkBn254(t *testing.T) { + plonkTestBn254(t, &commitmentCircuit{[]frontend.Variable{1}}) +} + +func TestFiveCommitmentsPlonk(t *testing.T) { + plonkTestBn254(t, &commitmentCircuit{[]frontend.Variable{1, 2, 3, 4, 5}}) +} + +type noCommitmentCircuit struct { + X frontend.Variable +} + +func (c *noCommitmentCircuit) Define(api frontend.API) error { + api.AssertIsEqual(c.X, 1) + api.AssertIsEqual(c.X, 1) + return nil +} + +func TestNoCommitmentCircuit(t *testing.T) { + plonkTestBn254(t, &noCommitmentCircuit{1}) +} + func plonkTestBn254(t *testing.T, assignment frontend.Circuit) { witnessFull, err := frontend.NewWitness(assignment, ecc.BN254.ScalarField()) assert.NoError(t, err) @@ -46,21 +68,3 @@ func plonkTestBn254(t *testing.T, assignment frontend.Circuit) { assert.NoError(t, err) } - -func TestSingleCommitmentPlonkBn254(t *testing.T) { - plonkTestBn254(t, &commitmentCircuit{[]frontend.Variable{1}}) -} - -type noCommitmentCircuit struct { - X frontend.Variable -} - -func (c *noCommitmentCircuit) Define(api frontend.API) error { - api.AssertIsEqual(c.X, 1) - api.AssertIsEqual(c.X, 1) - return nil -} - -func TestNoCommitmentCircuit(t *testing.T) { - plonkTestBn254(t, &noCommitmentCircuit{1}) -} From 09a780aa3a6f1eb7be166f6dca6b0163733da478 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 17 Mar 2023 13:48:54 -0400 Subject: [PATCH 159/464] build: generify setup changes --- internal/backend/bls12-377/plonk/setup.go | 32 ++++++++++++++----- internal/backend/bls12-381/plonk/setup.go | 32 ++++++++++++++----- internal/backend/bls24-315/plonk/setup.go | 32 ++++++++++++++----- internal/backend/bls24-317/plonk/setup.go | 32 ++++++++++++++----- internal/backend/bw6-633/plonk/setup.go | 32 ++++++++++++++----- internal/backend/bw6-761/plonk/setup.go | 32 ++++++++++++++----- .../zkpschemes/plonk/plonk.setup.go.tmpl | 32 ++++++++++++++----- 7 files changed, 168 insertions(+), 56 deletions(-) diff --git a/internal/backend/bls12-377/plonk/setup.go b/internal/backend/bls12-377/plonk/setup.go index e7f0b7a553..304c341709 100644 --- a/internal/backend/bls12-377/plonk/setup.go +++ b/internal/backend/bls12-377/plonk/setup.go @@ -41,11 +41,11 @@ type ProvingKey struct { // TODO store iop.Polynomial here, not []fr.Element for more "type safety" - // qr,ql,qm,qo (in canonical basis). - Ql, Qr, Qm, Qo []fr.Element + // qr,ql,qm,qo,cqp (in canonical basis). + Ql, Qr, Qm, Qo, QcPrime []fr.Element - // qr,ql,qm,qo (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. - lQl, lQr, lQm, lQo []fr.Element + // qr,ql,qm,qo,qcp (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. + lQl, lQr, lQm, lQo, lQcPrime []fr.Element // LQk (CQk) qk in Lagrange basis (canonical basis), prepended with as many zeroes as public inputs. // Storing LQk in Lagrange basis saves a fft... @@ -90,7 +90,9 @@ type VerifyingKey struct { // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk kzg.Digest + Ql, Qr, Qm, Qo, Qk, QcPrime kzg.Digest + + CommitmentInfo constraint.Commitment } // Setup sets proving and verifying keys @@ -100,6 +102,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // The verifying key shares data with the proving key pk.Vk = &vk + vk.CommitmentInfo = spr.CommitmentInfo nbConstraints := len(spr.Constraints) @@ -126,15 +129,16 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } - // public polynomials corresponding to constraints: [ placholders | constraints | assertions ] + // public polynomials corresponding to constraints: [ placeholders | constraints | assertions ] pk.Ql = make([]fr.Element, pk.Domain[0].Cardinality) pk.Qr = make([]fr.Element, pk.Domain[0].Cardinality) pk.Qm = make([]fr.Element, pk.Domain[0].Cardinality) + pk.QcPrime = make([]fr.Element, pk.Domain[0].Cardinality) pk.Qo = make([]fr.Element, pk.Domain[0].Cardinality) pk.CQk = make([]fr.Element, pk.Domain[0].Cardinality) pk.LQk = make([]fr.Element, pk.Domain[0].Cardinality) - for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistant + for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent pk.Ql[i].SetOne().Neg(&pk.Ql[i]) pk.Qr[i].SetZero() pk.Qm[i].SetZero() @@ -154,16 +158,22 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) pk.LQk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } + for _, committed := range spr.CommitmentInfo.Committed { + pk.QcPrime[committed].SetOne() + } + pk.Domain[0].FFTInverse(pk.Ql, fft.DIF) pk.Domain[0].FFTInverse(pk.Qr, fft.DIF) pk.Domain[0].FFTInverse(pk.Qm, fft.DIF) pk.Domain[0].FFTInverse(pk.Qo, fft.DIF) pk.Domain[0].FFTInverse(pk.CQk, fft.DIF) + pk.Domain[0].FFTInverse(pk.QcPrime, fft.DIF) fft.BitReverse(pk.Ql) fft.BitReverse(pk.Qr) fft.BitReverse(pk.Qm) fft.BitReverse(pk.Qo) fft.BitReverse(pk.CQk) + fft.BitReverse(pk.QcPrime) // build permutation. Note: at this stage, the permutation takes in account the placeholders buildPermutation(spr, &pk) @@ -185,6 +195,9 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) if vk.Qm, err = kzg.Commit(pk.Qm, vk.KZGSRS); err != nil { return nil, nil, err } + if vk.QcPrime, err = kzg.Commit(pk.QcPrime, vk.KZGSRS); err != nil { + return nil, nil, err + } if vk.Qo, err = kzg.Commit(pk.Qo, vk.KZGSRS); err != nil { return nil, nil, err } @@ -271,6 +284,7 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { wqriop := iop.NewPolynomial(clone(pk.Qr, pk.Domain[1].Cardinality), canReg) wqmiop := iop.NewPolynomial(clone(pk.Qm, pk.Domain[1].Cardinality), canReg) wqoiop := iop.NewPolynomial(clone(pk.Qo, pk.Domain[1].Cardinality), canReg) + wqcpiop := iop.NewPolynomial(clone(pk.QcPrime, pk.Domain[1].Cardinality), canReg) ws1 := iop.NewPolynomial(clone(pk.S1Canonical, pk.Domain[1].Cardinality), canReg) ws2 := iop.NewPolynomial(clone(pk.S2Canonical, pk.Domain[1].Cardinality), canReg) @@ -280,6 +294,7 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { wqriop.ToLagrangeCoset(&pk.Domain[1]) wqmiop.ToLagrangeCoset(&pk.Domain[1]) wqoiop.ToLagrangeCoset(&pk.Domain[1]) + wqcpiop.ToLagrangeCoset(&pk.Domain[1]) ws1.ToLagrangeCoset(&pk.Domain[1]) ws2.ToLagrangeCoset(&pk.Domain[1]) @@ -289,6 +304,7 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { pk.lQr = wqriop.Coefficients() pk.lQm = wqmiop.Coefficients() pk.lQo = wqoiop.Coefficients() + pk.lQcPrime = wqcpiop.Coefficients() pk.lS1LagrangeCoset = ws1.Coefficients() pk.lS2LagrangeCoset = ws2.Coefficients() @@ -370,7 +386,7 @@ func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { // This should be used after deserializing a VerifyingKey // as vk.KZG is NOT serialized // -// Note that this instantiate a new FFT domain using vk.Size +// Note that this instantiates a new FFT domain using vk.Size func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { _srs := srs.(*kzg.SRS) diff --git a/internal/backend/bls12-381/plonk/setup.go b/internal/backend/bls12-381/plonk/setup.go index e86f945c71..38656c5103 100644 --- a/internal/backend/bls12-381/plonk/setup.go +++ b/internal/backend/bls12-381/plonk/setup.go @@ -41,11 +41,11 @@ type ProvingKey struct { // TODO store iop.Polynomial here, not []fr.Element for more "type safety" - // qr,ql,qm,qo (in canonical basis). - Ql, Qr, Qm, Qo []fr.Element + // qr,ql,qm,qo,cqp (in canonical basis). + Ql, Qr, Qm, Qo, QcPrime []fr.Element - // qr,ql,qm,qo (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. - lQl, lQr, lQm, lQo []fr.Element + // qr,ql,qm,qo,qcp (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. + lQl, lQr, lQm, lQo, lQcPrime []fr.Element // LQk (CQk) qk in Lagrange basis (canonical basis), prepended with as many zeroes as public inputs. // Storing LQk in Lagrange basis saves a fft... @@ -90,7 +90,9 @@ type VerifyingKey struct { // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk kzg.Digest + Ql, Qr, Qm, Qo, Qk, QcPrime kzg.Digest + + CommitmentInfo constraint.Commitment } // Setup sets proving and verifying keys @@ -100,6 +102,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // The verifying key shares data with the proving key pk.Vk = &vk + vk.CommitmentInfo = spr.CommitmentInfo nbConstraints := len(spr.Constraints) @@ -126,15 +129,16 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } - // public polynomials corresponding to constraints: [ placholders | constraints | assertions ] + // public polynomials corresponding to constraints: [ placeholders | constraints | assertions ] pk.Ql = make([]fr.Element, pk.Domain[0].Cardinality) pk.Qr = make([]fr.Element, pk.Domain[0].Cardinality) pk.Qm = make([]fr.Element, pk.Domain[0].Cardinality) + pk.QcPrime = make([]fr.Element, pk.Domain[0].Cardinality) pk.Qo = make([]fr.Element, pk.Domain[0].Cardinality) pk.CQk = make([]fr.Element, pk.Domain[0].Cardinality) pk.LQk = make([]fr.Element, pk.Domain[0].Cardinality) - for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistant + for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent pk.Ql[i].SetOne().Neg(&pk.Ql[i]) pk.Qr[i].SetZero() pk.Qm[i].SetZero() @@ -154,16 +158,22 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) pk.LQk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } + for _, committed := range spr.CommitmentInfo.Committed { + pk.QcPrime[committed].SetOne() + } + pk.Domain[0].FFTInverse(pk.Ql, fft.DIF) pk.Domain[0].FFTInverse(pk.Qr, fft.DIF) pk.Domain[0].FFTInverse(pk.Qm, fft.DIF) pk.Domain[0].FFTInverse(pk.Qo, fft.DIF) pk.Domain[0].FFTInverse(pk.CQk, fft.DIF) + pk.Domain[0].FFTInverse(pk.QcPrime, fft.DIF) fft.BitReverse(pk.Ql) fft.BitReverse(pk.Qr) fft.BitReverse(pk.Qm) fft.BitReverse(pk.Qo) fft.BitReverse(pk.CQk) + fft.BitReverse(pk.QcPrime) // build permutation. Note: at this stage, the permutation takes in account the placeholders buildPermutation(spr, &pk) @@ -185,6 +195,9 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) if vk.Qm, err = kzg.Commit(pk.Qm, vk.KZGSRS); err != nil { return nil, nil, err } + if vk.QcPrime, err = kzg.Commit(pk.QcPrime, vk.KZGSRS); err != nil { + return nil, nil, err + } if vk.Qo, err = kzg.Commit(pk.Qo, vk.KZGSRS); err != nil { return nil, nil, err } @@ -271,6 +284,7 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { wqriop := iop.NewPolynomial(clone(pk.Qr, pk.Domain[1].Cardinality), canReg) wqmiop := iop.NewPolynomial(clone(pk.Qm, pk.Domain[1].Cardinality), canReg) wqoiop := iop.NewPolynomial(clone(pk.Qo, pk.Domain[1].Cardinality), canReg) + wqcpiop := iop.NewPolynomial(clone(pk.QcPrime, pk.Domain[1].Cardinality), canReg) ws1 := iop.NewPolynomial(clone(pk.S1Canonical, pk.Domain[1].Cardinality), canReg) ws2 := iop.NewPolynomial(clone(pk.S2Canonical, pk.Domain[1].Cardinality), canReg) @@ -280,6 +294,7 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { wqriop.ToLagrangeCoset(&pk.Domain[1]) wqmiop.ToLagrangeCoset(&pk.Domain[1]) wqoiop.ToLagrangeCoset(&pk.Domain[1]) + wqcpiop.ToLagrangeCoset(&pk.Domain[1]) ws1.ToLagrangeCoset(&pk.Domain[1]) ws2.ToLagrangeCoset(&pk.Domain[1]) @@ -289,6 +304,7 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { pk.lQr = wqriop.Coefficients() pk.lQm = wqmiop.Coefficients() pk.lQo = wqoiop.Coefficients() + pk.lQcPrime = wqcpiop.Coefficients() pk.lS1LagrangeCoset = ws1.Coefficients() pk.lS2LagrangeCoset = ws2.Coefficients() @@ -370,7 +386,7 @@ func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { // This should be used after deserializing a VerifyingKey // as vk.KZG is NOT serialized // -// Note that this instantiate a new FFT domain using vk.Size +// Note that this instantiates a new FFT domain using vk.Size func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { _srs := srs.(*kzg.SRS) diff --git a/internal/backend/bls24-315/plonk/setup.go b/internal/backend/bls24-315/plonk/setup.go index 0bdfcb2ff9..4acee1a909 100644 --- a/internal/backend/bls24-315/plonk/setup.go +++ b/internal/backend/bls24-315/plonk/setup.go @@ -41,11 +41,11 @@ type ProvingKey struct { // TODO store iop.Polynomial here, not []fr.Element for more "type safety" - // qr,ql,qm,qo (in canonical basis). - Ql, Qr, Qm, Qo []fr.Element + // qr,ql,qm,qo,cqp (in canonical basis). + Ql, Qr, Qm, Qo, QcPrime []fr.Element - // qr,ql,qm,qo (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. - lQl, lQr, lQm, lQo []fr.Element + // qr,ql,qm,qo,qcp (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. + lQl, lQr, lQm, lQo, lQcPrime []fr.Element // LQk (CQk) qk in Lagrange basis (canonical basis), prepended with as many zeroes as public inputs. // Storing LQk in Lagrange basis saves a fft... @@ -90,7 +90,9 @@ type VerifyingKey struct { // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk kzg.Digest + Ql, Qr, Qm, Qo, Qk, QcPrime kzg.Digest + + CommitmentInfo constraint.Commitment } // Setup sets proving and verifying keys @@ -100,6 +102,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // The verifying key shares data with the proving key pk.Vk = &vk + vk.CommitmentInfo = spr.CommitmentInfo nbConstraints := len(spr.Constraints) @@ -126,15 +129,16 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } - // public polynomials corresponding to constraints: [ placholders | constraints | assertions ] + // public polynomials corresponding to constraints: [ placeholders | constraints | assertions ] pk.Ql = make([]fr.Element, pk.Domain[0].Cardinality) pk.Qr = make([]fr.Element, pk.Domain[0].Cardinality) pk.Qm = make([]fr.Element, pk.Domain[0].Cardinality) + pk.QcPrime = make([]fr.Element, pk.Domain[0].Cardinality) pk.Qo = make([]fr.Element, pk.Domain[0].Cardinality) pk.CQk = make([]fr.Element, pk.Domain[0].Cardinality) pk.LQk = make([]fr.Element, pk.Domain[0].Cardinality) - for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistant + for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent pk.Ql[i].SetOne().Neg(&pk.Ql[i]) pk.Qr[i].SetZero() pk.Qm[i].SetZero() @@ -154,16 +158,22 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) pk.LQk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } + for _, committed := range spr.CommitmentInfo.Committed { + pk.QcPrime[committed].SetOne() + } + pk.Domain[0].FFTInverse(pk.Ql, fft.DIF) pk.Domain[0].FFTInverse(pk.Qr, fft.DIF) pk.Domain[0].FFTInverse(pk.Qm, fft.DIF) pk.Domain[0].FFTInverse(pk.Qo, fft.DIF) pk.Domain[0].FFTInverse(pk.CQk, fft.DIF) + pk.Domain[0].FFTInverse(pk.QcPrime, fft.DIF) fft.BitReverse(pk.Ql) fft.BitReverse(pk.Qr) fft.BitReverse(pk.Qm) fft.BitReverse(pk.Qo) fft.BitReverse(pk.CQk) + fft.BitReverse(pk.QcPrime) // build permutation. Note: at this stage, the permutation takes in account the placeholders buildPermutation(spr, &pk) @@ -185,6 +195,9 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) if vk.Qm, err = kzg.Commit(pk.Qm, vk.KZGSRS); err != nil { return nil, nil, err } + if vk.QcPrime, err = kzg.Commit(pk.QcPrime, vk.KZGSRS); err != nil { + return nil, nil, err + } if vk.Qo, err = kzg.Commit(pk.Qo, vk.KZGSRS); err != nil { return nil, nil, err } @@ -271,6 +284,7 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { wqriop := iop.NewPolynomial(clone(pk.Qr, pk.Domain[1].Cardinality), canReg) wqmiop := iop.NewPolynomial(clone(pk.Qm, pk.Domain[1].Cardinality), canReg) wqoiop := iop.NewPolynomial(clone(pk.Qo, pk.Domain[1].Cardinality), canReg) + wqcpiop := iop.NewPolynomial(clone(pk.QcPrime, pk.Domain[1].Cardinality), canReg) ws1 := iop.NewPolynomial(clone(pk.S1Canonical, pk.Domain[1].Cardinality), canReg) ws2 := iop.NewPolynomial(clone(pk.S2Canonical, pk.Domain[1].Cardinality), canReg) @@ -280,6 +294,7 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { wqriop.ToLagrangeCoset(&pk.Domain[1]) wqmiop.ToLagrangeCoset(&pk.Domain[1]) wqoiop.ToLagrangeCoset(&pk.Domain[1]) + wqcpiop.ToLagrangeCoset(&pk.Domain[1]) ws1.ToLagrangeCoset(&pk.Domain[1]) ws2.ToLagrangeCoset(&pk.Domain[1]) @@ -289,6 +304,7 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { pk.lQr = wqriop.Coefficients() pk.lQm = wqmiop.Coefficients() pk.lQo = wqoiop.Coefficients() + pk.lQcPrime = wqcpiop.Coefficients() pk.lS1LagrangeCoset = ws1.Coefficients() pk.lS2LagrangeCoset = ws2.Coefficients() @@ -370,7 +386,7 @@ func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { // This should be used after deserializing a VerifyingKey // as vk.KZG is NOT serialized // -// Note that this instantiate a new FFT domain using vk.Size +// Note that this instantiates a new FFT domain using vk.Size func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { _srs := srs.(*kzg.SRS) diff --git a/internal/backend/bls24-317/plonk/setup.go b/internal/backend/bls24-317/plonk/setup.go index 08c3689967..e0fcf8eff5 100644 --- a/internal/backend/bls24-317/plonk/setup.go +++ b/internal/backend/bls24-317/plonk/setup.go @@ -41,11 +41,11 @@ type ProvingKey struct { // TODO store iop.Polynomial here, not []fr.Element for more "type safety" - // qr,ql,qm,qo (in canonical basis). - Ql, Qr, Qm, Qo []fr.Element + // qr,ql,qm,qo,cqp (in canonical basis). + Ql, Qr, Qm, Qo, QcPrime []fr.Element - // qr,ql,qm,qo (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. - lQl, lQr, lQm, lQo []fr.Element + // qr,ql,qm,qo,qcp (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. + lQl, lQr, lQm, lQo, lQcPrime []fr.Element // LQk (CQk) qk in Lagrange basis (canonical basis), prepended with as many zeroes as public inputs. // Storing LQk in Lagrange basis saves a fft... @@ -90,7 +90,9 @@ type VerifyingKey struct { // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk kzg.Digest + Ql, Qr, Qm, Qo, Qk, QcPrime kzg.Digest + + CommitmentInfo constraint.Commitment } // Setup sets proving and verifying keys @@ -100,6 +102,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // The verifying key shares data with the proving key pk.Vk = &vk + vk.CommitmentInfo = spr.CommitmentInfo nbConstraints := len(spr.Constraints) @@ -126,15 +129,16 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } - // public polynomials corresponding to constraints: [ placholders | constraints | assertions ] + // public polynomials corresponding to constraints: [ placeholders | constraints | assertions ] pk.Ql = make([]fr.Element, pk.Domain[0].Cardinality) pk.Qr = make([]fr.Element, pk.Domain[0].Cardinality) pk.Qm = make([]fr.Element, pk.Domain[0].Cardinality) + pk.QcPrime = make([]fr.Element, pk.Domain[0].Cardinality) pk.Qo = make([]fr.Element, pk.Domain[0].Cardinality) pk.CQk = make([]fr.Element, pk.Domain[0].Cardinality) pk.LQk = make([]fr.Element, pk.Domain[0].Cardinality) - for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistant + for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent pk.Ql[i].SetOne().Neg(&pk.Ql[i]) pk.Qr[i].SetZero() pk.Qm[i].SetZero() @@ -154,16 +158,22 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) pk.LQk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } + for _, committed := range spr.CommitmentInfo.Committed { + pk.QcPrime[committed].SetOne() + } + pk.Domain[0].FFTInverse(pk.Ql, fft.DIF) pk.Domain[0].FFTInverse(pk.Qr, fft.DIF) pk.Domain[0].FFTInverse(pk.Qm, fft.DIF) pk.Domain[0].FFTInverse(pk.Qo, fft.DIF) pk.Domain[0].FFTInverse(pk.CQk, fft.DIF) + pk.Domain[0].FFTInverse(pk.QcPrime, fft.DIF) fft.BitReverse(pk.Ql) fft.BitReverse(pk.Qr) fft.BitReverse(pk.Qm) fft.BitReverse(pk.Qo) fft.BitReverse(pk.CQk) + fft.BitReverse(pk.QcPrime) // build permutation. Note: at this stage, the permutation takes in account the placeholders buildPermutation(spr, &pk) @@ -185,6 +195,9 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) if vk.Qm, err = kzg.Commit(pk.Qm, vk.KZGSRS); err != nil { return nil, nil, err } + if vk.QcPrime, err = kzg.Commit(pk.QcPrime, vk.KZGSRS); err != nil { + return nil, nil, err + } if vk.Qo, err = kzg.Commit(pk.Qo, vk.KZGSRS); err != nil { return nil, nil, err } @@ -271,6 +284,7 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { wqriop := iop.NewPolynomial(clone(pk.Qr, pk.Domain[1].Cardinality), canReg) wqmiop := iop.NewPolynomial(clone(pk.Qm, pk.Domain[1].Cardinality), canReg) wqoiop := iop.NewPolynomial(clone(pk.Qo, pk.Domain[1].Cardinality), canReg) + wqcpiop := iop.NewPolynomial(clone(pk.QcPrime, pk.Domain[1].Cardinality), canReg) ws1 := iop.NewPolynomial(clone(pk.S1Canonical, pk.Domain[1].Cardinality), canReg) ws2 := iop.NewPolynomial(clone(pk.S2Canonical, pk.Domain[1].Cardinality), canReg) @@ -280,6 +294,7 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { wqriop.ToLagrangeCoset(&pk.Domain[1]) wqmiop.ToLagrangeCoset(&pk.Domain[1]) wqoiop.ToLagrangeCoset(&pk.Domain[1]) + wqcpiop.ToLagrangeCoset(&pk.Domain[1]) ws1.ToLagrangeCoset(&pk.Domain[1]) ws2.ToLagrangeCoset(&pk.Domain[1]) @@ -289,6 +304,7 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { pk.lQr = wqriop.Coefficients() pk.lQm = wqmiop.Coefficients() pk.lQo = wqoiop.Coefficients() + pk.lQcPrime = wqcpiop.Coefficients() pk.lS1LagrangeCoset = ws1.Coefficients() pk.lS2LagrangeCoset = ws2.Coefficients() @@ -370,7 +386,7 @@ func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { // This should be used after deserializing a VerifyingKey // as vk.KZG is NOT serialized // -// Note that this instantiate a new FFT domain using vk.Size +// Note that this instantiates a new FFT domain using vk.Size func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { _srs := srs.(*kzg.SRS) diff --git a/internal/backend/bw6-633/plonk/setup.go b/internal/backend/bw6-633/plonk/setup.go index 4e6d650887..03a48ed8f0 100644 --- a/internal/backend/bw6-633/plonk/setup.go +++ b/internal/backend/bw6-633/plonk/setup.go @@ -41,11 +41,11 @@ type ProvingKey struct { // TODO store iop.Polynomial here, not []fr.Element for more "type safety" - // qr,ql,qm,qo (in canonical basis). - Ql, Qr, Qm, Qo []fr.Element + // qr,ql,qm,qo,cqp (in canonical basis). + Ql, Qr, Qm, Qo, QcPrime []fr.Element - // qr,ql,qm,qo (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. - lQl, lQr, lQm, lQo []fr.Element + // qr,ql,qm,qo,qcp (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. + lQl, lQr, lQm, lQo, lQcPrime []fr.Element // LQk (CQk) qk in Lagrange basis (canonical basis), prepended with as many zeroes as public inputs. // Storing LQk in Lagrange basis saves a fft... @@ -90,7 +90,9 @@ type VerifyingKey struct { // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk kzg.Digest + Ql, Qr, Qm, Qo, Qk, QcPrime kzg.Digest + + CommitmentInfo constraint.Commitment } // Setup sets proving and verifying keys @@ -100,6 +102,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // The verifying key shares data with the proving key pk.Vk = &vk + vk.CommitmentInfo = spr.CommitmentInfo nbConstraints := len(spr.Constraints) @@ -126,15 +129,16 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } - // public polynomials corresponding to constraints: [ placholders | constraints | assertions ] + // public polynomials corresponding to constraints: [ placeholders | constraints | assertions ] pk.Ql = make([]fr.Element, pk.Domain[0].Cardinality) pk.Qr = make([]fr.Element, pk.Domain[0].Cardinality) pk.Qm = make([]fr.Element, pk.Domain[0].Cardinality) + pk.QcPrime = make([]fr.Element, pk.Domain[0].Cardinality) pk.Qo = make([]fr.Element, pk.Domain[0].Cardinality) pk.CQk = make([]fr.Element, pk.Domain[0].Cardinality) pk.LQk = make([]fr.Element, pk.Domain[0].Cardinality) - for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistant + for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent pk.Ql[i].SetOne().Neg(&pk.Ql[i]) pk.Qr[i].SetZero() pk.Qm[i].SetZero() @@ -154,16 +158,22 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) pk.LQk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } + for _, committed := range spr.CommitmentInfo.Committed { + pk.QcPrime[committed].SetOne() + } + pk.Domain[0].FFTInverse(pk.Ql, fft.DIF) pk.Domain[0].FFTInverse(pk.Qr, fft.DIF) pk.Domain[0].FFTInverse(pk.Qm, fft.DIF) pk.Domain[0].FFTInverse(pk.Qo, fft.DIF) pk.Domain[0].FFTInverse(pk.CQk, fft.DIF) + pk.Domain[0].FFTInverse(pk.QcPrime, fft.DIF) fft.BitReverse(pk.Ql) fft.BitReverse(pk.Qr) fft.BitReverse(pk.Qm) fft.BitReverse(pk.Qo) fft.BitReverse(pk.CQk) + fft.BitReverse(pk.QcPrime) // build permutation. Note: at this stage, the permutation takes in account the placeholders buildPermutation(spr, &pk) @@ -185,6 +195,9 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) if vk.Qm, err = kzg.Commit(pk.Qm, vk.KZGSRS); err != nil { return nil, nil, err } + if vk.QcPrime, err = kzg.Commit(pk.QcPrime, vk.KZGSRS); err != nil { + return nil, nil, err + } if vk.Qo, err = kzg.Commit(pk.Qo, vk.KZGSRS); err != nil { return nil, nil, err } @@ -271,6 +284,7 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { wqriop := iop.NewPolynomial(clone(pk.Qr, pk.Domain[1].Cardinality), canReg) wqmiop := iop.NewPolynomial(clone(pk.Qm, pk.Domain[1].Cardinality), canReg) wqoiop := iop.NewPolynomial(clone(pk.Qo, pk.Domain[1].Cardinality), canReg) + wqcpiop := iop.NewPolynomial(clone(pk.QcPrime, pk.Domain[1].Cardinality), canReg) ws1 := iop.NewPolynomial(clone(pk.S1Canonical, pk.Domain[1].Cardinality), canReg) ws2 := iop.NewPolynomial(clone(pk.S2Canonical, pk.Domain[1].Cardinality), canReg) @@ -280,6 +294,7 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { wqriop.ToLagrangeCoset(&pk.Domain[1]) wqmiop.ToLagrangeCoset(&pk.Domain[1]) wqoiop.ToLagrangeCoset(&pk.Domain[1]) + wqcpiop.ToLagrangeCoset(&pk.Domain[1]) ws1.ToLagrangeCoset(&pk.Domain[1]) ws2.ToLagrangeCoset(&pk.Domain[1]) @@ -289,6 +304,7 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { pk.lQr = wqriop.Coefficients() pk.lQm = wqmiop.Coefficients() pk.lQo = wqoiop.Coefficients() + pk.lQcPrime = wqcpiop.Coefficients() pk.lS1LagrangeCoset = ws1.Coefficients() pk.lS2LagrangeCoset = ws2.Coefficients() @@ -370,7 +386,7 @@ func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { // This should be used after deserializing a VerifyingKey // as vk.KZG is NOT serialized // -// Note that this instantiate a new FFT domain using vk.Size +// Note that this instantiates a new FFT domain using vk.Size func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { _srs := srs.(*kzg.SRS) diff --git a/internal/backend/bw6-761/plonk/setup.go b/internal/backend/bw6-761/plonk/setup.go index 096aba6f95..8dda20e8dc 100644 --- a/internal/backend/bw6-761/plonk/setup.go +++ b/internal/backend/bw6-761/plonk/setup.go @@ -41,11 +41,11 @@ type ProvingKey struct { // TODO store iop.Polynomial here, not []fr.Element for more "type safety" - // qr,ql,qm,qo (in canonical basis). - Ql, Qr, Qm, Qo []fr.Element + // qr,ql,qm,qo,cqp (in canonical basis). + Ql, Qr, Qm, Qo, QcPrime []fr.Element - // qr,ql,qm,qo (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. - lQl, lQr, lQm, lQo []fr.Element + // qr,ql,qm,qo,qcp (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. + lQl, lQr, lQm, lQo, lQcPrime []fr.Element // LQk (CQk) qk in Lagrange basis (canonical basis), prepended with as many zeroes as public inputs. // Storing LQk in Lagrange basis saves a fft... @@ -90,7 +90,9 @@ type VerifyingKey struct { // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk kzg.Digest + Ql, Qr, Qm, Qo, Qk, QcPrime kzg.Digest + + CommitmentInfo constraint.Commitment } // Setup sets proving and verifying keys @@ -100,6 +102,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // The verifying key shares data with the proving key pk.Vk = &vk + vk.CommitmentInfo = spr.CommitmentInfo nbConstraints := len(spr.Constraints) @@ -126,15 +129,16 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } - // public polynomials corresponding to constraints: [ placholders | constraints | assertions ] + // public polynomials corresponding to constraints: [ placeholders | constraints | assertions ] pk.Ql = make([]fr.Element, pk.Domain[0].Cardinality) pk.Qr = make([]fr.Element, pk.Domain[0].Cardinality) pk.Qm = make([]fr.Element, pk.Domain[0].Cardinality) + pk.QcPrime = make([]fr.Element, pk.Domain[0].Cardinality) pk.Qo = make([]fr.Element, pk.Domain[0].Cardinality) pk.CQk = make([]fr.Element, pk.Domain[0].Cardinality) pk.LQk = make([]fr.Element, pk.Domain[0].Cardinality) - for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistant + for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent pk.Ql[i].SetOne().Neg(&pk.Ql[i]) pk.Qr[i].SetZero() pk.Qm[i].SetZero() @@ -154,16 +158,22 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) pk.LQk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } + for _, committed := range spr.CommitmentInfo.Committed { + pk.QcPrime[committed].SetOne() + } + pk.Domain[0].FFTInverse(pk.Ql, fft.DIF) pk.Domain[0].FFTInverse(pk.Qr, fft.DIF) pk.Domain[0].FFTInverse(pk.Qm, fft.DIF) pk.Domain[0].FFTInverse(pk.Qo, fft.DIF) pk.Domain[0].FFTInverse(pk.CQk, fft.DIF) + pk.Domain[0].FFTInverse(pk.QcPrime, fft.DIF) fft.BitReverse(pk.Ql) fft.BitReverse(pk.Qr) fft.BitReverse(pk.Qm) fft.BitReverse(pk.Qo) fft.BitReverse(pk.CQk) + fft.BitReverse(pk.QcPrime) // build permutation. Note: at this stage, the permutation takes in account the placeholders buildPermutation(spr, &pk) @@ -185,6 +195,9 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) if vk.Qm, err = kzg.Commit(pk.Qm, vk.KZGSRS); err != nil { return nil, nil, err } + if vk.QcPrime, err = kzg.Commit(pk.QcPrime, vk.KZGSRS); err != nil { + return nil, nil, err + } if vk.Qo, err = kzg.Commit(pk.Qo, vk.KZGSRS); err != nil { return nil, nil, err } @@ -271,6 +284,7 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { wqriop := iop.NewPolynomial(clone(pk.Qr, pk.Domain[1].Cardinality), canReg) wqmiop := iop.NewPolynomial(clone(pk.Qm, pk.Domain[1].Cardinality), canReg) wqoiop := iop.NewPolynomial(clone(pk.Qo, pk.Domain[1].Cardinality), canReg) + wqcpiop := iop.NewPolynomial(clone(pk.QcPrime, pk.Domain[1].Cardinality), canReg) ws1 := iop.NewPolynomial(clone(pk.S1Canonical, pk.Domain[1].Cardinality), canReg) ws2 := iop.NewPolynomial(clone(pk.S2Canonical, pk.Domain[1].Cardinality), canReg) @@ -280,6 +294,7 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { wqriop.ToLagrangeCoset(&pk.Domain[1]) wqmiop.ToLagrangeCoset(&pk.Domain[1]) wqoiop.ToLagrangeCoset(&pk.Domain[1]) + wqcpiop.ToLagrangeCoset(&pk.Domain[1]) ws1.ToLagrangeCoset(&pk.Domain[1]) ws2.ToLagrangeCoset(&pk.Domain[1]) @@ -289,6 +304,7 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { pk.lQr = wqriop.Coefficients() pk.lQm = wqmiop.Coefficients() pk.lQo = wqoiop.Coefficients() + pk.lQcPrime = wqcpiop.Coefficients() pk.lS1LagrangeCoset = ws1.Coefficients() pk.lS2LagrangeCoset = ws2.Coefficients() @@ -370,7 +386,7 @@ func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { // This should be used after deserializing a VerifyingKey // as vk.KZG is NOT serialized // -// Note that this instantiate a new FFT domain using vk.Size +// Note that this instantiates a new FFT domain using vk.Size func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { _srs := srs.(*kzg.SRS) diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl index 810078c132..1e6c44129e 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl @@ -23,11 +23,11 @@ type ProvingKey struct { // TODO store iop.Polynomial here, not []fr.Element for more "type safety" - // qr,ql,qm,qo (in canonical basis). - Ql, Qr, Qm, Qo []fr.Element + // qr,ql,qm,qo,cqp (in canonical basis). + Ql, Qr, Qm, Qo, QcPrime []fr.Element - // qr,ql,qm,qo (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. - lQl, lQr, lQm, lQo []fr.Element + // qr,ql,qm,qo,qcp (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. + lQl, lQr, lQm, lQo, lQcPrime []fr.Element // LQk (CQk) qk in Lagrange basis (canonical basis), prepended with as many zeroes as public inputs. // Storing LQk in Lagrange basis saves a fft... @@ -72,7 +72,9 @@ type VerifyingKey struct { // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk kzg.Digest + Ql, Qr, Qm, Qo, Qk, QcPrime kzg.Digest + + CommitmentInfo constraint.Commitment } // Setup sets proving and verifying keys @@ -82,6 +84,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // The verifying key shares data with the proving key pk.Vk = &vk + vk.CommitmentInfo = spr.CommitmentInfo nbConstraints := len(spr.Constraints) @@ -108,15 +111,16 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } - // public polynomials corresponding to constraints: [ placholders | constraints | assertions ] + // public polynomials corresponding to constraints: [ placeholders | constraints | assertions ] pk.Ql = make([]fr.Element, pk.Domain[0].Cardinality) pk.Qr = make([]fr.Element, pk.Domain[0].Cardinality) pk.Qm = make([]fr.Element, pk.Domain[0].Cardinality) + pk.QcPrime = make([]fr.Element, pk.Domain[0].Cardinality) pk.Qo = make([]fr.Element, pk.Domain[0].Cardinality) pk.CQk = make([]fr.Element, pk.Domain[0].Cardinality) pk.LQk = make([]fr.Element, pk.Domain[0].Cardinality) - for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistant + for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent pk.Ql[i].SetOne().Neg(&pk.Ql[i]) pk.Qr[i].SetZero() pk.Qm[i].SetZero() @@ -136,16 +140,22 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) pk.LQk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } + for _, committed := range spr.CommitmentInfo.Committed { + pk.QcPrime[committed].SetOne() + } + pk.Domain[0].FFTInverse(pk.Ql, fft.DIF) pk.Domain[0].FFTInverse(pk.Qr, fft.DIF) pk.Domain[0].FFTInverse(pk.Qm, fft.DIF) pk.Domain[0].FFTInverse(pk.Qo, fft.DIF) pk.Domain[0].FFTInverse(pk.CQk, fft.DIF) + pk.Domain[0].FFTInverse(pk.QcPrime, fft.DIF) fft.BitReverse(pk.Ql) fft.BitReverse(pk.Qr) fft.BitReverse(pk.Qm) fft.BitReverse(pk.Qo) fft.BitReverse(pk.CQk) + fft.BitReverse(pk.QcPrime) // build permutation. Note: at this stage, the permutation takes in account the placeholders buildPermutation(spr, &pk) @@ -167,6 +177,9 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) if vk.Qm, err = kzg.Commit(pk.Qm, vk.KZGSRS); err != nil { return nil, nil, err } + if vk.QcPrime, err = kzg.Commit(pk.QcPrime, vk.KZGSRS); err != nil { + return nil, nil, err + } if vk.Qo, err = kzg.Commit(pk.Qo, vk.KZGSRS); err != nil { return nil, nil, err } @@ -253,6 +266,7 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { wqriop := iop.NewPolynomial(clone(pk.Qr, pk.Domain[1].Cardinality), canReg) wqmiop := iop.NewPolynomial(clone(pk.Qm, pk.Domain[1].Cardinality), canReg) wqoiop := iop.NewPolynomial(clone(pk.Qo, pk.Domain[1].Cardinality), canReg) + wqcpiop := iop.NewPolynomial(clone(pk.QcPrime, pk.Domain[1].Cardinality), canReg) ws1 := iop.NewPolynomial(clone(pk.S1Canonical, pk.Domain[1].Cardinality), canReg) ws2 := iop.NewPolynomial(clone(pk.S2Canonical, pk.Domain[1].Cardinality), canReg) @@ -262,6 +276,7 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { wqriop.ToLagrangeCoset(&pk.Domain[1]) wqmiop.ToLagrangeCoset(&pk.Domain[1]) wqoiop.ToLagrangeCoset(&pk.Domain[1]) + wqcpiop.ToLagrangeCoset(&pk.Domain[1]) ws1.ToLagrangeCoset(&pk.Domain[1]) ws2.ToLagrangeCoset(&pk.Domain[1]) @@ -271,6 +286,7 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { pk.lQr = wqriop.Coefficients() pk.lQm = wqmiop.Coefficients() pk.lQo = wqoiop.Coefficients() + pk.lQcPrime = wqcpiop.Coefficients() pk.lS1LagrangeCoset = ws1.Coefficients() pk.lS2LagrangeCoset = ws2.Coefficients() @@ -349,7 +365,7 @@ func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { // This should be used after deserializing a VerifyingKey // as vk.KZG is NOT serialized // -// Note that this instantiate a new FFT domain using vk.Size +// Note that this instantiates a new FFT domain using vk.Size func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { _srs := srs.(*kzg.SRS) From 34efb7267793156ceb98b898870937788f7f33cf Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 17 Mar 2023 14:02:12 -0400 Subject: [PATCH 160/464] build: generify prover changes --- internal/backend/bls12-377/plonk/prove.go | 109 ++++++++++++----- internal/backend/bls12-381/plonk/prove.go | 109 ++++++++++++----- internal/backend/bls24-315/plonk/prove.go | 109 ++++++++++++----- internal/backend/bls24-317/plonk/prove.go | 109 ++++++++++++----- internal/backend/bn254/plonk/prove.go | 16 ++- internal/backend/bw6-633/plonk/prove.go | 109 ++++++++++++----- internal/backend/bw6-761/plonk/prove.go | 109 ++++++++++++----- .../zkpschemes/plonk/plonk.prove.go.tmpl | 110 +++++++++++++----- 8 files changed, 575 insertions(+), 205 deletions(-) diff --git a/internal/backend/bls12-377/plonk/prove.go b/internal/backend/bls12-377/plonk/prove.go index 7347d6f861..b92b5df144 100644 --- a/internal/backend/bls12-377/plonk/prove.go +++ b/internal/backend/bls12-377/plonk/prove.go @@ -38,6 +38,7 @@ import ( "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" ) @@ -53,7 +54,10 @@ type Proof struct { // Commitments to h1, h2, h3 such that h = h1 + Xh2 + X**2h3 is the quotient polynomial H [3]kzg.Digest - // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2 + // PI2, the BSB22 commitment + PI2 kzg.Digest + + // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2, qCPrime BatchedProof kzg.BatchOpeningProof // Opening proof of Z at zeta*mu @@ -78,6 +82,45 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // result proof := &Proof{} + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + var ( + wpi2iop *iop.Polynomial // canonical + commitmentVal fr.Element // TODO @Tabaie get rid of this + ) + if spr.CommitmentInfo.Is() { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo.HintID, func(_ *big.Int, ins, outs []*big.Int) error { + pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + for i := range ins { + pi2[spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) + } + var ( + err error + hashRes []fr.Element + ) + if _, err = pi2[spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { + return err + } + pi2iop := iop.NewPolynomial(&pi2, lagReg) + wpi2iop = pi2iop.ShallowClone() + wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err + } + if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + return err + } + commitmentVal = hashRes[0] // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses + commitmentVal.BigInt(outs[0]) + return nil + })) + } else { + // TODO Leaving pi2 in for testing. In the future, bypass when no commitment present + pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + + pi2iop := iop.NewPolynomial(&pi2, lagReg) + wpi2iop = pi2iop.ShallowClone() + wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + } // query l, r, o in Lagrange basis, not blinded _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) @@ -89,7 +132,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts evaluationRDomainSmall := []fr.Element(solution.R) evaluationODomainSmall := []fr.Element(solution.O) - lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} liop := iop.NewPolynomial(&evaluationLDomainSmall, lagReg) riop := iop.NewPolynomial(&evaluationRDomainSmall, lagReg) oiop := iop.NewPolynomial(&evaluationODomainSmall, lagReg) @@ -120,7 +162,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)]); err != nil { return nil, err } - gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) + gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) // TODO @Tabaie @ThomasPiellard add BSB commitment here? if err != nil { return nil, err } @@ -171,13 +213,17 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, pk.Domain[0].Cardinality) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], pk.LQk[len(spr.Public):]) + if spr.CommitmentInfo.Is() { + qkCompletedCanonical[spr.CommitmentInfo.CommitmentIndex] = commitmentVal + } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) - // l, r, o are blinded here + // l, r, o are already blinded bwliop.ToLagrangeCoset(&pk.Domain[1]) bwriop.ToLagrangeCoset(&pk.Domain[1]) bwoiop.ToLagrangeCoset(&pk.Domain[1]) + pi2iop := wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form lagrangeCosetBitReversed := iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse} @@ -186,6 +232,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wqriop := iop.NewPolynomial(&pk.lQr, lagrangeCosetBitReversed) wqmiop := iop.NewPolynomial(&pk.lQm, lagrangeCosetBitReversed) wqoiop := iop.NewPolynomial(&pk.lQo, lagrangeCosetBitReversed) + wqcpiop := iop.NewPolynomial(&pk.lQcPrime, lagrangeCosetBitReversed) // lagrange coset form canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} wqkiop := iop.NewPolynomial(&qkCompletedCanonical, canReg) @@ -220,7 +267,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ToLagrangeCoset(&pk.Domain[1]) // Full capture using latest gnark crypto... - fic := func(fql, fqr, fqm, fqo, fqk, l, r, o fr.Element) fr.Element { + fic := func(fql, fqr, fqm, fqo, fqk, fqCPrime, l, r, o, pi2 fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary var ic, tmp fr.Element @@ -231,6 +278,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ic.Add(&ic, &tmp) tmp.Mul(&fqo, &o) ic.Add(&ic, &tmp).Add(&ic, &fqk) + tmp.Mul(&fqCPrime, &pi2) + ic.Add(&ic, &tmp) return ic } @@ -264,13 +313,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return one } - // 0 , 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 - // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk,lone + // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15 , 16 + // l , r , o, id, s1, s2, s3, z, zs, PI2, ql, qr, qm, qo, qk, qCPrime, lone fm := func(x ...fr.Element) fr.Element { - a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2]) + a := fic(x[10], x[11], x[12], x[13], x[14], x[15], x[0], x[1], x[2], x[9]) b := fo(x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8]) - c := fone(x[7], x[14]) + c := fone(x[7], x[16]) c.Mul(&c, &alpha).Add(&c, &b).Mul(&c, &alpha).Add(&c, &a) @@ -286,17 +335,19 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ws3, bwziop, bwsziop, + pi2iop, wqliop, wqriop, wqmiop, wqoiop, wqkiop, + wqcpiop, wloneiop, ) if err != nil { return nil, err } - h, err := iop.DivideByXMinusOne(testEval, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) + h, err := iop.DivideByXMinusOne(testEval, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) // TODO Rename to DivideByXNMinusOne or DivideByVanishingPoly etc if err != nil { return nil, err } @@ -316,27 +367,22 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } - // compute evaluations of (blinded version of) l, r, o, z at zeta - var blzeta, brzeta, bozeta fr.Element + // compute evaluations of (blinded version of) l, r, o, z, qCPrime at zeta + var blzeta, brzeta, bozeta, qcpzeta fr.Element var wgEvals sync.WaitGroup - wgEvals.Add(3) - - go func() { - bwliop.ToCanonical(&pk.Domain[1]).ToRegular() - blzeta = bwliop.Evaluate(zeta) - wgEvals.Done() - }() - - go func() { - bwriop.ToCanonical(&pk.Domain[1]).ToRegular() - brzeta = bwriop.Evaluate(zeta) + wgEvals.Add(4) + evalAtZeta := func(poly *iop.Polynomial, res *fr.Element) { + poly.ToCanonical(&pk.Domain[1]).ToRegular() + *res = poly.Evaluate(zeta) wgEvals.Done() - }() - + } + go evalAtZeta(bwliop, &blzeta) + go evalAtZeta(bwriop, &brzeta) + go evalAtZeta(bwoiop, &bozeta) go func() { - bwoiop.ToCanonical(&pk.Domain[1]).ToRegular() - bozeta = bwoiop.Evaluate(zeta) + qcpiop := iop.NewPolynomial(&pk.QcPrime, canReg) + qcpzeta = qcpiop.Evaluate(zeta) wgEvals.Done() }() @@ -375,7 +421,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts gamma, zeta, bzuzeta, + qcpzeta, bwziop.Coefficients()[:bwziop.BlindedSize()], + wpi2iop.Coefficients(), pk, ) @@ -422,6 +470,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.Coefficients()[:bwoiop.BlindedSize()], pk.S1Canonical, pk.S2Canonical, + pk.QcPrime, }, []kzg.Digest{ foldedHDigest, @@ -431,6 +480,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.LRO[2], pk.Vk.S[0], pk.Vk.S[1], + pk.Vk.QcPrime, }, zeta, hFunc, @@ -511,7 +561,7 @@ func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error // α²*L₁(ζ)*Z(X) // + α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*id1(ζ)+γ)*(r(ζ)+β*id2(ζ)+γ)*(o(ζ)+β*id3(ζ)+γ)) // + l(ζ)*Ql(X) + l(ζ)r(ζ)*Qm(X) + r(ζ)*Qr(X) + o(ζ)*Qo(X) + Qk(X) -func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu fr.Element, blindedZCanonical []fr.Element, pk *ProvingKey) []fr.Element { +func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu, qcpZeta fr.Element, blindedZCanonical []fr.Element, pi2Canonical []fr.Element, pk *ProvingKey) []fr.Element { // first part: individual constraints var rl fr.Element @@ -591,6 +641,9 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, t0.Mul(&pk.Qo[i], &oZeta).Add(&t0, &pk.CQk[i]) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) + + t0.Mul(&pi2Canonical[i], &qcpZeta) + linPol[i].Add(&linPol[i], &t0) } t0.Mul(&blindedZCanonical[i], &lagrangeZeta) diff --git a/internal/backend/bls12-381/plonk/prove.go b/internal/backend/bls12-381/plonk/prove.go index 98267ceee0..e167f70bc4 100644 --- a/internal/backend/bls12-381/plonk/prove.go +++ b/internal/backend/bls12-381/plonk/prove.go @@ -38,6 +38,7 @@ import ( "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" ) @@ -53,7 +54,10 @@ type Proof struct { // Commitments to h1, h2, h3 such that h = h1 + Xh2 + X**2h3 is the quotient polynomial H [3]kzg.Digest - // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2 + // PI2, the BSB22 commitment + PI2 kzg.Digest + + // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2, qCPrime BatchedProof kzg.BatchOpeningProof // Opening proof of Z at zeta*mu @@ -78,6 +82,45 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // result proof := &Proof{} + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + var ( + wpi2iop *iop.Polynomial // canonical + commitmentVal fr.Element // TODO @Tabaie get rid of this + ) + if spr.CommitmentInfo.Is() { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo.HintID, func(_ *big.Int, ins, outs []*big.Int) error { + pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + for i := range ins { + pi2[spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) + } + var ( + err error + hashRes []fr.Element + ) + if _, err = pi2[spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { + return err + } + pi2iop := iop.NewPolynomial(&pi2, lagReg) + wpi2iop = pi2iop.ShallowClone() + wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err + } + if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + return err + } + commitmentVal = hashRes[0] // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses + commitmentVal.BigInt(outs[0]) + return nil + })) + } else { + // TODO Leaving pi2 in for testing. In the future, bypass when no commitment present + pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + + pi2iop := iop.NewPolynomial(&pi2, lagReg) + wpi2iop = pi2iop.ShallowClone() + wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + } // query l, r, o in Lagrange basis, not blinded _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) @@ -89,7 +132,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts evaluationRDomainSmall := []fr.Element(solution.R) evaluationODomainSmall := []fr.Element(solution.O) - lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} liop := iop.NewPolynomial(&evaluationLDomainSmall, lagReg) riop := iop.NewPolynomial(&evaluationRDomainSmall, lagReg) oiop := iop.NewPolynomial(&evaluationODomainSmall, lagReg) @@ -120,7 +162,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)]); err != nil { return nil, err } - gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) + gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) // TODO @Tabaie @ThomasPiellard add BSB commitment here? if err != nil { return nil, err } @@ -171,13 +213,17 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, pk.Domain[0].Cardinality) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], pk.LQk[len(spr.Public):]) + if spr.CommitmentInfo.Is() { + qkCompletedCanonical[spr.CommitmentInfo.CommitmentIndex] = commitmentVal + } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) - // l, r, o are blinded here + // l, r, o are already blinded bwliop.ToLagrangeCoset(&pk.Domain[1]) bwriop.ToLagrangeCoset(&pk.Domain[1]) bwoiop.ToLagrangeCoset(&pk.Domain[1]) + pi2iop := wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form lagrangeCosetBitReversed := iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse} @@ -186,6 +232,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wqriop := iop.NewPolynomial(&pk.lQr, lagrangeCosetBitReversed) wqmiop := iop.NewPolynomial(&pk.lQm, lagrangeCosetBitReversed) wqoiop := iop.NewPolynomial(&pk.lQo, lagrangeCosetBitReversed) + wqcpiop := iop.NewPolynomial(&pk.lQcPrime, lagrangeCosetBitReversed) // lagrange coset form canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} wqkiop := iop.NewPolynomial(&qkCompletedCanonical, canReg) @@ -220,7 +267,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ToLagrangeCoset(&pk.Domain[1]) // Full capture using latest gnark crypto... - fic := func(fql, fqr, fqm, fqo, fqk, l, r, o fr.Element) fr.Element { + fic := func(fql, fqr, fqm, fqo, fqk, fqCPrime, l, r, o, pi2 fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary var ic, tmp fr.Element @@ -231,6 +278,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ic.Add(&ic, &tmp) tmp.Mul(&fqo, &o) ic.Add(&ic, &tmp).Add(&ic, &fqk) + tmp.Mul(&fqCPrime, &pi2) + ic.Add(&ic, &tmp) return ic } @@ -264,13 +313,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return one } - // 0 , 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 - // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk,lone + // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15 , 16 + // l , r , o, id, s1, s2, s3, z, zs, PI2, ql, qr, qm, qo, qk, qCPrime, lone fm := func(x ...fr.Element) fr.Element { - a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2]) + a := fic(x[10], x[11], x[12], x[13], x[14], x[15], x[0], x[1], x[2], x[9]) b := fo(x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8]) - c := fone(x[7], x[14]) + c := fone(x[7], x[16]) c.Mul(&c, &alpha).Add(&c, &b).Mul(&c, &alpha).Add(&c, &a) @@ -286,17 +335,19 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ws3, bwziop, bwsziop, + pi2iop, wqliop, wqriop, wqmiop, wqoiop, wqkiop, + wqcpiop, wloneiop, ) if err != nil { return nil, err } - h, err := iop.DivideByXMinusOne(testEval, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) + h, err := iop.DivideByXMinusOne(testEval, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) // TODO Rename to DivideByXNMinusOne or DivideByVanishingPoly etc if err != nil { return nil, err } @@ -316,27 +367,22 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } - // compute evaluations of (blinded version of) l, r, o, z at zeta - var blzeta, brzeta, bozeta fr.Element + // compute evaluations of (blinded version of) l, r, o, z, qCPrime at zeta + var blzeta, brzeta, bozeta, qcpzeta fr.Element var wgEvals sync.WaitGroup - wgEvals.Add(3) - - go func() { - bwliop.ToCanonical(&pk.Domain[1]).ToRegular() - blzeta = bwliop.Evaluate(zeta) - wgEvals.Done() - }() - - go func() { - bwriop.ToCanonical(&pk.Domain[1]).ToRegular() - brzeta = bwriop.Evaluate(zeta) + wgEvals.Add(4) + evalAtZeta := func(poly *iop.Polynomial, res *fr.Element) { + poly.ToCanonical(&pk.Domain[1]).ToRegular() + *res = poly.Evaluate(zeta) wgEvals.Done() - }() - + } + go evalAtZeta(bwliop, &blzeta) + go evalAtZeta(bwriop, &brzeta) + go evalAtZeta(bwoiop, &bozeta) go func() { - bwoiop.ToCanonical(&pk.Domain[1]).ToRegular() - bozeta = bwoiop.Evaluate(zeta) + qcpiop := iop.NewPolynomial(&pk.QcPrime, canReg) + qcpzeta = qcpiop.Evaluate(zeta) wgEvals.Done() }() @@ -375,7 +421,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts gamma, zeta, bzuzeta, + qcpzeta, bwziop.Coefficients()[:bwziop.BlindedSize()], + wpi2iop.Coefficients(), pk, ) @@ -422,6 +470,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.Coefficients()[:bwoiop.BlindedSize()], pk.S1Canonical, pk.S2Canonical, + pk.QcPrime, }, []kzg.Digest{ foldedHDigest, @@ -431,6 +480,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.LRO[2], pk.Vk.S[0], pk.Vk.S[1], + pk.Vk.QcPrime, }, zeta, hFunc, @@ -511,7 +561,7 @@ func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error // α²*L₁(ζ)*Z(X) // + α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*id1(ζ)+γ)*(r(ζ)+β*id2(ζ)+γ)*(o(ζ)+β*id3(ζ)+γ)) // + l(ζ)*Ql(X) + l(ζ)r(ζ)*Qm(X) + r(ζ)*Qr(X) + o(ζ)*Qo(X) + Qk(X) -func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu fr.Element, blindedZCanonical []fr.Element, pk *ProvingKey) []fr.Element { +func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu, qcpZeta fr.Element, blindedZCanonical []fr.Element, pi2Canonical []fr.Element, pk *ProvingKey) []fr.Element { // first part: individual constraints var rl fr.Element @@ -591,6 +641,9 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, t0.Mul(&pk.Qo[i], &oZeta).Add(&t0, &pk.CQk[i]) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) + + t0.Mul(&pi2Canonical[i], &qcpZeta) + linPol[i].Add(&linPol[i], &t0) } t0.Mul(&blindedZCanonical[i], &lagrangeZeta) diff --git a/internal/backend/bls24-315/plonk/prove.go b/internal/backend/bls24-315/plonk/prove.go index dcff52621b..d3b13d8d82 100644 --- a/internal/backend/bls24-315/plonk/prove.go +++ b/internal/backend/bls24-315/plonk/prove.go @@ -38,6 +38,7 @@ import ( "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" ) @@ -53,7 +54,10 @@ type Proof struct { // Commitments to h1, h2, h3 such that h = h1 + Xh2 + X**2h3 is the quotient polynomial H [3]kzg.Digest - // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2 + // PI2, the BSB22 commitment + PI2 kzg.Digest + + // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2, qCPrime BatchedProof kzg.BatchOpeningProof // Opening proof of Z at zeta*mu @@ -78,6 +82,45 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // result proof := &Proof{} + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + var ( + wpi2iop *iop.Polynomial // canonical + commitmentVal fr.Element // TODO @Tabaie get rid of this + ) + if spr.CommitmentInfo.Is() { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo.HintID, func(_ *big.Int, ins, outs []*big.Int) error { + pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + for i := range ins { + pi2[spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) + } + var ( + err error + hashRes []fr.Element + ) + if _, err = pi2[spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { + return err + } + pi2iop := iop.NewPolynomial(&pi2, lagReg) + wpi2iop = pi2iop.ShallowClone() + wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err + } + if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + return err + } + commitmentVal = hashRes[0] // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses + commitmentVal.BigInt(outs[0]) + return nil + })) + } else { + // TODO Leaving pi2 in for testing. In the future, bypass when no commitment present + pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + + pi2iop := iop.NewPolynomial(&pi2, lagReg) + wpi2iop = pi2iop.ShallowClone() + wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + } // query l, r, o in Lagrange basis, not blinded _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) @@ -89,7 +132,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts evaluationRDomainSmall := []fr.Element(solution.R) evaluationODomainSmall := []fr.Element(solution.O) - lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} liop := iop.NewPolynomial(&evaluationLDomainSmall, lagReg) riop := iop.NewPolynomial(&evaluationRDomainSmall, lagReg) oiop := iop.NewPolynomial(&evaluationODomainSmall, lagReg) @@ -120,7 +162,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)]); err != nil { return nil, err } - gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) + gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) // TODO @Tabaie @ThomasPiellard add BSB commitment here? if err != nil { return nil, err } @@ -171,13 +213,17 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, pk.Domain[0].Cardinality) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], pk.LQk[len(spr.Public):]) + if spr.CommitmentInfo.Is() { + qkCompletedCanonical[spr.CommitmentInfo.CommitmentIndex] = commitmentVal + } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) - // l, r, o are blinded here + // l, r, o are already blinded bwliop.ToLagrangeCoset(&pk.Domain[1]) bwriop.ToLagrangeCoset(&pk.Domain[1]) bwoiop.ToLagrangeCoset(&pk.Domain[1]) + pi2iop := wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form lagrangeCosetBitReversed := iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse} @@ -186,6 +232,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wqriop := iop.NewPolynomial(&pk.lQr, lagrangeCosetBitReversed) wqmiop := iop.NewPolynomial(&pk.lQm, lagrangeCosetBitReversed) wqoiop := iop.NewPolynomial(&pk.lQo, lagrangeCosetBitReversed) + wqcpiop := iop.NewPolynomial(&pk.lQcPrime, lagrangeCosetBitReversed) // lagrange coset form canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} wqkiop := iop.NewPolynomial(&qkCompletedCanonical, canReg) @@ -220,7 +267,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ToLagrangeCoset(&pk.Domain[1]) // Full capture using latest gnark crypto... - fic := func(fql, fqr, fqm, fqo, fqk, l, r, o fr.Element) fr.Element { + fic := func(fql, fqr, fqm, fqo, fqk, fqCPrime, l, r, o, pi2 fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary var ic, tmp fr.Element @@ -231,6 +278,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ic.Add(&ic, &tmp) tmp.Mul(&fqo, &o) ic.Add(&ic, &tmp).Add(&ic, &fqk) + tmp.Mul(&fqCPrime, &pi2) + ic.Add(&ic, &tmp) return ic } @@ -264,13 +313,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return one } - // 0 , 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 - // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk,lone + // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15 , 16 + // l , r , o, id, s1, s2, s3, z, zs, PI2, ql, qr, qm, qo, qk, qCPrime, lone fm := func(x ...fr.Element) fr.Element { - a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2]) + a := fic(x[10], x[11], x[12], x[13], x[14], x[15], x[0], x[1], x[2], x[9]) b := fo(x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8]) - c := fone(x[7], x[14]) + c := fone(x[7], x[16]) c.Mul(&c, &alpha).Add(&c, &b).Mul(&c, &alpha).Add(&c, &a) @@ -286,17 +335,19 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ws3, bwziop, bwsziop, + pi2iop, wqliop, wqriop, wqmiop, wqoiop, wqkiop, + wqcpiop, wloneiop, ) if err != nil { return nil, err } - h, err := iop.DivideByXMinusOne(testEval, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) + h, err := iop.DivideByXMinusOne(testEval, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) // TODO Rename to DivideByXNMinusOne or DivideByVanishingPoly etc if err != nil { return nil, err } @@ -316,27 +367,22 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } - // compute evaluations of (blinded version of) l, r, o, z at zeta - var blzeta, brzeta, bozeta fr.Element + // compute evaluations of (blinded version of) l, r, o, z, qCPrime at zeta + var blzeta, brzeta, bozeta, qcpzeta fr.Element var wgEvals sync.WaitGroup - wgEvals.Add(3) - - go func() { - bwliop.ToCanonical(&pk.Domain[1]).ToRegular() - blzeta = bwliop.Evaluate(zeta) - wgEvals.Done() - }() - - go func() { - bwriop.ToCanonical(&pk.Domain[1]).ToRegular() - brzeta = bwriop.Evaluate(zeta) + wgEvals.Add(4) + evalAtZeta := func(poly *iop.Polynomial, res *fr.Element) { + poly.ToCanonical(&pk.Domain[1]).ToRegular() + *res = poly.Evaluate(zeta) wgEvals.Done() - }() - + } + go evalAtZeta(bwliop, &blzeta) + go evalAtZeta(bwriop, &brzeta) + go evalAtZeta(bwoiop, &bozeta) go func() { - bwoiop.ToCanonical(&pk.Domain[1]).ToRegular() - bozeta = bwoiop.Evaluate(zeta) + qcpiop := iop.NewPolynomial(&pk.QcPrime, canReg) + qcpzeta = qcpiop.Evaluate(zeta) wgEvals.Done() }() @@ -375,7 +421,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts gamma, zeta, bzuzeta, + qcpzeta, bwziop.Coefficients()[:bwziop.BlindedSize()], + wpi2iop.Coefficients(), pk, ) @@ -422,6 +470,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.Coefficients()[:bwoiop.BlindedSize()], pk.S1Canonical, pk.S2Canonical, + pk.QcPrime, }, []kzg.Digest{ foldedHDigest, @@ -431,6 +480,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.LRO[2], pk.Vk.S[0], pk.Vk.S[1], + pk.Vk.QcPrime, }, zeta, hFunc, @@ -511,7 +561,7 @@ func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error // α²*L₁(ζ)*Z(X) // + α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*id1(ζ)+γ)*(r(ζ)+β*id2(ζ)+γ)*(o(ζ)+β*id3(ζ)+γ)) // + l(ζ)*Ql(X) + l(ζ)r(ζ)*Qm(X) + r(ζ)*Qr(X) + o(ζ)*Qo(X) + Qk(X) -func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu fr.Element, blindedZCanonical []fr.Element, pk *ProvingKey) []fr.Element { +func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu, qcpZeta fr.Element, blindedZCanonical []fr.Element, pi2Canonical []fr.Element, pk *ProvingKey) []fr.Element { // first part: individual constraints var rl fr.Element @@ -591,6 +641,9 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, t0.Mul(&pk.Qo[i], &oZeta).Add(&t0, &pk.CQk[i]) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) + + t0.Mul(&pi2Canonical[i], &qcpZeta) + linPol[i].Add(&linPol[i], &t0) } t0.Mul(&blindedZCanonical[i], &lagrangeZeta) diff --git a/internal/backend/bls24-317/plonk/prove.go b/internal/backend/bls24-317/plonk/prove.go index 400232aead..34c26a3e35 100644 --- a/internal/backend/bls24-317/plonk/prove.go +++ b/internal/backend/bls24-317/plonk/prove.go @@ -38,6 +38,7 @@ import ( "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" ) @@ -53,7 +54,10 @@ type Proof struct { // Commitments to h1, h2, h3 such that h = h1 + Xh2 + X**2h3 is the quotient polynomial H [3]kzg.Digest - // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2 + // PI2, the BSB22 commitment + PI2 kzg.Digest + + // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2, qCPrime BatchedProof kzg.BatchOpeningProof // Opening proof of Z at zeta*mu @@ -78,6 +82,45 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // result proof := &Proof{} + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + var ( + wpi2iop *iop.Polynomial // canonical + commitmentVal fr.Element // TODO @Tabaie get rid of this + ) + if spr.CommitmentInfo.Is() { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo.HintID, func(_ *big.Int, ins, outs []*big.Int) error { + pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + for i := range ins { + pi2[spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) + } + var ( + err error + hashRes []fr.Element + ) + if _, err = pi2[spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { + return err + } + pi2iop := iop.NewPolynomial(&pi2, lagReg) + wpi2iop = pi2iop.ShallowClone() + wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err + } + if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + return err + } + commitmentVal = hashRes[0] // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses + commitmentVal.BigInt(outs[0]) + return nil + })) + } else { + // TODO Leaving pi2 in for testing. In the future, bypass when no commitment present + pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + + pi2iop := iop.NewPolynomial(&pi2, lagReg) + wpi2iop = pi2iop.ShallowClone() + wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + } // query l, r, o in Lagrange basis, not blinded _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) @@ -89,7 +132,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts evaluationRDomainSmall := []fr.Element(solution.R) evaluationODomainSmall := []fr.Element(solution.O) - lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} liop := iop.NewPolynomial(&evaluationLDomainSmall, lagReg) riop := iop.NewPolynomial(&evaluationRDomainSmall, lagReg) oiop := iop.NewPolynomial(&evaluationODomainSmall, lagReg) @@ -120,7 +162,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)]); err != nil { return nil, err } - gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) + gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) // TODO @Tabaie @ThomasPiellard add BSB commitment here? if err != nil { return nil, err } @@ -171,13 +213,17 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, pk.Domain[0].Cardinality) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], pk.LQk[len(spr.Public):]) + if spr.CommitmentInfo.Is() { + qkCompletedCanonical[spr.CommitmentInfo.CommitmentIndex] = commitmentVal + } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) - // l, r, o are blinded here + // l, r, o are already blinded bwliop.ToLagrangeCoset(&pk.Domain[1]) bwriop.ToLagrangeCoset(&pk.Domain[1]) bwoiop.ToLagrangeCoset(&pk.Domain[1]) + pi2iop := wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form lagrangeCosetBitReversed := iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse} @@ -186,6 +232,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wqriop := iop.NewPolynomial(&pk.lQr, lagrangeCosetBitReversed) wqmiop := iop.NewPolynomial(&pk.lQm, lagrangeCosetBitReversed) wqoiop := iop.NewPolynomial(&pk.lQo, lagrangeCosetBitReversed) + wqcpiop := iop.NewPolynomial(&pk.lQcPrime, lagrangeCosetBitReversed) // lagrange coset form canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} wqkiop := iop.NewPolynomial(&qkCompletedCanonical, canReg) @@ -220,7 +267,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ToLagrangeCoset(&pk.Domain[1]) // Full capture using latest gnark crypto... - fic := func(fql, fqr, fqm, fqo, fqk, l, r, o fr.Element) fr.Element { + fic := func(fql, fqr, fqm, fqo, fqk, fqCPrime, l, r, o, pi2 fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary var ic, tmp fr.Element @@ -231,6 +278,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ic.Add(&ic, &tmp) tmp.Mul(&fqo, &o) ic.Add(&ic, &tmp).Add(&ic, &fqk) + tmp.Mul(&fqCPrime, &pi2) + ic.Add(&ic, &tmp) return ic } @@ -264,13 +313,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return one } - // 0 , 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 - // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk,lone + // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15 , 16 + // l , r , o, id, s1, s2, s3, z, zs, PI2, ql, qr, qm, qo, qk, qCPrime, lone fm := func(x ...fr.Element) fr.Element { - a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2]) + a := fic(x[10], x[11], x[12], x[13], x[14], x[15], x[0], x[1], x[2], x[9]) b := fo(x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8]) - c := fone(x[7], x[14]) + c := fone(x[7], x[16]) c.Mul(&c, &alpha).Add(&c, &b).Mul(&c, &alpha).Add(&c, &a) @@ -286,17 +335,19 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ws3, bwziop, bwsziop, + pi2iop, wqliop, wqriop, wqmiop, wqoiop, wqkiop, + wqcpiop, wloneiop, ) if err != nil { return nil, err } - h, err := iop.DivideByXMinusOne(testEval, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) + h, err := iop.DivideByXMinusOne(testEval, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) // TODO Rename to DivideByXNMinusOne or DivideByVanishingPoly etc if err != nil { return nil, err } @@ -316,27 +367,22 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } - // compute evaluations of (blinded version of) l, r, o, z at zeta - var blzeta, brzeta, bozeta fr.Element + // compute evaluations of (blinded version of) l, r, o, z, qCPrime at zeta + var blzeta, brzeta, bozeta, qcpzeta fr.Element var wgEvals sync.WaitGroup - wgEvals.Add(3) - - go func() { - bwliop.ToCanonical(&pk.Domain[1]).ToRegular() - blzeta = bwliop.Evaluate(zeta) - wgEvals.Done() - }() - - go func() { - bwriop.ToCanonical(&pk.Domain[1]).ToRegular() - brzeta = bwriop.Evaluate(zeta) + wgEvals.Add(4) + evalAtZeta := func(poly *iop.Polynomial, res *fr.Element) { + poly.ToCanonical(&pk.Domain[1]).ToRegular() + *res = poly.Evaluate(zeta) wgEvals.Done() - }() - + } + go evalAtZeta(bwliop, &blzeta) + go evalAtZeta(bwriop, &brzeta) + go evalAtZeta(bwoiop, &bozeta) go func() { - bwoiop.ToCanonical(&pk.Domain[1]).ToRegular() - bozeta = bwoiop.Evaluate(zeta) + qcpiop := iop.NewPolynomial(&pk.QcPrime, canReg) + qcpzeta = qcpiop.Evaluate(zeta) wgEvals.Done() }() @@ -375,7 +421,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts gamma, zeta, bzuzeta, + qcpzeta, bwziop.Coefficients()[:bwziop.BlindedSize()], + wpi2iop.Coefficients(), pk, ) @@ -422,6 +470,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.Coefficients()[:bwoiop.BlindedSize()], pk.S1Canonical, pk.S2Canonical, + pk.QcPrime, }, []kzg.Digest{ foldedHDigest, @@ -431,6 +480,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.LRO[2], pk.Vk.S[0], pk.Vk.S[1], + pk.Vk.QcPrime, }, zeta, hFunc, @@ -511,7 +561,7 @@ func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error // α²*L₁(ζ)*Z(X) // + α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*id1(ζ)+γ)*(r(ζ)+β*id2(ζ)+γ)*(o(ζ)+β*id3(ζ)+γ)) // + l(ζ)*Ql(X) + l(ζ)r(ζ)*Qm(X) + r(ζ)*Qr(X) + o(ζ)*Qo(X) + Qk(X) -func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu fr.Element, blindedZCanonical []fr.Element, pk *ProvingKey) []fr.Element { +func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu, qcpZeta fr.Element, blindedZCanonical []fr.Element, pi2Canonical []fr.Element, pk *ProvingKey) []fr.Element { // first part: individual constraints var rl fr.Element @@ -591,6 +641,9 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, t0.Mul(&pk.Qo[i], &oZeta).Add(&t0, &pk.CQk[i]) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) + + t0.Mul(&pi2Canonical[i], &qcpZeta) + linPol[i].Add(&linPol[i], &t0) } t0.Mul(&blindedZCanonical[i], &lagrangeZeta) diff --git a/internal/backend/bn254/plonk/prove.go b/internal/backend/bn254/plonk/prove.go index 933032ff56..3a12bd59cc 100644 --- a/internal/backend/bn254/plonk/prove.go +++ b/internal/backend/bn254/plonk/prove.go @@ -18,7 +18,6 @@ package plonk import ( "crypto/sha256" - "github.com/consensys/gnark/constraint/solver" "math/big" "runtime" "sync" @@ -39,6 +38,7 @@ import ( "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" ) @@ -335,19 +335,19 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ws3, bwziop, bwsziop, - pi2iop, // TODO @Tabaie correct format + pi2iop, wqliop, wqriop, wqmiop, wqoiop, wqkiop, - wqcpiop, // TODO @Tabaie correct format + wqcpiop, wloneiop, ) if err != nil { return nil, err } - h, err := iop.DivideByXMinusOne(testEval, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) // TODO @Tabaie not x^n - 1? + h, err := iop.DivideByXMinusOne(testEval, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) // TODO Rename to DivideByXNMinusOne or DivideByVanishingPoly etc if err != nil { return nil, err } @@ -381,7 +381,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts go evalAtZeta(bwriop, &brzeta) go evalAtZeta(bwoiop, &bozeta) go func() { - qcpiop := iop.NewPolynomial(&pk.QcPrime, canReg) // TODO @Tabaie canReg correct? + qcpiop := iop.NewPolynomial(&pk.QcPrime, canReg) qcpzeta = qcpiop.Evaluate(zeta) wgEvals.Done() }() @@ -501,7 +501,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { n := runtime.NumCPU() / 2 var err0, err1, err2 error - chCommit0 := make(chan struct{}, 1) // TODO @Tabaie use wait group? + chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) go func() { proof.LRO[0], err0 = kzg.Commit(bcl, srs, n) @@ -550,8 +550,6 @@ func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error return err1 } -// Discuss whether there is a benefit to opening pi2 instead - // computeLinearizedPolynomial computes the linearized polynomial in canonical basis. // The purpose is to commit and open all in one ql, qr, qm, qo, qk. // * lZeta, rZeta, oZeta are the evaluation of l, r, o at zeta @@ -572,7 +570,7 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, // second part: // Z(μζ)(l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*β*s3(X)-Z(X)(l(ζ)+β*id1(ζ)+γ)*(r(ζ)+β*id2(ζ)+γ)*(o(ζ)+β*id3(ζ)+γ) var s1, s2 fr.Element - chS1 := make(chan struct{}, 1) // TODO @Tabaie wait group? + chS1 := make(chan struct{}, 1) go func() { ps1 := iop.NewPolynomial(&pk.S1Canonical, iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) s1 = ps1.Evaluate(zeta) // s1(ζ) diff --git a/internal/backend/bw6-633/plonk/prove.go b/internal/backend/bw6-633/plonk/prove.go index d19ff91d8a..55c7a3c373 100644 --- a/internal/backend/bw6-633/plonk/prove.go +++ b/internal/backend/bw6-633/plonk/prove.go @@ -38,6 +38,7 @@ import ( "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" ) @@ -53,7 +54,10 @@ type Proof struct { // Commitments to h1, h2, h3 such that h = h1 + Xh2 + X**2h3 is the quotient polynomial H [3]kzg.Digest - // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2 + // PI2, the BSB22 commitment + PI2 kzg.Digest + + // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2, qCPrime BatchedProof kzg.BatchOpeningProof // Opening proof of Z at zeta*mu @@ -78,6 +82,45 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // result proof := &Proof{} + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + var ( + wpi2iop *iop.Polynomial // canonical + commitmentVal fr.Element // TODO @Tabaie get rid of this + ) + if spr.CommitmentInfo.Is() { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo.HintID, func(_ *big.Int, ins, outs []*big.Int) error { + pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + for i := range ins { + pi2[spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) + } + var ( + err error + hashRes []fr.Element + ) + if _, err = pi2[spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { + return err + } + pi2iop := iop.NewPolynomial(&pi2, lagReg) + wpi2iop = pi2iop.ShallowClone() + wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err + } + if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + return err + } + commitmentVal = hashRes[0] // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses + commitmentVal.BigInt(outs[0]) + return nil + })) + } else { + // TODO Leaving pi2 in for testing. In the future, bypass when no commitment present + pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + + pi2iop := iop.NewPolynomial(&pi2, lagReg) + wpi2iop = pi2iop.ShallowClone() + wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + } // query l, r, o in Lagrange basis, not blinded _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) @@ -89,7 +132,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts evaluationRDomainSmall := []fr.Element(solution.R) evaluationODomainSmall := []fr.Element(solution.O) - lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} liop := iop.NewPolynomial(&evaluationLDomainSmall, lagReg) riop := iop.NewPolynomial(&evaluationRDomainSmall, lagReg) oiop := iop.NewPolynomial(&evaluationODomainSmall, lagReg) @@ -120,7 +162,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)]); err != nil { return nil, err } - gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) + gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) // TODO @Tabaie @ThomasPiellard add BSB commitment here? if err != nil { return nil, err } @@ -171,13 +213,17 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, pk.Domain[0].Cardinality) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], pk.LQk[len(spr.Public):]) + if spr.CommitmentInfo.Is() { + qkCompletedCanonical[spr.CommitmentInfo.CommitmentIndex] = commitmentVal + } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) - // l, r, o are blinded here + // l, r, o are already blinded bwliop.ToLagrangeCoset(&pk.Domain[1]) bwriop.ToLagrangeCoset(&pk.Domain[1]) bwoiop.ToLagrangeCoset(&pk.Domain[1]) + pi2iop := wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form lagrangeCosetBitReversed := iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse} @@ -186,6 +232,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wqriop := iop.NewPolynomial(&pk.lQr, lagrangeCosetBitReversed) wqmiop := iop.NewPolynomial(&pk.lQm, lagrangeCosetBitReversed) wqoiop := iop.NewPolynomial(&pk.lQo, lagrangeCosetBitReversed) + wqcpiop := iop.NewPolynomial(&pk.lQcPrime, lagrangeCosetBitReversed) // lagrange coset form canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} wqkiop := iop.NewPolynomial(&qkCompletedCanonical, canReg) @@ -220,7 +267,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ToLagrangeCoset(&pk.Domain[1]) // Full capture using latest gnark crypto... - fic := func(fql, fqr, fqm, fqo, fqk, l, r, o fr.Element) fr.Element { + fic := func(fql, fqr, fqm, fqo, fqk, fqCPrime, l, r, o, pi2 fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary var ic, tmp fr.Element @@ -231,6 +278,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ic.Add(&ic, &tmp) tmp.Mul(&fqo, &o) ic.Add(&ic, &tmp).Add(&ic, &fqk) + tmp.Mul(&fqCPrime, &pi2) + ic.Add(&ic, &tmp) return ic } @@ -264,13 +313,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return one } - // 0 , 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 - // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk,lone + // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15 , 16 + // l , r , o, id, s1, s2, s3, z, zs, PI2, ql, qr, qm, qo, qk, qCPrime, lone fm := func(x ...fr.Element) fr.Element { - a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2]) + a := fic(x[10], x[11], x[12], x[13], x[14], x[15], x[0], x[1], x[2], x[9]) b := fo(x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8]) - c := fone(x[7], x[14]) + c := fone(x[7], x[16]) c.Mul(&c, &alpha).Add(&c, &b).Mul(&c, &alpha).Add(&c, &a) @@ -286,17 +335,19 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ws3, bwziop, bwsziop, + pi2iop, wqliop, wqriop, wqmiop, wqoiop, wqkiop, + wqcpiop, wloneiop, ) if err != nil { return nil, err } - h, err := iop.DivideByXMinusOne(testEval, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) + h, err := iop.DivideByXMinusOne(testEval, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) // TODO Rename to DivideByXNMinusOne or DivideByVanishingPoly etc if err != nil { return nil, err } @@ -316,27 +367,22 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } - // compute evaluations of (blinded version of) l, r, o, z at zeta - var blzeta, brzeta, bozeta fr.Element + // compute evaluations of (blinded version of) l, r, o, z, qCPrime at zeta + var blzeta, brzeta, bozeta, qcpzeta fr.Element var wgEvals sync.WaitGroup - wgEvals.Add(3) - - go func() { - bwliop.ToCanonical(&pk.Domain[1]).ToRegular() - blzeta = bwliop.Evaluate(zeta) - wgEvals.Done() - }() - - go func() { - bwriop.ToCanonical(&pk.Domain[1]).ToRegular() - brzeta = bwriop.Evaluate(zeta) + wgEvals.Add(4) + evalAtZeta := func(poly *iop.Polynomial, res *fr.Element) { + poly.ToCanonical(&pk.Domain[1]).ToRegular() + *res = poly.Evaluate(zeta) wgEvals.Done() - }() - + } + go evalAtZeta(bwliop, &blzeta) + go evalAtZeta(bwriop, &brzeta) + go evalAtZeta(bwoiop, &bozeta) go func() { - bwoiop.ToCanonical(&pk.Domain[1]).ToRegular() - bozeta = bwoiop.Evaluate(zeta) + qcpiop := iop.NewPolynomial(&pk.QcPrime, canReg) + qcpzeta = qcpiop.Evaluate(zeta) wgEvals.Done() }() @@ -375,7 +421,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts gamma, zeta, bzuzeta, + qcpzeta, bwziop.Coefficients()[:bwziop.BlindedSize()], + wpi2iop.Coefficients(), pk, ) @@ -422,6 +470,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.Coefficients()[:bwoiop.BlindedSize()], pk.S1Canonical, pk.S2Canonical, + pk.QcPrime, }, []kzg.Digest{ foldedHDigest, @@ -431,6 +480,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.LRO[2], pk.Vk.S[0], pk.Vk.S[1], + pk.Vk.QcPrime, }, zeta, hFunc, @@ -511,7 +561,7 @@ func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error // α²*L₁(ζ)*Z(X) // + α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*id1(ζ)+γ)*(r(ζ)+β*id2(ζ)+γ)*(o(ζ)+β*id3(ζ)+γ)) // + l(ζ)*Ql(X) + l(ζ)r(ζ)*Qm(X) + r(ζ)*Qr(X) + o(ζ)*Qo(X) + Qk(X) -func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu fr.Element, blindedZCanonical []fr.Element, pk *ProvingKey) []fr.Element { +func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu, qcpZeta fr.Element, blindedZCanonical []fr.Element, pi2Canonical []fr.Element, pk *ProvingKey) []fr.Element { // first part: individual constraints var rl fr.Element @@ -591,6 +641,9 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, t0.Mul(&pk.Qo[i], &oZeta).Add(&t0, &pk.CQk[i]) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) + + t0.Mul(&pi2Canonical[i], &qcpZeta) + linPol[i].Add(&linPol[i], &t0) } t0.Mul(&blindedZCanonical[i], &lagrangeZeta) diff --git a/internal/backend/bw6-761/plonk/prove.go b/internal/backend/bw6-761/plonk/prove.go index c8854b1938..032ff8e37a 100644 --- a/internal/backend/bw6-761/plonk/prove.go +++ b/internal/backend/bw6-761/plonk/prove.go @@ -38,6 +38,7 @@ import ( "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" ) @@ -53,7 +54,10 @@ type Proof struct { // Commitments to h1, h2, h3 such that h = h1 + Xh2 + X**2h3 is the quotient polynomial H [3]kzg.Digest - // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2 + // PI2, the BSB22 commitment + PI2 kzg.Digest + + // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2, qCPrime BatchedProof kzg.BatchOpeningProof // Opening proof of Z at zeta*mu @@ -78,6 +82,45 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // result proof := &Proof{} + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + var ( + wpi2iop *iop.Polynomial // canonical + commitmentVal fr.Element // TODO @Tabaie get rid of this + ) + if spr.CommitmentInfo.Is() { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo.HintID, func(_ *big.Int, ins, outs []*big.Int) error { + pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + for i := range ins { + pi2[spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) + } + var ( + err error + hashRes []fr.Element + ) + if _, err = pi2[spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { + return err + } + pi2iop := iop.NewPolynomial(&pi2, lagReg) + wpi2iop = pi2iop.ShallowClone() + wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err + } + if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + return err + } + commitmentVal = hashRes[0] // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses + commitmentVal.BigInt(outs[0]) + return nil + })) + } else { + // TODO Leaving pi2 in for testing. In the future, bypass when no commitment present + pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + + pi2iop := iop.NewPolynomial(&pi2, lagReg) + wpi2iop = pi2iop.ShallowClone() + wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + } // query l, r, o in Lagrange basis, not blinded _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) @@ -89,7 +132,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts evaluationRDomainSmall := []fr.Element(solution.R) evaluationODomainSmall := []fr.Element(solution.O) - lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} liop := iop.NewPolynomial(&evaluationLDomainSmall, lagReg) riop := iop.NewPolynomial(&evaluationRDomainSmall, lagReg) oiop := iop.NewPolynomial(&evaluationODomainSmall, lagReg) @@ -120,7 +162,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)]); err != nil { return nil, err } - gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) + gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) // TODO @Tabaie @ThomasPiellard add BSB commitment here? if err != nil { return nil, err } @@ -171,13 +213,17 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, pk.Domain[0].Cardinality) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], pk.LQk[len(spr.Public):]) + if spr.CommitmentInfo.Is() { + qkCompletedCanonical[spr.CommitmentInfo.CommitmentIndex] = commitmentVal + } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) - // l, r, o are blinded here + // l, r, o are already blinded bwliop.ToLagrangeCoset(&pk.Domain[1]) bwriop.ToLagrangeCoset(&pk.Domain[1]) bwoiop.ToLagrangeCoset(&pk.Domain[1]) + pi2iop := wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form lagrangeCosetBitReversed := iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse} @@ -186,6 +232,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wqriop := iop.NewPolynomial(&pk.lQr, lagrangeCosetBitReversed) wqmiop := iop.NewPolynomial(&pk.lQm, lagrangeCosetBitReversed) wqoiop := iop.NewPolynomial(&pk.lQo, lagrangeCosetBitReversed) + wqcpiop := iop.NewPolynomial(&pk.lQcPrime, lagrangeCosetBitReversed) // lagrange coset form canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} wqkiop := iop.NewPolynomial(&qkCompletedCanonical, canReg) @@ -220,7 +267,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ToLagrangeCoset(&pk.Domain[1]) // Full capture using latest gnark crypto... - fic := func(fql, fqr, fqm, fqo, fqk, l, r, o fr.Element) fr.Element { + fic := func(fql, fqr, fqm, fqo, fqk, fqCPrime, l, r, o, pi2 fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary var ic, tmp fr.Element @@ -231,6 +278,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ic.Add(&ic, &tmp) tmp.Mul(&fqo, &o) ic.Add(&ic, &tmp).Add(&ic, &fqk) + tmp.Mul(&fqCPrime, &pi2) + ic.Add(&ic, &tmp) return ic } @@ -264,13 +313,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return one } - // 0 , 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 - // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk,lone + // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15 , 16 + // l , r , o, id, s1, s2, s3, z, zs, PI2, ql, qr, qm, qo, qk, qCPrime, lone fm := func(x ...fr.Element) fr.Element { - a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2]) + a := fic(x[10], x[11], x[12], x[13], x[14], x[15], x[0], x[1], x[2], x[9]) b := fo(x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8]) - c := fone(x[7], x[14]) + c := fone(x[7], x[16]) c.Mul(&c, &alpha).Add(&c, &b).Mul(&c, &alpha).Add(&c, &a) @@ -286,17 +335,19 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ws3, bwziop, bwsziop, + pi2iop, wqliop, wqriop, wqmiop, wqoiop, wqkiop, + wqcpiop, wloneiop, ) if err != nil { return nil, err } - h, err := iop.DivideByXMinusOne(testEval, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) + h, err := iop.DivideByXMinusOne(testEval, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) // TODO Rename to DivideByXNMinusOne or DivideByVanishingPoly etc if err != nil { return nil, err } @@ -316,27 +367,22 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } - // compute evaluations of (blinded version of) l, r, o, z at zeta - var blzeta, brzeta, bozeta fr.Element + // compute evaluations of (blinded version of) l, r, o, z, qCPrime at zeta + var blzeta, brzeta, bozeta, qcpzeta fr.Element var wgEvals sync.WaitGroup - wgEvals.Add(3) - - go func() { - bwliop.ToCanonical(&pk.Domain[1]).ToRegular() - blzeta = bwliop.Evaluate(zeta) - wgEvals.Done() - }() - - go func() { - bwriop.ToCanonical(&pk.Domain[1]).ToRegular() - brzeta = bwriop.Evaluate(zeta) + wgEvals.Add(4) + evalAtZeta := func(poly *iop.Polynomial, res *fr.Element) { + poly.ToCanonical(&pk.Domain[1]).ToRegular() + *res = poly.Evaluate(zeta) wgEvals.Done() - }() - + } + go evalAtZeta(bwliop, &blzeta) + go evalAtZeta(bwriop, &brzeta) + go evalAtZeta(bwoiop, &bozeta) go func() { - bwoiop.ToCanonical(&pk.Domain[1]).ToRegular() - bozeta = bwoiop.Evaluate(zeta) + qcpiop := iop.NewPolynomial(&pk.QcPrime, canReg) + qcpzeta = qcpiop.Evaluate(zeta) wgEvals.Done() }() @@ -375,7 +421,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts gamma, zeta, bzuzeta, + qcpzeta, bwziop.Coefficients()[:bwziop.BlindedSize()], + wpi2iop.Coefficients(), pk, ) @@ -422,6 +470,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.Coefficients()[:bwoiop.BlindedSize()], pk.S1Canonical, pk.S2Canonical, + pk.QcPrime, }, []kzg.Digest{ foldedHDigest, @@ -431,6 +480,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.LRO[2], pk.Vk.S[0], pk.Vk.S[1], + pk.Vk.QcPrime, }, zeta, hFunc, @@ -511,7 +561,7 @@ func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error // α²*L₁(ζ)*Z(X) // + α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*id1(ζ)+γ)*(r(ζ)+β*id2(ζ)+γ)*(o(ζ)+β*id3(ζ)+γ)) // + l(ζ)*Ql(X) + l(ζ)r(ζ)*Qm(X) + r(ζ)*Qr(X) + o(ζ)*Qo(X) + Qk(X) -func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu fr.Element, blindedZCanonical []fr.Element, pk *ProvingKey) []fr.Element { +func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu, qcpZeta fr.Element, blindedZCanonical []fr.Element, pi2Canonical []fr.Element, pk *ProvingKey) []fr.Element { // first part: individual constraints var rl fr.Element @@ -591,6 +641,9 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, t0.Mul(&pk.Qo[i], &oZeta).Add(&t0, &pk.CQk[i]) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) + + t0.Mul(&pi2Canonical[i], &qcpZeta) + linPol[i].Add(&linPol[i], &t0) } t0.Mul(&blindedZCanonical[i], &lagrangeZeta) diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl index 307ee05dbb..de5fd91dee 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl @@ -14,6 +14,7 @@ import ( {{ template "import_backend_cs" . }} "github.com/consensys/gnark-crypto/ecc/{{toLower .Curve}}/fr/iop" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/logger" @@ -31,7 +32,10 @@ type Proof struct { // Commitments to h1, h2, h3 such that h = h1 + Xh2 + X**2h3 is the quotient polynomial H [3]kzg.Digest - // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2 + // PI2, the BSB22 commitment + PI2 kzg.Digest + + // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2, qCPrime BatchedProof kzg.BatchOpeningProof // Opening proof of Z at zeta*mu @@ -56,6 +60,45 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // result proof := &Proof{} + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + var ( + wpi2iop *iop.Polynomial // canonical + commitmentVal fr.Element // TODO @Tabaie get rid of this + ) + if spr.CommitmentInfo.Is() { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo.HintID, func(_ *big.Int, ins, outs []*big.Int) error { + pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + for i := range ins { + pi2[spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) + } + var ( + err error + hashRes []fr.Element + ) + if _, err = pi2[spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { + return err + } + pi2iop := iop.NewPolynomial(&pi2, lagReg) + wpi2iop = pi2iop.ShallowClone() + wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err + } + if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + return err + } + commitmentVal = hashRes[0] // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses + commitmentVal.BigInt(outs[0]) + return nil + })) + } else { + // TODO Leaving pi2 in for testing. In the future, bypass when no commitment present + pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + + pi2iop := iop.NewPolynomial(&pi2, lagReg) + wpi2iop = pi2iop.ShallowClone() + wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + } // query l, r, o in Lagrange basis, not blinded _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) @@ -67,7 +110,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts evaluationRDomainSmall := []fr.Element(solution.R) evaluationODomainSmall := []fr.Element(solution.O) - lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} liop := iop.NewPolynomial(&evaluationLDomainSmall, lagReg) riop := iop.NewPolynomial(&evaluationRDomainSmall, lagReg) oiop := iop.NewPolynomial(&evaluationODomainSmall, lagReg) @@ -98,7 +140,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)]); err != nil { return nil, err } - gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) + gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) // TODO @Tabaie @ThomasPiellard add BSB commitment here? if err != nil { return nil, err } @@ -149,13 +191,17 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, pk.Domain[0].Cardinality) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], pk.LQk[len(spr.Public):]) + if spr.CommitmentInfo.Is() { + qkCompletedCanonical[spr.CommitmentInfo.CommitmentIndex] = commitmentVal + } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) - // l, r, o are blinded here + // l, r, o are already blinded bwliop.ToLagrangeCoset(&pk.Domain[1]) bwriop.ToLagrangeCoset(&pk.Domain[1]) bwoiop.ToLagrangeCoset(&pk.Domain[1]) + pi2iop := wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form lagrangeCosetBitReversed := iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse} @@ -164,6 +210,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wqriop := iop.NewPolynomial(&pk.lQr, lagrangeCosetBitReversed) wqmiop := iop.NewPolynomial(&pk.lQm, lagrangeCosetBitReversed) wqoiop := iop.NewPolynomial(&pk.lQo, lagrangeCosetBitReversed) + wqcpiop := iop.NewPolynomial(&pk.lQcPrime, lagrangeCosetBitReversed) // lagrange coset form + canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} wqkiop := iop.NewPolynomial(&qkCompletedCanonical, canReg) @@ -198,7 +246,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ToLagrangeCoset(&pk.Domain[1]) // Full capture using latest gnark crypto... - fic := func(fql, fqr, fqm, fqo, fqk, l, r, o fr.Element) fr.Element { + fic := func(fql, fqr, fqm, fqo, fqk, fqCPrime, l, r, o, pi2 fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary var ic, tmp fr.Element @@ -209,6 +257,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ic.Add(&ic, &tmp) tmp.Mul(&fqo, &o) ic.Add(&ic, &tmp).Add(&ic, &fqk) + tmp.Mul(&fqCPrime, &pi2) + ic.Add(&ic, &tmp) return ic } @@ -242,13 +292,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return one } - // 0 , 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 - // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk,lone + // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15 , 16 + // l , r , o, id, s1, s2, s3, z, zs, PI2, ql, qr, qm, qo, qk, qCPrime, lone fm := func(x ...fr.Element) fr.Element { - a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2]) + a := fic(x[10], x[11], x[12], x[13], x[14], x[15], x[0], x[1], x[2], x[9]) b := fo(x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8]) - c := fone(x[7], x[14]) + c := fone(x[7], x[16]) c.Mul(&c, &alpha).Add(&c, &b).Mul(&c, &alpha).Add(&c, &a) @@ -264,17 +314,19 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ws3, bwziop, bwsziop, + pi2iop, wqliop, wqriop, wqmiop, wqoiop, wqkiop, + wqcpiop, wloneiop, ) if err != nil { return nil, err } - h, err := iop.DivideByXMinusOne(testEval, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) + h, err := iop.DivideByXMinusOne(testEval, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]})// TODO Rename to DivideByXNMinusOne or DivideByVanishingPoly etc if err != nil { return nil, err } @@ -294,27 +346,22 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } - // compute evaluations of (blinded version of) l, r, o, z at zeta - var blzeta, brzeta, bozeta fr.Element + // compute evaluations of (blinded version of) l, r, o, z, qCPrime at zeta + var blzeta, brzeta, bozeta, qcpzeta fr.Element var wgEvals sync.WaitGroup - wgEvals.Add(3) - - go func() { - bwliop.ToCanonical(&pk.Domain[1]).ToRegular() - blzeta = bwliop.Evaluate(zeta) - wgEvals.Done() - }() - - go func() { - bwriop.ToCanonical(&pk.Domain[1]).ToRegular() - brzeta = bwriop.Evaluate(zeta) + wgEvals.Add(4) + evalAtZeta := func(poly *iop.Polynomial, res *fr.Element) { + poly.ToCanonical(&pk.Domain[1]).ToRegular() + *res = poly.Evaluate(zeta) wgEvals.Done() - }() - + } + go evalAtZeta(bwliop, &blzeta) + go evalAtZeta(bwriop, &brzeta) + go evalAtZeta(bwoiop, &bozeta) go func() { - bwoiop.ToCanonical(&pk.Domain[1]).ToRegular() - bozeta = bwoiop.Evaluate(zeta) + qcpiop := iop.NewPolynomial(&pk.QcPrime, canReg) + qcpzeta = qcpiop.Evaluate(zeta) wgEvals.Done() }() @@ -353,7 +400,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts gamma, zeta, bzuzeta, + qcpzeta, bwziop.Coefficients()[:bwziop.BlindedSize()], + wpi2iop.Coefficients(), pk, ) @@ -400,6 +449,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.Coefficients()[:bwoiop.BlindedSize()], pk.S1Canonical, pk.S2Canonical, + pk.QcPrime, }, []kzg.Digest{ foldedHDigest, @@ -409,6 +459,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.LRO[2], pk.Vk.S[0], pk.Vk.S[1], + pk.Vk.QcPrime, }, zeta, hFunc, @@ -489,7 +540,7 @@ func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error // α²*L₁(ζ)*Z(X) // + α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*id1(ζ)+γ)*(r(ζ)+β*id2(ζ)+γ)*(o(ζ)+β*id3(ζ)+γ)) // + l(ζ)*Ql(X) + l(ζ)r(ζ)*Qm(X) + r(ζ)*Qr(X) + o(ζ)*Qo(X) + Qk(X) -func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu fr.Element, blindedZCanonical []fr.Element, pk *ProvingKey) []fr.Element { +func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu, qcpZeta fr.Element, blindedZCanonical []fr.Element, pi2Canonical []fr.Element, pk *ProvingKey) []fr.Element { // first part: individual constraints var rl fr.Element @@ -569,6 +620,9 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, t0.Mul(&pk.Qo[i], &oZeta).Add(&t0, &pk.CQk[i]) linPol[i].Add(&linPol[i], &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) + + t0.Mul(&pi2Canonical[i], &qcpZeta) + linPol[i].Add(&linPol[i], &t0) } t0.Mul(&blindedZCanonical[i], &lagrangeZeta) From bf3b36c2002034fafe8a71209d0c3e48391209b4 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 17 Mar 2023 14:04:45 -0400 Subject: [PATCH 161/464] fix: minor mistake in setup generification --- internal/backend/bls12-377/plonk/setup.go | 4 +++- internal/backend/bls12-381/plonk/setup.go | 4 +++- internal/backend/bls24-315/plonk/setup.go | 4 +++- internal/backend/bls24-317/plonk/setup.go | 4 +++- internal/backend/bw6-633/plonk/setup.go | 4 +++- internal/backend/bw6-761/plonk/setup.go | 4 +++- .../backend/template/zkpschemes/plonk/plonk.setup.go.tmpl | 4 +++- 7 files changed, 21 insertions(+), 7 deletions(-) diff --git a/internal/backend/bls12-377/plonk/setup.go b/internal/backend/bls12-377/plonk/setup.go index 304c341709..5d60f14e23 100644 --- a/internal/backend/bls12-377/plonk/setup.go +++ b/internal/backend/bls12-377/plonk/setup.go @@ -22,6 +22,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/iop" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/kzg" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls12-377" kzgg "github.com/consensys/gnark-crypto/kzg" @@ -41,7 +42,8 @@ type ProvingKey struct { // TODO store iop.Polynomial here, not []fr.Element for more "type safety" - // qr,ql,qm,qo,cqp (in canonical basis). + // qr,ql,qm,qo,qcp (in canonical basis). + // QcPrime denotes the constraints defining committed variables Ql, Qr, Qm, Qo, QcPrime []fr.Element // qr,ql,qm,qo,qcp (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. diff --git a/internal/backend/bls12-381/plonk/setup.go b/internal/backend/bls12-381/plonk/setup.go index 38656c5103..6dbde91d45 100644 --- a/internal/backend/bls12-381/plonk/setup.go +++ b/internal/backend/bls12-381/plonk/setup.go @@ -22,6 +22,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/iop" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/kzg" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls12-381" kzgg "github.com/consensys/gnark-crypto/kzg" @@ -41,7 +42,8 @@ type ProvingKey struct { // TODO store iop.Polynomial here, not []fr.Element for more "type safety" - // qr,ql,qm,qo,cqp (in canonical basis). + // qr,ql,qm,qo,qcp (in canonical basis). + // QcPrime denotes the constraints defining committed variables Ql, Qr, Qm, Qo, QcPrime []fr.Element // qr,ql,qm,qo,qcp (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. diff --git a/internal/backend/bls24-315/plonk/setup.go b/internal/backend/bls24-315/plonk/setup.go index 4acee1a909..639072f8fa 100644 --- a/internal/backend/bls24-315/plonk/setup.go +++ b/internal/backend/bls24-315/plonk/setup.go @@ -22,6 +22,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/iop" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/kzg" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls24-315" kzgg "github.com/consensys/gnark-crypto/kzg" @@ -41,7 +42,8 @@ type ProvingKey struct { // TODO store iop.Polynomial here, not []fr.Element for more "type safety" - // qr,ql,qm,qo,cqp (in canonical basis). + // qr,ql,qm,qo,qcp (in canonical basis). + // QcPrime denotes the constraints defining committed variables Ql, Qr, Qm, Qo, QcPrime []fr.Element // qr,ql,qm,qo,qcp (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. diff --git a/internal/backend/bls24-317/plonk/setup.go b/internal/backend/bls24-317/plonk/setup.go index e0fcf8eff5..550619f851 100644 --- a/internal/backend/bls24-317/plonk/setup.go +++ b/internal/backend/bls24-317/plonk/setup.go @@ -22,6 +22,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/iop" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/kzg" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls24-317" kzgg "github.com/consensys/gnark-crypto/kzg" @@ -41,7 +42,8 @@ type ProvingKey struct { // TODO store iop.Polynomial here, not []fr.Element for more "type safety" - // qr,ql,qm,qo,cqp (in canonical basis). + // qr,ql,qm,qo,qcp (in canonical basis). + // QcPrime denotes the constraints defining committed variables Ql, Qr, Qm, Qo, QcPrime []fr.Element // qr,ql,qm,qo,qcp (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. diff --git a/internal/backend/bw6-633/plonk/setup.go b/internal/backend/bw6-633/plonk/setup.go index 03a48ed8f0..90d614c4c0 100644 --- a/internal/backend/bw6-633/plonk/setup.go +++ b/internal/backend/bw6-633/plonk/setup.go @@ -22,6 +22,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/fft" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/iop" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/kzg" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bw6-633" kzgg "github.com/consensys/gnark-crypto/kzg" @@ -41,7 +42,8 @@ type ProvingKey struct { // TODO store iop.Polynomial here, not []fr.Element for more "type safety" - // qr,ql,qm,qo,cqp (in canonical basis). + // qr,ql,qm,qo,qcp (in canonical basis). + // QcPrime denotes the constraints defining committed variables Ql, Qr, Qm, Qo, QcPrime []fr.Element // qr,ql,qm,qo,qcp (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. diff --git a/internal/backend/bw6-761/plonk/setup.go b/internal/backend/bw6-761/plonk/setup.go index 8dda20e8dc..6beaf377a5 100644 --- a/internal/backend/bw6-761/plonk/setup.go +++ b/internal/backend/bw6-761/plonk/setup.go @@ -22,6 +22,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/fft" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/iop" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/kzg" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bw6-761" kzgg "github.com/consensys/gnark-crypto/kzg" @@ -41,7 +42,8 @@ type ProvingKey struct { // TODO store iop.Polynomial here, not []fr.Element for more "type safety" - // qr,ql,qm,qo,cqp (in canonical basis). + // qr,ql,qm,qo,qcp (in canonical basis). + // QcPrime denotes the constraints defining committed variables Ql, Qr, Qm, Qo, QcPrime []fr.Element // qr,ql,qm,qo,qcp (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl index 1e6c44129e..d75218457a 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl @@ -3,6 +3,7 @@ import ( {{- template "import_kzg" . }} {{- template "import_fr" . }} {{- template "import_fft" . }} + "github.com/consensys/gnark/constraint" {{- template "import_backend_cs" . }} "github.com/consensys/gnark-crypto/ecc/{{toLower .Curve}}/fr/iop" @@ -23,7 +24,8 @@ type ProvingKey struct { // TODO store iop.Polynomial here, not []fr.Element for more "type safety" - // qr,ql,qm,qo,cqp (in canonical basis). + // qr,ql,qm,qo,qcp (in canonical basis). + // QcPrime denotes the constraints defining committed variables Ql, Qr, Qm, Qo, QcPrime []fr.Element // qr,ql,qm,qo,qcp (in lagrange coset basis) --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. From 351bb03439d8e5ceaa06bdc57aa828a1cd55ff9f Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 17 Mar 2023 14:09:24 -0400 Subject: [PATCH 162/464] build: generify verifier changes --- internal/backend/bls12-377/plonk/verify.go | 70 +++++++++++++------ internal/backend/bls12-381/plonk/verify.go | 70 +++++++++++++------ internal/backend/bls24-315/plonk/verify.go | 70 +++++++++++++------ internal/backend/bls24-317/plonk/verify.go | 70 +++++++++++++------ internal/backend/bn254/plonk/verify.go | 3 +- internal/backend/bw6-633/plonk/verify.go | 70 +++++++++++++------ internal/backend/bw6-761/plonk/verify.go | 70 +++++++++++++------ .../zkpschemes/plonk/plonk.verify.go.tmpl | 70 +++++++++++++------ 8 files changed, 344 insertions(+), 149 deletions(-) diff --git a/internal/backend/bls12-377/plonk/verify.go b/internal/backend/bls12-377/plonk/verify.go index ca61aa05c4..b5348e6eb6 100644 --- a/internal/backend/bls12-377/plonk/verify.go +++ b/internal/backend/bls12-377/plonk/verify.go @@ -85,25 +85,51 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zetaPowerM.Exp(zeta, &bExpo) zzeta.Sub(&zetaPowerM, &one) - // ccompute PI = ∑_{i Date: Fri, 17 Mar 2023 14:34:01 -0400 Subject: [PATCH 163/464] test: more for bsb22 plonk --- test/commitments_test.go | 69 +++++++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 22 deletions(-) diff --git a/test/commitments_test.go b/test/commitments_test.go index 592b9166ec..7db456ef7b 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -5,10 +5,10 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/scs" "github.com/stretchr/testify/assert" + "math/big" "testing" "github.com/consensys/gnark/backend/plonk" - cs "github.com/consensys/gnark/constraint/bn254" ) type commitmentCircuit struct { @@ -23,12 +23,18 @@ func (c *commitmentCircuit) Define(api frontend.API) error { return err } -func TestSingleCommitmentPlonkBn254(t *testing.T) { - plonkTestBn254(t, &commitmentCircuit{[]frontend.Variable{1}}) +func (c *commitmentCircuit) hollow() frontend.Circuit { + return &commitmentCircuit{make([]frontend.Variable, len(c.X))} +} + +func TestSingleCommitmentPlonk(t *testing.T) { + assignment := &commitmentCircuit{[]frontend.Variable{1}} + plonkTest(t, assignment.hollow(), assignment) } func TestFiveCommitmentsPlonk(t *testing.T) { - plonkTestBn254(t, &commitmentCircuit{[]frontend.Variable{1, 2, 3, 4, 5}}) + assignment := &commitmentCircuit{[]frontend.Variable{1, 2, 3, 4, 5}} + plonkTest(t, assignment.hollow(), assignment) } type noCommitmentCircuit struct { @@ -41,30 +47,49 @@ func (c *noCommitmentCircuit) Define(api frontend.API) error { return nil } -func TestNoCommitmentCircuit(t *testing.T) { - plonkTestBn254(t, &noCommitmentCircuit{1}) +func TestNoCommitmentCircuitPlonk(t *testing.T) { + plonkTest(t, &noCommitmentCircuit{}, &noCommitmentCircuit{1}) } -func plonkTestBn254(t *testing.T, assignment frontend.Circuit) { - witnessFull, err := frontend.NewWitness(assignment, ecc.BN254.ScalarField()) - assert.NoError(t, err) - witnessPublic, err := witnessFull.Public() - assert.NoError(t, err) +func plonkTest(t *testing.T, circuit, assignment frontend.Circuit) { + + fr := []ecc.ID{ + ecc.BN254, + ecc.BLS12_381, + ecc.BLS12_377, + ecc.BLS24_315, + //ecc.BLS12_378, TODO: @Tabaie Not autogenerated? + ecc.BLS24_317, + ecc.BW6_633, + //ecc.BW6_756, TODO: @Tabaie Not autogenerated? + ecc.BW6_761, + } + + run := func(mod *big.Int) func(t *testing.T) { + return func(t *testing.T) { + ccs, err := frontend.Compile(mod, scs.NewBuilder, circuit) + assert.NoError(t, err) - ccs, err := frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, assignment) - assert.NoError(t, err) + witnessFull, err := frontend.NewWitness(assignment, mod) + assert.NoError(t, err) + witnessPublic, err := witnessFull.Public() + assert.NoError(t, err) - _r1cs := ccs.(*cs.SparseR1CS) - srs, err := NewKZGSRS(_r1cs) - assert.NoError(t, err) + srs, err := NewKZGSRS(ccs) + assert.NoError(t, err) - pk, vk, err := plonk.Setup(ccs, srs) - assert.NoError(t, err) + pk, vk, err := plonk.Setup(ccs, srs) + assert.NoError(t, err) - proof, err := plonk.Prove(ccs, pk, witnessFull) - assert.NoError(t, err) + proof, err := plonk.Prove(ccs, pk, witnessFull) + assert.NoError(t, err) - err = plonk.Verify(proof, vk, witnessPublic) - assert.NoError(t, err) + err = plonk.Verify(proof, vk, witnessPublic) + assert.NoError(t, err) + } + } + for _, id := range fr { + t.Run(id.String(), run(id.ScalarField())) + } } From ce6c378bb90526f99778f2e92a9b8fec0bc2148b Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 17 Mar 2023 15:07:32 -0400 Subject: [PATCH 164/464] build: go generate --- backend/plonk/bls12-377/setup.go | 25 +++++++++++++++++++++++-- backend/plonk/bls12-381/setup.go | 25 +++++++++++++++++++++++-- backend/plonk/bls24-315/setup.go | 25 +++++++++++++++++++++++-- backend/plonk/bls24-317/setup.go | 25 +++++++++++++++++++++++-- backend/plonk/bn254/setup.go | 25 +++++++++++++++++++++++-- backend/plonk/bw6-633/setup.go | 25 +++++++++++++++++++++++-- backend/plonk/bw6-761/setup.go | 25 +++++++++++++++++++++++-- 7 files changed, 161 insertions(+), 14 deletions(-) diff --git a/backend/plonk/bls12-377/setup.go b/backend/plonk/bls12-377/setup.go index 92cfa3f071..0e59a6a9b8 100644 --- a/backend/plonk/bls12-377/setup.go +++ b/backend/plonk/bls12-377/setup.go @@ -23,6 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/iop" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/kzg" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls12-377" kzgg "github.com/consensys/gnark-crypto/kzg" @@ -38,6 +39,13 @@ type Trace struct { // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. Ql, Qr, Qm, Qo, Qk *iop.Polynomial + // qcp (in canonical basis). + // QcPrime denotes the constraints defining committed variables + QcPrime []fr.Element + + // qcp (in lagrange coset basis) + lQcPrime []fr.Element + // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. // The set of interpolation is of size N, so to represent the permutation S we let S acts on the // set A=(, u*, u^{2}*) of size 3*N, where u is outside (its use is to shift the set ). @@ -73,7 +81,9 @@ type VerifyingKey struct { // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk kzg.Digest + Ql, Qr, Qm, Qo, Qk, QcPrime kzg.Digest + + CommitmentInfo constraint.Commitment } // ProvingKey stores the data needed to generate a proof: @@ -116,6 +126,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) var pk ProvingKey var vk VerifyingKey pk.Vk = &vk + vk.CommitmentInfo = spr.CommitmentInfo // nbConstraints := len(spr.Constraints) // step 0: set the fft domains @@ -153,6 +164,13 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } + pk.QcPrime = make([]fr.Element, pk.Domain[0].Cardinality) + for _, committed := range spr.CommitmentInfo.Committed { + pk.QcPrime[committed].SetOne() + } + if vk.QcPrime, err = kzg.Commit(pk.QcPrime, vk.KZGSRS); err != nil { + return nil, nil, err + } // step 5: evaluate ql, qr, qm, qo, s1, s2, s3 on LagrangeCoset (NOT qk) // we clone them, because the canonical versions are going to be used in // the opening proof @@ -164,6 +182,9 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset // basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. func (pk *ProvingKey) computeLagrangeCosetPolys() { + wqcpiop := iop.NewPolynomial(clone(pk.QcPrime, pk.Domain[1].Cardinality), iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) + wqcpiop.ToLagrangeCoset(&pk.Domain[1]) + pk.lQcPrime = wqcpiop.Coefficients() pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) @@ -196,7 +217,7 @@ func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { // This should be used after deserializing a VerifyingKey // as vk.KZG is NOT serialized // -// Note that this instantiate a new FFT domain using vk.Size +// Note that this instantiates a new FFT domain using vk.Size func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { _srs := srs.(*kzg.SRS) diff --git a/backend/plonk/bls12-381/setup.go b/backend/plonk/bls12-381/setup.go index 4e06fd46d5..2ac4d0bfdc 100644 --- a/backend/plonk/bls12-381/setup.go +++ b/backend/plonk/bls12-381/setup.go @@ -23,6 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/iop" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/kzg" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls12-381" kzgg "github.com/consensys/gnark-crypto/kzg" @@ -38,6 +39,13 @@ type Trace struct { // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. Ql, Qr, Qm, Qo, Qk *iop.Polynomial + // qcp (in canonical basis). + // QcPrime denotes the constraints defining committed variables + QcPrime []fr.Element + + // qcp (in lagrange coset basis) + lQcPrime []fr.Element + // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. // The set of interpolation is of size N, so to represent the permutation S we let S acts on the // set A=(, u*, u^{2}*) of size 3*N, where u is outside (its use is to shift the set ). @@ -73,7 +81,9 @@ type VerifyingKey struct { // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk kzg.Digest + Ql, Qr, Qm, Qo, Qk, QcPrime kzg.Digest + + CommitmentInfo constraint.Commitment } // ProvingKey stores the data needed to generate a proof: @@ -116,6 +126,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) var pk ProvingKey var vk VerifyingKey pk.Vk = &vk + vk.CommitmentInfo = spr.CommitmentInfo // nbConstraints := len(spr.Constraints) // step 0: set the fft domains @@ -153,6 +164,13 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } + pk.QcPrime = make([]fr.Element, pk.Domain[0].Cardinality) + for _, committed := range spr.CommitmentInfo.Committed { + pk.QcPrime[committed].SetOne() + } + if vk.QcPrime, err = kzg.Commit(pk.QcPrime, vk.KZGSRS); err != nil { + return nil, nil, err + } // step 5: evaluate ql, qr, qm, qo, s1, s2, s3 on LagrangeCoset (NOT qk) // we clone them, because the canonical versions are going to be used in // the opening proof @@ -164,6 +182,9 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset // basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. func (pk *ProvingKey) computeLagrangeCosetPolys() { + wqcpiop := iop.NewPolynomial(clone(pk.QcPrime, pk.Domain[1].Cardinality), iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) + wqcpiop.ToLagrangeCoset(&pk.Domain[1]) + pk.lQcPrime = wqcpiop.Coefficients() pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) @@ -196,7 +217,7 @@ func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { // This should be used after deserializing a VerifyingKey // as vk.KZG is NOT serialized // -// Note that this instantiate a new FFT domain using vk.Size +// Note that this instantiates a new FFT domain using vk.Size func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { _srs := srs.(*kzg.SRS) diff --git a/backend/plonk/bls24-315/setup.go b/backend/plonk/bls24-315/setup.go index 56aa9666e4..7f46b14c76 100644 --- a/backend/plonk/bls24-315/setup.go +++ b/backend/plonk/bls24-315/setup.go @@ -23,6 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/iop" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/kzg" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls24-315" kzgg "github.com/consensys/gnark-crypto/kzg" @@ -38,6 +39,13 @@ type Trace struct { // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. Ql, Qr, Qm, Qo, Qk *iop.Polynomial + // qcp (in canonical basis). + // QcPrime denotes the constraints defining committed variables + QcPrime []fr.Element + + // qcp (in lagrange coset basis) + lQcPrime []fr.Element + // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. // The set of interpolation is of size N, so to represent the permutation S we let S acts on the // set A=(, u*, u^{2}*) of size 3*N, where u is outside (its use is to shift the set ). @@ -73,7 +81,9 @@ type VerifyingKey struct { // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk kzg.Digest + Ql, Qr, Qm, Qo, Qk, QcPrime kzg.Digest + + CommitmentInfo constraint.Commitment } // ProvingKey stores the data needed to generate a proof: @@ -116,6 +126,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) var pk ProvingKey var vk VerifyingKey pk.Vk = &vk + vk.CommitmentInfo = spr.CommitmentInfo // nbConstraints := len(spr.Constraints) // step 0: set the fft domains @@ -153,6 +164,13 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } + pk.QcPrime = make([]fr.Element, pk.Domain[0].Cardinality) + for _, committed := range spr.CommitmentInfo.Committed { + pk.QcPrime[committed].SetOne() + } + if vk.QcPrime, err = kzg.Commit(pk.QcPrime, vk.KZGSRS); err != nil { + return nil, nil, err + } // step 5: evaluate ql, qr, qm, qo, s1, s2, s3 on LagrangeCoset (NOT qk) // we clone them, because the canonical versions are going to be used in // the opening proof @@ -164,6 +182,9 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset // basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. func (pk *ProvingKey) computeLagrangeCosetPolys() { + wqcpiop := iop.NewPolynomial(clone(pk.QcPrime, pk.Domain[1].Cardinality), iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) + wqcpiop.ToLagrangeCoset(&pk.Domain[1]) + pk.lQcPrime = wqcpiop.Coefficients() pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) @@ -196,7 +217,7 @@ func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { // This should be used after deserializing a VerifyingKey // as vk.KZG is NOT serialized // -// Note that this instantiate a new FFT domain using vk.Size +// Note that this instantiates a new FFT domain using vk.Size func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { _srs := srs.(*kzg.SRS) diff --git a/backend/plonk/bls24-317/setup.go b/backend/plonk/bls24-317/setup.go index dacb91b88f..03d88876a6 100644 --- a/backend/plonk/bls24-317/setup.go +++ b/backend/plonk/bls24-317/setup.go @@ -23,6 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/iop" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/kzg" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls24-317" kzgg "github.com/consensys/gnark-crypto/kzg" @@ -38,6 +39,13 @@ type Trace struct { // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. Ql, Qr, Qm, Qo, Qk *iop.Polynomial + // qcp (in canonical basis). + // QcPrime denotes the constraints defining committed variables + QcPrime []fr.Element + + // qcp (in lagrange coset basis) + lQcPrime []fr.Element + // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. // The set of interpolation is of size N, so to represent the permutation S we let S acts on the // set A=(, u*, u^{2}*) of size 3*N, where u is outside (its use is to shift the set ). @@ -73,7 +81,9 @@ type VerifyingKey struct { // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk kzg.Digest + Ql, Qr, Qm, Qo, Qk, QcPrime kzg.Digest + + CommitmentInfo constraint.Commitment } // ProvingKey stores the data needed to generate a proof: @@ -116,6 +126,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) var pk ProvingKey var vk VerifyingKey pk.Vk = &vk + vk.CommitmentInfo = spr.CommitmentInfo // nbConstraints := len(spr.Constraints) // step 0: set the fft domains @@ -153,6 +164,13 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } + pk.QcPrime = make([]fr.Element, pk.Domain[0].Cardinality) + for _, committed := range spr.CommitmentInfo.Committed { + pk.QcPrime[committed].SetOne() + } + if vk.QcPrime, err = kzg.Commit(pk.QcPrime, vk.KZGSRS); err != nil { + return nil, nil, err + } // step 5: evaluate ql, qr, qm, qo, s1, s2, s3 on LagrangeCoset (NOT qk) // we clone them, because the canonical versions are going to be used in // the opening proof @@ -164,6 +182,9 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset // basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. func (pk *ProvingKey) computeLagrangeCosetPolys() { + wqcpiop := iop.NewPolynomial(clone(pk.QcPrime, pk.Domain[1].Cardinality), iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) + wqcpiop.ToLagrangeCoset(&pk.Domain[1]) + pk.lQcPrime = wqcpiop.Coefficients() pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) @@ -196,7 +217,7 @@ func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { // This should be used after deserializing a VerifyingKey // as vk.KZG is NOT serialized // -// Note that this instantiate a new FFT domain using vk.Size +// Note that this instantiates a new FFT domain using vk.Size func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { _srs := srs.(*kzg.SRS) diff --git a/backend/plonk/bn254/setup.go b/backend/plonk/bn254/setup.go index 815de53b7d..188f78f80f 100644 --- a/backend/plonk/bn254/setup.go +++ b/backend/plonk/bn254/setup.go @@ -23,6 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" "github.com/consensys/gnark-crypto/ecc/bn254/fr/iop" "github.com/consensys/gnark-crypto/ecc/bn254/fr/kzg" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bn254" kzgg "github.com/consensys/gnark-crypto/kzg" @@ -38,6 +39,13 @@ type Trace struct { // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. Ql, Qr, Qm, Qo, Qk *iop.Polynomial + // qcp (in canonical basis). + // QcPrime denotes the constraints defining committed variables + QcPrime []fr.Element + + // qcp (in lagrange coset basis) + lQcPrime []fr.Element + // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. // The set of interpolation is of size N, so to represent the permutation S we let S acts on the // set A=(, u*, u^{2}*) of size 3*N, where u is outside (its use is to shift the set ). @@ -73,7 +81,9 @@ type VerifyingKey struct { // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk kzg.Digest + Ql, Qr, Qm, Qo, Qk, QcPrime kzg.Digest + + CommitmentInfo constraint.Commitment } // ProvingKey stores the data needed to generate a proof: @@ -116,6 +126,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) var pk ProvingKey var vk VerifyingKey pk.Vk = &vk + vk.CommitmentInfo = spr.CommitmentInfo // nbConstraints := len(spr.Constraints) // step 0: set the fft domains @@ -153,6 +164,13 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } + pk.QcPrime = make([]fr.Element, pk.Domain[0].Cardinality) + for _, committed := range spr.CommitmentInfo.Committed { + pk.QcPrime[committed].SetOne() + } + if vk.QcPrime, err = kzg.Commit(pk.QcPrime, vk.KZGSRS); err != nil { + return nil, nil, err + } // step 5: evaluate ql, qr, qm, qo, s1, s2, s3 on LagrangeCoset (NOT qk) // we clone them, because the canonical versions are going to be used in // the opening proof @@ -164,6 +182,9 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset // basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. func (pk *ProvingKey) computeLagrangeCosetPolys() { + wqcpiop := iop.NewPolynomial(clone(pk.QcPrime, pk.Domain[1].Cardinality), iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) + wqcpiop.ToLagrangeCoset(&pk.Domain[1]) + pk.lQcPrime = wqcpiop.Coefficients() pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) @@ -196,7 +217,7 @@ func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { // This should be used after deserializing a VerifyingKey // as vk.KZG is NOT serialized // -// Note that this instantiate a new FFT domain using vk.Size +// Note that this instantiates a new FFT domain using vk.Size func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { _srs := srs.(*kzg.SRS) diff --git a/backend/plonk/bw6-633/setup.go b/backend/plonk/bw6-633/setup.go index 4bcf075b01..41a52d7474 100644 --- a/backend/plonk/bw6-633/setup.go +++ b/backend/plonk/bw6-633/setup.go @@ -23,6 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/fft" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/iop" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/kzg" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bw6-633" kzgg "github.com/consensys/gnark-crypto/kzg" @@ -38,6 +39,13 @@ type Trace struct { // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. Ql, Qr, Qm, Qo, Qk *iop.Polynomial + // qcp (in canonical basis). + // QcPrime denotes the constraints defining committed variables + QcPrime []fr.Element + + // qcp (in lagrange coset basis) + lQcPrime []fr.Element + // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. // The set of interpolation is of size N, so to represent the permutation S we let S acts on the // set A=(, u*, u^{2}*) of size 3*N, where u is outside (its use is to shift the set ). @@ -73,7 +81,9 @@ type VerifyingKey struct { // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk kzg.Digest + Ql, Qr, Qm, Qo, Qk, QcPrime kzg.Digest + + CommitmentInfo constraint.Commitment } // ProvingKey stores the data needed to generate a proof: @@ -116,6 +126,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) var pk ProvingKey var vk VerifyingKey pk.Vk = &vk + vk.CommitmentInfo = spr.CommitmentInfo // nbConstraints := len(spr.Constraints) // step 0: set the fft domains @@ -153,6 +164,13 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } + pk.QcPrime = make([]fr.Element, pk.Domain[0].Cardinality) + for _, committed := range spr.CommitmentInfo.Committed { + pk.QcPrime[committed].SetOne() + } + if vk.QcPrime, err = kzg.Commit(pk.QcPrime, vk.KZGSRS); err != nil { + return nil, nil, err + } // step 5: evaluate ql, qr, qm, qo, s1, s2, s3 on LagrangeCoset (NOT qk) // we clone them, because the canonical versions are going to be used in // the opening proof @@ -164,6 +182,9 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset // basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. func (pk *ProvingKey) computeLagrangeCosetPolys() { + wqcpiop := iop.NewPolynomial(clone(pk.QcPrime, pk.Domain[1].Cardinality), iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) + wqcpiop.ToLagrangeCoset(&pk.Domain[1]) + pk.lQcPrime = wqcpiop.Coefficients() pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) @@ -196,7 +217,7 @@ func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { // This should be used after deserializing a VerifyingKey // as vk.KZG is NOT serialized // -// Note that this instantiate a new FFT domain using vk.Size +// Note that this instantiates a new FFT domain using vk.Size func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { _srs := srs.(*kzg.SRS) diff --git a/backend/plonk/bw6-761/setup.go b/backend/plonk/bw6-761/setup.go index ac49fe86aa..928f7d3ff1 100644 --- a/backend/plonk/bw6-761/setup.go +++ b/backend/plonk/bw6-761/setup.go @@ -23,6 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/fft" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/iop" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/kzg" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bw6-761" kzgg "github.com/consensys/gnark-crypto/kzg" @@ -38,6 +39,13 @@ type Trace struct { // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. Ql, Qr, Qm, Qo, Qk *iop.Polynomial + // qcp (in canonical basis). + // QcPrime denotes the constraints defining committed variables + QcPrime []fr.Element + + // qcp (in lagrange coset basis) + lQcPrime []fr.Element + // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. // The set of interpolation is of size N, so to represent the permutation S we let S acts on the // set A=(, u*, u^{2}*) of size 3*N, where u is outside (its use is to shift the set ). @@ -73,7 +81,9 @@ type VerifyingKey struct { // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk kzg.Digest + Ql, Qr, Qm, Qo, Qk, QcPrime kzg.Digest + + CommitmentInfo constraint.Commitment } // ProvingKey stores the data needed to generate a proof: @@ -116,6 +126,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) var pk ProvingKey var vk VerifyingKey pk.Vk = &vk + vk.CommitmentInfo = spr.CommitmentInfo // nbConstraints := len(spr.Constraints) // step 0: set the fft domains @@ -153,6 +164,13 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } + pk.QcPrime = make([]fr.Element, pk.Domain[0].Cardinality) + for _, committed := range spr.CommitmentInfo.Committed { + pk.QcPrime[committed].SetOne() + } + if vk.QcPrime, err = kzg.Commit(pk.QcPrime, vk.KZGSRS); err != nil { + return nil, nil, err + } // step 5: evaluate ql, qr, qm, qo, s1, s2, s3 on LagrangeCoset (NOT qk) // we clone them, because the canonical versions are going to be used in // the opening proof @@ -164,6 +182,9 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset // basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. func (pk *ProvingKey) computeLagrangeCosetPolys() { + wqcpiop := iop.NewPolynomial(clone(pk.QcPrime, pk.Domain[1].Cardinality), iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) + wqcpiop.ToLagrangeCoset(&pk.Domain[1]) + pk.lQcPrime = wqcpiop.Coefficients() pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) @@ -196,7 +217,7 @@ func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { // This should be used after deserializing a VerifyingKey // as vk.KZG is NOT serialized // -// Note that this instantiate a new FFT domain using vk.Size +// Note that this instantiates a new FFT domain using vk.Size func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { _srs := srs.(*kzg.SRS) From c771cadf00089fbd2ec92047947fd168f37cc59d Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 17 Mar 2023 15:20:50 -0400 Subject: [PATCH 165/464] fix: match latest backend changes in bw6-761 --- backend/plonk/bw6-761/prove.go | 11 ++++----- backend/plonk/bw6-761/setup.go | 41 ++++++++++++++------------------- backend/plonk/bw6-761/verify.go | 2 +- test/commitments_test.go | 4 ++-- 4 files changed, 24 insertions(+), 34 deletions(-) diff --git a/backend/plonk/bw6-761/prove.go b/backend/plonk/bw6-761/prove.go index 0df8b0926e..86e593ef8d 100644 --- a/backend/plonk/bw6-761/prove.go +++ b/backend/plonk/bw6-761/prove.go @@ -227,9 +227,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.ToLagrangeCoset(&pk.Domain[1]) pi2iop := wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form - lagrangeCosetBitReversed := iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse} // we don't mutate so no need to clone the coefficients from the proving key. - wqcpiop := iop.NewPolynomial(&pk.lQcPrime, lagrangeCosetBitReversed) // lagrange coset form canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} lcqk := iop.NewPolynomial(&qkCompletedCanonical, canReg) lcqk.ToLagrangeCoset(&pk.Domain[1]) @@ -331,7 +329,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pk.lcQm, pk.lcQo, lcqk, - wqcpiop, + pk.lcQcp, wloneiop, ) if err != nil { @@ -371,8 +369,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts go evalAtZeta(bwriop, &brzeta) go evalAtZeta(bwoiop, &bozeta) go func() { - qcpiop := iop.NewPolynomial(&pk.QcPrime, canReg) - qcpzeta = qcpiop.Evaluate(zeta) + qcpzeta = pk.trace.Qcp.Evaluate(zeta) wgEvals.Done() }() @@ -460,7 +457,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.Coefficients()[:bwoiop.BlindedSize()], pk.trace.S1.Coefficients(), pk.trace.S2.Coefficients(), - pk.QcPrime, + pk.trace.Qcp.Coefficients(), }, []kzg.Digest{ foldedHDigest, @@ -470,7 +467,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.LRO[2], pk.Vk.S[0], pk.Vk.S[1], - pk.Vk.QcPrime, + pk.Vk.Qcp, }, zeta, hFunc, diff --git a/backend/plonk/bw6-761/setup.go b/backend/plonk/bw6-761/setup.go index 928f7d3ff1..098fbf4dee 100644 --- a/backend/plonk/bw6-761/setup.go +++ b/backend/plonk/bw6-761/setup.go @@ -37,14 +37,7 @@ type Trace struct { // completed by the prover. At those indices i (so from 0 to nb_public_variables), LQl[i]=-1 // so the first nb_public_variables constraints look like this: // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. - Ql, Qr, Qm, Qo, Qk *iop.Polynomial - - // qcp (in canonical basis). - // QcPrime denotes the constraints defining committed variables - QcPrime []fr.Element - - // qcp (in lagrange coset basis) - lQcPrime []fr.Element + Ql, Qr, Qm, Qo, Qk, Qcp *iop.Polynomial // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. // The set of interpolation is of size N, so to represent the permutation S we let S acts on the @@ -81,7 +74,7 @@ type VerifyingKey struct { // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk, QcPrime kzg.Digest + Ql, Qr, Qm, Qo, Qk, Qcp kzg.Digest CommitmentInfo constraint.Commitment } @@ -106,8 +99,8 @@ type ProvingKey struct { // Verifying Key is embedded into the proving key (needed by Prove) Vk *VerifyingKey - // qr,ql,qm,qo in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. - lcQl, lcQr, lcQm, lcQo *iop.Polynomial + // qr,ql,qm,qo,qcp in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo, Qcp once. + lcQl, lcQr, lcQm, lcQo, lcQcp *iop.Polynomial // LQk qk in Lagrange form -> to be completed by the prover. After being completed, lQk *iop.Polynomial @@ -142,7 +135,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } - // step 2: ql, qr, qm, qo, qk in Lagrange Basis + // step 2: ql, qr, qm, qo, qk, qcp in Lagrange Basis BuildTrace(spr, &pk.trace) // step 3: build the permutation and build the polynomials S1, S2, S3 to encode the permutation. @@ -164,13 +157,6 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } - pk.QcPrime = make([]fr.Element, pk.Domain[0].Cardinality) - for _, committed := range spr.CommitmentInfo.Committed { - pk.QcPrime[committed].SetOne() - } - if vk.QcPrime, err = kzg.Commit(pk.QcPrime, vk.KZGSRS); err != nil { - return nil, nil, err - } // step 5: evaluate ql, qr, qm, qo, s1, s2, s3 on LagrangeCoset (NOT qk) // we clone them, because the canonical versions are going to be used in // the opening proof @@ -182,9 +168,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset // basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. func (pk *ProvingKey) computeLagrangeCosetPolys() { - wqcpiop := iop.NewPolynomial(clone(pk.QcPrime, pk.Domain[1].Cardinality), iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) - wqcpiop.ToLagrangeCoset(&pk.Domain[1]) - pk.lQcPrime = wqcpiop.Coefficients() + pk.lcQcp = pk.trace.Qcp.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) @@ -235,15 +219,16 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { nbConstraints := len(spr.Constraints) sizeSystem := uint64(nbConstraints + len(spr.Public)) - size := ecc.NextPowerOfTwo(uint64(sizeSystem)) + size := ecc.NextPowerOfTwo(sizeSystem) ql := make([]fr.Element, size) qr := make([]fr.Element, size) qm := make([]fr.Element, size) qo := make([]fr.Element, size) qk := make([]fr.Element, size) + qcp := make([]fr.Element, size) - for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistant + for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent ql[i].SetOne().Neg(&ql[i]) qr[i].SetZero() qm[i].SetZero() @@ -260,6 +245,9 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } + for _, committed := range spr.CommitmentInfo.Committed { + qcp[committed].SetOne() + } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} @@ -268,6 +256,7 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { pt.Qm = iop.NewPolynomial(&qm, lagReg) pt.Qo = iop.NewPolynomial(&qo, lagReg) pt.Qk = iop.NewPolynomial(&qk, lagReg) + pt.Qcp = iop.NewPolynomial(&qcp, lagReg) } @@ -280,6 +269,7 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { trace.Qm.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qo.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qk.ToCanonical(&pk.Domain[0]).ToRegular() // -> qk is not complete + trace.Qcp.ToCanonical(&pk.Domain[0]).ToRegular() trace.S1.ToCanonical(&pk.Domain[0]).ToRegular() trace.S2.ToCanonical(&pk.Domain[0]).ToRegular() trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() @@ -300,6 +290,9 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Vk.KZGSRS); err != nil { return err } + if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err + } if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Vk.KZGSRS); err != nil { return err } diff --git a/backend/plonk/bw6-761/verify.go b/backend/plonk/bw6-761/verify.go index a3b6f98067..563865fb17 100644 --- a/backend/plonk/bw6-761/verify.go +++ b/backend/plonk/bw6-761/verify.go @@ -235,7 +235,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { proof.LRO[2], vk.S[0], vk.S[1], - vk.QcPrime, + vk.Qcp, }, &proof.BatchedProof, zeta, diff --git a/test/commitments_test.go b/test/commitments_test.go index 7db456ef7b..ae66501343 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -54,13 +54,13 @@ func TestNoCommitmentCircuitPlonk(t *testing.T) { func plonkTest(t *testing.T, circuit, assignment frontend.Circuit) { fr := []ecc.ID{ - ecc.BN254, + /*ecc.BN254, ecc.BLS12_381, ecc.BLS12_377, ecc.BLS24_315, //ecc.BLS12_378, TODO: @Tabaie Not autogenerated? ecc.BLS24_317, - ecc.BW6_633, + ecc.BW6_633,*/ //ecc.BW6_756, TODO: @Tabaie Not autogenerated? ecc.BW6_761, } From 3f63d8dcb8619618721ddb26a840a10ed39b0c11 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 17 Mar 2023 15:39:49 -0400 Subject: [PATCH 166/464] build: generify setup changes --- backend/plonk/bls12-377/setup.go | 45 ++++++++----------- backend/plonk/bls12-381/setup.go | 45 ++++++++----------- backend/plonk/bls24-315/setup.go | 45 ++++++++----------- backend/plonk/bls24-317/setup.go | 45 ++++++++----------- backend/plonk/bn254/setup.go | 45 ++++++++----------- backend/plonk/bw6-633/setup.go | 45 ++++++++----------- backend/plonk/bw6-761/setup.go | 4 +- .../zkpschemes/plonk/plonk.setup.go.tmpl | 45 ++++++++----------- 8 files changed, 135 insertions(+), 184 deletions(-) diff --git a/backend/plonk/bls12-377/setup.go b/backend/plonk/bls12-377/setup.go index 0e59a6a9b8..76df42b111 100644 --- a/backend/plonk/bls12-377/setup.go +++ b/backend/plonk/bls12-377/setup.go @@ -37,14 +37,7 @@ type Trace struct { // completed by the prover. At those indices i (so from 0 to nb_public_variables), LQl[i]=-1 // so the first nb_public_variables constraints look like this: // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. - Ql, Qr, Qm, Qo, Qk *iop.Polynomial - - // qcp (in canonical basis). - // QcPrime denotes the constraints defining committed variables - QcPrime []fr.Element - - // qcp (in lagrange coset basis) - lQcPrime []fr.Element + Ql, Qr, Qm, Qo, Qk, Qcp *iop.Polynomial // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. // The set of interpolation is of size N, so to represent the permutation S we let S acts on the @@ -79,9 +72,9 @@ type VerifyingKey struct { // S commitments to S1, S2, S3 S [3]kzg.Digest - // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. + // Commitments to ql, qr, qm, qo, qcp prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk, QcPrime kzg.Digest + Ql, Qr, Qm, Qo, Qk, Qcp kzg.Digest CommitmentInfo constraint.Commitment } @@ -99,15 +92,15 @@ type ProvingKey struct { // stores ql, qr, qm, qo, qk (-> to be completed by the prover) // and s1, s2, s3. They are set in canonical basis before generating the proof, they will be used // for computing the opening proofs (hence the canonical form). The canonical version - // of qk incompleted is used in the linearisation polynomial. + // of qk incomplete is used in the linearisation polynomial. // The polynomials in trace are in canonical basis. trace Trace // Verifying Key is embedded into the proving key (needed by Prove) Vk *VerifyingKey - // qr,ql,qm,qo in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. - lcQl, lcQr, lcQm, lcQo *iop.Polynomial + // qr,ql,qm,qo,qcp in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo, Qcp once. + lcQl, lcQr, lcQm, lcQo, lcQcp *iop.Polynomial // LQk qk in Lagrange form -> to be completed by the prover. After being completed, lQk *iop.Polynomial @@ -142,7 +135,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } - // step 2: ql, qr, qm, qo, qk in Lagrange Basis + // step 2: ql, qr, qm, qo, qk, qcp in Lagrange Basis BuildTrace(spr, &pk.trace) // step 3: build the permutation and build the polynomials S1, S2, S3 to encode the permutation. @@ -164,13 +157,6 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } - pk.QcPrime = make([]fr.Element, pk.Domain[0].Cardinality) - for _, committed := range spr.CommitmentInfo.Committed { - pk.QcPrime[committed].SetOne() - } - if vk.QcPrime, err = kzg.Commit(pk.QcPrime, vk.KZGSRS); err != nil { - return nil, nil, err - } // step 5: evaluate ql, qr, qm, qo, s1, s2, s3 on LagrangeCoset (NOT qk) // we clone them, because the canonical versions are going to be used in // the opening proof @@ -182,9 +168,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset // basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. func (pk *ProvingKey) computeLagrangeCosetPolys() { - wqcpiop := iop.NewPolynomial(clone(pk.QcPrime, pk.Domain[1].Cardinality), iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) - wqcpiop.ToLagrangeCoset(&pk.Domain[1]) - pk.lQcPrime = wqcpiop.Coefficients() + pk.lcQcp = pk.trace.Qcp.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) @@ -235,15 +219,16 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { nbConstraints := len(spr.Constraints) sizeSystem := uint64(nbConstraints + len(spr.Public)) - size := ecc.NextPowerOfTwo(uint64(sizeSystem)) + size := ecc.NextPowerOfTwo(sizeSystem) ql := make([]fr.Element, size) qr := make([]fr.Element, size) qm := make([]fr.Element, size) qo := make([]fr.Element, size) qk := make([]fr.Element, size) + qcp := make([]fr.Element, size) - for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistant + for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent ql[i].SetOne().Neg(&ql[i]) qr[i].SetZero() qm[i].SetZero() @@ -260,6 +245,9 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } + for _, committed := range spr.CommitmentInfo.Committed { + qcp[committed].SetOne() + } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} @@ -268,6 +256,7 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { pt.Qm = iop.NewPolynomial(&qm, lagReg) pt.Qo = iop.NewPolynomial(&qo, lagReg) pt.Qk = iop.NewPolynomial(&qk, lagReg) + pt.Qcp = iop.NewPolynomial(&qcp, lagReg) } @@ -280,6 +269,7 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { trace.Qm.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qo.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qk.ToCanonical(&pk.Domain[0]).ToRegular() // -> qk is not complete + trace.Qcp.ToCanonical(&pk.Domain[0]).ToRegular() trace.S1.ToCanonical(&pk.Domain[0]).ToRegular() trace.S2.ToCanonical(&pk.Domain[0]).ToRegular() trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() @@ -300,6 +290,9 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Vk.KZGSRS); err != nil { return err } + if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err + } if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Vk.KZGSRS); err != nil { return err } diff --git a/backend/plonk/bls12-381/setup.go b/backend/plonk/bls12-381/setup.go index 2ac4d0bfdc..c74b6ef864 100644 --- a/backend/plonk/bls12-381/setup.go +++ b/backend/plonk/bls12-381/setup.go @@ -37,14 +37,7 @@ type Trace struct { // completed by the prover. At those indices i (so from 0 to nb_public_variables), LQl[i]=-1 // so the first nb_public_variables constraints look like this: // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. - Ql, Qr, Qm, Qo, Qk *iop.Polynomial - - // qcp (in canonical basis). - // QcPrime denotes the constraints defining committed variables - QcPrime []fr.Element - - // qcp (in lagrange coset basis) - lQcPrime []fr.Element + Ql, Qr, Qm, Qo, Qk, Qcp *iop.Polynomial // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. // The set of interpolation is of size N, so to represent the permutation S we let S acts on the @@ -79,9 +72,9 @@ type VerifyingKey struct { // S commitments to S1, S2, S3 S [3]kzg.Digest - // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. + // Commitments to ql, qr, qm, qo, qcp prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk, QcPrime kzg.Digest + Ql, Qr, Qm, Qo, Qk, Qcp kzg.Digest CommitmentInfo constraint.Commitment } @@ -99,15 +92,15 @@ type ProvingKey struct { // stores ql, qr, qm, qo, qk (-> to be completed by the prover) // and s1, s2, s3. They are set in canonical basis before generating the proof, they will be used // for computing the opening proofs (hence the canonical form). The canonical version - // of qk incompleted is used in the linearisation polynomial. + // of qk incomplete is used in the linearisation polynomial. // The polynomials in trace are in canonical basis. trace Trace // Verifying Key is embedded into the proving key (needed by Prove) Vk *VerifyingKey - // qr,ql,qm,qo in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. - lcQl, lcQr, lcQm, lcQo *iop.Polynomial + // qr,ql,qm,qo,qcp in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo, Qcp once. + lcQl, lcQr, lcQm, lcQo, lcQcp *iop.Polynomial // LQk qk in Lagrange form -> to be completed by the prover. After being completed, lQk *iop.Polynomial @@ -142,7 +135,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } - // step 2: ql, qr, qm, qo, qk in Lagrange Basis + // step 2: ql, qr, qm, qo, qk, qcp in Lagrange Basis BuildTrace(spr, &pk.trace) // step 3: build the permutation and build the polynomials S1, S2, S3 to encode the permutation. @@ -164,13 +157,6 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } - pk.QcPrime = make([]fr.Element, pk.Domain[0].Cardinality) - for _, committed := range spr.CommitmentInfo.Committed { - pk.QcPrime[committed].SetOne() - } - if vk.QcPrime, err = kzg.Commit(pk.QcPrime, vk.KZGSRS); err != nil { - return nil, nil, err - } // step 5: evaluate ql, qr, qm, qo, s1, s2, s3 on LagrangeCoset (NOT qk) // we clone them, because the canonical versions are going to be used in // the opening proof @@ -182,9 +168,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset // basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. func (pk *ProvingKey) computeLagrangeCosetPolys() { - wqcpiop := iop.NewPolynomial(clone(pk.QcPrime, pk.Domain[1].Cardinality), iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) - wqcpiop.ToLagrangeCoset(&pk.Domain[1]) - pk.lQcPrime = wqcpiop.Coefficients() + pk.lcQcp = pk.trace.Qcp.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) @@ -235,15 +219,16 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { nbConstraints := len(spr.Constraints) sizeSystem := uint64(nbConstraints + len(spr.Public)) - size := ecc.NextPowerOfTwo(uint64(sizeSystem)) + size := ecc.NextPowerOfTwo(sizeSystem) ql := make([]fr.Element, size) qr := make([]fr.Element, size) qm := make([]fr.Element, size) qo := make([]fr.Element, size) qk := make([]fr.Element, size) + qcp := make([]fr.Element, size) - for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistant + for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent ql[i].SetOne().Neg(&ql[i]) qr[i].SetZero() qm[i].SetZero() @@ -260,6 +245,9 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } + for _, committed := range spr.CommitmentInfo.Committed { + qcp[committed].SetOne() + } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} @@ -268,6 +256,7 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { pt.Qm = iop.NewPolynomial(&qm, lagReg) pt.Qo = iop.NewPolynomial(&qo, lagReg) pt.Qk = iop.NewPolynomial(&qk, lagReg) + pt.Qcp = iop.NewPolynomial(&qcp, lagReg) } @@ -280,6 +269,7 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { trace.Qm.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qo.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qk.ToCanonical(&pk.Domain[0]).ToRegular() // -> qk is not complete + trace.Qcp.ToCanonical(&pk.Domain[0]).ToRegular() trace.S1.ToCanonical(&pk.Domain[0]).ToRegular() trace.S2.ToCanonical(&pk.Domain[0]).ToRegular() trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() @@ -300,6 +290,9 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Vk.KZGSRS); err != nil { return err } + if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err + } if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Vk.KZGSRS); err != nil { return err } diff --git a/backend/plonk/bls24-315/setup.go b/backend/plonk/bls24-315/setup.go index 7f46b14c76..b422638bf3 100644 --- a/backend/plonk/bls24-315/setup.go +++ b/backend/plonk/bls24-315/setup.go @@ -37,14 +37,7 @@ type Trace struct { // completed by the prover. At those indices i (so from 0 to nb_public_variables), LQl[i]=-1 // so the first nb_public_variables constraints look like this: // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. - Ql, Qr, Qm, Qo, Qk *iop.Polynomial - - // qcp (in canonical basis). - // QcPrime denotes the constraints defining committed variables - QcPrime []fr.Element - - // qcp (in lagrange coset basis) - lQcPrime []fr.Element + Ql, Qr, Qm, Qo, Qk, Qcp *iop.Polynomial // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. // The set of interpolation is of size N, so to represent the permutation S we let S acts on the @@ -79,9 +72,9 @@ type VerifyingKey struct { // S commitments to S1, S2, S3 S [3]kzg.Digest - // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. + // Commitments to ql, qr, qm, qo, qcp prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk, QcPrime kzg.Digest + Ql, Qr, Qm, Qo, Qk, Qcp kzg.Digest CommitmentInfo constraint.Commitment } @@ -99,15 +92,15 @@ type ProvingKey struct { // stores ql, qr, qm, qo, qk (-> to be completed by the prover) // and s1, s2, s3. They are set in canonical basis before generating the proof, they will be used // for computing the opening proofs (hence the canonical form). The canonical version - // of qk incompleted is used in the linearisation polynomial. + // of qk incomplete is used in the linearisation polynomial. // The polynomials in trace are in canonical basis. trace Trace // Verifying Key is embedded into the proving key (needed by Prove) Vk *VerifyingKey - // qr,ql,qm,qo in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. - lcQl, lcQr, lcQm, lcQo *iop.Polynomial + // qr,ql,qm,qo,qcp in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo, Qcp once. + lcQl, lcQr, lcQm, lcQo, lcQcp *iop.Polynomial // LQk qk in Lagrange form -> to be completed by the prover. After being completed, lQk *iop.Polynomial @@ -142,7 +135,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } - // step 2: ql, qr, qm, qo, qk in Lagrange Basis + // step 2: ql, qr, qm, qo, qk, qcp in Lagrange Basis BuildTrace(spr, &pk.trace) // step 3: build the permutation and build the polynomials S1, S2, S3 to encode the permutation. @@ -164,13 +157,6 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } - pk.QcPrime = make([]fr.Element, pk.Domain[0].Cardinality) - for _, committed := range spr.CommitmentInfo.Committed { - pk.QcPrime[committed].SetOne() - } - if vk.QcPrime, err = kzg.Commit(pk.QcPrime, vk.KZGSRS); err != nil { - return nil, nil, err - } // step 5: evaluate ql, qr, qm, qo, s1, s2, s3 on LagrangeCoset (NOT qk) // we clone them, because the canonical versions are going to be used in // the opening proof @@ -182,9 +168,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset // basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. func (pk *ProvingKey) computeLagrangeCosetPolys() { - wqcpiop := iop.NewPolynomial(clone(pk.QcPrime, pk.Domain[1].Cardinality), iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) - wqcpiop.ToLagrangeCoset(&pk.Domain[1]) - pk.lQcPrime = wqcpiop.Coefficients() + pk.lcQcp = pk.trace.Qcp.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) @@ -235,15 +219,16 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { nbConstraints := len(spr.Constraints) sizeSystem := uint64(nbConstraints + len(spr.Public)) - size := ecc.NextPowerOfTwo(uint64(sizeSystem)) + size := ecc.NextPowerOfTwo(sizeSystem) ql := make([]fr.Element, size) qr := make([]fr.Element, size) qm := make([]fr.Element, size) qo := make([]fr.Element, size) qk := make([]fr.Element, size) + qcp := make([]fr.Element, size) - for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistant + for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent ql[i].SetOne().Neg(&ql[i]) qr[i].SetZero() qm[i].SetZero() @@ -260,6 +245,9 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } + for _, committed := range spr.CommitmentInfo.Committed { + qcp[committed].SetOne() + } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} @@ -268,6 +256,7 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { pt.Qm = iop.NewPolynomial(&qm, lagReg) pt.Qo = iop.NewPolynomial(&qo, lagReg) pt.Qk = iop.NewPolynomial(&qk, lagReg) + pt.Qcp = iop.NewPolynomial(&qcp, lagReg) } @@ -280,6 +269,7 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { trace.Qm.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qo.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qk.ToCanonical(&pk.Domain[0]).ToRegular() // -> qk is not complete + trace.Qcp.ToCanonical(&pk.Domain[0]).ToRegular() trace.S1.ToCanonical(&pk.Domain[0]).ToRegular() trace.S2.ToCanonical(&pk.Domain[0]).ToRegular() trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() @@ -300,6 +290,9 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Vk.KZGSRS); err != nil { return err } + if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err + } if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Vk.KZGSRS); err != nil { return err } diff --git a/backend/plonk/bls24-317/setup.go b/backend/plonk/bls24-317/setup.go index 03d88876a6..c21a166d84 100644 --- a/backend/plonk/bls24-317/setup.go +++ b/backend/plonk/bls24-317/setup.go @@ -37,14 +37,7 @@ type Trace struct { // completed by the prover. At those indices i (so from 0 to nb_public_variables), LQl[i]=-1 // so the first nb_public_variables constraints look like this: // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. - Ql, Qr, Qm, Qo, Qk *iop.Polynomial - - // qcp (in canonical basis). - // QcPrime denotes the constraints defining committed variables - QcPrime []fr.Element - - // qcp (in lagrange coset basis) - lQcPrime []fr.Element + Ql, Qr, Qm, Qo, Qk, Qcp *iop.Polynomial // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. // The set of interpolation is of size N, so to represent the permutation S we let S acts on the @@ -79,9 +72,9 @@ type VerifyingKey struct { // S commitments to S1, S2, S3 S [3]kzg.Digest - // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. + // Commitments to ql, qr, qm, qo, qcp prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk, QcPrime kzg.Digest + Ql, Qr, Qm, Qo, Qk, Qcp kzg.Digest CommitmentInfo constraint.Commitment } @@ -99,15 +92,15 @@ type ProvingKey struct { // stores ql, qr, qm, qo, qk (-> to be completed by the prover) // and s1, s2, s3. They are set in canonical basis before generating the proof, they will be used // for computing the opening proofs (hence the canonical form). The canonical version - // of qk incompleted is used in the linearisation polynomial. + // of qk incomplete is used in the linearisation polynomial. // The polynomials in trace are in canonical basis. trace Trace // Verifying Key is embedded into the proving key (needed by Prove) Vk *VerifyingKey - // qr,ql,qm,qo in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. - lcQl, lcQr, lcQm, lcQo *iop.Polynomial + // qr,ql,qm,qo,qcp in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo, Qcp once. + lcQl, lcQr, lcQm, lcQo, lcQcp *iop.Polynomial // LQk qk in Lagrange form -> to be completed by the prover. After being completed, lQk *iop.Polynomial @@ -142,7 +135,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } - // step 2: ql, qr, qm, qo, qk in Lagrange Basis + // step 2: ql, qr, qm, qo, qk, qcp in Lagrange Basis BuildTrace(spr, &pk.trace) // step 3: build the permutation and build the polynomials S1, S2, S3 to encode the permutation. @@ -164,13 +157,6 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } - pk.QcPrime = make([]fr.Element, pk.Domain[0].Cardinality) - for _, committed := range spr.CommitmentInfo.Committed { - pk.QcPrime[committed].SetOne() - } - if vk.QcPrime, err = kzg.Commit(pk.QcPrime, vk.KZGSRS); err != nil { - return nil, nil, err - } // step 5: evaluate ql, qr, qm, qo, s1, s2, s3 on LagrangeCoset (NOT qk) // we clone them, because the canonical versions are going to be used in // the opening proof @@ -182,9 +168,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset // basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. func (pk *ProvingKey) computeLagrangeCosetPolys() { - wqcpiop := iop.NewPolynomial(clone(pk.QcPrime, pk.Domain[1].Cardinality), iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) - wqcpiop.ToLagrangeCoset(&pk.Domain[1]) - pk.lQcPrime = wqcpiop.Coefficients() + pk.lcQcp = pk.trace.Qcp.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) @@ -235,15 +219,16 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { nbConstraints := len(spr.Constraints) sizeSystem := uint64(nbConstraints + len(spr.Public)) - size := ecc.NextPowerOfTwo(uint64(sizeSystem)) + size := ecc.NextPowerOfTwo(sizeSystem) ql := make([]fr.Element, size) qr := make([]fr.Element, size) qm := make([]fr.Element, size) qo := make([]fr.Element, size) qk := make([]fr.Element, size) + qcp := make([]fr.Element, size) - for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistant + for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent ql[i].SetOne().Neg(&ql[i]) qr[i].SetZero() qm[i].SetZero() @@ -260,6 +245,9 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } + for _, committed := range spr.CommitmentInfo.Committed { + qcp[committed].SetOne() + } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} @@ -268,6 +256,7 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { pt.Qm = iop.NewPolynomial(&qm, lagReg) pt.Qo = iop.NewPolynomial(&qo, lagReg) pt.Qk = iop.NewPolynomial(&qk, lagReg) + pt.Qcp = iop.NewPolynomial(&qcp, lagReg) } @@ -280,6 +269,7 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { trace.Qm.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qo.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qk.ToCanonical(&pk.Domain[0]).ToRegular() // -> qk is not complete + trace.Qcp.ToCanonical(&pk.Domain[0]).ToRegular() trace.S1.ToCanonical(&pk.Domain[0]).ToRegular() trace.S2.ToCanonical(&pk.Domain[0]).ToRegular() trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() @@ -300,6 +290,9 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Vk.KZGSRS); err != nil { return err } + if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err + } if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Vk.KZGSRS); err != nil { return err } diff --git a/backend/plonk/bn254/setup.go b/backend/plonk/bn254/setup.go index 188f78f80f..8f0a666bb2 100644 --- a/backend/plonk/bn254/setup.go +++ b/backend/plonk/bn254/setup.go @@ -37,14 +37,7 @@ type Trace struct { // completed by the prover. At those indices i (so from 0 to nb_public_variables), LQl[i]=-1 // so the first nb_public_variables constraints look like this: // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. - Ql, Qr, Qm, Qo, Qk *iop.Polynomial - - // qcp (in canonical basis). - // QcPrime denotes the constraints defining committed variables - QcPrime []fr.Element - - // qcp (in lagrange coset basis) - lQcPrime []fr.Element + Ql, Qr, Qm, Qo, Qk, Qcp *iop.Polynomial // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. // The set of interpolation is of size N, so to represent the permutation S we let S acts on the @@ -79,9 +72,9 @@ type VerifyingKey struct { // S commitments to S1, S2, S3 S [3]kzg.Digest - // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. + // Commitments to ql, qr, qm, qo, qcp prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk, QcPrime kzg.Digest + Ql, Qr, Qm, Qo, Qk, Qcp kzg.Digest CommitmentInfo constraint.Commitment } @@ -99,15 +92,15 @@ type ProvingKey struct { // stores ql, qr, qm, qo, qk (-> to be completed by the prover) // and s1, s2, s3. They are set in canonical basis before generating the proof, they will be used // for computing the opening proofs (hence the canonical form). The canonical version - // of qk incompleted is used in the linearisation polynomial. + // of qk incomplete is used in the linearisation polynomial. // The polynomials in trace are in canonical basis. trace Trace // Verifying Key is embedded into the proving key (needed by Prove) Vk *VerifyingKey - // qr,ql,qm,qo in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. - lcQl, lcQr, lcQm, lcQo *iop.Polynomial + // qr,ql,qm,qo,qcp in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo, Qcp once. + lcQl, lcQr, lcQm, lcQo, lcQcp *iop.Polynomial // LQk qk in Lagrange form -> to be completed by the prover. After being completed, lQk *iop.Polynomial @@ -142,7 +135,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } - // step 2: ql, qr, qm, qo, qk in Lagrange Basis + // step 2: ql, qr, qm, qo, qk, qcp in Lagrange Basis BuildTrace(spr, &pk.trace) // step 3: build the permutation and build the polynomials S1, S2, S3 to encode the permutation. @@ -164,13 +157,6 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } - pk.QcPrime = make([]fr.Element, pk.Domain[0].Cardinality) - for _, committed := range spr.CommitmentInfo.Committed { - pk.QcPrime[committed].SetOne() - } - if vk.QcPrime, err = kzg.Commit(pk.QcPrime, vk.KZGSRS); err != nil { - return nil, nil, err - } // step 5: evaluate ql, qr, qm, qo, s1, s2, s3 on LagrangeCoset (NOT qk) // we clone them, because the canonical versions are going to be used in // the opening proof @@ -182,9 +168,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset // basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. func (pk *ProvingKey) computeLagrangeCosetPolys() { - wqcpiop := iop.NewPolynomial(clone(pk.QcPrime, pk.Domain[1].Cardinality), iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) - wqcpiop.ToLagrangeCoset(&pk.Domain[1]) - pk.lQcPrime = wqcpiop.Coefficients() + pk.lcQcp = pk.trace.Qcp.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) @@ -235,15 +219,16 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { nbConstraints := len(spr.Constraints) sizeSystem := uint64(nbConstraints + len(spr.Public)) - size := ecc.NextPowerOfTwo(uint64(sizeSystem)) + size := ecc.NextPowerOfTwo(sizeSystem) ql := make([]fr.Element, size) qr := make([]fr.Element, size) qm := make([]fr.Element, size) qo := make([]fr.Element, size) qk := make([]fr.Element, size) + qcp := make([]fr.Element, size) - for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistant + for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent ql[i].SetOne().Neg(&ql[i]) qr[i].SetZero() qm[i].SetZero() @@ -260,6 +245,9 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } + for _, committed := range spr.CommitmentInfo.Committed { + qcp[committed].SetOne() + } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} @@ -268,6 +256,7 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { pt.Qm = iop.NewPolynomial(&qm, lagReg) pt.Qo = iop.NewPolynomial(&qo, lagReg) pt.Qk = iop.NewPolynomial(&qk, lagReg) + pt.Qcp = iop.NewPolynomial(&qcp, lagReg) } @@ -280,6 +269,7 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { trace.Qm.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qo.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qk.ToCanonical(&pk.Domain[0]).ToRegular() // -> qk is not complete + trace.Qcp.ToCanonical(&pk.Domain[0]).ToRegular() trace.S1.ToCanonical(&pk.Domain[0]).ToRegular() trace.S2.ToCanonical(&pk.Domain[0]).ToRegular() trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() @@ -300,6 +290,9 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Vk.KZGSRS); err != nil { return err } + if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err + } if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Vk.KZGSRS); err != nil { return err } diff --git a/backend/plonk/bw6-633/setup.go b/backend/plonk/bw6-633/setup.go index 41a52d7474..b4f3edf6a3 100644 --- a/backend/plonk/bw6-633/setup.go +++ b/backend/plonk/bw6-633/setup.go @@ -37,14 +37,7 @@ type Trace struct { // completed by the prover. At those indices i (so from 0 to nb_public_variables), LQl[i]=-1 // so the first nb_public_variables constraints look like this: // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. - Ql, Qr, Qm, Qo, Qk *iop.Polynomial - - // qcp (in canonical basis). - // QcPrime denotes the constraints defining committed variables - QcPrime []fr.Element - - // qcp (in lagrange coset basis) - lQcPrime []fr.Element + Ql, Qr, Qm, Qo, Qk, Qcp *iop.Polynomial // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. // The set of interpolation is of size N, so to represent the permutation S we let S acts on the @@ -79,9 +72,9 @@ type VerifyingKey struct { // S commitments to S1, S2, S3 S [3]kzg.Digest - // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. + // Commitments to ql, qr, qm, qo, qcp prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk, QcPrime kzg.Digest + Ql, Qr, Qm, Qo, Qk, Qcp kzg.Digest CommitmentInfo constraint.Commitment } @@ -99,15 +92,15 @@ type ProvingKey struct { // stores ql, qr, qm, qo, qk (-> to be completed by the prover) // and s1, s2, s3. They are set in canonical basis before generating the proof, they will be used // for computing the opening proofs (hence the canonical form). The canonical version - // of qk incompleted is used in the linearisation polynomial. + // of qk incomplete is used in the linearisation polynomial. // The polynomials in trace are in canonical basis. trace Trace // Verifying Key is embedded into the proving key (needed by Prove) Vk *VerifyingKey - // qr,ql,qm,qo in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. - lcQl, lcQr, lcQm, lcQo *iop.Polynomial + // qr,ql,qm,qo,qcp in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo, Qcp once. + lcQl, lcQr, lcQm, lcQo, lcQcp *iop.Polynomial // LQk qk in Lagrange form -> to be completed by the prover. After being completed, lQk *iop.Polynomial @@ -142,7 +135,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } - // step 2: ql, qr, qm, qo, qk in Lagrange Basis + // step 2: ql, qr, qm, qo, qk, qcp in Lagrange Basis BuildTrace(spr, &pk.trace) // step 3: build the permutation and build the polynomials S1, S2, S3 to encode the permutation. @@ -164,13 +157,6 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } - pk.QcPrime = make([]fr.Element, pk.Domain[0].Cardinality) - for _, committed := range spr.CommitmentInfo.Committed { - pk.QcPrime[committed].SetOne() - } - if vk.QcPrime, err = kzg.Commit(pk.QcPrime, vk.KZGSRS); err != nil { - return nil, nil, err - } // step 5: evaluate ql, qr, qm, qo, s1, s2, s3 on LagrangeCoset (NOT qk) // we clone them, because the canonical versions are going to be used in // the opening proof @@ -182,9 +168,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset // basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. func (pk *ProvingKey) computeLagrangeCosetPolys() { - wqcpiop := iop.NewPolynomial(clone(pk.QcPrime, pk.Domain[1].Cardinality), iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) - wqcpiop.ToLagrangeCoset(&pk.Domain[1]) - pk.lQcPrime = wqcpiop.Coefficients() + pk.lcQcp = pk.trace.Qcp.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) @@ -235,15 +219,16 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { nbConstraints := len(spr.Constraints) sizeSystem := uint64(nbConstraints + len(spr.Public)) - size := ecc.NextPowerOfTwo(uint64(sizeSystem)) + size := ecc.NextPowerOfTwo(sizeSystem) ql := make([]fr.Element, size) qr := make([]fr.Element, size) qm := make([]fr.Element, size) qo := make([]fr.Element, size) qk := make([]fr.Element, size) + qcp := make([]fr.Element, size) - for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistant + for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent ql[i].SetOne().Neg(&ql[i]) qr[i].SetZero() qm[i].SetZero() @@ -260,6 +245,9 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } + for _, committed := range spr.CommitmentInfo.Committed { + qcp[committed].SetOne() + } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} @@ -268,6 +256,7 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { pt.Qm = iop.NewPolynomial(&qm, lagReg) pt.Qo = iop.NewPolynomial(&qo, lagReg) pt.Qk = iop.NewPolynomial(&qk, lagReg) + pt.Qcp = iop.NewPolynomial(&qcp, lagReg) } @@ -280,6 +269,7 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { trace.Qm.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qo.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qk.ToCanonical(&pk.Domain[0]).ToRegular() // -> qk is not complete + trace.Qcp.ToCanonical(&pk.Domain[0]).ToRegular() trace.S1.ToCanonical(&pk.Domain[0]).ToRegular() trace.S2.ToCanonical(&pk.Domain[0]).ToRegular() trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() @@ -300,6 +290,9 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Vk.KZGSRS); err != nil { return err } + if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err + } if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Vk.KZGSRS); err != nil { return err } diff --git a/backend/plonk/bw6-761/setup.go b/backend/plonk/bw6-761/setup.go index 098fbf4dee..b37b2dda55 100644 --- a/backend/plonk/bw6-761/setup.go +++ b/backend/plonk/bw6-761/setup.go @@ -72,7 +72,7 @@ type VerifyingKey struct { // S commitments to S1, S2, S3 S [3]kzg.Digest - // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. + // Commitments to ql, qr, qm, qo, qcp prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. Ql, Qr, Qm, Qo, Qk, Qcp kzg.Digest @@ -92,7 +92,7 @@ type ProvingKey struct { // stores ql, qr, qm, qo, qk (-> to be completed by the prover) // and s1, s2, s3. They are set in canonical basis before generating the proof, they will be used // for computing the opening proofs (hence the canonical form). The canonical version - // of qk incompleted is used in the linearisation polynomial. + // of qk incomplete is used in the linearisation polynomial. // The polynomials in trace are in canonical basis. trace Trace diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl index 32f3fbb5a6..955b638132 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl @@ -19,14 +19,7 @@ type Trace struct { // completed by the prover. At those indices i (so from 0 to nb_public_variables), LQl[i]=-1 // so the first nb_public_variables constraints look like this: // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. - Ql, Qr, Qm, Qo, Qk *iop.Polynomial - - // qcp (in canonical basis). - // QcPrime denotes the constraints defining committed variables - QcPrime []fr.Element - - // qcp (in lagrange coset basis) - lQcPrime []fr.Element + Ql, Qr, Qm, Qo, Qk, Qcp *iop.Polynomial // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. // The set of interpolation is of size N, so to represent the permutation S we let S acts on the @@ -61,9 +54,9 @@ type VerifyingKey struct { // S commitments to S1, S2, S3 S [3]kzg.Digest - // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. + // Commitments to ql, qr, qm, qo, qcp prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk, QcPrime kzg.Digest + Ql, Qr, Qm, Qo, Qk, Qcp kzg.Digest CommitmentInfo constraint.Commitment } @@ -81,15 +74,15 @@ type ProvingKey struct { // stores ql, qr, qm, qo, qk (-> to be completed by the prover) // and s1, s2, s3. They are set in canonical basis before generating the proof, they will be used // for computing the opening proofs (hence the canonical form). The canonical version - // of qk incompleted is used in the linearisation polynomial. + // of qk incomplete is used in the linearisation polynomial. // The polynomials in trace are in canonical basis. trace Trace // Verifying Key is embedded into the proving key (needed by Prove) Vk *VerifyingKey - // qr,ql,qm,qo in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo once. - lcQl, lcQr, lcQm, lcQo *iop.Polynomial + // qr,ql,qm,qo,qcp in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo, Qcp once. + lcQl, lcQr, lcQm, lcQo, lcQcp *iop.Polynomial // LQk qk in Lagrange form -> to be completed by the prover. After being completed, lQk *iop.Polynomial @@ -124,7 +117,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } - // step 2: ql, qr, qm, qo, qk in Lagrange Basis + // step 2: ql, qr, qm, qo, qk, qcp in Lagrange Basis BuildTrace(spr, &pk.trace) // step 3: build the permutation and build the polynomials S1, S2, S3 to encode the permutation. @@ -146,13 +139,6 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) return nil, nil, err } - pk.QcPrime = make([]fr.Element, pk.Domain[0].Cardinality) - for _, committed := range spr.CommitmentInfo.Committed { - pk.QcPrime[committed].SetOne() - } - if vk.QcPrime, err = kzg.Commit(pk.QcPrime, vk.KZGSRS); err != nil { - return nil, nil, err - } // step 5: evaluate ql, qr, qm, qo, s1, s2, s3 on LagrangeCoset (NOT qk) // we clone them, because the canonical versions are going to be used in // the opening proof @@ -164,9 +150,7 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) // computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset // basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. func (pk *ProvingKey) computeLagrangeCosetPolys() { - wqcpiop := iop.NewPolynomial(clone(pk.QcPrime, pk.Domain[1].Cardinality), iop.Form{Basis: iop.Canonical, Layout: iop.Regular}) - wqcpiop.ToLagrangeCoset(&pk.Domain[1]) - pk.lQcPrime = wqcpiop.Coefficients() + pk.lcQcp = pk.trace.Qcp.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) @@ -217,15 +201,16 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { nbConstraints := len(spr.Constraints) sizeSystem := uint64(nbConstraints + len(spr.Public)) - size := ecc.NextPowerOfTwo(uint64(sizeSystem)) + size := ecc.NextPowerOfTwo(sizeSystem) ql := make([]fr.Element, size) qr := make([]fr.Element, size) qm := make([]fr.Element, size) qo := make([]fr.Element, size) qk := make([]fr.Element, size) + qcp := make([]fr.Element, size) - for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistant + for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent ql[i].SetOne().Neg(&ql[i]) qr[i].SetZero() qm[i].SetZero() @@ -242,6 +227,9 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } + for _, committed := range spr.CommitmentInfo.Committed { + qcp[committed].SetOne() + } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} @@ -250,6 +238,7 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { pt.Qm = iop.NewPolynomial(&qm, lagReg) pt.Qo = iop.NewPolynomial(&qo, lagReg) pt.Qk = iop.NewPolynomial(&qk, lagReg) + pt.Qcp = iop.NewPolynomial(&qcp, lagReg) } @@ -262,6 +251,7 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { trace.Qm.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qo.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qk.ToCanonical(&pk.Domain[0]).ToRegular() // -> qk is not complete + trace.Qcp.ToCanonical(&pk.Domain[0]).ToRegular() trace.S1.ToCanonical(&pk.Domain[0]).ToRegular() trace.S2.ToCanonical(&pk.Domain[0]).ToRegular() trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() @@ -282,6 +272,9 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Vk.KZGSRS); err != nil { return err } + if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Vk.KZGSRS); err != nil { + return err + } if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Vk.KZGSRS); err != nil { return err } From 6d54a3095572ee13d12943b189868f34b054e5d2 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 17 Mar 2023 15:42:55 -0400 Subject: [PATCH 167/464] build: generify prover changes --- backend/plonk/bls12-377/prove.go | 11 ++++------- backend/plonk/bls12-381/prove.go | 11 ++++------- backend/plonk/bls24-315/prove.go | 11 ++++------- backend/plonk/bls24-317/prove.go | 11 ++++------- backend/plonk/bn254/prove.go | 11 ++++------- backend/plonk/bw6-633/prove.go | 11 ++++------- .../template/zkpschemes/plonk/plonk.prove.go.tmpl | 11 ++++------- 7 files changed, 28 insertions(+), 49 deletions(-) diff --git a/backend/plonk/bls12-377/prove.go b/backend/plonk/bls12-377/prove.go index 1cd45b72a9..7bf2495024 100644 --- a/backend/plonk/bls12-377/prove.go +++ b/backend/plonk/bls12-377/prove.go @@ -227,9 +227,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.ToLagrangeCoset(&pk.Domain[1]) pi2iop := wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form - lagrangeCosetBitReversed := iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse} // we don't mutate so no need to clone the coefficients from the proving key. - wqcpiop := iop.NewPolynomial(&pk.lQcPrime, lagrangeCosetBitReversed) // lagrange coset form canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} lcqk := iop.NewPolynomial(&qkCompletedCanonical, canReg) lcqk.ToLagrangeCoset(&pk.Domain[1]) @@ -331,7 +329,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pk.lcQm, pk.lcQo, lcqk, - wqcpiop, + pk.lcQcp, wloneiop, ) if err != nil { @@ -371,8 +369,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts go evalAtZeta(bwriop, &brzeta) go evalAtZeta(bwoiop, &bozeta) go func() { - qcpiop := iop.NewPolynomial(&pk.QcPrime, canReg) - qcpzeta = qcpiop.Evaluate(zeta) + qcpzeta = pk.trace.Qcp.Evaluate(zeta) wgEvals.Done() }() @@ -460,7 +457,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.Coefficients()[:bwoiop.BlindedSize()], pk.trace.S1.Coefficients(), pk.trace.S2.Coefficients(), - pk.QcPrime, + pk.trace.Qcp.Coefficients(), }, []kzg.Digest{ foldedHDigest, @@ -470,7 +467,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.LRO[2], pk.Vk.S[0], pk.Vk.S[1], - pk.Vk.QcPrime, + pk.Vk.Qcp, }, zeta, hFunc, diff --git a/backend/plonk/bls12-381/prove.go b/backend/plonk/bls12-381/prove.go index 1f0bd49654..b3bcae3c22 100644 --- a/backend/plonk/bls12-381/prove.go +++ b/backend/plonk/bls12-381/prove.go @@ -227,9 +227,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.ToLagrangeCoset(&pk.Domain[1]) pi2iop := wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form - lagrangeCosetBitReversed := iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse} // we don't mutate so no need to clone the coefficients from the proving key. - wqcpiop := iop.NewPolynomial(&pk.lQcPrime, lagrangeCosetBitReversed) // lagrange coset form canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} lcqk := iop.NewPolynomial(&qkCompletedCanonical, canReg) lcqk.ToLagrangeCoset(&pk.Domain[1]) @@ -331,7 +329,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pk.lcQm, pk.lcQo, lcqk, - wqcpiop, + pk.lcQcp, wloneiop, ) if err != nil { @@ -371,8 +369,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts go evalAtZeta(bwriop, &brzeta) go evalAtZeta(bwoiop, &bozeta) go func() { - qcpiop := iop.NewPolynomial(&pk.QcPrime, canReg) - qcpzeta = qcpiop.Evaluate(zeta) + qcpzeta = pk.trace.Qcp.Evaluate(zeta) wgEvals.Done() }() @@ -460,7 +457,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.Coefficients()[:bwoiop.BlindedSize()], pk.trace.S1.Coefficients(), pk.trace.S2.Coefficients(), - pk.QcPrime, + pk.trace.Qcp.Coefficients(), }, []kzg.Digest{ foldedHDigest, @@ -470,7 +467,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.LRO[2], pk.Vk.S[0], pk.Vk.S[1], - pk.Vk.QcPrime, + pk.Vk.Qcp, }, zeta, hFunc, diff --git a/backend/plonk/bls24-315/prove.go b/backend/plonk/bls24-315/prove.go index 70b861164a..7a4866ae71 100644 --- a/backend/plonk/bls24-315/prove.go +++ b/backend/plonk/bls24-315/prove.go @@ -227,9 +227,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.ToLagrangeCoset(&pk.Domain[1]) pi2iop := wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form - lagrangeCosetBitReversed := iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse} // we don't mutate so no need to clone the coefficients from the proving key. - wqcpiop := iop.NewPolynomial(&pk.lQcPrime, lagrangeCosetBitReversed) // lagrange coset form canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} lcqk := iop.NewPolynomial(&qkCompletedCanonical, canReg) lcqk.ToLagrangeCoset(&pk.Domain[1]) @@ -331,7 +329,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pk.lcQm, pk.lcQo, lcqk, - wqcpiop, + pk.lcQcp, wloneiop, ) if err != nil { @@ -371,8 +369,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts go evalAtZeta(bwriop, &brzeta) go evalAtZeta(bwoiop, &bozeta) go func() { - qcpiop := iop.NewPolynomial(&pk.QcPrime, canReg) - qcpzeta = qcpiop.Evaluate(zeta) + qcpzeta = pk.trace.Qcp.Evaluate(zeta) wgEvals.Done() }() @@ -460,7 +457,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.Coefficients()[:bwoiop.BlindedSize()], pk.trace.S1.Coefficients(), pk.trace.S2.Coefficients(), - pk.QcPrime, + pk.trace.Qcp.Coefficients(), }, []kzg.Digest{ foldedHDigest, @@ -470,7 +467,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.LRO[2], pk.Vk.S[0], pk.Vk.S[1], - pk.Vk.QcPrime, + pk.Vk.Qcp, }, zeta, hFunc, diff --git a/backend/plonk/bls24-317/prove.go b/backend/plonk/bls24-317/prove.go index 70d7e0476d..d2b4571337 100644 --- a/backend/plonk/bls24-317/prove.go +++ b/backend/plonk/bls24-317/prove.go @@ -227,9 +227,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.ToLagrangeCoset(&pk.Domain[1]) pi2iop := wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form - lagrangeCosetBitReversed := iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse} // we don't mutate so no need to clone the coefficients from the proving key. - wqcpiop := iop.NewPolynomial(&pk.lQcPrime, lagrangeCosetBitReversed) // lagrange coset form canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} lcqk := iop.NewPolynomial(&qkCompletedCanonical, canReg) lcqk.ToLagrangeCoset(&pk.Domain[1]) @@ -331,7 +329,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pk.lcQm, pk.lcQo, lcqk, - wqcpiop, + pk.lcQcp, wloneiop, ) if err != nil { @@ -371,8 +369,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts go evalAtZeta(bwriop, &brzeta) go evalAtZeta(bwoiop, &bozeta) go func() { - qcpiop := iop.NewPolynomial(&pk.QcPrime, canReg) - qcpzeta = qcpiop.Evaluate(zeta) + qcpzeta = pk.trace.Qcp.Evaluate(zeta) wgEvals.Done() }() @@ -460,7 +457,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.Coefficients()[:bwoiop.BlindedSize()], pk.trace.S1.Coefficients(), pk.trace.S2.Coefficients(), - pk.QcPrime, + pk.trace.Qcp.Coefficients(), }, []kzg.Digest{ foldedHDigest, @@ -470,7 +467,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.LRO[2], pk.Vk.S[0], pk.Vk.S[1], - pk.Vk.QcPrime, + pk.Vk.Qcp, }, zeta, hFunc, diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index da584458d8..82de08be40 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -227,9 +227,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.ToLagrangeCoset(&pk.Domain[1]) pi2iop := wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form - lagrangeCosetBitReversed := iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse} // we don't mutate so no need to clone the coefficients from the proving key. - wqcpiop := iop.NewPolynomial(&pk.lQcPrime, lagrangeCosetBitReversed) // lagrange coset form canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} lcqk := iop.NewPolynomial(&qkCompletedCanonical, canReg) lcqk.ToLagrangeCoset(&pk.Domain[1]) @@ -331,7 +329,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pk.lcQm, pk.lcQo, lcqk, - wqcpiop, + pk.lcQcp, wloneiop, ) if err != nil { @@ -371,8 +369,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts go evalAtZeta(bwriop, &brzeta) go evalAtZeta(bwoiop, &bozeta) go func() { - qcpiop := iop.NewPolynomial(&pk.QcPrime, canReg) - qcpzeta = qcpiop.Evaluate(zeta) + qcpzeta = pk.trace.Qcp.Evaluate(zeta) wgEvals.Done() }() @@ -460,7 +457,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.Coefficients()[:bwoiop.BlindedSize()], pk.trace.S1.Coefficients(), pk.trace.S2.Coefficients(), - pk.QcPrime, + pk.trace.Qcp.Coefficients(), }, []kzg.Digest{ foldedHDigest, @@ -470,7 +467,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.LRO[2], pk.Vk.S[0], pk.Vk.S[1], - pk.Vk.QcPrime, + pk.Vk.Qcp, }, zeta, hFunc, diff --git a/backend/plonk/bw6-633/prove.go b/backend/plonk/bw6-633/prove.go index daffaa0ba3..44c6d3c744 100644 --- a/backend/plonk/bw6-633/prove.go +++ b/backend/plonk/bw6-633/prove.go @@ -227,9 +227,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.ToLagrangeCoset(&pk.Domain[1]) pi2iop := wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form - lagrangeCosetBitReversed := iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse} // we don't mutate so no need to clone the coefficients from the proving key. - wqcpiop := iop.NewPolynomial(&pk.lQcPrime, lagrangeCosetBitReversed) // lagrange coset form canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} lcqk := iop.NewPolynomial(&qkCompletedCanonical, canReg) lcqk.ToLagrangeCoset(&pk.Domain[1]) @@ -331,7 +329,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pk.lcQm, pk.lcQo, lcqk, - wqcpiop, + pk.lcQcp, wloneiop, ) if err != nil { @@ -371,8 +369,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts go evalAtZeta(bwriop, &brzeta) go evalAtZeta(bwoiop, &bozeta) go func() { - qcpiop := iop.NewPolynomial(&pk.QcPrime, canReg) - qcpzeta = qcpiop.Evaluate(zeta) + qcpzeta = pk.trace.Qcp.Evaluate(zeta) wgEvals.Done() }() @@ -460,7 +457,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.Coefficients()[:bwoiop.BlindedSize()], pk.trace.S1.Coefficients(), pk.trace.S2.Coefficients(), - pk.QcPrime, + pk.trace.Qcp.Coefficients(), }, []kzg.Digest{ foldedHDigest, @@ -470,7 +467,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.LRO[2], pk.Vk.S[0], pk.Vk.S[1], - pk.Vk.QcPrime, + pk.Vk.Qcp, }, zeta, hFunc, diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl index ea06d0d527..f74fea95aa 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl @@ -205,9 +205,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.ToLagrangeCoset(&pk.Domain[1]) pi2iop := wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form - lagrangeCosetBitReversed := iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse} // we don't mutate so no need to clone the coefficients from the proving key. - wqcpiop := iop.NewPolynomial(&pk.lQcPrime, lagrangeCosetBitReversed) // lagrange coset form canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} lcqk := iop.NewPolynomial(&qkCompletedCanonical, canReg) lcqk.ToLagrangeCoset(&pk.Domain[1]) @@ -309,7 +307,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pk.lcQm, pk.lcQo, lcqk, - wqcpiop, + pk.lcQcp, wloneiop, ) if err != nil { @@ -349,8 +347,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts go evalAtZeta(bwriop, &brzeta) go evalAtZeta(bwoiop, &bozeta) go func() { - qcpiop := iop.NewPolynomial(&pk.QcPrime, canReg) - qcpzeta = qcpiop.Evaluate(zeta) + qcpzeta = pk.trace.Qcp.Evaluate(zeta) wgEvals.Done() }() @@ -438,7 +435,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.Coefficients()[:bwoiop.BlindedSize()], pk.trace.S1.Coefficients(), pk.trace.S2.Coefficients(), - pk.QcPrime, + pk.trace.Qcp.Coefficients(), }, []kzg.Digest{ foldedHDigest, @@ -448,7 +445,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.LRO[2], pk.Vk.S[0], pk.Vk.S[1], - pk.Vk.QcPrime, + pk.Vk.Qcp, }, zeta, hFunc, From 425e849465a051f977fc7eaa96dc7b5aca07b43f Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 17 Mar 2023 15:43:24 -0400 Subject: [PATCH 168/464] build: generify verifier changes --- backend/plonk/bls12-377/verify.go | 2 +- backend/plonk/bls12-381/verify.go | 2 +- backend/plonk/bls24-315/verify.go | 2 +- backend/plonk/bls24-317/verify.go | 2 +- backend/plonk/bn254/verify.go | 2 +- backend/plonk/bw6-633/verify.go | 2 +- .../backend/template/zkpschemes/plonk/plonk.verify.go.tmpl | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/backend/plonk/bls12-377/verify.go b/backend/plonk/bls12-377/verify.go index b5348e6eb6..59fb95c6f6 100644 --- a/backend/plonk/bls12-377/verify.go +++ b/backend/plonk/bls12-377/verify.go @@ -235,7 +235,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { proof.LRO[2], vk.S[0], vk.S[1], - vk.QcPrime, + vk.Qcp, }, &proof.BatchedProof, zeta, diff --git a/backend/plonk/bls12-381/verify.go b/backend/plonk/bls12-381/verify.go index ad37fe5a83..548596e415 100644 --- a/backend/plonk/bls12-381/verify.go +++ b/backend/plonk/bls12-381/verify.go @@ -235,7 +235,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { proof.LRO[2], vk.S[0], vk.S[1], - vk.QcPrime, + vk.Qcp, }, &proof.BatchedProof, zeta, diff --git a/backend/plonk/bls24-315/verify.go b/backend/plonk/bls24-315/verify.go index d0dffbb352..fcd50ea35c 100644 --- a/backend/plonk/bls24-315/verify.go +++ b/backend/plonk/bls24-315/verify.go @@ -235,7 +235,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { proof.LRO[2], vk.S[0], vk.S[1], - vk.QcPrime, + vk.Qcp, }, &proof.BatchedProof, zeta, diff --git a/backend/plonk/bls24-317/verify.go b/backend/plonk/bls24-317/verify.go index 94b80ee88a..e98d8487c1 100644 --- a/backend/plonk/bls24-317/verify.go +++ b/backend/plonk/bls24-317/verify.go @@ -235,7 +235,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { proof.LRO[2], vk.S[0], vk.S[1], - vk.QcPrime, + vk.Qcp, }, &proof.BatchedProof, zeta, diff --git a/backend/plonk/bn254/verify.go b/backend/plonk/bn254/verify.go index 8795d9e2d1..5d7296fb28 100644 --- a/backend/plonk/bn254/verify.go +++ b/backend/plonk/bn254/verify.go @@ -237,7 +237,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { proof.LRO[2], vk.S[0], vk.S[1], - vk.QcPrime, + vk.Qcp, }, &proof.BatchedProof, zeta, diff --git a/backend/plonk/bw6-633/verify.go b/backend/plonk/bw6-633/verify.go index 14c1d2c18e..51f7e19df4 100644 --- a/backend/plonk/bw6-633/verify.go +++ b/backend/plonk/bw6-633/verify.go @@ -235,7 +235,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { proof.LRO[2], vk.S[0], vk.S[1], - vk.QcPrime, + vk.Qcp, }, &proof.BatchedProof, zeta, diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl index 66b0436352..2d313e28bc 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl @@ -216,7 +216,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { proof.LRO[2], vk.S[0], vk.S[1], - vk.QcPrime, + vk.Qcp, }, &proof.BatchedProof, zeta, From 9e87acb6fb6aeaa39bf5d6774d35184fb35f7198 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 17 Mar 2023 16:46:15 -0400 Subject: [PATCH 169/464] fix: bsb22 in plonk with public vars --- backend/plonk/bn254/prove.go | 7 ++++--- backend/plonk/bn254/setup.go | 2 +- backend/plonk/bn254/verify.go | 2 +- backend/plonk/bw6-761/verify.go | 2 +- test/commitments_test.go | 27 ++++++++++++++++++--------- 5 files changed, 25 insertions(+), 15 deletions(-) diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index 82de08be40..d083007f42 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -90,14 +90,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if spr.CommitmentInfo.Is() { opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo.HintID, func(_ *big.Int, ins, outs []*big.Int) error { pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + offset := spr.GetNbPublicVariables() for i := range ins { - pi2[spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) + pi2[offset+spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - if _, err = pi2[spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { + if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { return err } pi2iop := iop.NewPolynomial(&pi2, lagReg) @@ -216,7 +217,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts copy(qkCompletedCanonical, lqkcoef) copy(qkCompletedCanonical, fw[:len(spr.Public)]) if spr.CommitmentInfo.Is() { - qkCompletedCanonical[spr.CommitmentInfo.CommitmentIndex] = commitmentVal + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) diff --git a/backend/plonk/bn254/setup.go b/backend/plonk/bn254/setup.go index 8f0a666bb2..8c1c4c4e2b 100644 --- a/backend/plonk/bn254/setup.go +++ b/backend/plonk/bn254/setup.go @@ -246,7 +246,7 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } for _, committed := range spr.CommitmentInfo.Committed { - qcp[committed].SetOne() + qcp[offset+committed].SetOne() } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} diff --git a/backend/plonk/bn254/verify.go b/backend/plonk/bn254/verify.go index 5d7296fb28..73882d690f 100644 --- a/backend/plonk/bn254/verify.go +++ b/backend/plonk/bn254/verify.go @@ -120,7 +120,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // Computing L_{CommitmentIndex} - wPowI.Exp(vk.Generator, big.NewInt(int64(vk.CommitmentInfo.CommitmentIndex))) + wPowI.Exp(vk.Generator, big.NewInt(int64(vk.NbPublicVariables)+int64(vk.CommitmentInfo.CommitmentIndex))) den.Sub(&zeta, &wPowI) // ζ-wⁱ lagrange.SetOne(). diff --git a/backend/plonk/bw6-761/verify.go b/backend/plonk/bw6-761/verify.go index 563865fb17..19271d8758 100644 --- a/backend/plonk/bw6-761/verify.go +++ b/backend/plonk/bw6-761/verify.go @@ -118,7 +118,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // Computing L_{CommitmentIndex} - wPowI.Exp(vk.Generator, big.NewInt(int64(vk.CommitmentInfo.CommitmentIndex))) + wPowI.Exp(vk.Generator, big.NewInt(int64(vk.NbPublicVariables)+int64(vk.CommitmentInfo.CommitmentIndex))) den.Sub(&zeta, &wPowI) // ζ-wⁱ lagrange.SetOne(). diff --git a/test/commitments_test.go b/test/commitments_test.go index ae66501343..05c0b4c5e6 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -12,7 +12,8 @@ import ( ) type commitmentCircuit struct { - X []frontend.Variable + Public []frontend.Variable `gnark:",public"` + X []frontend.Variable } func (c *commitmentCircuit) Define(api frontend.API) error { @@ -20,20 +21,28 @@ func (c *commitmentCircuit) Define(api frontend.API) error { if err == nil { api.AssertIsDifferent(commitment, 0) } + for _, p := range c.Public { + api.AssertIsEqual(p, 0) + } return err } func (c *commitmentCircuit) hollow() frontend.Circuit { - return &commitmentCircuit{make([]frontend.Variable, len(c.X))} + return &commitmentCircuit{Public: make([]frontend.Variable, len(c.Public)), X: make([]frontend.Variable, len(c.X))} } func TestSingleCommitmentPlonk(t *testing.T) { - assignment := &commitmentCircuit{[]frontend.Variable{1}} + assignment := &commitmentCircuit{X: []frontend.Variable{1}, Public: []frontend.Variable{}} plonkTest(t, assignment.hollow(), assignment) } func TestFiveCommitmentsPlonk(t *testing.T) { - assignment := &commitmentCircuit{[]frontend.Variable{1, 2, 3, 4, 5}} + assignment := &commitmentCircuit{X: []frontend.Variable{1, 2, 3, 4, 5}, Public: []frontend.Variable{}} + plonkTest(t, assignment.hollow(), assignment) +} + +func TestSingleCommitmentSinglePublicPlonk(t *testing.T) { + assignment := &commitmentCircuit{X: []frontend.Variable{0}, Public: []frontend.Variable{0}} plonkTest(t, assignment.hollow(), assignment) } @@ -54,15 +63,15 @@ func TestNoCommitmentCircuitPlonk(t *testing.T) { func plonkTest(t *testing.T, circuit, assignment frontend.Circuit) { fr := []ecc.ID{ - /*ecc.BN254, - ecc.BLS12_381, - ecc.BLS12_377, + ecc.BN254, + //ecc.BLS12_381, + /*ecc.BLS12_377, ecc.BLS24_315, //ecc.BLS12_378, TODO: @Tabaie Not autogenerated? ecc.BLS24_317, - ecc.BW6_633,*/ + ecc.BW6_633, //ecc.BW6_756, TODO: @Tabaie Not autogenerated? - ecc.BW6_761, + ecc.BW6_761,*/ } run := func(mod *big.Int) func(t *testing.T) { From 382d04b40bf1b9afc41a1bace31758cc40843848 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 17 Mar 2023 16:47:17 -0400 Subject: [PATCH 170/464] test: public values --- test/commitments_test.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/commitments_test.go b/test/commitments_test.go index 05c0b4c5e6..87a47a55c6 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -22,7 +22,7 @@ func (c *commitmentCircuit) Define(api frontend.API) error { api.AssertIsDifferent(commitment, 0) } for _, p := range c.Public { - api.AssertIsEqual(p, 0) + api.AssertIsDifferent(p, 0) } return err } @@ -42,7 +42,12 @@ func TestFiveCommitmentsPlonk(t *testing.T) { } func TestSingleCommitmentSinglePublicPlonk(t *testing.T) { - assignment := &commitmentCircuit{X: []frontend.Variable{0}, Public: []frontend.Variable{0}} + assignment := &commitmentCircuit{X: []frontend.Variable{0}, Public: []frontend.Variable{1}} + plonkTest(t, assignment.hollow(), assignment) +} + +func TestFiveCommitmentsFivePublicPlonk(t *testing.T) { + assignment := &commitmentCircuit{X: []frontend.Variable{0, 1, 2, 3, 4}, Public: []frontend.Variable{1, 2, 3, 4, 5}} plonkTest(t, assignment.hollow(), assignment) } From bbaad2d3ecafe8d9346d23391e043bc5f212166c Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 17 Mar 2023 16:51:25 -0400 Subject: [PATCH 171/464] build: generify public var fix --- backend/plonk/bls12-377/prove.go | 7 ++++--- backend/plonk/bls12-377/setup.go | 2 +- backend/plonk/bls12-377/verify.go | 2 +- backend/plonk/bls12-381/prove.go | 7 ++++--- backend/plonk/bls12-381/setup.go | 2 +- backend/plonk/bls12-381/verify.go | 2 +- backend/plonk/bls24-315/prove.go | 7 ++++--- backend/plonk/bls24-315/setup.go | 2 +- backend/plonk/bls24-315/verify.go | 2 +- backend/plonk/bls24-317/prove.go | 7 ++++--- backend/plonk/bls24-317/setup.go | 2 +- backend/plonk/bls24-317/verify.go | 2 +- backend/plonk/bw6-633/prove.go | 7 ++++--- backend/plonk/bw6-633/setup.go | 2 +- backend/plonk/bw6-633/verify.go | 2 +- backend/plonk/bw6-761/prove.go | 7 ++++--- backend/plonk/bw6-761/setup.go | 2 +- .../backend/template/zkpschemes/plonk/plonk.prove.go.tmpl | 7 ++++--- .../backend/template/zkpschemes/plonk/plonk.setup.go.tmpl | 2 +- .../backend/template/zkpschemes/plonk/plonk.verify.go.tmpl | 2 +- test/commitments_test.go | 6 +++--- 21 files changed, 44 insertions(+), 37 deletions(-) diff --git a/backend/plonk/bls12-377/prove.go b/backend/plonk/bls12-377/prove.go index 7bf2495024..be489c2cc4 100644 --- a/backend/plonk/bls12-377/prove.go +++ b/backend/plonk/bls12-377/prove.go @@ -90,14 +90,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if spr.CommitmentInfo.Is() { opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo.HintID, func(_ *big.Int, ins, outs []*big.Int) error { pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + offset := spr.GetNbPublicVariables() for i := range ins { - pi2[spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) + pi2[offset+spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - if _, err = pi2[spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { + if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { return err } pi2iop := iop.NewPolynomial(&pi2, lagReg) @@ -216,7 +217,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts copy(qkCompletedCanonical, lqkcoef) copy(qkCompletedCanonical, fw[:len(spr.Public)]) if spr.CommitmentInfo.Is() { - qkCompletedCanonical[spr.CommitmentInfo.CommitmentIndex] = commitmentVal + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) diff --git a/backend/plonk/bls12-377/setup.go b/backend/plonk/bls12-377/setup.go index 76df42b111..252a127f4d 100644 --- a/backend/plonk/bls12-377/setup.go +++ b/backend/plonk/bls12-377/setup.go @@ -246,7 +246,7 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } for _, committed := range spr.CommitmentInfo.Committed { - qcp[committed].SetOne() + qcp[offset+committed].SetOne() } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} diff --git a/backend/plonk/bls12-377/verify.go b/backend/plonk/bls12-377/verify.go index 59fb95c6f6..0ebce1d17b 100644 --- a/backend/plonk/bls12-377/verify.go +++ b/backend/plonk/bls12-377/verify.go @@ -118,7 +118,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // Computing L_{CommitmentIndex} - wPowI.Exp(vk.Generator, big.NewInt(int64(vk.CommitmentInfo.CommitmentIndex))) + wPowI.Exp(vk.Generator, big.NewInt(int64(vk.NbPublicVariables)+int64(vk.CommitmentInfo.CommitmentIndex))) den.Sub(&zeta, &wPowI) // ζ-wⁱ lagrange.SetOne(). diff --git a/backend/plonk/bls12-381/prove.go b/backend/plonk/bls12-381/prove.go index b3bcae3c22..d7ddcac799 100644 --- a/backend/plonk/bls12-381/prove.go +++ b/backend/plonk/bls12-381/prove.go @@ -90,14 +90,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if spr.CommitmentInfo.Is() { opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo.HintID, func(_ *big.Int, ins, outs []*big.Int) error { pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + offset := spr.GetNbPublicVariables() for i := range ins { - pi2[spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) + pi2[offset+spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - if _, err = pi2[spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { + if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { return err } pi2iop := iop.NewPolynomial(&pi2, lagReg) @@ -216,7 +217,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts copy(qkCompletedCanonical, lqkcoef) copy(qkCompletedCanonical, fw[:len(spr.Public)]) if spr.CommitmentInfo.Is() { - qkCompletedCanonical[spr.CommitmentInfo.CommitmentIndex] = commitmentVal + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) diff --git a/backend/plonk/bls12-381/setup.go b/backend/plonk/bls12-381/setup.go index c74b6ef864..588b72b35d 100644 --- a/backend/plonk/bls12-381/setup.go +++ b/backend/plonk/bls12-381/setup.go @@ -246,7 +246,7 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } for _, committed := range spr.CommitmentInfo.Committed { - qcp[committed].SetOne() + qcp[offset+committed].SetOne() } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} diff --git a/backend/plonk/bls12-381/verify.go b/backend/plonk/bls12-381/verify.go index 548596e415..26aab2c350 100644 --- a/backend/plonk/bls12-381/verify.go +++ b/backend/plonk/bls12-381/verify.go @@ -118,7 +118,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // Computing L_{CommitmentIndex} - wPowI.Exp(vk.Generator, big.NewInt(int64(vk.CommitmentInfo.CommitmentIndex))) + wPowI.Exp(vk.Generator, big.NewInt(int64(vk.NbPublicVariables)+int64(vk.CommitmentInfo.CommitmentIndex))) den.Sub(&zeta, &wPowI) // ζ-wⁱ lagrange.SetOne(). diff --git a/backend/plonk/bls24-315/prove.go b/backend/plonk/bls24-315/prove.go index 7a4866ae71..6f25f2c8e4 100644 --- a/backend/plonk/bls24-315/prove.go +++ b/backend/plonk/bls24-315/prove.go @@ -90,14 +90,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if spr.CommitmentInfo.Is() { opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo.HintID, func(_ *big.Int, ins, outs []*big.Int) error { pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + offset := spr.GetNbPublicVariables() for i := range ins { - pi2[spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) + pi2[offset+spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - if _, err = pi2[spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { + if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { return err } pi2iop := iop.NewPolynomial(&pi2, lagReg) @@ -216,7 +217,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts copy(qkCompletedCanonical, lqkcoef) copy(qkCompletedCanonical, fw[:len(spr.Public)]) if spr.CommitmentInfo.Is() { - qkCompletedCanonical[spr.CommitmentInfo.CommitmentIndex] = commitmentVal + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) diff --git a/backend/plonk/bls24-315/setup.go b/backend/plonk/bls24-315/setup.go index b422638bf3..bf4c04a9b7 100644 --- a/backend/plonk/bls24-315/setup.go +++ b/backend/plonk/bls24-315/setup.go @@ -246,7 +246,7 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } for _, committed := range spr.CommitmentInfo.Committed { - qcp[committed].SetOne() + qcp[offset+committed].SetOne() } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} diff --git a/backend/plonk/bls24-315/verify.go b/backend/plonk/bls24-315/verify.go index fcd50ea35c..5a68363b93 100644 --- a/backend/plonk/bls24-315/verify.go +++ b/backend/plonk/bls24-315/verify.go @@ -118,7 +118,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // Computing L_{CommitmentIndex} - wPowI.Exp(vk.Generator, big.NewInt(int64(vk.CommitmentInfo.CommitmentIndex))) + wPowI.Exp(vk.Generator, big.NewInt(int64(vk.NbPublicVariables)+int64(vk.CommitmentInfo.CommitmentIndex))) den.Sub(&zeta, &wPowI) // ζ-wⁱ lagrange.SetOne(). diff --git a/backend/plonk/bls24-317/prove.go b/backend/plonk/bls24-317/prove.go index d2b4571337..b33a2426f8 100644 --- a/backend/plonk/bls24-317/prove.go +++ b/backend/plonk/bls24-317/prove.go @@ -90,14 +90,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if spr.CommitmentInfo.Is() { opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo.HintID, func(_ *big.Int, ins, outs []*big.Int) error { pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + offset := spr.GetNbPublicVariables() for i := range ins { - pi2[spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) + pi2[offset+spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - if _, err = pi2[spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { + if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { return err } pi2iop := iop.NewPolynomial(&pi2, lagReg) @@ -216,7 +217,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts copy(qkCompletedCanonical, lqkcoef) copy(qkCompletedCanonical, fw[:len(spr.Public)]) if spr.CommitmentInfo.Is() { - qkCompletedCanonical[spr.CommitmentInfo.CommitmentIndex] = commitmentVal + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) diff --git a/backend/plonk/bls24-317/setup.go b/backend/plonk/bls24-317/setup.go index c21a166d84..d7917e3a36 100644 --- a/backend/plonk/bls24-317/setup.go +++ b/backend/plonk/bls24-317/setup.go @@ -246,7 +246,7 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } for _, committed := range spr.CommitmentInfo.Committed { - qcp[committed].SetOne() + qcp[offset+committed].SetOne() } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} diff --git a/backend/plonk/bls24-317/verify.go b/backend/plonk/bls24-317/verify.go index e98d8487c1..ad716138e9 100644 --- a/backend/plonk/bls24-317/verify.go +++ b/backend/plonk/bls24-317/verify.go @@ -118,7 +118,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // Computing L_{CommitmentIndex} - wPowI.Exp(vk.Generator, big.NewInt(int64(vk.CommitmentInfo.CommitmentIndex))) + wPowI.Exp(vk.Generator, big.NewInt(int64(vk.NbPublicVariables)+int64(vk.CommitmentInfo.CommitmentIndex))) den.Sub(&zeta, &wPowI) // ζ-wⁱ lagrange.SetOne(). diff --git a/backend/plonk/bw6-633/prove.go b/backend/plonk/bw6-633/prove.go index 44c6d3c744..0b32012975 100644 --- a/backend/plonk/bw6-633/prove.go +++ b/backend/plonk/bw6-633/prove.go @@ -90,14 +90,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if spr.CommitmentInfo.Is() { opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo.HintID, func(_ *big.Int, ins, outs []*big.Int) error { pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + offset := spr.GetNbPublicVariables() for i := range ins { - pi2[spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) + pi2[offset+spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - if _, err = pi2[spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { + if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { return err } pi2iop := iop.NewPolynomial(&pi2, lagReg) @@ -216,7 +217,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts copy(qkCompletedCanonical, lqkcoef) copy(qkCompletedCanonical, fw[:len(spr.Public)]) if spr.CommitmentInfo.Is() { - qkCompletedCanonical[spr.CommitmentInfo.CommitmentIndex] = commitmentVal + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) diff --git a/backend/plonk/bw6-633/setup.go b/backend/plonk/bw6-633/setup.go index b4f3edf6a3..9ecea2e1c2 100644 --- a/backend/plonk/bw6-633/setup.go +++ b/backend/plonk/bw6-633/setup.go @@ -246,7 +246,7 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } for _, committed := range spr.CommitmentInfo.Committed { - qcp[committed].SetOne() + qcp[offset+committed].SetOne() } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} diff --git a/backend/plonk/bw6-633/verify.go b/backend/plonk/bw6-633/verify.go index 51f7e19df4..1389c4cad6 100644 --- a/backend/plonk/bw6-633/verify.go +++ b/backend/plonk/bw6-633/verify.go @@ -118,7 +118,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // Computing L_{CommitmentIndex} - wPowI.Exp(vk.Generator, big.NewInt(int64(vk.CommitmentInfo.CommitmentIndex))) + wPowI.Exp(vk.Generator, big.NewInt(int64(vk.NbPublicVariables)+int64(vk.CommitmentInfo.CommitmentIndex))) den.Sub(&zeta, &wPowI) // ζ-wⁱ lagrange.SetOne(). diff --git a/backend/plonk/bw6-761/prove.go b/backend/plonk/bw6-761/prove.go index 86e593ef8d..1cf7510bb7 100644 --- a/backend/plonk/bw6-761/prove.go +++ b/backend/plonk/bw6-761/prove.go @@ -90,14 +90,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if spr.CommitmentInfo.Is() { opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo.HintID, func(_ *big.Int, ins, outs []*big.Int) error { pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + offset := spr.GetNbPublicVariables() for i := range ins { - pi2[spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) + pi2[offset+spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - if _, err = pi2[spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { + if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { return err } pi2iop := iop.NewPolynomial(&pi2, lagReg) @@ -216,7 +217,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts copy(qkCompletedCanonical, lqkcoef) copy(qkCompletedCanonical, fw[:len(spr.Public)]) if spr.CommitmentInfo.Is() { - qkCompletedCanonical[spr.CommitmentInfo.CommitmentIndex] = commitmentVal + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) diff --git a/backend/plonk/bw6-761/setup.go b/backend/plonk/bw6-761/setup.go index b37b2dda55..fc5326bbff 100644 --- a/backend/plonk/bw6-761/setup.go +++ b/backend/plonk/bw6-761/setup.go @@ -246,7 +246,7 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } for _, committed := range spr.CommitmentInfo.Committed { - qcp[committed].SetOne() + qcp[offset+committed].SetOne() } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl index f74fea95aa..66b35ea21e 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl @@ -68,14 +68,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if spr.CommitmentInfo.Is() { opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo.HintID, func(_ *big.Int, ins, outs []*big.Int) error { pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + offset := spr.GetNbPublicVariables() for i := range ins { - pi2[spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) + pi2[offset+spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - if _, err = pi2[spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { + if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { return err } pi2iop := iop.NewPolynomial(&pi2, lagReg) @@ -194,7 +195,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts copy(qkCompletedCanonical, lqkcoef) copy(qkCompletedCanonical, fw[:len(spr.Public)]) if spr.CommitmentInfo.Is() { - qkCompletedCanonical[spr.CommitmentInfo.CommitmentIndex] = commitmentVal + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl index 955b638132..541ce66125 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl @@ -228,7 +228,7 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) } for _, committed := range spr.CommitmentInfo.Committed { - qcp[committed].SetOne() + qcp[offset+committed].SetOne() } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl index 2d313e28bc..279ce11260 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl @@ -99,7 +99,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // Computing L_{CommitmentIndex} - wPowI.Exp(vk.Generator, big.NewInt(int64(vk.CommitmentInfo.CommitmentIndex))) + wPowI.Exp(vk.Generator, big.NewInt(int64(vk.NbPublicVariables)+int64(vk.CommitmentInfo.CommitmentIndex))) den.Sub(&zeta, &wPowI) // ζ-wⁱ lagrange.SetOne(). diff --git a/test/commitments_test.go b/test/commitments_test.go index 87a47a55c6..4b1f5a3486 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -69,14 +69,14 @@ func plonkTest(t *testing.T, circuit, assignment frontend.Circuit) { fr := []ecc.ID{ ecc.BN254, - //ecc.BLS12_381, - /*ecc.BLS12_377, + ecc.BLS12_381, + ecc.BLS12_377, ecc.BLS24_315, //ecc.BLS12_378, TODO: @Tabaie Not autogenerated? ecc.BLS24_317, ecc.BW6_633, //ecc.BW6_756, TODO: @Tabaie Not autogenerated? - ecc.BW6_761,*/ + ecc.BW6_761, } run := func(mod *big.Int) func(t *testing.T) { From 745919fbe1ecb1a4dbd05d2ad6ed5deb3aad8c8e Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 17 Mar 2023 17:04:43 -0400 Subject: [PATCH 172/464] fix: add pi2 to fs - bn254 --- backend/plonk/bn254/prove.go | 2 +- backend/plonk/bn254/verify.go | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index d083007f42..0e40705ac3 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -160,7 +160,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)]); err != nil { + if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.PI2); err != nil { return nil, err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) // TODO @Tabaie @ThomasPiellard add BSB commitment here? diff --git a/backend/plonk/bn254/verify.go b/backend/plonk/bn254/verify.go index 73882d690f..2e34906da9 100644 --- a/backend/plonk/bn254/verify.go +++ b/backend/plonk/bn254/verify.go @@ -53,7 +53,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *vk, publicWitness); err != nil { + if err := bindPublicData(&fs, "gamma", *vk, publicWitness, proof.PI2); err != nil { return err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) @@ -124,9 +124,9 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { den.Sub(&zeta, &wPowI) // ζ-wⁱ lagrange.SetOne(). - Sub(&zeta, &lagrange). // ζ-1 - Mul(&lagrange, &wPowI). // wⁱ(ζ-1) - Div(&lagrange, &den). // wⁱ(ζ-1)/(ζ-wⁱ) + Sub(&zeta, &lagrange). // ζ-1 + Mul(&lagrange, &wPowI). // wⁱ(ζ-1) + Div(&lagrange, &den). // wⁱ(ζ-1)/(ζ-wⁱ) Mul(&lagrange, &lagrangeOne) // wⁱ/n (ζⁿ-1)/(ζ-wⁱ) xiLi.Mul(&lagrange, &hashRes[0]) @@ -161,8 +161,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { Mul(&alphaSquareLagrange, &alpha) // α²*L₁(ζ) linearizedPolynomialZeta. - Add(&linearizedPolynomialZeta, &pi). // linearizedpolynomial + pi(zeta) - Add(&linearizedPolynomialZeta, &_s1). // linearizedpolynomial+pi(zeta)+α*(Z(μζ))*(l(ζ)+s1(ζ)+γ)*(r(ζ)+s2(ζ)+γ)*(o(ζ)+γ) + Add(&linearizedPolynomialZeta, &pi). // linearizedpolynomial + pi(zeta) + Add(&linearizedPolynomialZeta, &_s1). // linearizedpolynomial+pi(zeta)+α*(Z(μζ))*(l(ζ)+s1(ζ)+γ)*(r(ζ)+s2(ζ)+γ)*(o(ζ)+γ) Sub(&linearizedPolynomialZeta, &alphaSquareLagrange) // linearizedpolynomial+pi(zeta)+α*(Z(μζ))*(l(ζ)+s1(ζ)+γ)*(r(ζ)+s2(ζ)+γ)*(o(ζ)+γ)-α²*L₁(ζ) // Compute H(ζ) using the previous result: H(ζ) = prev_result/(ζⁿ-1) @@ -270,7 +270,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } -func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element) error { +func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element, pi2 kzg.Digest) error { // permutation if err := fs.Bind(challenge, vk.S[0].Marshal()); err != nil { @@ -307,6 +307,11 @@ func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey } } + // bsb22 commitment + if err := fs.Bind(challenge, pi2.Marshal()); err != nil { + return err + } + return nil } From 6fc52d2120e64846a32b23ab8b7a1638918b8d79 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 17 Mar 2023 17:17:17 -0400 Subject: [PATCH 173/464] fix: double blind commitment --- backend/plonk/bls12-377/prove.go | 7 +++++-- backend/plonk/bls12-377/verify.go | 9 +++++++-- backend/plonk/bls12-381/prove.go | 7 +++++-- backend/plonk/bls12-381/verify.go | 9 +++++++-- backend/plonk/bls24-315/prove.go | 7 +++++-- backend/plonk/bls24-315/verify.go | 9 +++++++-- backend/plonk/bls24-317/prove.go | 7 +++++-- backend/plonk/bls24-317/verify.go | 9 +++++++-- backend/plonk/bn254/prove.go | 5 ++++- backend/plonk/bn254/verify.go | 10 +++++----- backend/plonk/bw6-633/prove.go | 7 +++++-- backend/plonk/bw6-633/verify.go | 9 +++++++-- backend/plonk/bw6-761/prove.go | 7 +++++-- backend/plonk/bw6-761/verify.go | 9 +++++++-- .../template/zkpschemes/plonk/plonk.prove.go.tmpl | 7 +++++-- 15 files changed, 86 insertions(+), 32 deletions(-) diff --git a/backend/plonk/bls12-377/prove.go b/backend/plonk/bls12-377/prove.go index be489c2cc4..5b4f00d77e 100644 --- a/backend/plonk/bls12-377/prove.go +++ b/backend/plonk/bls12-377/prove.go @@ -98,7 +98,10 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts err error hashRes []fr.Element ) - if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { + if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + return err + } + if _, err = pi2[offset+len(spr.Constraints)-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding return err } pi2iop := iop.NewPolynomial(&pi2, lagReg) @@ -160,7 +163,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)]); err != nil { + if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.PI2); err != nil { return nil, err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) // TODO @Tabaie @ThomasPiellard add BSB commitment here? diff --git a/backend/plonk/bls12-377/verify.go b/backend/plonk/bls12-377/verify.go index 0ebce1d17b..65c7881cf6 100644 --- a/backend/plonk/bls12-377/verify.go +++ b/backend/plonk/bls12-377/verify.go @@ -51,7 +51,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *vk, publicWitness); err != nil { + if err := bindPublicData(&fs, "gamma", *vk, publicWitness, proof.PI2); err != nil { return err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) @@ -268,7 +268,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } -func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element) error { +func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element, pi2 kzg.Digest) error { // permutation if err := fs.Bind(challenge, vk.S[0].Marshal()); err != nil { @@ -305,6 +305,11 @@ func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey } } + // bsb22 commitment + if err := fs.Bind(challenge, pi2.Marshal()); err != nil { + return err + } + return nil } diff --git a/backend/plonk/bls12-381/prove.go b/backend/plonk/bls12-381/prove.go index d7ddcac799..1272865ecb 100644 --- a/backend/plonk/bls12-381/prove.go +++ b/backend/plonk/bls12-381/prove.go @@ -98,7 +98,10 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts err error hashRes []fr.Element ) - if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { + if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + return err + } + if _, err = pi2[offset+len(spr.Constraints)-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding return err } pi2iop := iop.NewPolynomial(&pi2, lagReg) @@ -160,7 +163,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)]); err != nil { + if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.PI2); err != nil { return nil, err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) // TODO @Tabaie @ThomasPiellard add BSB commitment here? diff --git a/backend/plonk/bls12-381/verify.go b/backend/plonk/bls12-381/verify.go index 26aab2c350..92d6451ab9 100644 --- a/backend/plonk/bls12-381/verify.go +++ b/backend/plonk/bls12-381/verify.go @@ -51,7 +51,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *vk, publicWitness); err != nil { + if err := bindPublicData(&fs, "gamma", *vk, publicWitness, proof.PI2); err != nil { return err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) @@ -268,7 +268,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } -func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element) error { +func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element, pi2 kzg.Digest) error { // permutation if err := fs.Bind(challenge, vk.S[0].Marshal()); err != nil { @@ -305,6 +305,11 @@ func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey } } + // bsb22 commitment + if err := fs.Bind(challenge, pi2.Marshal()); err != nil { + return err + } + return nil } diff --git a/backend/plonk/bls24-315/prove.go b/backend/plonk/bls24-315/prove.go index 6f25f2c8e4..30a78e3000 100644 --- a/backend/plonk/bls24-315/prove.go +++ b/backend/plonk/bls24-315/prove.go @@ -98,7 +98,10 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts err error hashRes []fr.Element ) - if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { + if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + return err + } + if _, err = pi2[offset+len(spr.Constraints)-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding return err } pi2iop := iop.NewPolynomial(&pi2, lagReg) @@ -160,7 +163,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)]); err != nil { + if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.PI2); err != nil { return nil, err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) // TODO @Tabaie @ThomasPiellard add BSB commitment here? diff --git a/backend/plonk/bls24-315/verify.go b/backend/plonk/bls24-315/verify.go index 5a68363b93..ca0b800e58 100644 --- a/backend/plonk/bls24-315/verify.go +++ b/backend/plonk/bls24-315/verify.go @@ -51,7 +51,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *vk, publicWitness); err != nil { + if err := bindPublicData(&fs, "gamma", *vk, publicWitness, proof.PI2); err != nil { return err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) @@ -268,7 +268,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } -func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element) error { +func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element, pi2 kzg.Digest) error { // permutation if err := fs.Bind(challenge, vk.S[0].Marshal()); err != nil { @@ -305,6 +305,11 @@ func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey } } + // bsb22 commitment + if err := fs.Bind(challenge, pi2.Marshal()); err != nil { + return err + } + return nil } diff --git a/backend/plonk/bls24-317/prove.go b/backend/plonk/bls24-317/prove.go index b33a2426f8..bf364c4dbb 100644 --- a/backend/plonk/bls24-317/prove.go +++ b/backend/plonk/bls24-317/prove.go @@ -98,7 +98,10 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts err error hashRes []fr.Element ) - if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { + if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + return err + } + if _, err = pi2[offset+len(spr.Constraints)-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding return err } pi2iop := iop.NewPolynomial(&pi2, lagReg) @@ -160,7 +163,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)]); err != nil { + if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.PI2); err != nil { return nil, err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) // TODO @Tabaie @ThomasPiellard add BSB commitment here? diff --git a/backend/plonk/bls24-317/verify.go b/backend/plonk/bls24-317/verify.go index ad716138e9..aecdd94022 100644 --- a/backend/plonk/bls24-317/verify.go +++ b/backend/plonk/bls24-317/verify.go @@ -51,7 +51,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *vk, publicWitness); err != nil { + if err := bindPublicData(&fs, "gamma", *vk, publicWitness, proof.PI2); err != nil { return err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) @@ -268,7 +268,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } -func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element) error { +func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element, pi2 kzg.Digest) error { // permutation if err := fs.Bind(challenge, vk.S[0].Marshal()); err != nil { @@ -305,6 +305,11 @@ func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey } } + // bsb22 commitment + if err := fs.Bind(challenge, pi2.Marshal()); err != nil { + return err + } + return nil } diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index 0e40705ac3..229c1de144 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -98,7 +98,10 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts err error hashRes []fr.Element ) - if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { + if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + return err + } + if _, err = pi2[offset+len(spr.Constraints)-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding return err } pi2iop := iop.NewPolynomial(&pi2, lagReg) diff --git a/backend/plonk/bn254/verify.go b/backend/plonk/bn254/verify.go index 2e34906da9..1785fa23d0 100644 --- a/backend/plonk/bn254/verify.go +++ b/backend/plonk/bn254/verify.go @@ -124,9 +124,9 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { den.Sub(&zeta, &wPowI) // ζ-wⁱ lagrange.SetOne(). - Sub(&zeta, &lagrange). // ζ-1 - Mul(&lagrange, &wPowI). // wⁱ(ζ-1) - Div(&lagrange, &den). // wⁱ(ζ-1)/(ζ-wⁱ) + Sub(&zeta, &lagrange). // ζ-1 + Mul(&lagrange, &wPowI). // wⁱ(ζ-1) + Div(&lagrange, &den). // wⁱ(ζ-1)/(ζ-wⁱ) Mul(&lagrange, &lagrangeOne) // wⁱ/n (ζⁿ-1)/(ζ-wⁱ) xiLi.Mul(&lagrange, &hashRes[0]) @@ -161,8 +161,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { Mul(&alphaSquareLagrange, &alpha) // α²*L₁(ζ) linearizedPolynomialZeta. - Add(&linearizedPolynomialZeta, &pi). // linearizedpolynomial + pi(zeta) - Add(&linearizedPolynomialZeta, &_s1). // linearizedpolynomial+pi(zeta)+α*(Z(μζ))*(l(ζ)+s1(ζ)+γ)*(r(ζ)+s2(ζ)+γ)*(o(ζ)+γ) + Add(&linearizedPolynomialZeta, &pi). // linearizedpolynomial + pi(zeta) + Add(&linearizedPolynomialZeta, &_s1). // linearizedpolynomial+pi(zeta)+α*(Z(μζ))*(l(ζ)+s1(ζ)+γ)*(r(ζ)+s2(ζ)+γ)*(o(ζ)+γ) Sub(&linearizedPolynomialZeta, &alphaSquareLagrange) // linearizedpolynomial+pi(zeta)+α*(Z(μζ))*(l(ζ)+s1(ζ)+γ)*(r(ζ)+s2(ζ)+γ)*(o(ζ)+γ)-α²*L₁(ζ) // Compute H(ζ) using the previous result: H(ζ) = prev_result/(ζⁿ-1) diff --git a/backend/plonk/bw6-633/prove.go b/backend/plonk/bw6-633/prove.go index 0b32012975..41e00da496 100644 --- a/backend/plonk/bw6-633/prove.go +++ b/backend/plonk/bw6-633/prove.go @@ -98,7 +98,10 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts err error hashRes []fr.Element ) - if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { + if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + return err + } + if _, err = pi2[offset+len(spr.Constraints)-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding return err } pi2iop := iop.NewPolynomial(&pi2, lagReg) @@ -160,7 +163,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)]); err != nil { + if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.PI2); err != nil { return nil, err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) // TODO @Tabaie @ThomasPiellard add BSB commitment here? diff --git a/backend/plonk/bw6-633/verify.go b/backend/plonk/bw6-633/verify.go index 1389c4cad6..bd0cb0e853 100644 --- a/backend/plonk/bw6-633/verify.go +++ b/backend/plonk/bw6-633/verify.go @@ -51,7 +51,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *vk, publicWitness); err != nil { + if err := bindPublicData(&fs, "gamma", *vk, publicWitness, proof.PI2); err != nil { return err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) @@ -268,7 +268,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } -func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element) error { +func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element, pi2 kzg.Digest) error { // permutation if err := fs.Bind(challenge, vk.S[0].Marshal()); err != nil { @@ -305,6 +305,11 @@ func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey } } + // bsb22 commitment + if err := fs.Bind(challenge, pi2.Marshal()); err != nil { + return err + } + return nil } diff --git a/backend/plonk/bw6-761/prove.go b/backend/plonk/bw6-761/prove.go index 1cf7510bb7..f844d7b22a 100644 --- a/backend/plonk/bw6-761/prove.go +++ b/backend/plonk/bw6-761/prove.go @@ -98,7 +98,10 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts err error hashRes []fr.Element ) - if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { + if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + return err + } + if _, err = pi2[offset+len(spr.Constraints)-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding return err } pi2iop := iop.NewPolynomial(&pi2, lagReg) @@ -160,7 +163,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)]); err != nil { + if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.PI2); err != nil { return nil, err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) // TODO @Tabaie @ThomasPiellard add BSB commitment here? diff --git a/backend/plonk/bw6-761/verify.go b/backend/plonk/bw6-761/verify.go index 19271d8758..71fa48eacb 100644 --- a/backend/plonk/bw6-761/verify.go +++ b/backend/plonk/bw6-761/verify.go @@ -51,7 +51,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *vk, publicWitness); err != nil { + if err := bindPublicData(&fs, "gamma", *vk, publicWitness, proof.PI2); err != nil { return err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) @@ -268,7 +268,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } -func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element) error { +func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element, pi2 kzg.Digest) error { // permutation if err := fs.Bind(challenge, vk.S[0].Marshal()); err != nil { @@ -305,6 +305,11 @@ func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey } } + // bsb22 commitment + if err := fs.Bind(challenge, pi2.Marshal()); err != nil { + return err + } + return nil } diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl index 66b35ea21e..5e08e165d2 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl @@ -76,7 +76,10 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts err error hashRes []fr.Element ) - if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { + if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + return err + } + if _, err = pi2[offset+len(spr.Constraints)-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding return err } pi2iop := iop.NewPolynomial(&pi2, lagReg) @@ -138,7 +141,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)]); err != nil { + if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.PI2); err != nil { return nil, err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) // TODO @Tabaie @ThomasPiellard add BSB commitment here? From 7fb9f0a95a586d3556254a96235bfccd517fb78a Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 17 Mar 2023 17:17:31 -0400 Subject: [PATCH 174/464] build: generify hashing pi2 --- .../template/zkpschemes/plonk/plonk.verify.go.tmpl | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl index 279ce11260..c6823ec6c5 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl @@ -32,7 +32,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *vk, publicWitness); err != nil { + if err := bindPublicData(&fs, "gamma", *vk, publicWitness, proof.PI2); err != nil { return err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) @@ -249,7 +249,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } -func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element) error { +func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element, pi2 kzg.Digest) error { // permutation if err := fs.Bind(challenge, vk.S[0].Marshal()); err != nil { @@ -286,6 +286,11 @@ func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey } } + // bsb22 commitment + if err := fs.Bind(challenge, pi2.Marshal()); err != nil { + return err + } + return nil } From a218ad1ec972532d6f1b3f6ecfc8f3bcff96a9f6 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 17 Mar 2023 17:40:27 -0400 Subject: [PATCH 175/464] fix: marshaling tests - plonk --- backend/plonk/bls12-377/marshal.go | 9 ++++++++- backend/plonk/bls12-377/marshal_test.go | 4 ++++ backend/plonk/bls12-381/marshal.go | 9 ++++++++- backend/plonk/bls12-381/marshal_test.go | 4 ++++ backend/plonk/bls24-315/marshal.go | 9 ++++++++- backend/plonk/bls24-315/marshal_test.go | 4 ++++ backend/plonk/bls24-317/marshal.go | 9 ++++++++- backend/plonk/bls24-317/marshal_test.go | 4 ++++ backend/plonk/bn254/marshal.go | 9 ++++++++- backend/plonk/bn254/marshal_test.go | 4 ++++ backend/plonk/bw6-633/marshal.go | 9 ++++++++- backend/plonk/bw6-633/marshal_test.go | 4 ++++ backend/plonk/bw6-761/marshal.go | 9 ++++++++- backend/plonk/bw6-761/marshal_test.go | 4 ++++ .../template/zkpschemes/plonk/plonk.marshal.go.tmpl | 9 ++++++++- .../template/zkpschemes/plonk/tests/marshal.go.tmpl | 4 ++++ 16 files changed, 96 insertions(+), 8 deletions(-) diff --git a/backend/plonk/bls12-377/marshal.go b/backend/plonk/bls12-377/marshal.go index 8194875d8b..7446ed3377 100644 --- a/backend/plonk/bls12-377/marshal.go +++ b/backend/plonk/bls12-377/marshal.go @@ -50,6 +50,7 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, + &proof.PI2, } for _, v := range toEncode { @@ -76,6 +77,7 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { &proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, + &proof.PI2, } for _, v := range toDecode { @@ -123,6 +125,7 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { ([]fr.Element)(pk.trace.Qm.Coefficients()), ([]fr.Element)(pk.trace.Qo.Coefficients()), ([]fr.Element)(pk.trace.Qk.Coefficients()), + ([]fr.Element)(pk.trace.Qcp.Coefficients()), ([]fr.Element)(pk.lQk.Coefficients()), ([]fr.Element)(pk.trace.S1.Coefficients()), ([]fr.Element)(pk.trace.S2.Coefficients()), @@ -163,13 +166,14 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { dec := curve.NewDecoder(r) - var ql, qr, qm, qo, qk, lqk, s1, s2, s3 []fr.Element + var ql, qr, qm, qo, qk, qcp, lqk, s1, s2, s3 []fr.Element toDecode := []interface{}{ &ql, &qr, &qm, &qo, &qk, + &qcp, &lqk, &s1, &s2, @@ -189,6 +193,7 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) @@ -220,6 +225,7 @@ func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { &vk.Qm, &vk.Qo, &vk.Qk, + &vk.Qcp, } for _, v := range toEncode { @@ -248,6 +254,7 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { &vk.Qm, &vk.Qo, &vk.Qk, + &vk.Qcp, } for _, v := range toDecode { diff --git a/backend/plonk/bls12-377/marshal_test.go b/backend/plonk/bls12-377/marshal_test.go index b9033af3af..a7798ea87b 100644 --- a/backend/plonk/bls12-377/marshal_test.go +++ b/backend/plonk/bls12-377/marshal_test.go @@ -121,6 +121,7 @@ func (pk *ProvingKey) randomize() { qo := randomScalars(n) qk := randomScalars(n) lqk := randomScalars(n) + qcp := randomScalars(n) s1 := randomScalars(n) s2 := randomScalars(n) s3 := randomScalars(n) @@ -131,6 +132,7 @@ func (pk *ProvingKey) randomize() { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) @@ -160,6 +162,7 @@ func (vk *VerifyingKey) randomize() { vk.Qm = randomPoint() vk.Qo = randomPoint() vk.Qk = randomPoint() + vk.Qcp = randomPoint() } func (proof *Proof) randomize() { @@ -174,6 +177,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() + proof.PI2 = randomPoint() } func randomPoint() curve.G1Affine { diff --git a/backend/plonk/bls12-381/marshal.go b/backend/plonk/bls12-381/marshal.go index b40458990f..d2a7af9e91 100644 --- a/backend/plonk/bls12-381/marshal.go +++ b/backend/plonk/bls12-381/marshal.go @@ -50,6 +50,7 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, + &proof.PI2, } for _, v := range toEncode { @@ -76,6 +77,7 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { &proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, + &proof.PI2, } for _, v := range toDecode { @@ -123,6 +125,7 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { ([]fr.Element)(pk.trace.Qm.Coefficients()), ([]fr.Element)(pk.trace.Qo.Coefficients()), ([]fr.Element)(pk.trace.Qk.Coefficients()), + ([]fr.Element)(pk.trace.Qcp.Coefficients()), ([]fr.Element)(pk.lQk.Coefficients()), ([]fr.Element)(pk.trace.S1.Coefficients()), ([]fr.Element)(pk.trace.S2.Coefficients()), @@ -163,13 +166,14 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { dec := curve.NewDecoder(r) - var ql, qr, qm, qo, qk, lqk, s1, s2, s3 []fr.Element + var ql, qr, qm, qo, qk, qcp, lqk, s1, s2, s3 []fr.Element toDecode := []interface{}{ &ql, &qr, &qm, &qo, &qk, + &qcp, &lqk, &s1, &s2, @@ -189,6 +193,7 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) @@ -220,6 +225,7 @@ func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { &vk.Qm, &vk.Qo, &vk.Qk, + &vk.Qcp, } for _, v := range toEncode { @@ -248,6 +254,7 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { &vk.Qm, &vk.Qo, &vk.Qk, + &vk.Qcp, } for _, v := range toDecode { diff --git a/backend/plonk/bls12-381/marshal_test.go b/backend/plonk/bls12-381/marshal_test.go index 3727a97afc..cbefa637ad 100644 --- a/backend/plonk/bls12-381/marshal_test.go +++ b/backend/plonk/bls12-381/marshal_test.go @@ -121,6 +121,7 @@ func (pk *ProvingKey) randomize() { qo := randomScalars(n) qk := randomScalars(n) lqk := randomScalars(n) + qcp := randomScalars(n) s1 := randomScalars(n) s2 := randomScalars(n) s3 := randomScalars(n) @@ -131,6 +132,7 @@ func (pk *ProvingKey) randomize() { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) @@ -160,6 +162,7 @@ func (vk *VerifyingKey) randomize() { vk.Qm = randomPoint() vk.Qo = randomPoint() vk.Qk = randomPoint() + vk.Qcp = randomPoint() } func (proof *Proof) randomize() { @@ -174,6 +177,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() + proof.PI2 = randomPoint() } func randomPoint() curve.G1Affine { diff --git a/backend/plonk/bls24-315/marshal.go b/backend/plonk/bls24-315/marshal.go index 0721e7a82b..bc9333bc74 100644 --- a/backend/plonk/bls24-315/marshal.go +++ b/backend/plonk/bls24-315/marshal.go @@ -50,6 +50,7 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, + &proof.PI2, } for _, v := range toEncode { @@ -76,6 +77,7 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { &proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, + &proof.PI2, } for _, v := range toDecode { @@ -123,6 +125,7 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { ([]fr.Element)(pk.trace.Qm.Coefficients()), ([]fr.Element)(pk.trace.Qo.Coefficients()), ([]fr.Element)(pk.trace.Qk.Coefficients()), + ([]fr.Element)(pk.trace.Qcp.Coefficients()), ([]fr.Element)(pk.lQk.Coefficients()), ([]fr.Element)(pk.trace.S1.Coefficients()), ([]fr.Element)(pk.trace.S2.Coefficients()), @@ -163,13 +166,14 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { dec := curve.NewDecoder(r) - var ql, qr, qm, qo, qk, lqk, s1, s2, s3 []fr.Element + var ql, qr, qm, qo, qk, qcp, lqk, s1, s2, s3 []fr.Element toDecode := []interface{}{ &ql, &qr, &qm, &qo, &qk, + &qcp, &lqk, &s1, &s2, @@ -189,6 +193,7 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) @@ -220,6 +225,7 @@ func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { &vk.Qm, &vk.Qo, &vk.Qk, + &vk.Qcp, } for _, v := range toEncode { @@ -248,6 +254,7 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { &vk.Qm, &vk.Qo, &vk.Qk, + &vk.Qcp, } for _, v := range toDecode { diff --git a/backend/plonk/bls24-315/marshal_test.go b/backend/plonk/bls24-315/marshal_test.go index 4fdf97dfdf..e3505822d7 100644 --- a/backend/plonk/bls24-315/marshal_test.go +++ b/backend/plonk/bls24-315/marshal_test.go @@ -121,6 +121,7 @@ func (pk *ProvingKey) randomize() { qo := randomScalars(n) qk := randomScalars(n) lqk := randomScalars(n) + qcp := randomScalars(n) s1 := randomScalars(n) s2 := randomScalars(n) s3 := randomScalars(n) @@ -131,6 +132,7 @@ func (pk *ProvingKey) randomize() { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) @@ -160,6 +162,7 @@ func (vk *VerifyingKey) randomize() { vk.Qm = randomPoint() vk.Qo = randomPoint() vk.Qk = randomPoint() + vk.Qcp = randomPoint() } func (proof *Proof) randomize() { @@ -174,6 +177,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() + proof.PI2 = randomPoint() } func randomPoint() curve.G1Affine { diff --git a/backend/plonk/bls24-317/marshal.go b/backend/plonk/bls24-317/marshal.go index 6d4d8b0fcd..d7742ca1e5 100644 --- a/backend/plonk/bls24-317/marshal.go +++ b/backend/plonk/bls24-317/marshal.go @@ -50,6 +50,7 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, + &proof.PI2, } for _, v := range toEncode { @@ -76,6 +77,7 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { &proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, + &proof.PI2, } for _, v := range toDecode { @@ -123,6 +125,7 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { ([]fr.Element)(pk.trace.Qm.Coefficients()), ([]fr.Element)(pk.trace.Qo.Coefficients()), ([]fr.Element)(pk.trace.Qk.Coefficients()), + ([]fr.Element)(pk.trace.Qcp.Coefficients()), ([]fr.Element)(pk.lQk.Coefficients()), ([]fr.Element)(pk.trace.S1.Coefficients()), ([]fr.Element)(pk.trace.S2.Coefficients()), @@ -163,13 +166,14 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { dec := curve.NewDecoder(r) - var ql, qr, qm, qo, qk, lqk, s1, s2, s3 []fr.Element + var ql, qr, qm, qo, qk, qcp, lqk, s1, s2, s3 []fr.Element toDecode := []interface{}{ &ql, &qr, &qm, &qo, &qk, + &qcp, &lqk, &s1, &s2, @@ -189,6 +193,7 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) @@ -220,6 +225,7 @@ func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { &vk.Qm, &vk.Qo, &vk.Qk, + &vk.Qcp, } for _, v := range toEncode { @@ -248,6 +254,7 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { &vk.Qm, &vk.Qo, &vk.Qk, + &vk.Qcp, } for _, v := range toDecode { diff --git a/backend/plonk/bls24-317/marshal_test.go b/backend/plonk/bls24-317/marshal_test.go index fa36ad1b3f..c8cb87e43f 100644 --- a/backend/plonk/bls24-317/marshal_test.go +++ b/backend/plonk/bls24-317/marshal_test.go @@ -121,6 +121,7 @@ func (pk *ProvingKey) randomize() { qo := randomScalars(n) qk := randomScalars(n) lqk := randomScalars(n) + qcp := randomScalars(n) s1 := randomScalars(n) s2 := randomScalars(n) s3 := randomScalars(n) @@ -131,6 +132,7 @@ func (pk *ProvingKey) randomize() { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) @@ -160,6 +162,7 @@ func (vk *VerifyingKey) randomize() { vk.Qm = randomPoint() vk.Qo = randomPoint() vk.Qk = randomPoint() + vk.Qcp = randomPoint() } func (proof *Proof) randomize() { @@ -174,6 +177,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() + proof.PI2 = randomPoint() } func randomPoint() curve.G1Affine { diff --git a/backend/plonk/bn254/marshal.go b/backend/plonk/bn254/marshal.go index 762065c319..dcd81bd10d 100644 --- a/backend/plonk/bn254/marshal.go +++ b/backend/plonk/bn254/marshal.go @@ -50,6 +50,7 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, + &proof.PI2, } for _, v := range toEncode { @@ -76,6 +77,7 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { &proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, + &proof.PI2, } for _, v := range toDecode { @@ -123,6 +125,7 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { ([]fr.Element)(pk.trace.Qm.Coefficients()), ([]fr.Element)(pk.trace.Qo.Coefficients()), ([]fr.Element)(pk.trace.Qk.Coefficients()), + ([]fr.Element)(pk.trace.Qcp.Coefficients()), ([]fr.Element)(pk.lQk.Coefficients()), ([]fr.Element)(pk.trace.S1.Coefficients()), ([]fr.Element)(pk.trace.S2.Coefficients()), @@ -163,13 +166,14 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { dec := curve.NewDecoder(r) - var ql, qr, qm, qo, qk, lqk, s1, s2, s3 []fr.Element + var ql, qr, qm, qo, qk, qcp, lqk, s1, s2, s3 []fr.Element toDecode := []interface{}{ &ql, &qr, &qm, &qo, &qk, + &qcp, &lqk, &s1, &s2, @@ -189,6 +193,7 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) @@ -220,6 +225,7 @@ func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { &vk.Qm, &vk.Qo, &vk.Qk, + &vk.Qcp, } for _, v := range toEncode { @@ -248,6 +254,7 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { &vk.Qm, &vk.Qo, &vk.Qk, + &vk.Qcp, } for _, v := range toDecode { diff --git a/backend/plonk/bn254/marshal_test.go b/backend/plonk/bn254/marshal_test.go index 4feae1aad4..3f35b03010 100644 --- a/backend/plonk/bn254/marshal_test.go +++ b/backend/plonk/bn254/marshal_test.go @@ -121,6 +121,7 @@ func (pk *ProvingKey) randomize() { qo := randomScalars(n) qk := randomScalars(n) lqk := randomScalars(n) + qcp := randomScalars(n) s1 := randomScalars(n) s2 := randomScalars(n) s3 := randomScalars(n) @@ -131,6 +132,7 @@ func (pk *ProvingKey) randomize() { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) @@ -160,6 +162,7 @@ func (vk *VerifyingKey) randomize() { vk.Qm = randomPoint() vk.Qo = randomPoint() vk.Qk = randomPoint() + vk.Qcp = randomPoint() } func (proof *Proof) randomize() { @@ -174,6 +177,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() + proof.PI2 = randomPoint() } func randomPoint() curve.G1Affine { diff --git a/backend/plonk/bw6-633/marshal.go b/backend/plonk/bw6-633/marshal.go index 6507039e1d..043b319cd3 100644 --- a/backend/plonk/bw6-633/marshal.go +++ b/backend/plonk/bw6-633/marshal.go @@ -50,6 +50,7 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, + &proof.PI2, } for _, v := range toEncode { @@ -76,6 +77,7 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { &proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, + &proof.PI2, } for _, v := range toDecode { @@ -123,6 +125,7 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { ([]fr.Element)(pk.trace.Qm.Coefficients()), ([]fr.Element)(pk.trace.Qo.Coefficients()), ([]fr.Element)(pk.trace.Qk.Coefficients()), + ([]fr.Element)(pk.trace.Qcp.Coefficients()), ([]fr.Element)(pk.lQk.Coefficients()), ([]fr.Element)(pk.trace.S1.Coefficients()), ([]fr.Element)(pk.trace.S2.Coefficients()), @@ -163,13 +166,14 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { dec := curve.NewDecoder(r) - var ql, qr, qm, qo, qk, lqk, s1, s2, s3 []fr.Element + var ql, qr, qm, qo, qk, qcp, lqk, s1, s2, s3 []fr.Element toDecode := []interface{}{ &ql, &qr, &qm, &qo, &qk, + &qcp, &lqk, &s1, &s2, @@ -189,6 +193,7 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) @@ -220,6 +225,7 @@ func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { &vk.Qm, &vk.Qo, &vk.Qk, + &vk.Qcp, } for _, v := range toEncode { @@ -248,6 +254,7 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { &vk.Qm, &vk.Qo, &vk.Qk, + &vk.Qcp, } for _, v := range toDecode { diff --git a/backend/plonk/bw6-633/marshal_test.go b/backend/plonk/bw6-633/marshal_test.go index 9d1403112e..4fa947d977 100644 --- a/backend/plonk/bw6-633/marshal_test.go +++ b/backend/plonk/bw6-633/marshal_test.go @@ -121,6 +121,7 @@ func (pk *ProvingKey) randomize() { qo := randomScalars(n) qk := randomScalars(n) lqk := randomScalars(n) + qcp := randomScalars(n) s1 := randomScalars(n) s2 := randomScalars(n) s3 := randomScalars(n) @@ -131,6 +132,7 @@ func (pk *ProvingKey) randomize() { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) @@ -160,6 +162,7 @@ func (vk *VerifyingKey) randomize() { vk.Qm = randomPoint() vk.Qo = randomPoint() vk.Qk = randomPoint() + vk.Qcp = randomPoint() } func (proof *Proof) randomize() { @@ -174,6 +177,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() + proof.PI2 = randomPoint() } func randomPoint() curve.G1Affine { diff --git a/backend/plonk/bw6-761/marshal.go b/backend/plonk/bw6-761/marshal.go index 110e046c3c..4cc8845a3f 100644 --- a/backend/plonk/bw6-761/marshal.go +++ b/backend/plonk/bw6-761/marshal.go @@ -50,6 +50,7 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, + &proof.PI2, } for _, v := range toEncode { @@ -76,6 +77,7 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { &proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, + &proof.PI2, } for _, v := range toDecode { @@ -123,6 +125,7 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { ([]fr.Element)(pk.trace.Qm.Coefficients()), ([]fr.Element)(pk.trace.Qo.Coefficients()), ([]fr.Element)(pk.trace.Qk.Coefficients()), + ([]fr.Element)(pk.trace.Qcp.Coefficients()), ([]fr.Element)(pk.lQk.Coefficients()), ([]fr.Element)(pk.trace.S1.Coefficients()), ([]fr.Element)(pk.trace.S2.Coefficients()), @@ -163,13 +166,14 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { dec := curve.NewDecoder(r) - var ql, qr, qm, qo, qk, lqk, s1, s2, s3 []fr.Element + var ql, qr, qm, qo, qk, qcp, lqk, s1, s2, s3 []fr.Element toDecode := []interface{}{ &ql, &qr, &qm, &qo, &qk, + &qcp, &lqk, &s1, &s2, @@ -189,6 +193,7 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) @@ -220,6 +225,7 @@ func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { &vk.Qm, &vk.Qo, &vk.Qk, + &vk.Qcp, } for _, v := range toEncode { @@ -248,6 +254,7 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { &vk.Qm, &vk.Qo, &vk.Qk, + &vk.Qcp, } for _, v := range toDecode { diff --git a/backend/plonk/bw6-761/marshal_test.go b/backend/plonk/bw6-761/marshal_test.go index c53c256851..a1228f4513 100644 --- a/backend/plonk/bw6-761/marshal_test.go +++ b/backend/plonk/bw6-761/marshal_test.go @@ -121,6 +121,7 @@ func (pk *ProvingKey) randomize() { qo := randomScalars(n) qk := randomScalars(n) lqk := randomScalars(n) + qcp := randomScalars(n) s1 := randomScalars(n) s2 := randomScalars(n) s3 := randomScalars(n) @@ -131,6 +132,7 @@ func (pk *ProvingKey) randomize() { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) @@ -160,6 +162,7 @@ func (vk *VerifyingKey) randomize() { vk.Qm = randomPoint() vk.Qo = randomPoint() vk.Qk = randomPoint() + vk.Qcp = randomPoint() } func (proof *Proof) randomize() { @@ -174,6 +177,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() + proof.PI2 = randomPoint() } func randomPoint() curve.G1Affine { diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl index 2b21e0978b..60a5a02cdf 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl @@ -31,6 +31,7 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, + &proof.PI2, } for _, v := range toEncode { @@ -57,6 +58,7 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { &proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, + &proof.PI2, } for _, v := range toDecode { @@ -104,6 +106,7 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { ([]fr.Element)(pk.trace.Qm.Coefficients()), ([]fr.Element)(pk.trace.Qo.Coefficients()), ([]fr.Element)(pk.trace.Qk.Coefficients()), + ([]fr.Element)(pk.trace.Qcp.Coefficients()), ([]fr.Element)(pk.lQk.Coefficients()), ([]fr.Element)(pk.trace.S1.Coefficients()), ([]fr.Element)(pk.trace.S2.Coefficients()), @@ -144,13 +147,14 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { dec := curve.NewDecoder(r) - var ql, qr, qm, qo, qk, lqk, s1, s2, s3 []fr.Element + var ql, qr, qm, qo, qk, qcp, lqk, s1, s2, s3 []fr.Element toDecode := []interface{}{ &ql, &qr, &qm, &qo, &qk, + &qcp, &lqk, &s1, &s2, @@ -170,6 +174,7 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) @@ -201,6 +206,7 @@ func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { &vk.Qm, &vk.Qo, &vk.Qk, + &vk.Qcp, } for _, v := range toEncode { @@ -229,6 +235,7 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { &vk.Qm, &vk.Qo, &vk.Qk, + &vk.Qcp, } for _, v := range toDecode { diff --git a/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl index 352a98012d..f1ef42add9 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl @@ -102,6 +102,7 @@ func (pk *ProvingKey) randomize() { qo := randomScalars(n) qk := randomScalars(n) lqk := randomScalars(n) + qcp := randomScalars(n) s1 := randomScalars(n) s2 := randomScalars(n) s3 := randomScalars(n) @@ -112,6 +113,7 @@ func (pk *ProvingKey) randomize() { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) + pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) @@ -141,6 +143,7 @@ func (vk *VerifyingKey) randomize() { vk.Qm = randomPoint() vk.Qo = randomPoint() vk.Qk = randomPoint() + vk.Qcp = randomPoint() } func (proof *Proof) randomize() { @@ -155,6 +158,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() + proof.PI2 = randomPoint() } func randomPoint() curve.G1Affine { From d5f3e17c1a484bfe810f5080de32826a6f6a0107 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 17 Mar 2023 17:52:55 -0400 Subject: [PATCH 176/464] revert reverting the version --- doc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc.go b/doc.go index 697944b7d7..b871010f37 100644 --- a/doc.go +++ b/doc.go @@ -22,7 +22,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" ) -var Version = semver.MustParse("0.8.0") +var Version = semver.MustParse("0.8.1-alpha") // Curves return the curves supported by gnark func Curves() []ecc.ID { From a3ba13c0c51d2649143d45c88cfbb311cde2e527 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Mon, 20 Mar 2023 19:23:18 +0000 Subject: [PATCH 177/464] feat: add bls12-381 to std/algebra/emulated --- .../emulated/fields_bls12381/e12_pairing.go | 21 +- .../emulated/fields_bls12381/e12_test.go | 30 +-- .../emulated/fields_bls12381/e2_test.go | 22 +- std/algebra/emulated/fields_bls12381/e6.go | 33 +-- .../emulated/fields_bls12381/e6_test.go | 31 +-- std/algebra/emulated/sw_bls12381/doc_test.go | 12 +- std/algebra/emulated/sw_bls12381/pairing.go | 216 +++++++++--------- .../emulated/sw_bls12381/pairing_test.go | 11 +- 8 files changed, 178 insertions(+), 198 deletions(-) diff --git a/std/algebra/emulated/fields_bls12381/e12_pairing.go b/std/algebra/emulated/fields_bls12381/e12_pairing.go index 593c154000..5d220a5d48 100644 --- a/std/algebra/emulated/fields_bls12381/e12_pairing.go +++ b/std/algebra/emulated/fields_bls12381/e12_pairing.go @@ -70,20 +70,25 @@ func (e Ext12) Expt(x *E12) *E12 { // MulBy014 multiplies z by an E12 sparse element of the form // // E12{ -// C0: E6{B0: 1, B1: c1, B2: 0}, -// C1: E6{B0: 0, B1: c4, B2: 0}, +// C0: E6{B0: c0, B1: c1, B2: 0}, +// C1: E6{B0: 0, B1: 1, B2: 0}, // } -func (e *Ext12) MulBy014(z *E12, c1, c4 *E2) *E12 { +func (e *Ext12) MulBy014(z *E12, c0, c1 *E2) *E12 { a := z.C0 - a = *e.Ext6.MulBy01(&a, c1) + a = *e.MulBy01(&a, c0, c1) - b := z.C1 - b = *e.Ext6.MulBy1(&b, c4) - d := e.Ext2.Add(c1, c4) + var b E6 + // Mul by E6{0, 1, 0} + b.B0 = *e.Ext2.MulByNonResidue(&z.C1.B2) + b.B2 = z.C1.B1 + b.B1 = z.C1.B0 + + one := e.Ext2.One() + d := e.Ext2.Add(c1, one) zC1 := e.Ext6.Add(&z.C1, &z.C0) - zC1 = e.Ext6.MulBy01(zC1, d) + zC1 = e.Ext6.MulBy01(zC1, c0, d) zC1 = e.Ext6.Sub(zC1, &a) zC1 = e.Ext6.Sub(zC1, &b) zC0 := e.Ext6.MulByNonResidue(&b) diff --git a/std/algebra/emulated/fields_bls12381/e12_test.go b/std/algebra/emulated/fields_bls12381/e12_test.go index eeccc23ead..8384e342de 100644 --- a/std/algebra/emulated/fields_bls12381/e12_test.go +++ b/std/algebra/emulated/fields_bls12381/e12_test.go @@ -41,7 +41,7 @@ func TestAddFp12(t *testing.T) { C: FromE12(&c), } - err := test.IsSolved(&e12Add{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e12Add{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -73,7 +73,7 @@ func TestSubFp12(t *testing.T) { C: FromE12(&c), } - err := test.IsSolved(&e12Sub{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e12Sub{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -106,7 +106,7 @@ func TestMulFp12(t *testing.T) { C: FromE12(&c), } - err := test.IsSolved(&e12Mul{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e12Mul{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -139,7 +139,7 @@ func TestDivFp12(t *testing.T) { C: FromE12(&c), } - err := test.IsSolved(&e12Div{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e12Div{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -170,7 +170,7 @@ func TestSquareFp12(t *testing.T) { C: FromE12(&c), } - err := test.IsSolved(&e12Square{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e12Square{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -208,7 +208,7 @@ func TestFp12CyclotomicSquare(t *testing.T) { C: FromE12(&c), } - err := test.IsSolved(&e12CycloSquare{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e12CycloSquare{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -245,7 +245,7 @@ func TestFp12CyclotomicSquareKarabina(t *testing.T) { C: FromE12(&c), } - err := test.IsSolved(&e12CycloSquareKarabina{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e12CycloSquareKarabina{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -284,7 +284,7 @@ func TestFp12CyclotomicSquareKarabinaAndDecompress(t *testing.T) { C: FromE12(&c), } - err := test.IsSolved(&e12CycloSquareKarabinaAndDecompress{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e12CycloSquareKarabinaAndDecompress{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -315,7 +315,7 @@ func TestConjugateFp12(t *testing.T) { C: FromE12(&c), } - err := test.IsSolved(&e12Conjugate{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e12Conjugate{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -346,7 +346,7 @@ func TestInverseFp12(t *testing.T) { C: FromE12(&c), } - err := test.IsSolved(&e12Inverse{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e12Inverse{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -385,7 +385,7 @@ func TestFp12Expt(t *testing.T) { C: FromE12(&c), } - err := test.IsSolved(&e12Expt{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e12Expt{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -415,7 +415,7 @@ func TestFrobeniusFp12(t *testing.T) { C: FromE12(&c), } - err := test.IsSolved(&e12Frobenius{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e12Frobenius{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -446,7 +446,7 @@ func TestFrobeniusSquareFp12(t *testing.T) { C: FromE12(&c), } - err := test.IsSolved(&e12FrobeniusSquare{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e12FrobeniusSquare{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -477,7 +477,7 @@ func TestFp12MulBy014(t *testing.T) { _, _ = b.SetRandom() _, _ = c.SetRandom() w.Set(&a) - w.MulBy014(&one, &b, &c) + w.MulBy014(&b, &c, &one) witness := e12MulBy014{ A: FromE12(&a), @@ -486,7 +486,7 @@ func TestFp12MulBy014(t *testing.T) { W: FromE12(&w), } - err := test.IsSolved(&e12MulBy014{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e12MulBy014{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } diff --git a/std/algebra/emulated/fields_bls12381/e2_test.go b/std/algebra/emulated/fields_bls12381/e2_test.go index 7ea1aae73a..972e6d3dce 100644 --- a/std/algebra/emulated/fields_bls12381/e2_test.go +++ b/std/algebra/emulated/fields_bls12381/e2_test.go @@ -38,7 +38,7 @@ func TestAddFp2(t *testing.T) { C: FromE2(&c), } - err := test.IsSolved(&e2Add{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e2Add{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -70,7 +70,7 @@ func TestSubFp2(t *testing.T) { C: FromE2(&c), } - err := test.IsSolved(&e2Sub{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e2Sub{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -101,7 +101,7 @@ func TestDoubleFp2(t *testing.T) { C: FromE2(&c), } - err := test.IsSolved(&e2Double{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e2Double{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -134,7 +134,7 @@ func TestMulFp2(t *testing.T) { C: FromE2(&c), } - err := test.IsSolved(&e2Mul{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e2Mul{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -165,7 +165,7 @@ func TestSquareFp2(t *testing.T) { C: FromE2(&c), } - err := test.IsSolved(&e2Square{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e2Square{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -198,7 +198,7 @@ func TestDivFp2(t *testing.T) { C: FromE2(&c), } - err := test.IsSolved(&e2Div{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e2Div{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -234,7 +234,7 @@ func TestMulByElement(t *testing.T) { C: FromE2(&c), } - err := test.IsSolved(&e2MulByElement{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e2MulByElement{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -266,7 +266,7 @@ func TestMulFp2ByNonResidue(t *testing.T) { C: FromE2(&c), } - err := test.IsSolved(&e2MulByNonResidue{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e2MulByNonResidue{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -298,7 +298,7 @@ func TestNegFp2(t *testing.T) { C: FromE2(&c), } - err := test.IsSolved(&e2Neg{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e2Neg{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -329,7 +329,7 @@ func TestConjugateFp2(t *testing.T) { C: FromE2(&c), } - err := test.IsSolved(&e2Conjugate{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e2Conjugate{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -360,6 +360,6 @@ func TestInverseFp2(t *testing.T) { C: FromE2(&c), } - err := test.IsSolved(&e2Inverse{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e2Inverse{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } diff --git a/std/algebra/emulated/fields_bls12381/e6.go b/std/algebra/emulated/fields_bls12381/e6.go index a9cb381ae8..c32e9e864b 100644 --- a/std/algebra/emulated/fields_bls12381/e6.go +++ b/std/algebra/emulated/fields_bls12381/e6.go @@ -151,9 +151,9 @@ func (e Ext6) MulByE2(x *E6, y *E2) *E6 { } } -// MulBy01 multiplication by sparse element (1,c1,0) -func (e Ext6) MulBy01(z *E6, c1 *E2) *E6 { - a := &z.B0 +// MulBy01 multiplication by sparse element (c0,c1,0) +func (e Ext6) MulBy01(z *E6, c0, c1 *E2) *E6 { + a := e.Ext2.Mul(&z.B0, c0) b := e.Ext2.Mul(&z.B1, c1) tmp := e.Ext2.Add(&z.B1, &z.B2) t0 := e.Ext2.Mul(c1, tmp) @@ -161,12 +161,12 @@ func (e Ext6) MulBy01(z *E6, c1 *E2) *E6 { t0 = e.Ext2.MulByNonResidue(t0) t0 = e.Ext2.Add(t0, a) tmp = e.Ext2.Add(&z.B0, &z.B2) - t2 := tmp + t2 := e.Ext2.Mul(c0, tmp) t2 = e.Ext2.Sub(t2, a) t2 = e.Ext2.Add(t2, b) + t1 := e.Ext2.Add(c0, c1) tmp = e.Ext2.Add(&z.B0, &z.B1) - t1 := e.Ext2.Mul(c1, tmp) - t1 = e.Ext2.Add(t1, tmp) + t1 = e.Ext2.Mul(t1, tmp) t1 = e.Ext2.Sub(t1, a) t1 = e.Ext2.Sub(t1, b) return &E6{ @@ -176,27 +176,6 @@ func (e Ext6) MulBy01(z *E6, c1 *E2) *E6 { } } -// MulBy1 multiplication of E6 by sparse element (0, c1, 0) -func (e Ext6) MulBy1(z *E6, c1 *E2) *E6 { - - b := e.Ext2.Mul(&z.B1, c1) - - tmp := e.Ext2.Add(&z.B1, &z.B2) - t0 := e.Ext2.Mul(c1, tmp) - t0 = e.Ext2.Sub(t0, b) - t0 = e.Ext2.MulByNonResidue(t0) - - tmp = e.Ext2.Add(&z.B0, &z.B1) - t1 := e.Ext2.Mul(c1, tmp) - t1 = e.Ext2.Sub(t1, b) - - return &E6{ - B0: *t0, - B1: *t1, - B2: *b, - } -} - func (e Ext6) MulByNonResidue(x *E6) *E6 { z2, z1, z0 := &x.B1, &x.B0, &x.B2 z0 = e.Ext2.MulByNonResidue(z0) diff --git a/std/algebra/emulated/fields_bls12381/e6_test.go b/std/algebra/emulated/fields_bls12381/e6_test.go index 6d59231bc3..7b784db822 100644 --- a/std/algebra/emulated/fields_bls12381/e6_test.go +++ b/std/algebra/emulated/fields_bls12381/e6_test.go @@ -37,7 +37,7 @@ func TestAddFp6(t *testing.T) { C: FromE6(&c), } - err := test.IsSolved(&e6Add{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e6Add{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -69,7 +69,7 @@ func TestSubFp6(t *testing.T) { C: FromE6(&c), } - err := test.IsSolved(&e6Sub{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e6Sub{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -102,7 +102,7 @@ func TestMulFp6(t *testing.T) { C: FromE6(&c), } - err := test.IsSolved(&e6Mul{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e6Mul{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -133,7 +133,7 @@ func TestSquareFp6(t *testing.T) { C: FromE6(&c), } - err := test.IsSolved(&e6Square{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e6Square{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -166,7 +166,7 @@ func TestDivFp6(t *testing.T) { C: FromE6(&c), } - err := test.IsSolved(&e6Div{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e6Div{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -198,7 +198,7 @@ func TestMulFp6ByNonResidue(t *testing.T) { C: FromE6(&c), } - err := test.IsSolved(&e6MulByNonResidue{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e6MulByNonResidue{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -234,21 +234,21 @@ func TestMulFp6ByE2(t *testing.T) { C: FromE6(&c), } - err := test.IsSolved(&e6MulByE2{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e6MulByE2{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } type e6MulBy01 struct { - A E6 - C1 E2 - C E6 `gnark:",public"` + A E6 + C0, C1 E2 + C E6 `gnark:",public"` } func (circuit *e6MulBy01) Define(api frontend.API) error { ba, _ := emulated.NewField[emulated.BLS12381Fp](api) e := NewExt6(ba) - expected := e.MulBy01(&circuit.A, &circuit.C1) + expected := e.MulBy01(&circuit.A, &circuit.C0, &circuit.C1) e.AssertIsEqual(expected, &circuit.C) return nil @@ -261,18 +261,19 @@ func TestMulFp6By01(t *testing.T) { var a, c bls12381.E6 var C0, C1 bls12381.E2 _, _ = a.SetRandom() - C0.SetOne() + _, _ = C0.SetRandom() _, _ = C1.SetRandom() c.Set(&a) c.MulBy01(&C0, &C1) witness := e6MulBy01{ A: FromE6(&a), + C0: FromE2(&C0), C1: FromE2(&C1), C: FromE6(&c), } - err := test.IsSolved(&e6MulBy01{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e6MulBy01{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -304,7 +305,7 @@ func TestNegFp6(t *testing.T) { C: FromE6(&c), } - err := test.IsSolved(&e6Neg{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e6Neg{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -336,6 +337,6 @@ func TestInverseFp6(t *testing.T) { C: FromE6(&c), } - err := test.IsSolved(&e6Inverse{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&e6Inverse{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } diff --git a/std/algebra/emulated/sw_bls12381/doc_test.go b/std/algebra/emulated/sw_bls12381/doc_test.go index 0e112a27c9..ae87b72997 100644 --- a/std/algebra/emulated/sw_bls12381/doc_test.go +++ b/std/algebra/emulated/sw_bls12381/doc_test.go @@ -2,11 +2,16 @@ package sw_bls12381_test import ( "crypto/rand" + "fmt" + "github.com/consensys/gnark-crypto/ecc" bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark/backend/groth16" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/std/algebra/emulated/sw_bls12381" ) -/* type PairCircuit struct { InG1 sw_bls12381.G1Affine InG2 sw_bls12381.G2Affine @@ -41,7 +46,7 @@ func ExamplePairing() { InG2: sw_bls12381.NewG2Affine(q), Res: sw_bls12381.NewGTEl(res), } - ccs, err := frontend.Compile(ecc.BLS12_381.ScalarField(), r1cs.NewBuilder, &circuit) + ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) if err != nil { panic(err) } else { @@ -53,7 +58,7 @@ func ExamplePairing() { } else { fmt.Println("setup done") } - secretWitness, err := frontend.NewWitness(&witness, ecc.BLS12_381.ScalarField()) + secretWitness, err := frontend.NewWitness(&witness, ecc.BN254.ScalarField()) if err != nil { panic(err) } else { @@ -78,7 +83,6 @@ func ExamplePairing() { fmt.Println("verify") } } -*/ func randomG1G2Affines() (p bls12381.G1Affine, q bls12381.G2Affine, err error) { _, _, G1AffGen, G2AffGen := bls12381.Generators() diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go index d739a74907..d55dad3bed 100644 --- a/std/algebra/emulated/sw_bls12381/pairing.go +++ b/std/algebra/emulated/sw_bls12381/pairing.go @@ -1,6 +1,7 @@ package sw_bls12381 import ( + "errors" "fmt" "math/big" @@ -102,13 +103,16 @@ func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { // lineEvaluation represents a sparse Fp12 Elmt (result of the line evaluation) // line: 1 - R0(x/y) - R1(1/y) = 0 instead of R0'*y - R1'*x - R2' = 0 This -// makes the multiplication by lines (MulBy034) and between lines (Mul034By034) +// makes the multiplication by lines (MulBy014) and between lines (Mul014By014) // circuit-efficient. type lineEvaluation struct { R0, R1 fields_bls12381.E2 } -/* +// Pair calculates the reduced pairing for a set of points +// ∏ᵢ e(Pᵢ, Qᵢ). +// +// This function doesn't check that the inputs are in the correct subgroup. func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { res, err := pr.MillerLoop(P, Q) if err != nil { @@ -122,19 +126,13 @@ func (pr Pairing) AssertIsEqual(x, y *GTEl) { pr.Ext12.AssertIsEqual(x, y) } -// loopCounter = 6*seed+2 in 2-NAF -// loopCounter = 29793968203157093288 -var loopCounter = [66]int8{ - 0, 0, 0, 1, 0, 1, 0, -1, 0, 0, -1, - 0, 0, 0, 1, 0, 0, -1, 0, -1, 0, 0, - 0, 1, 0, -1, 0, 0, 0, 0, -1, 0, 0, - 1, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, - -1, 0, 0, -1, 0, 1, 0, -1, 0, 0, 0, - -1, 0, -1, 0, 0, 0, 1, 0, -1, 0, 1, -} +// loopCounter = seed in binary +// +// seed=-15132376222941642752 +var loopCounter = [64]int8{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, 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, 1, 0, 0, 1, 0, 1, 1} // MillerLoop computes the multi-Miller loop -// ∏ᵢ { fᵢ_{ℓ,Q}(P) · ℓᵢ_{[ℓ]q,π(q)}(p) · ℓᵢ_{[ℓ]q+π(q),-π²(q)}(p) } +// ∏ᵢ { fᵢ_{u,Q}(P) } func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { // check input size match n := len(P) @@ -146,61 +144,42 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { var l1, l2 *lineEvaluation Qacc := make([]*G2Affine, n) - QNeg := make([]*G2Affine, n) yInv := make([]*emulated.Element[emulated.BLS12381Fp], n) xOverY := make([]*emulated.Element[emulated.BLS12381Fp], n) for k := 0; k < n; k++ { Qacc[k] = Q[k] - QNeg[k] = &G2Affine{X: Q[k].X, Y: *pr.Ext2.Neg(&Q[k].Y)} - // (x,0) cannot be on BLS12381 because -3 is a cubic non-residue in Fp + // (x,0) cannot be on BLS12-381 because -4 is a cubic non-residue in Fp // so, 1/y is well defined for all points P's yInv[k] = pr.curveF.Inverse(&P[k].Y) xOverY[k] = pr.curveF.MulMod(&P[k].X, yInv[k]) } - // Compute ∏ᵢ { fᵢ_{ℓ,Q}(P) } - // i = len(loopCounter) - 2, separately to avoid E12 Square - // (Square(res) = 1² = 1) - - // k = 0, separately to avoid MulBy034 (res × ℓ) - // (assign line to res) - Qacc[0], l1 = pr.doubleStep(Qacc[0]) - // line evaluation at P[0] - res.C1.B0 = *pr.MulByElement(&l1.R0, xOverY[0]) - res.C1.B1 = *pr.MulByElement(&l1.R1, yInv[0]) - - if n >= 2 { - // k = 1, separately to avoid MulBy034 (res × ℓ) - // (res is also a line at this point, so we use Mul034By034 ℓ × ℓ) - Qacc[1], l1 = pr.doubleStep(Qacc[1]) - // line evaluation at P[1] - l1.R0 = *pr.MulByElement(&l1.R0, xOverY[1]) - l1.R1 = *pr.MulByElement(&l1.R1, yInv[1]) - res = pr.Mul034By034(&l1.R0, &l1.R1, &res.C1.B0, &res.C1.B1) - } - - if n >= 3 { - // k >= 2 - for k := 2; k < n; k++ { - // Qacc[k] ← 2Qacc[k] and l1 the tangent ℓ passing 2Qacc[k] - Qacc[k], l1 = pr.doubleStep(Qacc[k]) - // line evaluation at P[k] - l1.R0 = *pr.MulByElement(&l1.R0, xOverY[k]) - l1.R1 = *pr.MulByElement(&l1.R1, yInv[k]) - // ℓ × res - res = pr.MulBy034(res, &l1.R0, &l1.R1) - } + // i = 62 + for k := 0; k < n; k++ { + // Qacc[k] ← 3Qacc[k], + // l1 the tangent ℓ to 2Q[k] + // l2 the line ℓ passing 2Q[k] and Q[k] + Qacc[k], l1, l2 = pr.tripleStep(Qacc[k]) + // line evaluation at P[k] + l1.R0 = *pr.MulByElement(&l1.R0, xOverY[k]) + l1.R1 = *pr.MulByElement(&l1.R1, yInv[k]) + // ℓ × res + res = pr.MulBy014(res, &l1.R1, &l1.R0) + // line evaluation at P[k] + l2.R0 = *pr.MulByElement(&l2.R0, xOverY[k]) + l2.R1 = *pr.MulByElement(&l2.R1, yInv[k]) + // ℓ × res + res = pr.MulBy014(res, &l2.R1, &l2.R0) } - for i := len(loopCounter) - 3; i >= 0; i-- { + // Compute ∏ᵢ { fᵢ_{u,Q}(P) } + for i := 61; i >= 1; i-- { // mutualize the square among n Miller loops // (∏ᵢfᵢ)² res = pr.Square(res) - switch loopCounter[i] { - - case 0: + if loopCounter[i] == 0 { for k := 0; k < n; k++ { // Qacc[k] ← 2Qacc[k] and l1 the tangent ℓ passing 2Qacc[k] Qacc[k], l1 = pr.doubleStep(Qacc[k]) @@ -208,10 +187,9 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { l1.R0 = *pr.MulByElement(&l1.R0, xOverY[k]) l1.R1 = *pr.MulByElement(&l1.R1, yInv[k]) // ℓ × res - res = pr.MulBy034(res, &l1.R0, &l1.R1) + res = pr.MulBy014(res, &l1.R1, &l1.R0) } - - case 1: + } else { for k := 0; k < n; k++ { // Qacc[k] ← 2Qacc[k]+Q[k], // l1 the line ℓ passing Qacc[k] and Q[k] @@ -221,73 +199,33 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { l1.R0 = *pr.MulByElement(&l1.R0, xOverY[k]) l1.R1 = *pr.MulByElement(&l1.R1, yInv[k]) // ℓ × res - res = pr.MulBy034(res, &l1.R0, &l1.R1) - // line evaluation at P[k] - l2.R0 = *pr.MulByElement(&l2.R0, xOverY[k]) - l2.R1 = *pr.MulByElement(&l2.R1, yInv[k]) - // ℓ × res - res = pr.MulBy034(res, &l2.R0, &l2.R1) - } - - case -1: - for k := 0; k < n; k++ { - // Qacc[k] ← 2Qacc[k]-Q[k], - // l1 the line ℓ passing Qacc[k] and -Q[k] - // l2 the line ℓ passing (Qacc[k]-Q[k]) and Qacc[k] - Qacc[k], l1, l2 = pr.doubleAndAddStep(Qacc[k], QNeg[k]) - // line evaluation at P[k] - l1.R0 = *pr.MulByElement(&l1.R0, xOverY[k]) - l1.R1 = *pr.MulByElement(&l1.R1, yInv[k]) - // ℓ × res - res = pr.MulBy034(res, &l1.R0, &l1.R1) + res = pr.MulBy014(res, &l1.R1, &l1.R0) // line evaluation at P[k] l2.R0 = *pr.MulByElement(&l2.R0, xOverY[k]) l2.R1 = *pr.MulByElement(&l2.R1, yInv[k]) // ℓ × res - res = pr.MulBy034(res, &l2.R0, &l2.R1) + res = pr.MulBy014(res, &l2.R1, &l2.R0) } - - default: - return nil, errors.New("invalid loopCounter") } } - // Compute ∏ᵢ { ℓᵢ_{[ℓ]q,π(q)}(p) · ℓᵢ_{[ℓ]q+π(q),-π²(q)}(p) } - Q1, Q2 := new(G2Affine), new(G2Affine) + // i = 0 + res = pr.Square(res) for k := 0; k < n; k++ { - //Q1 = π(Q) - Q1.X = *pr.Ext12.Ext2.Conjugate(&Q[k].X) - Q1.X = *pr.Ext12.Ext2.MulByNonResidue1Power2(&Q1.X) - Q1.Y = *pr.Ext12.Ext2.Conjugate(&Q[k].Y) - Q1.Y = *pr.Ext12.Ext2.MulByNonResidue1Power3(&Q1.Y) - - // Q2 = -π²(Q) - Q2.X = *pr.Ext12.Ext2.MulByNonResidue2Power2(&Q[k].X) - Q2.Y = *pr.Ext12.Ext2.MulByNonResidue2Power3(&Q[k].Y) - Q2.Y = *pr.Ext12.Ext2.Neg(&Q2.Y) - - // Qacc[k] ← Qacc[k]+π(Q) and - // l1 the line passing Qacc[k] and π(Q) - Qacc[k], l1 = pr.addStep(Qacc[k], Q1) - // line evaluation at P[k] - l1.R0 = *pr.Ext2.MulByElement(&l1.R0, xOverY[k]) - l1.R1 = *pr.Ext2.MulByElement(&l1.R1, yInv[k]) - // ℓ × res - res = pr.MulBy034(res, &l1.R0, &l1.R1) - - // l2 the line passing Qacc[k] and -π²(Q) - l2 = pr.lineCompute(Qacc[k], Q2) + // l1 the tangent ℓ passing 2Qacc[k] + l1 = pr.tangentCompute(Qacc[k]) // line evaluation at P[k] - l2.R0 = *pr.MulByElement(&l2.R0, xOverY[k]) - l2.R1 = *pr.MulByElement(&l2.R1, yInv[k]) + l1.R0 = *pr.MulByElement(&l1.R0, xOverY[k]) + l1.R1 = *pr.MulByElement(&l1.R1, yInv[k]) // ℓ × res - res = pr.MulBy034(res, &l2.R0, &l2.R1) - + res = pr.MulBy014(res, &l1.R1, &l1.R0) } + // negative x₀ + res = pr.Ext12.Conjugate(res) + return res, nil } -*/ // doubleAndAddStep doubles p1 and adds p2 to the result in affine coordinates, and evaluates the line in Miller loop // https://eprint.iacr.org/2022/1162 (Section 6.1) @@ -408,13 +346,65 @@ func (pr Pairing) addStep(p1, p2 *G2Affine) (*G2Affine, *lineEvaluation) { } -// lineCompute computes the line that goes through p1 and p2 but does not compute p1+p2 -func (pr Pairing) lineCompute(p1, p2 *G2Affine) *lineEvaluation { +// tripleStep triples p1 in affine coordinates, and evaluates the line in Miller loop +func (pr Pairing) tripleStep(p1 *G2Affine) (*G2Affine, *lineEvaluation, *lineEvaluation) { - // compute λ = (y2-y1)/(x2-x1) - qypy := pr.Ext2.Sub(&p2.Y, &p1.Y) - qxpx := pr.Ext2.Sub(&p2.X, &p1.X) - λ := pr.Ext2.DivUnchecked(qypy, qxpx) + var line1, line2 lineEvaluation + var res G2Affine + + // λ1 = 3x²/2y + n := pr.Ext2.Square(&p1.X) + three := big.NewInt(3) + n = pr.Ext2.MulByConstElement(n, three) + d := pr.Ext2.Double(&p1.Y) + λ1 := pr.Ext2.DivUnchecked(n, d) + + // compute line1 + line1.R0 = *pr.Ext2.Neg(λ1) + line1.R1 = *pr.Ext2.Mul(λ1, &p1.X) + line1.R1 = *pr.Ext2.Sub(&line1.R1, &p1.Y) + + // x2 = λ1²-2x + x2 := pr.Ext2.Square(λ1) + x2 = pr.Ext2.Sub(x2, &p1.X) + x2 = pr.Ext2.Sub(x2, &p1.X) + + // ommit yr computation, and + // compute λ2 = 2y/(x2 − x) − λ1. + x1x2 := pr.Ext2.Sub(&p1.X, x2) + λ2 := pr.Ext2.DivUnchecked(d, x1x2) + λ2 = pr.Ext2.Sub(λ2, λ1) + + // compute line2 + line2.R0 = *pr.Ext2.Neg(λ2) + line2.R1 = *pr.Ext2.Mul(λ2, &p1.X) + line2.R1 = *pr.Ext2.Sub(&line2.R1, &p1.Y) + + // xr = λ²-p.x-x2 + λ2λ2 := pr.Ext2.Mul(λ2, λ2) + qxrx := pr.Ext2.Add(x2, &p1.X) + xr := pr.Ext2.Sub(λ2λ2, qxrx) + + // yr = λ(p.x-xr) - p.y + pxrx := pr.Ext2.Sub(&p1.X, xr) + λ2pxrx := pr.Ext2.Mul(λ2, pxrx) + yr := pr.Ext2.Sub(λ2pxrx, &p1.Y) + + res.X = *xr + res.Y = *yr + + return &res, &line1, &line2 +} + +// tangentCompute computes the line that goes through p1 and p2 but does not compute p1+p2 +func (pr Pairing) tangentCompute(p1 *G2Affine) *lineEvaluation { + + // λ = 3x²/2y + n := pr.Ext2.Square(&p1.X) + three := big.NewInt(3) + n = pr.Ext2.MulByConstElement(n, three) + d := pr.Ext2.Double(&p1.Y) + λ := pr.Ext2.DivUnchecked(n, d) var line lineEvaluation line.R0 = *pr.Ext2.Neg(λ) diff --git a/std/algebra/emulated/sw_bls12381/pairing_test.go b/std/algebra/emulated/sw_bls12381/pairing_test.go index 63d32d14e8..4b30bbac99 100644 --- a/std/algebra/emulated/sw_bls12381/pairing_test.go +++ b/std/algebra/emulated/sw_bls12381/pairing_test.go @@ -7,7 +7,10 @@ import ( "github.com/consensys/gnark-crypto/ecc" bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/profile" "github.com/consensys/gnark/test" ) @@ -49,11 +52,10 @@ func TestFinalExponentiationTestSolve(t *testing.T) { InGt: NewGTEl(gt), Res: NewGTEl(res), } - err := test.IsSolved(&FinalExponentiationCircuit{}, &witness, ecc.BLS12_381.ScalarField()) + err := test.IsSolved(&FinalExponentiationCircuit{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } -/* type PairCircuit struct { InG1 G1Affine InG2 G2Affine @@ -83,7 +85,7 @@ func TestPairTestSolve(t *testing.T) { InG2: NewG2Affine(q), Res: NewGTEl(res), } - err = test.IsSolved(&PairCircuit{}, &witness, ecc.BLS12_381.ScalarField()) + err = test.IsSolved(&PairCircuit{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -93,8 +95,7 @@ var ccsBench constraint.ConstraintSystem func BenchmarkPairing(b *testing.B) { var c PairCircuit p := profile.Start() - ccsBench, _ = frontend.Compile(ecc.BLS12_381.ScalarField(), r1cs.NewBuilder, &c) + ccsBench, _ = frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &c) p.Stop() fmt.Println(p.NbConstraints()) } -*/ From 08e637cf9bf5f26ae551ff5a292935ad03eda807 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Mon, 20 Mar 2023 16:27:05 -0400 Subject: [PATCH 178/464] fix: update stats --- internal/stats/latest.stats | Bin 2803 -> 2803 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/internal/stats/latest.stats b/internal/stats/latest.stats index 27e6782e0237df4bb959280fdee86aabc437f96a..88e364c06c07b5ce7f5143ecb1d6a86f12d2362d 100644 GIT binary patch delta 190 zcmew?`dM^?J0qj`WJON#&G%SZnI=22v`o(9YMrdW`DZde^TWx`9Cs%tvp<+D!^JcC z53}23eWnMK-5E3MZ5}cH^IXBe_zw?5Ux@LaIY^CB8&I7FLNNmeUVU&QaT@@1PY?jr C`%2yb delta 186 zcmew?`dM^?JLBY?oSF6IRgC}2{xLBA!@~&v#rQ9H9#BopEg&vKC}!Zms}F7@ZUZLY z Date: Mon, 20 Mar 2023 23:16:29 +0000 Subject: [PATCH 179/464] perf(bls12-381/pairing): optimize first iteration of MillerLoop --- .../emulated/fields_bls12381/e12_pairing.go | 66 +++++++++++++++++++ std/algebra/emulated/fields_bls12381/e2.go | 9 +++ std/algebra/emulated/fields_bls12381/e6.go | 26 ++++++++ std/algebra/emulated/sw_bls12381/pairing.go | 36 ++++++++-- 4 files changed, 132 insertions(+), 5 deletions(-) diff --git a/std/algebra/emulated/fields_bls12381/e12_pairing.go b/std/algebra/emulated/fields_bls12381/e12_pairing.go index 5d220a5d48..223cfe2f64 100644 --- a/std/algebra/emulated/fields_bls12381/e12_pairing.go +++ b/std/algebra/emulated/fields_bls12381/e12_pairing.go @@ -30,6 +30,9 @@ func (e Ext12) ExptHalf(x *E12) *E12 { z = e.Mul(x, z) // Step 8: z = x^0x68 + // TODO: for 3 squares in a row SQR12345 variant of Karabina's cyclotomic + // square (paragraph 5.6) is preferred. + // NCycloSquareCompressed() implements SQR2345 variant. z = e.NCycloSquareCompressed(z, 3) z = e.DecompressKarabina(z) @@ -99,3 +102,66 @@ func (e *Ext12) MulBy014(z *E12, c0, c1 *E2) *E12 { C1: *zC1, } } + +// multiplies two E12 sparse element of the form: +// +// E12{ +// C0: E6{B0: c0, B1: c1, B2: 0}, +// C1: E6{B0: 0, B1: 1, B2: 0}, +// } +// +// and +// +// E12{ +// C0: E6{B0: d0, B1: d1, B2: 0}, +// C1: E6{B0: 0, B1: 1, B2: 0}, +// } +func (e Ext12) Mul014By014(d0, d1, c0, c1 *E2) *[5]E2 { + one := e.Ext2.One() + x0 := e.Ext2.Mul(c0, d0) + x1 := e.Ext2.Mul(c1, d1) + tmp := e.Ext2.Add(c0, one) + x04 := e.Ext2.Add(d0, one) + x04 = e.Ext2.Mul(x04, tmp) + x04 = e.Ext2.Sub(x04, x0) + x04 = e.Ext2.Sub(x04, one) + tmp = e.Ext2.Add(c0, c1) + x01 := e.Ext2.Add(d0, d1) + x01 = e.Ext2.Mul(x01, tmp) + x01 = e.Ext2.Sub(x01, x0) + x01 = e.Ext2.Sub(x01, x1) + tmp = e.Ext2.Add(c1, one) + x14 := e.Ext2.Add(d1, one) + x14 = e.Ext2.Mul(x14, tmp) + x14 = e.Ext2.Sub(x14, x1) + x14 = e.Ext2.Sub(x14, one) + + zC0B0 := e.Ext2.NonResidue() + zC0B0 = e.Ext2.Add(zC0B0, x0) + + return &[5]E2{*zC0B0, *x01, *x1, *x04, *x14} +} + +// MulBy01245 multiplies z by an E12 sparse element of the form +// +// E12{ +// C0: E6{B0: c0, B1: c1, B2: c2}, +// C1: E6{B0: 0, B1: c4, B2: c5}, +// } +func (e *Ext12) MulBy01245(z *E12, x *[5]E2) *E12 { + c0 := &E6{B0: x[0], B1: x[1], B2: x[2]} + c1 := &E6{B0: *e.Ext2.Zero(), B1: x[3], B2: x[4]} + a := e.Ext6.Add(&z.C0, &z.C1) + b := e.Ext6.Add(c0, c1) + a = e.Ext6.Mul(a, b) + b = e.Ext6.Mul(&z.C0, c0) + c := e.Ext6.MulBy12(&z.C1, &x[3], &x[4]) + z1 := e.Ext6.Sub(a, b) + z1 = e.Ext6.Sub(z1, c) + z0 := e.Ext6.MulByNonResidue(c) + z0 = e.Ext6.Add(z0, b) + return &E12{ + C0: *z0, + C1: *z1, + } +} diff --git a/std/algebra/emulated/fields_bls12381/e2.go b/std/algebra/emulated/fields_bls12381/e2.go index 4c2e6b8e2f..f4fd3fe7d9 100644 --- a/std/algebra/emulated/fields_bls12381/e2.go +++ b/std/algebra/emulated/fields_bls12381/e2.go @@ -237,6 +237,15 @@ func (e Ext2) Zero() *E2 { } } +// returns 1+u +func (e Ext2) NonResidue() *E2 { + one := e.fp.One() + return &E2{ + A0: *one, + A1: *one, + } +} + func (e Ext2) Square(x *E2) *E2 { a := e.fp.Add(&x.A0, &x.A1) b := e.fp.Sub(&x.A0, &x.A1) diff --git a/std/algebra/emulated/fields_bls12381/e6.go b/std/algebra/emulated/fields_bls12381/e6.go index c32e9e864b..e42f307589 100644 --- a/std/algebra/emulated/fields_bls12381/e6.go +++ b/std/algebra/emulated/fields_bls12381/e6.go @@ -151,6 +151,32 @@ func (e Ext6) MulByE2(x *E6, y *E2) *E6 { } } +// MulBy12 multiplication by sparse element (0,b1,b2) +func (e Ext6) MulBy12(x *E6, b1, b2 *E2) *E6 { + t1 := e.Ext2.Mul(&x.B1, b1) + t2 := e.Ext2.Mul(&x.B2, b2) + c0 := e.Ext2.Add(&x.B1, &x.B2) + tmp := e.Ext2.Add(b1, b2) + c0 = e.Ext2.Mul(c0, tmp) + c0 = e.Ext2.Sub(c0, t1) + c0 = e.Ext2.Sub(c0, t2) + c0 = e.Ext2.MulByNonResidue(c0) + c1 := e.Ext2.Add(&x.B0, &x.B1) + c1 = e.Ext2.Mul(c1, b1) + c1 = e.Ext2.Sub(c1, t1) + tmp = e.Ext2.MulByNonResidue(t2) + c1 = e.Ext2.Add(c1, tmp) + tmp = e.Ext2.Add(&x.B0, &x.B2) + c2 := e.Ext2.Mul(b2, tmp) + c2 = e.Ext2.Sub(c2, t2) + c2 = e.Ext2.Add(c2, t1) + return &E6{ + B0: *c0, + B1: *c1, + B2: *c2, + } +} + // MulBy01 multiplication by sparse element (c0,c1,0) func (e Ext6) MulBy01(z *E6, c0, c1 *E2) *E6 { a := e.Ext2.Mul(&z.B0, c0) diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go index d55dad3bed..f8f738b12e 100644 --- a/std/algebra/emulated/sw_bls12381/pairing.go +++ b/std/algebra/emulated/sw_bls12381/pairing.go @@ -155,8 +155,34 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { xOverY[k] = pr.curveF.MulMod(&P[k].X, yInv[k]) } - // i = 62 - for k := 0; k < n; k++ { + // Compute ∏ᵢ { fᵢ_{x₀,Q}(P) } + + // i = 62, separately to avoid an E12 Square + // (Square(res) = 1² = 1) + + // k = 0, separately to avoid MulBy034 (res × ℓ) + + // Qacc[k] ← 3Qacc[k], + // l1 the tangent ℓ to 2Q[k] + // l2 the line ℓ passing 2Q[k] and Q[k] + Qacc[0], l1, l2 = pr.tripleStep(Qacc[0]) + // line evaluation at P[0] + // and assign line to res (R1, R0, 0, 0, 1, 0) + res.C0.B1 = *pr.MulByElement(&l1.R0, xOverY[0]) + res.C0.B0 = *pr.MulByElement(&l1.R1, yInv[0]) + res.C1.B1 = *pr.Ext2.One() + // line evaluation at P[0] + l2.R0 = *pr.MulByElement(&l2.R0, xOverY[0]) + l2.R1 = *pr.MulByElement(&l2.R1, yInv[0]) + // res = ℓ × ℓ + prodLines := *pr.Mul014By014(&l2.R1, &l2.R0, &res.C0.B0, &res.C0.B1) + res.C0.B0 = prodLines[0] + res.C0.B1 = prodLines[1] + res.C0.B2 = prodLines[2] + res.C1.B1 = prodLines[3] + res.C1.B2 = prodLines[4] + + for k := 1; k < n; k++ { // Qacc[k] ← 3Qacc[k], // l1 the tangent ℓ to 2Q[k] // l2 the line ℓ passing 2Q[k] and Q[k] @@ -198,18 +224,18 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { // line evaluation at P[k] l1.R0 = *pr.MulByElement(&l1.R0, xOverY[k]) l1.R1 = *pr.MulByElement(&l1.R1, yInv[k]) - // ℓ × res - res = pr.MulBy014(res, &l1.R1, &l1.R0) // line evaluation at P[k] l2.R0 = *pr.MulByElement(&l2.R0, xOverY[k]) l2.R1 = *pr.MulByElement(&l2.R1, yInv[k]) // ℓ × res + res = pr.MulBy014(res, &l1.R1, &l1.R0) + // ℓ × res res = pr.MulBy014(res, &l2.R1, &l2.R0) } } } - // i = 0 + // i = 0, separately to avoid a point doubling res = pr.Square(res) for k := 0; k < n; k++ { // l1 the tangent ℓ passing 2Qacc[k] From c9217504d0233a9ad4362b3215bdc3296b019ed4 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Mon, 20 Mar 2023 23:54:43 +0000 Subject: [PATCH 180/464] build: go get gnark-crypto@develop --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 2e0673510b..0f33c69eb1 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 - github.com/consensys/gnark-crypto v0.9.2-0.20230314094804-5185eb8c3978 + github.com/consensys/gnark-crypto v0.9.2-0.20230320235232-ffa6f508088a github.com/fxamacker/cbor/v2 v2.4.0 github.com/google/go-cmp v0.5.9 github.com/google/pprof v0.0.0-20230207041349-798e818bf904 diff --git a/go.sum b/go.sum index 0b2cb4335f..4ddb264e07 100644 --- a/go.sum +++ b/go.sum @@ -8,6 +8,8 @@ github.com/consensys/gnark-crypto v0.9.2-0.20230303095500-84be66f759b2 h1:AoLNGE github.com/consensys/gnark-crypto v0.9.2-0.20230303095500-84be66f759b2/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= github.com/consensys/gnark-crypto v0.9.2-0.20230314094804-5185eb8c3978 h1:jMmg1FkGd5+Fv1jWNTwSIGVz5qkabvPvbfFb5v1mmIA= github.com/consensys/gnark-crypto v0.9.2-0.20230314094804-5185eb8c3978/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= +github.com/consensys/gnark-crypto v0.9.2-0.20230320235232-ffa6f508088a h1:Yhj1LwaNW0HsMmJO2FNdU+1V1vQ5+ssq+cACUHVW7vw= +github.com/consensys/gnark-crypto v0.9.2-0.20230320235232-ffa6f508088a/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= From 088b3da167e35915c03ef7c6b3904b6f40db3d21 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Mon, 20 Mar 2023 23:58:24 +0000 Subject: [PATCH 181/464] refactor: remove profiler in test --- std/algebra/emulated/sw_bls12381/pairing_test.go | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/std/algebra/emulated/sw_bls12381/pairing_test.go b/std/algebra/emulated/sw_bls12381/pairing_test.go index 4b30bbac99..06827f88e4 100644 --- a/std/algebra/emulated/sw_bls12381/pairing_test.go +++ b/std/algebra/emulated/sw_bls12381/pairing_test.go @@ -7,10 +7,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" - "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/profile" "github.com/consensys/gnark/test" ) @@ -88,14 +85,3 @@ func TestPairTestSolve(t *testing.T) { err = test.IsSolved(&PairCircuit{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } - -// bench -var ccsBench constraint.ConstraintSystem - -func BenchmarkPairing(b *testing.B) { - var c PairCircuit - p := profile.Start() - ccsBench, _ = frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &c) - p.Stop() - fmt.Println(p.NbConstraints()) -} From a6fffcf2c4e16f5c9c9cb3e5aadbbc1768376bfe Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 21 Mar 2023 09:08:53 +0000 Subject: [PATCH 182/464] perf: optimize final exp (Fuentes et al.) --- std/algebra/emulated/sw_bn254/pairing.go | 46 +++++++++++------------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 2aae15dc83..ea41ad6cb1 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -72,7 +72,7 @@ func NewPairing(api frontend.API) (*Pairing, error) { // // and r does NOT divide d' func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { - var t [4]*GTEl + var t [5]*GTEl // Easy part // (p⁶-1)(p²+1) @@ -85,36 +85,32 @@ func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { // 2x₀(6x₀²+3x₀+1)(p⁴-p²+1)/r // Duquesne and Ghammam // https://eprint.iacr.org/2015/192.pdf - // Fuentes et al. variant (alg. 10) + // Fuentes et al. (alg. 6) t[0] = pr.Ext12.Expt(result) t[0] = pr.Ext12.Conjugate(t[0]) t[0] = pr.Ext12.CyclotomicSquare(t[0]) - t[2] = pr.Ext12.Expt(t[0]) + t[1] = pr.Ext12.CyclotomicSquare(t[0]) + t[1] = pr.Ext12.Mul(t[0], t[1]) + t[2] = pr.Ext12.Expt(t[1]) t[2] = pr.Ext12.Conjugate(t[2]) - t[1] = pr.Ext12.CyclotomicSquare(t[2]) - t[2] = pr.Ext12.Mul(t[2], t[1]) - t[2] = pr.Ext12.Mul(t[2], result) - t[1] = pr.Ext12.Expt(t[2]) - t[1] = pr.Ext12.CyclotomicSquare(t[1]) - t[1] = pr.Ext12.Mul(t[1], t[2]) - t[1] = pr.Ext12.Conjugate(t[1]) t[3] = pr.Ext12.Conjugate(t[1]) - t[1] = pr.Ext12.CyclotomicSquare(t[0]) - t[1] = pr.Ext12.Mul(t[1], result) - t[1] = pr.Ext12.Conjugate(t[1]) - t[1] = pr.Ext12.Mul(t[1], t[3]) - t[0] = pr.Ext12.Mul(t[0], t[1]) - t[2] = pr.Ext12.Mul(t[2], t[1]) - t[3] = pr.Ext12.FrobeniusSquare(t[1]) + t[1] = pr.Ext12.Mul(t[2], t[3]) + t[3] = pr.Ext12.CyclotomicSquare(t[2]) + t[4] = pr.Ext12.Expt(t[3]) + t[4] = pr.Ext12.Mul(t[4], t[1]) + t[3] = pr.Ext12.Mul(t[4], t[0]) + t[0] = pr.Ext12.Mul(t[4], t[2]) + t[0] = pr.Ext12.Mul(result, t[0]) + t[2] = pr.Ext12.Frobenius(t[3]) + t[0] = pr.Ext12.Mul(t[2], t[0]) + t[2] = pr.Ext12.FrobeniusSquare(t[4]) + t[0] = pr.Ext12.Mul(t[2], t[0]) + t[2] = pr.Ext12.Conjugate(result) t[2] = pr.Ext12.Mul(t[2], t[3]) - t[3] = pr.Ext12.Conjugate(result) - t[3] = pr.Ext12.Mul(t[3], t[0]) - t[1] = pr.Ext12.FrobeniusCube(t[3]) - t[2] = pr.Ext12.Mul(t[2], t[1]) - t[1] = pr.Ext12.Frobenius(t[0]) - t[1] = pr.Ext12.Mul(t[1], t[2]) - - return t[1] + t[2] = pr.Ext12.FrobeniusCube(t[2]) + t[0] = pr.Ext12.Mul(t[2], t[0]) + + return t[0] } func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { From 37af3ceeccc90891d1785b5db53240038ac5f9ad Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 21 Mar 2023 23:59:23 +0000 Subject: [PATCH 183/464] perf(bn254/pairing): use torus-based arithmetic for final exp --- std/algebra/emulated/fields_bn254/e12.go | 146 ------ .../emulated/fields_bn254/e12_pairing.go | 196 ++++++-- std/algebra/emulated/fields_bn254/e12_test.go | 421 ++++++++++++++---- std/algebra/emulated/fields_bn254/e6.go | 50 +++ std/algebra/emulated/fields_bn254/e6_test.go | 72 +++ std/algebra/emulated/fields_bn254/hints.go | 29 ++ std/algebra/emulated/sw_bn254/pairing.go | 73 +-- std/algebra/emulated/sw_bn254/pairing_test.go | 14 + 8 files changed, 702 insertions(+), 299 deletions(-) diff --git a/std/algebra/emulated/fields_bn254/e12.go b/std/algebra/emulated/fields_bn254/e12.go index 8f18867f98..cf73a547ed 100644 --- a/std/algebra/emulated/fields_bn254/e12.go +++ b/std/algebra/emulated/fields_bn254/e12.go @@ -116,152 +116,6 @@ func (e Ext12) CyclotomicSquare(x *E12) *E12 { } } -// Karabina's compressed cyclotomic square -// https://eprint.iacr.org/2010/542.pdf -// Th. 3.2 with minor modifications to fit our tower -func (e Ext12) CyclotomicSquareCompressed(x *E12) *E12 { - - // t0 = g1² - t0 := e.Ext2.Square(&x.C0.B1) - // t1 = g5² - t1 := e.Ext2.Square(&x.C1.B2) - // t5 = g1 + g5 - t5 := e.Ext2.Add(&x.C0.B1, &x.C1.B2) - // t2 = (g1 + g5)² - t2 := e.Ext2.Square(t5) - - // t3 = g1² + g5² - t3 := e.Ext2.Add(t0, t1) - // t5 = 2 * g1 * g5 - t5 = e.Ext2.Sub(t2, t3) - - // t6 = g3 + g2 - t6 := e.Ext2.Add(&x.C1.B0, &x.C0.B2) - // t3 = (g3 + g2)² - t3 = e.Ext2.Square(t6) - // t2 = g3² - t2 = e.Ext2.Square(&x.C1.B0) - - // t6 = 2 * nr * g1 * g5 - t6 = e.Ext2.MulByNonResidue(t5) - // t5 = 4 * nr * g1 * g5 + 2 * g3 - t5 = e.Ext2.Add(t6, &x.C1.B0) - t5 = e.Ext2.Double(t5) - // z3 = 6 * nr * g1 * g5 + 2 * g3 - C1B0 := e.Ext2.Add(t5, t6) - - // t4 = nr * g5² - t4 := e.Ext2.MulByNonResidue(t1) - // t5 = nr * g5² + g1² - t5 = e.Ext2.Add(t0, t4) - // t6 = nr * g5² + g1² - g2 - t6 = e.Ext2.Sub(t5, &x.C0.B2) - - // t1 = g2² - t1 = e.Ext2.Square(&x.C0.B2) - - // t6 = 2 * nr * g5² + 2 * g1² - 2*g2 - t6 = e.Ext2.Double(t6) - // z2 = 3 * nr * g5² + 3 * g1² - 2*g2 - C0B2 := e.Ext2.Add(t6, t5) - - // t4 = nr * g2² - t4 = e.Ext2.MulByNonResidue(t1) - // t5 = g3² + nr * g2² - t5 = e.Ext2.Add(t2, t4) - // t6 = g3² + nr * g2² - g1 - t6 = e.Ext2.Sub(t5, &x.C0.B1) - // t6 = 2 * g3² + 2 * nr * g2² - 2 * g1 - t6 = e.Ext2.Double(t6) - // z1 = 3 * g3² + 3 * nr * g2² - 2 * g1 - C0B1 := e.Ext2.Add(t6, t5) - - // t0 = g2² + g3² - t0 = e.Ext2.Add(t2, t1) - // t5 = 2 * g3 * g2 - t5 = e.Ext2.Sub(t3, t0) - // t6 = 2 * g3 * g2 + g5 - t6 = e.Ext2.Add(t5, &x.C1.B2) - // t6 = 4 * g3 * g2 + 2 * g5 - t6 = e.Ext2.Double(t6) - // z5 = 6 * g3 * g2 + 2 * g5 - C1B2 := e.Ext2.Add(t5, t6) - - zero := e.Ext2.Zero() - - return &E12{ - C0: E6{ - B0: *zero, - B1: *C0B1, - B2: *C0B2, - }, - C1: E6{ - B0: *C1B0, - B1: *zero, - B2: *C1B2, - }, - } -} - -func (e Ext12) NCycloSquareCompressed(z *E12, n int) *E12 { - for i := 0; i < n; i++ { - z = e.CyclotomicSquareCompressed(z) - } - return z -} - -// DecompressKarabina Karabina's cyclotomic square result -func (e Ext12) DecompressKarabina(x *E12) *E12 { - - one := e.Ext2.One() - - // TODO: hadle the g3==0 case with MUX - - // t0 = g1² - t0 := e.Ext2.Square(&x.C0.B1) - // t1 = 3 * g1² - 2 * g2 - t1 := e.Ext2.Sub(t0, &x.C0.B2) - t1 = e.Ext2.Double(t1) - t1 = e.Ext2.Add(t1, t0) - // t0 = E * g5² + t1 - t2 := e.Ext2.Square(&x.C1.B2) - t0 = e.Ext2.MulByNonResidue(t2) - t0 = e.Ext2.Add(t0, t1) - // t1 = 4 * g3 - t1 = e.Ext2.Double(&x.C1.B0) - t1 = e.Ext2.Double(t1) - - // z4 = g4 - C1B1 := e.Ext2.DivUnchecked(t0, t1) - - // t1 = g2 * g1 - t1 = e.Ext2.Mul(&x.C0.B2, &x.C0.B1) - // t2 = 2 * g4² - 3 * g2 * g1 - t2 = e.Ext2.Square(C1B1) - t2 = e.Ext2.Sub(t2, t1) - t2 = e.Ext2.Double(t2) - t2 = e.Ext2.Sub(t2, t1) - // t1 = g3 * g5 (g3 can be 0) - t1 = e.Ext2.Mul(&x.C1.B0, &x.C1.B2) - // c₀ = E * (2 * g4² + g3 * g5 - 3 * g2 * g1) + 1 - t2 = e.Ext2.Add(t2, t1) - C0B0 := e.Ext2.MulByNonResidue(t2) - C0B0 = e.Ext2.Add(C0B0, one) - - return &E12{ - C0: E6{ - B0: *C0B0, - B1: x.C0.B1, - B2: x.C0.B2, - }, - C1: E6{ - B0: x.C1.B0, - B1: *C1B1, - B2: x.C1.B2, - }, - } -} - func (e Ext12) Frobenius(x *E12) *E12 { t0 := e.Ext2.Conjugate(&x.C0.B0) t1 := e.Ext2.Conjugate(&x.C0.B1) diff --git a/std/algebra/emulated/fields_bn254/e12_pairing.go b/std/algebra/emulated/fields_bn254/e12_pairing.go index 0cfacc6355..0f4b2456ba 100644 --- a/std/algebra/emulated/fields_bn254/e12_pairing.go +++ b/std/algebra/emulated/fields_bn254/e12_pairing.go @@ -1,6 +1,19 @@ package fields_bn254 -func (e Ext12) Expt(x *E12) *E12 { +import ( + "github.com/consensys/gnark/std/math/emulated" +) + +func (e Ext12) nCycloSquareTorus(z *E6, n int) *E6 { + for i := 0; i < n; i++ { + z = e.SquareTorus(z) + } + return z +} + +// Exponentiation by the seed t=4965661367192848881 +// The computations are performed on E6 compressed form using Torus-based arithmetic. +func (e Ext12) ExptTorus(x *E6) *E6 { // Expt computation is derived from the addition chain: // // _10 = 2*1 @@ -23,44 +36,36 @@ func (e Ext12) Expt(x *E12) *E12 { // // Generated by github.com/mmcloughlin/addchain v0.4.0. - t3 := e.CyclotomicSquare(x) - t5 := e.CyclotomicSquare(t3) - result := e.CyclotomicSquare(t5) - t0 := e.CyclotomicSquare(result) - t2 := e.Mul(x, t0) - t0 = e.Mul(t3, t2) - t1 := e.Mul(x, t0) - t4 := e.Mul(result, t2) - t6 := e.CyclotomicSquare(t2) - t1 = e.Mul(t0, t1) - t0 = e.Mul(t3, t1) - t6 = e.NCycloSquareCompressed(t6, 6) - t6 = e.DecompressKarabina(t6) - t5 = e.Mul(t5, t6) - t5 = e.Mul(t4, t5) - t5 = e.NCycloSquareCompressed(t5, 7) - t5 = e.DecompressKarabina(t5) - t4 = e.Mul(t4, t5) - t4 = e.NCycloSquareCompressed(t4, 8) - t4 = e.DecompressKarabina(t4) - t4 = e.Mul(t0, t4) - t3 = e.Mul(t3, t4) - t3 = e.NCycloSquareCompressed(t3, 6) - t3 = e.DecompressKarabina(t3) - t2 = e.Mul(t2, t3) - t2 = e.NCycloSquareCompressed(t2, 8) - t2 = e.DecompressKarabina(t2) - t2 = e.Mul(t0, t2) - t2 = e.NCycloSquareCompressed(t2, 6) - t2 = e.DecompressKarabina(t2) - t2 = e.Mul(t0, t2) - t2 = e.NCycloSquareCompressed(t2, 10) - t2 = e.DecompressKarabina(t2) - t1 = e.Mul(t1, t2) - t1 = e.NCycloSquareCompressed(t1, 6) - t1 = e.DecompressKarabina(t1) - t0 = e.Mul(t0, t1) - z := e.Mul(result, t0) + t3 := e.SquareTorus(x) + t5 := e.SquareTorus(t3) + result := e.SquareTorus(t5) + t0 := e.SquareTorus(result) + t2 := e.MulTorus(x, t0) + t0 = e.MulTorus(t3, t2) + t1 := e.MulTorus(x, t0) + t4 := e.MulTorus(result, t2) + t6 := e.SquareTorus(t2) + t1 = e.MulTorus(t0, t1) + t0 = e.MulTorus(t3, t1) + t6 = e.nCycloSquareTorus(t6, 6) + t5 = e.MulTorus(t5, t6) + t5 = e.MulTorus(t4, t5) + t5 = e.nCycloSquareTorus(t5, 7) + t4 = e.MulTorus(t4, t5) + t4 = e.nCycloSquareTorus(t4, 8) + t4 = e.MulTorus(t0, t4) + t3 = e.MulTorus(t3, t4) + t3 = e.nCycloSquareTorus(t3, 6) + t2 = e.MulTorus(t2, t3) + t2 = e.nCycloSquareTorus(t2, 8) + t2 = e.MulTorus(t0, t2) + t2 = e.nCycloSquareTorus(t2, 6) + t2 = e.MulTorus(t0, t2) + t2 = e.nCycloSquareTorus(t2, 10) + t1 = e.MulTorus(t1, t2) + t1 = e.nCycloSquareTorus(t1, 6) + t0 = e.MulTorus(t0, t1) + z := e.MulTorus(result, t0) return z } @@ -178,3 +183,116 @@ func (e *Ext12) Mul01234By034(x *[5]E2, z3, z4 *E2) *E12 { C1: *z1, } } + +// Torus-based arithmetic: +// +// After the easy part of the final exponentiation the elements are in a proper +// subgroup of Fpk (E12) that coincides with some algebraic tori. The elements +// are in the torus Tk(Fp) and thus in each torus Tk/d(Fp^d) for d|k, d≠k. We +// take d=6. So the elements are in T2(Fp6). +// Let G_{q,2} = {m ∈ Fq^2 | m^(q+1) = 1} where q = p^6. +// When m.C1 = 0, then m.C0 must be 1 or −1. +// +// We recall the tower construction: +// +// 𝔽p²[u] = 𝔽p/u²+1 +// 𝔽p⁶[v] = 𝔽p²/v³-9-u +// 𝔽p¹²[w] = 𝔽p⁶/w²-v + +// CompressTorus compresses x ∈ E12 to (x.C0 + 1)/x.C1 ∈ E6 +func (e Ext12) CompressTorus(x *E12) *E6 { + // x in G_{q,2} \ {-1,1} + y := e.Ext6.Add(&x.C0, e.Ext6.One()) + y = e.Ext6.DivUnchecked(y, &x.C1) + return y +} + +// DecompressTorus decompresses y ∈ E6 to (y+w)/(y-w) ∈ E12 +func (e Ext12) DecompressTorus(y *E6) *E12 { + var n, d E12 + one := e.Ext6.One() + n.C0 = *y + n.C1 = *one + d.C0 = *y + d.C1 = *e.Ext6.Neg(one) + + x := e.DivUnchecked(&n, &d) + return x +} + +// MulTorus multiplies two compressed elements y1, y2 ∈ E6 +// and returns (y1 * y2 + v)/(y1 + y2) +func (e Ext12) MulTorus(y1, y2 *E6) *E6 { + n := e.Ext6.Mul(y1, y2) + n.B1 = *e.Ext2.Add(&n.B1, e.Ext2.One()) + d := e.Ext6.Add(y1, y2) + y3 := e.Ext6.DivUnchecked(n, d) + return y3 +} + +// InverseTorus inverses a compressed elements y ∈ E6 +// and returns -y +func (e Ext12) InverseTorus(y *E6) *E6 { + return e.Ext6.Neg(y) +} + +// SquareTorus squares a compressed elements y ∈ E6 +// and returns (y + v/g)/2 +func (e Ext12) SquareTorus(y *E6) *E6 { + yInv := e.Ext6.Inverse(y) + // Mul by (0,1,0) + tmp := yInv.B0 + yInv.B0 = *e.Ext2.MulByNonResidue(&yInv.B2) + yInv.B2 = yInv.B1 + yInv.B1 = tmp + + res := e.Ext6.Add(y, yInv) + res = e.Ext6.Halve(res) + + return res +} + +// FrobeniusTorus raises a compressed elements y ∈ E6 to the modulus p +// and returns y^p / v^((p-1)/2) +func (e Ext12) FrobeniusTorus(y *E6) *E6 { + t0 := e.Ext2.Conjugate(&y.B0) + t1 := e.Ext2.Conjugate(&y.B1) + t2 := e.Ext2.Conjugate(&y.B2) + t1 = e.Ext2.MulByNonResidue1Power2(t1) + t2 = e.Ext2.MulByNonResidue1Power4(t2) + + v0 := E2{emulated.ValueOf[emulated.BN254Fp]("18566938241244942414004596690298913868373833782006617400804628704885040364344"), emulated.ValueOf[emulated.BN254Fp]("5722266937896532885780051958958348231143373700109372999374820235121374419868")} + res := &E6{B0: *t0, B1: *t1, B2: *t2} + res = e.Ext6.MulBy0(res, &v0) + + return res +} + +// FrobeniusSquareTorus raises a compressed elements y ∈ E6 to the square modulus p^2 +// and returns y^(p^2) / v^((p^2-1)/2) +func (e Ext12) FrobeniusSquareTorus(y *E6) *E6 { + v0 := emulated.ValueOf[emulated.BN254Fp]("2203960485148121921418603742825762020974279258880205651967") + t0 := e.Ext2.MulByElement(&y.B0, &v0) + t1 := e.Ext2.MulByNonResidue2Power2(&y.B1) + t1 = e.Ext2.MulByElement(t1, &v0) + t2 := e.Ext2.MulByNonResidue2Power4(&y.B2) + t2 = e.Ext2.MulByElement(t2, &v0) + + return &E6{B0: *t0, B1: *t1, B2: *t2} +} + +// FrobeniusCubeTorus raises a compressed elements y ∈ E6 to the cube modulus p^3 +// and returns y^(p^3) / v^((p^3-1)/2) +func (e Ext12) FrobeniusCubeTorus(y *E6) *E6 { + t0 := e.Ext2.Conjugate(&y.B0) + t1 := e.Ext2.Conjugate(&y.B1) + t2 := e.Ext2.Conjugate(&y.B2) + t1 = e.Ext2.MulByNonResidue3Power2(t1) + t2 = e.Ext2.MulByNonResidue3Power4(t2) + + v0 := E2{emulated.ValueOf[emulated.BN254Fp]("10190819375481120917420622822672549775783927716138318623895010788866272024264"), emulated.ValueOf[emulated.BN254Fp]("303847389135065887422783454877609941456349188919719272345083954437860409601")} + res := &E6{B0: *t0, B1: *t1, B2: *t2} + res = e.Ext6.MulBy0(res, &v0) + + return res +} diff --git a/std/algebra/emulated/fields_bn254/e12_test.go b/std/algebra/emulated/fields_bn254/e12_test.go index f8c31760a8..6c864d492f 100644 --- a/std/algebra/emulated/fields_bn254/e12_test.go +++ b/std/algebra/emulated/fields_bn254/e12_test.go @@ -208,82 +208,6 @@ func TestFp12CyclotomicSquare(t *testing.T) { assert.NoError(err) } -type e12CycloSquareKarabina struct { - A E12 - C E12 `gnark:",public"` -} - -func (circuit *e12CycloSquareKarabina) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt12(ba) - expected := e.CyclotomicSquareCompressed(&circuit.A) - e.AssertIsEqual(expected, &circuit.C) - return nil -} - -func TestFp12CyclotomicSquareKarabina(t *testing.T) { - - assert := test.NewAssert(t) - // witness values - var a, c bn254.E12 - _, _ = a.SetRandom() - - // put a in the cyclotomic subgroup - var tmp bn254.E12 - tmp.Conjugate(&a) - a.Inverse(&a) - tmp.Mul(&tmp, &a) - a.FrobeniusSquare(&tmp).Mul(&a, &tmp) - c.CyclotomicSquareCompressed(&a) - - witness := e12CycloSquareKarabina{ - A: FromE12(&a), - C: FromE12(&c), - } - - err := test.IsSolved(&e12CycloSquareKarabina{}, &witness, ecc.BN254.ScalarField()) - assert.NoError(err) -} - -type e12CycloSquareKarabinaAndDecompress struct { - A E12 - C E12 `gnark:",public"` -} - -func (circuit *e12CycloSquareKarabinaAndDecompress) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt12(ba) - expected := e.CyclotomicSquareCompressed(&circuit.A) - expected = e.DecompressKarabina(expected) - e.AssertIsEqual(expected, &circuit.C) - return nil -} - -func TestFp12CyclotomicSquareKarabinaAndDecompress(t *testing.T) { - - assert := test.NewAssert(t) - // witness values - var a, c bn254.E12 - _, _ = a.SetRandom() - - // put a in the cyclotomic subgroup - var tmp bn254.E12 - tmp.Conjugate(&a) - a.Inverse(&a) - tmp.Mul(&tmp, &a) - a.FrobeniusSquare(&tmp).Mul(&a, &tmp) - c.CyclotomicSquareCompressed(&a) - c.DecompressKarabina(&c) - - witness := e12CycloSquareKarabina{ - A: FromE12(&a), - C: FromE12(&c), - } - - err := test.IsSolved(&e12CycloSquareKarabinaAndDecompress{}, &witness, ecc.BN254.ScalarField()) - assert.NoError(err) -} - type e12Conjugate struct { A E12 C E12 `gnark:",public"` @@ -346,15 +270,16 @@ func TestInverseFp12(t *testing.T) { assert.NoError(err) } -type e12Expt struct { - A E12 +type e12ExptTorus struct { + A E6 C E12 `gnark:",public"` } -func (circuit *e12Expt) Define(api frontend.API) error { +func (circuit *e12ExptTorus) Define(api frontend.API) error { ba, _ := emulated.NewField[emulated.BN254Fp](api) e := NewExt12(ba) - expected := e.Expt(&circuit.A) + z := e.ExptTorus(&circuit.A) + expected := e.DecompressTorus(z) e.AssertIsEqual(expected, &circuit.C) return nil @@ -375,13 +300,13 @@ func TestFp12Expt(t *testing.T) { a.FrobeniusSquare(&tmp).Mul(&a, &tmp) c.Expt(&a) - - witness := e12Expt{ - A: FromE12(&a), + _a, _ := a.CompressTorus() + witness := e12ExptTorus{ + A: FromE6(&_a), C: FromE12(&c), } - err := test.IsSolved(&e12Expt{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&e12ExptTorus{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } @@ -517,3 +442,331 @@ func TestFp12MulBy034(t *testing.T) { assert.NoError(err) } + +// Torus-based arithmetic +type torusCompress struct { + A E12 + C E6 `gnark:",public"` +} + +func (circuit *torusCompress) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt12(ba) + expected := e.CompressTorus(&circuit.A) + e.Ext6.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestTorusCompress(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a bn254.E12 + _, _ = a.SetRandom() + + // put a in the cyclotomic subgroup + var tmp bn254.E12 + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + + c, _ := a.CompressTorus() + + witness := torusCompress{ + A: FromE12(&a), + C: FromE6(&c), + } + + err := test.IsSolved(&torusCompress{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type torusDecompress struct { + A E12 + C E12 `gnark:",public"` +} + +func (circuit *torusDecompress) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt12(ba) + compressed := e.CompressTorus(&circuit.A) + expected := e.DecompressTorus(compressed) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestTorusDecompress(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a bn254.E12 + _, _ = a.SetRandom() + + // put a in the cyclotomic subgroup + var tmp bn254.E12 + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + + d, _ := a.CompressTorus() + c := d.DecompressTorus() + + witness := torusDecompress{ + A: FromE12(&a), + C: FromE12(&c), + } + + err := test.IsSolved(&torusDecompress{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type torusMul struct { + A E12 + B E12 + C E12 `gnark:",public"` +} + +func (circuit *torusMul) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt12(ba) + compressedA := e.CompressTorus(&circuit.A) + compressedB := e.CompressTorus(&circuit.B) + compressedAB := e.MulTorus(compressedA, compressedB) + expected := e.DecompressTorus(compressedAB) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestTorusMul(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, b, c, tmp bn254.E12 + _, _ = a.SetRandom() + _, _ = b.SetRandom() + + // put a in the cyclotomic subgroup + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + // put b in the cyclotomic subgroup + tmp.Conjugate(&b) + b.Inverse(&b) + tmp.Mul(&tmp, &b) + b.FrobeniusSquare(&tmp).Mul(&b, &tmp) + + // uncompressed mul + c.Mul(&a, &b) + + witness := torusMul{ + A: FromE12(&a), + B: FromE12(&b), + C: FromE12(&c), + } + + err := test.IsSolved(&torusMul{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type torusInverse struct { + A E12 + C E12 `gnark:",public"` +} + +func (circuit *torusInverse) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt12(ba) + compressed := e.CompressTorus(&circuit.A) + compressed = e.InverseTorus(compressed) + expected := e.DecompressTorus(compressed) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestTorusInverse(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c, tmp bn254.E12 + _, _ = a.SetRandom() + + // put a in the cyclotomic subgroup + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + + // uncompressed inverse + c.Inverse(&a) + + witness := torusInverse{ + A: FromE12(&a), + C: FromE12(&c), + } + + err := test.IsSolved(&torusInverse{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type torusFrobenius struct { + A E12 + C E12 `gnark:",public"` +} + +func (circuit *torusFrobenius) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt12(ba) + compressed := e.CompressTorus(&circuit.A) + compressed = e.FrobeniusTorus(compressed) + expected := e.DecompressTorus(compressed) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestTorusFrobenius(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c, tmp bn254.E12 + _, _ = a.SetRandom() + + // put a in the cyclotomic subgroup + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + + // uncompressed frobenius + c.Frobenius(&a) + + witness := torusFrobenius{ + A: FromE12(&a), + C: FromE12(&c), + } + + err := test.IsSolved(&torusFrobenius{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type torusFrobeniusSquare struct { + A E12 + C E12 `gnark:",public"` +} + +func (circuit *torusFrobeniusSquare) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt12(ba) + compressed := e.CompressTorus(&circuit.A) + compressed = e.FrobeniusSquareTorus(compressed) + expected := e.DecompressTorus(compressed) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestTorusFrobeniusSquare(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c, tmp bn254.E12 + _, _ = a.SetRandom() + + // put a in the cyclotomic subgroup + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + + // uncompressed frobeniusSquare + c.FrobeniusSquare(&a) + + witness := torusFrobeniusSquare{ + A: FromE12(&a), + C: FromE12(&c), + } + + err := test.IsSolved(&torusFrobeniusSquare{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type torusFrobeniusCube struct { + A E12 + C E12 `gnark:",public"` +} + +func (circuit *torusFrobeniusCube) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt12(ba) + compressed := e.CompressTorus(&circuit.A) + compressed = e.FrobeniusCubeTorus(compressed) + expected := e.DecompressTorus(compressed) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestTorusFrobeniusCube(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c, tmp bn254.E12 + _, _ = a.SetRandom() + + // put a in the cyclotomic subgroup + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + + // uncompressed frobeniusCube + c.FrobeniusCube(&a) + + witness := torusFrobeniusCube{ + A: FromE12(&a), + C: FromE12(&c), + } + + err := test.IsSolved(&torusFrobeniusCube{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type torusSquare struct { + A E12 + C E12 `gnark:",public"` +} + +func (circuit *torusSquare) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt12(ba) + compressed := e.CompressTorus(&circuit.A) + compressed = e.SquareTorus(compressed) + expected := e.DecompressTorus(compressed) + e.AssertIsEqual(expected, &circuit.C) + return nil +} + +func TestTorusSquare(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c, tmp bn254.E12 + _, _ = a.SetRandom() + + // put a in the cyclotomic subgroup + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + + // uncompressed square + c.Square(&a) + + witness := torusSquare{ + A: FromE12(&a), + C: FromE12(&c), + } + + err := test.IsSolved(&torusSquare{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} diff --git a/std/algebra/emulated/fields_bn254/e6.go b/std/algebra/emulated/fields_bn254/e6.go index b5ab693cd1..44cd0cab8b 100644 --- a/std/algebra/emulated/fields_bn254/e6.go +++ b/std/algebra/emulated/fields_bn254/e6.go @@ -151,6 +151,29 @@ func (e Ext6) MulByE2(x *E6, y *E2) *E6 { } } +// MulBy0 multiplies z by an E6 sparse element of the form +// +// E6{ +// B0: c0, +// B1: 0, +// B2: 0, +// } +func (e Ext6) MulBy0(z *E6, c0 *E2) *E6 { + a := e.Ext2.Mul(&z.B0, c0) + tmp := e.Ext2.Add(&z.B1, &z.B2) + tmp = e.Ext2.Add(&z.B0, &z.B2) + t2 := e.Ext2.Mul(c0, tmp) + t2 = e.Ext2.Sub(t2, a) + tmp = e.Ext2.Add(&z.B0, &z.B1) + t1 := e.Ext2.Mul(c0, tmp) + t1 = e.Ext2.Sub(t1, a) + return &E6{ + B0: *a, + B1: *t1, + B2: *t2, + } +} + // MulBy01 multiplies z by an E6 sparse element of the form // // E6{ @@ -229,6 +252,12 @@ func (e Ext6) MulByNonResidue(x *E6) *E6 { } } +func (e Ext6) FrobeniusSquare(x *E6) *E6 { + z01 := e.Ext2.MulByNonResidue2Power2(&x.B1) + z02 := e.Ext2.MulByNonResidue2Power4(&x.B2) + return &E6{B0: x.B0, B1: *z01, B2: *z02} +} + func (e Ext6) AssertIsEqual(x, y *E6) { e.Ext2.AssertIsEqual(&x.B0, &y.B0) e.Ext2.AssertIsEqual(&x.B1, &y.B1) @@ -287,3 +316,24 @@ func (e Ext6) DivUnchecked(x, y *E6) *E6 { return &div } + +func (e Ext6) Halve(x *E6) *E6 { + res, err := e.fp.NewHint(halveE6Hint, 6, &x.B0.A0, &x.B0.A1, &x.B1.A0, &x.B1.A1, &x.B2.A0, &x.B2.A1) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + half := E6{ + B0: E2{A0: *res[0], A1: *res[1]}, + B1: E2{A0: *res[2], A1: *res[3]}, + B2: E2{A0: *res[4], A1: *res[5]}, + } + + // 2*half == x + _x := e.double(&half) + e.AssertIsEqual(x, _x) + + return &half + +} diff --git a/std/algebra/emulated/fields_bn254/e6_test.go b/std/algebra/emulated/fields_bn254/e6_test.go index a3fbfebd6f..12398222a4 100644 --- a/std/algebra/emulated/fields_bn254/e6_test.go +++ b/std/algebra/emulated/fields_bn254/e6_test.go @@ -278,6 +278,43 @@ func TestMulFp6By01(t *testing.T) { } +type e6MulBy0 struct { + A E6 + C0 E2 + C E6 `gnark:",public"` +} + +func (circuit *e6MulBy0) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt6(ba) + expected := e.MulBy0(&circuit.A, &circuit.C0) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestMulFp6By0(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E6 + var C0, zero bn254.E2 + _, _ = a.SetRandom() + _, _ = C0.SetRandom() + c.Set(&a) + c.MulBy01(&C0, &zero) + + witness := e6MulBy0{ + A: FromE6(&a), + C0: FromE2(&C0), + C: FromE6(&c), + } + + err := test.IsSolved(&e6MulBy0{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + type e6Neg struct { A E6 C E6 `gnark:",public"` @@ -340,3 +377,38 @@ func TestInverseFp6(t *testing.T) { err := test.IsSolved(&e6Inverse{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } + +type e6Halve struct { + A E6 + C E6 `gnark:",public"` +} + +func (circuit *e6Halve) Define(api frontend.API) error { + + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := NewExt6(ba) + expected := e.Halve(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestHalveFp6(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bn254.E6 + _, _ = a.SetRandom() + c.Set(&a) + c.B0.Halve() + c.B1.Halve() + c.B2.Halve() + + witness := e6Halve{ + A: FromE6(&a), + C: FromE6(&c), + } + + err := test.IsSolved(&e6Halve{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} diff --git a/std/algebra/emulated/fields_bn254/hints.go b/std/algebra/emulated/fields_bn254/hints.go index b69e5012fc..f6e9a9ffae 100644 --- a/std/algebra/emulated/fields_bn254/hints.go +++ b/std/algebra/emulated/fields_bn254/hints.go @@ -21,6 +21,7 @@ func GetHints() []solver.Hint { // E6 divE6Hint, inverseE6Hint, + halveE6Hint, // E12 divE12Hint, inverseE12Hint, @@ -121,6 +122,34 @@ func divE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error }) } +func halveE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, c bn254.E6 + + a.B0.A0.SetBigInt(inputs[0]) + a.B0.A1.SetBigInt(inputs[1]) + a.B1.A0.SetBigInt(inputs[2]) + a.B1.A1.SetBigInt(inputs[3]) + a.B2.A0.SetBigInt(inputs[4]) + a.B2.A1.SetBigInt(inputs[5]) + + c.Set(&a) + c.B0.Halve() + c.B1.Halve() + c.B2.Halve() + + c.B0.A0.BigInt(outputs[0]) + c.B0.A1.BigInt(outputs[1]) + c.B1.A0.BigInt(outputs[2]) + c.B1.A1.BigInt(outputs[3]) + c.B2.A0.BigInt(outputs[4]) + c.B2.A1.BigInt(outputs[5]) + + return nil + }) +} + // E12 hints func inverseE12Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { return emulated.UnwrapHint(nativeInputs, nativeOutputs, diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index ea41ad6cb1..8b591c5895 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -71,48 +71,61 @@ func NewPairing(api frontend.API) (*Pairing, error) { // 2x₀(6x₀²+3x₀+1) // // and r does NOT divide d' +// +// FinalExponentiation returns a decompressed element in E12 func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { - var t [5]*GTEl + res := pr.FinalExponentiationTorus(e) + return pr.DecompressTorus(res) +} + +// FinalExponentiationTorus returns compressed element in E6 +func (pr Pairing) FinalExponentiationTorus(e *GTEl) *fields_bn254.E6 { // Easy part // (p⁶-1)(p²+1) - t[0] = pr.Ext12.Conjugate(e) - t[0] = pr.Ext12.DivUnchecked(t[0], e) - result := pr.Ext12.FrobeniusSquare(t[0]) - result = pr.Ext12.Mul(result, t[0]) + // with Torus compression absorbed + c := pr.Ext6.DivUnchecked(&e.C0, &e.C1) + c = pr.Ext6.Neg(c) + t0 := pr.FrobeniusSquareTorus(c) + c = pr.MulTorus(t0, c) // Hard part (up to permutation) // 2x₀(6x₀²+3x₀+1)(p⁴-p²+1)/r // Duquesne and Ghammam // https://eprint.iacr.org/2015/192.pdf // Fuentes et al. (alg. 6) - t[0] = pr.Ext12.Expt(result) - t[0] = pr.Ext12.Conjugate(t[0]) - t[0] = pr.Ext12.CyclotomicSquare(t[0]) - t[1] = pr.Ext12.CyclotomicSquare(t[0]) - t[1] = pr.Ext12.Mul(t[0], t[1]) - t[2] = pr.Ext12.Expt(t[1]) - t[2] = pr.Ext12.Conjugate(t[2]) - t[3] = pr.Ext12.Conjugate(t[1]) - t[1] = pr.Ext12.Mul(t[2], t[3]) - t[3] = pr.Ext12.CyclotomicSquare(t[2]) - t[4] = pr.Ext12.Expt(t[3]) - t[4] = pr.Ext12.Mul(t[4], t[1]) - t[3] = pr.Ext12.Mul(t[4], t[0]) - t[0] = pr.Ext12.Mul(t[4], t[2]) - t[0] = pr.Ext12.Mul(result, t[0]) - t[2] = pr.Ext12.Frobenius(t[3]) - t[0] = pr.Ext12.Mul(t[2], t[0]) - t[2] = pr.Ext12.FrobeniusSquare(t[4]) - t[0] = pr.Ext12.Mul(t[2], t[0]) - t[2] = pr.Ext12.Conjugate(result) - t[2] = pr.Ext12.Mul(t[2], t[3]) - t[2] = pr.Ext12.FrobeniusCube(t[2]) - t[0] = pr.Ext12.Mul(t[2], t[0]) - - return t[0] + // performed in Torus compressed form + t0 = pr.ExptTorus(c) + t0 = pr.InverseTorus(t0) + t0 = pr.SquareTorus(t0) + t1 := pr.SquareTorus(t0) + t1 = pr.MulTorus(t0, t1) + t2 := pr.ExptTorus(t1) + t2 = pr.InverseTorus(t2) + t3 := pr.InverseTorus(t1) + t1 = pr.MulTorus(t2, t3) + t3 = pr.SquareTorus(t2) + t4 := pr.ExptTorus(t3) + t4 = pr.MulTorus(t1, t4) + t3 = pr.MulTorus(t0, t4) + t0 = pr.MulTorus(t2, t4) + t0 = pr.MulTorus(c, t0) + t2 = pr.FrobeniusTorus(t3) + t0 = pr.MulTorus(t2, t0) + t2 = pr.FrobeniusSquareTorus(t4) + t0 = pr.MulTorus(t2, t0) + t2 = pr.InverseTorus(c) + t2 = pr.MulTorus(t2, t3) + t2 = pr.FrobeniusCubeTorus(t2) + t0 = pr.MulTorus(t2, t0) + + return t0 } +// Pair calculates the reduced pairing for a set of points +// ∏ᵢ e(Pᵢ, Qᵢ). +// +// This function doesn't check that the inputs are in the correct subgroup. See IsInSubGroup. func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { res, err := pr.MillerLoop(P, Q) if err != nil { diff --git a/std/algebra/emulated/sw_bn254/pairing_test.go b/std/algebra/emulated/sw_bn254/pairing_test.go index 7009a2a21f..4cb7ed26fc 100644 --- a/std/algebra/emulated/sw_bn254/pairing_test.go +++ b/std/algebra/emulated/sw_bn254/pairing_test.go @@ -7,7 +7,10 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/profile" "github.com/consensys/gnark/test" ) @@ -123,3 +126,14 @@ func TestMultiPairTestSolve(t *testing.T) { err = test.IsSolved(&MultiPairCircuit{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } + +// bench +var ccsBench constraint.ConstraintSystem + +func BenchmarkPairing(b *testing.B) { + var c PairCircuit + p := profile.Start() + ccsBench, _ = frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &c) + p.Stop() + fmt.Println(p.NbConstraints()) +} From 1e4a59f57e95e9812c890d0e01163ec38ab4c481 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 22 Mar 2023 00:18:17 +0000 Subject: [PATCH 184/464] refactor: remove profiler in test --- std/algebra/emulated/fields_bn254/e12_pairing.go | 3 ++- std/algebra/emulated/sw_bn254/pairing.go | 5 ++++- std/algebra/emulated/sw_bn254/pairing_test.go | 14 -------------- 3 files changed, 6 insertions(+), 16 deletions(-) diff --git a/std/algebra/emulated/fields_bn254/e12_pairing.go b/std/algebra/emulated/fields_bn254/e12_pairing.go index 0f4b2456ba..1dbac65b63 100644 --- a/std/algebra/emulated/fields_bn254/e12_pairing.go +++ b/std/algebra/emulated/fields_bn254/e12_pairing.go @@ -201,7 +201,7 @@ func (e *Ext12) Mul01234By034(x *[5]E2, z3, z4 *E2) *E12 { // CompressTorus compresses x ∈ E12 to (x.C0 + 1)/x.C1 ∈ E6 func (e Ext12) CompressTorus(x *E12) *E6 { - // x in G_{q,2} \ {-1,1} + // x ∈ G_{q,2} \ {-1,1} y := e.Ext6.Add(&x.C0, e.Ext6.One()) y = e.Ext6.DivUnchecked(y, &x.C1) return y @@ -222,6 +222,7 @@ func (e Ext12) DecompressTorus(y *E6) *E12 { // MulTorus multiplies two compressed elements y1, y2 ∈ E6 // and returns (y1 * y2 + v)/(y1 + y2) +// N.B.: we use MulTorus in the final exponentiation throughout y1 ≠ -y2 always. func (e Ext12) MulTorus(y1, y2 *E6) *E6 { n := e.Ext6.Mul(y1, y2) n.B1 = *e.Ext2.Add(&n.B1, e.Ext2.One()) diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 8b591c5895..ec2a8e00af 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -83,7 +83,10 @@ func (pr Pairing) FinalExponentiationTorus(e *GTEl) *fields_bn254.E6 { // Easy part // (p⁶-1)(p²+1) - // with Torus compression absorbed + // with Torus compression absorbed. + // The Miller loop result is ≠ {-1,1}, otherwise this means P and Q + // are linearly dependant and not from G1 and G2 respectively. + // So e ∈ G_{q,2} \ {-1,1} and hence e.C1 ≠ 0 c := pr.Ext6.DivUnchecked(&e.C0, &e.C1) c = pr.Ext6.Neg(c) t0 := pr.FrobeniusSquareTorus(c) diff --git a/std/algebra/emulated/sw_bn254/pairing_test.go b/std/algebra/emulated/sw_bn254/pairing_test.go index 4cb7ed26fc..7009a2a21f 100644 --- a/std/algebra/emulated/sw_bn254/pairing_test.go +++ b/std/algebra/emulated/sw_bn254/pairing_test.go @@ -7,10 +7,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/profile" "github.com/consensys/gnark/test" ) @@ -126,14 +123,3 @@ func TestMultiPairTestSolve(t *testing.T) { err = test.IsSolved(&MultiPairCircuit{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } - -// bench -var ccsBench constraint.ConstraintSystem - -func BenchmarkPairing(b *testing.B) { - var c PairCircuit - p := profile.Start() - ccsBench, _ = frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &c) - p.Stop() - fmt.Println(p.NbConstraints()) -} From 18e89f1c291ecf42eeb3df9825a0d08238a30d84 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 22 Mar 2023 00:21:53 +0000 Subject: [PATCH 185/464] fix: remove an ineffectual assign in E6 --- std/algebra/emulated/fields_bn254/e6.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/std/algebra/emulated/fields_bn254/e6.go b/std/algebra/emulated/fields_bn254/e6.go index 44cd0cab8b..00e9dbf0f2 100644 --- a/std/algebra/emulated/fields_bn254/e6.go +++ b/std/algebra/emulated/fields_bn254/e6.go @@ -160,8 +160,7 @@ func (e Ext6) MulByE2(x *E6, y *E2) *E6 { // } func (e Ext6) MulBy0(z *E6, c0 *E2) *E6 { a := e.Ext2.Mul(&z.B0, c0) - tmp := e.Ext2.Add(&z.B1, &z.B2) - tmp = e.Ext2.Add(&z.B0, &z.B2) + tmp := e.Ext2.Add(&z.B0, &z.B2) t2 := e.Ext2.Mul(c0, tmp) t2 = e.Ext2.Sub(t2, a) tmp = e.Ext2.Add(&z.B0, &z.B1) From 912ec7137c395849991034755e9a5410eaa526db Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 22 Mar 2023 13:40:39 +0000 Subject: [PATCH 186/464] perf(bls12-381/pairing): use torus-based arithmetic for final exp --- std/algebra/emulated/fields_bls12381/e12.go | 243 ------------- .../emulated/fields_bls12381/e12_pairing.go | 152 ++++++-- .../emulated/fields_bls12381/e12_test.go | 339 +++++++++++------- std/algebra/emulated/fields_bls12381/e6.go | 43 +++ std/algebra/emulated/fields_bls12381/hints.go | 29 ++ std/algebra/emulated/sw_bls12381/pairing.go | 58 +-- 6 files changed, 450 insertions(+), 414 deletions(-) diff --git a/std/algebra/emulated/fields_bls12381/e12.go b/std/algebra/emulated/fields_bls12381/e12.go index 127daeb0e3..dcc6e7a150 100644 --- a/std/algebra/emulated/fields_bls12381/e12.go +++ b/std/algebra/emulated/fields_bls12381/e12.go @@ -58,249 +58,6 @@ func (e Ext12) Mul(x, y *E12) *E12 { } } -func (e Ext12) CyclotomicSquare(x *E12) *E12 { - t0 := e.Ext2.Square(&x.C1.B1) - t1 := e.Ext2.Square(&x.C0.B0) - t6 := e.Ext2.Add(&x.C1.B1, &x.C0.B0) - t6 = e.Ext2.Square(t6) - t6 = e.Ext2.Sub(t6, t0) - t6 = e.Ext2.Sub(t6, t1) - t2 := e.Ext2.Square(&x.C0.B2) - t3 := e.Ext2.Square(&x.C1.B0) - t7 := e.Ext2.Add(&x.C0.B2, &x.C1.B0) - t7 = e.Ext2.Square(t7) - t7 = e.Ext2.Sub(t7, t2) - t7 = e.Ext2.Sub(t7, t3) - t4 := e.Ext2.Square(&x.C1.B2) - t5 := e.Ext2.Square(&x.C0.B1) - t8 := e.Ext2.Add(&x.C1.B2, &x.C0.B1) - t8 = e.Ext2.Square(t8) - t8 = e.Ext2.Sub(t8, t4) - t8 = e.Ext2.Sub(t8, t5) - t8 = e.Ext2.MulByNonResidue(t8) - t0 = e.Ext2.MulByNonResidue(t0) - t0 = e.Ext2.Add(t0, t1) - t2 = e.Ext2.MulByNonResidue(t2) - t2 = e.Ext2.Add(t2, t3) - t4 = e.Ext2.MulByNonResidue(t4) - t4 = e.Ext2.Add(t4, t5) - z00 := e.Ext2.Sub(t0, &x.C0.B0) - z00 = e.Ext2.Double(z00) - z00 = e.Ext2.Add(z00, t0) - z01 := e.Ext2.Sub(t2, &x.C0.B1) - z01 = e.Ext2.Double(z01) - z01 = e.Ext2.Add(z01, t2) - z02 := e.Ext2.Sub(t4, &x.C0.B2) - z02 = e.Ext2.Double(z02) - z02 = e.Ext2.Add(z02, t4) - z10 := e.Ext2.Add(t8, &x.C1.B0) - z10 = e.Ext2.Double(z10) - z10 = e.Ext2.Add(z10, t8) - z11 := e.Ext2.Add(t6, &x.C1.B1) - z11 = e.Ext2.Double(z11) - z11 = e.Ext2.Add(z11, t6) - z12 := e.Ext2.Add(t7, &x.C1.B2) - z12 = e.Ext2.Double(z12) - z12 = e.Ext2.Add(z12, t7) - return &E12{ - C0: E6{ - B0: *z00, - B1: *z01, - B2: *z02, - }, - C1: E6{ - B0: *z10, - B1: *z11, - B2: *z12, - }, - } -} - -// Karabina's compressed cyclotomic square -// https://eprint.iacr.org/2010/542.pdf -// Th. 3.2 with minor modifications to fit our tower -func (e Ext12) CyclotomicSquareCompressed(x *E12) *E12 { - - // t0 = g1² - t0 := e.Ext2.Square(&x.C0.B1) - // t1 = g5² - t1 := e.Ext2.Square(&x.C1.B2) - // t5 = g1 + g5 - t5 := e.Ext2.Add(&x.C0.B1, &x.C1.B2) - // t2 = (g1 + g5)² - t2 := e.Ext2.Square(t5) - - // t3 = g1² + g5² - t3 := e.Ext2.Add(t0, t1) - // t5 = 2 * g1 * g5 - t5 = e.Ext2.Sub(t2, t3) - - // t6 = g3 + g2 - t6 := e.Ext2.Add(&x.C1.B0, &x.C0.B2) - // t3 = (g3 + g2)² - t3 = e.Ext2.Square(t6) - // t2 = g3² - t2 = e.Ext2.Square(&x.C1.B0) - - // t6 = 2 * nr * g1 * g5 - t6 = e.Ext2.MulByNonResidue(t5) - // t5 = 4 * nr * g1 * g5 + 2 * g3 - t5 = e.Ext2.Add(t6, &x.C1.B0) - t5 = e.Ext2.Double(t5) - // z3 = 6 * nr * g1 * g5 + 2 * g3 - C1B0 := e.Ext2.Add(t5, t6) - - // t4 = nr * g5² - t4 := e.Ext2.MulByNonResidue(t1) - // t5 = nr * g5² + g1² - t5 = e.Ext2.Add(t0, t4) - // t6 = nr * g5² + g1² - g2 - t6 = e.Ext2.Sub(t5, &x.C0.B2) - - // t1 = g2² - t1 = e.Ext2.Square(&x.C0.B2) - - // t6 = 2 * nr * g5² + 2 * g1² - 2*g2 - t6 = e.Ext2.Double(t6) - // z2 = 3 * nr * g5² + 3 * g1² - 2*g2 - C0B2 := e.Ext2.Add(t6, t5) - - // t4 = nr * g2² - t4 = e.Ext2.MulByNonResidue(t1) - // t5 = g3² + nr * g2² - t5 = e.Ext2.Add(t2, t4) - // t6 = g3² + nr * g2² - g1 - t6 = e.Ext2.Sub(t5, &x.C0.B1) - // t6 = 2 * g3² + 2 * nr * g2² - 2 * g1 - t6 = e.Ext2.Double(t6) - // z1 = 3 * g3² + 3 * nr * g2² - 2 * g1 - C0B1 := e.Ext2.Add(t6, t5) - - // t0 = g2² + g3² - t0 = e.Ext2.Add(t2, t1) - // t5 = 2 * g3 * g2 - t5 = e.Ext2.Sub(t3, t0) - // t6 = 2 * g3 * g2 + g5 - t6 = e.Ext2.Add(t5, &x.C1.B2) - // t6 = 4 * g3 * g2 + 2 * g5 - t6 = e.Ext2.Double(t6) - // z5 = 6 * g3 * g2 + 2 * g5 - C1B2 := e.Ext2.Add(t5, t6) - - zero := e.Ext2.Zero() - - return &E12{ - C0: E6{ - B0: *zero, - B1: *C0B1, - B2: *C0B2, - }, - C1: E6{ - B0: *C1B0, - B1: *zero, - B2: *C1B2, - }, - } -} - -func (e Ext12) NCycloSquareCompressed(z *E12, n int) *E12 { - for i := 0; i < n; i++ { - z = e.CyclotomicSquareCompressed(z) - } - return z -} - -// DecompressKarabina Karabina's cyclotomic square result -func (e Ext12) DecompressKarabina(x *E12) *E12 { - - one := e.Ext2.One() - - // TODO: hadle the g3==0 case with MUX - - // t0 = g1² - t0 := e.Ext2.Square(&x.C0.B1) - // t1 = 3 * g1² - 2 * g2 - t1 := e.Ext2.Sub(t0, &x.C0.B2) - t1 = e.Ext2.Double(t1) - t1 = e.Ext2.Add(t1, t0) - // t0 = E * g5² + t1 - t2 := e.Ext2.Square(&x.C1.B2) - t0 = e.Ext2.MulByNonResidue(t2) - t0 = e.Ext2.Add(t0, t1) - // t1 = 4 * g3 - t1 = e.Ext2.Double(&x.C1.B0) - t1 = e.Ext2.Double(t1) - - // z4 = g4 - C1B1 := e.Ext2.DivUnchecked(t0, t1) - - // t1 = g2 * g1 - t1 = e.Ext2.Mul(&x.C0.B2, &x.C0.B1) - // t2 = 2 * g4² - 3 * g2 * g1 - t2 = e.Ext2.Square(C1B1) - t2 = e.Ext2.Sub(t2, t1) - t2 = e.Ext2.Double(t2) - t2 = e.Ext2.Sub(t2, t1) - // t1 = g3 * g5 (g3 can be 0) - t1 = e.Ext2.Mul(&x.C1.B0, &x.C1.B2) - // c₀ = E * (2 * g4² + g3 * g5 - 3 * g2 * g1) + 1 - t2 = e.Ext2.Add(t2, t1) - C0B0 := e.Ext2.MulByNonResidue(t2) - C0B0 = e.Ext2.Add(C0B0, one) - - return &E12{ - C0: E6{ - B0: *C0B0, - B1: x.C0.B1, - B2: x.C0.B2, - }, - C1: E6{ - B0: x.C1.B0, - B1: *C1B1, - B2: x.C1.B2, - }, - } -} - -func (e Ext12) Frobenius(x *E12) *E12 { - t0 := e.Ext2.Conjugate(&x.C0.B0) - t1 := e.Ext2.Conjugate(&x.C0.B1) - t2 := e.Ext2.Conjugate(&x.C0.B2) - t3 := e.Ext2.Conjugate(&x.C1.B0) - t4 := e.Ext2.Conjugate(&x.C1.B1) - t5 := e.Ext2.Conjugate(&x.C1.B2) - t1 = e.Ext2.MulByNonResidue1Power2(t1) - t2 = e.Ext2.MulByNonResidue1Power4(t2) - t3 = e.Ext2.MulByNonResidue1Power1(t3) - t4 = e.Ext2.MulByNonResidue1Power3(t4) - t5 = e.Ext2.MulByNonResidue1Power5(t5) - return &E12{ - C0: E6{ - B0: *t0, - B1: *t1, - B2: *t2, - }, - C1: E6{ - B0: *t3, - B1: *t4, - B2: *t5, - }, - } -} - -func (e Ext12) FrobeniusSquare(x *E12) *E12 { - z00 := &x.C0.B0 - z01 := e.Ext2.MulByNonResidue2Power2(&x.C0.B1) - z02 := e.Ext2.MulByNonResidue2Power4(&x.C0.B2) - z10 := e.Ext2.MulByNonResidue2Power1(&x.C1.B0) - z11 := e.Ext2.MulByNonResidue2Power3(&x.C1.B1) - z12 := e.Ext2.MulByNonResidue2Power5(&x.C1.B2) - return &E12{ - C0: E6{B0: *z00, B1: *z01, B2: *z02}, - C1: E6{B0: *z10, B1: *z11, B2: *z12}, - } -} - func (e Ext12) One() *E12 { z000 := e.fp.One() zero := e.fp.Zero() diff --git a/std/algebra/emulated/fields_bls12381/e12_pairing.go b/std/algebra/emulated/fields_bls12381/e12_pairing.go index 223cfe2f64..b2d832e6a4 100644 --- a/std/algebra/emulated/fields_bls12381/e12_pairing.go +++ b/std/algebra/emulated/fields_bls12381/e12_pairing.go @@ -1,8 +1,17 @@ package fields_bls12381 -// ExptHalf set z to x^(t/2) in E12 and return z +import "github.com/consensys/gnark/std/math/emulated" + +func (e Ext12) nSquareTorus(z *E6, n int) *E6 { + for i := 0; i < n; i++ { + z = e.SquareTorus(z) + } + return z +} + +// ExptHalfTorus set z to x^(t/2) in E6 and return z // const t/2 uint64 = 7566188111470821376 // negative -func (e Ext12) ExptHalf(x *E12) *E12 { +func (e Ext12) ExptHalfTorus(x *E6) *E6 { // FixedExp computation is derived from the addition chain: // // _10 = 2*1 @@ -18,55 +27,48 @@ func (e Ext12) ExptHalf(x *E12) *E12 { // Generated by github.com/mmcloughlin/addchain v0.4.0. // Step 1: z = x^0x2 - z := e.Square(x) + z := e.SquareTorus(x) // Step 2: z = x^0x3 - z = e.Mul(x, z) + z = e.MulTorus(x, z) - z = e.CyclotomicSquare(z) - z = e.CyclotomicSquare(z) + z = e.SquareTorus(z) + z = e.SquareTorus(z) // Step 5: z = x^0xd - z = e.Mul(x, z) + z = e.MulTorus(x, z) // Step 8: z = x^0x68 - // TODO: for 3 squares in a row SQR12345 variant of Karabina's cyclotomic - // square (paragraph 5.6) is preferred. - // NCycloSquareCompressed() implements SQR2345 variant. - z = e.NCycloSquareCompressed(z, 3) - z = e.DecompressKarabina(z) + z = e.nSquareTorus(z, 3) // Step 9: z = x^0x69 - z = e.Mul(x, z) + z = e.MulTorus(x, z) // Step 18: z = x^0xd200 - z = e.NCycloSquareCompressed(z, 9) - z = e.DecompressKarabina(z) + z = e.nSquareTorus(z, 9) // Step 19: z = x^0xd201 - z = e.Mul(x, z) + z = e.MulTorus(x, z) // Step 51: z = x^0xd20100000000 - z = e.NCycloSquareCompressed(z, 32) - z = e.DecompressKarabina(z) + z = e.nSquareTorus(z, 32) // Step 52: z = x^0xd20100000001 - z = e.Mul(x, z) + z = e.MulTorus(x, z) // Step 67: z = x^0x6900800000008000 - z = e.NCycloSquareCompressed(z, 15) - z = e.DecompressKarabina(z) + z = e.nSquareTorus(z, 15) - z = e.Conjugate(z) // because tAbsVal is negative + z = e.InverseTorus(z) // because tAbsVal is negative return z } -// Expt set z to xᵗ in E12 and return z +// ExptTorus set z to xᵗ in E6 and return z // const t uint64 = 15132376222941642752 // negative -func (e Ext12) Expt(x *E12) *E12 { - z := e.ExptHalf(x) - z = e.CyclotomicSquare(z) +func (e Ext12) ExptTorus(x *E6) *E6 { + z := e.ExptHalfTorus(x) + z = e.SquareTorus(z) return z } @@ -165,3 +167,101 @@ func (e *Ext12) MulBy01245(z *E12, x *[5]E2) *E12 { C1: *z1, } } + +// Torus-based arithmetic: +// +// After the easy part of the final exponentiation the elements are in a proper +// subgroup of Fpk (E12) that coincides with some algebraic tori. The elements +// are in the torus Tk(Fp) and thus in each torus Tk/d(Fp^d) for d|k, d≠k. We +// take d=6. So the elements are in T2(Fp6). +// Let G_{q,2} = {m ∈ Fq^2 | m^(q+1) = 1} where q = p^6. +// When m.C1 = 0, then m.C0 must be 1 or −1. +// +// We recall the tower construction: +// +// 𝔽p²[u] = 𝔽p/u²+1 +// 𝔽p⁶[v] = 𝔽p²/v³-1-u +// 𝔽p¹²[w] = 𝔽p⁶/w²-v + +// CompressTorus compresses x ∈ E12 to (x.C0 + 1)/x.C1 ∈ E6 +func (e Ext12) CompressTorus(x *E12) *E6 { + // x ∈ G_{q,2} \ {-1,1} + y := e.Ext6.Add(&x.C0, e.Ext6.One()) + y = e.Ext6.DivUnchecked(y, &x.C1) + return y +} + +// DecompressTorus decompresses y ∈ E6 to (y+w)/(y-w) ∈ E12 +func (e Ext12) DecompressTorus(y *E6) *E12 { + var n, d E12 + one := e.Ext6.One() + n.C0 = *y + n.C1 = *one + d.C0 = *y + d.C1 = *e.Ext6.Neg(one) + + x := e.DivUnchecked(&n, &d) + return x +} + +// MulTorus multiplies two compressed elements y1, y2 ∈ E6 +// and returns (y1 * y2 + v)/(y1 + y2) +// N.B.: we use MulTorus in the final exponentiation throughout y1 ≠ -y2 always. +func (e Ext12) MulTorus(y1, y2 *E6) *E6 { + n := e.Ext6.Mul(y1, y2) + n.B1 = *e.Ext2.Add(&n.B1, e.Ext2.One()) + d := e.Ext6.Add(y1, y2) + y3 := e.Ext6.DivUnchecked(n, d) + return y3 +} + +// InverseTorus inverses a compressed elements y ∈ E6 +// and returns -y +func (e Ext12) InverseTorus(y *E6) *E6 { + return e.Ext6.Neg(y) +} + +// SquareTorus squares a compressed elements y ∈ E6 +// and returns (y + v/g)/2 +func (e Ext12) SquareTorus(y *E6) *E6 { + yInv := e.Ext6.Inverse(y) + // Mul by (0,1,0) + tmp := yInv.B0 + yInv.B0 = *e.Ext2.MulByNonResidue(&yInv.B2) + yInv.B2 = yInv.B1 + yInv.B1 = tmp + + res := e.Ext6.Add(y, yInv) + res = e.Ext6.Halve(res) + + return res +} + +// FrobeniusTorus raises a compressed elements y ∈ E6 to the modulus p +// and returns y^p / v^((p-1)/2) +func (e Ext12) FrobeniusTorus(y *E6) *E6 { + t0 := e.Ext2.Conjugate(&y.B0) + t1 := e.Ext2.Conjugate(&y.B1) + t2 := e.Ext2.Conjugate(&y.B2) + t1 = e.Ext2.MulByNonResidue1Power2(t1) + t2 = e.Ext2.MulByNonResidue1Power4(t2) + + v0 := E2{emulated.ValueOf[emulated.BLS12381Fp]("877076961050607968509681729531255177986764537961432449499635504522207616027455086505066378536590128544573588734230"), emulated.ValueOf[emulated.BLS12381Fp]("877076961050607968509681729531255177986764537961432449499635504522207616027455086505066378536590128544573588734230")} + res := &E6{B0: *t0, B1: *t1, B2: *t2} + res = e.Ext6.MulBy0(res, &v0) + + return res +} + +// FrobeniusSquareTorus raises a compressed elements y ∈ E6 to the square modulus p^2 +// and returns y^(p^2) / v^((p^2-1)/2) +func (e Ext12) FrobeniusSquareTorus(y *E6) *E6 { + v0 := emulated.ValueOf[emulated.BLS12381Fp]("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437") + t0 := e.Ext2.MulByElement(&y.B0, &v0) + t1 := e.Ext2.MulByNonResidue2Power2(&y.B1) + t1 = e.Ext2.MulByElement(t1, &v0) + t2 := e.Ext2.MulByNonResidue2Power4(&y.B2) + t2 = e.Ext2.MulByElement(t2, &v0) + + return &E6{B0: *t0, B1: *t1, B2: *t2} +} diff --git a/std/algebra/emulated/fields_bls12381/e12_test.go b/std/algebra/emulated/fields_bls12381/e12_test.go index 8384e342de..7410827c46 100644 --- a/std/algebra/emulated/fields_bls12381/e12_test.go +++ b/std/algebra/emulated/fields_bls12381/e12_test.go @@ -1,15 +1,11 @@ package fields_bls12381 import ( - "fmt" "testing" "github.com/consensys/gnark-crypto/ecc" bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" - "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/profile" "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/test" ) @@ -175,57 +171,84 @@ func TestSquareFp12(t *testing.T) { } -type e12CycloSquare struct { +type e12Conjugate struct { A E12 C E12 `gnark:",public"` } -func (circuit *e12CycloSquare) Define(api frontend.API) error { +func (circuit *e12Conjugate) Define(api frontend.API) error { ba, _ := emulated.NewField[emulated.BLS12381Fp](api) e := NewExt12(ba) - expected := e.CyclotomicSquare(&circuit.A) + expected := e.Conjugate(&circuit.A) e.AssertIsEqual(expected, &circuit.C) + return nil } -func TestFp12CyclotomicSquare(t *testing.T) { +func TestConjugateFp12(t *testing.T) { assert := test.NewAssert(t) // witness values var a, c bls12381.E12 _, _ = a.SetRandom() + c.Conjugate(&a) - // put a in the cyclotomic subgroup - var tmp bls12381.E12 - tmp.Conjugate(&a) - a.Inverse(&a) - tmp.Mul(&tmp, &a) - a.FrobeniusSquare(&tmp).Mul(&a, &tmp) - c.CyclotomicSquare(&a) - - witness := e12CycloSquare{ + witness := e12Conjugate{ A: FromE12(&a), C: FromE12(&c), } - err := test.IsSolved(&e12CycloSquare{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&e12Conjugate{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } -type e12CycloSquareKarabina struct { +type e12Inverse struct { A E12 C E12 `gnark:",public"` } -func (circuit *e12CycloSquareKarabina) Define(api frontend.API) error { +func (circuit *e12Inverse) Define(api frontend.API) error { + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt12(ba) + expected := e.Inverse(&circuit.A) + e.AssertIsEqual(expected, &circuit.C) + + return nil +} + +func TestInverseFp12(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, c bls12381.E12 + _, _ = a.SetRandom() + c.Inverse(&a) + + witness := e12Inverse{ + A: FromE12(&a), + C: FromE12(&c), + } + + err := test.IsSolved(&e12Inverse{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type e12ExptTorus struct { + A E6 + C E12 `gnark:",public"` +} + +func (circuit *e12ExptTorus) Define(api frontend.API) error { ba, _ := emulated.NewField[emulated.BLS12381Fp](api) e := NewExt12(ba) - expected := e.CyclotomicSquareCompressed(&circuit.A) + z := e.ExptTorus(&circuit.A) + expected := e.DecompressTorus(z) e.AssertIsEqual(expected, &circuit.C) + return nil } -func TestFp12CyclotomicSquareKarabina(t *testing.T) { +func TestFp12ExptTorus(t *testing.T) { assert := test.NewAssert(t) // witness values @@ -238,36 +261,77 @@ func TestFp12CyclotomicSquareKarabina(t *testing.T) { a.Inverse(&a) tmp.Mul(&tmp, &a) a.FrobeniusSquare(&tmp).Mul(&a, &tmp) - c.CyclotomicSquareCompressed(&a) - witness := e12CycloSquareKarabina{ - A: FromE12(&a), + c.Expt(&a) + _a, _ := a.CompressTorus() + witness := e12ExptTorus{ + A: FromE6(&_a), C: FromE12(&c), } - err := test.IsSolved(&e12CycloSquareKarabina{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&e12ExptTorus{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } -type e12CycloSquareKarabinaAndDecompress struct { +type e12MulBy014 struct { + A E12 `gnark:",public"` + W E12 + B, C E2 +} + +func (circuit *e12MulBy014) Define(api frontend.API) error { + + ba, _ := emulated.NewField[emulated.BLS12381Fp](api) + e := NewExt12(ba) + res := e.MulBy014(&circuit.A, &circuit.B, &circuit.C) + e.AssertIsEqual(res, &circuit.W) + return nil +} + +func TestFp12MulBy014(t *testing.T) { + + assert := test.NewAssert(t) + // witness values + var a, w bls12381.E12 + _, _ = a.SetRandom() + var one, b, c bls12381.E2 + one.SetOne() + _, _ = b.SetRandom() + _, _ = c.SetRandom() + w.Set(&a) + w.MulBy014(&b, &c, &one) + + witness := e12MulBy014{ + A: FromE12(&a), + B: FromE2(&b), + C: FromE2(&c), + W: FromE12(&w), + } + + err := test.IsSolved(&e12MulBy014{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +// Torus-based arithmetic +type torusCompress struct { A E12 - C E12 `gnark:",public"` + C E6 `gnark:",public"` } -func (circuit *e12CycloSquareKarabinaAndDecompress) Define(api frontend.API) error { +func (circuit *torusCompress) Define(api frontend.API) error { ba, _ := emulated.NewField[emulated.BLS12381Fp](api) e := NewExt12(ba) - expected := e.CyclotomicSquareCompressed(&circuit.A) - expected = e.DecompressKarabina(expected) - e.AssertIsEqual(expected, &circuit.C) + expected := e.CompressTorus(&circuit.A) + e.Ext6.AssertIsEqual(expected, &circuit.C) return nil } -func TestFp12CyclotomicSquareKarabinaAndDecompress(t *testing.T) { +func TestTorusCompress(t *testing.T) { assert := test.NewAssert(t) // witness values - var a, c bls12381.E12 + var a bls12381.E12 _, _ = a.SetRandom() // put a in the cyclotomic subgroup @@ -276,228 +340,263 @@ func TestFp12CyclotomicSquareKarabinaAndDecompress(t *testing.T) { a.Inverse(&a) tmp.Mul(&tmp, &a) a.FrobeniusSquare(&tmp).Mul(&a, &tmp) - c.CyclotomicSquareCompressed(&a) - c.DecompressKarabina(&c) - witness := e12CycloSquareKarabina{ + c, _ := a.CompressTorus() + + witness := torusCompress{ A: FromE12(&a), - C: FromE12(&c), + C: FromE6(&c), } - err := test.IsSolved(&e12CycloSquareKarabinaAndDecompress{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&torusCompress{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } -type e12Conjugate struct { +type torusDecompress struct { A E12 C E12 `gnark:",public"` } -func (circuit *e12Conjugate) Define(api frontend.API) error { +func (circuit *torusDecompress) Define(api frontend.API) error { ba, _ := emulated.NewField[emulated.BLS12381Fp](api) e := NewExt12(ba) - expected := e.Conjugate(&circuit.A) + compressed := e.CompressTorus(&circuit.A) + expected := e.DecompressTorus(compressed) e.AssertIsEqual(expected, &circuit.C) - return nil } -func TestConjugateFp12(t *testing.T) { +func TestTorusDecompress(t *testing.T) { assert := test.NewAssert(t) // witness values - var a, c bls12381.E12 + var a bls12381.E12 _, _ = a.SetRandom() - c.Conjugate(&a) - witness := e12Conjugate{ + // put a in the cyclotomic subgroup + var tmp bls12381.E12 + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + + d, _ := a.CompressTorus() + c := d.DecompressTorus() + + witness := torusDecompress{ A: FromE12(&a), C: FromE12(&c), } - err := test.IsSolved(&e12Conjugate{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&torusDecompress{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } -type e12Inverse struct { +type torusMul struct { A E12 + B E12 C E12 `gnark:",public"` } -func (circuit *e12Inverse) Define(api frontend.API) error { +func (circuit *torusMul) Define(api frontend.API) error { ba, _ := emulated.NewField[emulated.BLS12381Fp](api) e := NewExt12(ba) - expected := e.Inverse(&circuit.A) + compressedA := e.CompressTorus(&circuit.A) + compressedB := e.CompressTorus(&circuit.B) + compressedAB := e.MulTorus(compressedA, compressedB) + expected := e.DecompressTorus(compressedAB) e.AssertIsEqual(expected, &circuit.C) - return nil } -func TestInverseFp12(t *testing.T) { +func TestTorusMul(t *testing.T) { assert := test.NewAssert(t) // witness values - var a, c bls12381.E12 + var a, b, c, tmp bls12381.E12 _, _ = a.SetRandom() - c.Inverse(&a) + _, _ = b.SetRandom() - witness := e12Inverse{ + // put a in the cyclotomic subgroup + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + // put b in the cyclotomic subgroup + tmp.Conjugate(&b) + b.Inverse(&b) + tmp.Mul(&tmp, &b) + b.FrobeniusSquare(&tmp).Mul(&b, &tmp) + + // uncompressed mul + c.Mul(&a, &b) + + witness := torusMul{ A: FromE12(&a), + B: FromE12(&b), C: FromE12(&c), } - err := test.IsSolved(&e12Inverse{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&torusMul{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } -type e12Expt struct { +type torusInverse struct { A E12 C E12 `gnark:",public"` } -func (circuit *e12Expt) Define(api frontend.API) error { +func (circuit *torusInverse) Define(api frontend.API) error { ba, _ := emulated.NewField[emulated.BLS12381Fp](api) e := NewExt12(ba) - expected := e.Expt(&circuit.A) + compressed := e.CompressTorus(&circuit.A) + compressed = e.InverseTorus(compressed) + expected := e.DecompressTorus(compressed) e.AssertIsEqual(expected, &circuit.C) - return nil } -func TestFp12Expt(t *testing.T) { +func TestTorusInverse(t *testing.T) { assert := test.NewAssert(t) // witness values - var a, c bls12381.E12 + var a, c, tmp bls12381.E12 _, _ = a.SetRandom() // put a in the cyclotomic subgroup - var tmp bls12381.E12 tmp.Conjugate(&a) a.Inverse(&a) tmp.Mul(&tmp, &a) a.FrobeniusSquare(&tmp).Mul(&a, &tmp) - c.Expt(&a) + // uncompressed inverse + c.Inverse(&a) - witness := e12Expt{ + witness := torusInverse{ A: FromE12(&a), C: FromE12(&c), } - err := test.IsSolved(&e12Expt{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&torusInverse{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } -type e12Frobenius struct { - A, C E12 +type torusFrobenius struct { + A E12 + C E12 `gnark:",public"` } -func (circuit *e12Frobenius) Define(api frontend.API) error { +func (circuit *torusFrobenius) Define(api frontend.API) error { ba, _ := emulated.NewField[emulated.BLS12381Fp](api) e := NewExt12(ba) - - expected := e.Frobenius(&circuit.A) + compressed := e.CompressTorus(&circuit.A) + compressed = e.FrobeniusTorus(compressed) + expected := e.DecompressTorus(compressed) e.AssertIsEqual(expected, &circuit.C) return nil } -func TestFrobeniusFp12(t *testing.T) { +func TestTorusFrobenius(t *testing.T) { assert := test.NewAssert(t) // witness values - var a, c bls12381.E12 + var a, c, tmp bls12381.E12 _, _ = a.SetRandom() + + // put a in the cyclotomic subgroup + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + + // uncompressed frobenius c.Frobenius(&a) - witness := e12Frobenius{ + witness := torusFrobenius{ A: FromE12(&a), C: FromE12(&c), } - err := test.IsSolved(&e12Frobenius{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&torusFrobenius{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) - } -type e12FrobeniusSquare struct { - A, C E12 +type torusFrobeniusSquare struct { + A E12 + C E12 `gnark:",public"` } -func (circuit *e12FrobeniusSquare) Define(api frontend.API) error { +func (circuit *torusFrobeniusSquare) Define(api frontend.API) error { ba, _ := emulated.NewField[emulated.BLS12381Fp](api) e := NewExt12(ba) - - expected := e.FrobeniusSquare(&circuit.A) + compressed := e.CompressTorus(&circuit.A) + compressed = e.FrobeniusSquareTorus(compressed) + expected := e.DecompressTorus(compressed) e.AssertIsEqual(expected, &circuit.C) return nil } -func TestFrobeniusSquareFp12(t *testing.T) { +func TestTorusFrobeniusSquare(t *testing.T) { assert := test.NewAssert(t) // witness values - var a, c bls12381.E12 + var a, c, tmp bls12381.E12 _, _ = a.SetRandom() + + // put a in the cyclotomic subgroup + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + + // uncompressed frobeniusSquare c.FrobeniusSquare(&a) - witness := e12FrobeniusSquare{ + witness := torusFrobeniusSquare{ A: FromE12(&a), C: FromE12(&c), } - err := test.IsSolved(&e12FrobeniusSquare{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&torusFrobeniusSquare{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) - } -type e12MulBy014 struct { - A E12 `gnark:",public"` - W E12 - B, C E2 +type torusSquare struct { + A E12 + C E12 `gnark:",public"` } -func (circuit *e12MulBy014) Define(api frontend.API) error { - +func (circuit *torusSquare) Define(api frontend.API) error { ba, _ := emulated.NewField[emulated.BLS12381Fp](api) e := NewExt12(ba) - res := e.MulBy014(&circuit.A, &circuit.B, &circuit.C) - e.AssertIsEqual(res, &circuit.W) + compressed := e.CompressTorus(&circuit.A) + compressed = e.SquareTorus(compressed) + expected := e.DecompressTorus(compressed) + e.AssertIsEqual(expected, &circuit.C) return nil } -func TestFp12MulBy014(t *testing.T) { +func TestTorusSquare(t *testing.T) { assert := test.NewAssert(t) // witness values - var a, w bls12381.E12 + var a, c, tmp bls12381.E12 _, _ = a.SetRandom() - var one, b, c bls12381.E2 - one.SetOne() - _, _ = b.SetRandom() - _, _ = c.SetRandom() - w.Set(&a) - w.MulBy014(&b, &c, &one) - witness := e12MulBy014{ + // put a in the cyclotomic subgroup + tmp.Conjugate(&a) + a.Inverse(&a) + tmp.Mul(&tmp, &a) + a.FrobeniusSquare(&tmp).Mul(&a, &tmp) + + // uncompressed square + c.Square(&a) + + witness := torusSquare{ A: FromE12(&a), - B: FromE2(&b), - C: FromE2(&c), - W: FromE12(&w), + C: FromE12(&c), } - err := test.IsSolved(&e12MulBy014{}, &witness, ecc.BN254.ScalarField()) + err := test.IsSolved(&torusSquare{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) - -} - -// bench -var ccsBench constraint.ConstraintSystem - -func BenchmarkExpt(b *testing.B) { - var c e12Expt - p := profile.Start() - ccsBench, _ = frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &c) - p.Stop() - fmt.Println(p.NbConstraints()) } diff --git a/std/algebra/emulated/fields_bls12381/e6.go b/std/algebra/emulated/fields_bls12381/e6.go index e42f307589..df95aa698c 100644 --- a/std/algebra/emulated/fields_bls12381/e6.go +++ b/std/algebra/emulated/fields_bls12381/e6.go @@ -177,6 +177,28 @@ func (e Ext6) MulBy12(x *E6, b1, b2 *E2) *E6 { } } +// MulBy0 multiplies z by an E6 sparse element of the form +// +// E6{ +// B0: c0, +// B1: 0, +// B2: 0, +// } +func (e Ext6) MulBy0(z *E6, c0 *E2) *E6 { + a := e.Ext2.Mul(&z.B0, c0) + tmp := e.Ext2.Add(&z.B0, &z.B2) + t2 := e.Ext2.Mul(c0, tmp) + t2 = e.Ext2.Sub(t2, a) + tmp = e.Ext2.Add(&z.B0, &z.B1) + t1 := e.Ext2.Mul(c0, tmp) + t1 = e.Ext2.Sub(t1, a) + return &E6{ + B0: *a, + B1: *t1, + B2: *t2, + } +} + // MulBy01 multiplication by sparse element (c0,c1,0) func (e Ext6) MulBy01(z *E6, c0, c1 *E2) *E6 { a := e.Ext2.Mul(&z.B0, c0) @@ -270,3 +292,24 @@ func (e Ext6) DivUnchecked(x, y *E6) *E6 { return &div } + +func (e Ext6) Halve(x *E6) *E6 { + res, err := e.fp.NewHint(halveE6Hint, 6, &x.B0.A0, &x.B0.A1, &x.B1.A0, &x.B1.A1, &x.B2.A0, &x.B2.A1) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + half := E6{ + B0: E2{A0: *res[0], A1: *res[1]}, + B1: E2{A0: *res[2], A1: *res[3]}, + B2: E2{A0: *res[4], A1: *res[5]}, + } + + // 2*half == x + _x := e.double(&half) + e.AssertIsEqual(x, _x) + + return &half + +} diff --git a/std/algebra/emulated/fields_bls12381/hints.go b/std/algebra/emulated/fields_bls12381/hints.go index 320c7ffaa9..4fbe179677 100644 --- a/std/algebra/emulated/fields_bls12381/hints.go +++ b/std/algebra/emulated/fields_bls12381/hints.go @@ -21,6 +21,7 @@ func GetHints() []solver.Hint { // E6 divE6Hint, inverseE6Hint, + halveE6Hint, // E12 divE12Hint, inverseE12Hint, @@ -121,6 +122,34 @@ func divE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error }) } +func halveE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, c bls12381.E6 + + a.B0.A0.SetBigInt(inputs[0]) + a.B0.A1.SetBigInt(inputs[1]) + a.B1.A0.SetBigInt(inputs[2]) + a.B1.A1.SetBigInt(inputs[3]) + a.B2.A0.SetBigInt(inputs[4]) + a.B2.A1.SetBigInt(inputs[5]) + + c.Set(&a) + c.B0.Halve() + c.B1.Halve() + c.B2.Halve() + + c.B0.A0.BigInt(outputs[0]) + c.B0.A1.BigInt(outputs[1]) + c.B1.A0.BigInt(outputs[2]) + c.B1.A1.BigInt(outputs[3]) + c.B2.A0.BigInt(outputs[4]) + c.B2.A1.BigInt(outputs[5]) + + return nil + }) +} + // E12 hints func inverseE12Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { return emulated.UnwrapHint(nativeInputs, nativeOutputs, diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go index f8f738b12e..e265ea78e0 100644 --- a/std/algebra/emulated/sw_bls12381/pairing.go +++ b/std/algebra/emulated/sw_bls12381/pairing.go @@ -67,38 +67,46 @@ func NewPairing(api frontend.API) (*Pairing, error) { // we use instead d=s ⋅ (p⁶-1)(p²+1)(p⁴ - p² +1)/r // where s is the cofactor 3 (Hayashida et al.) func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { - var t [4]*GTEl + res := pr.FinalExponentiationTorus(e) + return pr.DecompressTorus(res) +} + +func (pr Pairing) FinalExponentiationTorus(e *GTEl) *fields_bls12381.E6 { // Easy part // (p⁶-1)(p²+1) - t[0] = pr.Ext12.Conjugate(e) - t[0] = pr.Ext12.DivUnchecked(t[0], e) - result := pr.Ext12.FrobeniusSquare(t[0]) - result = pr.Ext12.Mul(result, t[0]) + // with Torus compression absorbed. + // The Miller loop result is ≠ {-1,1}, otherwise this means P and Q + // are linearly dependant and not from G1 and G2 respectively. + // So e ∈ G_{q,2} \ {-1,1} and hence e.C1 ≠ 0 + c := pr.Ext6.DivUnchecked(&e.C0, &e.C1) + c = pr.Ext6.Neg(c) + t0 := pr.FrobeniusSquareTorus(c) + c = pr.MulTorus(t0, c) // Hard part (up to permutation) // Daiki Hayashida, Kenichiro Hayasaka and Tadanori Teruya // https://eprint.iacr.org/2020/875.pdf - t[0] = pr.CyclotomicSquare(result) - t[1] = pr.ExptHalf(t[0]) - t[2] = pr.Conjugate(result) - t[1] = pr.Mul(t[1], t[2]) - t[2] = pr.Expt(t[1]) - t[1] = pr.Conjugate(t[1]) - t[1] = pr.Mul(t[1], t[2]) - t[2] = pr.Expt(t[1]) - t[1] = pr.Frobenius(t[1]) - t[1] = pr.Mul(t[1], t[2]) - result = pr.Mul(result, t[0]) - t[0] = pr.Expt(t[1]) - t[2] = pr.Expt(t[0]) - t[0] = pr.FrobeniusSquare(t[1]) - t[1] = pr.Conjugate(t[1]) - t[1] = pr.Mul(t[1], t[2]) - t[1] = pr.Mul(t[1], t[0]) - result = pr.Mul(result, t[1]) - - return result + t0 = pr.SquareTorus(c) + t1 := pr.ExptHalfTorus(t0) + t2 := pr.InverseTorus(c) + t1 = pr.MulTorus(t1, t2) + t2 = pr.ExptTorus(t1) + t1 = pr.InverseTorus(t1) + t1 = pr.MulTorus(t1, t2) + t2 = pr.ExptTorus(t1) + t1 = pr.FrobeniusTorus(t1) + t1 = pr.MulTorus(t1, t2) + c = pr.MulTorus(c, t0) + t0 = pr.ExptTorus(t1) + t2 = pr.ExptTorus(t0) + t0 = pr.FrobeniusSquareTorus(t1) + t1 = pr.InverseTorus(t1) + t1 = pr.MulTorus(t1, t2) + t1 = pr.MulTorus(t1, t0) + c = pr.MulTorus(c, t1) + + return c } // lineEvaluation represents a sparse Fp12 Elmt (result of the line evaluation) From 2f972afa4cb552a5e0b3017fc4c6e38963011d9f Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 22 Mar 2023 13:48:47 +0000 Subject: [PATCH 187/464] refactor: remove dead code (Frobenius and GS cyclosq) --- std/algebra/emulated/fields_bn254/e12.go | 123 ---------------- .../emulated/fields_bn254/e12_pairing.go | 18 +-- std/algebra/emulated/fields_bn254/e12_test.go | 132 +----------------- 3 files changed, 10 insertions(+), 263 deletions(-) diff --git a/std/algebra/emulated/fields_bn254/e12.go b/std/algebra/emulated/fields_bn254/e12.go index cf73a547ed..14763df9a4 100644 --- a/std/algebra/emulated/fields_bn254/e12.go +++ b/std/algebra/emulated/fields_bn254/e12.go @@ -58,129 +58,6 @@ func (e Ext12) Mul(x, y *E12) *E12 { } } -func (e Ext12) CyclotomicSquare(x *E12) *E12 { - t0 := e.Ext2.Square(&x.C1.B1) - t1 := e.Ext2.Square(&x.C0.B0) - t6 := e.Ext2.Add(&x.C1.B1, &x.C0.B0) - t6 = e.Ext2.Square(t6) - t6 = e.Ext2.Sub(t6, t0) - t6 = e.Ext2.Sub(t6, t1) - t2 := e.Ext2.Square(&x.C0.B2) - t3 := e.Ext2.Square(&x.C1.B0) - t7 := e.Ext2.Add(&x.C0.B2, &x.C1.B0) - t7 = e.Ext2.Square(t7) - t7 = e.Ext2.Sub(t7, t2) - t7 = e.Ext2.Sub(t7, t3) - t4 := e.Ext2.Square(&x.C1.B2) - t5 := e.Ext2.Square(&x.C0.B1) - t8 := e.Ext2.Add(&x.C1.B2, &x.C0.B1) - t8 = e.Ext2.Square(t8) - t8 = e.Ext2.Sub(t8, t4) - t8 = e.Ext2.Sub(t8, t5) - t8 = e.Ext2.MulByNonResidue(t8) - t0 = e.Ext2.MulByNonResidue(t0) - t0 = e.Ext2.Add(t0, t1) - t2 = e.Ext2.MulByNonResidue(t2) - t2 = e.Ext2.Add(t2, t3) - t4 = e.Ext2.MulByNonResidue(t4) - t4 = e.Ext2.Add(t4, t5) - z00 := e.Ext2.Sub(t0, &x.C0.B0) - z00 = e.Ext2.Double(z00) - z00 = e.Ext2.Add(z00, t0) - z01 := e.Ext2.Sub(t2, &x.C0.B1) - z01 = e.Ext2.Double(z01) - z01 = e.Ext2.Add(z01, t2) - z02 := e.Ext2.Sub(t4, &x.C0.B2) - z02 = e.Ext2.Double(z02) - z02 = e.Ext2.Add(z02, t4) - z10 := e.Ext2.Add(t8, &x.C1.B0) - z10 = e.Ext2.Double(z10) - z10 = e.Ext2.Add(z10, t8) - z11 := e.Ext2.Add(t6, &x.C1.B1) - z11 = e.Ext2.Double(z11) - z11 = e.Ext2.Add(z11, t6) - z12 := e.Ext2.Add(t7, &x.C1.B2) - z12 = e.Ext2.Double(z12) - z12 = e.Ext2.Add(z12, t7) - return &E12{ - C0: E6{ - B0: *z00, - B1: *z01, - B2: *z02, - }, - C1: E6{ - B0: *z10, - B1: *z11, - B2: *z12, - }, - } -} - -func (e Ext12) Frobenius(x *E12) *E12 { - t0 := e.Ext2.Conjugate(&x.C0.B0) - t1 := e.Ext2.Conjugate(&x.C0.B1) - t2 := e.Ext2.Conjugate(&x.C0.B2) - t3 := e.Ext2.Conjugate(&x.C1.B0) - t4 := e.Ext2.Conjugate(&x.C1.B1) - t5 := e.Ext2.Conjugate(&x.C1.B2) - t1 = e.Ext2.MulByNonResidue1Power2(t1) - t2 = e.Ext2.MulByNonResidue1Power4(t2) - t3 = e.Ext2.MulByNonResidue1Power1(t3) - t4 = e.Ext2.MulByNonResidue1Power3(t4) - t5 = e.Ext2.MulByNonResidue1Power5(t5) - return &E12{ - C0: E6{ - B0: *t0, - B1: *t1, - B2: *t2, - }, - C1: E6{ - B0: *t3, - B1: *t4, - B2: *t5, - }, - } -} - -func (e Ext12) FrobeniusSquare(x *E12) *E12 { - z00 := &x.C0.B0 - z01 := e.Ext2.MulByNonResidue2Power2(&x.C0.B1) - z02 := e.Ext2.MulByNonResidue2Power4(&x.C0.B2) - z10 := e.Ext2.MulByNonResidue2Power1(&x.C1.B0) - z11 := e.Ext2.MulByNonResidue2Power3(&x.C1.B1) - z12 := e.Ext2.MulByNonResidue2Power5(&x.C1.B2) - return &E12{ - C0: E6{B0: *z00, B1: *z01, B2: *z02}, - C1: E6{B0: *z10, B1: *z11, B2: *z12}, - } -} - -func (e Ext12) FrobeniusCube(x *E12) *E12 { - t0 := e.Ext2.Conjugate(&x.C0.B0) - t1 := e.Ext2.Conjugate(&x.C0.B1) - t2 := e.Ext2.Conjugate(&x.C0.B2) - t3 := e.Ext2.Conjugate(&x.C1.B0) - t4 := e.Ext2.Conjugate(&x.C1.B1) - t5 := e.Ext2.Conjugate(&x.C1.B2) - t1 = e.Ext2.MulByNonResidue3Power2(t1) - t2 = e.Ext2.MulByNonResidue3Power4(t2) - t3 = e.Ext2.MulByNonResidue3Power1(t3) - t4 = e.Ext2.MulByNonResidue3Power3(t4) - t5 = e.Ext2.MulByNonResidue3Power5(t5) - return &E12{ - C0: E6{ - B0: *t0, - B1: *t1, - B2: *t2, - }, - C1: E6{ - B0: *t3, - B1: *t4, - B2: *t5, - }, - } -} - func (e Ext12) Zero() *E12 { zero := e.fp.Zero() return &E12{ diff --git a/std/algebra/emulated/fields_bn254/e12_pairing.go b/std/algebra/emulated/fields_bn254/e12_pairing.go index 1dbac65b63..1584966fae 100644 --- a/std/algebra/emulated/fields_bn254/e12_pairing.go +++ b/std/algebra/emulated/fields_bn254/e12_pairing.go @@ -4,7 +4,7 @@ import ( "github.com/consensys/gnark/std/math/emulated" ) -func (e Ext12) nCycloSquareTorus(z *E6, n int) *E6 { +func (e Ext12) nSquareTorus(z *E6, n int) *E6 { for i := 0; i < n; i++ { z = e.SquareTorus(z) } @@ -47,23 +47,23 @@ func (e Ext12) ExptTorus(x *E6) *E6 { t6 := e.SquareTorus(t2) t1 = e.MulTorus(t0, t1) t0 = e.MulTorus(t3, t1) - t6 = e.nCycloSquareTorus(t6, 6) + t6 = e.nSquareTorus(t6, 6) t5 = e.MulTorus(t5, t6) t5 = e.MulTorus(t4, t5) - t5 = e.nCycloSquareTorus(t5, 7) + t5 = e.nSquareTorus(t5, 7) t4 = e.MulTorus(t4, t5) - t4 = e.nCycloSquareTorus(t4, 8) + t4 = e.nSquareTorus(t4, 8) t4 = e.MulTorus(t0, t4) t3 = e.MulTorus(t3, t4) - t3 = e.nCycloSquareTorus(t3, 6) + t3 = e.nSquareTorus(t3, 6) t2 = e.MulTorus(t2, t3) - t2 = e.nCycloSquareTorus(t2, 8) + t2 = e.nSquareTorus(t2, 8) t2 = e.MulTorus(t0, t2) - t2 = e.nCycloSquareTorus(t2, 6) + t2 = e.nSquareTorus(t2, 6) t2 = e.MulTorus(t0, t2) - t2 = e.nCycloSquareTorus(t2, 10) + t2 = e.nSquareTorus(t2, 10) t1 = e.MulTorus(t1, t2) - t1 = e.nCycloSquareTorus(t1, 6) + t1 = e.nSquareTorus(t1, 6) t0 = e.MulTorus(t0, t1) z := e.MulTorus(result, t0) return z diff --git a/std/algebra/emulated/fields_bn254/e12_test.go b/std/algebra/emulated/fields_bn254/e12_test.go index 6c864d492f..7c7e8185a4 100644 --- a/std/algebra/emulated/fields_bn254/e12_test.go +++ b/std/algebra/emulated/fields_bn254/e12_test.go @@ -171,43 +171,6 @@ func TestSquareFp12(t *testing.T) { } -type e12CycloSquare struct { - A E12 - C E12 `gnark:",public"` -} - -func (circuit *e12CycloSquare) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt12(ba) - expected := e.CyclotomicSquare(&circuit.A) - e.AssertIsEqual(expected, &circuit.C) - return nil -} - -func TestFp12CyclotomicSquare(t *testing.T) { - - assert := test.NewAssert(t) - // witness values - var a, c bn254.E12 - _, _ = a.SetRandom() - - // put a in the cyclotomic subgroup - var tmp bn254.E12 - tmp.Conjugate(&a) - a.Inverse(&a) - tmp.Mul(&tmp, &a) - a.FrobeniusSquare(&tmp).Mul(&a, &tmp) - c.CyclotomicSquare(&a) - - witness := e12CycloSquare{ - A: FromE12(&a), - C: FromE12(&c), - } - - err := test.IsSolved(&e12CycloSquare{}, &witness, ecc.BN254.ScalarField()) - assert.NoError(err) -} - type e12Conjugate struct { A E12 C E12 `gnark:",public"` @@ -285,7 +248,7 @@ func (circuit *e12ExptTorus) Define(api frontend.API) error { return nil } -func TestFp12Expt(t *testing.T) { +func TestFp12ExptTorus(t *testing.T) { assert := test.NewAssert(t) // witness values @@ -310,99 +273,6 @@ func TestFp12Expt(t *testing.T) { assert.NoError(err) } -type e12Frobenius struct { - A, C E12 -} - -func (circuit *e12Frobenius) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt12(ba) - - expected := e.Frobenius(&circuit.A) - e.AssertIsEqual(expected, &circuit.C) - return nil -} - -func TestFrobeniusFp12(t *testing.T) { - - assert := test.NewAssert(t) - // witness values - var a, c bn254.E12 - _, _ = a.SetRandom() - c.Frobenius(&a) - - witness := e12Frobenius{ - A: FromE12(&a), - C: FromE12(&c), - } - - err := test.IsSolved(&e12Frobenius{}, &witness, ecc.BN254.ScalarField()) - assert.NoError(err) - -} - -type e12FrobeniusSquare struct { - A, C E12 -} - -func (circuit *e12FrobeniusSquare) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt12(ba) - - expected := e.FrobeniusSquare(&circuit.A) - e.AssertIsEqual(expected, &circuit.C) - return nil -} - -func TestFrobeniusSquareFp12(t *testing.T) { - - assert := test.NewAssert(t) - // witness values - var a, c bn254.E12 - _, _ = a.SetRandom() - c.FrobeniusSquare(&a) - - witness := e12FrobeniusSquare{ - A: FromE12(&a), - C: FromE12(&c), - } - - err := test.IsSolved(&e12FrobeniusSquare{}, &witness, ecc.BN254.ScalarField()) - assert.NoError(err) - -} - -type e12FrobeniusCube struct { - A, C E12 -} - -func (circuit *e12FrobeniusCube) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt12(ba) - - expected := e.FrobeniusCube(&circuit.A) - e.AssertIsEqual(expected, &circuit.C) - return nil -} - -func TestFrobeniusCubeFp12(t *testing.T) { - - assert := test.NewAssert(t) - // witness values - var a, c bn254.E12 - _, _ = a.SetRandom() - c.FrobeniusCube(&a) - - witness := e12FrobeniusCube{ - A: FromE12(&a), - C: FromE12(&c), - } - - err := test.IsSolved(&e12FrobeniusCube{}, &witness, ecc.BN254.ScalarField()) - assert.NoError(err) - -} - type e12MulBy034 struct { A E12 `gnark:",public"` W E12 From 4af54dab38a6e88957ee14cd61bb63290681adcc Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 22 Mar 2023 14:15:56 +0000 Subject: [PATCH 188/464] test: product of pairings on bls12-381 --- .../emulated/sw_bls12381/pairing_test.go | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/std/algebra/emulated/sw_bls12381/pairing_test.go b/std/algebra/emulated/sw_bls12381/pairing_test.go index 06827f88e4..0be5ff02a6 100644 --- a/std/algebra/emulated/sw_bls12381/pairing_test.go +++ b/std/algebra/emulated/sw_bls12381/pairing_test.go @@ -85,3 +85,41 @@ func TestPairTestSolve(t *testing.T) { err = test.IsSolved(&PairCircuit{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } + +type MultiPairCircuit struct { + In1G1 G1Affine + In2G1 G1Affine + In1G2 G2Affine + In2G2 G2Affine + Res GTEl +} + +func (c *MultiPairCircuit) Define(api frontend.API) error { + pairing, err := NewPairing(api) + if err != nil { + return fmt.Errorf("new pairing: %w", err) + } + res, err := pairing.Pair([]*G1Affine{&c.In1G1, &c.In1G1, &c.In2G1, &c.In2G1}, []*G2Affine{&c.In1G2, &c.In2G2, &c.In1G2, &c.In2G2}) + if err != nil { + return fmt.Errorf("pair: %w", err) + } + pairing.AssertIsEqual(res, &c.Res) + return nil +} + +func TestMultiPairTestSolve(t *testing.T) { + assert := test.NewAssert(t) + p1, q1 := randomG1G2Affines(assert) + p2, q2 := randomG1G2Affines(assert) + res, err := bls12381.Pair([]bls12381.G1Affine{p1, p1, p2, p2}, []bls12381.G2Affine{q1, q2, q1, q2}) + assert.NoError(err) + witness := MultiPairCircuit{ + In1G1: NewG1Affine(p1), + In1G2: NewG2Affine(q1), + In2G1: NewG1Affine(p2), + In2G2: NewG2Affine(q2), + Res: NewGTEl(res), + } + err = test.IsSolved(&MultiPairCircuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} From e51b4f618f9be098a030b9a7f6e3e614a780ebca Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 22 Mar 2023 18:32:26 +0000 Subject: [PATCH 189/464] perf(bn254/pairing): use hint for SquareTorus --- .../emulated/fields_bn254/e12_pairing.go | 33 +++++++++++------ std/algebra/emulated/fields_bn254/e6.go | 21 ----------- std/algebra/emulated/fields_bn254/e6_test.go | 35 ------------------- std/algebra/emulated/fields_bn254/hints.go | 11 +++--- 4 files changed, 28 insertions(+), 72 deletions(-) diff --git a/std/algebra/emulated/fields_bn254/e12_pairing.go b/std/algebra/emulated/fields_bn254/e12_pairing.go index 1584966fae..fa33cf90ab 100644 --- a/std/algebra/emulated/fields_bn254/e12_pairing.go +++ b/std/algebra/emulated/fields_bn254/e12_pairing.go @@ -238,19 +238,32 @@ func (e Ext12) InverseTorus(y *E6) *E6 { } // SquareTorus squares a compressed elements y ∈ E6 -// and returns (y + v/g)/2 +// and returns (y + v/y)/2 +// +// It uses a hint to verify that (2x-y)y = v saving one E6 AssertIsEqual. func (e Ext12) SquareTorus(y *E6) *E6 { - yInv := e.Ext6.Inverse(y) - // Mul by (0,1,0) - tmp := yInv.B0 - yInv.B0 = *e.Ext2.MulByNonResidue(&yInv.B2) - yInv.B2 = yInv.B1 - yInv.B1 = tmp + res, err := e.fp.NewHint(squareTorusHint, 6, &y.B0.A0, &y.B0.A1, &y.B1.A0, &y.B1.A1, &y.B2.A0, &y.B2.A1) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } - res := e.Ext6.Add(y, yInv) - res = e.Ext6.Halve(res) + sq := E6{ + B0: E2{A0: *res[0], A1: *res[1]}, + B1: E2{A0: *res[2], A1: *res[3]}, + B2: E2{A0: *res[4], A1: *res[5]}, + } + + // v = (2x-y)y + v := e.Ext6.double(&sq) + v = e.Ext6.Sub(v, y) + v = e.Ext6.Mul(v, y) + + _v := E6{B0: *e.Ext2.Zero(), B1: *e.Ext2.One(), B2: *e.Ext2.Zero()} + e.Ext6.AssertIsEqual(v, &_v) + + return &sq - return res } // FrobeniusTorus raises a compressed elements y ∈ E6 to the modulus p diff --git a/std/algebra/emulated/fields_bn254/e6.go b/std/algebra/emulated/fields_bn254/e6.go index 00e9dbf0f2..dc9c2801d6 100644 --- a/std/algebra/emulated/fields_bn254/e6.go +++ b/std/algebra/emulated/fields_bn254/e6.go @@ -315,24 +315,3 @@ func (e Ext6) DivUnchecked(x, y *E6) *E6 { return &div } - -func (e Ext6) Halve(x *E6) *E6 { - res, err := e.fp.NewHint(halveE6Hint, 6, &x.B0.A0, &x.B0.A1, &x.B1.A0, &x.B1.A1, &x.B2.A0, &x.B2.A1) - if err != nil { - // err is non-nil only for invalid number of inputs - panic(err) - } - - half := E6{ - B0: E2{A0: *res[0], A1: *res[1]}, - B1: E2{A0: *res[2], A1: *res[3]}, - B2: E2{A0: *res[4], A1: *res[5]}, - } - - // 2*half == x - _x := e.double(&half) - e.AssertIsEqual(x, _x) - - return &half - -} diff --git a/std/algebra/emulated/fields_bn254/e6_test.go b/std/algebra/emulated/fields_bn254/e6_test.go index 12398222a4..05bfc4b121 100644 --- a/std/algebra/emulated/fields_bn254/e6_test.go +++ b/std/algebra/emulated/fields_bn254/e6_test.go @@ -377,38 +377,3 @@ func TestInverseFp6(t *testing.T) { err := test.IsSolved(&e6Inverse{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } - -type e6Halve struct { - A E6 - C E6 `gnark:",public"` -} - -func (circuit *e6Halve) Define(api frontend.API) error { - - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt6(ba) - expected := e.Halve(&circuit.A) - e.AssertIsEqual(expected, &circuit.C) - - return nil -} - -func TestHalveFp6(t *testing.T) { - - assert := test.NewAssert(t) - // witness values - var a, c bn254.E6 - _, _ = a.SetRandom() - c.Set(&a) - c.B0.Halve() - c.B1.Halve() - c.B2.Halve() - - witness := e6Halve{ - A: FromE6(&a), - C: FromE6(&c), - } - - err := test.IsSolved(&e6Halve{}, &witness, ecc.BN254.ScalarField()) - assert.NoError(err) -} diff --git a/std/algebra/emulated/fields_bn254/hints.go b/std/algebra/emulated/fields_bn254/hints.go index f6e9a9ffae..b08d6ed977 100644 --- a/std/algebra/emulated/fields_bn254/hints.go +++ b/std/algebra/emulated/fields_bn254/hints.go @@ -21,7 +21,7 @@ func GetHints() []solver.Hint { // E6 divE6Hint, inverseE6Hint, - halveE6Hint, + squareTorusHint, // E12 divE12Hint, inverseE12Hint, @@ -122,7 +122,7 @@ func divE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error }) } -func halveE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { +func squareTorusHint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { return emulated.UnwrapHint(nativeInputs, nativeOutputs, func(mod *big.Int, inputs, outputs []*big.Int) error { var a, c bn254.E6 @@ -134,10 +134,9 @@ func halveE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) err a.B2.A0.SetBigInt(inputs[4]) a.B2.A1.SetBigInt(inputs[5]) - c.Set(&a) - c.B0.Halve() - c.B1.Halve() - c.B2.Halve() + _c := a.DecompressTorus() + _c.CyclotomicSquare(&_c) + c, _ = _c.CompressTorus() c.B0.A0.BigInt(outputs[0]) c.B0.A1.BigInt(outputs[1]) From 411c800511012a5cfcf5131add9546c1819926ab Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 22 Mar 2023 18:38:49 +0000 Subject: [PATCH 190/464] perf(bls12-381/pairing): use hint for SquareTorus --- .../emulated/fields_bls12381/e12_pairing.go | 33 +++++++++++++------ std/algebra/emulated/fields_bls12381/e6.go | 21 ------------ std/algebra/emulated/fields_bls12381/hints.go | 11 +++---- 3 files changed, 28 insertions(+), 37 deletions(-) diff --git a/std/algebra/emulated/fields_bls12381/e12_pairing.go b/std/algebra/emulated/fields_bls12381/e12_pairing.go index b2d832e6a4..7bec959778 100644 --- a/std/algebra/emulated/fields_bls12381/e12_pairing.go +++ b/std/algebra/emulated/fields_bls12381/e12_pairing.go @@ -222,19 +222,32 @@ func (e Ext12) InverseTorus(y *E6) *E6 { } // SquareTorus squares a compressed elements y ∈ E6 -// and returns (y + v/g)/2 +// and returns (y + v/y)/2 +// +// It uses a hint to verify that (2x-y)y = v saving one E6 AssertIsEqual. func (e Ext12) SquareTorus(y *E6) *E6 { - yInv := e.Ext6.Inverse(y) - // Mul by (0,1,0) - tmp := yInv.B0 - yInv.B0 = *e.Ext2.MulByNonResidue(&yInv.B2) - yInv.B2 = yInv.B1 - yInv.B1 = tmp + res, err := e.fp.NewHint(squareTorusHint, 6, &y.B0.A0, &y.B0.A1, &y.B1.A0, &y.B1.A1, &y.B2.A0, &y.B2.A1) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } - res := e.Ext6.Add(y, yInv) - res = e.Ext6.Halve(res) + sq := E6{ + B0: E2{A0: *res[0], A1: *res[1]}, + B1: E2{A0: *res[2], A1: *res[3]}, + B2: E2{A0: *res[4], A1: *res[5]}, + } + + // v = (2x-y)y + v := e.Ext6.double(&sq) + v = e.Ext6.Sub(v, y) + v = e.Ext6.Mul(v, y) + + _v := E6{B0: *e.Ext2.Zero(), B1: *e.Ext2.One(), B2: *e.Ext2.Zero()} + e.Ext6.AssertIsEqual(v, &_v) + + return &sq - return res } // FrobeniusTorus raises a compressed elements y ∈ E6 to the modulus p diff --git a/std/algebra/emulated/fields_bls12381/e6.go b/std/algebra/emulated/fields_bls12381/e6.go index df95aa698c..bfec67bf23 100644 --- a/std/algebra/emulated/fields_bls12381/e6.go +++ b/std/algebra/emulated/fields_bls12381/e6.go @@ -292,24 +292,3 @@ func (e Ext6) DivUnchecked(x, y *E6) *E6 { return &div } - -func (e Ext6) Halve(x *E6) *E6 { - res, err := e.fp.NewHint(halveE6Hint, 6, &x.B0.A0, &x.B0.A1, &x.B1.A0, &x.B1.A1, &x.B2.A0, &x.B2.A1) - if err != nil { - // err is non-nil only for invalid number of inputs - panic(err) - } - - half := E6{ - B0: E2{A0: *res[0], A1: *res[1]}, - B1: E2{A0: *res[2], A1: *res[3]}, - B2: E2{A0: *res[4], A1: *res[5]}, - } - - // 2*half == x - _x := e.double(&half) - e.AssertIsEqual(x, _x) - - return &half - -} diff --git a/std/algebra/emulated/fields_bls12381/hints.go b/std/algebra/emulated/fields_bls12381/hints.go index 4fbe179677..c8455f40cf 100644 --- a/std/algebra/emulated/fields_bls12381/hints.go +++ b/std/algebra/emulated/fields_bls12381/hints.go @@ -21,7 +21,7 @@ func GetHints() []solver.Hint { // E6 divE6Hint, inverseE6Hint, - halveE6Hint, + squareTorusHint, // E12 divE12Hint, inverseE12Hint, @@ -122,7 +122,7 @@ func divE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error }) } -func halveE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { +func squareTorusHint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { return emulated.UnwrapHint(nativeInputs, nativeOutputs, func(mod *big.Int, inputs, outputs []*big.Int) error { var a, c bls12381.E6 @@ -134,10 +134,9 @@ func halveE6Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) err a.B2.A0.SetBigInt(inputs[4]) a.B2.A1.SetBigInt(inputs[5]) - c.Set(&a) - c.B0.Halve() - c.B1.Halve() - c.B2.Halve() + _c := a.DecompressTorus() + _c.CyclotomicSquare(&_c) + c, _ = _c.CompressTorus() c.B0.A0.BigInt(outputs[0]) c.B0.A1.BigInt(outputs[1]) From 8d62ed2404b602953e464dbb6bd6f5e0a1dbbc43 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 23 Mar 2023 11:48:17 +0100 Subject: [PATCH 191/464] refactor: make E6 double public --- std/algebra/emulated/fields_bls12381/e12.go | 2 +- std/algebra/emulated/fields_bls12381/e12_pairing.go | 2 +- std/algebra/emulated/fields_bls12381/e6.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/std/algebra/emulated/fields_bls12381/e12.go b/std/algebra/emulated/fields_bls12381/e12.go index dcc6e7a150..5bdab91e6b 100644 --- a/std/algebra/emulated/fields_bls12381/e12.go +++ b/std/algebra/emulated/fields_bls12381/e12.go @@ -83,7 +83,7 @@ func (e Ext12) Square(x *E12) *E12 { c2 := e.Ext6.Mul(&x.C0, &x.C1) c0 = e.Ext6.Mul(c0, c3) c0 = e.Ext6.Add(c0, c2) - z1 := e.Ext6.double(c2) + z1 := e.Ext6.Double(c2) c2 = e.Ext6.MulByNonResidue(c2) z0 := e.Ext6.Add(c0, c2) return &E12{ diff --git a/std/algebra/emulated/fields_bls12381/e12_pairing.go b/std/algebra/emulated/fields_bls12381/e12_pairing.go index 7bec959778..c096b0d2fd 100644 --- a/std/algebra/emulated/fields_bls12381/e12_pairing.go +++ b/std/algebra/emulated/fields_bls12381/e12_pairing.go @@ -239,7 +239,7 @@ func (e Ext12) SquareTorus(y *E6) *E6 { } // v = (2x-y)y - v := e.Ext6.double(&sq) + v := e.Ext6.Double(&sq) v = e.Ext6.Sub(v, y) v = e.Ext6.Mul(v, y) diff --git a/std/algebra/emulated/fields_bls12381/e6.go b/std/algebra/emulated/fields_bls12381/e6.go index bfec67bf23..7073fd4711 100644 --- a/std/algebra/emulated/fields_bls12381/e6.go +++ b/std/algebra/emulated/fields_bls12381/e6.go @@ -102,7 +102,7 @@ func (e Ext6) Mul(x, y *E6) *E6 { } } -func (e Ext6) double(x *E6) *E6 { +func (e Ext6) Double(x *E6) *E6 { z0 := e.Ext2.Double(&x.B0) z1 := e.Ext2.Double(&x.B1) z2 := e.Ext2.Double(&x.B2) From 66128241e6743e58da1b813e5893b0e0636697f0 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Thu, 23 Mar 2023 13:23:51 +0000 Subject: [PATCH 192/464] docs: comment about subgroup membership --- std/algebra/emulated/sw_bn254/pairing.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index ec2a8e00af..dfc8b3ac84 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -128,7 +128,7 @@ func (pr Pairing) FinalExponentiationTorus(e *GTEl) *fields_bn254.E6 { // Pair calculates the reduced pairing for a set of points // ∏ᵢ e(Pᵢ, Qᵢ). // -// This function doesn't check that the inputs are in the correct subgroup. See IsInSubGroup. +// This function doesn't check that the inputs are in the correct subgroup. func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { res, err := pr.MillerLoop(P, Q) if err != nil { @@ -183,8 +183,11 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { for k := 0; k < n; k++ { Qacc[k] = Q[k] QNeg[k] = &G2Affine{X: Q[k].X, Y: *pr.Ext2.Neg(&Q[k].Y)} - // (x,0) cannot be on BN254 because -3 is a cubic non-residue in Fp - // so, 1/y is well defined for all points P's + // P and Q are supposed to be on G1 and G2 respectively of prime order r. + // The point (x,0) is of order 2. But this function does not check + // subgroup membership. + // Anyway (x,0) cannot be on BN254 because -3 is a cubic non-residue in Fp. + // So, 1/y is well defined for all points P's. yInv[k] = pr.curveF.Inverse(&P[k].Y) xOverY[k] = pr.curveF.MulMod(&P[k].X, yInv[k]) } From 6f97d9ebebfb03624f7235e9c1c1e90b31afa4c8 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Thu, 23 Mar 2023 13:30:23 +0000 Subject: [PATCH 193/464] docs: comment about subgroup membership --- std/algebra/emulated/sw_bls12381/pairing.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go index e265ea78e0..1639c1af5f 100644 --- a/std/algebra/emulated/sw_bls12381/pairing.go +++ b/std/algebra/emulated/sw_bls12381/pairing.go @@ -157,7 +157,10 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { for k := 0; k < n; k++ { Qacc[k] = Q[k] - // (x,0) cannot be on BLS12-381 because -4 is a cubic non-residue in Fp + // P and Q are supposed to be on G1 and G2 respectively of prime order r. + // The point (x,0) is of order 2. But this function does not check + // subgroup membership. + // Anyway (x,0) cannot be on BLS12-381 because -4 is a cubic non-residue in Fp. // so, 1/y is well defined for all points P's yInv[k] = pr.curveF.Inverse(&P[k].Y) xOverY[k] = pr.curveF.MulMod(&P[k].X, yInv[k]) From 263b4b3e84b3041557cbc1d6e4e60ff77e1a51e7 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Thu, 23 Mar 2023 17:42:15 +0000 Subject: [PATCH 194/464] feat: add IsOnCurve to sw_emulated --- std/algebra/emulated/sw_emulated/point.go | 15 ++++++++ .../emulated/sw_emulated/point_test.go | 34 +++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/std/algebra/emulated/sw_emulated/point.go b/std/algebra/emulated/sw_emulated/point.go index 414b011de2..c650afd4d3 100644 --- a/std/algebra/emulated/sw_emulated/point.go +++ b/std/algebra/emulated/sw_emulated/point.go @@ -38,6 +38,7 @@ func New[Base, Scalars emulated.FieldParams](api frontend.API, params CurveParam }, gm: emuGm, a: emulated.ValueOf[Base](params.A), + b: emulated.ValueOf[Base](params.B), addA: params.A.Cmp(big.NewInt(0)) != 0, }, nil } @@ -60,6 +61,7 @@ type Curve[Base, Scalars emulated.FieldParams] struct { gm []AffinePoint[Base] a emulated.Element[Base] + b emulated.Element[Base] addA bool } @@ -120,6 +122,19 @@ func (c *Curve[B, S]) Add(p, q *AffinePoint[B]) *AffinePoint[B] { } } +func (c *Curve[B, S]) AssertIsOnCurve(p *AffinePoint[B]) { + // y^2 = x^3+ax+b + left := c.baseApi.Mul(&p.Y, &p.Y) + right := c.baseApi.Mul(&p.X, &p.X) + right = c.baseApi.Mul(right, &p.X) + right = c.baseApi.Add(right, &c.b) + if c.addA { + ax := c.baseApi.Mul(&c.a, &p.X) + right = c.baseApi.Add(right, ax) + } + c.baseApi.AssertIsEqual(left, right) +} + // Double doubles p and return it. It doesn't modify p. // It uses affine coordinates. func (c *Curve[B, S]) Double(p *AffinePoint[B]) *AffinePoint[B] { diff --git a/std/algebra/emulated/sw_emulated/point_test.go b/std/algebra/emulated/sw_emulated/point_test.go index 6703970c1a..11539b046d 100644 --- a/std/algebra/emulated/sw_emulated/point_test.go +++ b/std/algebra/emulated/sw_emulated/point_test.go @@ -345,3 +345,37 @@ func TestScalarMul2(t *testing.T) { _, err = frontend.Compile(testCurve.ScalarField(), r1cs.NewBuilder, &circuit) assert.NoError(err) } + +type IsOnCurveTest[T, S emulated.FieldParams] struct { + Q AffinePoint[T] +} + +func (c *IsOnCurveTest[T, S]) Define(api frontend.API) error { + cr, err := New[T, S](api, GetCurveParams[T]()) + if err != nil { + return err + } + cr.AssertIsOnCurve(&c.Q) + return nil +} + +func TestIsOnCurve(t *testing.T) { + assert := test.NewAssert(t) + _, g := secp256k1.Generators() + var r fr_secp.Element + _, _ = r.SetRandom() + s := new(big.Int) + r.BigInt(s) + var Q secp256k1.G1Affine + Q.ScalarMultiplication(&g, s) + + circuit := IsOnCurveTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{} + witness := IsOnCurveTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ + Q: AffinePoint[emulated.Secp256k1Fp]{ + X: emulated.ValueOf[emulated.Secp256k1Fp](Q.X), + Y: emulated.ValueOf[emulated.Secp256k1Fp](Q.Y), + }, + } + err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) + assert.NoError(err) +} From b922e01c5df38bafb70887b4d5d1845471e78260 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 23 Mar 2023 21:02:42 -0400 Subject: [PATCH 195/464] refactor: same bsb22 placeholder for groth16 and plonk --- constraint/bn254/r1cs_sparse.go | 11 +++++++++++ frontend/cs/commitment.go | 26 ++++++++++++++++++++++++++ frontend/cs/r1cs/api.go | 24 +++--------------------- frontend/cs/scs/api.go | 11 +++-------- std/math/emulated/element_test.go | 13 ++++++++++--- 5 files changed, 53 insertions(+), 32 deletions(-) create mode 100644 frontend/cs/commitment.go diff --git a/constraint/bn254/r1cs_sparse.go b/constraint/bn254/r1cs_sparse.go index a60a4763da..63b046ab37 100644 --- a/constraint/bn254/r1cs_sparse.go +++ b/constraint/bn254/r1cs_sparse.go @@ -195,6 +195,8 @@ func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, er } +var SolveSequentially = false + func (cs *SparseR1CS) parallelSolve(solution *solution, coefficientsNegInv fr.Vector) error { // minWorkPerCPU is the minimum target number of constraint a task should hold // in other words, if a level has less than minWorkPerCPU, it will not be parallelized and executed @@ -208,6 +210,8 @@ func (cs *SparseR1CS) parallelSolve(solution *solution, coefficientsNegInv fr.Ve chTasks := make(chan []int, runtime.NumCPU()) chError := make(chan *UnsatisfiedConstraintError, runtime.NumCPU()) + var m sync.Mutex + // start a worker pool // each worker wait on chTasks // a task is a slice of constraint indexes to be solved @@ -215,6 +219,10 @@ func (cs *SparseR1CS) parallelSolve(solution *solution, coefficientsNegInv fr.Ve go func() { for t := range chTasks { for _, i := range t { + if SolveSequentially { + m.Lock() + } + //fmt.Println("solving constraint", i) // for each constraint in the task, solve it. if err := cs.solveConstraint(cs.Constraints[i], solution, coefficientsNegInv); err != nil { chError <- &UnsatisfiedConstraintError{CID: i, Err: err} @@ -231,6 +239,9 @@ func (cs *SparseR1CS) parallelSolve(solution *solution, coefficientsNegInv fr.Ve wg.Done() return } + if SolveSequentially { + m.Unlock() + } } wg.Done() } diff --git a/frontend/cs/commitment.go b/frontend/cs/commitment.go new file mode 100644 index 0000000000..f0d26b96e7 --- /dev/null +++ b/frontend/cs/commitment.go @@ -0,0 +1,26 @@ +package cs + +import ( + "fmt" + "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/debug" + "github.com/consensys/gnark/logger" + "math/big" + "os" + "strings" +) + +func Bsb22CommitmentComputePlaceholder(_ *big.Int, _ []*big.Int, output []*big.Int) error { + if (len(os.Args) > 0 && (strings.HasSuffix(os.Args[0], ".test") || strings.HasSuffix(os.Args[0], ".test.exe"))) || debug.Debug { + // usually we only run solver without prover during testing + log := logger.Logger() + log.Error().Msg("Augmented groth16 commitment hint not replaced. Proof will not be sound!") + output[0].SetInt64(0) + return nil + } + return fmt.Errorf("placeholder function: to be replaced by commitment computation") +} + +func init() { + solver.RegisterHint(Bsb22CommitmentComputePlaceholder) +} diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index 347024dc20..3f182b3539 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -19,8 +19,7 @@ package r1cs import ( "errors" "fmt" - "math/big" - "os" + "github.com/consensys/gnark/frontend/cs" "path/filepath" "reflect" "runtime" @@ -28,11 +27,9 @@ import ( "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/debug" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/internal/expr" "github.com/consensys/gnark/frontend/schema" - "github.com/consensys/gnark/logger" "github.com/consensys/gnark/std/math/bits" ) @@ -729,12 +726,12 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error // hint is used at solving time to compute the actual value of the commitment // it is going to be dynamically replaced at solving time. - hintOut, err := builder.NewHint(bsb22CommitmentComputePlaceholder, 1, builder.getCommittedVariables(&commitment)...) + hintOut, err := builder.NewHint(cs.Bsb22CommitmentComputePlaceholder, 1, builder.getCommittedVariables(&commitment)...) if err != nil { return nil, err } cVar := hintOut[0] - commitment.HintID = solver.GetHintID(bsb22CommitmentComputePlaceholder) // TODO @gbotrel probably not needed + commitment.HintID = solver.GetHintID(cs.Bsb22CommitmentComputePlaceholder) // TODO @gbotrel probably not needed commitment.CommitmentIndex = (cVar.(expr.LinearExpression))[0].WireID() @@ -758,18 +755,3 @@ func (builder *builder) getCommittedVariables(i *constraint.Commitment) []fronte } return res } - -func bsb22CommitmentComputePlaceholder(_ *big.Int, _ []*big.Int, output []*big.Int) error { - if (len(os.Args) > 0 && (strings.HasSuffix(os.Args[0], ".test") || strings.HasSuffix(os.Args[0], ".test.exe"))) || debug.Debug { - // usually we only run solver without prover during testing - log := logger.Logger() - log.Error().Msg("Augmented groth16 commitment hint not replaced. Proof will not be sound!") - output[0].SetInt64(0) - return nil - } - return fmt.Errorf("placeholder function: to be replaced by commitment computation") -} - -func init() { - solver.RegisterHint(bsb22CommitmentComputePlaceholder) -} diff --git a/frontend/cs/scs/api.go b/frontend/cs/scs/api.go index e52146b163..b8bf9b0cf9 100644 --- a/frontend/cs/scs/api.go +++ b/frontend/cs/scs/api.go @@ -17,9 +17,8 @@ limitations under the License. package scs import ( - "errors" "fmt" - "math/big" + "github.com/consensys/gnark/frontend/cs" "path/filepath" "reflect" "runtime" @@ -561,10 +560,6 @@ func (builder *builder) Compiler() frontend.Compiler { return builder } -func scsBsb22CommitmentHintPlaceholder(*big.Int, []*big.Int, []*big.Int) error { - return errors.New("placeholder - should never be called") -} - func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error) { committed := make([]int, len(v)) @@ -574,7 +569,7 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error committed[i] = builder.cs.GetNbConstraints() builder.addPlonkConstraint(sparseR1C{xa: vINeg.VID, qL: vINeg.Coeff, commitment: constraint.COMMITTED}) } - outs, err := builder.NewHint(scsBsb22CommitmentHintPlaceholder, 1, v...) + outs, err := builder.NewHint(cs.Bsb22CommitmentComputePlaceholder, 1, v...) if err != nil { return nil, err } @@ -583,7 +578,7 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error builder.addPlonkConstraint(sparseR1C{xa: commitmentVar.VID, qL: commitmentVar.Coeff, commitment: constraint.COMMITMENT}) // value will be injected later return outs[0], builder.cs.AddCommitment(constraint.Commitment{ - HintID: solver.GetHintID(scsBsb22CommitmentHintPlaceholder), + HintID: solver.GetHintID(cs.Bsb22CommitmentComputePlaceholder), CommitmentIndex: commitmentConstraintIndex, Committed: committed, }) diff --git a/std/math/emulated/element_test.go b/std/math/emulated/element_test.go index aa7d5f8cd7..03db64f3e4 100644 --- a/std/math/emulated/element_test.go +++ b/std/math/emulated/element_test.go @@ -3,6 +3,7 @@ package emulated import ( "crypto/rand" "fmt" + cs "github.com/consensys/gnark/constraint/bn254" "math/big" "reflect" "testing" @@ -37,8 +38,14 @@ func testName[T FieldParams]() string { func TestAssertLimbEqualityNoOverflow(t *testing.T) { testAssertLimbEqualityNoOverflow[Goldilocks](t) - testAssertLimbEqualityNoOverflow[Secp256k1Fp](t) - testAssertLimbEqualityNoOverflow[BN254Fp](t) + //testAssertLimbEqualityNoOverflow[Secp256k1Fp](t) + //testAssertLimbEqualityNoOverflow[BN254Fp](t) +} + +func TestAssertLimbEqualityNoOverflowSequential(t *testing.T) { + cs.SolveSequentially = true + testAssertLimbEqualityNoOverflow[Goldilocks](t) + cs.SolveSequentially = false } func testAssertLimbEqualityNoOverflow[T FieldParams](t *testing.T) { @@ -49,7 +56,7 @@ func testAssertLimbEqualityNoOverflow[T FieldParams](t *testing.T) { val, _ := rand.Int(rand.Reader, fp.Modulus()) witness.A = ValueOf[T](val) witness.B = ValueOf[T](val) - assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) + assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends( /*backend.GROTH16,*/ backend.PLONK)) }, testName[T]()) } From fc31d311cfb92b3191d69bdc790c78ad197c04cc Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 24 Mar 2023 10:03:25 +0000 Subject: [PATCH 196/464] feat: add IsOnCurve to sw_bn254/g2 --- std/algebra/emulated/sw_bn254/g2.go | 18 +++++++++++++++ std/algebra/emulated/sw_bn254/g2_test.go | 28 ++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 std/algebra/emulated/sw_bn254/g2_test.go diff --git a/std/algebra/emulated/sw_bn254/g2.go b/std/algebra/emulated/sw_bn254/g2.go index 9fd94325c5..3a11c7872f 100644 --- a/std/algebra/emulated/sw_bn254/g2.go +++ b/std/algebra/emulated/sw_bn254/g2.go @@ -2,6 +2,7 @@ package sw_bn254 import ( "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/algebra/emulated/fields_bn254" "github.com/consensys/gnark/std/math/emulated" ) @@ -22,3 +23,20 @@ func NewG2Affine(v bn254.G2Affine) G2Affine { }, } } + +func (p *G2Affine) AssertIsOnCurve(api frontend.API) { + ba, _ := emulated.NewField[emulated.BN254Fp](api) + e := fields_bn254.NewExt2(ba) + + // Y^2 = X^3 + b + // where b = 3/(9+u) + b := fields_bn254.E2{ + A0: emulated.ValueOf[emulated.BN254Fp]("19485874751759354771024239261021720505790618469301721065564631296452457478373"), + A1: emulated.ValueOf[emulated.BN254Fp]("266929791119991161246907387137283842545076965332900288569378510910307636690"), + } + left := e.Square(&p.Y) + right := e.Square(&p.X) + right = e.Mul(right, &p.X) + right = e.Add(right, &b) + e.AssertIsEqual(left, right) +} diff --git a/std/algebra/emulated/sw_bn254/g2_test.go b/std/algebra/emulated/sw_bn254/g2_test.go new file mode 100644 index 0000000000..8a04a91381 --- /dev/null +++ b/std/algebra/emulated/sw_bn254/g2_test.go @@ -0,0 +1,28 @@ +package sw_bn254 + +import ( + "testing" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/test" +) + +type IsOnCurveCircuit struct { + Q G2Affine +} + +func (c *IsOnCurveCircuit) Define(api frontend.API) error { + c.Q.AssertIsOnCurve(api) + return nil +} + +func TestIsOnCurve(t *testing.T) { + assert := test.NewAssert(t) + _, q := randomG1G2Affines(assert) + witness := IsOnCurveCircuit{ + Q: NewG2Affine(q), + } + err := test.IsSolved(&IsOnCurveCircuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} From a434221ef4ceda26b547d2c64b5d566f2a19ba60 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Fri, 24 Mar 2023 11:33:05 +0100 Subject: [PATCH 197/464] feat: set default compression threshold (#599) * feat: set default compression threshold * test: update circuit statistics --- frontend/compile.go | 11 ++++++++++- internal/stats/latest.stats | Bin 2803 -> 2803 bytes 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/frontend/compile.go b/frontend/compile.go index 02f0ec384f..2a6266c44d 100644 --- a/frontend/compile.go +++ b/frontend/compile.go @@ -37,7 +37,7 @@ func Compile(field *big.Int, newBuilder NewBuilder, circuit Circuit, opts ...Com log := logger.Logger() log.Info().Msg("compiling circuit") // parse options - opt := CompileConfig{} + opt := defaultCompileConfig() for _, o := range opts { if err := o(&opt); err != nil { log.Err(err).Msg("applying compile option") @@ -144,6 +144,12 @@ func callDeferred(builder Builder) error { // type for available options. type CompileOption func(opt *CompileConfig) error +func defaultCompileConfig() CompileConfig { + return CompileConfig{ + CompressThreshold: 300, + } +} + type CompileConfig struct { Capacity int IgnoreUnconstrainedInputs bool @@ -187,6 +193,9 @@ func IgnoreUnconstrainedInputs() CompileOption { // fast. The compression adds some overhead in the number of constraints. The // overhead and compile performance depends on threshold value, and it should be // chosen carefully. +// +// If this option is not given then by default we use the compress threshold of +// 300. func WithCompressThreshold(threshold int) CompileOption { return func(opt *CompileConfig) error { opt.CompressThreshold = threshold diff --git a/internal/stats/latest.stats b/internal/stats/latest.stats index 27e6782e0237df4bb959280fdee86aabc437f96a..10dd24f37c845e66c4cb646f14f4d030ff3314e9 100644 GIT binary patch delta 215 zcmew?`dM^B*5uW!4=3w0c?z>I{$u*WzzCu$7#Nut|1tiXe3!#{@_mj)eBU5)|Cp*k zvXlEcdl|(iD{_iYzQ`D895h*uwRdtdyDJtwlbu*vCik#ipUltv zaI!Op8y+hiCuTYE-D3R5aRX>Ddm0d@Ox)EwIghJ#@&{&RwtLGM|J_?QS&~I_vOD98 T$ueBZta*(8qVguYaA^SmF(pqD delta 201 zcmew?`dM^B)?`)=C-EDM|2VEOF#cmt0pcVegY^#(|C&6X!+G*T4#&wmIbTfnX7uD? zV*JPSiGdMBl}%p2*ge^u?cwBfPGz?18yNpx-!ORsr{?50EG?7OnZ5XSG5+J*1~iJt z4~V@c*E9D{%z8Mvfc5%h9u`-=FA$UdF;#%gif8GatikSvZowOD>K1Y-v&u34i;|ms Ll1ppyBaT)8V8%=R From 45394fcb21b8eab46576188d7e6baf1ec24f85a0 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 24 Mar 2023 12:19:49 +0000 Subject: [PATCH 198/464] feat(pairing): check points are on curve and twist --- std/algebra/emulated/sw_bn254/g2.go | 18 ------------ std/algebra/emulated/sw_bn254/g2_test.go | 28 ------------------ std/algebra/emulated/sw_bn254/pairing.go | 29 +++++++++++++++++++ std/algebra/emulated/sw_bn254/pairing_test.go | 14 +++++++++ 4 files changed, 43 insertions(+), 46 deletions(-) delete mode 100644 std/algebra/emulated/sw_bn254/g2_test.go diff --git a/std/algebra/emulated/sw_bn254/g2.go b/std/algebra/emulated/sw_bn254/g2.go index 3a11c7872f..9fd94325c5 100644 --- a/std/algebra/emulated/sw_bn254/g2.go +++ b/std/algebra/emulated/sw_bn254/g2.go @@ -2,7 +2,6 @@ package sw_bn254 import ( "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/algebra/emulated/fields_bn254" "github.com/consensys/gnark/std/math/emulated" ) @@ -23,20 +22,3 @@ func NewG2Affine(v bn254.G2Affine) G2Affine { }, } } - -func (p *G2Affine) AssertIsOnCurve(api frontend.API) { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := fields_bn254.NewExt2(ba) - - // Y^2 = X^3 + b - // where b = 3/(9+u) - b := fields_bn254.E2{ - A0: emulated.ValueOf[emulated.BN254Fp]("19485874751759354771024239261021720505790618469301721065564631296452457478373"), - A1: emulated.ValueOf[emulated.BN254Fp]("266929791119991161246907387137283842545076965332900288569378510910307636690"), - } - left := e.Square(&p.Y) - right := e.Square(&p.X) - right = e.Mul(right, &p.X) - right = e.Add(right, &b) - e.AssertIsEqual(left, right) -} diff --git a/std/algebra/emulated/sw_bn254/g2_test.go b/std/algebra/emulated/sw_bn254/g2_test.go deleted file mode 100644 index 8a04a91381..0000000000 --- a/std/algebra/emulated/sw_bn254/g2_test.go +++ /dev/null @@ -1,28 +0,0 @@ -package sw_bn254 - -import ( - "testing" - - "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/test" -) - -type IsOnCurveCircuit struct { - Q G2Affine -} - -func (c *IsOnCurveCircuit) Define(api frontend.API) error { - c.Q.AssertIsOnCurve(api) - return nil -} - -func TestIsOnCurve(t *testing.T) { - assert := test.NewAssert(t) - _, q := randomG1G2Affines(assert) - witness := IsOnCurveCircuit{ - Q: NewG2Affine(q), - } - err := test.IsSolved(&IsOnCurveCircuit{}, &witness, ecc.BN254.ScalarField()) - assert.NoError(err) -} diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index dfc8b3ac84..c80ad6eb49 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -142,6 +142,29 @@ func (pr Pairing) AssertIsEqual(x, y *GTEl) { pr.Ext12.AssertIsEqual(x, y) } +func (pr Pairing) AssertIsOnCurve(P *G1Affine) { + // Curve: Y^2 = X^3 + b, where b = 3 + three := emulated.ValueOf[emulated.BN254Fp](3) + left := pr.curveF.Mul(&P.Y, &P.Y) + right := pr.curveF.Mul(&P.X, &P.X) + right = pr.curveF.Mul(right, &P.X) + right = pr.curveF.Add(right, &three) + pr.curveF.AssertIsEqual(left, right) +} + +func (pr Pairing) AssertIsOnTwist(Q *G2Affine) { + // Twist: Y^2 = X^3 + b', where b' = 3/(9+u) + b := fields_bn254.E2{ + A0: emulated.ValueOf[emulated.BN254Fp]("19485874751759354771024239261021720505790618469301721065564631296452457478373"), + A1: emulated.ValueOf[emulated.BN254Fp]("266929791119991161246907387137283842545076965332900288569378510910307636690"), + } + left := pr.Ext2.Square(&Q.Y) + right := pr.Ext2.Square(&Q.X) + right = pr.Ext2.Mul(right, &Q.X) + right = pr.Ext2.Add(right, &b) + pr.Ext2.AssertIsEqual(left, right) +} + // loopCounter = 6x₀+2 = 29793968203157093288 // // in 2-NAF @@ -171,6 +194,12 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { return nil, errors.New("invalid inputs sizes") } + // check points are on curve + for k := 0; k < n; k++ { + pr.AssertIsOnCurve(P[k]) + pr.AssertIsOnTwist(Q[k]) + } + res := pr.Ext12.One() var prodLines [5]fields_bn254.E2 diff --git a/std/algebra/emulated/sw_bn254/pairing_test.go b/std/algebra/emulated/sw_bn254/pairing_test.go index 7009a2a21f..4cb7ed26fc 100644 --- a/std/algebra/emulated/sw_bn254/pairing_test.go +++ b/std/algebra/emulated/sw_bn254/pairing_test.go @@ -7,7 +7,10 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/profile" "github.com/consensys/gnark/test" ) @@ -123,3 +126,14 @@ func TestMultiPairTestSolve(t *testing.T) { err = test.IsSolved(&MultiPairCircuit{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } + +// bench +var ccsBench constraint.ConstraintSystem + +func BenchmarkPairing(b *testing.B) { + var c PairCircuit + p := profile.Start() + ccsBench, _ = frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &c) + p.Stop() + fmt.Println(p.NbConstraints()) +} From 8f89251cb228450b1cecfb4ac0d6418053e51d17 Mon Sep 17 00:00:00 2001 From: ThomasPiellard Date: Fri, 24 Mar 2023 15:46:29 +0100 Subject: [PATCH 199/464] feat: range checks using log derivative, fixes #581 (#583) * feat: range checks using log derivative, fixes #581 * feat: compute constraints for log-deriv range check * feat: use unchecked division * chore: cleanup test * feat: compress groth16 linear expression * docs: refer to log-derivate idea paper * fix: include exponents in commitment * test: more cleanup * fix: compute a bit more complex fake commit * test: update circuit statistics --------- Co-authored-by: Ivo Kubjas --- frontend/cs/r1cs/api.go | 9 +++-- internal/stats/latest.stats | Bin 2803 -> 2803 bytes std/rangecheck/rangecheck.go | 3 +- std/rangecheck/rangecheck_commit.go | 60 +++++++++------------------- std/rangecheck/rangecheck_test.go | 9 ++--- 5 files changed, 30 insertions(+), 51 deletions(-) diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index ebc7c96c08..6784c8df7e 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -759,12 +759,15 @@ func (builder *builder) getCommittedVariables(i *constraint.Commitment) []fronte return res } -func bsb22CommitmentComputePlaceholder(_ *big.Int, _ []*big.Int, output []*big.Int) error { +func bsb22CommitmentComputePlaceholder(mod *big.Int, input []*big.Int, output []*big.Int) error { if (len(os.Args) > 0 && (strings.HasSuffix(os.Args[0], ".test") || strings.HasSuffix(os.Args[0], ".test.exe"))) || debug.Debug { // usually we only run solver without prover during testing log := logger.Logger() - log.Error().Msg("Augmented groth16 commitment hint not replaced. Proof will not be sound!") - output[0].SetInt64(0) + log.Error().Msg("Augmented groth16 commitment hint not replaced. Proof will not be sound and verification will fail!") + for i := range input { + output[0].Add(output[0], input[i]) + output[0].Mod(output[0], mod) + } return nil } return fmt.Errorf("placeholder function: to be replaced by commitment computation") diff --git a/internal/stats/latest.stats b/internal/stats/latest.stats index 10dd24f37c845e66c4cb646f14f4d030ff3314e9..1afedc740b579076c7016131b1b1d627eeb2846e 100644 GIT binary patch delta 127 zcmew?`dM^B)?{s_Kbs3!cQ8)&W_&PNo%!ixR*t)q7jgwnPUj4o{D`Ap?)?oNKp za(8kHTkB*YwxG$}TpBhae;EHMWiT-Q!^05pVf-fvQX^Qw_)mHTT=C=$T+Wj>aXC&t Hz#0Sq!IL&N diff --git a/std/rangecheck/rangecheck.go b/std/rangecheck/rangecheck.go index b3bf870690..f7152df3e5 100644 --- a/std/rangecheck/rangecheck.go +++ b/std/rangecheck/rangecheck.go @@ -2,10 +2,11 @@ // // This package chooses the most optimal path for performing range checks: // - if the backend supports native range checking and the frontend exports the variables in the proprietary format by implementing [frontend.Rangechecker], then use it directly; -// - if the backend supports creating a commitment of variables by implementing [frontend.Committer], then we use the product argument as in [BCG+18]. [r1cs.NewBuilder] returns a builder which implements this interface; +// - if the backend supports creating a commitment of variables by implementing [frontend.Committer], then we use the log-derivative variant [[Haböck22]] of the product argument as in [[BCG+18]] . [r1cs.NewBuilder] returns a builder which implements this interface; // - lacking these, we perform binary decomposition of variable into bits. // // [BCG+18]: https://eprint.iacr.org/2018/380 +// [Haböck22]: https://eprint.iacr.org/2022/1530 package rangecheck import ( diff --git a/std/rangecheck/rangecheck_commit.go b/std/rangecheck/rangecheck_commit.go index f5b6ddb30c..309b25d471 100644 --- a/std/rangecheck/rangecheck_commit.go +++ b/std/rangecheck/rangecheck_commit.go @@ -4,13 +4,11 @@ import ( "fmt" "math" "math/big" - stdbits "math/bits" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/internal/frontendtype" "github.com/consensys/gnark/internal/kvstore" - "github.com/consensys/gnark/std/math/bits" ) type ctxCheckerKey struct{} @@ -96,29 +94,23 @@ func (c *commitChecker) commit(api frontend.API) error { if err != nil { panic(fmt.Sprintf("count %v", err)) } - // compute the poly \pi (X - s_i)^{e_i} - commitment, err := committer.Commit(collected...) + // compute the ratoinal function Sum_i e_i / (X - s_i) + commitment, err := committer.Commit(append(collected, exps...)...) if err != nil { panic(fmt.Sprintf("commit %v", err)) } - logn := stdbits.Len(uint(len(decomposed))) - var lp frontend.Variable = 1 + // lp = Sum_i e_i / (X - s_i) + var lp frontend.Variable = 0 for i := 0; i < nbTable; i++ { - expbits := bits.ToBinary(api, exps[i], bits.WithNbDigits(logn)) - var acc frontend.Variable = 1 - tmp := api.Sub(commitment, i) - for j := 0; j < logn; j++ { - curr := api.Select(expbits[j], tmp, 1) - acc = api.Mul(acc, curr) - tmp = api.Mul(tmp, tmp) - } - lp = api.Mul(lp, acc) + tmp := api.DivUnchecked(exps[i], api.Sub(commitment, i)) + lp = api.Add(lp, tmp) } - // compute the poly \pi (X - f_i) - var rp frontend.Variable = 1 + + // rp = Sum_i 1 \ (X - f_i) + var rp frontend.Variable = 0 for i := range decomposed { - val := api.Sub(commitment, decomposed[i]) - rp = api.Mul(rp, val) + tmp := api.Inverse(api.Sub(commitment, decomposed[i])) + rp = api.Add(rp, tmp) } api.AssertIsEqual(lp, rp) return nil @@ -206,17 +198,10 @@ func nbR1CSConstraints(baseLength int, collected []checkedVariable) int { for i := range collected { nbDecomposed += int(decompSize(collected[i].bits, baseLength)) } - eqs := len(collected) // single composition check per collected - logn := stdbits.Len(uint(nbDecomposed)) - nbTable := 1 << baseLength - nbLeft := nbTable * - (logn + // tobinary - logn + // select per exponent bit - logn + // mul per exponent bit - logn + // mul per exponent bit - 1) // final mul - nbRight := nbDecomposed // mul all decomposed - return nbLeft + nbRight + eqs + 1 // single for final equality + eqs := len(collected) // correctness of decomposition + nbRight := nbDecomposed // inverse per decomposed + nbleft := (1 << baseLength) // div per table + return nbleft + nbRight + eqs + 1 } func nbPLONKConstraints(baseLength int, collected []checkedVariable) int { @@ -224,15 +209,8 @@ func nbPLONKConstraints(baseLength int, collected []checkedVariable) int { for i := range collected { nbDecomposed += int(decompSize(collected[i].bits, baseLength)) } - eqs := nbDecomposed // check correctness of every decomposition. this is nbDecomp adds + eq cost per collected - logn := stdbits.Len(uint(nbDecomposed)) - nbTable := 1 << baseLength - nbLeft := nbTable * - (3*logn + // tobinary. decomposition check + binary check - 2*logn + // select per exponent bit - logn + // mul per exponent bit - logn + // mul per exponent bit - 1) // final mul - nbRight := 2 * nbDecomposed // per decomposed sub and mul - return nbLeft + nbRight + eqs + 1 // single for final equality + eqs := nbDecomposed // check correctness of every decomposition. this is nbDecomp adds + eq cost per collected + nbRight := 3 * nbDecomposed // denominator sub, inv and large sum per table entry + nbleft := 3 * (1 << baseLength) // denominator sub, div and large sum per table entry + return nbleft + nbRight + eqs + 1 // and the final assert } diff --git a/std/rangecheck/rangecheck_test.go b/std/rangecheck/rangecheck_test.go index e135376afb..994921d0ce 100644 --- a/std/rangecheck/rangecheck_test.go +++ b/std/rangecheck/rangecheck_test.go @@ -15,7 +15,6 @@ import ( type CheckCircuit struct { Vals []frontend.Variable bits int - base int } func (c *CheckCircuit) Define(api frontend.API) error { @@ -30,7 +29,6 @@ func TestCheck(t *testing.T) { assert := test.NewAssert(t) var err error bits := 64 - base := 11 nbVals := 100000 bound := new(big.Int).Lsh(big.NewInt(1), uint(bits)) vals := make([]frontend.Variable, nbVals) @@ -40,11 +38,10 @@ func TestCheck(t *testing.T) { t.Fatal(err) } } - witness := CheckCircuit{Vals: vals, bits: bits, base: base} - circuit := CheckCircuit{Vals: make([]frontend.Variable, len(vals)), bits: bits, base: base} + witness := CheckCircuit{Vals: vals, bits: bits} + circuit := CheckCircuit{Vals: make([]frontend.Variable, len(vals)), bits: bits} err = test.IsSolved(&circuit, &witness, goldilocks.Modulus()) assert.NoError(err) - ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) + _, err = frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit, frontend.WithCompressThreshold(100)) assert.NoError(err) - t.Log(ccs.GetNbConstraints()) } From 5209bbf39033033fadb3f4bf098ea3e47fa1e9b8 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 24 Mar 2023 11:04:39 -0400 Subject: [PATCH 200/464] fix: plonk.Commit race condition --- constraint/bls12-377/r1cs_sparse.go | 2 +- constraint/bls12-381/r1cs_sparse.go | 2 +- constraint/bls24-315/r1cs_sparse.go | 2 +- constraint/bls24-317/r1cs_sparse.go | 2 +- constraint/bn254/r1cs_sparse.go | 13 +------------ constraint/bw6-633/r1cs_sparse.go | 2 +- constraint/bw6-761/r1cs_sparse.go | 2 +- constraint/tinyfield/r1cs_sparse.go | 2 +- .../template/representations/r1cs.sparse.go.tmpl | 2 +- std/math/emulated/element_test.go | 11 ++--------- 10 files changed, 11 insertions(+), 29 deletions(-) diff --git a/constraint/bls12-377/r1cs_sparse.go b/constraint/bls12-377/r1cs_sparse.go index 191fbacdcc..a63f2f86ed 100644 --- a/constraint/bls12-377/r1cs_sparse.go +++ b/constraint/bls12-377/r1cs_sparse.go @@ -358,7 +358,7 @@ func (cs *SparseR1CS) computeHints(c constraint.SparseR1C, solution *solution) ( // if it doesn't, then this function returns and does nothing func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution, coefficientsNegInv fr.Vector) error { - if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. + if c.Commitment == constraint.COMMITTED { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time } diff --git a/constraint/bls12-381/r1cs_sparse.go b/constraint/bls12-381/r1cs_sparse.go index 26a688214e..c223170fb3 100644 --- a/constraint/bls12-381/r1cs_sparse.go +++ b/constraint/bls12-381/r1cs_sparse.go @@ -358,7 +358,7 @@ func (cs *SparseR1CS) computeHints(c constraint.SparseR1C, solution *solution) ( // if it doesn't, then this function returns and does nothing func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution, coefficientsNegInv fr.Vector) error { - if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. + if c.Commitment == constraint.COMMITTED { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time } diff --git a/constraint/bls24-315/r1cs_sparse.go b/constraint/bls24-315/r1cs_sparse.go index 8380f4d27e..72f9533ad1 100644 --- a/constraint/bls24-315/r1cs_sparse.go +++ b/constraint/bls24-315/r1cs_sparse.go @@ -358,7 +358,7 @@ func (cs *SparseR1CS) computeHints(c constraint.SparseR1C, solution *solution) ( // if it doesn't, then this function returns and does nothing func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution, coefficientsNegInv fr.Vector) error { - if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. + if c.Commitment == constraint.COMMITTED { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time } diff --git a/constraint/bls24-317/r1cs_sparse.go b/constraint/bls24-317/r1cs_sparse.go index d3f5c85bf3..a23ca0a472 100644 --- a/constraint/bls24-317/r1cs_sparse.go +++ b/constraint/bls24-317/r1cs_sparse.go @@ -358,7 +358,7 @@ func (cs *SparseR1CS) computeHints(c constraint.SparseR1C, solution *solution) ( // if it doesn't, then this function returns and does nothing func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution, coefficientsNegInv fr.Vector) error { - if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. + if c.Commitment == constraint.COMMITTED { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time } diff --git a/constraint/bn254/r1cs_sparse.go b/constraint/bn254/r1cs_sparse.go index 63b046ab37..260b2a141b 100644 --- a/constraint/bn254/r1cs_sparse.go +++ b/constraint/bn254/r1cs_sparse.go @@ -195,8 +195,6 @@ func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, er } -var SolveSequentially = false - func (cs *SparseR1CS) parallelSolve(solution *solution, coefficientsNegInv fr.Vector) error { // minWorkPerCPU is the minimum target number of constraint a task should hold // in other words, if a level has less than minWorkPerCPU, it will not be parallelized and executed @@ -210,8 +208,6 @@ func (cs *SparseR1CS) parallelSolve(solution *solution, coefficientsNegInv fr.Ve chTasks := make(chan []int, runtime.NumCPU()) chError := make(chan *UnsatisfiedConstraintError, runtime.NumCPU()) - var m sync.Mutex - // start a worker pool // each worker wait on chTasks // a task is a slice of constraint indexes to be solved @@ -219,10 +215,6 @@ func (cs *SparseR1CS) parallelSolve(solution *solution, coefficientsNegInv fr.Ve go func() { for t := range chTasks { for _, i := range t { - if SolveSequentially { - m.Lock() - } - //fmt.Println("solving constraint", i) // for each constraint in the task, solve it. if err := cs.solveConstraint(cs.Constraints[i], solution, coefficientsNegInv); err != nil { chError <- &UnsatisfiedConstraintError{CID: i, Err: err} @@ -239,9 +231,6 @@ func (cs *SparseR1CS) parallelSolve(solution *solution, coefficientsNegInv fr.Ve wg.Done() return } - if SolveSequentially { - m.Unlock() - } } wg.Done() } @@ -369,7 +358,7 @@ func (cs *SparseR1CS) computeHints(c constraint.SparseR1C, solution *solution) ( // if it doesn't, then this function returns and does nothing func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution, coefficientsNegInv fr.Vector) error { - if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. + if c.Commitment == constraint.COMMITTED { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time } diff --git a/constraint/bw6-633/r1cs_sparse.go b/constraint/bw6-633/r1cs_sparse.go index 0469239489..a05dcca6f0 100644 --- a/constraint/bw6-633/r1cs_sparse.go +++ b/constraint/bw6-633/r1cs_sparse.go @@ -358,7 +358,7 @@ func (cs *SparseR1CS) computeHints(c constraint.SparseR1C, solution *solution) ( // if it doesn't, then this function returns and does nothing func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution, coefficientsNegInv fr.Vector) error { - if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. + if c.Commitment == constraint.COMMITTED { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time } diff --git a/constraint/bw6-761/r1cs_sparse.go b/constraint/bw6-761/r1cs_sparse.go index 161e8a4f8d..a20aa0d35b 100644 --- a/constraint/bw6-761/r1cs_sparse.go +++ b/constraint/bw6-761/r1cs_sparse.go @@ -358,7 +358,7 @@ func (cs *SparseR1CS) computeHints(c constraint.SparseR1C, solution *solution) ( // if it doesn't, then this function returns and does nothing func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution, coefficientsNegInv fr.Vector) error { - if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. + if c.Commitment == constraint.COMMITTED { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time } diff --git a/constraint/tinyfield/r1cs_sparse.go b/constraint/tinyfield/r1cs_sparse.go index 243ec50364..cd7ff1de1c 100644 --- a/constraint/tinyfield/r1cs_sparse.go +++ b/constraint/tinyfield/r1cs_sparse.go @@ -358,7 +358,7 @@ func (cs *SparseR1CS) computeHints(c constraint.SparseR1C, solution *solution) ( // if it doesn't, then this function returns and does nothing func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution, coefficientsNegInv fr.Vector) error { - if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. + if c.Commitment == constraint.COMMITTED { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time } diff --git a/internal/generator/backend/template/representations/r1cs.sparse.go.tmpl b/internal/generator/backend/template/representations/r1cs.sparse.go.tmpl index 004bd40a36..54553702c1 100644 --- a/internal/generator/backend/template/representations/r1cs.sparse.go.tmpl +++ b/internal/generator/backend/template/representations/r1cs.sparse.go.tmpl @@ -348,7 +348,7 @@ func (cs *SparseR1CS) computeHints(c constraint.SparseR1C, solution *solution) ( // if it doesn't, then this function returns and does nothing func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution, coefficientsNegInv fr.Vector) error { - if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. + if c.Commitment == constraint.COMMITTED { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time } diff --git a/std/math/emulated/element_test.go b/std/math/emulated/element_test.go index 03db64f3e4..526f14e0d2 100644 --- a/std/math/emulated/element_test.go +++ b/std/math/emulated/element_test.go @@ -3,7 +3,6 @@ package emulated import ( "crypto/rand" "fmt" - cs "github.com/consensys/gnark/constraint/bn254" "math/big" "reflect" "testing" @@ -38,14 +37,8 @@ func testName[T FieldParams]() string { func TestAssertLimbEqualityNoOverflow(t *testing.T) { testAssertLimbEqualityNoOverflow[Goldilocks](t) - //testAssertLimbEqualityNoOverflow[Secp256k1Fp](t) - //testAssertLimbEqualityNoOverflow[BN254Fp](t) -} - -func TestAssertLimbEqualityNoOverflowSequential(t *testing.T) { - cs.SolveSequentially = true - testAssertLimbEqualityNoOverflow[Goldilocks](t) - cs.SolveSequentially = false + testAssertLimbEqualityNoOverflow[Secp256k1Fp](t) + testAssertLimbEqualityNoOverflow[BN254Fp](t) } func testAssertLimbEqualityNoOverflow[T FieldParams](t *testing.T) { From 381a76094f810dfb3f57a427b78364fa921b3394 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 24 Mar 2023 11:12:11 -0400 Subject: [PATCH 201/464] fix: use frontend.Committer properly --- frontend/api.go | 1 - test/commitments_test.go | 7 ++++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/frontend/api.go b/frontend/api.go index 3e7e97c475..a54e2ec3c0 100644 --- a/frontend/api.go +++ b/frontend/api.go @@ -24,7 +24,6 @@ import ( // API represents the available functions to circuit developers type API interface { - Committer // TODO: Remove and find out how we're supposed to call api.Commit now // --------------------------------------------------------------------------------------------- // Arithmetic diff --git a/test/commitments_test.go b/test/commitments_test.go index 4b1f5a3486..ca9de731ec 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -1,6 +1,7 @@ package test import ( + "fmt" "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/scs" @@ -17,7 +18,11 @@ type commitmentCircuit struct { } func (c *commitmentCircuit) Define(api frontend.API) error { - commitment, err := api.Commit(c.X...) + committer, ok := api.(frontend.Committer) + if !ok { + return fmt.Errorf("type %T doesn't impl the Committer interface", api) + } + commitment, err := committer.Commit(c.X...) if err == nil { api.AssertIsDifferent(commitment, 0) } From 59b52db5f2fdcf205ef74da3d02982591f192971 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 24 Mar 2023 11:13:57 -0400 Subject: [PATCH 202/464] doc: explain committed constraint --- frontend/cs/scs/api.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontend/cs/scs/api.go b/frontend/cs/scs/api.go index b8bf9b0cf9..27bf10de2b 100644 --- a/frontend/cs/scs/api.go +++ b/frontend/cs/scs/api.go @@ -575,6 +575,8 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error } commitmentVar := builder.Neg(outs[0]).(expr.Term) commitmentConstraintIndex := builder.cs.GetNbConstraints() + // a constraint to enforce consistency between the commitment and committed value + // - v + comm(n) = 0 builder.addPlonkConstraint(sparseR1C{xa: commitmentVar.VID, qL: commitmentVar.Coeff, commitment: constraint.COMMITMENT}) // value will be injected later return outs[0], builder.cs.AddCommitment(constraint.Commitment{ From 5dd397fafc91f3942c31b96a7cf12af31123ab29 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 24 Mar 2023 13:04:51 -0400 Subject: [PATCH 203/464] fix: filter constants --- frontend/cs/scs/api.go | 12 ++++++++++ test/commitments_test.go | 49 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/frontend/cs/scs/api.go b/frontend/cs/scs/api.go index 27bf10de2b..e30399aa8c 100644 --- a/frontend/cs/scs/api.go +++ b/frontend/cs/scs/api.go @@ -562,6 +562,8 @@ func (builder *builder) Compiler() frontend.Compiler { func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error) { + v = filterConstants(v) // TODO: @Tabaie Settle on a way to represent even constants; conventional hash? + committed := make([]int, len(v)) for i, vI := range v { // TODO @Tabaie Perf; If public, just hash it @@ -586,6 +588,16 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error }) } +func filterConstants(v []frontend.Variable) []frontend.Variable { + res := make([]frontend.Variable, 0, len(v)) + for _, vI := range v { + if _, ok := vI.(expr.Term); ok { + res = append(res, vI) + } + } + return res +} + func (*builder) FrontendType() frontendtype.Type { return frontendtype.SCS } diff --git a/test/commitments_test.go b/test/commitments_test.go index ca9de731ec..79ea57da44 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -18,11 +18,8 @@ type commitmentCircuit struct { } func (c *commitmentCircuit) Define(api frontend.API) error { - committer, ok := api.(frontend.Committer) - if !ok { - return fmt.Errorf("type %T doesn't impl the Committer interface", api) - } - commitment, err := committer.Commit(c.X...) + + commitment, err := tryCommit(api, c.X...) if err == nil { api.AssertIsDifferent(commitment, 0) } @@ -112,3 +109,45 @@ func plonkTest(t *testing.T, circuit, assignment frontend.Circuit) { t.Run(id.String(), run(id.ScalarField())) } } + +type committedConstantCircuit struct { + X frontend.Variable +} + +func (c *committedConstantCircuit) Define(api frontend.API) error { + commitment, err := tryCommit(api, 1) + if err != nil { + return err + } + api.AssertIsDifferent(commitment, c.X) + return nil +} + +func TestCommittedConstant(t *testing.T) { + plonkTest(t, &committedConstantCircuit{}, &committedConstantCircuit{1}) +} + +type committedPublicCircuit struct { + X frontend.Variable `gnark:",public"` +} + +func (c *committedPublicCircuit) Define(api frontend.API) error { + commitment, err := tryCommit(api, c.X) + if err != nil { + return err + } + api.AssertIsDifferent(commitment, c.X) + return nil +} + +func TestCommittedPublic(t *testing.T) { + plonkTest(t, &committedPublicCircuit{}, &committedPublicCircuit{1}) +} + +func tryCommit(api frontend.API, x ...frontend.Variable) (frontend.Variable, error) { + committer, ok := api.(frontend.Committer) + if !ok { + return nil, fmt.Errorf("type %T doesn't impl the Committer interface", api) + } + return committer.Commit(x...) +} From 706ce29d2a6c3212dc9cc3134af73b07de0a2b1a Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 24 Mar 2023 13:08:14 -0400 Subject: [PATCH 204/464] doc: explain commitment constraint --- frontend/cs/scs/api.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frontend/cs/scs/api.go b/frontend/cs/scs/api.go index e30399aa8c..f2e67b3cfe 100644 --- a/frontend/cs/scs/api.go +++ b/frontend/cs/scs/api.go @@ -569,6 +569,8 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error for i, vI := range v { // TODO @Tabaie Perf; If public, just hash it vINeg := builder.Neg(vI).(expr.Term) committed[i] = builder.cs.GetNbConstraints() + // a constraint to enforce consistency between the commitment and committed value + // - v + comm(n) = 0 builder.addPlonkConstraint(sparseR1C{xa: vINeg.VID, qL: vINeg.Coeff, commitment: constraint.COMMITTED}) } outs, err := builder.NewHint(cs.Bsb22CommitmentComputePlaceholder, 1, v...) @@ -577,8 +579,7 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error } commitmentVar := builder.Neg(outs[0]).(expr.Term) commitmentConstraintIndex := builder.cs.GetNbConstraints() - // a constraint to enforce consistency between the commitment and committed value - // - v + comm(n) = 0 + // RHS will be provided by both prover and verifier independently, as for a public wire builder.addPlonkConstraint(sparseR1C{xa: commitmentVar.VID, qL: commitmentVar.Coeff, commitment: constraint.COMMITMENT}) // value will be injected later return outs[0], builder.cs.AddCommitment(constraint.Commitment{ From 843447da930b48dd8d939d6df1b18fd9977135b9 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 24 Mar 2023 16:20:35 -0400 Subject: [PATCH 205/464] build: update stats --- internal/stats/latest.stats | Bin 2803 -> 2803 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/internal/stats/latest.stats b/internal/stats/latest.stats index 1afedc740b579076c7016131b1b1d627eeb2846e..b7d8ec2a89a11baee3905b98988693d0543bf5a8 100644 GIT binary patch delta 195 zcmew?`dM^B*5nkn*2!|r4<>tYJed5LAI=lg~3gn0%Y#;p86X%=+>w#(!o17#RQIVFdqT{1-eAs3ztX5SJkoGjQP5 J2R9P80RS;?TZI4s From 80fb56210803ff929972a20dc9f6a04bd102ef7e Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 28 Mar 2023 18:48:50 -0500 Subject: [PATCH 206/464] fix: don't set comm to 0; it might be inverted --- frontend/cs/commitment.go | 15 ++++++++++++--- frontend/cs/r1cs/api.go | 2 +- std/math/emulated/element_test.go | 2 +- test/commitments_test.go | 13 ++++++++++--- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/frontend/cs/commitment.go b/frontend/cs/commitment.go index f0d26b96e7..04c954a6b9 100644 --- a/frontend/cs/commitment.go +++ b/frontend/cs/commitment.go @@ -1,6 +1,7 @@ package cs import ( + "crypto/sha256" "fmt" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/debug" @@ -10,12 +11,20 @@ import ( "strings" ) -func Bsb22CommitmentComputePlaceholder(_ *big.Int, _ []*big.Int, output []*big.Int) error { +func Bsb22CommitmentComputePlaceholder(mod *big.Int, input []*big.Int, output []*big.Int) error { if (len(os.Args) > 0 && (strings.HasSuffix(os.Args[0], ".test") || strings.HasSuffix(os.Args[0], ".test.exe"))) || debug.Debug { // usually we only run solver without prover during testing log := logger.Logger() - log.Error().Msg("Augmented groth16 commitment hint not replaced. Proof will not be sound!") - output[0].SetInt64(0) + log.Error().Msg("Augmented groth16 commitment hint not replaced. Proof will not be sound and verification will fail!") + toHash := make([]byte, 0, (1+mod.BitLen()/8)*len(input)) + for _, in := range input { + inBytes := in.Bytes() + toHash = append(toHash, inBytes[:]...) + } + hsh := sha256.New().Sum(toHash) + output[0].SetBytes(hsh) + output[0].Mod(output[0], mod) + return nil } return fmt.Errorf("placeholder function: to be replaced by commitment computation") diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index 3f182b3539..84e86052fe 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -670,7 +670,7 @@ func (builder *builder) Compiler() frontend.Compiler { } func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error) { - // we want to build a sorted slice of commited variables, without duplicates + // we want to build a sorted slice of committed variables, without duplicates // this is the same algorithm as builder.add(...); but we expect len(v) to be quite large. vars, s := builder.toVariables(v...) diff --git a/std/math/emulated/element_test.go b/std/math/emulated/element_test.go index 526f14e0d2..aa7d5f8cd7 100644 --- a/std/math/emulated/element_test.go +++ b/std/math/emulated/element_test.go @@ -49,7 +49,7 @@ func testAssertLimbEqualityNoOverflow[T FieldParams](t *testing.T) { val, _ := rand.Int(rand.Reader, fp.Modulus()) witness.A = ValueOf[T](val) witness.B = ValueOf[T](val) - assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends( /*backend.GROTH16,*/ backend.PLONK)) + assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } diff --git a/test/commitments_test.go b/test/commitments_test.go index 79ea57da44..49f77329fe 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -3,6 +3,7 @@ package test import ( "fmt" "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/backend" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/scs" "github.com/stretchr/testify/assert" @@ -20,9 +21,10 @@ type commitmentCircuit struct { func (c *commitmentCircuit) Define(api frontend.API) error { commitment, err := tryCommit(api, c.X...) - if err == nil { - api.AssertIsDifferent(commitment, 0) + if err != nil { + return err } + api.AssertIsDifferent(commitment, c.X[0]) for _, p := range c.Public { api.AssertIsDifferent(p, 0) } @@ -38,6 +40,11 @@ func TestSingleCommitmentPlonk(t *testing.T) { plonkTest(t, assignment.hollow(), assignment) } +func TestSingleCommitmentFuzzer(t *testing.T) { + assignment := &commitmentCircuit{X: []frontend.Variable{1}, Public: []frontend.Variable{}} + NewAssert(t).ProverSucceeded(assignment.hollow(), assignment, WithCurves(ecc.BN254), WithBackends(backend.GROTH16)) // TODO: Make generic +} + func TestFiveCommitmentsPlonk(t *testing.T) { assignment := &commitmentCircuit{X: []frontend.Variable{1, 2, 3, 4, 5}, Public: []frontend.Variable{}} plonkTest(t, assignment.hollow(), assignment) @@ -115,7 +122,7 @@ type committedConstantCircuit struct { } func (c *committedConstantCircuit) Define(api frontend.API) error { - commitment, err := tryCommit(api, 1) + commitment, err := tryCommit(api, 1, c.X) if err != nil { return err } From b69c6c9e2ea5280ae50be6997d92d07b79773d0f Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Wed, 29 Mar 2023 18:26:20 +0200 Subject: [PATCH 207/464] feat: isZero in field emulation (#609) * feat: store p-1 * feat: implement comparison methods * docs: emphasize that compare non-reduce * fix: emulated equality bitsplit padding * fix: split consts manually to bits * fix: failing prover should use full witness * test: assertInRange and IsZero * chore: comment emulated Cmp impl * chore: remove irrelevant comment --- std/math/emulated/element_test.go | 76 +++++++++++++++++++++++++++++++ std/math/emulated/field.go | 22 ++++++--- std/math/emulated/field_assert.go | 65 +++++++++++++++++++++++++- std/math/emulated/field_binary.go | 7 ++- std/math/emulated/field_ops.go | 1 - test/assert.go | 4 +- 6 files changed, 162 insertions(+), 13 deletions(-) diff --git a/std/math/emulated/element_test.go b/std/math/emulated/element_test.go index aa7d5f8cd7..61842df893 100644 --- a/std/math/emulated/element_test.go +++ b/std/math/emulated/element_test.go @@ -800,3 +800,79 @@ func TestIssue348UnconstrainedLimbs(t *testing.T) { // inputs. assert.Error(err) } + +type AssertInRangeCircuit[T FieldParams] struct { + X Element[T] +} + +func (c *AssertInRangeCircuit[T]) Define(api frontend.API) error { + f, err := NewField[T](api) + if err != nil { + return err + } + f.AssertIsInRange(&c.X) + return nil +} + +func TestAssertInRange(t *testing.T) { + testAssertIsInRange[Goldilocks](t) + testAssertIsInRange[Secp256k1Fp](t) + testAssertIsInRange[BN254Fp](t) +} + +func testAssertIsInRange[T FieldParams](t *testing.T) { + var fp T + assert := test.NewAssert(t) + assert.Run(func(assert *test.Assert) { + X, _ := rand.Int(rand.Reader, fp.Modulus()) + circuit := AssertInRangeCircuit[T]{} + witness := AssertInRangeCircuit[T]{X: ValueOf[T](X)} + assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) + witness2 := AssertInRangeCircuit[T]{X: ValueOf[T](0)} + t := 0 + for i := 0; i < int(fp.NbLimbs())-1; i++ { + L := new(big.Int).Lsh(big.NewInt(1), fp.BitsPerLimb()) + L.Sub(L, big.NewInt(1)) + witness2.X.Limbs[i] = L + t += int(fp.BitsPerLimb()) + } + highlimb := fp.Modulus().BitLen() - t + L := new(big.Int).Lsh(big.NewInt(1), uint(highlimb)) + L.Sub(L, big.NewInt(1)) + witness2.X.Limbs[fp.NbLimbs()-1] = L + assert.ProverFailed(&circuit, &witness2, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) + }, testName[T]()) +} + +type IsZeroCircuit[T FieldParams] struct { + X, Y Element[T] + Zero frontend.Variable +} + +func (c *IsZeroCircuit[T]) Define(api frontend.API) error { + f, err := NewField[T](api) + if err != nil { + return err + } + R := f.Add(&c.X, &c.Y) + api.AssertIsEqual(c.Zero, f.IsZero(R)) + return nil +} + +func TestIsZero(t *testing.T) { + testIsZero[Goldilocks](t) + testIsZero[Secp256k1Fp](t) + testIsZero[BN254Fp](t) +} + +func testIsZero[T FieldParams](t *testing.T) { + var fp T + assert := test.NewAssert(t) + assert.Run(func(assert *test.Assert) { + X, _ := rand.Int(rand.Reader, fp.Modulus()) + Y := new(big.Int).Sub(fp.Modulus(), X) + circuit := IsZeroCircuit[T]{} + assert.ProverSucceeded(&circuit, &IsZeroCircuit[T]{X: ValueOf[T](X), Y: ValueOf[T](Y), Zero: 1}, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) + assert.ProverSucceeded(&circuit, &IsZeroCircuit[T]{X: ValueOf[T](X), Y: ValueOf[T](0), Zero: 0}, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) + }, testName[T]()) +} diff --git a/std/math/emulated/field.go b/std/math/emulated/field.go index 240638d161..9be78f0afc 100644 --- a/std/math/emulated/field.go +++ b/std/math/emulated/field.go @@ -29,12 +29,14 @@ type Field[T FieldParams] struct { maxOfOnce sync.Once // constants for often used elements n, 0 and 1. Allocated only once - nConstOnce sync.Once - nConst *Element[T] - zeroConstOnce sync.Once - zeroConst *Element[T] - oneConstOnce sync.Once - oneConst *Element[T] + nConstOnce sync.Once + nConst *Element[T] + nprevConstOnce sync.Once + nprevConst *Element[T] + zeroConstOnce sync.Once + zeroConst *Element[T] + oneConstOnce sync.Once + oneConst *Element[T] log zerolog.Logger @@ -142,6 +144,14 @@ func (f *Field[T]) Modulus() *Element[T] { return f.nConst } +// modulusPrev returns modulus-1 as a constant. +func (f *Field[T]) modulusPrev() *Element[T] { + f.nprevConstOnce.Do(func() { + f.nprevConst = newConstElement[T](new(big.Int).Sub(f.fParams.Modulus(), big.NewInt(1))) + }) + return f.nprevConst +} + // packLimbs returns an element from the given limbs. // If strict is true, the most significant limb will be constrained to have width of the most // significant limb of the modulus, which may have less bits than the other limbs. In which case, diff --git a/std/math/emulated/field_assert.go b/std/math/emulated/field_assert.go index f988a7fcf0..2a02715900 100644 --- a/std/math/emulated/field_assert.go +++ b/std/math/emulated/field_assert.go @@ -144,7 +144,9 @@ func (f *Field[T]) AssertIsEqual(a, b *Element[T]) { f.AssertLimbsEquality(diff, kp) } -// AssertIsLessOrEqual ensures that e is less or equal than a. +// AssertIsLessOrEqual ensures that e is less or equal than a. For proper +// bitwise comparison first reduce the element using [Reduce] and then assert +// that its value is less than the modulus using [AssertIsInRange]. func (f *Field[T]) AssertIsLessOrEqual(e, a *Element[T]) { // we omit conditional width assertion as is done in ToBits below if e.overflow+a.overflow > 0 { @@ -155,7 +157,7 @@ func (f *Field[T]) AssertIsLessOrEqual(e, a *Element[T]) { ff := func(xbits, ybits []frontend.Variable) []frontend.Variable { diff := len(xbits) - len(ybits) ybits = append(ybits, make([]frontend.Variable, diff)...) - for i := len(ybits) - diff - 1; i < len(ybits); i++ { + for i := len(ybits) - diff; i < len(ybits); i++ { ybits[i] = 0 } return ybits @@ -176,3 +178,62 @@ func (f *Field[T]) AssertIsLessOrEqual(e, a *Element[T]) { f.api.AssertIsEqual(ll, 0) } } + +// AssertIsInRange ensures that a is less than the emulated modulus. When we +// call [Reduce] then we only ensure that the result is width-constrained, but +// not actually less than the modulus. This means that the actual value may be +// either x or x + p. For arithmetic it is sufficient, but for binary comparison +// it is not. For binary comparison the values have both to be below the +// modulus. +func (f *Field[T]) AssertIsInRange(a *Element[T]) { + // we omit conditional width assertion as is done in ToBits down the calling stack + f.AssertIsLessOrEqual(a, f.modulusPrev()) +} + +// IsZero returns a boolean indicating if the element is strictly zero. The +// method internally reduces the element and asserts that the value is less than +// the modulus. +func (f *Field[T]) IsZero(a *Element[T]) frontend.Variable { + ca := f.Reduce(a) + f.AssertIsInRange(ca) + res := f.api.IsZero(ca.Limbs[0]) + for i := 1; i < len(ca.Limbs); i++ { + f.api.Mul(res, f.api.IsZero(ca.Limbs[i])) + } + return res +} + +// // Cmp returns: +// // - -1 if a < b +// // - 0 if a = b +// // - 1 if a > b +// // +// // The method internally reduces the element and asserts that the value is less +// // than the modulus. +// func (f *Field[T]) Cmp(a, b *Element[T]) frontend.Variable { +// ca := f.Reduce(a) +// f.AssertIsInRange(ca) +// cb := f.Reduce(b) +// f.AssertIsInRange(cb) +// var res frontend.Variable = 0 +// for i := int(f.fParams.NbLimbs() - 1); i >= 0; i-- { +// lmbCmp := f.api.Cmp(ca.Limbs[i], cb.Limbs[i]) +// res = f.api.Select(f.api.IsZero(res), lmbCmp, res) +// } +// return res +// } + +// TODO(@ivokub) +// func (f *Field[T]) AssertIsDifferent(a, b *Element[T]) { +// ca := f.Reduce(a) +// f.AssertIsInRange(ca) +// cb := f.Reduce(b) +// f.AssertIsInRange(cb) +// var res frontend.Variable = 0 +// for i := 0; i < int(f.fParams.NbLimbs()); i++ { +// cmp := f.api.Cmp(ca.Limbs[i], cb.Limbs[i]) +// cmpsq := f.api.Mul(cmp, cmp) +// res = f.api.Add(res, cmpsq) +// } +// f.api.AssertIsDifferent(res, 0) +// } diff --git a/std/math/emulated/field_binary.go b/std/math/emulated/field_binary.go index 213f1654c2..3088bd0be0 100644 --- a/std/math/emulated/field_binary.go +++ b/std/math/emulated/field_binary.go @@ -14,7 +14,12 @@ func (f *Field[T]) ToBits(a *Element[T]) []frontend.Variable { f.enforceWidthConditional(a) ba, aConst := f.constantValue(a) if aConst { - return f.api.ToBinary(ba, int(f.fParams.BitsPerLimb()*f.fParams.NbLimbs())) + ba.Mod(ba, f.fParams.Modulus()) + res := make([]frontend.Variable, f.fParams.BitsPerLimb()*f.fParams.NbLimbs()) + for i := range res { + res[i] = ba.Bit(i) + } + return res } var carry frontend.Variable = 0 var fullBits []frontend.Variable diff --git a/std/math/emulated/field_ops.go b/std/math/emulated/field_ops.go index 228106bcbf..31739cf716 100644 --- a/std/math/emulated/field_ops.go +++ b/std/math/emulated/field_ops.go @@ -214,7 +214,6 @@ func (f *Field[T]) Reduce(a *Element[T]) *Element[T] { if err != nil { panic(fmt.Sprintf("reduction hint: %v", err)) } - // TODO @gbotrel fixme: AssertIsEqual(a, e) crashes Pairing test f.AssertIsEqual(e, a) return e } diff --git a/test/assert.go b/test/assert.go index 0c916ee88d..4f1581b14d 100644 --- a/test/assert.go +++ b/test/assert.go @@ -213,8 +213,6 @@ func (assert *Assert) ProverFailed(circuit frontend.Circuit, invalidAssignment f // parse assignment invalidWitness, err := frontend.NewWitness(invalidAssignment, curve.ScalarField()) assert.NoError(err, "can't parse invalid assignment") - invalidPublicWitness, err := frontend.NewWitness(invalidAssignment, curve.ScalarField(), frontend.PublicOnly()) - assert.NoError(err, "can't parse invalid assignment") for _, b := range opt.backends { curve := curve @@ -233,7 +231,7 @@ func (assert *Assert) ProverFailed(circuit frontend.Circuit, invalidAssignment f mustError(err) assert.t.Parallel() - err = ccs.IsSolved(invalidPublicWitness) + err = ccs.IsSolved(invalidWitness) mustError(err) }, curve.String(), b.String()) } From 4afeaac072cf84bd2d600f5def8df1ebd8963ac5 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Wed, 29 Mar 2023 13:23:09 -0500 Subject: [PATCH 208/464] Perf/plonkprover (#593) * perf: liop and wliop duplicate polys * perf: avoid copyiing zeroes * perf: parallelize + precompute ID iop only once * perf: parallelize + precompute ID iop only once * perf: more parallelizationn * perf: one less lagrange conversion * perf: computeLinearizedPolynomial reuse memory from blindedZCanonical * perf: more plonk parrallel stuff * perf: mark a todo for commit part without commit * build: update go.mod with correct gnark crypto * perf(plonk): lcIdIOP is manually generated * build: update to latest gnark-crypto --------- Co-authored-by: Thomas Piellard --- backend/plonk/bls12-377/prove.go | 326 +++++++++-------- backend/plonk/bls12-377/setup.go | 23 ++ backend/plonk/bls12-381/prove.go | 326 +++++++++-------- backend/plonk/bls12-381/setup.go | 23 ++ backend/plonk/bls24-315/prove.go | 326 +++++++++-------- backend/plonk/bls24-315/setup.go | 23 ++ backend/plonk/bls24-317/prove.go | 326 +++++++++-------- backend/plonk/bls24-317/setup.go | 23 ++ backend/plonk/bn254/prove.go | 326 +++++++++-------- backend/plonk/bn254/setup.go | 23 ++ backend/plonk/bw6-633/prove.go | 326 +++++++++-------- backend/plonk/bw6-633/setup.go | 23 ++ backend/plonk/bw6-761/prove.go | 326 +++++++++-------- backend/plonk/bw6-761/setup.go | 23 ++ backend/plonk/plonk_test.go | 2 +- go.mod | 5 +- go.sum | 16 +- .../zkpschemes/plonk/plonk.prove.go.tmpl | 334 +++++++++++------- .../zkpschemes/plonk/plonk.setup.go.tmpl | 23 ++ internal/tinyfield/element.go | 7 +- 20 files changed, 1711 insertions(+), 1119 deletions(-) diff --git a/backend/plonk/bls12-377/prove.go b/backend/plonk/bls12-377/prove.go index 5b4f00d77e..f07386a923 100644 --- a/backend/plonk/bls12-377/prove.go +++ b/backend/plonk/bls12-377/prove.go @@ -123,7 +123,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pi2iop := iop.NewPolynomial(&pi2, lagReg) wpi2iop = pi2iop.ShallowClone() - wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + // wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() } // query l, r, o in Lagrange basis, not blinded @@ -131,41 +131,88 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if err != nil { return nil, err } + // TODO @gbotrel deal with that conversion lazily + var lcpi2iop *iop.Polynomial + if spr.CommitmentInfo.Is() { + lcpi2iop = wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form + } else { + coeffs := make([]fr.Element, pk.Domain[1].Cardinality) + lcpi2iop = iop.NewPolynomial(&coeffs, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.Regular}) + } solution := _solution.(*cs.SparseR1CSSolution) evaluationLDomainSmall := []fr.Element(solution.L) evaluationRDomainSmall := []fr.Element(solution.R) evaluationODomainSmall := []fr.Element(solution.O) - liop := iop.NewPolynomial(&evaluationLDomainSmall, lagReg) - riop := iop.NewPolynomial(&evaluationRDomainSmall, lagReg) - oiop := iop.NewPolynomial(&evaluationODomainSmall, lagReg) - wliop := liop.ShallowClone() - wriop := riop.ShallowClone() - woiop := oiop.ShallowClone() - wliop.ToCanonical(&pk.Domain[0]).ToRegular() - wriop.ToCanonical(&pk.Domain[0]).ToRegular() - woiop.ToCanonical(&pk.Domain[0]).ToRegular() - - // Blind l, r, o before committing - // we set the underlying slice capacity to domain[1].Cardinality to minimize mem moves. - bwliop := wliop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) - bwriop := wriop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) - bwoiop := woiop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) - if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Vk.KZGSRS); err != nil { - return nil, err - } + // l, r o and blinded versions + var ( + wliop, + wriop, + woiop, + bwliop, + bwriop, + bwoiop *iop.Polynomial + ) + var wgLRO sync.WaitGroup + wgLRO.Add(3) + go func() { + // we keep in lagrange regular form since iop.BuildRatioCopyConstraint prefers it in this form. + wliop = iop.NewPolynomial(&evaluationLDomainSmall, lagReg) + // we set the underlying slice capacity to domain[1].Cardinality to minimize mem moves. + bwliop = wliop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) + wgLRO.Done() + }() + go func() { + wriop = iop.NewPolynomial(&evaluationRDomainSmall, lagReg) + bwriop = wriop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) + wgLRO.Done() + }() + go func() { + woiop = iop.NewPolynomial(&evaluationODomainSmall, lagReg) + bwoiop = woiop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) + wgLRO.Done() + }() fw, ok := fullWitness.Vector().(fr.Vector) if !ok { return nil, witness.ErrInvalidWitness } + // start computing lcqk + var lcqk *iop.Polynomial + chLcqk := make(chan struct{}, 1) + go func() { + // compute qk in canonical basis, completed with the public inputs + // We copy the coeffs of qk to pk is not mutated + lqkcoef := pk.lQk.Coefficients() + qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) + copy(qkCompletedCanonical, fw[:len(spr.Public)]) + copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) + if spr.CommitmentInfo.Is() { + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal + } + pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) + fft.BitReverse(qkCompletedCanonical) + + canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} + lcqk = iop.NewPolynomial(&qkCompletedCanonical, canReg) + lcqk.ToLagrangeCoset(&pk.Domain[1]) + close(chLcqk) + }() + // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.PI2); err != nil { return nil, err } + + // wait for polys to be blinded + wgLRO.Wait() + if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Vk.KZGSRS); err != nil { + return nil, err + } + gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) // TODO @Tabaie @ThomasPiellard add BSB commitment here? if err != nil { return nil, err @@ -179,15 +226,28 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts var beta fr.Element beta.SetBytes(bbeta) + // l, r, o are already blinded + wgLRO.Add(3) + go func() { + bwliop.ToLagrangeCoset(&pk.Domain[1]) + wgLRO.Done() + }() + go func() { + bwriop.ToLagrangeCoset(&pk.Domain[1]) + wgLRO.Done() + }() + go func() { + bwoiop.ToLagrangeCoset(&pk.Domain[1]) + wgLRO.Done() + }() + // compute the copy constraint's ratio - // We copy liop, riop, oiop because they are fft'ed in the process. - // We could have not copied them at the cost of doing one more bit reverse - // per poly... + // note that wliop, wriop and woiop are fft'ed (mutated) in the process. ziop, err := iop.BuildRatioCopyConstraint( []*iop.Polynomial{ - liop.Clone(), - riop.Clone(), - oiop.Clone(), + wliop, + wriop, + woiop, }, pk.trace.S, beta, @@ -200,63 +260,29 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // commit to the blinded version of z - bwziop := ziop // iop.NewWrappedPolynomial(&ziop) - bwziop.Blind(2) - proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Vk.KZGSRS, runtime.NumCPU()*2) - if err != nil { - return proof, err - } - - // derive alpha from the Comm(l), Comm(r), Comm(o), Com(Z) - alpha, err := deriveRandomness(&fs, "alpha", &proof.Z) - if err != nil { - return proof, err - } + chZ := make(chan error, 1) + var bwziop, bwsziop *iop.Polynomial + var alpha fr.Element + go func() { + bwziop = ziop // iop.NewWrappedPolynomial(&ziop) + bwziop.Blind(2) + proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Vk.KZGSRS, runtime.NumCPU()*2) + if err != nil { + chZ <- err + } - // compute qk in canonical basis, completed with the public inputs - // We copy the coeffs of qk to pk is not mutated - lqkcoef := pk.lQk.Coefficients() - qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) - copy(qkCompletedCanonical, lqkcoef) - copy(qkCompletedCanonical, fw[:len(spr.Public)]) - if spr.CommitmentInfo.Is() { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal - } - pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) - fft.BitReverse(qkCompletedCanonical) + // derive alpha from the Comm(l), Comm(r), Comm(o), Com(Z) + alpha, err = deriveRandomness(&fs, "alpha", &proof.Z) + if err != nil { + chZ <- err + } - // l, r, o are already blinded - bwliop.ToLagrangeCoset(&pk.Domain[1]) - bwriop.ToLagrangeCoset(&pk.Domain[1]) - bwoiop.ToLagrangeCoset(&pk.Domain[1]) - pi2iop := wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form - - // we don't mutate so no need to clone the coefficients from the proving key. - canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} - lcqk := iop.NewPolynomial(&qkCompletedCanonical, canReg) - lcqk.ToLagrangeCoset(&pk.Domain[1]) - - // storing Id - id := make([]fr.Element, pk.Domain[1].Cardinality) - id[1].SetOne() - widiop := iop.NewPolynomial(&id, canReg) - widiop.ToLagrangeCoset(&pk.Domain[1]) - - // Store z(g*x), without reallocating a slice - bwsziop := bwziop.ShallowClone().Shift(1) - bwsziop.ToLagrangeCoset(&pk.Domain[1]) - - // L_{g^{0}} - cap := pk.Domain[1].Cardinality - if cap < pk.Domain[0].Cardinality { - cap = pk.Domain[0].Cardinality // sanity check - } - lone := make([]fr.Element, pk.Domain[0].Cardinality, cap) - lone[0].SetOne() - loneiop := iop.NewPolynomial(&lone, lagReg) - wloneiop := loneiop.ToCanonical(&pk.Domain[0]). - ToRegular(). - ToLagrangeCoset(&pk.Domain[1]) + // Store z(g*x), without reallocating a slice + bwsziop = bwziop.ShallowClone().Shift(1) + bwsziop.ToLagrangeCoset(&pk.Domain[1]) + chZ <- nil + close(chZ) + }() // Full capture using latest gnark crypto... fic := func(fql, fqr, fqm, fqo, fqk, fqCPrime, l, r, o, pi2 fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary @@ -277,15 +303,14 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } fo := func(l, r, o, fid, fs1, fs2, fs3, fz, fzs fr.Element) fr.Element { - var uu fr.Element - u := pk.Domain[0].FrMultiplicativeGen - uu.Mul(&u, &u) - + u := &pk.Domain[0].FrMultiplicativeGen var a, b, tmp fr.Element - a.Mul(&beta, &fid).Add(&a, &l).Add(&a, &gamma) - tmp.Mul(&beta, &u).Mul(&tmp, &fid).Add(&tmp, &r).Add(&tmp, &gamma) + b.Mul(&beta, &fid) + a.Add(&b, &l).Add(&a, &gamma) + b.Mul(&b, u) + tmp.Add(&b, &r).Add(&tmp, &gamma) a.Mul(&a, &tmp) - tmp.Mul(&beta, &uu).Mul(&tmp, &fid).Add(&tmp, &o).Add(&tmp, &gamma) + tmp.Mul(&b, u).Add(&tmp, &o).Add(&tmp, &gamma) a.Mul(&a, &tmp).Mul(&a, &fz) b.Mul(&beta, &fs1).Add(&b, &l).Add(&b, &gamma) @@ -317,28 +342,47 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return c } + + // wait for lcqk + <-chLcqk + + // wait for Z part + if err := <-chZ; err != nil { + return proof, err + } + + // wait for l, r o lagrange coset conversion + wgLRO.Wait() + systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, bwliop, bwriop, bwoiop, - widiop, + pk.lcIdIOP, pk.lcS1, pk.lcS2, pk.lcS3, bwziop, bwsziop, - pi2iop, + lcpi2iop, pk.lcQl, pk.lcQr, pk.lcQm, pk.lcQo, lcqk, pk.lcQcp, - wloneiop, + pk.lLoneIOP, ) if err != nil { return nil, err } + // open blinded Z at zeta*z + chbwzIOP := make(chan struct{}, 1) + go func() { + bwziop.ToCanonical(&pk.Domain[1]).ToRegular() + close(chbwzIOP) + }() + h, err := iop.DivideByXMinusOne(systemEvaluation, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) // TODO Rename to DivideByXNMinusOne or DivideByVanishingPoly etc if err != nil { return nil, err @@ -377,10 +421,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wgEvals.Done() }() - // open blinded Z at zeta*z - bwziop.ToCanonical(&pk.Domain[1]).ToRegular() var zetaShifted fr.Element zetaShifted.Mul(&zeta, &pk.Vk.Generator) + <-chbwzIOP proof.ZShiftedOpening, err = kzg.Open( bwziop.Coefficients()[:bwziop.BlindedSize()], zetaShifted, @@ -390,8 +433,39 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } - // blinded z evaluated at u*zeta - bzuzeta := proof.ZShiftedOpening.ClaimedValue + // start to compute foldedH and foldedHDigest while computeLinearizedPolynomial runs. + computeFoldedH := make(chan struct{}, 1) + var foldedH []fr.Element + var foldedHDigest kzg.Digest + go func() { + // foldedHDigest = Comm(h1) + ζᵐ⁺²*Comm(h2) + ζ²⁽ᵐ⁺²⁾*Comm(h3) + var bZetaPowerm, bSize big.Int + bSize.SetUint64(pk.Domain[0].Cardinality + 2) // +2 because of the masking (h of degree 3(n+2)-1) + var zetaPowerm fr.Element + zetaPowerm.Exp(zeta, &bSize) + zetaPowerm.BigInt(&bZetaPowerm) + foldedHDigest = proof.H[2] + foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) + foldedHDigest.Add(&foldedHDigest, &proof.H[1]) // ζᵐ⁺²*Comm(h3) + foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) + foldedHDigest.Add(&foldedHDigest, &proof.H[0]) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) + Comm(h1) + + // foldedH = h1 + ζ*h2 + ζ²*h3 + foldedH = h.Coefficients()[2*(pk.Domain[0].Cardinality+2) : 3*(pk.Domain[0].Cardinality+2)] + h2 := h.Coefficients()[pk.Domain[0].Cardinality+2 : 2*(pk.Domain[0].Cardinality+2)] + h1 := h.Coefficients()[:pk.Domain[0].Cardinality+2] + utils.Parallelize(len(foldedH), func(start, end int) { + for i := start; i < end; i++ { + foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζᵐ⁺²*h3 + foldedH[i].Add(&foldedH[i], &h2[i]) // ζ^{m+2)*h3+h2 + foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζ²⁽ᵐ⁺²⁾*h3+h2*ζᵐ⁺² + foldedH[i].Add(&foldedH[i], &h1[i]) // ζ^{2(m+2)*h3+ζᵐ⁺²*h2 + h1 + } + }) + close(computeFoldedH) + }() + + wgEvals.Wait() // wait for the evaluations var ( linearizedPolynomialCanonical []fr.Element @@ -399,10 +473,12 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts errLPoly error ) - wgEvals.Wait() // wait for the evaluations + // blinded z evaluated at u*zeta + bzuzeta := proof.ZShiftedOpening.ClaimedValue // compute the linearization polynomial r at zeta // (goal: save committing separately to z, ql, qr, qm, qo, k + // note: we linearizedPolynomialCanonical reuses bwziop memory linearizedPolynomialCanonical = computeLinearizedPolynomial( blzeta, brzeta, @@ -420,37 +496,14 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // TODO this commitment is only necessary to derive the challenge, we should // be able to avoid doing it and get the challenge in another way - linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Vk.KZGSRS) - - // foldedHDigest = Comm(h1) + ζᵐ⁺²*Comm(h2) + ζ²⁽ᵐ⁺²⁾*Comm(h3) - var bZetaPowerm, bSize big.Int - bSize.SetUint64(pk.Domain[0].Cardinality + 2) // +2 because of the masking (h of degree 3(n+2)-1) - var zetaPowerm fr.Element - zetaPowerm.Exp(zeta, &bSize) - zetaPowerm.BigInt(&bZetaPowerm) - foldedHDigest := proof.H[2] - foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) - foldedHDigest.Add(&foldedHDigest, &proof.H[1]) // ζᵐ⁺²*Comm(h3) - foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) - foldedHDigest.Add(&foldedHDigest, &proof.H[0]) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) + Comm(h1) - - // foldedH = h1 + ζ*h2 + ζ²*h3 - foldedH := h.Coefficients()[2*(pk.Domain[0].Cardinality+2) : 3*(pk.Domain[0].Cardinality+2)] - h2 := h.Coefficients()[pk.Domain[0].Cardinality+2 : 2*(pk.Domain[0].Cardinality+2)] - h1 := h.Coefficients()[:pk.Domain[0].Cardinality+2] - utils.Parallelize(len(foldedH), func(start, end int) { - for i := start; i < end; i++ { - foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζᵐ⁺²*h3 - foldedH[i].Add(&foldedH[i], &h2[i]) // ζ^{m+2)*h3+h2 - foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζ²⁽ᵐ⁺²⁾*h3+h2*ζᵐ⁺² - foldedH[i].Add(&foldedH[i], &h1[i]) // ζ^{2(m+2)*h3+ζᵐ⁺²*h2 + h1 - } - }) - + linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Vk.KZGSRS, runtime.NumCPU()*2) if errLPoly != nil { return nil, errLPoly } + // wait for foldedH and foldedHDigest + <-computeFoldedH + // Batch open the first list of polynomials proof.BatchedProof, err = kzg.BatchOpenSinglePoint( [][]fr.Element{ @@ -490,7 +543,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // fills proof.LRO with kzg commits of bcl, bcr and bco func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { - n := runtime.NumCPU() / 2 + n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) @@ -516,7 +569,7 @@ func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { } func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error { - n := runtime.NumCPU() / 2 + n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) @@ -599,26 +652,23 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, Mul(&lagrangeZeta, &alpha). Mul(&lagrangeZeta, &pk.Domain[0].CardinalityInv) // (1/n)*α²*L₁(ζ) - linPol := make([]fr.Element, len(blindedZCanonical)) - copy(linPol, blindedZCanonical) - s3canonical := pk.trace.S3.Coefficients() - utils.Parallelize(len(linPol), func(start, end int) { + utils.Parallelize(len(blindedZCanonical), func(start, end int) { - var t0, t1 fr.Element + var t, t0, t1 fr.Element for i := start; i < end; i++ { - linPol[i].Mul(&linPol[i], &s2) // -Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + t.Mul(&blindedZCanonical[i], &s2) // -Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) if i < len(s3canonical) { t0.Mul(&s3canonical[i], &s1) // (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*β*s3(X) - linPol[i].Add(&linPol[i], &t0) + t.Add(&t, &t0) } - linPol[i].Mul(&linPol[i], &alpha) // α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ)) + t.Mul(&t, &alpha) // α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ)) cql := pk.trace.Ql.Coefficients() cqr := pk.trace.Qr.Coefficients() @@ -630,21 +680,21 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, t1.Mul(&cqm[i], &rl) // linPol = linPol + l(ζ)r(ζ)*Qm(X) t0.Mul(&cql[i], &lZeta) t0.Add(&t0, &t1) - linPol[i].Add(&linPol[i], &t0) // linPol = linPol + l(ζ)*Ql(X) + t.Add(&t, &t0) // linPol = linPol + l(ζ)*Ql(X) t0.Mul(&cqr[i], &rZeta) - linPol[i].Add(&linPol[i], &t0) // linPol = linPol + r(ζ)*Qr(X) + t.Add(&t, &t0) // linPol = linPol + r(ζ)*Qr(X) t0.Mul(&cqo[i], &oZeta).Add(&t0, &cqk[i]) - linPol[i].Add(&linPol[i], &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) + t.Add(&t, &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) t0.Mul(&pi2Canonical[i], &qcpZeta) - linPol[i].Add(&linPol[i], &t0) + t.Add(&t, &t0) } t0.Mul(&blindedZCanonical[i], &lagrangeZeta) - linPol[i].Add(&linPol[i], &t0) // finish the computation + blindedZCanonical[i].Add(&t, &t0) // finish the computation } }) - return linPol + return blindedZCanonical } diff --git a/backend/plonk/bls12-377/setup.go b/backend/plonk/bls12-377/setup.go index 252a127f4d..5b84129c1b 100644 --- a/backend/plonk/bls12-377/setup.go +++ b/backend/plonk/bls12-377/setup.go @@ -112,6 +112,9 @@ type ProvingKey struct { // in lagrange coset basis --> these are not serialized, but computed from S1Canonical, S2Canonical, S3Canonical once. lcS1, lcS2, lcS3 *iop.Polynomial + + // in lagrange coset basis --> not serialized id and L_{g^{0}} + lcIdIOP, lLoneIOP *iop.Polynomial } func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) { @@ -176,6 +179,26 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { pk.lcS1 = pk.trace.S1.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcS2 = pk.trace.S2.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcS3 = pk.trace.S3.Clone().ToLagrangeCoset(&pk.Domain[1]) + + // storing Id + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + id := make([]fr.Element, pk.Domain[1].Cardinality) + id[0].Set(&pk.Domain[1].FrMultiplicativeGen) + for i := 1; i < int(pk.Domain[1].Cardinality); i++ { + id[i].Mul(&id[i-1], &pk.Domain[1].Generator) + } + pk.lcIdIOP = iop.NewPolynomial(&id, lagReg) + + // L_{g^{0}} + cap := pk.Domain[1].Cardinality + if cap < pk.Domain[0].Cardinality { + cap = pk.Domain[0].Cardinality // sanity check + } + lone := make([]fr.Element, pk.Domain[0].Cardinality, cap) + lone[0].SetOne() + pk.lLoneIOP = iop.NewPolynomial(&lone, lagReg).ToCanonical(&pk.Domain[0]). + ToRegular(). + ToLagrangeCoset(&pk.Domain[1]) } // NbPublicWitness returns the expected public witness size (number of field elements) diff --git a/backend/plonk/bls12-381/prove.go b/backend/plonk/bls12-381/prove.go index 1272865ecb..61ab610fb2 100644 --- a/backend/plonk/bls12-381/prove.go +++ b/backend/plonk/bls12-381/prove.go @@ -123,7 +123,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pi2iop := iop.NewPolynomial(&pi2, lagReg) wpi2iop = pi2iop.ShallowClone() - wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + // wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() } // query l, r, o in Lagrange basis, not blinded @@ -131,41 +131,88 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if err != nil { return nil, err } + // TODO @gbotrel deal with that conversion lazily + var lcpi2iop *iop.Polynomial + if spr.CommitmentInfo.Is() { + lcpi2iop = wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form + } else { + coeffs := make([]fr.Element, pk.Domain[1].Cardinality) + lcpi2iop = iop.NewPolynomial(&coeffs, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.Regular}) + } solution := _solution.(*cs.SparseR1CSSolution) evaluationLDomainSmall := []fr.Element(solution.L) evaluationRDomainSmall := []fr.Element(solution.R) evaluationODomainSmall := []fr.Element(solution.O) - liop := iop.NewPolynomial(&evaluationLDomainSmall, lagReg) - riop := iop.NewPolynomial(&evaluationRDomainSmall, lagReg) - oiop := iop.NewPolynomial(&evaluationODomainSmall, lagReg) - wliop := liop.ShallowClone() - wriop := riop.ShallowClone() - woiop := oiop.ShallowClone() - wliop.ToCanonical(&pk.Domain[0]).ToRegular() - wriop.ToCanonical(&pk.Domain[0]).ToRegular() - woiop.ToCanonical(&pk.Domain[0]).ToRegular() - - // Blind l, r, o before committing - // we set the underlying slice capacity to domain[1].Cardinality to minimize mem moves. - bwliop := wliop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) - bwriop := wriop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) - bwoiop := woiop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) - if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Vk.KZGSRS); err != nil { - return nil, err - } + // l, r o and blinded versions + var ( + wliop, + wriop, + woiop, + bwliop, + bwriop, + bwoiop *iop.Polynomial + ) + var wgLRO sync.WaitGroup + wgLRO.Add(3) + go func() { + // we keep in lagrange regular form since iop.BuildRatioCopyConstraint prefers it in this form. + wliop = iop.NewPolynomial(&evaluationLDomainSmall, lagReg) + // we set the underlying slice capacity to domain[1].Cardinality to minimize mem moves. + bwliop = wliop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) + wgLRO.Done() + }() + go func() { + wriop = iop.NewPolynomial(&evaluationRDomainSmall, lagReg) + bwriop = wriop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) + wgLRO.Done() + }() + go func() { + woiop = iop.NewPolynomial(&evaluationODomainSmall, lagReg) + bwoiop = woiop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) + wgLRO.Done() + }() fw, ok := fullWitness.Vector().(fr.Vector) if !ok { return nil, witness.ErrInvalidWitness } + // start computing lcqk + var lcqk *iop.Polynomial + chLcqk := make(chan struct{}, 1) + go func() { + // compute qk in canonical basis, completed with the public inputs + // We copy the coeffs of qk to pk is not mutated + lqkcoef := pk.lQk.Coefficients() + qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) + copy(qkCompletedCanonical, fw[:len(spr.Public)]) + copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) + if spr.CommitmentInfo.Is() { + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal + } + pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) + fft.BitReverse(qkCompletedCanonical) + + canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} + lcqk = iop.NewPolynomial(&qkCompletedCanonical, canReg) + lcqk.ToLagrangeCoset(&pk.Domain[1]) + close(chLcqk) + }() + // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.PI2); err != nil { return nil, err } + + // wait for polys to be blinded + wgLRO.Wait() + if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Vk.KZGSRS); err != nil { + return nil, err + } + gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) // TODO @Tabaie @ThomasPiellard add BSB commitment here? if err != nil { return nil, err @@ -179,15 +226,28 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts var beta fr.Element beta.SetBytes(bbeta) + // l, r, o are already blinded + wgLRO.Add(3) + go func() { + bwliop.ToLagrangeCoset(&pk.Domain[1]) + wgLRO.Done() + }() + go func() { + bwriop.ToLagrangeCoset(&pk.Domain[1]) + wgLRO.Done() + }() + go func() { + bwoiop.ToLagrangeCoset(&pk.Domain[1]) + wgLRO.Done() + }() + // compute the copy constraint's ratio - // We copy liop, riop, oiop because they are fft'ed in the process. - // We could have not copied them at the cost of doing one more bit reverse - // per poly... + // note that wliop, wriop and woiop are fft'ed (mutated) in the process. ziop, err := iop.BuildRatioCopyConstraint( []*iop.Polynomial{ - liop.Clone(), - riop.Clone(), - oiop.Clone(), + wliop, + wriop, + woiop, }, pk.trace.S, beta, @@ -200,63 +260,29 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // commit to the blinded version of z - bwziop := ziop // iop.NewWrappedPolynomial(&ziop) - bwziop.Blind(2) - proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Vk.KZGSRS, runtime.NumCPU()*2) - if err != nil { - return proof, err - } - - // derive alpha from the Comm(l), Comm(r), Comm(o), Com(Z) - alpha, err := deriveRandomness(&fs, "alpha", &proof.Z) - if err != nil { - return proof, err - } + chZ := make(chan error, 1) + var bwziop, bwsziop *iop.Polynomial + var alpha fr.Element + go func() { + bwziop = ziop // iop.NewWrappedPolynomial(&ziop) + bwziop.Blind(2) + proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Vk.KZGSRS, runtime.NumCPU()*2) + if err != nil { + chZ <- err + } - // compute qk in canonical basis, completed with the public inputs - // We copy the coeffs of qk to pk is not mutated - lqkcoef := pk.lQk.Coefficients() - qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) - copy(qkCompletedCanonical, lqkcoef) - copy(qkCompletedCanonical, fw[:len(spr.Public)]) - if spr.CommitmentInfo.Is() { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal - } - pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) - fft.BitReverse(qkCompletedCanonical) + // derive alpha from the Comm(l), Comm(r), Comm(o), Com(Z) + alpha, err = deriveRandomness(&fs, "alpha", &proof.Z) + if err != nil { + chZ <- err + } - // l, r, o are already blinded - bwliop.ToLagrangeCoset(&pk.Domain[1]) - bwriop.ToLagrangeCoset(&pk.Domain[1]) - bwoiop.ToLagrangeCoset(&pk.Domain[1]) - pi2iop := wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form - - // we don't mutate so no need to clone the coefficients from the proving key. - canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} - lcqk := iop.NewPolynomial(&qkCompletedCanonical, canReg) - lcqk.ToLagrangeCoset(&pk.Domain[1]) - - // storing Id - id := make([]fr.Element, pk.Domain[1].Cardinality) - id[1].SetOne() - widiop := iop.NewPolynomial(&id, canReg) - widiop.ToLagrangeCoset(&pk.Domain[1]) - - // Store z(g*x), without reallocating a slice - bwsziop := bwziop.ShallowClone().Shift(1) - bwsziop.ToLagrangeCoset(&pk.Domain[1]) - - // L_{g^{0}} - cap := pk.Domain[1].Cardinality - if cap < pk.Domain[0].Cardinality { - cap = pk.Domain[0].Cardinality // sanity check - } - lone := make([]fr.Element, pk.Domain[0].Cardinality, cap) - lone[0].SetOne() - loneiop := iop.NewPolynomial(&lone, lagReg) - wloneiop := loneiop.ToCanonical(&pk.Domain[0]). - ToRegular(). - ToLagrangeCoset(&pk.Domain[1]) + // Store z(g*x), without reallocating a slice + bwsziop = bwziop.ShallowClone().Shift(1) + bwsziop.ToLagrangeCoset(&pk.Domain[1]) + chZ <- nil + close(chZ) + }() // Full capture using latest gnark crypto... fic := func(fql, fqr, fqm, fqo, fqk, fqCPrime, l, r, o, pi2 fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary @@ -277,15 +303,14 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } fo := func(l, r, o, fid, fs1, fs2, fs3, fz, fzs fr.Element) fr.Element { - var uu fr.Element - u := pk.Domain[0].FrMultiplicativeGen - uu.Mul(&u, &u) - + u := &pk.Domain[0].FrMultiplicativeGen var a, b, tmp fr.Element - a.Mul(&beta, &fid).Add(&a, &l).Add(&a, &gamma) - tmp.Mul(&beta, &u).Mul(&tmp, &fid).Add(&tmp, &r).Add(&tmp, &gamma) + b.Mul(&beta, &fid) + a.Add(&b, &l).Add(&a, &gamma) + b.Mul(&b, u) + tmp.Add(&b, &r).Add(&tmp, &gamma) a.Mul(&a, &tmp) - tmp.Mul(&beta, &uu).Mul(&tmp, &fid).Add(&tmp, &o).Add(&tmp, &gamma) + tmp.Mul(&b, u).Add(&tmp, &o).Add(&tmp, &gamma) a.Mul(&a, &tmp).Mul(&a, &fz) b.Mul(&beta, &fs1).Add(&b, &l).Add(&b, &gamma) @@ -317,28 +342,47 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return c } + + // wait for lcqk + <-chLcqk + + // wait for Z part + if err := <-chZ; err != nil { + return proof, err + } + + // wait for l, r o lagrange coset conversion + wgLRO.Wait() + systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, bwliop, bwriop, bwoiop, - widiop, + pk.lcIdIOP, pk.lcS1, pk.lcS2, pk.lcS3, bwziop, bwsziop, - pi2iop, + lcpi2iop, pk.lcQl, pk.lcQr, pk.lcQm, pk.lcQo, lcqk, pk.lcQcp, - wloneiop, + pk.lLoneIOP, ) if err != nil { return nil, err } + // open blinded Z at zeta*z + chbwzIOP := make(chan struct{}, 1) + go func() { + bwziop.ToCanonical(&pk.Domain[1]).ToRegular() + close(chbwzIOP) + }() + h, err := iop.DivideByXMinusOne(systemEvaluation, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) // TODO Rename to DivideByXNMinusOne or DivideByVanishingPoly etc if err != nil { return nil, err @@ -377,10 +421,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wgEvals.Done() }() - // open blinded Z at zeta*z - bwziop.ToCanonical(&pk.Domain[1]).ToRegular() var zetaShifted fr.Element zetaShifted.Mul(&zeta, &pk.Vk.Generator) + <-chbwzIOP proof.ZShiftedOpening, err = kzg.Open( bwziop.Coefficients()[:bwziop.BlindedSize()], zetaShifted, @@ -390,8 +433,39 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } - // blinded z evaluated at u*zeta - bzuzeta := proof.ZShiftedOpening.ClaimedValue + // start to compute foldedH and foldedHDigest while computeLinearizedPolynomial runs. + computeFoldedH := make(chan struct{}, 1) + var foldedH []fr.Element + var foldedHDigest kzg.Digest + go func() { + // foldedHDigest = Comm(h1) + ζᵐ⁺²*Comm(h2) + ζ²⁽ᵐ⁺²⁾*Comm(h3) + var bZetaPowerm, bSize big.Int + bSize.SetUint64(pk.Domain[0].Cardinality + 2) // +2 because of the masking (h of degree 3(n+2)-1) + var zetaPowerm fr.Element + zetaPowerm.Exp(zeta, &bSize) + zetaPowerm.BigInt(&bZetaPowerm) + foldedHDigest = proof.H[2] + foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) + foldedHDigest.Add(&foldedHDigest, &proof.H[1]) // ζᵐ⁺²*Comm(h3) + foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) + foldedHDigest.Add(&foldedHDigest, &proof.H[0]) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) + Comm(h1) + + // foldedH = h1 + ζ*h2 + ζ²*h3 + foldedH = h.Coefficients()[2*(pk.Domain[0].Cardinality+2) : 3*(pk.Domain[0].Cardinality+2)] + h2 := h.Coefficients()[pk.Domain[0].Cardinality+2 : 2*(pk.Domain[0].Cardinality+2)] + h1 := h.Coefficients()[:pk.Domain[0].Cardinality+2] + utils.Parallelize(len(foldedH), func(start, end int) { + for i := start; i < end; i++ { + foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζᵐ⁺²*h3 + foldedH[i].Add(&foldedH[i], &h2[i]) // ζ^{m+2)*h3+h2 + foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζ²⁽ᵐ⁺²⁾*h3+h2*ζᵐ⁺² + foldedH[i].Add(&foldedH[i], &h1[i]) // ζ^{2(m+2)*h3+ζᵐ⁺²*h2 + h1 + } + }) + close(computeFoldedH) + }() + + wgEvals.Wait() // wait for the evaluations var ( linearizedPolynomialCanonical []fr.Element @@ -399,10 +473,12 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts errLPoly error ) - wgEvals.Wait() // wait for the evaluations + // blinded z evaluated at u*zeta + bzuzeta := proof.ZShiftedOpening.ClaimedValue // compute the linearization polynomial r at zeta // (goal: save committing separately to z, ql, qr, qm, qo, k + // note: we linearizedPolynomialCanonical reuses bwziop memory linearizedPolynomialCanonical = computeLinearizedPolynomial( blzeta, brzeta, @@ -420,37 +496,14 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // TODO this commitment is only necessary to derive the challenge, we should // be able to avoid doing it and get the challenge in another way - linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Vk.KZGSRS) - - // foldedHDigest = Comm(h1) + ζᵐ⁺²*Comm(h2) + ζ²⁽ᵐ⁺²⁾*Comm(h3) - var bZetaPowerm, bSize big.Int - bSize.SetUint64(pk.Domain[0].Cardinality + 2) // +2 because of the masking (h of degree 3(n+2)-1) - var zetaPowerm fr.Element - zetaPowerm.Exp(zeta, &bSize) - zetaPowerm.BigInt(&bZetaPowerm) - foldedHDigest := proof.H[2] - foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) - foldedHDigest.Add(&foldedHDigest, &proof.H[1]) // ζᵐ⁺²*Comm(h3) - foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) - foldedHDigest.Add(&foldedHDigest, &proof.H[0]) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) + Comm(h1) - - // foldedH = h1 + ζ*h2 + ζ²*h3 - foldedH := h.Coefficients()[2*(pk.Domain[0].Cardinality+2) : 3*(pk.Domain[0].Cardinality+2)] - h2 := h.Coefficients()[pk.Domain[0].Cardinality+2 : 2*(pk.Domain[0].Cardinality+2)] - h1 := h.Coefficients()[:pk.Domain[0].Cardinality+2] - utils.Parallelize(len(foldedH), func(start, end int) { - for i := start; i < end; i++ { - foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζᵐ⁺²*h3 - foldedH[i].Add(&foldedH[i], &h2[i]) // ζ^{m+2)*h3+h2 - foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζ²⁽ᵐ⁺²⁾*h3+h2*ζᵐ⁺² - foldedH[i].Add(&foldedH[i], &h1[i]) // ζ^{2(m+2)*h3+ζᵐ⁺²*h2 + h1 - } - }) - + linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Vk.KZGSRS, runtime.NumCPU()*2) if errLPoly != nil { return nil, errLPoly } + // wait for foldedH and foldedHDigest + <-computeFoldedH + // Batch open the first list of polynomials proof.BatchedProof, err = kzg.BatchOpenSinglePoint( [][]fr.Element{ @@ -490,7 +543,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // fills proof.LRO with kzg commits of bcl, bcr and bco func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { - n := runtime.NumCPU() / 2 + n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) @@ -516,7 +569,7 @@ func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { } func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error { - n := runtime.NumCPU() / 2 + n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) @@ -599,26 +652,23 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, Mul(&lagrangeZeta, &alpha). Mul(&lagrangeZeta, &pk.Domain[0].CardinalityInv) // (1/n)*α²*L₁(ζ) - linPol := make([]fr.Element, len(blindedZCanonical)) - copy(linPol, blindedZCanonical) - s3canonical := pk.trace.S3.Coefficients() - utils.Parallelize(len(linPol), func(start, end int) { + utils.Parallelize(len(blindedZCanonical), func(start, end int) { - var t0, t1 fr.Element + var t, t0, t1 fr.Element for i := start; i < end; i++ { - linPol[i].Mul(&linPol[i], &s2) // -Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + t.Mul(&blindedZCanonical[i], &s2) // -Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) if i < len(s3canonical) { t0.Mul(&s3canonical[i], &s1) // (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*β*s3(X) - linPol[i].Add(&linPol[i], &t0) + t.Add(&t, &t0) } - linPol[i].Mul(&linPol[i], &alpha) // α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ)) + t.Mul(&t, &alpha) // α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ)) cql := pk.trace.Ql.Coefficients() cqr := pk.trace.Qr.Coefficients() @@ -630,21 +680,21 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, t1.Mul(&cqm[i], &rl) // linPol = linPol + l(ζ)r(ζ)*Qm(X) t0.Mul(&cql[i], &lZeta) t0.Add(&t0, &t1) - linPol[i].Add(&linPol[i], &t0) // linPol = linPol + l(ζ)*Ql(X) + t.Add(&t, &t0) // linPol = linPol + l(ζ)*Ql(X) t0.Mul(&cqr[i], &rZeta) - linPol[i].Add(&linPol[i], &t0) // linPol = linPol + r(ζ)*Qr(X) + t.Add(&t, &t0) // linPol = linPol + r(ζ)*Qr(X) t0.Mul(&cqo[i], &oZeta).Add(&t0, &cqk[i]) - linPol[i].Add(&linPol[i], &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) + t.Add(&t, &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) t0.Mul(&pi2Canonical[i], &qcpZeta) - linPol[i].Add(&linPol[i], &t0) + t.Add(&t, &t0) } t0.Mul(&blindedZCanonical[i], &lagrangeZeta) - linPol[i].Add(&linPol[i], &t0) // finish the computation + blindedZCanonical[i].Add(&t, &t0) // finish the computation } }) - return linPol + return blindedZCanonical } diff --git a/backend/plonk/bls12-381/setup.go b/backend/plonk/bls12-381/setup.go index 588b72b35d..229b43b649 100644 --- a/backend/plonk/bls12-381/setup.go +++ b/backend/plonk/bls12-381/setup.go @@ -112,6 +112,9 @@ type ProvingKey struct { // in lagrange coset basis --> these are not serialized, but computed from S1Canonical, S2Canonical, S3Canonical once. lcS1, lcS2, lcS3 *iop.Polynomial + + // in lagrange coset basis --> not serialized id and L_{g^{0}} + lcIdIOP, lLoneIOP *iop.Polynomial } func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) { @@ -176,6 +179,26 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { pk.lcS1 = pk.trace.S1.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcS2 = pk.trace.S2.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcS3 = pk.trace.S3.Clone().ToLagrangeCoset(&pk.Domain[1]) + + // storing Id + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + id := make([]fr.Element, pk.Domain[1].Cardinality) + id[0].Set(&pk.Domain[1].FrMultiplicativeGen) + for i := 1; i < int(pk.Domain[1].Cardinality); i++ { + id[i].Mul(&id[i-1], &pk.Domain[1].Generator) + } + pk.lcIdIOP = iop.NewPolynomial(&id, lagReg) + + // L_{g^{0}} + cap := pk.Domain[1].Cardinality + if cap < pk.Domain[0].Cardinality { + cap = pk.Domain[0].Cardinality // sanity check + } + lone := make([]fr.Element, pk.Domain[0].Cardinality, cap) + lone[0].SetOne() + pk.lLoneIOP = iop.NewPolynomial(&lone, lagReg).ToCanonical(&pk.Domain[0]). + ToRegular(). + ToLagrangeCoset(&pk.Domain[1]) } // NbPublicWitness returns the expected public witness size (number of field elements) diff --git a/backend/plonk/bls24-315/prove.go b/backend/plonk/bls24-315/prove.go index 30a78e3000..97d1f0f22b 100644 --- a/backend/plonk/bls24-315/prove.go +++ b/backend/plonk/bls24-315/prove.go @@ -123,7 +123,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pi2iop := iop.NewPolynomial(&pi2, lagReg) wpi2iop = pi2iop.ShallowClone() - wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + // wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() } // query l, r, o in Lagrange basis, not blinded @@ -131,41 +131,88 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if err != nil { return nil, err } + // TODO @gbotrel deal with that conversion lazily + var lcpi2iop *iop.Polynomial + if spr.CommitmentInfo.Is() { + lcpi2iop = wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form + } else { + coeffs := make([]fr.Element, pk.Domain[1].Cardinality) + lcpi2iop = iop.NewPolynomial(&coeffs, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.Regular}) + } solution := _solution.(*cs.SparseR1CSSolution) evaluationLDomainSmall := []fr.Element(solution.L) evaluationRDomainSmall := []fr.Element(solution.R) evaluationODomainSmall := []fr.Element(solution.O) - liop := iop.NewPolynomial(&evaluationLDomainSmall, lagReg) - riop := iop.NewPolynomial(&evaluationRDomainSmall, lagReg) - oiop := iop.NewPolynomial(&evaluationODomainSmall, lagReg) - wliop := liop.ShallowClone() - wriop := riop.ShallowClone() - woiop := oiop.ShallowClone() - wliop.ToCanonical(&pk.Domain[0]).ToRegular() - wriop.ToCanonical(&pk.Domain[0]).ToRegular() - woiop.ToCanonical(&pk.Domain[0]).ToRegular() - - // Blind l, r, o before committing - // we set the underlying slice capacity to domain[1].Cardinality to minimize mem moves. - bwliop := wliop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) - bwriop := wriop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) - bwoiop := woiop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) - if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Vk.KZGSRS); err != nil { - return nil, err - } + // l, r o and blinded versions + var ( + wliop, + wriop, + woiop, + bwliop, + bwriop, + bwoiop *iop.Polynomial + ) + var wgLRO sync.WaitGroup + wgLRO.Add(3) + go func() { + // we keep in lagrange regular form since iop.BuildRatioCopyConstraint prefers it in this form. + wliop = iop.NewPolynomial(&evaluationLDomainSmall, lagReg) + // we set the underlying slice capacity to domain[1].Cardinality to minimize mem moves. + bwliop = wliop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) + wgLRO.Done() + }() + go func() { + wriop = iop.NewPolynomial(&evaluationRDomainSmall, lagReg) + bwriop = wriop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) + wgLRO.Done() + }() + go func() { + woiop = iop.NewPolynomial(&evaluationODomainSmall, lagReg) + bwoiop = woiop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) + wgLRO.Done() + }() fw, ok := fullWitness.Vector().(fr.Vector) if !ok { return nil, witness.ErrInvalidWitness } + // start computing lcqk + var lcqk *iop.Polynomial + chLcqk := make(chan struct{}, 1) + go func() { + // compute qk in canonical basis, completed with the public inputs + // We copy the coeffs of qk to pk is not mutated + lqkcoef := pk.lQk.Coefficients() + qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) + copy(qkCompletedCanonical, fw[:len(spr.Public)]) + copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) + if spr.CommitmentInfo.Is() { + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal + } + pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) + fft.BitReverse(qkCompletedCanonical) + + canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} + lcqk = iop.NewPolynomial(&qkCompletedCanonical, canReg) + lcqk.ToLagrangeCoset(&pk.Domain[1]) + close(chLcqk) + }() + // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.PI2); err != nil { return nil, err } + + // wait for polys to be blinded + wgLRO.Wait() + if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Vk.KZGSRS); err != nil { + return nil, err + } + gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) // TODO @Tabaie @ThomasPiellard add BSB commitment here? if err != nil { return nil, err @@ -179,15 +226,28 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts var beta fr.Element beta.SetBytes(bbeta) + // l, r, o are already blinded + wgLRO.Add(3) + go func() { + bwliop.ToLagrangeCoset(&pk.Domain[1]) + wgLRO.Done() + }() + go func() { + bwriop.ToLagrangeCoset(&pk.Domain[1]) + wgLRO.Done() + }() + go func() { + bwoiop.ToLagrangeCoset(&pk.Domain[1]) + wgLRO.Done() + }() + // compute the copy constraint's ratio - // We copy liop, riop, oiop because they are fft'ed in the process. - // We could have not copied them at the cost of doing one more bit reverse - // per poly... + // note that wliop, wriop and woiop are fft'ed (mutated) in the process. ziop, err := iop.BuildRatioCopyConstraint( []*iop.Polynomial{ - liop.Clone(), - riop.Clone(), - oiop.Clone(), + wliop, + wriop, + woiop, }, pk.trace.S, beta, @@ -200,63 +260,29 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // commit to the blinded version of z - bwziop := ziop // iop.NewWrappedPolynomial(&ziop) - bwziop.Blind(2) - proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Vk.KZGSRS, runtime.NumCPU()*2) - if err != nil { - return proof, err - } - - // derive alpha from the Comm(l), Comm(r), Comm(o), Com(Z) - alpha, err := deriveRandomness(&fs, "alpha", &proof.Z) - if err != nil { - return proof, err - } + chZ := make(chan error, 1) + var bwziop, bwsziop *iop.Polynomial + var alpha fr.Element + go func() { + bwziop = ziop // iop.NewWrappedPolynomial(&ziop) + bwziop.Blind(2) + proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Vk.KZGSRS, runtime.NumCPU()*2) + if err != nil { + chZ <- err + } - // compute qk in canonical basis, completed with the public inputs - // We copy the coeffs of qk to pk is not mutated - lqkcoef := pk.lQk.Coefficients() - qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) - copy(qkCompletedCanonical, lqkcoef) - copy(qkCompletedCanonical, fw[:len(spr.Public)]) - if spr.CommitmentInfo.Is() { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal - } - pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) - fft.BitReverse(qkCompletedCanonical) + // derive alpha from the Comm(l), Comm(r), Comm(o), Com(Z) + alpha, err = deriveRandomness(&fs, "alpha", &proof.Z) + if err != nil { + chZ <- err + } - // l, r, o are already blinded - bwliop.ToLagrangeCoset(&pk.Domain[1]) - bwriop.ToLagrangeCoset(&pk.Domain[1]) - bwoiop.ToLagrangeCoset(&pk.Domain[1]) - pi2iop := wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form - - // we don't mutate so no need to clone the coefficients from the proving key. - canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} - lcqk := iop.NewPolynomial(&qkCompletedCanonical, canReg) - lcqk.ToLagrangeCoset(&pk.Domain[1]) - - // storing Id - id := make([]fr.Element, pk.Domain[1].Cardinality) - id[1].SetOne() - widiop := iop.NewPolynomial(&id, canReg) - widiop.ToLagrangeCoset(&pk.Domain[1]) - - // Store z(g*x), without reallocating a slice - bwsziop := bwziop.ShallowClone().Shift(1) - bwsziop.ToLagrangeCoset(&pk.Domain[1]) - - // L_{g^{0}} - cap := pk.Domain[1].Cardinality - if cap < pk.Domain[0].Cardinality { - cap = pk.Domain[0].Cardinality // sanity check - } - lone := make([]fr.Element, pk.Domain[0].Cardinality, cap) - lone[0].SetOne() - loneiop := iop.NewPolynomial(&lone, lagReg) - wloneiop := loneiop.ToCanonical(&pk.Domain[0]). - ToRegular(). - ToLagrangeCoset(&pk.Domain[1]) + // Store z(g*x), without reallocating a slice + bwsziop = bwziop.ShallowClone().Shift(1) + bwsziop.ToLagrangeCoset(&pk.Domain[1]) + chZ <- nil + close(chZ) + }() // Full capture using latest gnark crypto... fic := func(fql, fqr, fqm, fqo, fqk, fqCPrime, l, r, o, pi2 fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary @@ -277,15 +303,14 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } fo := func(l, r, o, fid, fs1, fs2, fs3, fz, fzs fr.Element) fr.Element { - var uu fr.Element - u := pk.Domain[0].FrMultiplicativeGen - uu.Mul(&u, &u) - + u := &pk.Domain[0].FrMultiplicativeGen var a, b, tmp fr.Element - a.Mul(&beta, &fid).Add(&a, &l).Add(&a, &gamma) - tmp.Mul(&beta, &u).Mul(&tmp, &fid).Add(&tmp, &r).Add(&tmp, &gamma) + b.Mul(&beta, &fid) + a.Add(&b, &l).Add(&a, &gamma) + b.Mul(&b, u) + tmp.Add(&b, &r).Add(&tmp, &gamma) a.Mul(&a, &tmp) - tmp.Mul(&beta, &uu).Mul(&tmp, &fid).Add(&tmp, &o).Add(&tmp, &gamma) + tmp.Mul(&b, u).Add(&tmp, &o).Add(&tmp, &gamma) a.Mul(&a, &tmp).Mul(&a, &fz) b.Mul(&beta, &fs1).Add(&b, &l).Add(&b, &gamma) @@ -317,28 +342,47 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return c } + + // wait for lcqk + <-chLcqk + + // wait for Z part + if err := <-chZ; err != nil { + return proof, err + } + + // wait for l, r o lagrange coset conversion + wgLRO.Wait() + systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, bwliop, bwriop, bwoiop, - widiop, + pk.lcIdIOP, pk.lcS1, pk.lcS2, pk.lcS3, bwziop, bwsziop, - pi2iop, + lcpi2iop, pk.lcQl, pk.lcQr, pk.lcQm, pk.lcQo, lcqk, pk.lcQcp, - wloneiop, + pk.lLoneIOP, ) if err != nil { return nil, err } + // open blinded Z at zeta*z + chbwzIOP := make(chan struct{}, 1) + go func() { + bwziop.ToCanonical(&pk.Domain[1]).ToRegular() + close(chbwzIOP) + }() + h, err := iop.DivideByXMinusOne(systemEvaluation, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) // TODO Rename to DivideByXNMinusOne or DivideByVanishingPoly etc if err != nil { return nil, err @@ -377,10 +421,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wgEvals.Done() }() - // open blinded Z at zeta*z - bwziop.ToCanonical(&pk.Domain[1]).ToRegular() var zetaShifted fr.Element zetaShifted.Mul(&zeta, &pk.Vk.Generator) + <-chbwzIOP proof.ZShiftedOpening, err = kzg.Open( bwziop.Coefficients()[:bwziop.BlindedSize()], zetaShifted, @@ -390,8 +433,39 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } - // blinded z evaluated at u*zeta - bzuzeta := proof.ZShiftedOpening.ClaimedValue + // start to compute foldedH and foldedHDigest while computeLinearizedPolynomial runs. + computeFoldedH := make(chan struct{}, 1) + var foldedH []fr.Element + var foldedHDigest kzg.Digest + go func() { + // foldedHDigest = Comm(h1) + ζᵐ⁺²*Comm(h2) + ζ²⁽ᵐ⁺²⁾*Comm(h3) + var bZetaPowerm, bSize big.Int + bSize.SetUint64(pk.Domain[0].Cardinality + 2) // +2 because of the masking (h of degree 3(n+2)-1) + var zetaPowerm fr.Element + zetaPowerm.Exp(zeta, &bSize) + zetaPowerm.BigInt(&bZetaPowerm) + foldedHDigest = proof.H[2] + foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) + foldedHDigest.Add(&foldedHDigest, &proof.H[1]) // ζᵐ⁺²*Comm(h3) + foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) + foldedHDigest.Add(&foldedHDigest, &proof.H[0]) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) + Comm(h1) + + // foldedH = h1 + ζ*h2 + ζ²*h3 + foldedH = h.Coefficients()[2*(pk.Domain[0].Cardinality+2) : 3*(pk.Domain[0].Cardinality+2)] + h2 := h.Coefficients()[pk.Domain[0].Cardinality+2 : 2*(pk.Domain[0].Cardinality+2)] + h1 := h.Coefficients()[:pk.Domain[0].Cardinality+2] + utils.Parallelize(len(foldedH), func(start, end int) { + for i := start; i < end; i++ { + foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζᵐ⁺²*h3 + foldedH[i].Add(&foldedH[i], &h2[i]) // ζ^{m+2)*h3+h2 + foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζ²⁽ᵐ⁺²⁾*h3+h2*ζᵐ⁺² + foldedH[i].Add(&foldedH[i], &h1[i]) // ζ^{2(m+2)*h3+ζᵐ⁺²*h2 + h1 + } + }) + close(computeFoldedH) + }() + + wgEvals.Wait() // wait for the evaluations var ( linearizedPolynomialCanonical []fr.Element @@ -399,10 +473,12 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts errLPoly error ) - wgEvals.Wait() // wait for the evaluations + // blinded z evaluated at u*zeta + bzuzeta := proof.ZShiftedOpening.ClaimedValue // compute the linearization polynomial r at zeta // (goal: save committing separately to z, ql, qr, qm, qo, k + // note: we linearizedPolynomialCanonical reuses bwziop memory linearizedPolynomialCanonical = computeLinearizedPolynomial( blzeta, brzeta, @@ -420,37 +496,14 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // TODO this commitment is only necessary to derive the challenge, we should // be able to avoid doing it and get the challenge in another way - linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Vk.KZGSRS) - - // foldedHDigest = Comm(h1) + ζᵐ⁺²*Comm(h2) + ζ²⁽ᵐ⁺²⁾*Comm(h3) - var bZetaPowerm, bSize big.Int - bSize.SetUint64(pk.Domain[0].Cardinality + 2) // +2 because of the masking (h of degree 3(n+2)-1) - var zetaPowerm fr.Element - zetaPowerm.Exp(zeta, &bSize) - zetaPowerm.BigInt(&bZetaPowerm) - foldedHDigest := proof.H[2] - foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) - foldedHDigest.Add(&foldedHDigest, &proof.H[1]) // ζᵐ⁺²*Comm(h3) - foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) - foldedHDigest.Add(&foldedHDigest, &proof.H[0]) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) + Comm(h1) - - // foldedH = h1 + ζ*h2 + ζ²*h3 - foldedH := h.Coefficients()[2*(pk.Domain[0].Cardinality+2) : 3*(pk.Domain[0].Cardinality+2)] - h2 := h.Coefficients()[pk.Domain[0].Cardinality+2 : 2*(pk.Domain[0].Cardinality+2)] - h1 := h.Coefficients()[:pk.Domain[0].Cardinality+2] - utils.Parallelize(len(foldedH), func(start, end int) { - for i := start; i < end; i++ { - foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζᵐ⁺²*h3 - foldedH[i].Add(&foldedH[i], &h2[i]) // ζ^{m+2)*h3+h2 - foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζ²⁽ᵐ⁺²⁾*h3+h2*ζᵐ⁺² - foldedH[i].Add(&foldedH[i], &h1[i]) // ζ^{2(m+2)*h3+ζᵐ⁺²*h2 + h1 - } - }) - + linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Vk.KZGSRS, runtime.NumCPU()*2) if errLPoly != nil { return nil, errLPoly } + // wait for foldedH and foldedHDigest + <-computeFoldedH + // Batch open the first list of polynomials proof.BatchedProof, err = kzg.BatchOpenSinglePoint( [][]fr.Element{ @@ -490,7 +543,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // fills proof.LRO with kzg commits of bcl, bcr and bco func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { - n := runtime.NumCPU() / 2 + n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) @@ -516,7 +569,7 @@ func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { } func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error { - n := runtime.NumCPU() / 2 + n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) @@ -599,26 +652,23 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, Mul(&lagrangeZeta, &alpha). Mul(&lagrangeZeta, &pk.Domain[0].CardinalityInv) // (1/n)*α²*L₁(ζ) - linPol := make([]fr.Element, len(blindedZCanonical)) - copy(linPol, blindedZCanonical) - s3canonical := pk.trace.S3.Coefficients() - utils.Parallelize(len(linPol), func(start, end int) { + utils.Parallelize(len(blindedZCanonical), func(start, end int) { - var t0, t1 fr.Element + var t, t0, t1 fr.Element for i := start; i < end; i++ { - linPol[i].Mul(&linPol[i], &s2) // -Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + t.Mul(&blindedZCanonical[i], &s2) // -Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) if i < len(s3canonical) { t0.Mul(&s3canonical[i], &s1) // (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*β*s3(X) - linPol[i].Add(&linPol[i], &t0) + t.Add(&t, &t0) } - linPol[i].Mul(&linPol[i], &alpha) // α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ)) + t.Mul(&t, &alpha) // α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ)) cql := pk.trace.Ql.Coefficients() cqr := pk.trace.Qr.Coefficients() @@ -630,21 +680,21 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, t1.Mul(&cqm[i], &rl) // linPol = linPol + l(ζ)r(ζ)*Qm(X) t0.Mul(&cql[i], &lZeta) t0.Add(&t0, &t1) - linPol[i].Add(&linPol[i], &t0) // linPol = linPol + l(ζ)*Ql(X) + t.Add(&t, &t0) // linPol = linPol + l(ζ)*Ql(X) t0.Mul(&cqr[i], &rZeta) - linPol[i].Add(&linPol[i], &t0) // linPol = linPol + r(ζ)*Qr(X) + t.Add(&t, &t0) // linPol = linPol + r(ζ)*Qr(X) t0.Mul(&cqo[i], &oZeta).Add(&t0, &cqk[i]) - linPol[i].Add(&linPol[i], &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) + t.Add(&t, &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) t0.Mul(&pi2Canonical[i], &qcpZeta) - linPol[i].Add(&linPol[i], &t0) + t.Add(&t, &t0) } t0.Mul(&blindedZCanonical[i], &lagrangeZeta) - linPol[i].Add(&linPol[i], &t0) // finish the computation + blindedZCanonical[i].Add(&t, &t0) // finish the computation } }) - return linPol + return blindedZCanonical } diff --git a/backend/plonk/bls24-315/setup.go b/backend/plonk/bls24-315/setup.go index bf4c04a9b7..0de7425e02 100644 --- a/backend/plonk/bls24-315/setup.go +++ b/backend/plonk/bls24-315/setup.go @@ -112,6 +112,9 @@ type ProvingKey struct { // in lagrange coset basis --> these are not serialized, but computed from S1Canonical, S2Canonical, S3Canonical once. lcS1, lcS2, lcS3 *iop.Polynomial + + // in lagrange coset basis --> not serialized id and L_{g^{0}} + lcIdIOP, lLoneIOP *iop.Polynomial } func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) { @@ -176,6 +179,26 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { pk.lcS1 = pk.trace.S1.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcS2 = pk.trace.S2.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcS3 = pk.trace.S3.Clone().ToLagrangeCoset(&pk.Domain[1]) + + // storing Id + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + id := make([]fr.Element, pk.Domain[1].Cardinality) + id[0].Set(&pk.Domain[1].FrMultiplicativeGen) + for i := 1; i < int(pk.Domain[1].Cardinality); i++ { + id[i].Mul(&id[i-1], &pk.Domain[1].Generator) + } + pk.lcIdIOP = iop.NewPolynomial(&id, lagReg) + + // L_{g^{0}} + cap := pk.Domain[1].Cardinality + if cap < pk.Domain[0].Cardinality { + cap = pk.Domain[0].Cardinality // sanity check + } + lone := make([]fr.Element, pk.Domain[0].Cardinality, cap) + lone[0].SetOne() + pk.lLoneIOP = iop.NewPolynomial(&lone, lagReg).ToCanonical(&pk.Domain[0]). + ToRegular(). + ToLagrangeCoset(&pk.Domain[1]) } // NbPublicWitness returns the expected public witness size (number of field elements) diff --git a/backend/plonk/bls24-317/prove.go b/backend/plonk/bls24-317/prove.go index bf364c4dbb..4964018989 100644 --- a/backend/plonk/bls24-317/prove.go +++ b/backend/plonk/bls24-317/prove.go @@ -123,7 +123,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pi2iop := iop.NewPolynomial(&pi2, lagReg) wpi2iop = pi2iop.ShallowClone() - wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + // wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() } // query l, r, o in Lagrange basis, not blinded @@ -131,41 +131,88 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if err != nil { return nil, err } + // TODO @gbotrel deal with that conversion lazily + var lcpi2iop *iop.Polynomial + if spr.CommitmentInfo.Is() { + lcpi2iop = wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form + } else { + coeffs := make([]fr.Element, pk.Domain[1].Cardinality) + lcpi2iop = iop.NewPolynomial(&coeffs, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.Regular}) + } solution := _solution.(*cs.SparseR1CSSolution) evaluationLDomainSmall := []fr.Element(solution.L) evaluationRDomainSmall := []fr.Element(solution.R) evaluationODomainSmall := []fr.Element(solution.O) - liop := iop.NewPolynomial(&evaluationLDomainSmall, lagReg) - riop := iop.NewPolynomial(&evaluationRDomainSmall, lagReg) - oiop := iop.NewPolynomial(&evaluationODomainSmall, lagReg) - wliop := liop.ShallowClone() - wriop := riop.ShallowClone() - woiop := oiop.ShallowClone() - wliop.ToCanonical(&pk.Domain[0]).ToRegular() - wriop.ToCanonical(&pk.Domain[0]).ToRegular() - woiop.ToCanonical(&pk.Domain[0]).ToRegular() - - // Blind l, r, o before committing - // we set the underlying slice capacity to domain[1].Cardinality to minimize mem moves. - bwliop := wliop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) - bwriop := wriop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) - bwoiop := woiop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) - if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Vk.KZGSRS); err != nil { - return nil, err - } + // l, r o and blinded versions + var ( + wliop, + wriop, + woiop, + bwliop, + bwriop, + bwoiop *iop.Polynomial + ) + var wgLRO sync.WaitGroup + wgLRO.Add(3) + go func() { + // we keep in lagrange regular form since iop.BuildRatioCopyConstraint prefers it in this form. + wliop = iop.NewPolynomial(&evaluationLDomainSmall, lagReg) + // we set the underlying slice capacity to domain[1].Cardinality to minimize mem moves. + bwliop = wliop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) + wgLRO.Done() + }() + go func() { + wriop = iop.NewPolynomial(&evaluationRDomainSmall, lagReg) + bwriop = wriop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) + wgLRO.Done() + }() + go func() { + woiop = iop.NewPolynomial(&evaluationODomainSmall, lagReg) + bwoiop = woiop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) + wgLRO.Done() + }() fw, ok := fullWitness.Vector().(fr.Vector) if !ok { return nil, witness.ErrInvalidWitness } + // start computing lcqk + var lcqk *iop.Polynomial + chLcqk := make(chan struct{}, 1) + go func() { + // compute qk in canonical basis, completed with the public inputs + // We copy the coeffs of qk to pk is not mutated + lqkcoef := pk.lQk.Coefficients() + qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) + copy(qkCompletedCanonical, fw[:len(spr.Public)]) + copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) + if spr.CommitmentInfo.Is() { + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal + } + pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) + fft.BitReverse(qkCompletedCanonical) + + canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} + lcqk = iop.NewPolynomial(&qkCompletedCanonical, canReg) + lcqk.ToLagrangeCoset(&pk.Domain[1]) + close(chLcqk) + }() + // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.PI2); err != nil { return nil, err } + + // wait for polys to be blinded + wgLRO.Wait() + if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Vk.KZGSRS); err != nil { + return nil, err + } + gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) // TODO @Tabaie @ThomasPiellard add BSB commitment here? if err != nil { return nil, err @@ -179,15 +226,28 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts var beta fr.Element beta.SetBytes(bbeta) + // l, r, o are already blinded + wgLRO.Add(3) + go func() { + bwliop.ToLagrangeCoset(&pk.Domain[1]) + wgLRO.Done() + }() + go func() { + bwriop.ToLagrangeCoset(&pk.Domain[1]) + wgLRO.Done() + }() + go func() { + bwoiop.ToLagrangeCoset(&pk.Domain[1]) + wgLRO.Done() + }() + // compute the copy constraint's ratio - // We copy liop, riop, oiop because they are fft'ed in the process. - // We could have not copied them at the cost of doing one more bit reverse - // per poly... + // note that wliop, wriop and woiop are fft'ed (mutated) in the process. ziop, err := iop.BuildRatioCopyConstraint( []*iop.Polynomial{ - liop.Clone(), - riop.Clone(), - oiop.Clone(), + wliop, + wriop, + woiop, }, pk.trace.S, beta, @@ -200,63 +260,29 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // commit to the blinded version of z - bwziop := ziop // iop.NewWrappedPolynomial(&ziop) - bwziop.Blind(2) - proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Vk.KZGSRS, runtime.NumCPU()*2) - if err != nil { - return proof, err - } - - // derive alpha from the Comm(l), Comm(r), Comm(o), Com(Z) - alpha, err := deriveRandomness(&fs, "alpha", &proof.Z) - if err != nil { - return proof, err - } + chZ := make(chan error, 1) + var bwziop, bwsziop *iop.Polynomial + var alpha fr.Element + go func() { + bwziop = ziop // iop.NewWrappedPolynomial(&ziop) + bwziop.Blind(2) + proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Vk.KZGSRS, runtime.NumCPU()*2) + if err != nil { + chZ <- err + } - // compute qk in canonical basis, completed with the public inputs - // We copy the coeffs of qk to pk is not mutated - lqkcoef := pk.lQk.Coefficients() - qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) - copy(qkCompletedCanonical, lqkcoef) - copy(qkCompletedCanonical, fw[:len(spr.Public)]) - if spr.CommitmentInfo.Is() { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal - } - pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) - fft.BitReverse(qkCompletedCanonical) + // derive alpha from the Comm(l), Comm(r), Comm(o), Com(Z) + alpha, err = deriveRandomness(&fs, "alpha", &proof.Z) + if err != nil { + chZ <- err + } - // l, r, o are already blinded - bwliop.ToLagrangeCoset(&pk.Domain[1]) - bwriop.ToLagrangeCoset(&pk.Domain[1]) - bwoiop.ToLagrangeCoset(&pk.Domain[1]) - pi2iop := wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form - - // we don't mutate so no need to clone the coefficients from the proving key. - canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} - lcqk := iop.NewPolynomial(&qkCompletedCanonical, canReg) - lcqk.ToLagrangeCoset(&pk.Domain[1]) - - // storing Id - id := make([]fr.Element, pk.Domain[1].Cardinality) - id[1].SetOne() - widiop := iop.NewPolynomial(&id, canReg) - widiop.ToLagrangeCoset(&pk.Domain[1]) - - // Store z(g*x), without reallocating a slice - bwsziop := bwziop.ShallowClone().Shift(1) - bwsziop.ToLagrangeCoset(&pk.Domain[1]) - - // L_{g^{0}} - cap := pk.Domain[1].Cardinality - if cap < pk.Domain[0].Cardinality { - cap = pk.Domain[0].Cardinality // sanity check - } - lone := make([]fr.Element, pk.Domain[0].Cardinality, cap) - lone[0].SetOne() - loneiop := iop.NewPolynomial(&lone, lagReg) - wloneiop := loneiop.ToCanonical(&pk.Domain[0]). - ToRegular(). - ToLagrangeCoset(&pk.Domain[1]) + // Store z(g*x), without reallocating a slice + bwsziop = bwziop.ShallowClone().Shift(1) + bwsziop.ToLagrangeCoset(&pk.Domain[1]) + chZ <- nil + close(chZ) + }() // Full capture using latest gnark crypto... fic := func(fql, fqr, fqm, fqo, fqk, fqCPrime, l, r, o, pi2 fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary @@ -277,15 +303,14 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } fo := func(l, r, o, fid, fs1, fs2, fs3, fz, fzs fr.Element) fr.Element { - var uu fr.Element - u := pk.Domain[0].FrMultiplicativeGen - uu.Mul(&u, &u) - + u := &pk.Domain[0].FrMultiplicativeGen var a, b, tmp fr.Element - a.Mul(&beta, &fid).Add(&a, &l).Add(&a, &gamma) - tmp.Mul(&beta, &u).Mul(&tmp, &fid).Add(&tmp, &r).Add(&tmp, &gamma) + b.Mul(&beta, &fid) + a.Add(&b, &l).Add(&a, &gamma) + b.Mul(&b, u) + tmp.Add(&b, &r).Add(&tmp, &gamma) a.Mul(&a, &tmp) - tmp.Mul(&beta, &uu).Mul(&tmp, &fid).Add(&tmp, &o).Add(&tmp, &gamma) + tmp.Mul(&b, u).Add(&tmp, &o).Add(&tmp, &gamma) a.Mul(&a, &tmp).Mul(&a, &fz) b.Mul(&beta, &fs1).Add(&b, &l).Add(&b, &gamma) @@ -317,28 +342,47 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return c } + + // wait for lcqk + <-chLcqk + + // wait for Z part + if err := <-chZ; err != nil { + return proof, err + } + + // wait for l, r o lagrange coset conversion + wgLRO.Wait() + systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, bwliop, bwriop, bwoiop, - widiop, + pk.lcIdIOP, pk.lcS1, pk.lcS2, pk.lcS3, bwziop, bwsziop, - pi2iop, + lcpi2iop, pk.lcQl, pk.lcQr, pk.lcQm, pk.lcQo, lcqk, pk.lcQcp, - wloneiop, + pk.lLoneIOP, ) if err != nil { return nil, err } + // open blinded Z at zeta*z + chbwzIOP := make(chan struct{}, 1) + go func() { + bwziop.ToCanonical(&pk.Domain[1]).ToRegular() + close(chbwzIOP) + }() + h, err := iop.DivideByXMinusOne(systemEvaluation, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) // TODO Rename to DivideByXNMinusOne or DivideByVanishingPoly etc if err != nil { return nil, err @@ -377,10 +421,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wgEvals.Done() }() - // open blinded Z at zeta*z - bwziop.ToCanonical(&pk.Domain[1]).ToRegular() var zetaShifted fr.Element zetaShifted.Mul(&zeta, &pk.Vk.Generator) + <-chbwzIOP proof.ZShiftedOpening, err = kzg.Open( bwziop.Coefficients()[:bwziop.BlindedSize()], zetaShifted, @@ -390,8 +433,39 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } - // blinded z evaluated at u*zeta - bzuzeta := proof.ZShiftedOpening.ClaimedValue + // start to compute foldedH and foldedHDigest while computeLinearizedPolynomial runs. + computeFoldedH := make(chan struct{}, 1) + var foldedH []fr.Element + var foldedHDigest kzg.Digest + go func() { + // foldedHDigest = Comm(h1) + ζᵐ⁺²*Comm(h2) + ζ²⁽ᵐ⁺²⁾*Comm(h3) + var bZetaPowerm, bSize big.Int + bSize.SetUint64(pk.Domain[0].Cardinality + 2) // +2 because of the masking (h of degree 3(n+2)-1) + var zetaPowerm fr.Element + zetaPowerm.Exp(zeta, &bSize) + zetaPowerm.BigInt(&bZetaPowerm) + foldedHDigest = proof.H[2] + foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) + foldedHDigest.Add(&foldedHDigest, &proof.H[1]) // ζᵐ⁺²*Comm(h3) + foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) + foldedHDigest.Add(&foldedHDigest, &proof.H[0]) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) + Comm(h1) + + // foldedH = h1 + ζ*h2 + ζ²*h3 + foldedH = h.Coefficients()[2*(pk.Domain[0].Cardinality+2) : 3*(pk.Domain[0].Cardinality+2)] + h2 := h.Coefficients()[pk.Domain[0].Cardinality+2 : 2*(pk.Domain[0].Cardinality+2)] + h1 := h.Coefficients()[:pk.Domain[0].Cardinality+2] + utils.Parallelize(len(foldedH), func(start, end int) { + for i := start; i < end; i++ { + foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζᵐ⁺²*h3 + foldedH[i].Add(&foldedH[i], &h2[i]) // ζ^{m+2)*h3+h2 + foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζ²⁽ᵐ⁺²⁾*h3+h2*ζᵐ⁺² + foldedH[i].Add(&foldedH[i], &h1[i]) // ζ^{2(m+2)*h3+ζᵐ⁺²*h2 + h1 + } + }) + close(computeFoldedH) + }() + + wgEvals.Wait() // wait for the evaluations var ( linearizedPolynomialCanonical []fr.Element @@ -399,10 +473,12 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts errLPoly error ) - wgEvals.Wait() // wait for the evaluations + // blinded z evaluated at u*zeta + bzuzeta := proof.ZShiftedOpening.ClaimedValue // compute the linearization polynomial r at zeta // (goal: save committing separately to z, ql, qr, qm, qo, k + // note: we linearizedPolynomialCanonical reuses bwziop memory linearizedPolynomialCanonical = computeLinearizedPolynomial( blzeta, brzeta, @@ -420,37 +496,14 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // TODO this commitment is only necessary to derive the challenge, we should // be able to avoid doing it and get the challenge in another way - linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Vk.KZGSRS) - - // foldedHDigest = Comm(h1) + ζᵐ⁺²*Comm(h2) + ζ²⁽ᵐ⁺²⁾*Comm(h3) - var bZetaPowerm, bSize big.Int - bSize.SetUint64(pk.Domain[0].Cardinality + 2) // +2 because of the masking (h of degree 3(n+2)-1) - var zetaPowerm fr.Element - zetaPowerm.Exp(zeta, &bSize) - zetaPowerm.BigInt(&bZetaPowerm) - foldedHDigest := proof.H[2] - foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) - foldedHDigest.Add(&foldedHDigest, &proof.H[1]) // ζᵐ⁺²*Comm(h3) - foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) - foldedHDigest.Add(&foldedHDigest, &proof.H[0]) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) + Comm(h1) - - // foldedH = h1 + ζ*h2 + ζ²*h3 - foldedH := h.Coefficients()[2*(pk.Domain[0].Cardinality+2) : 3*(pk.Domain[0].Cardinality+2)] - h2 := h.Coefficients()[pk.Domain[0].Cardinality+2 : 2*(pk.Domain[0].Cardinality+2)] - h1 := h.Coefficients()[:pk.Domain[0].Cardinality+2] - utils.Parallelize(len(foldedH), func(start, end int) { - for i := start; i < end; i++ { - foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζᵐ⁺²*h3 - foldedH[i].Add(&foldedH[i], &h2[i]) // ζ^{m+2)*h3+h2 - foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζ²⁽ᵐ⁺²⁾*h3+h2*ζᵐ⁺² - foldedH[i].Add(&foldedH[i], &h1[i]) // ζ^{2(m+2)*h3+ζᵐ⁺²*h2 + h1 - } - }) - + linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Vk.KZGSRS, runtime.NumCPU()*2) if errLPoly != nil { return nil, errLPoly } + // wait for foldedH and foldedHDigest + <-computeFoldedH + // Batch open the first list of polynomials proof.BatchedProof, err = kzg.BatchOpenSinglePoint( [][]fr.Element{ @@ -490,7 +543,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // fills proof.LRO with kzg commits of bcl, bcr and bco func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { - n := runtime.NumCPU() / 2 + n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) @@ -516,7 +569,7 @@ func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { } func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error { - n := runtime.NumCPU() / 2 + n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) @@ -599,26 +652,23 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, Mul(&lagrangeZeta, &alpha). Mul(&lagrangeZeta, &pk.Domain[0].CardinalityInv) // (1/n)*α²*L₁(ζ) - linPol := make([]fr.Element, len(blindedZCanonical)) - copy(linPol, blindedZCanonical) - s3canonical := pk.trace.S3.Coefficients() - utils.Parallelize(len(linPol), func(start, end int) { + utils.Parallelize(len(blindedZCanonical), func(start, end int) { - var t0, t1 fr.Element + var t, t0, t1 fr.Element for i := start; i < end; i++ { - linPol[i].Mul(&linPol[i], &s2) // -Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + t.Mul(&blindedZCanonical[i], &s2) // -Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) if i < len(s3canonical) { t0.Mul(&s3canonical[i], &s1) // (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*β*s3(X) - linPol[i].Add(&linPol[i], &t0) + t.Add(&t, &t0) } - linPol[i].Mul(&linPol[i], &alpha) // α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ)) + t.Mul(&t, &alpha) // α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ)) cql := pk.trace.Ql.Coefficients() cqr := pk.trace.Qr.Coefficients() @@ -630,21 +680,21 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, t1.Mul(&cqm[i], &rl) // linPol = linPol + l(ζ)r(ζ)*Qm(X) t0.Mul(&cql[i], &lZeta) t0.Add(&t0, &t1) - linPol[i].Add(&linPol[i], &t0) // linPol = linPol + l(ζ)*Ql(X) + t.Add(&t, &t0) // linPol = linPol + l(ζ)*Ql(X) t0.Mul(&cqr[i], &rZeta) - linPol[i].Add(&linPol[i], &t0) // linPol = linPol + r(ζ)*Qr(X) + t.Add(&t, &t0) // linPol = linPol + r(ζ)*Qr(X) t0.Mul(&cqo[i], &oZeta).Add(&t0, &cqk[i]) - linPol[i].Add(&linPol[i], &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) + t.Add(&t, &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) t0.Mul(&pi2Canonical[i], &qcpZeta) - linPol[i].Add(&linPol[i], &t0) + t.Add(&t, &t0) } t0.Mul(&blindedZCanonical[i], &lagrangeZeta) - linPol[i].Add(&linPol[i], &t0) // finish the computation + blindedZCanonical[i].Add(&t, &t0) // finish the computation } }) - return linPol + return blindedZCanonical } diff --git a/backend/plonk/bls24-317/setup.go b/backend/plonk/bls24-317/setup.go index d7917e3a36..391b8595b1 100644 --- a/backend/plonk/bls24-317/setup.go +++ b/backend/plonk/bls24-317/setup.go @@ -112,6 +112,9 @@ type ProvingKey struct { // in lagrange coset basis --> these are not serialized, but computed from S1Canonical, S2Canonical, S3Canonical once. lcS1, lcS2, lcS3 *iop.Polynomial + + // in lagrange coset basis --> not serialized id and L_{g^{0}} + lcIdIOP, lLoneIOP *iop.Polynomial } func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) { @@ -176,6 +179,26 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { pk.lcS1 = pk.trace.S1.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcS2 = pk.trace.S2.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcS3 = pk.trace.S3.Clone().ToLagrangeCoset(&pk.Domain[1]) + + // storing Id + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + id := make([]fr.Element, pk.Domain[1].Cardinality) + id[0].Set(&pk.Domain[1].FrMultiplicativeGen) + for i := 1; i < int(pk.Domain[1].Cardinality); i++ { + id[i].Mul(&id[i-1], &pk.Domain[1].Generator) + } + pk.lcIdIOP = iop.NewPolynomial(&id, lagReg) + + // L_{g^{0}} + cap := pk.Domain[1].Cardinality + if cap < pk.Domain[0].Cardinality { + cap = pk.Domain[0].Cardinality // sanity check + } + lone := make([]fr.Element, pk.Domain[0].Cardinality, cap) + lone[0].SetOne() + pk.lLoneIOP = iop.NewPolynomial(&lone, lagReg).ToCanonical(&pk.Domain[0]). + ToRegular(). + ToLagrangeCoset(&pk.Domain[1]) } // NbPublicWitness returns the expected public witness size (number of field elements) diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index 229c1de144..b27a4c15be 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -123,7 +123,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pi2iop := iop.NewPolynomial(&pi2, lagReg) wpi2iop = pi2iop.ShallowClone() - wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + // wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() } // query l, r, o in Lagrange basis, not blinded @@ -131,41 +131,88 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if err != nil { return nil, err } + // TODO @gbotrel deal with that conversion lazily + var lcpi2iop *iop.Polynomial + if spr.CommitmentInfo.Is() { + lcpi2iop = wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form + } else { + coeffs := make([]fr.Element, pk.Domain[1].Cardinality) + lcpi2iop = iop.NewPolynomial(&coeffs, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.Regular}) + } solution := _solution.(*cs.SparseR1CSSolution) evaluationLDomainSmall := []fr.Element(solution.L) evaluationRDomainSmall := []fr.Element(solution.R) evaluationODomainSmall := []fr.Element(solution.O) - liop := iop.NewPolynomial(&evaluationLDomainSmall, lagReg) - riop := iop.NewPolynomial(&evaluationRDomainSmall, lagReg) - oiop := iop.NewPolynomial(&evaluationODomainSmall, lagReg) - wliop := liop.ShallowClone() - wriop := riop.ShallowClone() - woiop := oiop.ShallowClone() - wliop.ToCanonical(&pk.Domain[0]).ToRegular() - wriop.ToCanonical(&pk.Domain[0]).ToRegular() - woiop.ToCanonical(&pk.Domain[0]).ToRegular() - - // Blind l, r, o before committing - // we set the underlying slice capacity to domain[1].Cardinality to minimize mem moves. - bwliop := wliop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) - bwriop := wriop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) - bwoiop := woiop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) - if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Vk.KZGSRS); err != nil { - return nil, err - } + // l, r o and blinded versions + var ( + wliop, + wriop, + woiop, + bwliop, + bwriop, + bwoiop *iop.Polynomial + ) + var wgLRO sync.WaitGroup + wgLRO.Add(3) + go func() { + // we keep in lagrange regular form since iop.BuildRatioCopyConstraint prefers it in this form. + wliop = iop.NewPolynomial(&evaluationLDomainSmall, lagReg) + // we set the underlying slice capacity to domain[1].Cardinality to minimize mem moves. + bwliop = wliop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) + wgLRO.Done() + }() + go func() { + wriop = iop.NewPolynomial(&evaluationRDomainSmall, lagReg) + bwriop = wriop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) + wgLRO.Done() + }() + go func() { + woiop = iop.NewPolynomial(&evaluationODomainSmall, lagReg) + bwoiop = woiop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) + wgLRO.Done() + }() fw, ok := fullWitness.Vector().(fr.Vector) if !ok { return nil, witness.ErrInvalidWitness } + // start computing lcqk + var lcqk *iop.Polynomial + chLcqk := make(chan struct{}, 1) + go func() { + // compute qk in canonical basis, completed with the public inputs + // We copy the coeffs of qk to pk is not mutated + lqkcoef := pk.lQk.Coefficients() + qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) + copy(qkCompletedCanonical, fw[:len(spr.Public)]) + copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) + if spr.CommitmentInfo.Is() { + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal + } + pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) + fft.BitReverse(qkCompletedCanonical) + + canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} + lcqk = iop.NewPolynomial(&qkCompletedCanonical, canReg) + lcqk.ToLagrangeCoset(&pk.Domain[1]) + close(chLcqk) + }() + // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.PI2); err != nil { return nil, err } + + // wait for polys to be blinded + wgLRO.Wait() + if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Vk.KZGSRS); err != nil { + return nil, err + } + gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) // TODO @Tabaie @ThomasPiellard add BSB commitment here? if err != nil { return nil, err @@ -179,15 +226,28 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts var beta fr.Element beta.SetBytes(bbeta) + // l, r, o are already blinded + wgLRO.Add(3) + go func() { + bwliop.ToLagrangeCoset(&pk.Domain[1]) + wgLRO.Done() + }() + go func() { + bwriop.ToLagrangeCoset(&pk.Domain[1]) + wgLRO.Done() + }() + go func() { + bwoiop.ToLagrangeCoset(&pk.Domain[1]) + wgLRO.Done() + }() + // compute the copy constraint's ratio - // We copy liop, riop, oiop because they are fft'ed in the process. - // We could have not copied them at the cost of doing one more bit reverse - // per poly... + // note that wliop, wriop and woiop are fft'ed (mutated) in the process. ziop, err := iop.BuildRatioCopyConstraint( []*iop.Polynomial{ - liop.Clone(), - riop.Clone(), - oiop.Clone(), + wliop, + wriop, + woiop, }, pk.trace.S, beta, @@ -200,63 +260,29 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // commit to the blinded version of z - bwziop := ziop // iop.NewWrappedPolynomial(&ziop) - bwziop.Blind(2) - proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Vk.KZGSRS, runtime.NumCPU()*2) - if err != nil { - return proof, err - } - - // derive alpha from the Comm(l), Comm(r), Comm(o), Com(Z) - alpha, err := deriveRandomness(&fs, "alpha", &proof.Z) - if err != nil { - return proof, err - } + chZ := make(chan error, 1) + var bwziop, bwsziop *iop.Polynomial + var alpha fr.Element + go func() { + bwziop = ziop // iop.NewWrappedPolynomial(&ziop) + bwziop.Blind(2) + proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Vk.KZGSRS, runtime.NumCPU()*2) + if err != nil { + chZ <- err + } - // compute qk in canonical basis, completed with the public inputs - // We copy the coeffs of qk to pk is not mutated - lqkcoef := pk.lQk.Coefficients() - qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) - copy(qkCompletedCanonical, lqkcoef) - copy(qkCompletedCanonical, fw[:len(spr.Public)]) - if spr.CommitmentInfo.Is() { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal - } - pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) - fft.BitReverse(qkCompletedCanonical) + // derive alpha from the Comm(l), Comm(r), Comm(o), Com(Z) + alpha, err = deriveRandomness(&fs, "alpha", &proof.Z) + if err != nil { + chZ <- err + } - // l, r, o are already blinded - bwliop.ToLagrangeCoset(&pk.Domain[1]) - bwriop.ToLagrangeCoset(&pk.Domain[1]) - bwoiop.ToLagrangeCoset(&pk.Domain[1]) - pi2iop := wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form - - // we don't mutate so no need to clone the coefficients from the proving key. - canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} - lcqk := iop.NewPolynomial(&qkCompletedCanonical, canReg) - lcqk.ToLagrangeCoset(&pk.Domain[1]) - - // storing Id - id := make([]fr.Element, pk.Domain[1].Cardinality) - id[1].SetOne() - widiop := iop.NewPolynomial(&id, canReg) - widiop.ToLagrangeCoset(&pk.Domain[1]) - - // Store z(g*x), without reallocating a slice - bwsziop := bwziop.ShallowClone().Shift(1) - bwsziop.ToLagrangeCoset(&pk.Domain[1]) - - // L_{g^{0}} - cap := pk.Domain[1].Cardinality - if cap < pk.Domain[0].Cardinality { - cap = pk.Domain[0].Cardinality // sanity check - } - lone := make([]fr.Element, pk.Domain[0].Cardinality, cap) - lone[0].SetOne() - loneiop := iop.NewPolynomial(&lone, lagReg) - wloneiop := loneiop.ToCanonical(&pk.Domain[0]). - ToRegular(). - ToLagrangeCoset(&pk.Domain[1]) + // Store z(g*x), without reallocating a slice + bwsziop = bwziop.ShallowClone().Shift(1) + bwsziop.ToLagrangeCoset(&pk.Domain[1]) + chZ <- nil + close(chZ) + }() // Full capture using latest gnark crypto... fic := func(fql, fqr, fqm, fqo, fqk, fqCPrime, l, r, o, pi2 fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary @@ -277,15 +303,14 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } fo := func(l, r, o, fid, fs1, fs2, fs3, fz, fzs fr.Element) fr.Element { - var uu fr.Element - u := pk.Domain[0].FrMultiplicativeGen - uu.Mul(&u, &u) - + u := &pk.Domain[0].FrMultiplicativeGen var a, b, tmp fr.Element - a.Mul(&beta, &fid).Add(&a, &l).Add(&a, &gamma) - tmp.Mul(&beta, &u).Mul(&tmp, &fid).Add(&tmp, &r).Add(&tmp, &gamma) + b.Mul(&beta, &fid) + a.Add(&b, &l).Add(&a, &gamma) + b.Mul(&b, u) + tmp.Add(&b, &r).Add(&tmp, &gamma) a.Mul(&a, &tmp) - tmp.Mul(&beta, &uu).Mul(&tmp, &fid).Add(&tmp, &o).Add(&tmp, &gamma) + tmp.Mul(&b, u).Add(&tmp, &o).Add(&tmp, &gamma) a.Mul(&a, &tmp).Mul(&a, &fz) b.Mul(&beta, &fs1).Add(&b, &l).Add(&b, &gamma) @@ -317,28 +342,47 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return c } + + // wait for lcqk + <-chLcqk + + // wait for Z part + if err := <-chZ; err != nil { + return proof, err + } + + // wait for l, r o lagrange coset conversion + wgLRO.Wait() + systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, bwliop, bwriop, bwoiop, - widiop, + pk.lcIdIOP, pk.lcS1, pk.lcS2, pk.lcS3, bwziop, bwsziop, - pi2iop, + lcpi2iop, pk.lcQl, pk.lcQr, pk.lcQm, pk.lcQo, lcqk, pk.lcQcp, - wloneiop, + pk.lLoneIOP, ) if err != nil { return nil, err } + // open blinded Z at zeta*z + chbwzIOP := make(chan struct{}, 1) + go func() { + bwziop.ToCanonical(&pk.Domain[1]).ToRegular() + close(chbwzIOP) + }() + h, err := iop.DivideByXMinusOne(systemEvaluation, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) // TODO Rename to DivideByXNMinusOne or DivideByVanishingPoly etc if err != nil { return nil, err @@ -377,10 +421,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wgEvals.Done() }() - // open blinded Z at zeta*z - bwziop.ToCanonical(&pk.Domain[1]).ToRegular() var zetaShifted fr.Element zetaShifted.Mul(&zeta, &pk.Vk.Generator) + <-chbwzIOP proof.ZShiftedOpening, err = kzg.Open( bwziop.Coefficients()[:bwziop.BlindedSize()], zetaShifted, @@ -390,8 +433,39 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } - // blinded z evaluated at u*zeta - bzuzeta := proof.ZShiftedOpening.ClaimedValue + // start to compute foldedH and foldedHDigest while computeLinearizedPolynomial runs. + computeFoldedH := make(chan struct{}, 1) + var foldedH []fr.Element + var foldedHDigest kzg.Digest + go func() { + // foldedHDigest = Comm(h1) + ζᵐ⁺²*Comm(h2) + ζ²⁽ᵐ⁺²⁾*Comm(h3) + var bZetaPowerm, bSize big.Int + bSize.SetUint64(pk.Domain[0].Cardinality + 2) // +2 because of the masking (h of degree 3(n+2)-1) + var zetaPowerm fr.Element + zetaPowerm.Exp(zeta, &bSize) + zetaPowerm.BigInt(&bZetaPowerm) + foldedHDigest = proof.H[2] + foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) + foldedHDigest.Add(&foldedHDigest, &proof.H[1]) // ζᵐ⁺²*Comm(h3) + foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) + foldedHDigest.Add(&foldedHDigest, &proof.H[0]) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) + Comm(h1) + + // foldedH = h1 + ζ*h2 + ζ²*h3 + foldedH = h.Coefficients()[2*(pk.Domain[0].Cardinality+2) : 3*(pk.Domain[0].Cardinality+2)] + h2 := h.Coefficients()[pk.Domain[0].Cardinality+2 : 2*(pk.Domain[0].Cardinality+2)] + h1 := h.Coefficients()[:pk.Domain[0].Cardinality+2] + utils.Parallelize(len(foldedH), func(start, end int) { + for i := start; i < end; i++ { + foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζᵐ⁺²*h3 + foldedH[i].Add(&foldedH[i], &h2[i]) // ζ^{m+2)*h3+h2 + foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζ²⁽ᵐ⁺²⁾*h3+h2*ζᵐ⁺² + foldedH[i].Add(&foldedH[i], &h1[i]) // ζ^{2(m+2)*h3+ζᵐ⁺²*h2 + h1 + } + }) + close(computeFoldedH) + }() + + wgEvals.Wait() // wait for the evaluations var ( linearizedPolynomialCanonical []fr.Element @@ -399,10 +473,12 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts errLPoly error ) - wgEvals.Wait() // wait for the evaluations + // blinded z evaluated at u*zeta + bzuzeta := proof.ZShiftedOpening.ClaimedValue // compute the linearization polynomial r at zeta // (goal: save committing separately to z, ql, qr, qm, qo, k + // note: we linearizedPolynomialCanonical reuses bwziop memory linearizedPolynomialCanonical = computeLinearizedPolynomial( blzeta, brzeta, @@ -420,37 +496,14 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // TODO this commitment is only necessary to derive the challenge, we should // be able to avoid doing it and get the challenge in another way - linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Vk.KZGSRS) - - // foldedHDigest = Comm(h1) + ζᵐ⁺²*Comm(h2) + ζ²⁽ᵐ⁺²⁾*Comm(h3) - var bZetaPowerm, bSize big.Int - bSize.SetUint64(pk.Domain[0].Cardinality + 2) // +2 because of the masking (h of degree 3(n+2)-1) - var zetaPowerm fr.Element - zetaPowerm.Exp(zeta, &bSize) - zetaPowerm.BigInt(&bZetaPowerm) - foldedHDigest := proof.H[2] - foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) - foldedHDigest.Add(&foldedHDigest, &proof.H[1]) // ζᵐ⁺²*Comm(h3) - foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) - foldedHDigest.Add(&foldedHDigest, &proof.H[0]) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) + Comm(h1) - - // foldedH = h1 + ζ*h2 + ζ²*h3 - foldedH := h.Coefficients()[2*(pk.Domain[0].Cardinality+2) : 3*(pk.Domain[0].Cardinality+2)] - h2 := h.Coefficients()[pk.Domain[0].Cardinality+2 : 2*(pk.Domain[0].Cardinality+2)] - h1 := h.Coefficients()[:pk.Domain[0].Cardinality+2] - utils.Parallelize(len(foldedH), func(start, end int) { - for i := start; i < end; i++ { - foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζᵐ⁺²*h3 - foldedH[i].Add(&foldedH[i], &h2[i]) // ζ^{m+2)*h3+h2 - foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζ²⁽ᵐ⁺²⁾*h3+h2*ζᵐ⁺² - foldedH[i].Add(&foldedH[i], &h1[i]) // ζ^{2(m+2)*h3+ζᵐ⁺²*h2 + h1 - } - }) - + linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Vk.KZGSRS, runtime.NumCPU()*2) if errLPoly != nil { return nil, errLPoly } + // wait for foldedH and foldedHDigest + <-computeFoldedH + // Batch open the first list of polynomials proof.BatchedProof, err = kzg.BatchOpenSinglePoint( [][]fr.Element{ @@ -490,7 +543,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // fills proof.LRO with kzg commits of bcl, bcr and bco func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { - n := runtime.NumCPU() / 2 + n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) @@ -516,7 +569,7 @@ func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { } func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error { - n := runtime.NumCPU() / 2 + n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) @@ -599,26 +652,23 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, Mul(&lagrangeZeta, &alpha). Mul(&lagrangeZeta, &pk.Domain[0].CardinalityInv) // (1/n)*α²*L₁(ζ) - linPol := make([]fr.Element, len(blindedZCanonical)) - copy(linPol, blindedZCanonical) - s3canonical := pk.trace.S3.Coefficients() - utils.Parallelize(len(linPol), func(start, end int) { + utils.Parallelize(len(blindedZCanonical), func(start, end int) { - var t0, t1 fr.Element + var t, t0, t1 fr.Element for i := start; i < end; i++ { - linPol[i].Mul(&linPol[i], &s2) // -Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + t.Mul(&blindedZCanonical[i], &s2) // -Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) if i < len(s3canonical) { t0.Mul(&s3canonical[i], &s1) // (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*β*s3(X) - linPol[i].Add(&linPol[i], &t0) + t.Add(&t, &t0) } - linPol[i].Mul(&linPol[i], &alpha) // α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ)) + t.Mul(&t, &alpha) // α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ)) cql := pk.trace.Ql.Coefficients() cqr := pk.trace.Qr.Coefficients() @@ -630,21 +680,21 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, t1.Mul(&cqm[i], &rl) // linPol = linPol + l(ζ)r(ζ)*Qm(X) t0.Mul(&cql[i], &lZeta) t0.Add(&t0, &t1) - linPol[i].Add(&linPol[i], &t0) // linPol = linPol + l(ζ)*Ql(X) + t.Add(&t, &t0) // linPol = linPol + l(ζ)*Ql(X) t0.Mul(&cqr[i], &rZeta) - linPol[i].Add(&linPol[i], &t0) // linPol = linPol + r(ζ)*Qr(X) + t.Add(&t, &t0) // linPol = linPol + r(ζ)*Qr(X) t0.Mul(&cqo[i], &oZeta).Add(&t0, &cqk[i]) - linPol[i].Add(&linPol[i], &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) + t.Add(&t, &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) t0.Mul(&pi2Canonical[i], &qcpZeta) - linPol[i].Add(&linPol[i], &t0) + t.Add(&t, &t0) } t0.Mul(&blindedZCanonical[i], &lagrangeZeta) - linPol[i].Add(&linPol[i], &t0) // finish the computation + blindedZCanonical[i].Add(&t, &t0) // finish the computation } }) - return linPol + return blindedZCanonical } diff --git a/backend/plonk/bn254/setup.go b/backend/plonk/bn254/setup.go index 8c1c4c4e2b..a4648d7ce0 100644 --- a/backend/plonk/bn254/setup.go +++ b/backend/plonk/bn254/setup.go @@ -112,6 +112,9 @@ type ProvingKey struct { // in lagrange coset basis --> these are not serialized, but computed from S1Canonical, S2Canonical, S3Canonical once. lcS1, lcS2, lcS3 *iop.Polynomial + + // in lagrange coset basis --> not serialized id and L_{g^{0}} + lcIdIOP, lLoneIOP *iop.Polynomial } func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) { @@ -176,6 +179,26 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { pk.lcS1 = pk.trace.S1.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcS2 = pk.trace.S2.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcS3 = pk.trace.S3.Clone().ToLagrangeCoset(&pk.Domain[1]) + + // storing Id + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + id := make([]fr.Element, pk.Domain[1].Cardinality) + id[0].Set(&pk.Domain[1].FrMultiplicativeGen) + for i := 1; i < int(pk.Domain[1].Cardinality); i++ { + id[i].Mul(&id[i-1], &pk.Domain[1].Generator) + } + pk.lcIdIOP = iop.NewPolynomial(&id, lagReg) + + // L_{g^{0}} + cap := pk.Domain[1].Cardinality + if cap < pk.Domain[0].Cardinality { + cap = pk.Domain[0].Cardinality // sanity check + } + lone := make([]fr.Element, pk.Domain[0].Cardinality, cap) + lone[0].SetOne() + pk.lLoneIOP = iop.NewPolynomial(&lone, lagReg).ToCanonical(&pk.Domain[0]). + ToRegular(). + ToLagrangeCoset(&pk.Domain[1]) } // NbPublicWitness returns the expected public witness size (number of field elements) diff --git a/backend/plonk/bw6-633/prove.go b/backend/plonk/bw6-633/prove.go index 41e00da496..031284a8ce 100644 --- a/backend/plonk/bw6-633/prove.go +++ b/backend/plonk/bw6-633/prove.go @@ -123,7 +123,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pi2iop := iop.NewPolynomial(&pi2, lagReg) wpi2iop = pi2iop.ShallowClone() - wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + // wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() } // query l, r, o in Lagrange basis, not blinded @@ -131,41 +131,88 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if err != nil { return nil, err } + // TODO @gbotrel deal with that conversion lazily + var lcpi2iop *iop.Polynomial + if spr.CommitmentInfo.Is() { + lcpi2iop = wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form + } else { + coeffs := make([]fr.Element, pk.Domain[1].Cardinality) + lcpi2iop = iop.NewPolynomial(&coeffs, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.Regular}) + } solution := _solution.(*cs.SparseR1CSSolution) evaluationLDomainSmall := []fr.Element(solution.L) evaluationRDomainSmall := []fr.Element(solution.R) evaluationODomainSmall := []fr.Element(solution.O) - liop := iop.NewPolynomial(&evaluationLDomainSmall, lagReg) - riop := iop.NewPolynomial(&evaluationRDomainSmall, lagReg) - oiop := iop.NewPolynomial(&evaluationODomainSmall, lagReg) - wliop := liop.ShallowClone() - wriop := riop.ShallowClone() - woiop := oiop.ShallowClone() - wliop.ToCanonical(&pk.Domain[0]).ToRegular() - wriop.ToCanonical(&pk.Domain[0]).ToRegular() - woiop.ToCanonical(&pk.Domain[0]).ToRegular() - - // Blind l, r, o before committing - // we set the underlying slice capacity to domain[1].Cardinality to minimize mem moves. - bwliop := wliop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) - bwriop := wriop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) - bwoiop := woiop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) - if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Vk.KZGSRS); err != nil { - return nil, err - } + // l, r o and blinded versions + var ( + wliop, + wriop, + woiop, + bwliop, + bwriop, + bwoiop *iop.Polynomial + ) + var wgLRO sync.WaitGroup + wgLRO.Add(3) + go func() { + // we keep in lagrange regular form since iop.BuildRatioCopyConstraint prefers it in this form. + wliop = iop.NewPolynomial(&evaluationLDomainSmall, lagReg) + // we set the underlying slice capacity to domain[1].Cardinality to minimize mem moves. + bwliop = wliop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) + wgLRO.Done() + }() + go func() { + wriop = iop.NewPolynomial(&evaluationRDomainSmall, lagReg) + bwriop = wriop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) + wgLRO.Done() + }() + go func() { + woiop = iop.NewPolynomial(&evaluationODomainSmall, lagReg) + bwoiop = woiop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) + wgLRO.Done() + }() fw, ok := fullWitness.Vector().(fr.Vector) if !ok { return nil, witness.ErrInvalidWitness } + // start computing lcqk + var lcqk *iop.Polynomial + chLcqk := make(chan struct{}, 1) + go func() { + // compute qk in canonical basis, completed with the public inputs + // We copy the coeffs of qk to pk is not mutated + lqkcoef := pk.lQk.Coefficients() + qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) + copy(qkCompletedCanonical, fw[:len(spr.Public)]) + copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) + if spr.CommitmentInfo.Is() { + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal + } + pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) + fft.BitReverse(qkCompletedCanonical) + + canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} + lcqk = iop.NewPolynomial(&qkCompletedCanonical, canReg) + lcqk.ToLagrangeCoset(&pk.Domain[1]) + close(chLcqk) + }() + // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.PI2); err != nil { return nil, err } + + // wait for polys to be blinded + wgLRO.Wait() + if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Vk.KZGSRS); err != nil { + return nil, err + } + gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) // TODO @Tabaie @ThomasPiellard add BSB commitment here? if err != nil { return nil, err @@ -179,15 +226,28 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts var beta fr.Element beta.SetBytes(bbeta) + // l, r, o are already blinded + wgLRO.Add(3) + go func() { + bwliop.ToLagrangeCoset(&pk.Domain[1]) + wgLRO.Done() + }() + go func() { + bwriop.ToLagrangeCoset(&pk.Domain[1]) + wgLRO.Done() + }() + go func() { + bwoiop.ToLagrangeCoset(&pk.Domain[1]) + wgLRO.Done() + }() + // compute the copy constraint's ratio - // We copy liop, riop, oiop because they are fft'ed in the process. - // We could have not copied them at the cost of doing one more bit reverse - // per poly... + // note that wliop, wriop and woiop are fft'ed (mutated) in the process. ziop, err := iop.BuildRatioCopyConstraint( []*iop.Polynomial{ - liop.Clone(), - riop.Clone(), - oiop.Clone(), + wliop, + wriop, + woiop, }, pk.trace.S, beta, @@ -200,63 +260,29 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // commit to the blinded version of z - bwziop := ziop // iop.NewWrappedPolynomial(&ziop) - bwziop.Blind(2) - proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Vk.KZGSRS, runtime.NumCPU()*2) - if err != nil { - return proof, err - } - - // derive alpha from the Comm(l), Comm(r), Comm(o), Com(Z) - alpha, err := deriveRandomness(&fs, "alpha", &proof.Z) - if err != nil { - return proof, err - } + chZ := make(chan error, 1) + var bwziop, bwsziop *iop.Polynomial + var alpha fr.Element + go func() { + bwziop = ziop // iop.NewWrappedPolynomial(&ziop) + bwziop.Blind(2) + proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Vk.KZGSRS, runtime.NumCPU()*2) + if err != nil { + chZ <- err + } - // compute qk in canonical basis, completed with the public inputs - // We copy the coeffs of qk to pk is not mutated - lqkcoef := pk.lQk.Coefficients() - qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) - copy(qkCompletedCanonical, lqkcoef) - copy(qkCompletedCanonical, fw[:len(spr.Public)]) - if spr.CommitmentInfo.Is() { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal - } - pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) - fft.BitReverse(qkCompletedCanonical) + // derive alpha from the Comm(l), Comm(r), Comm(o), Com(Z) + alpha, err = deriveRandomness(&fs, "alpha", &proof.Z) + if err != nil { + chZ <- err + } - // l, r, o are already blinded - bwliop.ToLagrangeCoset(&pk.Domain[1]) - bwriop.ToLagrangeCoset(&pk.Domain[1]) - bwoiop.ToLagrangeCoset(&pk.Domain[1]) - pi2iop := wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form - - // we don't mutate so no need to clone the coefficients from the proving key. - canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} - lcqk := iop.NewPolynomial(&qkCompletedCanonical, canReg) - lcqk.ToLagrangeCoset(&pk.Domain[1]) - - // storing Id - id := make([]fr.Element, pk.Domain[1].Cardinality) - id[1].SetOne() - widiop := iop.NewPolynomial(&id, canReg) - widiop.ToLagrangeCoset(&pk.Domain[1]) - - // Store z(g*x), without reallocating a slice - bwsziop := bwziop.ShallowClone().Shift(1) - bwsziop.ToLagrangeCoset(&pk.Domain[1]) - - // L_{g^{0}} - cap := pk.Domain[1].Cardinality - if cap < pk.Domain[0].Cardinality { - cap = pk.Domain[0].Cardinality // sanity check - } - lone := make([]fr.Element, pk.Domain[0].Cardinality, cap) - lone[0].SetOne() - loneiop := iop.NewPolynomial(&lone, lagReg) - wloneiop := loneiop.ToCanonical(&pk.Domain[0]). - ToRegular(). - ToLagrangeCoset(&pk.Domain[1]) + // Store z(g*x), without reallocating a slice + bwsziop = bwziop.ShallowClone().Shift(1) + bwsziop.ToLagrangeCoset(&pk.Domain[1]) + chZ <- nil + close(chZ) + }() // Full capture using latest gnark crypto... fic := func(fql, fqr, fqm, fqo, fqk, fqCPrime, l, r, o, pi2 fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary @@ -277,15 +303,14 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } fo := func(l, r, o, fid, fs1, fs2, fs3, fz, fzs fr.Element) fr.Element { - var uu fr.Element - u := pk.Domain[0].FrMultiplicativeGen - uu.Mul(&u, &u) - + u := &pk.Domain[0].FrMultiplicativeGen var a, b, tmp fr.Element - a.Mul(&beta, &fid).Add(&a, &l).Add(&a, &gamma) - tmp.Mul(&beta, &u).Mul(&tmp, &fid).Add(&tmp, &r).Add(&tmp, &gamma) + b.Mul(&beta, &fid) + a.Add(&b, &l).Add(&a, &gamma) + b.Mul(&b, u) + tmp.Add(&b, &r).Add(&tmp, &gamma) a.Mul(&a, &tmp) - tmp.Mul(&beta, &uu).Mul(&tmp, &fid).Add(&tmp, &o).Add(&tmp, &gamma) + tmp.Mul(&b, u).Add(&tmp, &o).Add(&tmp, &gamma) a.Mul(&a, &tmp).Mul(&a, &fz) b.Mul(&beta, &fs1).Add(&b, &l).Add(&b, &gamma) @@ -317,28 +342,47 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return c } + + // wait for lcqk + <-chLcqk + + // wait for Z part + if err := <-chZ; err != nil { + return proof, err + } + + // wait for l, r o lagrange coset conversion + wgLRO.Wait() + systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, bwliop, bwriop, bwoiop, - widiop, + pk.lcIdIOP, pk.lcS1, pk.lcS2, pk.lcS3, bwziop, bwsziop, - pi2iop, + lcpi2iop, pk.lcQl, pk.lcQr, pk.lcQm, pk.lcQo, lcqk, pk.lcQcp, - wloneiop, + pk.lLoneIOP, ) if err != nil { return nil, err } + // open blinded Z at zeta*z + chbwzIOP := make(chan struct{}, 1) + go func() { + bwziop.ToCanonical(&pk.Domain[1]).ToRegular() + close(chbwzIOP) + }() + h, err := iop.DivideByXMinusOne(systemEvaluation, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) // TODO Rename to DivideByXNMinusOne or DivideByVanishingPoly etc if err != nil { return nil, err @@ -377,10 +421,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wgEvals.Done() }() - // open blinded Z at zeta*z - bwziop.ToCanonical(&pk.Domain[1]).ToRegular() var zetaShifted fr.Element zetaShifted.Mul(&zeta, &pk.Vk.Generator) + <-chbwzIOP proof.ZShiftedOpening, err = kzg.Open( bwziop.Coefficients()[:bwziop.BlindedSize()], zetaShifted, @@ -390,8 +433,39 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } - // blinded z evaluated at u*zeta - bzuzeta := proof.ZShiftedOpening.ClaimedValue + // start to compute foldedH and foldedHDigest while computeLinearizedPolynomial runs. + computeFoldedH := make(chan struct{}, 1) + var foldedH []fr.Element + var foldedHDigest kzg.Digest + go func() { + // foldedHDigest = Comm(h1) + ζᵐ⁺²*Comm(h2) + ζ²⁽ᵐ⁺²⁾*Comm(h3) + var bZetaPowerm, bSize big.Int + bSize.SetUint64(pk.Domain[0].Cardinality + 2) // +2 because of the masking (h of degree 3(n+2)-1) + var zetaPowerm fr.Element + zetaPowerm.Exp(zeta, &bSize) + zetaPowerm.BigInt(&bZetaPowerm) + foldedHDigest = proof.H[2] + foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) + foldedHDigest.Add(&foldedHDigest, &proof.H[1]) // ζᵐ⁺²*Comm(h3) + foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) + foldedHDigest.Add(&foldedHDigest, &proof.H[0]) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) + Comm(h1) + + // foldedH = h1 + ζ*h2 + ζ²*h3 + foldedH = h.Coefficients()[2*(pk.Domain[0].Cardinality+2) : 3*(pk.Domain[0].Cardinality+2)] + h2 := h.Coefficients()[pk.Domain[0].Cardinality+2 : 2*(pk.Domain[0].Cardinality+2)] + h1 := h.Coefficients()[:pk.Domain[0].Cardinality+2] + utils.Parallelize(len(foldedH), func(start, end int) { + for i := start; i < end; i++ { + foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζᵐ⁺²*h3 + foldedH[i].Add(&foldedH[i], &h2[i]) // ζ^{m+2)*h3+h2 + foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζ²⁽ᵐ⁺²⁾*h3+h2*ζᵐ⁺² + foldedH[i].Add(&foldedH[i], &h1[i]) // ζ^{2(m+2)*h3+ζᵐ⁺²*h2 + h1 + } + }) + close(computeFoldedH) + }() + + wgEvals.Wait() // wait for the evaluations var ( linearizedPolynomialCanonical []fr.Element @@ -399,10 +473,12 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts errLPoly error ) - wgEvals.Wait() // wait for the evaluations + // blinded z evaluated at u*zeta + bzuzeta := proof.ZShiftedOpening.ClaimedValue // compute the linearization polynomial r at zeta // (goal: save committing separately to z, ql, qr, qm, qo, k + // note: we linearizedPolynomialCanonical reuses bwziop memory linearizedPolynomialCanonical = computeLinearizedPolynomial( blzeta, brzeta, @@ -420,37 +496,14 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // TODO this commitment is only necessary to derive the challenge, we should // be able to avoid doing it and get the challenge in another way - linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Vk.KZGSRS) - - // foldedHDigest = Comm(h1) + ζᵐ⁺²*Comm(h2) + ζ²⁽ᵐ⁺²⁾*Comm(h3) - var bZetaPowerm, bSize big.Int - bSize.SetUint64(pk.Domain[0].Cardinality + 2) // +2 because of the masking (h of degree 3(n+2)-1) - var zetaPowerm fr.Element - zetaPowerm.Exp(zeta, &bSize) - zetaPowerm.BigInt(&bZetaPowerm) - foldedHDigest := proof.H[2] - foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) - foldedHDigest.Add(&foldedHDigest, &proof.H[1]) // ζᵐ⁺²*Comm(h3) - foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) - foldedHDigest.Add(&foldedHDigest, &proof.H[0]) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) + Comm(h1) - - // foldedH = h1 + ζ*h2 + ζ²*h3 - foldedH := h.Coefficients()[2*(pk.Domain[0].Cardinality+2) : 3*(pk.Domain[0].Cardinality+2)] - h2 := h.Coefficients()[pk.Domain[0].Cardinality+2 : 2*(pk.Domain[0].Cardinality+2)] - h1 := h.Coefficients()[:pk.Domain[0].Cardinality+2] - utils.Parallelize(len(foldedH), func(start, end int) { - for i := start; i < end; i++ { - foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζᵐ⁺²*h3 - foldedH[i].Add(&foldedH[i], &h2[i]) // ζ^{m+2)*h3+h2 - foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζ²⁽ᵐ⁺²⁾*h3+h2*ζᵐ⁺² - foldedH[i].Add(&foldedH[i], &h1[i]) // ζ^{2(m+2)*h3+ζᵐ⁺²*h2 + h1 - } - }) - + linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Vk.KZGSRS, runtime.NumCPU()*2) if errLPoly != nil { return nil, errLPoly } + // wait for foldedH and foldedHDigest + <-computeFoldedH + // Batch open the first list of polynomials proof.BatchedProof, err = kzg.BatchOpenSinglePoint( [][]fr.Element{ @@ -490,7 +543,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // fills proof.LRO with kzg commits of bcl, bcr and bco func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { - n := runtime.NumCPU() / 2 + n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) @@ -516,7 +569,7 @@ func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { } func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error { - n := runtime.NumCPU() / 2 + n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) @@ -599,26 +652,23 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, Mul(&lagrangeZeta, &alpha). Mul(&lagrangeZeta, &pk.Domain[0].CardinalityInv) // (1/n)*α²*L₁(ζ) - linPol := make([]fr.Element, len(blindedZCanonical)) - copy(linPol, blindedZCanonical) - s3canonical := pk.trace.S3.Coefficients() - utils.Parallelize(len(linPol), func(start, end int) { + utils.Parallelize(len(blindedZCanonical), func(start, end int) { - var t0, t1 fr.Element + var t, t0, t1 fr.Element for i := start; i < end; i++ { - linPol[i].Mul(&linPol[i], &s2) // -Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + t.Mul(&blindedZCanonical[i], &s2) // -Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) if i < len(s3canonical) { t0.Mul(&s3canonical[i], &s1) // (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*β*s3(X) - linPol[i].Add(&linPol[i], &t0) + t.Add(&t, &t0) } - linPol[i].Mul(&linPol[i], &alpha) // α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ)) + t.Mul(&t, &alpha) // α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ)) cql := pk.trace.Ql.Coefficients() cqr := pk.trace.Qr.Coefficients() @@ -630,21 +680,21 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, t1.Mul(&cqm[i], &rl) // linPol = linPol + l(ζ)r(ζ)*Qm(X) t0.Mul(&cql[i], &lZeta) t0.Add(&t0, &t1) - linPol[i].Add(&linPol[i], &t0) // linPol = linPol + l(ζ)*Ql(X) + t.Add(&t, &t0) // linPol = linPol + l(ζ)*Ql(X) t0.Mul(&cqr[i], &rZeta) - linPol[i].Add(&linPol[i], &t0) // linPol = linPol + r(ζ)*Qr(X) + t.Add(&t, &t0) // linPol = linPol + r(ζ)*Qr(X) t0.Mul(&cqo[i], &oZeta).Add(&t0, &cqk[i]) - linPol[i].Add(&linPol[i], &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) + t.Add(&t, &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) t0.Mul(&pi2Canonical[i], &qcpZeta) - linPol[i].Add(&linPol[i], &t0) + t.Add(&t, &t0) } t0.Mul(&blindedZCanonical[i], &lagrangeZeta) - linPol[i].Add(&linPol[i], &t0) // finish the computation + blindedZCanonical[i].Add(&t, &t0) // finish the computation } }) - return linPol + return blindedZCanonical } diff --git a/backend/plonk/bw6-633/setup.go b/backend/plonk/bw6-633/setup.go index 9ecea2e1c2..ad0a65d154 100644 --- a/backend/plonk/bw6-633/setup.go +++ b/backend/plonk/bw6-633/setup.go @@ -112,6 +112,9 @@ type ProvingKey struct { // in lagrange coset basis --> these are not serialized, but computed from S1Canonical, S2Canonical, S3Canonical once. lcS1, lcS2, lcS3 *iop.Polynomial + + // in lagrange coset basis --> not serialized id and L_{g^{0}} + lcIdIOP, lLoneIOP *iop.Polynomial } func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) { @@ -176,6 +179,26 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { pk.lcS1 = pk.trace.S1.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcS2 = pk.trace.S2.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcS3 = pk.trace.S3.Clone().ToLagrangeCoset(&pk.Domain[1]) + + // storing Id + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + id := make([]fr.Element, pk.Domain[1].Cardinality) + id[0].Set(&pk.Domain[1].FrMultiplicativeGen) + for i := 1; i < int(pk.Domain[1].Cardinality); i++ { + id[i].Mul(&id[i-1], &pk.Domain[1].Generator) + } + pk.lcIdIOP = iop.NewPolynomial(&id, lagReg) + + // L_{g^{0}} + cap := pk.Domain[1].Cardinality + if cap < pk.Domain[0].Cardinality { + cap = pk.Domain[0].Cardinality // sanity check + } + lone := make([]fr.Element, pk.Domain[0].Cardinality, cap) + lone[0].SetOne() + pk.lLoneIOP = iop.NewPolynomial(&lone, lagReg).ToCanonical(&pk.Domain[0]). + ToRegular(). + ToLagrangeCoset(&pk.Domain[1]) } // NbPublicWitness returns the expected public witness size (number of field elements) diff --git a/backend/plonk/bw6-761/prove.go b/backend/plonk/bw6-761/prove.go index f844d7b22a..29c32cac7b 100644 --- a/backend/plonk/bw6-761/prove.go +++ b/backend/plonk/bw6-761/prove.go @@ -123,7 +123,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pi2iop := iop.NewPolynomial(&pi2, lagReg) wpi2iop = pi2iop.ShallowClone() - wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + // wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() } // query l, r, o in Lagrange basis, not blinded @@ -131,41 +131,88 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if err != nil { return nil, err } + // TODO @gbotrel deal with that conversion lazily + var lcpi2iop *iop.Polynomial + if spr.CommitmentInfo.Is() { + lcpi2iop = wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form + } else { + coeffs := make([]fr.Element, pk.Domain[1].Cardinality) + lcpi2iop = iop.NewPolynomial(&coeffs, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.Regular}) + } solution := _solution.(*cs.SparseR1CSSolution) evaluationLDomainSmall := []fr.Element(solution.L) evaluationRDomainSmall := []fr.Element(solution.R) evaluationODomainSmall := []fr.Element(solution.O) - liop := iop.NewPolynomial(&evaluationLDomainSmall, lagReg) - riop := iop.NewPolynomial(&evaluationRDomainSmall, lagReg) - oiop := iop.NewPolynomial(&evaluationODomainSmall, lagReg) - wliop := liop.ShallowClone() - wriop := riop.ShallowClone() - woiop := oiop.ShallowClone() - wliop.ToCanonical(&pk.Domain[0]).ToRegular() - wriop.ToCanonical(&pk.Domain[0]).ToRegular() - woiop.ToCanonical(&pk.Domain[0]).ToRegular() - - // Blind l, r, o before committing - // we set the underlying slice capacity to domain[1].Cardinality to minimize mem moves. - bwliop := wliop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) - bwriop := wriop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) - bwoiop := woiop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) - if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Vk.KZGSRS); err != nil { - return nil, err - } + // l, r o and blinded versions + var ( + wliop, + wriop, + woiop, + bwliop, + bwriop, + bwoiop *iop.Polynomial + ) + var wgLRO sync.WaitGroup + wgLRO.Add(3) + go func() { + // we keep in lagrange regular form since iop.BuildRatioCopyConstraint prefers it in this form. + wliop = iop.NewPolynomial(&evaluationLDomainSmall, lagReg) + // we set the underlying slice capacity to domain[1].Cardinality to minimize mem moves. + bwliop = wliop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) + wgLRO.Done() + }() + go func() { + wriop = iop.NewPolynomial(&evaluationRDomainSmall, lagReg) + bwriop = wriop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) + wgLRO.Done() + }() + go func() { + woiop = iop.NewPolynomial(&evaluationODomainSmall, lagReg) + bwoiop = woiop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) + wgLRO.Done() + }() fw, ok := fullWitness.Vector().(fr.Vector) if !ok { return nil, witness.ErrInvalidWitness } + // start computing lcqk + var lcqk *iop.Polynomial + chLcqk := make(chan struct{}, 1) + go func() { + // compute qk in canonical basis, completed with the public inputs + // We copy the coeffs of qk to pk is not mutated + lqkcoef := pk.lQk.Coefficients() + qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) + copy(qkCompletedCanonical, fw[:len(spr.Public)]) + copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) + if spr.CommitmentInfo.Is() { + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal + } + pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) + fft.BitReverse(qkCompletedCanonical) + + canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} + lcqk = iop.NewPolynomial(&qkCompletedCanonical, canReg) + lcqk.ToLagrangeCoset(&pk.Domain[1]) + close(chLcqk) + }() + // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.PI2); err != nil { return nil, err } + + // wait for polys to be blinded + wgLRO.Wait() + if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Vk.KZGSRS); err != nil { + return nil, err + } + gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) // TODO @Tabaie @ThomasPiellard add BSB commitment here? if err != nil { return nil, err @@ -179,15 +226,28 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts var beta fr.Element beta.SetBytes(bbeta) + // l, r, o are already blinded + wgLRO.Add(3) + go func() { + bwliop.ToLagrangeCoset(&pk.Domain[1]) + wgLRO.Done() + }() + go func() { + bwriop.ToLagrangeCoset(&pk.Domain[1]) + wgLRO.Done() + }() + go func() { + bwoiop.ToLagrangeCoset(&pk.Domain[1]) + wgLRO.Done() + }() + // compute the copy constraint's ratio - // We copy liop, riop, oiop because they are fft'ed in the process. - // We could have not copied them at the cost of doing one more bit reverse - // per poly... + // note that wliop, wriop and woiop are fft'ed (mutated) in the process. ziop, err := iop.BuildRatioCopyConstraint( []*iop.Polynomial{ - liop.Clone(), - riop.Clone(), - oiop.Clone(), + wliop, + wriop, + woiop, }, pk.trace.S, beta, @@ -200,63 +260,29 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // commit to the blinded version of z - bwziop := ziop // iop.NewWrappedPolynomial(&ziop) - bwziop.Blind(2) - proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Vk.KZGSRS, runtime.NumCPU()*2) - if err != nil { - return proof, err - } - - // derive alpha from the Comm(l), Comm(r), Comm(o), Com(Z) - alpha, err := deriveRandomness(&fs, "alpha", &proof.Z) - if err != nil { - return proof, err - } + chZ := make(chan error, 1) + var bwziop, bwsziop *iop.Polynomial + var alpha fr.Element + go func() { + bwziop = ziop // iop.NewWrappedPolynomial(&ziop) + bwziop.Blind(2) + proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Vk.KZGSRS, runtime.NumCPU()*2) + if err != nil { + chZ <- err + } - // compute qk in canonical basis, completed with the public inputs - // We copy the coeffs of qk to pk is not mutated - lqkcoef := pk.lQk.Coefficients() - qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) - copy(qkCompletedCanonical, lqkcoef) - copy(qkCompletedCanonical, fw[:len(spr.Public)]) - if spr.CommitmentInfo.Is() { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal - } - pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) - fft.BitReverse(qkCompletedCanonical) + // derive alpha from the Comm(l), Comm(r), Comm(o), Com(Z) + alpha, err = deriveRandomness(&fs, "alpha", &proof.Z) + if err != nil { + chZ <- err + } - // l, r, o are already blinded - bwliop.ToLagrangeCoset(&pk.Domain[1]) - bwriop.ToLagrangeCoset(&pk.Domain[1]) - bwoiop.ToLagrangeCoset(&pk.Domain[1]) - pi2iop := wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form - - // we don't mutate so no need to clone the coefficients from the proving key. - canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} - lcqk := iop.NewPolynomial(&qkCompletedCanonical, canReg) - lcqk.ToLagrangeCoset(&pk.Domain[1]) - - // storing Id - id := make([]fr.Element, pk.Domain[1].Cardinality) - id[1].SetOne() - widiop := iop.NewPolynomial(&id, canReg) - widiop.ToLagrangeCoset(&pk.Domain[1]) - - // Store z(g*x), without reallocating a slice - bwsziop := bwziop.ShallowClone().Shift(1) - bwsziop.ToLagrangeCoset(&pk.Domain[1]) - - // L_{g^{0}} - cap := pk.Domain[1].Cardinality - if cap < pk.Domain[0].Cardinality { - cap = pk.Domain[0].Cardinality // sanity check - } - lone := make([]fr.Element, pk.Domain[0].Cardinality, cap) - lone[0].SetOne() - loneiop := iop.NewPolynomial(&lone, lagReg) - wloneiop := loneiop.ToCanonical(&pk.Domain[0]). - ToRegular(). - ToLagrangeCoset(&pk.Domain[1]) + // Store z(g*x), without reallocating a slice + bwsziop = bwziop.ShallowClone().Shift(1) + bwsziop.ToLagrangeCoset(&pk.Domain[1]) + chZ <- nil + close(chZ) + }() // Full capture using latest gnark crypto... fic := func(fql, fqr, fqm, fqo, fqk, fqCPrime, l, r, o, pi2 fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary @@ -277,15 +303,14 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } fo := func(l, r, o, fid, fs1, fs2, fs3, fz, fzs fr.Element) fr.Element { - var uu fr.Element - u := pk.Domain[0].FrMultiplicativeGen - uu.Mul(&u, &u) - + u := &pk.Domain[0].FrMultiplicativeGen var a, b, tmp fr.Element - a.Mul(&beta, &fid).Add(&a, &l).Add(&a, &gamma) - tmp.Mul(&beta, &u).Mul(&tmp, &fid).Add(&tmp, &r).Add(&tmp, &gamma) + b.Mul(&beta, &fid) + a.Add(&b, &l).Add(&a, &gamma) + b.Mul(&b, u) + tmp.Add(&b, &r).Add(&tmp, &gamma) a.Mul(&a, &tmp) - tmp.Mul(&beta, &uu).Mul(&tmp, &fid).Add(&tmp, &o).Add(&tmp, &gamma) + tmp.Mul(&b, u).Add(&tmp, &o).Add(&tmp, &gamma) a.Mul(&a, &tmp).Mul(&a, &fz) b.Mul(&beta, &fs1).Add(&b, &l).Add(&b, &gamma) @@ -317,28 +342,47 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return c } + + // wait for lcqk + <-chLcqk + + // wait for Z part + if err := <-chZ; err != nil { + return proof, err + } + + // wait for l, r o lagrange coset conversion + wgLRO.Wait() + systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, bwliop, bwriop, bwoiop, - widiop, + pk.lcIdIOP, pk.lcS1, pk.lcS2, pk.lcS3, bwziop, bwsziop, - pi2iop, + lcpi2iop, pk.lcQl, pk.lcQr, pk.lcQm, pk.lcQo, lcqk, pk.lcQcp, - wloneiop, + pk.lLoneIOP, ) if err != nil { return nil, err } + // open blinded Z at zeta*z + chbwzIOP := make(chan struct{}, 1) + go func() { + bwziop.ToCanonical(&pk.Domain[1]).ToRegular() + close(chbwzIOP) + }() + h, err := iop.DivideByXMinusOne(systemEvaluation, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) // TODO Rename to DivideByXNMinusOne or DivideByVanishingPoly etc if err != nil { return nil, err @@ -377,10 +421,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wgEvals.Done() }() - // open blinded Z at zeta*z - bwziop.ToCanonical(&pk.Domain[1]).ToRegular() var zetaShifted fr.Element zetaShifted.Mul(&zeta, &pk.Vk.Generator) + <-chbwzIOP proof.ZShiftedOpening, err = kzg.Open( bwziop.Coefficients()[:bwziop.BlindedSize()], zetaShifted, @@ -390,8 +433,39 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } - // blinded z evaluated at u*zeta - bzuzeta := proof.ZShiftedOpening.ClaimedValue + // start to compute foldedH and foldedHDigest while computeLinearizedPolynomial runs. + computeFoldedH := make(chan struct{}, 1) + var foldedH []fr.Element + var foldedHDigest kzg.Digest + go func() { + // foldedHDigest = Comm(h1) + ζᵐ⁺²*Comm(h2) + ζ²⁽ᵐ⁺²⁾*Comm(h3) + var bZetaPowerm, bSize big.Int + bSize.SetUint64(pk.Domain[0].Cardinality + 2) // +2 because of the masking (h of degree 3(n+2)-1) + var zetaPowerm fr.Element + zetaPowerm.Exp(zeta, &bSize) + zetaPowerm.BigInt(&bZetaPowerm) + foldedHDigest = proof.H[2] + foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) + foldedHDigest.Add(&foldedHDigest, &proof.H[1]) // ζᵐ⁺²*Comm(h3) + foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) + foldedHDigest.Add(&foldedHDigest, &proof.H[0]) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) + Comm(h1) + + // foldedH = h1 + ζ*h2 + ζ²*h3 + foldedH = h.Coefficients()[2*(pk.Domain[0].Cardinality+2) : 3*(pk.Domain[0].Cardinality+2)] + h2 := h.Coefficients()[pk.Domain[0].Cardinality+2 : 2*(pk.Domain[0].Cardinality+2)] + h1 := h.Coefficients()[:pk.Domain[0].Cardinality+2] + utils.Parallelize(len(foldedH), func(start, end int) { + for i := start; i < end; i++ { + foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζᵐ⁺²*h3 + foldedH[i].Add(&foldedH[i], &h2[i]) // ζ^{m+2)*h3+h2 + foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζ²⁽ᵐ⁺²⁾*h3+h2*ζᵐ⁺² + foldedH[i].Add(&foldedH[i], &h1[i]) // ζ^{2(m+2)*h3+ζᵐ⁺²*h2 + h1 + } + }) + close(computeFoldedH) + }() + + wgEvals.Wait() // wait for the evaluations var ( linearizedPolynomialCanonical []fr.Element @@ -399,10 +473,12 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts errLPoly error ) - wgEvals.Wait() // wait for the evaluations + // blinded z evaluated at u*zeta + bzuzeta := proof.ZShiftedOpening.ClaimedValue // compute the linearization polynomial r at zeta // (goal: save committing separately to z, ql, qr, qm, qo, k + // note: we linearizedPolynomialCanonical reuses bwziop memory linearizedPolynomialCanonical = computeLinearizedPolynomial( blzeta, brzeta, @@ -420,37 +496,14 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // TODO this commitment is only necessary to derive the challenge, we should // be able to avoid doing it and get the challenge in another way - linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Vk.KZGSRS) - - // foldedHDigest = Comm(h1) + ζᵐ⁺²*Comm(h2) + ζ²⁽ᵐ⁺²⁾*Comm(h3) - var bZetaPowerm, bSize big.Int - bSize.SetUint64(pk.Domain[0].Cardinality + 2) // +2 because of the masking (h of degree 3(n+2)-1) - var zetaPowerm fr.Element - zetaPowerm.Exp(zeta, &bSize) - zetaPowerm.BigInt(&bZetaPowerm) - foldedHDigest := proof.H[2] - foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) - foldedHDigest.Add(&foldedHDigest, &proof.H[1]) // ζᵐ⁺²*Comm(h3) - foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) - foldedHDigest.Add(&foldedHDigest, &proof.H[0]) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) + Comm(h1) - - // foldedH = h1 + ζ*h2 + ζ²*h3 - foldedH := h.Coefficients()[2*(pk.Domain[0].Cardinality+2) : 3*(pk.Domain[0].Cardinality+2)] - h2 := h.Coefficients()[pk.Domain[0].Cardinality+2 : 2*(pk.Domain[0].Cardinality+2)] - h1 := h.Coefficients()[:pk.Domain[0].Cardinality+2] - utils.Parallelize(len(foldedH), func(start, end int) { - for i := start; i < end; i++ { - foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζᵐ⁺²*h3 - foldedH[i].Add(&foldedH[i], &h2[i]) // ζ^{m+2)*h3+h2 - foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζ²⁽ᵐ⁺²⁾*h3+h2*ζᵐ⁺² - foldedH[i].Add(&foldedH[i], &h1[i]) // ζ^{2(m+2)*h3+ζᵐ⁺²*h2 + h1 - } - }) - + linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Vk.KZGSRS, runtime.NumCPU()*2) if errLPoly != nil { return nil, errLPoly } + // wait for foldedH and foldedHDigest + <-computeFoldedH + // Batch open the first list of polynomials proof.BatchedProof, err = kzg.BatchOpenSinglePoint( [][]fr.Element{ @@ -490,7 +543,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // fills proof.LRO with kzg commits of bcl, bcr and bco func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { - n := runtime.NumCPU() / 2 + n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) @@ -516,7 +569,7 @@ func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { } func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error { - n := runtime.NumCPU() / 2 + n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) @@ -599,26 +652,23 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, Mul(&lagrangeZeta, &alpha). Mul(&lagrangeZeta, &pk.Domain[0].CardinalityInv) // (1/n)*α²*L₁(ζ) - linPol := make([]fr.Element, len(blindedZCanonical)) - copy(linPol, blindedZCanonical) - s3canonical := pk.trace.S3.Coefficients() - utils.Parallelize(len(linPol), func(start, end int) { + utils.Parallelize(len(blindedZCanonical), func(start, end int) { - var t0, t1 fr.Element + var t, t0, t1 fr.Element for i := start; i < end; i++ { - linPol[i].Mul(&linPol[i], &s2) // -Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + t.Mul(&blindedZCanonical[i], &s2) // -Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) if i < len(s3canonical) { t0.Mul(&s3canonical[i], &s1) // (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*β*s3(X) - linPol[i].Add(&linPol[i], &t0) + t.Add(&t, &t0) } - linPol[i].Mul(&linPol[i], &alpha) // α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ)) + t.Mul(&t, &alpha) // α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ)) cql := pk.trace.Ql.Coefficients() cqr := pk.trace.Qr.Coefficients() @@ -630,21 +680,21 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, t1.Mul(&cqm[i], &rl) // linPol = linPol + l(ζ)r(ζ)*Qm(X) t0.Mul(&cql[i], &lZeta) t0.Add(&t0, &t1) - linPol[i].Add(&linPol[i], &t0) // linPol = linPol + l(ζ)*Ql(X) + t.Add(&t, &t0) // linPol = linPol + l(ζ)*Ql(X) t0.Mul(&cqr[i], &rZeta) - linPol[i].Add(&linPol[i], &t0) // linPol = linPol + r(ζ)*Qr(X) + t.Add(&t, &t0) // linPol = linPol + r(ζ)*Qr(X) t0.Mul(&cqo[i], &oZeta).Add(&t0, &cqk[i]) - linPol[i].Add(&linPol[i], &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) + t.Add(&t, &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) t0.Mul(&pi2Canonical[i], &qcpZeta) - linPol[i].Add(&linPol[i], &t0) + t.Add(&t, &t0) } t0.Mul(&blindedZCanonical[i], &lagrangeZeta) - linPol[i].Add(&linPol[i], &t0) // finish the computation + blindedZCanonical[i].Add(&t, &t0) // finish the computation } }) - return linPol + return blindedZCanonical } diff --git a/backend/plonk/bw6-761/setup.go b/backend/plonk/bw6-761/setup.go index fc5326bbff..7135a1108d 100644 --- a/backend/plonk/bw6-761/setup.go +++ b/backend/plonk/bw6-761/setup.go @@ -112,6 +112,9 @@ type ProvingKey struct { // in lagrange coset basis --> these are not serialized, but computed from S1Canonical, S2Canonical, S3Canonical once. lcS1, lcS2, lcS3 *iop.Polynomial + + // in lagrange coset basis --> not serialized id and L_{g^{0}} + lcIdIOP, lLoneIOP *iop.Polynomial } func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) { @@ -176,6 +179,26 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { pk.lcS1 = pk.trace.S1.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcS2 = pk.trace.S2.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcS3 = pk.trace.S3.Clone().ToLagrangeCoset(&pk.Domain[1]) + + // storing Id + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + id := make([]fr.Element, pk.Domain[1].Cardinality) + id[0].Set(&pk.Domain[1].FrMultiplicativeGen) + for i := 1; i < int(pk.Domain[1].Cardinality); i++ { + id[i].Mul(&id[i-1], &pk.Domain[1].Generator) + } + pk.lcIdIOP = iop.NewPolynomial(&id, lagReg) + + // L_{g^{0}} + cap := pk.Domain[1].Cardinality + if cap < pk.Domain[0].Cardinality { + cap = pk.Domain[0].Cardinality // sanity check + } + lone := make([]fr.Element, pk.Domain[0].Cardinality, cap) + lone[0].SetOne() + pk.lLoneIOP = iop.NewPolynomial(&lone, lagReg).ToCanonical(&pk.Domain[0]). + ToRegular(). + ToLagrangeCoset(&pk.Domain[1]) } // NbPublicWitness returns the expected public witness size (number of field elements) diff --git a/backend/plonk/plonk_test.go b/backend/plonk/plonk_test.go index 211ef6a243..2a1bc38290 100644 --- a/backend/plonk/plonk_test.go +++ b/backend/plonk/plonk_test.go @@ -135,7 +135,7 @@ func (circuit *refCircuit) Define(api frontend.API) error { } func referenceCircuit(curve ecc.ID) (constraint.ConstraintSystem, frontend.Circuit, kzg.SRS) { - const nbConstraints = 40000 + const nbConstraints = 400000 circuit := refCircuit{ nbConstraints: nbConstraints, } diff --git a/go.mod b/go.mod index 0f33c69eb1..5a9e32610b 100644 --- a/go.mod +++ b/go.mod @@ -3,12 +3,13 @@ module github.com/consensys/gnark go 1.18 require ( + github.com/bits-and-blooms/bitset v1.5.0 github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 - github.com/consensys/gnark-crypto v0.9.2-0.20230320235232-ffa6f508088a + github.com/consensys/gnark-crypto v0.9.2-0.20230329155745-a57dcc3b53de github.com/fxamacker/cbor/v2 v2.4.0 github.com/google/go-cmp v0.5.9 - github.com/google/pprof v0.0.0-20230207041349-798e818bf904 + github.com/google/pprof v0.0.0-20230309165930-d61513b1440d github.com/leanovate/gopter v0.2.9 github.com/rs/zerolog v1.29.0 github.com/stretchr/testify v1.8.2 diff --git a/go.sum b/go.sum index 4ddb264e07..aa7606bed0 100644 --- a/go.sum +++ b/go.sum @@ -1,15 +1,11 @@ +github.com/bits-and-blooms/bitset v1.5.0 h1:NpE8frKRLGHIcEzkR+gZhiioW1+WbYV6fKwD6ZIpQT8= +github.com/bits-and-blooms/bitset v1.5.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.9.2-0.20230222154459-49b5c6cfd875 h1:FTOvlE+90hvp+XHi8i89xCejJ0627wfbP0RSWzmVFks= -github.com/consensys/gnark-crypto v0.9.2-0.20230222154459-49b5c6cfd875/go.mod h1:a2DQL4+5ywF6safEeZFEPGRiiGbjzGFRUN2sg06VuU4= -github.com/consensys/gnark-crypto v0.9.2-0.20230303095500-84be66f759b2 h1:AoLNGEIQLDhT2lIryd4xphtjappHJtAk6ouV2FYPHZY= -github.com/consensys/gnark-crypto v0.9.2-0.20230303095500-84be66f759b2/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= -github.com/consensys/gnark-crypto v0.9.2-0.20230314094804-5185eb8c3978 h1:jMmg1FkGd5+Fv1jWNTwSIGVz5qkabvPvbfFb5v1mmIA= -github.com/consensys/gnark-crypto v0.9.2-0.20230314094804-5185eb8c3978/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= -github.com/consensys/gnark-crypto v0.9.2-0.20230320235232-ffa6f508088a h1:Yhj1LwaNW0HsMmJO2FNdU+1V1vQ5+ssq+cACUHVW7vw= -github.com/consensys/gnark-crypto v0.9.2-0.20230320235232-ffa6f508088a/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= +github.com/consensys/gnark-crypto v0.9.2-0.20230329155745-a57dcc3b53de h1:W5lRxU8Rk8CDLHMTeyNst0VESbcU5RZ3U1TS9MNGgCQ= +github.com/consensys/gnark-crypto v0.9.2-0.20230329155745-a57dcc3b53de/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -20,8 +16,8 @@ github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrt github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/pprof v0.0.0-20230207041349-798e818bf904 h1:4/hN5RUoecvl+RmJRE2YxKWtnnQls6rQjjW5oV7qg2U= -github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg= +github.com/google/pprof v0.0.0-20230309165930-d61513b1440d h1:um9/pc7tKMINFfP1eE7Wv6PRGXlcCSJkVajF7KJw3uQ= +github.com/google/pprof v0.0.0-20230309165930-d61513b1440d/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl index 5e08e165d2..adb6ca524f 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl @@ -101,7 +101,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pi2iop := iop.NewPolynomial(&pi2, lagReg) wpi2iop = pi2iop.ShallowClone() - wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + // wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() } // query l, r, o in Lagrange basis, not blinded @@ -109,41 +109,90 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if err != nil { return nil, err } + // TODO @gbotrel deal with that conversion lazily + var lcpi2iop *iop.Polynomial + if spr.CommitmentInfo.Is() { + lcpi2iop = wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form + } else { + coeffs := make([]fr.Element, pk.Domain[1].Cardinality) + lcpi2iop = iop.NewPolynomial(&coeffs, iop.Form{Basis:iop.LagrangeCoset, Layout: iop.Regular}) + } solution := _solution.(*cs.SparseR1CSSolution) evaluationLDomainSmall := []fr.Element(solution.L) evaluationRDomainSmall := []fr.Element(solution.R) evaluationODomainSmall := []fr.Element(solution.O) - liop := iop.NewPolynomial(&evaluationLDomainSmall, lagReg) - riop := iop.NewPolynomial(&evaluationRDomainSmall, lagReg) - oiop := iop.NewPolynomial(&evaluationODomainSmall, lagReg) - wliop := liop.ShallowClone() - wriop := riop.ShallowClone() - woiop := oiop.ShallowClone() - wliop.ToCanonical(&pk.Domain[0]).ToRegular() - wriop.ToCanonical(&pk.Domain[0]).ToRegular() - woiop.ToCanonical(&pk.Domain[0]).ToRegular() - - // Blind l, r, o before committing - // we set the underlying slice capacity to domain[1].Cardinality to minimize mem moves. - bwliop := wliop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) - bwriop := wriop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) - bwoiop := woiop.Clone(int(pk.Domain[1].Cardinality)).Blind(1) - if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Vk.KZGSRS); err != nil { - return nil, err - } + // l, r o and blinded versions + var ( + wliop, + wriop, + woiop, + bwliop, + bwriop, + bwoiop *iop.Polynomial + ) + var wgLRO sync.WaitGroup + wgLRO.Add(3) + go func() { + // we keep in lagrange regular form since iop.BuildRatioCopyConstraint prefers it in this form. + wliop = iop.NewPolynomial(&evaluationLDomainSmall, lagReg) + // we set the underlying slice capacity to domain[1].Cardinality to minimize mem moves. + bwliop = wliop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) + wgLRO.Done() + }() + go func() { + wriop = iop.NewPolynomial(&evaluationRDomainSmall, lagReg) + bwriop = wriop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) + wgLRO.Done() + }() + go func() { + woiop = iop.NewPolynomial(&evaluationODomainSmall, lagReg) + bwoiop = woiop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) + wgLRO.Done() + }() + fw, ok := fullWitness.Vector().(fr.Vector) if !ok { return nil, witness.ErrInvalidWitness } + + // start computing lcqk + var lcqk *iop.Polynomial + chLcqk := make(chan struct{}, 1) + go func() { + // compute qk in canonical basis, completed with the public inputs + // We copy the coeffs of qk to pk is not mutated + lqkcoef := pk.lQk.Coefficients() + qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) + copy(qkCompletedCanonical, fw[:len(spr.Public)]) + copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) + if spr.CommitmentInfo.Is() { + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal + } + pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) + fft.BitReverse(qkCompletedCanonical) + + canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} + lcqk = iop.NewPolynomial(&qkCompletedCanonical, canReg) + lcqk.ToLagrangeCoset(&pk.Domain[1]) + close(chLcqk) + }() + // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.PI2); err != nil { return nil, err } + + // wait for polys to be blinded + wgLRO.Wait() + if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Vk.KZGSRS); err != nil { + return nil, err + } + gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) // TODO @Tabaie @ThomasPiellard add BSB commitment here? if err != nil { return nil, err @@ -157,15 +206,29 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts var beta fr.Element beta.SetBytes(bbeta) + // l, r, o are already blinded + wgLRO.Add(3) + go func() { + bwliop.ToLagrangeCoset(&pk.Domain[1]) + wgLRO.Done() + }() + go func() { + bwriop.ToLagrangeCoset(&pk.Domain[1]) + wgLRO.Done() + }() + go func() { + bwoiop.ToLagrangeCoset(&pk.Domain[1]) + wgLRO.Done() + }() + + // compute the copy constraint's ratio - // We copy liop, riop, oiop because they are fft'ed in the process. - // We could have not copied them at the cost of doing one more bit reverse - // per poly... + // note that wliop, wriop and woiop are fft'ed (mutated) in the process. ziop, err := iop.BuildRatioCopyConstraint( []*iop.Polynomial{ - liop.Clone(), - riop.Clone(), - oiop.Clone(), + wliop, + wriop, + woiop, }, pk.trace.S, beta, @@ -178,63 +241,30 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // commit to the blinded version of z - bwziop := ziop // iop.NewWrappedPolynomial(&ziop) - bwziop.Blind(2) - proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Vk.KZGSRS, runtime.NumCPU()*2) - if err != nil { - return proof, err - } - - // derive alpha from the Comm(l), Comm(r), Comm(o), Com(Z) - alpha, err := deriveRandomness(&fs, "alpha", &proof.Z) - if err != nil { - return proof, err - } + chZ := make(chan error, 1) + var bwziop, bwsziop *iop.Polynomial + var alpha fr.Element + go func() { + bwziop = ziop // iop.NewWrappedPolynomial(&ziop) + bwziop.Blind(2) + proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Vk.KZGSRS, runtime.NumCPU()*2) + if err != nil { + chZ <- err + } - // compute qk in canonical basis, completed with the public inputs - // We copy the coeffs of qk to pk is not mutated - lqkcoef := pk.lQk.Coefficients() - qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) - copy(qkCompletedCanonical, lqkcoef) - copy(qkCompletedCanonical, fw[:len(spr.Public)]) - if spr.CommitmentInfo.Is() { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal - } - pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) - fft.BitReverse(qkCompletedCanonical) + // derive alpha from the Comm(l), Comm(r), Comm(o), Com(Z) + alpha, err = deriveRandomness(&fs, "alpha", &proof.Z) + if err != nil { + chZ <- err + } - // l, r, o are already blinded - bwliop.ToLagrangeCoset(&pk.Domain[1]) - bwriop.ToLagrangeCoset(&pk.Domain[1]) - bwoiop.ToLagrangeCoset(&pk.Domain[1]) - pi2iop := wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form - - // we don't mutate so no need to clone the coefficients from the proving key. - canReg := iop.Form{Basis: iop.Canonical, Layout: iop.Regular} - lcqk := iop.NewPolynomial(&qkCompletedCanonical, canReg) - lcqk.ToLagrangeCoset(&pk.Domain[1]) - - // storing Id - id := make([]fr.Element, pk.Domain[1].Cardinality) - id[1].SetOne() - widiop := iop.NewPolynomial(&id, canReg) - widiop.ToLagrangeCoset(&pk.Domain[1]) - - // Store z(g*x), without reallocating a slice - bwsziop := bwziop.ShallowClone().Shift(1) - bwsziop.ToLagrangeCoset(&pk.Domain[1]) - - // L_{g^{0}} - cap := pk.Domain[1].Cardinality - if cap < pk.Domain[0].Cardinality { - cap = pk.Domain[0].Cardinality // sanity check - } - lone := make([]fr.Element, pk.Domain[0].Cardinality, cap) - lone[0].SetOne() - loneiop := iop.NewPolynomial(&lone, lagReg) - wloneiop := loneiop.ToCanonical(&pk.Domain[0]). - ToRegular(). - ToLagrangeCoset(&pk.Domain[1]) + // Store z(g*x), without reallocating a slice + bwsziop = bwziop.ShallowClone().Shift(1) + bwsziop.ToLagrangeCoset(&pk.Domain[1]) + chZ <- nil + close(chZ) + }() + // Full capture using latest gnark crypto... fic := func(fql, fqr, fqm, fqo, fqk, fqCPrime, l, r, o, pi2 fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary @@ -254,16 +284,16 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return ic } + fo := func(l, r, o, fid, fs1, fs2, fs3, fz, fzs fr.Element) fr.Element { - var uu fr.Element - u := pk.Domain[0].FrMultiplicativeGen - uu.Mul(&u, &u) - + u := &pk.Domain[0].FrMultiplicativeGen var a, b, tmp fr.Element - a.Mul(&beta, &fid).Add(&a, &l).Add(&a, &gamma) - tmp.Mul(&beta, &u).Mul(&tmp, &fid).Add(&tmp, &r).Add(&tmp, &gamma) + b.Mul(&beta, &fid) + a.Add(&b, &l).Add(&a, &gamma) + b.Mul(&b, u) + tmp.Add(&b, &r).Add(&tmp, &gamma) a.Mul(&a, &tmp) - tmp.Mul(&beta, &uu).Mul(&tmp, &fid).Add(&tmp, &o).Add(&tmp, &gamma) + tmp.Mul(&b, u).Add(&tmp, &o).Add(&tmp, &gamma) a.Mul(&a, &tmp).Mul(&a, &fz) b.Mul(&beta, &fs1).Add(&b, &l).Add(&b, &gamma) @@ -295,28 +325,48 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return c } + + // wait for lcqk + <-chLcqk + + // wait for Z part + if err := <-chZ; err != nil { + return proof, err + } + + // wait for l, r o lagrange coset conversion + wgLRO.Wait() + systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, bwliop, bwriop, bwoiop, - widiop, + pk.lcIdIOP, pk.lcS1, pk.lcS2, pk.lcS3, bwziop, bwsziop, - pi2iop, + lcpi2iop, pk.lcQl, pk.lcQr, pk.lcQm, pk.lcQo, lcqk, pk.lcQcp, - wloneiop, + pk.lLoneIOP, ) if err != nil { return nil, err } + // open blinded Z at zeta*z + chbwzIOP := make(chan struct{}, 1) + go func() { + bwziop.ToCanonical(&pk.Domain[1]).ToRegular() + close(chbwzIOP) + }() + + h, err := iop.DivideByXMinusOne(systemEvaluation, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) // TODO Rename to DivideByXNMinusOne or DivideByVanishingPoly etc if err != nil { return nil, err @@ -355,10 +405,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wgEvals.Done() }() - // open blinded Z at zeta*z - bwziop.ToCanonical(&pk.Domain[1]).ToRegular() var zetaShifted fr.Element zetaShifted.Mul(&zeta, &pk.Vk.Generator) + <-chbwzIOP proof.ZShiftedOpening, err = kzg.Open( bwziop.Coefficients()[:bwziop.BlindedSize()], zetaShifted, @@ -368,19 +417,54 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } - // blinded z evaluated at u*zeta - bzuzeta := proof.ZShiftedOpening.ClaimedValue + // start to compute foldedH and foldedHDigest while computeLinearizedPolynomial runs. + computeFoldedH := make(chan struct{}, 1) + var foldedH []fr.Element + var foldedHDigest kzg.Digest + go func() { + // foldedHDigest = Comm(h1) + ζᵐ⁺²*Comm(h2) + ζ²⁽ᵐ⁺²⁾*Comm(h3) + var bZetaPowerm, bSize big.Int + bSize.SetUint64(pk.Domain[0].Cardinality + 2) // +2 because of the masking (h of degree 3(n+2)-1) + var zetaPowerm fr.Element + zetaPowerm.Exp(zeta, &bSize) + zetaPowerm.BigInt(&bZetaPowerm) + foldedHDigest = proof.H[2] + foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) + foldedHDigest.Add(&foldedHDigest, &proof.H[1]) // ζᵐ⁺²*Comm(h3) + foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) + foldedHDigest.Add(&foldedHDigest, &proof.H[0]) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) + Comm(h1) + + // foldedH = h1 + ζ*h2 + ζ²*h3 + foldedH = h.Coefficients()[2*(pk.Domain[0].Cardinality+2) : 3*(pk.Domain[0].Cardinality+2)] + h2 := h.Coefficients()[pk.Domain[0].Cardinality+2 : 2*(pk.Domain[0].Cardinality+2)] + h1 := h.Coefficients()[:pk.Domain[0].Cardinality+2] + utils.Parallelize(len(foldedH), func(start, end int) { + for i := start; i < end; i++ { + foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζᵐ⁺²*h3 + foldedH[i].Add(&foldedH[i], &h2[i]) // ζ^{m+2)*h3+h2 + foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζ²⁽ᵐ⁺²⁾*h3+h2*ζᵐ⁺² + foldedH[i].Add(&foldedH[i], &h1[i]) // ζ^{2(m+2)*h3+ζᵐ⁺²*h2 + h1 + } + }) + close(computeFoldedH) + }() + + wgEvals.Wait() // wait for the evaluations + + var ( linearizedPolynomialCanonical []fr.Element linearizedPolynomialDigest curve.G1Affine errLPoly error ) - wgEvals.Wait() // wait for the evaluations + // blinded z evaluated at u*zeta + bzuzeta := proof.ZShiftedOpening.ClaimedValue // compute the linearization polynomial r at zeta // (goal: save committing separately to z, ql, qr, qm, qo, k + // note: we linearizedPolynomialCanonical reuses bwziop memory linearizedPolynomialCanonical = computeLinearizedPolynomial( blzeta, brzeta, @@ -398,37 +482,15 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // TODO this commitment is only necessary to derive the challenge, we should // be able to avoid doing it and get the challenge in another way - linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Vk.KZGSRS) - - // foldedHDigest = Comm(h1) + ζᵐ⁺²*Comm(h2) + ζ²⁽ᵐ⁺²⁾*Comm(h3) - var bZetaPowerm, bSize big.Int - bSize.SetUint64(pk.Domain[0].Cardinality + 2) // +2 because of the masking (h of degree 3(n+2)-1) - var zetaPowerm fr.Element - zetaPowerm.Exp(zeta, &bSize) - zetaPowerm.BigInt(&bZetaPowerm) - foldedHDigest := proof.H[2] - foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) - foldedHDigest.Add(&foldedHDigest, &proof.H[1]) // ζᵐ⁺²*Comm(h3) - foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) - foldedHDigest.Add(&foldedHDigest, &proof.H[0]) // ζ²⁽ᵐ⁺²⁾*Comm(h3) + ζᵐ⁺²*Comm(h2) + Comm(h1) - - // foldedH = h1 + ζ*h2 + ζ²*h3 - foldedH := h.Coefficients()[2*(pk.Domain[0].Cardinality+2) : 3*(pk.Domain[0].Cardinality+2)] - h2 := h.Coefficients()[pk.Domain[0].Cardinality+2 : 2*(pk.Domain[0].Cardinality+2)] - h1 := h.Coefficients()[:pk.Domain[0].Cardinality+2] - utils.Parallelize(len(foldedH), func(start, end int) { - for i := start; i < end; i++ { - foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζᵐ⁺²*h3 - foldedH[i].Add(&foldedH[i], &h2[i]) // ζ^{m+2)*h3+h2 - foldedH[i].Mul(&foldedH[i], &zetaPowerm) // ζ²⁽ᵐ⁺²⁾*h3+h2*ζᵐ⁺² - foldedH[i].Add(&foldedH[i], &h1[i]) // ζ^{2(m+2)*h3+ζᵐ⁺²*h2 + h1 - } - }) - + linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Vk.KZGSRS, runtime.NumCPU() * 2) if errLPoly != nil { return nil, errLPoly } + + // wait for foldedH and foldedHDigest + <-computeFoldedH + // Batch open the first list of polynomials proof.BatchedProof, err = kzg.BatchOpenSinglePoint( [][]fr.Element{ @@ -468,7 +530,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // fills proof.LRO with kzg commits of bcl, bcr and bco func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { - n := runtime.NumCPU() / 2 + n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) @@ -494,7 +556,7 @@ func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { } func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error { - n := runtime.NumCPU() / 2 + n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) @@ -577,26 +639,24 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, Mul(&lagrangeZeta, &alpha). Mul(&lagrangeZeta, &pk.Domain[0].CardinalityInv) // (1/n)*α²*L₁(ζ) - linPol := make([]fr.Element, len(blindedZCanonical)) - copy(linPol, blindedZCanonical) s3canonical := pk.trace.S3.Coefficients() - utils.Parallelize(len(linPol), func(start, end int) { + utils.Parallelize(len(blindedZCanonical), func(start, end int) { - var t0, t1 fr.Element + var t, t0, t1 fr.Element for i := start; i < end; i++ { - linPol[i].Mul(&linPol[i], &s2) // -Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + t.Mul(&blindedZCanonical[i], &s2) // -Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) if i < len(s3canonical) { t0.Mul(&s3canonical[i], &s1) // (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*β*s3(X) - linPol[i].Add(&linPol[i], &t0) + t.Add(&t, &t0) } - linPol[i].Mul(&linPol[i], &alpha) // α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ)) + t.Mul(&t, &alpha) // α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ)) cql := pk.trace.Ql.Coefficients() cqr := pk.trace.Qr.Coefficients() @@ -608,21 +668,21 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, t1.Mul(&cqm[i], &rl) // linPol = linPol + l(ζ)r(ζ)*Qm(X) t0.Mul(&cql[i], &lZeta) t0.Add(&t0, &t1) - linPol[i].Add(&linPol[i], &t0) // linPol = linPol + l(ζ)*Ql(X) + t.Add(&t, &t0) // linPol = linPol + l(ζ)*Ql(X) t0.Mul(&cqr[i], &rZeta) - linPol[i].Add(&linPol[i], &t0) // linPol = linPol + r(ζ)*Qr(X) + t.Add(&t, &t0) // linPol = linPol + r(ζ)*Qr(X) t0.Mul(&cqo[i], &oZeta).Add(&t0, &cqk[i]) - linPol[i].Add(&linPol[i], &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) + t.Add(&t, &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) t0.Mul(&pi2Canonical[i], &qcpZeta) - linPol[i].Add(&linPol[i], &t0) + t.Add(&t, &t0) } t0.Mul(&blindedZCanonical[i], &lagrangeZeta) - linPol[i].Add(&linPol[i], &t0) // finish the computation + blindedZCanonical[i].Add(&t, &t0) // finish the computation } }) - return linPol + return blindedZCanonical } \ No newline at end of file diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl index 541ce66125..233b89c076 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl @@ -94,6 +94,9 @@ type ProvingKey struct { // in lagrange coset basis --> these are not serialized, but computed from S1Canonical, S2Canonical, S3Canonical once. lcS1, lcS2, lcS3 *iop.Polynomial + + // in lagrange coset basis --> not serialized id and L_{g^{0}} + lcIdIOP, lLoneIOP *iop.Polynomial } func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) { @@ -158,6 +161,26 @@ func (pk *ProvingKey) computeLagrangeCosetPolys() { pk.lcS1 = pk.trace.S1.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcS2 = pk.trace.S2.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcS3 = pk.trace.S3.Clone().ToLagrangeCoset(&pk.Domain[1]) + + // storing Id + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + id := make([]fr.Element, pk.Domain[1].Cardinality) + id[0].Set(&pk.Domain[1].FrMultiplicativeGen) + for i := 1; i < int(pk.Domain[1].Cardinality); i++ { + id[i].Mul(&id[i-1], &pk.Domain[1].Generator) + } + pk.lcIdIOP = iop.NewPolynomial(&id, lagReg) + + // L_{g^{0}} + cap := pk.Domain[1].Cardinality + if cap < pk.Domain[0].Cardinality { + cap = pk.Domain[0].Cardinality // sanity check + } + lone := make([]fr.Element, pk.Domain[0].Cardinality, cap) + lone[0].SetOne() + pk.lLoneIOP = iop.NewPolynomial(&lone, lagReg).ToCanonical(&pk.Domain[0]). + ToRegular(). + ToLagrangeCoset(&pk.Domain[1]) } // NbPublicWitness returns the expected public witness size (number of field elements) diff --git a/internal/tinyfield/element.go b/internal/tinyfield/element.go index ec15e0514b..86f134f590 100644 --- a/internal/tinyfield/element.go +++ b/internal/tinyfield/element.go @@ -27,6 +27,7 @@ import ( "strconv" "strings" + "github.com/bits-and-blooms/bitset" "github.com/consensys/gnark-crypto/field/hash" "github.com/consensys/gnark-crypto/field/pool" ) @@ -498,12 +499,12 @@ func BatchInvert(a []Element) []Element { return res } - zeroes := make([]bool, len(a)) + zeroes := bitset.New(uint(len(a))) accumulator := One() for i := 0; i < len(a); i++ { if a[i].IsZero() { - zeroes[i] = true + zeroes.Set(uint(i)) continue } res[i] = accumulator @@ -513,7 +514,7 @@ func BatchInvert(a []Element) []Element { accumulator.Inverse(&accumulator) for i := len(a) - 1; i >= 0; i-- { - if zeroes[i] { + if zeroes.Test(uint(i)) { continue } res[i].Mul(&res[i], &accumulator) From a97a47094c25dae74487466520764dec7afb4de1 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 30 Mar 2023 01:14:36 +0200 Subject: [PATCH 209/464] feat: add gadget for enabling multiple commitments in-circuit (#562) * feat: add multi-commit gadget * fix: first defer put was double * feat: get deferred functions at every loop When we use range, then we fix the deferred loops when we initialize range. But actually some deferred functions may defer more functions. Iterate over all of them. * feat: use multi-commit output in range checking gadget * refactor: use BN254 in range check test * feat: check if no callbacks registered * feat: do not domain-separate commitments when only single callback * chore: move to internal * docs: package name --- frontend/compile.go | 4 +- internal/circuitdefer/defer.go | 4 +- std/internal/multicommit/doc_test.go | 104 ++++++++++++++++ std/internal/multicommit/nativecommit.go | 113 ++++++++++++++++++ std/internal/multicommit/nativecommit_test.go | 72 +++++++++++ std/rangecheck/rangecheck_commit.go | 40 +++---- std/rangecheck/rangecheck_test.go | 3 +- test/engine.go | 4 +- 8 files changed, 313 insertions(+), 31 deletions(-) create mode 100644 std/internal/multicommit/doc_test.go create mode 100644 std/internal/multicommit/nativecommit.go create mode 100644 std/internal/multicommit/nativecommit_test.go diff --git a/frontend/compile.go b/frontend/compile.go index 2a6266c44d..072aca1c34 100644 --- a/frontend/compile.go +++ b/frontend/compile.go @@ -131,8 +131,8 @@ func parseCircuit(builder Builder, circuit Circuit) (err error) { } func callDeferred(builder Builder) error { - for i, cb := range circuitdefer.GetAll[func(API) error](builder) { - if err := cb(builder); err != nil { + for i := 0; i < len(circuitdefer.GetAll[func(API) error](builder)); i++ { + if err := circuitdefer.GetAll[func(API) error](builder)[i](builder); err != nil { return fmt.Errorf("defer fn %d: %w", i, err) } } diff --git a/internal/circuitdefer/defer.go b/internal/circuitdefer/defer.go index f21ac65d5e..4bda7383e7 100644 --- a/internal/circuitdefer/defer.go +++ b/internal/circuitdefer/defer.go @@ -15,9 +15,7 @@ func Put[T any](builder any, cb T) { } val := kv.GetKeyValue(deferKey{}) var deferred []T - if val == nil { - deferred = []T{cb} - } else { + if val != nil { var ok bool deferred, ok = val.([]T) if !ok { diff --git a/std/internal/multicommit/doc_test.go b/std/internal/multicommit/doc_test.go new file mode 100644 index 0000000000..42eb8d9e99 --- /dev/null +++ b/std/internal/multicommit/doc_test.go @@ -0,0 +1,104 @@ +package multicommit_test + +import ( + "fmt" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/backend/groth16" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/std/internal/multicommit" +) + +// MultipleCommitmentCircuit is an example circuit showing usage of multiple +// independent commitments in-circuit. +type MultipleCommitmentsCircuit struct { + Secrets [4]frontend.Variable +} + +func (c *MultipleCommitmentsCircuit) Define(api frontend.API) error { + // first callback receives first unique commitment derived from the root commitment + multicommit.WithCommitment(api, func(api frontend.API, commitment frontend.Variable) error { + // compute (X-s[0]) * (X-s[1]) for a random X + res := api.Mul(api.Sub(commitment, c.Secrets[0]), api.Sub(commitment, c.Secrets[1])) + api.AssertIsDifferent(res, 0) + return nil + }, c.Secrets[:2]...) + + // second callback receives second unique commitment derived from the root commitment + multicommit.WithCommitment(api, func(api frontend.API, commitment frontend.Variable) error { + // compute (X-s[2]) * (X-s[3]) for a random X + res := api.Mul(api.Sub(commitment, c.Secrets[2]), api.Sub(commitment, c.Secrets[3])) + api.AssertIsDifferent(res, 0) + return nil + }, c.Secrets[2:4]...) + + // we do not have to pass any variables in if other calls to [WithCommitment] have + multicommit.WithCommitment(api, func(api frontend.API, commitment frontend.Variable) error { + // compute (X-s[0]) for a random X + api.AssertIsDifferent(api.Sub(commitment, c.Secrets[0]), 0) + return nil + }) + + // we can share variables between the callbacks + var shared, stored frontend.Variable + multicommit.WithCommitment(api, func(api frontend.API, commitment frontend.Variable) error { + shared = api.Add(c.Secrets[0], commitment) + stored = commitment + return nil + }) + multicommit.WithCommitment(api, func(api frontend.API, commitment frontend.Variable) error { + api.AssertIsEqual(api.Sub(shared, stored), c.Secrets[0]) + return nil + }) + return nil +} + +// Full written on how to use multiple commitments in a circuit. +func ExampleWithCommitment() { + circuit := MultipleCommitmentsCircuit{} + assignment := MultipleCommitmentsCircuit{Secrets: [4]frontend.Variable{1, 2, 3, 4}} + ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) + if err != nil { + panic(err) + } else { + fmt.Println("compiled") + } + pk, vk, err := groth16.Setup(ccs) + if err != nil { + panic(err) + } else { + fmt.Println("setup done") + } + secretWitness, err := frontend.NewWitness(&assignment, ecc.BN254.ScalarField()) + if err != nil { + panic(err) + } else { + fmt.Println("secret witness") + } + publicWitness, err := secretWitness.Public() + if err != nil { + panic(err) + } else { + fmt.Println("public witness") + } + proof, err := groth16.Prove(ccs, pk, secretWitness) + if err != nil { + panic(err) + } else { + fmt.Println("proof") + } + err = groth16.Verify(proof, vk, publicWitness) + if err != nil { + panic(err) + } else { + fmt.Println("verify") + } + // Output: + // compiled + // setup done + // secret witness + // public witness + // proof + // verify +} diff --git a/std/internal/multicommit/nativecommit.go b/std/internal/multicommit/nativecommit.go new file mode 100644 index 0000000000..7e641c3189 --- /dev/null +++ b/std/internal/multicommit/nativecommit.go @@ -0,0 +1,113 @@ +// Package multicommit implements commitment expansion. +// +// If the builder implements [frontend.Committer] interface, then we can commit +// to the variables and get a commitment which can be used as a unique +// randomness in the circuit. For current builders implementing this interface, +// the function can only be called once in a circuit. This makes it difficult to +// compose different gadgets which require randomness. +// +// This package extends the commitment interface by allowing to receive several +// functions unique commitment multiple times. It does this by collecting all +// variables to commit and the callbacks which want to access a commitment. Then +// we internally defer a function which computes the commitment over all input +// committed variables and then uses this commitment to derive a per-callback +// unique commitment. The callbacks are then called with these unique derived +// commitments instead. +package multicommit + +import ( + "fmt" + + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/internal/kvstore" + "github.com/consensys/gnark/std/hash/mimc" +) + +type multicommiter struct { + closed bool + vars []frontend.Variable + cbs []WithCommitmentFn +} + +type ctxMulticommiterKey struct{} + +// getCached gets the cached committer from the key-value storage. If it is not +// there then creates, stores and defers it, and then returns. +func getCached(api frontend.API) *multicommiter { + kv, ok := api.(kvstore.Store) + if !ok { + // if the builder doesn't implement key-value store then cannot store + // multi-committer in cache. + panic("builder should implement key-value store") + } + mc := kv.GetKeyValue(ctxMulticommiterKey{}) + if mc != nil { + if mct, ok := mc.(*multicommiter); ok { + return mct + } else { + panic("stored multicommiter is of invalid type") + } + } + mct := &multicommiter{} + kv.SetKeyValue(ctxMulticommiterKey{}, mct) + api.Compiler().Defer(mct.commitAndCall) + return mct +} + +func (mct *multicommiter) commitAndCall(api frontend.API) error { + // close collecting input in case anyone wants to check more variables to commit to. + mct.closed = true + if len(mct.cbs) == 0 { + // shouldn't happen. we defer this function on creating multicommitter + // instance. It is probably some race. + panic("calling commiter with zero callbacks") + } + commiter, ok := api.Compiler().(frontend.Committer) + if !ok { + panic("compiler doesn't implement frontend.Committer") + } + cmt, err := commiter.Commit(mct.vars...) + if err != nil { + return fmt.Errorf("commit: %w", err) + } + if len(mct.cbs) == 1 { + if err = mct.cbs[0](api, cmt); err != nil { + return fmt.Errorf("single callback: %w", err) + } + } else { + hasher, err := mimc.NewMiMC(api) + if err != nil { + return fmt.Errorf("new hasher: %w", err) + } + for i, cb := range mct.cbs { + hasher.Reset() + hasher.Write(i+1, cmt) + localcmt := hasher.Sum() + if err = cb(api, localcmt); err != nil { + return fmt.Errorf("with commitment callback %d: %w", i, err) + } + } + } + return nil +} + +// WithCommitmentFn is the function which is called asynchronously after all +// variables have been committed to. See [WithCommitment] for scheduling a +// function of this type. Every called functions received a distinct commitment +// built from a single root. +// +// It is invalid to call [WithCommitment] in this method recursively and this +// leads to panic. However, the method can call defer for other callbacks. +type WithCommitmentFn func(api frontend.API, commitment frontend.Variable) error + +// WithCommitment schedules the function cb to be called with a unique +// commitment. We append the variables committedVariables to be committed to +// with the native [frontend.Committer] interface. +func WithCommitment(api frontend.API, cb WithCommitmentFn, committedVariables ...frontend.Variable) { + mct := getCached(api) + if mct.closed { + panic("called WithCommitment recursively") + } + mct.vars = append(mct.vars, committedVariables...) + mct.cbs = append(mct.cbs, cb) +} diff --git a/std/internal/multicommit/nativecommit_test.go b/std/internal/multicommit/nativecommit_test.go new file mode 100644 index 0000000000..4b570b7f33 --- /dev/null +++ b/std/internal/multicommit/nativecommit_test.go @@ -0,0 +1,72 @@ +package multicommit + +import ( + "testing" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/test" +) + +type noRecursionCircuit struct { + X frontend.Variable +} + +func (c *noRecursionCircuit) Define(api frontend.API) error { + WithCommitment(api, func(api frontend.API, commitment frontend.Variable) error { + WithCommitment(api, func(api frontend.API, commitment frontend.Variable) error { return nil }, commitment) + return nil + }, c.X) + return nil +} + +func TestNoRecursion(t *testing.T) { + circuit := noRecursionCircuit{} + assert := test.NewAssert(t) + _, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) + assert.Error(err) +} + +type multipleCommitmentCircuit struct { + X frontend.Variable +} + +func (c *multipleCommitmentCircuit) Define(api frontend.API) error { + var stored frontend.Variable + // first callback receives first unique commitment derived from the root commitment + WithCommitment(api, func(api frontend.API, commitment frontend.Variable) error { + api.AssertIsDifferent(c.X, commitment) + stored = commitment + return nil + }, c.X) + WithCommitment(api, func(api frontend.API, commitment frontend.Variable) error { + api.AssertIsDifferent(stored, commitment) + return nil + }, c.X) + return nil +} + +func TestMultipleCommitments(t *testing.T) { + circuit := multipleCommitmentCircuit{} + assignment := multipleCommitmentCircuit{X: 10} + assert := test.NewAssert(t) + assert.ProverSucceeded(&circuit, &assignment, test.WithCurves(ecc.BN254), test.WithBackends(backend.GROTH16)) // right now PLONK doesn't implement commitment +} + +type noCommitVariable struct { + X frontend.Variable +} + +func (c *noCommitVariable) Define(api frontend.API) error { + WithCommitment(api, func(api frontend.API, commitment frontend.Variable) error { return nil }) + return nil +} + +func TestNoCommitVariable(t *testing.T) { + circuit := noCommitVariable{} + assert := test.NewAssert(t) + _, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) + assert.Error(err) +} diff --git a/std/rangecheck/rangecheck_commit.go b/std/rangecheck/rangecheck_commit.go index 309b25d471..62cad9f866 100644 --- a/std/rangecheck/rangecheck_commit.go +++ b/std/rangecheck/rangecheck_commit.go @@ -9,6 +9,7 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/internal/frontendtype" "github.com/consensys/gnark/internal/kvstore" + "github.com/consensys/gnark/std/internal/multicommit" ) type ctxCheckerKey struct{} @@ -61,10 +62,6 @@ func (c *commitChecker) commit(api frontend.API) error { if len(c.collected) == 0 { return nil } - committer, ok := api.(frontend.Committer) - if !ok { - panic("expected committer API") - } baseLength := c.getOptimalBasewidth(api) // decompose into smaller limbs decomposed := make([]frontend.Variable, 0, len(c.collected)) @@ -94,25 +91,24 @@ func (c *commitChecker) commit(api frontend.API) error { if err != nil { panic(fmt.Sprintf("count %v", err)) } - // compute the ratoinal function Sum_i e_i / (X - s_i) - commitment, err := committer.Commit(append(collected, exps...)...) - if err != nil { - panic(fmt.Sprintf("commit %v", err)) - } - // lp = Sum_i e_i / (X - s_i) - var lp frontend.Variable = 0 - for i := 0; i < nbTable; i++ { - tmp := api.DivUnchecked(exps[i], api.Sub(commitment, i)) - lp = api.Add(lp, tmp) - } + multicommit.WithCommitment(api, func(api frontend.API, commitment frontend.Variable) error { + // compute the ratoinal function Sum_i e_i / (X - s_i) + // lp = Sum_i e_i / (X - s_i) + var lp frontend.Variable = 0 + for i := 0; i < nbTable; i++ { + tmp := api.DivUnchecked(exps[i], api.Sub(commitment, i)) + lp = api.Add(lp, tmp) + } - // rp = Sum_i 1 \ (X - f_i) - var rp frontend.Variable = 0 - for i := range decomposed { - tmp := api.Inverse(api.Sub(commitment, decomposed[i])) - rp = api.Add(rp, tmp) - } - api.AssertIsEqual(lp, rp) + // rp = Sum_i 1 \ (X - f_i) + var rp frontend.Variable = 0 + for i := range decomposed { + tmp := api.Inverse(api.Sub(commitment, decomposed[i])) + rp = api.Add(rp, tmp) + } + api.AssertIsEqual(lp, rp) + return nil + }, append(collected, exps...)...) return nil } diff --git a/std/rangecheck/rangecheck_test.go b/std/rangecheck/rangecheck_test.go index 994921d0ce..42a26827d8 100644 --- a/std/rangecheck/rangecheck_test.go +++ b/std/rangecheck/rangecheck_test.go @@ -6,7 +6,6 @@ import ( "testing" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/field/goldilocks" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/consensys/gnark/test" @@ -40,7 +39,7 @@ func TestCheck(t *testing.T) { } witness := CheckCircuit{Vals: vals, bits: bits} circuit := CheckCircuit{Vals: make([]frontend.Variable, len(vals)), bits: bits} - err = test.IsSolved(&circuit, &witness, goldilocks.Modulus()) + err = test.IsSolved(&circuit, &witness, ecc.BN254.ScalarField()) assert.NoError(err) _, err = frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit, frontend.WithCompressThreshold(100)) assert.NoError(err) diff --git a/test/engine.go b/test/engine.go index e72ff5f8e7..0691b9335e 100644 --- a/test/engine.go +++ b/test/engine.go @@ -140,8 +140,8 @@ func IsSolved(circuit, witness frontend.Circuit, field *big.Int, opts ...TestEng } func callDeferred(builder *engine) error { - for i, cb := range circuitdefer.GetAll[func(frontend.API) error](builder) { - if err := cb(builder); err != nil { + for i := 0; i < len(circuitdefer.GetAll[func(frontend.API) error](builder)); i++ { + if err := circuitdefer.GetAll[func(frontend.API) error](builder)[i](builder); err != nil { return fmt.Errorf("defer fn %d: %w", i, err) } } From 974435187159b5e2e41343b08f24f009549d2c94 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Thu, 30 Mar 2023 14:21:18 -0500 Subject: [PATCH 210/464] build: update ci script --- .github/workflows/pr.yml | 20 ++++++++++---------- .github/workflows/push.yml | 20 ++++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index efd14e8cbe..0ce12537db 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -5,14 +5,14 @@ jobs: runs-on: ubuntu-latest steps: - name: install Go - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: - go-version: 1.19.x + go-version: 1.20.x - name: checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 - - uses: actions/cache@v2 + - uses: actions/cache@v3 with: path: | ~/go/pkg/mod @@ -40,19 +40,19 @@ jobs: test: strategy: matrix: - go-version: [1.19.x] + go-version: [1.20.x] os: [ubuntu-latest] runs-on: ${{ matrix.os }} needs: - staticcheck steps: - name: install Go - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: go-version: ${{ matrix.go-version }} - name: checkout code - uses: actions/checkout@v2 - - uses: actions/cache@v2 + uses: actions/checkout@v3 + - uses: actions/cache@v3 with: path: | ~/go/pkg/mod @@ -78,7 +78,7 @@ jobs: steps: - name: Notify slack -- workflow failed id: slack - uses: slackapi/slack-github-action@v1.19.0 + uses: slackapi/slack-github-action@v1.23.0 with: payload: | { @@ -101,7 +101,7 @@ jobs: steps: - name: Notify slack -- workflow succeeded id: slack - uses: slackapi/slack-github-action@v1.19.0 + uses: slackapi/slack-github-action@v1.23.0 with: payload: | { diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 3ef5179a51..c908d67ace 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -9,14 +9,14 @@ jobs: runs-on: ubuntu-latest steps: - name: install Go - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: - go-version: 1.19.x + go-version: 1.20.x - name: checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 - - uses: actions/cache@v2 + - uses: actions/cache@v3 with: path: | ~/go/pkg/mod @@ -44,19 +44,19 @@ jobs: test: strategy: matrix: - go-version: [1.19.x] + go-version: [1.20.x] os: [ubuntu-latest, windows-latest, macos-latest] runs-on: ${{ matrix.os }} needs: - staticcheck steps: - name: install Go - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: go-version: ${{ matrix.go-version }} - name: checkout code - uses: actions/checkout@v2 - - uses: actions/cache@v2 + uses: actions/checkout@v3 + - uses: actions/cache@v3 with: path: | ~/go/pkg/mod @@ -86,7 +86,7 @@ jobs: steps: - name: Notify slack -- workflow failed id: slack - uses: slackapi/slack-github-action@v1.19.0 + uses: slackapi/slack-github-action@v1.23.0 with: payload: | { @@ -109,7 +109,7 @@ jobs: steps: - name: Notify slack -- workflow succeeded id: slack - uses: slackapi/slack-github-action@v1.19.0 + uses: slackapi/slack-github-action@v1.23.0 with: payload: | { From 17e2743737b581311a00064ed559d67eea859762 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Thu, 30 Mar 2023 15:02:40 -0500 Subject: [PATCH 211/464] fix: restore reference plonk circuit size --- backend/plonk/plonk_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/plonk/plonk_test.go b/backend/plonk/plonk_test.go index 2a1bc38290..211ef6a243 100644 --- a/backend/plonk/plonk_test.go +++ b/backend/plonk/plonk_test.go @@ -135,7 +135,7 @@ func (circuit *refCircuit) Define(api frontend.API) error { } func referenceCircuit(curve ecc.ID) (constraint.ConstraintSystem, frontend.Circuit, kzg.SRS) { - const nbConstraints = 400000 + const nbConstraints = 40000 circuit := refCircuit{ nbConstraints: nbConstraints, } From 465cec1f247bc825a6ece020722a0f01628031f9 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 31 Mar 2023 13:02:20 +0200 Subject: [PATCH 212/464] feat(fields_bn254): add IsZero in extensions --- std/algebra/emulated/fields_bn254/e12.go | 7 +++++++ std/algebra/emulated/fields_bn254/e2.go | 7 +++++++ std/algebra/emulated/fields_bn254/e6.go | 8 ++++++++ 3 files changed, 22 insertions(+) diff --git a/std/algebra/emulated/fields_bn254/e12.go b/std/algebra/emulated/fields_bn254/e12.go index 14763df9a4..5948ad593b 100644 --- a/std/algebra/emulated/fields_bn254/e12.go +++ b/std/algebra/emulated/fields_bn254/e12.go @@ -2,6 +2,7 @@ package fields_bn254 import ( "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/frontend" ) type E12 struct { @@ -91,6 +92,12 @@ func (e Ext12) One() *E12 { } } +func (e Ext12) IsZero(api frontend.API, z *E12) frontend.Variable { + c0 := e.Ext6.IsZero(api, &z.C0) + c1 := e.Ext6.IsZero(api, &z.C1) + return api.And(c0, c1) +} + func (e Ext12) Square(x *E12) *E12 { c0 := e.Ext6.Sub(&x.C0, &x.C1) c3 := e.Ext6.MulByNonResidue(&x.C1) diff --git a/std/algebra/emulated/fields_bn254/e2.go b/std/algebra/emulated/fields_bn254/e2.go index 008d259eab..c53cf552c5 100644 --- a/std/algebra/emulated/fields_bn254/e2.go +++ b/std/algebra/emulated/fields_bn254/e2.go @@ -4,6 +4,7 @@ import ( "math/big" "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/math/emulated" ) @@ -253,6 +254,12 @@ func (e Ext2) Zero() *E2 { } } +func (e Ext2) IsZero(api frontend.API, z *E2) frontend.Variable { + a0 := e.fp.IsZero(&z.A0) + a1 := e.fp.IsZero(&z.A1) + return api.And(a0, a1) +} + func (e Ext2) Square(x *E2) *E2 { a := e.fp.Add(&x.A0, &x.A1) b := e.fp.Sub(&x.A0, &x.A1) diff --git a/std/algebra/emulated/fields_bn254/e6.go b/std/algebra/emulated/fields_bn254/e6.go index dc9c2801d6..029ebcb8bb 100644 --- a/std/algebra/emulated/fields_bn254/e6.go +++ b/std/algebra/emulated/fields_bn254/e6.go @@ -2,6 +2,7 @@ package fields_bn254 import ( "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/frontend" ) type E6 struct { @@ -38,6 +39,13 @@ func (e Ext6) Zero() *E6 { } } +func (e Ext6) IsZero(api frontend.API, z *E6) frontend.Variable { + b0 := e.Ext2.IsZero(api, &z.B0) + b1 := e.Ext2.IsZero(api, &z.B1) + b2 := e.Ext2.IsZero(api, &z.B2) + return api.And(api.And(b0, b1), b2) +} + func (e Ext6) Add(x, y *E6) *E6 { z0 := e.Ext2.Add(&x.B0, &y.B0) z1 := e.Ext2.Add(&x.B1, &y.B1) From 7af74dd6b9ce25eb746b662276bde58311391927 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 31 Mar 2023 13:09:21 +0200 Subject: [PATCH 213/464] feat(fields_bn254): add Select in extensions --- std/algebra/emulated/fields_bn254/e12.go | 6 ++++++ std/algebra/emulated/fields_bn254/e2.go | 6 ++++++ std/algebra/emulated/fields_bn254/e6.go | 7 +++++++ 3 files changed, 19 insertions(+) diff --git a/std/algebra/emulated/fields_bn254/e12.go b/std/algebra/emulated/fields_bn254/e12.go index 5948ad593b..37289bd3eb 100644 --- a/std/algebra/emulated/fields_bn254/e12.go +++ b/std/algebra/emulated/fields_bn254/e12.go @@ -186,3 +186,9 @@ func (e Ext12) DivUnchecked(x, y *E12) *E12 { return &div } + +func (e Ext12) Select(selector frontend.Variable, z1, z0 *E12) *E12 { + c0 := e.Ext6.Select(selector, &z1.C0, &z0.C0) + c1 := e.Ext6.Select(selector, &z1.C1, &z0.C1) + return &E12{C0: *c0, C1: *c1} +} diff --git a/std/algebra/emulated/fields_bn254/e2.go b/std/algebra/emulated/fields_bn254/e2.go index c53cf552c5..8dba1edfaf 100644 --- a/std/algebra/emulated/fields_bn254/e2.go +++ b/std/algebra/emulated/fields_bn254/e2.go @@ -334,3 +334,9 @@ func (e Ext2) DivUnchecked(x, y *E2) *E2 { return &div } + +func (e Ext2) Select(selector frontend.Variable, z1, z0 *E2) *E2 { + a0 := e.fp.Select(selector, &z1.A0, &z0.A0) + a1 := e.fp.Select(selector, &z1.A1, &z0.A1) + return &E2{A0: *a0, A1: *a1} +} diff --git a/std/algebra/emulated/fields_bn254/e6.go b/std/algebra/emulated/fields_bn254/e6.go index 029ebcb8bb..581e05a2cf 100644 --- a/std/algebra/emulated/fields_bn254/e6.go +++ b/std/algebra/emulated/fields_bn254/e6.go @@ -323,3 +323,10 @@ func (e Ext6) DivUnchecked(x, y *E6) *E6 { return &div } + +func (e Ext6) Select(selector frontend.Variable, z1, z0 *E6) *E6 { + b0 := e.Ext2.Select(selector, &z1.B0, &z0.B0) + b1 := e.Ext2.Select(selector, &z1.B1, &z0.B1) + b2 := e.Ext2.Select(selector, &z1.B2, &z0.B2) + return &E6{B0: *b0, B1: *b1, B2: *b2} +} From dbd819cf03f1388c609571851129e7f5b0d2eb43 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 31 Mar 2023 13:18:06 +0200 Subject: [PATCH 214/464] feat(fields_bn254): add String helpers --- std/algebra/emulated/fields_bn254/e12.go | 6 +++++ std/algebra/emulated/fields_bn254/e2.go | 13 +++++++++ std/algebra/emulated/fields_bn254/e6.go | 6 +++++ std/math/emulated/field_ops.go | 34 ++++++++++++++++++++++++ 4 files changed, 59 insertions(+) diff --git a/std/algebra/emulated/fields_bn254/e12.go b/std/algebra/emulated/fields_bn254/e12.go index 37289bd3eb..0a59bbf6bf 100644 --- a/std/algebra/emulated/fields_bn254/e12.go +++ b/std/algebra/emulated/fields_bn254/e12.go @@ -1,6 +1,8 @@ package fields_bn254 import ( + "fmt" + "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark/frontend" ) @@ -192,3 +194,7 @@ func (e Ext12) Select(selector frontend.Variable, z1, z0 *E12) *E12 { c1 := e.Ext6.Select(selector, &z1.C1, &z0.C1) return &E12{C0: *c0, C1: *c1} } + +func (e Ext12) String(x *E12) string { + return fmt.Sprintf("%s+(%s)*w", e.Ext6.String(&x.C0), e.Ext6.String(&x.C1)) +} diff --git a/std/algebra/emulated/fields_bn254/e2.go b/std/algebra/emulated/fields_bn254/e2.go index 8dba1edfaf..c26a1d1f41 100644 --- a/std/algebra/emulated/fields_bn254/e2.go +++ b/std/algebra/emulated/fields_bn254/e2.go @@ -1,6 +1,7 @@ package fields_bn254 import ( + "fmt" "math/big" "github.com/consensys/gnark-crypto/ecc/bn254" @@ -340,3 +341,15 @@ func (e Ext2) Select(selector frontend.Variable, z1, z0 *E2) *E2 { a1 := e.fp.Select(selector, &z1.A1, &z0.A1) return &E2{A0: *a0, A1: *a1} } + +func (e Ext2) String(x *E2) string { + x0, err := e.fp.String(&x.A0) + if err != nil { + x0 = "?" + } + x1, err := e.fp.String(&x.A1) + if err != nil { + x1 = "?" + } + return fmt.Sprintf("%s+%s*u", x0, x1) +} diff --git a/std/algebra/emulated/fields_bn254/e6.go b/std/algebra/emulated/fields_bn254/e6.go index 581e05a2cf..c6acf60423 100644 --- a/std/algebra/emulated/fields_bn254/e6.go +++ b/std/algebra/emulated/fields_bn254/e6.go @@ -1,6 +1,8 @@ package fields_bn254 import ( + "fmt" + "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark/frontend" ) @@ -330,3 +332,7 @@ func (e Ext6) Select(selector frontend.Variable, z1, z0 *E6) *E6 { b2 := e.Ext2.Select(selector, &z1.B2, &z0.B2) return &E6{B0: *b0, B1: *b1, B2: *b2} } + +func (e Ext6) String(x *E6) string { + return fmt.Sprintf("%s+(%s)*v+(%s)*v**2", e.Ext2.String(&x.B0), e.Ext2.String(&x.B1), e.Ext2.String(&x.B2)) +} diff --git a/std/math/emulated/field_ops.go b/std/math/emulated/field_ops.go index 31739cf716..b40bfbc8c7 100644 --- a/std/math/emulated/field_ops.go +++ b/std/math/emulated/field_ops.go @@ -368,3 +368,37 @@ type overflowError struct { func (e overflowError) Error() string { return fmt.Sprintf("op %s overflow %d exceeds max %d", e.op, e.nextOverflow, e.maxOverflow) } + +func (f *Field[T]) String(a *Element[T]) (string, error) { + // for debug only, if is not test engine then no-op + var fp T + blimbs := make([]*big.Int, len(a.Limbs)) + for i, v := range a.Limbs { + switch vv := v.(type) { + case *big.Int: + blimbs[i] = vv + case big.Int: + blimbs[i] = &vv + case int: + blimbs[i] = new(big.Int) + blimbs[i].SetInt64(int64(vv)) + case uint: + blimbs[i] = new(big.Int) + blimbs[i].SetUint64(uint64(vv)) + default: + return "", fmt.Errorf("not big int") + } + } + res := new(big.Int) + err := recompose(blimbs, fp.BitsPerLimb(), res) + if err != nil { + return "", fmt.Errorf("recompose: %w", err) + } + reduced := new(big.Int).Mod(res, fp.Modulus()) + return reduced.String(), nil +} + +func (f *Field[T]) Println(a *Element[T]) { + res, _ := f.String(a) + fmt.Println(res) +} From 773a4b9f14ebbd4b2d0b4cba823634b3952fd130 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 31 Mar 2023 16:17:13 +0200 Subject: [PATCH 215/464] fix: finalExp when element is 1 in torus --- std/algebra/emulated/sw_bn254/doc_test.go | 2 +- std/algebra/emulated/sw_bn254/pairing.go | 24 +++++++++++-------- std/algebra/emulated/sw_bn254/pairing_test.go | 6 ++--- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/std/algebra/emulated/sw_bn254/doc_test.go b/std/algebra/emulated/sw_bn254/doc_test.go index db095a0210..f3d41bf4f8 100644 --- a/std/algebra/emulated/sw_bn254/doc_test.go +++ b/std/algebra/emulated/sw_bn254/doc_test.go @@ -23,7 +23,7 @@ func (c *PairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res, err := pairing.Pair([]*sw_bn254.G1Affine{&c.InG1}, []*sw_bn254.G2Affine{&c.InG2}) + res, err := pairing.Pair(api, []*sw_bn254.G1Affine{&c.InG1}, []*sw_bn254.G2Affine{&c.InG2}) if err != nil { return fmt.Errorf("pair: %w", err) } diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index dfc8b3ac84..c1c6009b52 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -73,13 +73,7 @@ func NewPairing(api frontend.API) (*Pairing, error) { // and r does NOT divide d' // // FinalExponentiation returns a decompressed element in E12 -func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { - res := pr.FinalExponentiationTorus(e) - return pr.DecompressTorus(res) -} - -// FinalExponentiationTorus returns compressed element in E6 -func (pr Pairing) FinalExponentiationTorus(e *GTEl) *fields_bn254.E6 { +func (pr Pairing) FinalExponentiation(api frontend.API, e *GTEl) *GTEl { // Easy part // (p⁶-1)(p²+1) @@ -87,6 +81,14 @@ func (pr Pairing) FinalExponentiationTorus(e *GTEl) *fields_bn254.E6 { // The Miller loop result is ≠ {-1,1}, otherwise this means P and Q // are linearly dependant and not from G1 and G2 respectively. // So e ∈ G_{q,2} \ {-1,1} and hence e.C1 ≠ 0 + selector := pr.Ext6.IsZero(api, &e.C1) + _dummy := fields_bn254.E6{ + B0: *pr.Ext2.One(), + B1: *pr.Ext2.One(), + B2: *pr.Ext2.One(), + } + e.C1 = *pr.Ext6.Select(selector, &_dummy, &e.C1) + c := pr.Ext6.DivUnchecked(&e.C0, &e.C1) c = pr.Ext6.Neg(c) t0 := pr.FrobeniusSquareTorus(c) @@ -122,19 +124,21 @@ func (pr Pairing) FinalExponentiationTorus(e *GTEl) *fields_bn254.E6 { t2 = pr.FrobeniusCubeTorus(t2) t0 = pr.MulTorus(t2, t0) - return t0 + result := pr.Select(selector, pr.One(), pr.DecompressTorus(t0)) + + return result } // Pair calculates the reduced pairing for a set of points // ∏ᵢ e(Pᵢ, Qᵢ). // // This function doesn't check that the inputs are in the correct subgroup. -func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { +func (pr Pairing) Pair(api frontend.API, P []*G1Affine, Q []*G2Affine) (*GTEl, error) { res, err := pr.MillerLoop(P, Q) if err != nil { return nil, fmt.Errorf("miller loop: %w", err) } - res = pr.FinalExponentiation(res) + res = pr.FinalExponentiation(api, res) return res, nil } diff --git a/std/algebra/emulated/sw_bn254/pairing_test.go b/std/algebra/emulated/sw_bn254/pairing_test.go index 7009a2a21f..4b06889410 100644 --- a/std/algebra/emulated/sw_bn254/pairing_test.go +++ b/std/algebra/emulated/sw_bn254/pairing_test.go @@ -35,7 +35,7 @@ func (c *FinalExponentiationCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res := pairing.FinalExponentiation(&c.InGt) + res := pairing.FinalExponentiation(api, &c.InGt) pairing.AssertIsEqual(res, &c.Res) return nil } @@ -64,7 +64,7 @@ func (c *PairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res, err := pairing.Pair([]*G1Affine{&c.InG1}, []*G2Affine{&c.InG2}) + res, err := pairing.Pair(api, []*G1Affine{&c.InG1}, []*G2Affine{&c.InG2}) if err != nil { return fmt.Errorf("pair: %w", err) } @@ -99,7 +99,7 @@ func (c *MultiPairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res, err := pairing.Pair([]*G1Affine{&c.In1G1, &c.In1G1, &c.In2G1, &c.In2G1}, []*G2Affine{&c.In1G2, &c.In2G2, &c.In1G2, &c.In2G2}) + res, err := pairing.Pair(api, []*G1Affine{&c.In1G1, &c.In1G1, &c.In2G1, &c.In2G1}, []*G2Affine{&c.In1G2, &c.In2G2, &c.In1G2, &c.In2G2}) if err != nil { return fmt.Errorf("pair: %w", err) } From 71e742b2d04528faa498169760bd49a7c7570930 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 31 Mar 2023 18:04:16 +0200 Subject: [PATCH 216/464] fix(bn254/pairing): issue 605, edge cases in torus arithmetic --- std/algebra/emulated/fields_bn254/e12.go | 8 +++- .../emulated/fields_bn254/e12_pairing.go | 2 +- std/algebra/emulated/fields_bn254/e2.go | 6 +++ std/algebra/emulated/fields_bn254/e6.go | 9 ++++- std/algebra/emulated/sw_bn254/pairing.go | 37 +++++++++++-------- 5 files changed, 43 insertions(+), 19 deletions(-) diff --git a/std/algebra/emulated/fields_bn254/e12.go b/std/algebra/emulated/fields_bn254/e12.go index 0a59bbf6bf..21f9c73279 100644 --- a/std/algebra/emulated/fields_bn254/e12.go +++ b/std/algebra/emulated/fields_bn254/e12.go @@ -108,7 +108,7 @@ func (e Ext12) Square(x *E12) *E12 { c2 := e.Ext6.Mul(&x.C0, &x.C1) c0 = e.Ext6.Mul(c0, c3) c0 = e.Ext6.Add(c0, c2) - z1 := e.Ext6.double(c2) + z1 := e.Ext6.Double(c2) c2 = e.Ext6.MulByNonResidue(c2) z0 := e.Ext6.Add(c0, c2) return &E12{ @@ -195,6 +195,12 @@ func (e Ext12) Select(selector frontend.Variable, z1, z0 *E12) *E12 { return &E12{C0: *c0, C1: *c1} } +func (e Ext12) Lookup2(s1, s2 frontend.Variable, a, b, c, d *E12) *E12 { + c0 := e.Ext6.Lookup2(s1, s2, &a.C0, &b.C0, &c.C0, &d.C0) + c1 := e.Ext6.Lookup2(s1, s2, &a.C1, &b.C1, &c.C1, &d.C1) + return &E12{C0: *c0, C1: *c1} +} + func (e Ext12) String(x *E12) string { return fmt.Sprintf("%s+(%s)*w", e.Ext6.String(&x.C0), e.Ext6.String(&x.C1)) } diff --git a/std/algebra/emulated/fields_bn254/e12_pairing.go b/std/algebra/emulated/fields_bn254/e12_pairing.go index fa33cf90ab..ecec07bb2f 100644 --- a/std/algebra/emulated/fields_bn254/e12_pairing.go +++ b/std/algebra/emulated/fields_bn254/e12_pairing.go @@ -255,7 +255,7 @@ func (e Ext12) SquareTorus(y *E6) *E6 { } // v = (2x-y)y - v := e.Ext6.double(&sq) + v := e.Ext6.Double(&sq) v = e.Ext6.Sub(v, y) v = e.Ext6.Mul(v, y) diff --git a/std/algebra/emulated/fields_bn254/e2.go b/std/algebra/emulated/fields_bn254/e2.go index c26a1d1f41..6fe2701623 100644 --- a/std/algebra/emulated/fields_bn254/e2.go +++ b/std/algebra/emulated/fields_bn254/e2.go @@ -342,6 +342,12 @@ func (e Ext2) Select(selector frontend.Variable, z1, z0 *E2) *E2 { return &E2{A0: *a0, A1: *a1} } +func (e Ext2) Lookup2(s1, s2 frontend.Variable, a, b, c, d *E2) *E2 { + a0 := e.fp.Lookup2(s1, s2, &a.A0, &b.A0, &c.A0, &d.A0) + a1 := e.fp.Lookup2(s1, s2, &a.A1, &b.A1, &c.A1, &d.A1) + return &E2{A0: *a0, A1: *a1} +} + func (e Ext2) String(x *E2) string { x0, err := e.fp.String(&x.A0) if err != nil { diff --git a/std/algebra/emulated/fields_bn254/e6.go b/std/algebra/emulated/fields_bn254/e6.go index c6acf60423..5971348416 100644 --- a/std/algebra/emulated/fields_bn254/e6.go +++ b/std/algebra/emulated/fields_bn254/e6.go @@ -112,7 +112,7 @@ func (e Ext6) Mul(x, y *E6) *E6 { } } -func (e Ext6) double(x *E6) *E6 { +func (e Ext6) Double(x *E6) *E6 { z0 := e.Ext2.Double(&x.B0) z1 := e.Ext2.Double(&x.B1) z2 := e.Ext2.Double(&x.B2) @@ -333,6 +333,13 @@ func (e Ext6) Select(selector frontend.Variable, z1, z0 *E6) *E6 { return &E6{B0: *b0, B1: *b1, B2: *b2} } +func (e Ext6) Lookup2(s1, s2 frontend.Variable, a, b, c, d *E6) *E6 { + b0 := e.Ext2.Lookup2(s1, s2, &a.B0, &b.B0, &c.B0, &d.B0) + b1 := e.Ext2.Lookup2(s1, s2, &a.B1, &b.B1, &c.B1, &d.B1) + b2 := e.Ext2.Lookup2(s1, s2, &a.B2, &b.B2, &c.B2, &d.B2) + return &E6{B0: *b0, B1: *b1, B2: *b2} +} + func (e Ext6) String(x *E6) string { return fmt.Sprintf("%s+(%s)*v+(%s)*v**2", e.Ext2.String(&x.B0), e.Ext2.String(&x.B1), e.Ext2.String(&x.B2)) } diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index c1c6009b52..4def192890 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -75,26 +75,27 @@ func NewPairing(api frontend.API) (*Pairing, error) { // FinalExponentiation returns a decompressed element in E12 func (pr Pairing) FinalExponentiation(api frontend.API, e *GTEl) *GTEl { - // Easy part + // 1. Easy part // (p⁶-1)(p²+1) - // with Torus compression absorbed. - // The Miller loop result is ≠ {-1,1}, otherwise this means P and Q - // are linearly dependant and not from G1 and G2 respectively. - // So e ∈ G_{q,2} \ {-1,1} and hence e.C1 ≠ 0 - selector := pr.Ext6.IsZero(api, &e.C1) - _dummy := fields_bn254.E6{ - B0: *pr.Ext2.One(), - B1: *pr.Ext2.One(), - B2: *pr.Ext2.One(), - } - e.C1 = *pr.Ext6.Select(selector, &_dummy, &e.C1) - + // + // The Miller loop result is ≠ {-1,1}, otherwise this means P and Q are + // linearly dependant and not from G1 and G2 respectively. + // So e ∈ G_{q,2}a \ {-1,1} and hence e.C1 ≠ 0. + // + // However, for a product of Miller loops this might happen. If this is + // the case, the result is 1 in the torus. We assign a dummy one to e.C1 + // and proceed further. + selector1 := pr.Ext6.IsZero(api, &e.C1) + _dummy := pr.Ext6.One() + e.C1 = *pr.Ext6.Select(selector1, _dummy, &e.C1) + + // Torus compression absorbed c := pr.Ext6.DivUnchecked(&e.C0, &e.C1) c = pr.Ext6.Neg(c) t0 := pr.FrobeniusSquareTorus(c) c = pr.MulTorus(t0, c) - // Hard part (up to permutation) + // 2. Hard part (up to permutation) // 2x₀(6x₀²+3x₀+1)(p⁴-p²+1)/r // Duquesne and Ghammam // https://eprint.iacr.org/2015/192.pdf @@ -122,9 +123,13 @@ func (pr Pairing) FinalExponentiation(api frontend.API, e *GTEl) *GTEl { t2 = pr.InverseTorus(c) t2 = pr.MulTorus(t2, t3) t2 = pr.FrobeniusCubeTorus(t2) - t0 = pr.MulTorus(t2, t0) - result := pr.Select(selector, pr.One(), pr.DecompressTorus(t0)) + // MulTorus(t0, t2) requires t0 ≠ t2. When this is the case it means the + // result is 1 in the torus and we return 1. + _sum := pr.Ext6.Add(t0, t2) + selector2 := pr.Ext6.IsZero(api, _sum) + t0 = pr.Ext6.Select(selector2, pr.Ext6.One(), t0) + result := pr.Lookup2(selector1, selector2, pr.DecompressTorus(pr.MulTorus(t2, t0)), pr.One(), pr.One(), pr.One()) return result } From 10e6b9d4188476d18bfd57145fbe54a95e9613a8 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 31 Mar 2023 18:37:05 +0200 Subject: [PATCH 217/464] fix(bls12-381/pairing): issue 605, edge cases in torus arithmetic --- std/algebra/emulated/fields_bls12381/e12.go | 42 ++++++++++++++++++- std/algebra/emulated/fields_bls12381/e2.go | 32 +++++++++++++- std/algebra/emulated/fields_bls12381/e6.go | 29 ++++++++++++- std/algebra/emulated/fields_bn254/e12.go | 1 - std/algebra/emulated/fields_bn254/e2.go | 1 - std/algebra/emulated/fields_bn254/e6.go | 1 - std/algebra/emulated/sw_bls12381/pairing.go | 46 ++++++++++++++------- std/algebra/emulated/sw_bn254/pairing.go | 5 ++- 8 files changed, 134 insertions(+), 23 deletions(-) diff --git a/std/algebra/emulated/fields_bls12381/e12.go b/std/algebra/emulated/fields_bls12381/e12.go index 5bdab91e6b..c5950068a9 100644 --- a/std/algebra/emulated/fields_bls12381/e12.go +++ b/std/algebra/emulated/fields_bls12381/e12.go @@ -1,7 +1,10 @@ package fields_bls12381 import ( + "fmt" + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark/frontend" ) type E12 struct { @@ -58,6 +61,22 @@ func (e Ext12) Mul(x, y *E12) *E12 { } } +func (e Ext12) Zero() *E12 { + zero := e.fp.Zero() + return &E12{ + C0: E6{ + B0: E2{A0: *zero, A1: *zero}, + B1: E2{A0: *zero, A1: *zero}, + B2: E2{A0: *zero, A1: *zero}, + }, + C1: E6{ + B0: E2{A0: *zero, A1: *zero}, + B1: E2{A0: *zero, A1: *zero}, + B2: E2{A0: *zero, A1: *zero}, + }, + } +} + func (e Ext12) One() *E12 { z000 := e.fp.One() zero := e.fp.Zero() @@ -75,6 +94,12 @@ func (e Ext12) One() *E12 { } } +func (e Ext12) IsZero(api frontend.API, z *E12) frontend.Variable { + c0 := e.Ext6.IsZero(api, &z.C0) + c1 := e.Ext6.IsZero(api, &z.C1) + return api.And(c0, c1) +} + func (e Ext12) Square(x *E12) *E12 { c0 := e.Ext6.Sub(&x.C0, &x.C1) c3 := e.Ext6.MulByNonResidue(&x.C1) @@ -135,7 +160,6 @@ func (e Ext12) Inverse(x *E12) *E12 { } -// DivUnchecked e2 elmts func (e Ext12) DivUnchecked(x, y *E12) *E12 { res, err := e.fp.NewHint(divE12Hint, 12, &x.C0.B0.A0, &x.C0.B0.A1, &x.C0.B1.A0, &x.C0.B1.A1, &x.C0.B2.A0, &x.C0.B2.A1, &x.C1.B0.A0, &x.C1.B0.A1, &x.C1.B1.A0, &x.C1.B1.A1, &x.C1.B2.A0, &x.C1.B2.A1, &y.C0.B0.A0, &y.C0.B0.A1, &y.C0.B1.A0, &y.C0.B1.A1, &y.C0.B2.A0, &y.C0.B2.A1, &y.C1.B0.A0, &y.C1.B0.A1, &y.C1.B1.A0, &y.C1.B1.A1, &y.C1.B2.A0, &y.C1.B2.A1) @@ -163,3 +187,19 @@ func (e Ext12) DivUnchecked(x, y *E12) *E12 { return &div } + +func (e Ext12) Select(selector frontend.Variable, z1, z0 *E12) *E12 { + c0 := e.Ext6.Select(selector, &z1.C0, &z0.C0) + c1 := e.Ext6.Select(selector, &z1.C1, &z0.C1) + return &E12{C0: *c0, C1: *c1} +} + +func (e Ext12) Lookup2(s1, s2 frontend.Variable, a, b, c, d *E12) *E12 { + c0 := e.Ext6.Lookup2(s1, s2, &a.C0, &b.C0, &c.C0, &d.C0) + c1 := e.Ext6.Lookup2(s1, s2, &a.C1, &b.C1, &c.C1, &d.C1) + return &E12{C0: *c0, C1: *c1} +} + +func (e Ext12) String(x *E12) string { + return fmt.Sprintf("%s+(%s)*w", e.Ext6.String(&x.C0), e.Ext6.String(&x.C1)) +} diff --git a/std/algebra/emulated/fields_bls12381/e2.go b/std/algebra/emulated/fields_bls12381/e2.go index f4fd3fe7d9..19f228ace1 100644 --- a/std/algebra/emulated/fields_bls12381/e2.go +++ b/std/algebra/emulated/fields_bls12381/e2.go @@ -1,9 +1,11 @@ package fields_bls12381 import ( + "fmt" "math/big" bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/math/emulated" ) @@ -236,6 +238,11 @@ func (e Ext2) Zero() *E2 { A1: *z1, } } +func (e Ext2) IsZero(api frontend.API, z *E2) frontend.Variable { + a0 := e.fp.IsZero(&z.A0) + a1 := e.fp.IsZero(&z.A1) + return api.And(a0, a1) +} // returns 1+u func (e Ext2) NonResidue() *E2 { @@ -301,7 +308,6 @@ func (e Ext2) Inverse(x *E2) *E2 { } -// DivUnchecked e2 elmts func (e Ext2) DivUnchecked(x, y *E2) *E2 { res, err := e.fp.NewHint(divE2Hint, 2, &x.A0, &x.A1, &y.A0, &y.A1) if err != nil { @@ -320,3 +326,27 @@ func (e Ext2) DivUnchecked(x, y *E2) *E2 { return &div } + +func (e Ext2) Select(selector frontend.Variable, z1, z0 *E2) *E2 { + a0 := e.fp.Select(selector, &z1.A0, &z0.A0) + a1 := e.fp.Select(selector, &z1.A1, &z0.A1) + return &E2{A0: *a0, A1: *a1} +} + +func (e Ext2) Lookup2(s1, s2 frontend.Variable, a, b, c, d *E2) *E2 { + a0 := e.fp.Lookup2(s1, s2, &a.A0, &b.A0, &c.A0, &d.A0) + a1 := e.fp.Lookup2(s1, s2, &a.A1, &b.A1, &c.A1, &d.A1) + return &E2{A0: *a0, A1: *a1} +} + +func (e Ext2) String(x *E2) string { + x0, err := e.fp.String(&x.A0) + if err != nil { + x0 = "?" + } + x1, err := e.fp.String(&x.A1) + if err != nil { + x1 = "?" + } + return fmt.Sprintf("%s+%s*u", x0, x1) +} diff --git a/std/algebra/emulated/fields_bls12381/e6.go b/std/algebra/emulated/fields_bls12381/e6.go index 7073fd4711..d6cddf0f37 100644 --- a/std/algebra/emulated/fields_bls12381/e6.go +++ b/std/algebra/emulated/fields_bls12381/e6.go @@ -1,7 +1,10 @@ package fields_bls12381 import ( + "fmt" + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark/frontend" ) type E6 struct { @@ -38,6 +41,13 @@ func (e Ext6) Zero() *E6 { } } +func (e Ext6) IsZero(api frontend.API, z *E6) frontend.Variable { + b0 := e.Ext2.IsZero(api, &z.B0) + b1 := e.Ext2.IsZero(api, &z.B1) + b2 := e.Ext2.IsZero(api, &z.B2) + return api.And(api.And(b0, b1), b2) +} + func (e Ext6) Add(x, y *E6) *E6 { z0 := e.Ext2.Add(&x.B0, &y.B0) z1 := e.Ext2.Add(&x.B1, &y.B1) @@ -272,7 +282,6 @@ func (e Ext6) Inverse(x *E6) *E6 { } -// DivUnchecked e2 elmts func (e Ext6) DivUnchecked(x, y *E6) *E6 { res, err := e.fp.NewHint(divE6Hint, 6, &x.B0.A0, &x.B0.A1, &x.B1.A0, &x.B1.A1, &x.B2.A0, &x.B2.A1, &y.B0.A0, &y.B0.A1, &y.B1.A0, &y.B1.A1, &y.B2.A0, &y.B2.A1) if err != nil { @@ -292,3 +301,21 @@ func (e Ext6) DivUnchecked(x, y *E6) *E6 { return &div } + +func (e Ext6) Select(selector frontend.Variable, z1, z0 *E6) *E6 { + b0 := e.Ext2.Select(selector, &z1.B0, &z0.B0) + b1 := e.Ext2.Select(selector, &z1.B1, &z0.B1) + b2 := e.Ext2.Select(selector, &z1.B2, &z0.B2) + return &E6{B0: *b0, B1: *b1, B2: *b2} +} + +func (e Ext6) Lookup2(s1, s2 frontend.Variable, a, b, c, d *E6) *E6 { + b0 := e.Ext2.Lookup2(s1, s2, &a.B0, &b.B0, &c.B0, &d.B0) + b1 := e.Ext2.Lookup2(s1, s2, &a.B1, &b.B1, &c.B1, &d.B1) + b2 := e.Ext2.Lookup2(s1, s2, &a.B2, &b.B2, &c.B2, &d.B2) + return &E6{B0: *b0, B1: *b1, B2: *b2} +} + +func (e Ext6) String(x *E6) string { + return fmt.Sprintf("%s+(%s)*v+(%s)*v**2", e.Ext2.String(&x.B0), e.Ext2.String(&x.B1), e.Ext2.String(&x.B2)) +} diff --git a/std/algebra/emulated/fields_bn254/e12.go b/std/algebra/emulated/fields_bn254/e12.go index 21f9c73279..885e71c2b4 100644 --- a/std/algebra/emulated/fields_bn254/e12.go +++ b/std/algebra/emulated/fields_bn254/e12.go @@ -160,7 +160,6 @@ func (e Ext12) Inverse(x *E12) *E12 { } -// DivUnchecked e2 elmts func (e Ext12) DivUnchecked(x, y *E12) *E12 { res, err := e.fp.NewHint(divE12Hint, 12, &x.C0.B0.A0, &x.C0.B0.A1, &x.C0.B1.A0, &x.C0.B1.A1, &x.C0.B2.A0, &x.C0.B2.A1, &x.C1.B0.A0, &x.C1.B0.A1, &x.C1.B1.A0, &x.C1.B1.A1, &x.C1.B2.A0, &x.C1.B2.A1, &y.C0.B0.A0, &y.C0.B0.A1, &y.C0.B1.A0, &y.C0.B1.A1, &y.C0.B2.A0, &y.C0.B2.A1, &y.C1.B0.A0, &y.C1.B0.A1, &y.C1.B1.A0, &y.C1.B1.A1, &y.C1.B2.A0, &y.C1.B2.A1) diff --git a/std/algebra/emulated/fields_bn254/e2.go b/std/algebra/emulated/fields_bn254/e2.go index 6fe2701623..bb18f5e9c9 100644 --- a/std/algebra/emulated/fields_bn254/e2.go +++ b/std/algebra/emulated/fields_bn254/e2.go @@ -316,7 +316,6 @@ func (e Ext2) Inverse(x *E2) *E2 { } -// DivUnchecked e2 elmts func (e Ext2) DivUnchecked(x, y *E2) *E2 { res, err := e.fp.NewHint(divE2Hint, 2, &x.A0, &x.A1, &y.A0, &y.A1) if err != nil { diff --git a/std/algebra/emulated/fields_bn254/e6.go b/std/algebra/emulated/fields_bn254/e6.go index 5971348416..35a1115b81 100644 --- a/std/algebra/emulated/fields_bn254/e6.go +++ b/std/algebra/emulated/fields_bn254/e6.go @@ -305,7 +305,6 @@ func (e Ext6) Inverse(x *E6) *E6 { } -// DivUnchecked e2 elmts func (e Ext6) DivUnchecked(x, y *E6) *E6 { res, err := e.fp.NewHint(divE6Hint, 6, &x.B0.A0, &x.B0.A1, &x.B1.A0, &x.B1.A1, &x.B2.A0, &x.B2.A1, &y.B0.A0, &y.B0.A1, &y.B1.A0, &y.B1.A1, &y.B2.A0, &y.B2.A1) if err != nil { diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go index 1639c1af5f..1bfd44541a 100644 --- a/std/algebra/emulated/sw_bls12381/pairing.go +++ b/std/algebra/emulated/sw_bls12381/pairing.go @@ -66,25 +66,30 @@ func NewPairing(api frontend.API) (*Pairing, error) { // where d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r // we use instead d=s ⋅ (p⁶-1)(p²+1)(p⁴ - p² +1)/r // where s is the cofactor 3 (Hayashida et al.) -func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { - res := pr.FinalExponentiationTorus(e) - return pr.DecompressTorus(res) -} - -func (pr Pairing) FinalExponentiationTorus(e *GTEl) *fields_bls12381.E6 { +func (pr Pairing) FinalExponentiation(api frontend.API, e *GTEl) *GTEl { - // Easy part + // 1. Easy part // (p⁶-1)(p²+1) - // with Torus compression absorbed. - // The Miller loop result is ≠ {-1,1}, otherwise this means P and Q - // are linearly dependant and not from G1 and G2 respectively. - // So e ∈ G_{q,2} \ {-1,1} and hence e.C1 ≠ 0 + // + // The Miller loop result is ≠ {-1,1}, otherwise this means P and Q are + // linearly dependant and not from G1 and G2 respectively. + // So e ∈ G_{q,2}a \ {-1,1} and hence e.C1 ≠ 0. + // + // However, for a product of Miller loops this might happen. If this is + // the case, the result is 1 in the torus. We assign a dummy one to e.C1 + // and proceed further. + selector1 := pr.Ext6.IsZero(api, &e.C1) + _dummy := pr.Ext6.One() + e.C1 = *pr.Ext6.Select(selector1, _dummy, &e.C1) + + // Torus compression absorbed c := pr.Ext6.DivUnchecked(&e.C0, &e.C1) c = pr.Ext6.Neg(c) t0 := pr.FrobeniusSquareTorus(c) c = pr.MulTorus(t0, c) - // Hard part (up to permutation) + // 2. Hard part (up to permutation) + // 3(p⁴-p²+1)/r // Daiki Hayashida, Kenichiro Hayasaka and Tadanori Teruya // https://eprint.iacr.org/2020/875.pdf t0 = pr.SquareTorus(c) @@ -104,9 +109,18 @@ func (pr Pairing) FinalExponentiationTorus(e *GTEl) *fields_bls12381.E6 { t1 = pr.InverseTorus(t1) t1 = pr.MulTorus(t1, t2) t1 = pr.MulTorus(t1, t0) - c = pr.MulTorus(c, t1) - return c + // MulTorus(c, t1) requires c ≠ t1. When this is the case it means the + // result is 1 in the torus. We assign a dummy one to t0 and proceed furhter. + // Finally we do a Lookup2 on both edge cases: + // - Only if seletor1=0 and selector2=0, returns to MulTorus(c, t1) decompressed, + // - otherwise, returns to 1. + _sum := pr.Ext6.Add(c, t1) + selector2 := pr.Ext6.IsZero(api, _sum) + t1 = pr.Ext6.Select(selector2, pr.Ext6.One(), t1) + result := pr.Lookup2(selector1, selector2, pr.DecompressTorus(pr.MulTorus(c, t1)), pr.One(), pr.One(), pr.One()) + + return result } // lineEvaluation represents a sparse Fp12 Elmt (result of the line evaluation) @@ -121,12 +135,12 @@ type lineEvaluation struct { // ∏ᵢ e(Pᵢ, Qᵢ). // // This function doesn't check that the inputs are in the correct subgroup. -func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { +func (pr Pairing) Pair(api frontend.API, P []*G1Affine, Q []*G2Affine) (*GTEl, error) { res, err := pr.MillerLoop(P, Q) if err != nil { return nil, fmt.Errorf("miller loop: %w", err) } - res = pr.FinalExponentiation(res) + res = pr.FinalExponentiation(api, res) return res, nil } diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 4def192890..c7b30411df 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -125,7 +125,10 @@ func (pr Pairing) FinalExponentiation(api frontend.API, e *GTEl) *GTEl { t2 = pr.FrobeniusCubeTorus(t2) // MulTorus(t0, t2) requires t0 ≠ t2. When this is the case it means the - // result is 1 in the torus and we return 1. + // result is 1 in the torus. We assign a dummy one to t0 and proceed furhter. + // Finally we do a Lookup2 on both edge cases: + // - Only if seletor1=0 and selector2=0, returns to MulTorus(t2, t0) decompressed, + // - otherwise, returns to 1. _sum := pr.Ext6.Add(t0, t2) selector2 := pr.Ext6.IsZero(api, _sum) t0 = pr.Ext6.Select(selector2, pr.Ext6.One(), t0) From 39a87ecead00f993d3b82386f4f7b418a17359ed Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 31 Mar 2023 18:52:33 +0200 Subject: [PATCH 218/464] test(bls12-381/pairing): fix test --- std/algebra/emulated/sw_bls12381/doc_test.go | 2 +- std/algebra/emulated/sw_bls12381/pairing_test.go | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/std/algebra/emulated/sw_bls12381/doc_test.go b/std/algebra/emulated/sw_bls12381/doc_test.go index ae87b72997..485ef0482d 100644 --- a/std/algebra/emulated/sw_bls12381/doc_test.go +++ b/std/algebra/emulated/sw_bls12381/doc_test.go @@ -23,7 +23,7 @@ func (c *PairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res, err := pairing.Pair([]*sw_bls12381.G1Affine{&c.InG1}, []*sw_bls12381.G2Affine{&c.InG2}) + res, err := pairing.Pair(api, []*sw_bls12381.G1Affine{&c.InG1}, []*sw_bls12381.G2Affine{&c.InG2}) if err != nil { return fmt.Errorf("pair: %w", err) } diff --git a/std/algebra/emulated/sw_bls12381/pairing_test.go b/std/algebra/emulated/sw_bls12381/pairing_test.go index 0be5ff02a6..aa2e5c0b35 100644 --- a/std/algebra/emulated/sw_bls12381/pairing_test.go +++ b/std/algebra/emulated/sw_bls12381/pairing_test.go @@ -35,7 +35,7 @@ func (c *FinalExponentiationCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res := pairing.FinalExponentiation(&c.InGt) + res := pairing.FinalExponentiation(api, &c.InGt) pairing.AssertIsEqual(res, &c.Res) return nil } @@ -64,7 +64,7 @@ func (c *PairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res, err := pairing.Pair([]*G1Affine{&c.InG1}, []*G2Affine{&c.InG2}) + res, err := pairing.Pair(api, []*G1Affine{&c.InG1}, []*G2Affine{&c.InG2}) if err != nil { return fmt.Errorf("pair: %w", err) } @@ -99,7 +99,7 @@ func (c *MultiPairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res, err := pairing.Pair([]*G1Affine{&c.In1G1, &c.In1G1, &c.In2G1, &c.In2G1}, []*G2Affine{&c.In1G2, &c.In2G2, &c.In1G2, &c.In2G2}) + res, err := pairing.Pair(api, []*G1Affine{&c.In1G1, &c.In1G1, &c.In2G1, &c.In2G1}, []*G2Affine{&c.In1G2, &c.In2G2, &c.In1G2, &c.In2G2}) if err != nil { return fmt.Errorf("pair: %w", err) } From efcaa0969adb76aa8a8b28388dea7a58e8097cd0 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Fri, 31 Mar 2023 21:36:05 +0200 Subject: [PATCH 219/464] chore: remove debug printing code --- std/algebra/emulated/fields_bls12381/e12.go | 6 ---- std/algebra/emulated/fields_bls12381/e2.go | 13 -------- std/algebra/emulated/fields_bls12381/e6.go | 6 ---- std/algebra/emulated/fields_bn254/e12.go | 6 ---- std/algebra/emulated/fields_bn254/e2.go | 13 -------- std/algebra/emulated/fields_bn254/e6.go | 6 ---- std/math/emulated/field_ops.go | 34 --------------------- 7 files changed, 84 deletions(-) diff --git a/std/algebra/emulated/fields_bls12381/e12.go b/std/algebra/emulated/fields_bls12381/e12.go index c5950068a9..461639f86d 100644 --- a/std/algebra/emulated/fields_bls12381/e12.go +++ b/std/algebra/emulated/fields_bls12381/e12.go @@ -1,8 +1,6 @@ package fields_bls12381 import ( - "fmt" - bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" "github.com/consensys/gnark/frontend" ) @@ -199,7 +197,3 @@ func (e Ext12) Lookup2(s1, s2 frontend.Variable, a, b, c, d *E12) *E12 { c1 := e.Ext6.Lookup2(s1, s2, &a.C1, &b.C1, &c.C1, &d.C1) return &E12{C0: *c0, C1: *c1} } - -func (e Ext12) String(x *E12) string { - return fmt.Sprintf("%s+(%s)*w", e.Ext6.String(&x.C0), e.Ext6.String(&x.C1)) -} diff --git a/std/algebra/emulated/fields_bls12381/e2.go b/std/algebra/emulated/fields_bls12381/e2.go index 19f228ace1..a7939fa631 100644 --- a/std/algebra/emulated/fields_bls12381/e2.go +++ b/std/algebra/emulated/fields_bls12381/e2.go @@ -1,7 +1,6 @@ package fields_bls12381 import ( - "fmt" "math/big" bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" @@ -338,15 +337,3 @@ func (e Ext2) Lookup2(s1, s2 frontend.Variable, a, b, c, d *E2) *E2 { a1 := e.fp.Lookup2(s1, s2, &a.A1, &b.A1, &c.A1, &d.A1) return &E2{A0: *a0, A1: *a1} } - -func (e Ext2) String(x *E2) string { - x0, err := e.fp.String(&x.A0) - if err != nil { - x0 = "?" - } - x1, err := e.fp.String(&x.A1) - if err != nil { - x1 = "?" - } - return fmt.Sprintf("%s+%s*u", x0, x1) -} diff --git a/std/algebra/emulated/fields_bls12381/e6.go b/std/algebra/emulated/fields_bls12381/e6.go index d6cddf0f37..62d8a9faaa 100644 --- a/std/algebra/emulated/fields_bls12381/e6.go +++ b/std/algebra/emulated/fields_bls12381/e6.go @@ -1,8 +1,6 @@ package fields_bls12381 import ( - "fmt" - bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" "github.com/consensys/gnark/frontend" ) @@ -315,7 +313,3 @@ func (e Ext6) Lookup2(s1, s2 frontend.Variable, a, b, c, d *E6) *E6 { b2 := e.Ext2.Lookup2(s1, s2, &a.B2, &b.B2, &c.B2, &d.B2) return &E6{B0: *b0, B1: *b1, B2: *b2} } - -func (e Ext6) String(x *E6) string { - return fmt.Sprintf("%s+(%s)*v+(%s)*v**2", e.Ext2.String(&x.B0), e.Ext2.String(&x.B1), e.Ext2.String(&x.B2)) -} diff --git a/std/algebra/emulated/fields_bn254/e12.go b/std/algebra/emulated/fields_bn254/e12.go index 885e71c2b4..d270a925ef 100644 --- a/std/algebra/emulated/fields_bn254/e12.go +++ b/std/algebra/emulated/fields_bn254/e12.go @@ -1,8 +1,6 @@ package fields_bn254 import ( - "fmt" - "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark/frontend" ) @@ -199,7 +197,3 @@ func (e Ext12) Lookup2(s1, s2 frontend.Variable, a, b, c, d *E12) *E12 { c1 := e.Ext6.Lookup2(s1, s2, &a.C1, &b.C1, &c.C1, &d.C1) return &E12{C0: *c0, C1: *c1} } - -func (e Ext12) String(x *E12) string { - return fmt.Sprintf("%s+(%s)*w", e.Ext6.String(&x.C0), e.Ext6.String(&x.C1)) -} diff --git a/std/algebra/emulated/fields_bn254/e2.go b/std/algebra/emulated/fields_bn254/e2.go index bb18f5e9c9..4fb3f1f2d7 100644 --- a/std/algebra/emulated/fields_bn254/e2.go +++ b/std/algebra/emulated/fields_bn254/e2.go @@ -1,7 +1,6 @@ package fields_bn254 import ( - "fmt" "math/big" "github.com/consensys/gnark-crypto/ecc/bn254" @@ -346,15 +345,3 @@ func (e Ext2) Lookup2(s1, s2 frontend.Variable, a, b, c, d *E2) *E2 { a1 := e.fp.Lookup2(s1, s2, &a.A1, &b.A1, &c.A1, &d.A1) return &E2{A0: *a0, A1: *a1} } - -func (e Ext2) String(x *E2) string { - x0, err := e.fp.String(&x.A0) - if err != nil { - x0 = "?" - } - x1, err := e.fp.String(&x.A1) - if err != nil { - x1 = "?" - } - return fmt.Sprintf("%s+%s*u", x0, x1) -} diff --git a/std/algebra/emulated/fields_bn254/e6.go b/std/algebra/emulated/fields_bn254/e6.go index 35a1115b81..f26d835327 100644 --- a/std/algebra/emulated/fields_bn254/e6.go +++ b/std/algebra/emulated/fields_bn254/e6.go @@ -1,8 +1,6 @@ package fields_bn254 import ( - "fmt" - "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark/frontend" ) @@ -338,7 +336,3 @@ func (e Ext6) Lookup2(s1, s2 frontend.Variable, a, b, c, d *E6) *E6 { b2 := e.Ext2.Lookup2(s1, s2, &a.B2, &b.B2, &c.B2, &d.B2) return &E6{B0: *b0, B1: *b1, B2: *b2} } - -func (e Ext6) String(x *E6) string { - return fmt.Sprintf("%s+(%s)*v+(%s)*v**2", e.Ext2.String(&x.B0), e.Ext2.String(&x.B1), e.Ext2.String(&x.B2)) -} diff --git a/std/math/emulated/field_ops.go b/std/math/emulated/field_ops.go index b40bfbc8c7..31739cf716 100644 --- a/std/math/emulated/field_ops.go +++ b/std/math/emulated/field_ops.go @@ -368,37 +368,3 @@ type overflowError struct { func (e overflowError) Error() string { return fmt.Sprintf("op %s overflow %d exceeds max %d", e.op, e.nextOverflow, e.maxOverflow) } - -func (f *Field[T]) String(a *Element[T]) (string, error) { - // for debug only, if is not test engine then no-op - var fp T - blimbs := make([]*big.Int, len(a.Limbs)) - for i, v := range a.Limbs { - switch vv := v.(type) { - case *big.Int: - blimbs[i] = vv - case big.Int: - blimbs[i] = &vv - case int: - blimbs[i] = new(big.Int) - blimbs[i].SetInt64(int64(vv)) - case uint: - blimbs[i] = new(big.Int) - blimbs[i].SetUint64(uint64(vv)) - default: - return "", fmt.Errorf("not big int") - } - } - res := new(big.Int) - err := recompose(blimbs, fp.BitsPerLimb(), res) - if err != nil { - return "", fmt.Errorf("recompose: %w", err) - } - reduced := new(big.Int).Mod(res, fp.Modulus()) - return reduced.String(), nil -} - -func (f *Field[T]) Println(a *Element[T]) { - res, _ := f.String(a) - fmt.Println(res) -} From 04885e03bdaf220adf9b7dbba1eedf829f534729 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Fri, 31 Mar 2023 21:59:01 +0200 Subject: [PATCH 220/464] refactor: embed api and init emulation in tower --- std/algebra/emulated/fields_bls12381/e12.go | 4 +- .../emulated/fields_bls12381/e12_test.go | 53 ++++++------------ std/algebra/emulated/fields_bls12381/e2.go | 9 ++- .../emulated/fields_bls12381/e2_test.go | 36 ++++-------- std/algebra/emulated/fields_bls12381/e6.go | 4 +- .../emulated/fields_bls12381/e6_test.go | 35 ++++-------- std/algebra/emulated/fields_bn254/e12.go | 4 +- std/algebra/emulated/fields_bn254/e12_test.go | 56 ++++++------------- std/algebra/emulated/fields_bn254/e2.go | 10 +++- std/algebra/emulated/fields_bn254/e2_test.go | 33 ++++------- std/algebra/emulated/fields_bn254/e6.go | 4 +- std/algebra/emulated/fields_bn254/e6_test.go | 38 ++++--------- std/algebra/emulated/sw_bls12381/pairing.go | 2 +- std/algebra/emulated/sw_bn254/pairing.go | 2 +- 14 files changed, 100 insertions(+), 190 deletions(-) diff --git a/std/algebra/emulated/fields_bls12381/e12.go b/std/algebra/emulated/fields_bls12381/e12.go index 461639f86d..a2e400fe2e 100644 --- a/std/algebra/emulated/fields_bls12381/e12.go +++ b/std/algebra/emulated/fields_bls12381/e12.go @@ -13,8 +13,8 @@ type Ext12 struct { *Ext6 } -func NewExt12(baseField *curveF) *Ext12 { - return &Ext12{Ext6: NewExt6(baseField)} +func NewExt12(api frontend.API) *Ext12 { + return &Ext12{Ext6: NewExt6(api)} } func (e Ext12) Add(x, y *E12) *E12 { diff --git a/std/algebra/emulated/fields_bls12381/e12_test.go b/std/algebra/emulated/fields_bls12381/e12_test.go index 7410827c46..cba62ef2be 100644 --- a/std/algebra/emulated/fields_bls12381/e12_test.go +++ b/std/algebra/emulated/fields_bls12381/e12_test.go @@ -6,7 +6,6 @@ import ( "github.com/consensys/gnark-crypto/ecc" bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/test" ) @@ -15,8 +14,7 @@ type e12Add struct { } func (circuit *e12Add) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt12(ba) + e := NewExt12(api) expected := e.Add(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) return nil @@ -47,8 +45,7 @@ type e12Sub struct { } func (circuit *e12Sub) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt12(ba) + e := NewExt12(api) expected := e.Sub(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) return nil @@ -79,9 +76,7 @@ type e12Mul struct { } func (circuit *e12Mul) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt12(ba) - + e := NewExt12(api) expected := e.Mul(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) return nil @@ -112,9 +107,7 @@ type e12Div struct { } func (circuit *e12Div) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt12(ba) - + e := NewExt12(api) expected := e.DivUnchecked(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) return nil @@ -145,9 +138,7 @@ type e12Square struct { } func (circuit *e12Square) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt12(ba) - + e := NewExt12(api) expected := e.Square(&circuit.A) e.AssertIsEqual(expected, &circuit.C) return nil @@ -177,8 +168,7 @@ type e12Conjugate struct { } func (circuit *e12Conjugate) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt12(ba) + e := NewExt12(api) expected := e.Conjugate(&circuit.A) e.AssertIsEqual(expected, &circuit.C) @@ -208,8 +198,7 @@ type e12Inverse struct { } func (circuit *e12Inverse) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt12(ba) + e := NewExt12(api) expected := e.Inverse(&circuit.A) e.AssertIsEqual(expected, &circuit.C) @@ -239,8 +228,7 @@ type e12ExptTorus struct { } func (circuit *e12ExptTorus) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt12(ba) + e := NewExt12(api) z := e.ExptTorus(&circuit.A) expected := e.DecompressTorus(z) e.AssertIsEqual(expected, &circuit.C) @@ -280,9 +268,7 @@ type e12MulBy014 struct { } func (circuit *e12MulBy014) Define(api frontend.API) error { - - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt12(ba) + e := NewExt12(api) res := e.MulBy014(&circuit.A, &circuit.B, &circuit.C) e.AssertIsEqual(res, &circuit.W) return nil @@ -320,8 +306,7 @@ type torusCompress struct { } func (circuit *torusCompress) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt12(ba) + e := NewExt12(api) expected := e.CompressTorus(&circuit.A) e.Ext6.AssertIsEqual(expected, &circuit.C) return nil @@ -358,8 +343,7 @@ type torusDecompress struct { } func (circuit *torusDecompress) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt12(ba) + e := NewExt12(api) compressed := e.CompressTorus(&circuit.A) expected := e.DecompressTorus(compressed) e.AssertIsEqual(expected, &circuit.C) @@ -399,8 +383,7 @@ type torusMul struct { } func (circuit *torusMul) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt12(ba) + e := NewExt12(api) compressedA := e.CompressTorus(&circuit.A) compressedB := e.CompressTorus(&circuit.B) compressedAB := e.MulTorus(compressedA, compressedB) @@ -447,8 +430,7 @@ type torusInverse struct { } func (circuit *torusInverse) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt12(ba) + e := NewExt12(api) compressed := e.CompressTorus(&circuit.A) compressed = e.InverseTorus(compressed) expected := e.DecompressTorus(compressed) @@ -487,8 +469,7 @@ type torusFrobenius struct { } func (circuit *torusFrobenius) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt12(ba) + e := NewExt12(api) compressed := e.CompressTorus(&circuit.A) compressed = e.FrobeniusTorus(compressed) expected := e.DecompressTorus(compressed) @@ -527,8 +508,7 @@ type torusFrobeniusSquare struct { } func (circuit *torusFrobeniusSquare) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt12(ba) + e := NewExt12(api) compressed := e.CompressTorus(&circuit.A) compressed = e.FrobeniusSquareTorus(compressed) expected := e.DecompressTorus(compressed) @@ -567,8 +547,7 @@ type torusSquare struct { } func (circuit *torusSquare) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt12(ba) + e := NewExt12(api) compressed := e.CompressTorus(&circuit.A) compressed = e.SquareTorus(compressed) expected := e.DecompressTorus(compressed) diff --git a/std/algebra/emulated/fields_bls12381/e2.go b/std/algebra/emulated/fields_bls12381/e2.go index a7939fa631..3fd2bca121 100644 --- a/std/algebra/emulated/fields_bls12381/e2.go +++ b/std/algebra/emulated/fields_bls12381/e2.go @@ -16,11 +16,16 @@ type E2 struct { } type Ext2 struct { + api frontend.API fp *curveF nonResidues map[int]map[int]*E2 } -func NewExt2(baseField *curveF) *Ext2 { +func NewExt2(api frontend.API) *Ext2 { + fp, err := emulated.NewField[emulated.BLS12381Fp](api) + if err != nil { + panic(err) + } pwrs := map[int]map[int]struct { A0 string A1 string @@ -50,7 +55,7 @@ func NewExt2(baseField *curveF) *Ext2 { nonResidues[pwr][coeff] = &el } } - return &Ext2{fp: baseField, nonResidues: nonResidues} + return &Ext2{api: api, fp: fp, nonResidues: nonResidues} } func (e Ext2) MulByElement(x *E2, y *baseEl) *E2 { diff --git a/std/algebra/emulated/fields_bls12381/e2_test.go b/std/algebra/emulated/fields_bls12381/e2_test.go index 972e6d3dce..4065af437c 100644 --- a/std/algebra/emulated/fields_bls12381/e2_test.go +++ b/std/algebra/emulated/fields_bls12381/e2_test.go @@ -16,8 +16,7 @@ type e2Add struct { } func (circuit *e2Add) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt2(ba) + e := NewExt2(api) expected := e.Add(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) return nil @@ -48,8 +47,7 @@ type e2Sub struct { } func (circuit *e2Sub) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt2(ba) + e := NewExt2(api) expected := e.Sub(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) return nil @@ -80,8 +78,7 @@ type e2Double struct { } func (circuit *e2Double) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt2(ba) + e := NewExt2(api) expected := e.Double(&circuit.A) e.AssertIsEqual(expected, &circuit.C) return nil @@ -111,9 +108,7 @@ type e2Mul struct { } func (circuit *e2Mul) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt2(ba) - + e := NewExt2(api) expected := e.Mul(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) return nil @@ -144,9 +139,7 @@ type e2Square struct { } func (circuit *e2Square) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt2(ba) - + e := NewExt2(api) expected := e.Square(&circuit.A) e.AssertIsEqual(expected, &circuit.C) return nil @@ -175,9 +168,7 @@ type e2Div struct { } func (circuit *e2Div) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt2(ba) - + e := NewExt2(api) expected := e.DivUnchecked(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) return nil @@ -210,8 +201,7 @@ type e2MulByElement struct { } func (circuit *e2MulByElement) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt2(ba) + e := NewExt2(api) expected := e.MulByElement(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) @@ -245,8 +235,7 @@ type e2MulByNonResidue struct { } func (circuit *e2MulByNonResidue) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt2(ba) + e := NewExt2(api) expected := e.MulByNonResidue(&circuit.A) e.AssertIsEqual(expected, &circuit.C) @@ -277,8 +266,7 @@ type e2Neg struct { } func (circuit *e2Neg) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt2(ba) + e := NewExt2(api) expected := e.Neg(&circuit.A) e.AssertIsEqual(expected, &circuit.C) @@ -308,8 +296,7 @@ type e2Conjugate struct { } func (circuit *e2Conjugate) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt2(ba) + e := NewExt2(api) expected := e.Conjugate(&circuit.A) e.AssertIsEqual(expected, &circuit.C) @@ -339,8 +326,7 @@ type e2Inverse struct { } func (circuit *e2Inverse) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt2(ba) + e := NewExt2(api) expected := e.Inverse(&circuit.A) e.AssertIsEqual(expected, &circuit.C) diff --git a/std/algebra/emulated/fields_bls12381/e6.go b/std/algebra/emulated/fields_bls12381/e6.go index 62d8a9faaa..4e8ddfd8ec 100644 --- a/std/algebra/emulated/fields_bls12381/e6.go +++ b/std/algebra/emulated/fields_bls12381/e6.go @@ -13,8 +13,8 @@ type Ext6 struct { *Ext2 } -func NewExt6(baseField *curveF) *Ext6 { - return &Ext6{Ext2: NewExt2(baseField)} +func NewExt6(api frontend.API) *Ext6 { + return &Ext6{Ext2: NewExt2(api)} } func (e Ext6) One() *E6 { diff --git a/std/algebra/emulated/fields_bls12381/e6_test.go b/std/algebra/emulated/fields_bls12381/e6_test.go index 7b784db822..7964833bdf 100644 --- a/std/algebra/emulated/fields_bls12381/e6_test.go +++ b/std/algebra/emulated/fields_bls12381/e6_test.go @@ -6,7 +6,6 @@ import ( "github.com/consensys/gnark-crypto/ecc" bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/test" ) @@ -15,8 +14,7 @@ type e6Add struct { } func (circuit *e6Add) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt6(ba) + e := NewExt6(api) expected := e.Add(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) return nil @@ -47,8 +45,7 @@ type e6Sub struct { } func (circuit *e6Sub) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt6(ba) + e := NewExt6(api) expected := e.Sub(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) return nil @@ -79,9 +76,7 @@ type e6Mul struct { } func (circuit *e6Mul) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt6(ba) - + e := NewExt6(api) expected := e.Mul(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) return nil @@ -112,9 +107,7 @@ type e6Square struct { } func (circuit *e6Square) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt6(ba) - + e := NewExt6(api) expected := e.Square(&circuit.A) e.AssertIsEqual(expected, &circuit.C) return nil @@ -143,9 +136,7 @@ type e6Div struct { } func (circuit *e6Div) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt6(ba) - + e := NewExt6(api) expected := e.DivUnchecked(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) return nil @@ -177,8 +168,7 @@ type e6MulByNonResidue struct { } func (circuit *e6MulByNonResidue) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt6(ba) + e := NewExt6(api) expected := e.MulByNonResidue(&circuit.A) e.AssertIsEqual(expected, &circuit.C) @@ -210,8 +200,7 @@ type e6MulByE2 struct { } func (circuit *e6MulByE2) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt6(ba) + e := NewExt6(api) expected := e.MulByE2(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) @@ -246,8 +235,7 @@ type e6MulBy01 struct { } func (circuit *e6MulBy01) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt6(ba) + e := NewExt6(api) expected := e.MulBy01(&circuit.A, &circuit.C0, &circuit.C1) e.AssertIsEqual(expected, &circuit.C) @@ -284,8 +272,7 @@ type e6Neg struct { } func (circuit *e6Neg) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt6(ba) + e := NewExt6(api) expected := e.Neg(&circuit.A) e.AssertIsEqual(expected, &circuit.C) @@ -315,9 +302,7 @@ type e6Inverse struct { } func (circuit *e6Inverse) Define(api frontend.API) error { - - ba, _ := emulated.NewField[emulated.BLS12381Fp](api) - e := NewExt6(ba) + e := NewExt6(api) expected := e.Inverse(&circuit.A) e.AssertIsEqual(expected, &circuit.C) diff --git a/std/algebra/emulated/fields_bn254/e12.go b/std/algebra/emulated/fields_bn254/e12.go index d270a925ef..4d3a23fcc3 100644 --- a/std/algebra/emulated/fields_bn254/e12.go +++ b/std/algebra/emulated/fields_bn254/e12.go @@ -13,8 +13,8 @@ type Ext12 struct { *Ext6 } -func NewExt12(baseField *curveF) *Ext12 { - return &Ext12{Ext6: NewExt6(baseField)} +func NewExt12(api frontend.API) *Ext12 { + return &Ext12{Ext6: NewExt6(api)} } func (e Ext12) Add(x, y *E12) *E12 { diff --git a/std/algebra/emulated/fields_bn254/e12_test.go b/std/algebra/emulated/fields_bn254/e12_test.go index 7c7e8185a4..a3289b4698 100644 --- a/std/algebra/emulated/fields_bn254/e12_test.go +++ b/std/algebra/emulated/fields_bn254/e12_test.go @@ -6,7 +6,6 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/test" ) @@ -15,8 +14,7 @@ type e12Add struct { } func (circuit *e12Add) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt12(ba) + e := NewExt12(api) expected := e.Add(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) return nil @@ -47,8 +45,7 @@ type e12Sub struct { } func (circuit *e12Sub) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt12(ba) + e := NewExt12(api) expected := e.Sub(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) return nil @@ -79,9 +76,7 @@ type e12Mul struct { } func (circuit *e12Mul) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt12(ba) - + e := NewExt12(api) expected := e.Mul(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) return nil @@ -112,9 +107,7 @@ type e12Div struct { } func (circuit *e12Div) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt12(ba) - + e := NewExt12(api) expected := e.DivUnchecked(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) return nil @@ -145,9 +138,7 @@ type e12Square struct { } func (circuit *e12Square) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt12(ba) - + e := NewExt12(api) expected := e.Square(&circuit.A) e.AssertIsEqual(expected, &circuit.C) return nil @@ -177,8 +168,7 @@ type e12Conjugate struct { } func (circuit *e12Conjugate) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt12(ba) + e := NewExt12(api) expected := e.Conjugate(&circuit.A) e.AssertIsEqual(expected, &circuit.C) @@ -208,8 +198,7 @@ type e12Inverse struct { } func (circuit *e12Inverse) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt12(ba) + e := NewExt12(api) expected := e.Inverse(&circuit.A) e.AssertIsEqual(expected, &circuit.C) @@ -239,8 +228,7 @@ type e12ExptTorus struct { } func (circuit *e12ExptTorus) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt12(ba) + e := NewExt12(api) z := e.ExptTorus(&circuit.A) expected := e.DecompressTorus(z) e.AssertIsEqual(expected, &circuit.C) @@ -280,9 +268,7 @@ type e12MulBy034 struct { } func (circuit *e12MulBy034) Define(api frontend.API) error { - - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt12(ba) + e := NewExt12(api) res := e.MulBy034(&circuit.A, &circuit.B, &circuit.C) e.AssertIsEqual(res, &circuit.W) return nil @@ -320,8 +306,7 @@ type torusCompress struct { } func (circuit *torusCompress) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt12(ba) + e := NewExt12(api) expected := e.CompressTorus(&circuit.A) e.Ext6.AssertIsEqual(expected, &circuit.C) return nil @@ -358,8 +343,7 @@ type torusDecompress struct { } func (circuit *torusDecompress) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt12(ba) + e := NewExt12(api) compressed := e.CompressTorus(&circuit.A) expected := e.DecompressTorus(compressed) e.AssertIsEqual(expected, &circuit.C) @@ -399,8 +383,7 @@ type torusMul struct { } func (circuit *torusMul) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt12(ba) + e := NewExt12(api) compressedA := e.CompressTorus(&circuit.A) compressedB := e.CompressTorus(&circuit.B) compressedAB := e.MulTorus(compressedA, compressedB) @@ -447,8 +430,7 @@ type torusInverse struct { } func (circuit *torusInverse) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt12(ba) + e := NewExt12(api) compressed := e.CompressTorus(&circuit.A) compressed = e.InverseTorus(compressed) expected := e.DecompressTorus(compressed) @@ -487,8 +469,7 @@ type torusFrobenius struct { } func (circuit *torusFrobenius) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt12(ba) + e := NewExt12(api) compressed := e.CompressTorus(&circuit.A) compressed = e.FrobeniusTorus(compressed) expected := e.DecompressTorus(compressed) @@ -527,8 +508,7 @@ type torusFrobeniusSquare struct { } func (circuit *torusFrobeniusSquare) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt12(ba) + e := NewExt12(api) compressed := e.CompressTorus(&circuit.A) compressed = e.FrobeniusSquareTorus(compressed) expected := e.DecompressTorus(compressed) @@ -567,8 +547,7 @@ type torusFrobeniusCube struct { } func (circuit *torusFrobeniusCube) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt12(ba) + e := NewExt12(api) compressed := e.CompressTorus(&circuit.A) compressed = e.FrobeniusCubeTorus(compressed) expected := e.DecompressTorus(compressed) @@ -607,8 +586,7 @@ type torusSquare struct { } func (circuit *torusSquare) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt12(ba) + e := NewExt12(api) compressed := e.CompressTorus(&circuit.A) compressed = e.SquareTorus(compressed) expected := e.DecompressTorus(compressed) diff --git a/std/algebra/emulated/fields_bn254/e2.go b/std/algebra/emulated/fields_bn254/e2.go index 4fb3f1f2d7..c337a9a9ce 100644 --- a/std/algebra/emulated/fields_bn254/e2.go +++ b/std/algebra/emulated/fields_bn254/e2.go @@ -16,11 +16,17 @@ type E2 struct { } type Ext2 struct { + api frontend.API fp *curveF nonResidues map[int]map[int]*E2 } -func NewExt2(baseField *curveF) *Ext2 { +func NewExt2(api frontend.API) *Ext2 { + fp, err := emulated.NewField[emulated.BN254Fp](api) + if err != nil { + // TODO: we start returning errors when generifying + panic(err) + } pwrs := map[int]map[int]struct { A0 string A1 string @@ -50,7 +56,7 @@ func NewExt2(baseField *curveF) *Ext2 { nonResidues[pwr][coeff] = &el } } - return &Ext2{fp: baseField, nonResidues: nonResidues} + return &Ext2{api: api, fp: fp, nonResidues: nonResidues} } func (e Ext2) MulByElement(x *E2, y *baseEl) *E2 { diff --git a/std/algebra/emulated/fields_bn254/e2_test.go b/std/algebra/emulated/fields_bn254/e2_test.go index a7721a5b94..de118a6a54 100644 --- a/std/algebra/emulated/fields_bn254/e2_test.go +++ b/std/algebra/emulated/fields_bn254/e2_test.go @@ -16,8 +16,7 @@ type e2Add struct { } func (circuit *e2Add) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt2(ba) + e := NewExt2(api) expected := e.Add(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) return nil @@ -80,8 +79,7 @@ type e2Double struct { } func (circuit *e2Double) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt2(ba) + e := NewExt2(api) expected := e.Double(&circuit.A) e.AssertIsEqual(expected, &circuit.C) return nil @@ -111,9 +109,7 @@ type e2Mul struct { } func (circuit *e2Mul) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt2(ba) - + e := NewExt2(api) expected := e.Mul(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) return nil @@ -144,9 +140,7 @@ type e2Square struct { } func (circuit *e2Square) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt2(ba) - + e := NewExt2(api) expected := e.Square(&circuit.A) e.AssertIsEqual(expected, &circuit.C) return nil @@ -175,9 +169,7 @@ type e2Div struct { } func (circuit *e2Div) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt2(ba) - + e := NewExt2(api) expected := e.DivUnchecked(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) return nil @@ -210,8 +202,7 @@ type e2MulByElement struct { } func (circuit *e2MulByElement) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt2(ba) + e := NewExt2(api) expected := e.MulByElement(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) @@ -245,8 +236,7 @@ type e2MulByNonResidue struct { } func (circuit *e2MulByNonResidue) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt2(ba) + e := NewExt2(api) expected := e.MulByNonResidue(&circuit.A) e.AssertIsEqual(expected, &circuit.C) @@ -277,8 +267,7 @@ type e2Neg struct { } func (circuit *e2Neg) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt2(ba) + e := NewExt2(api) expected := e.Neg(&circuit.A) e.AssertIsEqual(expected, &circuit.C) @@ -308,8 +297,7 @@ type e2Conjugate struct { } func (circuit *e2Conjugate) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt2(ba) + e := NewExt2(api) expected := e.Conjugate(&circuit.A) e.AssertIsEqual(expected, &circuit.C) @@ -339,8 +327,7 @@ type e2Inverse struct { } func (circuit *e2Inverse) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt2(ba) + e := NewExt2(api) expected := e.Inverse(&circuit.A) e.AssertIsEqual(expected, &circuit.C) diff --git a/std/algebra/emulated/fields_bn254/e6.go b/std/algebra/emulated/fields_bn254/e6.go index f26d835327..d794b2db45 100644 --- a/std/algebra/emulated/fields_bn254/e6.go +++ b/std/algebra/emulated/fields_bn254/e6.go @@ -13,8 +13,8 @@ type Ext6 struct { *Ext2 } -func NewExt6(baseField *curveF) *Ext6 { - return &Ext6{Ext2: NewExt2(baseField)} +func NewExt6(api frontend.API) *Ext6 { + return &Ext6{Ext2: NewExt2(api)} } func (e Ext6) One() *E6 { diff --git a/std/algebra/emulated/fields_bn254/e6_test.go b/std/algebra/emulated/fields_bn254/e6_test.go index 05bfc4b121..6c46bb7d46 100644 --- a/std/algebra/emulated/fields_bn254/e6_test.go +++ b/std/algebra/emulated/fields_bn254/e6_test.go @@ -6,7 +6,6 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/test" ) @@ -15,8 +14,7 @@ type e6Add struct { } func (circuit *e6Add) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt6(ba) + e := NewExt6(api) expected := e.Add(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) return nil @@ -47,8 +45,7 @@ type e6Sub struct { } func (circuit *e6Sub) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt6(ba) + e := NewExt6(api) expected := e.Sub(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) return nil @@ -79,9 +76,7 @@ type e6Mul struct { } func (circuit *e6Mul) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt6(ba) - + e := NewExt6(api) expected := e.Mul(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) return nil @@ -112,9 +107,7 @@ type e6Square struct { } func (circuit *e6Square) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt6(ba) - + e := NewExt6(api) expected := e.Square(&circuit.A) e.AssertIsEqual(expected, &circuit.C) return nil @@ -143,9 +136,7 @@ type e6Div struct { } func (circuit *e6Div) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt6(ba) - + e := NewExt6(api) expected := e.DivUnchecked(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) return nil @@ -177,8 +168,7 @@ type e6MulByNonResidue struct { } func (circuit *e6MulByNonResidue) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt6(ba) + e := NewExt6(api) expected := e.MulByNonResidue(&circuit.A) e.AssertIsEqual(expected, &circuit.C) @@ -210,8 +200,7 @@ type e6MulByE2 struct { } func (circuit *e6MulByE2) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt6(ba) + e := NewExt6(api) expected := e.MulByE2(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) @@ -246,8 +235,7 @@ type e6MulBy01 struct { } func (circuit *e6MulBy01) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt6(ba) + e := NewExt6(api) expected := e.MulBy01(&circuit.A, &circuit.C0, &circuit.C1) e.AssertIsEqual(expected, &circuit.C) @@ -285,8 +273,7 @@ type e6MulBy0 struct { } func (circuit *e6MulBy0) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt6(ba) + e := NewExt6(api) expected := e.MulBy0(&circuit.A, &circuit.C0) e.AssertIsEqual(expected, &circuit.C) @@ -321,8 +308,7 @@ type e6Neg struct { } func (circuit *e6Neg) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt6(ba) + e := NewExt6(api) expected := e.Neg(&circuit.A) e.AssertIsEqual(expected, &circuit.C) @@ -352,9 +338,7 @@ type e6Inverse struct { } func (circuit *e6Inverse) Define(api frontend.API) error { - - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt6(ba) + e := NewExt6(api) expected := e.Inverse(&circuit.A) e.AssertIsEqual(expected, &circuit.C) diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go index 1bfd44541a..72eda1b2f5 100644 --- a/std/algebra/emulated/sw_bls12381/pairing.go +++ b/std/algebra/emulated/sw_bls12381/pairing.go @@ -57,7 +57,7 @@ func NewPairing(api frontend.API) (*Pairing, error) { return nil, fmt.Errorf("new base api: %w", err) } return &Pairing{ - Ext12: fields_bls12381.NewExt12(ba), + Ext12: fields_bls12381.NewExt12(api), curveF: ba, }, nil } diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index c7b30411df..8f41581df9 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -57,7 +57,7 @@ func NewPairing(api frontend.API) (*Pairing, error) { return nil, fmt.Errorf("new base api: %w", err) } return &Pairing{ - Ext12: fields_bn254.NewExt12(ba), + Ext12: fields_bn254.NewExt12(api), curveF: ba, }, nil } From 74e12dec7a572a581e798ea6c93e1044ec9392f5 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Fri, 31 Mar 2023 22:00:03 +0200 Subject: [PATCH 221/464] refactor: do not pass api in towers --- std/algebra/emulated/fields_bls12381/e12.go | 8 ++++---- std/algebra/emulated/fields_bls12381/e2.go | 4 ++-- std/algebra/emulated/fields_bls12381/e6.go | 10 +++++----- std/algebra/emulated/fields_bn254/e12.go | 8 ++++---- std/algebra/emulated/fields_bn254/e2.go | 4 ++-- std/algebra/emulated/fields_bn254/e6.go | 10 +++++----- std/algebra/emulated/sw_bls12381/pairing.go | 4 ++-- std/algebra/emulated/sw_bn254/pairing.go | 4 ++-- 8 files changed, 26 insertions(+), 26 deletions(-) diff --git a/std/algebra/emulated/fields_bls12381/e12.go b/std/algebra/emulated/fields_bls12381/e12.go index a2e400fe2e..d452c4f0cb 100644 --- a/std/algebra/emulated/fields_bls12381/e12.go +++ b/std/algebra/emulated/fields_bls12381/e12.go @@ -92,10 +92,10 @@ func (e Ext12) One() *E12 { } } -func (e Ext12) IsZero(api frontend.API, z *E12) frontend.Variable { - c0 := e.Ext6.IsZero(api, &z.C0) - c1 := e.Ext6.IsZero(api, &z.C1) - return api.And(c0, c1) +func (e Ext12) IsZero(z *E12) frontend.Variable { + c0 := e.Ext6.IsZero(&z.C0) + c1 := e.Ext6.IsZero(&z.C1) + return e.api.And(c0, c1) } func (e Ext12) Square(x *E12) *E12 { diff --git a/std/algebra/emulated/fields_bls12381/e2.go b/std/algebra/emulated/fields_bls12381/e2.go index 3fd2bca121..e36178b215 100644 --- a/std/algebra/emulated/fields_bls12381/e2.go +++ b/std/algebra/emulated/fields_bls12381/e2.go @@ -242,10 +242,10 @@ func (e Ext2) Zero() *E2 { A1: *z1, } } -func (e Ext2) IsZero(api frontend.API, z *E2) frontend.Variable { +func (e Ext2) IsZero(z *E2) frontend.Variable { a0 := e.fp.IsZero(&z.A0) a1 := e.fp.IsZero(&z.A1) - return api.And(a0, a1) + return e.api.And(a0, a1) } // returns 1+u diff --git a/std/algebra/emulated/fields_bls12381/e6.go b/std/algebra/emulated/fields_bls12381/e6.go index 4e8ddfd8ec..85e522eeb4 100644 --- a/std/algebra/emulated/fields_bls12381/e6.go +++ b/std/algebra/emulated/fields_bls12381/e6.go @@ -39,11 +39,11 @@ func (e Ext6) Zero() *E6 { } } -func (e Ext6) IsZero(api frontend.API, z *E6) frontend.Variable { - b0 := e.Ext2.IsZero(api, &z.B0) - b1 := e.Ext2.IsZero(api, &z.B1) - b2 := e.Ext2.IsZero(api, &z.B2) - return api.And(api.And(b0, b1), b2) +func (e Ext6) IsZero(z *E6) frontend.Variable { + b0 := e.Ext2.IsZero(&z.B0) + b1 := e.Ext2.IsZero(&z.B1) + b2 := e.Ext2.IsZero(&z.B2) + return e.api.And(e.api.And(b0, b1), b2) } func (e Ext6) Add(x, y *E6) *E6 { diff --git a/std/algebra/emulated/fields_bn254/e12.go b/std/algebra/emulated/fields_bn254/e12.go index 4d3a23fcc3..abe8bd9a9e 100644 --- a/std/algebra/emulated/fields_bn254/e12.go +++ b/std/algebra/emulated/fields_bn254/e12.go @@ -92,10 +92,10 @@ func (e Ext12) One() *E12 { } } -func (e Ext12) IsZero(api frontend.API, z *E12) frontend.Variable { - c0 := e.Ext6.IsZero(api, &z.C0) - c1 := e.Ext6.IsZero(api, &z.C1) - return api.And(c0, c1) +func (e Ext12) IsZero(z *E12) frontend.Variable { + c0 := e.Ext6.IsZero(&z.C0) + c1 := e.Ext6.IsZero(&z.C1) + return e.api.And(c0, c1) } func (e Ext12) Square(x *E12) *E12 { diff --git a/std/algebra/emulated/fields_bn254/e2.go b/std/algebra/emulated/fields_bn254/e2.go index c337a9a9ce..161712f197 100644 --- a/std/algebra/emulated/fields_bn254/e2.go +++ b/std/algebra/emulated/fields_bn254/e2.go @@ -260,10 +260,10 @@ func (e Ext2) Zero() *E2 { } } -func (e Ext2) IsZero(api frontend.API, z *E2) frontend.Variable { +func (e Ext2) IsZero(z *E2) frontend.Variable { a0 := e.fp.IsZero(&z.A0) a1 := e.fp.IsZero(&z.A1) - return api.And(a0, a1) + return e.api.And(a0, a1) } func (e Ext2) Square(x *E2) *E2 { diff --git a/std/algebra/emulated/fields_bn254/e6.go b/std/algebra/emulated/fields_bn254/e6.go index d794b2db45..4330fa49fb 100644 --- a/std/algebra/emulated/fields_bn254/e6.go +++ b/std/algebra/emulated/fields_bn254/e6.go @@ -39,11 +39,11 @@ func (e Ext6) Zero() *E6 { } } -func (e Ext6) IsZero(api frontend.API, z *E6) frontend.Variable { - b0 := e.Ext2.IsZero(api, &z.B0) - b1 := e.Ext2.IsZero(api, &z.B1) - b2 := e.Ext2.IsZero(api, &z.B2) - return api.And(api.And(b0, b1), b2) +func (e Ext6) IsZero(z *E6) frontend.Variable { + b0 := e.Ext2.IsZero(&z.B0) + b1 := e.Ext2.IsZero(&z.B1) + b2 := e.Ext2.IsZero(&z.B2) + return e.api.And(e.api.And(b0, b1), b2) } func (e Ext6) Add(x, y *E6) *E6 { diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go index 72eda1b2f5..c2b35ee26d 100644 --- a/std/algebra/emulated/sw_bls12381/pairing.go +++ b/std/algebra/emulated/sw_bls12381/pairing.go @@ -78,7 +78,7 @@ func (pr Pairing) FinalExponentiation(api frontend.API, e *GTEl) *GTEl { // However, for a product of Miller loops this might happen. If this is // the case, the result is 1 in the torus. We assign a dummy one to e.C1 // and proceed further. - selector1 := pr.Ext6.IsZero(api, &e.C1) + selector1 := pr.Ext6.IsZero(&e.C1) _dummy := pr.Ext6.One() e.C1 = *pr.Ext6.Select(selector1, _dummy, &e.C1) @@ -116,7 +116,7 @@ func (pr Pairing) FinalExponentiation(api frontend.API, e *GTEl) *GTEl { // - Only if seletor1=0 and selector2=0, returns to MulTorus(c, t1) decompressed, // - otherwise, returns to 1. _sum := pr.Ext6.Add(c, t1) - selector2 := pr.Ext6.IsZero(api, _sum) + selector2 := pr.Ext6.IsZero(_sum) t1 = pr.Ext6.Select(selector2, pr.Ext6.One(), t1) result := pr.Lookup2(selector1, selector2, pr.DecompressTorus(pr.MulTorus(c, t1)), pr.One(), pr.One(), pr.One()) diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 8f41581df9..c837edb541 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -85,7 +85,7 @@ func (pr Pairing) FinalExponentiation(api frontend.API, e *GTEl) *GTEl { // However, for a product of Miller loops this might happen. If this is // the case, the result is 1 in the torus. We assign a dummy one to e.C1 // and proceed further. - selector1 := pr.Ext6.IsZero(api, &e.C1) + selector1 := pr.Ext6.IsZero(&e.C1) _dummy := pr.Ext6.One() e.C1 = *pr.Ext6.Select(selector1, _dummy, &e.C1) @@ -130,7 +130,7 @@ func (pr Pairing) FinalExponentiation(api frontend.API, e *GTEl) *GTEl { // - Only if seletor1=0 and selector2=0, returns to MulTorus(t2, t0) decompressed, // - otherwise, returns to 1. _sum := pr.Ext6.Add(t0, t2) - selector2 := pr.Ext6.IsZero(api, _sum) + selector2 := pr.Ext6.IsZero(_sum) t0 = pr.Ext6.Select(selector2, pr.Ext6.One(), t0) result := pr.Lookup2(selector1, selector2, pr.DecompressTorus(pr.MulTorus(t2, t0)), pr.One(), pr.One(), pr.One()) From 710c17c1b7f391af30d4f59259f64d42bd17bc54 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Fri, 31 Mar 2023 22:02:02 +0200 Subject: [PATCH 222/464] refactor: do not pass api in pairing --- std/algebra/emulated/sw_bls12381/doc_test.go | 2 +- std/algebra/emulated/sw_bls12381/pairing.go | 6 +++--- std/algebra/emulated/sw_bls12381/pairing_test.go | 6 +++--- std/algebra/emulated/sw_bn254/doc_test.go | 2 +- std/algebra/emulated/sw_bn254/pairing.go | 6 +++--- std/algebra/emulated/sw_bn254/pairing_test.go | 6 +++--- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/std/algebra/emulated/sw_bls12381/doc_test.go b/std/algebra/emulated/sw_bls12381/doc_test.go index 485ef0482d..ae87b72997 100644 --- a/std/algebra/emulated/sw_bls12381/doc_test.go +++ b/std/algebra/emulated/sw_bls12381/doc_test.go @@ -23,7 +23,7 @@ func (c *PairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res, err := pairing.Pair(api, []*sw_bls12381.G1Affine{&c.InG1}, []*sw_bls12381.G2Affine{&c.InG2}) + res, err := pairing.Pair([]*sw_bls12381.G1Affine{&c.InG1}, []*sw_bls12381.G2Affine{&c.InG2}) if err != nil { return fmt.Errorf("pair: %w", err) } diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go index c2b35ee26d..19ad070983 100644 --- a/std/algebra/emulated/sw_bls12381/pairing.go +++ b/std/algebra/emulated/sw_bls12381/pairing.go @@ -66,7 +66,7 @@ func NewPairing(api frontend.API) (*Pairing, error) { // where d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r // we use instead d=s ⋅ (p⁶-1)(p²+1)(p⁴ - p² +1)/r // where s is the cofactor 3 (Hayashida et al.) -func (pr Pairing) FinalExponentiation(api frontend.API, e *GTEl) *GTEl { +func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { // 1. Easy part // (p⁶-1)(p²+1) @@ -135,12 +135,12 @@ type lineEvaluation struct { // ∏ᵢ e(Pᵢ, Qᵢ). // // This function doesn't check that the inputs are in the correct subgroup. -func (pr Pairing) Pair(api frontend.API, P []*G1Affine, Q []*G2Affine) (*GTEl, error) { +func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { res, err := pr.MillerLoop(P, Q) if err != nil { return nil, fmt.Errorf("miller loop: %w", err) } - res = pr.FinalExponentiation(api, res) + res = pr.FinalExponentiation(res) return res, nil } diff --git a/std/algebra/emulated/sw_bls12381/pairing_test.go b/std/algebra/emulated/sw_bls12381/pairing_test.go index aa2e5c0b35..0be5ff02a6 100644 --- a/std/algebra/emulated/sw_bls12381/pairing_test.go +++ b/std/algebra/emulated/sw_bls12381/pairing_test.go @@ -35,7 +35,7 @@ func (c *FinalExponentiationCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res := pairing.FinalExponentiation(api, &c.InGt) + res := pairing.FinalExponentiation(&c.InGt) pairing.AssertIsEqual(res, &c.Res) return nil } @@ -64,7 +64,7 @@ func (c *PairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res, err := pairing.Pair(api, []*G1Affine{&c.InG1}, []*G2Affine{&c.InG2}) + res, err := pairing.Pair([]*G1Affine{&c.InG1}, []*G2Affine{&c.InG2}) if err != nil { return fmt.Errorf("pair: %w", err) } @@ -99,7 +99,7 @@ func (c *MultiPairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res, err := pairing.Pair(api, []*G1Affine{&c.In1G1, &c.In1G1, &c.In2G1, &c.In2G1}, []*G2Affine{&c.In1G2, &c.In2G2, &c.In1G2, &c.In2G2}) + res, err := pairing.Pair([]*G1Affine{&c.In1G1, &c.In1G1, &c.In2G1, &c.In2G1}, []*G2Affine{&c.In1G2, &c.In2G2, &c.In1G2, &c.In2G2}) if err != nil { return fmt.Errorf("pair: %w", err) } diff --git a/std/algebra/emulated/sw_bn254/doc_test.go b/std/algebra/emulated/sw_bn254/doc_test.go index f3d41bf4f8..db095a0210 100644 --- a/std/algebra/emulated/sw_bn254/doc_test.go +++ b/std/algebra/emulated/sw_bn254/doc_test.go @@ -23,7 +23,7 @@ func (c *PairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res, err := pairing.Pair(api, []*sw_bn254.G1Affine{&c.InG1}, []*sw_bn254.G2Affine{&c.InG2}) + res, err := pairing.Pair([]*sw_bn254.G1Affine{&c.InG1}, []*sw_bn254.G2Affine{&c.InG2}) if err != nil { return fmt.Errorf("pair: %w", err) } diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index c837edb541..2739d59243 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -73,7 +73,7 @@ func NewPairing(api frontend.API) (*Pairing, error) { // and r does NOT divide d' // // FinalExponentiation returns a decompressed element in E12 -func (pr Pairing) FinalExponentiation(api frontend.API, e *GTEl) *GTEl { +func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { // 1. Easy part // (p⁶-1)(p²+1) @@ -141,12 +141,12 @@ func (pr Pairing) FinalExponentiation(api frontend.API, e *GTEl) *GTEl { // ∏ᵢ e(Pᵢ, Qᵢ). // // This function doesn't check that the inputs are in the correct subgroup. -func (pr Pairing) Pair(api frontend.API, P []*G1Affine, Q []*G2Affine) (*GTEl, error) { +func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { res, err := pr.MillerLoop(P, Q) if err != nil { return nil, fmt.Errorf("miller loop: %w", err) } - res = pr.FinalExponentiation(api, res) + res = pr.FinalExponentiation(res) return res, nil } diff --git a/std/algebra/emulated/sw_bn254/pairing_test.go b/std/algebra/emulated/sw_bn254/pairing_test.go index 4b06889410..7009a2a21f 100644 --- a/std/algebra/emulated/sw_bn254/pairing_test.go +++ b/std/algebra/emulated/sw_bn254/pairing_test.go @@ -35,7 +35,7 @@ func (c *FinalExponentiationCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res := pairing.FinalExponentiation(api, &c.InGt) + res := pairing.FinalExponentiation(&c.InGt) pairing.AssertIsEqual(res, &c.Res) return nil } @@ -64,7 +64,7 @@ func (c *PairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res, err := pairing.Pair(api, []*G1Affine{&c.InG1}, []*G2Affine{&c.InG2}) + res, err := pairing.Pair([]*G1Affine{&c.InG1}, []*G2Affine{&c.InG2}) if err != nil { return fmt.Errorf("pair: %w", err) } @@ -99,7 +99,7 @@ func (c *MultiPairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res, err := pairing.Pair(api, []*G1Affine{&c.In1G1, &c.In1G1, &c.In2G1, &c.In2G1}, []*G2Affine{&c.In1G2, &c.In2G2, &c.In1G2, &c.In2G2}) + res, err := pairing.Pair([]*G1Affine{&c.In1G1, &c.In1G1, &c.In2G1, &c.In2G1}, []*G2Affine{&c.In1G2, &c.In2G2, &c.In1G2, &c.In2G2}) if err != nil { return fmt.Errorf("pair: %w", err) } From 998938c3fbe52260e370d46bcb6912fe7de2ce64 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Sat, 1 Apr 2023 01:00:44 +0200 Subject: [PATCH 223/464] fix: one omitted change --- std/algebra/emulated/fields_bn254/e2_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/std/algebra/emulated/fields_bn254/e2_test.go b/std/algebra/emulated/fields_bn254/e2_test.go index de118a6a54..55c2564b02 100644 --- a/std/algebra/emulated/fields_bn254/e2_test.go +++ b/std/algebra/emulated/fields_bn254/e2_test.go @@ -47,8 +47,7 @@ type e2Sub struct { } func (circuit *e2Sub) Define(api frontend.API) error { - ba, _ := emulated.NewField[emulated.BN254Fp](api) - e := NewExt2(ba) + e := NewExt2(api) expected := e.Sub(&circuit.A, &circuit.B) e.AssertIsEqual(expected, &circuit.C) return nil From 12c89e679550790502283154e037de06d7153f6a Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Sat, 1 Apr 2023 01:16:37 +0200 Subject: [PATCH 224/464] feat: store api in pairing structs --- std/algebra/emulated/sw_bls12381/pairing.go | 2 ++ std/algebra/emulated/sw_bn254/pairing.go | 2 ++ 2 files changed, 4 insertions(+) diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go index 19ad070983..a583226671 100644 --- a/std/algebra/emulated/sw_bls12381/pairing.go +++ b/std/algebra/emulated/sw_bls12381/pairing.go @@ -12,6 +12,7 @@ import ( ) type Pairing struct { + api frontend.API *fields_bls12381.Ext12 curveF *emulated.Field[emulated.BLS12381Fp] } @@ -57,6 +58,7 @@ func NewPairing(api frontend.API) (*Pairing, error) { return nil, fmt.Errorf("new base api: %w", err) } return &Pairing{ + api: api, Ext12: fields_bls12381.NewExt12(api), curveF: ba, }, nil diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 2739d59243..cfbe89f2da 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -12,6 +12,7 @@ import ( ) type Pairing struct { + api frontend.API *fields_bn254.Ext12 curveF *emulated.Field[emulated.BN254Fp] } @@ -57,6 +58,7 @@ func NewPairing(api frontend.API) (*Pairing, error) { return nil, fmt.Errorf("new base api: %w", err) } return &Pairing{ + api: api, Ext12: fields_bn254.NewExt12(api), curveF: ba, }, nil From b756271e249bc18adfce4788188b9027278c9351 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Sat, 1 Apr 2023 01:17:48 +0200 Subject: [PATCH 225/464] refactor: reuse dummy one --- std/algebra/emulated/sw_bls12381/pairing.go | 2 +- std/algebra/emulated/sw_bn254/pairing.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go index a583226671..5bdef6f952 100644 --- a/std/algebra/emulated/sw_bls12381/pairing.go +++ b/std/algebra/emulated/sw_bls12381/pairing.go @@ -119,7 +119,7 @@ func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { // - otherwise, returns to 1. _sum := pr.Ext6.Add(c, t1) selector2 := pr.Ext6.IsZero(_sum) - t1 = pr.Ext6.Select(selector2, pr.Ext6.One(), t1) + t1 = pr.Ext6.Select(selector2, _dummy, t1) result := pr.Lookup2(selector1, selector2, pr.DecompressTorus(pr.MulTorus(c, t1)), pr.One(), pr.One(), pr.One()) return result diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index cfbe89f2da..68db260749 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -133,7 +133,7 @@ func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { // - otherwise, returns to 1. _sum := pr.Ext6.Add(t0, t2) selector2 := pr.Ext6.IsZero(_sum) - t0 = pr.Ext6.Select(selector2, pr.Ext6.One(), t0) + t0 = pr.Ext6.Select(selector2, _dummy, t0) result := pr.Lookup2(selector1, selector2, pr.DecompressTorus(pr.MulTorus(t2, t0)), pr.One(), pr.One(), pr.One()) return result From c9bba780fcc1d88d6c4466608adee41e243849d0 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Sat, 1 Apr 2023 01:18:21 +0200 Subject: [PATCH 226/464] refactor: use select instead of lookup2 Lookup2 is slighly more inefficient than select, but because we do select for all E12 elements, then should add up. --- std/algebra/emulated/sw_bls12381/pairing.go | 5 +++-- std/algebra/emulated/sw_bn254/pairing.go | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go index 5bdef6f952..404ac0e2dd 100644 --- a/std/algebra/emulated/sw_bls12381/pairing.go +++ b/std/algebra/emulated/sw_bls12381/pairing.go @@ -114,13 +114,14 @@ func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { // MulTorus(c, t1) requires c ≠ t1. When this is the case it means the // result is 1 in the torus. We assign a dummy one to t0 and proceed furhter. - // Finally we do a Lookup2 on both edge cases: + // Finally we do a select on both edge cases: // - Only if seletor1=0 and selector2=0, returns to MulTorus(c, t1) decompressed, // - otherwise, returns to 1. _sum := pr.Ext6.Add(c, t1) selector2 := pr.Ext6.IsZero(_sum) t1 = pr.Ext6.Select(selector2, _dummy, t1) - result := pr.Lookup2(selector1, selector2, pr.DecompressTorus(pr.MulTorus(c, t1)), pr.One(), pr.One(), pr.One()) + selector := pr.api.Mul(pr.api.Sub(1, selector1), pr.api.Sub(1, selector2)) + result := pr.Select(selector, pr.DecompressTorus(pr.MulTorus(c, t1)), pr.One()) return result } diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 68db260749..a514e50a91 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -128,13 +128,14 @@ func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { // MulTorus(t0, t2) requires t0 ≠ t2. When this is the case it means the // result is 1 in the torus. We assign a dummy one to t0 and proceed furhter. - // Finally we do a Lookup2 on both edge cases: + // Finally we do a select on both edge cases: // - Only if seletor1=0 and selector2=0, returns to MulTorus(t2, t0) decompressed, // - otherwise, returns to 1. _sum := pr.Ext6.Add(t0, t2) selector2 := pr.Ext6.IsZero(_sum) t0 = pr.Ext6.Select(selector2, _dummy, t0) - result := pr.Lookup2(selector1, selector2, pr.DecompressTorus(pr.MulTorus(t2, t0)), pr.One(), pr.One(), pr.One()) + selector := pr.api.Mul(pr.api.Sub(1, selector1), pr.api.Sub(1, selector2)) + result := pr.Select(selector, pr.DecompressTorus(pr.MulTorus(t2, t0)), pr.One()) return result } From 27dce2b9817b5daeee03ba013661ac6739dae511 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Sat, 1 Apr 2023 01:30:07 +0200 Subject: [PATCH 227/464] docs: correct comment --- std/algebra/emulated/sw_bls12381/pairing.go | 2 +- std/algebra/emulated/sw_bn254/pairing.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go index 404ac0e2dd..d24328c28a 100644 --- a/std/algebra/emulated/sw_bls12381/pairing.go +++ b/std/algebra/emulated/sw_bls12381/pairing.go @@ -112,7 +112,7 @@ func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { t1 = pr.MulTorus(t1, t2) t1 = pr.MulTorus(t1, t0) - // MulTorus(c, t1) requires c ≠ t1. When this is the case it means the + // MulTorus(c, t1) requires c ≠ -t1. When this is the case it means the // result is 1 in the torus. We assign a dummy one to t0 and proceed furhter. // Finally we do a select on both edge cases: // - Only if seletor1=0 and selector2=0, returns to MulTorus(c, t1) decompressed, diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index a514e50a91..f43b40c782 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -126,7 +126,7 @@ func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { t2 = pr.MulTorus(t2, t3) t2 = pr.FrobeniusCubeTorus(t2) - // MulTorus(t0, t2) requires t0 ≠ t2. When this is the case it means the + // MulTorus(t0, t2) requires t0 ≠ -t2. When this is the case it means the // result is 1 in the torus. We assign a dummy one to t0 and proceed furhter. // Finally we do a select on both edge cases: // - Only if seletor1=0 and selector2=0, returns to MulTorus(t2, t0) decompressed, From 568329521c843a7af3694cc1a9d33c372818d516 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Sat, 1 Apr 2023 01:49:17 +0200 Subject: [PATCH 228/464] docs: clarify some comments --- std/algebra/emulated/sw_bls12381/pairing.go | 16 +++++++++++----- std/algebra/emulated/sw_bn254/pairing.go | 17 +++++++++++------ 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go index d24328c28a..4ab2e8f69d 100644 --- a/std/algebra/emulated/sw_bls12381/pairing.go +++ b/std/algebra/emulated/sw_bls12381/pairing.go @@ -78,13 +78,18 @@ func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { // So e ∈ G_{q,2}a \ {-1,1} and hence e.C1 ≠ 0. // // However, for a product of Miller loops this might happen. If this is - // the case, the result is 1 in the torus. We assign a dummy one to e.C1 + // the case, the result is 1 in the torus. We assign a dummy value (1) to e.C1 // and proceed further. selector1 := pr.Ext6.IsZero(&e.C1) _dummy := pr.Ext6.One() e.C1 = *pr.Ext6.Select(selector1, _dummy, &e.C1) - // Torus compression absorbed + // Torus compression absorbed: + // Raising e to (p⁶-1) is + // e^(p⁶) / e = (e.C0 - w*e.C1) / (e.C0 + w*e.C1) + // = (-e.C0/e.C1 + w) / (-e.C0/e.C1 - w) + // So the fraction -e.C0/e.C1 is already in the torus. + // This absorbs the torus compression in the easy part. c := pr.Ext6.DivUnchecked(&e.C0, &e.C1) c = pr.Ext6.Neg(c) t0 := pr.FrobeniusSquareTorus(c) @@ -112,9 +117,10 @@ func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { t1 = pr.MulTorus(t1, t2) t1 = pr.MulTorus(t1, t0) - // MulTorus(c, t1) requires c ≠ -t1. When this is the case it means the - // result is 1 in the torus. We assign a dummy one to t0 and proceed furhter. - // Finally we do a select on both edge cases: + // MulTorus(t0, t2) requires t0 ≠ -t2. When this is t0 = -t2, it means the + // product is 1 in the torus. We assign a dummy value (1) to t0 and proceed furhter. + // - Only if seletor1=0 and selector2=0, we return MulTorus(t2, t0) decompressed. + // - Otherwise, we return 1. // - Only if seletor1=0 and selector2=0, returns to MulTorus(c, t1) decompressed, // - otherwise, returns to 1. _sum := pr.Ext6.Add(c, t1) diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index f43b40c782..e8ece685b5 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -85,13 +85,18 @@ func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { // So e ∈ G_{q,2}a \ {-1,1} and hence e.C1 ≠ 0. // // However, for a product of Miller loops this might happen. If this is - // the case, the result is 1 in the torus. We assign a dummy one to e.C1 + // the case, the result is 1 in the torus. We assign a dummy value (1) to e.C1 // and proceed further. selector1 := pr.Ext6.IsZero(&e.C1) _dummy := pr.Ext6.One() e.C1 = *pr.Ext6.Select(selector1, _dummy, &e.C1) - // Torus compression absorbed + // Torus compression absorbed: + // Raising e to (p⁶-1) is + // e^(p⁶) / e = (e.C0 - w*e.C1) / (e.C0 + w*e.C1) + // = (-e.C0/e.C1 + w) / (-e.C0/e.C1 - w) + // So the fraction -e.C0/e.C1 is already in the torus. + // This absorbs the torus compression in the easy part. c := pr.Ext6.DivUnchecked(&e.C0, &e.C1) c = pr.Ext6.Neg(c) t0 := pr.FrobeniusSquareTorus(c) @@ -126,11 +131,11 @@ func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { t2 = pr.MulTorus(t2, t3) t2 = pr.FrobeniusCubeTorus(t2) - // MulTorus(t0, t2) requires t0 ≠ -t2. When this is the case it means the - // result is 1 in the torus. We assign a dummy one to t0 and proceed furhter. + // MulTorus(t0, t2) requires t0 ≠ -t2. When this is t0 = -t2, it means the + // product is 1 in the torus. We assign a dummy value (1) to t0 and proceed furhter. // Finally we do a select on both edge cases: - // - Only if seletor1=0 and selector2=0, returns to MulTorus(t2, t0) decompressed, - // - otherwise, returns to 1. + // - Only if seletor1=0 and selector2=0, we return MulTorus(t2, t0) decompressed. + // - Otherwise, we return 1. _sum := pr.Ext6.Add(t0, t2) selector2 := pr.Ext6.IsZero(_sum) t0 = pr.Ext6.Select(selector2, _dummy, t0) From d4f67b64a28db34fa3b3e7a1ec70ab09891da4d7 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Sat, 1 Apr 2023 02:31:15 +0200 Subject: [PATCH 229/464] perf(pairings): switch to no edge-cases when single pairing --- std/algebra/emulated/sw_bls12381/pairing.go | 72 ++++++++++-------- .../emulated/sw_bls12381/pairing_test.go | 2 +- std/algebra/emulated/sw_bn254/pairing.go | 73 +++++++++++-------- std/algebra/emulated/sw_bn254/pairing_test.go | 2 +- 4 files changed, 89 insertions(+), 60 deletions(-) diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go index 4ab2e8f69d..0fd56059a0 100644 --- a/std/algebra/emulated/sw_bls12381/pairing.go +++ b/std/algebra/emulated/sw_bls12381/pairing.go @@ -68,21 +68,27 @@ func NewPairing(api frontend.API) (*Pairing, error) { // where d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r // we use instead d=s ⋅ (p⁶-1)(p²+1)(p⁴ - p² +1)/r // where s is the cofactor 3 (Hayashida et al.) -func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { +func (pr Pairing) FinalExponentiation(e *GTEl, n int) *GTEl { // 1. Easy part // (p⁶-1)(p²+1) - // - // The Miller loop result is ≠ {-1,1}, otherwise this means P and Q are - // linearly dependant and not from G1 and G2 respectively. - // So e ∈ G_{q,2}a \ {-1,1} and hence e.C1 ≠ 0. - // - // However, for a product of Miller loops this might happen. If this is - // the case, the result is 1 in the torus. We assign a dummy value (1) to e.C1 - // and proceed further. - selector1 := pr.Ext6.IsZero(&e.C1) + var selector1, selector2 frontend.Variable _dummy := pr.Ext6.One() - e.C1 = *pr.Ext6.Select(selector1, _dummy, &e.C1) + + switch n { + case 1: + // The Miller loop result is ≠ {-1,1}, otherwise this means P and Q are + // linearly dependant and not from G1 and G2 respectively. + // So e ∈ G_{q,2}a \ {-1,1} and hence e.C1 ≠ 0. + // Nothing to do. + + default: + // However, for a product of Miller loops (n>=2) this might happen. If this is + // the case, the result is 1 in the torus. We assign a dummy value (1) to e.C1 + // and proceed further. + selector1 = pr.Ext6.IsZero(&e.C1) + e.C1 = *pr.Ext6.Select(selector1, _dummy, &e.C1) + } // Torus compression absorbed: // Raising e to (p⁶-1) is @@ -117,19 +123,27 @@ func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { t1 = pr.MulTorus(t1, t2) t1 = pr.MulTorus(t1, t0) - // MulTorus(t0, t2) requires t0 ≠ -t2. When this is t0 = -t2, it means the - // product is 1 in the torus. We assign a dummy value (1) to t0 and proceed furhter. - // - Only if seletor1=0 and selector2=0, we return MulTorus(t2, t0) decompressed. - // - Otherwise, we return 1. - // - Only if seletor1=0 and selector2=0, returns to MulTorus(c, t1) decompressed, - // - otherwise, returns to 1. - _sum := pr.Ext6.Add(c, t1) - selector2 := pr.Ext6.IsZero(_sum) - t1 = pr.Ext6.Select(selector2, _dummy, t1) - selector := pr.api.Mul(pr.api.Sub(1, selector1), pr.api.Sub(1, selector2)) - result := pr.Select(selector, pr.DecompressTorus(pr.MulTorus(c, t1)), pr.One()) - - return result + var result GTEl + switch n { + // MulTorus(c, t1) requires c ≠ -t1. When c = -t1, it means the + // product is 1 in the torus. + case 1: + // For a single pairing, this does not happen because the pairing is non-degenerate. + result = *pr.DecompressTorus(pr.MulTorus(c, t1)) + default: + // For a product of pairings this might happen when the result is expected to be 1. + // We assign a dummy value (1) to t1 and proceed furhter. + // Finally we do a select on both edge cases: + // - Only if seletor1=0 and selector2=0, we return MulTorus(c, t1) decompressed. + // - Otherwise, we return 1. + _sum := pr.Ext6.Add(c, t1) + selector2 = pr.Ext6.IsZero(_sum) + t1 = pr.Ext6.Select(selector2, _dummy, t1) + selector := pr.api.Mul(pr.api.Sub(1, selector1), pr.api.Sub(1, selector2)) + result = *pr.Select(selector, pr.DecompressTorus(pr.MulTorus(c, t1)), pr.One()) + } + + return &result } // lineEvaluation represents a sparse Fp12 Elmt (result of the line evaluation) @@ -145,11 +159,11 @@ type lineEvaluation struct { // // This function doesn't check that the inputs are in the correct subgroup. func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { - res, err := pr.MillerLoop(P, Q) + res, n, err := pr.MillerLoop(P, Q) if err != nil { return nil, fmt.Errorf("miller loop: %w", err) } - res = pr.FinalExponentiation(res) + res = pr.FinalExponentiation(res, n) return res, nil } @@ -164,11 +178,11 @@ var loopCounter = [64]int8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, // MillerLoop computes the multi-Miller loop // ∏ᵢ { fᵢ_{u,Q}(P) } -func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { +func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, int, error) { // check input size match n := len(P) if n == 0 || n != len(Q) { - return nil, errors.New("invalid inputs sizes") + return nil, n, errors.New("invalid inputs sizes") } res := pr.Ext12.One() @@ -284,7 +298,7 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { // negative x₀ res = pr.Ext12.Conjugate(res) - return res, nil + return res, n, nil } // doubleAndAddStep doubles p1 and adds p2 to the result in affine coordinates, and evaluates the line in Miller loop diff --git a/std/algebra/emulated/sw_bls12381/pairing_test.go b/std/algebra/emulated/sw_bls12381/pairing_test.go index 0be5ff02a6..2be7793e8c 100644 --- a/std/algebra/emulated/sw_bls12381/pairing_test.go +++ b/std/algebra/emulated/sw_bls12381/pairing_test.go @@ -35,7 +35,7 @@ func (c *FinalExponentiationCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res := pairing.FinalExponentiation(&c.InGt) + res := pairing.FinalExponentiation(&c.InGt, 1) pairing.AssertIsEqual(res, &c.Res) return nil } diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index e8ece685b5..681082879c 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -75,21 +75,27 @@ func NewPairing(api frontend.API) (*Pairing, error) { // and r does NOT divide d' // // FinalExponentiation returns a decompressed element in E12 -func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { +func (pr Pairing) FinalExponentiation(e *GTEl, n int) *GTEl { // 1. Easy part // (p⁶-1)(p²+1) - // - // The Miller loop result is ≠ {-1,1}, otherwise this means P and Q are - // linearly dependant and not from G1 and G2 respectively. - // So e ∈ G_{q,2}a \ {-1,1} and hence e.C1 ≠ 0. - // - // However, for a product of Miller loops this might happen. If this is - // the case, the result is 1 in the torus. We assign a dummy value (1) to e.C1 - // and proceed further. - selector1 := pr.Ext6.IsZero(&e.C1) + var selector1, selector2 frontend.Variable _dummy := pr.Ext6.One() - e.C1 = *pr.Ext6.Select(selector1, _dummy, &e.C1) + + switch n { + case 1: + // The Miller loop result is ≠ {-1,1}, otherwise this means P and Q are + // linearly dependant and not from G1 and G2 respectively. + // So e ∈ G_{q,2}a \ {-1,1} and hence e.C1 ≠ 0. + // Nothing to do. + + default: + // However, for a product of Miller loops (n>=2) this might happen. If this is + // the case, the result is 1 in the torus. We assign a dummy value (1) to e.C1 + // and proceed further. + selector1 = pr.Ext6.IsZero(&e.C1) + e.C1 = *pr.Ext6.Select(selector1, _dummy, &e.C1) + } // Torus compression absorbed: // Raising e to (p⁶-1) is @@ -131,18 +137,27 @@ func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { t2 = pr.MulTorus(t2, t3) t2 = pr.FrobeniusCubeTorus(t2) - // MulTorus(t0, t2) requires t0 ≠ -t2. When this is t0 = -t2, it means the - // product is 1 in the torus. We assign a dummy value (1) to t0 and proceed furhter. - // Finally we do a select on both edge cases: - // - Only if seletor1=0 and selector2=0, we return MulTorus(t2, t0) decompressed. - // - Otherwise, we return 1. - _sum := pr.Ext6.Add(t0, t2) - selector2 := pr.Ext6.IsZero(_sum) - t0 = pr.Ext6.Select(selector2, _dummy, t0) - selector := pr.api.Mul(pr.api.Sub(1, selector1), pr.api.Sub(1, selector2)) - result := pr.Select(selector, pr.DecompressTorus(pr.MulTorus(t2, t0)), pr.One()) - - return result + var result GTEl + switch n { + // MulTorus(t0, t2) requires t0 ≠ -t2. When t0 = -t2, it means the + // product is 1 in the torus. + case 1: + // For a single pairing, this does not happen because the pairing is non-degenerate. + result = *pr.DecompressTorus(pr.MulTorus(t2, t0)) + default: + // For a product of pairings this might happen when the result is expected to be 1. + // We assign a dummy value (1) to t0 and proceed furhter. + // Finally we do a select on both edge cases: + // - Only if seletor1=0 and selector2=0, we return MulTorus(t2, t0) decompressed. + // - Otherwise, we return 1. + _sum := pr.Ext6.Add(t0, t2) + selector2 = pr.Ext6.IsZero(_sum) + t0 = pr.Ext6.Select(selector2, _dummy, t0) + selector := pr.api.Mul(pr.api.Sub(1, selector1), pr.api.Sub(1, selector2)) + result = *pr.Select(selector, pr.DecompressTorus(pr.MulTorus(t2, t0)), pr.One()) + } + + return &result } // Pair calculates the reduced pairing for a set of points @@ -150,11 +165,11 @@ func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { // // This function doesn't check that the inputs are in the correct subgroup. func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { - res, err := pr.MillerLoop(P, Q) + res, n, err := pr.MillerLoop(P, Q) if err != nil { return nil, fmt.Errorf("miller loop: %w", err) } - res = pr.FinalExponentiation(res) + res = pr.FinalExponentiation(res, n) return res, nil } @@ -184,11 +199,11 @@ type lineEvaluation struct { // MillerLoop computes the multi-Miller loop // ∏ᵢ { fᵢ_{6x₀+2,Q}(P) · ℓᵢ_{[6x₀+2]Q,π(Q)}(P) · ℓᵢ_{[6x₀+2]Q+π(Q),-π²(Q)}(P) } -func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { +func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, int, error) { // check input size match n := len(P) if n == 0 || n != len(Q) { - return nil, errors.New("invalid inputs sizes") + return nil, n, errors.New("invalid inputs sizes") } res := pr.Ext12.One() @@ -358,7 +373,7 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { } default: - return nil, errors.New("invalid loopCounter") + return nil, n, errors.New("invalid loopCounter") } } @@ -397,7 +412,7 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { } - return res, nil + return res, n, nil } // doubleAndAddStep doubles p1 and adds p2 to the result in affine coordinates, and evaluates the line in Miller loop diff --git a/std/algebra/emulated/sw_bn254/pairing_test.go b/std/algebra/emulated/sw_bn254/pairing_test.go index 7009a2a21f..1f17347727 100644 --- a/std/algebra/emulated/sw_bn254/pairing_test.go +++ b/std/algebra/emulated/sw_bn254/pairing_test.go @@ -35,7 +35,7 @@ func (c *FinalExponentiationCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res := pairing.FinalExponentiation(&c.InGt) + res := pairing.FinalExponentiation(&c.InGt, 1) pairing.AssertIsEqual(res, &c.Res) return nil } From de7b2ec7f9cda3a5bca69db798340c90828eaa95 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Sat, 1 Apr 2023 15:42:50 +0200 Subject: [PATCH 230/464] feat: add PairingCheck function --- std/algebra/emulated/sw_bls12381/pairing.go | 30 ++++++++++++++-- .../emulated/sw_bls12381/pairing_test.go | 35 +++++++++++++++++++ std/algebra/emulated/sw_bn254/pairing.go | 22 ++++++++++-- std/algebra/emulated/sw_bn254/pairing_test.go | 35 +++++++++++++++++++ 4 files changed, 116 insertions(+), 6 deletions(-) diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go index 0fd56059a0..44b345e93a 100644 --- a/std/algebra/emulated/sw_bls12381/pairing.go +++ b/std/algebra/emulated/sw_bls12381/pairing.go @@ -79,7 +79,7 @@ func (pr Pairing) FinalExponentiation(e *GTEl, n int) *GTEl { case 1: // The Miller loop result is ≠ {-1,1}, otherwise this means P and Q are // linearly dependant and not from G1 and G2 respectively. - // So e ∈ G_{q,2}a \ {-1,1} and hence e.C1 ≠ 0. + // So e ∈ G_{q,2} \ {-1,1} and hence e.C1 ≠ 0. // Nothing to do. default: @@ -105,6 +105,7 @@ func (pr Pairing) FinalExponentiation(e *GTEl, n int) *GTEl { // 3(p⁴-p²+1)/r // Daiki Hayashida, Kenichiro Hayasaka and Tadanori Teruya // https://eprint.iacr.org/2020/875.pdf + // performed in torus compressed form t0 = pr.SquareTorus(c) t1 := pr.ExptHalfTorus(t0) t2 := pr.InverseTorus(c) @@ -157,7 +158,7 @@ type lineEvaluation struct { // Pair calculates the reduced pairing for a set of points // ∏ᵢ e(Pᵢ, Qᵢ). // -// This function doesn't check that the inputs are in the correct subgroup. +// This function doesn't check that the inputs are in the correct subgroups. func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { res, n, err := pr.MillerLoop(P, Q) if err != nil { @@ -167,6 +168,22 @@ func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { return res, nil } +// PairingCheck calculates the reduced pairing for a set of points and asserts if the result is One +// ∏ᵢ e(Pᵢ, Qᵢ) =? 1 +// +// This function doesn't check that the inputs are in the correct subgroups. +func (pr Pairing) PairingCheck(P []*G1Affine, Q []*G2Affine) error { + f, err := pr.Pair(P, Q) + if err != nil { + return err + + } + one := pr.One() + pr.AssertIsEqual(f, one) + + return nil +} + func (pr Pairing) AssertIsEqual(x, y *GTEl) { pr.Ext12.AssertIsEqual(x, y) } @@ -174,7 +191,14 @@ func (pr Pairing) AssertIsEqual(x, y *GTEl) { // loopCounter = seed in binary // // seed=-15132376222941642752 -var loopCounter = [64]int8{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, 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, 1, 0, 0, 1, 0, 1, 1} +var loopCounter = [64]int8{ + 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, 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, 1, 0, 0, 1, 0, 1, 1, +} // MillerLoop computes the multi-Miller loop // ∏ᵢ { fᵢ_{u,Q}(P) } diff --git a/std/algebra/emulated/sw_bls12381/pairing_test.go b/std/algebra/emulated/sw_bls12381/pairing_test.go index 2be7793e8c..5523ced8fc 100644 --- a/std/algebra/emulated/sw_bls12381/pairing_test.go +++ b/std/algebra/emulated/sw_bls12381/pairing_test.go @@ -123,3 +123,38 @@ func TestMultiPairTestSolve(t *testing.T) { err = test.IsSolved(&MultiPairCircuit{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } + +type PairingCheckCircuit struct { + In1G1 G1Affine + In2G1 G1Affine + In1G2 G2Affine + In2G2 G2Affine +} + +func (c *PairingCheckCircuit) Define(api frontend.API) error { + pairing, err := NewPairing(api) + if err != nil { + return fmt.Errorf("new pairing: %w", err) + } + err = pairing.PairingCheck([]*G1Affine{&c.In1G1, &c.In1G1, &c.In2G1, &c.In2G1}, []*G2Affine{&c.In1G2, &c.In2G2, &c.In1G2, &c.In2G2}) + if err != nil { + return fmt.Errorf("pair: %w", err) + } + return nil +} + +func TestPairingCheckTestSolve(t *testing.T) { + assert := test.NewAssert(t) + p1, q1 := randomG1G2Affines(assert) + _, q2 := randomG1G2Affines(assert) + var p2 bls12381.G1Affine + p2.Neg(&p1) + witness := PairingCheckCircuit{ + In1G1: NewG1Affine(p1), + In1G2: NewG2Affine(q1), + In2G1: NewG1Affine(p2), + In2G2: NewG2Affine(q2), + } + err := test.IsSolved(&PairingCheckCircuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 681082879c..4bfaa38943 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -86,7 +86,7 @@ func (pr Pairing) FinalExponentiation(e *GTEl, n int) *GTEl { case 1: // The Miller loop result is ≠ {-1,1}, otherwise this means P and Q are // linearly dependant and not from G1 and G2 respectively. - // So e ∈ G_{q,2}a \ {-1,1} and hence e.C1 ≠ 0. + // So e ∈ G_{q,2} \ {-1,1} and hence e.C1 ≠ 0. // Nothing to do. default: @@ -113,7 +113,7 @@ func (pr Pairing) FinalExponentiation(e *GTEl, n int) *GTEl { // Duquesne and Ghammam // https://eprint.iacr.org/2015/192.pdf // Fuentes et al. (alg. 6) - // performed in Torus compressed form + // performed in torus compressed form t0 = pr.ExptTorus(c) t0 = pr.InverseTorus(t0) t0 = pr.SquareTorus(t0) @@ -163,7 +163,7 @@ func (pr Pairing) FinalExponentiation(e *GTEl, n int) *GTEl { // Pair calculates the reduced pairing for a set of points // ∏ᵢ e(Pᵢ, Qᵢ). // -// This function doesn't check that the inputs are in the correct subgroup. +// This function doesn't check that the inputs are in the correct subgroups. func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { res, n, err := pr.MillerLoop(P, Q) if err != nil { @@ -173,6 +173,22 @@ func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { return res, nil } +// PairingCheck calculates the reduced pairing for a set of points and asserts if the result is One +// ∏ᵢ e(Pᵢ, Qᵢ) =? 1 +// +// This function doesn't check that the inputs are in the correct subgroups. +func (pr Pairing) PairingCheck(P []*G1Affine, Q []*G2Affine) error { + f, err := pr.Pair(P, Q) + if err != nil { + return err + + } + one := pr.One() + pr.AssertIsEqual(f, one) + + return nil +} + func (pr Pairing) AssertIsEqual(x, y *GTEl) { pr.Ext12.AssertIsEqual(x, y) } diff --git a/std/algebra/emulated/sw_bn254/pairing_test.go b/std/algebra/emulated/sw_bn254/pairing_test.go index 1f17347727..9a00b1db08 100644 --- a/std/algebra/emulated/sw_bn254/pairing_test.go +++ b/std/algebra/emulated/sw_bn254/pairing_test.go @@ -123,3 +123,38 @@ func TestMultiPairTestSolve(t *testing.T) { err = test.IsSolved(&MultiPairCircuit{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } + +type PairingCheckCircuit struct { + In1G1 G1Affine + In2G1 G1Affine + In1G2 G2Affine + In2G2 G2Affine +} + +func (c *PairingCheckCircuit) Define(api frontend.API) error { + pairing, err := NewPairing(api) + if err != nil { + return fmt.Errorf("new pairing: %w", err) + } + err = pairing.PairingCheck([]*G1Affine{&c.In1G1, &c.In1G1, &c.In2G1, &c.In2G1}, []*G2Affine{&c.In1G2, &c.In2G2, &c.In1G2, &c.In2G2}) + if err != nil { + return fmt.Errorf("pair: %w", err) + } + return nil +} + +func TestPairingCheckTestSolve(t *testing.T) { + assert := test.NewAssert(t) + p1, q1 := randomG1G2Affines(assert) + _, q2 := randomG1G2Affines(assert) + var p2 bn254.G1Affine + p2.Neg(&p1) + witness := PairingCheckCircuit{ + In1G1: NewG1Affine(p1), + In1G2: NewG2Affine(q1), + In2G1: NewG1Affine(p2), + In2G2: NewG2Affine(q2), + } + err := test.IsSolved(&PairingCheckCircuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} From dd6918f2a4435c68279af4d0e5673bc09565032b Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 4 Apr 2023 11:03:09 +0200 Subject: [PATCH 231/464] refactor: separate final exp into safe and unsafe --- std/algebra/emulated/sw_bls12381/pairing.go | 73 ++++++++++++++----- .../emulated/sw_bls12381/pairing_test.go | 2 +- std/algebra/emulated/sw_bn254/pairing.go | 67 +++++++++++++---- std/algebra/emulated/sw_bn254/pairing_test.go | 2 +- 4 files changed, 111 insertions(+), 33 deletions(-) diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go index 44b345e93a..788f6203b1 100644 --- a/std/algebra/emulated/sw_bls12381/pairing.go +++ b/std/algebra/emulated/sw_bls12381/pairing.go @@ -64,25 +64,65 @@ func NewPairing(api frontend.API) (*Pairing, error) { }, nil } -// FinalExponentiation computes the exponentiation (∏ᵢ zᵢ)ᵈ -// where d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r -// we use instead d=s ⋅ (p⁶-1)(p²+1)(p⁴ - p² +1)/r -// where s is the cofactor 3 (Hayashida et al.) -func (pr Pairing) FinalExponentiation(e *GTEl, n int) *GTEl { +// FinalExponentiation computes the exponentiation (∏ᵢ zᵢ)ᵈ where +// +// d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r +// +// we use instead +// +// d=s ⋅ (p⁶-1)(p²+1)(p⁴ - p² +1)/r +// +// where s is the cofactor 3 (Hayashida et al.). +// +// This is the safe version of the method where e may be {-1,1}. If it is known +// that e ≠ {-1,1} then using the unsafe version of the method saves +// considerable amount of constraints. When called with the result of +// [MillerLoop], then current method is applicable when length of the inputs to +// Miller loop is 1. +func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { + return pr.finalExponentiation(e, false) +} + +// FinalExponentiationUnsafe computes the exponentiation (∏ᵢ zᵢ)ᵈ where +// +// d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r +// +// we use instead +// +// d=s ⋅ (p⁶-1)(p²+1)(p⁴ - p² +1)/r +// +// where s is the cofactor 3 (Hayashida et al.). +// +// This is the unsafe version of the method where e may NOT be {-1,1}. If e ∈ +// {-1, 1}, then there exists no valid solution to the circuit. This method is +// applicable when called with the result of [MillerLoop] method when the length +// of the inputs to Miller loop is 1. +func (pr Pairing) FinalExponentiationUnsafe(e *GTEl) *GTEl { + return pr.finalExponentiation(e, true) +} + +// finalExponentiation computes the exponentiation (∏ᵢ zᵢ)ᵈ where +// +// d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r +// +// we use instead +// +// d=s ⋅ (p⁶-1)(p²+1)(p⁴ - p² +1)/r +// +// where s is the cofactor 3 (Hayashida et al.). +func (pr Pairing) finalExponentiation(e *GTEl, unsafe bool) *GTEl { // 1. Easy part // (p⁶-1)(p²+1) var selector1, selector2 frontend.Variable _dummy := pr.Ext6.One() - switch n { - case 1: + if unsafe { // The Miller loop result is ≠ {-1,1}, otherwise this means P and Q are // linearly dependant and not from G1 and G2 respectively. // So e ∈ G_{q,2} \ {-1,1} and hence e.C1 ≠ 0. // Nothing to do. - - default: + } else { // However, for a product of Miller loops (n>=2) this might happen. If this is // the case, the result is 1 in the torus. We assign a dummy value (1) to e.C1 // and proceed further. @@ -125,13 +165,12 @@ func (pr Pairing) FinalExponentiation(e *GTEl, n int) *GTEl { t1 = pr.MulTorus(t1, t0) var result GTEl - switch n { // MulTorus(c, t1) requires c ≠ -t1. When c = -t1, it means the // product is 1 in the torus. - case 1: + if unsafe { // For a single pairing, this does not happen because the pairing is non-degenerate. result = *pr.DecompressTorus(pr.MulTorus(c, t1)) - default: + } else { // For a product of pairings this might happen when the result is expected to be 1. // We assign a dummy value (1) to t1 and proceed furhter. // Finally we do a select on both edge cases: @@ -160,11 +199,11 @@ type lineEvaluation struct { // // This function doesn't check that the inputs are in the correct subgroups. func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { - res, n, err := pr.MillerLoop(P, Q) + res, err := pr.MillerLoop(P, Q) if err != nil { return nil, fmt.Errorf("miller loop: %w", err) } - res = pr.FinalExponentiation(res, n) + res = pr.finalExponentiation(res, len(P) == 1) return res, nil } @@ -202,11 +241,11 @@ var loopCounter = [64]int8{ // MillerLoop computes the multi-Miller loop // ∏ᵢ { fᵢ_{u,Q}(P) } -func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, int, error) { +func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { // check input size match n := len(P) if n == 0 || n != len(Q) { - return nil, n, errors.New("invalid inputs sizes") + return nil, errors.New("invalid inputs sizes") } res := pr.Ext12.One() @@ -322,7 +361,7 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, int, error) { // negative x₀ res = pr.Ext12.Conjugate(res) - return res, n, nil + return res, nil } // doubleAndAddStep doubles p1 and adds p2 to the result in affine coordinates, and evaluates the line in Miller loop diff --git a/std/algebra/emulated/sw_bls12381/pairing_test.go b/std/algebra/emulated/sw_bls12381/pairing_test.go index 5523ced8fc..f9b16663a0 100644 --- a/std/algebra/emulated/sw_bls12381/pairing_test.go +++ b/std/algebra/emulated/sw_bls12381/pairing_test.go @@ -35,7 +35,7 @@ func (c *FinalExponentiationCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res := pairing.FinalExponentiation(&c.InGt, 1) + res := pairing.FinalExponentiation(&c.InGt) pairing.AssertIsEqual(res, &c.Res) return nil } diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 4bfaa38943..88245f1714 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -74,22 +74,62 @@ func NewPairing(api frontend.API) (*Pairing, error) { // // and r does NOT divide d' // -// FinalExponentiation returns a decompressed element in E12 -func (pr Pairing) FinalExponentiation(e *GTEl, n int) *GTEl { +// FinalExponentiation returns a decompressed element in E12. +// +// This is the safe version of the method where e may be {-1,1}. If it is known +// that e ≠ {-1,1} then using the unsafe version of the method saves +// considerable amount of constraints. When called with the result of +// [MillerLoop], then current method is applicable when length of the inputs to +// Miller loop is 1. +func (pr Pairing) FinalExponentiation(e *GTEl) *GTEl { + return pr.finalExponentiation(e, false) +} + +// FinalExponentiationUnsafe computes the exponentiation eᵈ where +// +// d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r. +// +// We use instead d'= s ⋅ d, where s is the cofactor +// +// 2x₀(6x₀²+3x₀+1) +// +// and r does NOT divide d' +// +// FinalExponentiationUnsafe returns a decompressed element in E12. +// +// This is the unsafe version of the method where e may NOT be {-1,1}. If e ∈ +// {-1, 1}, then there exists no valid solution to the circuit. This method is +// applicable when called with the result of [MillerLoop] method when the length +// of the inputs to Miller loop is 1. +func (pr Pairing) FinalExponentiationUnsafe(e *GTEl) *GTEl { + return pr.finalExponentiation(e, true) +} + +// finalExponentiation computes the exponentiation eᵈ where +// +// d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r. +// +// We use instead d'= s ⋅ d, where s is the cofactor +// +// 2x₀(6x₀²+3x₀+1) +// +// and r does NOT divide d' +// +// finalExponentiation returns a decompressed element in E12 +func (pr Pairing) finalExponentiation(e *GTEl, unsafe bool) *GTEl { // 1. Easy part // (p⁶-1)(p²+1) var selector1, selector2 frontend.Variable _dummy := pr.Ext6.One() - switch n { - case 1: + if unsafe { // The Miller loop result is ≠ {-1,1}, otherwise this means P and Q are // linearly dependant and not from G1 and G2 respectively. // So e ∈ G_{q,2} \ {-1,1} and hence e.C1 ≠ 0. // Nothing to do. - default: + } else { // However, for a product of Miller loops (n>=2) this might happen. If this is // the case, the result is 1 in the torus. We assign a dummy value (1) to e.C1 // and proceed further. @@ -138,13 +178,12 @@ func (pr Pairing) FinalExponentiation(e *GTEl, n int) *GTEl { t2 = pr.FrobeniusCubeTorus(t2) var result GTEl - switch n { // MulTorus(t0, t2) requires t0 ≠ -t2. When t0 = -t2, it means the // product is 1 in the torus. - case 1: + if unsafe { // For a single pairing, this does not happen because the pairing is non-degenerate. result = *pr.DecompressTorus(pr.MulTorus(t2, t0)) - default: + } else { // For a product of pairings this might happen when the result is expected to be 1. // We assign a dummy value (1) to t0 and proceed furhter. // Finally we do a select on both edge cases: @@ -165,11 +204,11 @@ func (pr Pairing) FinalExponentiation(e *GTEl, n int) *GTEl { // // This function doesn't check that the inputs are in the correct subgroups. func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { - res, n, err := pr.MillerLoop(P, Q) + res, err := pr.MillerLoop(P, Q) if err != nil { return nil, fmt.Errorf("miller loop: %w", err) } - res = pr.FinalExponentiation(res, n) + res = pr.finalExponentiation(res, len(P) == 1) return res, nil } @@ -215,11 +254,11 @@ type lineEvaluation struct { // MillerLoop computes the multi-Miller loop // ∏ᵢ { fᵢ_{6x₀+2,Q}(P) · ℓᵢ_{[6x₀+2]Q,π(Q)}(P) · ℓᵢ_{[6x₀+2]Q+π(Q),-π²(Q)}(P) } -func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, int, error) { +func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { // check input size match n := len(P) if n == 0 || n != len(Q) { - return nil, n, errors.New("invalid inputs sizes") + return nil, errors.New("invalid inputs sizes") } res := pr.Ext12.One() @@ -389,7 +428,7 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, int, error) { } default: - return nil, n, errors.New("invalid loopCounter") + return nil, errors.New("invalid loopCounter") } } @@ -428,7 +467,7 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, int, error) { } - return res, n, nil + return res, nil } // doubleAndAddStep doubles p1 and adds p2 to the result in affine coordinates, and evaluates the line in Miller loop diff --git a/std/algebra/emulated/sw_bn254/pairing_test.go b/std/algebra/emulated/sw_bn254/pairing_test.go index 9a00b1db08..3d24335e5d 100644 --- a/std/algebra/emulated/sw_bn254/pairing_test.go +++ b/std/algebra/emulated/sw_bn254/pairing_test.go @@ -35,7 +35,7 @@ func (c *FinalExponentiationCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res := pairing.FinalExponentiation(&c.InGt, 1) + res := pairing.FinalExponentiation(&c.InGt) pairing.AssertIsEqual(res, &c.Res) return nil } From 7f37089f0bb4794795d69797fa90f4dfcb4f4fbf Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 4 Apr 2023 11:05:29 +0200 Subject: [PATCH 232/464] test: test also unsafe final exp --- std/algebra/emulated/sw_bls12381/pairing_test.go | 6 ++++-- std/algebra/emulated/sw_bn254/pairing_test.go | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/std/algebra/emulated/sw_bls12381/pairing_test.go b/std/algebra/emulated/sw_bls12381/pairing_test.go index f9b16663a0..4f2080644f 100644 --- a/std/algebra/emulated/sw_bls12381/pairing_test.go +++ b/std/algebra/emulated/sw_bls12381/pairing_test.go @@ -35,8 +35,10 @@ func (c *FinalExponentiationCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res := pairing.FinalExponentiation(&c.InGt) - pairing.AssertIsEqual(res, &c.Res) + res1 := pairing.FinalExponentiation(&c.InGt) + pairing.AssertIsEqual(res1, &c.Res) + res2 := pairing.FinalExponentiationUnsafe(&c.InGt) + pairing.AssertIsEqual(res2, &c.Res) return nil } diff --git a/std/algebra/emulated/sw_bn254/pairing_test.go b/std/algebra/emulated/sw_bn254/pairing_test.go index 3d24335e5d..0fc757fcd4 100644 --- a/std/algebra/emulated/sw_bn254/pairing_test.go +++ b/std/algebra/emulated/sw_bn254/pairing_test.go @@ -35,8 +35,10 @@ func (c *FinalExponentiationCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } - res := pairing.FinalExponentiation(&c.InGt) - pairing.AssertIsEqual(res, &c.Res) + res1 := pairing.FinalExponentiation(&c.InGt) + pairing.AssertIsEqual(res1, &c.Res) + res2 := pairing.FinalExponentiationUnsafe(&c.InGt) + pairing.AssertIsEqual(res2, &c.Res) return nil } From 5b819fe7efcf198b542409e5262e4e24fe61accd Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 4 Apr 2023 11:16:36 +0200 Subject: [PATCH 233/464] test: add safe final exp tests --- .../emulated/sw_bls12381/pairing_test.go | 36 +++++++++++++++++++ std/algebra/emulated/sw_bn254/pairing_test.go | 36 +++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/std/algebra/emulated/sw_bls12381/pairing_test.go b/std/algebra/emulated/sw_bls12381/pairing_test.go index 4f2080644f..ec1bf2baec 100644 --- a/std/algebra/emulated/sw_bls12381/pairing_test.go +++ b/std/algebra/emulated/sw_bls12381/pairing_test.go @@ -160,3 +160,39 @@ func TestPairingCheckTestSolve(t *testing.T) { err := test.IsSolved(&PairingCheckCircuit{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } + +type FinalExponentiationSafeCircuit struct { + P1, P2 G1Affine + Q1, Q2 G2Affine +} + +func (c *FinalExponentiationSafeCircuit) Define(api frontend.API) error { + pairing, err := NewPairing(api) + if err != nil { + return err + } + res, err := pairing.MillerLoop([]*G1Affine{&c.P1, &c.P2}, []*G2Affine{&c.Q1, &c.Q2}) + if err != nil { + return err + } + res2 := pairing.FinalExponentiation(res) + one := pairing.Ext12.One() + pairing.AssertIsEqual(one, res2) + return nil +} + +func TestFinalExponentiationSafeCircuit(t *testing.T) { + assert := test.NewAssert(t) + _, _, p1, q1 := bls12381.Generators() + var p2 bls12381.G1Affine + var q2 bls12381.G2Affine + p2.Neg(&p1) + q2.Set(&q1) + err := test.IsSolved(&FinalExponentiationSafeCircuit{}, &FinalExponentiationSafeCircuit{ + P1: NewG1Affine(p1), + P2: NewG1Affine(p2), + Q1: NewG2Affine(q1), + Q2: NewG2Affine(q2), + }, ecc.BN254.ScalarField()) + assert.NoError(err) +} diff --git a/std/algebra/emulated/sw_bn254/pairing_test.go b/std/algebra/emulated/sw_bn254/pairing_test.go index 0fc757fcd4..1d76ca0d45 100644 --- a/std/algebra/emulated/sw_bn254/pairing_test.go +++ b/std/algebra/emulated/sw_bn254/pairing_test.go @@ -160,3 +160,39 @@ func TestPairingCheckTestSolve(t *testing.T) { err := test.IsSolved(&PairingCheckCircuit{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } + +type FinalExponentiationSafeCircuit struct { + P1, P2 G1Affine + Q1, Q2 G2Affine +} + +func (c *FinalExponentiationSafeCircuit) Define(api frontend.API) error { + pairing, err := NewPairing(api) + if err != nil { + return err + } + res, err := pairing.MillerLoop([]*G1Affine{&c.P1, &c.P2}, []*G2Affine{&c.Q1, &c.Q2}) + if err != nil { + return err + } + res2 := pairing.FinalExponentiation(res) + one := pairing.Ext12.One() + pairing.AssertIsEqual(one, res2) + return nil +} + +func TestFinalExponentiationSafeCircuit(t *testing.T) { + assert := test.NewAssert(t) + _, _, p1, q1 := bn254.Generators() + var p2 bn254.G1Affine + var q2 bn254.G2Affine + p2.Neg(&p1) + q2.Set(&q1) + err := test.IsSolved(&FinalExponentiationSafeCircuit{}, &FinalExponentiationSafeCircuit{ + P1: NewG1Affine(p1), + P2: NewG1Affine(p2), + Q1: NewG2Affine(q1), + Q2: NewG2Affine(q2), + }, ecc.BN254.ScalarField()) + assert.NoError(err) +} From 5c6f12dd90f745aea89fc188c40851cab22de0d9 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 6 Apr 2023 12:12:33 +0200 Subject: [PATCH 234/464] feat: add EVM precompiles (#488) * feat: add ECRec, ECAdd, ECMul, ECPair EVM precompiles * fix: inut check that input slice elements are canonical in NewElement We perform the check in the following packLimbs anyway. And the check there is more precise. We only need to figure out if we have variables or constants. * test: skip full tests * docs: fix typo * fix: ECPair performs pairing check * fix: ECPair takes multiple input pairs * test: generate passing ecpair test * test: use random points in ECPair test --------- Co-authored-by: Youssef El Housni --- std/evmprecompiles/01-ecrecover.go | 79 +++++++++++ std/evmprecompiles/01-ecrecover_test.go | 100 ++++++++++++++ std/evmprecompiles/02-sha256.go | 3 + std/evmprecompiles/04-id.go | 3 + std/evmprecompiles/05-expmod.go | 1 + std/evmprecompiles/06-bnadd.go | 19 +++ std/evmprecompiles/07-bnmul.go | 19 +++ std/evmprecompiles/08-bnpairing.go | 19 +++ std/evmprecompiles/bn_test.go | 168 ++++++++++++++++++++++++ std/evmprecompiles/compose.go | 37 ++++++ std/evmprecompiles/doc.go | 18 +++ std/evmprecompiles/hints.go | 97 ++++++++++++++ std/hints.go | 2 + std/math/emulated/field.go | 5 - 14 files changed, 565 insertions(+), 5 deletions(-) create mode 100644 std/evmprecompiles/01-ecrecover.go create mode 100644 std/evmprecompiles/01-ecrecover_test.go create mode 100644 std/evmprecompiles/02-sha256.go create mode 100644 std/evmprecompiles/04-id.go create mode 100644 std/evmprecompiles/05-expmod.go create mode 100644 std/evmprecompiles/06-bnadd.go create mode 100644 std/evmprecompiles/07-bnmul.go create mode 100644 std/evmprecompiles/08-bnpairing.go create mode 100644 std/evmprecompiles/bn_test.go create mode 100644 std/evmprecompiles/compose.go create mode 100644 std/evmprecompiles/doc.go create mode 100644 std/evmprecompiles/hints.go diff --git a/std/evmprecompiles/01-ecrecover.go b/std/evmprecompiles/01-ecrecover.go new file mode 100644 index 0000000000..28fa0667a2 --- /dev/null +++ b/std/evmprecompiles/01-ecrecover.go @@ -0,0 +1,79 @@ +package evmprecompiles + +import ( + "fmt" + + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/algebra/emulated/sw_emulated" + "github.com/consensys/gnark/std/math/bits" + "github.com/consensys/gnark/std/math/emulated" +) + +// ECRecover implements [ECRECOVER] precompile contract at address 0x01. +// +// [ECRECOVER]: https://ethereum.github.io/execution-specs/autoapi/ethereum/paris/vm/precompiled_contracts/ecrecover/index.html +func ECRecover(api frontend.API, msg emulated.Element[emulated.Secp256k1Fr], + v frontend.Variable, r, s emulated.Element[emulated.Secp256k1Fr]) *sw_emulated.AffinePoint[emulated.Secp256k1Fp] { + // EVM uses v \in {27, 28}, but everyone else v >= 0. Convert back + v = api.Sub(v, 27) + var emfp emulated.Secp256k1Fp + var emfr emulated.Secp256k1Fr + fpField, err := emulated.NewField[emulated.Secp256k1Fp](api) + if err != nil { + panic(fmt.Sprintf("new field: %v", err)) + } + frField, err := emulated.NewField[emulated.Secp256k1Fr](api) + if err != nil { + panic(fmt.Sprintf("new field: %v", err)) + } + // with the encoding we may have that r,s < 2*Fr (i.e. not r,s < Fr). Apply more thorough checks. + frField.AssertIsLessOrEqual(&r, frField.Modulus()) + frField.AssertIsLessOrEqual(&s, frField.Modulus()) + curve, err := sw_emulated.New[emulated.Secp256k1Fp, emulated.Secp256k1Fr](api, sw_emulated.GetSecp256k1Params()) + if err != nil { + panic(fmt.Sprintf("new curve: %v", err)) + } + // we cannot directly use the field emulation hint calling wrappers as we work between two fields. + Rlimbs, err := api.Compiler().NewHint(recoverPointHint, 2*int(emfp.NbLimbs()), recoverPointHintArgs(v, r)...) + if err != nil { + panic(fmt.Sprintf("point hint: %v", err)) + } + R := sw_emulated.AffinePoint[emulated.Secp256k1Fp]{ + X: *fpField.NewElement(Rlimbs[0:emfp.NbLimbs()]), + Y: *fpField.NewElement(Rlimbs[emfp.NbLimbs() : 2*emfp.NbLimbs()]), + } + // we cannot directly use the field emulation hint calling wrappers as we work between two fields. + Plimbs, err := api.Compiler().NewHint(recoverPublicKeyHint, 2*int(emfp.NbLimbs()), recoverPublicKeyHintArgs(msg, v, r, s)...) + if err != nil { + panic(fmt.Sprintf("point hint: %v", err)) + } + P := sw_emulated.AffinePoint[emulated.Secp256k1Fp]{ + X: *fpField.NewElement(Plimbs[0:emfp.NbLimbs()]), + Y: *fpField.NewElement(Plimbs[emfp.NbLimbs() : 2*emfp.NbLimbs()]), + } + // check that len(v) = 2 + vbits := bits.ToBinary(api, v, bits.WithNbDigits(2)) + // check that Rx is correct: x = r+v[1]*fr + tmp := fpField.Select(vbits[1], fpField.NewElement(emfr.Modulus()), fpField.NewElement(0)) + rbits := frField.ToBits(&r) + rfp := fpField.FromBits(rbits...) + tmp = fpField.Add(rfp, tmp) + fpField.AssertIsEqual(tmp, &R.X) + // check that Ry is correct: highbit(y) = v[0] + Rynormal := fpField.Reduce(&R.Y) + Rybits := fpField.ToBits(Rynormal) + api.AssertIsEqual(vbits[0], Rybits[emfp.Modulus().BitLen()-1]) + // compute rinv = r^{-1} mod fr + rinv := frField.Inverse(&r) + // compute u1 = -msg * rinv + u1 := frField.MulMod(&msg, rinv) + u1 = frField.Neg(u1) + // compute u2 = s * rinv + u2 := frField.MulMod(&s, rinv) + // check u1 * G + u2 R == P + A := curve.ScalarMulBase(u1) + B := curve.ScalarMul(&R, u2) + C := curve.Add(A, B) + curve.AssertIsEqual(C, &P) + return &P +} diff --git a/std/evmprecompiles/01-ecrecover_test.go b/std/evmprecompiles/01-ecrecover_test.go new file mode 100644 index 0000000000..b9193dd372 --- /dev/null +++ b/std/evmprecompiles/01-ecrecover_test.go @@ -0,0 +1,100 @@ +package evmprecompiles + +import ( + "crypto/rand" + "fmt" + "testing" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/secp256k1/ecdsa" + "github.com/consensys/gnark-crypto/ecc/secp256k1/fr" + "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/algebra/emulated/sw_emulated" + "github.com/consensys/gnark/std/math/emulated" + "github.com/consensys/gnark/test" +) + +func TestSignForRecoverCorrectness(t *testing.T) { + sk, err := ecdsa.GenerateKey(rand.Reader) + if err != nil { + t.Fatal("generate", err) + } + pk := sk.PublicKey + msg := []byte("test") + _, r, s, err := sk.SignForRecover(msg, nil) + if err != nil { + t.Fatal("sign", err) + } + var sig ecdsa.Signature + r.FillBytes(sig.R[:fr.Bytes]) + s.FillBytes(sig.S[:fr.Bytes]) + sigM := sig.Bytes() + ok, err := pk.Verify(sigM, msg, nil) + if err != nil { + t.Fatal("verify", err) + } + if !ok { + t.Fatal("not verified") + } +} + +type ecrecoverCircuit struct { + Message emulated.Element[emulated.Secp256k1Fr] + V frontend.Variable + R emulated.Element[emulated.Secp256k1Fr] + S emulated.Element[emulated.Secp256k1Fr] + Expected sw_emulated.AffinePoint[emulated.Secp256k1Fp] +} + +func (c *ecrecoverCircuit) Define(api frontend.API) error { + curve, err := sw_emulated.New[emulated.Secp256k1Fp, emulated.Secp256k1Fr](api, sw_emulated.GetSecp256k1Params()) + if err != nil { + return fmt.Errorf("new curve: %w", err) + } + res := ECRecover(api, c.Message, c.V, c.R, c.S) + curve.AssertIsEqual(&c.Expected, res) + return nil +} + +func testRoutineECRecover(t *testing.T) (circ, wit frontend.Circuit) { + sk, err := ecdsa.GenerateKey(rand.Reader) + if err != nil { + t.Fatal("generate", err) + } + pk := sk.PublicKey + msg := []byte("test") + v, r, s, err := sk.SignForRecover(msg, nil) + if err != nil { + t.Fatal("sign", err) + } + circuit := ecrecoverCircuit{} + witness := ecrecoverCircuit{ + Message: emulated.ValueOf[emulated.Secp256k1Fr](ecdsa.HashToInt(msg)), + V: v + 27, // EVM constant + R: emulated.ValueOf[emulated.Secp256k1Fr](r), + S: emulated.ValueOf[emulated.Secp256k1Fr](s), + Expected: sw_emulated.AffinePoint[emulated.Secp256k1Fp]{ + X: emulated.ValueOf[emulated.Secp256k1Fp](pk.A.X), + Y: emulated.ValueOf[emulated.Secp256k1Fp](pk.A.Y), + }, + } + return &circuit, &witness +} + +func TestECRecoverCircuitShort(t *testing.T) { + assert := test.NewAssert(t) + circuit, witness := testRoutineECRecover(t) + err := test.IsSolved(circuit, witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +func TestECRecoverCircuitFull(t *testing.T) { + t.Skip("skipping very long test") + assert := test.NewAssert(t) + circuit, witness := testRoutineECRecover(t) + assert.ProverSucceeded(circuit, witness, + test.NoFuzzing(), test.NoSerialization(), + test.WithBackends(backend.GROTH16, backend.PLONK), test.WithCurves(ecc.BN254), + ) +} diff --git a/std/evmprecompiles/02-sha256.go b/std/evmprecompiles/02-sha256.go new file mode 100644 index 0000000000..ae0c33e733 --- /dev/null +++ b/std/evmprecompiles/02-sha256.go @@ -0,0 +1,3 @@ +package evmprecompiles + +// will implement later diff --git a/std/evmprecompiles/04-id.go b/std/evmprecompiles/04-id.go new file mode 100644 index 0000000000..d554d428c8 --- /dev/null +++ b/std/evmprecompiles/04-id.go @@ -0,0 +1,3 @@ +package evmprecompiles + +// not going to implement. It is trivial. diff --git a/std/evmprecompiles/05-expmod.go b/std/evmprecompiles/05-expmod.go new file mode 100644 index 0000000000..6b1eb16123 --- /dev/null +++ b/std/evmprecompiles/05-expmod.go @@ -0,0 +1 @@ +package evmprecompiles diff --git a/std/evmprecompiles/06-bnadd.go b/std/evmprecompiles/06-bnadd.go new file mode 100644 index 0000000000..d9eb8b32dd --- /dev/null +++ b/std/evmprecompiles/06-bnadd.go @@ -0,0 +1,19 @@ +package evmprecompiles + +import ( + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/algebra/emulated/sw_emulated" + "github.com/consensys/gnark/std/math/emulated" +) + +// ECAdd implements [ALT_BN128_ADD] precompile contract at address 0x06. +// +// [ALT_BN128_ADD]: https://ethereum.github.io/execution-specs/autoapi/ethereum/paris/vm/precompiled_contracts/alt_bn128/index.html#alt-bn128-add +func ECAdd(api frontend.API, P, Q *sw_emulated.AffinePoint[emulated.BN254Fp]) *sw_emulated.AffinePoint[emulated.BN254Fp] { + curve, err := sw_emulated.New[emulated.BN254Fp, emulated.BN254Fr](api, sw_emulated.GetBN254Params()) + if err != nil { + panic(err) + } + res := curve.Add(P, Q) + return res +} diff --git a/std/evmprecompiles/07-bnmul.go b/std/evmprecompiles/07-bnmul.go new file mode 100644 index 0000000000..1b6d2d6fa8 --- /dev/null +++ b/std/evmprecompiles/07-bnmul.go @@ -0,0 +1,19 @@ +package evmprecompiles + +import ( + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/algebra/emulated/sw_emulated" + "github.com/consensys/gnark/std/math/emulated" +) + +// ECMul implements [ALT_BN128_MUL] precompile contract at address 0x07. +// +// [ALT_BN128_MUL]: https://ethereum.github.io/execution-specs/autoapi/ethereum/paris/vm/precompiled_contracts/alt_bn128/index.html#alt-bn128-mul +func ECMul(api frontend.API, P *sw_emulated.AffinePoint[emulated.BN254Fp], u *emulated.Element[emulated.BN254Fr]) *sw_emulated.AffinePoint[emulated.BN254Fp] { + curve, err := sw_emulated.New[emulated.BN254Fp, emulated.BN254Fr](api, sw_emulated.GetBN254Params()) + if err != nil { + panic(err) + } + res := curve.ScalarMul(P, u) + return res +} diff --git a/std/evmprecompiles/08-bnpairing.go b/std/evmprecompiles/08-bnpairing.go new file mode 100644 index 0000000000..cab5c3ad2b --- /dev/null +++ b/std/evmprecompiles/08-bnpairing.go @@ -0,0 +1,19 @@ +package evmprecompiles + +import ( + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/algebra/emulated/sw_bn254" +) + +// ECPair implements [ALT_BN128_PAIRING_CHECK] precompile contract at address 0x08. +// +// [ALT_BN128_PAIRING_CHECK]: https://ethereum.github.io/execution-specs/autoapi/ethereum/paris/vm/precompiled_contracts/alt_bn128/index.html#alt-bn128-pairing-check +func ECPair(api frontend.API, P []*sw_bn254.G1Affine, Q []*sw_bn254.G2Affine) { + pair, err := sw_bn254.NewPairing(api) + if err != nil { + panic(err) + } + if err := pair.PairingCheck(P, Q); err != nil { + panic(err) + } +} diff --git a/std/evmprecompiles/bn_test.go b/std/evmprecompiles/bn_test.go new file mode 100644 index 0000000000..748155624f --- /dev/null +++ b/std/evmprecompiles/bn_test.go @@ -0,0 +1,168 @@ +package evmprecompiles + +import ( + "math/big" + "testing" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/algebra/emulated/sw_bn254" + "github.com/consensys/gnark/std/algebra/emulated/sw_emulated" + "github.com/consensys/gnark/std/math/emulated" + "github.com/consensys/gnark/test" +) + +type ecaddCircuit struct { + X0 sw_emulated.AffinePoint[emulated.BN254Fp] + X1 sw_emulated.AffinePoint[emulated.BN254Fp] + Expected sw_emulated.AffinePoint[emulated.BN254Fp] +} + +func (c *ecaddCircuit) Define(api frontend.API) error { + curve, err := sw_emulated.New[emulated.BN254Fp, emulated.BN254Fr](api, sw_emulated.GetBN254Params()) + if err != nil { + return err + } + res := ECAdd(api, &c.X0, &c.X1) + curve.AssertIsEqual(res, &c.Expected) + return nil +} + +func testRoutineECAdd(t *testing.T) (circ, wit frontend.Circuit) { + _, _, G, _ := bn254.Generators() + var u, v fr.Element + u.SetRandom() + v.SetRandom() + var P, Q bn254.G1Affine + P.ScalarMultiplication(&G, u.BigInt(new(big.Int))) + Q.ScalarMultiplication(&G, v.BigInt(new(big.Int))) + var expected bn254.G1Affine + expected.Add(&P, &Q) + circuit := ecaddCircuit{} + witness := ecaddCircuit{ + X0: sw_emulated.AffinePoint[emulated.BN254Fp]{ + X: emulated.ValueOf[emulated.BN254Fp](P.X), + Y: emulated.ValueOf[emulated.BN254Fp](P.Y), + }, + X1: sw_emulated.AffinePoint[emulated.BN254Fp]{ + X: emulated.ValueOf[emulated.BN254Fp](Q.X), + Y: emulated.ValueOf[emulated.BN254Fp](Q.Y), + }, + Expected: sw_emulated.AffinePoint[emulated.BN254Fp]{ + X: emulated.ValueOf[emulated.BN254Fp](expected.X), + Y: emulated.ValueOf[emulated.BN254Fp](expected.Y), + }, + } + return &circuit, &witness +} + +func TestECAddCircuitShort(t *testing.T) { + assert := test.NewAssert(t) + circuit, witness := testRoutineECAdd(t) + err := test.IsSolved(circuit, witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +func TestECAddCircuitFull(t *testing.T) { + assert := test.NewAssert(t) + circuit, witness := testRoutineECAdd(t) + assert.ProverSucceeded(circuit, witness, + test.NoFuzzing(), test.NoSerialization(), + test.WithBackends(backend.GROTH16, backend.PLONK), test.WithCurves(ecc.BN254), + ) +} + +type ecmulCircuit struct { + X0 sw_emulated.AffinePoint[emulated.BN254Fp] + U emulated.Element[emulated.BN254Fr] + Expected sw_emulated.AffinePoint[emulated.BN254Fp] +} + +func (c *ecmulCircuit) Define(api frontend.API) error { + curve, err := sw_emulated.New[emulated.BN254Fp, emulated.BN254Fr](api, sw_emulated.GetBN254Params()) + if err != nil { + return err + } + res := ECMul(api, &c.X0, &c.U) + curve.AssertIsEqual(res, &c.Expected) + return nil +} + +func testRoutineECMul(t *testing.T) (circ, wit frontend.Circuit) { + _, _, G, _ := bn254.Generators() + var u, v fr.Element + u.SetRandom() + v.SetRandom() + var P bn254.G1Affine + P.ScalarMultiplication(&G, u.BigInt(new(big.Int))) + var expected bn254.G1Affine + expected.ScalarMultiplication(&P, v.BigInt(new(big.Int))) + circuit := ecmulCircuit{} + witness := ecmulCircuit{ + X0: sw_emulated.AffinePoint[emulated.BN254Fp]{ + X: emulated.ValueOf[emulated.BN254Fp](P.X), + Y: emulated.ValueOf[emulated.BN254Fp](P.Y), + }, + U: emulated.ValueOf[emulated.BN254Fr](v), + Expected: sw_emulated.AffinePoint[emulated.BN254Fp]{ + X: emulated.ValueOf[emulated.BN254Fp](expected.X), + Y: emulated.ValueOf[emulated.BN254Fp](expected.Y), + }, + } + return &circuit, &witness +} + +func TestECMulCircuitShort(t *testing.T) { + assert := test.NewAssert(t) + circuit, witness := testRoutineECMul(t) + err := test.IsSolved(circuit, witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +func TestECMulCircuitFull(t *testing.T) { + t.Skip("skipping very long test") + assert := test.NewAssert(t) + circuit, witness := testRoutineECMul(t) + assert.ProverSucceeded(circuit, witness, + test.NoFuzzing(), test.NoSerialization(), + test.WithBackends(backend.GROTH16, backend.PLONK), test.WithCurves(ecc.BN254), + ) +} + +type ecpairCircuit struct { + P [2]sw_bn254.G1Affine + Q [2]sw_bn254.G2Affine +} + +func (c *ecpairCircuit) Define(api frontend.API) error { + P := []*sw_bn254.G1Affine{&c.P[0], &c.P[1]} + Q := []*sw_bn254.G2Affine{&c.Q[0], &c.Q[1]} + ECPair(api, P, Q) + return nil +} + +func TestECPairCircuitShort(t *testing.T) { + assert := test.NewAssert(t) + _, _, p1, q1 := bn254.Generators() + + var u, v fr.Element + u.SetRandom() + v.SetRandom() + + p1.ScalarMultiplication(&p1, u.BigInt(new(big.Int))) + q1.ScalarMultiplication(&q1, v.BigInt(new(big.Int))) + + var p2 bn254.G1Affine + var q2 bn254.G2Affine + p2.Neg(&p1) + q2.Set(&q1) + + err := test.IsSolved(&ecpairCircuit{}, &ecpairCircuit{ + P: [2]sw_bn254.G1Affine{sw_bn254.NewG1Affine(p1), sw_bn254.NewG1Affine(p2)}, + Q: [2]sw_bn254.G2Affine{sw_bn254.NewG2Affine(q1), sw_bn254.NewG2Affine(q2)}, + }, ecc.BN254.ScalarField()) + assert.NoError(err) +} diff --git a/std/evmprecompiles/compose.go b/std/evmprecompiles/compose.go new file mode 100644 index 0000000000..c1ffaff2aa --- /dev/null +++ b/std/evmprecompiles/compose.go @@ -0,0 +1,37 @@ +package evmprecompiles + +import ( + "fmt" + "math/big" +) + +func recompose(inputs []*big.Int, nbBits uint) *big.Int { + res := new(big.Int) + if len(inputs) == 0 { + return res + } + for i := range inputs { + res.Lsh(res, nbBits) + res.Add(res, inputs[len(inputs)-i-1]) + } + return res +} + +func decompose(input *big.Int, nbBits uint, res []*big.Int) error { + // limb modulus + if input.BitLen() > len(res)*int(nbBits) { + return fmt.Errorf("decomposed integer does not fit into res") + } + for _, r := range res { + if r == nil { + return fmt.Errorf("result slice element uninitalized") + } + } + base := new(big.Int).Lsh(big.NewInt(1), nbBits) + tmp := new(big.Int).Set(input) + for i := 0; i < len(res); i++ { + res[i].Mod(tmp, base) + tmp.Rsh(tmp, nbBits) + } + return nil +} diff --git a/std/evmprecompiles/doc.go b/std/evmprecompiles/doc.go new file mode 100644 index 0000000000..7c515eaa51 --- /dev/null +++ b/std/evmprecompiles/doc.go @@ -0,0 +1,18 @@ +// Package evmprecompiles implements the Ethereum VM precompile contracts. +// +// This package collects all the precompile functions into a single location for +// easier integration. The main functionality is implemented elsewhere. This +// package right now implements: +// 1. ECRECOVER ✅ -- function [ECRecover] +// 2. SHA256 ❌ -- in progress +// 3. RIPEMD160 ❌ -- postponed +// 4. ID ❌ -- trivial to implement without function +// 5. EXPMOD ❌ -- in progress +// 6. BN_ADD ✅ -- function [ECAdd] +// 7. BN_MUL ✅ -- function [ECMul] +// 8. SNARKV ✅ -- function [ECPair] +// 9. BLAKE2F ❌ -- postponed +// +// This package uses local representation for the arguments. It is up to the +// user to instantiate corresponding types from their application-specific data. +package evmprecompiles diff --git a/std/evmprecompiles/hints.go b/std/evmprecompiles/hints.go new file mode 100644 index 0000000000..0ebc231ae0 --- /dev/null +++ b/std/evmprecompiles/hints.go @@ -0,0 +1,97 @@ +package evmprecompiles + +import ( + "fmt" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/secp256k1/ecdsa" + "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/math/emulated" +) + +func init() { + solver.RegisterHint(GetHints()...) +} + +// GetHints returns all the hints used in this package. +func GetHints() []solver.Hint { + return []solver.Hint{recoverPointHint, recoverPublicKeyHint} +} + +func recoverPointHintArgs(v frontend.Variable, r emulated.Element[emulated.Secp256k1Fr]) []frontend.Variable { + args := []frontend.Variable{v} + args = append(args, r.Limbs...) + return args +} + +func recoverPointHint(_ *big.Int, inputs []*big.Int, outputs []*big.Int) error { + var emfp emulated.Secp256k1Fp + if len(inputs) != int(emfp.NbLimbs())+1 { + return fmt.Errorf("expected input %d limbs got %d", emfp.NbLimbs()+1, len(inputs)) + } + if !inputs[0].IsInt64() { + return fmt.Errorf("first input supposed to be in [0,3]") + } + if len(outputs) != 2*int(emfp.NbLimbs()) { + return fmt.Errorf("expected output %d limbs got %d", 2*emfp.NbLimbs(), len(outputs)) + } + v := inputs[0].Uint64() + r := recompose(inputs[1:], emfp.BitsPerLimb()) + P, err := ecdsa.RecoverP(uint(v), r) + if err != nil { + return fmt.Errorf("recover: %s", err) + } + if err := decompose(P.X.BigInt(new(big.Int)), emfp.BitsPerLimb(), outputs[0:emfp.NbLimbs()]); err != nil { + return fmt.Errorf("decompose x: %w", err) + } + if err := decompose(P.Y.BigInt(new(big.Int)), emfp.BitsPerLimb(), outputs[emfp.NbLimbs():]); err != nil { + return fmt.Errorf("decompose y: %w", err) + } + return nil +} + +func recoverPublicKeyHintArgs(msg emulated.Element[emulated.Secp256k1Fr], + v frontend.Variable, r, s emulated.Element[emulated.Secp256k1Fr]) []frontend.Variable { + args := msg.Limbs + args = append(args, v) + args = append(args, r.Limbs...) + args = append(args, s.Limbs...) + return args +} + +func recoverPublicKeyHint(_ *big.Int, inputs []*big.Int, outputs []*big.Int) error { + // message -nb limbs + // then v - 1 + // r -- nb limbs + // s -- nb limbs + // return 2x nb limbs + var emfr emulated.Secp256k1Fr + var emfp emulated.Secp256k1Fp + if len(inputs) != int(emfr.NbLimbs())*3+1 { + return fmt.Errorf("expected %d limbs got %d", emfr.NbLimbs()*3+1, len(inputs)) + } + if !inputs[emfr.NbLimbs()].IsInt64() { + return fmt.Errorf("second input input must be in [0,3]") + } + if len(outputs) != 2*int(emfp.NbLimbs()) { + return fmt.Errorf("expected output %d limbs got %d", 2*emfp.NbLimbs(), len(outputs)) + } + msg := recompose(inputs[:emfr.NbLimbs()], emfr.BitsPerLimb()) + v := inputs[emfr.NbLimbs()].Uint64() + r := recompose(inputs[emfr.NbLimbs()+1:2*emfr.NbLimbs()+1], emfr.BitsPerLimb()) + s := recompose(inputs[2*emfr.NbLimbs()+1:3*emfr.NbLimbs()+1], emfr.BitsPerLimb()) + var pk ecdsa.PublicKey + if err := pk.RecoverFrom(msg.Bytes(), uint(v), r, s); err != nil { + return fmt.Errorf("recover public key: %w", err) + } + Px := pk.A.X.BigInt(new(big.Int)) + Py := pk.A.Y.BigInt(new(big.Int)) + if err := decompose(Px, emfp.BitsPerLimb(), outputs[0:emfp.NbLimbs()]); err != nil { + return fmt.Errorf("decompose x: %w", err) + } + if err := decompose(Py, emfp.BitsPerLimb(), outputs[emfp.NbLimbs():2*emfp.NbLimbs()]); err != nil { + return fmt.Errorf("decompose y: %w", err) + } + return nil +} diff --git a/std/hints.go b/std/hints.go index cb061cd72d..2d04483004 100644 --- a/std/hints.go +++ b/std/hints.go @@ -6,6 +6,7 @@ import ( "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/std/algebra/native/sw_bls12377" "github.com/consensys/gnark/std/algebra/native/sw_bls24315" + "github.com/consensys/gnark/std/evmprecompiles" "github.com/consensys/gnark/std/math/bits" "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/std/rangecheck" @@ -35,4 +36,5 @@ func registerHints() { solver.RegisterHint(selector.GetHints()...) solver.RegisterHint(emulated.GetHints()...) solver.RegisterHint(rangecheck.CountHint, rangecheck.DecomposeHint) + solver.RegisterHint(evmprecompiles.GetHints()...) } diff --git a/std/math/emulated/field.go b/std/math/emulated/field.go index 9be78f0afc..124f4e9b37 100644 --- a/std/math/emulated/field.go +++ b/std/math/emulated/field.go @@ -109,11 +109,6 @@ func (f *Field[T]) NewElement(v interface{}) *Element[T] { return f.packLimbs([]frontend.Variable{v}, true) } if e, ok := v.([]frontend.Variable); ok { - for _, sv := range e { - if !frontend.IsCanonical(sv) { - panic("[]frontend.Variable that are not canonical (known to the compiler) is not a valid input") - } - } return f.packLimbs(e, true) } c := ValueOf[T](v) From 6bb3e4dbabe9f63c219f12ca273bf17d4d782bbc Mon Sep 17 00:00:00 2001 From: aybehrouz Date: Thu, 6 Apr 2023 15:20:51 +0330 Subject: [PATCH 235/464] perf: use `api.Select` for 2 to 1 mux A 2 to 1 multiplexer is a special case and has an efficient solution which can not be generalized to other cases. Therefore, we should use `api.Select` for constructing 2 to 1 multiplexers. --- std/selector/multiplexer.go | 3 +++ std/selector/multiplexer_test.go | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/std/selector/multiplexer.go b/std/selector/multiplexer.go index af3b3e99f1..25b162eb93 100644 --- a/std/selector/multiplexer.go +++ b/std/selector/multiplexer.go @@ -63,6 +63,9 @@ func generateSelector(api frontend.API, wantMux bool, sel frontend.Variable, var indicators []frontend.Variable var err error if wantMux { + if len(values) == 2 { + return api.Select(sel, values[1], values[0]) + } indicators, err = api.Compiler().NewHint(muxIndicators, len(values), sel) } else { indicators, err = api.Compiler().NewHint(mapIndicators, len(keys), append(keys, sel)...) diff --git a/std/selector/multiplexer_test.go b/std/selector/multiplexer_test.go index a0233205d1..79d7a31e00 100644 --- a/std/selector/multiplexer_test.go +++ b/std/selector/multiplexer_test.go @@ -36,6 +36,19 @@ func (c *ignoredOutputMuxCircuit) Define(api frontend.API) error { return nil } +type mux2to1Circuit struct { + SEL frontend.Variable + I0, I1 frontend.Variable + OUT frontend.Variable +} + +func (c *mux2to1Circuit) Define(api frontend.API) error { + // We ignore the output + out := selector.Mux(api, c.SEL, c.I0, c.I1) + api.AssertIsEqual(out, c.OUT) + return nil +} + func TestMux(t *testing.T) { assert := test.NewAssert(t) @@ -59,6 +72,13 @@ func TestMux(t *testing.T) { assert.ProverFailed(&ignoredOutputMuxCircuit{}, &ignoredOutputMuxCircuit{SEL: 3, I0: 0, I1: 1, I2: 2}) assert.ProverFailed(&ignoredOutputMuxCircuit{}, &ignoredOutputMuxCircuit{SEL: -1, I0: 0, I1: 1, I2: 2}) + + // 2 to 1 mux + assert.ProverSucceeded(&mux2to1Circuit{}, &mux2to1Circuit{SEL: 1, I0: 10, I1: 20, OUT: 20}) + + assert.ProverSucceeded(&mux2to1Circuit{}, &mux2to1Circuit{SEL: 0, I0: 10, I1: 20, OUT: 10}) + + assert.ProverFailed(&mux2to1Circuit{}, &mux2to1Circuit{SEL: 2, I0: 10, I1: 20, OUT: 20}) } // Map tests: From c3b3310e2b823f64159379b84e01296f9bc98320 Mon Sep 17 00:00:00 2001 From: aybehrouz Date: Thu, 6 Apr 2023 18:04:12 +0330 Subject: [PATCH 236/464] perf: use `api.Lookup2` for constructing 4 to 1 mux --- std/selector/multiplexer.go | 10 ++++++++++ std/selector/multiplexer_test.go | 31 +++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/std/selector/multiplexer.go b/std/selector/multiplexer.go index 25b162eb93..b8f0ca878e 100644 --- a/std/selector/multiplexer.go +++ b/std/selector/multiplexer.go @@ -14,6 +14,7 @@ package selector import ( "fmt" + "github.com/consensys/gnark/std/math/bits" "math/big" "github.com/consensys/gnark/constraint/solver" @@ -66,7 +67,16 @@ func generateSelector(api frontend.API, wantMux bool, sel frontend.Variable, if len(values) == 2 { return api.Select(sel, values[1], values[0]) } + + if len(values) == 4 { + // api.Lookup2 adds constraints for the boolean assertion, so we use + // bits.WithUnconstrainedOutputs() + selBits := bits.ToBinary(api, sel, bits.WithNbDigits(2), bits.WithUnconstrainedOutputs()) + return api.Lookup2(selBits[0], selBits[1], values[0], values[1], values[2], values[3]) + } + indicators, err = api.Compiler().NewHint(muxIndicators, len(values), sel) + } else { indicators, err = api.Compiler().NewHint(mapIndicators, len(keys), append(keys, sel)...) } diff --git a/std/selector/multiplexer_test.go b/std/selector/multiplexer_test.go index 79d7a31e00..03b6ddf093 100644 --- a/std/selector/multiplexer_test.go +++ b/std/selector/multiplexer_test.go @@ -49,6 +49,18 @@ func (c *mux2to1Circuit) Define(api frontend.API) error { return nil } +type mux4to1Circuit struct { + SEL frontend.Variable + In [4]frontend.Variable + OUT frontend.Variable +} + +func (c *mux4to1Circuit) Define(api frontend.API) error { + out := selector.Mux(api, c.SEL, c.In[:]...) + api.AssertIsEqual(out, c.OUT) + return nil +} + func TestMux(t *testing.T) { assert := test.NewAssert(t) @@ -79,6 +91,25 @@ func TestMux(t *testing.T) { assert.ProverSucceeded(&mux2to1Circuit{}, &mux2to1Circuit{SEL: 0, I0: 10, I1: 20, OUT: 10}) assert.ProverFailed(&mux2to1Circuit{}, &mux2to1Circuit{SEL: 2, I0: 10, I1: 20, OUT: 20}) + + // 4 to 1 mux + assert.ProverSucceeded(&mux4to1Circuit{}, &mux4to1Circuit{ + SEL: 3, + In: [4]frontend.Variable{11, 22, 33, 44}, + OUT: 44, + }) + + assert.ProverSucceeded(&mux4to1Circuit{}, &mux4to1Circuit{ + SEL: 1, + In: [4]frontend.Variable{11, 22, 33, 44}, + OUT: 22, + }) + + assert.ProverFailed(&mux4to1Circuit{}, &mux4to1Circuit{ + SEL: 4, + In: [4]frontend.Variable{11, 22, 33, 44}, + OUT: 44, + }) } // Map tests: From 52f24650e36d937dedeaec017478ba2828d55d78 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 7 Apr 2023 16:13:04 +0200 Subject: [PATCH 237/464] test: test bls12-381 in sw_emulated + comments --- std/algebra/emulated/sw_bls12381/pairing.go | 23 ++++++++ std/algebra/emulated/sw_bn254/pairing.go | 10 +--- std/algebra/emulated/sw_emulated/params.go | 19 +++++++ .../emulated/sw_emulated/params_compute.go | 27 ++++++++++ std/algebra/emulated/sw_emulated/point.go | 33 +++++++----- .../emulated/sw_emulated/point_test.go | 54 +++++++++++++++++++ std/math/emulated/params.go | 11 ++++ 7 files changed, 156 insertions(+), 21 deletions(-) diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go index 788f6203b1..032453d788 100644 --- a/std/algebra/emulated/sw_bls12381/pairing.go +++ b/std/algebra/emulated/sw_bls12381/pairing.go @@ -227,6 +227,29 @@ func (pr Pairing) AssertIsEqual(x, y *GTEl) { pr.Ext12.AssertIsEqual(x, y) } +func (pr Pairing) AssertIsOnCurve(P *G1Affine) { + // Curve: Y² == X³ + aX + b, where a=0 and b=4 + four := emulated.ValueOf[emulated.BLS12381Fp](4) + left := pr.curveF.Mul(&P.Y, &P.Y) + right := pr.curveF.Mul(&P.X, &P.X) + right = pr.curveF.Mul(right, &P.X) + right = pr.curveF.Add(right, &four) + pr.curveF.AssertIsEqual(left, right) +} + +func (pr Pairing) AssertIsOnTwist(Q *G2Affine) { + // Twist: Y² == X³ + aX + b, where a=0 and b=4(1+u) + b := fields_bls12381.E2{ + A0: emulated.ValueOf[emulated.BLS12381Fp]("4"), + A1: emulated.ValueOf[emulated.BLS12381Fp]("4"), + } + left := pr.Ext2.Square(&Q.Y) + right := pr.Ext2.Square(&Q.X) + right = pr.Ext2.Mul(right, &Q.X) + right = pr.Ext2.Add(right, &b) + pr.Ext2.AssertIsEqual(left, right) +} + // loopCounter = seed in binary // // seed=-15132376222941642752 diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 15d7f2f88e..22798fa029 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -233,7 +233,7 @@ func (pr Pairing) AssertIsEqual(x, y *GTEl) { } func (pr Pairing) AssertIsOnCurve(P *G1Affine) { - // Curve: Y^2 = X^3 + b, where b = 3 + // Curve: Y² == X³ + aX + b, where a=0 and b=3 three := emulated.ValueOf[emulated.BN254Fp](3) left := pr.curveF.Mul(&P.Y, &P.Y) right := pr.curveF.Mul(&P.X, &P.X) @@ -243,7 +243,7 @@ func (pr Pairing) AssertIsOnCurve(P *G1Affine) { } func (pr Pairing) AssertIsOnTwist(Q *G2Affine) { - // Twist: Y^2 = X^3 + b', where b' = 3/(9+u) + // Twist: Y² == X³ + aX + b, where a=0 and b=3/(9+u) b := fields_bn254.E2{ A0: emulated.ValueOf[emulated.BN254Fp]("19485874751759354771024239261021720505790618469301721065564631296452457478373"), A1: emulated.ValueOf[emulated.BN254Fp]("266929791119991161246907387137283842545076965332900288569378510910307636690"), @@ -284,12 +284,6 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { return nil, errors.New("invalid inputs sizes") } - // check points are on curve - for k := 0; k < n; k++ { - pr.AssertIsOnCurve(P[k]) - pr.AssertIsOnTwist(Q[k]) - } - res := pr.Ext12.One() var prodLines [5]fields_bn254.E2 diff --git a/std/algebra/emulated/sw_emulated/params.go b/std/algebra/emulated/sw_emulated/params.go index b9f00ec707..bb513b6e41 100644 --- a/std/algebra/emulated/sw_emulated/params.go +++ b/std/algebra/emulated/sw_emulated/params.go @@ -3,6 +3,7 @@ package sw_emulated import ( "math/big" + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/secp256k1" "github.com/consensys/gnark/std/math/emulated" @@ -50,6 +51,20 @@ func GetBN254Params() CurveParams { } } +// GetBLS12381Params returns the curve parameters for the curve BLS12-381. +// When initialising new curve, use the base field [emulated.BLS12381Fp] and scalar +// field [emulated.BLS12381Fr]. +func GetBLS12381Params() CurveParams { + _, _, g1aff, _ := bls12381.Generators() + return CurveParams{ + A: big.NewInt(0), + B: big.NewInt(4), + Gx: g1aff.X.BigInt(new(big.Int)), + Gy: g1aff.Y.BigInt(new(big.Int)), + Gm: computeBLS12381Table(), + } +} + // GetCurveParams returns suitable curve parameters given the parametric type Base as base field. func GetCurveParams[Base emulated.FieldParams]() CurveParams { var t Base @@ -58,6 +73,8 @@ func GetCurveParams[Base emulated.FieldParams]() CurveParams { return secp256k1Params case "30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47": return bn254Params + case "1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab": + return bls12381Params default: panic("no stored parameters") } @@ -66,9 +83,11 @@ func GetCurveParams[Base emulated.FieldParams]() CurveParams { var ( secp256k1Params CurveParams bn254Params CurveParams + bls12381Params CurveParams ) func init() { secp256k1Params = GetSecp256k1Params() bn254Params = GetBN254Params() + bls12381Params = GetBLS12381Params() } diff --git a/std/algebra/emulated/sw_emulated/params_compute.go b/std/algebra/emulated/sw_emulated/params_compute.go index fbdabea300..58d3e26df8 100644 --- a/std/algebra/emulated/sw_emulated/params_compute.go +++ b/std/algebra/emulated/sw_emulated/params_compute.go @@ -3,6 +3,7 @@ package sw_emulated import ( "math/big" + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/secp256k1" ) @@ -58,3 +59,29 @@ func computeBN254Table() [][2]*big.Int { } return table } + +func computeBLS12381Table() [][2]*big.Int { + Gjac, _, _, _ := bls12381.Generators() + table := make([][2]*big.Int, 256) + tmp := new(bls12381.G1Jac).Set(&Gjac) + aff := new(bls12381.G1Affine) + jac := new(bls12381.G1Jac) + for i := 1; i < 256; i++ { + tmp = tmp.Double(tmp) + switch i { + case 1, 2: + jac.Set(tmp).AddAssign(&Gjac) + aff.FromJacobian(jac) + table[i-1] = [2]*big.Int{aff.X.BigInt(new(big.Int)), aff.Y.BigInt(new(big.Int))} + case 3: + jac.Set(tmp).SubAssign(&Gjac) + aff.FromJacobian(jac) + table[i-1] = [2]*big.Int{aff.X.BigInt(new(big.Int)), aff.Y.BigInt(new(big.Int))} + fallthrough + default: + aff.FromJacobian(tmp) + table[i] = [2]*big.Int{aff.X.BigInt(new(big.Int)), aff.Y.BigInt(new(big.Int))} + } + } + return table +} diff --git a/std/algebra/emulated/sw_emulated/point.go b/std/algebra/emulated/sw_emulated/point.go index c650afd4d3..511e528825 100644 --- a/std/algebra/emulated/sw_emulated/point.go +++ b/std/algebra/emulated/sw_emulated/point.go @@ -98,6 +98,8 @@ func (c *Curve[B, S]) AssertIsEqual(p, q *AffinePoint[B]) { } // Add adds p and q and returns it. It doesn't modify p nor q. +// This function doesn't check that the p and q are on the curve. See AssertIsOnCurve. +// // It uses incomplete formulas in affine coordinates. // The points p and q should be different and nonzero (neutral element). func (c *Curve[B, S]) Add(p, q *AffinePoint[B]) *AffinePoint[B] { @@ -122,11 +124,11 @@ func (c *Curve[B, S]) Add(p, q *AffinePoint[B]) *AffinePoint[B] { } } +// AssertIsOnCurve asserts if p belongs to the curve. It doesn't modify p. func (c *Curve[B, S]) AssertIsOnCurve(p *AffinePoint[B]) { - // y^2 = x^3+ax+b + // Y² == X³ + aX + b left := c.baseApi.Mul(&p.Y, &p.Y) - right := c.baseApi.Mul(&p.X, &p.X) - right = c.baseApi.Mul(right, &p.X) + right := c.baseApi.Mul(&p.X, c.baseApi.Mul(&p.X, &p.X)) right = c.baseApi.Add(right, &c.b) if c.addA { ax := c.baseApi.Mul(&c.a, &p.X) @@ -136,6 +138,8 @@ func (c *Curve[B, S]) AssertIsOnCurve(p *AffinePoint[B]) { } // Double doubles p and return it. It doesn't modify p. +// This function doesn't check that the p is on the curve. See AssertIsOnCurve. +// // It uses affine coordinates. func (c *Curve[B, S]) Double(p *AffinePoint[B]) *AffinePoint[B] { @@ -164,13 +168,14 @@ func (c *Curve[B, S]) Double(p *AffinePoint[B]) *AffinePoint[B] { } } -// Triple triples p and return it. It follows [ELM03] (Section 3.1). -// Saves the computation of the y coordinate of 2p as it is used only in the computation of λ2, -// which can be computed as +// Triple triples p and return it. It doesn't modify p. +// This function doesn't check that the p is on the curve. See AssertIsOnCurve. // -// λ2 = -λ1-2*p.y/(x2-p.x) +// It follows [ELM03] (Section 3.1). This saves the computation of the y +// coordinate of 2p as it is used only in the computation of λ2, which can be +// computed as // -// instead. It doesn't modify p. +// λ2 = -λ1-2*p.y/(x2-p.x) // // [ELM03]: https://arxiv.org/pdf/math/0208038.pdf func (c *Curve[B, S]) Triple(p *AffinePoint[B]) *AffinePoint[B] { @@ -211,13 +216,14 @@ func (c *Curve[B, S]) Triple(p *AffinePoint[B]) *AffinePoint[B] { } } -// DoubleAndAdd computes 2p+q as (p+q)+p. It follows [ELM03] (Section 3.1) -// Saves the computation of the y coordinate of p+q as it is used only in the computation of λ2, -// which can be computed as +// DoubleAndAdd computes 2p+q as (p+q)+p. It doesn't modify p nor q. +// This function doesn't check that the p and q are on the curve. See AssertIsOnCurve. // -// λ2 = -λ1-2*p.y/(x2-p.x) +// It follows [ELM03] (Section 3.1). This saves the computation of the y +// coordinate of p+q as it is used only in the computation of λ2, which can be +// computed as // -// instead. It doesn't modify p nor q. +// λ2 = -λ1-2*p.y/(x2-p.x) // // [ELM03]: https://arxiv.org/pdf/math/0208038.pdf func (c *Curve[B, S]) DoubleAndAdd(p, q *AffinePoint[B]) *AffinePoint[B] { @@ -284,6 +290,7 @@ func (c *Curve[B, S]) Lookup2(b0, b1 frontend.Variable, i0, i1, i2, i3 *AffinePo } // ScalarMul computes s * p and returns it. It doesn't modify p nor s. +// This function doesn't check that the p is on the curve. See AssertIsOnCurve. // // It computes the standard little-endian variable-base double-and-add algorithm // [HMV04] (Algorithm 3.26). diff --git a/std/algebra/emulated/sw_emulated/point_test.go b/std/algebra/emulated/sw_emulated/point_test.go index 11539b046d..a7557cc6ce 100644 --- a/std/algebra/emulated/sw_emulated/point_test.go +++ b/std/algebra/emulated/sw_emulated/point_test.go @@ -5,6 +5,8 @@ import ( "testing" "github.com/consensys/gnark-crypto/ecc" + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + fr_bls381 "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "github.com/consensys/gnark-crypto/ecc/bn254" fr_bn "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark-crypto/ecc/secp256k1" @@ -275,6 +277,30 @@ func TestScalarMulBase2(t *testing.T) { assert.NoError(err) } +func TestScalarMulBase3(t *testing.T) { + assert := test.NewAssert(t) + _, _, g, _ := bls12381.Generators() + var r fr_bn.Element + _, _ = r.SetRandom() + s := new(big.Int) + r.BigInt(s) + var S bls12381.G1Affine + S.ScalarMultiplication(&g, s) + + circuit := ScalarMulBaseTest[emulated.BLS12381Fp, emulated.BLS12381Fr]{} + witness := ScalarMulBaseTest[emulated.BLS12381Fp, emulated.BLS12381Fr]{ + S: emulated.ValueOf[emulated.BLS12381Fr](s), + Q: AffinePoint[emulated.BLS12381Fp]{ + X: emulated.ValueOf[emulated.BLS12381Fp](S.X), + Y: emulated.ValueOf[emulated.BLS12381Fp](S.Y), + }, + } + err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) + assert.NoError(err) + _, err = frontend.Compile(testCurve.ScalarField(), r1cs.NewBuilder, &circuit) + assert.NoError(err) +} + type ScalarMulTest[T, S emulated.FieldParams] struct { P, Q AffinePoint[T] S emulated.Element[S] @@ -346,6 +372,34 @@ func TestScalarMul2(t *testing.T) { assert.NoError(err) } +func TestScalarMul3(t *testing.T) { + assert := test.NewAssert(t) + var r fr_bls381.Element + _, _ = r.SetRandom() + s := new(big.Int) + r.BigInt(s) + var res bls12381.G1Affine + _, _, gen, _ := bls12381.Generators() + res.ScalarMultiplication(&gen, s) + + circuit := ScalarMulTest[emulated.BLS12381Fp, emulated.BLS12381Fr]{} + witness := ScalarMulTest[emulated.BLS12381Fp, emulated.BLS12381Fr]{ + S: emulated.ValueOf[emulated.BLS12381Fr](s), + P: AffinePoint[emulated.BLS12381Fp]{ + X: emulated.ValueOf[emulated.BLS12381Fp](gen.X), + Y: emulated.ValueOf[emulated.BLS12381Fp](gen.Y), + }, + Q: AffinePoint[emulated.BLS12381Fp]{ + X: emulated.ValueOf[emulated.BLS12381Fp](res.X), + Y: emulated.ValueOf[emulated.BLS12381Fp](res.Y), + }, + } + err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) + assert.NoError(err) + _, err = frontend.Compile(testCurve.ScalarField(), r1cs.NewBuilder, &circuit) + assert.NoError(err) +} + type IsOnCurveTest[T, S emulated.FieldParams] struct { Q AffinePoint[T] } diff --git a/std/math/emulated/params.go b/std/math/emulated/params.go index eda8ebddc5..b40b2f2493 100644 --- a/std/math/emulated/params.go +++ b/std/math/emulated/params.go @@ -97,3 +97,14 @@ func (fp BLS12381Fp) NbLimbs() uint { return 6 } func (fp BLS12381Fp) BitsPerLimb() uint { return 64 } func (fp BLS12381Fp) IsPrime() bool { return true } func (fp BLS12381Fp) Modulus() *big.Int { return ecc.BLS12_381.BaseField() } + +// BLS12381Fr provide type parametrization for emulated field on 4 limb of width +// 64bits for modulus +// 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001. +// This is the scalar field of the BLS12-381 curve. +type BLS12381Fr struct{} + +func (fp BLS12381Fr) NbLimbs() uint { return 4 } +func (fp BLS12381Fr) BitsPerLimb() uint { return 64 } +func (fp BLS12381Fr) IsPrime() bool { return true } +func (fp BLS12381Fr) Modulus() *big.Int { return ecc.BLS12_381.ScalarField() } From b9484d1bf36af264b801b83d18eee0d7f04d65ac Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 7 Apr 2023 16:15:29 +0200 Subject: [PATCH 238/464] test: add bn254 and bl12381 test of AssertIsOnCurve --- .../emulated/sw_emulated/point_test.go | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/std/algebra/emulated/sw_emulated/point_test.go b/std/algebra/emulated/sw_emulated/point_test.go index a7557cc6ce..14c18c5c2f 100644 --- a/std/algebra/emulated/sw_emulated/point_test.go +++ b/std/algebra/emulated/sw_emulated/point_test.go @@ -433,3 +433,45 @@ func TestIsOnCurve(t *testing.T) { err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) assert.NoError(err) } + +func TestIsOnCurve2(t *testing.T) { + assert := test.NewAssert(t) + _, _, g, _ := bn254.Generators() + var r fr_secp.Element + _, _ = r.SetRandom() + s := new(big.Int) + r.BigInt(s) + var Q bn254.G1Affine + Q.ScalarMultiplication(&g, s) + + circuit := IsOnCurveTest[emulated.BN254Fp, emulated.BN254Fr]{} + witness := IsOnCurveTest[emulated.BN254Fp, emulated.BN254Fr]{ + Q: AffinePoint[emulated.BN254Fp]{ + X: emulated.ValueOf[emulated.BN254Fp](Q.X), + Y: emulated.ValueOf[emulated.BN254Fp](Q.Y), + }, + } + err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) + assert.NoError(err) +} + +func TestIsOnCurve3(t *testing.T) { + assert := test.NewAssert(t) + _, _, g, _ := bls12381.Generators() + var r fr_secp.Element + _, _ = r.SetRandom() + s := new(big.Int) + r.BigInt(s) + var Q bls12381.G1Affine + Q.ScalarMultiplication(&g, s) + + circuit := IsOnCurveTest[emulated.BLS12381Fp, emulated.BLS12381Fr]{} + witness := IsOnCurveTest[emulated.BLS12381Fp, emulated.BLS12381Fr]{ + Q: AffinePoint[emulated.BLS12381Fp]{ + X: emulated.ValueOf[emulated.BLS12381Fp](Q.X), + Y: emulated.ValueOf[emulated.BLS12381Fp](Q.Y), + }, + } + err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) + assert.NoError(err) +} From 3bea95b9bbe44eb1dc08be44dd5dbd56d5c215bc Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 7 Apr 2023 18:04:58 +0200 Subject: [PATCH 239/464] feat(sw_bn254): add AssertIsOnG2 --- std/algebra/emulated/sw_bn254/hints.go | 43 +++++++++++++++++++ std/algebra/emulated/sw_bn254/pairing.go | 28 ++++++++++++ std/algebra/emulated/sw_bn254/pairing_test.go | 32 ++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 std/algebra/emulated/sw_bn254/hints.go diff --git a/std/algebra/emulated/sw_bn254/hints.go b/std/algebra/emulated/sw_bn254/hints.go new file mode 100644 index 0000000000..b1674afdb9 --- /dev/null +++ b/std/algebra/emulated/sw_bn254/hints.go @@ -0,0 +1,43 @@ +package sw_bn254 + +import ( + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/std/math/emulated" +) + +func init() { + solver.RegisterHint(subgroupG2Hint) +} + +func subgroupG2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, c bn254.G2Affine + + a.X.A0.SetBigInt(inputs[0]) + a.X.A1.SetBigInt(inputs[1]) + a.Y.A0.SetBigInt(inputs[2]) + a.Y.A1.SetBigInt(inputs[3]) + + // c = ψ³([2x₀]a) - ψ²([x₀]a) - ψ([x₀]a) - [x₀]a + x0, _ := new(big.Int).SetString("4965661367192848881", 10) + var aJac, t1, t2, t3 bn254.G2Jac + aJac.FromAffine(&a) + aJac.ScalarMultiplication(&aJac, x0) + t1.Psi(&aJac) + t2.Psi(&t1) + t3.Psi(&t2).Double(&t3).Neg(&t3) + aJac.AddAssign(&t1).AddAssign(&t2).AddAssign(&t3).Neg(&aJac) + c.FromJacobian(&aJac) + + c.X.A0.BigInt(outputs[0]) + c.X.A1.BigInt(outputs[1]) + c.Y.A0.BigInt(outputs[2]) + c.Y.A1.BigInt(outputs[3]) + + return nil + }) +} diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 22798fa029..f710639dde 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -255,6 +255,34 @@ func (pr Pairing) AssertIsOnTwist(Q *G2Affine) { pr.Ext2.AssertIsEqual(left, right) } +func (pr Pairing) AssertIsOnG1(P *G1Affine) { + // BN254 has a prime order, so we only + // 1- Check P is on the curve + pr.AssertIsOnCurve(P) +} + +func (pr Pairing) AssertIsOnG2(Q *G2Affine) { + // 1- Check Q is on the curve + pr.AssertIsOnTwist(Q) + + // 2- Check Q has the right subgroup order + res, err := pr.curveF.NewHint(subgroupG2Hint, 4, &Q.X.A0, &Q.X.A1, &Q.Y.A0, &Q.Y.A1) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + // _Q = ψ³([2x₀]Q) - ψ²([x₀]Q) - ψ([x₀]Q) - [x₀]Q + _Q := G2Affine{ + X: fields_bn254.E2{A0: *res[0], A1: *res[1]}, + Y: fields_bn254.E2{A0: *res[2], A1: *res[3]}, + } + + // [r]Q == 0 <==> Q = _Q + pr.Ext2.AssertIsEqual(&Q.X, &_Q.X) + pr.Ext2.AssertIsEqual(&Q.Y, &_Q.Y) +} + // loopCounter = 6x₀+2 = 29793968203157093288 // // in 2-NAF diff --git a/std/algebra/emulated/sw_bn254/pairing_test.go b/std/algebra/emulated/sw_bn254/pairing_test.go index 1d76ca0d45..e31adee388 100644 --- a/std/algebra/emulated/sw_bn254/pairing_test.go +++ b/std/algebra/emulated/sw_bn254/pairing_test.go @@ -66,6 +66,8 @@ func (c *PairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } + pairing.AssertIsOnG1(&c.InG1) + pairing.AssertIsOnG2(&c.InG2) res, err := pairing.Pair([]*G1Affine{&c.InG1}, []*G2Affine{&c.InG2}) if err != nil { return fmt.Errorf("pair: %w", err) @@ -101,6 +103,10 @@ func (c *MultiPairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } + pairing.AssertIsOnG1(&c.In1G1) + pairing.AssertIsOnG1(&c.In2G1) + pairing.AssertIsOnG2(&c.In1G2) + pairing.AssertIsOnG2(&c.In2G2) res, err := pairing.Pair([]*G1Affine{&c.In1G1, &c.In1G1, &c.In2G1, &c.In2G1}, []*G2Affine{&c.In1G2, &c.In2G2, &c.In1G2, &c.In2G2}) if err != nil { return fmt.Errorf("pair: %w", err) @@ -196,3 +202,29 @@ func TestFinalExponentiationSafeCircuit(t *testing.T) { }, ecc.BN254.ScalarField()) assert.NoError(err) } + +type GroupMembershipCircuit struct { + InG1 G1Affine + InG2 G2Affine +} + +func (c *GroupMembershipCircuit) Define(api frontend.API) error { + pairing, err := NewPairing(api) + if err != nil { + return fmt.Errorf("new pairing: %w", err) + } + pairing.AssertIsOnG1(&c.InG1) + pairing.AssertIsOnG2(&c.InG2) + return nil +} + +func TestGroupMembershipSolve(t *testing.T) { + assert := test.NewAssert(t) + p, q := randomG1G2Affines(assert) + witness := GroupMembershipCircuit{ + InG1: NewG1Affine(p), + InG2: NewG2Affine(q), + } + err := test.IsSolved(&GroupMembershipCircuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} From d62695e0a0f8c8e27cfe92f6c16f45665be91921 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 7 Apr 2023 18:44:30 +0200 Subject: [PATCH 240/464] feat(sw_bls12381): add AssertIsOnG1 and AssertIsOnG2 --- std/algebra/emulated/sw_bls12381/hints.go | 68 +++++++++++++++++++ std/algebra/emulated/sw_bls12381/pairing.go | 59 ++++++++++++++++ .../emulated/sw_bls12381/pairing_test.go | 32 +++++++++ std/algebra/emulated/sw_bn254/pairing.go | 14 ++-- 4 files changed, 166 insertions(+), 7 deletions(-) create mode 100644 std/algebra/emulated/sw_bls12381/hints.go diff --git a/std/algebra/emulated/sw_bls12381/hints.go b/std/algebra/emulated/sw_bls12381/hints.go new file mode 100644 index 0000000000..b9f34dcc1a --- /dev/null +++ b/std/algebra/emulated/sw_bls12381/hints.go @@ -0,0 +1,68 @@ +package sw_bls12381 + +import ( + "math/big" + + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/std/math/emulated" +) + +func init() { + solver.RegisterHint(GetHints()...) +} + +// GetHints returns all hint functions used in the package. +func GetHints() []solver.Hint { + return []solver.Hint{ + subgroupG1Hint, + subgroupG2Hint, + } +} + +func subgroupG1Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, c bls12381.G1Affine + + a.X.SetBigInt(inputs[0]) + a.Y.SetBigInt(inputs[1]) + + // c = -[x²]ϕ(p) + x0, _ := new(big.Int).SetString("15132376222941642752", 10) // negative + var jac bls12381.G1Jac + jac.FromAffine(&a) + jac.Phi(&jac).ScalarMultiplication(&jac, x0). + ScalarMultiplication(&jac, x0). + Neg(&jac) + c.FromJacobian(&jac) + + c.X.BigInt(outputs[0]) + c.Y.BigInt(outputs[1]) + + return nil + }) +} + +func subgroupG2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { + return emulated.UnwrapHint(nativeInputs, nativeOutputs, + func(mod *big.Int, inputs, outputs []*big.Int) error { + var a, c bls12381.G2Affine + + a.X.A0.SetBigInt(inputs[0]) + a.X.A1.SetBigInt(inputs[1]) + a.Y.A0.SetBigInt(inputs[2]) + a.Y.A1.SetBigInt(inputs[3]) + + // c = [x₀]a + x0, _ := new(big.Int).SetString("15132376222941642752", 10) // negative + c.ScalarMultiplication(&a, x0).Neg(&c) + + c.X.A0.BigInt(outputs[0]) + c.X.A1.BigInt(outputs[1]) + c.Y.A0.BigInt(outputs[2]) + c.Y.A1.BigInt(outputs[3]) + + return nil + }) +} diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go index 032453d788..0f15634c44 100644 --- a/std/algebra/emulated/sw_bls12381/pairing.go +++ b/std/algebra/emulated/sw_bls12381/pairing.go @@ -250,6 +250,65 @@ func (pr Pairing) AssertIsOnTwist(Q *G2Affine) { pr.Ext2.AssertIsEqual(left, right) } +func (pr Pairing) AssertIsOnG1(P *G1Affine) { + // 1- Check P is on the curve + pr.AssertIsOnCurve(P) + + // 2- Check P has the right subgroup order + res, err := pr.curveF.NewHint(subgroupG1Hint, 2, &P.X, &P.Y) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + // _P = -[x²]ϕ(p) + _P := G1Affine{ + X: *res[0], + Y: *res[1], + } + + // [r]Q == 0 <==> P = _P + pr.curveF.AssertIsEqual(&P.X, &_P.X) + pr.curveF.AssertIsEqual(&P.Y, &_P.Y) +} + +func (pr Pairing) AssertIsOnG2(Q *G2Affine) { + // 1- Check Q is on the curve + pr.AssertIsOnTwist(Q) + + // 2- Check Q has the right subgroup order + res, err := pr.curveF.NewHint(subgroupG2Hint, 4, &Q.X.A0, &Q.X.A1, &Q.Y.A0, &Q.Y.A1) + if err != nil { + // err is non-nil only for invalid number of inputs + panic(err) + } + + // _Q = [x₀]Q + _Q := G2Affine{ + X: fields_bls12381.E2{A0: *res[0], A1: *res[1]}, + Y: fields_bls12381.E2{A0: *res[2], A1: *res[3]}, + } + + // [r]Q == 0 <==> ψ(Q) = _Q + var psiQ G2Affine + u1 := emulated.ValueOf[emulated.BLS12381Fp]("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437") + v := fields_bls12381.E2{ + A0: emulated.ValueOf[emulated.BLS12381Fp]("2973677408986561043442465346520108879172042883009249989176415018091420807192182638567116318576472649347015917690530"), + A1: emulated.ValueOf[emulated.BLS12381Fp]("1028732146235106349975324479215795277384839936929757896155643118032610843298655225875571310552543014690878354869257"), + } + + // ψ(Q) + psiQ.X = *pr.Ext2.Conjugate(&Q.X) + tmp := *pr.curveF.Mul(&psiQ.X.A1, &u1) + psiQ.X.A1 = *pr.curveF.Mul(&psiQ.X.A0, &u1) + psiQ.X.A0 = *pr.curveF.Neg(&tmp) + psiQ.Y = *pr.Ext2.Conjugate(&Q.Y) + psiQ.Y = *pr.Ext2.Mul(&psiQ.Y, &v) + + pr.Ext2.AssertIsEqual(&psiQ.X, &_Q.X) + pr.Ext2.AssertIsEqual(&psiQ.Y, &_Q.Y) +} + // loopCounter = seed in binary // // seed=-15132376222941642752 diff --git a/std/algebra/emulated/sw_bls12381/pairing_test.go b/std/algebra/emulated/sw_bls12381/pairing_test.go index ec1bf2baec..5a104df470 100644 --- a/std/algebra/emulated/sw_bls12381/pairing_test.go +++ b/std/algebra/emulated/sw_bls12381/pairing_test.go @@ -66,6 +66,8 @@ func (c *PairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } + pairing.AssertIsOnG1(&c.InG1) + pairing.AssertIsOnG2(&c.InG2) res, err := pairing.Pair([]*G1Affine{&c.InG1}, []*G2Affine{&c.InG2}) if err != nil { return fmt.Errorf("pair: %w", err) @@ -101,6 +103,10 @@ func (c *MultiPairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } + pairing.AssertIsOnG1(&c.In1G1) + pairing.AssertIsOnG1(&c.In2G1) + pairing.AssertIsOnG2(&c.In1G2) + pairing.AssertIsOnG2(&c.In2G2) res, err := pairing.Pair([]*G1Affine{&c.In1G1, &c.In1G1, &c.In2G1, &c.In2G1}, []*G2Affine{&c.In1G2, &c.In2G2, &c.In1G2, &c.In2G2}) if err != nil { return fmt.Errorf("pair: %w", err) @@ -196,3 +202,29 @@ func TestFinalExponentiationSafeCircuit(t *testing.T) { }, ecc.BN254.ScalarField()) assert.NoError(err) } + +type GroupMembershipCircuit struct { + InG1 G1Affine + InG2 G2Affine +} + +func (c *GroupMembershipCircuit) Define(api frontend.API) error { + pairing, err := NewPairing(api) + if err != nil { + return fmt.Errorf("new pairing: %w", err) + } + pairing.AssertIsOnG1(&c.InG1) + pairing.AssertIsOnG2(&c.InG2) + return nil +} + +func TestGroupMembershipSolve(t *testing.T) { + assert := test.NewAssert(t) + p, q := randomG1G2Affines(assert) + witness := GroupMembershipCircuit{ + InG1: NewG1Affine(p), + InG2: NewG2Affine(q), + } + err := test.IsSolved(&GroupMembershipCircuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index f710639dde..b1563011ed 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -487,15 +487,15 @@ func (pr Pairing) MillerLoop(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { Q1, Q2 := new(G2Affine), new(G2Affine) for k := 0; k < n; k++ { //Q1 = π(Q) - Q1.X = *pr.Ext12.Ext2.Conjugate(&Q[k].X) - Q1.X = *pr.Ext12.Ext2.MulByNonResidue1Power2(&Q1.X) - Q1.Y = *pr.Ext12.Ext2.Conjugate(&Q[k].Y) - Q1.Y = *pr.Ext12.Ext2.MulByNonResidue1Power3(&Q1.Y) + Q1.X = *pr.Ext2.Conjugate(&Q[k].X) + Q1.X = *pr.Ext2.MulByNonResidue1Power2(&Q1.X) + Q1.Y = *pr.Ext2.Conjugate(&Q[k].Y) + Q1.Y = *pr.Ext2.MulByNonResidue1Power3(&Q1.Y) // Q2 = -π²(Q) - Q2.X = *pr.Ext12.Ext2.MulByNonResidue2Power2(&Q[k].X) - Q2.Y = *pr.Ext12.Ext2.MulByNonResidue2Power3(&Q[k].Y) - Q2.Y = *pr.Ext12.Ext2.Neg(&Q2.Y) + Q2.X = *pr.Ext2.MulByNonResidue2Power2(&Q[k].X) + Q2.Y = *pr.Ext2.MulByNonResidue2Power3(&Q[k].Y) + Q2.Y = *pr.Ext2.Neg(&Q2.Y) // Qacc[k] ← Qacc[k]+π(Q) and // l1 the line passing Qacc[k] and π(Q) From c2bb3627d8e85c1481cb6bd097ad6a9f250446aa Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Sat, 8 Apr 2023 01:15:16 +0200 Subject: [PATCH 241/464] feat(sw_emulated): AddSafe for input points equal or not --- std/algebra/emulated/sw_emulated/point.go | 40 +++++++++++- .../emulated/sw_emulated/point_test.go | 12 ++-- std/evmprecompiles/06-bnadd.go | 3 +- std/math/emulated/field_ops.go | 19 ++++++ std/math/emulated/hints.go | 61 +++++++++++++++++++ 5 files changed, 128 insertions(+), 7 deletions(-) diff --git a/std/algebra/emulated/sw_emulated/point.go b/std/algebra/emulated/sw_emulated/point.go index 414b011de2..8fd1725a0d 100644 --- a/std/algebra/emulated/sw_emulated/point.go +++ b/std/algebra/emulated/sw_emulated/point.go @@ -96,13 +96,49 @@ func (c *Curve[B, S]) AssertIsEqual(p, q *AffinePoint[B]) { } // Add adds p and q and returns it. It doesn't modify p nor q. +// +// ⚠️ p must be different than q and both nonzero. +// // It uses incomplete formulas in affine coordinates. -// The points p and q should be different and nonzero (neutral element). func (c *Curve[B, S]) Add(p, q *AffinePoint[B]) *AffinePoint[B] { + return c.add(p, q, false) +} + +// AddSafe adds p and q and returns it. It doesn't modify p nor q. +// +// ✅ p can be equal to q, but none nonzero. +// +// It uses incomplete formulas in affine coordinates. +func (c *Curve[B, S]) AddSafe(p, q *AffinePoint[B]) *AffinePoint[B] { + return c.add(p, q, true) +} + +// add adds p and q and returns it. It doesn't modify p nor q. +// It uses incomplete formulas in affine coordinates. +func (c *Curve[B, S]) add(p, q *AffinePoint[B], safe bool) *AffinePoint[B] { + // compute λ = (q.y-p.y)/(q.x-p.x) qypy := c.baseApi.Sub(&q.Y, &p.Y) qxpx := c.baseApi.Sub(&q.X, &p.X) - λ := c.baseApi.Div(qypy, qxpx) + + // if qxpx == 0, set λ to 0 + λ := c.baseApi.DivSpecial(qypy, qxpx) + + if safe { + // compute _λ = (3p.x²+a)/2*p.y + xx3a := c.baseApi.MulMod(&p.X, &p.X) + xx3a = c.baseApi.MulConst(xx3a, big.NewInt(3)) + if c.addA { + xx3a = c.baseApi.Add(xx3a, &c.a) + } + y2 := c.baseApi.MulConst(&p.Y, big.NewInt(2)) + _λ := c.baseApi.Div(xx3a, y2) + + selector := c.api.And( + c.baseApi.IsZero(qxpx), c.baseApi.IsZero(qypy), + ) + λ = c.baseApi.Select(selector, _λ, λ) + } // xr = λ²-p.x-q.x λλ := c.baseApi.MulMod(λ, λ) diff --git a/std/algebra/emulated/sw_emulated/point_test.go b/std/algebra/emulated/sw_emulated/point_test.go index 6703970c1a..6915274989 100644 --- a/std/algebra/emulated/sw_emulated/point_test.go +++ b/std/algebra/emulated/sw_emulated/point_test.go @@ -61,8 +61,10 @@ func (c *AddTest[T, S]) Define(api frontend.API) error { if err != nil { return err } - res := cr.Add(&c.P, &c.Q) - cr.AssertIsEqual(res, &c.R) + res1 := cr.Add(&c.P, &c.Q) + res2 := cr.AddSafe(&c.P, &c.Q) + cr.AssertIsEqual(res1, &c.R) + cr.AssertIsEqual(res2, &c.R) return nil } @@ -104,8 +106,10 @@ func (c *DoubleTest[T, S]) Define(api frontend.API) error { if err != nil { return err } - res := cr.Double(&c.P) - cr.AssertIsEqual(res, &c.Q) + res1 := cr.Double(&c.P) + res2 := cr.AddSafe(&c.P, &c.P) + cr.AssertIsEqual(res1, &c.Q) + cr.AssertIsEqual(res2, &c.Q) return nil } diff --git a/std/evmprecompiles/06-bnadd.go b/std/evmprecompiles/06-bnadd.go index d9eb8b32dd..fc23f5867f 100644 --- a/std/evmprecompiles/06-bnadd.go +++ b/std/evmprecompiles/06-bnadd.go @@ -14,6 +14,7 @@ func ECAdd(api frontend.API, P, Q *sw_emulated.AffinePoint[emulated.BN254Fp]) *s if err != nil { panic(err) } - res := curve.Add(P, Q) + // We use AddSafe because P can be equal to Q + res := curve.AddSafe(P, Q) return res } diff --git a/std/math/emulated/field_ops.go b/std/math/emulated/field_ops.go index 31739cf716..22924cbd66 100644 --- a/std/math/emulated/field_ops.go +++ b/std/math/emulated/field_ops.go @@ -9,6 +9,25 @@ import ( "github.com/consensys/gnark/frontend" ) +// DivSpecial computes a/b and returns it. It uses [DivHint] as a hint function. +// if b == 0, return 0 +func (f *Field[T]) DivSpecial(a, b *Element[T]) *Element[T] { + // omit width assertion as for a is done in AssertIsEqual and for b is done in Mul below + if !f.fParams.IsPrime() { + // TODO shouldn't we still try to do a classic int div in a hint, constraint the result, and let it fail? + // that would enable things like uint32 div ? + panic("modulus not a prime") + } + div, err := f.computeSpecialDivisionHint(a.Limbs, b.Limbs) + if err != nil { + panic(fmt.Sprintf("compute division: %v", err)) + } + e := f.packLimbs(div, true) + res := f.Mul(e, b) + f.AssertIsEqual(res, a) + return e +} + // Div computes a/b and returns it. It uses [DivHint] as a hint function. func (f *Field[T]) Div(a, b *Element[T]) *Element[T] { // omit width assertion as for a is done in AssertIsEqual and for b is done in Mul below diff --git a/std/math/emulated/hints.go b/std/math/emulated/hints.go index 00ecd2d8f6..26731099b8 100644 --- a/std/math/emulated/hints.go +++ b/std/math/emulated/hints.go @@ -19,6 +19,7 @@ func init() { func GetHints() []solver.Hint { return []solver.Hint{ DivHint, + DivSpecialHint, QuoHint, InverseHint, MultiplicationHint, @@ -202,6 +203,22 @@ func InverseHint(mod *big.Int, inputs []*big.Int, outputs []*big.Int) error { return nil } +// computeSpecialDivisionHint packs the inputs for DivisionHint hint function. +func (f *Field[T]) computeSpecialDivisionHint(nomLimbs, denomLimbs []frontend.Variable) (divLimbs []frontend.Variable, err error) { + var fp T + hintInputs := []frontend.Variable{ + fp.BitsPerLimb(), + fp.NbLimbs(), + len(denomLimbs), + len(nomLimbs), + } + p := f.Modulus() + hintInputs = append(hintInputs, p.Limbs...) + hintInputs = append(hintInputs, nomLimbs...) + hintInputs = append(hintInputs, denomLimbs...) + return f.api.NewHint(DivSpecialHint, int(fp.NbLimbs()), hintInputs...) +} + // computeDivisionHint packs the inputs for DivisionHint hint function. func (f *Field[T]) computeDivisionHint(nomLimbs, denomLimbs []frontend.Variable) (divLimbs []frontend.Variable, err error) { var fp T @@ -218,6 +235,50 @@ func (f *Field[T]) computeDivisionHint(nomLimbs, denomLimbs []frontend.Variable) return f.api.NewHint(DivHint, int(fp.NbLimbs()), hintInputs...) } +// DivSpecialHint computes the value z = x/y for inputs x and y and stores z in +// outputs. +// If y == 0, return z=0 +func DivSpecialHint(mod *big.Int, inputs []*big.Int, outputs []*big.Int) error { + if len(inputs) < 3 { + return fmt.Errorf("input must be at least three elements") + } + nbBits := uint(inputs[0].Uint64()) + nbLimbs := int(inputs[1].Int64()) + nbDenomLimbs := int(inputs[2].Int64()) + // nominator does not have to be reduced and can be more than nbLimbs. + // Denominator and order have to be nbLimbs long. + nbNomLimbs := int(inputs[3].Int64()) + if len(inputs[4:]) != nbLimbs+nbNomLimbs+nbDenomLimbs { + return fmt.Errorf("input length mismatch") + } + if len(outputs) != nbLimbs { + return fmt.Errorf("result does not fit into output") + } + p := new(big.Int) + if err := recompose(inputs[4:4+nbLimbs], nbBits, p); err != nil { + return fmt.Errorf("recompose emulated order: %w", err) + } + nominator := new(big.Int) + if err := recompose(inputs[4+nbLimbs:4+nbLimbs+nbNomLimbs], nbBits, nominator); err != nil { + return fmt.Errorf("recompose nominator: %w", err) + } + denominator := new(big.Int) + if err := recompose(inputs[4+nbLimbs+nbNomLimbs:], nbBits, denominator); err != nil { + return fmt.Errorf("recompose denominator: %w", err) + } + res := new(big.Int).ModInverse(denominator, p) + if res == nil { + // if denominator == 0, set res to 0 + res = new(big.Int) + } + res.Mul(res, nominator) + res.Mod(res, p) + if err := decompose(res, nbBits, outputs); err != nil { + return fmt.Errorf("decompose division: %w", err) + } + return nil +} + // DivHint computes the value z = x/y for inputs x and y and stores z in // outputs. func DivHint(mod *big.Int, inputs []*big.Int, outputs []*big.Int) error { From d8d669db75e072e17200be8b15f52ecf8c784f05 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Sat, 8 Apr 2023 18:39:47 -0500 Subject: [PATCH 242/464] refactor: use separated kzg pk, vk --- backend/plonk/bls12-377/marshal.go | 20 +++---- backend/plonk/bls12-377/prove.go | 30 +++++----- backend/plonk/bls12-377/setup.go | 60 ++++++------------- backend/plonk/bls12-377/verify.go | 2 +- backend/plonk/bls12-381/marshal.go | 20 +++---- backend/plonk/bls12-381/prove.go | 30 +++++----- backend/plonk/bls12-381/setup.go | 60 ++++++------------- backend/plonk/bls12-381/verify.go | 2 +- backend/plonk/bls24-315/marshal.go | 20 +++---- backend/plonk/bls24-315/prove.go | 30 +++++----- backend/plonk/bls24-315/setup.go | 60 ++++++------------- backend/plonk/bls24-315/verify.go | 2 +- backend/plonk/bls24-317/marshal.go | 20 +++---- backend/plonk/bls24-317/prove.go | 30 +++++----- backend/plonk/bls24-317/setup.go | 60 ++++++------------- backend/plonk/bls24-317/verify.go | 2 +- backend/plonk/bn254/marshal.go | 20 +++---- backend/plonk/bn254/prove.go | 30 +++++----- backend/plonk/bn254/setup.go | 60 ++++++------------- backend/plonk/bn254/verify.go | 2 +- backend/plonk/bw6-633/marshal.go | 20 +++---- backend/plonk/bw6-633/prove.go | 30 +++++----- backend/plonk/bw6-633/setup.go | 60 ++++++------------- backend/plonk/bw6-633/verify.go | 2 +- backend/plonk/bw6-761/marshal.go | 20 +++---- backend/plonk/bw6-761/prove.go | 30 +++++----- backend/plonk/bw6-761/setup.go | 60 ++++++------------- backend/plonk/bw6-761/verify.go | 2 +- backend/plonk/plonk.go | 18 +++--- go.mod | 2 +- go.sum | 4 +- .../zkpschemes/plonk/plonk.marshal.go.tmpl | 20 +++---- .../zkpschemes/plonk/plonk.prove.go.tmpl | 30 +++++----- .../zkpschemes/plonk/plonk.setup.go.tmpl | 59 ++++++------------ .../zkpschemes/plonk/plonk.verify.go.tmpl | 2 +- std/commitments/kzg_bls24315/verifier_test.go | 40 ++++++------- test/kzg_srs.go | 1 - 37 files changed, 391 insertions(+), 569 deletions(-) diff --git a/backend/plonk/bls12-377/marshal.go b/backend/plonk/bls12-377/marshal.go index 7446ed3377..658a4d38f3 100644 --- a/backend/plonk/bls12-377/marshal.go +++ b/backend/plonk/bls12-377/marshal.go @@ -120,16 +120,16 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { // encode the size (nor does it convert from Montgomery to Regular form) // so we explicitly transmit []fr.Element toEncode := []interface{}{ - ([]fr.Element)(pk.trace.Ql.Coefficients()), - ([]fr.Element)(pk.trace.Qr.Coefficients()), - ([]fr.Element)(pk.trace.Qm.Coefficients()), - ([]fr.Element)(pk.trace.Qo.Coefficients()), - ([]fr.Element)(pk.trace.Qk.Coefficients()), - ([]fr.Element)(pk.trace.Qcp.Coefficients()), - ([]fr.Element)(pk.lQk.Coefficients()), - ([]fr.Element)(pk.trace.S1.Coefficients()), - ([]fr.Element)(pk.trace.S2.Coefficients()), - ([]fr.Element)(pk.trace.S3.Coefficients()), + pk.trace.Ql.Coefficients(), + pk.trace.Qr.Coefficients(), + pk.trace.Qm.Coefficients(), + pk.trace.Qo.Coefficients(), + pk.trace.Qk.Coefficients(), + pk.trace.Qcp.Coefficients(), + pk.lQk.Coefficients(), + pk.trace.S1.Coefficients(), + pk.trace.S2.Coefficients(), + pk.trace.S3.Coefficients(), pk.trace.S, } diff --git a/backend/plonk/bls12-377/prove.go b/backend/plonk/bls12-377/prove.go index f07386a923..1e912a70a3 100644 --- a/backend/plonk/bls12-377/prove.go +++ b/backend/plonk/bls12-377/prove.go @@ -107,7 +107,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pi2iop := iop.NewPolynomial(&pi2, lagReg) wpi2iop = pi2iop.ShallowClone() wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() - if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Vk.KZGSRS); err != nil { + if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Kzg); err != nil { return err } if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { @@ -209,7 +209,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // wait for polys to be blinded wgLRO.Wait() - if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Vk.KZGSRS); err != nil { + if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Kzg); err != nil { return nil, err } @@ -266,7 +266,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts go func() { bwziop = ziop // iop.NewWrappedPolynomial(&ziop) bwziop.Blind(2) - proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Vk.KZGSRS, runtime.NumCPU()*2) + proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Kzg, runtime.NumCPU()*2) if err != nil { chZ <- err } @@ -393,7 +393,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts h.Coefficients()[:pk.Domain[0].Cardinality+2], h.Coefficients()[pk.Domain[0].Cardinality+2:2*(pk.Domain[0].Cardinality+2)], h.Coefficients()[2*(pk.Domain[0].Cardinality+2):3*(pk.Domain[0].Cardinality+2)], - proof, pk.Vk.KZGSRS); err != nil { + proof, pk.Kzg); err != nil { return nil, err } @@ -427,7 +427,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.ZShiftedOpening, err = kzg.Open( bwziop.Coefficients()[:bwziop.BlindedSize()], zetaShifted, - pk.Vk.KZGSRS, + pk.Kzg, ) if err != nil { return nil, err @@ -496,7 +496,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // TODO this commitment is only necessary to derive the challenge, we should // be able to avoid doing it and get the challenge in another way - linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Vk.KZGSRS, runtime.NumCPU()*2) + linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Kzg, runtime.NumCPU()*2) if errLPoly != nil { return nil, errLPoly } @@ -528,7 +528,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts }, zeta, hFunc, - pk.Vk.KZGSRS, + pk.Kzg, ) log.Debug().Dur("took", time.Since(start)).Msg("prover done") @@ -542,20 +542,20 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // fills proof.LRO with kzg commits of bcl, bcr and bco -func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { +func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, kzgPk kzg.ProvingKey) error { n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) go func() { - proof.LRO[0], err0 = kzg.Commit(bcl, srs, n) + proof.LRO[0], err0 = kzg.Commit(bcl, kzgPk, n) close(chCommit0) }() go func() { - proof.LRO[1], err1 = kzg.Commit(bcr, srs, n) + proof.LRO[1], err1 = kzg.Commit(bcr, kzgPk, n) close(chCommit1) }() - if proof.LRO[2], err2 = kzg.Commit(bco, srs, n); err2 != nil { + if proof.LRO[2], err2 = kzg.Commit(bco, kzgPk, n); err2 != nil { return err2 } <-chCommit0 @@ -568,20 +568,20 @@ func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { return err1 } -func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error { +func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, kzgPk kzg.ProvingKey) error { n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) go func() { - proof.H[0], err0 = kzg.Commit(h1, srs, n) + proof.H[0], err0 = kzg.Commit(h1, kzgPk, n) close(chCommit0) }() go func() { - proof.H[1], err1 = kzg.Commit(h2, srs, n) + proof.H[1], err1 = kzg.Commit(h2, kzgPk, n) close(chCommit1) }() - if proof.H[2], err2 = kzg.Commit(h3, srs, n); err2 != nil { + if proof.H[2], err2 = kzg.Commit(h3, kzgPk, n); err2 != nil { return err2 } <-chCommit0 diff --git a/backend/plonk/bls12-377/setup.go b/backend/plonk/bls12-377/setup.go index 5b84129c1b..1ec3889ec2 100644 --- a/backend/plonk/bls12-377/setup.go +++ b/backend/plonk/bls12-377/setup.go @@ -25,8 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/kzg" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls12-377" - - kzgg "github.com/consensys/gnark-crypto/kzg" + //kzgg "github.com/consensys/gnark-crypto/kzg" TODO Figure out why this is useful ) // Trace stores a plonk trace as columns @@ -64,7 +63,7 @@ type VerifyingKey struct { NbPublicVariables uint64 // Commitment scheme that is used for an instantiation of PLONK - KZGSRS *kzg.SRS + Kzg kzg.VerifyingKey // cosetShift generator of the coset on the small domain CosetShift fr.Element @@ -96,6 +95,8 @@ type ProvingKey struct { // The polynomials in trace are in canonical basis. trace Trace + Kzg kzg.ProvingKey + // Verifying Key is embedded into the proving key (needed by Prove) Vk *VerifyingKey @@ -117,7 +118,7 @@ type ProvingKey struct { lcIdIOP, lLoneIOP *iop.Polynomial } -func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) { +func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, error) { var pk ProvingKey var vk VerifyingKey @@ -134,9 +135,11 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) vk.SizeInv.SetUint64(vk.Size).Inverse(&vk.SizeInv) vk.Generator.Set(&pk.Domain[0].Generator) vk.NbPublicVariables = uint64(len(spr.Public)) - if err := pk.InitKZG(srs); err != nil { - return nil, nil, err + if len(kzgSrs.Pk.G1) < int(vk.Size) { + return nil, nil, errors.New("kzg srs is too small") } + pk.Kzg = kzgSrs.Pk + vk.Kzg = kzgSrs.Vk // step 2: ql, qr, qm, qo, qk, qcp in Lagrange Basis BuildTrace(spr, &pk.trace) @@ -211,32 +214,7 @@ func (pk *ProvingKey) VerifyingKey() interface{} { return pk.Vk } -// InitKZG inits pk.Vk.KZG using pk.Domain[0] cardinality and provided SRS -// -// This should be used after deserializing a ProvingKey -// as pk.Vk.KZG is NOT serialized -func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { - return pk.Vk.InitKZG(srs) -} - -// InitKZG inits vk.KZG using provided SRS -// -// This should be used after deserializing a VerifyingKey -// as vk.KZG is NOT serialized -// -// Note that this instantiates a new FFT domain using vk.Size -func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { - _srs := srs.(*kzg.SRS) - - if len(_srs.G1) < int(vk.Size) { - return errors.New("kzg srs is too small") - } - vk.KZGSRS = _srs - - return nil -} - -// BuildTrace fills the constatn columns ql, qr, qm, qo, qk from the sparser1cs. +// BuildTrace fills the constant columns ql, qr, qm, qo, qk from the sparser1cs. // Size is the size of the system that is nb_constraints+nb_public_variables func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { @@ -298,31 +276,31 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() var err error - if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qr, err = kzg.Commit(pk.trace.Qr.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qr, err = kzg.Commit(pk.trace.Qr.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qm, err = kzg.Commit(pk.trace.Qm.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qm, err = kzg.Commit(pk.trace.Qm.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qo, err = kzg.Commit(pk.trace.Qo.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qo, err = kzg.Commit(pk.trace.Qo.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.S[1], err = kzg.Commit(pk.trace.S2.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.S[1], err = kzg.Commit(pk.trace.S2.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.S[2], err = kzg.Commit(pk.trace.S3.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.S[2], err = kzg.Commit(pk.trace.S3.Coefficients(), pk.Kzg); err != nil { return err } return nil diff --git a/backend/plonk/bls12-377/verify.go b/backend/plonk/bls12-377/verify.go index 65c7881cf6..2469dba207 100644 --- a/backend/plonk/bls12-377/verify.go +++ b/backend/plonk/bls12-377/verify.go @@ -260,7 +260,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zeta, shiftedZeta, }, - vk.KZGSRS, + vk.Kzg, ) log.Debug().Dur("took", time.Since(start)).Msg("verifier done") diff --git a/backend/plonk/bls12-381/marshal.go b/backend/plonk/bls12-381/marshal.go index d2a7af9e91..fa5155e955 100644 --- a/backend/plonk/bls12-381/marshal.go +++ b/backend/plonk/bls12-381/marshal.go @@ -120,16 +120,16 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { // encode the size (nor does it convert from Montgomery to Regular form) // so we explicitly transmit []fr.Element toEncode := []interface{}{ - ([]fr.Element)(pk.trace.Ql.Coefficients()), - ([]fr.Element)(pk.trace.Qr.Coefficients()), - ([]fr.Element)(pk.trace.Qm.Coefficients()), - ([]fr.Element)(pk.trace.Qo.Coefficients()), - ([]fr.Element)(pk.trace.Qk.Coefficients()), - ([]fr.Element)(pk.trace.Qcp.Coefficients()), - ([]fr.Element)(pk.lQk.Coefficients()), - ([]fr.Element)(pk.trace.S1.Coefficients()), - ([]fr.Element)(pk.trace.S2.Coefficients()), - ([]fr.Element)(pk.trace.S3.Coefficients()), + pk.trace.Ql.Coefficients(), + pk.trace.Qr.Coefficients(), + pk.trace.Qm.Coefficients(), + pk.trace.Qo.Coefficients(), + pk.trace.Qk.Coefficients(), + pk.trace.Qcp.Coefficients(), + pk.lQk.Coefficients(), + pk.trace.S1.Coefficients(), + pk.trace.S2.Coefficients(), + pk.trace.S3.Coefficients(), pk.trace.S, } diff --git a/backend/plonk/bls12-381/prove.go b/backend/plonk/bls12-381/prove.go index 61ab610fb2..c4515421dc 100644 --- a/backend/plonk/bls12-381/prove.go +++ b/backend/plonk/bls12-381/prove.go @@ -107,7 +107,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pi2iop := iop.NewPolynomial(&pi2, lagReg) wpi2iop = pi2iop.ShallowClone() wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() - if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Vk.KZGSRS); err != nil { + if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Kzg); err != nil { return err } if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { @@ -209,7 +209,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // wait for polys to be blinded wgLRO.Wait() - if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Vk.KZGSRS); err != nil { + if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Kzg); err != nil { return nil, err } @@ -266,7 +266,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts go func() { bwziop = ziop // iop.NewWrappedPolynomial(&ziop) bwziop.Blind(2) - proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Vk.KZGSRS, runtime.NumCPU()*2) + proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Kzg, runtime.NumCPU()*2) if err != nil { chZ <- err } @@ -393,7 +393,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts h.Coefficients()[:pk.Domain[0].Cardinality+2], h.Coefficients()[pk.Domain[0].Cardinality+2:2*(pk.Domain[0].Cardinality+2)], h.Coefficients()[2*(pk.Domain[0].Cardinality+2):3*(pk.Domain[0].Cardinality+2)], - proof, pk.Vk.KZGSRS); err != nil { + proof, pk.Kzg); err != nil { return nil, err } @@ -427,7 +427,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.ZShiftedOpening, err = kzg.Open( bwziop.Coefficients()[:bwziop.BlindedSize()], zetaShifted, - pk.Vk.KZGSRS, + pk.Kzg, ) if err != nil { return nil, err @@ -496,7 +496,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // TODO this commitment is only necessary to derive the challenge, we should // be able to avoid doing it and get the challenge in another way - linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Vk.KZGSRS, runtime.NumCPU()*2) + linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Kzg, runtime.NumCPU()*2) if errLPoly != nil { return nil, errLPoly } @@ -528,7 +528,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts }, zeta, hFunc, - pk.Vk.KZGSRS, + pk.Kzg, ) log.Debug().Dur("took", time.Since(start)).Msg("prover done") @@ -542,20 +542,20 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // fills proof.LRO with kzg commits of bcl, bcr and bco -func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { +func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, kzgPk kzg.ProvingKey) error { n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) go func() { - proof.LRO[0], err0 = kzg.Commit(bcl, srs, n) + proof.LRO[0], err0 = kzg.Commit(bcl, kzgPk, n) close(chCommit0) }() go func() { - proof.LRO[1], err1 = kzg.Commit(bcr, srs, n) + proof.LRO[1], err1 = kzg.Commit(bcr, kzgPk, n) close(chCommit1) }() - if proof.LRO[2], err2 = kzg.Commit(bco, srs, n); err2 != nil { + if proof.LRO[2], err2 = kzg.Commit(bco, kzgPk, n); err2 != nil { return err2 } <-chCommit0 @@ -568,20 +568,20 @@ func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { return err1 } -func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error { +func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, kzgPk kzg.ProvingKey) error { n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) go func() { - proof.H[0], err0 = kzg.Commit(h1, srs, n) + proof.H[0], err0 = kzg.Commit(h1, kzgPk, n) close(chCommit0) }() go func() { - proof.H[1], err1 = kzg.Commit(h2, srs, n) + proof.H[1], err1 = kzg.Commit(h2, kzgPk, n) close(chCommit1) }() - if proof.H[2], err2 = kzg.Commit(h3, srs, n); err2 != nil { + if proof.H[2], err2 = kzg.Commit(h3, kzgPk, n); err2 != nil { return err2 } <-chCommit0 diff --git a/backend/plonk/bls12-381/setup.go b/backend/plonk/bls12-381/setup.go index 229b43b649..0941233c1d 100644 --- a/backend/plonk/bls12-381/setup.go +++ b/backend/plonk/bls12-381/setup.go @@ -25,8 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/kzg" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls12-381" - - kzgg "github.com/consensys/gnark-crypto/kzg" + //kzgg "github.com/consensys/gnark-crypto/kzg" TODO Figure out why this is useful ) // Trace stores a plonk trace as columns @@ -64,7 +63,7 @@ type VerifyingKey struct { NbPublicVariables uint64 // Commitment scheme that is used for an instantiation of PLONK - KZGSRS *kzg.SRS + Kzg kzg.VerifyingKey // cosetShift generator of the coset on the small domain CosetShift fr.Element @@ -96,6 +95,8 @@ type ProvingKey struct { // The polynomials in trace are in canonical basis. trace Trace + Kzg kzg.ProvingKey + // Verifying Key is embedded into the proving key (needed by Prove) Vk *VerifyingKey @@ -117,7 +118,7 @@ type ProvingKey struct { lcIdIOP, lLoneIOP *iop.Polynomial } -func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) { +func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, error) { var pk ProvingKey var vk VerifyingKey @@ -134,9 +135,11 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) vk.SizeInv.SetUint64(vk.Size).Inverse(&vk.SizeInv) vk.Generator.Set(&pk.Domain[0].Generator) vk.NbPublicVariables = uint64(len(spr.Public)) - if err := pk.InitKZG(srs); err != nil { - return nil, nil, err + if len(kzgSrs.Pk.G1) < int(vk.Size) { + return nil, nil, errors.New("kzg srs is too small") } + pk.Kzg = kzgSrs.Pk + vk.Kzg = kzgSrs.Vk // step 2: ql, qr, qm, qo, qk, qcp in Lagrange Basis BuildTrace(spr, &pk.trace) @@ -211,32 +214,7 @@ func (pk *ProvingKey) VerifyingKey() interface{} { return pk.Vk } -// InitKZG inits pk.Vk.KZG using pk.Domain[0] cardinality and provided SRS -// -// This should be used after deserializing a ProvingKey -// as pk.Vk.KZG is NOT serialized -func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { - return pk.Vk.InitKZG(srs) -} - -// InitKZG inits vk.KZG using provided SRS -// -// This should be used after deserializing a VerifyingKey -// as vk.KZG is NOT serialized -// -// Note that this instantiates a new FFT domain using vk.Size -func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { - _srs := srs.(*kzg.SRS) - - if len(_srs.G1) < int(vk.Size) { - return errors.New("kzg srs is too small") - } - vk.KZGSRS = _srs - - return nil -} - -// BuildTrace fills the constatn columns ql, qr, qm, qo, qk from the sparser1cs. +// BuildTrace fills the constant columns ql, qr, qm, qo, qk from the sparser1cs. // Size is the size of the system that is nb_constraints+nb_public_variables func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { @@ -298,31 +276,31 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() var err error - if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qr, err = kzg.Commit(pk.trace.Qr.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qr, err = kzg.Commit(pk.trace.Qr.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qm, err = kzg.Commit(pk.trace.Qm.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qm, err = kzg.Commit(pk.trace.Qm.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qo, err = kzg.Commit(pk.trace.Qo.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qo, err = kzg.Commit(pk.trace.Qo.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.S[1], err = kzg.Commit(pk.trace.S2.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.S[1], err = kzg.Commit(pk.trace.S2.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.S[2], err = kzg.Commit(pk.trace.S3.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.S[2], err = kzg.Commit(pk.trace.S3.Coefficients(), pk.Kzg); err != nil { return err } return nil diff --git a/backend/plonk/bls12-381/verify.go b/backend/plonk/bls12-381/verify.go index 92d6451ab9..8b09849b14 100644 --- a/backend/plonk/bls12-381/verify.go +++ b/backend/plonk/bls12-381/verify.go @@ -260,7 +260,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zeta, shiftedZeta, }, - vk.KZGSRS, + vk.Kzg, ) log.Debug().Dur("took", time.Since(start)).Msg("verifier done") diff --git a/backend/plonk/bls24-315/marshal.go b/backend/plonk/bls24-315/marshal.go index bc9333bc74..f7d6f74c45 100644 --- a/backend/plonk/bls24-315/marshal.go +++ b/backend/plonk/bls24-315/marshal.go @@ -120,16 +120,16 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { // encode the size (nor does it convert from Montgomery to Regular form) // so we explicitly transmit []fr.Element toEncode := []interface{}{ - ([]fr.Element)(pk.trace.Ql.Coefficients()), - ([]fr.Element)(pk.trace.Qr.Coefficients()), - ([]fr.Element)(pk.trace.Qm.Coefficients()), - ([]fr.Element)(pk.trace.Qo.Coefficients()), - ([]fr.Element)(pk.trace.Qk.Coefficients()), - ([]fr.Element)(pk.trace.Qcp.Coefficients()), - ([]fr.Element)(pk.lQk.Coefficients()), - ([]fr.Element)(pk.trace.S1.Coefficients()), - ([]fr.Element)(pk.trace.S2.Coefficients()), - ([]fr.Element)(pk.trace.S3.Coefficients()), + pk.trace.Ql.Coefficients(), + pk.trace.Qr.Coefficients(), + pk.trace.Qm.Coefficients(), + pk.trace.Qo.Coefficients(), + pk.trace.Qk.Coefficients(), + pk.trace.Qcp.Coefficients(), + pk.lQk.Coefficients(), + pk.trace.S1.Coefficients(), + pk.trace.S2.Coefficients(), + pk.trace.S3.Coefficients(), pk.trace.S, } diff --git a/backend/plonk/bls24-315/prove.go b/backend/plonk/bls24-315/prove.go index 97d1f0f22b..5a330eabf1 100644 --- a/backend/plonk/bls24-315/prove.go +++ b/backend/plonk/bls24-315/prove.go @@ -107,7 +107,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pi2iop := iop.NewPolynomial(&pi2, lagReg) wpi2iop = pi2iop.ShallowClone() wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() - if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Vk.KZGSRS); err != nil { + if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Kzg); err != nil { return err } if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { @@ -209,7 +209,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // wait for polys to be blinded wgLRO.Wait() - if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Vk.KZGSRS); err != nil { + if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Kzg); err != nil { return nil, err } @@ -266,7 +266,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts go func() { bwziop = ziop // iop.NewWrappedPolynomial(&ziop) bwziop.Blind(2) - proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Vk.KZGSRS, runtime.NumCPU()*2) + proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Kzg, runtime.NumCPU()*2) if err != nil { chZ <- err } @@ -393,7 +393,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts h.Coefficients()[:pk.Domain[0].Cardinality+2], h.Coefficients()[pk.Domain[0].Cardinality+2:2*(pk.Domain[0].Cardinality+2)], h.Coefficients()[2*(pk.Domain[0].Cardinality+2):3*(pk.Domain[0].Cardinality+2)], - proof, pk.Vk.KZGSRS); err != nil { + proof, pk.Kzg); err != nil { return nil, err } @@ -427,7 +427,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.ZShiftedOpening, err = kzg.Open( bwziop.Coefficients()[:bwziop.BlindedSize()], zetaShifted, - pk.Vk.KZGSRS, + pk.Kzg, ) if err != nil { return nil, err @@ -496,7 +496,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // TODO this commitment is only necessary to derive the challenge, we should // be able to avoid doing it and get the challenge in another way - linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Vk.KZGSRS, runtime.NumCPU()*2) + linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Kzg, runtime.NumCPU()*2) if errLPoly != nil { return nil, errLPoly } @@ -528,7 +528,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts }, zeta, hFunc, - pk.Vk.KZGSRS, + pk.Kzg, ) log.Debug().Dur("took", time.Since(start)).Msg("prover done") @@ -542,20 +542,20 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // fills proof.LRO with kzg commits of bcl, bcr and bco -func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { +func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, kzgPk kzg.ProvingKey) error { n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) go func() { - proof.LRO[0], err0 = kzg.Commit(bcl, srs, n) + proof.LRO[0], err0 = kzg.Commit(bcl, kzgPk, n) close(chCommit0) }() go func() { - proof.LRO[1], err1 = kzg.Commit(bcr, srs, n) + proof.LRO[1], err1 = kzg.Commit(bcr, kzgPk, n) close(chCommit1) }() - if proof.LRO[2], err2 = kzg.Commit(bco, srs, n); err2 != nil { + if proof.LRO[2], err2 = kzg.Commit(bco, kzgPk, n); err2 != nil { return err2 } <-chCommit0 @@ -568,20 +568,20 @@ func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { return err1 } -func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error { +func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, kzgPk kzg.ProvingKey) error { n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) go func() { - proof.H[0], err0 = kzg.Commit(h1, srs, n) + proof.H[0], err0 = kzg.Commit(h1, kzgPk, n) close(chCommit0) }() go func() { - proof.H[1], err1 = kzg.Commit(h2, srs, n) + proof.H[1], err1 = kzg.Commit(h2, kzgPk, n) close(chCommit1) }() - if proof.H[2], err2 = kzg.Commit(h3, srs, n); err2 != nil { + if proof.H[2], err2 = kzg.Commit(h3, kzgPk, n); err2 != nil { return err2 } <-chCommit0 diff --git a/backend/plonk/bls24-315/setup.go b/backend/plonk/bls24-315/setup.go index 0de7425e02..ad1e7d9970 100644 --- a/backend/plonk/bls24-315/setup.go +++ b/backend/plonk/bls24-315/setup.go @@ -25,8 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/kzg" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls24-315" - - kzgg "github.com/consensys/gnark-crypto/kzg" + //kzgg "github.com/consensys/gnark-crypto/kzg" TODO Figure out why this is useful ) // Trace stores a plonk trace as columns @@ -64,7 +63,7 @@ type VerifyingKey struct { NbPublicVariables uint64 // Commitment scheme that is used for an instantiation of PLONK - KZGSRS *kzg.SRS + Kzg kzg.VerifyingKey // cosetShift generator of the coset on the small domain CosetShift fr.Element @@ -96,6 +95,8 @@ type ProvingKey struct { // The polynomials in trace are in canonical basis. trace Trace + Kzg kzg.ProvingKey + // Verifying Key is embedded into the proving key (needed by Prove) Vk *VerifyingKey @@ -117,7 +118,7 @@ type ProvingKey struct { lcIdIOP, lLoneIOP *iop.Polynomial } -func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) { +func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, error) { var pk ProvingKey var vk VerifyingKey @@ -134,9 +135,11 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) vk.SizeInv.SetUint64(vk.Size).Inverse(&vk.SizeInv) vk.Generator.Set(&pk.Domain[0].Generator) vk.NbPublicVariables = uint64(len(spr.Public)) - if err := pk.InitKZG(srs); err != nil { - return nil, nil, err + if len(kzgSrs.Pk.G1) < int(vk.Size) { + return nil, nil, errors.New("kzg srs is too small") } + pk.Kzg = kzgSrs.Pk + vk.Kzg = kzgSrs.Vk // step 2: ql, qr, qm, qo, qk, qcp in Lagrange Basis BuildTrace(spr, &pk.trace) @@ -211,32 +214,7 @@ func (pk *ProvingKey) VerifyingKey() interface{} { return pk.Vk } -// InitKZG inits pk.Vk.KZG using pk.Domain[0] cardinality and provided SRS -// -// This should be used after deserializing a ProvingKey -// as pk.Vk.KZG is NOT serialized -func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { - return pk.Vk.InitKZG(srs) -} - -// InitKZG inits vk.KZG using provided SRS -// -// This should be used after deserializing a VerifyingKey -// as vk.KZG is NOT serialized -// -// Note that this instantiates a new FFT domain using vk.Size -func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { - _srs := srs.(*kzg.SRS) - - if len(_srs.G1) < int(vk.Size) { - return errors.New("kzg srs is too small") - } - vk.KZGSRS = _srs - - return nil -} - -// BuildTrace fills the constatn columns ql, qr, qm, qo, qk from the sparser1cs. +// BuildTrace fills the constant columns ql, qr, qm, qo, qk from the sparser1cs. // Size is the size of the system that is nb_constraints+nb_public_variables func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { @@ -298,31 +276,31 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() var err error - if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qr, err = kzg.Commit(pk.trace.Qr.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qr, err = kzg.Commit(pk.trace.Qr.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qm, err = kzg.Commit(pk.trace.Qm.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qm, err = kzg.Commit(pk.trace.Qm.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qo, err = kzg.Commit(pk.trace.Qo.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qo, err = kzg.Commit(pk.trace.Qo.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.S[1], err = kzg.Commit(pk.trace.S2.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.S[1], err = kzg.Commit(pk.trace.S2.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.S[2], err = kzg.Commit(pk.trace.S3.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.S[2], err = kzg.Commit(pk.trace.S3.Coefficients(), pk.Kzg); err != nil { return err } return nil diff --git a/backend/plonk/bls24-315/verify.go b/backend/plonk/bls24-315/verify.go index ca0b800e58..86ec2c7520 100644 --- a/backend/plonk/bls24-315/verify.go +++ b/backend/plonk/bls24-315/verify.go @@ -260,7 +260,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zeta, shiftedZeta, }, - vk.KZGSRS, + vk.Kzg, ) log.Debug().Dur("took", time.Since(start)).Msg("verifier done") diff --git a/backend/plonk/bls24-317/marshal.go b/backend/plonk/bls24-317/marshal.go index d7742ca1e5..a9d51f46b3 100644 --- a/backend/plonk/bls24-317/marshal.go +++ b/backend/plonk/bls24-317/marshal.go @@ -120,16 +120,16 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { // encode the size (nor does it convert from Montgomery to Regular form) // so we explicitly transmit []fr.Element toEncode := []interface{}{ - ([]fr.Element)(pk.trace.Ql.Coefficients()), - ([]fr.Element)(pk.trace.Qr.Coefficients()), - ([]fr.Element)(pk.trace.Qm.Coefficients()), - ([]fr.Element)(pk.trace.Qo.Coefficients()), - ([]fr.Element)(pk.trace.Qk.Coefficients()), - ([]fr.Element)(pk.trace.Qcp.Coefficients()), - ([]fr.Element)(pk.lQk.Coefficients()), - ([]fr.Element)(pk.trace.S1.Coefficients()), - ([]fr.Element)(pk.trace.S2.Coefficients()), - ([]fr.Element)(pk.trace.S3.Coefficients()), + pk.trace.Ql.Coefficients(), + pk.trace.Qr.Coefficients(), + pk.trace.Qm.Coefficients(), + pk.trace.Qo.Coefficients(), + pk.trace.Qk.Coefficients(), + pk.trace.Qcp.Coefficients(), + pk.lQk.Coefficients(), + pk.trace.S1.Coefficients(), + pk.trace.S2.Coefficients(), + pk.trace.S3.Coefficients(), pk.trace.S, } diff --git a/backend/plonk/bls24-317/prove.go b/backend/plonk/bls24-317/prove.go index 4964018989..bddd98c8ac 100644 --- a/backend/plonk/bls24-317/prove.go +++ b/backend/plonk/bls24-317/prove.go @@ -107,7 +107,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pi2iop := iop.NewPolynomial(&pi2, lagReg) wpi2iop = pi2iop.ShallowClone() wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() - if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Vk.KZGSRS); err != nil { + if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Kzg); err != nil { return err } if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { @@ -209,7 +209,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // wait for polys to be blinded wgLRO.Wait() - if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Vk.KZGSRS); err != nil { + if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Kzg); err != nil { return nil, err } @@ -266,7 +266,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts go func() { bwziop = ziop // iop.NewWrappedPolynomial(&ziop) bwziop.Blind(2) - proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Vk.KZGSRS, runtime.NumCPU()*2) + proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Kzg, runtime.NumCPU()*2) if err != nil { chZ <- err } @@ -393,7 +393,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts h.Coefficients()[:pk.Domain[0].Cardinality+2], h.Coefficients()[pk.Domain[0].Cardinality+2:2*(pk.Domain[0].Cardinality+2)], h.Coefficients()[2*(pk.Domain[0].Cardinality+2):3*(pk.Domain[0].Cardinality+2)], - proof, pk.Vk.KZGSRS); err != nil { + proof, pk.Kzg); err != nil { return nil, err } @@ -427,7 +427,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.ZShiftedOpening, err = kzg.Open( bwziop.Coefficients()[:bwziop.BlindedSize()], zetaShifted, - pk.Vk.KZGSRS, + pk.Kzg, ) if err != nil { return nil, err @@ -496,7 +496,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // TODO this commitment is only necessary to derive the challenge, we should // be able to avoid doing it and get the challenge in another way - linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Vk.KZGSRS, runtime.NumCPU()*2) + linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Kzg, runtime.NumCPU()*2) if errLPoly != nil { return nil, errLPoly } @@ -528,7 +528,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts }, zeta, hFunc, - pk.Vk.KZGSRS, + pk.Kzg, ) log.Debug().Dur("took", time.Since(start)).Msg("prover done") @@ -542,20 +542,20 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // fills proof.LRO with kzg commits of bcl, bcr and bco -func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { +func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, kzgPk kzg.ProvingKey) error { n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) go func() { - proof.LRO[0], err0 = kzg.Commit(bcl, srs, n) + proof.LRO[0], err0 = kzg.Commit(bcl, kzgPk, n) close(chCommit0) }() go func() { - proof.LRO[1], err1 = kzg.Commit(bcr, srs, n) + proof.LRO[1], err1 = kzg.Commit(bcr, kzgPk, n) close(chCommit1) }() - if proof.LRO[2], err2 = kzg.Commit(bco, srs, n); err2 != nil { + if proof.LRO[2], err2 = kzg.Commit(bco, kzgPk, n); err2 != nil { return err2 } <-chCommit0 @@ -568,20 +568,20 @@ func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { return err1 } -func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error { +func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, kzgPk kzg.ProvingKey) error { n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) go func() { - proof.H[0], err0 = kzg.Commit(h1, srs, n) + proof.H[0], err0 = kzg.Commit(h1, kzgPk, n) close(chCommit0) }() go func() { - proof.H[1], err1 = kzg.Commit(h2, srs, n) + proof.H[1], err1 = kzg.Commit(h2, kzgPk, n) close(chCommit1) }() - if proof.H[2], err2 = kzg.Commit(h3, srs, n); err2 != nil { + if proof.H[2], err2 = kzg.Commit(h3, kzgPk, n); err2 != nil { return err2 } <-chCommit0 diff --git a/backend/plonk/bls24-317/setup.go b/backend/plonk/bls24-317/setup.go index 391b8595b1..4c68571076 100644 --- a/backend/plonk/bls24-317/setup.go +++ b/backend/plonk/bls24-317/setup.go @@ -25,8 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/kzg" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls24-317" - - kzgg "github.com/consensys/gnark-crypto/kzg" + //kzgg "github.com/consensys/gnark-crypto/kzg" TODO Figure out why this is useful ) // Trace stores a plonk trace as columns @@ -64,7 +63,7 @@ type VerifyingKey struct { NbPublicVariables uint64 // Commitment scheme that is used for an instantiation of PLONK - KZGSRS *kzg.SRS + Kzg kzg.VerifyingKey // cosetShift generator of the coset on the small domain CosetShift fr.Element @@ -96,6 +95,8 @@ type ProvingKey struct { // The polynomials in trace are in canonical basis. trace Trace + Kzg kzg.ProvingKey + // Verifying Key is embedded into the proving key (needed by Prove) Vk *VerifyingKey @@ -117,7 +118,7 @@ type ProvingKey struct { lcIdIOP, lLoneIOP *iop.Polynomial } -func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) { +func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, error) { var pk ProvingKey var vk VerifyingKey @@ -134,9 +135,11 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) vk.SizeInv.SetUint64(vk.Size).Inverse(&vk.SizeInv) vk.Generator.Set(&pk.Domain[0].Generator) vk.NbPublicVariables = uint64(len(spr.Public)) - if err := pk.InitKZG(srs); err != nil { - return nil, nil, err + if len(kzgSrs.Pk.G1) < int(vk.Size) { + return nil, nil, errors.New("kzg srs is too small") } + pk.Kzg = kzgSrs.Pk + vk.Kzg = kzgSrs.Vk // step 2: ql, qr, qm, qo, qk, qcp in Lagrange Basis BuildTrace(spr, &pk.trace) @@ -211,32 +214,7 @@ func (pk *ProvingKey) VerifyingKey() interface{} { return pk.Vk } -// InitKZG inits pk.Vk.KZG using pk.Domain[0] cardinality and provided SRS -// -// This should be used after deserializing a ProvingKey -// as pk.Vk.KZG is NOT serialized -func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { - return pk.Vk.InitKZG(srs) -} - -// InitKZG inits vk.KZG using provided SRS -// -// This should be used after deserializing a VerifyingKey -// as vk.KZG is NOT serialized -// -// Note that this instantiates a new FFT domain using vk.Size -func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { - _srs := srs.(*kzg.SRS) - - if len(_srs.G1) < int(vk.Size) { - return errors.New("kzg srs is too small") - } - vk.KZGSRS = _srs - - return nil -} - -// BuildTrace fills the constatn columns ql, qr, qm, qo, qk from the sparser1cs. +// BuildTrace fills the constant columns ql, qr, qm, qo, qk from the sparser1cs. // Size is the size of the system that is nb_constraints+nb_public_variables func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { @@ -298,31 +276,31 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() var err error - if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qr, err = kzg.Commit(pk.trace.Qr.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qr, err = kzg.Commit(pk.trace.Qr.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qm, err = kzg.Commit(pk.trace.Qm.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qm, err = kzg.Commit(pk.trace.Qm.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qo, err = kzg.Commit(pk.trace.Qo.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qo, err = kzg.Commit(pk.trace.Qo.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.S[1], err = kzg.Commit(pk.trace.S2.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.S[1], err = kzg.Commit(pk.trace.S2.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.S[2], err = kzg.Commit(pk.trace.S3.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.S[2], err = kzg.Commit(pk.trace.S3.Coefficients(), pk.Kzg); err != nil { return err } return nil diff --git a/backend/plonk/bls24-317/verify.go b/backend/plonk/bls24-317/verify.go index aecdd94022..5b344c9d7a 100644 --- a/backend/plonk/bls24-317/verify.go +++ b/backend/plonk/bls24-317/verify.go @@ -260,7 +260,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zeta, shiftedZeta, }, - vk.KZGSRS, + vk.Kzg, ) log.Debug().Dur("took", time.Since(start)).Msg("verifier done") diff --git a/backend/plonk/bn254/marshal.go b/backend/plonk/bn254/marshal.go index dcd81bd10d..eb57ed6e05 100644 --- a/backend/plonk/bn254/marshal.go +++ b/backend/plonk/bn254/marshal.go @@ -120,16 +120,16 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { // encode the size (nor does it convert from Montgomery to Regular form) // so we explicitly transmit []fr.Element toEncode := []interface{}{ - ([]fr.Element)(pk.trace.Ql.Coefficients()), - ([]fr.Element)(pk.trace.Qr.Coefficients()), - ([]fr.Element)(pk.trace.Qm.Coefficients()), - ([]fr.Element)(pk.trace.Qo.Coefficients()), - ([]fr.Element)(pk.trace.Qk.Coefficients()), - ([]fr.Element)(pk.trace.Qcp.Coefficients()), - ([]fr.Element)(pk.lQk.Coefficients()), - ([]fr.Element)(pk.trace.S1.Coefficients()), - ([]fr.Element)(pk.trace.S2.Coefficients()), - ([]fr.Element)(pk.trace.S3.Coefficients()), + pk.trace.Ql.Coefficients(), + pk.trace.Qr.Coefficients(), + pk.trace.Qm.Coefficients(), + pk.trace.Qo.Coefficients(), + pk.trace.Qk.Coefficients(), + pk.trace.Qcp.Coefficients(), + pk.lQk.Coefficients(), + pk.trace.S1.Coefficients(), + pk.trace.S2.Coefficients(), + pk.trace.S3.Coefficients(), pk.trace.S, } diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index b27a4c15be..6158a5f2e6 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -107,7 +107,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pi2iop := iop.NewPolynomial(&pi2, lagReg) wpi2iop = pi2iop.ShallowClone() wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() - if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Vk.KZGSRS); err != nil { + if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Kzg); err != nil { return err } if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { @@ -209,7 +209,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // wait for polys to be blinded wgLRO.Wait() - if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Vk.KZGSRS); err != nil { + if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Kzg); err != nil { return nil, err } @@ -266,7 +266,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts go func() { bwziop = ziop // iop.NewWrappedPolynomial(&ziop) bwziop.Blind(2) - proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Vk.KZGSRS, runtime.NumCPU()*2) + proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Kzg, runtime.NumCPU()*2) if err != nil { chZ <- err } @@ -393,7 +393,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts h.Coefficients()[:pk.Domain[0].Cardinality+2], h.Coefficients()[pk.Domain[0].Cardinality+2:2*(pk.Domain[0].Cardinality+2)], h.Coefficients()[2*(pk.Domain[0].Cardinality+2):3*(pk.Domain[0].Cardinality+2)], - proof, pk.Vk.KZGSRS); err != nil { + proof, pk.Kzg); err != nil { return nil, err } @@ -427,7 +427,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.ZShiftedOpening, err = kzg.Open( bwziop.Coefficients()[:bwziop.BlindedSize()], zetaShifted, - pk.Vk.KZGSRS, + pk.Kzg, ) if err != nil { return nil, err @@ -496,7 +496,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // TODO this commitment is only necessary to derive the challenge, we should // be able to avoid doing it and get the challenge in another way - linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Vk.KZGSRS, runtime.NumCPU()*2) + linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Kzg, runtime.NumCPU()*2) if errLPoly != nil { return nil, errLPoly } @@ -528,7 +528,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts }, zeta, hFunc, - pk.Vk.KZGSRS, + pk.Kzg, ) log.Debug().Dur("took", time.Since(start)).Msg("prover done") @@ -542,20 +542,20 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // fills proof.LRO with kzg commits of bcl, bcr and bco -func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { +func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, kzgPk kzg.ProvingKey) error { n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) go func() { - proof.LRO[0], err0 = kzg.Commit(bcl, srs, n) + proof.LRO[0], err0 = kzg.Commit(bcl, kzgPk, n) close(chCommit0) }() go func() { - proof.LRO[1], err1 = kzg.Commit(bcr, srs, n) + proof.LRO[1], err1 = kzg.Commit(bcr, kzgPk, n) close(chCommit1) }() - if proof.LRO[2], err2 = kzg.Commit(bco, srs, n); err2 != nil { + if proof.LRO[2], err2 = kzg.Commit(bco, kzgPk, n); err2 != nil { return err2 } <-chCommit0 @@ -568,20 +568,20 @@ func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { return err1 } -func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error { +func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, kzgPk kzg.ProvingKey) error { n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) go func() { - proof.H[0], err0 = kzg.Commit(h1, srs, n) + proof.H[0], err0 = kzg.Commit(h1, kzgPk, n) close(chCommit0) }() go func() { - proof.H[1], err1 = kzg.Commit(h2, srs, n) + proof.H[1], err1 = kzg.Commit(h2, kzgPk, n) close(chCommit1) }() - if proof.H[2], err2 = kzg.Commit(h3, srs, n); err2 != nil { + if proof.H[2], err2 = kzg.Commit(h3, kzgPk, n); err2 != nil { return err2 } <-chCommit0 diff --git a/backend/plonk/bn254/setup.go b/backend/plonk/bn254/setup.go index a4648d7ce0..7b527c3204 100644 --- a/backend/plonk/bn254/setup.go +++ b/backend/plonk/bn254/setup.go @@ -25,8 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr/kzg" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bn254" - - kzgg "github.com/consensys/gnark-crypto/kzg" + //kzgg "github.com/consensys/gnark-crypto/kzg" TODO Figure out why this is useful ) // Trace stores a plonk trace as columns @@ -64,7 +63,7 @@ type VerifyingKey struct { NbPublicVariables uint64 // Commitment scheme that is used for an instantiation of PLONK - KZGSRS *kzg.SRS + Kzg kzg.VerifyingKey // cosetShift generator of the coset on the small domain CosetShift fr.Element @@ -96,6 +95,8 @@ type ProvingKey struct { // The polynomials in trace are in canonical basis. trace Trace + Kzg kzg.ProvingKey + // Verifying Key is embedded into the proving key (needed by Prove) Vk *VerifyingKey @@ -117,7 +118,7 @@ type ProvingKey struct { lcIdIOP, lLoneIOP *iop.Polynomial } -func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) { +func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, error) { var pk ProvingKey var vk VerifyingKey @@ -134,9 +135,11 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) vk.SizeInv.SetUint64(vk.Size).Inverse(&vk.SizeInv) vk.Generator.Set(&pk.Domain[0].Generator) vk.NbPublicVariables = uint64(len(spr.Public)) - if err := pk.InitKZG(srs); err != nil { - return nil, nil, err + if len(kzgSrs.Pk.G1) < int(vk.Size) { + return nil, nil, errors.New("kzg srs is too small") } + pk.Kzg = kzgSrs.Pk + vk.Kzg = kzgSrs.Vk // step 2: ql, qr, qm, qo, qk, qcp in Lagrange Basis BuildTrace(spr, &pk.trace) @@ -211,32 +214,7 @@ func (pk *ProvingKey) VerifyingKey() interface{} { return pk.Vk } -// InitKZG inits pk.Vk.KZG using pk.Domain[0] cardinality and provided SRS -// -// This should be used after deserializing a ProvingKey -// as pk.Vk.KZG is NOT serialized -func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { - return pk.Vk.InitKZG(srs) -} - -// InitKZG inits vk.KZG using provided SRS -// -// This should be used after deserializing a VerifyingKey -// as vk.KZG is NOT serialized -// -// Note that this instantiates a new FFT domain using vk.Size -func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { - _srs := srs.(*kzg.SRS) - - if len(_srs.G1) < int(vk.Size) { - return errors.New("kzg srs is too small") - } - vk.KZGSRS = _srs - - return nil -} - -// BuildTrace fills the constatn columns ql, qr, qm, qo, qk from the sparser1cs. +// BuildTrace fills the constant columns ql, qr, qm, qo, qk from the sparser1cs. // Size is the size of the system that is nb_constraints+nb_public_variables func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { @@ -298,31 +276,31 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() var err error - if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qr, err = kzg.Commit(pk.trace.Qr.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qr, err = kzg.Commit(pk.trace.Qr.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qm, err = kzg.Commit(pk.trace.Qm.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qm, err = kzg.Commit(pk.trace.Qm.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qo, err = kzg.Commit(pk.trace.Qo.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qo, err = kzg.Commit(pk.trace.Qo.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.S[1], err = kzg.Commit(pk.trace.S2.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.S[1], err = kzg.Commit(pk.trace.S2.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.S[2], err = kzg.Commit(pk.trace.S3.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.S[2], err = kzg.Commit(pk.trace.S3.Coefficients(), pk.Kzg); err != nil { return err } return nil diff --git a/backend/plonk/bn254/verify.go b/backend/plonk/bn254/verify.go index 1785fa23d0..0cd822dfd8 100644 --- a/backend/plonk/bn254/verify.go +++ b/backend/plonk/bn254/verify.go @@ -262,7 +262,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zeta, shiftedZeta, }, - vk.KZGSRS, + vk.Kzg, ) log.Debug().Dur("took", time.Since(start)).Msg("verifier done") diff --git a/backend/plonk/bw6-633/marshal.go b/backend/plonk/bw6-633/marshal.go index 043b319cd3..438c592199 100644 --- a/backend/plonk/bw6-633/marshal.go +++ b/backend/plonk/bw6-633/marshal.go @@ -120,16 +120,16 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { // encode the size (nor does it convert from Montgomery to Regular form) // so we explicitly transmit []fr.Element toEncode := []interface{}{ - ([]fr.Element)(pk.trace.Ql.Coefficients()), - ([]fr.Element)(pk.trace.Qr.Coefficients()), - ([]fr.Element)(pk.trace.Qm.Coefficients()), - ([]fr.Element)(pk.trace.Qo.Coefficients()), - ([]fr.Element)(pk.trace.Qk.Coefficients()), - ([]fr.Element)(pk.trace.Qcp.Coefficients()), - ([]fr.Element)(pk.lQk.Coefficients()), - ([]fr.Element)(pk.trace.S1.Coefficients()), - ([]fr.Element)(pk.trace.S2.Coefficients()), - ([]fr.Element)(pk.trace.S3.Coefficients()), + pk.trace.Ql.Coefficients(), + pk.trace.Qr.Coefficients(), + pk.trace.Qm.Coefficients(), + pk.trace.Qo.Coefficients(), + pk.trace.Qk.Coefficients(), + pk.trace.Qcp.Coefficients(), + pk.lQk.Coefficients(), + pk.trace.S1.Coefficients(), + pk.trace.S2.Coefficients(), + pk.trace.S3.Coefficients(), pk.trace.S, } diff --git a/backend/plonk/bw6-633/prove.go b/backend/plonk/bw6-633/prove.go index 031284a8ce..668be5ab74 100644 --- a/backend/plonk/bw6-633/prove.go +++ b/backend/plonk/bw6-633/prove.go @@ -107,7 +107,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pi2iop := iop.NewPolynomial(&pi2, lagReg) wpi2iop = pi2iop.ShallowClone() wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() - if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Vk.KZGSRS); err != nil { + if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Kzg); err != nil { return err } if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { @@ -209,7 +209,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // wait for polys to be blinded wgLRO.Wait() - if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Vk.KZGSRS); err != nil { + if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Kzg); err != nil { return nil, err } @@ -266,7 +266,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts go func() { bwziop = ziop // iop.NewWrappedPolynomial(&ziop) bwziop.Blind(2) - proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Vk.KZGSRS, runtime.NumCPU()*2) + proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Kzg, runtime.NumCPU()*2) if err != nil { chZ <- err } @@ -393,7 +393,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts h.Coefficients()[:pk.Domain[0].Cardinality+2], h.Coefficients()[pk.Domain[0].Cardinality+2:2*(pk.Domain[0].Cardinality+2)], h.Coefficients()[2*(pk.Domain[0].Cardinality+2):3*(pk.Domain[0].Cardinality+2)], - proof, pk.Vk.KZGSRS); err != nil { + proof, pk.Kzg); err != nil { return nil, err } @@ -427,7 +427,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.ZShiftedOpening, err = kzg.Open( bwziop.Coefficients()[:bwziop.BlindedSize()], zetaShifted, - pk.Vk.KZGSRS, + pk.Kzg, ) if err != nil { return nil, err @@ -496,7 +496,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // TODO this commitment is only necessary to derive the challenge, we should // be able to avoid doing it and get the challenge in another way - linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Vk.KZGSRS, runtime.NumCPU()*2) + linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Kzg, runtime.NumCPU()*2) if errLPoly != nil { return nil, errLPoly } @@ -528,7 +528,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts }, zeta, hFunc, - pk.Vk.KZGSRS, + pk.Kzg, ) log.Debug().Dur("took", time.Since(start)).Msg("prover done") @@ -542,20 +542,20 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // fills proof.LRO with kzg commits of bcl, bcr and bco -func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { +func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, kzgPk kzg.ProvingKey) error { n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) go func() { - proof.LRO[0], err0 = kzg.Commit(bcl, srs, n) + proof.LRO[0], err0 = kzg.Commit(bcl, kzgPk, n) close(chCommit0) }() go func() { - proof.LRO[1], err1 = kzg.Commit(bcr, srs, n) + proof.LRO[1], err1 = kzg.Commit(bcr, kzgPk, n) close(chCommit1) }() - if proof.LRO[2], err2 = kzg.Commit(bco, srs, n); err2 != nil { + if proof.LRO[2], err2 = kzg.Commit(bco, kzgPk, n); err2 != nil { return err2 } <-chCommit0 @@ -568,20 +568,20 @@ func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { return err1 } -func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error { +func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, kzgPk kzg.ProvingKey) error { n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) go func() { - proof.H[0], err0 = kzg.Commit(h1, srs, n) + proof.H[0], err0 = kzg.Commit(h1, kzgPk, n) close(chCommit0) }() go func() { - proof.H[1], err1 = kzg.Commit(h2, srs, n) + proof.H[1], err1 = kzg.Commit(h2, kzgPk, n) close(chCommit1) }() - if proof.H[2], err2 = kzg.Commit(h3, srs, n); err2 != nil { + if proof.H[2], err2 = kzg.Commit(h3, kzgPk, n); err2 != nil { return err2 } <-chCommit0 diff --git a/backend/plonk/bw6-633/setup.go b/backend/plonk/bw6-633/setup.go index ad0a65d154..2eb9988b09 100644 --- a/backend/plonk/bw6-633/setup.go +++ b/backend/plonk/bw6-633/setup.go @@ -25,8 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/kzg" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bw6-633" - - kzgg "github.com/consensys/gnark-crypto/kzg" + //kzgg "github.com/consensys/gnark-crypto/kzg" TODO Figure out why this is useful ) // Trace stores a plonk trace as columns @@ -64,7 +63,7 @@ type VerifyingKey struct { NbPublicVariables uint64 // Commitment scheme that is used for an instantiation of PLONK - KZGSRS *kzg.SRS + Kzg kzg.VerifyingKey // cosetShift generator of the coset on the small domain CosetShift fr.Element @@ -96,6 +95,8 @@ type ProvingKey struct { // The polynomials in trace are in canonical basis. trace Trace + Kzg kzg.ProvingKey + // Verifying Key is embedded into the proving key (needed by Prove) Vk *VerifyingKey @@ -117,7 +118,7 @@ type ProvingKey struct { lcIdIOP, lLoneIOP *iop.Polynomial } -func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) { +func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, error) { var pk ProvingKey var vk VerifyingKey @@ -134,9 +135,11 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) vk.SizeInv.SetUint64(vk.Size).Inverse(&vk.SizeInv) vk.Generator.Set(&pk.Domain[0].Generator) vk.NbPublicVariables = uint64(len(spr.Public)) - if err := pk.InitKZG(srs); err != nil { - return nil, nil, err + if len(kzgSrs.Pk.G1) < int(vk.Size) { + return nil, nil, errors.New("kzg srs is too small") } + pk.Kzg = kzgSrs.Pk + vk.Kzg = kzgSrs.Vk // step 2: ql, qr, qm, qo, qk, qcp in Lagrange Basis BuildTrace(spr, &pk.trace) @@ -211,32 +214,7 @@ func (pk *ProvingKey) VerifyingKey() interface{} { return pk.Vk } -// InitKZG inits pk.Vk.KZG using pk.Domain[0] cardinality and provided SRS -// -// This should be used after deserializing a ProvingKey -// as pk.Vk.KZG is NOT serialized -func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { - return pk.Vk.InitKZG(srs) -} - -// InitKZG inits vk.KZG using provided SRS -// -// This should be used after deserializing a VerifyingKey -// as vk.KZG is NOT serialized -// -// Note that this instantiates a new FFT domain using vk.Size -func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { - _srs := srs.(*kzg.SRS) - - if len(_srs.G1) < int(vk.Size) { - return errors.New("kzg srs is too small") - } - vk.KZGSRS = _srs - - return nil -} - -// BuildTrace fills the constatn columns ql, qr, qm, qo, qk from the sparser1cs. +// BuildTrace fills the constant columns ql, qr, qm, qo, qk from the sparser1cs. // Size is the size of the system that is nb_constraints+nb_public_variables func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { @@ -298,31 +276,31 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() var err error - if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qr, err = kzg.Commit(pk.trace.Qr.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qr, err = kzg.Commit(pk.trace.Qr.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qm, err = kzg.Commit(pk.trace.Qm.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qm, err = kzg.Commit(pk.trace.Qm.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qo, err = kzg.Commit(pk.trace.Qo.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qo, err = kzg.Commit(pk.trace.Qo.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.S[1], err = kzg.Commit(pk.trace.S2.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.S[1], err = kzg.Commit(pk.trace.S2.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.S[2], err = kzg.Commit(pk.trace.S3.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.S[2], err = kzg.Commit(pk.trace.S3.Coefficients(), pk.Kzg); err != nil { return err } return nil diff --git a/backend/plonk/bw6-633/verify.go b/backend/plonk/bw6-633/verify.go index bd0cb0e853..9a7cc5bd7f 100644 --- a/backend/plonk/bw6-633/verify.go +++ b/backend/plonk/bw6-633/verify.go @@ -260,7 +260,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zeta, shiftedZeta, }, - vk.KZGSRS, + vk.Kzg, ) log.Debug().Dur("took", time.Since(start)).Msg("verifier done") diff --git a/backend/plonk/bw6-761/marshal.go b/backend/plonk/bw6-761/marshal.go index 4cc8845a3f..a257c6cfe4 100644 --- a/backend/plonk/bw6-761/marshal.go +++ b/backend/plonk/bw6-761/marshal.go @@ -120,16 +120,16 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { // encode the size (nor does it convert from Montgomery to Regular form) // so we explicitly transmit []fr.Element toEncode := []interface{}{ - ([]fr.Element)(pk.trace.Ql.Coefficients()), - ([]fr.Element)(pk.trace.Qr.Coefficients()), - ([]fr.Element)(pk.trace.Qm.Coefficients()), - ([]fr.Element)(pk.trace.Qo.Coefficients()), - ([]fr.Element)(pk.trace.Qk.Coefficients()), - ([]fr.Element)(pk.trace.Qcp.Coefficients()), - ([]fr.Element)(pk.lQk.Coefficients()), - ([]fr.Element)(pk.trace.S1.Coefficients()), - ([]fr.Element)(pk.trace.S2.Coefficients()), - ([]fr.Element)(pk.trace.S3.Coefficients()), + pk.trace.Ql.Coefficients(), + pk.trace.Qr.Coefficients(), + pk.trace.Qm.Coefficients(), + pk.trace.Qo.Coefficients(), + pk.trace.Qk.Coefficients(), + pk.trace.Qcp.Coefficients(), + pk.lQk.Coefficients(), + pk.trace.S1.Coefficients(), + pk.trace.S2.Coefficients(), + pk.trace.S3.Coefficients(), pk.trace.S, } diff --git a/backend/plonk/bw6-761/prove.go b/backend/plonk/bw6-761/prove.go index 29c32cac7b..4d5e3ddde0 100644 --- a/backend/plonk/bw6-761/prove.go +++ b/backend/plonk/bw6-761/prove.go @@ -107,7 +107,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pi2iop := iop.NewPolynomial(&pi2, lagReg) wpi2iop = pi2iop.ShallowClone() wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() - if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Vk.KZGSRS); err != nil { + if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Kzg); err != nil { return err } if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { @@ -209,7 +209,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // wait for polys to be blinded wgLRO.Wait() - if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Vk.KZGSRS); err != nil { + if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Kzg); err != nil { return nil, err } @@ -266,7 +266,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts go func() { bwziop = ziop // iop.NewWrappedPolynomial(&ziop) bwziop.Blind(2) - proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Vk.KZGSRS, runtime.NumCPU()*2) + proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Kzg, runtime.NumCPU()*2) if err != nil { chZ <- err } @@ -393,7 +393,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts h.Coefficients()[:pk.Domain[0].Cardinality+2], h.Coefficients()[pk.Domain[0].Cardinality+2:2*(pk.Domain[0].Cardinality+2)], h.Coefficients()[2*(pk.Domain[0].Cardinality+2):3*(pk.Domain[0].Cardinality+2)], - proof, pk.Vk.KZGSRS); err != nil { + proof, pk.Kzg); err != nil { return nil, err } @@ -427,7 +427,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.ZShiftedOpening, err = kzg.Open( bwziop.Coefficients()[:bwziop.BlindedSize()], zetaShifted, - pk.Vk.KZGSRS, + pk.Kzg, ) if err != nil { return nil, err @@ -496,7 +496,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // TODO this commitment is only necessary to derive the challenge, we should // be able to avoid doing it and get the challenge in another way - linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Vk.KZGSRS, runtime.NumCPU()*2) + linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Kzg, runtime.NumCPU()*2) if errLPoly != nil { return nil, errLPoly } @@ -528,7 +528,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts }, zeta, hFunc, - pk.Vk.KZGSRS, + pk.Kzg, ) log.Debug().Dur("took", time.Since(start)).Msg("prover done") @@ -542,20 +542,20 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // fills proof.LRO with kzg commits of bcl, bcr and bco -func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { +func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, kzgPk kzg.ProvingKey) error { n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) go func() { - proof.LRO[0], err0 = kzg.Commit(bcl, srs, n) + proof.LRO[0], err0 = kzg.Commit(bcl, kzgPk, n) close(chCommit0) }() go func() { - proof.LRO[1], err1 = kzg.Commit(bcr, srs, n) + proof.LRO[1], err1 = kzg.Commit(bcr, kzgPk, n) close(chCommit1) }() - if proof.LRO[2], err2 = kzg.Commit(bco, srs, n); err2 != nil { + if proof.LRO[2], err2 = kzg.Commit(bco, kzgPk, n); err2 != nil { return err2 } <-chCommit0 @@ -568,20 +568,20 @@ func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { return err1 } -func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error { +func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, kzgPk kzg.ProvingKey) error { n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) go func() { - proof.H[0], err0 = kzg.Commit(h1, srs, n) + proof.H[0], err0 = kzg.Commit(h1, kzgPk, n) close(chCommit0) }() go func() { - proof.H[1], err1 = kzg.Commit(h2, srs, n) + proof.H[1], err1 = kzg.Commit(h2, kzgPk, n) close(chCommit1) }() - if proof.H[2], err2 = kzg.Commit(h3, srs, n); err2 != nil { + if proof.H[2], err2 = kzg.Commit(h3, kzgPk, n); err2 != nil { return err2 } <-chCommit0 diff --git a/backend/plonk/bw6-761/setup.go b/backend/plonk/bw6-761/setup.go index 7135a1108d..e9b40ca29c 100644 --- a/backend/plonk/bw6-761/setup.go +++ b/backend/plonk/bw6-761/setup.go @@ -25,8 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/kzg" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bw6-761" - - kzgg "github.com/consensys/gnark-crypto/kzg" + //kzgg "github.com/consensys/gnark-crypto/kzg" TODO Figure out why this is useful ) // Trace stores a plonk trace as columns @@ -64,7 +63,7 @@ type VerifyingKey struct { NbPublicVariables uint64 // Commitment scheme that is used for an instantiation of PLONK - KZGSRS *kzg.SRS + Kzg kzg.VerifyingKey // cosetShift generator of the coset on the small domain CosetShift fr.Element @@ -96,6 +95,8 @@ type ProvingKey struct { // The polynomials in trace are in canonical basis. trace Trace + Kzg kzg.ProvingKey + // Verifying Key is embedded into the proving key (needed by Prove) Vk *VerifyingKey @@ -117,7 +118,7 @@ type ProvingKey struct { lcIdIOP, lLoneIOP *iop.Polynomial } -func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) { +func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, error) { var pk ProvingKey var vk VerifyingKey @@ -134,9 +135,11 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) vk.SizeInv.SetUint64(vk.Size).Inverse(&vk.SizeInv) vk.Generator.Set(&pk.Domain[0].Generator) vk.NbPublicVariables = uint64(len(spr.Public)) - if err := pk.InitKZG(srs); err != nil { - return nil, nil, err + if len(kzgSrs.Pk.G1) < int(vk.Size) { + return nil, nil, errors.New("kzg srs is too small") } + pk.Kzg = kzgSrs.Pk + vk.Kzg = kzgSrs.Vk // step 2: ql, qr, qm, qo, qk, qcp in Lagrange Basis BuildTrace(spr, &pk.trace) @@ -211,32 +214,7 @@ func (pk *ProvingKey) VerifyingKey() interface{} { return pk.Vk } -// InitKZG inits pk.Vk.KZG using pk.Domain[0] cardinality and provided SRS -// -// This should be used after deserializing a ProvingKey -// as pk.Vk.KZG is NOT serialized -func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { - return pk.Vk.InitKZG(srs) -} - -// InitKZG inits vk.KZG using provided SRS -// -// This should be used after deserializing a VerifyingKey -// as vk.KZG is NOT serialized -// -// Note that this instantiates a new FFT domain using vk.Size -func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { - _srs := srs.(*kzg.SRS) - - if len(_srs.G1) < int(vk.Size) { - return errors.New("kzg srs is too small") - } - vk.KZGSRS = _srs - - return nil -} - -// BuildTrace fills the constatn columns ql, qr, qm, qo, qk from the sparser1cs. +// BuildTrace fills the constant columns ql, qr, qm, qo, qk from the sparser1cs. // Size is the size of the system that is nb_constraints+nb_public_variables func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { @@ -298,31 +276,31 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() var err error - if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qr, err = kzg.Commit(pk.trace.Qr.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qr, err = kzg.Commit(pk.trace.Qr.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qm, err = kzg.Commit(pk.trace.Qm.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qm, err = kzg.Commit(pk.trace.Qm.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qo, err = kzg.Commit(pk.trace.Qo.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qo, err = kzg.Commit(pk.trace.Qo.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.S[1], err = kzg.Commit(pk.trace.S2.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.S[1], err = kzg.Commit(pk.trace.S2.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.S[2], err = kzg.Commit(pk.trace.S3.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.S[2], err = kzg.Commit(pk.trace.S3.Coefficients(), pk.Kzg); err != nil { return err } return nil diff --git a/backend/plonk/bw6-761/verify.go b/backend/plonk/bw6-761/verify.go index 71fa48eacb..ae0b60e1aa 100644 --- a/backend/plonk/bw6-761/verify.go +++ b/backend/plonk/bw6-761/verify.go @@ -260,7 +260,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zeta, shiftedZeta, }, - vk.KZGSRS, + vk.Kzg, ) log.Debug().Dur("took", time.Since(start)).Msg("verifier done") diff --git a/backend/plonk/plonk.go b/backend/plonk/plonk.go index b567000643..fa4cf16b95 100644 --- a/backend/plonk/plonk.go +++ b/backend/plonk/plonk.go @@ -78,7 +78,6 @@ type Proof interface { type ProvingKey interface { io.WriterTo io.ReaderFrom - InitKZG(srs kzg.SRS) error VerifyingKey() interface{} } @@ -88,29 +87,28 @@ type ProvingKey interface { type VerifyingKey interface { io.WriterTo io.ReaderFrom - InitKZG(srs kzg.SRS) error NbPublicWitness() int // number of elements expected in the public witness ExportSolidity(w io.Writer) error } // Setup prepares the public data associated to a circuit + public inputs. -func Setup(ccs constraint.ConstraintSystem, kzgSRS kzg.SRS) (ProvingKey, VerifyingKey, error) { +func Setup(ccs constraint.ConstraintSystem, kzgSrs kzg.SRS) (ProvingKey, VerifyingKey, error) { switch tccs := ccs.(type) { case *cs_bn254.SparseR1CS: - return plonk_bn254.Setup(tccs, kzgSRS.(*kzg_bn254.SRS)) + return plonk_bn254.Setup(tccs, *kzgSrs.(*kzg_bn254.SRS)) case *cs_bls12381.SparseR1CS: - return plonk_bls12381.Setup(tccs, kzgSRS.(*kzg_bls12381.SRS)) + return plonk_bls12381.Setup(tccs, *kzgSrs.(*kzg_bls12381.SRS)) case *cs_bls12377.SparseR1CS: - return plonk_bls12377.Setup(tccs, kzgSRS.(*kzg_bls12377.SRS)) + return plonk_bls12377.Setup(tccs, *kzgSrs.(*kzg_bls12377.SRS)) case *cs_bw6761.SparseR1CS: - return plonk_bw6761.Setup(tccs, kzgSRS.(*kzg_bw6761.SRS)) + return plonk_bw6761.Setup(tccs, *kzgSrs.(*kzg_bw6761.SRS)) case *cs_bls24317.SparseR1CS: - return plonk_bls24317.Setup(tccs, kzgSRS.(*kzg_bls24317.SRS)) + return plonk_bls24317.Setup(tccs, *kzgSrs.(*kzg_bls24317.SRS)) case *cs_bls24315.SparseR1CS: - return plonk_bls24315.Setup(tccs, kzgSRS.(*kzg_bls24315.SRS)) + return plonk_bls24315.Setup(tccs, *kzgSrs.(*kzg_bls24315.SRS)) case *cs_bw6633.SparseR1CS: - return plonk_bw6633.Setup(tccs, kzgSRS.(*kzg_bw6633.SRS)) + return plonk_bw6633.Setup(tccs, *kzgSrs.(*kzg_bw6633.SRS)) default: panic("unrecognized SparseR1CS curve type") } diff --git a/go.mod b/go.mod index 5a9e32610b..1d8704907a 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/bits-and-blooms/bitset v1.5.0 github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 - github.com/consensys/gnark-crypto v0.9.2-0.20230329155745-a57dcc3b53de + github.com/consensys/gnark-crypto v0.10.1-0.20230408232650-7fda2542de4d github.com/fxamacker/cbor/v2 v2.4.0 github.com/google/go-cmp v0.5.9 github.com/google/pprof v0.0.0-20230309165930-d61513b1440d diff --git a/go.sum b/go.sum index aa7606bed0..9a33fe7c0a 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,8 @@ github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.9.2-0.20230329155745-a57dcc3b53de h1:W5lRxU8Rk8CDLHMTeyNst0VESbcU5RZ3U1TS9MNGgCQ= -github.com/consensys/gnark-crypto v0.9.2-0.20230329155745-a57dcc3b53de/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= +github.com/consensys/gnark-crypto v0.10.1-0.20230408232650-7fda2542de4d h1:TJ2dYEdgx8dVt4Jv/ftodldmVkQK3R4ntCGyo1u0v3U= +github.com/consensys/gnark-crypto v0.10.1-0.20230408232650-7fda2542de4d/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl index 60a5a02cdf..c648f7d129 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl @@ -101,16 +101,16 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { // encode the size (nor does it convert from Montgomery to Regular form) // so we explicitly transmit []fr.Element toEncode := []interface{}{ - ([]fr.Element)(pk.trace.Ql.Coefficients()), - ([]fr.Element)(pk.trace.Qr.Coefficients()), - ([]fr.Element)(pk.trace.Qm.Coefficients()), - ([]fr.Element)(pk.trace.Qo.Coefficients()), - ([]fr.Element)(pk.trace.Qk.Coefficients()), - ([]fr.Element)(pk.trace.Qcp.Coefficients()), - ([]fr.Element)(pk.lQk.Coefficients()), - ([]fr.Element)(pk.trace.S1.Coefficients()), - ([]fr.Element)(pk.trace.S2.Coefficients()), - ([]fr.Element)(pk.trace.S3.Coefficients()), + pk.trace.Ql.Coefficients(), + pk.trace.Qr.Coefficients(), + pk.trace.Qm.Coefficients(), + pk.trace.Qo.Coefficients(), + pk.trace.Qk.Coefficients(), + pk.trace.Qcp.Coefficients(), + pk.lQk.Coefficients(), + pk.trace.S1.Coefficients(), + pk.trace.S2.Coefficients(), + pk.trace.S3.Coefficients(), pk.trace.S, } diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl index adb6ca524f..5854b53a6a 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl @@ -85,7 +85,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pi2iop := iop.NewPolynomial(&pi2, lagReg) wpi2iop = pi2iop.ShallowClone() wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() - if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Vk.KZGSRS); err != nil { + if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Kzg); err != nil { return err } if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { @@ -189,7 +189,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // wait for polys to be blinded wgLRO.Wait() - if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Vk.KZGSRS); err != nil { + if err := commitToLRO(bwliop.Coefficients(), bwriop.Coefficients(), bwoiop.Coefficients(), proof, pk.Kzg); err != nil { return nil, err } @@ -247,7 +247,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts go func() { bwziop = ziop // iop.NewWrappedPolynomial(&ziop) bwziop.Blind(2) - proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Vk.KZGSRS, runtime.NumCPU()*2) + proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Kzg, runtime.NumCPU()*2) if err != nil { chZ <- err } @@ -377,7 +377,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts h.Coefficients()[:pk.Domain[0].Cardinality+2], h.Coefficients()[pk.Domain[0].Cardinality+2:2*(pk.Domain[0].Cardinality+2)], h.Coefficients()[2*(pk.Domain[0].Cardinality+2):3*(pk.Domain[0].Cardinality+2)], - proof, pk.Vk.KZGSRS); err != nil { + proof, pk.Kzg); err != nil { return nil, err } @@ -411,7 +411,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.ZShiftedOpening, err = kzg.Open( bwziop.Coefficients()[:bwziop.BlindedSize()], zetaShifted, - pk.Vk.KZGSRS, + pk.Kzg, ) if err != nil { return nil, err @@ -482,7 +482,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // TODO this commitment is only necessary to derive the challenge, we should // be able to avoid doing it and get the challenge in another way - linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Vk.KZGSRS, runtime.NumCPU() * 2) + linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Kzg, runtime.NumCPU() * 2) if errLPoly != nil { return nil, errLPoly } @@ -515,7 +515,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts }, zeta, hFunc, - pk.Vk.KZGSRS, + pk.Kzg, ) log.Debug().Dur("took", time.Since(start)).Msg("prover done") @@ -529,20 +529,20 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // fills proof.LRO with kzg commits of bcl, bcr and bco -func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { +func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, kzgPk kzg.ProvingKey) error { n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) go func() { - proof.LRO[0], err0 = kzg.Commit(bcl, srs, n) + proof.LRO[0], err0 = kzg.Commit(bcl, kzgPk, n) close(chCommit0) }() go func() { - proof.LRO[1], err1 = kzg.Commit(bcr, srs, n) + proof.LRO[1], err1 = kzg.Commit(bcr, kzgPk, n) close(chCommit1) }() - if proof.LRO[2], err2 = kzg.Commit(bco, srs, n); err2 != nil { + if proof.LRO[2], err2 = kzg.Commit(bco, kzgPk, n); err2 != nil { return err2 } <-chCommit0 @@ -555,20 +555,20 @@ func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, srs *kzg.SRS) error { return err1 } -func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, srs *kzg.SRS) error { +func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, kzgPk kzg.ProvingKey) error { n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) go func() { - proof.H[0], err0 = kzg.Commit(h1, srs, n) + proof.H[0], err0 = kzg.Commit(h1, kzgPk, n) close(chCommit0) }() go func() { - proof.H[1], err1 = kzg.Commit(h2, srs, n) + proof.H[1], err1 = kzg.Commit(h2, kzgPk, n) close(chCommit1) }() - if proof.H[2], err2 = kzg.Commit(h3, srs, n); err2 != nil { + if proof.H[2], err2 = kzg.Commit(h3, kzgPk, n); err2 != nil { return err2 } <-chCommit0 diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl index 233b89c076..014e31fdd2 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl @@ -8,7 +8,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/{{toLower .Curve}}/fr/iop" "github.com/consensys/gnark-crypto/ecc" - kzgg "github.com/consensys/gnark-crypto/kzg" + //kzgg "github.com/consensys/gnark-crypto/kzg" TODO Figure out why this is useful ) // Trace stores a plonk trace as columns @@ -46,7 +46,7 @@ type VerifyingKey struct { NbPublicVariables uint64 // Commitment scheme that is used for an instantiation of PLONK - KZGSRS *kzg.SRS + Kzg kzg.VerifyingKey // cosetShift generator of the coset on the small domain CosetShift fr.Element @@ -78,6 +78,8 @@ type ProvingKey struct { // The polynomials in trace are in canonical basis. trace Trace + Kzg kzg.ProvingKey + // Verifying Key is embedded into the proving key (needed by Prove) Vk *VerifyingKey @@ -99,7 +101,7 @@ type ProvingKey struct { lcIdIOP, lLoneIOP *iop.Polynomial } -func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) { +func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, error) { var pk ProvingKey var vk VerifyingKey @@ -116,9 +118,11 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) vk.SizeInv.SetUint64(vk.Size).Inverse(&vk.SizeInv) vk.Generator.Set(&pk.Domain[0].Generator) vk.NbPublicVariables = uint64(len(spr.Public)) - if err := pk.InitKZG(srs); err != nil { - return nil, nil, err + if len(kzgSrs.Pk.G1) < int(vk.Size) { + return nil, nil, errors.New("kzg srs is too small") } + pk.Kzg = kzgSrs.Pk + vk.Kzg = kzgSrs.Vk // step 2: ql, qr, qm, qo, qk, qcp in Lagrange Basis BuildTrace(spr, &pk.trace) @@ -193,32 +197,7 @@ func (pk *ProvingKey) VerifyingKey() interface{} { return pk.Vk } -// InitKZG inits pk.Vk.KZG using pk.Domain[0] cardinality and provided SRS -// -// This should be used after deserializing a ProvingKey -// as pk.Vk.KZG is NOT serialized -func (pk *ProvingKey) InitKZG(srs kzgg.SRS) error { - return pk.Vk.InitKZG(srs) -} - -// InitKZG inits vk.KZG using provided SRS -// -// This should be used after deserializing a VerifyingKey -// as vk.KZG is NOT serialized -// -// Note that this instantiates a new FFT domain using vk.Size -func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { - _srs := srs.(*kzg.SRS) - - if len(_srs.G1) < int(vk.Size) { - return errors.New("kzg srs is too small") - } - vk.KZGSRS = _srs - - return nil -} - -// BuildTrace fills the constatn columns ql, qr, qm, qo, qk from the sparser1cs. +// BuildTrace fills the constant columns ql, qr, qm, qo, qk from the sparser1cs. // Size is the size of the system that is nb_constraints+nb_public_variables func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { @@ -280,31 +259,31 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() var err error - if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qr, err = kzg.Commit(pk.trace.Qr.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qr, err = kzg.Commit(pk.trace.Qr.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qm, err = kzg.Commit(pk.trace.Qm.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qm, err = kzg.Commit(pk.trace.Qm.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qo, err = kzg.Commit(pk.trace.Qo.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qo, err = kzg.Commit(pk.trace.Qo.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.S[1], err = kzg.Commit(pk.trace.S2.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.S[1], err = kzg.Commit(pk.trace.S2.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.S[2], err = kzg.Commit(pk.trace.S3.Coefficients(), pk.Vk.KZGSRS); err != nil { + if pk.Vk.S[2], err = kzg.Commit(pk.trace.S3.Coefficients(), pk.Kzg); err != nil { return err } return nil diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl index c6823ec6c5..5e4fe4f310 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl @@ -241,7 +241,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zeta, shiftedZeta, }, - vk.KZGSRS, + vk.Kzg, ) log.Debug().Dur("took", time.Since(start)).Msg("verifier done") diff --git a/std/commitments/kzg_bls24315/verifier_test.go b/std/commitments/kzg_bls24315/verifier_test.go index a937e408ac..d2588cacee 100644 --- a/std/commitments/kzg_bls24315/verifier_test.go +++ b/std/commitments/kzg_bls24315/verifier_test.go @@ -69,17 +69,17 @@ func TestVerifierDynamic(t *testing.T) { } // commit to the polynomial - com, err := kzg.Commit(f, srs) + com, err := kzg.Commit(f, srs.Pk) assert.NoError(err) // create opening proof var point fr.Element point.SetRandom() - proof, err := kzg.Open(f, point, srs) + proof, err := kzg.Open(f, point, srs.Pk) assert.NoError(err) // check that the proof is correct - err = kzg.Verify(&com, &proof, point, srs) + err = kzg.Verify(&com, &proof, point, srs.Vk) if err != nil { t.Fatal(err) } @@ -98,23 +98,23 @@ func TestVerifierDynamic(t *testing.T) { witness.S = point.String() - witness.VerifKey.G2[0].X.B0.A0 = srs.G2[0].X.B0.A0.String() - witness.VerifKey.G2[0].X.B0.A1 = srs.G2[0].X.B0.A1.String() - witness.VerifKey.G2[0].X.B1.A0 = srs.G2[0].X.B1.A0.String() - witness.VerifKey.G2[0].X.B1.A1 = srs.G2[0].X.B1.A1.String() - witness.VerifKey.G2[0].Y.B0.A0 = srs.G2[0].Y.B0.A0.String() - witness.VerifKey.G2[0].Y.B0.A1 = srs.G2[0].Y.B0.A1.String() - witness.VerifKey.G2[0].Y.B1.A0 = srs.G2[0].Y.B1.A0.String() - witness.VerifKey.G2[0].Y.B1.A1 = srs.G2[0].Y.B1.A1.String() - - witness.VerifKey.G2[1].X.B0.A0 = srs.G2[1].X.B0.A0.String() - witness.VerifKey.G2[1].X.B0.A1 = srs.G2[1].X.B0.A1.String() - witness.VerifKey.G2[1].X.B1.A0 = srs.G2[1].X.B1.A0.String() - witness.VerifKey.G2[1].X.B1.A1 = srs.G2[1].X.B1.A1.String() - witness.VerifKey.G2[1].Y.B0.A0 = srs.G2[1].Y.B0.A0.String() - witness.VerifKey.G2[1].Y.B0.A1 = srs.G2[1].Y.B0.A1.String() - witness.VerifKey.G2[1].Y.B1.A0 = srs.G2[1].Y.B1.A0.String() - witness.VerifKey.G2[1].Y.B1.A1 = srs.G2[1].Y.B1.A1.String() + witness.VerifKey.G2[0].X.B0.A0 = srs.Vk.G2[0].X.B0.A0.String() + witness.VerifKey.G2[0].X.B0.A1 = srs.Vk.G2[0].X.B0.A1.String() + witness.VerifKey.G2[0].X.B1.A0 = srs.Vk.G2[0].X.B1.A0.String() + witness.VerifKey.G2[0].X.B1.A1 = srs.Vk.G2[0].X.B1.A1.String() + witness.VerifKey.G2[0].Y.B0.A0 = srs.Vk.G2[0].Y.B0.A0.String() + witness.VerifKey.G2[0].Y.B0.A1 = srs.Vk.G2[0].Y.B0.A1.String() + witness.VerifKey.G2[0].Y.B1.A0 = srs.Vk.G2[0].Y.B1.A0.String() + witness.VerifKey.G2[0].Y.B1.A1 = srs.Vk.G2[0].Y.B1.A1.String() + + witness.VerifKey.G2[1].X.B0.A0 = srs.Vk.G2[1].X.B0.A0.String() + witness.VerifKey.G2[1].X.B0.A1 = srs.Vk.G2[1].X.B0.A1.String() + witness.VerifKey.G2[1].X.B1.A0 = srs.Vk.G2[1].X.B1.A0.String() + witness.VerifKey.G2[1].X.B1.A1 = srs.Vk.G2[1].X.B1.A1.String() + witness.VerifKey.G2[1].Y.B0.A0 = srs.Vk.G2[1].Y.B0.A0.String() + witness.VerifKey.G2[1].Y.B0.A1 = srs.Vk.G2[1].Y.B0.A1.String() + witness.VerifKey.G2[1].Y.B1.A0 = srs.Vk.G2[1].Y.B1.A0.String() + witness.VerifKey.G2[1].Y.B1.A1 = srs.Vk.G2[1].Y.B1.A1.String() // check if the circuit is solved var circuit verifierCircuit diff --git a/test/kzg_srs.go b/test/kzg_srs.go index 4002762919..c67b89be7f 100644 --- a/test/kzg_srs.go +++ b/test/kzg_srs.go @@ -51,7 +51,6 @@ func NewKZGSRS(ccs constraint.ConstraintSystem) (kzg.SRS, error) { } return newKZGSRS(utils.FieldToCurve(ccs.Field()), kzgSize) - } var srsCache map[ecc.ID]kzg.SRS From afb54509d518772c9434c0ffc0d5f7beeab953d3 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Sat, 8 Apr 2023 18:41:52 -0500 Subject: [PATCH 243/464] refactor: more adapting to separated kzg srs --- std/commitments/kzg_bls12377/verifier_test.go | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/std/commitments/kzg_bls12377/verifier_test.go b/std/commitments/kzg_bls12377/verifier_test.go index 58563a44ea..09b7684b5e 100644 --- a/std/commitments/kzg_bls12377/verifier_test.go +++ b/std/commitments/kzg_bls12377/verifier_test.go @@ -69,17 +69,17 @@ func TestVerifierDynamic(t *testing.T) { } // commit to the polynomial - com, err := kzg.Commit(f, srs) + com, err := kzg.Commit(f, srs.Pk) assert.NoError(err) // create opening proof var point fr.Element point.SetRandom() - proof, err := kzg.Open(f, point, srs) + proof, err := kzg.Open(f, point, srs.Pk) assert.NoError(err) // check that the proof is correct - err = kzg.Verify(&com, &proof, point, srs) + err = kzg.Verify(&com, &proof, point, srs.Vk) if err != nil { t.Fatal(err) } @@ -98,14 +98,14 @@ func TestVerifierDynamic(t *testing.T) { witness.S = point.String() - witness.VerifKey.G2[0].X.A0 = srs.G2[0].X.A0.String() - witness.VerifKey.G2[0].X.A1 = srs.G2[0].X.A1.String() - witness.VerifKey.G2[0].Y.A0 = srs.G2[0].Y.A0.String() - witness.VerifKey.G2[0].Y.A1 = srs.G2[0].Y.A1.String() - witness.VerifKey.G2[1].X.A0 = srs.G2[1].X.A0.String() - witness.VerifKey.G2[1].X.A1 = srs.G2[1].X.A1.String() - witness.VerifKey.G2[1].Y.A0 = srs.G2[1].Y.A0.String() - witness.VerifKey.G2[1].Y.A1 = srs.G2[1].Y.A1.String() + witness.VerifKey.G2[0].X.A0 = srs.Vk.G2[0].X.A0.String() + witness.VerifKey.G2[0].X.A1 = srs.Vk.G2[0].X.A1.String() + witness.VerifKey.G2[0].Y.A0 = srs.Vk.G2[0].Y.A0.String() + witness.VerifKey.G2[0].Y.A1 = srs.Vk.G2[0].Y.A1.String() + witness.VerifKey.G2[1].X.A0 = srs.Vk.G2[1].X.A0.String() + witness.VerifKey.G2[1].X.A1 = srs.Vk.G2[1].X.A1.String() + witness.VerifKey.G2[1].Y.A0 = srs.Vk.G2[1].Y.A0.String() + witness.VerifKey.G2[1].Y.A1 = srs.Vk.G2[1].Y.A1.String() // check if the circuit is solved var circuit verifierCircuit From ad3fd19490c4e2705571497b03910a1f7d52370b Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Sat, 8 Apr 2023 19:28:19 -0500 Subject: [PATCH 244/464] refactor: do not include committed wires indexes in plonk vk --- backend/plonk/bls12-377/setup.go | 7 ++++--- backend/plonk/bls12-377/verify.go | 6 +++--- backend/plonk/bls12-381/setup.go | 7 ++++--- backend/plonk/bls12-381/verify.go | 6 +++--- backend/plonk/bls24-315/setup.go | 7 ++++--- backend/plonk/bls24-315/verify.go | 6 +++--- backend/plonk/bls24-317/setup.go | 7 ++++--- backend/plonk/bls24-317/verify.go | 6 +++--- backend/plonk/bn254/setup.go | 7 ++++--- backend/plonk/bn254/verify.go | 6 +++--- backend/plonk/bw6-633/setup.go | 7 ++++--- backend/plonk/bw6-633/verify.go | 6 +++--- backend/plonk/bw6-761/setup.go | 7 ++++--- backend/plonk/bw6-761/verify.go | 6 +++--- .../template/zkpschemes/plonk/plonk.setup.go.tmpl | 7 ++++--- .../template/zkpschemes/plonk/plonk.verify.go.tmpl | 14 +++++++------- 16 files changed, 60 insertions(+), 52 deletions(-) diff --git a/backend/plonk/bls12-377/setup.go b/backend/plonk/bls12-377/setup.go index 5b84129c1b..395f688f77 100644 --- a/backend/plonk/bls12-377/setup.go +++ b/backend/plonk/bls12-377/setup.go @@ -23,7 +23,6 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/iop" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/kzg" - "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls12-377" kzgg "github.com/consensys/gnark-crypto/kzg" @@ -76,7 +75,7 @@ type VerifyingKey struct { // In particular Qk is not complete. Ql, Qr, Qm, Qo, Qk, Qcp kzg.Digest - CommitmentInfo constraint.Commitment + CommitmentConstraintIndexes []uint64 } // ProvingKey stores the data needed to generate a proof: @@ -122,7 +121,9 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - vk.CommitmentInfo = spr.CommitmentInfo + if spr.CommitmentInfo.Is() { + vk.CommitmentConstraintIndexes = []uint64{uint64(spr.CommitmentInfo.CommitmentIndex)} + } // nbConstraints := len(spr.Constraints) // step 0: set the fft domains diff --git a/backend/plonk/bls12-377/verify.go b/backend/plonk/bls12-377/verify.go index 65c7881cf6..e09e4fc440 100644 --- a/backend/plonk/bls12-377/verify.go +++ b/backend/plonk/bls12-377/verify.go @@ -110,15 +110,15 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } } - if vk.CommitmentInfo.Is() { - var hashRes []fr.Element + for i := range vk.CommitmentConstraintIndexes { + var hashRes []fr.Element // TODO: when multi commits are implemented: PI2 -> PI2[i] if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } // Computing L_{CommitmentIndex} - wPowI.Exp(vk.Generator, big.NewInt(int64(vk.NbPublicVariables)+int64(vk.CommitmentInfo.CommitmentIndex))) + wPowI.Exp(vk.Generator, big.NewInt(int64(vk.NbPublicVariables)+int64(vk.CommitmentConstraintIndexes[i]))) den.Sub(&zeta, &wPowI) // ζ-wⁱ lagrange.SetOne(). diff --git a/backend/plonk/bls12-381/setup.go b/backend/plonk/bls12-381/setup.go index 229b43b649..74ea66bafa 100644 --- a/backend/plonk/bls12-381/setup.go +++ b/backend/plonk/bls12-381/setup.go @@ -23,7 +23,6 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/iop" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/kzg" - "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls12-381" kzgg "github.com/consensys/gnark-crypto/kzg" @@ -76,7 +75,7 @@ type VerifyingKey struct { // In particular Qk is not complete. Ql, Qr, Qm, Qo, Qk, Qcp kzg.Digest - CommitmentInfo constraint.Commitment + CommitmentConstraintIndexes []uint64 } // ProvingKey stores the data needed to generate a proof: @@ -122,7 +121,9 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - vk.CommitmentInfo = spr.CommitmentInfo + if spr.CommitmentInfo.Is() { + vk.CommitmentConstraintIndexes = []uint64{uint64(spr.CommitmentInfo.CommitmentIndex)} + } // nbConstraints := len(spr.Constraints) // step 0: set the fft domains diff --git a/backend/plonk/bls12-381/verify.go b/backend/plonk/bls12-381/verify.go index 92d6451ab9..bf90d086ec 100644 --- a/backend/plonk/bls12-381/verify.go +++ b/backend/plonk/bls12-381/verify.go @@ -110,15 +110,15 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } } - if vk.CommitmentInfo.Is() { - var hashRes []fr.Element + for i := range vk.CommitmentConstraintIndexes { + var hashRes []fr.Element // TODO: when multi commits are implemented: PI2 -> PI2[i] if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } // Computing L_{CommitmentIndex} - wPowI.Exp(vk.Generator, big.NewInt(int64(vk.NbPublicVariables)+int64(vk.CommitmentInfo.CommitmentIndex))) + wPowI.Exp(vk.Generator, big.NewInt(int64(vk.NbPublicVariables)+int64(vk.CommitmentConstraintIndexes[i]))) den.Sub(&zeta, &wPowI) // ζ-wⁱ lagrange.SetOne(). diff --git a/backend/plonk/bls24-315/setup.go b/backend/plonk/bls24-315/setup.go index 0de7425e02..6739872eaf 100644 --- a/backend/plonk/bls24-315/setup.go +++ b/backend/plonk/bls24-315/setup.go @@ -23,7 +23,6 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/iop" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/kzg" - "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls24-315" kzgg "github.com/consensys/gnark-crypto/kzg" @@ -76,7 +75,7 @@ type VerifyingKey struct { // In particular Qk is not complete. Ql, Qr, Qm, Qo, Qk, Qcp kzg.Digest - CommitmentInfo constraint.Commitment + CommitmentConstraintIndexes []uint64 } // ProvingKey stores the data needed to generate a proof: @@ -122,7 +121,9 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - vk.CommitmentInfo = spr.CommitmentInfo + if spr.CommitmentInfo.Is() { + vk.CommitmentConstraintIndexes = []uint64{uint64(spr.CommitmentInfo.CommitmentIndex)} + } // nbConstraints := len(spr.Constraints) // step 0: set the fft domains diff --git a/backend/plonk/bls24-315/verify.go b/backend/plonk/bls24-315/verify.go index ca0b800e58..949886d86e 100644 --- a/backend/plonk/bls24-315/verify.go +++ b/backend/plonk/bls24-315/verify.go @@ -110,15 +110,15 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } } - if vk.CommitmentInfo.Is() { - var hashRes []fr.Element + for i := range vk.CommitmentConstraintIndexes { + var hashRes []fr.Element // TODO: when multi commits are implemented: PI2 -> PI2[i] if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } // Computing L_{CommitmentIndex} - wPowI.Exp(vk.Generator, big.NewInt(int64(vk.NbPublicVariables)+int64(vk.CommitmentInfo.CommitmentIndex))) + wPowI.Exp(vk.Generator, big.NewInt(int64(vk.NbPublicVariables)+int64(vk.CommitmentConstraintIndexes[i]))) den.Sub(&zeta, &wPowI) // ζ-wⁱ lagrange.SetOne(). diff --git a/backend/plonk/bls24-317/setup.go b/backend/plonk/bls24-317/setup.go index 391b8595b1..f8c102c819 100644 --- a/backend/plonk/bls24-317/setup.go +++ b/backend/plonk/bls24-317/setup.go @@ -23,7 +23,6 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/iop" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/kzg" - "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls24-317" kzgg "github.com/consensys/gnark-crypto/kzg" @@ -76,7 +75,7 @@ type VerifyingKey struct { // In particular Qk is not complete. Ql, Qr, Qm, Qo, Qk, Qcp kzg.Digest - CommitmentInfo constraint.Commitment + CommitmentConstraintIndexes []uint64 } // ProvingKey stores the data needed to generate a proof: @@ -122,7 +121,9 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - vk.CommitmentInfo = spr.CommitmentInfo + if spr.CommitmentInfo.Is() { + vk.CommitmentConstraintIndexes = []uint64{uint64(spr.CommitmentInfo.CommitmentIndex)} + } // nbConstraints := len(spr.Constraints) // step 0: set the fft domains diff --git a/backend/plonk/bls24-317/verify.go b/backend/plonk/bls24-317/verify.go index aecdd94022..a7852295fb 100644 --- a/backend/plonk/bls24-317/verify.go +++ b/backend/plonk/bls24-317/verify.go @@ -110,15 +110,15 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } } - if vk.CommitmentInfo.Is() { - var hashRes []fr.Element + for i := range vk.CommitmentConstraintIndexes { + var hashRes []fr.Element // TODO: when multi commits are implemented: PI2 -> PI2[i] if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } // Computing L_{CommitmentIndex} - wPowI.Exp(vk.Generator, big.NewInt(int64(vk.NbPublicVariables)+int64(vk.CommitmentInfo.CommitmentIndex))) + wPowI.Exp(vk.Generator, big.NewInt(int64(vk.NbPublicVariables)+int64(vk.CommitmentConstraintIndexes[i]))) den.Sub(&zeta, &wPowI) // ζ-wⁱ lagrange.SetOne(). diff --git a/backend/plonk/bn254/setup.go b/backend/plonk/bn254/setup.go index a4648d7ce0..bb7b80372c 100644 --- a/backend/plonk/bn254/setup.go +++ b/backend/plonk/bn254/setup.go @@ -23,7 +23,6 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" "github.com/consensys/gnark-crypto/ecc/bn254/fr/iop" "github.com/consensys/gnark-crypto/ecc/bn254/fr/kzg" - "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bn254" kzgg "github.com/consensys/gnark-crypto/kzg" @@ -76,7 +75,7 @@ type VerifyingKey struct { // In particular Qk is not complete. Ql, Qr, Qm, Qo, Qk, Qcp kzg.Digest - CommitmentInfo constraint.Commitment + CommitmentConstraintIndexes []uint64 } // ProvingKey stores the data needed to generate a proof: @@ -122,7 +121,9 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - vk.CommitmentInfo = spr.CommitmentInfo + if spr.CommitmentInfo.Is() { + vk.CommitmentConstraintIndexes = []uint64{uint64(spr.CommitmentInfo.CommitmentIndex)} + } // nbConstraints := len(spr.Constraints) // step 0: set the fft domains diff --git a/backend/plonk/bn254/verify.go b/backend/plonk/bn254/verify.go index 1785fa23d0..db685c866c 100644 --- a/backend/plonk/bn254/verify.go +++ b/backend/plonk/bn254/verify.go @@ -112,15 +112,15 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } } - if vk.CommitmentInfo.Is() { - var hashRes []fr.Element + for i := range vk.CommitmentConstraintIndexes { + var hashRes []fr.Element // TODO: when multi commits are implemented: PI2 -> PI2[i] if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } // Computing L_{CommitmentIndex} - wPowI.Exp(vk.Generator, big.NewInt(int64(vk.NbPublicVariables)+int64(vk.CommitmentInfo.CommitmentIndex))) + wPowI.Exp(vk.Generator, big.NewInt(int64(vk.NbPublicVariables)+int64(vk.CommitmentConstraintIndexes[i]))) den.Sub(&zeta, &wPowI) // ζ-wⁱ lagrange.SetOne(). diff --git a/backend/plonk/bw6-633/setup.go b/backend/plonk/bw6-633/setup.go index ad0a65d154..4ec615fdb4 100644 --- a/backend/plonk/bw6-633/setup.go +++ b/backend/plonk/bw6-633/setup.go @@ -23,7 +23,6 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/fft" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/iop" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/kzg" - "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bw6-633" kzgg "github.com/consensys/gnark-crypto/kzg" @@ -76,7 +75,7 @@ type VerifyingKey struct { // In particular Qk is not complete. Ql, Qr, Qm, Qo, Qk, Qcp kzg.Digest - CommitmentInfo constraint.Commitment + CommitmentConstraintIndexes []uint64 } // ProvingKey stores the data needed to generate a proof: @@ -122,7 +121,9 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - vk.CommitmentInfo = spr.CommitmentInfo + if spr.CommitmentInfo.Is() { + vk.CommitmentConstraintIndexes = []uint64{uint64(spr.CommitmentInfo.CommitmentIndex)} + } // nbConstraints := len(spr.Constraints) // step 0: set the fft domains diff --git a/backend/plonk/bw6-633/verify.go b/backend/plonk/bw6-633/verify.go index bd0cb0e853..411501c99d 100644 --- a/backend/plonk/bw6-633/verify.go +++ b/backend/plonk/bw6-633/verify.go @@ -110,15 +110,15 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } } - if vk.CommitmentInfo.Is() { - var hashRes []fr.Element + for i := range vk.CommitmentConstraintIndexes { + var hashRes []fr.Element // TODO: when multi commits are implemented: PI2 -> PI2[i] if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } // Computing L_{CommitmentIndex} - wPowI.Exp(vk.Generator, big.NewInt(int64(vk.NbPublicVariables)+int64(vk.CommitmentInfo.CommitmentIndex))) + wPowI.Exp(vk.Generator, big.NewInt(int64(vk.NbPublicVariables)+int64(vk.CommitmentConstraintIndexes[i]))) den.Sub(&zeta, &wPowI) // ζ-wⁱ lagrange.SetOne(). diff --git a/backend/plonk/bw6-761/setup.go b/backend/plonk/bw6-761/setup.go index 7135a1108d..4ec96d46be 100644 --- a/backend/plonk/bw6-761/setup.go +++ b/backend/plonk/bw6-761/setup.go @@ -23,7 +23,6 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/fft" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/iop" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/kzg" - "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bw6-761" kzgg "github.com/consensys/gnark-crypto/kzg" @@ -76,7 +75,7 @@ type VerifyingKey struct { // In particular Qk is not complete. Ql, Qr, Qm, Qo, Qk, Qcp kzg.Digest - CommitmentInfo constraint.Commitment + CommitmentConstraintIndexes []uint64 } // ProvingKey stores the data needed to generate a proof: @@ -122,7 +121,9 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - vk.CommitmentInfo = spr.CommitmentInfo + if spr.CommitmentInfo.Is() { + vk.CommitmentConstraintIndexes = []uint64{uint64(spr.CommitmentInfo.CommitmentIndex)} + } // nbConstraints := len(spr.Constraints) // step 0: set the fft domains diff --git a/backend/plonk/bw6-761/verify.go b/backend/plonk/bw6-761/verify.go index 71fa48eacb..6a5dd4a7e5 100644 --- a/backend/plonk/bw6-761/verify.go +++ b/backend/plonk/bw6-761/verify.go @@ -110,15 +110,15 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } } - if vk.CommitmentInfo.Is() { - var hashRes []fr.Element + for i := range vk.CommitmentConstraintIndexes { + var hashRes []fr.Element // TODO: when multi commits are implemented: PI2 -> PI2[i] if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } // Computing L_{CommitmentIndex} - wPowI.Exp(vk.Generator, big.NewInt(int64(vk.NbPublicVariables)+int64(vk.CommitmentInfo.CommitmentIndex))) + wPowI.Exp(vk.Generator, big.NewInt(int64(vk.NbPublicVariables)+int64(vk.CommitmentConstraintIndexes[i]))) den.Sub(&zeta, &wPowI) // ζ-wⁱ lagrange.SetOne(). diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl index 233b89c076..7b03b94c32 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl @@ -3,7 +3,6 @@ import ( {{- template "import_kzg" . }} {{- template "import_fr" . }} {{- template "import_fft" . }} - "github.com/consensys/gnark/constraint" {{- template "import_backend_cs" . }} "github.com/consensys/gnark-crypto/ecc/{{toLower .Curve}}/fr/iop" "github.com/consensys/gnark-crypto/ecc" @@ -58,7 +57,7 @@ type VerifyingKey struct { // In particular Qk is not complete. Ql, Qr, Qm, Qo, Qk, Qcp kzg.Digest - CommitmentInfo constraint.Commitment + CommitmentConstraintIndexes []uint64 } // ProvingKey stores the data needed to generate a proof: @@ -104,7 +103,9 @@ func Setup(spr *cs.SparseR1CS, srs *kzg.SRS) (*ProvingKey, *VerifyingKey, error) var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - vk.CommitmentInfo = spr.CommitmentInfo + if spr.CommitmentInfo.Is() { + vk.CommitmentConstraintIndexes = []uint64{uint64(spr.CommitmentInfo.CommitmentIndex)} + } // nbConstraints := len(spr.Constraints) // step 0: set the fft domains diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl index c6823ec6c5..4970f37113 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl @@ -91,22 +91,22 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } } - if vk.CommitmentInfo.Is() { - var hashRes []fr.Element + for i := range vk.CommitmentConstraintIndexes { + var hashRes []fr.Element // TODO: when multi commits are implemented: PI2 -> PI2[i] if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } // Computing L_{CommitmentIndex} - wPowI.Exp(vk.Generator, big.NewInt(int64(vk.NbPublicVariables)+int64(vk.CommitmentInfo.CommitmentIndex))) + wPowI.Exp(vk.Generator, big.NewInt(int64(vk.NbPublicVariables)+int64(vk.CommitmentConstraintIndexes[i]))) den.Sub(&zeta, &wPowI) // ζ-wⁱ lagrange.SetOne(). - Sub(&zeta, &lagrange). // ζ-1 - Mul(&lagrange, &wPowI). // wⁱ(ζ-1) - Div(&lagrange, &den). // wⁱ(ζ-1)/(ζ-wⁱ) - Mul(&lagrange, &lagrangeOne) // wⁱ/n (ζⁿ-1)/(ζ-wⁱ) + Sub(&zeta, &lagrange). // ζ-1 + Mul(&lagrange, &wPowI). // wⁱ(ζ-1) + Div(&lagrange, &den). // wⁱ(ζ-1)/(ζ-wⁱ) + Mul(&lagrange, &lagrangeOne) // wⁱ/n (ζⁿ-1)/(ζ-wⁱ) xiLi.Mul(&lagrange, &hashRes[0]) pi.Add(&pi, &xiLi) From cce13ba5cf6a514af91c34db3dad0f5a47a6f48d Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Sun, 9 Apr 2023 14:06:21 +0000 Subject: [PATCH 245/464] feat: use Brier-Joye unified add for evm ecadd --- std/algebra/emulated/sw_emulated/point.go | 68 ++++++++++--------- .../emulated/sw_emulated/point_test.go | 4 +- std/evmprecompiles/06-bnadd.go | 4 +- 3 files changed, 40 insertions(+), 36 deletions(-) diff --git a/std/algebra/emulated/sw_emulated/point.go b/std/algebra/emulated/sw_emulated/point.go index 8fd1725a0d..b4e5d8a00f 100644 --- a/std/algebra/emulated/sw_emulated/point.go +++ b/std/algebra/emulated/sw_emulated/point.go @@ -101,22 +101,6 @@ func (c *Curve[B, S]) AssertIsEqual(p, q *AffinePoint[B]) { // // It uses incomplete formulas in affine coordinates. func (c *Curve[B, S]) Add(p, q *AffinePoint[B]) *AffinePoint[B] { - return c.add(p, q, false) -} - -// AddSafe adds p and q and returns it. It doesn't modify p nor q. -// -// ✅ p can be equal to q, but none nonzero. -// -// It uses incomplete formulas in affine coordinates. -func (c *Curve[B, S]) AddSafe(p, q *AffinePoint[B]) *AffinePoint[B] { - return c.add(p, q, true) -} - -// add adds p and q and returns it. It doesn't modify p nor q. -// It uses incomplete formulas in affine coordinates. -func (c *Curve[B, S]) add(p, q *AffinePoint[B], safe bool) *AffinePoint[B] { - // compute λ = (q.y-p.y)/(q.x-p.x) qypy := c.baseApi.Sub(&q.Y, &p.Y) qxpx := c.baseApi.Sub(&q.X, &p.X) @@ -124,22 +108,6 @@ func (c *Curve[B, S]) add(p, q *AffinePoint[B], safe bool) *AffinePoint[B] { // if qxpx == 0, set λ to 0 λ := c.baseApi.DivSpecial(qypy, qxpx) - if safe { - // compute _λ = (3p.x²+a)/2*p.y - xx3a := c.baseApi.MulMod(&p.X, &p.X) - xx3a = c.baseApi.MulConst(xx3a, big.NewInt(3)) - if c.addA { - xx3a = c.baseApi.Add(xx3a, &c.a) - } - y2 := c.baseApi.MulConst(&p.Y, big.NewInt(2)) - _λ := c.baseApi.Div(xx3a, y2) - - selector := c.api.And( - c.baseApi.IsZero(qxpx), c.baseApi.IsZero(qypy), - ) - λ = c.baseApi.Select(selector, _λ, λ) - } - // xr = λ²-p.x-q.x λλ := c.baseApi.MulMod(λ, λ) qxpx = c.baseApi.Add(&p.X, &q.X) @@ -156,6 +124,42 @@ func (c *Curve[B, S]) add(p, q *AffinePoint[B], safe bool) *AffinePoint[B] { } } +// AddUnified adds p and q and returns it. It doesn't modify p nor q. +// +// ✅ p can be equal to q, but none nonzero. +// +// It uses the unified formulas of Brier and Joye [BriJoy02] (Corollary 1). +// +// [BriJoy02]: https://link.springer.com/content/pdf/10.1007/3-540-45664-3_24.pdf +func (c *Curve[B, S]) AddUnified(p, q *AffinePoint[B]) *AffinePoint[B] { + + // λ = ((p.x+q.x)² - p.x*q.x + a)/(p.y1 + q.y), if p.y + q.y = 0 + pxqx := c.baseApi.MulMod(&p.X, &q.X) + num := c.baseApi.Add(&p.X, &q.X) + num = c.baseApi.MulMod(num, num) + num = c.baseApi.Sub(num, pxqx) + if c.addA { + num = c.baseApi.Add(num, &c.a) + } + denum := c.baseApi.Add(&p.Y, &q.Y) + λ := c.baseApi.Div(num, denum) + + // x = λ^2 - p.x - q.x + xr := c.baseApi.MulMod(λ, λ) + xr = c.baseApi.Sub(xr, &p.X) + xr = c.baseApi.Sub(xr, &q.X) + + // y = λ(p.x - xr) - p.y + yr := c.baseApi.Sub(&p.X, xr) + yr = c.baseApi.MulMod(yr, λ) + yr = c.baseApi.Sub(yr, &p.Y) + + return &AffinePoint[B]{ + X: *c.baseApi.Reduce(xr), + Y: *c.baseApi.Reduce(yr), + } +} + // Double doubles p and return it. It doesn't modify p. // It uses affine coordinates. func (c *Curve[B, S]) Double(p *AffinePoint[B]) *AffinePoint[B] { diff --git a/std/algebra/emulated/sw_emulated/point_test.go b/std/algebra/emulated/sw_emulated/point_test.go index 6915274989..cb3096812a 100644 --- a/std/algebra/emulated/sw_emulated/point_test.go +++ b/std/algebra/emulated/sw_emulated/point_test.go @@ -62,7 +62,7 @@ func (c *AddTest[T, S]) Define(api frontend.API) error { return err } res1 := cr.Add(&c.P, &c.Q) - res2 := cr.AddSafe(&c.P, &c.Q) + res2 := cr.AddUnified(&c.P, &c.Q) cr.AssertIsEqual(res1, &c.R) cr.AssertIsEqual(res2, &c.R) return nil @@ -107,7 +107,7 @@ func (c *DoubleTest[T, S]) Define(api frontend.API) error { return err } res1 := cr.Double(&c.P) - res2 := cr.AddSafe(&c.P, &c.P) + res2 := cr.AddUnified(&c.P, &c.P) cr.AssertIsEqual(res1, &c.Q) cr.AssertIsEqual(res2, &c.Q) return nil diff --git a/std/evmprecompiles/06-bnadd.go b/std/evmprecompiles/06-bnadd.go index fc23f5867f..0f819d9833 100644 --- a/std/evmprecompiles/06-bnadd.go +++ b/std/evmprecompiles/06-bnadd.go @@ -14,7 +14,7 @@ func ECAdd(api frontend.API, P, Q *sw_emulated.AffinePoint[emulated.BN254Fp]) *s if err != nil { panic(err) } - // We use AddSafe because P can be equal to Q - res := curve.AddSafe(P, Q) + // We use AddUnified because P can be equal to Q + res := curve.AddUnified(P, Q) return res } From 73661f0add888f3857674991fc7fb93a6f15c2ab Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Sun, 9 Apr 2023 14:11:44 +0000 Subject: [PATCH 246/464] refactor: remove DivSpecial --- std/algebra/emulated/sw_emulated/point.go | 4 +- std/math/emulated/field_ops.go | 19 ------- std/math/emulated/hints.go | 61 ----------------------- 3 files changed, 1 insertion(+), 83 deletions(-) diff --git a/std/algebra/emulated/sw_emulated/point.go b/std/algebra/emulated/sw_emulated/point.go index b4e5d8a00f..7642b106f2 100644 --- a/std/algebra/emulated/sw_emulated/point.go +++ b/std/algebra/emulated/sw_emulated/point.go @@ -104,9 +104,7 @@ func (c *Curve[B, S]) Add(p, q *AffinePoint[B]) *AffinePoint[B] { // compute λ = (q.y-p.y)/(q.x-p.x) qypy := c.baseApi.Sub(&q.Y, &p.Y) qxpx := c.baseApi.Sub(&q.X, &p.X) - - // if qxpx == 0, set λ to 0 - λ := c.baseApi.DivSpecial(qypy, qxpx) + λ := c.baseApi.Div(qypy, qxpx) // xr = λ²-p.x-q.x λλ := c.baseApi.MulMod(λ, λ) diff --git a/std/math/emulated/field_ops.go b/std/math/emulated/field_ops.go index 22924cbd66..31739cf716 100644 --- a/std/math/emulated/field_ops.go +++ b/std/math/emulated/field_ops.go @@ -9,25 +9,6 @@ import ( "github.com/consensys/gnark/frontend" ) -// DivSpecial computes a/b and returns it. It uses [DivHint] as a hint function. -// if b == 0, return 0 -func (f *Field[T]) DivSpecial(a, b *Element[T]) *Element[T] { - // omit width assertion as for a is done in AssertIsEqual and for b is done in Mul below - if !f.fParams.IsPrime() { - // TODO shouldn't we still try to do a classic int div in a hint, constraint the result, and let it fail? - // that would enable things like uint32 div ? - panic("modulus not a prime") - } - div, err := f.computeSpecialDivisionHint(a.Limbs, b.Limbs) - if err != nil { - panic(fmt.Sprintf("compute division: %v", err)) - } - e := f.packLimbs(div, true) - res := f.Mul(e, b) - f.AssertIsEqual(res, a) - return e -} - // Div computes a/b and returns it. It uses [DivHint] as a hint function. func (f *Field[T]) Div(a, b *Element[T]) *Element[T] { // omit width assertion as for a is done in AssertIsEqual and for b is done in Mul below diff --git a/std/math/emulated/hints.go b/std/math/emulated/hints.go index 26731099b8..00ecd2d8f6 100644 --- a/std/math/emulated/hints.go +++ b/std/math/emulated/hints.go @@ -19,7 +19,6 @@ func init() { func GetHints() []solver.Hint { return []solver.Hint{ DivHint, - DivSpecialHint, QuoHint, InverseHint, MultiplicationHint, @@ -203,22 +202,6 @@ func InverseHint(mod *big.Int, inputs []*big.Int, outputs []*big.Int) error { return nil } -// computeSpecialDivisionHint packs the inputs for DivisionHint hint function. -func (f *Field[T]) computeSpecialDivisionHint(nomLimbs, denomLimbs []frontend.Variable) (divLimbs []frontend.Variable, err error) { - var fp T - hintInputs := []frontend.Variable{ - fp.BitsPerLimb(), - fp.NbLimbs(), - len(denomLimbs), - len(nomLimbs), - } - p := f.Modulus() - hintInputs = append(hintInputs, p.Limbs...) - hintInputs = append(hintInputs, nomLimbs...) - hintInputs = append(hintInputs, denomLimbs...) - return f.api.NewHint(DivSpecialHint, int(fp.NbLimbs()), hintInputs...) -} - // computeDivisionHint packs the inputs for DivisionHint hint function. func (f *Field[T]) computeDivisionHint(nomLimbs, denomLimbs []frontend.Variable) (divLimbs []frontend.Variable, err error) { var fp T @@ -235,50 +218,6 @@ func (f *Field[T]) computeDivisionHint(nomLimbs, denomLimbs []frontend.Variable) return f.api.NewHint(DivHint, int(fp.NbLimbs()), hintInputs...) } -// DivSpecialHint computes the value z = x/y for inputs x and y and stores z in -// outputs. -// If y == 0, return z=0 -func DivSpecialHint(mod *big.Int, inputs []*big.Int, outputs []*big.Int) error { - if len(inputs) < 3 { - return fmt.Errorf("input must be at least three elements") - } - nbBits := uint(inputs[0].Uint64()) - nbLimbs := int(inputs[1].Int64()) - nbDenomLimbs := int(inputs[2].Int64()) - // nominator does not have to be reduced and can be more than nbLimbs. - // Denominator and order have to be nbLimbs long. - nbNomLimbs := int(inputs[3].Int64()) - if len(inputs[4:]) != nbLimbs+nbNomLimbs+nbDenomLimbs { - return fmt.Errorf("input length mismatch") - } - if len(outputs) != nbLimbs { - return fmt.Errorf("result does not fit into output") - } - p := new(big.Int) - if err := recompose(inputs[4:4+nbLimbs], nbBits, p); err != nil { - return fmt.Errorf("recompose emulated order: %w", err) - } - nominator := new(big.Int) - if err := recompose(inputs[4+nbLimbs:4+nbLimbs+nbNomLimbs], nbBits, nominator); err != nil { - return fmt.Errorf("recompose nominator: %w", err) - } - denominator := new(big.Int) - if err := recompose(inputs[4+nbLimbs+nbNomLimbs:], nbBits, denominator); err != nil { - return fmt.Errorf("recompose denominator: %w", err) - } - res := new(big.Int).ModInverse(denominator, p) - if res == nil { - // if denominator == 0, set res to 0 - res = new(big.Int) - } - res.Mul(res, nominator) - res.Mod(res, p) - if err := decompose(res, nbBits, outputs); err != nil { - return fmt.Errorf("decompose division: %w", err) - } - return nil -} - // DivHint computes the value z = x/y for inputs x and y and stores z in // outputs. func DivHint(mod *big.Int, inputs []*big.Int, outputs []*big.Int) error { From 16d4dcd2ed816d049713d5e453ad46c66595bda2 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Sun, 9 Apr 2023 10:42:28 -0500 Subject: [PATCH 247/464] feat: serialize minimal commitmentinfo with plonk vk --- backend/plonk/bls12-377/marshal.go | 2 ++ backend/plonk/bls12-377/marshal_test.go | 1 + backend/plonk/bls12-381/marshal.go | 2 ++ backend/plonk/bls12-381/marshal_test.go | 1 + backend/plonk/bls24-315/marshal.go | 2 ++ backend/plonk/bls24-315/marshal_test.go | 1 + backend/plonk/bls24-317/marshal.go | 2 ++ backend/plonk/bls24-317/marshal_test.go | 1 + backend/plonk/bn254/marshal.go | 9 ++++++++- backend/plonk/bn254/marshal_test.go | 1 + backend/plonk/bw6-633/marshal.go | 2 ++ backend/plonk/bw6-633/marshal_test.go | 1 + backend/plonk/bw6-761/marshal.go | 2 ++ backend/plonk/bw6-761/marshal_test.go | 1 + go.mod | 2 +- go.sum | 4 ++-- .../template/zkpschemes/plonk/plonk.marshal.go.tmpl | 2 ++ .../template/zkpschemes/plonk/tests/marshal.go.tmpl | 1 + 18 files changed, 33 insertions(+), 4 deletions(-) diff --git a/backend/plonk/bls12-377/marshal.go b/backend/plonk/bls12-377/marshal.go index 7446ed3377..bb75096555 100644 --- a/backend/plonk/bls12-377/marshal.go +++ b/backend/plonk/bls12-377/marshal.go @@ -226,6 +226,7 @@ func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { &vk.Qo, &vk.Qk, &vk.Qcp, + vk.CommitmentConstraintIndexes, } for _, v := range toEncode { @@ -255,6 +256,7 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { &vk.Qo, &vk.Qk, &vk.Qcp, + &vk.CommitmentConstraintIndexes, } for _, v := range toDecode { diff --git a/backend/plonk/bls12-377/marshal_test.go b/backend/plonk/bls12-377/marshal_test.go index a7798ea87b..bc928b6749 100644 --- a/backend/plonk/bls12-377/marshal_test.go +++ b/backend/plonk/bls12-377/marshal_test.go @@ -152,6 +152,7 @@ func (vk *VerifyingKey) randomize() { vk.SizeInv.SetRandom() vk.Generator.SetRandom() vk.NbPublicVariables = rand.Uint64() + vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} vk.CosetShift.SetRandom() vk.S[0] = randomPoint() diff --git a/backend/plonk/bls12-381/marshal.go b/backend/plonk/bls12-381/marshal.go index d2a7af9e91..a63b7f9ec5 100644 --- a/backend/plonk/bls12-381/marshal.go +++ b/backend/plonk/bls12-381/marshal.go @@ -226,6 +226,7 @@ func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { &vk.Qo, &vk.Qk, &vk.Qcp, + vk.CommitmentConstraintIndexes, } for _, v := range toEncode { @@ -255,6 +256,7 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { &vk.Qo, &vk.Qk, &vk.Qcp, + &vk.CommitmentConstraintIndexes, } for _, v := range toDecode { diff --git a/backend/plonk/bls12-381/marshal_test.go b/backend/plonk/bls12-381/marshal_test.go index cbefa637ad..6c86955b9f 100644 --- a/backend/plonk/bls12-381/marshal_test.go +++ b/backend/plonk/bls12-381/marshal_test.go @@ -152,6 +152,7 @@ func (vk *VerifyingKey) randomize() { vk.SizeInv.SetRandom() vk.Generator.SetRandom() vk.NbPublicVariables = rand.Uint64() + vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} vk.CosetShift.SetRandom() vk.S[0] = randomPoint() diff --git a/backend/plonk/bls24-315/marshal.go b/backend/plonk/bls24-315/marshal.go index bc9333bc74..501c5a862f 100644 --- a/backend/plonk/bls24-315/marshal.go +++ b/backend/plonk/bls24-315/marshal.go @@ -226,6 +226,7 @@ func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { &vk.Qo, &vk.Qk, &vk.Qcp, + vk.CommitmentConstraintIndexes, } for _, v := range toEncode { @@ -255,6 +256,7 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { &vk.Qo, &vk.Qk, &vk.Qcp, + &vk.CommitmentConstraintIndexes, } for _, v := range toDecode { diff --git a/backend/plonk/bls24-315/marshal_test.go b/backend/plonk/bls24-315/marshal_test.go index e3505822d7..bb4272dbee 100644 --- a/backend/plonk/bls24-315/marshal_test.go +++ b/backend/plonk/bls24-315/marshal_test.go @@ -152,6 +152,7 @@ func (vk *VerifyingKey) randomize() { vk.SizeInv.SetRandom() vk.Generator.SetRandom() vk.NbPublicVariables = rand.Uint64() + vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} vk.CosetShift.SetRandom() vk.S[0] = randomPoint() diff --git a/backend/plonk/bls24-317/marshal.go b/backend/plonk/bls24-317/marshal.go index d7742ca1e5..d569c9cb2c 100644 --- a/backend/plonk/bls24-317/marshal.go +++ b/backend/plonk/bls24-317/marshal.go @@ -226,6 +226,7 @@ func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { &vk.Qo, &vk.Qk, &vk.Qcp, + vk.CommitmentConstraintIndexes, } for _, v := range toEncode { @@ -255,6 +256,7 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { &vk.Qo, &vk.Qk, &vk.Qcp, + &vk.CommitmentConstraintIndexes, } for _, v := range toDecode { diff --git a/backend/plonk/bls24-317/marshal_test.go b/backend/plonk/bls24-317/marshal_test.go index c8cb87e43f..2c40412336 100644 --- a/backend/plonk/bls24-317/marshal_test.go +++ b/backend/plonk/bls24-317/marshal_test.go @@ -152,6 +152,7 @@ func (vk *VerifyingKey) randomize() { vk.SizeInv.SetRandom() vk.Generator.SetRandom() vk.NbPublicVariables = rand.Uint64() + vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} vk.CosetShift.SetRandom() vk.S[0] = randomPoint() diff --git a/backend/plonk/bn254/marshal.go b/backend/plonk/bn254/marshal.go index dcd81bd10d..70d010818e 100644 --- a/backend/plonk/bn254/marshal.go +++ b/backend/plonk/bn254/marshal.go @@ -17,6 +17,7 @@ package plonk import ( + "fmt" curve "github.com/consensys/gnark-crypto/ecc/bn254" "errors" @@ -226,9 +227,14 @@ func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { &vk.Qo, &vk.Qk, &vk.Qcp, + vk.CommitmentConstraintIndexes, } - for _, v := range toEncode { + for i, v := range toEncode { + if i == len(toEncode)-1 { + fmt.Println(" dis da one") + } + //fmt.Println("attempting to write") if err := enc.Encode(v); err != nil { return enc.BytesWritten(), err } @@ -255,6 +261,7 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { &vk.Qo, &vk.Qk, &vk.Qcp, + &vk.CommitmentConstraintIndexes, } for _, v := range toDecode { diff --git a/backend/plonk/bn254/marshal_test.go b/backend/plonk/bn254/marshal_test.go index 3f35b03010..0d82de6274 100644 --- a/backend/plonk/bn254/marshal_test.go +++ b/backend/plonk/bn254/marshal_test.go @@ -152,6 +152,7 @@ func (vk *VerifyingKey) randomize() { vk.SizeInv.SetRandom() vk.Generator.SetRandom() vk.NbPublicVariables = rand.Uint64() + vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} vk.CosetShift.SetRandom() vk.S[0] = randomPoint() diff --git a/backend/plonk/bw6-633/marshal.go b/backend/plonk/bw6-633/marshal.go index 043b319cd3..b57f6acb06 100644 --- a/backend/plonk/bw6-633/marshal.go +++ b/backend/plonk/bw6-633/marshal.go @@ -226,6 +226,7 @@ func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { &vk.Qo, &vk.Qk, &vk.Qcp, + vk.CommitmentConstraintIndexes, } for _, v := range toEncode { @@ -255,6 +256,7 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { &vk.Qo, &vk.Qk, &vk.Qcp, + &vk.CommitmentConstraintIndexes, } for _, v := range toDecode { diff --git a/backend/plonk/bw6-633/marshal_test.go b/backend/plonk/bw6-633/marshal_test.go index 4fa947d977..04f36f8945 100644 --- a/backend/plonk/bw6-633/marshal_test.go +++ b/backend/plonk/bw6-633/marshal_test.go @@ -152,6 +152,7 @@ func (vk *VerifyingKey) randomize() { vk.SizeInv.SetRandom() vk.Generator.SetRandom() vk.NbPublicVariables = rand.Uint64() + vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} vk.CosetShift.SetRandom() vk.S[0] = randomPoint() diff --git a/backend/plonk/bw6-761/marshal.go b/backend/plonk/bw6-761/marshal.go index 4cc8845a3f..3a1bdf39e2 100644 --- a/backend/plonk/bw6-761/marshal.go +++ b/backend/plonk/bw6-761/marshal.go @@ -226,6 +226,7 @@ func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { &vk.Qo, &vk.Qk, &vk.Qcp, + vk.CommitmentConstraintIndexes, } for _, v := range toEncode { @@ -255,6 +256,7 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { &vk.Qo, &vk.Qk, &vk.Qcp, + &vk.CommitmentConstraintIndexes, } for _, v := range toDecode { diff --git a/backend/plonk/bw6-761/marshal_test.go b/backend/plonk/bw6-761/marshal_test.go index a1228f4513..18e553b256 100644 --- a/backend/plonk/bw6-761/marshal_test.go +++ b/backend/plonk/bw6-761/marshal_test.go @@ -152,6 +152,7 @@ func (vk *VerifyingKey) randomize() { vk.SizeInv.SetRandom() vk.Generator.SetRandom() vk.NbPublicVariables = rand.Uint64() + vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} vk.CosetShift.SetRandom() vk.S[0] = randomPoint() diff --git a/go.mod b/go.mod index 5a9e32610b..196602a5bd 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/bits-and-blooms/bitset v1.5.0 github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 - github.com/consensys/gnark-crypto v0.9.2-0.20230329155745-a57dcc3b53de + github.com/consensys/gnark-crypto v0.10.1-0.20230409144652-f385aa74853e github.com/fxamacker/cbor/v2 v2.4.0 github.com/google/go-cmp v0.5.9 github.com/google/pprof v0.0.0-20230309165930-d61513b1440d diff --git a/go.sum b/go.sum index aa7606bed0..6acc9ebf91 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,8 @@ github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.9.2-0.20230329155745-a57dcc3b53de h1:W5lRxU8Rk8CDLHMTeyNst0VESbcU5RZ3U1TS9MNGgCQ= -github.com/consensys/gnark-crypto v0.9.2-0.20230329155745-a57dcc3b53de/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= +github.com/consensys/gnark-crypto v0.10.1-0.20230409144652-f385aa74853e h1:Ot7heRTeRrEy1t/MB0wCxNmCADSCE2yCewrq8z0IZBo= +github.com/consensys/gnark-crypto v0.10.1-0.20230409144652-f385aa74853e/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl index 60a5a02cdf..fc889fe30a 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl @@ -207,6 +207,7 @@ func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { &vk.Qo, &vk.Qk, &vk.Qcp, + vk.CommitmentConstraintIndexes, } for _, v := range toEncode { @@ -236,6 +237,7 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { &vk.Qo, &vk.Qk, &vk.Qcp, + &vk.CommitmentConstraintIndexes, } for _, v := range toDecode { diff --git a/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl index f1ef42add9..63d96b40f0 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl @@ -133,6 +133,7 @@ func (vk *VerifyingKey) randomize() { vk.SizeInv.SetRandom() vk.Generator.SetRandom() vk.NbPublicVariables = rand.Uint64() + vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} vk.CosetShift.SetRandom() vk.S[0] = randomPoint() From b35135989eb7ad6f300e3c0dcf120eee91ec7751 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Sun, 9 Apr 2023 11:00:43 -0500 Subject: [PATCH 248/464] build: go generate --- backend/plonk/bn254/marshal.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/backend/plonk/bn254/marshal.go b/backend/plonk/bn254/marshal.go index 70d010818e..70830adab6 100644 --- a/backend/plonk/bn254/marshal.go +++ b/backend/plonk/bn254/marshal.go @@ -17,7 +17,6 @@ package plonk import ( - "fmt" curve "github.com/consensys/gnark-crypto/ecc/bn254" "errors" @@ -230,11 +229,7 @@ func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { vk.CommitmentConstraintIndexes, } - for i, v := range toEncode { - if i == len(toEncode)-1 { - fmt.Println(" dis da one") - } - //fmt.Println("attempting to write") + for _, v := range toEncode { if err := enc.Encode(v); err != nil { return enc.BytesWritten(), err } From d23cd95b0d599091848c979acb6335dc79b13e7f Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Sun, 9 Apr 2023 19:53:02 -0500 Subject: [PATCH 249/464] feat: plonkVk.WriteRawTo --- backend/plonk/bls12-377/marshal.go | 9 +++++++++ backend/plonk/bls12-381/marshal.go | 9 +++++++++ backend/plonk/bls24-315/marshal.go | 9 +++++++++ backend/plonk/bls24-317/marshal.go | 9 +++++++++ backend/plonk/bn254/marshal.go | 9 +++++++++ backend/plonk/bw6-633/marshal.go | 9 +++++++++ backend/plonk/bw6-761/marshal.go | 9 +++++++++ .../template/zkpschemes/plonk/plonk.marshal.go.tmpl | 9 +++++++++ 8 files changed, 72 insertions(+) diff --git a/backend/plonk/bls12-377/marshal.go b/backend/plonk/bls12-377/marshal.go index bb75096555..cb66671f4d 100644 --- a/backend/plonk/bls12-377/marshal.go +++ b/backend/plonk/bls12-377/marshal.go @@ -209,6 +209,15 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { // WriteTo writes binary encoding of VerifyingKey to w func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { + return vk.writeTo(w) +} + +// WriteRawTo writes binary encoding of VerifyingKey to w without point compression +func (vk *VerifyingKey) WriteRawTo(w io.Writer) (int64, error) { + return vk.writeTo(w, curve.RawEncoding()) +} + +func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*curve.Encoder)) (n int64, err error) { enc := curve.NewEncoder(w) toEncode := []interface{}{ diff --git a/backend/plonk/bls12-381/marshal.go b/backend/plonk/bls12-381/marshal.go index a63b7f9ec5..20501d04fe 100644 --- a/backend/plonk/bls12-381/marshal.go +++ b/backend/plonk/bls12-381/marshal.go @@ -209,6 +209,15 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { // WriteTo writes binary encoding of VerifyingKey to w func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { + return vk.writeTo(w) +} + +// WriteRawTo writes binary encoding of VerifyingKey to w without point compression +func (vk *VerifyingKey) WriteRawTo(w io.Writer) (int64, error) { + return vk.writeTo(w, curve.RawEncoding()) +} + +func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*curve.Encoder)) (n int64, err error) { enc := curve.NewEncoder(w) toEncode := []interface{}{ diff --git a/backend/plonk/bls24-315/marshal.go b/backend/plonk/bls24-315/marshal.go index 501c5a862f..1327d8f7fe 100644 --- a/backend/plonk/bls24-315/marshal.go +++ b/backend/plonk/bls24-315/marshal.go @@ -209,6 +209,15 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { // WriteTo writes binary encoding of VerifyingKey to w func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { + return vk.writeTo(w) +} + +// WriteRawTo writes binary encoding of VerifyingKey to w without point compression +func (vk *VerifyingKey) WriteRawTo(w io.Writer) (int64, error) { + return vk.writeTo(w, curve.RawEncoding()) +} + +func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*curve.Encoder)) (n int64, err error) { enc := curve.NewEncoder(w) toEncode := []interface{}{ diff --git a/backend/plonk/bls24-317/marshal.go b/backend/plonk/bls24-317/marshal.go index d569c9cb2c..37d019db78 100644 --- a/backend/plonk/bls24-317/marshal.go +++ b/backend/plonk/bls24-317/marshal.go @@ -209,6 +209,15 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { // WriteTo writes binary encoding of VerifyingKey to w func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { + return vk.writeTo(w) +} + +// WriteRawTo writes binary encoding of VerifyingKey to w without point compression +func (vk *VerifyingKey) WriteRawTo(w io.Writer) (int64, error) { + return vk.writeTo(w, curve.RawEncoding()) +} + +func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*curve.Encoder)) (n int64, err error) { enc := curve.NewEncoder(w) toEncode := []interface{}{ diff --git a/backend/plonk/bn254/marshal.go b/backend/plonk/bn254/marshal.go index 70830adab6..ec0009eb93 100644 --- a/backend/plonk/bn254/marshal.go +++ b/backend/plonk/bn254/marshal.go @@ -209,6 +209,15 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { // WriteTo writes binary encoding of VerifyingKey to w func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { + return vk.writeTo(w) +} + +// WriteRawTo writes binary encoding of VerifyingKey to w without point compression +func (vk *VerifyingKey) WriteRawTo(w io.Writer) (int64, error) { + return vk.writeTo(w, curve.RawEncoding()) +} + +func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*curve.Encoder)) (n int64, err error) { enc := curve.NewEncoder(w) toEncode := []interface{}{ diff --git a/backend/plonk/bw6-633/marshal.go b/backend/plonk/bw6-633/marshal.go index b57f6acb06..1c9295df91 100644 --- a/backend/plonk/bw6-633/marshal.go +++ b/backend/plonk/bw6-633/marshal.go @@ -209,6 +209,15 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { // WriteTo writes binary encoding of VerifyingKey to w func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { + return vk.writeTo(w) +} + +// WriteRawTo writes binary encoding of VerifyingKey to w without point compression +func (vk *VerifyingKey) WriteRawTo(w io.Writer) (int64, error) { + return vk.writeTo(w, curve.RawEncoding()) +} + +func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*curve.Encoder)) (n int64, err error) { enc := curve.NewEncoder(w) toEncode := []interface{}{ diff --git a/backend/plonk/bw6-761/marshal.go b/backend/plonk/bw6-761/marshal.go index 3a1bdf39e2..2cc4c5e3fe 100644 --- a/backend/plonk/bw6-761/marshal.go +++ b/backend/plonk/bw6-761/marshal.go @@ -209,6 +209,15 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { // WriteTo writes binary encoding of VerifyingKey to w func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { + return vk.writeTo(w) +} + +// WriteRawTo writes binary encoding of VerifyingKey to w without point compression +func (vk *VerifyingKey) WriteRawTo(w io.Writer) (int64, error) { + return vk.writeTo(w, curve.RawEncoding()) +} + +func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*curve.Encoder)) (n int64, err error) { enc := curve.NewEncoder(w) toEncode := []interface{}{ diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl index fc889fe30a..49efb30461 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl @@ -190,6 +190,15 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { // WriteTo writes binary encoding of VerifyingKey to w func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { + return vk.writeTo(w) +} + +// WriteRawTo writes binary encoding of VerifyingKey to w without point compression +func (vk *VerifyingKey) WriteRawTo(w io.Writer) (int64, error) { + return vk.writeTo(w, curve.RawEncoding()) +} + +func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*curve.Encoder)) (n int64, err error) { enc := curve.NewEncoder(w) toEncode := []interface{}{ From 9d1743bb3f823122899c6f82ffb670a6ebbcf612 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 11 Apr 2023 17:13:21 +0200 Subject: [PATCH 250/464] feat: add modular square root in field emulation (#623) * feat: add sqrt * test: add sqrt test --- std/math/emulated/element_test.go | 36 +++++++++++++++++++++++++++++++ std/math/emulated/field_ops.go | 15 +++++++++++++ std/math/emulated/hints.go | 19 ++++++++++++++++ 3 files changed, 70 insertions(+) diff --git a/std/math/emulated/element_test.go b/std/math/emulated/element_test.go index 61842df893..86ab97b605 100644 --- a/std/math/emulated/element_test.go +++ b/std/math/emulated/element_test.go @@ -876,3 +876,39 @@ func testIsZero[T FieldParams](t *testing.T) { assert.ProverSucceeded(&circuit, &IsZeroCircuit[T]{X: ValueOf[T](X), Y: ValueOf[T](0), Zero: 0}, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) }, testName[T]()) } + +type SqrtCircuit[T FieldParams] struct { + X, Expected Element[T] +} + +func (c *SqrtCircuit[T]) Define(api frontend.API) error { + f, err := NewField[T](api) + if err != nil { + return err + } + res := f.Sqrt(&c.X) + f.AssertIsEqual(res, &c.Expected) + return nil +} + +func TestSqrt(t *testing.T) { + testSqrt[Goldilocks](t) + testSqrt[Secp256k1Fp](t) + testSqrt[BN254Fp](t) +} + +func testSqrt[T FieldParams](t *testing.T) { + var fp T + assert := test.NewAssert(t) + assert.Run(func(assert *test.Assert) { + var X *big.Int + exp := new(big.Int) + for { + X, _ = rand.Int(rand.Reader, fp.Modulus()) + if exp.ModSqrt(X, fp.Modulus()) != nil { + break + } + } + assert.ProverSucceeded(&SqrtCircuit[T]{}, &SqrtCircuit[T]{X: ValueOf[T](X), Expected: ValueOf[T](exp)}, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) + }, testName[T]()) +} diff --git a/std/math/emulated/field_ops.go b/std/math/emulated/field_ops.go index 31739cf716..3999aee633 100644 --- a/std/math/emulated/field_ops.go +++ b/std/math/emulated/field_ops.go @@ -44,6 +44,21 @@ func (f *Field[T]) Inverse(a *Element[T]) *Element[T] { return e } +// Sqrt computes square root of a and returns it. It uses [SqrtHint]. +func (f *Field[T]) Sqrt(a *Element[T]) *Element[T] { + // omit width assertion as is done in Mul below + if !f.fParams.IsPrime() { + panic("modulus not a prime") + } + res, err := f.NewHint(SqrtHint, 1, a) + if err != nil { + panic(fmt.Sprintf("compute sqrt: %v", err)) + } + _a := f.Mul(res[0], res[0]) + f.AssertIsEqual(_a, a) + return res[0] +} + // Add computes a+b and returns it. If the result wouldn't fit into Element, then // first reduces the inputs (larger first) and tries again. Doesn't mutate // inputs. diff --git a/std/math/emulated/hints.go b/std/math/emulated/hints.go index 00ecd2d8f6..e0aeff00ab 100644 --- a/std/math/emulated/hints.go +++ b/std/math/emulated/hints.go @@ -24,6 +24,7 @@ func GetHints() []solver.Hint { MultiplicationHint, RemHint, RightShift, + SqrtHint, } } @@ -304,3 +305,21 @@ func RightShift(_ *big.Int, inputs []*big.Int, outputs []*big.Int) error { outputs[0].Rsh(inputs[1], uint(shift)) return nil } + +// SqrtHint compute square root of the input. +func SqrtHint(mod *big.Int, inputs []*big.Int, outputs []*big.Int) error { + return UnwrapHint(inputs, outputs, func(field *big.Int, inputs, outputs []*big.Int) error { + if len(inputs) != 1 { + return fmt.Errorf("expecting single input") + } + if len(outputs) != 1 { + return fmt.Errorf("expecting single output") + } + res := new(big.Int) + if res.ModSqrt(inputs[0], field) == nil { + return fmt.Errorf("no square root") + } + outputs[0].Set(res) + return nil + }) +} From a69acbb3a572701fcafff777a4e7da1fe5cc8723 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 11 Apr 2023 15:18:57 +0000 Subject: [PATCH 251/464] chore: git ignore go workspace (#635) --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 5f2754da70..02c2647a19 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,7 @@ gnarkd/circuits/** # Jetbrains stuff .idea/ + +# go workspace +go.work +go.work.sum From ba144ccb6c7fd887900667365e2d26c12693bb58 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 11 Apr 2023 15:34:58 +0000 Subject: [PATCH 252/464] chore: point to gnark-crypto@develop --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 5a9e32610b..e27a842665 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/bits-and-blooms/bitset v1.5.0 github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 - github.com/consensys/gnark-crypto v0.9.2-0.20230329155745-a57dcc3b53de + github.com/consensys/gnark-crypto v0.10.1-0.20230411152222-ebbf6920ad59 github.com/fxamacker/cbor/v2 v2.4.0 github.com/google/go-cmp v0.5.9 github.com/google/pprof v0.0.0-20230309165930-d61513b1440d diff --git a/go.sum b/go.sum index aa7606bed0..b840dcf2ae 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/Yj github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= github.com/consensys/gnark-crypto v0.9.2-0.20230329155745-a57dcc3b53de h1:W5lRxU8Rk8CDLHMTeyNst0VESbcU5RZ3U1TS9MNGgCQ= github.com/consensys/gnark-crypto v0.9.2-0.20230329155745-a57dcc3b53de/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= +github.com/consensys/gnark-crypto v0.10.1-0.20230411152222-ebbf6920ad59 h1:KYAxBDzdiFQWO+lptSBb+7/UUHKjObS87Bx7pBGX1DU= +github.com/consensys/gnark-crypto v0.10.1-0.20230411152222-ebbf6920ad59/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= From 35b2a7a2cfcb3f46371245905f217b3042a5300e Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 11 Apr 2023 18:41:58 +0000 Subject: [PATCH 253/464] fix(ecadd): add y1+y2=0 edge case --- std/algebra/emulated/sw_emulated/point.go | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/std/algebra/emulated/sw_emulated/point.go b/std/algebra/emulated/sw_emulated/point.go index 7642b106f2..20759ec40e 100644 --- a/std/algebra/emulated/sw_emulated/point.go +++ b/std/algebra/emulated/sw_emulated/point.go @@ -131,7 +131,7 @@ func (c *Curve[B, S]) Add(p, q *AffinePoint[B]) *AffinePoint[B] { // [BriJoy02]: https://link.springer.com/content/pdf/10.1007/3-540-45664-3_24.pdf func (c *Curve[B, S]) AddUnified(p, q *AffinePoint[B]) *AffinePoint[B] { - // λ = ((p.x+q.x)² - p.x*q.x + a)/(p.y1 + q.y), if p.y + q.y = 0 + // λ = ((p.x+q.x)² - p.x*q.x + a)/(p.y1 + q.y) pxqx := c.baseApi.MulMod(&p.X, &q.X) num := c.baseApi.Add(&p.X, &q.X) num = c.baseApi.MulMod(num, num) @@ -140,6 +140,9 @@ func (c *Curve[B, S]) AddUnified(p, q *AffinePoint[B]) *AffinePoint[B] { num = c.baseApi.Add(num, &c.a) } denum := c.baseApi.Add(&p.Y, &q.Y) + // if p.y + q.y = 0, assign dummy 1 to denum and continue + selector := c.baseApi.IsZero(denum) + denum = c.baseApi.Select(selector, c.baseApi.One(), denum) λ := c.baseApi.Div(num, denum) // x = λ^2 - p.x - q.x @@ -152,10 +155,14 @@ func (c *Curve[B, S]) AddUnified(p, q *AffinePoint[B]) *AffinePoint[B] { yr = c.baseApi.MulMod(yr, λ) yr = c.baseApi.Sub(yr, &p.Y) - return &AffinePoint[B]{ - X: *c.baseApi.Reduce(xr), - Y: *c.baseApi.Reduce(yr), - } + // if p.y + q.y = 0, return (0, 0) + result := c.Select(selector, &AffinePoint[B]{X: *denum, Y: *denum}, + &AffinePoint[B]{ + X: *c.baseApi.Reduce(xr), + Y: *c.baseApi.Reduce(yr), + }) + + return result } // Double doubles p and return it. It doesn't modify p. From 0e0958ccc78c3b199f514ea17ed3d4e42a5e51cf Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 11 Apr 2023 18:54:54 +0000 Subject: [PATCH 254/464] feat: use AssertIsOnG2 for ECPAIR precompile + comments --- std/evmprecompiles/06-bnadd.go | 1 + std/evmprecompiles/07-bnmul.go | 1 + std/evmprecompiles/08-bnpairing.go | 7 +++++++ 3 files changed, 9 insertions(+) diff --git a/std/evmprecompiles/06-bnadd.go b/std/evmprecompiles/06-bnadd.go index d9eb8b32dd..43760da543 100644 --- a/std/evmprecompiles/06-bnadd.go +++ b/std/evmprecompiles/06-bnadd.go @@ -14,6 +14,7 @@ func ECAdd(api frontend.API, P, Q *sw_emulated.AffinePoint[emulated.BN254Fp]) *s if err != nil { panic(err) } + // Check that P and Q are on the curve (done in the zkEVM ⚠️ ) res := curve.Add(P, Q) return res } diff --git a/std/evmprecompiles/07-bnmul.go b/std/evmprecompiles/07-bnmul.go index 1b6d2d6fa8..eb1c02ccda 100644 --- a/std/evmprecompiles/07-bnmul.go +++ b/std/evmprecompiles/07-bnmul.go @@ -14,6 +14,7 @@ func ECMul(api frontend.API, P *sw_emulated.AffinePoint[emulated.BN254Fp], u *em if err != nil { panic(err) } + // Check that P is on the curve (done in the zkEVM ⚠️ ) res := curve.ScalarMul(P, u) return res } diff --git a/std/evmprecompiles/08-bnpairing.go b/std/evmprecompiles/08-bnpairing.go index cab5c3ad2b..01dbbab99c 100644 --- a/std/evmprecompiles/08-bnpairing.go +++ b/std/evmprecompiles/08-bnpairing.go @@ -13,6 +13,13 @@ func ECPair(api frontend.API, P []*sw_bn254.G1Affine, Q []*sw_bn254.G2Affine) { if err != nil { panic(err) } + // 1- Check that Pᵢ are on G1 (done in the zkEVM ⚠️ ) + // 2- Check that Qᵢ are on G2 + for i := 0; i < len(Q); i++ { + pair.AssertIsOnG2(Q[i]) + } + + // 3- Check that ∏ᵢ e(Pᵢ, Qᵢ) == 1 if err := pair.PairingCheck(P, Q); err != nil { panic(err) } From 19a8962c9743ce7d6c8b6417c7dff3909edc5588 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 12 Apr 2023 13:23:12 +0000 Subject: [PATCH 255/464] feat(sw_emulated): infinity as (0,0) edge-cases in UnifiedAdd --- std/algebra/emulated/sw_emulated/point.go | 34 +++-- .../emulated/sw_emulated/point_test.go | 128 ++++++++++++++++-- 2 files changed, 143 insertions(+), 19 deletions(-) diff --git a/std/algebra/emulated/sw_emulated/point.go b/std/algebra/emulated/sw_emulated/point.go index 20759ec40e..950e36d60a 100644 --- a/std/algebra/emulated/sw_emulated/point.go +++ b/std/algebra/emulated/sw_emulated/point.go @@ -124,14 +124,22 @@ func (c *Curve[B, S]) Add(p, q *AffinePoint[B]) *AffinePoint[B] { // AddUnified adds p and q and returns it. It doesn't modify p nor q. // -// ✅ p can be equal to q, but none nonzero. +// ✅ p can be equal to q, and either or both can be (0,0). +// (0,0) is not on the curve but we conventionally take it as the +// neutral/infinity point as per the EVM [EYP]. // // It uses the unified formulas of Brier and Joye [BriJoy02] (Corollary 1). // // [BriJoy02]: https://link.springer.com/content/pdf/10.1007/3-540-45664-3_24.pdf +// [EYP]: https://ethereum.github.io/yellowpaper/paper.pdf func (c *Curve[B, S]) AddUnified(p, q *AffinePoint[B]) *AffinePoint[B] { - // λ = ((p.x+q.x)² - p.x*q.x + a)/(p.y1 + q.y) + // selector1 = 1 when p is (0,0) and 0 otherwise + selector1 := c.api.And(c.baseApi.IsZero(&p.X), c.baseApi.IsZero(&p.Y)) + // selector2 = 1 when q is (0,0) and 0 otherwise + selector2 := c.api.And(c.baseApi.IsZero(&q.X), c.baseApi.IsZero(&q.Y)) + + // λ = ((p.x+q.x)² - p.x*q.x + a)/(p.y + q.y) pxqx := c.baseApi.MulMod(&p.X, &q.X) num := c.baseApi.Add(&p.X, &q.X) num = c.baseApi.MulMod(num, num) @@ -141,8 +149,8 @@ func (c *Curve[B, S]) AddUnified(p, q *AffinePoint[B]) *AffinePoint[B] { } denum := c.baseApi.Add(&p.Y, &q.Y) // if p.y + q.y = 0, assign dummy 1 to denum and continue - selector := c.baseApi.IsZero(denum) - denum = c.baseApi.Select(selector, c.baseApi.One(), denum) + selector3 := c.baseApi.IsZero(denum) + denum = c.baseApi.Select(selector3, c.baseApi.One(), denum) λ := c.baseApi.Div(num, denum) // x = λ^2 - p.x - q.x @@ -154,15 +162,21 @@ func (c *Curve[B, S]) AddUnified(p, q *AffinePoint[B]) *AffinePoint[B] { yr := c.baseApi.Sub(&p.X, xr) yr = c.baseApi.MulMod(yr, λ) yr = c.baseApi.Sub(yr, &p.Y) + result := AffinePoint[B]{ + X: *c.baseApi.Reduce(xr), + Y: *c.baseApi.Reduce(yr), + } + zero := c.baseApi.Zero() + infinity := AffinePoint[B]{X: *zero, Y: *zero} + // if p=(0,0) return q + result = *c.Select(selector1, q, &result) + // if q=(0,0) return p + result = *c.Select(selector2, p, &result) // if p.y + q.y = 0, return (0, 0) - result := c.Select(selector, &AffinePoint[B]{X: *denum, Y: *denum}, - &AffinePoint[B]{ - X: *c.baseApi.Reduce(xr), - Y: *c.baseApi.Reduce(yr), - }) + result = *c.Select(selector3, &infinity, &result) - return result + return &result } // Double doubles p and return it. It doesn't modify p. diff --git a/std/algebra/emulated/sw_emulated/point_test.go b/std/algebra/emulated/sw_emulated/point_test.go index cb3096812a..2973eca572 100644 --- a/std/algebra/emulated/sw_emulated/point_test.go +++ b/std/algebra/emulated/sw_emulated/point_test.go @@ -11,7 +11,6 @@ import ( fp_secp "github.com/consensys/gnark-crypto/ecc/secp256k1/fp" fr_secp "github.com/consensys/gnark-crypto/ecc/secp256k1/fr" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/test" ) @@ -216,6 +215,125 @@ func TestDoubleAndAdd(t *testing.T) { assert.NoError(err) } +type AddUnifiedEdgeCases[T, S emulated.FieldParams] struct { + P, Q, R AffinePoint[T] +} + +func (c *AddUnifiedEdgeCases[T, S]) Define(api frontend.API) error { + cr, err := New[T, S](api, GetCurveParams[T]()) + if err != nil { + return err + } + res := cr.AddUnified(&c.P, &c.Q) + cr.AssertIsEqual(res, &c.R) + return nil +} + +func TestAddUnifiedEdgeCases(t *testing.T) { + assert := test.NewAssert(t) + var infinity bn254.G1Affine + _, _, g, _ := bn254.Generators() + var r fr_bn.Element + _, _ = r.SetRandom() + s := new(big.Int) + r.BigInt(s) + var S, Sn bn254.G1Affine + S.ScalarMultiplication(&g, s) + Sn.Neg(&S) + + circuit := AddUnifiedEdgeCases[emulated.BN254Fp, emulated.BN254Fr]{} + + // (0,0) + (0,0) == (0,0) + witness1 := AddUnifiedEdgeCases[emulated.BN254Fp, emulated.BN254Fr]{ + P: AffinePoint[emulated.BN254Fp]{ + X: emulated.ValueOf[emulated.BN254Fp](infinity.X), + Y: emulated.ValueOf[emulated.BN254Fp](infinity.Y), + }, + Q: AffinePoint[emulated.BN254Fp]{ + X: emulated.ValueOf[emulated.BN254Fp](infinity.X), + Y: emulated.ValueOf[emulated.BN254Fp](infinity.Y), + }, + R: AffinePoint[emulated.BN254Fp]{ + X: emulated.ValueOf[emulated.BN254Fp](infinity.X), + Y: emulated.ValueOf[emulated.BN254Fp](infinity.Y), + }, + } + err := test.IsSolved(&circuit, &witness1, testCurve.ScalarField()) + assert.NoError(err) + + // S + (0,0) == S + witness2 := AddUnifiedEdgeCases[emulated.BN254Fp, emulated.BN254Fr]{ + P: AffinePoint[emulated.BN254Fp]{ + X: emulated.ValueOf[emulated.BN254Fp](S.X), + Y: emulated.ValueOf[emulated.BN254Fp](S.Y), + }, + Q: AffinePoint[emulated.BN254Fp]{ + X: emulated.ValueOf[emulated.BN254Fp](infinity.X), + Y: emulated.ValueOf[emulated.BN254Fp](infinity.Y), + }, + R: AffinePoint[emulated.BN254Fp]{ + X: emulated.ValueOf[emulated.BN254Fp](S.X), + Y: emulated.ValueOf[emulated.BN254Fp](S.Y), + }, + } + err = test.IsSolved(&circuit, &witness2, testCurve.ScalarField()) + assert.NoError(err) + + // (0,0) + S == S + witness3 := AddUnifiedEdgeCases[emulated.BN254Fp, emulated.BN254Fr]{ + P: AffinePoint[emulated.BN254Fp]{ + X: emulated.ValueOf[emulated.BN254Fp](infinity.X), + Y: emulated.ValueOf[emulated.BN254Fp](infinity.Y), + }, + Q: AffinePoint[emulated.BN254Fp]{ + X: emulated.ValueOf[emulated.BN254Fp](S.X), + Y: emulated.ValueOf[emulated.BN254Fp](S.Y), + }, + R: AffinePoint[emulated.BN254Fp]{ + X: emulated.ValueOf[emulated.BN254Fp](S.X), + Y: emulated.ValueOf[emulated.BN254Fp](S.Y), + }, + } + err = test.IsSolved(&circuit, &witness3, testCurve.ScalarField()) + assert.NoError(err) + + // S + (-S) == (0,0) + witness4 := AddUnifiedEdgeCases[emulated.BN254Fp, emulated.BN254Fr]{ + P: AffinePoint[emulated.BN254Fp]{ + X: emulated.ValueOf[emulated.BN254Fp](S.X), + Y: emulated.ValueOf[emulated.BN254Fp](S.Y), + }, + Q: AffinePoint[emulated.BN254Fp]{ + X: emulated.ValueOf[emulated.BN254Fp](Sn.X), + Y: emulated.ValueOf[emulated.BN254Fp](Sn.Y), + }, + R: AffinePoint[emulated.BN254Fp]{ + X: emulated.ValueOf[emulated.BN254Fp](infinity.X), + Y: emulated.ValueOf[emulated.BN254Fp](infinity.Y), + }, + } + err = test.IsSolved(&circuit, &witness4, testCurve.ScalarField()) + assert.NoError(err) + + // (-S) + S == (0,0) + witness5 := AddUnifiedEdgeCases[emulated.BN254Fp, emulated.BN254Fr]{ + P: AffinePoint[emulated.BN254Fp]{ + X: emulated.ValueOf[emulated.BN254Fp](Sn.X), + Y: emulated.ValueOf[emulated.BN254Fp](Sn.Y), + }, + Q: AffinePoint[emulated.BN254Fp]{ + X: emulated.ValueOf[emulated.BN254Fp](S.X), + Y: emulated.ValueOf[emulated.BN254Fp](S.Y), + }, + R: AffinePoint[emulated.BN254Fp]{ + X: emulated.ValueOf[emulated.BN254Fp](infinity.X), + Y: emulated.ValueOf[emulated.BN254Fp](infinity.Y), + }, + } + err = test.IsSolved(&circuit, &witness5, testCurve.ScalarField()) + assert.NoError(err) +} + type ScalarMulBaseTest[T, S emulated.FieldParams] struct { Q AffinePoint[T] S emulated.Element[S] @@ -251,8 +369,6 @@ func TestScalarMulBase(t *testing.T) { } err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) assert.NoError(err) - _, err = frontend.Compile(testCurve.ScalarField(), r1cs.NewBuilder, &circuit) - assert.NoError(err) } func TestScalarMulBase2(t *testing.T) { @@ -275,8 +391,6 @@ func TestScalarMulBase2(t *testing.T) { } err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) assert.NoError(err) - _, err = frontend.Compile(testCurve.ScalarField(), r1cs.NewBuilder, &circuit) - assert.NoError(err) } type ScalarMulTest[T, S emulated.FieldParams] struct { @@ -318,8 +432,6 @@ func TestScalarMul(t *testing.T) { } err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) assert.NoError(err) - _, err = frontend.Compile(testCurve.ScalarField(), r1cs.NewBuilder, &circuit) - assert.NoError(err) } func TestScalarMul2(t *testing.T) { @@ -346,6 +458,4 @@ func TestScalarMul2(t *testing.T) { } err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) assert.NoError(err) - _, err = frontend.Compile(testCurve.ScalarField(), r1cs.NewBuilder, &circuit) - assert.NoError(err) } From 44fe9afeb82cf64d8bc41d18c6721c9a3ca76358 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 12 Apr 2023 13:59:05 +0000 Subject: [PATCH 256/464] feat(sw_emulated): infinity as (0,0) edge-cases in ScalarMul --- std/algebra/emulated/sw_emulated/point.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/std/algebra/emulated/sw_emulated/point.go b/std/algebra/emulated/sw_emulated/point.go index 950e36d60a..aa86c2bde9 100644 --- a/std/algebra/emulated/sw_emulated/point.go +++ b/std/algebra/emulated/sw_emulated/point.go @@ -342,6 +342,12 @@ func (c *Curve[B, S]) Lookup2(b0, b1 frontend.Variable, i0, i1, i2, i3 *AffinePo // [ELM03]: https://arxiv.org/pdf/math/0208038.pdf // [HMV04]: https://link.springer.com/book/10.1007/b97644 func (c *Curve[B, S]) ScalarMul(p *AffinePoint[B], s *emulated.Element[S]) *AffinePoint[B] { + + // if p=(0,0) we assign a dummy (0,1) to p and continue + selector := c.api.And(c.baseApi.IsZero(&p.X), c.baseApi.IsZero(&p.Y)) + one := c.baseApi.One() + p = c.Select(selector, &AffinePoint[B]{X: *one, Y: *one}, p) + var st S sr := c.scalarApi.Reduce(s) sBits := c.scalarApi.ToBits(sr) @@ -367,9 +373,15 @@ func (c *Curve[B, S]) ScalarMul(p *AffinePoint[B], s *emulated.Element[S]) *Affi res = c.Select(sBits[n-1], tmp, res) // i = 0 - tmp = c.Add(res, c.Neg(p)) + // we use AddUnified here instead of Add so that when s=0, res=(0,0) + // because AddUnified(p, -p) = (0,0) + tmp = c.AddUnified(res, c.Neg(p)) res = c.Select(sBits[0], res, tmp) + // if p=(0,0), return (0,0) + zero := c.baseApi.Zero() + res = c.Select(selector, &AffinePoint[B]{X: *zero, Y: *zero}, res) + return res } From fa0592a0e638f4309558184249102942edf38575 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 12 Apr 2023 15:27:51 +0000 Subject: [PATCH 257/464] test(sw_emulated): infinity as (0,0) edge-cases in ScalarMul --- .../emulated/sw_emulated/point_test.go | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/std/algebra/emulated/sw_emulated/point_test.go b/std/algebra/emulated/sw_emulated/point_test.go index 2973eca572..738f019fab 100644 --- a/std/algebra/emulated/sw_emulated/point_test.go +++ b/std/algebra/emulated/sw_emulated/point_test.go @@ -459,3 +459,62 @@ func TestScalarMul2(t *testing.T) { err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) assert.NoError(err) } + +type ScalarMulEdgeCases[T, S emulated.FieldParams] struct { + P, R AffinePoint[T] + S emulated.Element[S] +} + +func (c *ScalarMulEdgeCases[T, S]) Define(api frontend.API) error { + cr, err := New[T, S](api, GetCurveParams[T]()) + if err != nil { + return err + } + res := cr.ScalarMul(&c.P, &c.S) + cr.AssertIsEqual(res, &c.R) + return nil +} + +func TestScalarMulEdgeCasesEdgeCases(t *testing.T) { + assert := test.NewAssert(t) + var infinity bn254.G1Affine + _, _, g, _ := bn254.Generators() + var r fr_bn.Element + _, _ = r.SetRandom() + s := new(big.Int) + r.BigInt(s) + var S bn254.G1Affine + S.ScalarMultiplication(&g, s) + + circuit := ScalarMulEdgeCases[emulated.BN254Fp, emulated.BN254Fr]{} + + // s * (0,0) == (0,0) + witness1 := ScalarMulEdgeCases[emulated.BN254Fp, emulated.BN254Fr]{ + S: emulated.ValueOf[emulated.BN254Fr](s), + P: AffinePoint[emulated.BN254Fp]{ + X: emulated.ValueOf[emulated.BN254Fp](infinity.X), + Y: emulated.ValueOf[emulated.BN254Fp](infinity.Y), + }, + R: AffinePoint[emulated.BN254Fp]{ + X: emulated.ValueOf[emulated.BN254Fp](infinity.X), + Y: emulated.ValueOf[emulated.BN254Fp](infinity.Y), + }, + } + err := test.IsSolved(&circuit, &witness1, testCurve.ScalarField()) + assert.NoError(err) + + // 0 * S == (0,0) + witness2 := ScalarMulEdgeCases[emulated.BN254Fp, emulated.BN254Fr]{ + S: emulated.ValueOf[emulated.BN254Fr](new(big.Int)), + P: AffinePoint[emulated.BN254Fp]{ + X: emulated.ValueOf[emulated.BN254Fp](S.X), + Y: emulated.ValueOf[emulated.BN254Fp](S.Y), + }, + R: AffinePoint[emulated.BN254Fp]{ + X: emulated.ValueOf[emulated.BN254Fp](infinity.X), + Y: emulated.ValueOf[emulated.BN254Fp](infinity.Y), + }, + } + err = test.IsSolved(&circuit, &witness2, testCurve.ScalarField()) + assert.NoError(err) +} From 855ef61ce259ef4e223a6bf68951d459cd5467b3 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 12 Apr 2023 15:41:23 +0000 Subject: [PATCH 258/464] docs: add comments to sw_emulated --- std/algebra/emulated/sw_emulated/point.go | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/std/algebra/emulated/sw_emulated/point.go b/std/algebra/emulated/sw_emulated/point.go index aa86c2bde9..10da372f05 100644 --- a/std/algebra/emulated/sw_emulated/point.go +++ b/std/algebra/emulated/sw_emulated/point.go @@ -97,7 +97,7 @@ func (c *Curve[B, S]) AssertIsEqual(p, q *AffinePoint[B]) { // Add adds p and q and returns it. It doesn't modify p nor q. // -// ⚠️ p must be different than q and both nonzero. +// ⚠️ p must be different than q and -q, and both nonzero. // // It uses incomplete formulas in affine coordinates. func (c *Curve[B, S]) Add(p, q *AffinePoint[B]) *AffinePoint[B] { @@ -180,6 +180,9 @@ func (c *Curve[B, S]) AddUnified(p, q *AffinePoint[B]) *AffinePoint[B] { } // Double doubles p and return it. It doesn't modify p. +// +// ⚠️ p.Y must be nonzero. +// // It uses affine coordinates. func (c *Curve[B, S]) Double(p *AffinePoint[B]) *AffinePoint[B] { @@ -216,6 +219,8 @@ func (c *Curve[B, S]) Double(p *AffinePoint[B]) *AffinePoint[B] { // // instead. It doesn't modify p. // +// ⚠️ p.Y must be nonzero. +// // [ELM03]: https://arxiv.org/pdf/math/0208038.pdf func (c *Curve[B, S]) Triple(p *AffinePoint[B]) *AffinePoint[B] { @@ -263,6 +268,8 @@ func (c *Curve[B, S]) Triple(p *AffinePoint[B]) *AffinePoint[B] { // // instead. It doesn't modify p nor q. // +// ⚠️ p must be different than q and -q, and both nonzero. +// // [ELM03]: https://arxiv.org/pdf/math/0208038.pdf func (c *Curve[B, S]) DoubleAndAdd(p, q *AffinePoint[B]) *AffinePoint[B] { @@ -329,6 +336,10 @@ func (c *Curve[B, S]) Lookup2(b0, b1 frontend.Variable, i0, i1, i2, i3 *AffinePo // ScalarMul computes s * p and returns it. It doesn't modify p nor s. // +// ✅ p can can be (0,0) and s can be 0. +// (0,0) is not on the curve but we conventionally take it as the +// neutral/infinity point as per the EVM [EYP]. +// // It computes the standard little-endian variable-base double-and-add algorithm // [HMV04] (Algorithm 3.26). // @@ -341,6 +352,7 @@ func (c *Curve[B, S]) Lookup2(b0, b1 frontend.Variable, i0, i1, i2, i3 *AffinePo // // [ELM03]: https://arxiv.org/pdf/math/0208038.pdf // [HMV04]: https://link.springer.com/book/10.1007/b97644 +// [EYP]: https://ethereum.github.io/yellowpaper/paper.pdf func (c *Curve[B, S]) ScalarMul(p *AffinePoint[B], s *emulated.Element[S]) *AffinePoint[B] { // if p=(0,0) we assign a dummy (0,1) to p and continue @@ -388,6 +400,10 @@ func (c *Curve[B, S]) ScalarMul(p *AffinePoint[B], s *emulated.Element[S]) *Affi // ScalarMulBase computes s * g and returns it, where g is the fixed generator. // It doesn't modify s. // +// ✅ When s=0, it retruns (0,0). +// (0,0) is not on the curve but we conventionally take it as the +// neutral/infinity point as per the EVM [EYP]. +// // It computes the standard little-endian fixed-base double-and-add algorithm // [HMV04] (Algorithm 3.26). // @@ -397,6 +413,7 @@ func (c *Curve[B, S]) ScalarMul(p *AffinePoint[B], s *emulated.Element[S]) *Affi // [3]g, [5]g and [7]g points. // // [HMV04]: https://link.springer.com/book/10.1007/b97644 +// [EYP]: https://ethereum.github.io/yellowpaper/paper.pdf func (c *Curve[B, S]) ScalarMulBase(s *emulated.Element[S]) *AffinePoint[B] { g := c.Generator() gm := c.GeneratorMultiples() @@ -416,7 +433,7 @@ func (c *Curve[B, S]) ScalarMulBase(s *emulated.Element[S]) *AffinePoint[B] { } // i = 0 - tmp := c.Add(res, c.Neg(g)) + tmp := c.AddUnified(res, c.Neg(g)) res = c.Select(sBits[0], res, tmp) return res From 460c1c906c56d4328a3658028b6af4a9c53ebcf0 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 12 Apr 2023 15:59:18 +0000 Subject: [PATCH 259/464] refactor: make double, add, triple and doubleAndAdd private --- std/algebra/emulated/sw_emulated/doc_test.go | 2 +- std/algebra/emulated/sw_emulated/point.go | 30 +++++++++---------- .../emulated/sw_emulated/point_test.go | 8 ++--- std/signature/ecdsa/ecdsa.go | 2 +- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/std/algebra/emulated/sw_emulated/doc_test.go b/std/algebra/emulated/sw_emulated/doc_test.go index bf939bfd3d..2d63969ecf 100644 --- a/std/algebra/emulated/sw_emulated/doc_test.go +++ b/std/algebra/emulated/sw_emulated/doc_test.go @@ -27,7 +27,7 @@ func (c *ExampleCurveCircuit[B, S]) Define(api frontend.API) error { g4 := curve.ScalarMul(G, &scalar4) // 4*G scalar5 := emulated.ValueOf[S](5) g5 := curve.ScalarMul(G, &scalar5) // 5*G - g9 := curve.Add(g4, g5) // 9*G + g9 := curve.AddUnified(g4, g5) // 9*G curve.AssertIsEqual(g9, &c.Res) return nil } diff --git a/std/algebra/emulated/sw_emulated/point.go b/std/algebra/emulated/sw_emulated/point.go index 10da372f05..69e3259476 100644 --- a/std/algebra/emulated/sw_emulated/point.go +++ b/std/algebra/emulated/sw_emulated/point.go @@ -95,12 +95,12 @@ func (c *Curve[B, S]) AssertIsEqual(p, q *AffinePoint[B]) { c.baseApi.AssertIsEqual(&p.Y, &q.Y) } -// Add adds p and q and returns it. It doesn't modify p nor q. +// add adds p and q and returns it. It doesn't modify p nor q. // // ⚠️ p must be different than q and -q, and both nonzero. // // It uses incomplete formulas in affine coordinates. -func (c *Curve[B, S]) Add(p, q *AffinePoint[B]) *AffinePoint[B] { +func (c *Curve[B, S]) add(p, q *AffinePoint[B]) *AffinePoint[B] { // compute λ = (q.y-p.y)/(q.x-p.x) qypy := c.baseApi.Sub(&q.Y, &p.Y) qxpx := c.baseApi.Sub(&q.X, &p.X) @@ -179,12 +179,12 @@ func (c *Curve[B, S]) AddUnified(p, q *AffinePoint[B]) *AffinePoint[B] { return &result } -// Double doubles p and return it. It doesn't modify p. +// double doubles p and return it. It doesn't modify p. // // ⚠️ p.Y must be nonzero. // // It uses affine coordinates. -func (c *Curve[B, S]) Double(p *AffinePoint[B]) *AffinePoint[B] { +func (c *Curve[B, S]) double(p *AffinePoint[B]) *AffinePoint[B] { // compute λ = (3p.x²+a)/2*p.y, here we assume a=0 (j invariant 0 curve) xx3a := c.baseApi.MulMod(&p.X, &p.X) @@ -211,7 +211,7 @@ func (c *Curve[B, S]) Double(p *AffinePoint[B]) *AffinePoint[B] { } } -// Triple triples p and return it. It follows [ELM03] (Section 3.1). +// triple triples p and return it. It follows [ELM03] (Section 3.1). // Saves the computation of the y coordinate of 2p as it is used only in the computation of λ2, // which can be computed as // @@ -222,7 +222,7 @@ func (c *Curve[B, S]) Double(p *AffinePoint[B]) *AffinePoint[B] { // ⚠️ p.Y must be nonzero. // // [ELM03]: https://arxiv.org/pdf/math/0208038.pdf -func (c *Curve[B, S]) Triple(p *AffinePoint[B]) *AffinePoint[B] { +func (c *Curve[B, S]) triple(p *AffinePoint[B]) *AffinePoint[B] { // compute λ1 = (3p.x²+a)/2p.y, here we assume a=0 (j invariant 0 curve) xx := c.baseApi.MulMod(&p.X, &p.X) @@ -260,7 +260,7 @@ func (c *Curve[B, S]) Triple(p *AffinePoint[B]) *AffinePoint[B] { } } -// DoubleAndAdd computes 2p+q as (p+q)+p. It follows [ELM03] (Section 3.1) +// doubleAndAdd computes 2p+q as (p+q)+p. It follows [ELM03] (Section 3.1) // Saves the computation of the y coordinate of p+q as it is used only in the computation of λ2, // which can be computed as // @@ -271,7 +271,7 @@ func (c *Curve[B, S]) Triple(p *AffinePoint[B]) *AffinePoint[B] { // ⚠️ p must be different than q and -q, and both nonzero. // // [ELM03]: https://arxiv.org/pdf/math/0208038.pdf -func (c *Curve[B, S]) DoubleAndAdd(p, q *AffinePoint[B]) *AffinePoint[B] { +func (c *Curve[B, S]) doubleAndAdd(p, q *AffinePoint[B]) *AffinePoint[B] { // compute λ1 = (q.y-p.y)/(q.x-p.x) yqyp := c.baseApi.Sub(&q.Y, &p.Y) @@ -366,22 +366,22 @@ func (c *Curve[B, S]) ScalarMul(p *AffinePoint[B], s *emulated.Element[S]) *Affi n := st.Modulus().BitLen() // i = 1 - tmp := c.Triple(p) + tmp := c.triple(p) res := c.Select(sBits[1], tmp, p) - acc := c.Add(tmp, p) + acc := c.add(tmp, p) for i := 2; i <= n-3; i++ { - tmp := c.Add(res, acc) + tmp := c.add(res, acc) res = c.Select(sBits[i], tmp, res) - acc = c.Double(acc) + acc = c.double(acc) } // i = n-2 - tmp = c.Add(res, acc) + tmp = c.add(res, acc) res = c.Select(sBits[n-2], tmp, res) // i = n-1 - tmp = c.DoubleAndAdd(acc, res) + tmp = c.doubleAndAdd(acc, res) res = c.Select(sBits[n-1], tmp, res) // i = 0 @@ -428,7 +428,7 @@ func (c *Curve[B, S]) ScalarMulBase(s *emulated.Element[S]) *AffinePoint[B] { for i := 3; i < st.Modulus().BitLen(); i++ { // gm[i] = [2^i]g - tmp := c.Add(res, &gm[i]) + tmp := c.add(res, &gm[i]) res = c.Select(sBits[i], tmp, res) } diff --git a/std/algebra/emulated/sw_emulated/point_test.go b/std/algebra/emulated/sw_emulated/point_test.go index 738f019fab..0b0f90fe9e 100644 --- a/std/algebra/emulated/sw_emulated/point_test.go +++ b/std/algebra/emulated/sw_emulated/point_test.go @@ -60,7 +60,7 @@ func (c *AddTest[T, S]) Define(api frontend.API) error { if err != nil { return err } - res1 := cr.Add(&c.P, &c.Q) + res1 := cr.add(&c.P, &c.Q) res2 := cr.AddUnified(&c.P, &c.Q) cr.AssertIsEqual(res1, &c.R) cr.AssertIsEqual(res2, &c.R) @@ -105,7 +105,7 @@ func (c *DoubleTest[T, S]) Define(api frontend.API) error { if err != nil { return err } - res1 := cr.Double(&c.P) + res1 := cr.double(&c.P) res2 := cr.AddUnified(&c.P, &c.P) cr.AssertIsEqual(res1, &c.Q) cr.AssertIsEqual(res2, &c.Q) @@ -143,7 +143,7 @@ func (c *TripleTest[T, S]) Define(api frontend.API) error { if err != nil { return err } - res := cr.Triple(&c.P) + res := cr.triple(&c.P) cr.AssertIsEqual(res, &c.Q) return nil } @@ -179,7 +179,7 @@ func (c *DoubleAndAddTest[T, S]) Define(api frontend.API) error { if err != nil { return err } - res := cr.DoubleAndAdd(&c.P, &c.Q) + res := cr.doubleAndAdd(&c.P, &c.Q) cr.AssertIsEqual(res, &c.R) return nil } diff --git a/std/signature/ecdsa/ecdsa.go b/std/signature/ecdsa/ecdsa.go index 86bdb5bac7..72495b303f 100644 --- a/std/signature/ecdsa/ecdsa.go +++ b/std/signature/ecdsa/ecdsa.go @@ -52,7 +52,7 @@ func (pk PublicKey[T, S]) Verify(api frontend.API, params sw_emulated.CurveParam qa := cr.ScalarMulBase(msInv) qb := cr.ScalarMul(&pkpt, rsInv) - q := cr.Add(qa, qb) + q := cr.AddUnified(qa, qb) qx := baseApi.Reduce(&q.X) qxBits := baseApi.ToBits(qx) rbits := scalarApi.ToBits(&sig.R) From 3b6747b705cbdb3f7d9f132006a9a45528514536 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 12 Apr 2023 16:03:17 +0000 Subject: [PATCH 260/464] fix: use AddUnified in ECRecover --- std/evmprecompiles/01-ecrecover.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/evmprecompiles/01-ecrecover.go b/std/evmprecompiles/01-ecrecover.go index 28fa0667a2..0c3b6df724 100644 --- a/std/evmprecompiles/01-ecrecover.go +++ b/std/evmprecompiles/01-ecrecover.go @@ -73,7 +73,7 @@ func ECRecover(api frontend.API, msg emulated.Element[emulated.Secp256k1Fr], // check u1 * G + u2 R == P A := curve.ScalarMulBase(u1) B := curve.ScalarMul(&R, u2) - C := curve.Add(A, B) + C := curve.AddUnified(A, B) curve.AssertIsEqual(C, &P) return &P } From 760d53473e8cad885416d8d45f31bda9e74124c7 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Thu, 13 Apr 2023 10:57:46 +0000 Subject: [PATCH 261/464] fix: add (0,0) case to curve membership --- std/algebra/emulated/sw_bls12381/pairing.go | 20 ++++++-- std/algebra/emulated/sw_bn254/pairing.go | 24 ++++++--- std/algebra/emulated/sw_emulated/point.go | 9 +++- .../emulated/sw_emulated/point_test.go | 51 +++++++++++++++---- 4 files changed, 83 insertions(+), 21 deletions(-) diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go index 0f15634c44..285f7cae23 100644 --- a/std/algebra/emulated/sw_bls12381/pairing.go +++ b/std/algebra/emulated/sw_bls12381/pairing.go @@ -229,24 +229,36 @@ func (pr Pairing) AssertIsEqual(x, y *GTEl) { func (pr Pairing) AssertIsOnCurve(P *G1Affine) { // Curve: Y² == X³ + aX + b, where a=0 and b=4 - four := emulated.ValueOf[emulated.BLS12381Fp](4) + // (X,Y) ∈ {Y² == X³ + aX + b} U (0,0) + + // if P=(0,0) we assign b=0 otherwise 3, and continue + selector := pr.api.And(pr.curveF.IsZero(&P.X), pr.curveF.IsZero(&P.Y)) + bCurve := emulated.ValueOf[emulated.BLS12381Fp](4) + b := pr.curveF.Select(selector, pr.curveF.Zero(), &bCurve) + left := pr.curveF.Mul(&P.Y, &P.Y) right := pr.curveF.Mul(&P.X, &P.X) right = pr.curveF.Mul(right, &P.X) - right = pr.curveF.Add(right, &four) + right = pr.curveF.Add(right, b) pr.curveF.AssertIsEqual(left, right) } func (pr Pairing) AssertIsOnTwist(Q *G2Affine) { // Twist: Y² == X³ + aX + b, where a=0 and b=4(1+u) - b := fields_bls12381.E2{ + // (X,Y) ∈ {Y² == X³ + aX + b} U (0,0) + + // if Q=(0,0) we assign b=0 otherwise 3/(9+u), and continue + selector := pr.api.And(pr.Ext2.IsZero(&Q.X), pr.Ext2.IsZero(&Q.Y)) + bTwist := fields_bls12381.E2{ A0: emulated.ValueOf[emulated.BLS12381Fp]("4"), A1: emulated.ValueOf[emulated.BLS12381Fp]("4"), } + b := pr.Ext2.Select(selector, pr.Ext2.Zero(), &bTwist) + left := pr.Ext2.Square(&Q.Y) right := pr.Ext2.Square(&Q.X) right = pr.Ext2.Mul(right, &Q.X) - right = pr.Ext2.Add(right, &b) + right = pr.Ext2.Add(right, b) pr.Ext2.AssertIsEqual(left, right) } diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index b1563011ed..09cb1d3637 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -202,7 +202,7 @@ func (pr Pairing) finalExponentiation(e *GTEl, unsafe bool) *GTEl { // Pair calculates the reduced pairing for a set of points // ∏ᵢ e(Pᵢ, Qᵢ). // -// This function doesn't check that the inputs are in the correct subgroups. +// This function doesn't check that the inputs are in the correct subgroups. See AssertIsOnG1 and AssertIsOnG2. func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { res, err := pr.MillerLoop(P, Q) if err != nil { @@ -215,7 +215,7 @@ func (pr Pairing) Pair(P []*G1Affine, Q []*G2Affine) (*GTEl, error) { // PairingCheck calculates the reduced pairing for a set of points and asserts if the result is One // ∏ᵢ e(Pᵢ, Qᵢ) =? 1 // -// This function doesn't check that the inputs are in the correct subgroups. +// This function doesn't check that the inputs are in the correct subgroups. See AssertIsOnG1 and AssertIsOnG2. func (pr Pairing) PairingCheck(P []*G1Affine, Q []*G2Affine) error { f, err := pr.Pair(P, Q) if err != nil { @@ -234,24 +234,36 @@ func (pr Pairing) AssertIsEqual(x, y *GTEl) { func (pr Pairing) AssertIsOnCurve(P *G1Affine) { // Curve: Y² == X³ + aX + b, where a=0 and b=3 - three := emulated.ValueOf[emulated.BN254Fp](3) + // (X,Y) ∈ {Y² == X³ + aX + b} U (0,0) + + // if P=(0,0) we assign b=0 otherwise 3, and continue + selector := pr.api.And(pr.curveF.IsZero(&P.X), pr.curveF.IsZero(&P.Y)) + bCurve := emulated.ValueOf[emulated.BN254Fp](3) + b := pr.curveF.Select(selector, pr.curveF.Zero(), &bCurve) + left := pr.curveF.Mul(&P.Y, &P.Y) right := pr.curveF.Mul(&P.X, &P.X) right = pr.curveF.Mul(right, &P.X) - right = pr.curveF.Add(right, &three) + right = pr.curveF.Add(right, b) pr.curveF.AssertIsEqual(left, right) } func (pr Pairing) AssertIsOnTwist(Q *G2Affine) { // Twist: Y² == X³ + aX + b, where a=0 and b=3/(9+u) - b := fields_bn254.E2{ + // (X,Y) ∈ {Y² == X³ + aX + b} U (0,0) + + // if Q=(0,0) we assign b=0 otherwise 3/(9+u), and continue + selector := pr.api.And(pr.Ext2.IsZero(&Q.X), pr.Ext2.IsZero(&Q.Y)) + bTwist := fields_bn254.E2{ A0: emulated.ValueOf[emulated.BN254Fp]("19485874751759354771024239261021720505790618469301721065564631296452457478373"), A1: emulated.ValueOf[emulated.BN254Fp]("266929791119991161246907387137283842545076965332900288569378510910307636690"), } + b := pr.Ext2.Select(selector, pr.Ext2.Zero(), &bTwist) + left := pr.Ext2.Square(&Q.Y) right := pr.Ext2.Square(&Q.X) right = pr.Ext2.Mul(right, &Q.X) - right = pr.Ext2.Add(right, &b) + right = pr.Ext2.Add(right, b) pr.Ext2.AssertIsEqual(left, right) } diff --git a/std/algebra/emulated/sw_emulated/point.go b/std/algebra/emulated/sw_emulated/point.go index 511e528825..fe87a384ad 100644 --- a/std/algebra/emulated/sw_emulated/point.go +++ b/std/algebra/emulated/sw_emulated/point.go @@ -126,10 +126,15 @@ func (c *Curve[B, S]) Add(p, q *AffinePoint[B]) *AffinePoint[B] { // AssertIsOnCurve asserts if p belongs to the curve. It doesn't modify p. func (c *Curve[B, S]) AssertIsOnCurve(p *AffinePoint[B]) { - // Y² == X³ + aX + b + // (X,Y) ∈ {Y² == X³ + aX + b} U (0,0) + + // if p=(0,0) we assign b=0 and continue + selector := c.api.And(c.baseApi.IsZero(&p.X), c.baseApi.IsZero(&p.Y)) + b := c.baseApi.Select(selector, c.baseApi.Zero(), &c.b) + left := c.baseApi.Mul(&p.Y, &p.Y) right := c.baseApi.Mul(&p.X, c.baseApi.Mul(&p.X, &p.X)) - right = c.baseApi.Add(right, &c.b) + right = c.baseApi.Add(right, b) if c.addA { ax := c.baseApi.Mul(&c.a, &p.X) right = c.baseApi.Add(right, ax) diff --git a/std/algebra/emulated/sw_emulated/point_test.go b/std/algebra/emulated/sw_emulated/point_test.go index 14c18c5c2f..d78085c9ea 100644 --- a/std/algebra/emulated/sw_emulated/point_test.go +++ b/std/algebra/emulated/sw_emulated/point_test.go @@ -420,17 +420,28 @@ func TestIsOnCurve(t *testing.T) { _, _ = r.SetRandom() s := new(big.Int) r.BigInt(s) - var Q secp256k1.G1Affine + var Q, infinity secp256k1.G1Affine Q.ScalarMultiplication(&g, s) + // Q=[s]G is on curve circuit := IsOnCurveTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{} - witness := IsOnCurveTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ + witness1 := IsOnCurveTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ Q: AffinePoint[emulated.Secp256k1Fp]{ X: emulated.ValueOf[emulated.Secp256k1Fp](Q.X), Y: emulated.ValueOf[emulated.Secp256k1Fp](Q.Y), }, } - err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) + err := test.IsSolved(&circuit, &witness1, testCurve.ScalarField()) + assert.NoError(err) + + // (0,0) is on curve + witness2 := IsOnCurveTest[emulated.Secp256k1Fp, emulated.Secp256k1Fr]{ + Q: AffinePoint[emulated.Secp256k1Fp]{ + X: emulated.ValueOf[emulated.Secp256k1Fp](infinity.X), + Y: emulated.ValueOf[emulated.Secp256k1Fp](infinity.Y), + }, + } + err = test.IsSolved(&circuit, &witness2, testCurve.ScalarField()) assert.NoError(err) } @@ -441,17 +452,28 @@ func TestIsOnCurve2(t *testing.T) { _, _ = r.SetRandom() s := new(big.Int) r.BigInt(s) - var Q bn254.G1Affine + var Q, infinity bn254.G1Affine Q.ScalarMultiplication(&g, s) + // Q=[s]G is on curve circuit := IsOnCurveTest[emulated.BN254Fp, emulated.BN254Fr]{} - witness := IsOnCurveTest[emulated.BN254Fp, emulated.BN254Fr]{ + witness1 := IsOnCurveTest[emulated.BN254Fp, emulated.BN254Fr]{ Q: AffinePoint[emulated.BN254Fp]{ X: emulated.ValueOf[emulated.BN254Fp](Q.X), Y: emulated.ValueOf[emulated.BN254Fp](Q.Y), }, } - err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) + err := test.IsSolved(&circuit, &witness1, testCurve.ScalarField()) + assert.NoError(err) + + // (0,0) is on curve + witness2 := IsOnCurveTest[emulated.BN254Fp, emulated.BN254Fr]{ + Q: AffinePoint[emulated.BN254Fp]{ + X: emulated.ValueOf[emulated.BN254Fp](infinity.X), + Y: emulated.ValueOf[emulated.BN254Fp](infinity.Y), + }, + } + err = test.IsSolved(&circuit, &witness2, testCurve.ScalarField()) assert.NoError(err) } @@ -462,16 +484,27 @@ func TestIsOnCurve3(t *testing.T) { _, _ = r.SetRandom() s := new(big.Int) r.BigInt(s) - var Q bls12381.G1Affine + var Q, infinity bls12381.G1Affine Q.ScalarMultiplication(&g, s) + // Q=[s]G is on curve circuit := IsOnCurveTest[emulated.BLS12381Fp, emulated.BLS12381Fr]{} - witness := IsOnCurveTest[emulated.BLS12381Fp, emulated.BLS12381Fr]{ + witness1 := IsOnCurveTest[emulated.BLS12381Fp, emulated.BLS12381Fr]{ Q: AffinePoint[emulated.BLS12381Fp]{ X: emulated.ValueOf[emulated.BLS12381Fp](Q.X), Y: emulated.ValueOf[emulated.BLS12381Fp](Q.Y), }, } - err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) + err := test.IsSolved(&circuit, &witness1, testCurve.ScalarField()) + assert.NoError(err) + + // (0,0) is on curve + witness2 := IsOnCurveTest[emulated.BLS12381Fp, emulated.BLS12381Fr]{ + Q: AffinePoint[emulated.BLS12381Fp]{ + X: emulated.ValueOf[emulated.BLS12381Fp](infinity.X), + Y: emulated.ValueOf[emulated.BLS12381Fp](infinity.Y), + }, + } + err = test.IsSolved(&circuit, &witness2, testCurve.ScalarField()) assert.NoError(err) } From b6cc50544f4d1368c1b5c65108ca3ce2021c0750 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Mon, 17 Apr 2023 16:57:33 +0200 Subject: [PATCH 262/464] feat(sw_bn254): G2 membership without hints --- std/algebra/emulated/sw_bn254/g2.go | 119 +++++++++++++++++++++++ std/algebra/emulated/sw_bn254/g2_test.go | 89 +++++++++++++++++ std/algebra/emulated/sw_bn254/hints.go | 43 -------- std/algebra/emulated/sw_bn254/pairing.go | 27 +++-- 4 files changed, 225 insertions(+), 53 deletions(-) create mode 100644 std/algebra/emulated/sw_bn254/g2_test.go delete mode 100644 std/algebra/emulated/sw_bn254/hints.go diff --git a/std/algebra/emulated/sw_bn254/g2.go b/std/algebra/emulated/sw_bn254/g2.go index 9fd94325c5..8c5ab4f7e6 100644 --- a/std/algebra/emulated/sw_bn254/g2.go +++ b/std/algebra/emulated/sw_bn254/g2.go @@ -1,15 +1,28 @@ package sw_bn254 import ( + "math/big" + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/algebra/emulated/fields_bn254" "github.com/consensys/gnark/std/math/emulated" ) +type G2 struct { + *fields_bn254.Ext2 +} + type G2Affine struct { X, Y fields_bn254.E2 } +func NewG2(api frontend.API) G2 { + return G2{ + Ext2: fields_bn254.NewExt2(api), + } +} + func NewG2Affine(v bn254.G2Affine) G2Affine { return G2Affine{ X: fields_bn254.E2{ @@ -22,3 +35,109 @@ func NewG2Affine(v bn254.G2Affine) G2Affine { }, } } + +func (g2 *G2) psi(q *G2Affine) *G2Affine { + u := fields_bn254.E2{ + A0: emulated.ValueOf[emulated.BN254Fp]("21575463638280843010398324269430826099269044274347216827212613867836435027261"), + A1: emulated.ValueOf[emulated.BN254Fp]("10307601595873709700152284273816112264069230130616436755625194854815875713954"), + } + v := fields_bn254.E2{ + A0: emulated.ValueOf[emulated.BN254Fp]("2821565182194536844548159561693502659359617185244120367078079554186484126554"), + A1: emulated.ValueOf[emulated.BN254Fp]("3505843767911556378687030309984248845540243509899259641013678093033130930403"), + } + + var psiq G2Affine + psiq.X = *g2.Ext2.Conjugate(&q.X) + psiq.X = *g2.Ext2.Mul(&psiq.X, &u) + psiq.Y = *g2.Ext2.Conjugate(&q.Y) + psiq.Y = *g2.Ext2.Mul(&psiq.Y, &v) + + return &psiq +} + +func (g2 *G2) scalarMulBySeed(q *G2Affine) *G2Affine { + // TODO: use 2-NAF or addchain (or maybe a ternary expansion) + var seed = [63]int8{1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1} + + // i = 62 + res := q + + for i := 61; i >= 0; i-- { + res = g2.double(res) + if seed[i] == 1 { + // TODO: use doubleAndAdd + res = g2.add(res, q) + } + } + + return res +} + +func (g2 G2) add(p, q *G2Affine) *G2Affine { + // compute λ = (q.y-p.y)/(q.x-p.x) + qypy := g2.Ext2.Sub(&q.Y, &p.Y) + qxpx := g2.Ext2.Sub(&q.X, &p.X) + // TODO: use Div + qxpx = g2.Ext2.Inverse(qxpx) + λ := g2.Ext2.Mul(qypy, qxpx) + + // xr = λ²-p.x-q.x + λλ := g2.Ext2.Mul(λ, λ) + qxpx = g2.Ext2.Add(&p.X, &q.X) + xr := g2.Ext2.Sub(λλ, qxpx) + + // p.y = λ(p.x-r.x) - p.y + pxrx := g2.Ext2.Sub(&p.X, xr) + λpxrx := g2.Ext2.Mul(λ, pxrx) + yr := g2.Ext2.Sub(λpxrx, &p.Y) + + return &G2Affine{ + X: *xr, + Y: *yr, + } +} + +func (g2 G2) neg(p *G2Affine) *G2Affine { + xr := &p.X + yr := g2.Ext2.Neg(&p.Y) + return &G2Affine{ + X: *xr, + Y: *yr, + } +} + +func (g2 G2) sub(p, q *G2Affine) *G2Affine { + qNeg := g2.neg(q) + return g2.add(p, qNeg) +} + +func (g2 *G2) double(p *G2Affine) *G2Affine { + // compute λ = (3p.x²)/2*p.y + xx3a := g2.Mul(&p.X, &p.X) + xx3a = g2.MulByConstElement(xx3a, big.NewInt(3)) + y2 := g2.Double(&p.Y) + // TODO: use Div + y2 = g2.Inverse(y2) + λ := g2.Mul(xx3a, y2) + + // xr = λ²-2p.x + x2 := g2.Double(&p.X) + λλ := g2.Mul(λ, λ) + xr := g2.Sub(λλ, x2) + + // yr = λ(p-xr) - p.y + pxrx := g2.Sub(&p.X, xr) + λpxrx := g2.Mul(λ, pxrx) + yr := g2.Sub(λpxrx, &p.Y) + + return &G2Affine{ + X: *xr, + Y: *yr, + } +} + +// AssertIsEqual asserts that p and q are the same point. +func (g2 *G2) AssertIsEqual(p, q *G2Affine) { + g2.Ext2.AssertIsEqual(&p.X, &q.X) + g2.Ext2.AssertIsEqual(&p.Y, &q.Y) +} diff --git a/std/algebra/emulated/sw_bn254/g2_test.go b/std/algebra/emulated/sw_bn254/g2_test.go new file mode 100644 index 0000000000..8a22c04063 --- /dev/null +++ b/std/algebra/emulated/sw_bn254/g2_test.go @@ -0,0 +1,89 @@ +package sw_bn254 + +import ( + "math/big" + "testing" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/test" +) + +type addG2Circuit struct { + In1, In2 G2Affine + Res G2Affine +} + +func (c *addG2Circuit) Define(api frontend.API) error { + g2 := NewG2(api) + res := g2.add(&c.In1, &c.In2) + g2.AssertIsEqual(res, &c.Res) + return nil +} + +func TestAddG2TestSolve(t *testing.T) { + assert := test.NewAssert(t) + _, in1 := randomG1G2Affines(assert) + _, in2 := randomG1G2Affines(assert) + var res bn254.G2Affine + res.Add(&in1, &in2) + witness := addG2Circuit{ + In1: NewG2Affine(in1), + In2: NewG2Affine(in2), + Res: NewG2Affine(res), + } + err := test.IsSolved(&addG2Circuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type doubleG2Circuit struct { + In1 G2Affine + Res G2Affine +} + +func (c *doubleG2Circuit) Define(api frontend.API) error { + g2 := NewG2(api) + res := g2.double(&c.In1) + g2.AssertIsEqual(res, &c.Res) + return nil +} + +func TestDoubleG2TestSolve(t *testing.T) { + assert := test.NewAssert(t) + _, in1 := randomG1G2Affines(assert) + var res bn254.G2Affine + res.Double(&in1) + witness := doubleG2Circuit{ + In1: NewG2Affine(in1), + Res: NewG2Affine(res), + } + err := test.IsSolved(&doubleG2Circuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type scalarMulG2BySeedCircuit struct { + In1 G2Affine + Res G2Affine +} + +func (c *scalarMulG2BySeedCircuit) Define(api frontend.API) error { + g2 := NewG2(api) + res := g2.scalarMulBySeed(&c.In1) + g2.AssertIsEqual(res, &c.Res) + return nil +} + +func TestScalarMulG2BySeedTestSolve(t *testing.T) { + assert := test.NewAssert(t) + _, in1 := randomG1G2Affines(assert) + var res bn254.G2Affine + x0, _ := new(big.Int).SetString("4965661367192848881", 10) + res.ScalarMultiplication(&in1, x0) + witness := scalarMulG2BySeedCircuit{ + In1: NewG2Affine(in1), + Res: NewG2Affine(res), + } + err := test.IsSolved(&scalarMulG2BySeedCircuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} diff --git a/std/algebra/emulated/sw_bn254/hints.go b/std/algebra/emulated/sw_bn254/hints.go deleted file mode 100644 index b1674afdb9..0000000000 --- a/std/algebra/emulated/sw_bn254/hints.go +++ /dev/null @@ -1,43 +0,0 @@ -package sw_bn254 - -import ( - "math/big" - - "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/std/math/emulated" -) - -func init() { - solver.RegisterHint(subgroupG2Hint) -} - -func subgroupG2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { - return emulated.UnwrapHint(nativeInputs, nativeOutputs, - func(mod *big.Int, inputs, outputs []*big.Int) error { - var a, c bn254.G2Affine - - a.X.A0.SetBigInt(inputs[0]) - a.X.A1.SetBigInt(inputs[1]) - a.Y.A0.SetBigInt(inputs[2]) - a.Y.A1.SetBigInt(inputs[3]) - - // c = ψ³([2x₀]a) - ψ²([x₀]a) - ψ([x₀]a) - [x₀]a - x0, _ := new(big.Int).SetString("4965661367192848881", 10) - var aJac, t1, t2, t3 bn254.G2Jac - aJac.FromAffine(&a) - aJac.ScalarMultiplication(&aJac, x0) - t1.Psi(&aJac) - t2.Psi(&t1) - t3.Psi(&t2).Double(&t3).Neg(&t3) - aJac.AddAssign(&t1).AddAssign(&t2).AddAssign(&t3).Neg(&aJac) - c.FromJacobian(&aJac) - - c.X.A0.BigInt(outputs[0]) - c.X.A1.BigInt(outputs[1]) - c.Y.A0.BigInt(outputs[2]) - c.Y.A1.BigInt(outputs[3]) - - return nil - }) -} diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 09cb1d3637..eb5da2957f 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -15,6 +15,7 @@ type Pairing struct { api frontend.API *fields_bn254.Ext12 curveF *emulated.Field[emulated.BN254Fp] + g2 G2 } type GTEl = fields_bn254.E12 @@ -61,6 +62,7 @@ func NewPairing(api frontend.API) (*Pairing, error) { api: api, Ext12: fields_bn254.NewExt12(api), curveF: ba, + g2: NewG2(api), }, nil } @@ -278,19 +280,24 @@ func (pr Pairing) AssertIsOnG2(Q *G2Affine) { pr.AssertIsOnTwist(Q) // 2- Check Q has the right subgroup order - res, err := pr.curveF.NewHint(subgroupG2Hint, 4, &Q.X.A0, &Q.X.A1, &Q.Y.A0, &Q.Y.A1) - if err != nil { - // err is non-nil only for invalid number of inputs - panic(err) - } + + // [x₀]Q + xQ := *pr.g2.scalarMulBySeed(Q) + // ψ([x₀]Q) + psixQ := *pr.g2.psi(&xQ) + // ψ²([x₀]Q) + // TODO: use phi instead (psi^2 = -phi) + psi2xQ := *pr.g2.psi(&psixQ) + // ψ³([2x₀]Q) + psi3xxQ := *pr.g2.double(&psi2xQ) + psi3xxQ = *pr.g2.psi(&psi3xxQ) // _Q = ψ³([2x₀]Q) - ψ²([x₀]Q) - ψ([x₀]Q) - [x₀]Q - _Q := G2Affine{ - X: fields_bn254.E2{A0: *res[0], A1: *res[1]}, - Y: fields_bn254.E2{A0: *res[2], A1: *res[3]}, - } + _Q := *pr.g2.sub(&psi3xxQ, &psi2xQ) + _Q = *pr.g2.sub(&_Q, &psixQ) + _Q = *pr.g2.sub(&_Q, &xQ) - // [r]Q == 0 <==> Q = _Q + // [r]Q == 0 <==> _Q == Q pr.Ext2.AssertIsEqual(&Q.X, &_Q.X) pr.Ext2.AssertIsEqual(&Q.Y, &_Q.Y) } From 1da8f15d35bb56aba58eda948c6cb286d6ae8a6d Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Mon, 17 Apr 2023 18:51:19 +0200 Subject: [PATCH 263/464] feat(sw_bn254): endomorphism optims for G2 membership --- std/algebra/emulated/sw_bn254/g2.go | 18 ++++++++++++------ std/algebra/emulated/sw_bn254/g2_test.go | 24 ++++++++++++++++++++++++ std/algebra/emulated/sw_bn254/pairing.go | 7 +++---- 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/std/algebra/emulated/sw_bn254/g2.go b/std/algebra/emulated/sw_bn254/g2.go index 8c5ab4f7e6..be15c491d7 100644 --- a/std/algebra/emulated/sw_bn254/g2.go +++ b/std/algebra/emulated/sw_bn254/g2.go @@ -36,6 +36,16 @@ func NewG2Affine(v bn254.G2Affine) G2Affine { } } +func (g2 *G2) phi(q *G2Affine) *G2Affine { + w := emulated.ValueOf[emulated.BN254Fp]("21888242871839275220042445260109153167277707414472061641714758635765020556616") + + var phiq G2Affine + phiq.X = *g2.Ext2.MulByElement(&q.X, &w) + phiq.Y = q.Y + + return &phiq +} + func (g2 *G2) psi(q *G2Affine) *G2Affine { u := fields_bn254.E2{ A0: emulated.ValueOf[emulated.BN254Fp]("21575463638280843010398324269430826099269044274347216827212613867836435027261"), @@ -77,9 +87,7 @@ func (g2 G2) add(p, q *G2Affine) *G2Affine { // compute λ = (q.y-p.y)/(q.x-p.x) qypy := g2.Ext2.Sub(&q.Y, &p.Y) qxpx := g2.Ext2.Sub(&q.X, &p.X) - // TODO: use Div - qxpx = g2.Ext2.Inverse(qxpx) - λ := g2.Ext2.Mul(qypy, qxpx) + λ := g2.Ext2.DivUnchecked(qypy, qxpx) // xr = λ²-p.x-q.x λλ := g2.Ext2.Mul(λ, λ) @@ -116,9 +124,7 @@ func (g2 *G2) double(p *G2Affine) *G2Affine { xx3a := g2.Mul(&p.X, &p.X) xx3a = g2.MulByConstElement(xx3a, big.NewInt(3)) y2 := g2.Double(&p.Y) - // TODO: use Div - y2 = g2.Inverse(y2) - λ := g2.Mul(xx3a, y2) + λ := g2.DivUnchecked(xx3a, y2) // xr = λ²-2p.x x2 := g2.Double(&p.X) diff --git a/std/algebra/emulated/sw_bn254/g2_test.go b/std/algebra/emulated/sw_bn254/g2_test.go index 8a22c04063..d7ccd9b848 100644 --- a/std/algebra/emulated/sw_bn254/g2_test.go +++ b/std/algebra/emulated/sw_bn254/g2_test.go @@ -87,3 +87,27 @@ func TestScalarMulG2BySeedTestSolve(t *testing.T) { err := test.IsSolved(&scalarMulG2BySeedCircuit{}, &witness, ecc.BN254.ScalarField()) assert.NoError(err) } + +type endomorphismG2Circuit struct { + In1 G2Affine +} + +func (c *endomorphismG2Circuit) Define(api frontend.API) error { + g2 := NewG2(api) + res1 := g2.phi(&c.In1) + res1 = g2.neg(res1) + res2 := g2.psi(&c.In1) + res2 = g2.psi(res2) + g2.AssertIsEqual(res1, res2) + return nil +} + +func TestEndomorphismG2TestSolve(t *testing.T) { + assert := test.NewAssert(t) + _, in1 := randomG1G2Affines(assert) + witness := endomorphismG2Circuit{ + In1: NewG2Affine(in1), + } + err := test.IsSolved(&endomorphismG2Circuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index eb5da2957f..939d4832aa 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -285,15 +285,14 @@ func (pr Pairing) AssertIsOnG2(Q *G2Affine) { xQ := *pr.g2.scalarMulBySeed(Q) // ψ([x₀]Q) psixQ := *pr.g2.psi(&xQ) - // ψ²([x₀]Q) - // TODO: use phi instead (psi^2 = -phi) - psi2xQ := *pr.g2.psi(&psixQ) + // ψ²([x₀]Q) = -ϕ([x₀]Q) + psi2xQ := *pr.g2.phi(&xQ) // ψ³([2x₀]Q) psi3xxQ := *pr.g2.double(&psi2xQ) psi3xxQ = *pr.g2.psi(&psi3xxQ) // _Q = ψ³([2x₀]Q) - ψ²([x₀]Q) - ψ([x₀]Q) - [x₀]Q - _Q := *pr.g2.sub(&psi3xxQ, &psi2xQ) + _Q := *pr.g2.sub(&psi2xQ, &psi3xxQ) _Q = *pr.g2.sub(&_Q, &psixQ) _Q = *pr.g2.sub(&_Q, &xQ) From 3979f8d2a2f17aae29bd87469614b344d2678b92 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Mon, 17 Apr 2023 19:01:25 +0200 Subject: [PATCH 264/464] perf(sw_bn254): optim of fixed scalar Mul on G2 --- std/algebra/emulated/sw_bn254/g2.go | 50 +++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/std/algebra/emulated/sw_bn254/g2.go b/std/algebra/emulated/sw_bn254/g2.go index be15c491d7..3278a91a51 100644 --- a/std/algebra/emulated/sw_bn254/g2.go +++ b/std/algebra/emulated/sw_bn254/g2.go @@ -73,10 +73,10 @@ func (g2 *G2) scalarMulBySeed(q *G2Affine) *G2Affine { res := q for i := 61; i >= 0; i-- { - res = g2.double(res) - if seed[i] == 1 { - // TODO: use doubleAndAdd - res = g2.add(res, q) + if seed[i] == 0 { + res = g2.double(res) + } else { + res = g2.doubleAndAdd(res, q) } } @@ -90,7 +90,7 @@ func (g2 G2) add(p, q *G2Affine) *G2Affine { λ := g2.Ext2.DivUnchecked(qypy, qxpx) // xr = λ²-p.x-q.x - λλ := g2.Ext2.Mul(λ, λ) + λλ := g2.Ext2.Square(λ) qxpx = g2.Ext2.Add(&p.X, &q.X) xr := g2.Ext2.Sub(λλ, qxpx) @@ -121,14 +121,14 @@ func (g2 G2) sub(p, q *G2Affine) *G2Affine { func (g2 *G2) double(p *G2Affine) *G2Affine { // compute λ = (3p.x²)/2*p.y - xx3a := g2.Mul(&p.X, &p.X) + xx3a := g2.Square(&p.X) xx3a = g2.MulByConstElement(xx3a, big.NewInt(3)) y2 := g2.Double(&p.Y) λ := g2.DivUnchecked(xx3a, y2) // xr = λ²-2p.x x2 := g2.Double(&p.X) - λλ := g2.Mul(λ, λ) + λλ := g2.Square(λ) xr := g2.Sub(λλ, x2) // yr = λ(p-xr) - p.y @@ -142,6 +142,42 @@ func (g2 *G2) double(p *G2Affine) *G2Affine { } } +func (g2 G2) doubleAndAdd(p, q *G2Affine) *G2Affine { + + // compute λ1 = (q.y-p.y)/(q.x-p.x) + yqyp := g2.Ext2.Sub(&q.Y, &p.Y) + xqxp := g2.Ext2.Sub(&q.X, &p.X) + λ1 := g2.Ext2.DivUnchecked(yqyp, xqxp) + + // compute x2 = λ1²-p.x-q.x + λ1λ1 := g2.Ext2.Square(λ1) + xqxp = g2.Ext2.Add(&p.X, &q.X) + x2 := g2.Ext2.Sub(λ1λ1, xqxp) + + // ommit y2 computation + // compute λ2 = -λ1-2*p.y/(x2-p.x) + ypyp := g2.Ext2.Add(&p.Y, &p.Y) + x2xp := g2.Ext2.Sub(x2, &p.X) + λ2 := g2.Ext2.DivUnchecked(ypyp, x2xp) + λ2 = g2.Ext2.Add(λ1, λ2) + λ2 = g2.Ext2.Neg(λ2) + + // compute x3 =λ2²-p.x-x3 + λ2λ2 := g2.Ext2.Square(λ2) + x3 := g2.Ext2.Sub(λ2λ2, &p.X) + x3 = g2.Ext2.Sub(x3, x2) + + // compute y3 = λ2*(p.x - x3)-p.y + y3 := g2.Ext2.Sub(&p.X, x3) + y3 = g2.Ext2.Mul(λ2, y3) + y3 = g2.Ext2.Sub(y3, &p.Y) + + return &G2Affine{ + X: *x3, + Y: *y3, + } +} + // AssertIsEqual asserts that p and q are the same point. func (g2 *G2) AssertIsEqual(p, q *G2Affine) { g2.Ext2.AssertIsEqual(&p.X, &q.X) From 73f927c994bc51dcee74a507c6c7777feb0b42b4 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Mon, 17 Apr 2023 19:14:46 +0200 Subject: [PATCH 265/464] perf(sw_bn254): use 2-NAF for fixed scalar Mul on G2 --- std/algebra/emulated/sw_bn254/g2.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/std/algebra/emulated/sw_bn254/g2.go b/std/algebra/emulated/sw_bn254/g2.go index 3278a91a51..95bbfd8e63 100644 --- a/std/algebra/emulated/sw_bn254/g2.go +++ b/std/algebra/emulated/sw_bn254/g2.go @@ -66,17 +66,21 @@ func (g2 *G2) psi(q *G2Affine) *G2Affine { } func (g2 *G2) scalarMulBySeed(q *G2Affine) *G2Affine { - // TODO: use 2-NAF or addchain (or maybe a ternary expansion) - var seed = [63]int8{1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1} + + qNeg := g2.neg(q) + seed := [66]int8{1, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, -1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0, -1, 0, -1, 0, 1, 0, 1, 0, 0, -1, 0, 1, 0, 1, 0, -1, 0, 0, 1, 0, 1, 0, 0, 0, 1} // i = 62 res := q for i := 61; i >= 0; i-- { - if seed[i] == 0 { + switch seed[i] { + case 0: res = g2.double(res) - } else { + case 1: res = g2.doubleAndAdd(res, q) + case -1: + res = g2.doubleAndAdd(res, qNeg) } } From ead049caef13abac48dabe20a48a23d5568d67e7 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Mon, 17 Apr 2023 19:27:54 +0200 Subject: [PATCH 266/464] fix(sw_bn254): fix size of 2-naf table of the seed --- std/algebra/emulated/sw_bn254/g2.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/algebra/emulated/sw_bn254/g2.go b/std/algebra/emulated/sw_bn254/g2.go index 95bbfd8e63..41429b6f03 100644 --- a/std/algebra/emulated/sw_bn254/g2.go +++ b/std/algebra/emulated/sw_bn254/g2.go @@ -68,7 +68,7 @@ func (g2 *G2) psi(q *G2Affine) *G2Affine { func (g2 *G2) scalarMulBySeed(q *G2Affine) *G2Affine { qNeg := g2.neg(q) - seed := [66]int8{1, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, -1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0, -1, 0, -1, 0, 1, 0, 1, 0, 0, -1, 0, 1, 0, 1, 0, -1, 0, 0, 1, 0, 1, 0, 0, 0, 1} + seed := [63]int8{1, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, -1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0, -1, 0, -1, 0, 1, 0, 1, 0, 0, -1, 0, 1, 0, 1, 0, -1, 0, 0, 1, 0, 1, 0, 0, 0, 1} // i = 62 res := q From b5caf13020e018f0e5c75d5dd28e5dd4b62a240f Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Mon, 17 Apr 2023 19:52:08 +0200 Subject: [PATCH 267/464] perf(sw_bn254): use addchain/doubleAndAdd for fixed scalar mul --- std/algebra/emulated/sw_bn254/g2.go | 59 +++++++++++++++++++---------- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/std/algebra/emulated/sw_bn254/g2.go b/std/algebra/emulated/sw_bn254/g2.go index 41429b6f03..bd6505cbb5 100644 --- a/std/algebra/emulated/sw_bn254/g2.go +++ b/std/algebra/emulated/sw_bn254/g2.go @@ -66,25 +66,38 @@ func (g2 *G2) psi(q *G2Affine) *G2Affine { } func (g2 *G2) scalarMulBySeed(q *G2Affine) *G2Affine { - - qNeg := g2.neg(q) - seed := [63]int8{1, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, -1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0, -1, 0, -1, 0, 1, 0, 1, 0, 0, -1, 0, 1, 0, 1, 0, -1, 0, 0, 1, 0, 1, 0, 0, 0, 1} - - // i = 62 - res := q - - for i := 61; i >= 0; i-- { - switch seed[i] { - case 0: - res = g2.double(res) - case 1: - res = g2.doubleAndAdd(res, q) - case -1: - res = g2.doubleAndAdd(res, qNeg) - } - } - - return res + z := g2.double(q) + t0 := g2.add(q, z) + t2 := g2.add(q, t0) + t1 := g2.add(z, t2) + z = g2.doubleAndAdd(t1, t0) + t0 = g2.add(t0, z) + t2 = g2.add(t2, t0) + t1 = g2.add(t1, t2) + t0 = g2.add(t0, t1) + t1 = g2.add(t1, t0) + t0 = g2.add(t0, t1) + t2 = g2.add(t2, t0) + t1 = g2.doubleAndAdd(t2, t1) + t2 = g2.add(t2, t1) + z = g2.add(z, t2) + t2 = g2.add(t2, z) + z = g2.doubleAndAdd(t2, z) + t0 = g2.add(t0, z) + t1 = g2.add(t1, t0) + t3 := g2.double(t1) + t3 = g2.doubleAndAdd(t3, t1) + t2 = g2.add(t2, t3) + t1 = g2.add(t1, t2) + t2 = g2.add(t2, t1) + t2 = g2.doubleN(t2, 16) + t1 = g2.doubleAndAdd(t2, t1) + t1 = g2.doubleN(t1, 13) + t0 = g2.doubleAndAdd(t1, t0) + t0 = g2.doubleN(t0, 15) + z = g2.doubleAndAdd(t0, z) + + return z } func (g2 G2) add(p, q *G2Affine) *G2Affine { @@ -146,6 +159,14 @@ func (g2 *G2) double(p *G2Affine) *G2Affine { } } +func (g2 *G2) doubleN(p *G2Affine, n int) *G2Affine { + pn := p + for s := 0; s < n; s++ { + pn = g2.double(pn) + } + return pn +} + func (g2 G2) doubleAndAdd(p, q *G2Affine) *G2Affine { // compute λ1 = (q.y-p.y)/(q.x-p.x) From e955bb54d8af13ba7554d7f8d56520ceb7927650 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Mon, 17 Apr 2023 20:18:19 +0200 Subject: [PATCH 268/464] fix: use jacobain double for test --- std/algebra/emulated/sw_bn254/g2_test.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/std/algebra/emulated/sw_bn254/g2_test.go b/std/algebra/emulated/sw_bn254/g2_test.go index d7ccd9b848..8aa5ae6cef 100644 --- a/std/algebra/emulated/sw_bn254/g2_test.go +++ b/std/algebra/emulated/sw_bn254/g2_test.go @@ -53,7 +53,10 @@ func TestDoubleG2TestSolve(t *testing.T) { assert := test.NewAssert(t) _, in1 := randomG1G2Affines(assert) var res bn254.G2Affine - res.Double(&in1) + var in1Jac, resJac bn254.G2Jac + in1Jac.FromAffine(&in1) + resJac.Double(&in1Jac) + res.FromJacobian(&resJac) witness := doubleG2Circuit{ In1: NewG2Affine(in1), Res: NewG2Affine(res), From 25687ff70a3685497f328b5432d862e528b3311c Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 18 Apr 2023 00:42:10 +0200 Subject: [PATCH 269/464] fix: field emulation subtract padding compute (#603) * fix: subtraction padding computation Previously when computing the next overflow after subtraction we took it as max(a.overflow+1, b.overflow+1), but it isn't correct due to wrong assumptions. Actually, the padding is always one larger than b.overflow (we compute it as such). And the next overflow is one more than max(padding, a.overflow) as when we add a and padding we may get an overflow bit. * test: update circuit statistics --- internal/stats/latest.stats | Bin 2803 -> 2803 bytes std/math/emulated/field_ops.go | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/stats/latest.stats b/internal/stats/latest.stats index b7d8ec2a89a11baee3905b98988693d0543bf5a8..fdd16f591d66d9dfcf382c161ac3407de8cde5d1 100644 GIT binary patch delta 57 zcmV-90LK6G74sF4YLm|a;E`&DlUE3YlZ*rClg0$sle`J#liLX4ldl5ZlXL`9k?-J> Podw;Kp$by7dIsGAPVXG2 delta 58 zcmV-A0LB0F74sF4YLiL~ljjHBvla>60h7-G Qgp>CK;gb>s<&(q+QXTRd(f|Me diff --git a/std/math/emulated/field_ops.go b/std/math/emulated/field_ops.go index 3999aee633..26125e7eaf 100644 --- a/std/math/emulated/field_ops.go +++ b/std/math/emulated/field_ops.go @@ -251,8 +251,8 @@ func (f *Field[T]) subNoReduce(a, b *Element[T]) *Element[T] { } func (f *Field[T]) subPreCond(a, b *Element[T]) (nextOverflow uint, err error) { - reduceRight := (a.overflow + 1) < (b.overflow + 1) - nextOverflow = max(b.overflow+1, a.overflow+1) + reduceRight := a.overflow < (b.overflow + 1) + nextOverflow = max(b.overflow+1, a.overflow) + 1 if nextOverflow > f.maxOverflow() { err = overflowError{op: "sub", nextOverflow: nextOverflow, maxOverflow: f.maxOverflow(), reduceRight: reduceRight} } From 6f3bf1f309cb0b51bba7b2f1fb23f282d05bd989 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 18 Apr 2023 00:44:54 +0200 Subject: [PATCH 270/464] docs: point at infinity --- std/algebra/emulated/sw_emulated/point.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/std/algebra/emulated/sw_emulated/point.go b/std/algebra/emulated/sw_emulated/point.go index 69e3259476..46bdd8d5fc 100644 --- a/std/algebra/emulated/sw_emulated/point.go +++ b/std/algebra/emulated/sw_emulated/point.go @@ -77,6 +77,9 @@ func (c *Curve[B, S]) GeneratorMultiples() []AffinePoint[B] { // AffinePoint represents a point on the elliptic curve. We do not check that // the point is actually on the curve. +// +// Point (0,0) represents point at the infinity. This representation is +// compatible with the EVM representations of points at infinity. type AffinePoint[Base emulated.FieldParams] struct { X, Y emulated.Element[Base] } From c262b0bc22aeb7e0bc23d8998e190839bd96c553 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 18 Apr 2023 00:45:25 +0200 Subject: [PATCH 271/464] docs: godoc linking --- std/algebra/emulated/sw_emulated/point.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/std/algebra/emulated/sw_emulated/point.go b/std/algebra/emulated/sw_emulated/point.go index 46bdd8d5fc..fad898b9ba 100644 --- a/std/algebra/emulated/sw_emulated/point.go +++ b/std/algebra/emulated/sw_emulated/point.go @@ -129,12 +129,12 @@ func (c *Curve[B, S]) add(p, q *AffinePoint[B]) *AffinePoint[B] { // // ✅ p can be equal to q, and either or both can be (0,0). // (0,0) is not on the curve but we conventionally take it as the -// neutral/infinity point as per the EVM [EYP]. +// neutral/infinity point as per the [EVM]. // -// It uses the unified formulas of Brier and Joye [BriJoy02] (Corollary 1). +// It uses the unified formulas of Brier and Joye ([[BriJoy02]] (Corollary 1)). // // [BriJoy02]: https://link.springer.com/content/pdf/10.1007/3-540-45664-3_24.pdf -// [EYP]: https://ethereum.github.io/yellowpaper/paper.pdf +// [EVM]: https://ethereum.github.io/yellowpaper/paper.pdf func (c *Curve[B, S]) AddUnified(p, q *AffinePoint[B]) *AffinePoint[B] { // selector1 = 1 when p is (0,0) and 0 otherwise @@ -341,7 +341,7 @@ func (c *Curve[B, S]) Lookup2(b0, b1 frontend.Variable, i0, i1, i2, i3 *AffinePo // // ✅ p can can be (0,0) and s can be 0. // (0,0) is not on the curve but we conventionally take it as the -// neutral/infinity point as per the EVM [EYP]. +// neutral/infinity point as per the [EVM]. // // It computes the standard little-endian variable-base double-and-add algorithm // [HMV04] (Algorithm 3.26). @@ -355,7 +355,7 @@ func (c *Curve[B, S]) Lookup2(b0, b1 frontend.Variable, i0, i1, i2, i3 *AffinePo // // [ELM03]: https://arxiv.org/pdf/math/0208038.pdf // [HMV04]: https://link.springer.com/book/10.1007/b97644 -// [EYP]: https://ethereum.github.io/yellowpaper/paper.pdf +// [EVM]: https://ethereum.github.io/yellowpaper/paper.pdf func (c *Curve[B, S]) ScalarMul(p *AffinePoint[B], s *emulated.Element[S]) *AffinePoint[B] { // if p=(0,0) we assign a dummy (0,1) to p and continue @@ -405,7 +405,7 @@ func (c *Curve[B, S]) ScalarMul(p *AffinePoint[B], s *emulated.Element[S]) *Affi // // ✅ When s=0, it retruns (0,0). // (0,0) is not on the curve but we conventionally take it as the -// neutral/infinity point as per the EVM [EYP]. +// neutral/infinity point as per the [EVM]. // // It computes the standard little-endian fixed-base double-and-add algorithm // [HMV04] (Algorithm 3.26). @@ -416,7 +416,7 @@ func (c *Curve[B, S]) ScalarMul(p *AffinePoint[B], s *emulated.Element[S]) *Affi // [3]g, [5]g and [7]g points. // // [HMV04]: https://link.springer.com/book/10.1007/b97644 -// [EYP]: https://ethereum.github.io/yellowpaper/paper.pdf +// [EVM]: https://ethereum.github.io/yellowpaper/paper.pdf func (c *Curve[B, S]) ScalarMulBase(s *emulated.Element[S]) *AffinePoint[B] { g := c.Generator() gm := c.GeneratorMultiples() From 44f60fcba0af6099433c20ffac47a22d52efbd98 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 18 Apr 2023 00:46:32 +0200 Subject: [PATCH 272/464] docs: typo --- std/algebra/emulated/sw_emulated/point.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/algebra/emulated/sw_emulated/point.go b/std/algebra/emulated/sw_emulated/point.go index fad898b9ba..e234fbdd98 100644 --- a/std/algebra/emulated/sw_emulated/point.go +++ b/std/algebra/emulated/sw_emulated/point.go @@ -403,7 +403,7 @@ func (c *Curve[B, S]) ScalarMul(p *AffinePoint[B], s *emulated.Element[S]) *Affi // ScalarMulBase computes s * g and returns it, where g is the fixed generator. // It doesn't modify s. // -// ✅ When s=0, it retruns (0,0). +// ✅ When s=0, it returns (0,0). // (0,0) is not on the curve but we conventionally take it as the // neutral/infinity point as per the [EVM]. // From 4ba43d34008d96d6614602ac2a5d36f8775830b6 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 18 Apr 2023 01:03:27 +0200 Subject: [PATCH 273/464] docs: comment about AddUnified --- std/algebra/emulated/sw_emulated/doc.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/std/algebra/emulated/sw_emulated/doc.go b/std/algebra/emulated/sw_emulated/doc.go index 5ff58f9467..dc83a96fcb 100644 --- a/std/algebra/emulated/sw_emulated/doc.go +++ b/std/algebra/emulated/sw_emulated/doc.go @@ -10,6 +10,10 @@ over some base field 𝐅p for some constants a, b ∈ 𝐅p. Additionally, for every curve we also define its generator (base point) G. All these parameters are stored in the variable of type [CurveParams]. +This package implements unified and complete point addition. The method +[Curve.AddUnified] can be used for point additions or in case of points at +infinity. As such, this package does not expose separate Add and Double methods. + The package provides a few curve parameters, see functions [GetSecp256k1Params] and [GetBN254Params]. From 259043eb6a7142e35e35f42c58cdc7a77cc47efd Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 18 Apr 2023 01:05:17 +0200 Subject: [PATCH 274/464] perf: optimise one sub --- std/algebra/emulated/sw_emulated/point.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/std/algebra/emulated/sw_emulated/point.go b/std/algebra/emulated/sw_emulated/point.go index e234fbdd98..c5a56dabd4 100644 --- a/std/algebra/emulated/sw_emulated/point.go +++ b/std/algebra/emulated/sw_emulated/point.go @@ -144,8 +144,8 @@ func (c *Curve[B, S]) AddUnified(p, q *AffinePoint[B]) *AffinePoint[B] { // λ = ((p.x+q.x)² - p.x*q.x + a)/(p.y + q.y) pxqx := c.baseApi.MulMod(&p.X, &q.X) - num := c.baseApi.Add(&p.X, &q.X) - num = c.baseApi.MulMod(num, num) + pxplusqx := c.baseApi.Add(&p.X, &q.X) + num := c.baseApi.MulMod(pxplusqx, pxplusqx) num = c.baseApi.Sub(num, pxqx) if c.addA { num = c.baseApi.Add(num, &c.a) @@ -158,8 +158,7 @@ func (c *Curve[B, S]) AddUnified(p, q *AffinePoint[B]) *AffinePoint[B] { // x = λ^2 - p.x - q.x xr := c.baseApi.MulMod(λ, λ) - xr = c.baseApi.Sub(xr, &p.X) - xr = c.baseApi.Sub(xr, &q.X) + xr = c.baseApi.Sub(xr, pxplusqx) // y = λ(p.x - xr) - p.y yr := c.baseApi.Sub(&p.X, xr) From 0d17cd7109efc8d5be4165a2d9f58b91fed7a61c Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 18 Apr 2023 01:36:10 +0200 Subject: [PATCH 275/464] refactor: init emulated constants once --- std/algebra/emulated/sw_bn254/g2.go | 31 ++++++++++++++++------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/std/algebra/emulated/sw_bn254/g2.go b/std/algebra/emulated/sw_bn254/g2.go index bd6505cbb5..5b9336d16f 100644 --- a/std/algebra/emulated/sw_bn254/g2.go +++ b/std/algebra/emulated/sw_bn254/g2.go @@ -11,6 +11,8 @@ import ( type G2 struct { *fields_bn254.Ext2 + w *emulated.Element[emulated.BN254Fp] + u, v *fields_bn254.E2 } type G2Affine struct { @@ -18,8 +20,20 @@ type G2Affine struct { } func NewG2(api frontend.API) G2 { + w := emulated.ValueOf[emulated.BN254Fp]("21888242871839275220042445260109153167277707414472061641714758635765020556616") + u := fields_bn254.E2{ + A0: emulated.ValueOf[emulated.BN254Fp]("21575463638280843010398324269430826099269044274347216827212613867836435027261"), + A1: emulated.ValueOf[emulated.BN254Fp]("10307601595873709700152284273816112264069230130616436755625194854815875713954"), + } + v := fields_bn254.E2{ + A0: emulated.ValueOf[emulated.BN254Fp]("2821565182194536844548159561693502659359617185244120367078079554186484126554"), + A1: emulated.ValueOf[emulated.BN254Fp]("3505843767911556378687030309984248845540243509899259641013678093033130930403"), + } return G2{ Ext2: fields_bn254.NewExt2(api), + w: &w, + u: &u, + v: &v, } } @@ -37,30 +51,19 @@ func NewG2Affine(v bn254.G2Affine) G2Affine { } func (g2 *G2) phi(q *G2Affine) *G2Affine { - w := emulated.ValueOf[emulated.BN254Fp]("21888242871839275220042445260109153167277707414472061641714758635765020556616") - var phiq G2Affine - phiq.X = *g2.Ext2.MulByElement(&q.X, &w) + phiq.X = *g2.Ext2.MulByElement(&q.X, g2.w) phiq.Y = q.Y return &phiq } func (g2 *G2) psi(q *G2Affine) *G2Affine { - u := fields_bn254.E2{ - A0: emulated.ValueOf[emulated.BN254Fp]("21575463638280843010398324269430826099269044274347216827212613867836435027261"), - A1: emulated.ValueOf[emulated.BN254Fp]("10307601595873709700152284273816112264069230130616436755625194854815875713954"), - } - v := fields_bn254.E2{ - A0: emulated.ValueOf[emulated.BN254Fp]("2821565182194536844548159561693502659359617185244120367078079554186484126554"), - A1: emulated.ValueOf[emulated.BN254Fp]("3505843767911556378687030309984248845540243509899259641013678093033130930403"), - } - var psiq G2Affine psiq.X = *g2.Ext2.Conjugate(&q.X) - psiq.X = *g2.Ext2.Mul(&psiq.X, &u) + psiq.X = *g2.Ext2.Mul(&psiq.X, g2.u) psiq.Y = *g2.Ext2.Conjugate(&q.Y) - psiq.Y = *g2.Ext2.Mul(&psiq.Y, &v) + psiq.Y = *g2.Ext2.Mul(&psiq.Y, g2.v) return &psiq } From d6a723205229239547e130b650d0623b14de88a1 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 18 Apr 2023 01:51:30 +0200 Subject: [PATCH 276/464] refactor: g2 gadget as pointer --- std/algebra/emulated/sw_bn254/g2.go | 4 ++-- std/algebra/emulated/sw_bn254/pairing.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/std/algebra/emulated/sw_bn254/g2.go b/std/algebra/emulated/sw_bn254/g2.go index 5b9336d16f..5daa790c7b 100644 --- a/std/algebra/emulated/sw_bn254/g2.go +++ b/std/algebra/emulated/sw_bn254/g2.go @@ -19,7 +19,7 @@ type G2Affine struct { X, Y fields_bn254.E2 } -func NewG2(api frontend.API) G2 { +func NewG2(api frontend.API) *G2 { w := emulated.ValueOf[emulated.BN254Fp]("21888242871839275220042445260109153167277707414472061641714758635765020556616") u := fields_bn254.E2{ A0: emulated.ValueOf[emulated.BN254Fp]("21575463638280843010398324269430826099269044274347216827212613867836435027261"), @@ -29,7 +29,7 @@ func NewG2(api frontend.API) G2 { A0: emulated.ValueOf[emulated.BN254Fp]("2821565182194536844548159561693502659359617185244120367078079554186484126554"), A1: emulated.ValueOf[emulated.BN254Fp]("3505843767911556378687030309984248845540243509899259641013678093033130930403"), } - return G2{ + return &G2{ Ext2: fields_bn254.NewExt2(api), w: &w, u: &u, diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 939d4832aa..5934392ddb 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -15,7 +15,7 @@ type Pairing struct { api frontend.API *fields_bn254.Ext12 curveF *emulated.Field[emulated.BN254Fp] - g2 G2 + g2 *G2 } type GTEl = fields_bn254.E12 From 8c87b181c71aa77a4403905ef46690a89d810934 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 18 Apr 2023 01:52:13 +0200 Subject: [PATCH 277/464] docs: subgroup check in doc-example --- std/algebra/emulated/sw_bls12381/doc_test.go | 4 ++++ std/algebra/emulated/sw_bn254/doc_test.go | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/std/algebra/emulated/sw_bls12381/doc_test.go b/std/algebra/emulated/sw_bls12381/doc_test.go index ae87b72997..a1ce0f5ca5 100644 --- a/std/algebra/emulated/sw_bls12381/doc_test.go +++ b/std/algebra/emulated/sw_bls12381/doc_test.go @@ -23,6 +23,10 @@ func (c *PairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } + // Pair method does not check that the points are in the proper groups. + pairing.AssertIsOnG1(&c.InG1) + pairing.AssertIsOnG2(&c.InG2) + // Compute the pairing res, err := pairing.Pair([]*sw_bls12381.G1Affine{&c.InG1}, []*sw_bls12381.G2Affine{&c.InG2}) if err != nil { return fmt.Errorf("pair: %w", err) diff --git a/std/algebra/emulated/sw_bn254/doc_test.go b/std/algebra/emulated/sw_bn254/doc_test.go index db095a0210..7d8ef6a6cd 100644 --- a/std/algebra/emulated/sw_bn254/doc_test.go +++ b/std/algebra/emulated/sw_bn254/doc_test.go @@ -23,6 +23,10 @@ func (c *PairCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new pairing: %w", err) } + // Pair method does not check that the points are in the proper groups. + pairing.AssertIsOnG1(&c.InG1) + pairing.AssertIsOnG2(&c.InG2) + // Compute the pairing res, err := pairing.Pair([]*sw_bn254.G1Affine{&c.InG1}, []*sw_bn254.G2Affine{&c.InG2}) if err != nil { return fmt.Errorf("pair: %w", err) From c89e53653cd6d3711f4d85bd6ea0e4db5819c7a9 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 18 Apr 2023 01:56:41 +0200 Subject: [PATCH 278/464] refactor: init point at return --- std/algebra/emulated/sw_bn254/g2.go | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/std/algebra/emulated/sw_bn254/g2.go b/std/algebra/emulated/sw_bn254/g2.go index 5daa790c7b..71026f66f0 100644 --- a/std/algebra/emulated/sw_bn254/g2.go +++ b/std/algebra/emulated/sw_bn254/g2.go @@ -51,21 +51,24 @@ func NewG2Affine(v bn254.G2Affine) G2Affine { } func (g2 *G2) phi(q *G2Affine) *G2Affine { - var phiq G2Affine - phiq.X = *g2.Ext2.MulByElement(&q.X, g2.w) - phiq.Y = q.Y + x := g2.Ext2.MulByElement(&q.X, g2.w) - return &phiq + return &G2Affine{ + X: *x, + Y: q.Y, + } } func (g2 *G2) psi(q *G2Affine) *G2Affine { - var psiq G2Affine - psiq.X = *g2.Ext2.Conjugate(&q.X) - psiq.X = *g2.Ext2.Mul(&psiq.X, g2.u) - psiq.Y = *g2.Ext2.Conjugate(&q.Y) - psiq.Y = *g2.Ext2.Mul(&psiq.Y, g2.v) + x := g2.Ext2.Conjugate(&q.X) + x = g2.Ext2.Mul(x, g2.u) + y := g2.Ext2.Conjugate(&q.Y) + y = g2.Ext2.Mul(y, g2.v) - return &psiq + return &G2Affine{ + X: *x, + Y: *y, + } } func (g2 *G2) scalarMulBySeed(q *G2Affine) *G2Affine { From ee8e8836dcfd2a297d051b52bdbca6b8f42ef140 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 18 Apr 2023 02:08:04 +0200 Subject: [PATCH 279/464] refactor: use assertIsOnCurve from sw_emulated --- std/algebra/emulated/sw_bls12381/pairing.go | 21 ++++++++------------- std/algebra/emulated/sw_bn254/pairing.go | 21 ++++++++------------- 2 files changed, 16 insertions(+), 26 deletions(-) diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go index 285f7cae23..3344d5edf4 100644 --- a/std/algebra/emulated/sw_bls12381/pairing.go +++ b/std/algebra/emulated/sw_bls12381/pairing.go @@ -8,6 +8,7 @@ import ( bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/algebra/emulated/fields_bls12381" + "github.com/consensys/gnark/std/algebra/emulated/sw_emulated" "github.com/consensys/gnark/std/math/emulated" ) @@ -15,6 +16,7 @@ type Pairing struct { api frontend.API *fields_bls12381.Ext12 curveF *emulated.Field[emulated.BLS12381Fp] + curve *sw_emulated.Curve[emulated.BLS12381Fp, emulated.BLS12381Fr] } type GTEl = fields_bls12381.E12 @@ -57,10 +59,15 @@ func NewPairing(api frontend.API) (*Pairing, error) { if err != nil { return nil, fmt.Errorf("new base api: %w", err) } + curve, err := sw_emulated.New[emulated.BLS12381Fp, emulated.BLS12381Fr](api, sw_emulated.GetBLS12381Params()) + if err != nil { + return nil, fmt.Errorf("new curve: %w", err) + } return &Pairing{ api: api, Ext12: fields_bls12381.NewExt12(api), curveF: ba, + curve: curve, }, nil } @@ -228,19 +235,7 @@ func (pr Pairing) AssertIsEqual(x, y *GTEl) { } func (pr Pairing) AssertIsOnCurve(P *G1Affine) { - // Curve: Y² == X³ + aX + b, where a=0 and b=4 - // (X,Y) ∈ {Y² == X³ + aX + b} U (0,0) - - // if P=(0,0) we assign b=0 otherwise 3, and continue - selector := pr.api.And(pr.curveF.IsZero(&P.X), pr.curveF.IsZero(&P.Y)) - bCurve := emulated.ValueOf[emulated.BLS12381Fp](4) - b := pr.curveF.Select(selector, pr.curveF.Zero(), &bCurve) - - left := pr.curveF.Mul(&P.Y, &P.Y) - right := pr.curveF.Mul(&P.X, &P.X) - right = pr.curveF.Mul(right, &P.X) - right = pr.curveF.Add(right, b) - pr.curveF.AssertIsEqual(left, right) + pr.curve.AssertIsOnCurve(P) } func (pr Pairing) AssertIsOnTwist(Q *G2Affine) { diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 5934392ddb..686b85ad12 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -8,6 +8,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/algebra/emulated/fields_bn254" + "github.com/consensys/gnark/std/algebra/emulated/sw_emulated" "github.com/consensys/gnark/std/math/emulated" ) @@ -15,6 +16,7 @@ type Pairing struct { api frontend.API *fields_bn254.Ext12 curveF *emulated.Field[emulated.BN254Fp] + curve *sw_emulated.Curve[emulated.BN254Fp, emulated.BN254Fr] g2 *G2 } @@ -58,10 +60,15 @@ func NewPairing(api frontend.API) (*Pairing, error) { if err != nil { return nil, fmt.Errorf("new base api: %w", err) } + curve, err := sw_emulated.New[emulated.BN254Fp, emulated.BN254Fr](api, sw_emulated.GetBN254Params()) + if err != nil { + return nil, fmt.Errorf("new curve: %w", err) + } return &Pairing{ api: api, Ext12: fields_bn254.NewExt12(api), curveF: ba, + curve: curve, g2: NewG2(api), }, nil } @@ -235,19 +242,7 @@ func (pr Pairing) AssertIsEqual(x, y *GTEl) { } func (pr Pairing) AssertIsOnCurve(P *G1Affine) { - // Curve: Y² == X³ + aX + b, where a=0 and b=3 - // (X,Y) ∈ {Y² == X³ + aX + b} U (0,0) - - // if P=(0,0) we assign b=0 otherwise 3, and continue - selector := pr.api.And(pr.curveF.IsZero(&P.X), pr.curveF.IsZero(&P.Y)) - bCurve := emulated.ValueOf[emulated.BN254Fp](3) - b := pr.curveF.Select(selector, pr.curveF.Zero(), &bCurve) - - left := pr.curveF.Mul(&P.Y, &P.Y) - right := pr.curveF.Mul(&P.X, &P.X) - right = pr.curveF.Mul(right, &P.X) - right = pr.curveF.Add(right, b) - pr.curveF.AssertIsEqual(left, right) + pr.curve.AssertIsOnCurve(P) } func (pr Pairing) AssertIsOnTwist(Q *G2Affine) { From 36ee060ff50731d14b88e0117ec6affc2c410036 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 18 Apr 2023 02:12:26 +0200 Subject: [PATCH 280/464] refactor: init b of twist once --- std/algebra/emulated/sw_bn254/pairing.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 686b85ad12..0602451f82 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -18,6 +18,7 @@ type Pairing struct { curveF *emulated.Field[emulated.BN254Fp] curve *sw_emulated.Curve[emulated.BN254Fp, emulated.BN254Fr] g2 *G2 + bTwist *fields_bn254.E2 } type GTEl = fields_bn254.E12 @@ -64,12 +65,17 @@ func NewPairing(api frontend.API) (*Pairing, error) { if err != nil { return nil, fmt.Errorf("new curve: %w", err) } + bTwist := fields_bn254.E2{ + A0: emulated.ValueOf[emulated.BN254Fp]("19485874751759354771024239261021720505790618469301721065564631296452457478373"), + A1: emulated.ValueOf[emulated.BN254Fp]("266929791119991161246907387137283842545076965332900288569378510910307636690"), + } return &Pairing{ api: api, Ext12: fields_bn254.NewExt12(api), curveF: ba, curve: curve, g2: NewG2(api), + bTwist: &bTwist, }, nil } @@ -251,11 +257,7 @@ func (pr Pairing) AssertIsOnTwist(Q *G2Affine) { // if Q=(0,0) we assign b=0 otherwise 3/(9+u), and continue selector := pr.api.And(pr.Ext2.IsZero(&Q.X), pr.Ext2.IsZero(&Q.Y)) - bTwist := fields_bn254.E2{ - A0: emulated.ValueOf[emulated.BN254Fp]("19485874751759354771024239261021720505790618469301721065564631296452457478373"), - A1: emulated.ValueOf[emulated.BN254Fp]("266929791119991161246907387137283842545076965332900288569378510910307636690"), - } - b := pr.Ext2.Select(selector, pr.Ext2.Zero(), &bTwist) + b := pr.Ext2.Select(selector, pr.Ext2.Zero(), pr.bTwist) left := pr.Ext2.Square(&Q.Y) right := pr.Ext2.Square(&Q.X) From 93604b78ac50f50113016a337e59f60f0a9d25f1 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 18 Apr 2023 02:13:08 +0200 Subject: [PATCH 281/464] refactor: in method work with pointers instead of values --- std/algebra/emulated/sw_bn254/pairing.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 0602451f82..852c731bae 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -279,19 +279,19 @@ func (pr Pairing) AssertIsOnG2(Q *G2Affine) { // 2- Check Q has the right subgroup order // [x₀]Q - xQ := *pr.g2.scalarMulBySeed(Q) + xQ := pr.g2.scalarMulBySeed(Q) // ψ([x₀]Q) - psixQ := *pr.g2.psi(&xQ) + psixQ := pr.g2.psi(xQ) // ψ²([x₀]Q) = -ϕ([x₀]Q) - psi2xQ := *pr.g2.phi(&xQ) + psi2xQ := pr.g2.phi(xQ) // ψ³([2x₀]Q) - psi3xxQ := *pr.g2.double(&psi2xQ) - psi3xxQ = *pr.g2.psi(&psi3xxQ) + psi3xxQ := pr.g2.double(psi2xQ) + psi3xxQ = pr.g2.psi(psi3xxQ) // _Q = ψ³([2x₀]Q) - ψ²([x₀]Q) - ψ([x₀]Q) - [x₀]Q - _Q := *pr.g2.sub(&psi2xQ, &psi3xxQ) - _Q = *pr.g2.sub(&_Q, &psixQ) - _Q = *pr.g2.sub(&_Q, &xQ) + _Q := pr.g2.sub(psi2xQ, psi3xxQ) + _Q = pr.g2.sub(_Q, psixQ) + _Q = pr.g2.sub(_Q, xQ) // [r]Q == 0 <==> _Q == Q pr.Ext2.AssertIsEqual(&Q.X, &_Q.X) From af9d1d4efdf88285683628bdf0d2ceb435a4a8b6 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 18 Apr 2023 15:01:30 +0200 Subject: [PATCH 282/464] feat(sw_bls12381): G1 and G2 membership without hints --- std/algebra/emulated/sw_bls12381/g1.go | 29 +++ std/algebra/emulated/sw_bls12381/g2.go | 195 ++++++++++++++++++++ std/algebra/emulated/sw_bls12381/g2_test.go | 120 ++++++++++++ std/algebra/emulated/sw_bls12381/hints.go | 68 ------- std/algebra/emulated/sw_bls12381/pairing.go | 81 ++++---- std/algebra/emulated/sw_bn254/g2_test.go | 28 +++ std/algebra/emulated/sw_bn254/pairing.go | 3 +- 7 files changed, 405 insertions(+), 119 deletions(-) create mode 100644 std/algebra/emulated/sw_bls12381/g2_test.go delete mode 100644 std/algebra/emulated/sw_bls12381/hints.go diff --git a/std/algebra/emulated/sw_bls12381/g1.go b/std/algebra/emulated/sw_bls12381/g1.go index fd95f4722b..f7908b5ded 100644 --- a/std/algebra/emulated/sw_bls12381/g1.go +++ b/std/algebra/emulated/sw_bls12381/g1.go @@ -1,7 +1,10 @@ package sw_bls12381 import ( + "fmt" + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/algebra/emulated/sw_emulated" "github.com/consensys/gnark/std/math/emulated" ) @@ -14,3 +17,29 @@ func NewG1Affine(v bls12381.G1Affine) G1Affine { Y: emulated.ValueOf[emulated.BLS12381Fp](v.Y), } } + +type G1 struct { + curveF *emulated.Field[emulated.BLS12381Fp] + w *emulated.Element[emulated.BLS12381Fp] +} + +func NewG1(api frontend.API) (*G1, error) { + ba, err := emulated.NewField[emulated.BLS12381Fp](api) + if err != nil { + return nil, fmt.Errorf("new base api: %w", err) + } + w := emulated.ValueOf[emulated.BLS12381Fp]("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436") + return &G1{ + curveF: ba, + w: &w, + }, nil +} + +func (g1 *G1) phi(q *G1Affine) *G1Affine { + x := g1.curveF.Mul(&q.X, g1.w) + + return &G1Affine{ + X: *x, + Y: q.Y, + } +} diff --git a/std/algebra/emulated/sw_bls12381/g2.go b/std/algebra/emulated/sw_bls12381/g2.go index f96ea4c354..45077a6cba 100644 --- a/std/algebra/emulated/sw_bls12381/g2.go +++ b/std/algebra/emulated/sw_bls12381/g2.go @@ -1,15 +1,39 @@ package sw_bls12381 import ( + "math/big" + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/algebra/emulated/fields_bls12381" "github.com/consensys/gnark/std/math/emulated" ) +type G2 struct { + *fields_bls12381.Ext2 + u1, w *emulated.Element[emulated.BLS12381Fp] + v *fields_bls12381.E2 +} + type G2Affine struct { X, Y fields_bls12381.E2 } +func NewG2(api frontend.API) *G2 { + w := emulated.ValueOf[emulated.BLS12381Fp]("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436") + u1 := emulated.ValueOf[emulated.BLS12381Fp]("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437") + v := fields_bls12381.E2{ + A0: emulated.ValueOf[emulated.BLS12381Fp]("2973677408986561043442465346520108879172042883009249989176415018091420807192182638567116318576472649347015917690530"), + A1: emulated.ValueOf[emulated.BLS12381Fp]("1028732146235106349975324479215795277384839936929757896155643118032610843298655225875571310552543014690878354869257"), + } + return &G2{ + Ext2: fields_bls12381.NewExt2(api), + w: &w, + u1: &u1, + v: &v, + } +} + func NewG2Affine(v bls12381.G2Affine) G2Affine { return G2Affine{ X: fields_bls12381.E2{ @@ -22,3 +46,174 @@ func NewG2Affine(v bls12381.G2Affine) G2Affine { }, } } + +func (g2 *G2) psi(q *G2Affine) *G2Affine { + x := g2.Ext2.MulByElement(&q.X, g2.u1) + y := g2.Ext2.Conjugate(&q.Y) + y = g2.Ext2.Mul(y, g2.v) + + return &G2Affine{ + X: fields_bls12381.E2{A0: x.A1, A1: x.A0}, + Y: *y, + } +} + +func (g2 *G2) scalarMulBySeed(q *G2Affine) *G2Affine { + + z := g2.triple(q) + z = g2.double(z) + z = g2.doubleAndAdd(z, q) + z = g2.doubleN(z, 2) + z = g2.doubleAndAdd(z, q) + z = g2.doubleN(z, 8) + z = g2.doubleAndAdd(z, q) + z = g2.doubleN(z, 31) + z = g2.doubleAndAdd(z, q) + z = g2.doubleN(z, 16) + + return g2.neg(z) +} + +func (g2 G2) add(p, q *G2Affine) *G2Affine { + // compute λ = (q.y-p.y)/(q.x-p.x) + qypy := g2.Ext2.Sub(&q.Y, &p.Y) + qxpx := g2.Ext2.Sub(&q.X, &p.X) + λ := g2.Ext2.DivUnchecked(qypy, qxpx) + + // xr = λ²-p.x-q.x + λλ := g2.Ext2.Square(λ) + qxpx = g2.Ext2.Add(&p.X, &q.X) + xr := g2.Ext2.Sub(λλ, qxpx) + + // p.y = λ(p.x-r.x) - p.y + pxrx := g2.Ext2.Sub(&p.X, xr) + λpxrx := g2.Ext2.Mul(λ, pxrx) + yr := g2.Ext2.Sub(λpxrx, &p.Y) + + return &G2Affine{ + X: *xr, + Y: *yr, + } +} + +func (g2 G2) neg(p *G2Affine) *G2Affine { + xr := &p.X + yr := g2.Ext2.Neg(&p.Y) + return &G2Affine{ + X: *xr, + Y: *yr, + } +} + +func (g2 G2) sub(p, q *G2Affine) *G2Affine { + qNeg := g2.neg(q) + return g2.add(p, qNeg) +} + +func (g2 *G2) double(p *G2Affine) *G2Affine { + // compute λ = (3p.x²)/2*p.y + xx3a := g2.Square(&p.X) + xx3a = g2.MulByConstElement(xx3a, big.NewInt(3)) + y2 := g2.Double(&p.Y) + λ := g2.DivUnchecked(xx3a, y2) + + // xr = λ²-2p.x + x2 := g2.Double(&p.X) + λλ := g2.Square(λ) + xr := g2.Sub(λλ, x2) + + // yr = λ(p-xr) - p.y + pxrx := g2.Sub(&p.X, xr) + λpxrx := g2.Mul(λ, pxrx) + yr := g2.Sub(λpxrx, &p.Y) + + return &G2Affine{ + X: *xr, + Y: *yr, + } +} + +func (g2 *G2) doubleN(p *G2Affine, n int) *G2Affine { + pn := p + for s := 0; s < n; s++ { + pn = g2.double(pn) + } + return pn +} + +func (g2 G2) triple(p *G2Affine) *G2Affine { + + // compute λ1 = (3p.x²)/2p.y + xx := g2.Square(&p.X) + xx = g2.MulByConstElement(xx, big.NewInt(3)) + y2 := g2.Double(&p.Y) + λ1 := g2.DivUnchecked(xx, y2) + + // xr = λ1²-2p.x + x2 := g2.MulByConstElement(&p.X, big.NewInt(2)) + λ1λ1 := g2.Square(λ1) + x2 = g2.Sub(λ1λ1, x2) + + // ommit y2 computation, and + // compute λ2 = 2p.y/(x2 − p.x) − λ1. + x1x2 := g2.Sub(&p.X, x2) + λ2 := g2.DivUnchecked(y2, x1x2) + λ2 = g2.Sub(λ2, λ1) + + // xr = λ²-p.x-x2 + λ2λ2 := g2.Square(λ2) + qxrx := g2.Add(x2, &p.X) + xr := g2.Sub(λ2λ2, qxrx) + + // yr = λ(p.x-xr) - p.y + pxrx := g2.Sub(&p.X, xr) + λ2pxrx := g2.Mul(λ2, pxrx) + yr := g2.Sub(λ2pxrx, &p.Y) + + return &G2Affine{ + X: *xr, + Y: *yr, + } +} + +func (g2 G2) doubleAndAdd(p, q *G2Affine) *G2Affine { + + // compute λ1 = (q.y-p.y)/(q.x-p.x) + yqyp := g2.Ext2.Sub(&q.Y, &p.Y) + xqxp := g2.Ext2.Sub(&q.X, &p.X) + λ1 := g2.Ext2.DivUnchecked(yqyp, xqxp) + + // compute x2 = λ1²-p.x-q.x + λ1λ1 := g2.Ext2.Square(λ1) + xqxp = g2.Ext2.Add(&p.X, &q.X) + x2 := g2.Ext2.Sub(λ1λ1, xqxp) + + // ommit y2 computation + // compute λ2 = -λ1-2*p.y/(x2-p.x) + ypyp := g2.Ext2.Add(&p.Y, &p.Y) + x2xp := g2.Ext2.Sub(x2, &p.X) + λ2 := g2.Ext2.DivUnchecked(ypyp, x2xp) + λ2 = g2.Ext2.Add(λ1, λ2) + λ2 = g2.Ext2.Neg(λ2) + + // compute x3 =λ2²-p.x-x3 + λ2λ2 := g2.Ext2.Square(λ2) + x3 := g2.Ext2.Sub(λ2λ2, &p.X) + x3 = g2.Ext2.Sub(x3, x2) + + // compute y3 = λ2*(p.x - x3)-p.y + y3 := g2.Ext2.Sub(&p.X, x3) + y3 = g2.Ext2.Mul(λ2, y3) + y3 = g2.Ext2.Sub(y3, &p.Y) + + return &G2Affine{ + X: *x3, + Y: *y3, + } +} + +// AssertIsEqual asserts that p and q are the same point. +func (g2 *G2) AssertIsEqual(p, q *G2Affine) { + g2.Ext2.AssertIsEqual(&p.X, &q.X) + g2.Ext2.AssertIsEqual(&p.Y, &q.Y) +} diff --git a/std/algebra/emulated/sw_bls12381/g2_test.go b/std/algebra/emulated/sw_bls12381/g2_test.go new file mode 100644 index 0000000000..76937d9623 --- /dev/null +++ b/std/algebra/emulated/sw_bls12381/g2_test.go @@ -0,0 +1,120 @@ +package sw_bls12381 + +import ( + "math/big" + "testing" + + "github.com/consensys/gnark-crypto/ecc" + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/test" +) + +type addG2Circuit struct { + In1, In2 G2Affine + Res G2Affine +} + +func (c *addG2Circuit) Define(api frontend.API) error { + g2 := NewG2(api) + res := g2.add(&c.In1, &c.In2) + g2.AssertIsEqual(res, &c.Res) + return nil +} + +func TestAddG2TestSolve(t *testing.T) { + assert := test.NewAssert(t) + _, in1 := randomG1G2Affines(assert) + _, in2 := randomG1G2Affines(assert) + var res bls12381.G2Affine + res.Add(&in1, &in2) + witness := addG2Circuit{ + In1: NewG2Affine(in1), + In2: NewG2Affine(in2), + Res: NewG2Affine(res), + } + err := test.IsSolved(&addG2Circuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type doubleG2Circuit struct { + In1 G2Affine + Res G2Affine +} + +func (c *doubleG2Circuit) Define(api frontend.API) error { + g2 := NewG2(api) + res := g2.double(&c.In1) + g2.AssertIsEqual(res, &c.Res) + return nil +} + +func TestDoubleG2TestSolve(t *testing.T) { + assert := test.NewAssert(t) + _, in1 := randomG1G2Affines(assert) + var res bls12381.G2Affine + var in1Jac, resJac bls12381.G2Jac + in1Jac.FromAffine(&in1) + resJac.Double(&in1Jac) + res.FromJacobian(&resJac) + witness := doubleG2Circuit{ + In1: NewG2Affine(in1), + Res: NewG2Affine(res), + } + err := test.IsSolved(&doubleG2Circuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type doubleAndAddG2Circuit struct { + In1, In2 G2Affine + Res G2Affine +} + +func (c *doubleAndAddG2Circuit) Define(api frontend.API) error { + g2 := NewG2(api) + res := g2.doubleAndAdd(&c.In1, &c.In2) + g2.AssertIsEqual(res, &c.Res) + return nil +} + +func TestDoubleAndAddG2TestSolve(t *testing.T) { + assert := test.NewAssert(t) + _, in1 := randomG1G2Affines(assert) + _, in2 := randomG1G2Affines(assert) + var res bls12381.G2Affine + res.Double(&in1). + Add(&res, &in2) + witness := doubleAndAddG2Circuit{ + In1: NewG2Affine(in1), + In2: NewG2Affine(in2), + Res: NewG2Affine(res), + } + err := test.IsSolved(&doubleAndAddG2Circuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type scalarMulG2BySeedCircuit struct { + In1 G2Affine + Res G2Affine +} + +func (c *scalarMulG2BySeedCircuit) Define(api frontend.API) error { + g2 := NewG2(api) + res := g2.scalarMulBySeed(&c.In1) + g2.AssertIsEqual(res, &c.Res) + return nil +} + +func TestScalarMulG2BySeedTestSolve(t *testing.T) { + assert := test.NewAssert(t) + _, in1 := randomG1G2Affines(assert) + var res bls12381.G2Affine + x0, _ := new(big.Int).SetString("15132376222941642752", 10) + res.ScalarMultiplication(&in1, x0).Neg(&res) + witness := scalarMulG2BySeedCircuit{ + In1: NewG2Affine(in1), + Res: NewG2Affine(res), + } + err := test.IsSolved(&scalarMulG2BySeedCircuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} diff --git a/std/algebra/emulated/sw_bls12381/hints.go b/std/algebra/emulated/sw_bls12381/hints.go deleted file mode 100644 index b9f34dcc1a..0000000000 --- a/std/algebra/emulated/sw_bls12381/hints.go +++ /dev/null @@ -1,68 +0,0 @@ -package sw_bls12381 - -import ( - "math/big" - - bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/std/math/emulated" -) - -func init() { - solver.RegisterHint(GetHints()...) -} - -// GetHints returns all hint functions used in the package. -func GetHints() []solver.Hint { - return []solver.Hint{ - subgroupG1Hint, - subgroupG2Hint, - } -} - -func subgroupG1Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { - return emulated.UnwrapHint(nativeInputs, nativeOutputs, - func(mod *big.Int, inputs, outputs []*big.Int) error { - var a, c bls12381.G1Affine - - a.X.SetBigInt(inputs[0]) - a.Y.SetBigInt(inputs[1]) - - // c = -[x²]ϕ(p) - x0, _ := new(big.Int).SetString("15132376222941642752", 10) // negative - var jac bls12381.G1Jac - jac.FromAffine(&a) - jac.Phi(&jac).ScalarMultiplication(&jac, x0). - ScalarMultiplication(&jac, x0). - Neg(&jac) - c.FromJacobian(&jac) - - c.X.BigInt(outputs[0]) - c.Y.BigInt(outputs[1]) - - return nil - }) -} - -func subgroupG2Hint(nativeMod *big.Int, nativeInputs, nativeOutputs []*big.Int) error { - return emulated.UnwrapHint(nativeInputs, nativeOutputs, - func(mod *big.Int, inputs, outputs []*big.Int) error { - var a, c bls12381.G2Affine - - a.X.A0.SetBigInt(inputs[0]) - a.X.A1.SetBigInt(inputs[1]) - a.Y.A0.SetBigInt(inputs[2]) - a.Y.A1.SetBigInt(inputs[3]) - - // c = [x₀]a - x0, _ := new(big.Int).SetString("15132376222941642752", 10) // negative - c.ScalarMultiplication(&a, x0).Neg(&c) - - c.X.A0.BigInt(outputs[0]) - c.X.A1.BigInt(outputs[1]) - c.Y.A0.BigInt(outputs[2]) - c.Y.A1.BigInt(outputs[3]) - - return nil - }) -} diff --git a/std/algebra/emulated/sw_bls12381/pairing.go b/std/algebra/emulated/sw_bls12381/pairing.go index 3344d5edf4..58038989c0 100644 --- a/std/algebra/emulated/sw_bls12381/pairing.go +++ b/std/algebra/emulated/sw_bls12381/pairing.go @@ -16,7 +16,10 @@ type Pairing struct { api frontend.API *fields_bls12381.Ext12 curveF *emulated.Field[emulated.BLS12381Fp] + g2 *G2 + g1 *G1 curve *sw_emulated.Curve[emulated.BLS12381Fp, emulated.BLS12381Fr] + bTwist *fields_bls12381.E2 } type GTEl = fields_bls12381.E12 @@ -63,11 +66,22 @@ func NewPairing(api frontend.API) (*Pairing, error) { if err != nil { return nil, fmt.Errorf("new curve: %w", err) } + bTwist := fields_bls12381.E2{ + A0: emulated.ValueOf[emulated.BLS12381Fp]("4"), + A1: emulated.ValueOf[emulated.BLS12381Fp]("4"), + } + g1, err := NewG1(api) + if err != nil { + return nil, fmt.Errorf("new G1 struct: %w", err) + } return &Pairing{ api: api, Ext12: fields_bls12381.NewExt12(api), curveF: ba, curve: curve, + g1: g1, + g2: NewG2(api), + bTwist: &bTwist, }, nil } @@ -244,11 +258,8 @@ func (pr Pairing) AssertIsOnTwist(Q *G2Affine) { // if Q=(0,0) we assign b=0 otherwise 3/(9+u), and continue selector := pr.api.And(pr.Ext2.IsZero(&Q.X), pr.Ext2.IsZero(&Q.Y)) - bTwist := fields_bls12381.E2{ - A0: emulated.ValueOf[emulated.BLS12381Fp]("4"), - A1: emulated.ValueOf[emulated.BLS12381Fp]("4"), - } - b := pr.Ext2.Select(selector, pr.Ext2.Zero(), &bTwist) + + b := pr.Ext2.Select(selector, pr.Ext2.Zero(), pr.bTwist) left := pr.Ext2.Square(&Q.Y) right := pr.Ext2.Square(&Q.X) @@ -262,21 +273,16 @@ func (pr Pairing) AssertIsOnG1(P *G1Affine) { pr.AssertIsOnCurve(P) // 2- Check P has the right subgroup order - res, err := pr.curveF.NewHint(subgroupG1Hint, 2, &P.X, &P.Y) - if err != nil { - // err is non-nil only for invalid number of inputs - panic(err) - } - - // _P = -[x²]ϕ(p) - _P := G1Affine{ - X: *res[0], - Y: *res[1], - } - - // [r]Q == 0 <==> P = _P - pr.curveF.AssertIsEqual(&P.X, &_P.X) - pr.curveF.AssertIsEqual(&P.Y, &_P.Y) + // TODO: add phi and scalarMulBySeedSquare to g1.go + // [x²]ϕ(P) + phiP := pr.g1.phi(P) + seedSquare := emulated.ValueOf[emulated.BLS12381Fr]("228988810152649578064853576960394133504") + // TODO: use addchain to construct a fixed-scalar ScalarMul + _P := pr.curve.ScalarMul(phiP, &seedSquare) + _P = pr.curve.Neg(_P) + + // [r]Q == 0 <==> P = -[x²]ϕ(P) + pr.curve.AssertIsEqual(_P, P) } func (pr Pairing) AssertIsOnG2(Q *G2Affine) { @@ -284,36 +290,13 @@ func (pr Pairing) AssertIsOnG2(Q *G2Affine) { pr.AssertIsOnTwist(Q) // 2- Check Q has the right subgroup order - res, err := pr.curveF.NewHint(subgroupG2Hint, 4, &Q.X.A0, &Q.X.A1, &Q.Y.A0, &Q.Y.A1) - if err != nil { - // err is non-nil only for invalid number of inputs - panic(err) - } - - // _Q = [x₀]Q - _Q := G2Affine{ - X: fields_bls12381.E2{A0: *res[0], A1: *res[1]}, - Y: fields_bls12381.E2{A0: *res[2], A1: *res[3]}, - } - - // [r]Q == 0 <==> ψ(Q) = _Q - var psiQ G2Affine - u1 := emulated.ValueOf[emulated.BLS12381Fp]("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437") - v := fields_bls12381.E2{ - A0: emulated.ValueOf[emulated.BLS12381Fp]("2973677408986561043442465346520108879172042883009249989176415018091420807192182638567116318576472649347015917690530"), - A1: emulated.ValueOf[emulated.BLS12381Fp]("1028732146235106349975324479215795277384839936929757896155643118032610843298655225875571310552543014690878354869257"), - } - + // [x₀]Q + xQ := pr.g2.scalarMulBySeed(Q) // ψ(Q) - psiQ.X = *pr.Ext2.Conjugate(&Q.X) - tmp := *pr.curveF.Mul(&psiQ.X.A1, &u1) - psiQ.X.A1 = *pr.curveF.Mul(&psiQ.X.A0, &u1) - psiQ.X.A0 = *pr.curveF.Neg(&tmp) - psiQ.Y = *pr.Ext2.Conjugate(&Q.Y) - psiQ.Y = *pr.Ext2.Mul(&psiQ.Y, &v) - - pr.Ext2.AssertIsEqual(&psiQ.X, &_Q.X) - pr.Ext2.AssertIsEqual(&psiQ.Y, &_Q.Y) + psiQ := pr.g2.psi(Q) + + // [r]Q == 0 <==> ψ(Q) == [x₀]Q + pr.g2.AssertIsEqual(xQ, psiQ) } // loopCounter = seed in binary diff --git a/std/algebra/emulated/sw_bn254/g2_test.go b/std/algebra/emulated/sw_bn254/g2_test.go index 8aa5ae6cef..1b189abc5b 100644 --- a/std/algebra/emulated/sw_bn254/g2_test.go +++ b/std/algebra/emulated/sw_bn254/g2_test.go @@ -65,6 +65,34 @@ func TestDoubleG2TestSolve(t *testing.T) { assert.NoError(err) } +type doubleAndAddG2Circuit struct { + In1, In2 G2Affine + Res G2Affine +} + +func (c *doubleAndAddG2Circuit) Define(api frontend.API) error { + g2 := NewG2(api) + res := g2.doubleAndAdd(&c.In1, &c.In2) + g2.AssertIsEqual(res, &c.Res) + return nil +} + +func TestDoubleAndAddG2TestSolve(t *testing.T) { + assert := test.NewAssert(t) + _, in1 := randomG1G2Affines(assert) + _, in2 := randomG1G2Affines(assert) + var res bn254.G2Affine + res.Double(&in1). + Add(&res, &in2) + witness := doubleAndAddG2Circuit{ + In1: NewG2Affine(in1), + In2: NewG2Affine(in2), + Res: NewG2Affine(res), + } + err := test.IsSolved(&doubleAndAddG2Circuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} + type scalarMulG2BySeedCircuit struct { In1 G2Affine Res G2Affine diff --git a/std/algebra/emulated/sw_bn254/pairing.go b/std/algebra/emulated/sw_bn254/pairing.go index 852c731bae..5ed4e08f81 100644 --- a/std/algebra/emulated/sw_bn254/pairing.go +++ b/std/algebra/emulated/sw_bn254/pairing.go @@ -294,8 +294,7 @@ func (pr Pairing) AssertIsOnG2(Q *G2Affine) { _Q = pr.g2.sub(_Q, xQ) // [r]Q == 0 <==> _Q == Q - pr.Ext2.AssertIsEqual(&Q.X, &_Q.X) - pr.Ext2.AssertIsEqual(&Q.Y, &_Q.Y) + pr.g2.AssertIsEqual(Q, _Q) } // loopCounter = 6x₀+2 = 29793968203157093288 From 20aba9cb40f685022b3562ce6b681e79fee0ba9b Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 18 Apr 2023 15:03:42 +0200 Subject: [PATCH 283/464] chore: go get gnark-crypto@develop --- go.mod | 2 +- go.sum | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index e27a842665..6339d3788b 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/bits-and-blooms/bitset v1.5.0 github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 - github.com/consensys/gnark-crypto v0.10.1-0.20230411152222-ebbf6920ad59 + github.com/consensys/gnark-crypto v0.10.1-0.20230418130058-330c1cb071dc github.com/fxamacker/cbor/v2 v2.4.0 github.com/google/go-cmp v0.5.9 github.com/google/pprof v0.0.0-20230309165930-d61513b1440d diff --git a/go.sum b/go.sum index b840dcf2ae..65a38fcad0 100644 --- a/go.sum +++ b/go.sum @@ -4,10 +4,8 @@ github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.9.2-0.20230329155745-a57dcc3b53de h1:W5lRxU8Rk8CDLHMTeyNst0VESbcU5RZ3U1TS9MNGgCQ= -github.com/consensys/gnark-crypto v0.9.2-0.20230329155745-a57dcc3b53de/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= -github.com/consensys/gnark-crypto v0.10.1-0.20230411152222-ebbf6920ad59 h1:KYAxBDzdiFQWO+lptSBb+7/UUHKjObS87Bx7pBGX1DU= -github.com/consensys/gnark-crypto v0.10.1-0.20230411152222-ebbf6920ad59/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= +github.com/consensys/gnark-crypto v0.10.1-0.20230418130058-330c1cb071dc h1:n5DKBt6tIB2+jm0mjgU56Zur9DiQE7FcWsDgK1+PijI= +github.com/consensys/gnark-crypto v0.10.1-0.20230418130058-330c1cb071dc/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= From f83323bdf138e19a1118fe9563a1ad73feded60a Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 18 Apr 2023 19:26:33 +0200 Subject: [PATCH 284/464] feat: log-derivative vector lookups (#620) * feat: add generic log-derivative arg * feat: add log-derivative vector lookup * refactor: use log deriv primitive in rangechecker * test: update circuit statistics * docs: add usage example --- internal/stats/latest.stats | Bin 2803 -> 2803 bytes std/hints.go | 6 +- std/internal/logderivarg/logderivarg.go | 220 ++++++++++++++++++ std/lookup/logderivlookup/doc_test.go | 90 +++++++ std/lookup/logderivlookup/logderivlookup.go | 141 +++++++++++ .../logderivlookup/logderivlookup_test.go | 51 ++++ std/rangecheck/rangecheck.go | 6 + std/rangecheck/rangecheck_commit.go | 59 +---- 8 files changed, 524 insertions(+), 49 deletions(-) create mode 100644 std/internal/logderivarg/logderivarg.go create mode 100644 std/lookup/logderivlookup/doc_test.go create mode 100644 std/lookup/logderivlookup/logderivlookup.go create mode 100644 std/lookup/logderivlookup/logderivlookup_test.go diff --git a/internal/stats/latest.stats b/internal/stats/latest.stats index fdd16f591d66d9dfcf382c161ac3407de8cde5d1..2441c9c6dfbbd503e98a0cffeda6fbdafd63d690 100644 GIT binary patch delta 189 zcmew?`dM^B)?_ixhm+aaA50Er%B(j&!T8VEivdXBW@u2%RHH4x_)lvULNNme zUVU&QaT_rCJY&n`@0@=oKWBeA`5>Fya^asbD}$zoi0Cl{~=P4;GdFnKb|%gN_h-53=o2XY8c LtUEh-I`ba@8U9FS diff --git a/std/hints.go b/std/hints.go index 2d04483004..57fe3b5c7e 100644 --- a/std/hints.go +++ b/std/hints.go @@ -7,6 +7,8 @@ import ( "github.com/consensys/gnark/std/algebra/native/sw_bls12377" "github.com/consensys/gnark/std/algebra/native/sw_bls24315" "github.com/consensys/gnark/std/evmprecompiles" + "github.com/consensys/gnark/std/internal/logderivarg" + "github.com/consensys/gnark/std/lookup/logderivlookup" "github.com/consensys/gnark/std/math/bits" "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/std/rangecheck" @@ -35,6 +37,8 @@ func registerHints() { solver.RegisterHint(bits.NBits) solver.RegisterHint(selector.GetHints()...) solver.RegisterHint(emulated.GetHints()...) - solver.RegisterHint(rangecheck.CountHint, rangecheck.DecomposeHint) + solver.RegisterHint(rangecheck.GetHints()...) solver.RegisterHint(evmprecompiles.GetHints()...) + solver.RegisterHint(logderivarg.GetHints()...) + solver.RegisterHint(logderivlookup.GetHints()...) } diff --git a/std/internal/logderivarg/logderivarg.go b/std/internal/logderivarg/logderivarg.go new file mode 100644 index 0000000000..c3741afcae --- /dev/null +++ b/std/internal/logderivarg/logderivarg.go @@ -0,0 +1,220 @@ +// Package logderivarg implements log-derivative argument. +// +// The log-derivative argument was described in [Haböck22] as an improvement +// over [BCG+18]. In [BCG+18], it was shown that to show inclusion of a multiset +// S in T, one can show +// +// ∏_{f∈F} (x-f)^count(f, S) == ∏_{s∈S} x-s, +// +// where function `count` counts the number of occurences of f in S. The problem +// with this approach is the high cost for exponentiating the left-hand side of +// the equation. However, in [Haböck22] it was shown that when avoiding the +// poles, we can perform the same check for the log-derivative variant of the +// equation: +// +// ∑_{f∈F} count(f,S)/(x-f) == ∑_{s∈S} 1/(x-s). +// +// Additionally, when the entries of both S and T are vectors, then instead we +// can check random linear combinations. So, when F is a matrix and S is a +// multiset of its rows, we first generate random linear coefficients (r_1, ..., +// r_n) and check +// +// ∑_{f∈F} count(f,S)/(x-∑_{i∈[n]}r_i*f_i) == ∑_{s∈S} 1/(x-∑_{i∈[n]}r_i*s_i). +// +// This package is a low-level primitive for building more extensive gadgets. It +// only checks the last equation, but the tables and queries should be built by +// the users. +// +// NB! The package doesn't check that the entries in table F are unique. +// +// [BCG+18]: https://eprint.iacr.org/2018/380 +// [Haböck22]: https://eprint.iacr.org/2022/1530 +package logderivarg + +// TODO: we handle both constant and variable tables. But for variable tables we +// have to ensure that all the table entries differ! Right now isn't a problem +// because everywhere we build we also have indices which ensure uniqueness. I +// guess the best approach is to have safe and unsafe versions where the safe +// version performs additional sorting. But that is really really expensive as +// we have to show that all sorted values ara monotonically increasing. + +import ( + "fmt" + "math/big" + + "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/hash/mimc" + "github.com/consensys/gnark/std/internal/multicommit" +) + +func init() { + solver.RegisterHint(GetHints()...) +} + +// GetHints returns all hints used in this package +func GetHints() []solver.Hint { + return []solver.Hint{countHint} +} + +// Table is a vector of vectors. +type Table [][]frontend.Variable + +// AsTable returns a vector as a single-column table. +func AsTable(vector []frontend.Variable) Table { + ret := make([][]frontend.Variable, len(vector)) + for i := range vector { + ret[i] = []frontend.Variable{vector[i]} + } + return ret +} + +// Build builds the argument using the table and queries. If both table and +// queries are multiple-column, then also samples coefficients for the random +// linear combinations. +func Build(api frontend.API, table Table, queries Table) error { + if len(table) == 0 { + return fmt.Errorf("table empty") + } + nbRow := len(table[0]) + constTable := true + countInputs := []frontend.Variable{len(table), nbRow} + for i := range table { + if len(table[i]) != nbRow { + return fmt.Errorf("table row length mismatch") + } + if constTable { + for j := range table[i] { + if _, isConst := api.Compiler().ConstantValue(table[i][j]); !isConst { + constTable = false + } + } + } + countInputs = append(countInputs, table[i]...) + } + for i := range queries { + if len(queries[i]) != nbRow { + return fmt.Errorf("query row length mismatch") + } + countInputs = append(countInputs, queries[i]...) + } + exps, err := api.NewHint(countHint, len(table), countInputs...) + if err != nil { + return fmt.Errorf("hint: %w", err) + } + + var toCommit []frontend.Variable + if !constTable { + for i := range table { + toCommit = append(toCommit, table[i]...) + } + } + for i := range queries { + toCommit = append(toCommit, queries[i]...) + } + toCommit = append(toCommit, exps...) + + multicommit.WithCommitment(api, func(api frontend.API, commitment frontend.Variable) error { + rowCoeffs, challenge := randLinearCoefficients(api, nbRow, commitment) + var lp frontend.Variable = 0 + for i := range table { + tmp := api.DivUnchecked(exps[i], api.Sub(challenge, randLinearCombination(api, rowCoeffs, table[i]))) + lp = api.Add(lp, tmp) + } + var rp frontend.Variable = 0 + for i := range queries { + tmp := api.Inverse(api.Sub(challenge, randLinearCombination(api, rowCoeffs, queries[i]))) + rp = api.Add(rp, tmp) + } + api.AssertIsEqual(lp, rp) + return nil + }, toCommit...) + return nil +} + +func randLinearCoefficients(api frontend.API, nbRow int, commitment frontend.Variable) (rowCoeffs []frontend.Variable, challenge frontend.Variable) { + if nbRow == 1 { + return []frontend.Variable{1}, commitment + } + hasher, err := mimc.NewMiMC(api) + if err != nil { + panic(err) + } + rowCoeffs = make([]frontend.Variable, nbRow) + for i := 0; i < nbRow; i++ { + hasher.Reset() + hasher.Write(i+1, commitment) + rowCoeffs[i] = hasher.Sum() + } + return rowCoeffs, commitment +} + +func randLinearCombination(api frontend.API, rowCoeffs []frontend.Variable, row []frontend.Variable) frontend.Variable { + if len(rowCoeffs) != len(row) { + panic("coefficient count mismatch") + } + var res frontend.Variable = 0 + for i := range rowCoeffs { + res = api.Add(res, api.Mul(rowCoeffs[i], row[i])) + } + return res +} + +func countHint(m *big.Int, inputs []*big.Int, outputs []*big.Int) error { + if len(inputs) <= 2 { + return fmt.Errorf("at least two input required") + } + if !inputs[0].IsInt64() { + return fmt.Errorf("first element must be length of table") + } + nbTable := int(inputs[0].Int64()) + if !inputs[1].IsInt64() { + return fmt.Errorf("first element must be length of row") + } + nbRow := int(inputs[1].Int64()) + if len(inputs) < 2+nbTable { + return fmt.Errorf("input doesn't fit table") + } + if len(outputs) != nbTable { + return fmt.Errorf("output not table size") + } + if (len(inputs)-2-nbTable*nbRow)%nbRow != 0 { + return fmt.Errorf("query count not full integer") + } + nbQueries := (len(inputs) - 2 - nbTable*nbRow) / nbRow + if nbQueries <= 0 { + return fmt.Errorf("at least one query required") + } + nbBytes := (m.BitLen() + 7) / 8 + buf := make([]byte, nbBytes*nbRow) + histo := make(map[string]int64, nbTable) // string key as big ints not comparable + for i := 0; i < nbTable; i++ { + for j := 0; j < nbRow; j++ { + inputs[2+nbRow*i+j].FillBytes(buf[j*nbBytes : (j+1)*nbBytes]) + } + k := string(buf) + if _, ok := histo[k]; ok { + return fmt.Errorf("duplicate key") + } + histo[k] = 0 + } + for i := 0; i < nbQueries; i++ { + for j := 0; j < nbRow; j++ { + inputs[2+nbRow*nbTable+nbRow*i+j].FillBytes(buf[j*nbBytes : (j+1)*nbBytes]) + } + k := string(buf) + v, ok := histo[k] + if !ok { + return fmt.Errorf("query element not in table") + } + v++ + histo[k] = v + } + for i := 0; i < nbTable; i++ { + for j := 0; j < nbRow; j++ { + inputs[2+nbRow*i+j].FillBytes(buf[j*nbBytes : (j+1)*nbBytes]) + } + outputs[i].Set(big.NewInt(histo[string(buf)])) + } + return nil +} diff --git a/std/lookup/logderivlookup/doc_test.go b/std/lookup/logderivlookup/doc_test.go new file mode 100644 index 0000000000..e8ab1a01e4 --- /dev/null +++ b/std/lookup/logderivlookup/doc_test.go @@ -0,0 +1,90 @@ +package logderivlookup_test + +import ( + "crypto/rand" + "fmt" + "math/big" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/backend/groth16" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/std/lookup/logderivlookup" +) + +type LookupCircuit struct { + Entries [1000]frontend.Variable + Queries, Expected [100]frontend.Variable +} + +func (c *LookupCircuit) Define(api frontend.API) error { + t := logderivlookup.New(api) + for i := range c.Entries { + t.Insert(c.Entries[i]) + } + results := t.Lookup(c.Queries[:]...) + if len(results) != len(c.Expected) { + return fmt.Errorf("length mismatch") + } + for i := range results { + api.AssertIsEqual(results[i], c.Expected[i]) + } + return nil +} + +func Example() { + field := ecc.BN254.ScalarField() + witness := LookupCircuit{} + bound := big.NewInt(int64(len(witness.Entries))) + for i := range witness.Entries { + witness.Entries[i], _ = rand.Int(rand.Reader, field) + } + for i := range witness.Queries { + q, _ := rand.Int(rand.Reader, bound) + witness.Queries[i] = q + witness.Expected[i] = new(big.Int).Set(witness.Entries[q.Int64()].(*big.Int)) + } + ccs, err := frontend.Compile(field, r1cs.NewBuilder, &LookupCircuit{}) + if err != nil { + panic(err) + } else { + fmt.Println("compiled") + } + pk, vk, err := groth16.Setup(ccs) + if err != nil { + panic(err) + } else { + fmt.Println("setup done") + } + secretWitness, err := frontend.NewWitness(&witness, ecc.BN254.ScalarField()) + if err != nil { + panic(err) + } else { + fmt.Println("secret witness") + } + publicWitness, err := secretWitness.Public() + if err != nil { + panic(err) + } else { + fmt.Println("public witness") + } + proof, err := groth16.Prove(ccs, pk, secretWitness) + if err != nil { + panic(err) + } else { + fmt.Println("proof") + } + err = groth16.Verify(proof, vk, publicWitness) + if err != nil { + panic(err) + } else { + fmt.Println("verify") + } + // Output: + // compiled + // setup done + // secret witness + // public witness + // proof + // verify +} diff --git a/std/lookup/logderivlookup/logderivlookup.go b/std/lookup/logderivlookup/logderivlookup.go new file mode 100644 index 0000000000..461500f732 --- /dev/null +++ b/std/lookup/logderivlookup/logderivlookup.go @@ -0,0 +1,141 @@ +// Package logderiv implements append-only lookups using log-derivative +// argument. +// +// The lookup is based on log-derivative argument as described in [logderivarg]. +// The lookup table is a matrix where first column is the index and the second +// column the stored values: +// +// 1 x_1 +// 2 x_2 +// ... +// n x_n +// +// When performing a query for index i, the prover returns x_i from memory and +// stores (i, x_i) as a query. During the log-derivative argument building we +// check that all queried tuples (i, x_i) are included in the table. +// +// The complexity of the lookups is linear in the size of the table and the +// number of queries (O(n+m)). +package logderivlookup + +import ( + "fmt" + "math/big" + + "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/internal/logderivarg" +) + +func init() { + solver.RegisterHint(GetHints()...) +} + +// GetHints returns all hints used in the package. +func GetHints() []solver.Hint { + return []solver.Hint{lookupHint} +} + +// Table holds all the entries and queries. +type Table struct { + api frontend.API + + entries []frontend.Variable + immutable bool + results []result +} + +type result struct { + ind frontend.Variable + val frontend.Variable +} + +// New returns a new [*Table]. It additionally defers building the +// log-derivative argument. +func New(api frontend.API) *Table { + t := &Table{api: api} + api.Compiler().Defer(t.commit) + return t +} + +// Insert inserts variable val into the lookup table and returns its index as a +// constant. It panics if the table is already committed. +func (t *Table) Insert(val frontend.Variable) (index int) { + if t.immutable { + panic("inserting into commited lookup table") + } + t.entries = append(t.entries, val) + return len(t.entries) - 1 +} + +// Lookup lookups up values from the lookup tables given by the indices inds. It +// returns a variable for every index. It panics during compile time when +// looking up from a committed or empty table. It panics during solving time +// when the index is out of bounds. +func (t *Table) Lookup(inds ...frontend.Variable) (vals []frontend.Variable) { + if t.immutable { + panic("looking up from a commited lookup table") + } + if len(inds) == 0 { + return nil + } + if len(t.entries) == 0 { + panic("looking up from empty table") + } + return t.callLookupHint(inds) +} + +func (t *Table) callLookupHint(inds []frontend.Variable) []frontend.Variable { + inputs := make([]frontend.Variable, len(t.entries)+len(inds)) + copy(inputs[:len(t.entries)], t.entries) + for i := range inds { + inputs[len(t.entries)+i] = inds[i] + } + hintResp, err := t.api.NewHint(lookupHint, len(inds), inputs...) + if err != nil { + panic(fmt.Sprintf("lookup hint: %v", err)) + } + res := make([]frontend.Variable, len(inds)) + results := make([]result, len(inds)) + for i := range inds { + res[i] = hintResp[i] + results[i] = result{ind: inds[i], val: hintResp[i]} + } + t.results = append(t.results, results...) + return res +} + +func (t *Table) entryTable() [][]frontend.Variable { + tbl := make([][]frontend.Variable, len(t.entries)) + for i := range t.entries { + tbl[i] = []frontend.Variable{i, t.entries[i]} + } + return tbl +} + +func (t *Table) resultsTable() [][]frontend.Variable { + tbl := make([][]frontend.Variable, len(t.results)) + for i := range t.results { + tbl[i] = []frontend.Variable{t.results[i].ind, t.results[i].val} + } + return tbl +} + +func (t *Table) commit(api frontend.API) error { + return logderivarg.Build(api, t.entryTable(), t.resultsTable()) +} + +func lookupHint(_ *big.Int, in []*big.Int, out []*big.Int) error { + nbTable := len(in) - len(out) + for i := 0; i < len(in)-nbTable; i++ { + if !in[nbTable+i].IsInt64() { + return fmt.Errorf("lookup query not integer") + } + ptr := int(in[nbTable+i].Int64()) + if ptr >= nbTable { + return fmt.Errorf("lookup query %d outside table size %d", ptr, nbTable) + } + out[i] = in[ptr] + } + return nil +} diff --git a/std/lookup/logderivlookup/logderivlookup_test.go b/std/lookup/logderivlookup/logderivlookup_test.go new file mode 100644 index 0000000000..6f5041322a --- /dev/null +++ b/std/lookup/logderivlookup/logderivlookup_test.go @@ -0,0 +1,51 @@ +package logderivlookup + +import ( + "crypto/rand" + "fmt" + "math/big" + "testing" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/test" +) + +type LookupCircuit struct { + Entries [1000]frontend.Variable + Queries, Expected [100]frontend.Variable +} + +func (c *LookupCircuit) Define(api frontend.API) error { + t := New(api) + for i := range c.Entries { + t.Insert(c.Entries[i]) + } + results := t.Lookup(c.Queries[:]...) + if len(results) != len(c.Expected) { + return fmt.Errorf("length mismatch") + } + for i := range results { + api.AssertIsEqual(results[i], c.Expected[i]) + } + return nil +} + +func TestLookup(t *testing.T) { + assert := test.NewAssert(t) + field := ecc.BN254.ScalarField() + witness := LookupCircuit{} + bound := big.NewInt(int64(len(witness.Entries))) + for i := range witness.Entries { + witness.Entries[i], _ = rand.Int(rand.Reader, field) + } + for i := range witness.Queries { + q, _ := rand.Int(rand.Reader, bound) + witness.Queries[i] = q + witness.Expected[i] = new(big.Int).Set(witness.Entries[q.Int64()].(*big.Int)) + } + assert.ProverSucceeded(&LookupCircuit{}, &witness, + test.WithCurves(ecc.BN254), + test.WithBackends(backend.GROTH16, backend.PLONK)) +} diff --git a/std/rangecheck/rangecheck.go b/std/rangecheck/rangecheck.go index f7152df3e5..8aac734dcb 100644 --- a/std/rangecheck/rangecheck.go +++ b/std/rangecheck/rangecheck.go @@ -10,6 +10,7 @@ package rangecheck import ( + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" ) @@ -29,3 +30,8 @@ func New(api frontend.API) frontend.Rangechecker { } return plainChecker{api: api} } + +// GetHints returns all hints used in this package +func GetHints() []solver.Hint { + return []solver.Hint{DecomposeHint} +} diff --git a/std/rangecheck/rangecheck_commit.go b/std/rangecheck/rangecheck_commit.go index 62cad9f866..6af6eb5be6 100644 --- a/std/rangecheck/rangecheck_commit.go +++ b/std/rangecheck/rangecheck_commit.go @@ -9,13 +9,13 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/internal/frontendtype" "github.com/consensys/gnark/internal/kvstore" - "github.com/consensys/gnark/std/internal/multicommit" + "github.com/consensys/gnark/std/internal/logderivarg" ) type ctxCheckerKey struct{} func init() { - solver.RegisterHint(DecomposeHint, CountHint) + solver.RegisterHint(DecomposeHint) } type checkedVariable struct { @@ -54,6 +54,14 @@ func (c *commitChecker) Check(in frontend.Variable, bits int) { c.collected = append(c.collected, checkedVariable{v: in, bits: bits}) } +func (c *commitChecker) buildTable(nbTable int) []frontend.Variable { + tbl := make([]frontend.Variable, nbTable) + for i := 0; i < nbTable; i++ { + tbl[i] = i + } + return tbl +} + func (c *commitChecker) commit(api frontend.API) error { if c.closed { return nil @@ -86,30 +94,7 @@ func (c *commitChecker) commit(api frontend.API) error { api.AssertIsEqual(composed, c.collected[i].v) } nbTable := 1 << baseLength - // compute the counts for every value in the range - exps, err := api.Compiler().NewHint(CountHint, nbTable, decomposed...) - if err != nil { - panic(fmt.Sprintf("count %v", err)) - } - multicommit.WithCommitment(api, func(api frontend.API, commitment frontend.Variable) error { - // compute the ratoinal function Sum_i e_i / (X - s_i) - // lp = Sum_i e_i / (X - s_i) - var lp frontend.Variable = 0 - for i := 0; i < nbTable; i++ { - tmp := api.DivUnchecked(exps[i], api.Sub(commitment, i)) - lp = api.Add(lp, tmp) - } - - // rp = Sum_i 1 \ (X - f_i) - var rp frontend.Variable = 0 - for i := range decomposed { - tmp := api.Inverse(api.Sub(commitment, decomposed[i])) - rp = api.Add(rp, tmp) - } - api.AssertIsEqual(lp, rp) - return nil - }, append(collected, exps...)...) - return nil + return logderivarg.Build(api, logderivarg.AsTable(c.buildTable(nbTable)), logderivarg.AsTable(decomposed)) } func decompSize(varSize int, limbSize int) int { @@ -142,28 +127,6 @@ func DecomposeHint(m *big.Int, inputs []*big.Int, outputs []*big.Int) error { return nil } -// CountHint is a hint function which is used in range checking using -// commitment. It counts the occurences of checked variables in the range and -// returns the counts. -func CountHint(m *big.Int, inputs []*big.Int, outputs []*big.Int) error { - nbVals := len(outputs) - if len(outputs) != nbVals { - return fmt.Errorf("output size %d does not match range size %d", len(outputs), nbVals) - } - counts := make(map[uint64]uint64, nbVals) - for i := 0; i < len(inputs); i++ { - if !inputs[i].IsUint64() { - return fmt.Errorf("input %d not uint64", i) - } - c := inputs[i].Uint64() - counts[c]++ - } - for i := 0; i < nbVals; i++ { - outputs[i].SetUint64(counts[uint64(i)]) - } - return nil -} - func (c *commitChecker) getOptimalBasewidth(api frontend.API) int { if ft, ok := api.(frontendtype.FrontendTyper); ok { switch ft.FrontendType() { From ca731090cf3ad789b1340ee985525b92382a78bc Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 19 Apr 2023 22:57:07 -0500 Subject: [PATCH 285/464] style: remove commented import --- backend/plonk/bls12-377/setup.go | 1 - backend/plonk/bls12-381/setup.go | 1 - backend/plonk/bls24-315/setup.go | 1 - backend/plonk/bls24-317/setup.go | 1 - backend/plonk/bn254/setup.go | 1 - backend/plonk/bw6-633/setup.go | 1 - backend/plonk/bw6-761/setup.go | 1 - .../backend/template/zkpschemes/plonk/plonk.setup.go.tmpl | 2 -- 8 files changed, 9 deletions(-) diff --git a/backend/plonk/bls12-377/setup.go b/backend/plonk/bls12-377/setup.go index 1ec3889ec2..98095b0cc2 100644 --- a/backend/plonk/bls12-377/setup.go +++ b/backend/plonk/bls12-377/setup.go @@ -25,7 +25,6 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/kzg" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls12-377" - //kzgg "github.com/consensys/gnark-crypto/kzg" TODO Figure out why this is useful ) // Trace stores a plonk trace as columns diff --git a/backend/plonk/bls12-381/setup.go b/backend/plonk/bls12-381/setup.go index 0941233c1d..28596565f4 100644 --- a/backend/plonk/bls12-381/setup.go +++ b/backend/plonk/bls12-381/setup.go @@ -25,7 +25,6 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/kzg" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls12-381" - //kzgg "github.com/consensys/gnark-crypto/kzg" TODO Figure out why this is useful ) // Trace stores a plonk trace as columns diff --git a/backend/plonk/bls24-315/setup.go b/backend/plonk/bls24-315/setup.go index ad1e7d9970..31f0e82b26 100644 --- a/backend/plonk/bls24-315/setup.go +++ b/backend/plonk/bls24-315/setup.go @@ -25,7 +25,6 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/kzg" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls24-315" - //kzgg "github.com/consensys/gnark-crypto/kzg" TODO Figure out why this is useful ) // Trace stores a plonk trace as columns diff --git a/backend/plonk/bls24-317/setup.go b/backend/plonk/bls24-317/setup.go index 4c68571076..8c084194fe 100644 --- a/backend/plonk/bls24-317/setup.go +++ b/backend/plonk/bls24-317/setup.go @@ -25,7 +25,6 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/kzg" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls24-317" - //kzgg "github.com/consensys/gnark-crypto/kzg" TODO Figure out why this is useful ) // Trace stores a plonk trace as columns diff --git a/backend/plonk/bn254/setup.go b/backend/plonk/bn254/setup.go index 7b527c3204..b340434190 100644 --- a/backend/plonk/bn254/setup.go +++ b/backend/plonk/bn254/setup.go @@ -25,7 +25,6 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr/kzg" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bn254" - //kzgg "github.com/consensys/gnark-crypto/kzg" TODO Figure out why this is useful ) // Trace stores a plonk trace as columns diff --git a/backend/plonk/bw6-633/setup.go b/backend/plonk/bw6-633/setup.go index 2eb9988b09..965721916f 100644 --- a/backend/plonk/bw6-633/setup.go +++ b/backend/plonk/bw6-633/setup.go @@ -25,7 +25,6 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/kzg" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bw6-633" - //kzgg "github.com/consensys/gnark-crypto/kzg" TODO Figure out why this is useful ) // Trace stores a plonk trace as columns diff --git a/backend/plonk/bw6-761/setup.go b/backend/plonk/bw6-761/setup.go index e9b40ca29c..ecae758c98 100644 --- a/backend/plonk/bw6-761/setup.go +++ b/backend/plonk/bw6-761/setup.go @@ -25,7 +25,6 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/kzg" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bw6-761" - //kzgg "github.com/consensys/gnark-crypto/kzg" TODO Figure out why this is useful ) // Trace stores a plonk trace as columns diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl index 014e31fdd2..e0cab5cdfc 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl @@ -7,8 +7,6 @@ import ( {{- template "import_backend_cs" . }} "github.com/consensys/gnark-crypto/ecc/{{toLower .Curve}}/fr/iop" "github.com/consensys/gnark-crypto/ecc" - - //kzgg "github.com/consensys/gnark-crypto/kzg" TODO Figure out why this is useful ) // Trace stores a plonk trace as columns From 06796ec0570b47d4b64083171da2248bb9a262db Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 19 Apr 2023 23:01:51 -0500 Subject: [PATCH 286/464] build: update gnark-crypto dep --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 1d8704907a..b634a7587f 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/bits-and-blooms/bitset v1.5.0 github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 - github.com/consensys/gnark-crypto v0.10.1-0.20230408232650-7fda2542de4d + github.com/consensys/gnark-crypto v0.10.1-0.20230420025556-eaeb6db64ed7 github.com/fxamacker/cbor/v2 v2.4.0 github.com/google/go-cmp v0.5.9 github.com/google/pprof v0.0.0-20230309165930-d61513b1440d diff --git a/go.sum b/go.sum index 9a33fe7c0a..4a3d2e0d10 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/Yj github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= github.com/consensys/gnark-crypto v0.10.1-0.20230408232650-7fda2542de4d h1:TJ2dYEdgx8dVt4Jv/ftodldmVkQK3R4ntCGyo1u0v3U= github.com/consensys/gnark-crypto v0.10.1-0.20230408232650-7fda2542de4d/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= +github.com/consensys/gnark-crypto v0.10.1-0.20230420025556-eaeb6db64ed7 h1:5OAqdipDbuXlHzpJY2xDjef1jn4gkdOpf4zRQB6WPaU= +github.com/consensys/gnark-crypto v0.10.1-0.20230420025556-eaeb6db64ed7/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= From cf3ae1d23f43849f8f3031e3f00a8d757f3c330e Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 20 Apr 2023 09:05:38 -0500 Subject: [PATCH 287/464] test: use deep.Equal in Plonk roundtrip --- backend/plonk/bn254/marshal.go | 2 +- backend/plonk/bn254/marshal_test.go | 6 ++++-- go.mod | 1 + go.sum | 2 ++ 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/backend/plonk/bn254/marshal.go b/backend/plonk/bn254/marshal.go index a3de182ed0..f523a7ed95 100644 --- a/backend/plonk/bn254/marshal.go +++ b/backend/plonk/bn254/marshal.go @@ -25,7 +25,7 @@ import ( "io" ) -// WriteTo writes binary encoding of Proof to w without point compression +// WriteRawTo writes binary encoding of Proof to w without point compression func (proof *Proof) WriteRawTo(w io.Writer) (int64, error) { return proof.writeTo(w, curve.RawEncoding()) } diff --git a/backend/plonk/bn254/marshal_test.go b/backend/plonk/bn254/marshal_test.go index 0d82de6274..46dd9819ca 100644 --- a/backend/plonk/bn254/marshal_test.go +++ b/backend/plonk/bn254/marshal_test.go @@ -30,6 +30,8 @@ import ( "math/rand" "reflect" "testing" + + "github.com/go-test/deep" ) func TestProofSerialization(t *testing.T) { @@ -76,8 +78,8 @@ func roundTripCheck(t *testing.T, from io.WriterTo, reconstructed io.ReaderFrom) t.Fatal("couldn't deserialize", err) } - if !reflect.DeepEqual(from, reconstructed) { - t.Fatal("reconstructed object don't match original") + if diff := deep.Equal(from, reconstructed); diff != nil { + t.Fatal("reconstructed object don't match original:\n", diff) } if written != read { diff --git a/go.mod b/go.mod index b634a7587f..d710159fbc 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect + github.com/go-test/deep v1.1.0 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect diff --git a/go.sum b/go.sum index 4a3d2e0d10..47b8d39c68 100644 --- a/go.sum +++ b/go.sum @@ -15,6 +15,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88= github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= From ee248a47556c08d3e7cd1e39668890e9d3001466 Mon Sep 17 00:00:00 2001 From: Sher Date: Fri, 21 Apr 2023 01:44:47 +0800 Subject: [PATCH 288/464] fix serializeCommitment (#651) Resolves #645 --- constraint/commitment.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/constraint/commitment.go b/constraint/commitment.go index adc7ce65fc..ec3786b559 100644 --- a/constraint/commitment.go +++ b/constraint/commitment.go @@ -44,9 +44,9 @@ func (i *Commitment) SerializeCommitment(privateCommitment []byte, publicCommitt copy(res, privateCommitment) offset := len(privateCommitment) - for j, inJ := range publicCommitted { - offset += j * fieldByteLen + for _, inJ := range publicCommitted { inJ.FillBytes(res[offset : offset+fieldByteLen]) + offset += fieldByteLen } return res From 9007023a6d8a9e6fec6baba1436a089ed531c735 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 20 Apr 2023 13:55:04 -0500 Subject: [PATCH 289/464] build: update gnark-crypto dependency --- backend/plonk/bls12-377/marshal.go | 2 +- backend/plonk/bls12-381/marshal.go | 2 +- backend/plonk/bls24-315/marshal.go | 2 +- backend/plonk/bls24-317/marshal.go | 2 +- backend/plonk/bn254/marshal_test.go | 6 ++---- backend/plonk/bw6-633/marshal.go | 2 +- backend/plonk/bw6-761/marshal.go | 2 +- go.mod | 2 +- go.sum | 2 ++ .../backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl | 2 +- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/backend/plonk/bls12-377/marshal.go b/backend/plonk/bls12-377/marshal.go index a1ea0f0972..00119d94ad 100644 --- a/backend/plonk/bls12-377/marshal.go +++ b/backend/plonk/bls12-377/marshal.go @@ -25,7 +25,7 @@ import ( "io" ) -// WriteTo writes binary encoding of Proof to w without point compression +// WriteRawTo writes binary encoding of Proof to w without point compression func (proof *Proof) WriteRawTo(w io.Writer) (int64, error) { return proof.writeTo(w, curve.RawEncoding()) } diff --git a/backend/plonk/bls12-381/marshal.go b/backend/plonk/bls12-381/marshal.go index 521e50157e..dc52cdedf6 100644 --- a/backend/plonk/bls12-381/marshal.go +++ b/backend/plonk/bls12-381/marshal.go @@ -25,7 +25,7 @@ import ( "io" ) -// WriteTo writes binary encoding of Proof to w without point compression +// WriteRawTo writes binary encoding of Proof to w without point compression func (proof *Proof) WriteRawTo(w io.Writer) (int64, error) { return proof.writeTo(w, curve.RawEncoding()) } diff --git a/backend/plonk/bls24-315/marshal.go b/backend/plonk/bls24-315/marshal.go index e26d5cf61b..b0b4d40c7d 100644 --- a/backend/plonk/bls24-315/marshal.go +++ b/backend/plonk/bls24-315/marshal.go @@ -25,7 +25,7 @@ import ( "io" ) -// WriteTo writes binary encoding of Proof to w without point compression +// WriteRawTo writes binary encoding of Proof to w without point compression func (proof *Proof) WriteRawTo(w io.Writer) (int64, error) { return proof.writeTo(w, curve.RawEncoding()) } diff --git a/backend/plonk/bls24-317/marshal.go b/backend/plonk/bls24-317/marshal.go index 031f0e7c94..ca62827d78 100644 --- a/backend/plonk/bls24-317/marshal.go +++ b/backend/plonk/bls24-317/marshal.go @@ -25,7 +25,7 @@ import ( "io" ) -// WriteTo writes binary encoding of Proof to w without point compression +// WriteRawTo writes binary encoding of Proof to w without point compression func (proof *Proof) WriteRawTo(w io.Writer) (int64, error) { return proof.writeTo(w, curve.RawEncoding()) } diff --git a/backend/plonk/bn254/marshal_test.go b/backend/plonk/bn254/marshal_test.go index 46dd9819ca..0d82de6274 100644 --- a/backend/plonk/bn254/marshal_test.go +++ b/backend/plonk/bn254/marshal_test.go @@ -30,8 +30,6 @@ import ( "math/rand" "reflect" "testing" - - "github.com/go-test/deep" ) func TestProofSerialization(t *testing.T) { @@ -78,8 +76,8 @@ func roundTripCheck(t *testing.T, from io.WriterTo, reconstructed io.ReaderFrom) t.Fatal("couldn't deserialize", err) } - if diff := deep.Equal(from, reconstructed); diff != nil { - t.Fatal("reconstructed object don't match original:\n", diff) + if !reflect.DeepEqual(from, reconstructed) { + t.Fatal("reconstructed object don't match original") } if written != read { diff --git a/backend/plonk/bw6-633/marshal.go b/backend/plonk/bw6-633/marshal.go index 36b9d0b045..f4d4f25461 100644 --- a/backend/plonk/bw6-633/marshal.go +++ b/backend/plonk/bw6-633/marshal.go @@ -25,7 +25,7 @@ import ( "io" ) -// WriteTo writes binary encoding of Proof to w without point compression +// WriteRawTo writes binary encoding of Proof to w without point compression func (proof *Proof) WriteRawTo(w io.Writer) (int64, error) { return proof.writeTo(w, curve.RawEncoding()) } diff --git a/backend/plonk/bw6-761/marshal.go b/backend/plonk/bw6-761/marshal.go index 82e93cf728..b3559a8077 100644 --- a/backend/plonk/bw6-761/marshal.go +++ b/backend/plonk/bw6-761/marshal.go @@ -25,7 +25,7 @@ import ( "io" ) -// WriteTo writes binary encoding of Proof to w without point compression +// WriteRawTo writes binary encoding of Proof to w without point compression func (proof *Proof) WriteRawTo(w io.Writer) (int64, error) { return proof.writeTo(w, curve.RawEncoding()) } diff --git a/go.mod b/go.mod index d710159fbc..71070246f1 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/bits-and-blooms/bitset v1.5.0 github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 - github.com/consensys/gnark-crypto v0.10.1-0.20230420025556-eaeb6db64ed7 + github.com/consensys/gnark-crypto v0.10.1-0.20230420183752-ed3709c81831 github.com/fxamacker/cbor/v2 v2.4.0 github.com/google/go-cmp v0.5.9 github.com/google/pprof v0.0.0-20230309165930-d61513b1440d diff --git a/go.sum b/go.sum index 47b8d39c68..8b9f7a7bfc 100644 --- a/go.sum +++ b/go.sum @@ -8,6 +8,8 @@ github.com/consensys/gnark-crypto v0.10.1-0.20230408232650-7fda2542de4d h1:TJ2dY github.com/consensys/gnark-crypto v0.10.1-0.20230408232650-7fda2542de4d/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= github.com/consensys/gnark-crypto v0.10.1-0.20230420025556-eaeb6db64ed7 h1:5OAqdipDbuXlHzpJY2xDjef1jn4gkdOpf4zRQB6WPaU= github.com/consensys/gnark-crypto v0.10.1-0.20230420025556-eaeb6db64ed7/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= +github.com/consensys/gnark-crypto v0.10.1-0.20230420183752-ed3709c81831 h1:2y5CcR1Ww4wJxCZX4psdiIqdaNb7Kd4WM8YfPqQb6yY= +github.com/consensys/gnark-crypto v0.10.1-0.20230420183752-ed3709c81831/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl index 9848a4e248..ae5b1e5f75 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl @@ -6,7 +6,7 @@ import ( "errors" ) -// WriteTo writes binary encoding of Proof to w without point compression +// WriteRawTo writes binary encoding of Proof to w without point compression func (proof *Proof) WriteRawTo(w io.Writer) (int64, error) { return proof.writeTo(w, curve.RawEncoding()) } From 8cf064433fe9b639d7d3f7d5db0323ce5f83e0a4 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 20 Apr 2023 14:00:06 -0500 Subject: [PATCH 290/464] fix: companion to pedersen breakup --- backend/groth16/bls12-377/setup.go | 7 +++---- backend/groth16/bls12-377/verify.go | 2 +- backend/groth16/bls12-381/setup.go | 7 +++---- backend/groth16/bls12-381/verify.go | 2 +- backend/groth16/bls24-315/setup.go | 7 +++---- backend/groth16/bls24-315/verify.go | 2 +- backend/groth16/bls24-317/setup.go | 7 +++---- backend/groth16/bls24-317/verify.go | 2 +- backend/groth16/bn254/setup.go | 7 +++---- backend/groth16/bn254/verify.go | 2 +- backend/groth16/bw6-633/setup.go | 7 +++---- backend/groth16/bw6-633/verify.go | 2 +- backend/groth16/bw6-761/setup.go | 7 +++---- backend/groth16/bw6-761/verify.go | 2 +- .../template/zkpschemes/groth16/groth16.setup.go.tmpl | 7 +++---- .../template/zkpschemes/groth16/groth16.verify.go.tmpl | 2 +- 16 files changed, 32 insertions(+), 40 deletions(-) diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index c1e7a22c9e..06f7b9907a 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -52,7 +52,7 @@ type ProvingKey struct { InfinityA, InfinityB []bool NbInfinityA, NbInfinityB uint64 - CommitmentKey pedersen.Key + CommitmentKey pedersen.ProvingKey } // VerifyingKey is used by a Groth16 verifier to verify the validity of a proof and a statement @@ -75,7 +75,7 @@ type VerifyingKey struct { // e(α, β) e curve.GT // not serialized - CommitmentKey pedersen.Key + CommitmentKey pedersen.VerifyingKey CommitmentInfo constraint.Commitment // since the verifier doesn't input a constraint system, this needs to be provided here } @@ -256,11 +256,10 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { if nbPrivateCommittedWires != 0 { commitmentBasis := g1PointsAff[offset:] - vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + pk.CommitmentKey, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) if err != nil { return err } - pk.CommitmentKey = vk.CommitmentKey } vk.CommitmentInfo = r1cs.CommitmentInfo // unfortunate but necessary diff --git a/backend/groth16/bls12-377/verify.go b/backend/groth16/bls12-377/verify.go index 6a9819c093..dc4be62f06 100644 --- a/backend/groth16/bls12-377/verify.go +++ b/backend/groth16/bls12-377/verify.go @@ -64,7 +64,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { if vk.CommitmentInfo.Is() { - if err := vk.CommitmentKey.VerifyKnowledgeProof(proof.Commitment, proof.CommitmentPok); err != nil { + if err := vk.CommitmentKey.Verify(proof.Commitment, proof.CommitmentPok); err != nil { return err } diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index dc23ffa75a..61b7077f03 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -52,7 +52,7 @@ type ProvingKey struct { InfinityA, InfinityB []bool NbInfinityA, NbInfinityB uint64 - CommitmentKey pedersen.Key + CommitmentKey pedersen.ProvingKey } // VerifyingKey is used by a Groth16 verifier to verify the validity of a proof and a statement @@ -75,7 +75,7 @@ type VerifyingKey struct { // e(α, β) e curve.GT // not serialized - CommitmentKey pedersen.Key + CommitmentKey pedersen.VerifyingKey CommitmentInfo constraint.Commitment // since the verifier doesn't input a constraint system, this needs to be provided here } @@ -256,11 +256,10 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { if nbPrivateCommittedWires != 0 { commitmentBasis := g1PointsAff[offset:] - vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + pk.CommitmentKey, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) if err != nil { return err } - pk.CommitmentKey = vk.CommitmentKey } vk.CommitmentInfo = r1cs.CommitmentInfo // unfortunate but necessary diff --git a/backend/groth16/bls12-381/verify.go b/backend/groth16/bls12-381/verify.go index 0a9de8c797..dd2c057ebb 100644 --- a/backend/groth16/bls12-381/verify.go +++ b/backend/groth16/bls12-381/verify.go @@ -64,7 +64,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { if vk.CommitmentInfo.Is() { - if err := vk.CommitmentKey.VerifyKnowledgeProof(proof.Commitment, proof.CommitmentPok); err != nil { + if err := vk.CommitmentKey.Verify(proof.Commitment, proof.CommitmentPok); err != nil { return err } diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index 6a4bf19a6f..cc9de5faa7 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -52,7 +52,7 @@ type ProvingKey struct { InfinityA, InfinityB []bool NbInfinityA, NbInfinityB uint64 - CommitmentKey pedersen.Key + CommitmentKey pedersen.ProvingKey } // VerifyingKey is used by a Groth16 verifier to verify the validity of a proof and a statement @@ -75,7 +75,7 @@ type VerifyingKey struct { // e(α, β) e curve.GT // not serialized - CommitmentKey pedersen.Key + CommitmentKey pedersen.VerifyingKey CommitmentInfo constraint.Commitment // since the verifier doesn't input a constraint system, this needs to be provided here } @@ -256,11 +256,10 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { if nbPrivateCommittedWires != 0 { commitmentBasis := g1PointsAff[offset:] - vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + pk.CommitmentKey, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) if err != nil { return err } - pk.CommitmentKey = vk.CommitmentKey } vk.CommitmentInfo = r1cs.CommitmentInfo // unfortunate but necessary diff --git a/backend/groth16/bls24-315/verify.go b/backend/groth16/bls24-315/verify.go index f0f170d9b3..b9bd2e2c84 100644 --- a/backend/groth16/bls24-315/verify.go +++ b/backend/groth16/bls24-315/verify.go @@ -64,7 +64,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { if vk.CommitmentInfo.Is() { - if err := vk.CommitmentKey.VerifyKnowledgeProof(proof.Commitment, proof.CommitmentPok); err != nil { + if err := vk.CommitmentKey.Verify(proof.Commitment, proof.CommitmentPok); err != nil { return err } diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index cd21b8dde9..32f4b9d8b8 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -52,7 +52,7 @@ type ProvingKey struct { InfinityA, InfinityB []bool NbInfinityA, NbInfinityB uint64 - CommitmentKey pedersen.Key + CommitmentKey pedersen.ProvingKey } // VerifyingKey is used by a Groth16 verifier to verify the validity of a proof and a statement @@ -75,7 +75,7 @@ type VerifyingKey struct { // e(α, β) e curve.GT // not serialized - CommitmentKey pedersen.Key + CommitmentKey pedersen.VerifyingKey CommitmentInfo constraint.Commitment // since the verifier doesn't input a constraint system, this needs to be provided here } @@ -256,11 +256,10 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { if nbPrivateCommittedWires != 0 { commitmentBasis := g1PointsAff[offset:] - vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + pk.CommitmentKey, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) if err != nil { return err } - pk.CommitmentKey = vk.CommitmentKey } vk.CommitmentInfo = r1cs.CommitmentInfo // unfortunate but necessary diff --git a/backend/groth16/bls24-317/verify.go b/backend/groth16/bls24-317/verify.go index e6f5f33f46..5d73519cc6 100644 --- a/backend/groth16/bls24-317/verify.go +++ b/backend/groth16/bls24-317/verify.go @@ -64,7 +64,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { if vk.CommitmentInfo.Is() { - if err := vk.CommitmentKey.VerifyKnowledgeProof(proof.Commitment, proof.CommitmentPok); err != nil { + if err := vk.CommitmentKey.Verify(proof.Commitment, proof.CommitmentPok); err != nil { return err } diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index e65295ebec..ea881503fc 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -52,7 +52,7 @@ type ProvingKey struct { InfinityA, InfinityB []bool NbInfinityA, NbInfinityB uint64 - CommitmentKey pedersen.Key + CommitmentKey pedersen.ProvingKey } // VerifyingKey is used by a Groth16 verifier to verify the validity of a proof and a statement @@ -75,7 +75,7 @@ type VerifyingKey struct { // e(α, β) e curve.GT // not serialized - CommitmentKey pedersen.Key + CommitmentKey pedersen.VerifyingKey CommitmentInfo constraint.Commitment // since the verifier doesn't input a constraint system, this needs to be provided here } @@ -256,11 +256,10 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { if nbPrivateCommittedWires != 0 { commitmentBasis := g1PointsAff[offset:] - vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + pk.CommitmentKey, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) if err != nil { return err } - pk.CommitmentKey = vk.CommitmentKey } vk.CommitmentInfo = r1cs.CommitmentInfo // unfortunate but necessary diff --git a/backend/groth16/bn254/verify.go b/backend/groth16/bn254/verify.go index 917ebf9166..a5a5b544ba 100644 --- a/backend/groth16/bn254/verify.go +++ b/backend/groth16/bn254/verify.go @@ -65,7 +65,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { if vk.CommitmentInfo.Is() { - if err := vk.CommitmentKey.VerifyKnowledgeProof(proof.Commitment, proof.CommitmentPok); err != nil { + if err := vk.CommitmentKey.Verify(proof.Commitment, proof.CommitmentPok); err != nil { return err } diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index 7118c2fa44..b5a2d3a9ec 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -52,7 +52,7 @@ type ProvingKey struct { InfinityA, InfinityB []bool NbInfinityA, NbInfinityB uint64 - CommitmentKey pedersen.Key + CommitmentKey pedersen.ProvingKey } // VerifyingKey is used by a Groth16 verifier to verify the validity of a proof and a statement @@ -75,7 +75,7 @@ type VerifyingKey struct { // e(α, β) e curve.GT // not serialized - CommitmentKey pedersen.Key + CommitmentKey pedersen.VerifyingKey CommitmentInfo constraint.Commitment // since the verifier doesn't input a constraint system, this needs to be provided here } @@ -256,11 +256,10 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { if nbPrivateCommittedWires != 0 { commitmentBasis := g1PointsAff[offset:] - vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + pk.CommitmentKey, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) if err != nil { return err } - pk.CommitmentKey = vk.CommitmentKey } vk.CommitmentInfo = r1cs.CommitmentInfo // unfortunate but necessary diff --git a/backend/groth16/bw6-633/verify.go b/backend/groth16/bw6-633/verify.go index 642bedc2d4..7b3dbf3807 100644 --- a/backend/groth16/bw6-633/verify.go +++ b/backend/groth16/bw6-633/verify.go @@ -64,7 +64,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { if vk.CommitmentInfo.Is() { - if err := vk.CommitmentKey.VerifyKnowledgeProof(proof.Commitment, proof.CommitmentPok); err != nil { + if err := vk.CommitmentKey.Verify(proof.Commitment, proof.CommitmentPok); err != nil { return err } diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index 5cc22cbfa5..316ca5b5e7 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -52,7 +52,7 @@ type ProvingKey struct { InfinityA, InfinityB []bool NbInfinityA, NbInfinityB uint64 - CommitmentKey pedersen.Key + CommitmentKey pedersen.ProvingKey } // VerifyingKey is used by a Groth16 verifier to verify the validity of a proof and a statement @@ -75,7 +75,7 @@ type VerifyingKey struct { // e(α, β) e curve.GT // not serialized - CommitmentKey pedersen.Key + CommitmentKey pedersen.VerifyingKey CommitmentInfo constraint.Commitment // since the verifier doesn't input a constraint system, this needs to be provided here } @@ -256,11 +256,10 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { if nbPrivateCommittedWires != 0 { commitmentBasis := g1PointsAff[offset:] - vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + pk.CommitmentKey, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) if err != nil { return err } - pk.CommitmentKey = vk.CommitmentKey } vk.CommitmentInfo = r1cs.CommitmentInfo // unfortunate but necessary diff --git a/backend/groth16/bw6-761/verify.go b/backend/groth16/bw6-761/verify.go index d1644cdb3b..5768e38c5a 100644 --- a/backend/groth16/bw6-761/verify.go +++ b/backend/groth16/bw6-761/verify.go @@ -64,7 +64,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { if vk.CommitmentInfo.Is() { - if err := vk.CommitmentKey.VerifyKnowledgeProof(proof.Commitment, proof.CommitmentPok); err != nil { + if err := vk.CommitmentKey.Verify(proof.Commitment, proof.CommitmentPok); err != nil { return err } diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl index ee62876564..5949c36130 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl @@ -34,7 +34,7 @@ type ProvingKey struct { InfinityA, InfinityB []bool NbInfinityA, NbInfinityB uint64 - CommitmentKey pedersen.Key + CommitmentKey pedersen.ProvingKey } // VerifyingKey is used by a Groth16 verifier to verify the validity of a proof and a statement @@ -57,7 +57,7 @@ type VerifyingKey struct { // e(α, β) e curve.GT // not serialized - CommitmentKey pedersen.Key + CommitmentKey pedersen.VerifyingKey CommitmentInfo constraint.Commitment // since the verifier doesn't input a constraint system, this needs to be provided here } @@ -238,11 +238,10 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { if nbPrivateCommittedWires != 0 { commitmentBasis := g1PointsAff[offset:] - vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + pk.CommitmentKey, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) if err != nil { return err } - pk.CommitmentKey = vk.CommitmentKey } vk.CommitmentInfo = r1cs.CommitmentInfo // unfortunate but necessary diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl index 29a7202c08..93767fedfe 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl @@ -49,7 +49,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { if vk.CommitmentInfo.Is() { - if err := vk.CommitmentKey.VerifyKnowledgeProof(proof.Commitment, proof.CommitmentPok); err != nil { + if err := vk.CommitmentKey.Verify(proof.Commitment, proof.CommitmentPok); err != nil { return err } From a48a8d12bfaa72b1507a711eca2998b02c7e95f5 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Thu, 20 Apr 2023 14:39:22 -0500 Subject: [PATCH 291/464] feat: introduce constraint blueprints. improve memory usage, enables custom gates and group of constraints (#641) * refactor: introduce blueprint in constraint/ and frontend/ package * fix: add temporary workaround for serialization of blueprints * fix: fix linter errors * fix: remove some empty branches * style: remove deadcode * perf: better mem footprint for hintmapping * perf: reduce uneeded allocs in solver * feat: add R1CIterator * feat: add SparseR1CIterator * refactor: move solver for plonkish into blueprint * perf: minor optim, do not inv 1 and -1 * perf: hunting allocs * perf: added bool gate for plonk * feat: kill usage of unsafe in r1cs blueprint * perf: minor adjustement in r1cs compile * fix: fix incorrect constraint * fix: fix PR comments * fix: hint should not change in/out ptr --- .gitignore | 2 + backend/groth16/bls12-377/mpcsetup/phase2.go | 8 +- backend/groth16/bls12-377/prove.go | 2 +- backend/groth16/bls12-377/setup.go | 22 +- backend/groth16/bls12-381/mpcsetup/phase2.go | 8 +- backend/groth16/bls12-381/prove.go | 2 +- backend/groth16/bls12-381/setup.go | 22 +- backend/groth16/bls24-315/mpcsetup/phase2.go | 8 +- backend/groth16/bls24-315/prove.go | 2 +- backend/groth16/bls24-315/setup.go | 22 +- backend/groth16/bls24-317/mpcsetup/phase2.go | 8 +- backend/groth16/bls24-317/prove.go | 2 +- backend/groth16/bls24-317/setup.go | 22 +- backend/groth16/bn254/mpcsetup/phase2.go | 8 +- backend/groth16/bn254/prove.go | 2 +- backend/groth16/bn254/setup.go | 22 +- backend/groth16/bw6-633/mpcsetup/phase2.go | 8 +- backend/groth16/bw6-633/prove.go | 2 +- backend/groth16/bw6-633/setup.go | 22 +- backend/groth16/bw6-761/mpcsetup/phase2.go | 8 +- backend/groth16/bw6-761/prove.go | 2 +- backend/groth16/bw6-761/setup.go | 22 +- backend/plonk/bls12-377/prove.go | 4 +- backend/plonk/bls12-377/setup.go | 36 +- backend/plonk/bls12-381/prove.go | 4 +- backend/plonk/bls12-381/setup.go | 36 +- backend/plonk/bls24-315/prove.go | 4 +- backend/plonk/bls24-315/setup.go | 36 +- backend/plonk/bls24-317/prove.go | 4 +- backend/plonk/bls24-317/setup.go | 36 +- backend/plonk/bn254/prove.go | 4 +- backend/plonk/bn254/setup.go | 36 +- backend/plonk/bw6-633/prove.go | 4 +- backend/plonk/bw6-633/setup.go | 36 +- backend/plonk/bw6-761/prove.go | 4 +- backend/plonk/bw6-761/setup.go | 36 +- backend/plonkfri/bls12-377/setup.go | 35 +- backend/plonkfri/bls12-381/setup.go | 35 +- backend/plonkfri/bls24-315/setup.go | 35 +- backend/plonkfri/bls24-317/setup.go | 35 +- backend/plonkfri/bn254/setup.go | 35 +- backend/plonkfri/bw6-633/setup.go | 35 +- backend/plonkfri/bw6-761/setup.go | 35 +- constraint/bls12-377/coeff.go | 58 +- constraint/bls12-377/r1cs.go | 467 ------------- constraint/bls12-377/r1cs_sparse.go | 533 --------------- constraint/bls12-377/r1cs_test.go | 42 +- constraint/bls12-377/solution.go | 383 ----------- constraint/bls12-377/solver.go | 614 +++++++++++++++++ constraint/bls12-377/system.go | 365 +++++++++++ constraint/bls12-381/coeff.go | 58 +- constraint/bls12-381/r1cs.go | 467 ------------- constraint/bls12-381/r1cs_sparse.go | 533 --------------- constraint/bls12-381/r1cs_test.go | 42 +- constraint/bls12-381/solution.go | 383 ----------- constraint/bls12-381/solver.go | 614 +++++++++++++++++ constraint/bls12-381/system.go | 365 +++++++++++ constraint/bls24-315/coeff.go | 58 +- constraint/bls24-315/r1cs.go | 467 ------------- constraint/bls24-315/r1cs_sparse.go | 533 --------------- constraint/bls24-315/r1cs_test.go | 42 +- constraint/bls24-315/solution.go | 383 ----------- constraint/bls24-315/solver.go | 614 +++++++++++++++++ constraint/bls24-315/system.go | 365 +++++++++++ constraint/bls24-317/coeff.go | 58 +- constraint/bls24-317/r1cs.go | 467 ------------- constraint/bls24-317/r1cs_sparse.go | 533 --------------- constraint/bls24-317/r1cs_test.go | 42 +- constraint/bls24-317/solution.go | 383 ----------- constraint/bls24-317/solver.go | 614 +++++++++++++++++ constraint/bls24-317/system.go | 365 +++++++++++ constraint/blueprint.go | 51 ++ constraint/blueprint_hint.go | 71 ++ constraint/blueprint_r1cs.go | 58 ++ constraint/blueprint_scs.go | 287 ++++++++ constraint/bn254/coeff.go | 58 +- constraint/bn254/r1cs.go | 467 ------------- constraint/bn254/r1cs_sparse.go | 533 --------------- constraint/bn254/r1cs_test.go | 42 +- constraint/bn254/solution.go | 383 ----------- constraint/bn254/solver.go | 614 +++++++++++++++++ constraint/bn254/system.go | 365 +++++++++++ constraint/bw6-633/coeff.go | 58 +- constraint/bw6-633/r1cs.go | 467 ------------- constraint/bw6-633/r1cs_sparse.go | 533 --------------- constraint/bw6-633/r1cs_test.go | 42 +- constraint/bw6-633/solution.go | 383 ----------- constraint/bw6-633/solver.go | 614 +++++++++++++++++ constraint/bw6-633/system.go | 365 +++++++++++ constraint/bw6-761/coeff.go | 58 +- constraint/bw6-761/r1cs.go | 467 ------------- constraint/bw6-761/r1cs_sparse.go | 533 --------------- constraint/bw6-761/r1cs_test.go | 42 +- constraint/bw6-761/solution.go | 383 ----------- constraint/bw6-761/solver.go | 614 +++++++++++++++++ constraint/bw6-761/system.go | 365 +++++++++++ constraint/coeff.go | 39 -- constraint/core.go | 374 +++++++++++ constraint/field.go | 29 + constraint/hint.go | 45 +- constraint/level_builder.go | 41 +- constraint/r1cs.go | 230 +++---- constraint/r1cs_sparse.go | 246 ++++--- constraint/r1cs_sparse_test.go | 45 +- constraint/r1cs_test.go | 20 +- constraint/system.go | 239 +------ constraint/term.go | 9 + constraint/tinyfield/coeff.go | 58 +- constraint/tinyfield/r1cs.go | 467 ------------- constraint/tinyfield/r1cs_sparse.go | 533 --------------- constraint/tinyfield/r1cs_test.go | 42 +- constraint/tinyfield/solution.go | 383 ----------- constraint/tinyfield/solver.go | 614 +++++++++++++++++ constraint/tinyfield/system.go | 365 +++++++++++ debug_test.go | 43 +- frontend/cs/r1cs/api.go | 72 +- frontend/cs/r1cs/api_assertions.go | 25 +- frontend/cs/r1cs/builder.go | 55 +- frontend/cs/r1cs/r1cs_test.go | 2 +- frontend/cs/scs/api.go | 89 +-- frontend/cs/scs/api_assertions.go | 22 +- frontend/cs/scs/builder.go | 358 +++++----- frontend/internal/expr/linear_expression.go | 10 +- go.mod | 2 +- internal/generator/backend/main.go | 5 +- .../template/representations/coeff.go.tmpl | 65 +- .../template/representations/r1cs.go.tmpl | 463 ------------- .../representations/r1cs.sparse.go.tmpl | 524 --------------- .../template/representations/solution.go.tmpl | 370 ----------- .../template/representations/solver.go.tmpl | 618 ++++++++++++++++++ .../template/representations/system.go.tmpl | 363 ++++++++++ .../representations/tests/r1cs.go.tmpl | 40 +- .../zkpschemes/groth16/groth16.prove.go.tmpl | 2 +- .../zkpschemes/groth16/groth16.setup.go.tmpl | 23 +- .../groth16/mpcsetup/phase2.go.tmpl | 10 +- .../zkpschemes/plonk/plonk.prove.go.tmpl | 4 +- .../zkpschemes/plonk/plonk.setup.go.tmpl | 39 +- .../zkpschemes/plonkfri/plonk.setup.go.tmpl | 37 +- profile/profile_test.go | 2 +- std/algebra/emulated/sw_bn254/pairing_test.go | 88 ++- std/lookup/logderivlookup/logderivlookup.go | 2 +- test/fuzz.go | 6 +- 142 files changed, 11681 insertions(+), 13889 deletions(-) delete mode 100644 constraint/bls12-377/r1cs.go delete mode 100644 constraint/bls12-377/r1cs_sparse.go delete mode 100644 constraint/bls12-377/solution.go create mode 100644 constraint/bls12-377/solver.go create mode 100644 constraint/bls12-377/system.go delete mode 100644 constraint/bls12-381/r1cs.go delete mode 100644 constraint/bls12-381/r1cs_sparse.go delete mode 100644 constraint/bls12-381/solution.go create mode 100644 constraint/bls12-381/solver.go create mode 100644 constraint/bls12-381/system.go delete mode 100644 constraint/bls24-315/r1cs.go delete mode 100644 constraint/bls24-315/r1cs_sparse.go delete mode 100644 constraint/bls24-315/solution.go create mode 100644 constraint/bls24-315/solver.go create mode 100644 constraint/bls24-315/system.go delete mode 100644 constraint/bls24-317/r1cs.go delete mode 100644 constraint/bls24-317/r1cs_sparse.go delete mode 100644 constraint/bls24-317/solution.go create mode 100644 constraint/bls24-317/solver.go create mode 100644 constraint/bls24-317/system.go create mode 100644 constraint/blueprint.go create mode 100644 constraint/blueprint_hint.go create mode 100644 constraint/blueprint_r1cs.go create mode 100644 constraint/blueprint_scs.go delete mode 100644 constraint/bn254/r1cs.go delete mode 100644 constraint/bn254/r1cs_sparse.go delete mode 100644 constraint/bn254/solution.go create mode 100644 constraint/bn254/solver.go create mode 100644 constraint/bn254/system.go delete mode 100644 constraint/bw6-633/r1cs.go delete mode 100644 constraint/bw6-633/r1cs_sparse.go delete mode 100644 constraint/bw6-633/solution.go create mode 100644 constraint/bw6-633/solver.go create mode 100644 constraint/bw6-633/system.go delete mode 100644 constraint/bw6-761/r1cs.go delete mode 100644 constraint/bw6-761/r1cs_sparse.go delete mode 100644 constraint/bw6-761/solution.go create mode 100644 constraint/bw6-761/solver.go create mode 100644 constraint/bw6-761/system.go delete mode 100644 constraint/coeff.go create mode 100644 constraint/core.go create mode 100644 constraint/field.go delete mode 100644 constraint/tinyfield/r1cs.go delete mode 100644 constraint/tinyfield/r1cs_sparse.go delete mode 100644 constraint/tinyfield/solution.go create mode 100644 constraint/tinyfield/solver.go create mode 100644 constraint/tinyfield/system.go delete mode 100644 internal/generator/backend/template/representations/r1cs.go.tmpl delete mode 100644 internal/generator/backend/template/representations/r1cs.sparse.go.tmpl delete mode 100644 internal/generator/backend/template/representations/solution.go.tmpl create mode 100644 internal/generator/backend/template/representations/solver.go.tmpl create mode 100644 internal/generator/backend/template/representations/system.go.tmpl diff --git a/.gitignore b/.gitignore index 02c2647a19..1be9af1ba2 100644 --- a/.gitignore +++ b/.gitignore @@ -54,3 +54,5 @@ gnarkd/circuits/** # go workspace go.work go.work.sum + +examples/gbotrel/** \ No newline at end of file diff --git a/backend/groth16/bls12-377/mpcsetup/phase2.go b/backend/groth16/bls12-377/mpcsetup/phase2.go index a43efe3fcc..3460138d12 100644 --- a/backend/groth16/bls12-377/mpcsetup/phase2.go +++ b/backend/groth16/bls12-377/mpcsetup/phase2.go @@ -114,7 +114,12 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { bA := make([]curve.G1Affine, nWires) aB := make([]curve.G1Affine, nWires) C := make([]curve.G1Affine, nWires) - for i, c := range r1cs.Constraints { + + // TODO @gbotrel use constraint iterator when available. + + i := 0 + it := r1cs.GetR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { // A for _, t := range c.L { accumulateG1(&evals.G1.A[t.WireID()], t, &coeffTau1[i]) @@ -130,6 +135,7 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { for _, t := range c.O { accumulateG1(&C[t.WireID()], t, &coeffTau1[i]) } + i++ } // Prepare default contribution diff --git a/backend/groth16/bls12-377/prove.go b/backend/groth16/bls12-377/prove.go index 249e2088ef..9fbb3d06ef 100644 --- a/backend/groth16/bls12-377/prove.go +++ b/backend/groth16/bls12-377/prove.go @@ -59,7 +59,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return nil, err } - log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", len(r1cs.Constraints)).Str("backend", "groth16").Logger() + log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() proof := &Proof{} diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index c1e7a22c9e..29c37cad94 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -103,7 +103,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } // Setting group for fft - domain := fft.NewDomain(uint64(len(r1cs.Constraints))) + domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) // samples toxic waste toxicWaste, err := sampleToxicWaste() @@ -334,7 +334,7 @@ func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr. var w fr.Element w.Set(&domain.Generator) wi := fr.One() - t := make([]fr.Element, len(r1cs.Constraints)+1) + t := make([]fr.Element, r1cs.GetNbConstraints()+1) for i := 0; i < len(t); i++ { t[i].Sub(&toxicWaste.t, &wi) wi.Mul(&wi, &w) // TODO this is already pre computed in fft.Domain @@ -378,8 +378,10 @@ func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr. // for each term appearing in the linear expression, // we compute term.Coefficient * L, and cumulate it in // A, B or C at the index of the variable - for i, c := range r1cs.Constraints { + j := 0 + it := r1cs.GetR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { for _, t := range c.L { accumulate(&A[t.WireID()], t, &L) } @@ -392,9 +394,12 @@ func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr. // Li+1 = w*Li*(t-w^i)/(t-w^(i+1)) L.Mul(&L, &w) - L.Mul(&L, &t[i]) - L.Mul(&L, &tInv[i+1]) + L.Mul(&L, &t[j]) + L.Mul(&L, &tInv[j+1]) + + j++ } + return } @@ -448,7 +453,7 @@ func sampleToxicWaste() (toxicWaste, error) { func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbConstraints := len(r1cs.Constraints) + nbConstraints := r1cs.GetNbConstraints() // Setting group for fft domain := fft.NewDomain(uint64(nbConstraints)) @@ -526,7 +531,9 @@ func dummyInfinityCount(r1cs *cs.R1CS) (nbZeroesA, nbZeroesB int) { A := make([]bool, nbWires) B := make([]bool, nbWires) - for _, c := range r1cs.Constraints { + + it := r1cs.GetR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { for _, t := range c.L { A[t.WireID()] = true } @@ -534,6 +541,7 @@ func dummyInfinityCount(r1cs *cs.R1CS) (nbZeroesA, nbZeroesB int) { B[t.WireID()] = true } } + for i := 0; i < nbWires; i++ { if !A[i] { nbZeroesA++ diff --git a/backend/groth16/bls12-381/mpcsetup/phase2.go b/backend/groth16/bls12-381/mpcsetup/phase2.go index 38066c8c7b..f2cd98bd77 100644 --- a/backend/groth16/bls12-381/mpcsetup/phase2.go +++ b/backend/groth16/bls12-381/mpcsetup/phase2.go @@ -114,7 +114,12 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { bA := make([]curve.G1Affine, nWires) aB := make([]curve.G1Affine, nWires) C := make([]curve.G1Affine, nWires) - for i, c := range r1cs.Constraints { + + // TODO @gbotrel use constraint iterator when available. + + i := 0 + it := r1cs.GetR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { // A for _, t := range c.L { accumulateG1(&evals.G1.A[t.WireID()], t, &coeffTau1[i]) @@ -130,6 +135,7 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { for _, t := range c.O { accumulateG1(&C[t.WireID()], t, &coeffTau1[i]) } + i++ } // Prepare default contribution diff --git a/backend/groth16/bls12-381/prove.go b/backend/groth16/bls12-381/prove.go index 0baec7df2e..254489f6f5 100644 --- a/backend/groth16/bls12-381/prove.go +++ b/backend/groth16/bls12-381/prove.go @@ -59,7 +59,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return nil, err } - log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", len(r1cs.Constraints)).Str("backend", "groth16").Logger() + log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() proof := &Proof{} diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index dc23ffa75a..b37fb7a7f4 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -103,7 +103,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } // Setting group for fft - domain := fft.NewDomain(uint64(len(r1cs.Constraints))) + domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) // samples toxic waste toxicWaste, err := sampleToxicWaste() @@ -334,7 +334,7 @@ func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr. var w fr.Element w.Set(&domain.Generator) wi := fr.One() - t := make([]fr.Element, len(r1cs.Constraints)+1) + t := make([]fr.Element, r1cs.GetNbConstraints()+1) for i := 0; i < len(t); i++ { t[i].Sub(&toxicWaste.t, &wi) wi.Mul(&wi, &w) // TODO this is already pre computed in fft.Domain @@ -378,8 +378,10 @@ func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr. // for each term appearing in the linear expression, // we compute term.Coefficient * L, and cumulate it in // A, B or C at the index of the variable - for i, c := range r1cs.Constraints { + j := 0 + it := r1cs.GetR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { for _, t := range c.L { accumulate(&A[t.WireID()], t, &L) } @@ -392,9 +394,12 @@ func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr. // Li+1 = w*Li*(t-w^i)/(t-w^(i+1)) L.Mul(&L, &w) - L.Mul(&L, &t[i]) - L.Mul(&L, &tInv[i+1]) + L.Mul(&L, &t[j]) + L.Mul(&L, &tInv[j+1]) + + j++ } + return } @@ -448,7 +453,7 @@ func sampleToxicWaste() (toxicWaste, error) { func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbConstraints := len(r1cs.Constraints) + nbConstraints := r1cs.GetNbConstraints() // Setting group for fft domain := fft.NewDomain(uint64(nbConstraints)) @@ -526,7 +531,9 @@ func dummyInfinityCount(r1cs *cs.R1CS) (nbZeroesA, nbZeroesB int) { A := make([]bool, nbWires) B := make([]bool, nbWires) - for _, c := range r1cs.Constraints { + + it := r1cs.GetR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { for _, t := range c.L { A[t.WireID()] = true } @@ -534,6 +541,7 @@ func dummyInfinityCount(r1cs *cs.R1CS) (nbZeroesA, nbZeroesB int) { B[t.WireID()] = true } } + for i := 0; i < nbWires; i++ { if !A[i] { nbZeroesA++ diff --git a/backend/groth16/bls24-315/mpcsetup/phase2.go b/backend/groth16/bls24-315/mpcsetup/phase2.go index a6da12a24a..b85efd3856 100644 --- a/backend/groth16/bls24-315/mpcsetup/phase2.go +++ b/backend/groth16/bls24-315/mpcsetup/phase2.go @@ -114,7 +114,12 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { bA := make([]curve.G1Affine, nWires) aB := make([]curve.G1Affine, nWires) C := make([]curve.G1Affine, nWires) - for i, c := range r1cs.Constraints { + + // TODO @gbotrel use constraint iterator when available. + + i := 0 + it := r1cs.GetR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { // A for _, t := range c.L { accumulateG1(&evals.G1.A[t.WireID()], t, &coeffTau1[i]) @@ -130,6 +135,7 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { for _, t := range c.O { accumulateG1(&C[t.WireID()], t, &coeffTau1[i]) } + i++ } // Prepare default contribution diff --git a/backend/groth16/bls24-315/prove.go b/backend/groth16/bls24-315/prove.go index ecc9fa3ce7..9f9b876250 100644 --- a/backend/groth16/bls24-315/prove.go +++ b/backend/groth16/bls24-315/prove.go @@ -59,7 +59,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return nil, err } - log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", len(r1cs.Constraints)).Str("backend", "groth16").Logger() + log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() proof := &Proof{} diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index 6a4bf19a6f..be51641a92 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -103,7 +103,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } // Setting group for fft - domain := fft.NewDomain(uint64(len(r1cs.Constraints))) + domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) // samples toxic waste toxicWaste, err := sampleToxicWaste() @@ -334,7 +334,7 @@ func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr. var w fr.Element w.Set(&domain.Generator) wi := fr.One() - t := make([]fr.Element, len(r1cs.Constraints)+1) + t := make([]fr.Element, r1cs.GetNbConstraints()+1) for i := 0; i < len(t); i++ { t[i].Sub(&toxicWaste.t, &wi) wi.Mul(&wi, &w) // TODO this is already pre computed in fft.Domain @@ -378,8 +378,10 @@ func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr. // for each term appearing in the linear expression, // we compute term.Coefficient * L, and cumulate it in // A, B or C at the index of the variable - for i, c := range r1cs.Constraints { + j := 0 + it := r1cs.GetR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { for _, t := range c.L { accumulate(&A[t.WireID()], t, &L) } @@ -392,9 +394,12 @@ func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr. // Li+1 = w*Li*(t-w^i)/(t-w^(i+1)) L.Mul(&L, &w) - L.Mul(&L, &t[i]) - L.Mul(&L, &tInv[i+1]) + L.Mul(&L, &t[j]) + L.Mul(&L, &tInv[j+1]) + + j++ } + return } @@ -448,7 +453,7 @@ func sampleToxicWaste() (toxicWaste, error) { func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbConstraints := len(r1cs.Constraints) + nbConstraints := r1cs.GetNbConstraints() // Setting group for fft domain := fft.NewDomain(uint64(nbConstraints)) @@ -526,7 +531,9 @@ func dummyInfinityCount(r1cs *cs.R1CS) (nbZeroesA, nbZeroesB int) { A := make([]bool, nbWires) B := make([]bool, nbWires) - for _, c := range r1cs.Constraints { + + it := r1cs.GetR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { for _, t := range c.L { A[t.WireID()] = true } @@ -534,6 +541,7 @@ func dummyInfinityCount(r1cs *cs.R1CS) (nbZeroesA, nbZeroesB int) { B[t.WireID()] = true } } + for i := 0; i < nbWires; i++ { if !A[i] { nbZeroesA++ diff --git a/backend/groth16/bls24-317/mpcsetup/phase2.go b/backend/groth16/bls24-317/mpcsetup/phase2.go index 15772e84c5..cac7bc08eb 100644 --- a/backend/groth16/bls24-317/mpcsetup/phase2.go +++ b/backend/groth16/bls24-317/mpcsetup/phase2.go @@ -114,7 +114,12 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { bA := make([]curve.G1Affine, nWires) aB := make([]curve.G1Affine, nWires) C := make([]curve.G1Affine, nWires) - for i, c := range r1cs.Constraints { + + // TODO @gbotrel use constraint iterator when available. + + i := 0 + it := r1cs.GetR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { // A for _, t := range c.L { accumulateG1(&evals.G1.A[t.WireID()], t, &coeffTau1[i]) @@ -130,6 +135,7 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { for _, t := range c.O { accumulateG1(&C[t.WireID()], t, &coeffTau1[i]) } + i++ } // Prepare default contribution diff --git a/backend/groth16/bls24-317/prove.go b/backend/groth16/bls24-317/prove.go index 9242f4a061..68a6a80896 100644 --- a/backend/groth16/bls24-317/prove.go +++ b/backend/groth16/bls24-317/prove.go @@ -59,7 +59,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return nil, err } - log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", len(r1cs.Constraints)).Str("backend", "groth16").Logger() + log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() proof := &Proof{} diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index cd21b8dde9..8353699900 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -103,7 +103,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } // Setting group for fft - domain := fft.NewDomain(uint64(len(r1cs.Constraints))) + domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) // samples toxic waste toxicWaste, err := sampleToxicWaste() @@ -334,7 +334,7 @@ func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr. var w fr.Element w.Set(&domain.Generator) wi := fr.One() - t := make([]fr.Element, len(r1cs.Constraints)+1) + t := make([]fr.Element, r1cs.GetNbConstraints()+1) for i := 0; i < len(t); i++ { t[i].Sub(&toxicWaste.t, &wi) wi.Mul(&wi, &w) // TODO this is already pre computed in fft.Domain @@ -378,8 +378,10 @@ func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr. // for each term appearing in the linear expression, // we compute term.Coefficient * L, and cumulate it in // A, B or C at the index of the variable - for i, c := range r1cs.Constraints { + j := 0 + it := r1cs.GetR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { for _, t := range c.L { accumulate(&A[t.WireID()], t, &L) } @@ -392,9 +394,12 @@ func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr. // Li+1 = w*Li*(t-w^i)/(t-w^(i+1)) L.Mul(&L, &w) - L.Mul(&L, &t[i]) - L.Mul(&L, &tInv[i+1]) + L.Mul(&L, &t[j]) + L.Mul(&L, &tInv[j+1]) + + j++ } + return } @@ -448,7 +453,7 @@ func sampleToxicWaste() (toxicWaste, error) { func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbConstraints := len(r1cs.Constraints) + nbConstraints := r1cs.GetNbConstraints() // Setting group for fft domain := fft.NewDomain(uint64(nbConstraints)) @@ -526,7 +531,9 @@ func dummyInfinityCount(r1cs *cs.R1CS) (nbZeroesA, nbZeroesB int) { A := make([]bool, nbWires) B := make([]bool, nbWires) - for _, c := range r1cs.Constraints { + + it := r1cs.GetR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { for _, t := range c.L { A[t.WireID()] = true } @@ -534,6 +541,7 @@ func dummyInfinityCount(r1cs *cs.R1CS) (nbZeroesA, nbZeroesB int) { B[t.WireID()] = true } } + for i := 0; i < nbWires; i++ { if !A[i] { nbZeroesA++ diff --git a/backend/groth16/bn254/mpcsetup/phase2.go b/backend/groth16/bn254/mpcsetup/phase2.go index 5ead8e8dd4..c14e14b509 100644 --- a/backend/groth16/bn254/mpcsetup/phase2.go +++ b/backend/groth16/bn254/mpcsetup/phase2.go @@ -114,7 +114,12 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { bA := make([]curve.G1Affine, nWires) aB := make([]curve.G1Affine, nWires) C := make([]curve.G1Affine, nWires) - for i, c := range r1cs.Constraints { + + // TODO @gbotrel use constraint iterator when available. + + i := 0 + it := r1cs.GetR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { // A for _, t := range c.L { accumulateG1(&evals.G1.A[t.WireID()], t, &coeffTau1[i]) @@ -130,6 +135,7 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { for _, t := range c.O { accumulateG1(&C[t.WireID()], t, &coeffTau1[i]) } + i++ } // Prepare default contribution diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index 7377a93bba..abda2496c5 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -59,7 +59,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return nil, err } - log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", len(r1cs.Constraints)).Str("backend", "groth16").Logger() + log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() proof := &Proof{} diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index e65295ebec..8b73a4a946 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -103,7 +103,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } // Setting group for fft - domain := fft.NewDomain(uint64(len(r1cs.Constraints))) + domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) // samples toxic waste toxicWaste, err := sampleToxicWaste() @@ -334,7 +334,7 @@ func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr. var w fr.Element w.Set(&domain.Generator) wi := fr.One() - t := make([]fr.Element, len(r1cs.Constraints)+1) + t := make([]fr.Element, r1cs.GetNbConstraints()+1) for i := 0; i < len(t); i++ { t[i].Sub(&toxicWaste.t, &wi) wi.Mul(&wi, &w) // TODO this is already pre computed in fft.Domain @@ -378,8 +378,10 @@ func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr. // for each term appearing in the linear expression, // we compute term.Coefficient * L, and cumulate it in // A, B or C at the index of the variable - for i, c := range r1cs.Constraints { + j := 0 + it := r1cs.GetR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { for _, t := range c.L { accumulate(&A[t.WireID()], t, &L) } @@ -392,9 +394,12 @@ func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr. // Li+1 = w*Li*(t-w^i)/(t-w^(i+1)) L.Mul(&L, &w) - L.Mul(&L, &t[i]) - L.Mul(&L, &tInv[i+1]) + L.Mul(&L, &t[j]) + L.Mul(&L, &tInv[j+1]) + + j++ } + return } @@ -448,7 +453,7 @@ func sampleToxicWaste() (toxicWaste, error) { func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbConstraints := len(r1cs.Constraints) + nbConstraints := r1cs.GetNbConstraints() // Setting group for fft domain := fft.NewDomain(uint64(nbConstraints)) @@ -526,7 +531,9 @@ func dummyInfinityCount(r1cs *cs.R1CS) (nbZeroesA, nbZeroesB int) { A := make([]bool, nbWires) B := make([]bool, nbWires) - for _, c := range r1cs.Constraints { + + it := r1cs.GetR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { for _, t := range c.L { A[t.WireID()] = true } @@ -534,6 +541,7 @@ func dummyInfinityCount(r1cs *cs.R1CS) (nbZeroesA, nbZeroesB int) { B[t.WireID()] = true } } + for i := 0; i < nbWires; i++ { if !A[i] { nbZeroesA++ diff --git a/backend/groth16/bw6-633/mpcsetup/phase2.go b/backend/groth16/bw6-633/mpcsetup/phase2.go index 2b9aff3529..e966fd021a 100644 --- a/backend/groth16/bw6-633/mpcsetup/phase2.go +++ b/backend/groth16/bw6-633/mpcsetup/phase2.go @@ -114,7 +114,12 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { bA := make([]curve.G1Affine, nWires) aB := make([]curve.G1Affine, nWires) C := make([]curve.G1Affine, nWires) - for i, c := range r1cs.Constraints { + + // TODO @gbotrel use constraint iterator when available. + + i := 0 + it := r1cs.GetR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { // A for _, t := range c.L { accumulateG1(&evals.G1.A[t.WireID()], t, &coeffTau1[i]) @@ -130,6 +135,7 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { for _, t := range c.O { accumulateG1(&C[t.WireID()], t, &coeffTau1[i]) } + i++ } // Prepare default contribution diff --git a/backend/groth16/bw6-633/prove.go b/backend/groth16/bw6-633/prove.go index 6779247d96..c05c73c5b4 100644 --- a/backend/groth16/bw6-633/prove.go +++ b/backend/groth16/bw6-633/prove.go @@ -59,7 +59,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return nil, err } - log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", len(r1cs.Constraints)).Str("backend", "groth16").Logger() + log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() proof := &Proof{} diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index 7118c2fa44..c4b4989ce3 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -103,7 +103,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } // Setting group for fft - domain := fft.NewDomain(uint64(len(r1cs.Constraints))) + domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) // samples toxic waste toxicWaste, err := sampleToxicWaste() @@ -334,7 +334,7 @@ func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr. var w fr.Element w.Set(&domain.Generator) wi := fr.One() - t := make([]fr.Element, len(r1cs.Constraints)+1) + t := make([]fr.Element, r1cs.GetNbConstraints()+1) for i := 0; i < len(t); i++ { t[i].Sub(&toxicWaste.t, &wi) wi.Mul(&wi, &w) // TODO this is already pre computed in fft.Domain @@ -378,8 +378,10 @@ func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr. // for each term appearing in the linear expression, // we compute term.Coefficient * L, and cumulate it in // A, B or C at the index of the variable - for i, c := range r1cs.Constraints { + j := 0 + it := r1cs.GetR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { for _, t := range c.L { accumulate(&A[t.WireID()], t, &L) } @@ -392,9 +394,12 @@ func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr. // Li+1 = w*Li*(t-w^i)/(t-w^(i+1)) L.Mul(&L, &w) - L.Mul(&L, &t[i]) - L.Mul(&L, &tInv[i+1]) + L.Mul(&L, &t[j]) + L.Mul(&L, &tInv[j+1]) + + j++ } + return } @@ -448,7 +453,7 @@ func sampleToxicWaste() (toxicWaste, error) { func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbConstraints := len(r1cs.Constraints) + nbConstraints := r1cs.GetNbConstraints() // Setting group for fft domain := fft.NewDomain(uint64(nbConstraints)) @@ -526,7 +531,9 @@ func dummyInfinityCount(r1cs *cs.R1CS) (nbZeroesA, nbZeroesB int) { A := make([]bool, nbWires) B := make([]bool, nbWires) - for _, c := range r1cs.Constraints { + + it := r1cs.GetR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { for _, t := range c.L { A[t.WireID()] = true } @@ -534,6 +541,7 @@ func dummyInfinityCount(r1cs *cs.R1CS) (nbZeroesA, nbZeroesB int) { B[t.WireID()] = true } } + for i := 0; i < nbWires; i++ { if !A[i] { nbZeroesA++ diff --git a/backend/groth16/bw6-761/mpcsetup/phase2.go b/backend/groth16/bw6-761/mpcsetup/phase2.go index b9bfb5b8ac..df2d2d5be9 100644 --- a/backend/groth16/bw6-761/mpcsetup/phase2.go +++ b/backend/groth16/bw6-761/mpcsetup/phase2.go @@ -114,7 +114,12 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { bA := make([]curve.G1Affine, nWires) aB := make([]curve.G1Affine, nWires) C := make([]curve.G1Affine, nWires) - for i, c := range r1cs.Constraints { + + // TODO @gbotrel use constraint iterator when available. + + i := 0 + it := r1cs.GetR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { // A for _, t := range c.L { accumulateG1(&evals.G1.A[t.WireID()], t, &coeffTau1[i]) @@ -130,6 +135,7 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { for _, t := range c.O { accumulateG1(&C[t.WireID()], t, &coeffTau1[i]) } + i++ } // Prepare default contribution diff --git a/backend/groth16/bw6-761/prove.go b/backend/groth16/bw6-761/prove.go index 5dff18221e..749f4df497 100644 --- a/backend/groth16/bw6-761/prove.go +++ b/backend/groth16/bw6-761/prove.go @@ -59,7 +59,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return nil, err } - log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", len(r1cs.Constraints)).Str("backend", "groth16").Logger() + log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() proof := &Proof{} diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index 5cc22cbfa5..c0ab0343da 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -103,7 +103,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } // Setting group for fft - domain := fft.NewDomain(uint64(len(r1cs.Constraints))) + domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) // samples toxic waste toxicWaste, err := sampleToxicWaste() @@ -334,7 +334,7 @@ func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr. var w fr.Element w.Set(&domain.Generator) wi := fr.One() - t := make([]fr.Element, len(r1cs.Constraints)+1) + t := make([]fr.Element, r1cs.GetNbConstraints()+1) for i := 0; i < len(t); i++ { t[i].Sub(&toxicWaste.t, &wi) wi.Mul(&wi, &w) // TODO this is already pre computed in fft.Domain @@ -378,8 +378,10 @@ func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr. // for each term appearing in the linear expression, // we compute term.Coefficient * L, and cumulate it in // A, B or C at the index of the variable - for i, c := range r1cs.Constraints { + j := 0 + it := r1cs.GetR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { for _, t := range c.L { accumulate(&A[t.WireID()], t, &L) } @@ -392,9 +394,12 @@ func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr. // Li+1 = w*Li*(t-w^i)/(t-w^(i+1)) L.Mul(&L, &w) - L.Mul(&L, &t[i]) - L.Mul(&L, &tInv[i+1]) + L.Mul(&L, &t[j]) + L.Mul(&L, &tInv[j+1]) + + j++ } + return } @@ -448,7 +453,7 @@ func sampleToxicWaste() (toxicWaste, error) { func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbConstraints := len(r1cs.Constraints) + nbConstraints := r1cs.GetNbConstraints() // Setting group for fft domain := fft.NewDomain(uint64(nbConstraints)) @@ -526,7 +531,9 @@ func dummyInfinityCount(r1cs *cs.R1CS) (nbZeroesA, nbZeroesB int) { A := make([]bool, nbWires) B := make([]bool, nbWires) - for _, c := range r1cs.Constraints { + + it := r1cs.GetR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { for _, t := range c.L { A[t.WireID()] = true } @@ -534,6 +541,7 @@ func dummyInfinityCount(r1cs *cs.R1CS) (nbZeroesA, nbZeroesB int) { B[t.WireID()] = true } } + for i := 0; i < nbWires; i++ { if !A[i] { nbZeroesA++ diff --git a/backend/plonk/bls12-377/prove.go b/backend/plonk/bls12-377/prove.go index f07386a923..ee9fcd12a4 100644 --- a/backend/plonk/bls12-377/prove.go +++ b/backend/plonk/bls12-377/prove.go @@ -66,7 +66,7 @@ type Proof struct { func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { - log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", len(spr.Constraints)).Str("backend", "plonk").Logger() + log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", spr.GetNbConstraints()).Str("backend", "plonk").Logger() opt, err := backend.NewProverConfig(opts...) if err != nil { @@ -101,7 +101,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } - if _, err = pi2[offset+len(spr.Constraints)-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding + if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding return err } pi2iop := iop.NewPolynomial(&pi2, lagReg) diff --git a/backend/plonk/bls12-377/setup.go b/backend/plonk/bls12-377/setup.go index 395f688f77..508f43d0db 100644 --- a/backend/plonk/bls12-377/setup.go +++ b/backend/plonk/bls12-377/setup.go @@ -241,7 +241,7 @@ func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { // Size is the size of the system that is nb_constraints+nb_public_variables func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { - nbConstraints := len(spr.Constraints) + nbConstraints := spr.GetNbConstraints() sizeSystem := uint64(nbConstraints + len(spr.Public)) size := ecc.NextPowerOfTwo(sizeSystem) @@ -260,15 +260,18 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qk[i].SetZero() // → to be completed by the prover } offset := len(spr.Public) - for i := 0; i < nbConstraints; i++ { // constraints - - ql[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) - qr[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) - qm[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). - Mul(&qm[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) - qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) - qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { + ql[offset+j].Set(&spr.Coefficients[c.QL]) + qr[offset+j].Set(&spr.Coefficients[c.QR]) + qm[offset+j].Set(&spr.Coefficients[c.QM]) + qo[offset+j].Set(&spr.Coefficients[c.QO]) + qk[offset+j].Set(&spr.Coefficients[c.QC]) + j++ } + for _, committed := range spr.CommitmentInfo.Committed { qcp[offset+committed].SetOne() } @@ -331,7 +334,7 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { func (pk *ProvingKey) initDomains(spr *cs.SparseR1CS) { - nbConstraints := len(spr.Constraints) + nbConstraints := spr.GetNbConstraints() sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints pk.Domain[0] = *fft.NewDomain(sizeSystem) @@ -377,10 +380,15 @@ func buildPermutation(spr *cs.SparseR1CS, pt *Trace, nbVariables int) { } offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // IDs of LRO associated to constraints - lro[offset+i] = spr.Constraints[i].L.WireID() - lro[sizeSolution+offset+i] = spr.Constraints[i].R.WireID() - lro[2*sizeSolution+offset+i] = spr.Constraints[i].O.WireID() + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { + lro[offset+j] = int(c.XA) + lro[sizeSolution+offset+j] = int(c.XB) + lro[2*sizeSolution+offset+j] = int(c.XC) + + j++ } // init cycle: diff --git a/backend/plonk/bls12-381/prove.go b/backend/plonk/bls12-381/prove.go index 61ab610fb2..6e64dde9f3 100644 --- a/backend/plonk/bls12-381/prove.go +++ b/backend/plonk/bls12-381/prove.go @@ -66,7 +66,7 @@ type Proof struct { func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { - log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", len(spr.Constraints)).Str("backend", "plonk").Logger() + log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", spr.GetNbConstraints()).Str("backend", "plonk").Logger() opt, err := backend.NewProverConfig(opts...) if err != nil { @@ -101,7 +101,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } - if _, err = pi2[offset+len(spr.Constraints)-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding + if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding return err } pi2iop := iop.NewPolynomial(&pi2, lagReg) diff --git a/backend/plonk/bls12-381/setup.go b/backend/plonk/bls12-381/setup.go index 74ea66bafa..0906088f3f 100644 --- a/backend/plonk/bls12-381/setup.go +++ b/backend/plonk/bls12-381/setup.go @@ -241,7 +241,7 @@ func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { // Size is the size of the system that is nb_constraints+nb_public_variables func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { - nbConstraints := len(spr.Constraints) + nbConstraints := spr.GetNbConstraints() sizeSystem := uint64(nbConstraints + len(spr.Public)) size := ecc.NextPowerOfTwo(sizeSystem) @@ -260,15 +260,18 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qk[i].SetZero() // → to be completed by the prover } offset := len(spr.Public) - for i := 0; i < nbConstraints; i++ { // constraints - - ql[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) - qr[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) - qm[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). - Mul(&qm[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) - qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) - qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { + ql[offset+j].Set(&spr.Coefficients[c.QL]) + qr[offset+j].Set(&spr.Coefficients[c.QR]) + qm[offset+j].Set(&spr.Coefficients[c.QM]) + qo[offset+j].Set(&spr.Coefficients[c.QO]) + qk[offset+j].Set(&spr.Coefficients[c.QC]) + j++ } + for _, committed := range spr.CommitmentInfo.Committed { qcp[offset+committed].SetOne() } @@ -331,7 +334,7 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { func (pk *ProvingKey) initDomains(spr *cs.SparseR1CS) { - nbConstraints := len(spr.Constraints) + nbConstraints := spr.GetNbConstraints() sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints pk.Domain[0] = *fft.NewDomain(sizeSystem) @@ -377,10 +380,15 @@ func buildPermutation(spr *cs.SparseR1CS, pt *Trace, nbVariables int) { } offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // IDs of LRO associated to constraints - lro[offset+i] = spr.Constraints[i].L.WireID() - lro[sizeSolution+offset+i] = spr.Constraints[i].R.WireID() - lro[2*sizeSolution+offset+i] = spr.Constraints[i].O.WireID() + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { + lro[offset+j] = int(c.XA) + lro[sizeSolution+offset+j] = int(c.XB) + lro[2*sizeSolution+offset+j] = int(c.XC) + + j++ } // init cycle: diff --git a/backend/plonk/bls24-315/prove.go b/backend/plonk/bls24-315/prove.go index 97d1f0f22b..d95361f4ec 100644 --- a/backend/plonk/bls24-315/prove.go +++ b/backend/plonk/bls24-315/prove.go @@ -66,7 +66,7 @@ type Proof struct { func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { - log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", len(spr.Constraints)).Str("backend", "plonk").Logger() + log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", spr.GetNbConstraints()).Str("backend", "plonk").Logger() opt, err := backend.NewProverConfig(opts...) if err != nil { @@ -101,7 +101,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } - if _, err = pi2[offset+len(spr.Constraints)-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding + if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding return err } pi2iop := iop.NewPolynomial(&pi2, lagReg) diff --git a/backend/plonk/bls24-315/setup.go b/backend/plonk/bls24-315/setup.go index 6739872eaf..5acba54a98 100644 --- a/backend/plonk/bls24-315/setup.go +++ b/backend/plonk/bls24-315/setup.go @@ -241,7 +241,7 @@ func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { // Size is the size of the system that is nb_constraints+nb_public_variables func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { - nbConstraints := len(spr.Constraints) + nbConstraints := spr.GetNbConstraints() sizeSystem := uint64(nbConstraints + len(spr.Public)) size := ecc.NextPowerOfTwo(sizeSystem) @@ -260,15 +260,18 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qk[i].SetZero() // → to be completed by the prover } offset := len(spr.Public) - for i := 0; i < nbConstraints; i++ { // constraints - - ql[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) - qr[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) - qm[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). - Mul(&qm[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) - qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) - qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { + ql[offset+j].Set(&spr.Coefficients[c.QL]) + qr[offset+j].Set(&spr.Coefficients[c.QR]) + qm[offset+j].Set(&spr.Coefficients[c.QM]) + qo[offset+j].Set(&spr.Coefficients[c.QO]) + qk[offset+j].Set(&spr.Coefficients[c.QC]) + j++ } + for _, committed := range spr.CommitmentInfo.Committed { qcp[offset+committed].SetOne() } @@ -331,7 +334,7 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { func (pk *ProvingKey) initDomains(spr *cs.SparseR1CS) { - nbConstraints := len(spr.Constraints) + nbConstraints := spr.GetNbConstraints() sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints pk.Domain[0] = *fft.NewDomain(sizeSystem) @@ -377,10 +380,15 @@ func buildPermutation(spr *cs.SparseR1CS, pt *Trace, nbVariables int) { } offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // IDs of LRO associated to constraints - lro[offset+i] = spr.Constraints[i].L.WireID() - lro[sizeSolution+offset+i] = spr.Constraints[i].R.WireID() - lro[2*sizeSolution+offset+i] = spr.Constraints[i].O.WireID() + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { + lro[offset+j] = int(c.XA) + lro[sizeSolution+offset+j] = int(c.XB) + lro[2*sizeSolution+offset+j] = int(c.XC) + + j++ } // init cycle: diff --git a/backend/plonk/bls24-317/prove.go b/backend/plonk/bls24-317/prove.go index 4964018989..3d971d133b 100644 --- a/backend/plonk/bls24-317/prove.go +++ b/backend/plonk/bls24-317/prove.go @@ -66,7 +66,7 @@ type Proof struct { func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { - log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", len(spr.Constraints)).Str("backend", "plonk").Logger() + log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", spr.GetNbConstraints()).Str("backend", "plonk").Logger() opt, err := backend.NewProverConfig(opts...) if err != nil { @@ -101,7 +101,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } - if _, err = pi2[offset+len(spr.Constraints)-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding + if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding return err } pi2iop := iop.NewPolynomial(&pi2, lagReg) diff --git a/backend/plonk/bls24-317/setup.go b/backend/plonk/bls24-317/setup.go index f8c102c819..0121690a9d 100644 --- a/backend/plonk/bls24-317/setup.go +++ b/backend/plonk/bls24-317/setup.go @@ -241,7 +241,7 @@ func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { // Size is the size of the system that is nb_constraints+nb_public_variables func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { - nbConstraints := len(spr.Constraints) + nbConstraints := spr.GetNbConstraints() sizeSystem := uint64(nbConstraints + len(spr.Public)) size := ecc.NextPowerOfTwo(sizeSystem) @@ -260,15 +260,18 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qk[i].SetZero() // → to be completed by the prover } offset := len(spr.Public) - for i := 0; i < nbConstraints; i++ { // constraints - - ql[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) - qr[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) - qm[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). - Mul(&qm[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) - qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) - qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { + ql[offset+j].Set(&spr.Coefficients[c.QL]) + qr[offset+j].Set(&spr.Coefficients[c.QR]) + qm[offset+j].Set(&spr.Coefficients[c.QM]) + qo[offset+j].Set(&spr.Coefficients[c.QO]) + qk[offset+j].Set(&spr.Coefficients[c.QC]) + j++ } + for _, committed := range spr.CommitmentInfo.Committed { qcp[offset+committed].SetOne() } @@ -331,7 +334,7 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { func (pk *ProvingKey) initDomains(spr *cs.SparseR1CS) { - nbConstraints := len(spr.Constraints) + nbConstraints := spr.GetNbConstraints() sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints pk.Domain[0] = *fft.NewDomain(sizeSystem) @@ -377,10 +380,15 @@ func buildPermutation(spr *cs.SparseR1CS, pt *Trace, nbVariables int) { } offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // IDs of LRO associated to constraints - lro[offset+i] = spr.Constraints[i].L.WireID() - lro[sizeSolution+offset+i] = spr.Constraints[i].R.WireID() - lro[2*sizeSolution+offset+i] = spr.Constraints[i].O.WireID() + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { + lro[offset+j] = int(c.XA) + lro[sizeSolution+offset+j] = int(c.XB) + lro[2*sizeSolution+offset+j] = int(c.XC) + + j++ } // init cycle: diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index b27a4c15be..1c77437000 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -66,7 +66,7 @@ type Proof struct { func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { - log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", len(spr.Constraints)).Str("backend", "plonk").Logger() + log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", spr.GetNbConstraints()).Str("backend", "plonk").Logger() opt, err := backend.NewProverConfig(opts...) if err != nil { @@ -101,7 +101,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } - if _, err = pi2[offset+len(spr.Constraints)-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding + if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding return err } pi2iop := iop.NewPolynomial(&pi2, lagReg) diff --git a/backend/plonk/bn254/setup.go b/backend/plonk/bn254/setup.go index bb7b80372c..47dd7bce0b 100644 --- a/backend/plonk/bn254/setup.go +++ b/backend/plonk/bn254/setup.go @@ -241,7 +241,7 @@ func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { // Size is the size of the system that is nb_constraints+nb_public_variables func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { - nbConstraints := len(spr.Constraints) + nbConstraints := spr.GetNbConstraints() sizeSystem := uint64(nbConstraints + len(spr.Public)) size := ecc.NextPowerOfTwo(sizeSystem) @@ -260,15 +260,18 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qk[i].SetZero() // → to be completed by the prover } offset := len(spr.Public) - for i := 0; i < nbConstraints; i++ { // constraints - - ql[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) - qr[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) - qm[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). - Mul(&qm[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) - qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) - qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { + ql[offset+j].Set(&spr.Coefficients[c.QL]) + qr[offset+j].Set(&spr.Coefficients[c.QR]) + qm[offset+j].Set(&spr.Coefficients[c.QM]) + qo[offset+j].Set(&spr.Coefficients[c.QO]) + qk[offset+j].Set(&spr.Coefficients[c.QC]) + j++ } + for _, committed := range spr.CommitmentInfo.Committed { qcp[offset+committed].SetOne() } @@ -331,7 +334,7 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { func (pk *ProvingKey) initDomains(spr *cs.SparseR1CS) { - nbConstraints := len(spr.Constraints) + nbConstraints := spr.GetNbConstraints() sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints pk.Domain[0] = *fft.NewDomain(sizeSystem) @@ -377,10 +380,15 @@ func buildPermutation(spr *cs.SparseR1CS, pt *Trace, nbVariables int) { } offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // IDs of LRO associated to constraints - lro[offset+i] = spr.Constraints[i].L.WireID() - lro[sizeSolution+offset+i] = spr.Constraints[i].R.WireID() - lro[2*sizeSolution+offset+i] = spr.Constraints[i].O.WireID() + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { + lro[offset+j] = int(c.XA) + lro[sizeSolution+offset+j] = int(c.XB) + lro[2*sizeSolution+offset+j] = int(c.XC) + + j++ } // init cycle: diff --git a/backend/plonk/bw6-633/prove.go b/backend/plonk/bw6-633/prove.go index 031284a8ce..8aaebb5ca5 100644 --- a/backend/plonk/bw6-633/prove.go +++ b/backend/plonk/bw6-633/prove.go @@ -66,7 +66,7 @@ type Proof struct { func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { - log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", len(spr.Constraints)).Str("backend", "plonk").Logger() + log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", spr.GetNbConstraints()).Str("backend", "plonk").Logger() opt, err := backend.NewProverConfig(opts...) if err != nil { @@ -101,7 +101,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } - if _, err = pi2[offset+len(spr.Constraints)-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding + if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding return err } pi2iop := iop.NewPolynomial(&pi2, lagReg) diff --git a/backend/plonk/bw6-633/setup.go b/backend/plonk/bw6-633/setup.go index 4ec615fdb4..6a2bbd5c89 100644 --- a/backend/plonk/bw6-633/setup.go +++ b/backend/plonk/bw6-633/setup.go @@ -241,7 +241,7 @@ func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { // Size is the size of the system that is nb_constraints+nb_public_variables func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { - nbConstraints := len(spr.Constraints) + nbConstraints := spr.GetNbConstraints() sizeSystem := uint64(nbConstraints + len(spr.Public)) size := ecc.NextPowerOfTwo(sizeSystem) @@ -260,15 +260,18 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qk[i].SetZero() // → to be completed by the prover } offset := len(spr.Public) - for i := 0; i < nbConstraints; i++ { // constraints - - ql[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) - qr[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) - qm[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). - Mul(&qm[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) - qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) - qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { + ql[offset+j].Set(&spr.Coefficients[c.QL]) + qr[offset+j].Set(&spr.Coefficients[c.QR]) + qm[offset+j].Set(&spr.Coefficients[c.QM]) + qo[offset+j].Set(&spr.Coefficients[c.QO]) + qk[offset+j].Set(&spr.Coefficients[c.QC]) + j++ } + for _, committed := range spr.CommitmentInfo.Committed { qcp[offset+committed].SetOne() } @@ -331,7 +334,7 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { func (pk *ProvingKey) initDomains(spr *cs.SparseR1CS) { - nbConstraints := len(spr.Constraints) + nbConstraints := spr.GetNbConstraints() sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints pk.Domain[0] = *fft.NewDomain(sizeSystem) @@ -377,10 +380,15 @@ func buildPermutation(spr *cs.SparseR1CS, pt *Trace, nbVariables int) { } offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // IDs of LRO associated to constraints - lro[offset+i] = spr.Constraints[i].L.WireID() - lro[sizeSolution+offset+i] = spr.Constraints[i].R.WireID() - lro[2*sizeSolution+offset+i] = spr.Constraints[i].O.WireID() + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { + lro[offset+j] = int(c.XA) + lro[sizeSolution+offset+j] = int(c.XB) + lro[2*sizeSolution+offset+j] = int(c.XC) + + j++ } // init cycle: diff --git a/backend/plonk/bw6-761/prove.go b/backend/plonk/bw6-761/prove.go index 29c32cac7b..e784d5d303 100644 --- a/backend/plonk/bw6-761/prove.go +++ b/backend/plonk/bw6-761/prove.go @@ -66,7 +66,7 @@ type Proof struct { func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { - log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", len(spr.Constraints)).Str("backend", "plonk").Logger() + log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", spr.GetNbConstraints()).Str("backend", "plonk").Logger() opt, err := backend.NewProverConfig(opts...) if err != nil { @@ -101,7 +101,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } - if _, err = pi2[offset+len(spr.Constraints)-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding + if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding return err } pi2iop := iop.NewPolynomial(&pi2, lagReg) diff --git a/backend/plonk/bw6-761/setup.go b/backend/plonk/bw6-761/setup.go index 4ec96d46be..e4a3872616 100644 --- a/backend/plonk/bw6-761/setup.go +++ b/backend/plonk/bw6-761/setup.go @@ -241,7 +241,7 @@ func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { // Size is the size of the system that is nb_constraints+nb_public_variables func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { - nbConstraints := len(spr.Constraints) + nbConstraints := spr.GetNbConstraints() sizeSystem := uint64(nbConstraints + len(spr.Public)) size := ecc.NextPowerOfTwo(sizeSystem) @@ -260,15 +260,18 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qk[i].SetZero() // → to be completed by the prover } offset := len(spr.Public) - for i := 0; i < nbConstraints; i++ { // constraints - - ql[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) - qr[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) - qm[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). - Mul(&qm[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) - qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) - qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { + ql[offset+j].Set(&spr.Coefficients[c.QL]) + qr[offset+j].Set(&spr.Coefficients[c.QR]) + qm[offset+j].Set(&spr.Coefficients[c.QM]) + qo[offset+j].Set(&spr.Coefficients[c.QO]) + qk[offset+j].Set(&spr.Coefficients[c.QC]) + j++ } + for _, committed := range spr.CommitmentInfo.Committed { qcp[offset+committed].SetOne() } @@ -331,7 +334,7 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { func (pk *ProvingKey) initDomains(spr *cs.SparseR1CS) { - nbConstraints := len(spr.Constraints) + nbConstraints := spr.GetNbConstraints() sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints pk.Domain[0] = *fft.NewDomain(sizeSystem) @@ -377,10 +380,15 @@ func buildPermutation(spr *cs.SparseR1CS, pt *Trace, nbVariables int) { } offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // IDs of LRO associated to constraints - lro[offset+i] = spr.Constraints[i].L.WireID() - lro[sizeSolution+offset+i] = spr.Constraints[i].R.WireID() - lro[2*sizeSolution+offset+i] = spr.Constraints[i].O.WireID() + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { + lro[offset+j] = int(c.XA) + lro[sizeSolution+offset+j] = int(c.XB) + lro[2*sizeSolution+offset+j] = int(c.XC) + + j++ } // init cycle: diff --git a/backend/plonkfri/bls12-377/setup.go b/backend/plonkfri/bls12-377/setup.go index 91e561f8ed..2168bbeeab 100644 --- a/backend/plonkfri/bls12-377/setup.go +++ b/backend/plonkfri/bls12-377/setup.go @@ -106,7 +106,7 @@ func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { // The verifying key shares data with the proving key pk.Vk = &vk - nbConstraints := len(spr.Constraints) + nbConstraints := spr.GetNbConstraints() // fft domains sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints @@ -156,15 +156,18 @@ func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { pk.CQkIncomplete[i].Set(&pk.LQkIncompleteDomainSmall[i]) // --> to be completed by the prover } offset := len(spr.Public) - for i := 0; i < nbConstraints; i++ { // constraints - - pk.EvaluationQlDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) - pk.EvaluationQrDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) - pk.EvaluationQmDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). - Mul(&pk.EvaluationQmDomainBigBitReversed[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) - pk.EvaluationQoDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) - pk.LQkIncompleteDomainSmall[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) - pk.CQkIncomplete[offset+i].Set(&pk.LQkIncompleteDomainSmall[offset+i]) + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { + pk.EvaluationQlDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QL]) + pk.EvaluationQrDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QR]) + pk.EvaluationQmDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QM]) + pk.EvaluationQoDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QO]) + pk.LQkIncompleteDomainSmall[offset+j].Set(&spr.Coefficients[c.QC]) + pk.CQkIncomplete[offset+j].Set(&pk.LQkIncompleteDomainSmall[offset+j]) + + j++ } pk.Domain[0].FFTInverse(pk.EvaluationQlDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) @@ -257,10 +260,14 @@ func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { } offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // IDs of LRO associated to constraints - lro[offset+i] = spr.Constraints[i].L.WireID() - lro[sizeSolution+offset+i] = spr.Constraints[i].R.WireID() - lro[2*sizeSolution+offset+i] = spr.Constraints[i].O.WireID() + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { + lro[offset+j] = int(c.XA) + lro[sizeSolution+offset+j] = int(c.XB) + lro[2*sizeSolution+offset+j] = int(c.XC) + j++ } // init cycle: diff --git a/backend/plonkfri/bls12-381/setup.go b/backend/plonkfri/bls12-381/setup.go index 7be1c02042..4f2b6e1b20 100644 --- a/backend/plonkfri/bls12-381/setup.go +++ b/backend/plonkfri/bls12-381/setup.go @@ -106,7 +106,7 @@ func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { // The verifying key shares data with the proving key pk.Vk = &vk - nbConstraints := len(spr.Constraints) + nbConstraints := spr.GetNbConstraints() // fft domains sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints @@ -156,15 +156,18 @@ func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { pk.CQkIncomplete[i].Set(&pk.LQkIncompleteDomainSmall[i]) // --> to be completed by the prover } offset := len(spr.Public) - for i := 0; i < nbConstraints; i++ { // constraints - - pk.EvaluationQlDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) - pk.EvaluationQrDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) - pk.EvaluationQmDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). - Mul(&pk.EvaluationQmDomainBigBitReversed[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) - pk.EvaluationQoDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) - pk.LQkIncompleteDomainSmall[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) - pk.CQkIncomplete[offset+i].Set(&pk.LQkIncompleteDomainSmall[offset+i]) + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { + pk.EvaluationQlDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QL]) + pk.EvaluationQrDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QR]) + pk.EvaluationQmDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QM]) + pk.EvaluationQoDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QO]) + pk.LQkIncompleteDomainSmall[offset+j].Set(&spr.Coefficients[c.QC]) + pk.CQkIncomplete[offset+j].Set(&pk.LQkIncompleteDomainSmall[offset+j]) + + j++ } pk.Domain[0].FFTInverse(pk.EvaluationQlDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) @@ -257,10 +260,14 @@ func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { } offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // IDs of LRO associated to constraints - lro[offset+i] = spr.Constraints[i].L.WireID() - lro[sizeSolution+offset+i] = spr.Constraints[i].R.WireID() - lro[2*sizeSolution+offset+i] = spr.Constraints[i].O.WireID() + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { + lro[offset+j] = int(c.XA) + lro[sizeSolution+offset+j] = int(c.XB) + lro[2*sizeSolution+offset+j] = int(c.XC) + j++ } // init cycle: diff --git a/backend/plonkfri/bls24-315/setup.go b/backend/plonkfri/bls24-315/setup.go index 32315bb39f..9063dc95d9 100644 --- a/backend/plonkfri/bls24-315/setup.go +++ b/backend/plonkfri/bls24-315/setup.go @@ -106,7 +106,7 @@ func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { // The verifying key shares data with the proving key pk.Vk = &vk - nbConstraints := len(spr.Constraints) + nbConstraints := spr.GetNbConstraints() // fft domains sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints @@ -156,15 +156,18 @@ func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { pk.CQkIncomplete[i].Set(&pk.LQkIncompleteDomainSmall[i]) // --> to be completed by the prover } offset := len(spr.Public) - for i := 0; i < nbConstraints; i++ { // constraints - - pk.EvaluationQlDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) - pk.EvaluationQrDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) - pk.EvaluationQmDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). - Mul(&pk.EvaluationQmDomainBigBitReversed[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) - pk.EvaluationQoDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) - pk.LQkIncompleteDomainSmall[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) - pk.CQkIncomplete[offset+i].Set(&pk.LQkIncompleteDomainSmall[offset+i]) + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { + pk.EvaluationQlDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QL]) + pk.EvaluationQrDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QR]) + pk.EvaluationQmDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QM]) + pk.EvaluationQoDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QO]) + pk.LQkIncompleteDomainSmall[offset+j].Set(&spr.Coefficients[c.QC]) + pk.CQkIncomplete[offset+j].Set(&pk.LQkIncompleteDomainSmall[offset+j]) + + j++ } pk.Domain[0].FFTInverse(pk.EvaluationQlDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) @@ -257,10 +260,14 @@ func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { } offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // IDs of LRO associated to constraints - lro[offset+i] = spr.Constraints[i].L.WireID() - lro[sizeSolution+offset+i] = spr.Constraints[i].R.WireID() - lro[2*sizeSolution+offset+i] = spr.Constraints[i].O.WireID() + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { + lro[offset+j] = int(c.XA) + lro[sizeSolution+offset+j] = int(c.XB) + lro[2*sizeSolution+offset+j] = int(c.XC) + j++ } // init cycle: diff --git a/backend/plonkfri/bls24-317/setup.go b/backend/plonkfri/bls24-317/setup.go index 266a8d0107..c2ab7ee5be 100644 --- a/backend/plonkfri/bls24-317/setup.go +++ b/backend/plonkfri/bls24-317/setup.go @@ -106,7 +106,7 @@ func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { // The verifying key shares data with the proving key pk.Vk = &vk - nbConstraints := len(spr.Constraints) + nbConstraints := spr.GetNbConstraints() // fft domains sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints @@ -156,15 +156,18 @@ func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { pk.CQkIncomplete[i].Set(&pk.LQkIncompleteDomainSmall[i]) // --> to be completed by the prover } offset := len(spr.Public) - for i := 0; i < nbConstraints; i++ { // constraints - - pk.EvaluationQlDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) - pk.EvaluationQrDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) - pk.EvaluationQmDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). - Mul(&pk.EvaluationQmDomainBigBitReversed[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) - pk.EvaluationQoDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) - pk.LQkIncompleteDomainSmall[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) - pk.CQkIncomplete[offset+i].Set(&pk.LQkIncompleteDomainSmall[offset+i]) + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { + pk.EvaluationQlDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QL]) + pk.EvaluationQrDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QR]) + pk.EvaluationQmDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QM]) + pk.EvaluationQoDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QO]) + pk.LQkIncompleteDomainSmall[offset+j].Set(&spr.Coefficients[c.QC]) + pk.CQkIncomplete[offset+j].Set(&pk.LQkIncompleteDomainSmall[offset+j]) + + j++ } pk.Domain[0].FFTInverse(pk.EvaluationQlDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) @@ -257,10 +260,14 @@ func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { } offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // IDs of LRO associated to constraints - lro[offset+i] = spr.Constraints[i].L.WireID() - lro[sizeSolution+offset+i] = spr.Constraints[i].R.WireID() - lro[2*sizeSolution+offset+i] = spr.Constraints[i].O.WireID() + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { + lro[offset+j] = int(c.XA) + lro[sizeSolution+offset+j] = int(c.XB) + lro[2*sizeSolution+offset+j] = int(c.XC) + j++ } // init cycle: diff --git a/backend/plonkfri/bn254/setup.go b/backend/plonkfri/bn254/setup.go index a2e5b2023d..6b37f37600 100644 --- a/backend/plonkfri/bn254/setup.go +++ b/backend/plonkfri/bn254/setup.go @@ -106,7 +106,7 @@ func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { // The verifying key shares data with the proving key pk.Vk = &vk - nbConstraints := len(spr.Constraints) + nbConstraints := spr.GetNbConstraints() // fft domains sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints @@ -156,15 +156,18 @@ func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { pk.CQkIncomplete[i].Set(&pk.LQkIncompleteDomainSmall[i]) // --> to be completed by the prover } offset := len(spr.Public) - for i := 0; i < nbConstraints; i++ { // constraints - - pk.EvaluationQlDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) - pk.EvaluationQrDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) - pk.EvaluationQmDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). - Mul(&pk.EvaluationQmDomainBigBitReversed[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) - pk.EvaluationQoDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) - pk.LQkIncompleteDomainSmall[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) - pk.CQkIncomplete[offset+i].Set(&pk.LQkIncompleteDomainSmall[offset+i]) + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { + pk.EvaluationQlDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QL]) + pk.EvaluationQrDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QR]) + pk.EvaluationQmDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QM]) + pk.EvaluationQoDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QO]) + pk.LQkIncompleteDomainSmall[offset+j].Set(&spr.Coefficients[c.QC]) + pk.CQkIncomplete[offset+j].Set(&pk.LQkIncompleteDomainSmall[offset+j]) + + j++ } pk.Domain[0].FFTInverse(pk.EvaluationQlDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) @@ -257,10 +260,14 @@ func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { } offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // IDs of LRO associated to constraints - lro[offset+i] = spr.Constraints[i].L.WireID() - lro[sizeSolution+offset+i] = spr.Constraints[i].R.WireID() - lro[2*sizeSolution+offset+i] = spr.Constraints[i].O.WireID() + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { + lro[offset+j] = int(c.XA) + lro[sizeSolution+offset+j] = int(c.XB) + lro[2*sizeSolution+offset+j] = int(c.XC) + j++ } // init cycle: diff --git a/backend/plonkfri/bw6-633/setup.go b/backend/plonkfri/bw6-633/setup.go index afad348574..dff84dbee9 100644 --- a/backend/plonkfri/bw6-633/setup.go +++ b/backend/plonkfri/bw6-633/setup.go @@ -106,7 +106,7 @@ func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { // The verifying key shares data with the proving key pk.Vk = &vk - nbConstraints := len(spr.Constraints) + nbConstraints := spr.GetNbConstraints() // fft domains sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints @@ -156,15 +156,18 @@ func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { pk.CQkIncomplete[i].Set(&pk.LQkIncompleteDomainSmall[i]) // --> to be completed by the prover } offset := len(spr.Public) - for i := 0; i < nbConstraints; i++ { // constraints - - pk.EvaluationQlDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) - pk.EvaluationQrDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) - pk.EvaluationQmDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). - Mul(&pk.EvaluationQmDomainBigBitReversed[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) - pk.EvaluationQoDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) - pk.LQkIncompleteDomainSmall[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) - pk.CQkIncomplete[offset+i].Set(&pk.LQkIncompleteDomainSmall[offset+i]) + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { + pk.EvaluationQlDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QL]) + pk.EvaluationQrDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QR]) + pk.EvaluationQmDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QM]) + pk.EvaluationQoDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QO]) + pk.LQkIncompleteDomainSmall[offset+j].Set(&spr.Coefficients[c.QC]) + pk.CQkIncomplete[offset+j].Set(&pk.LQkIncompleteDomainSmall[offset+j]) + + j++ } pk.Domain[0].FFTInverse(pk.EvaluationQlDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) @@ -257,10 +260,14 @@ func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { } offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // IDs of LRO associated to constraints - lro[offset+i] = spr.Constraints[i].L.WireID() - lro[sizeSolution+offset+i] = spr.Constraints[i].R.WireID() - lro[2*sizeSolution+offset+i] = spr.Constraints[i].O.WireID() + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { + lro[offset+j] = int(c.XA) + lro[sizeSolution+offset+j] = int(c.XB) + lro[2*sizeSolution+offset+j] = int(c.XC) + j++ } // init cycle: diff --git a/backend/plonkfri/bw6-761/setup.go b/backend/plonkfri/bw6-761/setup.go index 3570409af5..ee278a5eda 100644 --- a/backend/plonkfri/bw6-761/setup.go +++ b/backend/plonkfri/bw6-761/setup.go @@ -106,7 +106,7 @@ func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { // The verifying key shares data with the proving key pk.Vk = &vk - nbConstraints := len(spr.Constraints) + nbConstraints := spr.GetNbConstraints() // fft domains sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints @@ -156,15 +156,18 @@ func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { pk.CQkIncomplete[i].Set(&pk.LQkIncompleteDomainSmall[i]) // --> to be completed by the prover } offset := len(spr.Public) - for i := 0; i < nbConstraints; i++ { // constraints - - pk.EvaluationQlDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) - pk.EvaluationQrDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) - pk.EvaluationQmDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). - Mul(&pk.EvaluationQmDomainBigBitReversed[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) - pk.EvaluationQoDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) - pk.LQkIncompleteDomainSmall[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) - pk.CQkIncomplete[offset+i].Set(&pk.LQkIncompleteDomainSmall[offset+i]) + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { + pk.EvaluationQlDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QL]) + pk.EvaluationQrDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QR]) + pk.EvaluationQmDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QM]) + pk.EvaluationQoDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QO]) + pk.LQkIncompleteDomainSmall[offset+j].Set(&spr.Coefficients[c.QC]) + pk.CQkIncomplete[offset+j].Set(&pk.LQkIncompleteDomainSmall[offset+j]) + + j++ } pk.Domain[0].FFTInverse(pk.EvaluationQlDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) @@ -257,10 +260,14 @@ func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { } offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // IDs of LRO associated to constraints - lro[offset+i] = spr.Constraints[i].L.WireID() - lro[sizeSolution+offset+i] = spr.Constraints[i].R.WireID() - lro[2*sizeSolution+offset+i] = spr.Constraints[i].O.WireID() + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c != nil; c = it.Next() { + lro[offset+j] = int(c.XA) + lro[sizeSolution+offset+j] = int(c.XB) + lro[2*sizeSolution+offset+j] = int(c.XC) + j++ } // init cycle: diff --git a/constraint/bls12-377/coeff.go b/constraint/bls12-377/coeff.go index cc8036f26f..5b4034aaab 100644 --- a/constraint/bls12-377/coeff.go +++ b/constraint/bls12-377/coeff.go @@ -46,7 +46,7 @@ func newCoeffTable(capacity int) CoeffTable { } -func (ct *CoeffTable) MakeTerm(coeff *constraint.Coeff, variableID int) constraint.Term { +func (ct *CoeffTable) AddCoeff(coeff constraint.Element) uint32 { c := (*fr.Element)(coeff[:]) var cID uint32 if c.IsZero() { @@ -69,7 +69,11 @@ func (ct *CoeffTable) MakeTerm(coeff *constraint.Coeff, variableID int) constrai ct.mCoeffs[cc] = cID } } + return cID +} +func (ct *CoeffTable) MakeTerm(coeff *constraint.Element, variableID int) constraint.Term { + cID := ct.AddCoeff(*coeff) return constraint.Term{VID: uint32(variableID), CID: cID} } @@ -78,7 +82,10 @@ func (ct *CoeffTable) CoeffToString(cID int) string { return ct.Coefficients[cID].String() } -var _ constraint.CoeffEngine = &arithEngine{} +// implements constraint.Field +type field struct{} + +var _ constraint.Field = &field{} var ( two fr.Element @@ -94,10 +101,7 @@ func init() { minusTwo.Neg(&two) } -// implements constraint.CoeffEngine -type arithEngine struct{} - -func (engine *arithEngine) FromInterface(i interface{}) constraint.Coeff { +func (engine *field) FromInterface(i interface{}) constraint.Element { var e fr.Element if _, err := e.SetInterface(i); err != nil { // need to clean that --> some code path are dissimilar @@ -106,55 +110,75 @@ func (engine *arithEngine) FromInterface(i interface{}) constraint.Coeff { b := utils.FromInterface(i) e.SetBigInt(&b) } - var r constraint.Coeff + var r constraint.Element copy(r[:], e[:]) return r } -func (engine *arithEngine) ToBigInt(c *constraint.Coeff) *big.Int { +func (engine *field) ToBigInt(c constraint.Element) *big.Int { e := (*fr.Element)(c[:]) r := new(big.Int) e.BigInt(r) return r } -func (engine *arithEngine) Mul(a, b *constraint.Coeff) { +func (engine *field) Mul(a, b constraint.Element) constraint.Element { _a := (*fr.Element)(a[:]) _b := (*fr.Element)(b[:]) _a.Mul(_a, _b) + return a } -func (engine *arithEngine) Add(a, b *constraint.Coeff) { + +func (engine *field) Add(a, b constraint.Element) constraint.Element { _a := (*fr.Element)(a[:]) _b := (*fr.Element)(b[:]) _a.Add(_a, _b) + return a } -func (engine *arithEngine) Sub(a, b *constraint.Coeff) { +func (engine *field) Sub(a, b constraint.Element) constraint.Element { _a := (*fr.Element)(a[:]) _b := (*fr.Element)(b[:]) _a.Sub(_a, _b) + return a } -func (engine *arithEngine) Neg(a *constraint.Coeff) { +func (engine *field) Neg(a constraint.Element) constraint.Element { e := (*fr.Element)(a[:]) e.Neg(e) + return a } -func (engine *arithEngine) Inverse(a *constraint.Coeff) { +func (engine *field) Inverse(a constraint.Element) (constraint.Element, bool) { + if a.IsZero() { + return a, false + } e := (*fr.Element)(a[:]) + if e.IsZero() { + return a, false + } else if e.IsOne() { + return a, true + } + var t fr.Element + t.Neg(e) + if t.IsOne() { + return a, true + } + e.Inverse(e) + return a, true } -func (engine *arithEngine) IsOne(a *constraint.Coeff) bool { +func (engine *field) IsOne(a constraint.Element) bool { e := (*fr.Element)(a[:]) return e.IsOne() } -func (engine *arithEngine) One() constraint.Coeff { +func (engine *field) One() constraint.Element { e := fr.One() - var r constraint.Coeff + var r constraint.Element copy(r[:], e[:]) return r } -func (engine *arithEngine) String(a *constraint.Coeff) string { +func (engine *field) String(a constraint.Element) string { e := (*fr.Element)(a[:]) return e.String() } diff --git a/constraint/bls12-377/r1cs.go b/constraint/bls12-377/r1cs.go deleted file mode 100644 index dc3797887c..0000000000 --- a/constraint/bls12-377/r1cs.go +++ /dev/null @@ -1,467 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// 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. - -// Code generated by gnark DO NOT EDIT - -package cs - -import ( - "errors" - "fmt" - "github.com/fxamacker/cbor/v2" - "io" - "runtime" - "sync" - "time" - - "github.com/consensys/gnark/backend/witness" - "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/internal/backend/ioutils" - "github.com/consensys/gnark/logger" - "github.com/consensys/gnark/profile" - - "github.com/consensys/gnark-crypto/ecc" - "math" - - "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" -) - -// R1CS describes a set of R1CS constraint -type R1CS struct { - constraint.R1CSCore - CoeffTable - arithEngine -} - -// NewR1CS returns a new R1CS and sets cs.Coefficient (fr.Element) from provided big.Int values -// -// capacity pre-allocates memory for capacity nbConstraints -func NewR1CS(capacity int) *R1CS { - r := R1CS{ - R1CSCore: constraint.R1CSCore{ - System: constraint.NewSystem(fr.Modulus()), - Constraints: make([]constraint.R1C, 0, capacity), - }, - CoeffTable: newCoeffTable(capacity / 10), - } - return &r -} - -func (cs *R1CS) AddConstraint(r1c constraint.R1C, debugInfo ...constraint.DebugInfo) int { - profile.RecordConstraint() - cs.Constraints = append(cs.Constraints, r1c) - cID := len(cs.Constraints) - 1 - if len(debugInfo) == 1 { - cs.DebugInfo = append(cs.DebugInfo, constraint.LogEntry(debugInfo[0])) - cs.MDebug[cID] = len(cs.DebugInfo) - 1 - } - - cs.UpdateLevel(cID, &r1c) - - return cID -} - -// Solve returns the vector w solution to the system, that is -// Aw o Bw - Cw = 0 -func (cs *R1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { - opt, err := solver.NewConfig(opts...) - if err != nil { - return nil, err - } - - var res R1CSSolution - - s := ecc.NextPowerOfTwo(uint64(len(cs.Constraints))) - res.A = make(fr.Vector, len(cs.Constraints), s) - res.B = make(fr.Vector, len(cs.Constraints), s) - res.C = make(fr.Vector, len(cs.Constraints), s) - - v := witness.Vector().(fr.Vector) - - res.W, err = cs.solve(v, res.A, res.B, res.C, opt) - if err != nil { - return nil, err - } - - return &res, nil -} - -// Solve sets all the wires and returns the a, b, c vectors. -// the cs system should have been compiled before. The entries in a, b, c are in Montgomery form. -// a, b, c vectors: ab-c = hz -// witness = [publicWires | secretWires] (without the ONE_WIRE !) -// returns [publicWires | secretWires | internalWires ] -func (cs *R1CS) solve(witness, a, b, c fr.Vector, opt solver.Config) (fr.Vector, error) { - log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() - - nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - solution, err := newSolution(&cs.System, nbWires, opt.HintFunctions, cs.Coefficients) - if err != nil { - return make(fr.Vector, nbWires), err - } - start := time.Now() - - if len(witness) != len(cs.Public)-1+len(cs.Secret) { // - 1 for ONE_WIRE - err = fmt.Errorf("invalid witness size, got %d, expected %d = %d (public) + %d (secret)", len(witness), int(len(cs.Public)-1+len(cs.Secret)), len(cs.Public)-1, len(cs.Secret)) - log.Err(err).Send() - return solution.values, err - } - - // compute the wires and the a, b, c polynomials - if len(a) != len(cs.Constraints) || len(b) != len(cs.Constraints) || len(c) != len(cs.Constraints) { - err = errors.New("invalid input size: len(a, b, c) == len(Constraints)") - log.Err(err).Send() - return solution.values, err - } - - solution.solved[0] = true // ONE_WIRE - solution.values[0].SetOne() - copy(solution.values[1:], witness) - for i := range witness { - solution.solved[i+1] = true - } - - // keep track of the number of wire instantiations we do, for a sanity check to ensure - // we instantiated all wires - solution.nbSolved += uint64(len(witness) + 1) - - // now that we know all inputs are set, defer log printing once all solution.values are computed - // (or sooner, if a constraint is not satisfied) - defer solution.printLogs(opt.Logger, cs.Logs) - - if err := cs.parallelSolve(a, b, c, &solution); err != nil { - if unsatisfiedErr, ok := err.(*UnsatisfiedConstraintError); ok { - log.Err(errors.New("unsatisfied constraint")).Int("id", unsatisfiedErr.CID).Send() - } else { - log.Err(err).Send() - } - return solution.values, err - } - - // sanity check; ensure all wires are marked as "instantiated" - if !solution.isValid() { - log.Err(errors.New("solver didn't instantiate all wires")).Send() - panic("solver didn't instantiate all wires") - } - - log.Debug().Dur("took", time.Since(start)).Msg("constraint system solver done") - - return solution.values, nil -} - -func (cs *R1CS) parallelSolve(a, b, c fr.Vector, solution *solution) error { - // minWorkPerCPU is the minimum target number of constraint a task should hold - // in other words, if a level has less than minWorkPerCPU, it will not be parallelized and executed - // sequentially without sync. - const minWorkPerCPU = 50.0 - - // cs.Levels has a list of levels, where all constraints in a level l(n) are independent - // and may only have dependencies on previous levels - // for each constraint - // we are guaranteed that each R1C contains at most one unsolved wire - // first we solve the unsolved wire (if any) - // then we check that the constraint is valid - // if a[i] * b[i] != c[i]; it means the constraint is not satisfied - - var wg sync.WaitGroup - chTasks := make(chan []int, runtime.NumCPU()) - chError := make(chan *UnsatisfiedConstraintError, runtime.NumCPU()) - - // start a worker pool - // each worker wait on chTasks - // a task is a slice of constraint indexes to be solved - for i := 0; i < runtime.NumCPU(); i++ { - go func() { - for t := range chTasks { - for _, i := range t { - // for each constraint in the task, solve it. - if err := cs.solveConstraint(cs.Constraints[i], solution, &a[i], &b[i], &c[i]); err != nil { - var debugInfo *string - if dID, ok := cs.MDebug[i]; ok { - debugInfo = new(string) - *debugInfo = solution.logValue(cs.DebugInfo[dID]) - } - chError <- &UnsatisfiedConstraintError{CID: i, Err: err, DebugInfo: debugInfo} - wg.Done() - return - } - } - wg.Done() - } - }() - } - - // clean up pool go routines - defer func() { - close(chTasks) - close(chError) - }() - - // for each level, we push the tasks - for _, level := range cs.Levels { - - // max CPU to use - maxCPU := float64(len(level)) / minWorkPerCPU - - if maxCPU <= 1.0 { - // we do it sequentially - for _, i := range level { - if err := cs.solveConstraint(cs.Constraints[i], solution, &a[i], &b[i], &c[i]); err != nil { - var debugInfo *string - if dID, ok := cs.MDebug[i]; ok { - debugInfo = new(string) - *debugInfo = solution.logValue(cs.DebugInfo[dID]) - } - return &UnsatisfiedConstraintError{CID: i, Err: err, DebugInfo: debugInfo} - } - } - continue - } - - // number of tasks for this level is set to number of CPU - // but if we don't have enough work for all our CPU, it can be lower. - nbTasks := runtime.NumCPU() - maxTasks := int(math.Ceil(maxCPU)) - if nbTasks > maxTasks { - nbTasks = maxTasks - } - nbIterationsPerCpus := len(level) / nbTasks - - // more CPUs than tasks: a CPU will work on exactly one iteration - // note: this depends on minWorkPerCPU constant - if nbIterationsPerCpus < 1 { - nbIterationsPerCpus = 1 - nbTasks = len(level) - } - - extraTasks := len(level) - (nbTasks * nbIterationsPerCpus) - extraTasksOffset := 0 - - for i := 0; i < nbTasks; i++ { - wg.Add(1) - _start := i*nbIterationsPerCpus + extraTasksOffset - _end := _start + nbIterationsPerCpus - if extraTasks > 0 { - _end++ - extraTasks-- - extraTasksOffset++ - } - // since we're never pushing more than num CPU tasks - // we will never be blocked here - chTasks <- level[_start:_end] - } - - // wait for the level to be done - wg.Wait() - - if len(chError) > 0 { - return <-chError - } - } - - return nil -} - -// IsSolved -// Deprecated: use _, err := Solve(...) instead -func (cs *R1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { - _, err := cs.Solve(witness, opts...) - return err -} - -// divByCoeff sets res = res / t.Coeff -func (cs *R1CS) divByCoeff(res *fr.Element, t constraint.Term) { - cID := t.CoeffID() - switch cID { - case constraint.CoeffIdOne: - return - case constraint.CoeffIdMinusOne: - res.Neg(res) - case constraint.CoeffIdZero: - panic("division by 0") - default: - // this is slow, but shouldn't happen as divByCoeff is called to - // remove the coeff of an unsolved wire - // but unsolved wires are (in gnark frontend) systematically set with a coeff == 1 or -1 - res.Div(res, &cs.Coefficients[cID]) - } -} - -// solveConstraint compute unsolved wires in the constraint, if any and set the solution accordingly -// -// returns an error if the solver called a hint function that errored -// returns false, nil if there was no wire to solve -// returns true, nil if exactly one wire was solved. In that case, it is redundant to check that -// the constraint is satisfied later. -func (cs *R1CS) solveConstraint(r constraint.R1C, solution *solution, a, b, c *fr.Element) error { - - // the index of the non-zero entry shows if L, R or O has an uninstantiated wire - // the content is the ID of the wire non instantiated - var loc uint8 - - var termToCompute constraint.Term - - processLExp := func(l constraint.LinearExpression, val *fr.Element, locValue uint8) error { - for _, t := range l { - vID := t.WireID() - - // wire is already computed, we just accumulate in val - if solution.solved[vID] { - solution.accumulateInto(t, val) - continue - } - - // first we check if this is a hint wire - if hint, ok := cs.MHints[vID]; ok { - if err := solution.solveWithHint(vID, hint); err != nil { - return err - } - // now that the wire is saved, accumulate it into a, b or c - solution.accumulateInto(t, val) - continue - } - - if loc != 0 { - panic("found more than one wire to instantiate") - } - termToCompute = t - loc = locValue - } - return nil - } - - if err := processLExp(r.L, a, 1); err != nil { - return err - } - - if err := processLExp(r.R, b, 2); err != nil { - return err - } - - if err := processLExp(r.O, c, 3); err != nil { - return err - } - - if loc == 0 { - // there is nothing to solve, may happen if we have an assertion - // (ie a constraints that doesn't yield any output) - // or if we solved the unsolved wires with hint functions - var check fr.Element - if !check.Mul(a, b).Equal(c) { - return fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String()) - } - return nil - } - - // we compute the wire value and instantiate it - wID := termToCompute.WireID() - - // solver result - var wire fr.Element - - switch loc { - case 1: - if !b.IsZero() { - wire.Div(c, b). - Sub(&wire, a) - a.Add(a, &wire) - } else { - // we didn't actually ensure that a * b == c - var check fr.Element - if !check.Mul(a, b).Equal(c) { - return fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String()) - } - } - case 2: - if !a.IsZero() { - wire.Div(c, a). - Sub(&wire, b) - b.Add(b, &wire) - } else { - var check fr.Element - if !check.Mul(a, b).Equal(c) { - return fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String()) - } - } - case 3: - wire.Mul(a, b). - Sub(&wire, c) - - c.Add(c, &wire) - } - - // wire is the term (coeff * value) - // but in the solution we want to store the value only - // note that in gnark frontend, coeff here is always 1 or -1 - cs.divByCoeff(&wire, termToCompute) - solution.set(wID, wire) - - return nil -} - -// GetConstraints return the list of R1C and a coefficient resolver -func (cs *R1CS) GetConstraints() ([]constraint.R1C, constraint.Resolver) { - return cs.Constraints, cs -} - -// GetNbCoefficients return the number of unique coefficients needed in the R1CS -func (cs *R1CS) GetNbCoefficients() int { - return len(cs.Coefficients) -} - -// CurveID returns curve ID as defined in gnark-crypto -func (cs *R1CS) CurveID() ecc.ID { - return ecc.BLS12_377 -} - -// WriteTo encodes R1CS into provided io.Writer using cbor -func (cs *R1CS) WriteTo(w io.Writer) (int64, error) { - _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written - enc, err := cbor.CoreDetEncOptions().EncMode() - if err != nil { - return 0, err - } - encoder := enc.NewEncoder(&_w) - - // encode our object - err = encoder.Encode(cs) - return _w.N, err -} - -// ReadFrom attempts to decode R1CS from io.Reader using cbor -func (cs *R1CS) ReadFrom(r io.Reader) (int64, error) { - dm, err := cbor.DecOptions{ - MaxArrayElements: 134217728, - MaxMapPairs: 134217728, - }.DecMode() - - if err != nil { - return 0, err - } - decoder := dm.NewDecoder(r) - - // initialize coeff table - cs.CoeffTable = newCoeffTable(0) - - if err := decoder.Decode(&cs); err != nil { - return int64(decoder.NumBytesRead()), err - } - - if err := cs.CheckSerializationHeader(); err != nil { - return int64(decoder.NumBytesRead()), err - } - - return int64(decoder.NumBytesRead()), nil -} diff --git a/constraint/bls12-377/r1cs_sparse.go b/constraint/bls12-377/r1cs_sparse.go deleted file mode 100644 index a63f2f86ed..0000000000 --- a/constraint/bls12-377/r1cs_sparse.go +++ /dev/null @@ -1,533 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// 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. - -// Code generated by gnark DO NOT EDIT - -package cs - -import ( - "errors" - "fmt" - "github.com/consensys/gnark-crypto/ecc" - "github.com/fxamacker/cbor/v2" - "io" - "math" - "runtime" - "sync" - "time" - - "github.com/consensys/gnark/backend/witness" - "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/internal/backend/ioutils" - "github.com/consensys/gnark/logger" - "github.com/consensys/gnark/profile" - - "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" -) - -// SparseR1CS represents a Plonk like circuit -type SparseR1CS struct { - constraint.SparseR1CSCore - CoeffTable - arithEngine -} - -// NewSparseR1CS returns a new SparseR1CS and sets r1cs.Coefficient (fr.Element) from provided big.Int values -func NewSparseR1CS(capacity int) *SparseR1CS { - cs := SparseR1CS{ - SparseR1CSCore: constraint.SparseR1CSCore{ - System: constraint.NewSystem(fr.Modulus()), - Constraints: make([]constraint.SparseR1C, 0, capacity), - }, - CoeffTable: newCoeffTable(capacity / 10), - } - - return &cs -} - -func (cs *SparseR1CS) AddConstraint(c constraint.SparseR1C, debugInfo ...constraint.DebugInfo) int { - profile.RecordConstraint() - cs.Constraints = append(cs.Constraints, c) - cID := len(cs.Constraints) - 1 - if len(debugInfo) == 1 { - cs.DebugInfo = append(cs.DebugInfo, constraint.LogEntry(debugInfo[0])) - cs.MDebug[cID] = len(cs.DebugInfo) - 1 - } - cs.UpdateLevel(cID, &c) - - return cID -} - -func (c *SparseR1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { - opt, err := solver.NewConfig(opts...) - if err != nil { - return nil, err - } - - // compute the constraint system solution - var solution []fr.Element - if solution, err = c.solve(witness.Vector().(fr.Vector), opt); err != nil { - return nil, err - } - - var res SparseR1CSSolution - // query l, r, o in Lagrange basis, not blinded - res.L, res.R, res.O = c.evaluateLROSmallDomain(solution) - - return &res, nil -} - -// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. -// solution = [ public | secret | internal ] -func (c *SparseR1CS) evaluateLROSmallDomain(solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { - - //s := int(pk.Domain[0].Cardinality) - s := c.GetNbConstraints() + len(c.Public) // len(spr.Public) is for the placeholder constraints - s = int(ecc.NextPowerOfTwo(uint64(s))) - - var l, r, o []fr.Element - l = make([]fr.Element, s) - r = make([]fr.Element, s) - o = make([]fr.Element, s) - s0 := solution[0] - - for i := 0; i < len(c.Public); i++ { // placeholders - l[i] = solution[i] - r[i] = s0 - o[i] = s0 - } - offset := len(c.Public) - for i := 0; i < len(c.Constraints); i++ { // constraints - l[offset+i] = solution[c.Constraints[i].L.WireID()] - r[offset+i] = solution[c.Constraints[i].R.WireID()] - o[offset+i] = solution[c.Constraints[i].O.WireID()] - } - offset += len(c.Constraints) - - for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) - l[offset+i] = s0 - r[offset+i] = s0 - o[offset+i] = s0 - } - - return l, r, o - -} - -// Solve sets all the wires. -// solution.values = [publicInputs | secretInputs | internalVariables ] -// witness: contains the input variables -// it returns the full slice of wires -func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, error) { - log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "plonk").Logger() - - // set the slices holding the solution.values and monitoring which variables have been solved - nbVariables := cs.NbInternalVariables + len(cs.Secret) + len(cs.Public) - - start := time.Now() - - expectedWitnessSize := len(cs.Public) + len(cs.Secret) - if len(witness) != expectedWitnessSize { - return make(fr.Vector, nbVariables), fmt.Errorf( - "invalid witness size, got %d, expected %d = %d (public) + %d (secret)", - len(witness), - expectedWitnessSize, - len(cs.Public), - len(cs.Secret), - ) - } - - // keep track of wire that have a value - solution, err := newSolution(&cs.System, nbVariables, opt.HintFunctions, cs.Coefficients) - if err != nil { - return solution.values, err - } - - // solution.values = [publicInputs | secretInputs | internalVariables ] -> we fill publicInputs | secretInputs - copy(solution.values, witness) - for i := 0; i < len(witness); i++ { - solution.solved[i] = true - } - - // keep track of the number of wire instantiations we do, for a sanity check to ensure - // we instantiated all wires - solution.nbSolved += uint64(len(witness)) - - // defer log printing once all solution.values are computed - defer solution.printLogs(opt.Logger, cs.Logs) - - // batch invert the coefficients to avoid many divisions in the solver - coefficientsNegInv := fr.BatchInvert(cs.Coefficients) - for i := 0; i < len(coefficientsNegInv); i++ { - coefficientsNegInv[i].Neg(&coefficientsNegInv[i]) - } - - if err := cs.parallelSolve(&solution, coefficientsNegInv); err != nil { - if unsatisfiedErr, ok := err.(*UnsatisfiedConstraintError); ok { - log.Err(errors.New("unsatisfied constraint")).Int("id", unsatisfiedErr.CID).Send() - } else { - log.Err(err).Send() - } - return solution.values, err - } - - // sanity check; ensure all wires are marked as "instantiated" - if !solution.isValid() { - log.Err(errors.New("solver didn't instantiate all wires")).Send() - panic("solver didn't instantiate all wires") - } - - log.Debug().Dur("took", time.Since(start)).Msg("constraint system solver done") - - return solution.values, nil - -} - -func (cs *SparseR1CS) parallelSolve(solution *solution, coefficientsNegInv fr.Vector) error { - // minWorkPerCPU is the minimum target number of constraint a task should hold - // in other words, if a level has less than minWorkPerCPU, it will not be parallelized and executed - // sequentially without sync. - const minWorkPerCPU = 50.0 - - // cs.Levels has a list of levels, where all constraints in a level l(n) are independent - // and may only have dependencies on previous levels - - var wg sync.WaitGroup - chTasks := make(chan []int, runtime.NumCPU()) - chError := make(chan *UnsatisfiedConstraintError, runtime.NumCPU()) - - // start a worker pool - // each worker wait on chTasks - // a task is a slice of constraint indexes to be solved - for i := 0; i < runtime.NumCPU(); i++ { - go func() { - for t := range chTasks { - for _, i := range t { - // for each constraint in the task, solve it. - if err := cs.solveConstraint(cs.Constraints[i], solution, coefficientsNegInv); err != nil { - chError <- &UnsatisfiedConstraintError{CID: i, Err: err} - wg.Done() - return - } - if err := cs.checkConstraint(cs.Constraints[i], solution); err != nil { - if dID, ok := cs.MDebug[i]; ok { - errMsg := solution.logValue(cs.DebugInfo[dID]) - chError <- &UnsatisfiedConstraintError{CID: i, DebugInfo: &errMsg} - } else { - chError <- &UnsatisfiedConstraintError{CID: i, Err: err} - } - wg.Done() - return - } - } - wg.Done() - } - }() - } - - // clean up pool go routines - defer func() { - close(chTasks) - close(chError) - }() - - // for each level, we push the tasks - for _, level := range cs.Levels { - - // max CPU to use - maxCPU := float64(len(level)) / minWorkPerCPU - - if maxCPU <= 1.0 { - // we do it sequentially - for _, i := range level { - if err := cs.solveConstraint(cs.Constraints[i], solution, coefficientsNegInv); err != nil { - return &UnsatisfiedConstraintError{CID: i, Err: err} - } - if err := cs.checkConstraint(cs.Constraints[i], solution); err != nil { - if dID, ok := cs.MDebug[i]; ok { - errMsg := solution.logValue(cs.DebugInfo[dID]) - return &UnsatisfiedConstraintError{CID: i, DebugInfo: &errMsg} - } - return &UnsatisfiedConstraintError{CID: i, Err: err} - } - } - continue - } - - // number of tasks for this level is set to number of CPU - // but if we don't have enough work for all our CPU, it can be lower. - nbTasks := runtime.NumCPU() - maxTasks := int(math.Ceil(maxCPU)) - if nbTasks > maxTasks { - nbTasks = maxTasks - } - nbIterationsPerCpus := len(level) / nbTasks - - // more CPUs than tasks: a CPU will work on exactly one iteration - // note: this depends on minWorkPerCPU constant - if nbIterationsPerCpus < 1 { - nbIterationsPerCpus = 1 - nbTasks = len(level) - } - - extraTasks := len(level) - (nbTasks * nbIterationsPerCpus) - extraTasksOffset := 0 - - for i := 0; i < nbTasks; i++ { - wg.Add(1) - _start := i*nbIterationsPerCpus + extraTasksOffset - _end := _start + nbIterationsPerCpus - if extraTasks > 0 { - _end++ - extraTasks-- - extraTasksOffset++ - } - // since we're never pushing more than num CPU tasks - // we will never be blocked here - chTasks <- level[_start:_end] - } - - // wait for the level to be done - wg.Wait() - - if len(chError) > 0 { - return <-chError - } - } - - return nil -} - -// computeHints computes wires associated with a hint function, if any -// if there is no remaining wire to solve, returns -1 -// else returns the wire position (L -> 0, R -> 1, O -> 2) -func (cs *SparseR1CS) computeHints(c constraint.SparseR1C, solution *solution) (int, error) { - r := -1 - lID, rID, oID := c.L.WireID(), c.R.WireID(), c.O.WireID() - - if (c.L.CoeffID() != 0 || c.M[0].CoeffID() != 0) && !solution.solved[lID] { - // check if it's a hint - if hint, ok := cs.MHints[lID]; ok { - if err := solution.solveWithHint(lID, hint); err != nil { - return -1, err - } - } else { - r = 0 - } - - } - - if (c.R.CoeffID() != 0 || c.M[1].CoeffID() != 0) && !solution.solved[rID] { - // check if it's a hint - if hint, ok := cs.MHints[rID]; ok { - if err := solution.solveWithHint(rID, hint); err != nil { - return -1, err - } - } else { - r = 1 - } - } - - if (c.O.CoeffID() != 0) && !solution.solved[oID] { - // check if it's a hint - if hint, ok := cs.MHints[oID]; ok { - if err := solution.solveWithHint(oID, hint); err != nil { - return -1, err - } - } else { - r = 2 - } - } - return r, nil -} - -// solveConstraint solve any unsolved wire in given constraint and update the solution -// a SparseR1C may have up to one unsolved wire (excluding hints) -// if it doesn't, then this function returns and does nothing -func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution, coefficientsNegInv fr.Vector) error { - - if c.Commitment == constraint.COMMITTED { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. - return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time - } - - lro, err := cs.computeHints(c, solution) - if err != nil { - return err - } - if lro == -1 { - // no unsolved wire - // can happen if the constraint contained only hint wires. - return nil - } - if lro == 1 { // we solve for R: u1L+u2R+u3LR+u4O+k=0 => R(u2+u3L)+u1L+u4O+k = 0 - if !solution.solved[c.L.WireID()] { - panic("L wire should be instantiated when we solve R") - } - var u1, u2, u3, den, num, v1, v2 fr.Element - u3.Mul(&cs.Coefficients[c.M[0].CoeffID()], &cs.Coefficients[c.M[1].CoeffID()]) - u1.Set(&cs.Coefficients[c.L.CoeffID()]) - u2.Set(&cs.Coefficients[c.R.CoeffID()]) - den.Mul(&u3, &solution.values[c.L.WireID()]).Add(&den, &u2) - - v1 = solution.computeTerm(c.L) - v2 = solution.computeTerm(c.O) - num.Add(&v1, &v2).Add(&num, &cs.Coefficients[c.K]) - - // TODO find a way to do lazy div (/ batch inversion) - num.Div(&num, &den).Neg(&num) - solution.set(c.L.WireID(), num) - return nil - } - - if lro == 0 { // we solve for L: u1L+u2R+u3LR+u4O+k=0 => L(u1+u3R)+u2R+u4O+k = 0 - if !solution.solved[c.R.WireID()] { - panic("R wire should be instantiated when we solve L") - } - var u1, u2, u3, den, num, v1, v2 fr.Element - u3.Mul(&cs.Coefficients[c.M[0].CoeffID()], &cs.Coefficients[c.M[1].CoeffID()]) - u1.Set(&cs.Coefficients[c.L.CoeffID()]) - u2.Set(&cs.Coefficients[c.R.CoeffID()]) - den.Mul(&u3, &solution.values[c.R.WireID()]).Add(&den, &u1) - - v1 = solution.computeTerm(c.R) - v2 = solution.computeTerm(c.O) - num.Add(&v1, &v2).Add(&num, &cs.Coefficients[c.K]) - - // TODO find a way to do lazy div (/ batch inversion) - num.Div(&num, &den).Neg(&num) - solution.set(c.L.WireID(), num) - return nil - - } - // O we solve for O - var o fr.Element - cID, vID := c.O.CoeffID(), c.O.WireID() - - l := solution.computeTerm(c.L) - r := solution.computeTerm(c.R) - m0 := solution.computeTerm(c.M[0]) - m1 := solution.computeTerm(c.M[1]) - - // o = - ((m0 * m1) + l + r + c.K) / c.O - o.Mul(&m0, &m1).Add(&o, &l).Add(&o, &r).Add(&o, &cs.Coefficients[c.K]) - o.Mul(&o, &coefficientsNegInv[cID]) - - solution.set(vID, o) - - return nil -} - -// IsSolved -// Deprecated: use _, err := Solve(...) instead -func (cs *SparseR1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { - _, err := cs.Solve(witness, opts...) - return err -} - -// GetConstraints return the list of SparseR1C and a coefficient resolver -func (cs *SparseR1CS) GetConstraints() ([]constraint.SparseR1C, constraint.Resolver) { - return cs.Constraints, cs -} - -func (cs *SparseR1CS) GetConstraint(i int) *constraint.SparseR1C { - if i < 0 || i >= len(cs.Constraints) { - return nil - } - return &cs.Constraints[i] -} - -func (cs *SparseR1CS) GetCoefficient(i int) (r constraint.Coeff) { - copy(r[:], cs.Coefficients[i][:]) - return -} - -// checkConstraint verifies that the constraint holds -func (cs *SparseR1CS) checkConstraint(c constraint.SparseR1C, solution *solution) error { - - if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. - return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time - } - - l := solution.computeTerm(c.L) - r := solution.computeTerm(c.R) - m0 := solution.computeTerm(c.M[0]) - m1 := solution.computeTerm(c.M[1]) - o := solution.computeTerm(c.O) - - // l + r + (m0 * m1) + o + c.K == 0 - var t fr.Element - t.Mul(&m0, &m1).Add(&t, &l).Add(&t, &r).Add(&t, &o).Add(&t, &cs.Coefficients[c.K]) - if !t.IsZero() { - return fmt.Errorf("qL⋅xa + qR⋅xb + qO⋅xc + qM⋅(xaxb) + qC != 0 → %s + %s + %s + (%s × %s) + %s != 0", - l.String(), - r.String(), - o.String(), - m0.String(), - m1.String(), - cs.Coefficients[c.K].String(), - ) - } - return nil - -} - -// GetNbCoefficients return the number of unique coefficients needed in the R1CS -func (cs *SparseR1CS) GetNbCoefficients() int { - return len(cs.Coefficients) -} - -// CurveID returns curve ID as defined in gnark-crypto (ecc.BLS12-377) -func (cs *SparseR1CS) CurveID() ecc.ID { - return ecc.BLS12_377 -} - -// WriteTo encodes SparseR1CS into provided io.Writer using cbor -func (cs *SparseR1CS) WriteTo(w io.Writer) (int64, error) { - _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written - enc, err := cbor.CoreDetEncOptions().EncMode() - if err != nil { - return 0, err - } - encoder := enc.NewEncoder(&_w) - - // encode our object - err = encoder.Encode(cs) - return _w.N, err -} - -// ReadFrom attempts to decode SparseR1CS from io.Reader using cbor -func (cs *SparseR1CS) ReadFrom(r io.Reader) (int64, error) { - dm, err := cbor.DecOptions{ - MaxArrayElements: 134217728, - MaxMapPairs: 134217728, - }.DecMode() - if err != nil { - return 0, err - } - decoder := dm.NewDecoder(r) - - // initialize coeff table - cs.CoeffTable = newCoeffTable(0) - - if err := decoder.Decode(cs); err != nil { - return int64(decoder.NumBytesRead()), err - } - - if err := cs.CheckSerializationHeader(); err != nil { - return int64(decoder.NumBytesRead()), err - } - - return int64(decoder.NumBytesRead()), nil -} diff --git a/constraint/bls12-377/r1cs_test.go b/constraint/bls12-377/r1cs_test.go index 926f9c1bb6..99c531bf98 100644 --- a/constraint/bls12-377/r1cs_test.go +++ b/constraint/bls12-377/r1cs_test.go @@ -20,6 +20,7 @@ import ( "bytes" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/frontend/cs/scs" "github.com/consensys/gnark/internal/backend/circuits" "reflect" "testing" @@ -76,10 +77,11 @@ func TestSerialization(t *testing.T) { if diff := cmp.Diff(r1cs1, &reconstructed, cmpopts.IgnoreFields(cs.R1CS{}, "System.q", - "arithEngine", + "field", "CoeffTable.mCoeffs", "System.lbWireLevel", "System.lbHints", + "System.genericHint", "System.SymbolTable", "System.lbOutputs", "System.bitLen")); diff != "" { @@ -147,12 +149,6 @@ func (circuit *circuit) Define(api frontend.API) error { func BenchmarkSolve(b *testing.B) { - var c circuit - ccs, err := frontend.Compile(fr.Modulus(), r1cs.NewBuilder, &c) - if err != nil { - b.Fatal(err) - } - var w circuit w.X = 1 w.Y = 1 @@ -161,8 +157,32 @@ func BenchmarkSolve(b *testing.B) { b.Fatal(err) } - b.ResetTimer() - for i := 0; i < b.N; i++ { - _ = ccs.IsSolved(witness) - } + b.Run("scs", func(b *testing.B) { + var c circuit + ccs, err := frontend.Compile(fr.Modulus(), scs.NewBuilder, &c) + if err != nil { + b.Fatal(err) + } + b.Log("scs nbConstraints", ccs.GetNbConstraints()) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = ccs.IsSolved(witness) + } + }) + + b.Run("r1cs", func(b *testing.B) { + var c circuit + ccs, err := frontend.Compile(fr.Modulus(), r1cs.NewBuilder, &c, frontend.WithCompressThreshold(10)) + if err != nil { + b.Fatal(err) + } + b.Log("r1cs nbConstraints", ccs.GetNbConstraints()) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = ccs.IsSolved(witness) + } + }) + } diff --git a/constraint/bls12-377/solution.go b/constraint/bls12-377/solution.go deleted file mode 100644 index 112682fafe..0000000000 --- a/constraint/bls12-377/solution.go +++ /dev/null @@ -1,383 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// 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. - -// Code generated by gnark DO NOT EDIT - -package cs - -import ( - "errors" - "fmt" - "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/debug" - "github.com/rs/zerolog" - "io" - "math/big" - "strconv" - "strings" - "sync/atomic" - - "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" -) - -// solution represents elements needed to compute -// a solution to a R1CS or SparseR1CS -type solution struct { - values, coefficients []fr.Element - solved []bool - nbSolved uint64 - mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function - st *debug.SymbolTable - cs *constraint.System -} - -func newSolution(cs *constraint.System, nbWires int, hintFunctions map[solver.HintID]solver.Hint, coefficients []fr.Element) (solution, error) { - - s := solution{ - cs: cs, - st: &cs.SymbolTable, - values: make([]fr.Element, nbWires), - coefficients: coefficients, - solved: make([]bool, nbWires), - mHintsFunctions: hintFunctions, - } - - // hintsDependencies is from compile time; it contains the list of hints the solver **needs** - var missing []string - for hintUUID, hintID := range cs.MHintsDependencies { - if _, ok := s.mHintsFunctions[hintUUID]; !ok { - missing = append(missing, hintID) - } - } - - if len(missing) > 0 { - return s, fmt.Errorf("solver missing hint(s): %v", missing) - } - - return s, nil -} - -func (s *solution) set(id int, value fr.Element) { - if s.solved[id] { - panic("solving the same wire twice should never happen.") - } - s.values[id] = value - s.solved[id] = true - atomic.AddUint64(&s.nbSolved, 1) - // s.nbSolved++ -} - -func (s *solution) isValid() bool { - return int(s.nbSolved) == len(s.values) -} - -// computeTerm computes coeff*variable -func (s *solution) computeTerm(t constraint.Term) fr.Element { - cID, vID := t.CoeffID(), t.WireID() - if cID != 0 && !s.solved[vID] { - panic("computing a term with an unsolved wire") - } - switch cID { - case constraint.CoeffIdZero: - return fr.Element{} - case constraint.CoeffIdOne: - return s.values[vID] - case constraint.CoeffIdTwo: - var res fr.Element - res.Double(&s.values[vID]) - return res - case constraint.CoeffIdMinusOne: - var res fr.Element - res.Neg(&s.values[vID]) - return res - default: - var res fr.Element - res.Mul(&s.coefficients[cID], &s.values[vID]) - return res - } -} - -// r += (t.coeff*t.value) -func (s *solution) accumulateInto(t constraint.Term, r *fr.Element) { - cID := t.CoeffID() - - if t.IsConstant() { - // needed for logs, we may want to not put this in the hot path if we need to - // optimize constraint system solver further. - r.Add(r, &s.coefficients[cID]) - return - } - - vID := t.WireID() - switch cID { - case constraint.CoeffIdZero: - return - case constraint.CoeffIdOne: - r.Add(r, &s.values[vID]) - case constraint.CoeffIdTwo: - var res fr.Element - res.Double(&s.values[vID]) - r.Add(r, &res) - case constraint.CoeffIdMinusOne: - r.Sub(r, &s.values[vID]) - default: - var res fr.Element - res.Mul(&s.coefficients[cID], &s.values[vID]) - r.Add(r, &res) - } -} - -// solveHint compute solution.values[vID] using provided solver hint -func (s *solution) solveWithHint(vID int, hID int) error { - // skip if the wire is already solved by a call to the same hint - // function on the same inputs - if s.solved[vID] { - return nil - } - - h := &s.cs.HintMappings[hID] - - // ensure hint function was provided - f, ok := s.mHintsFunctions[h.HintID] - if !ok { - return errors.New("missing hint function") - } - - // tmp IO big int memory - nbInputs := len(h.Inputs) - nbOutputs := len(h.Outputs) - inputs := make([]*big.Int, nbInputs) - outputs := make([]*big.Int, nbOutputs) - for i := 0; i < nbOutputs; i++ { - outputs[i] = big.NewInt(0) - } - - q := fr.Modulus() - - // for each input, we set its big int value, IF all the wires are solved - // the only case where all wires may not be solved, is if one of the input of this hint - // is the output of another hint. - // it is safe to recursively solve this with the parallel solver, since all hints-output wires - // that we can solve this way are marked to be solved with the current constraint we are processing. - recursiveSolve := func(t constraint.Term) error { - if t.IsConstant() { - return nil - } - wID := t.WireID() - if s.solved[wID] { - return nil - } - // unsolved dependency - if h, ok := s.cs.MHints[wID]; ok { - // solve recursively. - return s.solveWithHint(wID, h) - } - - // it's not a hint, we panic. - panic("solver can't compute hint; one or more input wires are unsolved") - } - - for i := 0; i < nbInputs; i++ { - inputs[i] = big.NewInt(0) - - var v fr.Element - for _, term := range h.Inputs[i] { - if err := recursiveSolve(term); err != nil { - return err - } - s.accumulateInto(term, &v) - } - v.BigInt(inputs[i]) - } - - err := f(q, inputs, outputs) - - var v fr.Element - for i := range outputs { - v.SetBigInt(outputs[i]) - s.set(h.Outputs[i], v) - } - - return err -} - -func (s *solution) printLogs(log zerolog.Logger, logs []constraint.LogEntry) { - if log.GetLevel() == zerolog.Disabled { - return - } - - for i := 0; i < len(logs); i++ { - logLine := s.logValue(logs[i]) - log.Debug().Str(zerolog.CallerFieldName, logs[i].Caller).Msg(logLine) - } -} - -const unsolvedVariable = "" - -func (s *solution) logValue(log constraint.LogEntry) string { - var toResolve []interface{} - var ( - eval fr.Element - missingValue bool - ) - for j := 0; j < len(log.ToResolve); j++ { - // before eval le - - missingValue = false - eval.SetZero() - - for _, t := range log.ToResolve[j] { - // for each term in the linear expression - - cID, vID := t.CoeffID(), t.WireID() - if t.IsConstant() { - // just add the constant - eval.Add(&eval, &s.coefficients[cID]) - continue - } - - if !s.solved[vID] { - missingValue = true - break // stop the loop we can't evaluate. - } - - tv := s.computeTerm(t) - eval.Add(&eval, &tv) - } - - // after - if missingValue { - toResolve = append(toResolve, unsolvedVariable) - } else { - // we have to append our accumulator - toResolve = append(toResolve, eval.String()) - } - - } - if len(log.Stack) > 0 { - var sbb strings.Builder - for _, lID := range log.Stack { - location := s.st.Locations[lID] - function := s.st.Functions[location.FunctionID] - - sbb.WriteString(function.Name) - sbb.WriteByte('\n') - sbb.WriteByte('\t') - sbb.WriteString(function.Filename) - sbb.WriteByte(':') - sbb.WriteString(strconv.Itoa(int(location.Line))) - sbb.WriteByte('\n') - } - toResolve = append(toResolve, sbb.String()) - } - return fmt.Sprintf(log.Format, toResolve...) -} - -// UnsatisfiedConstraintError wraps an error with useful metadata on the unsatisfied constraint -type UnsatisfiedConstraintError struct { - Err error - CID int // constraint ID - DebugInfo *string // optional debug info -} - -func (r *UnsatisfiedConstraintError) Error() string { - if r.DebugInfo != nil { - return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, *r.DebugInfo) - } - return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, r.Err.Error()) -} - -// R1CSSolution represent a valid assignment to all the variables in the constraint system. -// The vector W such that Aw o Bw - Cw = 0 -type R1CSSolution struct { - W fr.Vector - A, B, C fr.Vector -} - -func (t *R1CSSolution) WriteTo(w io.Writer) (int64, error) { - n, err := t.W.WriteTo(w) - if err != nil { - return n, err - } - a, err := t.A.WriteTo(w) - n += a - if err != nil { - return n, err - } - a, err = t.B.WriteTo(w) - n += a - if err != nil { - return n, err - } - a, err = t.C.WriteTo(w) - n += a - return n, err -} - -func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { - n, err := t.W.ReadFrom(r) - if err != nil { - return n, err - } - a, err := t.A.ReadFrom(r) - a += n - if err != nil { - return n, err - } - a, err = t.B.ReadFrom(r) - a += n - if err != nil { - return n, err - } - a, err = t.C.ReadFrom(r) - n += a - return n, err -} - -// SparseR1CSSolution represent a valid assignment to all the variables in the constraint system. -type SparseR1CSSolution struct { - L, R, O fr.Vector -} - -func (t *SparseR1CSSolution) WriteTo(w io.Writer) (int64, error) { - n, err := t.L.WriteTo(w) - if err != nil { - return n, err - } - a, err := t.R.WriteTo(w) - n += a - if err != nil { - return n, err - } - a, err = t.O.WriteTo(w) - n += a - return n, err - -} - -func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { - n, err := t.L.ReadFrom(r) - if err != nil { - return n, err - } - a, err := t.R.ReadFrom(r) - a += n - if err != nil { - return n, err - } - a, err = t.O.ReadFrom(r) - a += n - return n, err -} diff --git a/constraint/bls12-377/solver.go b/constraint/bls12-377/solver.go new file mode 100644 index 0000000000..acfd4fdb13 --- /dev/null +++ b/constraint/bls12-377/solver.go @@ -0,0 +1,614 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package cs + +import ( + "errors" + "fmt" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/field/pool" + "github.com/consensys/gnark/constraint" + csolver "github.com/consensys/gnark/constraint/solver" + "github.com/rs/zerolog" + "math" + "math/big" + "runtime" + "strconv" + "strings" + "sync" + "sync/atomic" + + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" +) + +// solver represent the state of the solver during a call to System.Solve(...) +type solver struct { + *system + + // values and solved are index by the wire (variable) id + values []fr.Element + solved []bool + nbSolved uint64 + + // maps hintID to hint function + mHintsFunctions map[csolver.HintID]csolver.Hint + + // used to out api.Println + logger zerolog.Logger + + a, b, c fr.Vector // R1CS solver will compute the a,b,c matrices + + q *big.Int +} + +func newSolver(cs *system, witness fr.Vector, opts ...csolver.Option) (*solver, error) { + // parse options + opt, err := csolver.NewConfig(opts...) + if err != nil { + return nil, err + } + + // check witness size + witnessOffset := 0 + if cs.Type == constraint.SystemR1CS { + witnessOffset++ + } + + nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables + expectedWitnessSize := len(cs.Public) - witnessOffset + len(cs.Secret) + + if len(witness) != expectedWitnessSize { + return nil, fmt.Errorf("invalid witness size, got %d, expected %d", len(witness), expectedWitnessSize) + } + + // check all hints are there + hintFunctions := opt.HintFunctions + + // hintsDependencies is from compile time; it contains the list of hints the solver **needs** + var missing []string + for hintUUID, hintID := range cs.MHintsDependencies { + if _, ok := hintFunctions[hintUUID]; !ok { + missing = append(missing, hintID) + } + } + + if len(missing) > 0 { + return nil, fmt.Errorf("solver missing hint(s): %v", missing) + } + + s := solver{ + system: cs, + values: make([]fr.Element, nbWires), + solved: make([]bool, nbWires), + mHintsFunctions: hintFunctions, + logger: opt.Logger, + q: cs.Field(), + } + + // set the witness indexes as solved + if witnessOffset == 1 { + s.solved[0] = true // ONE_WIRE + s.values[0].SetOne() + } + copy(s.values[witnessOffset:], witness) + for i := range witness { + s.solved[i+witnessOffset] = true + } + + // keep track of the number of wire instantiations we do, for a post solve sanity check + // to ensure we instantiated all wires + s.nbSolved += uint64(len(witness) + witnessOffset) + + if s.Type == constraint.SystemR1CS { + n := ecc.NextPowerOfTwo(uint64(cs.GetNbConstraints())) + s.a = make(fr.Vector, cs.GetNbConstraints(), n) + s.b = make(fr.Vector, cs.GetNbConstraints(), n) + s.c = make(fr.Vector, cs.GetNbConstraints(), n) + } + + return &s, nil +} + +func (s *solver) set(id int, value fr.Element) { + if s.solved[id] { + panic("solving the same wire twice should never happen.") + } + s.values[id] = value + s.solved[id] = true + atomic.AddUint64(&s.nbSolved, 1) +} + +// computeTerm computes coeff*variable +// TODO @gbotrel check if t is a Constant only +func (s *solver) computeTerm(t constraint.Term) fr.Element { + cID, vID := t.CoeffID(), t.WireID() + if cID != 0 && !s.solved[vID] { + panic("computing a term with an unsolved wire") + } + switch cID { + case constraint.CoeffIdZero: + return fr.Element{} + case constraint.CoeffIdOne: + return s.values[vID] + case constraint.CoeffIdTwo: + var res fr.Element + res.Double(&s.values[vID]) + return res + case constraint.CoeffIdMinusOne: + var res fr.Element + res.Neg(&s.values[vID]) + return res + default: + var res fr.Element + res.Mul(&s.Coefficients[cID], &s.values[vID]) + return res + } +} + +// r += (t.coeff*t.value) +// TODO @gbotrel check t.IsConstant on the caller side when necessary +func (s *solver) accumulateInto(t constraint.Term, r *fr.Element) { + cID := t.CoeffID() + vID := t.WireID() + + switch cID { + case constraint.CoeffIdZero: + return + case constraint.CoeffIdOne: + r.Add(r, &s.values[vID]) + case constraint.CoeffIdTwo: + var res fr.Element + res.Double(&s.values[vID]) + r.Add(r, &res) + case constraint.CoeffIdMinusOne: + r.Sub(r, &s.values[vID]) + default: + var res fr.Element + res.Mul(&s.Coefficients[cID], &s.values[vID]) + r.Add(r, &res) + } +} + +// solveWithHint executes a hint and assign the result to its defined outputs. +func (s *solver) solveWithHint(h *constraint.HintMapping) error { + // ensure hint function was provided + f, ok := s.mHintsFunctions[h.HintID] + if !ok { + return errors.New("missing hint function") + } + + // tmp IO big int memory + nbInputs := len(h.Inputs) + nbOutputs := int(h.OutputRange.End - h.OutputRange.Start) + inputs := make([]*big.Int, nbInputs) + outputs := make([]*big.Int, nbOutputs) + for i := 0; i < nbOutputs; i++ { + outputs[i] = pool.BigInt.Get() + outputs[i].SetUint64(0) + } + + q := pool.BigInt.Get() + q.Set(s.q) + + for i := 0; i < nbInputs; i++ { + var v fr.Element + for _, term := range h.Inputs[i] { + if term.IsConstant() { + v.Add(&v, &s.Coefficients[term.CoeffID()]) + continue + } + s.accumulateInto(term, &v) + } + inputs[i] = pool.BigInt.Get() + v.BigInt(inputs[i]) + } + + err := f(q, inputs, outputs) + + var v fr.Element + for i := range outputs { + v.SetBigInt(outputs[i]) + s.set(int(h.OutputRange.Start)+i, v) + pool.BigInt.Put(outputs[i]) + } + + for i := range inputs { + pool.BigInt.Put(inputs[i]) + } + + pool.BigInt.Put(q) + + return err +} + +func (s *solver) printLogs(logs []constraint.LogEntry) { + if s.logger.GetLevel() == zerolog.Disabled { + return + } + + for i := 0; i < len(logs); i++ { + logLine := s.logValue(logs[i]) + s.logger.Debug().Str(zerolog.CallerFieldName, logs[i].Caller).Msg(logLine) + } +} + +const unsolvedVariable = "" + +func (s *solver) logValue(log constraint.LogEntry) string { + var toResolve []interface{} + var ( + eval fr.Element + missingValue bool + ) + for j := 0; j < len(log.ToResolve); j++ { + // before eval le + + missingValue = false + eval.SetZero() + + for _, t := range log.ToResolve[j] { + // for each term in the linear expression + + cID, vID := t.CoeffID(), t.WireID() + if t.IsConstant() { + // just add the constant + eval.Add(&eval, &s.Coefficients[cID]) + continue + } + + if !s.solved[vID] { + missingValue = true + break // stop the loop we can't evaluate. + } + + tv := s.computeTerm(t) + eval.Add(&eval, &tv) + } + + // after + if missingValue { + toResolve = append(toResolve, unsolvedVariable) + } else { + // we have to append our accumulator + toResolve = append(toResolve, eval.String()) + } + + } + if len(log.Stack) > 0 { + var sbb strings.Builder + for _, lID := range log.Stack { + location := s.SymbolTable.Locations[lID] + function := s.SymbolTable.Functions[location.FunctionID] + + sbb.WriteString(function.Name) + sbb.WriteByte('\n') + sbb.WriteByte('\t') + sbb.WriteString(function.Filename) + sbb.WriteByte(':') + sbb.WriteString(strconv.Itoa(int(location.Line))) + sbb.WriteByte('\n') + } + toResolve = append(toResolve, sbb.String()) + } + return fmt.Sprintf(log.Format, toResolve...) +} + +// divByCoeff sets res = res / t.Coeff +func (solver *solver) divByCoeff(res *fr.Element, cID uint32) { + switch cID { + case constraint.CoeffIdOne: + return + case constraint.CoeffIdMinusOne: + res.Neg(res) + case constraint.CoeffIdZero: + panic("division by 0") + default: + // this is slow, but shouldn't happen as divByCoeff is called to + // remove the coeff of an unsolved wire + // but unsolved wires are (in gnark frontend) systematically set with a coeff == 1 or -1 + res.Div(res, &solver.Coefficients[cID]) + } +} + +// Implement constraint.Solver +func (s *solver) GetValue(cID, vID uint32) constraint.Element { + var r constraint.Element + e := s.computeTerm(constraint.Term{CID: cID, VID: vID}) + copy(r[:], e[:]) + return r +} +func (s *solver) GetCoeff(cID uint32) constraint.Element { + var r constraint.Element + copy(r[:], s.Coefficients[cID][:]) + return r +} +func (s *solver) SetValue(vID uint32, f constraint.Element) { + s.set(int(vID), *(*fr.Element)(f[:])) +} + +func (s *solver) IsSolved(vID uint32) bool { + return s.solved[vID] +} + +// processInstruction decodes the instruction and execute blueprint-defined logic. +// an instruction can encode a hint, a custom constraint or a generic constraint. +func (solver *solver) processInstruction(inst constraint.Instruction, scratch *scratch) error { + // fetch the blueprint + blueprint := solver.Blueprints[inst.BlueprintID] + calldata := solver.GetCallData(inst) + cID := inst.ConstraintOffset // here we have 1 constraint in the instruction only + + if solver.Type == constraint.SystemR1CS { + if bc, ok := blueprint.(constraint.BlueprintR1C); ok { + // TODO @gbotrel we use the solveR1C method for now, having user-defined + // blueprint for R1CS would require constraint.Solver interface to add methods + // to set a,b,c since it's more efficient to compute these while we solve. + bc.DecompressR1C(&scratch.tR1C, calldata) + return solver.solveR1C(cID, &scratch.tR1C) + } + } else if solver.Type == constraint.SystemSparseR1CS { + // blueprint declared "I know how to solve this." + if bc, ok := blueprint.(constraint.BlueprintSolvable); ok { + if err := bc.Solve(solver, calldata); err != nil { + return solver.wrapErrWithDebugInfo(cID, err) + } + return nil + } + } + + // blueprint encodes a hint, we execute. + // TODO @gbotrel may be worth it to move hint logic in blueprint "solve" + if bc, ok := blueprint.(constraint.BlueprintHint); ok { + bc.DecompressHint(&scratch.tHint, calldata) + return solver.solveWithHint(&scratch.tHint) + } + + return nil +} + +// run runs the solver. it return an error if a constraint is not satisfied or if not all wires +// were instantiated. +func (solver *solver) run() error { + // minWorkPerCPU is the minimum target number of constraint a task should hold + // in other words, if a level has less than minWorkPerCPU, it will not be parallelized and executed + // sequentially without sync. + const minWorkPerCPU = 50.0 // TODO @gbotrel revisit that with blocks. + + // cs.Levels has a list of levels, where all constraints in a level l(n) are independent + // and may only have dependencies on previous levels + // for each constraint + // we are guaranteed that each R1C contains at most one unsolved wire + // first we solve the unsolved wire (if any) + // then we check that the constraint is valid + // if a[i] * b[i] != c[i]; it means the constraint is not satisfied + var wg sync.WaitGroup + chTasks := make(chan []int, runtime.NumCPU()) + chError := make(chan error, runtime.NumCPU()) + + // start a worker pool + // each worker wait on chTasks + // a task is a slice of constraint indexes to be solved + for i := 0; i < runtime.NumCPU(); i++ { + go func() { + var scratch scratch + for t := range chTasks { + for _, i := range t { + if err := solver.processInstruction(solver.Instructions[i], &scratch); err != nil { + chError <- err + wg.Done() + return + } + } + wg.Done() + } + }() + } + + // clean up pool go routines + defer func() { + close(chTasks) + close(chError) + }() + + var scratch scratch + + // for each level, we push the tasks + for _, level := range solver.Levels { + + // max CPU to use + maxCPU := float64(len(level)) / minWorkPerCPU + + if maxCPU <= 1.0 { + // we do it sequentially + for _, i := range level { + if err := solver.processInstruction(solver.Instructions[i], &scratch); err != nil { + return err + } + } + continue + } + + // number of tasks for this level is set to number of CPU + // but if we don't have enough work for all our CPU, it can be lower. + nbTasks := runtime.NumCPU() + maxTasks := int(math.Ceil(maxCPU)) + if nbTasks > maxTasks { + nbTasks = maxTasks + } + nbIterationsPerCpus := len(level) / nbTasks + + // more CPUs than tasks: a CPU will work on exactly one iteration + // note: this depends on minWorkPerCPU constant + if nbIterationsPerCpus < 1 { + nbIterationsPerCpus = 1 + nbTasks = len(level) + } + + extraTasks := len(level) - (nbTasks * nbIterationsPerCpus) + extraTasksOffset := 0 + + for i := 0; i < nbTasks; i++ { + wg.Add(1) + _start := i*nbIterationsPerCpus + extraTasksOffset + _end := _start + nbIterationsPerCpus + if extraTasks > 0 { + _end++ + extraTasks-- + extraTasksOffset++ + } + // since we're never pushing more than num CPU tasks + // we will never be blocked here + chTasks <- level[_start:_end] + } + + // wait for the level to be done + wg.Wait() + + if len(chError) > 0 { + return <-chError + } + } + + if int(solver.nbSolved) != len(solver.values) { + return errors.New("solver didn't assign a value to all wires") + } + + return nil +} + +// solveR1C compute unsolved wires in the constraint, if any and set the solver accordingly +// +// returns an error if the solver called a hint function that errored +// returns false, nil if there was no wire to solve +// returns true, nil if exactly one wire was solved. In that case, it is redundant to check that +// the constraint is satisfied later. +func (solver *solver) solveR1C(cID uint32, r *constraint.R1C) error { + a, b, c := &solver.a[cID], &solver.b[cID], &solver.c[cID] + + // the index of the non-zero entry shows if L, R or O has an uninstantiated wire + // the content is the ID of the wire non instantiated + var loc uint8 + + var termToCompute constraint.Term + + processLExp := func(l constraint.LinearExpression, val *fr.Element, locValue uint8) { + for _, t := range l { + vID := t.WireID() + + // wire is already computed, we just accumulate in val + if solver.solved[vID] { + solver.accumulateInto(t, val) + continue + } + + if loc != 0 { + panic("found more than one wire to instantiate") + } + termToCompute = t + loc = locValue + } + } + + processLExp(r.L, a, 1) + processLExp(r.R, b, 2) + processLExp(r.O, c, 3) + + if loc == 0 { + // there is nothing to solve, may happen if we have an assertion + // (ie a constraints that doesn't yield any output) + // or if we solved the unsolved wires with hint functions + var check fr.Element + if !check.Mul(a, b).Equal(c) { + return solver.wrapErrWithDebugInfo(cID, fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String())) + } + return nil + } + + // we compute the wire value and instantiate it + wID := termToCompute.WireID() + + // solver result + var wire fr.Element + + switch loc { + case 1: + if !b.IsZero() { + wire.Div(c, b). + Sub(&wire, a) + a.Add(a, &wire) + } else { + // we didn't actually ensure that a * b == c + var check fr.Element + if !check.Mul(a, b).Equal(c) { + return solver.wrapErrWithDebugInfo(cID, fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String())) + } + } + case 2: + if !a.IsZero() { + wire.Div(c, a). + Sub(&wire, b) + b.Add(b, &wire) + } else { + var check fr.Element + if !check.Mul(a, b).Equal(c) { + return solver.wrapErrWithDebugInfo(cID, fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String())) + } + } + case 3: + wire.Mul(a, b). + Sub(&wire, c) + + c.Add(c, &wire) + } + + // wire is the term (coeff * value) + // but in the solver we want to store the value only + // note that in gnark frontend, coeff here is always 1 or -1 + solver.divByCoeff(&wire, termToCompute.CID) + solver.set(wID, wire) + + return nil +} + +// UnsatisfiedConstraintError wraps an error with useful metadata on the unsatisfied constraint +type UnsatisfiedConstraintError struct { + Err error + CID int // constraint ID + DebugInfo *string // optional debug info +} + +func (r *UnsatisfiedConstraintError) Error() string { + if r.DebugInfo != nil { + return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, *r.DebugInfo) + } + return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, r.Err.Error()) +} + +func (solver *solver) wrapErrWithDebugInfo(cID uint32, err error) *UnsatisfiedConstraintError { + var debugInfo *string + if dID, ok := solver.MDebug[int(cID)]; ok { + debugInfo = new(string) + *debugInfo = solver.logValue(solver.DebugInfo[dID]) + } + return &UnsatisfiedConstraintError{CID: int(cID), Err: err, DebugInfo: debugInfo} +} + +// temporary variables to avoid memallocs in hotloop +type scratch struct { + tR1C constraint.R1C + tHint constraint.HintMapping +} diff --git a/constraint/bls12-377/system.go b/constraint/bls12-377/system.go new file mode 100644 index 0000000000..ffb212c059 --- /dev/null +++ b/constraint/bls12-377/system.go @@ -0,0 +1,365 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package cs + +import ( + "github.com/fxamacker/cbor/v2" + "io" + "time" + + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint" + csolver "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/internal/backend/ioutils" + "github.com/consensys/gnark/logger" + "reflect" + + "github.com/consensys/gnark-crypto/ecc" + + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" +) + +type R1CS = system +type SparseR1CS = system + +// system is a curved-typed constraint.System with a concrete coefficient table (fr.Element) +type system struct { + constraint.System + CoeffTable + field +} + +func NewR1CS(capacity int) *R1CS { + return newSystem(capacity, constraint.SystemR1CS) +} + +func NewSparseR1CS(capacity int) *SparseR1CS { + return newSystem(capacity, constraint.SystemSparseR1CS) +} + +func newSystem(capacity int, t constraint.SystemType) *system { + return &system{ + System: constraint.NewSystem(fr.Modulus(), capacity, t), + CoeffTable: newCoeffTable(capacity / 10), + } +} + +// Solve solves the constraint system with provided witness. +// If it's a R1CS returns R1CSSolution +// If it's a SparseR1CS returns SparseR1CSSolution +func (cs *system) Solve(witness witness.Witness, opts ...csolver.Option) (any, error) { + log := logger.Logger().With().Int("nbConstraints", cs.GetNbConstraints()).Logger() + start := time.Now() + + v := witness.Vector().(fr.Vector) + + // init the solver + solver, err := newSolver(cs, v, opts...) + if err != nil { + log.Err(err).Send() + return nil, err + } + + // defer log printing once all solver.values are computed + // (or sooner, if a constraint is not satisfied) + defer solver.printLogs(cs.Logs) + + // run it. + if err := solver.run(); err != nil { + log.Err(err).Send() + return nil, err + } + + log.Debug().Dur("took", time.Since(start)).Msg("constraint system solver done") + + // format the solution + // TODO @gbotrel revisit post-refactor + if cs.Type == constraint.SystemR1CS { + var res R1CSSolution + res.W = solver.values + res.A = solver.a + res.B = solver.b + res.C = solver.c + return &res, nil + } else { + // sparse R1CS + var res SparseR1CSSolution + // query l, r, o in Lagrange basis, not blinded + res.L, res.R, res.O = evaluateLROSmallDomain(cs, solver.values) + + return &res, nil + } + +} + +// IsSolved +// Deprecated: use _, err := Solve(...) instead +func (cs *system) IsSolved(witness witness.Witness, opts ...csolver.Option) error { + _, err := cs.Solve(witness, opts...) + return err +} + +// GetR1Cs return the list of R1C +func (cs *system) GetR1Cs() []constraint.R1C { + toReturn := make([]constraint.R1C, 0, cs.GetNbConstraints()) + + for _, inst := range cs.Instructions { + blueprint := cs.Blueprints[inst.BlueprintID] + if bc, ok := blueprint.(constraint.BlueprintR1C); ok { + var r1c constraint.R1C + bc.DecompressR1C(&r1c, cs.GetCallData(inst)) + toReturn = append(toReturn, r1c) + } else { + panic("not implemented") + } + } + return toReturn +} + +// GetNbCoefficients return the number of unique coefficients needed in the R1CS +func (cs *system) GetNbCoefficients() int { + return len(cs.Coefficients) +} + +// CurveID returns curve ID as defined in gnark-crypto +func (cs *system) CurveID() ecc.ID { + return ecc.BLS12_377 +} + +// WriteTo encodes R1CS into provided io.Writer using cbor +func (cs *system) WriteTo(w io.Writer) (int64, error) { + _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written + ts := getTagSet() + enc, err := cbor.CoreDetEncOptions().EncModeWithTags(ts) + if err != nil { + return 0, err + } + encoder := enc.NewEncoder(&_w) + + // encode our object + err = encoder.Encode(cs) + return _w.N, err +} + +// ReadFrom attempts to decode R1CS from io.Reader using cbor +func (cs *system) ReadFrom(r io.Reader) (int64, error) { + ts := getTagSet() + dm, err := cbor.DecOptions{ + MaxArrayElements: 134217728, + MaxMapPairs: 134217728, + }.DecModeWithTags(ts) + + if err != nil { + return 0, err + } + decoder := dm.NewDecoder(r) + + // initialize coeff table + cs.CoeffTable = newCoeffTable(0) + + if err := decoder.Decode(&cs); err != nil { + return int64(decoder.NumBytesRead()), err + } + + if err := cs.CheckSerializationHeader(); err != nil { + return int64(decoder.NumBytesRead()), err + } + + return int64(decoder.NumBytesRead()), nil +} + +func (cs *system) GetCoefficient(i int) (r constraint.Element) { + copy(r[:], cs.Coefficients[i][:]) + return +} + +// GetSparseR1Cs return the list of SparseR1C +func (cs *system) GetSparseR1Cs() []constraint.SparseR1C { + + toReturn := make([]constraint.SparseR1C, 0, cs.GetNbConstraints()) + + for _, inst := range cs.Instructions { + blueprint := cs.Blueprints[inst.BlueprintID] + if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { + var sparseR1C constraint.SparseR1C + calldata := cs.CallData[inst.StartCallData : inst.StartCallData+uint64(blueprint.NbInputs())] + bc.DecompressSparseR1C(&sparseR1C, calldata) + toReturn = append(toReturn, sparseR1C) + } else { + panic("not implemented") + } + } + return toReturn +} + +// evaluateLROSmallDomain extracts the solver l, r, o, and returns it in lagrange form. +// solver = [ public | secret | internal ] +// TODO @gbotrel refactor; this seems to be a small util function for plonk +func evaluateLROSmallDomain(cs *system, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { + + //s := int(pk.Domain[0].Cardinality) + s := cs.GetNbConstraints() + len(cs.Public) // len(spr.Public) is for the placeholder constraints + s = int(ecc.NextPowerOfTwo(uint64(s))) + + var l, r, o []fr.Element + l = make([]fr.Element, s) + r = make([]fr.Element, s) + o = make([]fr.Element, s) + s0 := solution[0] + + for i := 0; i < len(cs.Public); i++ { // placeholders + l[i] = solution[i] + r[i] = s0 + o[i] = s0 + } + offset := len(cs.Public) + nbConstraints := cs.GetNbConstraints() + + var sparseR1C constraint.SparseR1C + j := 0 + for _, inst := range cs.Instructions { + blueprint := cs.Blueprints[inst.BlueprintID] + if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { + bc.DecompressSparseR1C(&sparseR1C, cs.GetCallData(inst)) + + l[offset+j] = solution[sparseR1C.XA] + r[offset+j] = solution[sparseR1C.XB] + o[offset+j] = solution[sparseR1C.XC] + j++ + } + } + + offset += nbConstraints + + for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solver[0]) + l[offset+i] = s0 + r[offset+i] = s0 + o[offset+i] = s0 + } + + return l, r, o + +} + +// R1CSSolution represent a valid assignment to all the variables in the constraint system. +// The vector W such that Aw o Bw - Cw = 0 +type R1CSSolution struct { + W fr.Vector + A, B, C fr.Vector +} + +func (t *R1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.W.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.A.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.B.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.C.WriteTo(w) + n += a + return n, err +} + +func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.W.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.A.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.B.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.C.ReadFrom(r) + n += a + return n, err +} + +// SparseR1CSSolution represent a valid assignment to all the variables in the constraint system. +type SparseR1CSSolution struct { + L, R, O fr.Vector +} + +func (t *SparseR1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.L.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.R.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.O.WriteTo(w) + n += a + return n, err + +} + +func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.L.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.R.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.O.ReadFrom(r) + a += n + return n, err +} + +func getTagSet() cbor.TagSet { + // temporary for refactor + ts := cbor.NewTagSet() + // https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml + // 65536-15309735 Unassigned + tagNum := uint64(5309735) + addType := func(t reflect.Type) { + if err := ts.Add( + cbor.TagOptions{EncTag: cbor.EncTagRequired, DecTag: cbor.DecTagRequired}, + t, + tagNum, + ); err != nil { + panic(err) + } + tagNum++ + } + + addType(reflect.TypeOf(constraint.BlueprintGenericHint{})) + addType(reflect.TypeOf(constraint.BlueprintGenericR1C{})) + addType(reflect.TypeOf(constraint.BlueprintGenericSparseR1C{})) + addType(reflect.TypeOf(constraint.BlueprintSparseR1CAdd{})) + addType(reflect.TypeOf(constraint.BlueprintSparseR1CMul{})) + + return ts +} diff --git a/constraint/bls12-381/coeff.go b/constraint/bls12-381/coeff.go index f0ea2ac85f..2d27dc0b02 100644 --- a/constraint/bls12-381/coeff.go +++ b/constraint/bls12-381/coeff.go @@ -46,7 +46,7 @@ func newCoeffTable(capacity int) CoeffTable { } -func (ct *CoeffTable) MakeTerm(coeff *constraint.Coeff, variableID int) constraint.Term { +func (ct *CoeffTable) AddCoeff(coeff constraint.Element) uint32 { c := (*fr.Element)(coeff[:]) var cID uint32 if c.IsZero() { @@ -69,7 +69,11 @@ func (ct *CoeffTable) MakeTerm(coeff *constraint.Coeff, variableID int) constrai ct.mCoeffs[cc] = cID } } + return cID +} +func (ct *CoeffTable) MakeTerm(coeff *constraint.Element, variableID int) constraint.Term { + cID := ct.AddCoeff(*coeff) return constraint.Term{VID: uint32(variableID), CID: cID} } @@ -78,7 +82,10 @@ func (ct *CoeffTable) CoeffToString(cID int) string { return ct.Coefficients[cID].String() } -var _ constraint.CoeffEngine = &arithEngine{} +// implements constraint.Field +type field struct{} + +var _ constraint.Field = &field{} var ( two fr.Element @@ -94,10 +101,7 @@ func init() { minusTwo.Neg(&two) } -// implements constraint.CoeffEngine -type arithEngine struct{} - -func (engine *arithEngine) FromInterface(i interface{}) constraint.Coeff { +func (engine *field) FromInterface(i interface{}) constraint.Element { var e fr.Element if _, err := e.SetInterface(i); err != nil { // need to clean that --> some code path are dissimilar @@ -106,55 +110,75 @@ func (engine *arithEngine) FromInterface(i interface{}) constraint.Coeff { b := utils.FromInterface(i) e.SetBigInt(&b) } - var r constraint.Coeff + var r constraint.Element copy(r[:], e[:]) return r } -func (engine *arithEngine) ToBigInt(c *constraint.Coeff) *big.Int { +func (engine *field) ToBigInt(c constraint.Element) *big.Int { e := (*fr.Element)(c[:]) r := new(big.Int) e.BigInt(r) return r } -func (engine *arithEngine) Mul(a, b *constraint.Coeff) { +func (engine *field) Mul(a, b constraint.Element) constraint.Element { _a := (*fr.Element)(a[:]) _b := (*fr.Element)(b[:]) _a.Mul(_a, _b) + return a } -func (engine *arithEngine) Add(a, b *constraint.Coeff) { + +func (engine *field) Add(a, b constraint.Element) constraint.Element { _a := (*fr.Element)(a[:]) _b := (*fr.Element)(b[:]) _a.Add(_a, _b) + return a } -func (engine *arithEngine) Sub(a, b *constraint.Coeff) { +func (engine *field) Sub(a, b constraint.Element) constraint.Element { _a := (*fr.Element)(a[:]) _b := (*fr.Element)(b[:]) _a.Sub(_a, _b) + return a } -func (engine *arithEngine) Neg(a *constraint.Coeff) { +func (engine *field) Neg(a constraint.Element) constraint.Element { e := (*fr.Element)(a[:]) e.Neg(e) + return a } -func (engine *arithEngine) Inverse(a *constraint.Coeff) { +func (engine *field) Inverse(a constraint.Element) (constraint.Element, bool) { + if a.IsZero() { + return a, false + } e := (*fr.Element)(a[:]) + if e.IsZero() { + return a, false + } else if e.IsOne() { + return a, true + } + var t fr.Element + t.Neg(e) + if t.IsOne() { + return a, true + } + e.Inverse(e) + return a, true } -func (engine *arithEngine) IsOne(a *constraint.Coeff) bool { +func (engine *field) IsOne(a constraint.Element) bool { e := (*fr.Element)(a[:]) return e.IsOne() } -func (engine *arithEngine) One() constraint.Coeff { +func (engine *field) One() constraint.Element { e := fr.One() - var r constraint.Coeff + var r constraint.Element copy(r[:], e[:]) return r } -func (engine *arithEngine) String(a *constraint.Coeff) string { +func (engine *field) String(a constraint.Element) string { e := (*fr.Element)(a[:]) return e.String() } diff --git a/constraint/bls12-381/r1cs.go b/constraint/bls12-381/r1cs.go deleted file mode 100644 index 063c5462fd..0000000000 --- a/constraint/bls12-381/r1cs.go +++ /dev/null @@ -1,467 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// 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. - -// Code generated by gnark DO NOT EDIT - -package cs - -import ( - "errors" - "fmt" - "github.com/fxamacker/cbor/v2" - "io" - "runtime" - "sync" - "time" - - "github.com/consensys/gnark/backend/witness" - "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/internal/backend/ioutils" - "github.com/consensys/gnark/logger" - "github.com/consensys/gnark/profile" - - "github.com/consensys/gnark-crypto/ecc" - "math" - - "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" -) - -// R1CS describes a set of R1CS constraint -type R1CS struct { - constraint.R1CSCore - CoeffTable - arithEngine -} - -// NewR1CS returns a new R1CS and sets cs.Coefficient (fr.Element) from provided big.Int values -// -// capacity pre-allocates memory for capacity nbConstraints -func NewR1CS(capacity int) *R1CS { - r := R1CS{ - R1CSCore: constraint.R1CSCore{ - System: constraint.NewSystem(fr.Modulus()), - Constraints: make([]constraint.R1C, 0, capacity), - }, - CoeffTable: newCoeffTable(capacity / 10), - } - return &r -} - -func (cs *R1CS) AddConstraint(r1c constraint.R1C, debugInfo ...constraint.DebugInfo) int { - profile.RecordConstraint() - cs.Constraints = append(cs.Constraints, r1c) - cID := len(cs.Constraints) - 1 - if len(debugInfo) == 1 { - cs.DebugInfo = append(cs.DebugInfo, constraint.LogEntry(debugInfo[0])) - cs.MDebug[cID] = len(cs.DebugInfo) - 1 - } - - cs.UpdateLevel(cID, &r1c) - - return cID -} - -// Solve returns the vector w solution to the system, that is -// Aw o Bw - Cw = 0 -func (cs *R1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { - opt, err := solver.NewConfig(opts...) - if err != nil { - return nil, err - } - - var res R1CSSolution - - s := ecc.NextPowerOfTwo(uint64(len(cs.Constraints))) - res.A = make(fr.Vector, len(cs.Constraints), s) - res.B = make(fr.Vector, len(cs.Constraints), s) - res.C = make(fr.Vector, len(cs.Constraints), s) - - v := witness.Vector().(fr.Vector) - - res.W, err = cs.solve(v, res.A, res.B, res.C, opt) - if err != nil { - return nil, err - } - - return &res, nil -} - -// Solve sets all the wires and returns the a, b, c vectors. -// the cs system should have been compiled before. The entries in a, b, c are in Montgomery form. -// a, b, c vectors: ab-c = hz -// witness = [publicWires | secretWires] (without the ONE_WIRE !) -// returns [publicWires | secretWires | internalWires ] -func (cs *R1CS) solve(witness, a, b, c fr.Vector, opt solver.Config) (fr.Vector, error) { - log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() - - nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - solution, err := newSolution(&cs.System, nbWires, opt.HintFunctions, cs.Coefficients) - if err != nil { - return make(fr.Vector, nbWires), err - } - start := time.Now() - - if len(witness) != len(cs.Public)-1+len(cs.Secret) { // - 1 for ONE_WIRE - err = fmt.Errorf("invalid witness size, got %d, expected %d = %d (public) + %d (secret)", len(witness), int(len(cs.Public)-1+len(cs.Secret)), len(cs.Public)-1, len(cs.Secret)) - log.Err(err).Send() - return solution.values, err - } - - // compute the wires and the a, b, c polynomials - if len(a) != len(cs.Constraints) || len(b) != len(cs.Constraints) || len(c) != len(cs.Constraints) { - err = errors.New("invalid input size: len(a, b, c) == len(Constraints)") - log.Err(err).Send() - return solution.values, err - } - - solution.solved[0] = true // ONE_WIRE - solution.values[0].SetOne() - copy(solution.values[1:], witness) - for i := range witness { - solution.solved[i+1] = true - } - - // keep track of the number of wire instantiations we do, for a sanity check to ensure - // we instantiated all wires - solution.nbSolved += uint64(len(witness) + 1) - - // now that we know all inputs are set, defer log printing once all solution.values are computed - // (or sooner, if a constraint is not satisfied) - defer solution.printLogs(opt.Logger, cs.Logs) - - if err := cs.parallelSolve(a, b, c, &solution); err != nil { - if unsatisfiedErr, ok := err.(*UnsatisfiedConstraintError); ok { - log.Err(errors.New("unsatisfied constraint")).Int("id", unsatisfiedErr.CID).Send() - } else { - log.Err(err).Send() - } - return solution.values, err - } - - // sanity check; ensure all wires are marked as "instantiated" - if !solution.isValid() { - log.Err(errors.New("solver didn't instantiate all wires")).Send() - panic("solver didn't instantiate all wires") - } - - log.Debug().Dur("took", time.Since(start)).Msg("constraint system solver done") - - return solution.values, nil -} - -func (cs *R1CS) parallelSolve(a, b, c fr.Vector, solution *solution) error { - // minWorkPerCPU is the minimum target number of constraint a task should hold - // in other words, if a level has less than minWorkPerCPU, it will not be parallelized and executed - // sequentially without sync. - const minWorkPerCPU = 50.0 - - // cs.Levels has a list of levels, where all constraints in a level l(n) are independent - // and may only have dependencies on previous levels - // for each constraint - // we are guaranteed that each R1C contains at most one unsolved wire - // first we solve the unsolved wire (if any) - // then we check that the constraint is valid - // if a[i] * b[i] != c[i]; it means the constraint is not satisfied - - var wg sync.WaitGroup - chTasks := make(chan []int, runtime.NumCPU()) - chError := make(chan *UnsatisfiedConstraintError, runtime.NumCPU()) - - // start a worker pool - // each worker wait on chTasks - // a task is a slice of constraint indexes to be solved - for i := 0; i < runtime.NumCPU(); i++ { - go func() { - for t := range chTasks { - for _, i := range t { - // for each constraint in the task, solve it. - if err := cs.solveConstraint(cs.Constraints[i], solution, &a[i], &b[i], &c[i]); err != nil { - var debugInfo *string - if dID, ok := cs.MDebug[i]; ok { - debugInfo = new(string) - *debugInfo = solution.logValue(cs.DebugInfo[dID]) - } - chError <- &UnsatisfiedConstraintError{CID: i, Err: err, DebugInfo: debugInfo} - wg.Done() - return - } - } - wg.Done() - } - }() - } - - // clean up pool go routines - defer func() { - close(chTasks) - close(chError) - }() - - // for each level, we push the tasks - for _, level := range cs.Levels { - - // max CPU to use - maxCPU := float64(len(level)) / minWorkPerCPU - - if maxCPU <= 1.0 { - // we do it sequentially - for _, i := range level { - if err := cs.solveConstraint(cs.Constraints[i], solution, &a[i], &b[i], &c[i]); err != nil { - var debugInfo *string - if dID, ok := cs.MDebug[i]; ok { - debugInfo = new(string) - *debugInfo = solution.logValue(cs.DebugInfo[dID]) - } - return &UnsatisfiedConstraintError{CID: i, Err: err, DebugInfo: debugInfo} - } - } - continue - } - - // number of tasks for this level is set to number of CPU - // but if we don't have enough work for all our CPU, it can be lower. - nbTasks := runtime.NumCPU() - maxTasks := int(math.Ceil(maxCPU)) - if nbTasks > maxTasks { - nbTasks = maxTasks - } - nbIterationsPerCpus := len(level) / nbTasks - - // more CPUs than tasks: a CPU will work on exactly one iteration - // note: this depends on minWorkPerCPU constant - if nbIterationsPerCpus < 1 { - nbIterationsPerCpus = 1 - nbTasks = len(level) - } - - extraTasks := len(level) - (nbTasks * nbIterationsPerCpus) - extraTasksOffset := 0 - - for i := 0; i < nbTasks; i++ { - wg.Add(1) - _start := i*nbIterationsPerCpus + extraTasksOffset - _end := _start + nbIterationsPerCpus - if extraTasks > 0 { - _end++ - extraTasks-- - extraTasksOffset++ - } - // since we're never pushing more than num CPU tasks - // we will never be blocked here - chTasks <- level[_start:_end] - } - - // wait for the level to be done - wg.Wait() - - if len(chError) > 0 { - return <-chError - } - } - - return nil -} - -// IsSolved -// Deprecated: use _, err := Solve(...) instead -func (cs *R1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { - _, err := cs.Solve(witness, opts...) - return err -} - -// divByCoeff sets res = res / t.Coeff -func (cs *R1CS) divByCoeff(res *fr.Element, t constraint.Term) { - cID := t.CoeffID() - switch cID { - case constraint.CoeffIdOne: - return - case constraint.CoeffIdMinusOne: - res.Neg(res) - case constraint.CoeffIdZero: - panic("division by 0") - default: - // this is slow, but shouldn't happen as divByCoeff is called to - // remove the coeff of an unsolved wire - // but unsolved wires are (in gnark frontend) systematically set with a coeff == 1 or -1 - res.Div(res, &cs.Coefficients[cID]) - } -} - -// solveConstraint compute unsolved wires in the constraint, if any and set the solution accordingly -// -// returns an error if the solver called a hint function that errored -// returns false, nil if there was no wire to solve -// returns true, nil if exactly one wire was solved. In that case, it is redundant to check that -// the constraint is satisfied later. -func (cs *R1CS) solveConstraint(r constraint.R1C, solution *solution, a, b, c *fr.Element) error { - - // the index of the non-zero entry shows if L, R or O has an uninstantiated wire - // the content is the ID of the wire non instantiated - var loc uint8 - - var termToCompute constraint.Term - - processLExp := func(l constraint.LinearExpression, val *fr.Element, locValue uint8) error { - for _, t := range l { - vID := t.WireID() - - // wire is already computed, we just accumulate in val - if solution.solved[vID] { - solution.accumulateInto(t, val) - continue - } - - // first we check if this is a hint wire - if hint, ok := cs.MHints[vID]; ok { - if err := solution.solveWithHint(vID, hint); err != nil { - return err - } - // now that the wire is saved, accumulate it into a, b or c - solution.accumulateInto(t, val) - continue - } - - if loc != 0 { - panic("found more than one wire to instantiate") - } - termToCompute = t - loc = locValue - } - return nil - } - - if err := processLExp(r.L, a, 1); err != nil { - return err - } - - if err := processLExp(r.R, b, 2); err != nil { - return err - } - - if err := processLExp(r.O, c, 3); err != nil { - return err - } - - if loc == 0 { - // there is nothing to solve, may happen if we have an assertion - // (ie a constraints that doesn't yield any output) - // or if we solved the unsolved wires with hint functions - var check fr.Element - if !check.Mul(a, b).Equal(c) { - return fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String()) - } - return nil - } - - // we compute the wire value and instantiate it - wID := termToCompute.WireID() - - // solver result - var wire fr.Element - - switch loc { - case 1: - if !b.IsZero() { - wire.Div(c, b). - Sub(&wire, a) - a.Add(a, &wire) - } else { - // we didn't actually ensure that a * b == c - var check fr.Element - if !check.Mul(a, b).Equal(c) { - return fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String()) - } - } - case 2: - if !a.IsZero() { - wire.Div(c, a). - Sub(&wire, b) - b.Add(b, &wire) - } else { - var check fr.Element - if !check.Mul(a, b).Equal(c) { - return fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String()) - } - } - case 3: - wire.Mul(a, b). - Sub(&wire, c) - - c.Add(c, &wire) - } - - // wire is the term (coeff * value) - // but in the solution we want to store the value only - // note that in gnark frontend, coeff here is always 1 or -1 - cs.divByCoeff(&wire, termToCompute) - solution.set(wID, wire) - - return nil -} - -// GetConstraints return the list of R1C and a coefficient resolver -func (cs *R1CS) GetConstraints() ([]constraint.R1C, constraint.Resolver) { - return cs.Constraints, cs -} - -// GetNbCoefficients return the number of unique coefficients needed in the R1CS -func (cs *R1CS) GetNbCoefficients() int { - return len(cs.Coefficients) -} - -// CurveID returns curve ID as defined in gnark-crypto -func (cs *R1CS) CurveID() ecc.ID { - return ecc.BLS12_381 -} - -// WriteTo encodes R1CS into provided io.Writer using cbor -func (cs *R1CS) WriteTo(w io.Writer) (int64, error) { - _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written - enc, err := cbor.CoreDetEncOptions().EncMode() - if err != nil { - return 0, err - } - encoder := enc.NewEncoder(&_w) - - // encode our object - err = encoder.Encode(cs) - return _w.N, err -} - -// ReadFrom attempts to decode R1CS from io.Reader using cbor -func (cs *R1CS) ReadFrom(r io.Reader) (int64, error) { - dm, err := cbor.DecOptions{ - MaxArrayElements: 134217728, - MaxMapPairs: 134217728, - }.DecMode() - - if err != nil { - return 0, err - } - decoder := dm.NewDecoder(r) - - // initialize coeff table - cs.CoeffTable = newCoeffTable(0) - - if err := decoder.Decode(&cs); err != nil { - return int64(decoder.NumBytesRead()), err - } - - if err := cs.CheckSerializationHeader(); err != nil { - return int64(decoder.NumBytesRead()), err - } - - return int64(decoder.NumBytesRead()), nil -} diff --git a/constraint/bls12-381/r1cs_sparse.go b/constraint/bls12-381/r1cs_sparse.go deleted file mode 100644 index c223170fb3..0000000000 --- a/constraint/bls12-381/r1cs_sparse.go +++ /dev/null @@ -1,533 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// 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. - -// Code generated by gnark DO NOT EDIT - -package cs - -import ( - "errors" - "fmt" - "github.com/consensys/gnark-crypto/ecc" - "github.com/fxamacker/cbor/v2" - "io" - "math" - "runtime" - "sync" - "time" - - "github.com/consensys/gnark/backend/witness" - "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/internal/backend/ioutils" - "github.com/consensys/gnark/logger" - "github.com/consensys/gnark/profile" - - "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" -) - -// SparseR1CS represents a Plonk like circuit -type SparseR1CS struct { - constraint.SparseR1CSCore - CoeffTable - arithEngine -} - -// NewSparseR1CS returns a new SparseR1CS and sets r1cs.Coefficient (fr.Element) from provided big.Int values -func NewSparseR1CS(capacity int) *SparseR1CS { - cs := SparseR1CS{ - SparseR1CSCore: constraint.SparseR1CSCore{ - System: constraint.NewSystem(fr.Modulus()), - Constraints: make([]constraint.SparseR1C, 0, capacity), - }, - CoeffTable: newCoeffTable(capacity / 10), - } - - return &cs -} - -func (cs *SparseR1CS) AddConstraint(c constraint.SparseR1C, debugInfo ...constraint.DebugInfo) int { - profile.RecordConstraint() - cs.Constraints = append(cs.Constraints, c) - cID := len(cs.Constraints) - 1 - if len(debugInfo) == 1 { - cs.DebugInfo = append(cs.DebugInfo, constraint.LogEntry(debugInfo[0])) - cs.MDebug[cID] = len(cs.DebugInfo) - 1 - } - cs.UpdateLevel(cID, &c) - - return cID -} - -func (c *SparseR1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { - opt, err := solver.NewConfig(opts...) - if err != nil { - return nil, err - } - - // compute the constraint system solution - var solution []fr.Element - if solution, err = c.solve(witness.Vector().(fr.Vector), opt); err != nil { - return nil, err - } - - var res SparseR1CSSolution - // query l, r, o in Lagrange basis, not blinded - res.L, res.R, res.O = c.evaluateLROSmallDomain(solution) - - return &res, nil -} - -// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. -// solution = [ public | secret | internal ] -func (c *SparseR1CS) evaluateLROSmallDomain(solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { - - //s := int(pk.Domain[0].Cardinality) - s := c.GetNbConstraints() + len(c.Public) // len(spr.Public) is for the placeholder constraints - s = int(ecc.NextPowerOfTwo(uint64(s))) - - var l, r, o []fr.Element - l = make([]fr.Element, s) - r = make([]fr.Element, s) - o = make([]fr.Element, s) - s0 := solution[0] - - for i := 0; i < len(c.Public); i++ { // placeholders - l[i] = solution[i] - r[i] = s0 - o[i] = s0 - } - offset := len(c.Public) - for i := 0; i < len(c.Constraints); i++ { // constraints - l[offset+i] = solution[c.Constraints[i].L.WireID()] - r[offset+i] = solution[c.Constraints[i].R.WireID()] - o[offset+i] = solution[c.Constraints[i].O.WireID()] - } - offset += len(c.Constraints) - - for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) - l[offset+i] = s0 - r[offset+i] = s0 - o[offset+i] = s0 - } - - return l, r, o - -} - -// Solve sets all the wires. -// solution.values = [publicInputs | secretInputs | internalVariables ] -// witness: contains the input variables -// it returns the full slice of wires -func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, error) { - log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "plonk").Logger() - - // set the slices holding the solution.values and monitoring which variables have been solved - nbVariables := cs.NbInternalVariables + len(cs.Secret) + len(cs.Public) - - start := time.Now() - - expectedWitnessSize := len(cs.Public) + len(cs.Secret) - if len(witness) != expectedWitnessSize { - return make(fr.Vector, nbVariables), fmt.Errorf( - "invalid witness size, got %d, expected %d = %d (public) + %d (secret)", - len(witness), - expectedWitnessSize, - len(cs.Public), - len(cs.Secret), - ) - } - - // keep track of wire that have a value - solution, err := newSolution(&cs.System, nbVariables, opt.HintFunctions, cs.Coefficients) - if err != nil { - return solution.values, err - } - - // solution.values = [publicInputs | secretInputs | internalVariables ] -> we fill publicInputs | secretInputs - copy(solution.values, witness) - for i := 0; i < len(witness); i++ { - solution.solved[i] = true - } - - // keep track of the number of wire instantiations we do, for a sanity check to ensure - // we instantiated all wires - solution.nbSolved += uint64(len(witness)) - - // defer log printing once all solution.values are computed - defer solution.printLogs(opt.Logger, cs.Logs) - - // batch invert the coefficients to avoid many divisions in the solver - coefficientsNegInv := fr.BatchInvert(cs.Coefficients) - for i := 0; i < len(coefficientsNegInv); i++ { - coefficientsNegInv[i].Neg(&coefficientsNegInv[i]) - } - - if err := cs.parallelSolve(&solution, coefficientsNegInv); err != nil { - if unsatisfiedErr, ok := err.(*UnsatisfiedConstraintError); ok { - log.Err(errors.New("unsatisfied constraint")).Int("id", unsatisfiedErr.CID).Send() - } else { - log.Err(err).Send() - } - return solution.values, err - } - - // sanity check; ensure all wires are marked as "instantiated" - if !solution.isValid() { - log.Err(errors.New("solver didn't instantiate all wires")).Send() - panic("solver didn't instantiate all wires") - } - - log.Debug().Dur("took", time.Since(start)).Msg("constraint system solver done") - - return solution.values, nil - -} - -func (cs *SparseR1CS) parallelSolve(solution *solution, coefficientsNegInv fr.Vector) error { - // minWorkPerCPU is the minimum target number of constraint a task should hold - // in other words, if a level has less than minWorkPerCPU, it will not be parallelized and executed - // sequentially without sync. - const minWorkPerCPU = 50.0 - - // cs.Levels has a list of levels, where all constraints in a level l(n) are independent - // and may only have dependencies on previous levels - - var wg sync.WaitGroup - chTasks := make(chan []int, runtime.NumCPU()) - chError := make(chan *UnsatisfiedConstraintError, runtime.NumCPU()) - - // start a worker pool - // each worker wait on chTasks - // a task is a slice of constraint indexes to be solved - for i := 0; i < runtime.NumCPU(); i++ { - go func() { - for t := range chTasks { - for _, i := range t { - // for each constraint in the task, solve it. - if err := cs.solveConstraint(cs.Constraints[i], solution, coefficientsNegInv); err != nil { - chError <- &UnsatisfiedConstraintError{CID: i, Err: err} - wg.Done() - return - } - if err := cs.checkConstraint(cs.Constraints[i], solution); err != nil { - if dID, ok := cs.MDebug[i]; ok { - errMsg := solution.logValue(cs.DebugInfo[dID]) - chError <- &UnsatisfiedConstraintError{CID: i, DebugInfo: &errMsg} - } else { - chError <- &UnsatisfiedConstraintError{CID: i, Err: err} - } - wg.Done() - return - } - } - wg.Done() - } - }() - } - - // clean up pool go routines - defer func() { - close(chTasks) - close(chError) - }() - - // for each level, we push the tasks - for _, level := range cs.Levels { - - // max CPU to use - maxCPU := float64(len(level)) / minWorkPerCPU - - if maxCPU <= 1.0 { - // we do it sequentially - for _, i := range level { - if err := cs.solveConstraint(cs.Constraints[i], solution, coefficientsNegInv); err != nil { - return &UnsatisfiedConstraintError{CID: i, Err: err} - } - if err := cs.checkConstraint(cs.Constraints[i], solution); err != nil { - if dID, ok := cs.MDebug[i]; ok { - errMsg := solution.logValue(cs.DebugInfo[dID]) - return &UnsatisfiedConstraintError{CID: i, DebugInfo: &errMsg} - } - return &UnsatisfiedConstraintError{CID: i, Err: err} - } - } - continue - } - - // number of tasks for this level is set to number of CPU - // but if we don't have enough work for all our CPU, it can be lower. - nbTasks := runtime.NumCPU() - maxTasks := int(math.Ceil(maxCPU)) - if nbTasks > maxTasks { - nbTasks = maxTasks - } - nbIterationsPerCpus := len(level) / nbTasks - - // more CPUs than tasks: a CPU will work on exactly one iteration - // note: this depends on minWorkPerCPU constant - if nbIterationsPerCpus < 1 { - nbIterationsPerCpus = 1 - nbTasks = len(level) - } - - extraTasks := len(level) - (nbTasks * nbIterationsPerCpus) - extraTasksOffset := 0 - - for i := 0; i < nbTasks; i++ { - wg.Add(1) - _start := i*nbIterationsPerCpus + extraTasksOffset - _end := _start + nbIterationsPerCpus - if extraTasks > 0 { - _end++ - extraTasks-- - extraTasksOffset++ - } - // since we're never pushing more than num CPU tasks - // we will never be blocked here - chTasks <- level[_start:_end] - } - - // wait for the level to be done - wg.Wait() - - if len(chError) > 0 { - return <-chError - } - } - - return nil -} - -// computeHints computes wires associated with a hint function, if any -// if there is no remaining wire to solve, returns -1 -// else returns the wire position (L -> 0, R -> 1, O -> 2) -func (cs *SparseR1CS) computeHints(c constraint.SparseR1C, solution *solution) (int, error) { - r := -1 - lID, rID, oID := c.L.WireID(), c.R.WireID(), c.O.WireID() - - if (c.L.CoeffID() != 0 || c.M[0].CoeffID() != 0) && !solution.solved[lID] { - // check if it's a hint - if hint, ok := cs.MHints[lID]; ok { - if err := solution.solveWithHint(lID, hint); err != nil { - return -1, err - } - } else { - r = 0 - } - - } - - if (c.R.CoeffID() != 0 || c.M[1].CoeffID() != 0) && !solution.solved[rID] { - // check if it's a hint - if hint, ok := cs.MHints[rID]; ok { - if err := solution.solveWithHint(rID, hint); err != nil { - return -1, err - } - } else { - r = 1 - } - } - - if (c.O.CoeffID() != 0) && !solution.solved[oID] { - // check if it's a hint - if hint, ok := cs.MHints[oID]; ok { - if err := solution.solveWithHint(oID, hint); err != nil { - return -1, err - } - } else { - r = 2 - } - } - return r, nil -} - -// solveConstraint solve any unsolved wire in given constraint and update the solution -// a SparseR1C may have up to one unsolved wire (excluding hints) -// if it doesn't, then this function returns and does nothing -func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution, coefficientsNegInv fr.Vector) error { - - if c.Commitment == constraint.COMMITTED { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. - return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time - } - - lro, err := cs.computeHints(c, solution) - if err != nil { - return err - } - if lro == -1 { - // no unsolved wire - // can happen if the constraint contained only hint wires. - return nil - } - if lro == 1 { // we solve for R: u1L+u2R+u3LR+u4O+k=0 => R(u2+u3L)+u1L+u4O+k = 0 - if !solution.solved[c.L.WireID()] { - panic("L wire should be instantiated when we solve R") - } - var u1, u2, u3, den, num, v1, v2 fr.Element - u3.Mul(&cs.Coefficients[c.M[0].CoeffID()], &cs.Coefficients[c.M[1].CoeffID()]) - u1.Set(&cs.Coefficients[c.L.CoeffID()]) - u2.Set(&cs.Coefficients[c.R.CoeffID()]) - den.Mul(&u3, &solution.values[c.L.WireID()]).Add(&den, &u2) - - v1 = solution.computeTerm(c.L) - v2 = solution.computeTerm(c.O) - num.Add(&v1, &v2).Add(&num, &cs.Coefficients[c.K]) - - // TODO find a way to do lazy div (/ batch inversion) - num.Div(&num, &den).Neg(&num) - solution.set(c.L.WireID(), num) - return nil - } - - if lro == 0 { // we solve for L: u1L+u2R+u3LR+u4O+k=0 => L(u1+u3R)+u2R+u4O+k = 0 - if !solution.solved[c.R.WireID()] { - panic("R wire should be instantiated when we solve L") - } - var u1, u2, u3, den, num, v1, v2 fr.Element - u3.Mul(&cs.Coefficients[c.M[0].CoeffID()], &cs.Coefficients[c.M[1].CoeffID()]) - u1.Set(&cs.Coefficients[c.L.CoeffID()]) - u2.Set(&cs.Coefficients[c.R.CoeffID()]) - den.Mul(&u3, &solution.values[c.R.WireID()]).Add(&den, &u1) - - v1 = solution.computeTerm(c.R) - v2 = solution.computeTerm(c.O) - num.Add(&v1, &v2).Add(&num, &cs.Coefficients[c.K]) - - // TODO find a way to do lazy div (/ batch inversion) - num.Div(&num, &den).Neg(&num) - solution.set(c.L.WireID(), num) - return nil - - } - // O we solve for O - var o fr.Element - cID, vID := c.O.CoeffID(), c.O.WireID() - - l := solution.computeTerm(c.L) - r := solution.computeTerm(c.R) - m0 := solution.computeTerm(c.M[0]) - m1 := solution.computeTerm(c.M[1]) - - // o = - ((m0 * m1) + l + r + c.K) / c.O - o.Mul(&m0, &m1).Add(&o, &l).Add(&o, &r).Add(&o, &cs.Coefficients[c.K]) - o.Mul(&o, &coefficientsNegInv[cID]) - - solution.set(vID, o) - - return nil -} - -// IsSolved -// Deprecated: use _, err := Solve(...) instead -func (cs *SparseR1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { - _, err := cs.Solve(witness, opts...) - return err -} - -// GetConstraints return the list of SparseR1C and a coefficient resolver -func (cs *SparseR1CS) GetConstraints() ([]constraint.SparseR1C, constraint.Resolver) { - return cs.Constraints, cs -} - -func (cs *SparseR1CS) GetConstraint(i int) *constraint.SparseR1C { - if i < 0 || i >= len(cs.Constraints) { - return nil - } - return &cs.Constraints[i] -} - -func (cs *SparseR1CS) GetCoefficient(i int) (r constraint.Coeff) { - copy(r[:], cs.Coefficients[i][:]) - return -} - -// checkConstraint verifies that the constraint holds -func (cs *SparseR1CS) checkConstraint(c constraint.SparseR1C, solution *solution) error { - - if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. - return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time - } - - l := solution.computeTerm(c.L) - r := solution.computeTerm(c.R) - m0 := solution.computeTerm(c.M[0]) - m1 := solution.computeTerm(c.M[1]) - o := solution.computeTerm(c.O) - - // l + r + (m0 * m1) + o + c.K == 0 - var t fr.Element - t.Mul(&m0, &m1).Add(&t, &l).Add(&t, &r).Add(&t, &o).Add(&t, &cs.Coefficients[c.K]) - if !t.IsZero() { - return fmt.Errorf("qL⋅xa + qR⋅xb + qO⋅xc + qM⋅(xaxb) + qC != 0 → %s + %s + %s + (%s × %s) + %s != 0", - l.String(), - r.String(), - o.String(), - m0.String(), - m1.String(), - cs.Coefficients[c.K].String(), - ) - } - return nil - -} - -// GetNbCoefficients return the number of unique coefficients needed in the R1CS -func (cs *SparseR1CS) GetNbCoefficients() int { - return len(cs.Coefficients) -} - -// CurveID returns curve ID as defined in gnark-crypto (ecc.BLS12-381) -func (cs *SparseR1CS) CurveID() ecc.ID { - return ecc.BLS12_381 -} - -// WriteTo encodes SparseR1CS into provided io.Writer using cbor -func (cs *SparseR1CS) WriteTo(w io.Writer) (int64, error) { - _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written - enc, err := cbor.CoreDetEncOptions().EncMode() - if err != nil { - return 0, err - } - encoder := enc.NewEncoder(&_w) - - // encode our object - err = encoder.Encode(cs) - return _w.N, err -} - -// ReadFrom attempts to decode SparseR1CS from io.Reader using cbor -func (cs *SparseR1CS) ReadFrom(r io.Reader) (int64, error) { - dm, err := cbor.DecOptions{ - MaxArrayElements: 134217728, - MaxMapPairs: 134217728, - }.DecMode() - if err != nil { - return 0, err - } - decoder := dm.NewDecoder(r) - - // initialize coeff table - cs.CoeffTable = newCoeffTable(0) - - if err := decoder.Decode(cs); err != nil { - return int64(decoder.NumBytesRead()), err - } - - if err := cs.CheckSerializationHeader(); err != nil { - return int64(decoder.NumBytesRead()), err - } - - return int64(decoder.NumBytesRead()), nil -} diff --git a/constraint/bls12-381/r1cs_test.go b/constraint/bls12-381/r1cs_test.go index 90c9e1e849..98830260bc 100644 --- a/constraint/bls12-381/r1cs_test.go +++ b/constraint/bls12-381/r1cs_test.go @@ -20,6 +20,7 @@ import ( "bytes" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/frontend/cs/scs" "github.com/consensys/gnark/internal/backend/circuits" "reflect" "testing" @@ -76,10 +77,11 @@ func TestSerialization(t *testing.T) { if diff := cmp.Diff(r1cs1, &reconstructed, cmpopts.IgnoreFields(cs.R1CS{}, "System.q", - "arithEngine", + "field", "CoeffTable.mCoeffs", "System.lbWireLevel", "System.lbHints", + "System.genericHint", "System.SymbolTable", "System.lbOutputs", "System.bitLen")); diff != "" { @@ -147,12 +149,6 @@ func (circuit *circuit) Define(api frontend.API) error { func BenchmarkSolve(b *testing.B) { - var c circuit - ccs, err := frontend.Compile(fr.Modulus(), r1cs.NewBuilder, &c) - if err != nil { - b.Fatal(err) - } - var w circuit w.X = 1 w.Y = 1 @@ -161,8 +157,32 @@ func BenchmarkSolve(b *testing.B) { b.Fatal(err) } - b.ResetTimer() - for i := 0; i < b.N; i++ { - _ = ccs.IsSolved(witness) - } + b.Run("scs", func(b *testing.B) { + var c circuit + ccs, err := frontend.Compile(fr.Modulus(), scs.NewBuilder, &c) + if err != nil { + b.Fatal(err) + } + b.Log("scs nbConstraints", ccs.GetNbConstraints()) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = ccs.IsSolved(witness) + } + }) + + b.Run("r1cs", func(b *testing.B) { + var c circuit + ccs, err := frontend.Compile(fr.Modulus(), r1cs.NewBuilder, &c, frontend.WithCompressThreshold(10)) + if err != nil { + b.Fatal(err) + } + b.Log("r1cs nbConstraints", ccs.GetNbConstraints()) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = ccs.IsSolved(witness) + } + }) + } diff --git a/constraint/bls12-381/solution.go b/constraint/bls12-381/solution.go deleted file mode 100644 index b267734702..0000000000 --- a/constraint/bls12-381/solution.go +++ /dev/null @@ -1,383 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// 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. - -// Code generated by gnark DO NOT EDIT - -package cs - -import ( - "errors" - "fmt" - "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/debug" - "github.com/rs/zerolog" - "io" - "math/big" - "strconv" - "strings" - "sync/atomic" - - "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" -) - -// solution represents elements needed to compute -// a solution to a R1CS or SparseR1CS -type solution struct { - values, coefficients []fr.Element - solved []bool - nbSolved uint64 - mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function - st *debug.SymbolTable - cs *constraint.System -} - -func newSolution(cs *constraint.System, nbWires int, hintFunctions map[solver.HintID]solver.Hint, coefficients []fr.Element) (solution, error) { - - s := solution{ - cs: cs, - st: &cs.SymbolTable, - values: make([]fr.Element, nbWires), - coefficients: coefficients, - solved: make([]bool, nbWires), - mHintsFunctions: hintFunctions, - } - - // hintsDependencies is from compile time; it contains the list of hints the solver **needs** - var missing []string - for hintUUID, hintID := range cs.MHintsDependencies { - if _, ok := s.mHintsFunctions[hintUUID]; !ok { - missing = append(missing, hintID) - } - } - - if len(missing) > 0 { - return s, fmt.Errorf("solver missing hint(s): %v", missing) - } - - return s, nil -} - -func (s *solution) set(id int, value fr.Element) { - if s.solved[id] { - panic("solving the same wire twice should never happen.") - } - s.values[id] = value - s.solved[id] = true - atomic.AddUint64(&s.nbSolved, 1) - // s.nbSolved++ -} - -func (s *solution) isValid() bool { - return int(s.nbSolved) == len(s.values) -} - -// computeTerm computes coeff*variable -func (s *solution) computeTerm(t constraint.Term) fr.Element { - cID, vID := t.CoeffID(), t.WireID() - if cID != 0 && !s.solved[vID] { - panic("computing a term with an unsolved wire") - } - switch cID { - case constraint.CoeffIdZero: - return fr.Element{} - case constraint.CoeffIdOne: - return s.values[vID] - case constraint.CoeffIdTwo: - var res fr.Element - res.Double(&s.values[vID]) - return res - case constraint.CoeffIdMinusOne: - var res fr.Element - res.Neg(&s.values[vID]) - return res - default: - var res fr.Element - res.Mul(&s.coefficients[cID], &s.values[vID]) - return res - } -} - -// r += (t.coeff*t.value) -func (s *solution) accumulateInto(t constraint.Term, r *fr.Element) { - cID := t.CoeffID() - - if t.IsConstant() { - // needed for logs, we may want to not put this in the hot path if we need to - // optimize constraint system solver further. - r.Add(r, &s.coefficients[cID]) - return - } - - vID := t.WireID() - switch cID { - case constraint.CoeffIdZero: - return - case constraint.CoeffIdOne: - r.Add(r, &s.values[vID]) - case constraint.CoeffIdTwo: - var res fr.Element - res.Double(&s.values[vID]) - r.Add(r, &res) - case constraint.CoeffIdMinusOne: - r.Sub(r, &s.values[vID]) - default: - var res fr.Element - res.Mul(&s.coefficients[cID], &s.values[vID]) - r.Add(r, &res) - } -} - -// solveHint compute solution.values[vID] using provided solver hint -func (s *solution) solveWithHint(vID int, hID int) error { - // skip if the wire is already solved by a call to the same hint - // function on the same inputs - if s.solved[vID] { - return nil - } - - h := &s.cs.HintMappings[hID] - - // ensure hint function was provided - f, ok := s.mHintsFunctions[h.HintID] - if !ok { - return errors.New("missing hint function") - } - - // tmp IO big int memory - nbInputs := len(h.Inputs) - nbOutputs := len(h.Outputs) - inputs := make([]*big.Int, nbInputs) - outputs := make([]*big.Int, nbOutputs) - for i := 0; i < nbOutputs; i++ { - outputs[i] = big.NewInt(0) - } - - q := fr.Modulus() - - // for each input, we set its big int value, IF all the wires are solved - // the only case where all wires may not be solved, is if one of the input of this hint - // is the output of another hint. - // it is safe to recursively solve this with the parallel solver, since all hints-output wires - // that we can solve this way are marked to be solved with the current constraint we are processing. - recursiveSolve := func(t constraint.Term) error { - if t.IsConstant() { - return nil - } - wID := t.WireID() - if s.solved[wID] { - return nil - } - // unsolved dependency - if h, ok := s.cs.MHints[wID]; ok { - // solve recursively. - return s.solveWithHint(wID, h) - } - - // it's not a hint, we panic. - panic("solver can't compute hint; one or more input wires are unsolved") - } - - for i := 0; i < nbInputs; i++ { - inputs[i] = big.NewInt(0) - - var v fr.Element - for _, term := range h.Inputs[i] { - if err := recursiveSolve(term); err != nil { - return err - } - s.accumulateInto(term, &v) - } - v.BigInt(inputs[i]) - } - - err := f(q, inputs, outputs) - - var v fr.Element - for i := range outputs { - v.SetBigInt(outputs[i]) - s.set(h.Outputs[i], v) - } - - return err -} - -func (s *solution) printLogs(log zerolog.Logger, logs []constraint.LogEntry) { - if log.GetLevel() == zerolog.Disabled { - return - } - - for i := 0; i < len(logs); i++ { - logLine := s.logValue(logs[i]) - log.Debug().Str(zerolog.CallerFieldName, logs[i].Caller).Msg(logLine) - } -} - -const unsolvedVariable = "" - -func (s *solution) logValue(log constraint.LogEntry) string { - var toResolve []interface{} - var ( - eval fr.Element - missingValue bool - ) - for j := 0; j < len(log.ToResolve); j++ { - // before eval le - - missingValue = false - eval.SetZero() - - for _, t := range log.ToResolve[j] { - // for each term in the linear expression - - cID, vID := t.CoeffID(), t.WireID() - if t.IsConstant() { - // just add the constant - eval.Add(&eval, &s.coefficients[cID]) - continue - } - - if !s.solved[vID] { - missingValue = true - break // stop the loop we can't evaluate. - } - - tv := s.computeTerm(t) - eval.Add(&eval, &tv) - } - - // after - if missingValue { - toResolve = append(toResolve, unsolvedVariable) - } else { - // we have to append our accumulator - toResolve = append(toResolve, eval.String()) - } - - } - if len(log.Stack) > 0 { - var sbb strings.Builder - for _, lID := range log.Stack { - location := s.st.Locations[lID] - function := s.st.Functions[location.FunctionID] - - sbb.WriteString(function.Name) - sbb.WriteByte('\n') - sbb.WriteByte('\t') - sbb.WriteString(function.Filename) - sbb.WriteByte(':') - sbb.WriteString(strconv.Itoa(int(location.Line))) - sbb.WriteByte('\n') - } - toResolve = append(toResolve, sbb.String()) - } - return fmt.Sprintf(log.Format, toResolve...) -} - -// UnsatisfiedConstraintError wraps an error with useful metadata on the unsatisfied constraint -type UnsatisfiedConstraintError struct { - Err error - CID int // constraint ID - DebugInfo *string // optional debug info -} - -func (r *UnsatisfiedConstraintError) Error() string { - if r.DebugInfo != nil { - return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, *r.DebugInfo) - } - return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, r.Err.Error()) -} - -// R1CSSolution represent a valid assignment to all the variables in the constraint system. -// The vector W such that Aw o Bw - Cw = 0 -type R1CSSolution struct { - W fr.Vector - A, B, C fr.Vector -} - -func (t *R1CSSolution) WriteTo(w io.Writer) (int64, error) { - n, err := t.W.WriteTo(w) - if err != nil { - return n, err - } - a, err := t.A.WriteTo(w) - n += a - if err != nil { - return n, err - } - a, err = t.B.WriteTo(w) - n += a - if err != nil { - return n, err - } - a, err = t.C.WriteTo(w) - n += a - return n, err -} - -func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { - n, err := t.W.ReadFrom(r) - if err != nil { - return n, err - } - a, err := t.A.ReadFrom(r) - a += n - if err != nil { - return n, err - } - a, err = t.B.ReadFrom(r) - a += n - if err != nil { - return n, err - } - a, err = t.C.ReadFrom(r) - n += a - return n, err -} - -// SparseR1CSSolution represent a valid assignment to all the variables in the constraint system. -type SparseR1CSSolution struct { - L, R, O fr.Vector -} - -func (t *SparseR1CSSolution) WriteTo(w io.Writer) (int64, error) { - n, err := t.L.WriteTo(w) - if err != nil { - return n, err - } - a, err := t.R.WriteTo(w) - n += a - if err != nil { - return n, err - } - a, err = t.O.WriteTo(w) - n += a - return n, err - -} - -func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { - n, err := t.L.ReadFrom(r) - if err != nil { - return n, err - } - a, err := t.R.ReadFrom(r) - a += n - if err != nil { - return n, err - } - a, err = t.O.ReadFrom(r) - a += n - return n, err -} diff --git a/constraint/bls12-381/solver.go b/constraint/bls12-381/solver.go new file mode 100644 index 0000000000..316b69cce5 --- /dev/null +++ b/constraint/bls12-381/solver.go @@ -0,0 +1,614 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package cs + +import ( + "errors" + "fmt" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/field/pool" + "github.com/consensys/gnark/constraint" + csolver "github.com/consensys/gnark/constraint/solver" + "github.com/rs/zerolog" + "math" + "math/big" + "runtime" + "strconv" + "strings" + "sync" + "sync/atomic" + + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" +) + +// solver represent the state of the solver during a call to System.Solve(...) +type solver struct { + *system + + // values and solved are index by the wire (variable) id + values []fr.Element + solved []bool + nbSolved uint64 + + // maps hintID to hint function + mHintsFunctions map[csolver.HintID]csolver.Hint + + // used to out api.Println + logger zerolog.Logger + + a, b, c fr.Vector // R1CS solver will compute the a,b,c matrices + + q *big.Int +} + +func newSolver(cs *system, witness fr.Vector, opts ...csolver.Option) (*solver, error) { + // parse options + opt, err := csolver.NewConfig(opts...) + if err != nil { + return nil, err + } + + // check witness size + witnessOffset := 0 + if cs.Type == constraint.SystemR1CS { + witnessOffset++ + } + + nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables + expectedWitnessSize := len(cs.Public) - witnessOffset + len(cs.Secret) + + if len(witness) != expectedWitnessSize { + return nil, fmt.Errorf("invalid witness size, got %d, expected %d", len(witness), expectedWitnessSize) + } + + // check all hints are there + hintFunctions := opt.HintFunctions + + // hintsDependencies is from compile time; it contains the list of hints the solver **needs** + var missing []string + for hintUUID, hintID := range cs.MHintsDependencies { + if _, ok := hintFunctions[hintUUID]; !ok { + missing = append(missing, hintID) + } + } + + if len(missing) > 0 { + return nil, fmt.Errorf("solver missing hint(s): %v", missing) + } + + s := solver{ + system: cs, + values: make([]fr.Element, nbWires), + solved: make([]bool, nbWires), + mHintsFunctions: hintFunctions, + logger: opt.Logger, + q: cs.Field(), + } + + // set the witness indexes as solved + if witnessOffset == 1 { + s.solved[0] = true // ONE_WIRE + s.values[0].SetOne() + } + copy(s.values[witnessOffset:], witness) + for i := range witness { + s.solved[i+witnessOffset] = true + } + + // keep track of the number of wire instantiations we do, for a post solve sanity check + // to ensure we instantiated all wires + s.nbSolved += uint64(len(witness) + witnessOffset) + + if s.Type == constraint.SystemR1CS { + n := ecc.NextPowerOfTwo(uint64(cs.GetNbConstraints())) + s.a = make(fr.Vector, cs.GetNbConstraints(), n) + s.b = make(fr.Vector, cs.GetNbConstraints(), n) + s.c = make(fr.Vector, cs.GetNbConstraints(), n) + } + + return &s, nil +} + +func (s *solver) set(id int, value fr.Element) { + if s.solved[id] { + panic("solving the same wire twice should never happen.") + } + s.values[id] = value + s.solved[id] = true + atomic.AddUint64(&s.nbSolved, 1) +} + +// computeTerm computes coeff*variable +// TODO @gbotrel check if t is a Constant only +func (s *solver) computeTerm(t constraint.Term) fr.Element { + cID, vID := t.CoeffID(), t.WireID() + if cID != 0 && !s.solved[vID] { + panic("computing a term with an unsolved wire") + } + switch cID { + case constraint.CoeffIdZero: + return fr.Element{} + case constraint.CoeffIdOne: + return s.values[vID] + case constraint.CoeffIdTwo: + var res fr.Element + res.Double(&s.values[vID]) + return res + case constraint.CoeffIdMinusOne: + var res fr.Element + res.Neg(&s.values[vID]) + return res + default: + var res fr.Element + res.Mul(&s.Coefficients[cID], &s.values[vID]) + return res + } +} + +// r += (t.coeff*t.value) +// TODO @gbotrel check t.IsConstant on the caller side when necessary +func (s *solver) accumulateInto(t constraint.Term, r *fr.Element) { + cID := t.CoeffID() + vID := t.WireID() + + switch cID { + case constraint.CoeffIdZero: + return + case constraint.CoeffIdOne: + r.Add(r, &s.values[vID]) + case constraint.CoeffIdTwo: + var res fr.Element + res.Double(&s.values[vID]) + r.Add(r, &res) + case constraint.CoeffIdMinusOne: + r.Sub(r, &s.values[vID]) + default: + var res fr.Element + res.Mul(&s.Coefficients[cID], &s.values[vID]) + r.Add(r, &res) + } +} + +// solveWithHint executes a hint and assign the result to its defined outputs. +func (s *solver) solveWithHint(h *constraint.HintMapping) error { + // ensure hint function was provided + f, ok := s.mHintsFunctions[h.HintID] + if !ok { + return errors.New("missing hint function") + } + + // tmp IO big int memory + nbInputs := len(h.Inputs) + nbOutputs := int(h.OutputRange.End - h.OutputRange.Start) + inputs := make([]*big.Int, nbInputs) + outputs := make([]*big.Int, nbOutputs) + for i := 0; i < nbOutputs; i++ { + outputs[i] = pool.BigInt.Get() + outputs[i].SetUint64(0) + } + + q := pool.BigInt.Get() + q.Set(s.q) + + for i := 0; i < nbInputs; i++ { + var v fr.Element + for _, term := range h.Inputs[i] { + if term.IsConstant() { + v.Add(&v, &s.Coefficients[term.CoeffID()]) + continue + } + s.accumulateInto(term, &v) + } + inputs[i] = pool.BigInt.Get() + v.BigInt(inputs[i]) + } + + err := f(q, inputs, outputs) + + var v fr.Element + for i := range outputs { + v.SetBigInt(outputs[i]) + s.set(int(h.OutputRange.Start)+i, v) + pool.BigInt.Put(outputs[i]) + } + + for i := range inputs { + pool.BigInt.Put(inputs[i]) + } + + pool.BigInt.Put(q) + + return err +} + +func (s *solver) printLogs(logs []constraint.LogEntry) { + if s.logger.GetLevel() == zerolog.Disabled { + return + } + + for i := 0; i < len(logs); i++ { + logLine := s.logValue(logs[i]) + s.logger.Debug().Str(zerolog.CallerFieldName, logs[i].Caller).Msg(logLine) + } +} + +const unsolvedVariable = "" + +func (s *solver) logValue(log constraint.LogEntry) string { + var toResolve []interface{} + var ( + eval fr.Element + missingValue bool + ) + for j := 0; j < len(log.ToResolve); j++ { + // before eval le + + missingValue = false + eval.SetZero() + + for _, t := range log.ToResolve[j] { + // for each term in the linear expression + + cID, vID := t.CoeffID(), t.WireID() + if t.IsConstant() { + // just add the constant + eval.Add(&eval, &s.Coefficients[cID]) + continue + } + + if !s.solved[vID] { + missingValue = true + break // stop the loop we can't evaluate. + } + + tv := s.computeTerm(t) + eval.Add(&eval, &tv) + } + + // after + if missingValue { + toResolve = append(toResolve, unsolvedVariable) + } else { + // we have to append our accumulator + toResolve = append(toResolve, eval.String()) + } + + } + if len(log.Stack) > 0 { + var sbb strings.Builder + for _, lID := range log.Stack { + location := s.SymbolTable.Locations[lID] + function := s.SymbolTable.Functions[location.FunctionID] + + sbb.WriteString(function.Name) + sbb.WriteByte('\n') + sbb.WriteByte('\t') + sbb.WriteString(function.Filename) + sbb.WriteByte(':') + sbb.WriteString(strconv.Itoa(int(location.Line))) + sbb.WriteByte('\n') + } + toResolve = append(toResolve, sbb.String()) + } + return fmt.Sprintf(log.Format, toResolve...) +} + +// divByCoeff sets res = res / t.Coeff +func (solver *solver) divByCoeff(res *fr.Element, cID uint32) { + switch cID { + case constraint.CoeffIdOne: + return + case constraint.CoeffIdMinusOne: + res.Neg(res) + case constraint.CoeffIdZero: + panic("division by 0") + default: + // this is slow, but shouldn't happen as divByCoeff is called to + // remove the coeff of an unsolved wire + // but unsolved wires are (in gnark frontend) systematically set with a coeff == 1 or -1 + res.Div(res, &solver.Coefficients[cID]) + } +} + +// Implement constraint.Solver +func (s *solver) GetValue(cID, vID uint32) constraint.Element { + var r constraint.Element + e := s.computeTerm(constraint.Term{CID: cID, VID: vID}) + copy(r[:], e[:]) + return r +} +func (s *solver) GetCoeff(cID uint32) constraint.Element { + var r constraint.Element + copy(r[:], s.Coefficients[cID][:]) + return r +} +func (s *solver) SetValue(vID uint32, f constraint.Element) { + s.set(int(vID), *(*fr.Element)(f[:])) +} + +func (s *solver) IsSolved(vID uint32) bool { + return s.solved[vID] +} + +// processInstruction decodes the instruction and execute blueprint-defined logic. +// an instruction can encode a hint, a custom constraint or a generic constraint. +func (solver *solver) processInstruction(inst constraint.Instruction, scratch *scratch) error { + // fetch the blueprint + blueprint := solver.Blueprints[inst.BlueprintID] + calldata := solver.GetCallData(inst) + cID := inst.ConstraintOffset // here we have 1 constraint in the instruction only + + if solver.Type == constraint.SystemR1CS { + if bc, ok := blueprint.(constraint.BlueprintR1C); ok { + // TODO @gbotrel we use the solveR1C method for now, having user-defined + // blueprint for R1CS would require constraint.Solver interface to add methods + // to set a,b,c since it's more efficient to compute these while we solve. + bc.DecompressR1C(&scratch.tR1C, calldata) + return solver.solveR1C(cID, &scratch.tR1C) + } + } else if solver.Type == constraint.SystemSparseR1CS { + // blueprint declared "I know how to solve this." + if bc, ok := blueprint.(constraint.BlueprintSolvable); ok { + if err := bc.Solve(solver, calldata); err != nil { + return solver.wrapErrWithDebugInfo(cID, err) + } + return nil + } + } + + // blueprint encodes a hint, we execute. + // TODO @gbotrel may be worth it to move hint logic in blueprint "solve" + if bc, ok := blueprint.(constraint.BlueprintHint); ok { + bc.DecompressHint(&scratch.tHint, calldata) + return solver.solveWithHint(&scratch.tHint) + } + + return nil +} + +// run runs the solver. it return an error if a constraint is not satisfied or if not all wires +// were instantiated. +func (solver *solver) run() error { + // minWorkPerCPU is the minimum target number of constraint a task should hold + // in other words, if a level has less than minWorkPerCPU, it will not be parallelized and executed + // sequentially without sync. + const minWorkPerCPU = 50.0 // TODO @gbotrel revisit that with blocks. + + // cs.Levels has a list of levels, where all constraints in a level l(n) are independent + // and may only have dependencies on previous levels + // for each constraint + // we are guaranteed that each R1C contains at most one unsolved wire + // first we solve the unsolved wire (if any) + // then we check that the constraint is valid + // if a[i] * b[i] != c[i]; it means the constraint is not satisfied + var wg sync.WaitGroup + chTasks := make(chan []int, runtime.NumCPU()) + chError := make(chan error, runtime.NumCPU()) + + // start a worker pool + // each worker wait on chTasks + // a task is a slice of constraint indexes to be solved + for i := 0; i < runtime.NumCPU(); i++ { + go func() { + var scratch scratch + for t := range chTasks { + for _, i := range t { + if err := solver.processInstruction(solver.Instructions[i], &scratch); err != nil { + chError <- err + wg.Done() + return + } + } + wg.Done() + } + }() + } + + // clean up pool go routines + defer func() { + close(chTasks) + close(chError) + }() + + var scratch scratch + + // for each level, we push the tasks + for _, level := range solver.Levels { + + // max CPU to use + maxCPU := float64(len(level)) / minWorkPerCPU + + if maxCPU <= 1.0 { + // we do it sequentially + for _, i := range level { + if err := solver.processInstruction(solver.Instructions[i], &scratch); err != nil { + return err + } + } + continue + } + + // number of tasks for this level is set to number of CPU + // but if we don't have enough work for all our CPU, it can be lower. + nbTasks := runtime.NumCPU() + maxTasks := int(math.Ceil(maxCPU)) + if nbTasks > maxTasks { + nbTasks = maxTasks + } + nbIterationsPerCpus := len(level) / nbTasks + + // more CPUs than tasks: a CPU will work on exactly one iteration + // note: this depends on minWorkPerCPU constant + if nbIterationsPerCpus < 1 { + nbIterationsPerCpus = 1 + nbTasks = len(level) + } + + extraTasks := len(level) - (nbTasks * nbIterationsPerCpus) + extraTasksOffset := 0 + + for i := 0; i < nbTasks; i++ { + wg.Add(1) + _start := i*nbIterationsPerCpus + extraTasksOffset + _end := _start + nbIterationsPerCpus + if extraTasks > 0 { + _end++ + extraTasks-- + extraTasksOffset++ + } + // since we're never pushing more than num CPU tasks + // we will never be blocked here + chTasks <- level[_start:_end] + } + + // wait for the level to be done + wg.Wait() + + if len(chError) > 0 { + return <-chError + } + } + + if int(solver.nbSolved) != len(solver.values) { + return errors.New("solver didn't assign a value to all wires") + } + + return nil +} + +// solveR1C compute unsolved wires in the constraint, if any and set the solver accordingly +// +// returns an error if the solver called a hint function that errored +// returns false, nil if there was no wire to solve +// returns true, nil if exactly one wire was solved. In that case, it is redundant to check that +// the constraint is satisfied later. +func (solver *solver) solveR1C(cID uint32, r *constraint.R1C) error { + a, b, c := &solver.a[cID], &solver.b[cID], &solver.c[cID] + + // the index of the non-zero entry shows if L, R or O has an uninstantiated wire + // the content is the ID of the wire non instantiated + var loc uint8 + + var termToCompute constraint.Term + + processLExp := func(l constraint.LinearExpression, val *fr.Element, locValue uint8) { + for _, t := range l { + vID := t.WireID() + + // wire is already computed, we just accumulate in val + if solver.solved[vID] { + solver.accumulateInto(t, val) + continue + } + + if loc != 0 { + panic("found more than one wire to instantiate") + } + termToCompute = t + loc = locValue + } + } + + processLExp(r.L, a, 1) + processLExp(r.R, b, 2) + processLExp(r.O, c, 3) + + if loc == 0 { + // there is nothing to solve, may happen if we have an assertion + // (ie a constraints that doesn't yield any output) + // or if we solved the unsolved wires with hint functions + var check fr.Element + if !check.Mul(a, b).Equal(c) { + return solver.wrapErrWithDebugInfo(cID, fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String())) + } + return nil + } + + // we compute the wire value and instantiate it + wID := termToCompute.WireID() + + // solver result + var wire fr.Element + + switch loc { + case 1: + if !b.IsZero() { + wire.Div(c, b). + Sub(&wire, a) + a.Add(a, &wire) + } else { + // we didn't actually ensure that a * b == c + var check fr.Element + if !check.Mul(a, b).Equal(c) { + return solver.wrapErrWithDebugInfo(cID, fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String())) + } + } + case 2: + if !a.IsZero() { + wire.Div(c, a). + Sub(&wire, b) + b.Add(b, &wire) + } else { + var check fr.Element + if !check.Mul(a, b).Equal(c) { + return solver.wrapErrWithDebugInfo(cID, fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String())) + } + } + case 3: + wire.Mul(a, b). + Sub(&wire, c) + + c.Add(c, &wire) + } + + // wire is the term (coeff * value) + // but in the solver we want to store the value only + // note that in gnark frontend, coeff here is always 1 or -1 + solver.divByCoeff(&wire, termToCompute.CID) + solver.set(wID, wire) + + return nil +} + +// UnsatisfiedConstraintError wraps an error with useful metadata on the unsatisfied constraint +type UnsatisfiedConstraintError struct { + Err error + CID int // constraint ID + DebugInfo *string // optional debug info +} + +func (r *UnsatisfiedConstraintError) Error() string { + if r.DebugInfo != nil { + return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, *r.DebugInfo) + } + return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, r.Err.Error()) +} + +func (solver *solver) wrapErrWithDebugInfo(cID uint32, err error) *UnsatisfiedConstraintError { + var debugInfo *string + if dID, ok := solver.MDebug[int(cID)]; ok { + debugInfo = new(string) + *debugInfo = solver.logValue(solver.DebugInfo[dID]) + } + return &UnsatisfiedConstraintError{CID: int(cID), Err: err, DebugInfo: debugInfo} +} + +// temporary variables to avoid memallocs in hotloop +type scratch struct { + tR1C constraint.R1C + tHint constraint.HintMapping +} diff --git a/constraint/bls12-381/system.go b/constraint/bls12-381/system.go new file mode 100644 index 0000000000..beca1bfe0d --- /dev/null +++ b/constraint/bls12-381/system.go @@ -0,0 +1,365 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package cs + +import ( + "github.com/fxamacker/cbor/v2" + "io" + "time" + + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint" + csolver "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/internal/backend/ioutils" + "github.com/consensys/gnark/logger" + "reflect" + + "github.com/consensys/gnark-crypto/ecc" + + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" +) + +type R1CS = system +type SparseR1CS = system + +// system is a curved-typed constraint.System with a concrete coefficient table (fr.Element) +type system struct { + constraint.System + CoeffTable + field +} + +func NewR1CS(capacity int) *R1CS { + return newSystem(capacity, constraint.SystemR1CS) +} + +func NewSparseR1CS(capacity int) *SparseR1CS { + return newSystem(capacity, constraint.SystemSparseR1CS) +} + +func newSystem(capacity int, t constraint.SystemType) *system { + return &system{ + System: constraint.NewSystem(fr.Modulus(), capacity, t), + CoeffTable: newCoeffTable(capacity / 10), + } +} + +// Solve solves the constraint system with provided witness. +// If it's a R1CS returns R1CSSolution +// If it's a SparseR1CS returns SparseR1CSSolution +func (cs *system) Solve(witness witness.Witness, opts ...csolver.Option) (any, error) { + log := logger.Logger().With().Int("nbConstraints", cs.GetNbConstraints()).Logger() + start := time.Now() + + v := witness.Vector().(fr.Vector) + + // init the solver + solver, err := newSolver(cs, v, opts...) + if err != nil { + log.Err(err).Send() + return nil, err + } + + // defer log printing once all solver.values are computed + // (or sooner, if a constraint is not satisfied) + defer solver.printLogs(cs.Logs) + + // run it. + if err := solver.run(); err != nil { + log.Err(err).Send() + return nil, err + } + + log.Debug().Dur("took", time.Since(start)).Msg("constraint system solver done") + + // format the solution + // TODO @gbotrel revisit post-refactor + if cs.Type == constraint.SystemR1CS { + var res R1CSSolution + res.W = solver.values + res.A = solver.a + res.B = solver.b + res.C = solver.c + return &res, nil + } else { + // sparse R1CS + var res SparseR1CSSolution + // query l, r, o in Lagrange basis, not blinded + res.L, res.R, res.O = evaluateLROSmallDomain(cs, solver.values) + + return &res, nil + } + +} + +// IsSolved +// Deprecated: use _, err := Solve(...) instead +func (cs *system) IsSolved(witness witness.Witness, opts ...csolver.Option) error { + _, err := cs.Solve(witness, opts...) + return err +} + +// GetR1Cs return the list of R1C +func (cs *system) GetR1Cs() []constraint.R1C { + toReturn := make([]constraint.R1C, 0, cs.GetNbConstraints()) + + for _, inst := range cs.Instructions { + blueprint := cs.Blueprints[inst.BlueprintID] + if bc, ok := blueprint.(constraint.BlueprintR1C); ok { + var r1c constraint.R1C + bc.DecompressR1C(&r1c, cs.GetCallData(inst)) + toReturn = append(toReturn, r1c) + } else { + panic("not implemented") + } + } + return toReturn +} + +// GetNbCoefficients return the number of unique coefficients needed in the R1CS +func (cs *system) GetNbCoefficients() int { + return len(cs.Coefficients) +} + +// CurveID returns curve ID as defined in gnark-crypto +func (cs *system) CurveID() ecc.ID { + return ecc.BLS12_381 +} + +// WriteTo encodes R1CS into provided io.Writer using cbor +func (cs *system) WriteTo(w io.Writer) (int64, error) { + _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written + ts := getTagSet() + enc, err := cbor.CoreDetEncOptions().EncModeWithTags(ts) + if err != nil { + return 0, err + } + encoder := enc.NewEncoder(&_w) + + // encode our object + err = encoder.Encode(cs) + return _w.N, err +} + +// ReadFrom attempts to decode R1CS from io.Reader using cbor +func (cs *system) ReadFrom(r io.Reader) (int64, error) { + ts := getTagSet() + dm, err := cbor.DecOptions{ + MaxArrayElements: 134217728, + MaxMapPairs: 134217728, + }.DecModeWithTags(ts) + + if err != nil { + return 0, err + } + decoder := dm.NewDecoder(r) + + // initialize coeff table + cs.CoeffTable = newCoeffTable(0) + + if err := decoder.Decode(&cs); err != nil { + return int64(decoder.NumBytesRead()), err + } + + if err := cs.CheckSerializationHeader(); err != nil { + return int64(decoder.NumBytesRead()), err + } + + return int64(decoder.NumBytesRead()), nil +} + +func (cs *system) GetCoefficient(i int) (r constraint.Element) { + copy(r[:], cs.Coefficients[i][:]) + return +} + +// GetSparseR1Cs return the list of SparseR1C +func (cs *system) GetSparseR1Cs() []constraint.SparseR1C { + + toReturn := make([]constraint.SparseR1C, 0, cs.GetNbConstraints()) + + for _, inst := range cs.Instructions { + blueprint := cs.Blueprints[inst.BlueprintID] + if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { + var sparseR1C constraint.SparseR1C + calldata := cs.CallData[inst.StartCallData : inst.StartCallData+uint64(blueprint.NbInputs())] + bc.DecompressSparseR1C(&sparseR1C, calldata) + toReturn = append(toReturn, sparseR1C) + } else { + panic("not implemented") + } + } + return toReturn +} + +// evaluateLROSmallDomain extracts the solver l, r, o, and returns it in lagrange form. +// solver = [ public | secret | internal ] +// TODO @gbotrel refactor; this seems to be a small util function for plonk +func evaluateLROSmallDomain(cs *system, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { + + //s := int(pk.Domain[0].Cardinality) + s := cs.GetNbConstraints() + len(cs.Public) // len(spr.Public) is for the placeholder constraints + s = int(ecc.NextPowerOfTwo(uint64(s))) + + var l, r, o []fr.Element + l = make([]fr.Element, s) + r = make([]fr.Element, s) + o = make([]fr.Element, s) + s0 := solution[0] + + for i := 0; i < len(cs.Public); i++ { // placeholders + l[i] = solution[i] + r[i] = s0 + o[i] = s0 + } + offset := len(cs.Public) + nbConstraints := cs.GetNbConstraints() + + var sparseR1C constraint.SparseR1C + j := 0 + for _, inst := range cs.Instructions { + blueprint := cs.Blueprints[inst.BlueprintID] + if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { + bc.DecompressSparseR1C(&sparseR1C, cs.GetCallData(inst)) + + l[offset+j] = solution[sparseR1C.XA] + r[offset+j] = solution[sparseR1C.XB] + o[offset+j] = solution[sparseR1C.XC] + j++ + } + } + + offset += nbConstraints + + for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solver[0]) + l[offset+i] = s0 + r[offset+i] = s0 + o[offset+i] = s0 + } + + return l, r, o + +} + +// R1CSSolution represent a valid assignment to all the variables in the constraint system. +// The vector W such that Aw o Bw - Cw = 0 +type R1CSSolution struct { + W fr.Vector + A, B, C fr.Vector +} + +func (t *R1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.W.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.A.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.B.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.C.WriteTo(w) + n += a + return n, err +} + +func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.W.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.A.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.B.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.C.ReadFrom(r) + n += a + return n, err +} + +// SparseR1CSSolution represent a valid assignment to all the variables in the constraint system. +type SparseR1CSSolution struct { + L, R, O fr.Vector +} + +func (t *SparseR1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.L.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.R.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.O.WriteTo(w) + n += a + return n, err + +} + +func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.L.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.R.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.O.ReadFrom(r) + a += n + return n, err +} + +func getTagSet() cbor.TagSet { + // temporary for refactor + ts := cbor.NewTagSet() + // https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml + // 65536-15309735 Unassigned + tagNum := uint64(5309735) + addType := func(t reflect.Type) { + if err := ts.Add( + cbor.TagOptions{EncTag: cbor.EncTagRequired, DecTag: cbor.DecTagRequired}, + t, + tagNum, + ); err != nil { + panic(err) + } + tagNum++ + } + + addType(reflect.TypeOf(constraint.BlueprintGenericHint{})) + addType(reflect.TypeOf(constraint.BlueprintGenericR1C{})) + addType(reflect.TypeOf(constraint.BlueprintGenericSparseR1C{})) + addType(reflect.TypeOf(constraint.BlueprintSparseR1CAdd{})) + addType(reflect.TypeOf(constraint.BlueprintSparseR1CMul{})) + + return ts +} diff --git a/constraint/bls24-315/coeff.go b/constraint/bls24-315/coeff.go index d91528f93e..3f117c9b0f 100644 --- a/constraint/bls24-315/coeff.go +++ b/constraint/bls24-315/coeff.go @@ -46,7 +46,7 @@ func newCoeffTable(capacity int) CoeffTable { } -func (ct *CoeffTable) MakeTerm(coeff *constraint.Coeff, variableID int) constraint.Term { +func (ct *CoeffTable) AddCoeff(coeff constraint.Element) uint32 { c := (*fr.Element)(coeff[:]) var cID uint32 if c.IsZero() { @@ -69,7 +69,11 @@ func (ct *CoeffTable) MakeTerm(coeff *constraint.Coeff, variableID int) constrai ct.mCoeffs[cc] = cID } } + return cID +} +func (ct *CoeffTable) MakeTerm(coeff *constraint.Element, variableID int) constraint.Term { + cID := ct.AddCoeff(*coeff) return constraint.Term{VID: uint32(variableID), CID: cID} } @@ -78,7 +82,10 @@ func (ct *CoeffTable) CoeffToString(cID int) string { return ct.Coefficients[cID].String() } -var _ constraint.CoeffEngine = &arithEngine{} +// implements constraint.Field +type field struct{} + +var _ constraint.Field = &field{} var ( two fr.Element @@ -94,10 +101,7 @@ func init() { minusTwo.Neg(&two) } -// implements constraint.CoeffEngine -type arithEngine struct{} - -func (engine *arithEngine) FromInterface(i interface{}) constraint.Coeff { +func (engine *field) FromInterface(i interface{}) constraint.Element { var e fr.Element if _, err := e.SetInterface(i); err != nil { // need to clean that --> some code path are dissimilar @@ -106,55 +110,75 @@ func (engine *arithEngine) FromInterface(i interface{}) constraint.Coeff { b := utils.FromInterface(i) e.SetBigInt(&b) } - var r constraint.Coeff + var r constraint.Element copy(r[:], e[:]) return r } -func (engine *arithEngine) ToBigInt(c *constraint.Coeff) *big.Int { +func (engine *field) ToBigInt(c constraint.Element) *big.Int { e := (*fr.Element)(c[:]) r := new(big.Int) e.BigInt(r) return r } -func (engine *arithEngine) Mul(a, b *constraint.Coeff) { +func (engine *field) Mul(a, b constraint.Element) constraint.Element { _a := (*fr.Element)(a[:]) _b := (*fr.Element)(b[:]) _a.Mul(_a, _b) + return a } -func (engine *arithEngine) Add(a, b *constraint.Coeff) { + +func (engine *field) Add(a, b constraint.Element) constraint.Element { _a := (*fr.Element)(a[:]) _b := (*fr.Element)(b[:]) _a.Add(_a, _b) + return a } -func (engine *arithEngine) Sub(a, b *constraint.Coeff) { +func (engine *field) Sub(a, b constraint.Element) constraint.Element { _a := (*fr.Element)(a[:]) _b := (*fr.Element)(b[:]) _a.Sub(_a, _b) + return a } -func (engine *arithEngine) Neg(a *constraint.Coeff) { +func (engine *field) Neg(a constraint.Element) constraint.Element { e := (*fr.Element)(a[:]) e.Neg(e) + return a } -func (engine *arithEngine) Inverse(a *constraint.Coeff) { +func (engine *field) Inverse(a constraint.Element) (constraint.Element, bool) { + if a.IsZero() { + return a, false + } e := (*fr.Element)(a[:]) + if e.IsZero() { + return a, false + } else if e.IsOne() { + return a, true + } + var t fr.Element + t.Neg(e) + if t.IsOne() { + return a, true + } + e.Inverse(e) + return a, true } -func (engine *arithEngine) IsOne(a *constraint.Coeff) bool { +func (engine *field) IsOne(a constraint.Element) bool { e := (*fr.Element)(a[:]) return e.IsOne() } -func (engine *arithEngine) One() constraint.Coeff { +func (engine *field) One() constraint.Element { e := fr.One() - var r constraint.Coeff + var r constraint.Element copy(r[:], e[:]) return r } -func (engine *arithEngine) String(a *constraint.Coeff) string { +func (engine *field) String(a constraint.Element) string { e := (*fr.Element)(a[:]) return e.String() } diff --git a/constraint/bls24-315/r1cs.go b/constraint/bls24-315/r1cs.go deleted file mode 100644 index 3c42462419..0000000000 --- a/constraint/bls24-315/r1cs.go +++ /dev/null @@ -1,467 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// 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. - -// Code generated by gnark DO NOT EDIT - -package cs - -import ( - "errors" - "fmt" - "github.com/fxamacker/cbor/v2" - "io" - "runtime" - "sync" - "time" - - "github.com/consensys/gnark/backend/witness" - "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/internal/backend/ioutils" - "github.com/consensys/gnark/logger" - "github.com/consensys/gnark/profile" - - "github.com/consensys/gnark-crypto/ecc" - "math" - - "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" -) - -// R1CS describes a set of R1CS constraint -type R1CS struct { - constraint.R1CSCore - CoeffTable - arithEngine -} - -// NewR1CS returns a new R1CS and sets cs.Coefficient (fr.Element) from provided big.Int values -// -// capacity pre-allocates memory for capacity nbConstraints -func NewR1CS(capacity int) *R1CS { - r := R1CS{ - R1CSCore: constraint.R1CSCore{ - System: constraint.NewSystem(fr.Modulus()), - Constraints: make([]constraint.R1C, 0, capacity), - }, - CoeffTable: newCoeffTable(capacity / 10), - } - return &r -} - -func (cs *R1CS) AddConstraint(r1c constraint.R1C, debugInfo ...constraint.DebugInfo) int { - profile.RecordConstraint() - cs.Constraints = append(cs.Constraints, r1c) - cID := len(cs.Constraints) - 1 - if len(debugInfo) == 1 { - cs.DebugInfo = append(cs.DebugInfo, constraint.LogEntry(debugInfo[0])) - cs.MDebug[cID] = len(cs.DebugInfo) - 1 - } - - cs.UpdateLevel(cID, &r1c) - - return cID -} - -// Solve returns the vector w solution to the system, that is -// Aw o Bw - Cw = 0 -func (cs *R1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { - opt, err := solver.NewConfig(opts...) - if err != nil { - return nil, err - } - - var res R1CSSolution - - s := ecc.NextPowerOfTwo(uint64(len(cs.Constraints))) - res.A = make(fr.Vector, len(cs.Constraints), s) - res.B = make(fr.Vector, len(cs.Constraints), s) - res.C = make(fr.Vector, len(cs.Constraints), s) - - v := witness.Vector().(fr.Vector) - - res.W, err = cs.solve(v, res.A, res.B, res.C, opt) - if err != nil { - return nil, err - } - - return &res, nil -} - -// Solve sets all the wires and returns the a, b, c vectors. -// the cs system should have been compiled before. The entries in a, b, c are in Montgomery form. -// a, b, c vectors: ab-c = hz -// witness = [publicWires | secretWires] (without the ONE_WIRE !) -// returns [publicWires | secretWires | internalWires ] -func (cs *R1CS) solve(witness, a, b, c fr.Vector, opt solver.Config) (fr.Vector, error) { - log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() - - nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - solution, err := newSolution(&cs.System, nbWires, opt.HintFunctions, cs.Coefficients) - if err != nil { - return make(fr.Vector, nbWires), err - } - start := time.Now() - - if len(witness) != len(cs.Public)-1+len(cs.Secret) { // - 1 for ONE_WIRE - err = fmt.Errorf("invalid witness size, got %d, expected %d = %d (public) + %d (secret)", len(witness), int(len(cs.Public)-1+len(cs.Secret)), len(cs.Public)-1, len(cs.Secret)) - log.Err(err).Send() - return solution.values, err - } - - // compute the wires and the a, b, c polynomials - if len(a) != len(cs.Constraints) || len(b) != len(cs.Constraints) || len(c) != len(cs.Constraints) { - err = errors.New("invalid input size: len(a, b, c) == len(Constraints)") - log.Err(err).Send() - return solution.values, err - } - - solution.solved[0] = true // ONE_WIRE - solution.values[0].SetOne() - copy(solution.values[1:], witness) - for i := range witness { - solution.solved[i+1] = true - } - - // keep track of the number of wire instantiations we do, for a sanity check to ensure - // we instantiated all wires - solution.nbSolved += uint64(len(witness) + 1) - - // now that we know all inputs are set, defer log printing once all solution.values are computed - // (or sooner, if a constraint is not satisfied) - defer solution.printLogs(opt.Logger, cs.Logs) - - if err := cs.parallelSolve(a, b, c, &solution); err != nil { - if unsatisfiedErr, ok := err.(*UnsatisfiedConstraintError); ok { - log.Err(errors.New("unsatisfied constraint")).Int("id", unsatisfiedErr.CID).Send() - } else { - log.Err(err).Send() - } - return solution.values, err - } - - // sanity check; ensure all wires are marked as "instantiated" - if !solution.isValid() { - log.Err(errors.New("solver didn't instantiate all wires")).Send() - panic("solver didn't instantiate all wires") - } - - log.Debug().Dur("took", time.Since(start)).Msg("constraint system solver done") - - return solution.values, nil -} - -func (cs *R1CS) parallelSolve(a, b, c fr.Vector, solution *solution) error { - // minWorkPerCPU is the minimum target number of constraint a task should hold - // in other words, if a level has less than minWorkPerCPU, it will not be parallelized and executed - // sequentially without sync. - const minWorkPerCPU = 50.0 - - // cs.Levels has a list of levels, where all constraints in a level l(n) are independent - // and may only have dependencies on previous levels - // for each constraint - // we are guaranteed that each R1C contains at most one unsolved wire - // first we solve the unsolved wire (if any) - // then we check that the constraint is valid - // if a[i] * b[i] != c[i]; it means the constraint is not satisfied - - var wg sync.WaitGroup - chTasks := make(chan []int, runtime.NumCPU()) - chError := make(chan *UnsatisfiedConstraintError, runtime.NumCPU()) - - // start a worker pool - // each worker wait on chTasks - // a task is a slice of constraint indexes to be solved - for i := 0; i < runtime.NumCPU(); i++ { - go func() { - for t := range chTasks { - for _, i := range t { - // for each constraint in the task, solve it. - if err := cs.solveConstraint(cs.Constraints[i], solution, &a[i], &b[i], &c[i]); err != nil { - var debugInfo *string - if dID, ok := cs.MDebug[i]; ok { - debugInfo = new(string) - *debugInfo = solution.logValue(cs.DebugInfo[dID]) - } - chError <- &UnsatisfiedConstraintError{CID: i, Err: err, DebugInfo: debugInfo} - wg.Done() - return - } - } - wg.Done() - } - }() - } - - // clean up pool go routines - defer func() { - close(chTasks) - close(chError) - }() - - // for each level, we push the tasks - for _, level := range cs.Levels { - - // max CPU to use - maxCPU := float64(len(level)) / minWorkPerCPU - - if maxCPU <= 1.0 { - // we do it sequentially - for _, i := range level { - if err := cs.solveConstraint(cs.Constraints[i], solution, &a[i], &b[i], &c[i]); err != nil { - var debugInfo *string - if dID, ok := cs.MDebug[i]; ok { - debugInfo = new(string) - *debugInfo = solution.logValue(cs.DebugInfo[dID]) - } - return &UnsatisfiedConstraintError{CID: i, Err: err, DebugInfo: debugInfo} - } - } - continue - } - - // number of tasks for this level is set to number of CPU - // but if we don't have enough work for all our CPU, it can be lower. - nbTasks := runtime.NumCPU() - maxTasks := int(math.Ceil(maxCPU)) - if nbTasks > maxTasks { - nbTasks = maxTasks - } - nbIterationsPerCpus := len(level) / nbTasks - - // more CPUs than tasks: a CPU will work on exactly one iteration - // note: this depends on minWorkPerCPU constant - if nbIterationsPerCpus < 1 { - nbIterationsPerCpus = 1 - nbTasks = len(level) - } - - extraTasks := len(level) - (nbTasks * nbIterationsPerCpus) - extraTasksOffset := 0 - - for i := 0; i < nbTasks; i++ { - wg.Add(1) - _start := i*nbIterationsPerCpus + extraTasksOffset - _end := _start + nbIterationsPerCpus - if extraTasks > 0 { - _end++ - extraTasks-- - extraTasksOffset++ - } - // since we're never pushing more than num CPU tasks - // we will never be blocked here - chTasks <- level[_start:_end] - } - - // wait for the level to be done - wg.Wait() - - if len(chError) > 0 { - return <-chError - } - } - - return nil -} - -// IsSolved -// Deprecated: use _, err := Solve(...) instead -func (cs *R1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { - _, err := cs.Solve(witness, opts...) - return err -} - -// divByCoeff sets res = res / t.Coeff -func (cs *R1CS) divByCoeff(res *fr.Element, t constraint.Term) { - cID := t.CoeffID() - switch cID { - case constraint.CoeffIdOne: - return - case constraint.CoeffIdMinusOne: - res.Neg(res) - case constraint.CoeffIdZero: - panic("division by 0") - default: - // this is slow, but shouldn't happen as divByCoeff is called to - // remove the coeff of an unsolved wire - // but unsolved wires are (in gnark frontend) systematically set with a coeff == 1 or -1 - res.Div(res, &cs.Coefficients[cID]) - } -} - -// solveConstraint compute unsolved wires in the constraint, if any and set the solution accordingly -// -// returns an error if the solver called a hint function that errored -// returns false, nil if there was no wire to solve -// returns true, nil if exactly one wire was solved. In that case, it is redundant to check that -// the constraint is satisfied later. -func (cs *R1CS) solveConstraint(r constraint.R1C, solution *solution, a, b, c *fr.Element) error { - - // the index of the non-zero entry shows if L, R or O has an uninstantiated wire - // the content is the ID of the wire non instantiated - var loc uint8 - - var termToCompute constraint.Term - - processLExp := func(l constraint.LinearExpression, val *fr.Element, locValue uint8) error { - for _, t := range l { - vID := t.WireID() - - // wire is already computed, we just accumulate in val - if solution.solved[vID] { - solution.accumulateInto(t, val) - continue - } - - // first we check if this is a hint wire - if hint, ok := cs.MHints[vID]; ok { - if err := solution.solveWithHint(vID, hint); err != nil { - return err - } - // now that the wire is saved, accumulate it into a, b or c - solution.accumulateInto(t, val) - continue - } - - if loc != 0 { - panic("found more than one wire to instantiate") - } - termToCompute = t - loc = locValue - } - return nil - } - - if err := processLExp(r.L, a, 1); err != nil { - return err - } - - if err := processLExp(r.R, b, 2); err != nil { - return err - } - - if err := processLExp(r.O, c, 3); err != nil { - return err - } - - if loc == 0 { - // there is nothing to solve, may happen if we have an assertion - // (ie a constraints that doesn't yield any output) - // or if we solved the unsolved wires with hint functions - var check fr.Element - if !check.Mul(a, b).Equal(c) { - return fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String()) - } - return nil - } - - // we compute the wire value and instantiate it - wID := termToCompute.WireID() - - // solver result - var wire fr.Element - - switch loc { - case 1: - if !b.IsZero() { - wire.Div(c, b). - Sub(&wire, a) - a.Add(a, &wire) - } else { - // we didn't actually ensure that a * b == c - var check fr.Element - if !check.Mul(a, b).Equal(c) { - return fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String()) - } - } - case 2: - if !a.IsZero() { - wire.Div(c, a). - Sub(&wire, b) - b.Add(b, &wire) - } else { - var check fr.Element - if !check.Mul(a, b).Equal(c) { - return fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String()) - } - } - case 3: - wire.Mul(a, b). - Sub(&wire, c) - - c.Add(c, &wire) - } - - // wire is the term (coeff * value) - // but in the solution we want to store the value only - // note that in gnark frontend, coeff here is always 1 or -1 - cs.divByCoeff(&wire, termToCompute) - solution.set(wID, wire) - - return nil -} - -// GetConstraints return the list of R1C and a coefficient resolver -func (cs *R1CS) GetConstraints() ([]constraint.R1C, constraint.Resolver) { - return cs.Constraints, cs -} - -// GetNbCoefficients return the number of unique coefficients needed in the R1CS -func (cs *R1CS) GetNbCoefficients() int { - return len(cs.Coefficients) -} - -// CurveID returns curve ID as defined in gnark-crypto -func (cs *R1CS) CurveID() ecc.ID { - return ecc.BLS24_315 -} - -// WriteTo encodes R1CS into provided io.Writer using cbor -func (cs *R1CS) WriteTo(w io.Writer) (int64, error) { - _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written - enc, err := cbor.CoreDetEncOptions().EncMode() - if err != nil { - return 0, err - } - encoder := enc.NewEncoder(&_w) - - // encode our object - err = encoder.Encode(cs) - return _w.N, err -} - -// ReadFrom attempts to decode R1CS from io.Reader using cbor -func (cs *R1CS) ReadFrom(r io.Reader) (int64, error) { - dm, err := cbor.DecOptions{ - MaxArrayElements: 134217728, - MaxMapPairs: 134217728, - }.DecMode() - - if err != nil { - return 0, err - } - decoder := dm.NewDecoder(r) - - // initialize coeff table - cs.CoeffTable = newCoeffTable(0) - - if err := decoder.Decode(&cs); err != nil { - return int64(decoder.NumBytesRead()), err - } - - if err := cs.CheckSerializationHeader(); err != nil { - return int64(decoder.NumBytesRead()), err - } - - return int64(decoder.NumBytesRead()), nil -} diff --git a/constraint/bls24-315/r1cs_sparse.go b/constraint/bls24-315/r1cs_sparse.go deleted file mode 100644 index 72f9533ad1..0000000000 --- a/constraint/bls24-315/r1cs_sparse.go +++ /dev/null @@ -1,533 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// 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. - -// Code generated by gnark DO NOT EDIT - -package cs - -import ( - "errors" - "fmt" - "github.com/consensys/gnark-crypto/ecc" - "github.com/fxamacker/cbor/v2" - "io" - "math" - "runtime" - "sync" - "time" - - "github.com/consensys/gnark/backend/witness" - "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/internal/backend/ioutils" - "github.com/consensys/gnark/logger" - "github.com/consensys/gnark/profile" - - "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" -) - -// SparseR1CS represents a Plonk like circuit -type SparseR1CS struct { - constraint.SparseR1CSCore - CoeffTable - arithEngine -} - -// NewSparseR1CS returns a new SparseR1CS and sets r1cs.Coefficient (fr.Element) from provided big.Int values -func NewSparseR1CS(capacity int) *SparseR1CS { - cs := SparseR1CS{ - SparseR1CSCore: constraint.SparseR1CSCore{ - System: constraint.NewSystem(fr.Modulus()), - Constraints: make([]constraint.SparseR1C, 0, capacity), - }, - CoeffTable: newCoeffTable(capacity / 10), - } - - return &cs -} - -func (cs *SparseR1CS) AddConstraint(c constraint.SparseR1C, debugInfo ...constraint.DebugInfo) int { - profile.RecordConstraint() - cs.Constraints = append(cs.Constraints, c) - cID := len(cs.Constraints) - 1 - if len(debugInfo) == 1 { - cs.DebugInfo = append(cs.DebugInfo, constraint.LogEntry(debugInfo[0])) - cs.MDebug[cID] = len(cs.DebugInfo) - 1 - } - cs.UpdateLevel(cID, &c) - - return cID -} - -func (c *SparseR1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { - opt, err := solver.NewConfig(opts...) - if err != nil { - return nil, err - } - - // compute the constraint system solution - var solution []fr.Element - if solution, err = c.solve(witness.Vector().(fr.Vector), opt); err != nil { - return nil, err - } - - var res SparseR1CSSolution - // query l, r, o in Lagrange basis, not blinded - res.L, res.R, res.O = c.evaluateLROSmallDomain(solution) - - return &res, nil -} - -// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. -// solution = [ public | secret | internal ] -func (c *SparseR1CS) evaluateLROSmallDomain(solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { - - //s := int(pk.Domain[0].Cardinality) - s := c.GetNbConstraints() + len(c.Public) // len(spr.Public) is for the placeholder constraints - s = int(ecc.NextPowerOfTwo(uint64(s))) - - var l, r, o []fr.Element - l = make([]fr.Element, s) - r = make([]fr.Element, s) - o = make([]fr.Element, s) - s0 := solution[0] - - for i := 0; i < len(c.Public); i++ { // placeholders - l[i] = solution[i] - r[i] = s0 - o[i] = s0 - } - offset := len(c.Public) - for i := 0; i < len(c.Constraints); i++ { // constraints - l[offset+i] = solution[c.Constraints[i].L.WireID()] - r[offset+i] = solution[c.Constraints[i].R.WireID()] - o[offset+i] = solution[c.Constraints[i].O.WireID()] - } - offset += len(c.Constraints) - - for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) - l[offset+i] = s0 - r[offset+i] = s0 - o[offset+i] = s0 - } - - return l, r, o - -} - -// Solve sets all the wires. -// solution.values = [publicInputs | secretInputs | internalVariables ] -// witness: contains the input variables -// it returns the full slice of wires -func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, error) { - log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "plonk").Logger() - - // set the slices holding the solution.values and monitoring which variables have been solved - nbVariables := cs.NbInternalVariables + len(cs.Secret) + len(cs.Public) - - start := time.Now() - - expectedWitnessSize := len(cs.Public) + len(cs.Secret) - if len(witness) != expectedWitnessSize { - return make(fr.Vector, nbVariables), fmt.Errorf( - "invalid witness size, got %d, expected %d = %d (public) + %d (secret)", - len(witness), - expectedWitnessSize, - len(cs.Public), - len(cs.Secret), - ) - } - - // keep track of wire that have a value - solution, err := newSolution(&cs.System, nbVariables, opt.HintFunctions, cs.Coefficients) - if err != nil { - return solution.values, err - } - - // solution.values = [publicInputs | secretInputs | internalVariables ] -> we fill publicInputs | secretInputs - copy(solution.values, witness) - for i := 0; i < len(witness); i++ { - solution.solved[i] = true - } - - // keep track of the number of wire instantiations we do, for a sanity check to ensure - // we instantiated all wires - solution.nbSolved += uint64(len(witness)) - - // defer log printing once all solution.values are computed - defer solution.printLogs(opt.Logger, cs.Logs) - - // batch invert the coefficients to avoid many divisions in the solver - coefficientsNegInv := fr.BatchInvert(cs.Coefficients) - for i := 0; i < len(coefficientsNegInv); i++ { - coefficientsNegInv[i].Neg(&coefficientsNegInv[i]) - } - - if err := cs.parallelSolve(&solution, coefficientsNegInv); err != nil { - if unsatisfiedErr, ok := err.(*UnsatisfiedConstraintError); ok { - log.Err(errors.New("unsatisfied constraint")).Int("id", unsatisfiedErr.CID).Send() - } else { - log.Err(err).Send() - } - return solution.values, err - } - - // sanity check; ensure all wires are marked as "instantiated" - if !solution.isValid() { - log.Err(errors.New("solver didn't instantiate all wires")).Send() - panic("solver didn't instantiate all wires") - } - - log.Debug().Dur("took", time.Since(start)).Msg("constraint system solver done") - - return solution.values, nil - -} - -func (cs *SparseR1CS) parallelSolve(solution *solution, coefficientsNegInv fr.Vector) error { - // minWorkPerCPU is the minimum target number of constraint a task should hold - // in other words, if a level has less than minWorkPerCPU, it will not be parallelized and executed - // sequentially without sync. - const minWorkPerCPU = 50.0 - - // cs.Levels has a list of levels, where all constraints in a level l(n) are independent - // and may only have dependencies on previous levels - - var wg sync.WaitGroup - chTasks := make(chan []int, runtime.NumCPU()) - chError := make(chan *UnsatisfiedConstraintError, runtime.NumCPU()) - - // start a worker pool - // each worker wait on chTasks - // a task is a slice of constraint indexes to be solved - for i := 0; i < runtime.NumCPU(); i++ { - go func() { - for t := range chTasks { - for _, i := range t { - // for each constraint in the task, solve it. - if err := cs.solveConstraint(cs.Constraints[i], solution, coefficientsNegInv); err != nil { - chError <- &UnsatisfiedConstraintError{CID: i, Err: err} - wg.Done() - return - } - if err := cs.checkConstraint(cs.Constraints[i], solution); err != nil { - if dID, ok := cs.MDebug[i]; ok { - errMsg := solution.logValue(cs.DebugInfo[dID]) - chError <- &UnsatisfiedConstraintError{CID: i, DebugInfo: &errMsg} - } else { - chError <- &UnsatisfiedConstraintError{CID: i, Err: err} - } - wg.Done() - return - } - } - wg.Done() - } - }() - } - - // clean up pool go routines - defer func() { - close(chTasks) - close(chError) - }() - - // for each level, we push the tasks - for _, level := range cs.Levels { - - // max CPU to use - maxCPU := float64(len(level)) / minWorkPerCPU - - if maxCPU <= 1.0 { - // we do it sequentially - for _, i := range level { - if err := cs.solveConstraint(cs.Constraints[i], solution, coefficientsNegInv); err != nil { - return &UnsatisfiedConstraintError{CID: i, Err: err} - } - if err := cs.checkConstraint(cs.Constraints[i], solution); err != nil { - if dID, ok := cs.MDebug[i]; ok { - errMsg := solution.logValue(cs.DebugInfo[dID]) - return &UnsatisfiedConstraintError{CID: i, DebugInfo: &errMsg} - } - return &UnsatisfiedConstraintError{CID: i, Err: err} - } - } - continue - } - - // number of tasks for this level is set to number of CPU - // but if we don't have enough work for all our CPU, it can be lower. - nbTasks := runtime.NumCPU() - maxTasks := int(math.Ceil(maxCPU)) - if nbTasks > maxTasks { - nbTasks = maxTasks - } - nbIterationsPerCpus := len(level) / nbTasks - - // more CPUs than tasks: a CPU will work on exactly one iteration - // note: this depends on minWorkPerCPU constant - if nbIterationsPerCpus < 1 { - nbIterationsPerCpus = 1 - nbTasks = len(level) - } - - extraTasks := len(level) - (nbTasks * nbIterationsPerCpus) - extraTasksOffset := 0 - - for i := 0; i < nbTasks; i++ { - wg.Add(1) - _start := i*nbIterationsPerCpus + extraTasksOffset - _end := _start + nbIterationsPerCpus - if extraTasks > 0 { - _end++ - extraTasks-- - extraTasksOffset++ - } - // since we're never pushing more than num CPU tasks - // we will never be blocked here - chTasks <- level[_start:_end] - } - - // wait for the level to be done - wg.Wait() - - if len(chError) > 0 { - return <-chError - } - } - - return nil -} - -// computeHints computes wires associated with a hint function, if any -// if there is no remaining wire to solve, returns -1 -// else returns the wire position (L -> 0, R -> 1, O -> 2) -func (cs *SparseR1CS) computeHints(c constraint.SparseR1C, solution *solution) (int, error) { - r := -1 - lID, rID, oID := c.L.WireID(), c.R.WireID(), c.O.WireID() - - if (c.L.CoeffID() != 0 || c.M[0].CoeffID() != 0) && !solution.solved[lID] { - // check if it's a hint - if hint, ok := cs.MHints[lID]; ok { - if err := solution.solveWithHint(lID, hint); err != nil { - return -1, err - } - } else { - r = 0 - } - - } - - if (c.R.CoeffID() != 0 || c.M[1].CoeffID() != 0) && !solution.solved[rID] { - // check if it's a hint - if hint, ok := cs.MHints[rID]; ok { - if err := solution.solveWithHint(rID, hint); err != nil { - return -1, err - } - } else { - r = 1 - } - } - - if (c.O.CoeffID() != 0) && !solution.solved[oID] { - // check if it's a hint - if hint, ok := cs.MHints[oID]; ok { - if err := solution.solveWithHint(oID, hint); err != nil { - return -1, err - } - } else { - r = 2 - } - } - return r, nil -} - -// solveConstraint solve any unsolved wire in given constraint and update the solution -// a SparseR1C may have up to one unsolved wire (excluding hints) -// if it doesn't, then this function returns and does nothing -func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution, coefficientsNegInv fr.Vector) error { - - if c.Commitment == constraint.COMMITTED { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. - return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time - } - - lro, err := cs.computeHints(c, solution) - if err != nil { - return err - } - if lro == -1 { - // no unsolved wire - // can happen if the constraint contained only hint wires. - return nil - } - if lro == 1 { // we solve for R: u1L+u2R+u3LR+u4O+k=0 => R(u2+u3L)+u1L+u4O+k = 0 - if !solution.solved[c.L.WireID()] { - panic("L wire should be instantiated when we solve R") - } - var u1, u2, u3, den, num, v1, v2 fr.Element - u3.Mul(&cs.Coefficients[c.M[0].CoeffID()], &cs.Coefficients[c.M[1].CoeffID()]) - u1.Set(&cs.Coefficients[c.L.CoeffID()]) - u2.Set(&cs.Coefficients[c.R.CoeffID()]) - den.Mul(&u3, &solution.values[c.L.WireID()]).Add(&den, &u2) - - v1 = solution.computeTerm(c.L) - v2 = solution.computeTerm(c.O) - num.Add(&v1, &v2).Add(&num, &cs.Coefficients[c.K]) - - // TODO find a way to do lazy div (/ batch inversion) - num.Div(&num, &den).Neg(&num) - solution.set(c.L.WireID(), num) - return nil - } - - if lro == 0 { // we solve for L: u1L+u2R+u3LR+u4O+k=0 => L(u1+u3R)+u2R+u4O+k = 0 - if !solution.solved[c.R.WireID()] { - panic("R wire should be instantiated when we solve L") - } - var u1, u2, u3, den, num, v1, v2 fr.Element - u3.Mul(&cs.Coefficients[c.M[0].CoeffID()], &cs.Coefficients[c.M[1].CoeffID()]) - u1.Set(&cs.Coefficients[c.L.CoeffID()]) - u2.Set(&cs.Coefficients[c.R.CoeffID()]) - den.Mul(&u3, &solution.values[c.R.WireID()]).Add(&den, &u1) - - v1 = solution.computeTerm(c.R) - v2 = solution.computeTerm(c.O) - num.Add(&v1, &v2).Add(&num, &cs.Coefficients[c.K]) - - // TODO find a way to do lazy div (/ batch inversion) - num.Div(&num, &den).Neg(&num) - solution.set(c.L.WireID(), num) - return nil - - } - // O we solve for O - var o fr.Element - cID, vID := c.O.CoeffID(), c.O.WireID() - - l := solution.computeTerm(c.L) - r := solution.computeTerm(c.R) - m0 := solution.computeTerm(c.M[0]) - m1 := solution.computeTerm(c.M[1]) - - // o = - ((m0 * m1) + l + r + c.K) / c.O - o.Mul(&m0, &m1).Add(&o, &l).Add(&o, &r).Add(&o, &cs.Coefficients[c.K]) - o.Mul(&o, &coefficientsNegInv[cID]) - - solution.set(vID, o) - - return nil -} - -// IsSolved -// Deprecated: use _, err := Solve(...) instead -func (cs *SparseR1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { - _, err := cs.Solve(witness, opts...) - return err -} - -// GetConstraints return the list of SparseR1C and a coefficient resolver -func (cs *SparseR1CS) GetConstraints() ([]constraint.SparseR1C, constraint.Resolver) { - return cs.Constraints, cs -} - -func (cs *SparseR1CS) GetConstraint(i int) *constraint.SparseR1C { - if i < 0 || i >= len(cs.Constraints) { - return nil - } - return &cs.Constraints[i] -} - -func (cs *SparseR1CS) GetCoefficient(i int) (r constraint.Coeff) { - copy(r[:], cs.Coefficients[i][:]) - return -} - -// checkConstraint verifies that the constraint holds -func (cs *SparseR1CS) checkConstraint(c constraint.SparseR1C, solution *solution) error { - - if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. - return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time - } - - l := solution.computeTerm(c.L) - r := solution.computeTerm(c.R) - m0 := solution.computeTerm(c.M[0]) - m1 := solution.computeTerm(c.M[1]) - o := solution.computeTerm(c.O) - - // l + r + (m0 * m1) + o + c.K == 0 - var t fr.Element - t.Mul(&m0, &m1).Add(&t, &l).Add(&t, &r).Add(&t, &o).Add(&t, &cs.Coefficients[c.K]) - if !t.IsZero() { - return fmt.Errorf("qL⋅xa + qR⋅xb + qO⋅xc + qM⋅(xaxb) + qC != 0 → %s + %s + %s + (%s × %s) + %s != 0", - l.String(), - r.String(), - o.String(), - m0.String(), - m1.String(), - cs.Coefficients[c.K].String(), - ) - } - return nil - -} - -// GetNbCoefficients return the number of unique coefficients needed in the R1CS -func (cs *SparseR1CS) GetNbCoefficients() int { - return len(cs.Coefficients) -} - -// CurveID returns curve ID as defined in gnark-crypto (ecc.BLS24-315) -func (cs *SparseR1CS) CurveID() ecc.ID { - return ecc.BLS24_315 -} - -// WriteTo encodes SparseR1CS into provided io.Writer using cbor -func (cs *SparseR1CS) WriteTo(w io.Writer) (int64, error) { - _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written - enc, err := cbor.CoreDetEncOptions().EncMode() - if err != nil { - return 0, err - } - encoder := enc.NewEncoder(&_w) - - // encode our object - err = encoder.Encode(cs) - return _w.N, err -} - -// ReadFrom attempts to decode SparseR1CS from io.Reader using cbor -func (cs *SparseR1CS) ReadFrom(r io.Reader) (int64, error) { - dm, err := cbor.DecOptions{ - MaxArrayElements: 134217728, - MaxMapPairs: 134217728, - }.DecMode() - if err != nil { - return 0, err - } - decoder := dm.NewDecoder(r) - - // initialize coeff table - cs.CoeffTable = newCoeffTable(0) - - if err := decoder.Decode(cs); err != nil { - return int64(decoder.NumBytesRead()), err - } - - if err := cs.CheckSerializationHeader(); err != nil { - return int64(decoder.NumBytesRead()), err - } - - return int64(decoder.NumBytesRead()), nil -} diff --git a/constraint/bls24-315/r1cs_test.go b/constraint/bls24-315/r1cs_test.go index a5cf07e4a3..a1baa6474c 100644 --- a/constraint/bls24-315/r1cs_test.go +++ b/constraint/bls24-315/r1cs_test.go @@ -20,6 +20,7 @@ import ( "bytes" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/frontend/cs/scs" "github.com/consensys/gnark/internal/backend/circuits" "reflect" "testing" @@ -76,10 +77,11 @@ func TestSerialization(t *testing.T) { if diff := cmp.Diff(r1cs1, &reconstructed, cmpopts.IgnoreFields(cs.R1CS{}, "System.q", - "arithEngine", + "field", "CoeffTable.mCoeffs", "System.lbWireLevel", "System.lbHints", + "System.genericHint", "System.SymbolTable", "System.lbOutputs", "System.bitLen")); diff != "" { @@ -147,12 +149,6 @@ func (circuit *circuit) Define(api frontend.API) error { func BenchmarkSolve(b *testing.B) { - var c circuit - ccs, err := frontend.Compile(fr.Modulus(), r1cs.NewBuilder, &c) - if err != nil { - b.Fatal(err) - } - var w circuit w.X = 1 w.Y = 1 @@ -161,8 +157,32 @@ func BenchmarkSolve(b *testing.B) { b.Fatal(err) } - b.ResetTimer() - for i := 0; i < b.N; i++ { - _ = ccs.IsSolved(witness) - } + b.Run("scs", func(b *testing.B) { + var c circuit + ccs, err := frontend.Compile(fr.Modulus(), scs.NewBuilder, &c) + if err != nil { + b.Fatal(err) + } + b.Log("scs nbConstraints", ccs.GetNbConstraints()) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = ccs.IsSolved(witness) + } + }) + + b.Run("r1cs", func(b *testing.B) { + var c circuit + ccs, err := frontend.Compile(fr.Modulus(), r1cs.NewBuilder, &c, frontend.WithCompressThreshold(10)) + if err != nil { + b.Fatal(err) + } + b.Log("r1cs nbConstraints", ccs.GetNbConstraints()) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = ccs.IsSolved(witness) + } + }) + } diff --git a/constraint/bls24-315/solution.go b/constraint/bls24-315/solution.go deleted file mode 100644 index cacdc58211..0000000000 --- a/constraint/bls24-315/solution.go +++ /dev/null @@ -1,383 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// 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. - -// Code generated by gnark DO NOT EDIT - -package cs - -import ( - "errors" - "fmt" - "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/debug" - "github.com/rs/zerolog" - "io" - "math/big" - "strconv" - "strings" - "sync/atomic" - - "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" -) - -// solution represents elements needed to compute -// a solution to a R1CS or SparseR1CS -type solution struct { - values, coefficients []fr.Element - solved []bool - nbSolved uint64 - mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function - st *debug.SymbolTable - cs *constraint.System -} - -func newSolution(cs *constraint.System, nbWires int, hintFunctions map[solver.HintID]solver.Hint, coefficients []fr.Element) (solution, error) { - - s := solution{ - cs: cs, - st: &cs.SymbolTable, - values: make([]fr.Element, nbWires), - coefficients: coefficients, - solved: make([]bool, nbWires), - mHintsFunctions: hintFunctions, - } - - // hintsDependencies is from compile time; it contains the list of hints the solver **needs** - var missing []string - for hintUUID, hintID := range cs.MHintsDependencies { - if _, ok := s.mHintsFunctions[hintUUID]; !ok { - missing = append(missing, hintID) - } - } - - if len(missing) > 0 { - return s, fmt.Errorf("solver missing hint(s): %v", missing) - } - - return s, nil -} - -func (s *solution) set(id int, value fr.Element) { - if s.solved[id] { - panic("solving the same wire twice should never happen.") - } - s.values[id] = value - s.solved[id] = true - atomic.AddUint64(&s.nbSolved, 1) - // s.nbSolved++ -} - -func (s *solution) isValid() bool { - return int(s.nbSolved) == len(s.values) -} - -// computeTerm computes coeff*variable -func (s *solution) computeTerm(t constraint.Term) fr.Element { - cID, vID := t.CoeffID(), t.WireID() - if cID != 0 && !s.solved[vID] { - panic("computing a term with an unsolved wire") - } - switch cID { - case constraint.CoeffIdZero: - return fr.Element{} - case constraint.CoeffIdOne: - return s.values[vID] - case constraint.CoeffIdTwo: - var res fr.Element - res.Double(&s.values[vID]) - return res - case constraint.CoeffIdMinusOne: - var res fr.Element - res.Neg(&s.values[vID]) - return res - default: - var res fr.Element - res.Mul(&s.coefficients[cID], &s.values[vID]) - return res - } -} - -// r += (t.coeff*t.value) -func (s *solution) accumulateInto(t constraint.Term, r *fr.Element) { - cID := t.CoeffID() - - if t.IsConstant() { - // needed for logs, we may want to not put this in the hot path if we need to - // optimize constraint system solver further. - r.Add(r, &s.coefficients[cID]) - return - } - - vID := t.WireID() - switch cID { - case constraint.CoeffIdZero: - return - case constraint.CoeffIdOne: - r.Add(r, &s.values[vID]) - case constraint.CoeffIdTwo: - var res fr.Element - res.Double(&s.values[vID]) - r.Add(r, &res) - case constraint.CoeffIdMinusOne: - r.Sub(r, &s.values[vID]) - default: - var res fr.Element - res.Mul(&s.coefficients[cID], &s.values[vID]) - r.Add(r, &res) - } -} - -// solveHint compute solution.values[vID] using provided solver hint -func (s *solution) solveWithHint(vID int, hID int) error { - // skip if the wire is already solved by a call to the same hint - // function on the same inputs - if s.solved[vID] { - return nil - } - - h := &s.cs.HintMappings[hID] - - // ensure hint function was provided - f, ok := s.mHintsFunctions[h.HintID] - if !ok { - return errors.New("missing hint function") - } - - // tmp IO big int memory - nbInputs := len(h.Inputs) - nbOutputs := len(h.Outputs) - inputs := make([]*big.Int, nbInputs) - outputs := make([]*big.Int, nbOutputs) - for i := 0; i < nbOutputs; i++ { - outputs[i] = big.NewInt(0) - } - - q := fr.Modulus() - - // for each input, we set its big int value, IF all the wires are solved - // the only case where all wires may not be solved, is if one of the input of this hint - // is the output of another hint. - // it is safe to recursively solve this with the parallel solver, since all hints-output wires - // that we can solve this way are marked to be solved with the current constraint we are processing. - recursiveSolve := func(t constraint.Term) error { - if t.IsConstant() { - return nil - } - wID := t.WireID() - if s.solved[wID] { - return nil - } - // unsolved dependency - if h, ok := s.cs.MHints[wID]; ok { - // solve recursively. - return s.solveWithHint(wID, h) - } - - // it's not a hint, we panic. - panic("solver can't compute hint; one or more input wires are unsolved") - } - - for i := 0; i < nbInputs; i++ { - inputs[i] = big.NewInt(0) - - var v fr.Element - for _, term := range h.Inputs[i] { - if err := recursiveSolve(term); err != nil { - return err - } - s.accumulateInto(term, &v) - } - v.BigInt(inputs[i]) - } - - err := f(q, inputs, outputs) - - var v fr.Element - for i := range outputs { - v.SetBigInt(outputs[i]) - s.set(h.Outputs[i], v) - } - - return err -} - -func (s *solution) printLogs(log zerolog.Logger, logs []constraint.LogEntry) { - if log.GetLevel() == zerolog.Disabled { - return - } - - for i := 0; i < len(logs); i++ { - logLine := s.logValue(logs[i]) - log.Debug().Str(zerolog.CallerFieldName, logs[i].Caller).Msg(logLine) - } -} - -const unsolvedVariable = "" - -func (s *solution) logValue(log constraint.LogEntry) string { - var toResolve []interface{} - var ( - eval fr.Element - missingValue bool - ) - for j := 0; j < len(log.ToResolve); j++ { - // before eval le - - missingValue = false - eval.SetZero() - - for _, t := range log.ToResolve[j] { - // for each term in the linear expression - - cID, vID := t.CoeffID(), t.WireID() - if t.IsConstant() { - // just add the constant - eval.Add(&eval, &s.coefficients[cID]) - continue - } - - if !s.solved[vID] { - missingValue = true - break // stop the loop we can't evaluate. - } - - tv := s.computeTerm(t) - eval.Add(&eval, &tv) - } - - // after - if missingValue { - toResolve = append(toResolve, unsolvedVariable) - } else { - // we have to append our accumulator - toResolve = append(toResolve, eval.String()) - } - - } - if len(log.Stack) > 0 { - var sbb strings.Builder - for _, lID := range log.Stack { - location := s.st.Locations[lID] - function := s.st.Functions[location.FunctionID] - - sbb.WriteString(function.Name) - sbb.WriteByte('\n') - sbb.WriteByte('\t') - sbb.WriteString(function.Filename) - sbb.WriteByte(':') - sbb.WriteString(strconv.Itoa(int(location.Line))) - sbb.WriteByte('\n') - } - toResolve = append(toResolve, sbb.String()) - } - return fmt.Sprintf(log.Format, toResolve...) -} - -// UnsatisfiedConstraintError wraps an error with useful metadata on the unsatisfied constraint -type UnsatisfiedConstraintError struct { - Err error - CID int // constraint ID - DebugInfo *string // optional debug info -} - -func (r *UnsatisfiedConstraintError) Error() string { - if r.DebugInfo != nil { - return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, *r.DebugInfo) - } - return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, r.Err.Error()) -} - -// R1CSSolution represent a valid assignment to all the variables in the constraint system. -// The vector W such that Aw o Bw - Cw = 0 -type R1CSSolution struct { - W fr.Vector - A, B, C fr.Vector -} - -func (t *R1CSSolution) WriteTo(w io.Writer) (int64, error) { - n, err := t.W.WriteTo(w) - if err != nil { - return n, err - } - a, err := t.A.WriteTo(w) - n += a - if err != nil { - return n, err - } - a, err = t.B.WriteTo(w) - n += a - if err != nil { - return n, err - } - a, err = t.C.WriteTo(w) - n += a - return n, err -} - -func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { - n, err := t.W.ReadFrom(r) - if err != nil { - return n, err - } - a, err := t.A.ReadFrom(r) - a += n - if err != nil { - return n, err - } - a, err = t.B.ReadFrom(r) - a += n - if err != nil { - return n, err - } - a, err = t.C.ReadFrom(r) - n += a - return n, err -} - -// SparseR1CSSolution represent a valid assignment to all the variables in the constraint system. -type SparseR1CSSolution struct { - L, R, O fr.Vector -} - -func (t *SparseR1CSSolution) WriteTo(w io.Writer) (int64, error) { - n, err := t.L.WriteTo(w) - if err != nil { - return n, err - } - a, err := t.R.WriteTo(w) - n += a - if err != nil { - return n, err - } - a, err = t.O.WriteTo(w) - n += a - return n, err - -} - -func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { - n, err := t.L.ReadFrom(r) - if err != nil { - return n, err - } - a, err := t.R.ReadFrom(r) - a += n - if err != nil { - return n, err - } - a, err = t.O.ReadFrom(r) - a += n - return n, err -} diff --git a/constraint/bls24-315/solver.go b/constraint/bls24-315/solver.go new file mode 100644 index 0000000000..1bd1ddcc1f --- /dev/null +++ b/constraint/bls24-315/solver.go @@ -0,0 +1,614 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package cs + +import ( + "errors" + "fmt" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/field/pool" + "github.com/consensys/gnark/constraint" + csolver "github.com/consensys/gnark/constraint/solver" + "github.com/rs/zerolog" + "math" + "math/big" + "runtime" + "strconv" + "strings" + "sync" + "sync/atomic" + + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" +) + +// solver represent the state of the solver during a call to System.Solve(...) +type solver struct { + *system + + // values and solved are index by the wire (variable) id + values []fr.Element + solved []bool + nbSolved uint64 + + // maps hintID to hint function + mHintsFunctions map[csolver.HintID]csolver.Hint + + // used to out api.Println + logger zerolog.Logger + + a, b, c fr.Vector // R1CS solver will compute the a,b,c matrices + + q *big.Int +} + +func newSolver(cs *system, witness fr.Vector, opts ...csolver.Option) (*solver, error) { + // parse options + opt, err := csolver.NewConfig(opts...) + if err != nil { + return nil, err + } + + // check witness size + witnessOffset := 0 + if cs.Type == constraint.SystemR1CS { + witnessOffset++ + } + + nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables + expectedWitnessSize := len(cs.Public) - witnessOffset + len(cs.Secret) + + if len(witness) != expectedWitnessSize { + return nil, fmt.Errorf("invalid witness size, got %d, expected %d", len(witness), expectedWitnessSize) + } + + // check all hints are there + hintFunctions := opt.HintFunctions + + // hintsDependencies is from compile time; it contains the list of hints the solver **needs** + var missing []string + for hintUUID, hintID := range cs.MHintsDependencies { + if _, ok := hintFunctions[hintUUID]; !ok { + missing = append(missing, hintID) + } + } + + if len(missing) > 0 { + return nil, fmt.Errorf("solver missing hint(s): %v", missing) + } + + s := solver{ + system: cs, + values: make([]fr.Element, nbWires), + solved: make([]bool, nbWires), + mHintsFunctions: hintFunctions, + logger: opt.Logger, + q: cs.Field(), + } + + // set the witness indexes as solved + if witnessOffset == 1 { + s.solved[0] = true // ONE_WIRE + s.values[0].SetOne() + } + copy(s.values[witnessOffset:], witness) + for i := range witness { + s.solved[i+witnessOffset] = true + } + + // keep track of the number of wire instantiations we do, for a post solve sanity check + // to ensure we instantiated all wires + s.nbSolved += uint64(len(witness) + witnessOffset) + + if s.Type == constraint.SystemR1CS { + n := ecc.NextPowerOfTwo(uint64(cs.GetNbConstraints())) + s.a = make(fr.Vector, cs.GetNbConstraints(), n) + s.b = make(fr.Vector, cs.GetNbConstraints(), n) + s.c = make(fr.Vector, cs.GetNbConstraints(), n) + } + + return &s, nil +} + +func (s *solver) set(id int, value fr.Element) { + if s.solved[id] { + panic("solving the same wire twice should never happen.") + } + s.values[id] = value + s.solved[id] = true + atomic.AddUint64(&s.nbSolved, 1) +} + +// computeTerm computes coeff*variable +// TODO @gbotrel check if t is a Constant only +func (s *solver) computeTerm(t constraint.Term) fr.Element { + cID, vID := t.CoeffID(), t.WireID() + if cID != 0 && !s.solved[vID] { + panic("computing a term with an unsolved wire") + } + switch cID { + case constraint.CoeffIdZero: + return fr.Element{} + case constraint.CoeffIdOne: + return s.values[vID] + case constraint.CoeffIdTwo: + var res fr.Element + res.Double(&s.values[vID]) + return res + case constraint.CoeffIdMinusOne: + var res fr.Element + res.Neg(&s.values[vID]) + return res + default: + var res fr.Element + res.Mul(&s.Coefficients[cID], &s.values[vID]) + return res + } +} + +// r += (t.coeff*t.value) +// TODO @gbotrel check t.IsConstant on the caller side when necessary +func (s *solver) accumulateInto(t constraint.Term, r *fr.Element) { + cID := t.CoeffID() + vID := t.WireID() + + switch cID { + case constraint.CoeffIdZero: + return + case constraint.CoeffIdOne: + r.Add(r, &s.values[vID]) + case constraint.CoeffIdTwo: + var res fr.Element + res.Double(&s.values[vID]) + r.Add(r, &res) + case constraint.CoeffIdMinusOne: + r.Sub(r, &s.values[vID]) + default: + var res fr.Element + res.Mul(&s.Coefficients[cID], &s.values[vID]) + r.Add(r, &res) + } +} + +// solveWithHint executes a hint and assign the result to its defined outputs. +func (s *solver) solveWithHint(h *constraint.HintMapping) error { + // ensure hint function was provided + f, ok := s.mHintsFunctions[h.HintID] + if !ok { + return errors.New("missing hint function") + } + + // tmp IO big int memory + nbInputs := len(h.Inputs) + nbOutputs := int(h.OutputRange.End - h.OutputRange.Start) + inputs := make([]*big.Int, nbInputs) + outputs := make([]*big.Int, nbOutputs) + for i := 0; i < nbOutputs; i++ { + outputs[i] = pool.BigInt.Get() + outputs[i].SetUint64(0) + } + + q := pool.BigInt.Get() + q.Set(s.q) + + for i := 0; i < nbInputs; i++ { + var v fr.Element + for _, term := range h.Inputs[i] { + if term.IsConstant() { + v.Add(&v, &s.Coefficients[term.CoeffID()]) + continue + } + s.accumulateInto(term, &v) + } + inputs[i] = pool.BigInt.Get() + v.BigInt(inputs[i]) + } + + err := f(q, inputs, outputs) + + var v fr.Element + for i := range outputs { + v.SetBigInt(outputs[i]) + s.set(int(h.OutputRange.Start)+i, v) + pool.BigInt.Put(outputs[i]) + } + + for i := range inputs { + pool.BigInt.Put(inputs[i]) + } + + pool.BigInt.Put(q) + + return err +} + +func (s *solver) printLogs(logs []constraint.LogEntry) { + if s.logger.GetLevel() == zerolog.Disabled { + return + } + + for i := 0; i < len(logs); i++ { + logLine := s.logValue(logs[i]) + s.logger.Debug().Str(zerolog.CallerFieldName, logs[i].Caller).Msg(logLine) + } +} + +const unsolvedVariable = "" + +func (s *solver) logValue(log constraint.LogEntry) string { + var toResolve []interface{} + var ( + eval fr.Element + missingValue bool + ) + for j := 0; j < len(log.ToResolve); j++ { + // before eval le + + missingValue = false + eval.SetZero() + + for _, t := range log.ToResolve[j] { + // for each term in the linear expression + + cID, vID := t.CoeffID(), t.WireID() + if t.IsConstant() { + // just add the constant + eval.Add(&eval, &s.Coefficients[cID]) + continue + } + + if !s.solved[vID] { + missingValue = true + break // stop the loop we can't evaluate. + } + + tv := s.computeTerm(t) + eval.Add(&eval, &tv) + } + + // after + if missingValue { + toResolve = append(toResolve, unsolvedVariable) + } else { + // we have to append our accumulator + toResolve = append(toResolve, eval.String()) + } + + } + if len(log.Stack) > 0 { + var sbb strings.Builder + for _, lID := range log.Stack { + location := s.SymbolTable.Locations[lID] + function := s.SymbolTable.Functions[location.FunctionID] + + sbb.WriteString(function.Name) + sbb.WriteByte('\n') + sbb.WriteByte('\t') + sbb.WriteString(function.Filename) + sbb.WriteByte(':') + sbb.WriteString(strconv.Itoa(int(location.Line))) + sbb.WriteByte('\n') + } + toResolve = append(toResolve, sbb.String()) + } + return fmt.Sprintf(log.Format, toResolve...) +} + +// divByCoeff sets res = res / t.Coeff +func (solver *solver) divByCoeff(res *fr.Element, cID uint32) { + switch cID { + case constraint.CoeffIdOne: + return + case constraint.CoeffIdMinusOne: + res.Neg(res) + case constraint.CoeffIdZero: + panic("division by 0") + default: + // this is slow, but shouldn't happen as divByCoeff is called to + // remove the coeff of an unsolved wire + // but unsolved wires are (in gnark frontend) systematically set with a coeff == 1 or -1 + res.Div(res, &solver.Coefficients[cID]) + } +} + +// Implement constraint.Solver +func (s *solver) GetValue(cID, vID uint32) constraint.Element { + var r constraint.Element + e := s.computeTerm(constraint.Term{CID: cID, VID: vID}) + copy(r[:], e[:]) + return r +} +func (s *solver) GetCoeff(cID uint32) constraint.Element { + var r constraint.Element + copy(r[:], s.Coefficients[cID][:]) + return r +} +func (s *solver) SetValue(vID uint32, f constraint.Element) { + s.set(int(vID), *(*fr.Element)(f[:])) +} + +func (s *solver) IsSolved(vID uint32) bool { + return s.solved[vID] +} + +// processInstruction decodes the instruction and execute blueprint-defined logic. +// an instruction can encode a hint, a custom constraint or a generic constraint. +func (solver *solver) processInstruction(inst constraint.Instruction, scratch *scratch) error { + // fetch the blueprint + blueprint := solver.Blueprints[inst.BlueprintID] + calldata := solver.GetCallData(inst) + cID := inst.ConstraintOffset // here we have 1 constraint in the instruction only + + if solver.Type == constraint.SystemR1CS { + if bc, ok := blueprint.(constraint.BlueprintR1C); ok { + // TODO @gbotrel we use the solveR1C method for now, having user-defined + // blueprint for R1CS would require constraint.Solver interface to add methods + // to set a,b,c since it's more efficient to compute these while we solve. + bc.DecompressR1C(&scratch.tR1C, calldata) + return solver.solveR1C(cID, &scratch.tR1C) + } + } else if solver.Type == constraint.SystemSparseR1CS { + // blueprint declared "I know how to solve this." + if bc, ok := blueprint.(constraint.BlueprintSolvable); ok { + if err := bc.Solve(solver, calldata); err != nil { + return solver.wrapErrWithDebugInfo(cID, err) + } + return nil + } + } + + // blueprint encodes a hint, we execute. + // TODO @gbotrel may be worth it to move hint logic in blueprint "solve" + if bc, ok := blueprint.(constraint.BlueprintHint); ok { + bc.DecompressHint(&scratch.tHint, calldata) + return solver.solveWithHint(&scratch.tHint) + } + + return nil +} + +// run runs the solver. it return an error if a constraint is not satisfied or if not all wires +// were instantiated. +func (solver *solver) run() error { + // minWorkPerCPU is the minimum target number of constraint a task should hold + // in other words, if a level has less than minWorkPerCPU, it will not be parallelized and executed + // sequentially without sync. + const minWorkPerCPU = 50.0 // TODO @gbotrel revisit that with blocks. + + // cs.Levels has a list of levels, where all constraints in a level l(n) are independent + // and may only have dependencies on previous levels + // for each constraint + // we are guaranteed that each R1C contains at most one unsolved wire + // first we solve the unsolved wire (if any) + // then we check that the constraint is valid + // if a[i] * b[i] != c[i]; it means the constraint is not satisfied + var wg sync.WaitGroup + chTasks := make(chan []int, runtime.NumCPU()) + chError := make(chan error, runtime.NumCPU()) + + // start a worker pool + // each worker wait on chTasks + // a task is a slice of constraint indexes to be solved + for i := 0; i < runtime.NumCPU(); i++ { + go func() { + var scratch scratch + for t := range chTasks { + for _, i := range t { + if err := solver.processInstruction(solver.Instructions[i], &scratch); err != nil { + chError <- err + wg.Done() + return + } + } + wg.Done() + } + }() + } + + // clean up pool go routines + defer func() { + close(chTasks) + close(chError) + }() + + var scratch scratch + + // for each level, we push the tasks + for _, level := range solver.Levels { + + // max CPU to use + maxCPU := float64(len(level)) / minWorkPerCPU + + if maxCPU <= 1.0 { + // we do it sequentially + for _, i := range level { + if err := solver.processInstruction(solver.Instructions[i], &scratch); err != nil { + return err + } + } + continue + } + + // number of tasks for this level is set to number of CPU + // but if we don't have enough work for all our CPU, it can be lower. + nbTasks := runtime.NumCPU() + maxTasks := int(math.Ceil(maxCPU)) + if nbTasks > maxTasks { + nbTasks = maxTasks + } + nbIterationsPerCpus := len(level) / nbTasks + + // more CPUs than tasks: a CPU will work on exactly one iteration + // note: this depends on minWorkPerCPU constant + if nbIterationsPerCpus < 1 { + nbIterationsPerCpus = 1 + nbTasks = len(level) + } + + extraTasks := len(level) - (nbTasks * nbIterationsPerCpus) + extraTasksOffset := 0 + + for i := 0; i < nbTasks; i++ { + wg.Add(1) + _start := i*nbIterationsPerCpus + extraTasksOffset + _end := _start + nbIterationsPerCpus + if extraTasks > 0 { + _end++ + extraTasks-- + extraTasksOffset++ + } + // since we're never pushing more than num CPU tasks + // we will never be blocked here + chTasks <- level[_start:_end] + } + + // wait for the level to be done + wg.Wait() + + if len(chError) > 0 { + return <-chError + } + } + + if int(solver.nbSolved) != len(solver.values) { + return errors.New("solver didn't assign a value to all wires") + } + + return nil +} + +// solveR1C compute unsolved wires in the constraint, if any and set the solver accordingly +// +// returns an error if the solver called a hint function that errored +// returns false, nil if there was no wire to solve +// returns true, nil if exactly one wire was solved. In that case, it is redundant to check that +// the constraint is satisfied later. +func (solver *solver) solveR1C(cID uint32, r *constraint.R1C) error { + a, b, c := &solver.a[cID], &solver.b[cID], &solver.c[cID] + + // the index of the non-zero entry shows if L, R or O has an uninstantiated wire + // the content is the ID of the wire non instantiated + var loc uint8 + + var termToCompute constraint.Term + + processLExp := func(l constraint.LinearExpression, val *fr.Element, locValue uint8) { + for _, t := range l { + vID := t.WireID() + + // wire is already computed, we just accumulate in val + if solver.solved[vID] { + solver.accumulateInto(t, val) + continue + } + + if loc != 0 { + panic("found more than one wire to instantiate") + } + termToCompute = t + loc = locValue + } + } + + processLExp(r.L, a, 1) + processLExp(r.R, b, 2) + processLExp(r.O, c, 3) + + if loc == 0 { + // there is nothing to solve, may happen if we have an assertion + // (ie a constraints that doesn't yield any output) + // or if we solved the unsolved wires with hint functions + var check fr.Element + if !check.Mul(a, b).Equal(c) { + return solver.wrapErrWithDebugInfo(cID, fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String())) + } + return nil + } + + // we compute the wire value and instantiate it + wID := termToCompute.WireID() + + // solver result + var wire fr.Element + + switch loc { + case 1: + if !b.IsZero() { + wire.Div(c, b). + Sub(&wire, a) + a.Add(a, &wire) + } else { + // we didn't actually ensure that a * b == c + var check fr.Element + if !check.Mul(a, b).Equal(c) { + return solver.wrapErrWithDebugInfo(cID, fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String())) + } + } + case 2: + if !a.IsZero() { + wire.Div(c, a). + Sub(&wire, b) + b.Add(b, &wire) + } else { + var check fr.Element + if !check.Mul(a, b).Equal(c) { + return solver.wrapErrWithDebugInfo(cID, fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String())) + } + } + case 3: + wire.Mul(a, b). + Sub(&wire, c) + + c.Add(c, &wire) + } + + // wire is the term (coeff * value) + // but in the solver we want to store the value only + // note that in gnark frontend, coeff here is always 1 or -1 + solver.divByCoeff(&wire, termToCompute.CID) + solver.set(wID, wire) + + return nil +} + +// UnsatisfiedConstraintError wraps an error with useful metadata on the unsatisfied constraint +type UnsatisfiedConstraintError struct { + Err error + CID int // constraint ID + DebugInfo *string // optional debug info +} + +func (r *UnsatisfiedConstraintError) Error() string { + if r.DebugInfo != nil { + return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, *r.DebugInfo) + } + return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, r.Err.Error()) +} + +func (solver *solver) wrapErrWithDebugInfo(cID uint32, err error) *UnsatisfiedConstraintError { + var debugInfo *string + if dID, ok := solver.MDebug[int(cID)]; ok { + debugInfo = new(string) + *debugInfo = solver.logValue(solver.DebugInfo[dID]) + } + return &UnsatisfiedConstraintError{CID: int(cID), Err: err, DebugInfo: debugInfo} +} + +// temporary variables to avoid memallocs in hotloop +type scratch struct { + tR1C constraint.R1C + tHint constraint.HintMapping +} diff --git a/constraint/bls24-315/system.go b/constraint/bls24-315/system.go new file mode 100644 index 0000000000..cf42528f80 --- /dev/null +++ b/constraint/bls24-315/system.go @@ -0,0 +1,365 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package cs + +import ( + "github.com/fxamacker/cbor/v2" + "io" + "time" + + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint" + csolver "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/internal/backend/ioutils" + "github.com/consensys/gnark/logger" + "reflect" + + "github.com/consensys/gnark-crypto/ecc" + + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" +) + +type R1CS = system +type SparseR1CS = system + +// system is a curved-typed constraint.System with a concrete coefficient table (fr.Element) +type system struct { + constraint.System + CoeffTable + field +} + +func NewR1CS(capacity int) *R1CS { + return newSystem(capacity, constraint.SystemR1CS) +} + +func NewSparseR1CS(capacity int) *SparseR1CS { + return newSystem(capacity, constraint.SystemSparseR1CS) +} + +func newSystem(capacity int, t constraint.SystemType) *system { + return &system{ + System: constraint.NewSystem(fr.Modulus(), capacity, t), + CoeffTable: newCoeffTable(capacity / 10), + } +} + +// Solve solves the constraint system with provided witness. +// If it's a R1CS returns R1CSSolution +// If it's a SparseR1CS returns SparseR1CSSolution +func (cs *system) Solve(witness witness.Witness, opts ...csolver.Option) (any, error) { + log := logger.Logger().With().Int("nbConstraints", cs.GetNbConstraints()).Logger() + start := time.Now() + + v := witness.Vector().(fr.Vector) + + // init the solver + solver, err := newSolver(cs, v, opts...) + if err != nil { + log.Err(err).Send() + return nil, err + } + + // defer log printing once all solver.values are computed + // (or sooner, if a constraint is not satisfied) + defer solver.printLogs(cs.Logs) + + // run it. + if err := solver.run(); err != nil { + log.Err(err).Send() + return nil, err + } + + log.Debug().Dur("took", time.Since(start)).Msg("constraint system solver done") + + // format the solution + // TODO @gbotrel revisit post-refactor + if cs.Type == constraint.SystemR1CS { + var res R1CSSolution + res.W = solver.values + res.A = solver.a + res.B = solver.b + res.C = solver.c + return &res, nil + } else { + // sparse R1CS + var res SparseR1CSSolution + // query l, r, o in Lagrange basis, not blinded + res.L, res.R, res.O = evaluateLROSmallDomain(cs, solver.values) + + return &res, nil + } + +} + +// IsSolved +// Deprecated: use _, err := Solve(...) instead +func (cs *system) IsSolved(witness witness.Witness, opts ...csolver.Option) error { + _, err := cs.Solve(witness, opts...) + return err +} + +// GetR1Cs return the list of R1C +func (cs *system) GetR1Cs() []constraint.R1C { + toReturn := make([]constraint.R1C, 0, cs.GetNbConstraints()) + + for _, inst := range cs.Instructions { + blueprint := cs.Blueprints[inst.BlueprintID] + if bc, ok := blueprint.(constraint.BlueprintR1C); ok { + var r1c constraint.R1C + bc.DecompressR1C(&r1c, cs.GetCallData(inst)) + toReturn = append(toReturn, r1c) + } else { + panic("not implemented") + } + } + return toReturn +} + +// GetNbCoefficients return the number of unique coefficients needed in the R1CS +func (cs *system) GetNbCoefficients() int { + return len(cs.Coefficients) +} + +// CurveID returns curve ID as defined in gnark-crypto +func (cs *system) CurveID() ecc.ID { + return ecc.BLS24_315 +} + +// WriteTo encodes R1CS into provided io.Writer using cbor +func (cs *system) WriteTo(w io.Writer) (int64, error) { + _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written + ts := getTagSet() + enc, err := cbor.CoreDetEncOptions().EncModeWithTags(ts) + if err != nil { + return 0, err + } + encoder := enc.NewEncoder(&_w) + + // encode our object + err = encoder.Encode(cs) + return _w.N, err +} + +// ReadFrom attempts to decode R1CS from io.Reader using cbor +func (cs *system) ReadFrom(r io.Reader) (int64, error) { + ts := getTagSet() + dm, err := cbor.DecOptions{ + MaxArrayElements: 134217728, + MaxMapPairs: 134217728, + }.DecModeWithTags(ts) + + if err != nil { + return 0, err + } + decoder := dm.NewDecoder(r) + + // initialize coeff table + cs.CoeffTable = newCoeffTable(0) + + if err := decoder.Decode(&cs); err != nil { + return int64(decoder.NumBytesRead()), err + } + + if err := cs.CheckSerializationHeader(); err != nil { + return int64(decoder.NumBytesRead()), err + } + + return int64(decoder.NumBytesRead()), nil +} + +func (cs *system) GetCoefficient(i int) (r constraint.Element) { + copy(r[:], cs.Coefficients[i][:]) + return +} + +// GetSparseR1Cs return the list of SparseR1C +func (cs *system) GetSparseR1Cs() []constraint.SparseR1C { + + toReturn := make([]constraint.SparseR1C, 0, cs.GetNbConstraints()) + + for _, inst := range cs.Instructions { + blueprint := cs.Blueprints[inst.BlueprintID] + if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { + var sparseR1C constraint.SparseR1C + calldata := cs.CallData[inst.StartCallData : inst.StartCallData+uint64(blueprint.NbInputs())] + bc.DecompressSparseR1C(&sparseR1C, calldata) + toReturn = append(toReturn, sparseR1C) + } else { + panic("not implemented") + } + } + return toReturn +} + +// evaluateLROSmallDomain extracts the solver l, r, o, and returns it in lagrange form. +// solver = [ public | secret | internal ] +// TODO @gbotrel refactor; this seems to be a small util function for plonk +func evaluateLROSmallDomain(cs *system, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { + + //s := int(pk.Domain[0].Cardinality) + s := cs.GetNbConstraints() + len(cs.Public) // len(spr.Public) is for the placeholder constraints + s = int(ecc.NextPowerOfTwo(uint64(s))) + + var l, r, o []fr.Element + l = make([]fr.Element, s) + r = make([]fr.Element, s) + o = make([]fr.Element, s) + s0 := solution[0] + + for i := 0; i < len(cs.Public); i++ { // placeholders + l[i] = solution[i] + r[i] = s0 + o[i] = s0 + } + offset := len(cs.Public) + nbConstraints := cs.GetNbConstraints() + + var sparseR1C constraint.SparseR1C + j := 0 + for _, inst := range cs.Instructions { + blueprint := cs.Blueprints[inst.BlueprintID] + if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { + bc.DecompressSparseR1C(&sparseR1C, cs.GetCallData(inst)) + + l[offset+j] = solution[sparseR1C.XA] + r[offset+j] = solution[sparseR1C.XB] + o[offset+j] = solution[sparseR1C.XC] + j++ + } + } + + offset += nbConstraints + + for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solver[0]) + l[offset+i] = s0 + r[offset+i] = s0 + o[offset+i] = s0 + } + + return l, r, o + +} + +// R1CSSolution represent a valid assignment to all the variables in the constraint system. +// The vector W such that Aw o Bw - Cw = 0 +type R1CSSolution struct { + W fr.Vector + A, B, C fr.Vector +} + +func (t *R1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.W.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.A.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.B.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.C.WriteTo(w) + n += a + return n, err +} + +func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.W.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.A.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.B.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.C.ReadFrom(r) + n += a + return n, err +} + +// SparseR1CSSolution represent a valid assignment to all the variables in the constraint system. +type SparseR1CSSolution struct { + L, R, O fr.Vector +} + +func (t *SparseR1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.L.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.R.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.O.WriteTo(w) + n += a + return n, err + +} + +func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.L.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.R.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.O.ReadFrom(r) + a += n + return n, err +} + +func getTagSet() cbor.TagSet { + // temporary for refactor + ts := cbor.NewTagSet() + // https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml + // 65536-15309735 Unassigned + tagNum := uint64(5309735) + addType := func(t reflect.Type) { + if err := ts.Add( + cbor.TagOptions{EncTag: cbor.EncTagRequired, DecTag: cbor.DecTagRequired}, + t, + tagNum, + ); err != nil { + panic(err) + } + tagNum++ + } + + addType(reflect.TypeOf(constraint.BlueprintGenericHint{})) + addType(reflect.TypeOf(constraint.BlueprintGenericR1C{})) + addType(reflect.TypeOf(constraint.BlueprintGenericSparseR1C{})) + addType(reflect.TypeOf(constraint.BlueprintSparseR1CAdd{})) + addType(reflect.TypeOf(constraint.BlueprintSparseR1CMul{})) + + return ts +} diff --git a/constraint/bls24-317/coeff.go b/constraint/bls24-317/coeff.go index d011d2bffb..20cbf188d7 100644 --- a/constraint/bls24-317/coeff.go +++ b/constraint/bls24-317/coeff.go @@ -46,7 +46,7 @@ func newCoeffTable(capacity int) CoeffTable { } -func (ct *CoeffTable) MakeTerm(coeff *constraint.Coeff, variableID int) constraint.Term { +func (ct *CoeffTable) AddCoeff(coeff constraint.Element) uint32 { c := (*fr.Element)(coeff[:]) var cID uint32 if c.IsZero() { @@ -69,7 +69,11 @@ func (ct *CoeffTable) MakeTerm(coeff *constraint.Coeff, variableID int) constrai ct.mCoeffs[cc] = cID } } + return cID +} +func (ct *CoeffTable) MakeTerm(coeff *constraint.Element, variableID int) constraint.Term { + cID := ct.AddCoeff(*coeff) return constraint.Term{VID: uint32(variableID), CID: cID} } @@ -78,7 +82,10 @@ func (ct *CoeffTable) CoeffToString(cID int) string { return ct.Coefficients[cID].String() } -var _ constraint.CoeffEngine = &arithEngine{} +// implements constraint.Field +type field struct{} + +var _ constraint.Field = &field{} var ( two fr.Element @@ -94,10 +101,7 @@ func init() { minusTwo.Neg(&two) } -// implements constraint.CoeffEngine -type arithEngine struct{} - -func (engine *arithEngine) FromInterface(i interface{}) constraint.Coeff { +func (engine *field) FromInterface(i interface{}) constraint.Element { var e fr.Element if _, err := e.SetInterface(i); err != nil { // need to clean that --> some code path are dissimilar @@ -106,55 +110,75 @@ func (engine *arithEngine) FromInterface(i interface{}) constraint.Coeff { b := utils.FromInterface(i) e.SetBigInt(&b) } - var r constraint.Coeff + var r constraint.Element copy(r[:], e[:]) return r } -func (engine *arithEngine) ToBigInt(c *constraint.Coeff) *big.Int { +func (engine *field) ToBigInt(c constraint.Element) *big.Int { e := (*fr.Element)(c[:]) r := new(big.Int) e.BigInt(r) return r } -func (engine *arithEngine) Mul(a, b *constraint.Coeff) { +func (engine *field) Mul(a, b constraint.Element) constraint.Element { _a := (*fr.Element)(a[:]) _b := (*fr.Element)(b[:]) _a.Mul(_a, _b) + return a } -func (engine *arithEngine) Add(a, b *constraint.Coeff) { + +func (engine *field) Add(a, b constraint.Element) constraint.Element { _a := (*fr.Element)(a[:]) _b := (*fr.Element)(b[:]) _a.Add(_a, _b) + return a } -func (engine *arithEngine) Sub(a, b *constraint.Coeff) { +func (engine *field) Sub(a, b constraint.Element) constraint.Element { _a := (*fr.Element)(a[:]) _b := (*fr.Element)(b[:]) _a.Sub(_a, _b) + return a } -func (engine *arithEngine) Neg(a *constraint.Coeff) { +func (engine *field) Neg(a constraint.Element) constraint.Element { e := (*fr.Element)(a[:]) e.Neg(e) + return a } -func (engine *arithEngine) Inverse(a *constraint.Coeff) { +func (engine *field) Inverse(a constraint.Element) (constraint.Element, bool) { + if a.IsZero() { + return a, false + } e := (*fr.Element)(a[:]) + if e.IsZero() { + return a, false + } else if e.IsOne() { + return a, true + } + var t fr.Element + t.Neg(e) + if t.IsOne() { + return a, true + } + e.Inverse(e) + return a, true } -func (engine *arithEngine) IsOne(a *constraint.Coeff) bool { +func (engine *field) IsOne(a constraint.Element) bool { e := (*fr.Element)(a[:]) return e.IsOne() } -func (engine *arithEngine) One() constraint.Coeff { +func (engine *field) One() constraint.Element { e := fr.One() - var r constraint.Coeff + var r constraint.Element copy(r[:], e[:]) return r } -func (engine *arithEngine) String(a *constraint.Coeff) string { +func (engine *field) String(a constraint.Element) string { e := (*fr.Element)(a[:]) return e.String() } diff --git a/constraint/bls24-317/r1cs.go b/constraint/bls24-317/r1cs.go deleted file mode 100644 index e397fb5073..0000000000 --- a/constraint/bls24-317/r1cs.go +++ /dev/null @@ -1,467 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// 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. - -// Code generated by gnark DO NOT EDIT - -package cs - -import ( - "errors" - "fmt" - "github.com/fxamacker/cbor/v2" - "io" - "runtime" - "sync" - "time" - - "github.com/consensys/gnark/backend/witness" - "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/internal/backend/ioutils" - "github.com/consensys/gnark/logger" - "github.com/consensys/gnark/profile" - - "github.com/consensys/gnark-crypto/ecc" - "math" - - "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" -) - -// R1CS describes a set of R1CS constraint -type R1CS struct { - constraint.R1CSCore - CoeffTable - arithEngine -} - -// NewR1CS returns a new R1CS and sets cs.Coefficient (fr.Element) from provided big.Int values -// -// capacity pre-allocates memory for capacity nbConstraints -func NewR1CS(capacity int) *R1CS { - r := R1CS{ - R1CSCore: constraint.R1CSCore{ - System: constraint.NewSystem(fr.Modulus()), - Constraints: make([]constraint.R1C, 0, capacity), - }, - CoeffTable: newCoeffTable(capacity / 10), - } - return &r -} - -func (cs *R1CS) AddConstraint(r1c constraint.R1C, debugInfo ...constraint.DebugInfo) int { - profile.RecordConstraint() - cs.Constraints = append(cs.Constraints, r1c) - cID := len(cs.Constraints) - 1 - if len(debugInfo) == 1 { - cs.DebugInfo = append(cs.DebugInfo, constraint.LogEntry(debugInfo[0])) - cs.MDebug[cID] = len(cs.DebugInfo) - 1 - } - - cs.UpdateLevel(cID, &r1c) - - return cID -} - -// Solve returns the vector w solution to the system, that is -// Aw o Bw - Cw = 0 -func (cs *R1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { - opt, err := solver.NewConfig(opts...) - if err != nil { - return nil, err - } - - var res R1CSSolution - - s := ecc.NextPowerOfTwo(uint64(len(cs.Constraints))) - res.A = make(fr.Vector, len(cs.Constraints), s) - res.B = make(fr.Vector, len(cs.Constraints), s) - res.C = make(fr.Vector, len(cs.Constraints), s) - - v := witness.Vector().(fr.Vector) - - res.W, err = cs.solve(v, res.A, res.B, res.C, opt) - if err != nil { - return nil, err - } - - return &res, nil -} - -// Solve sets all the wires and returns the a, b, c vectors. -// the cs system should have been compiled before. The entries in a, b, c are in Montgomery form. -// a, b, c vectors: ab-c = hz -// witness = [publicWires | secretWires] (without the ONE_WIRE !) -// returns [publicWires | secretWires | internalWires ] -func (cs *R1CS) solve(witness, a, b, c fr.Vector, opt solver.Config) (fr.Vector, error) { - log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() - - nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - solution, err := newSolution(&cs.System, nbWires, opt.HintFunctions, cs.Coefficients) - if err != nil { - return make(fr.Vector, nbWires), err - } - start := time.Now() - - if len(witness) != len(cs.Public)-1+len(cs.Secret) { // - 1 for ONE_WIRE - err = fmt.Errorf("invalid witness size, got %d, expected %d = %d (public) + %d (secret)", len(witness), int(len(cs.Public)-1+len(cs.Secret)), len(cs.Public)-1, len(cs.Secret)) - log.Err(err).Send() - return solution.values, err - } - - // compute the wires and the a, b, c polynomials - if len(a) != len(cs.Constraints) || len(b) != len(cs.Constraints) || len(c) != len(cs.Constraints) { - err = errors.New("invalid input size: len(a, b, c) == len(Constraints)") - log.Err(err).Send() - return solution.values, err - } - - solution.solved[0] = true // ONE_WIRE - solution.values[0].SetOne() - copy(solution.values[1:], witness) - for i := range witness { - solution.solved[i+1] = true - } - - // keep track of the number of wire instantiations we do, for a sanity check to ensure - // we instantiated all wires - solution.nbSolved += uint64(len(witness) + 1) - - // now that we know all inputs are set, defer log printing once all solution.values are computed - // (or sooner, if a constraint is not satisfied) - defer solution.printLogs(opt.Logger, cs.Logs) - - if err := cs.parallelSolve(a, b, c, &solution); err != nil { - if unsatisfiedErr, ok := err.(*UnsatisfiedConstraintError); ok { - log.Err(errors.New("unsatisfied constraint")).Int("id", unsatisfiedErr.CID).Send() - } else { - log.Err(err).Send() - } - return solution.values, err - } - - // sanity check; ensure all wires are marked as "instantiated" - if !solution.isValid() { - log.Err(errors.New("solver didn't instantiate all wires")).Send() - panic("solver didn't instantiate all wires") - } - - log.Debug().Dur("took", time.Since(start)).Msg("constraint system solver done") - - return solution.values, nil -} - -func (cs *R1CS) parallelSolve(a, b, c fr.Vector, solution *solution) error { - // minWorkPerCPU is the minimum target number of constraint a task should hold - // in other words, if a level has less than minWorkPerCPU, it will not be parallelized and executed - // sequentially without sync. - const minWorkPerCPU = 50.0 - - // cs.Levels has a list of levels, where all constraints in a level l(n) are independent - // and may only have dependencies on previous levels - // for each constraint - // we are guaranteed that each R1C contains at most one unsolved wire - // first we solve the unsolved wire (if any) - // then we check that the constraint is valid - // if a[i] * b[i] != c[i]; it means the constraint is not satisfied - - var wg sync.WaitGroup - chTasks := make(chan []int, runtime.NumCPU()) - chError := make(chan *UnsatisfiedConstraintError, runtime.NumCPU()) - - // start a worker pool - // each worker wait on chTasks - // a task is a slice of constraint indexes to be solved - for i := 0; i < runtime.NumCPU(); i++ { - go func() { - for t := range chTasks { - for _, i := range t { - // for each constraint in the task, solve it. - if err := cs.solveConstraint(cs.Constraints[i], solution, &a[i], &b[i], &c[i]); err != nil { - var debugInfo *string - if dID, ok := cs.MDebug[i]; ok { - debugInfo = new(string) - *debugInfo = solution.logValue(cs.DebugInfo[dID]) - } - chError <- &UnsatisfiedConstraintError{CID: i, Err: err, DebugInfo: debugInfo} - wg.Done() - return - } - } - wg.Done() - } - }() - } - - // clean up pool go routines - defer func() { - close(chTasks) - close(chError) - }() - - // for each level, we push the tasks - for _, level := range cs.Levels { - - // max CPU to use - maxCPU := float64(len(level)) / minWorkPerCPU - - if maxCPU <= 1.0 { - // we do it sequentially - for _, i := range level { - if err := cs.solveConstraint(cs.Constraints[i], solution, &a[i], &b[i], &c[i]); err != nil { - var debugInfo *string - if dID, ok := cs.MDebug[i]; ok { - debugInfo = new(string) - *debugInfo = solution.logValue(cs.DebugInfo[dID]) - } - return &UnsatisfiedConstraintError{CID: i, Err: err, DebugInfo: debugInfo} - } - } - continue - } - - // number of tasks for this level is set to number of CPU - // but if we don't have enough work for all our CPU, it can be lower. - nbTasks := runtime.NumCPU() - maxTasks := int(math.Ceil(maxCPU)) - if nbTasks > maxTasks { - nbTasks = maxTasks - } - nbIterationsPerCpus := len(level) / nbTasks - - // more CPUs than tasks: a CPU will work on exactly one iteration - // note: this depends on minWorkPerCPU constant - if nbIterationsPerCpus < 1 { - nbIterationsPerCpus = 1 - nbTasks = len(level) - } - - extraTasks := len(level) - (nbTasks * nbIterationsPerCpus) - extraTasksOffset := 0 - - for i := 0; i < nbTasks; i++ { - wg.Add(1) - _start := i*nbIterationsPerCpus + extraTasksOffset - _end := _start + nbIterationsPerCpus - if extraTasks > 0 { - _end++ - extraTasks-- - extraTasksOffset++ - } - // since we're never pushing more than num CPU tasks - // we will never be blocked here - chTasks <- level[_start:_end] - } - - // wait for the level to be done - wg.Wait() - - if len(chError) > 0 { - return <-chError - } - } - - return nil -} - -// IsSolved -// Deprecated: use _, err := Solve(...) instead -func (cs *R1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { - _, err := cs.Solve(witness, opts...) - return err -} - -// divByCoeff sets res = res / t.Coeff -func (cs *R1CS) divByCoeff(res *fr.Element, t constraint.Term) { - cID := t.CoeffID() - switch cID { - case constraint.CoeffIdOne: - return - case constraint.CoeffIdMinusOne: - res.Neg(res) - case constraint.CoeffIdZero: - panic("division by 0") - default: - // this is slow, but shouldn't happen as divByCoeff is called to - // remove the coeff of an unsolved wire - // but unsolved wires are (in gnark frontend) systematically set with a coeff == 1 or -1 - res.Div(res, &cs.Coefficients[cID]) - } -} - -// solveConstraint compute unsolved wires in the constraint, if any and set the solution accordingly -// -// returns an error if the solver called a hint function that errored -// returns false, nil if there was no wire to solve -// returns true, nil if exactly one wire was solved. In that case, it is redundant to check that -// the constraint is satisfied later. -func (cs *R1CS) solveConstraint(r constraint.R1C, solution *solution, a, b, c *fr.Element) error { - - // the index of the non-zero entry shows if L, R or O has an uninstantiated wire - // the content is the ID of the wire non instantiated - var loc uint8 - - var termToCompute constraint.Term - - processLExp := func(l constraint.LinearExpression, val *fr.Element, locValue uint8) error { - for _, t := range l { - vID := t.WireID() - - // wire is already computed, we just accumulate in val - if solution.solved[vID] { - solution.accumulateInto(t, val) - continue - } - - // first we check if this is a hint wire - if hint, ok := cs.MHints[vID]; ok { - if err := solution.solveWithHint(vID, hint); err != nil { - return err - } - // now that the wire is saved, accumulate it into a, b or c - solution.accumulateInto(t, val) - continue - } - - if loc != 0 { - panic("found more than one wire to instantiate") - } - termToCompute = t - loc = locValue - } - return nil - } - - if err := processLExp(r.L, a, 1); err != nil { - return err - } - - if err := processLExp(r.R, b, 2); err != nil { - return err - } - - if err := processLExp(r.O, c, 3); err != nil { - return err - } - - if loc == 0 { - // there is nothing to solve, may happen if we have an assertion - // (ie a constraints that doesn't yield any output) - // or if we solved the unsolved wires with hint functions - var check fr.Element - if !check.Mul(a, b).Equal(c) { - return fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String()) - } - return nil - } - - // we compute the wire value and instantiate it - wID := termToCompute.WireID() - - // solver result - var wire fr.Element - - switch loc { - case 1: - if !b.IsZero() { - wire.Div(c, b). - Sub(&wire, a) - a.Add(a, &wire) - } else { - // we didn't actually ensure that a * b == c - var check fr.Element - if !check.Mul(a, b).Equal(c) { - return fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String()) - } - } - case 2: - if !a.IsZero() { - wire.Div(c, a). - Sub(&wire, b) - b.Add(b, &wire) - } else { - var check fr.Element - if !check.Mul(a, b).Equal(c) { - return fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String()) - } - } - case 3: - wire.Mul(a, b). - Sub(&wire, c) - - c.Add(c, &wire) - } - - // wire is the term (coeff * value) - // but in the solution we want to store the value only - // note that in gnark frontend, coeff here is always 1 or -1 - cs.divByCoeff(&wire, termToCompute) - solution.set(wID, wire) - - return nil -} - -// GetConstraints return the list of R1C and a coefficient resolver -func (cs *R1CS) GetConstraints() ([]constraint.R1C, constraint.Resolver) { - return cs.Constraints, cs -} - -// GetNbCoefficients return the number of unique coefficients needed in the R1CS -func (cs *R1CS) GetNbCoefficients() int { - return len(cs.Coefficients) -} - -// CurveID returns curve ID as defined in gnark-crypto -func (cs *R1CS) CurveID() ecc.ID { - return ecc.BLS24_317 -} - -// WriteTo encodes R1CS into provided io.Writer using cbor -func (cs *R1CS) WriteTo(w io.Writer) (int64, error) { - _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written - enc, err := cbor.CoreDetEncOptions().EncMode() - if err != nil { - return 0, err - } - encoder := enc.NewEncoder(&_w) - - // encode our object - err = encoder.Encode(cs) - return _w.N, err -} - -// ReadFrom attempts to decode R1CS from io.Reader using cbor -func (cs *R1CS) ReadFrom(r io.Reader) (int64, error) { - dm, err := cbor.DecOptions{ - MaxArrayElements: 134217728, - MaxMapPairs: 134217728, - }.DecMode() - - if err != nil { - return 0, err - } - decoder := dm.NewDecoder(r) - - // initialize coeff table - cs.CoeffTable = newCoeffTable(0) - - if err := decoder.Decode(&cs); err != nil { - return int64(decoder.NumBytesRead()), err - } - - if err := cs.CheckSerializationHeader(); err != nil { - return int64(decoder.NumBytesRead()), err - } - - return int64(decoder.NumBytesRead()), nil -} diff --git a/constraint/bls24-317/r1cs_sparse.go b/constraint/bls24-317/r1cs_sparse.go deleted file mode 100644 index a23ca0a472..0000000000 --- a/constraint/bls24-317/r1cs_sparse.go +++ /dev/null @@ -1,533 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// 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. - -// Code generated by gnark DO NOT EDIT - -package cs - -import ( - "errors" - "fmt" - "github.com/consensys/gnark-crypto/ecc" - "github.com/fxamacker/cbor/v2" - "io" - "math" - "runtime" - "sync" - "time" - - "github.com/consensys/gnark/backend/witness" - "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/internal/backend/ioutils" - "github.com/consensys/gnark/logger" - "github.com/consensys/gnark/profile" - - "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" -) - -// SparseR1CS represents a Plonk like circuit -type SparseR1CS struct { - constraint.SparseR1CSCore - CoeffTable - arithEngine -} - -// NewSparseR1CS returns a new SparseR1CS and sets r1cs.Coefficient (fr.Element) from provided big.Int values -func NewSparseR1CS(capacity int) *SparseR1CS { - cs := SparseR1CS{ - SparseR1CSCore: constraint.SparseR1CSCore{ - System: constraint.NewSystem(fr.Modulus()), - Constraints: make([]constraint.SparseR1C, 0, capacity), - }, - CoeffTable: newCoeffTable(capacity / 10), - } - - return &cs -} - -func (cs *SparseR1CS) AddConstraint(c constraint.SparseR1C, debugInfo ...constraint.DebugInfo) int { - profile.RecordConstraint() - cs.Constraints = append(cs.Constraints, c) - cID := len(cs.Constraints) - 1 - if len(debugInfo) == 1 { - cs.DebugInfo = append(cs.DebugInfo, constraint.LogEntry(debugInfo[0])) - cs.MDebug[cID] = len(cs.DebugInfo) - 1 - } - cs.UpdateLevel(cID, &c) - - return cID -} - -func (c *SparseR1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { - opt, err := solver.NewConfig(opts...) - if err != nil { - return nil, err - } - - // compute the constraint system solution - var solution []fr.Element - if solution, err = c.solve(witness.Vector().(fr.Vector), opt); err != nil { - return nil, err - } - - var res SparseR1CSSolution - // query l, r, o in Lagrange basis, not blinded - res.L, res.R, res.O = c.evaluateLROSmallDomain(solution) - - return &res, nil -} - -// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. -// solution = [ public | secret | internal ] -func (c *SparseR1CS) evaluateLROSmallDomain(solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { - - //s := int(pk.Domain[0].Cardinality) - s := c.GetNbConstraints() + len(c.Public) // len(spr.Public) is for the placeholder constraints - s = int(ecc.NextPowerOfTwo(uint64(s))) - - var l, r, o []fr.Element - l = make([]fr.Element, s) - r = make([]fr.Element, s) - o = make([]fr.Element, s) - s0 := solution[0] - - for i := 0; i < len(c.Public); i++ { // placeholders - l[i] = solution[i] - r[i] = s0 - o[i] = s0 - } - offset := len(c.Public) - for i := 0; i < len(c.Constraints); i++ { // constraints - l[offset+i] = solution[c.Constraints[i].L.WireID()] - r[offset+i] = solution[c.Constraints[i].R.WireID()] - o[offset+i] = solution[c.Constraints[i].O.WireID()] - } - offset += len(c.Constraints) - - for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) - l[offset+i] = s0 - r[offset+i] = s0 - o[offset+i] = s0 - } - - return l, r, o - -} - -// Solve sets all the wires. -// solution.values = [publicInputs | secretInputs | internalVariables ] -// witness: contains the input variables -// it returns the full slice of wires -func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, error) { - log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "plonk").Logger() - - // set the slices holding the solution.values and monitoring which variables have been solved - nbVariables := cs.NbInternalVariables + len(cs.Secret) + len(cs.Public) - - start := time.Now() - - expectedWitnessSize := len(cs.Public) + len(cs.Secret) - if len(witness) != expectedWitnessSize { - return make(fr.Vector, nbVariables), fmt.Errorf( - "invalid witness size, got %d, expected %d = %d (public) + %d (secret)", - len(witness), - expectedWitnessSize, - len(cs.Public), - len(cs.Secret), - ) - } - - // keep track of wire that have a value - solution, err := newSolution(&cs.System, nbVariables, opt.HintFunctions, cs.Coefficients) - if err != nil { - return solution.values, err - } - - // solution.values = [publicInputs | secretInputs | internalVariables ] -> we fill publicInputs | secretInputs - copy(solution.values, witness) - for i := 0; i < len(witness); i++ { - solution.solved[i] = true - } - - // keep track of the number of wire instantiations we do, for a sanity check to ensure - // we instantiated all wires - solution.nbSolved += uint64(len(witness)) - - // defer log printing once all solution.values are computed - defer solution.printLogs(opt.Logger, cs.Logs) - - // batch invert the coefficients to avoid many divisions in the solver - coefficientsNegInv := fr.BatchInvert(cs.Coefficients) - for i := 0; i < len(coefficientsNegInv); i++ { - coefficientsNegInv[i].Neg(&coefficientsNegInv[i]) - } - - if err := cs.parallelSolve(&solution, coefficientsNegInv); err != nil { - if unsatisfiedErr, ok := err.(*UnsatisfiedConstraintError); ok { - log.Err(errors.New("unsatisfied constraint")).Int("id", unsatisfiedErr.CID).Send() - } else { - log.Err(err).Send() - } - return solution.values, err - } - - // sanity check; ensure all wires are marked as "instantiated" - if !solution.isValid() { - log.Err(errors.New("solver didn't instantiate all wires")).Send() - panic("solver didn't instantiate all wires") - } - - log.Debug().Dur("took", time.Since(start)).Msg("constraint system solver done") - - return solution.values, nil - -} - -func (cs *SparseR1CS) parallelSolve(solution *solution, coefficientsNegInv fr.Vector) error { - // minWorkPerCPU is the minimum target number of constraint a task should hold - // in other words, if a level has less than minWorkPerCPU, it will not be parallelized and executed - // sequentially without sync. - const minWorkPerCPU = 50.0 - - // cs.Levels has a list of levels, where all constraints in a level l(n) are independent - // and may only have dependencies on previous levels - - var wg sync.WaitGroup - chTasks := make(chan []int, runtime.NumCPU()) - chError := make(chan *UnsatisfiedConstraintError, runtime.NumCPU()) - - // start a worker pool - // each worker wait on chTasks - // a task is a slice of constraint indexes to be solved - for i := 0; i < runtime.NumCPU(); i++ { - go func() { - for t := range chTasks { - for _, i := range t { - // for each constraint in the task, solve it. - if err := cs.solveConstraint(cs.Constraints[i], solution, coefficientsNegInv); err != nil { - chError <- &UnsatisfiedConstraintError{CID: i, Err: err} - wg.Done() - return - } - if err := cs.checkConstraint(cs.Constraints[i], solution); err != nil { - if dID, ok := cs.MDebug[i]; ok { - errMsg := solution.logValue(cs.DebugInfo[dID]) - chError <- &UnsatisfiedConstraintError{CID: i, DebugInfo: &errMsg} - } else { - chError <- &UnsatisfiedConstraintError{CID: i, Err: err} - } - wg.Done() - return - } - } - wg.Done() - } - }() - } - - // clean up pool go routines - defer func() { - close(chTasks) - close(chError) - }() - - // for each level, we push the tasks - for _, level := range cs.Levels { - - // max CPU to use - maxCPU := float64(len(level)) / minWorkPerCPU - - if maxCPU <= 1.0 { - // we do it sequentially - for _, i := range level { - if err := cs.solveConstraint(cs.Constraints[i], solution, coefficientsNegInv); err != nil { - return &UnsatisfiedConstraintError{CID: i, Err: err} - } - if err := cs.checkConstraint(cs.Constraints[i], solution); err != nil { - if dID, ok := cs.MDebug[i]; ok { - errMsg := solution.logValue(cs.DebugInfo[dID]) - return &UnsatisfiedConstraintError{CID: i, DebugInfo: &errMsg} - } - return &UnsatisfiedConstraintError{CID: i, Err: err} - } - } - continue - } - - // number of tasks for this level is set to number of CPU - // but if we don't have enough work for all our CPU, it can be lower. - nbTasks := runtime.NumCPU() - maxTasks := int(math.Ceil(maxCPU)) - if nbTasks > maxTasks { - nbTasks = maxTasks - } - nbIterationsPerCpus := len(level) / nbTasks - - // more CPUs than tasks: a CPU will work on exactly one iteration - // note: this depends on minWorkPerCPU constant - if nbIterationsPerCpus < 1 { - nbIterationsPerCpus = 1 - nbTasks = len(level) - } - - extraTasks := len(level) - (nbTasks * nbIterationsPerCpus) - extraTasksOffset := 0 - - for i := 0; i < nbTasks; i++ { - wg.Add(1) - _start := i*nbIterationsPerCpus + extraTasksOffset - _end := _start + nbIterationsPerCpus - if extraTasks > 0 { - _end++ - extraTasks-- - extraTasksOffset++ - } - // since we're never pushing more than num CPU tasks - // we will never be blocked here - chTasks <- level[_start:_end] - } - - // wait for the level to be done - wg.Wait() - - if len(chError) > 0 { - return <-chError - } - } - - return nil -} - -// computeHints computes wires associated with a hint function, if any -// if there is no remaining wire to solve, returns -1 -// else returns the wire position (L -> 0, R -> 1, O -> 2) -func (cs *SparseR1CS) computeHints(c constraint.SparseR1C, solution *solution) (int, error) { - r := -1 - lID, rID, oID := c.L.WireID(), c.R.WireID(), c.O.WireID() - - if (c.L.CoeffID() != 0 || c.M[0].CoeffID() != 0) && !solution.solved[lID] { - // check if it's a hint - if hint, ok := cs.MHints[lID]; ok { - if err := solution.solveWithHint(lID, hint); err != nil { - return -1, err - } - } else { - r = 0 - } - - } - - if (c.R.CoeffID() != 0 || c.M[1].CoeffID() != 0) && !solution.solved[rID] { - // check if it's a hint - if hint, ok := cs.MHints[rID]; ok { - if err := solution.solveWithHint(rID, hint); err != nil { - return -1, err - } - } else { - r = 1 - } - } - - if (c.O.CoeffID() != 0) && !solution.solved[oID] { - // check if it's a hint - if hint, ok := cs.MHints[oID]; ok { - if err := solution.solveWithHint(oID, hint); err != nil { - return -1, err - } - } else { - r = 2 - } - } - return r, nil -} - -// solveConstraint solve any unsolved wire in given constraint and update the solution -// a SparseR1C may have up to one unsolved wire (excluding hints) -// if it doesn't, then this function returns and does nothing -func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution, coefficientsNegInv fr.Vector) error { - - if c.Commitment == constraint.COMMITTED { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. - return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time - } - - lro, err := cs.computeHints(c, solution) - if err != nil { - return err - } - if lro == -1 { - // no unsolved wire - // can happen if the constraint contained only hint wires. - return nil - } - if lro == 1 { // we solve for R: u1L+u2R+u3LR+u4O+k=0 => R(u2+u3L)+u1L+u4O+k = 0 - if !solution.solved[c.L.WireID()] { - panic("L wire should be instantiated when we solve R") - } - var u1, u2, u3, den, num, v1, v2 fr.Element - u3.Mul(&cs.Coefficients[c.M[0].CoeffID()], &cs.Coefficients[c.M[1].CoeffID()]) - u1.Set(&cs.Coefficients[c.L.CoeffID()]) - u2.Set(&cs.Coefficients[c.R.CoeffID()]) - den.Mul(&u3, &solution.values[c.L.WireID()]).Add(&den, &u2) - - v1 = solution.computeTerm(c.L) - v2 = solution.computeTerm(c.O) - num.Add(&v1, &v2).Add(&num, &cs.Coefficients[c.K]) - - // TODO find a way to do lazy div (/ batch inversion) - num.Div(&num, &den).Neg(&num) - solution.set(c.L.WireID(), num) - return nil - } - - if lro == 0 { // we solve for L: u1L+u2R+u3LR+u4O+k=0 => L(u1+u3R)+u2R+u4O+k = 0 - if !solution.solved[c.R.WireID()] { - panic("R wire should be instantiated when we solve L") - } - var u1, u2, u3, den, num, v1, v2 fr.Element - u3.Mul(&cs.Coefficients[c.M[0].CoeffID()], &cs.Coefficients[c.M[1].CoeffID()]) - u1.Set(&cs.Coefficients[c.L.CoeffID()]) - u2.Set(&cs.Coefficients[c.R.CoeffID()]) - den.Mul(&u3, &solution.values[c.R.WireID()]).Add(&den, &u1) - - v1 = solution.computeTerm(c.R) - v2 = solution.computeTerm(c.O) - num.Add(&v1, &v2).Add(&num, &cs.Coefficients[c.K]) - - // TODO find a way to do lazy div (/ batch inversion) - num.Div(&num, &den).Neg(&num) - solution.set(c.L.WireID(), num) - return nil - - } - // O we solve for O - var o fr.Element - cID, vID := c.O.CoeffID(), c.O.WireID() - - l := solution.computeTerm(c.L) - r := solution.computeTerm(c.R) - m0 := solution.computeTerm(c.M[0]) - m1 := solution.computeTerm(c.M[1]) - - // o = - ((m0 * m1) + l + r + c.K) / c.O - o.Mul(&m0, &m1).Add(&o, &l).Add(&o, &r).Add(&o, &cs.Coefficients[c.K]) - o.Mul(&o, &coefficientsNegInv[cID]) - - solution.set(vID, o) - - return nil -} - -// IsSolved -// Deprecated: use _, err := Solve(...) instead -func (cs *SparseR1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { - _, err := cs.Solve(witness, opts...) - return err -} - -// GetConstraints return the list of SparseR1C and a coefficient resolver -func (cs *SparseR1CS) GetConstraints() ([]constraint.SparseR1C, constraint.Resolver) { - return cs.Constraints, cs -} - -func (cs *SparseR1CS) GetConstraint(i int) *constraint.SparseR1C { - if i < 0 || i >= len(cs.Constraints) { - return nil - } - return &cs.Constraints[i] -} - -func (cs *SparseR1CS) GetCoefficient(i int) (r constraint.Coeff) { - copy(r[:], cs.Coefficients[i][:]) - return -} - -// checkConstraint verifies that the constraint holds -func (cs *SparseR1CS) checkConstraint(c constraint.SparseR1C, solution *solution) error { - - if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. - return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time - } - - l := solution.computeTerm(c.L) - r := solution.computeTerm(c.R) - m0 := solution.computeTerm(c.M[0]) - m1 := solution.computeTerm(c.M[1]) - o := solution.computeTerm(c.O) - - // l + r + (m0 * m1) + o + c.K == 0 - var t fr.Element - t.Mul(&m0, &m1).Add(&t, &l).Add(&t, &r).Add(&t, &o).Add(&t, &cs.Coefficients[c.K]) - if !t.IsZero() { - return fmt.Errorf("qL⋅xa + qR⋅xb + qO⋅xc + qM⋅(xaxb) + qC != 0 → %s + %s + %s + (%s × %s) + %s != 0", - l.String(), - r.String(), - o.String(), - m0.String(), - m1.String(), - cs.Coefficients[c.K].String(), - ) - } - return nil - -} - -// GetNbCoefficients return the number of unique coefficients needed in the R1CS -func (cs *SparseR1CS) GetNbCoefficients() int { - return len(cs.Coefficients) -} - -// CurveID returns curve ID as defined in gnark-crypto (ecc.BLS24-317) -func (cs *SparseR1CS) CurveID() ecc.ID { - return ecc.BLS24_317 -} - -// WriteTo encodes SparseR1CS into provided io.Writer using cbor -func (cs *SparseR1CS) WriteTo(w io.Writer) (int64, error) { - _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written - enc, err := cbor.CoreDetEncOptions().EncMode() - if err != nil { - return 0, err - } - encoder := enc.NewEncoder(&_w) - - // encode our object - err = encoder.Encode(cs) - return _w.N, err -} - -// ReadFrom attempts to decode SparseR1CS from io.Reader using cbor -func (cs *SparseR1CS) ReadFrom(r io.Reader) (int64, error) { - dm, err := cbor.DecOptions{ - MaxArrayElements: 134217728, - MaxMapPairs: 134217728, - }.DecMode() - if err != nil { - return 0, err - } - decoder := dm.NewDecoder(r) - - // initialize coeff table - cs.CoeffTable = newCoeffTable(0) - - if err := decoder.Decode(cs); err != nil { - return int64(decoder.NumBytesRead()), err - } - - if err := cs.CheckSerializationHeader(); err != nil { - return int64(decoder.NumBytesRead()), err - } - - return int64(decoder.NumBytesRead()), nil -} diff --git a/constraint/bls24-317/r1cs_test.go b/constraint/bls24-317/r1cs_test.go index eff1f06499..ef2a685d08 100644 --- a/constraint/bls24-317/r1cs_test.go +++ b/constraint/bls24-317/r1cs_test.go @@ -20,6 +20,7 @@ import ( "bytes" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/frontend/cs/scs" "github.com/consensys/gnark/internal/backend/circuits" "reflect" "testing" @@ -76,10 +77,11 @@ func TestSerialization(t *testing.T) { if diff := cmp.Diff(r1cs1, &reconstructed, cmpopts.IgnoreFields(cs.R1CS{}, "System.q", - "arithEngine", + "field", "CoeffTable.mCoeffs", "System.lbWireLevel", "System.lbHints", + "System.genericHint", "System.SymbolTable", "System.lbOutputs", "System.bitLen")); diff != "" { @@ -147,12 +149,6 @@ func (circuit *circuit) Define(api frontend.API) error { func BenchmarkSolve(b *testing.B) { - var c circuit - ccs, err := frontend.Compile(fr.Modulus(), r1cs.NewBuilder, &c) - if err != nil { - b.Fatal(err) - } - var w circuit w.X = 1 w.Y = 1 @@ -161,8 +157,32 @@ func BenchmarkSolve(b *testing.B) { b.Fatal(err) } - b.ResetTimer() - for i := 0; i < b.N; i++ { - _ = ccs.IsSolved(witness) - } + b.Run("scs", func(b *testing.B) { + var c circuit + ccs, err := frontend.Compile(fr.Modulus(), scs.NewBuilder, &c) + if err != nil { + b.Fatal(err) + } + b.Log("scs nbConstraints", ccs.GetNbConstraints()) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = ccs.IsSolved(witness) + } + }) + + b.Run("r1cs", func(b *testing.B) { + var c circuit + ccs, err := frontend.Compile(fr.Modulus(), r1cs.NewBuilder, &c, frontend.WithCompressThreshold(10)) + if err != nil { + b.Fatal(err) + } + b.Log("r1cs nbConstraints", ccs.GetNbConstraints()) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = ccs.IsSolved(witness) + } + }) + } diff --git a/constraint/bls24-317/solution.go b/constraint/bls24-317/solution.go deleted file mode 100644 index 789d74ac9b..0000000000 --- a/constraint/bls24-317/solution.go +++ /dev/null @@ -1,383 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// 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. - -// Code generated by gnark DO NOT EDIT - -package cs - -import ( - "errors" - "fmt" - "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/debug" - "github.com/rs/zerolog" - "io" - "math/big" - "strconv" - "strings" - "sync/atomic" - - "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" -) - -// solution represents elements needed to compute -// a solution to a R1CS or SparseR1CS -type solution struct { - values, coefficients []fr.Element - solved []bool - nbSolved uint64 - mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function - st *debug.SymbolTable - cs *constraint.System -} - -func newSolution(cs *constraint.System, nbWires int, hintFunctions map[solver.HintID]solver.Hint, coefficients []fr.Element) (solution, error) { - - s := solution{ - cs: cs, - st: &cs.SymbolTable, - values: make([]fr.Element, nbWires), - coefficients: coefficients, - solved: make([]bool, nbWires), - mHintsFunctions: hintFunctions, - } - - // hintsDependencies is from compile time; it contains the list of hints the solver **needs** - var missing []string - for hintUUID, hintID := range cs.MHintsDependencies { - if _, ok := s.mHintsFunctions[hintUUID]; !ok { - missing = append(missing, hintID) - } - } - - if len(missing) > 0 { - return s, fmt.Errorf("solver missing hint(s): %v", missing) - } - - return s, nil -} - -func (s *solution) set(id int, value fr.Element) { - if s.solved[id] { - panic("solving the same wire twice should never happen.") - } - s.values[id] = value - s.solved[id] = true - atomic.AddUint64(&s.nbSolved, 1) - // s.nbSolved++ -} - -func (s *solution) isValid() bool { - return int(s.nbSolved) == len(s.values) -} - -// computeTerm computes coeff*variable -func (s *solution) computeTerm(t constraint.Term) fr.Element { - cID, vID := t.CoeffID(), t.WireID() - if cID != 0 && !s.solved[vID] { - panic("computing a term with an unsolved wire") - } - switch cID { - case constraint.CoeffIdZero: - return fr.Element{} - case constraint.CoeffIdOne: - return s.values[vID] - case constraint.CoeffIdTwo: - var res fr.Element - res.Double(&s.values[vID]) - return res - case constraint.CoeffIdMinusOne: - var res fr.Element - res.Neg(&s.values[vID]) - return res - default: - var res fr.Element - res.Mul(&s.coefficients[cID], &s.values[vID]) - return res - } -} - -// r += (t.coeff*t.value) -func (s *solution) accumulateInto(t constraint.Term, r *fr.Element) { - cID := t.CoeffID() - - if t.IsConstant() { - // needed for logs, we may want to not put this in the hot path if we need to - // optimize constraint system solver further. - r.Add(r, &s.coefficients[cID]) - return - } - - vID := t.WireID() - switch cID { - case constraint.CoeffIdZero: - return - case constraint.CoeffIdOne: - r.Add(r, &s.values[vID]) - case constraint.CoeffIdTwo: - var res fr.Element - res.Double(&s.values[vID]) - r.Add(r, &res) - case constraint.CoeffIdMinusOne: - r.Sub(r, &s.values[vID]) - default: - var res fr.Element - res.Mul(&s.coefficients[cID], &s.values[vID]) - r.Add(r, &res) - } -} - -// solveHint compute solution.values[vID] using provided solver hint -func (s *solution) solveWithHint(vID int, hID int) error { - // skip if the wire is already solved by a call to the same hint - // function on the same inputs - if s.solved[vID] { - return nil - } - - h := &s.cs.HintMappings[hID] - - // ensure hint function was provided - f, ok := s.mHintsFunctions[h.HintID] - if !ok { - return errors.New("missing hint function") - } - - // tmp IO big int memory - nbInputs := len(h.Inputs) - nbOutputs := len(h.Outputs) - inputs := make([]*big.Int, nbInputs) - outputs := make([]*big.Int, nbOutputs) - for i := 0; i < nbOutputs; i++ { - outputs[i] = big.NewInt(0) - } - - q := fr.Modulus() - - // for each input, we set its big int value, IF all the wires are solved - // the only case where all wires may not be solved, is if one of the input of this hint - // is the output of another hint. - // it is safe to recursively solve this with the parallel solver, since all hints-output wires - // that we can solve this way are marked to be solved with the current constraint we are processing. - recursiveSolve := func(t constraint.Term) error { - if t.IsConstant() { - return nil - } - wID := t.WireID() - if s.solved[wID] { - return nil - } - // unsolved dependency - if h, ok := s.cs.MHints[wID]; ok { - // solve recursively. - return s.solveWithHint(wID, h) - } - - // it's not a hint, we panic. - panic("solver can't compute hint; one or more input wires are unsolved") - } - - for i := 0; i < nbInputs; i++ { - inputs[i] = big.NewInt(0) - - var v fr.Element - for _, term := range h.Inputs[i] { - if err := recursiveSolve(term); err != nil { - return err - } - s.accumulateInto(term, &v) - } - v.BigInt(inputs[i]) - } - - err := f(q, inputs, outputs) - - var v fr.Element - for i := range outputs { - v.SetBigInt(outputs[i]) - s.set(h.Outputs[i], v) - } - - return err -} - -func (s *solution) printLogs(log zerolog.Logger, logs []constraint.LogEntry) { - if log.GetLevel() == zerolog.Disabled { - return - } - - for i := 0; i < len(logs); i++ { - logLine := s.logValue(logs[i]) - log.Debug().Str(zerolog.CallerFieldName, logs[i].Caller).Msg(logLine) - } -} - -const unsolvedVariable = "" - -func (s *solution) logValue(log constraint.LogEntry) string { - var toResolve []interface{} - var ( - eval fr.Element - missingValue bool - ) - for j := 0; j < len(log.ToResolve); j++ { - // before eval le - - missingValue = false - eval.SetZero() - - for _, t := range log.ToResolve[j] { - // for each term in the linear expression - - cID, vID := t.CoeffID(), t.WireID() - if t.IsConstant() { - // just add the constant - eval.Add(&eval, &s.coefficients[cID]) - continue - } - - if !s.solved[vID] { - missingValue = true - break // stop the loop we can't evaluate. - } - - tv := s.computeTerm(t) - eval.Add(&eval, &tv) - } - - // after - if missingValue { - toResolve = append(toResolve, unsolvedVariable) - } else { - // we have to append our accumulator - toResolve = append(toResolve, eval.String()) - } - - } - if len(log.Stack) > 0 { - var sbb strings.Builder - for _, lID := range log.Stack { - location := s.st.Locations[lID] - function := s.st.Functions[location.FunctionID] - - sbb.WriteString(function.Name) - sbb.WriteByte('\n') - sbb.WriteByte('\t') - sbb.WriteString(function.Filename) - sbb.WriteByte(':') - sbb.WriteString(strconv.Itoa(int(location.Line))) - sbb.WriteByte('\n') - } - toResolve = append(toResolve, sbb.String()) - } - return fmt.Sprintf(log.Format, toResolve...) -} - -// UnsatisfiedConstraintError wraps an error with useful metadata on the unsatisfied constraint -type UnsatisfiedConstraintError struct { - Err error - CID int // constraint ID - DebugInfo *string // optional debug info -} - -func (r *UnsatisfiedConstraintError) Error() string { - if r.DebugInfo != nil { - return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, *r.DebugInfo) - } - return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, r.Err.Error()) -} - -// R1CSSolution represent a valid assignment to all the variables in the constraint system. -// The vector W such that Aw o Bw - Cw = 0 -type R1CSSolution struct { - W fr.Vector - A, B, C fr.Vector -} - -func (t *R1CSSolution) WriteTo(w io.Writer) (int64, error) { - n, err := t.W.WriteTo(w) - if err != nil { - return n, err - } - a, err := t.A.WriteTo(w) - n += a - if err != nil { - return n, err - } - a, err = t.B.WriteTo(w) - n += a - if err != nil { - return n, err - } - a, err = t.C.WriteTo(w) - n += a - return n, err -} - -func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { - n, err := t.W.ReadFrom(r) - if err != nil { - return n, err - } - a, err := t.A.ReadFrom(r) - a += n - if err != nil { - return n, err - } - a, err = t.B.ReadFrom(r) - a += n - if err != nil { - return n, err - } - a, err = t.C.ReadFrom(r) - n += a - return n, err -} - -// SparseR1CSSolution represent a valid assignment to all the variables in the constraint system. -type SparseR1CSSolution struct { - L, R, O fr.Vector -} - -func (t *SparseR1CSSolution) WriteTo(w io.Writer) (int64, error) { - n, err := t.L.WriteTo(w) - if err != nil { - return n, err - } - a, err := t.R.WriteTo(w) - n += a - if err != nil { - return n, err - } - a, err = t.O.WriteTo(w) - n += a - return n, err - -} - -func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { - n, err := t.L.ReadFrom(r) - if err != nil { - return n, err - } - a, err := t.R.ReadFrom(r) - a += n - if err != nil { - return n, err - } - a, err = t.O.ReadFrom(r) - a += n - return n, err -} diff --git a/constraint/bls24-317/solver.go b/constraint/bls24-317/solver.go new file mode 100644 index 0000000000..17b06208d3 --- /dev/null +++ b/constraint/bls24-317/solver.go @@ -0,0 +1,614 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package cs + +import ( + "errors" + "fmt" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/field/pool" + "github.com/consensys/gnark/constraint" + csolver "github.com/consensys/gnark/constraint/solver" + "github.com/rs/zerolog" + "math" + "math/big" + "runtime" + "strconv" + "strings" + "sync" + "sync/atomic" + + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" +) + +// solver represent the state of the solver during a call to System.Solve(...) +type solver struct { + *system + + // values and solved are index by the wire (variable) id + values []fr.Element + solved []bool + nbSolved uint64 + + // maps hintID to hint function + mHintsFunctions map[csolver.HintID]csolver.Hint + + // used to out api.Println + logger zerolog.Logger + + a, b, c fr.Vector // R1CS solver will compute the a,b,c matrices + + q *big.Int +} + +func newSolver(cs *system, witness fr.Vector, opts ...csolver.Option) (*solver, error) { + // parse options + opt, err := csolver.NewConfig(opts...) + if err != nil { + return nil, err + } + + // check witness size + witnessOffset := 0 + if cs.Type == constraint.SystemR1CS { + witnessOffset++ + } + + nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables + expectedWitnessSize := len(cs.Public) - witnessOffset + len(cs.Secret) + + if len(witness) != expectedWitnessSize { + return nil, fmt.Errorf("invalid witness size, got %d, expected %d", len(witness), expectedWitnessSize) + } + + // check all hints are there + hintFunctions := opt.HintFunctions + + // hintsDependencies is from compile time; it contains the list of hints the solver **needs** + var missing []string + for hintUUID, hintID := range cs.MHintsDependencies { + if _, ok := hintFunctions[hintUUID]; !ok { + missing = append(missing, hintID) + } + } + + if len(missing) > 0 { + return nil, fmt.Errorf("solver missing hint(s): %v", missing) + } + + s := solver{ + system: cs, + values: make([]fr.Element, nbWires), + solved: make([]bool, nbWires), + mHintsFunctions: hintFunctions, + logger: opt.Logger, + q: cs.Field(), + } + + // set the witness indexes as solved + if witnessOffset == 1 { + s.solved[0] = true // ONE_WIRE + s.values[0].SetOne() + } + copy(s.values[witnessOffset:], witness) + for i := range witness { + s.solved[i+witnessOffset] = true + } + + // keep track of the number of wire instantiations we do, for a post solve sanity check + // to ensure we instantiated all wires + s.nbSolved += uint64(len(witness) + witnessOffset) + + if s.Type == constraint.SystemR1CS { + n := ecc.NextPowerOfTwo(uint64(cs.GetNbConstraints())) + s.a = make(fr.Vector, cs.GetNbConstraints(), n) + s.b = make(fr.Vector, cs.GetNbConstraints(), n) + s.c = make(fr.Vector, cs.GetNbConstraints(), n) + } + + return &s, nil +} + +func (s *solver) set(id int, value fr.Element) { + if s.solved[id] { + panic("solving the same wire twice should never happen.") + } + s.values[id] = value + s.solved[id] = true + atomic.AddUint64(&s.nbSolved, 1) +} + +// computeTerm computes coeff*variable +// TODO @gbotrel check if t is a Constant only +func (s *solver) computeTerm(t constraint.Term) fr.Element { + cID, vID := t.CoeffID(), t.WireID() + if cID != 0 && !s.solved[vID] { + panic("computing a term with an unsolved wire") + } + switch cID { + case constraint.CoeffIdZero: + return fr.Element{} + case constraint.CoeffIdOne: + return s.values[vID] + case constraint.CoeffIdTwo: + var res fr.Element + res.Double(&s.values[vID]) + return res + case constraint.CoeffIdMinusOne: + var res fr.Element + res.Neg(&s.values[vID]) + return res + default: + var res fr.Element + res.Mul(&s.Coefficients[cID], &s.values[vID]) + return res + } +} + +// r += (t.coeff*t.value) +// TODO @gbotrel check t.IsConstant on the caller side when necessary +func (s *solver) accumulateInto(t constraint.Term, r *fr.Element) { + cID := t.CoeffID() + vID := t.WireID() + + switch cID { + case constraint.CoeffIdZero: + return + case constraint.CoeffIdOne: + r.Add(r, &s.values[vID]) + case constraint.CoeffIdTwo: + var res fr.Element + res.Double(&s.values[vID]) + r.Add(r, &res) + case constraint.CoeffIdMinusOne: + r.Sub(r, &s.values[vID]) + default: + var res fr.Element + res.Mul(&s.Coefficients[cID], &s.values[vID]) + r.Add(r, &res) + } +} + +// solveWithHint executes a hint and assign the result to its defined outputs. +func (s *solver) solveWithHint(h *constraint.HintMapping) error { + // ensure hint function was provided + f, ok := s.mHintsFunctions[h.HintID] + if !ok { + return errors.New("missing hint function") + } + + // tmp IO big int memory + nbInputs := len(h.Inputs) + nbOutputs := int(h.OutputRange.End - h.OutputRange.Start) + inputs := make([]*big.Int, nbInputs) + outputs := make([]*big.Int, nbOutputs) + for i := 0; i < nbOutputs; i++ { + outputs[i] = pool.BigInt.Get() + outputs[i].SetUint64(0) + } + + q := pool.BigInt.Get() + q.Set(s.q) + + for i := 0; i < nbInputs; i++ { + var v fr.Element + for _, term := range h.Inputs[i] { + if term.IsConstant() { + v.Add(&v, &s.Coefficients[term.CoeffID()]) + continue + } + s.accumulateInto(term, &v) + } + inputs[i] = pool.BigInt.Get() + v.BigInt(inputs[i]) + } + + err := f(q, inputs, outputs) + + var v fr.Element + for i := range outputs { + v.SetBigInt(outputs[i]) + s.set(int(h.OutputRange.Start)+i, v) + pool.BigInt.Put(outputs[i]) + } + + for i := range inputs { + pool.BigInt.Put(inputs[i]) + } + + pool.BigInt.Put(q) + + return err +} + +func (s *solver) printLogs(logs []constraint.LogEntry) { + if s.logger.GetLevel() == zerolog.Disabled { + return + } + + for i := 0; i < len(logs); i++ { + logLine := s.logValue(logs[i]) + s.logger.Debug().Str(zerolog.CallerFieldName, logs[i].Caller).Msg(logLine) + } +} + +const unsolvedVariable = "" + +func (s *solver) logValue(log constraint.LogEntry) string { + var toResolve []interface{} + var ( + eval fr.Element + missingValue bool + ) + for j := 0; j < len(log.ToResolve); j++ { + // before eval le + + missingValue = false + eval.SetZero() + + for _, t := range log.ToResolve[j] { + // for each term in the linear expression + + cID, vID := t.CoeffID(), t.WireID() + if t.IsConstant() { + // just add the constant + eval.Add(&eval, &s.Coefficients[cID]) + continue + } + + if !s.solved[vID] { + missingValue = true + break // stop the loop we can't evaluate. + } + + tv := s.computeTerm(t) + eval.Add(&eval, &tv) + } + + // after + if missingValue { + toResolve = append(toResolve, unsolvedVariable) + } else { + // we have to append our accumulator + toResolve = append(toResolve, eval.String()) + } + + } + if len(log.Stack) > 0 { + var sbb strings.Builder + for _, lID := range log.Stack { + location := s.SymbolTable.Locations[lID] + function := s.SymbolTable.Functions[location.FunctionID] + + sbb.WriteString(function.Name) + sbb.WriteByte('\n') + sbb.WriteByte('\t') + sbb.WriteString(function.Filename) + sbb.WriteByte(':') + sbb.WriteString(strconv.Itoa(int(location.Line))) + sbb.WriteByte('\n') + } + toResolve = append(toResolve, sbb.String()) + } + return fmt.Sprintf(log.Format, toResolve...) +} + +// divByCoeff sets res = res / t.Coeff +func (solver *solver) divByCoeff(res *fr.Element, cID uint32) { + switch cID { + case constraint.CoeffIdOne: + return + case constraint.CoeffIdMinusOne: + res.Neg(res) + case constraint.CoeffIdZero: + panic("division by 0") + default: + // this is slow, but shouldn't happen as divByCoeff is called to + // remove the coeff of an unsolved wire + // but unsolved wires are (in gnark frontend) systematically set with a coeff == 1 or -1 + res.Div(res, &solver.Coefficients[cID]) + } +} + +// Implement constraint.Solver +func (s *solver) GetValue(cID, vID uint32) constraint.Element { + var r constraint.Element + e := s.computeTerm(constraint.Term{CID: cID, VID: vID}) + copy(r[:], e[:]) + return r +} +func (s *solver) GetCoeff(cID uint32) constraint.Element { + var r constraint.Element + copy(r[:], s.Coefficients[cID][:]) + return r +} +func (s *solver) SetValue(vID uint32, f constraint.Element) { + s.set(int(vID), *(*fr.Element)(f[:])) +} + +func (s *solver) IsSolved(vID uint32) bool { + return s.solved[vID] +} + +// processInstruction decodes the instruction and execute blueprint-defined logic. +// an instruction can encode a hint, a custom constraint or a generic constraint. +func (solver *solver) processInstruction(inst constraint.Instruction, scratch *scratch) error { + // fetch the blueprint + blueprint := solver.Blueprints[inst.BlueprintID] + calldata := solver.GetCallData(inst) + cID := inst.ConstraintOffset // here we have 1 constraint in the instruction only + + if solver.Type == constraint.SystemR1CS { + if bc, ok := blueprint.(constraint.BlueprintR1C); ok { + // TODO @gbotrel we use the solveR1C method for now, having user-defined + // blueprint for R1CS would require constraint.Solver interface to add methods + // to set a,b,c since it's more efficient to compute these while we solve. + bc.DecompressR1C(&scratch.tR1C, calldata) + return solver.solveR1C(cID, &scratch.tR1C) + } + } else if solver.Type == constraint.SystemSparseR1CS { + // blueprint declared "I know how to solve this." + if bc, ok := blueprint.(constraint.BlueprintSolvable); ok { + if err := bc.Solve(solver, calldata); err != nil { + return solver.wrapErrWithDebugInfo(cID, err) + } + return nil + } + } + + // blueprint encodes a hint, we execute. + // TODO @gbotrel may be worth it to move hint logic in blueprint "solve" + if bc, ok := blueprint.(constraint.BlueprintHint); ok { + bc.DecompressHint(&scratch.tHint, calldata) + return solver.solveWithHint(&scratch.tHint) + } + + return nil +} + +// run runs the solver. it return an error if a constraint is not satisfied or if not all wires +// were instantiated. +func (solver *solver) run() error { + // minWorkPerCPU is the minimum target number of constraint a task should hold + // in other words, if a level has less than minWorkPerCPU, it will not be parallelized and executed + // sequentially without sync. + const minWorkPerCPU = 50.0 // TODO @gbotrel revisit that with blocks. + + // cs.Levels has a list of levels, where all constraints in a level l(n) are independent + // and may only have dependencies on previous levels + // for each constraint + // we are guaranteed that each R1C contains at most one unsolved wire + // first we solve the unsolved wire (if any) + // then we check that the constraint is valid + // if a[i] * b[i] != c[i]; it means the constraint is not satisfied + var wg sync.WaitGroup + chTasks := make(chan []int, runtime.NumCPU()) + chError := make(chan error, runtime.NumCPU()) + + // start a worker pool + // each worker wait on chTasks + // a task is a slice of constraint indexes to be solved + for i := 0; i < runtime.NumCPU(); i++ { + go func() { + var scratch scratch + for t := range chTasks { + for _, i := range t { + if err := solver.processInstruction(solver.Instructions[i], &scratch); err != nil { + chError <- err + wg.Done() + return + } + } + wg.Done() + } + }() + } + + // clean up pool go routines + defer func() { + close(chTasks) + close(chError) + }() + + var scratch scratch + + // for each level, we push the tasks + for _, level := range solver.Levels { + + // max CPU to use + maxCPU := float64(len(level)) / minWorkPerCPU + + if maxCPU <= 1.0 { + // we do it sequentially + for _, i := range level { + if err := solver.processInstruction(solver.Instructions[i], &scratch); err != nil { + return err + } + } + continue + } + + // number of tasks for this level is set to number of CPU + // but if we don't have enough work for all our CPU, it can be lower. + nbTasks := runtime.NumCPU() + maxTasks := int(math.Ceil(maxCPU)) + if nbTasks > maxTasks { + nbTasks = maxTasks + } + nbIterationsPerCpus := len(level) / nbTasks + + // more CPUs than tasks: a CPU will work on exactly one iteration + // note: this depends on minWorkPerCPU constant + if nbIterationsPerCpus < 1 { + nbIterationsPerCpus = 1 + nbTasks = len(level) + } + + extraTasks := len(level) - (nbTasks * nbIterationsPerCpus) + extraTasksOffset := 0 + + for i := 0; i < nbTasks; i++ { + wg.Add(1) + _start := i*nbIterationsPerCpus + extraTasksOffset + _end := _start + nbIterationsPerCpus + if extraTasks > 0 { + _end++ + extraTasks-- + extraTasksOffset++ + } + // since we're never pushing more than num CPU tasks + // we will never be blocked here + chTasks <- level[_start:_end] + } + + // wait for the level to be done + wg.Wait() + + if len(chError) > 0 { + return <-chError + } + } + + if int(solver.nbSolved) != len(solver.values) { + return errors.New("solver didn't assign a value to all wires") + } + + return nil +} + +// solveR1C compute unsolved wires in the constraint, if any and set the solver accordingly +// +// returns an error if the solver called a hint function that errored +// returns false, nil if there was no wire to solve +// returns true, nil if exactly one wire was solved. In that case, it is redundant to check that +// the constraint is satisfied later. +func (solver *solver) solveR1C(cID uint32, r *constraint.R1C) error { + a, b, c := &solver.a[cID], &solver.b[cID], &solver.c[cID] + + // the index of the non-zero entry shows if L, R or O has an uninstantiated wire + // the content is the ID of the wire non instantiated + var loc uint8 + + var termToCompute constraint.Term + + processLExp := func(l constraint.LinearExpression, val *fr.Element, locValue uint8) { + for _, t := range l { + vID := t.WireID() + + // wire is already computed, we just accumulate in val + if solver.solved[vID] { + solver.accumulateInto(t, val) + continue + } + + if loc != 0 { + panic("found more than one wire to instantiate") + } + termToCompute = t + loc = locValue + } + } + + processLExp(r.L, a, 1) + processLExp(r.R, b, 2) + processLExp(r.O, c, 3) + + if loc == 0 { + // there is nothing to solve, may happen if we have an assertion + // (ie a constraints that doesn't yield any output) + // or if we solved the unsolved wires with hint functions + var check fr.Element + if !check.Mul(a, b).Equal(c) { + return solver.wrapErrWithDebugInfo(cID, fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String())) + } + return nil + } + + // we compute the wire value and instantiate it + wID := termToCompute.WireID() + + // solver result + var wire fr.Element + + switch loc { + case 1: + if !b.IsZero() { + wire.Div(c, b). + Sub(&wire, a) + a.Add(a, &wire) + } else { + // we didn't actually ensure that a * b == c + var check fr.Element + if !check.Mul(a, b).Equal(c) { + return solver.wrapErrWithDebugInfo(cID, fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String())) + } + } + case 2: + if !a.IsZero() { + wire.Div(c, a). + Sub(&wire, b) + b.Add(b, &wire) + } else { + var check fr.Element + if !check.Mul(a, b).Equal(c) { + return solver.wrapErrWithDebugInfo(cID, fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String())) + } + } + case 3: + wire.Mul(a, b). + Sub(&wire, c) + + c.Add(c, &wire) + } + + // wire is the term (coeff * value) + // but in the solver we want to store the value only + // note that in gnark frontend, coeff here is always 1 or -1 + solver.divByCoeff(&wire, termToCompute.CID) + solver.set(wID, wire) + + return nil +} + +// UnsatisfiedConstraintError wraps an error with useful metadata on the unsatisfied constraint +type UnsatisfiedConstraintError struct { + Err error + CID int // constraint ID + DebugInfo *string // optional debug info +} + +func (r *UnsatisfiedConstraintError) Error() string { + if r.DebugInfo != nil { + return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, *r.DebugInfo) + } + return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, r.Err.Error()) +} + +func (solver *solver) wrapErrWithDebugInfo(cID uint32, err error) *UnsatisfiedConstraintError { + var debugInfo *string + if dID, ok := solver.MDebug[int(cID)]; ok { + debugInfo = new(string) + *debugInfo = solver.logValue(solver.DebugInfo[dID]) + } + return &UnsatisfiedConstraintError{CID: int(cID), Err: err, DebugInfo: debugInfo} +} + +// temporary variables to avoid memallocs in hotloop +type scratch struct { + tR1C constraint.R1C + tHint constraint.HintMapping +} diff --git a/constraint/bls24-317/system.go b/constraint/bls24-317/system.go new file mode 100644 index 0000000000..2730d2cf15 --- /dev/null +++ b/constraint/bls24-317/system.go @@ -0,0 +1,365 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package cs + +import ( + "github.com/fxamacker/cbor/v2" + "io" + "time" + + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint" + csolver "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/internal/backend/ioutils" + "github.com/consensys/gnark/logger" + "reflect" + + "github.com/consensys/gnark-crypto/ecc" + + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" +) + +type R1CS = system +type SparseR1CS = system + +// system is a curved-typed constraint.System with a concrete coefficient table (fr.Element) +type system struct { + constraint.System + CoeffTable + field +} + +func NewR1CS(capacity int) *R1CS { + return newSystem(capacity, constraint.SystemR1CS) +} + +func NewSparseR1CS(capacity int) *SparseR1CS { + return newSystem(capacity, constraint.SystemSparseR1CS) +} + +func newSystem(capacity int, t constraint.SystemType) *system { + return &system{ + System: constraint.NewSystem(fr.Modulus(), capacity, t), + CoeffTable: newCoeffTable(capacity / 10), + } +} + +// Solve solves the constraint system with provided witness. +// If it's a R1CS returns R1CSSolution +// If it's a SparseR1CS returns SparseR1CSSolution +func (cs *system) Solve(witness witness.Witness, opts ...csolver.Option) (any, error) { + log := logger.Logger().With().Int("nbConstraints", cs.GetNbConstraints()).Logger() + start := time.Now() + + v := witness.Vector().(fr.Vector) + + // init the solver + solver, err := newSolver(cs, v, opts...) + if err != nil { + log.Err(err).Send() + return nil, err + } + + // defer log printing once all solver.values are computed + // (or sooner, if a constraint is not satisfied) + defer solver.printLogs(cs.Logs) + + // run it. + if err := solver.run(); err != nil { + log.Err(err).Send() + return nil, err + } + + log.Debug().Dur("took", time.Since(start)).Msg("constraint system solver done") + + // format the solution + // TODO @gbotrel revisit post-refactor + if cs.Type == constraint.SystemR1CS { + var res R1CSSolution + res.W = solver.values + res.A = solver.a + res.B = solver.b + res.C = solver.c + return &res, nil + } else { + // sparse R1CS + var res SparseR1CSSolution + // query l, r, o in Lagrange basis, not blinded + res.L, res.R, res.O = evaluateLROSmallDomain(cs, solver.values) + + return &res, nil + } + +} + +// IsSolved +// Deprecated: use _, err := Solve(...) instead +func (cs *system) IsSolved(witness witness.Witness, opts ...csolver.Option) error { + _, err := cs.Solve(witness, opts...) + return err +} + +// GetR1Cs return the list of R1C +func (cs *system) GetR1Cs() []constraint.R1C { + toReturn := make([]constraint.R1C, 0, cs.GetNbConstraints()) + + for _, inst := range cs.Instructions { + blueprint := cs.Blueprints[inst.BlueprintID] + if bc, ok := blueprint.(constraint.BlueprintR1C); ok { + var r1c constraint.R1C + bc.DecompressR1C(&r1c, cs.GetCallData(inst)) + toReturn = append(toReturn, r1c) + } else { + panic("not implemented") + } + } + return toReturn +} + +// GetNbCoefficients return the number of unique coefficients needed in the R1CS +func (cs *system) GetNbCoefficients() int { + return len(cs.Coefficients) +} + +// CurveID returns curve ID as defined in gnark-crypto +func (cs *system) CurveID() ecc.ID { + return ecc.BLS24_317 +} + +// WriteTo encodes R1CS into provided io.Writer using cbor +func (cs *system) WriteTo(w io.Writer) (int64, error) { + _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written + ts := getTagSet() + enc, err := cbor.CoreDetEncOptions().EncModeWithTags(ts) + if err != nil { + return 0, err + } + encoder := enc.NewEncoder(&_w) + + // encode our object + err = encoder.Encode(cs) + return _w.N, err +} + +// ReadFrom attempts to decode R1CS from io.Reader using cbor +func (cs *system) ReadFrom(r io.Reader) (int64, error) { + ts := getTagSet() + dm, err := cbor.DecOptions{ + MaxArrayElements: 134217728, + MaxMapPairs: 134217728, + }.DecModeWithTags(ts) + + if err != nil { + return 0, err + } + decoder := dm.NewDecoder(r) + + // initialize coeff table + cs.CoeffTable = newCoeffTable(0) + + if err := decoder.Decode(&cs); err != nil { + return int64(decoder.NumBytesRead()), err + } + + if err := cs.CheckSerializationHeader(); err != nil { + return int64(decoder.NumBytesRead()), err + } + + return int64(decoder.NumBytesRead()), nil +} + +func (cs *system) GetCoefficient(i int) (r constraint.Element) { + copy(r[:], cs.Coefficients[i][:]) + return +} + +// GetSparseR1Cs return the list of SparseR1C +func (cs *system) GetSparseR1Cs() []constraint.SparseR1C { + + toReturn := make([]constraint.SparseR1C, 0, cs.GetNbConstraints()) + + for _, inst := range cs.Instructions { + blueprint := cs.Blueprints[inst.BlueprintID] + if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { + var sparseR1C constraint.SparseR1C + calldata := cs.CallData[inst.StartCallData : inst.StartCallData+uint64(blueprint.NbInputs())] + bc.DecompressSparseR1C(&sparseR1C, calldata) + toReturn = append(toReturn, sparseR1C) + } else { + panic("not implemented") + } + } + return toReturn +} + +// evaluateLROSmallDomain extracts the solver l, r, o, and returns it in lagrange form. +// solver = [ public | secret | internal ] +// TODO @gbotrel refactor; this seems to be a small util function for plonk +func evaluateLROSmallDomain(cs *system, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { + + //s := int(pk.Domain[0].Cardinality) + s := cs.GetNbConstraints() + len(cs.Public) // len(spr.Public) is for the placeholder constraints + s = int(ecc.NextPowerOfTwo(uint64(s))) + + var l, r, o []fr.Element + l = make([]fr.Element, s) + r = make([]fr.Element, s) + o = make([]fr.Element, s) + s0 := solution[0] + + for i := 0; i < len(cs.Public); i++ { // placeholders + l[i] = solution[i] + r[i] = s0 + o[i] = s0 + } + offset := len(cs.Public) + nbConstraints := cs.GetNbConstraints() + + var sparseR1C constraint.SparseR1C + j := 0 + for _, inst := range cs.Instructions { + blueprint := cs.Blueprints[inst.BlueprintID] + if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { + bc.DecompressSparseR1C(&sparseR1C, cs.GetCallData(inst)) + + l[offset+j] = solution[sparseR1C.XA] + r[offset+j] = solution[sparseR1C.XB] + o[offset+j] = solution[sparseR1C.XC] + j++ + } + } + + offset += nbConstraints + + for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solver[0]) + l[offset+i] = s0 + r[offset+i] = s0 + o[offset+i] = s0 + } + + return l, r, o + +} + +// R1CSSolution represent a valid assignment to all the variables in the constraint system. +// The vector W such that Aw o Bw - Cw = 0 +type R1CSSolution struct { + W fr.Vector + A, B, C fr.Vector +} + +func (t *R1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.W.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.A.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.B.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.C.WriteTo(w) + n += a + return n, err +} + +func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.W.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.A.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.B.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.C.ReadFrom(r) + n += a + return n, err +} + +// SparseR1CSSolution represent a valid assignment to all the variables in the constraint system. +type SparseR1CSSolution struct { + L, R, O fr.Vector +} + +func (t *SparseR1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.L.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.R.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.O.WriteTo(w) + n += a + return n, err + +} + +func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.L.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.R.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.O.ReadFrom(r) + a += n + return n, err +} + +func getTagSet() cbor.TagSet { + // temporary for refactor + ts := cbor.NewTagSet() + // https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml + // 65536-15309735 Unassigned + tagNum := uint64(5309735) + addType := func(t reflect.Type) { + if err := ts.Add( + cbor.TagOptions{EncTag: cbor.EncTagRequired, DecTag: cbor.DecTagRequired}, + t, + tagNum, + ); err != nil { + panic(err) + } + tagNum++ + } + + addType(reflect.TypeOf(constraint.BlueprintGenericHint{})) + addType(reflect.TypeOf(constraint.BlueprintGenericR1C{})) + addType(reflect.TypeOf(constraint.BlueprintGenericSparseR1C{})) + addType(reflect.TypeOf(constraint.BlueprintSparseR1CAdd{})) + addType(reflect.TypeOf(constraint.BlueprintSparseR1CMul{})) + + return ts +} diff --git a/constraint/blueprint.go b/constraint/blueprint.go new file mode 100644 index 0000000000..8e7abe42ce --- /dev/null +++ b/constraint/blueprint.go @@ -0,0 +1,51 @@ +package constraint + +type BlueprintID uint32 + +// Blueprint enable representing heterogenous constraints or instructions in a constraint system +// in a memory efficient way. Blueprints essentially help the frontend/ to "compress" +// constraints or instructions, and specify for the solving (or zksnark setup) part how to +// "decompress" and optionally "solve" the associated wires. +type Blueprint interface { + // NbInputs return the number of calldata input this blueprint expects. + // If this is unknown at compile time, implementation must return -1 and store + // the actual number of inputs in the first index of the calldata. + NbInputs() int + + // NbConstraints return the number of constraints this blueprint creates. + NbConstraints() int +} + +// Solver represents the state of a constraint system solver at runtime. Blueprint can interact +// with this object to perform run time logic, solve constraints and assign values in the solution. +type Solver interface { + Field + GetValue(cID, vID uint32) Element + GetCoeff(cID uint32) Element + SetValue(vID uint32, f Element) + IsSolved(vID uint32) bool +} + +// BlueprintSolvable represents a blueprint that knows how to solve itself. +type BlueprintSolvable interface { + // Solve may return an error if the decoded constraint / calldata is unsolvable. + Solve(s Solver, calldata []uint32) error +} + +// BlueprintR1C indicates that the blueprint and associated calldata encodes a R1C +type BlueprintR1C interface { + CompressR1C(c *R1C) []uint32 + DecompressR1C(into *R1C, calldata []uint32) +} + +// BlueprintSparseR1C indicates that the blueprint and associated calldata encodes a SparseR1C. +type BlueprintSparseR1C interface { + CompressSparseR1C(c *SparseR1C) []uint32 + DecompressSparseR1C(into *SparseR1C, calldata []uint32) +} + +// BlueprintHint indicates that the blueprint and associated calldata encodes a hint. +type BlueprintHint interface { + CompressHint(HintMapping) []uint32 + DecompressHint(h *HintMapping, calldata []uint32) +} diff --git a/constraint/blueprint_hint.go b/constraint/blueprint_hint.go new file mode 100644 index 0000000000..bc171232ac --- /dev/null +++ b/constraint/blueprint_hint.go @@ -0,0 +1,71 @@ +package constraint + +import "github.com/consensys/gnark/constraint/solver" + +type BlueprintGenericHint struct{} + +func (b *BlueprintGenericHint) DecompressHint(h *HintMapping, calldata []uint32) { + // ignore first call data == nbInputs + h.HintID = solver.HintID(calldata[1]) + lenInputs := int(calldata[2]) + if cap(h.Inputs) >= lenInputs { + h.Inputs = h.Inputs[:lenInputs] + } else { + h.Inputs = make([]LinearExpression, lenInputs) + } + + j := 3 + for i := 0; i < lenInputs; i++ { + n := int(calldata[j]) // len of linear expr + j++ + if cap(h.Inputs[i]) >= n { + h.Inputs[i] = h.Inputs[i][:0] + } else { + h.Inputs[i] = make(LinearExpression, 0, n) + } + for k := 0; k < n; k++ { + h.Inputs[i] = append(h.Inputs[i], Term{CID: calldata[j], VID: calldata[j+1]}) + j += 2 + } + } + h.OutputRange.Start = calldata[j] + h.OutputRange.End = calldata[j+1] +} + +func (b *BlueprintGenericHint) CompressHint(h HintMapping) []uint32 { + nbInputs := 1 // storing nb inputs + nbInputs++ // hintID + nbInputs++ // len(h.Inputs) + for i := 0; i < len(h.Inputs); i++ { + nbInputs++ // len of h.Inputs[i] + nbInputs += len(h.Inputs[i]) * 2 + } + + nbInputs += 2 // output range start / end + + r := make([]uint32, 0, nbInputs) + r = append(r, uint32(nbInputs)) + r = append(r, uint32(h.HintID)) + r = append(r, uint32(len(h.Inputs))) + + for _, l := range h.Inputs { + r = append(r, uint32(len(l))) + for _, t := range l { + r = append(r, uint32(t.CoeffID()), uint32(t.WireID())) + } + } + + r = append(r, h.OutputRange.Start) + r = append(r, h.OutputRange.End) + if len(r) != nbInputs { + panic("invalid") + } + return r +} + +func (b *BlueprintGenericHint) NbInputs() int { + return -1 +} +func (b *BlueprintGenericHint) NbConstraints() int { + return 0 +} diff --git a/constraint/blueprint_r1cs.go b/constraint/blueprint_r1cs.go new file mode 100644 index 0000000000..936a15cc07 --- /dev/null +++ b/constraint/blueprint_r1cs.go @@ -0,0 +1,58 @@ +package constraint + +// BlueprintGenericR1C implements Blueprint and BlueprintR1C. +// Encodes +// +// L * R == 0 +type BlueprintGenericR1C struct{} + +func (b *BlueprintGenericR1C) NbInputs() int { + // size of linear expressions are unknown. + return -1 +} +func (b *BlueprintGenericR1C) NbConstraints() int { + return 1 +} + +func (b *BlueprintGenericR1C) CompressR1C(c *R1C) []uint32 { + // we store total nb inputs, len L, len R, len O, and then the "flatten" linear expressions + nbInputs := 4 + 2*(len(c.L)+len(c.R)+len(c.O)) + r := make([]uint32, 0, nbInputs) + r = append(r, uint32(nbInputs)) + r = append(r, uint32(len(c.L)), uint32(len(c.R)), uint32(len(c.O))) + for _, t := range c.L { + r = append(r, uint32(t.CoeffID()), uint32(t.WireID())) + } + for _, t := range c.R { + r = append(r, uint32(t.CoeffID()), uint32(t.WireID())) + } + for _, t := range c.O { + r = append(r, uint32(t.CoeffID()), uint32(t.WireID())) + } + return r +} + +func (b *BlueprintGenericR1C) DecompressR1C(c *R1C, calldata []uint32) { + copySlice := func(slice *LinearExpression, expectedLen, idx int) { + if cap(*slice) >= expectedLen { + (*slice) = (*slice)[:expectedLen] + } else { + (*slice) = make(LinearExpression, expectedLen, expectedLen*2) + } + for k := 0; k < expectedLen; k++ { + (*slice)[k].CID = calldata[idx] + idx++ + (*slice)[k].VID = calldata[idx] + idx++ + } + } + + lenL := int(calldata[1]) + lenR := int(calldata[2]) + lenO := int(calldata[3]) + + const offset = 4 + copySlice(&c.L, lenL, offset) + copySlice(&c.R, lenR, offset+2*lenL) + copySlice(&c.O, lenO, offset+2*(lenL+lenR)) +} diff --git a/constraint/blueprint_scs.go b/constraint/blueprint_scs.go new file mode 100644 index 0000000000..f12584289b --- /dev/null +++ b/constraint/blueprint_scs.go @@ -0,0 +1,287 @@ +package constraint + +import ( + "errors" + "fmt" +) + +var ( + errDivideByZero = errors.New("division by 0") + errBoolConstrain = errors.New("boolean constraint doesn't hold") +) + +// BlueprintGenericSparseR1C implements Blueprint and BlueprintSparseR1C. +// Encodes +// +// qL⋅xa + qR⋅xb + qO⋅xc + qM⋅(xaxb) + qC == 0 +type BlueprintGenericSparseR1C struct{} + +func (b *BlueprintGenericSparseR1C) NbInputs() int { + return 9 // number of fields in SparseR1C +} +func (b *BlueprintGenericSparseR1C) NbConstraints() int { + return 1 +} + +func (b *BlueprintGenericSparseR1C) CompressSparseR1C(c *SparseR1C) []uint32 { + return []uint32{ + c.XA, + c.XB, + c.XC, + c.QL, + c.QR, + c.QO, + c.QM, + c.QC, + uint32(c.Commitment), + } +} + +func (b *BlueprintGenericSparseR1C) DecompressSparseR1C(c *SparseR1C, calldata []uint32) { + c.Clear() + + c.XA = calldata[0] + c.XB = calldata[1] + c.XC = calldata[2] + c.QL = calldata[3] + c.QR = calldata[4] + c.QO = calldata[5] + c.QM = calldata[6] + c.QC = calldata[7] + c.Commitment = CommitmentConstraint(calldata[8]) +} + +func (b *BlueprintGenericSparseR1C) Solve(s Solver, calldata []uint32) error { + var c SparseR1C + b.DecompressSparseR1C(&c, calldata) + if c.Commitment != NOT { + // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. + // these are there for enforcing the correctness of the commitment and can be skipped in solving time + return nil + } + + var ok bool + + // constraint has at most one unsolved wire. + if !s.IsSolved(c.XA) { + // we solve for L: u1L+u2R+u3LR+u4O+k=0 => L(u1+u3R)+u2R+u4O+k = 0 + u1 := s.GetCoeff(c.QL) + den := s.GetValue(c.QM, c.XB) + den = s.Add(den, u1) + den, ok = s.Inverse(den) + if !ok { + return errDivideByZero + } + v1 := s.GetValue(c.QR, c.XB) + v2 := s.GetValue(c.QO, c.XC) + num := s.Add(v1, v2) + num = s.Add(num, s.GetCoeff(c.QC)) + num = s.Mul(num, den) + num = s.Neg(num) + s.SetValue(c.XA, num) + } else if !s.IsSolved(c.XB) { + u2 := s.GetCoeff(c.QR) + den := s.GetValue(c.QM, c.XA) + den = s.Add(den, u2) + den, ok = s.Inverse(den) + if !ok { + return errDivideByZero + } + + v1 := s.GetValue(c.QL, c.XA) + v2 := s.GetValue(c.QO, c.XC) + + num := s.Add(v1, v2) + num = s.Add(num, s.GetCoeff(c.QC)) + num = s.Mul(num, den) + num = s.Neg(num) + s.SetValue(c.XB, num) + + } else if !s.IsSolved(c.XC) { + // O we solve for O + l := s.GetValue(c.QL, c.XA) + r := s.GetValue(c.QR, c.XB) + m0 := s.GetValue(c.QM, c.XA) + m1 := s.GetValue(CoeffIdOne, c.XB) + + // o = - ((m0 * m1) + l + r + c.QC) / c.O + o := s.Mul(m0, m1) + o = s.Add(o, l) + o = s.Add(o, r) + o = s.Add(o, s.GetCoeff(c.QC)) + + den := s.GetCoeff(c.QO) + den, ok = s.Inverse(den) + if !ok { + return errDivideByZero + } + o = s.Mul(o, den) + o = s.Neg(o) + + s.SetValue(c.XC, o) + } else { + // all wires are solved, we verify that the constraint hold. + // this can happen when all wires are from hints or if the constraint is an assertion. + return b.checkConstraint(&c, s) + } + return nil +} + +func (b *BlueprintGenericSparseR1C) checkConstraint(c *SparseR1C, s Solver) error { + l := s.GetValue(c.QL, c.XA) + r := s.GetValue(c.QR, c.XB) + m0 := s.GetValue(c.QM, c.XA) + m1 := s.GetValue(CoeffIdOne, c.XB) + m0 = s.Mul(m0, m1) + o := s.GetValue(c.QO, c.XC) + qC := s.GetCoeff(c.QC) + + t := s.Add(m0, l) + t = s.Add(t, r) + t = s.Add(t, o) + t = s.Add(t, qC) + + if !t.IsZero() { + return fmt.Errorf("qL⋅xa + qR⋅xb + qO⋅xc + qM⋅(xaxb) + qC != 0 → %s + %s + %s + %s + %s != 0", + s.String(l), + s.String(r), + s.String(o), + s.String(m0), + s.String(qC), + ) + } + return nil +} + +// BlueprintSparseR1CMul implements Blueprint, BlueprintSolvable and BlueprintSparseR1C. +// Encodes +// +// qM⋅(xaxb) == xc +type BlueprintSparseR1CMul struct{} + +func (b *BlueprintSparseR1CMul) NbInputs() int { + return 4 +} +func (b *BlueprintSparseR1CMul) NbConstraints() int { + return 1 +} + +func (b *BlueprintSparseR1CMul) CompressSparseR1C(c *SparseR1C) []uint32 { + return []uint32{ + c.XA, + c.XB, + c.XC, + c.QM, + } +} + +func (b *BlueprintSparseR1CMul) Solve(s Solver, calldata []uint32) error { + // qM⋅(xaxb) == xc + m0 := s.GetValue(calldata[3], calldata[0]) + m1 := s.GetValue(CoeffIdOne, calldata[1]) + + m0 = s.Mul(m0, m1) + + s.SetValue(calldata[2], m0) + return nil +} + +func (b *BlueprintSparseR1CMul) DecompressSparseR1C(c *SparseR1C, calldata []uint32) { + c.Clear() + c.XA = calldata[0] + c.XB = calldata[1] + c.XC = calldata[2] + c.QO = CoeffIdMinusOne + c.QM = calldata[3] +} + +// BlueprintSparseR1CAdd implements Blueprint, BlueprintSolvable and BlueprintSparseR1C. +// Encodes +// +// qL⋅xa + qR⋅xb + qC == xc +type BlueprintSparseR1CAdd struct{} + +func (b *BlueprintSparseR1CAdd) NbInputs() int { + return 6 +} +func (b *BlueprintSparseR1CAdd) NbConstraints() int { + return 1 +} + +func (b *BlueprintSparseR1CAdd) CompressSparseR1C(c *SparseR1C) []uint32 { + return []uint32{ + c.XA, + c.XB, + c.XC, + c.QL, + c.QR, + c.QC, + } +} + +func (blueprint *BlueprintSparseR1CAdd) Solve(s Solver, calldata []uint32) error { + // a + b + k == c + a := s.GetValue(calldata[3], calldata[0]) + b := s.GetValue(calldata[4], calldata[1]) + k := s.GetCoeff(calldata[5]) + + a = s.Add(a, b) + a = s.Add(a, k) + + s.SetValue(calldata[2], a) + return nil +} + +func (b *BlueprintSparseR1CAdd) DecompressSparseR1C(c *SparseR1C, calldata []uint32) { + c.Clear() + c.XA = calldata[0] + c.XB = calldata[1] + c.XC = calldata[2] + c.QL = calldata[3] + c.QR = calldata[4] + c.QO = CoeffIdMinusOne + c.QC = calldata[5] +} + +// BlueprintSparseR1CBool implements Blueprint, BlueprintSolvable and BlueprintSparseR1C. +// Encodes +// +// qL⋅xa + qM⋅(xa*xa) == 0 +// that is v + -v*v == 0 +type BlueprintSparseR1CBool struct{} + +func (b *BlueprintSparseR1CBool) NbInputs() int { + return 3 +} +func (b *BlueprintSparseR1CBool) NbConstraints() int { + return 1 +} + +func (b *BlueprintSparseR1CBool) CompressSparseR1C(c *SparseR1C) []uint32 { + return []uint32{ + c.XA, + c.QL, + c.QM, + } +} + +func (blueprint *BlueprintSparseR1CBool) Solve(s Solver, calldata []uint32) error { + // all wires are already solved, we just check the constraint. + v1 := s.GetValue(calldata[1], calldata[0]) + v2 := s.GetValue(calldata[2], calldata[0]) + v := s.GetValue(CoeffIdOne, calldata[0]) + v = s.Mul(v, v2) + v = s.Add(v1, v) + if !v.IsZero() { + return errBoolConstrain + } + return nil +} + +func (b *BlueprintSparseR1CBool) DecompressSparseR1C(c *SparseR1C, calldata []uint32) { + c.Clear() + c.XA = calldata[0] + c.XB = c.XA + c.QL = calldata[1] + c.QM = calldata[2] +} diff --git a/constraint/bn254/coeff.go b/constraint/bn254/coeff.go index 2835fd1555..b4d06ad0a6 100644 --- a/constraint/bn254/coeff.go +++ b/constraint/bn254/coeff.go @@ -46,7 +46,7 @@ func newCoeffTable(capacity int) CoeffTable { } -func (ct *CoeffTable) MakeTerm(coeff *constraint.Coeff, variableID int) constraint.Term { +func (ct *CoeffTable) AddCoeff(coeff constraint.Element) uint32 { c := (*fr.Element)(coeff[:]) var cID uint32 if c.IsZero() { @@ -69,7 +69,11 @@ func (ct *CoeffTable) MakeTerm(coeff *constraint.Coeff, variableID int) constrai ct.mCoeffs[cc] = cID } } + return cID +} +func (ct *CoeffTable) MakeTerm(coeff *constraint.Element, variableID int) constraint.Term { + cID := ct.AddCoeff(*coeff) return constraint.Term{VID: uint32(variableID), CID: cID} } @@ -78,7 +82,10 @@ func (ct *CoeffTable) CoeffToString(cID int) string { return ct.Coefficients[cID].String() } -var _ constraint.CoeffEngine = &arithEngine{} +// implements constraint.Field +type field struct{} + +var _ constraint.Field = &field{} var ( two fr.Element @@ -94,10 +101,7 @@ func init() { minusTwo.Neg(&two) } -// implements constraint.CoeffEngine -type arithEngine struct{} - -func (engine *arithEngine) FromInterface(i interface{}) constraint.Coeff { +func (engine *field) FromInterface(i interface{}) constraint.Element { var e fr.Element if _, err := e.SetInterface(i); err != nil { // need to clean that --> some code path are dissimilar @@ -106,55 +110,75 @@ func (engine *arithEngine) FromInterface(i interface{}) constraint.Coeff { b := utils.FromInterface(i) e.SetBigInt(&b) } - var r constraint.Coeff + var r constraint.Element copy(r[:], e[:]) return r } -func (engine *arithEngine) ToBigInt(c *constraint.Coeff) *big.Int { +func (engine *field) ToBigInt(c constraint.Element) *big.Int { e := (*fr.Element)(c[:]) r := new(big.Int) e.BigInt(r) return r } -func (engine *arithEngine) Mul(a, b *constraint.Coeff) { +func (engine *field) Mul(a, b constraint.Element) constraint.Element { _a := (*fr.Element)(a[:]) _b := (*fr.Element)(b[:]) _a.Mul(_a, _b) + return a } -func (engine *arithEngine) Add(a, b *constraint.Coeff) { + +func (engine *field) Add(a, b constraint.Element) constraint.Element { _a := (*fr.Element)(a[:]) _b := (*fr.Element)(b[:]) _a.Add(_a, _b) + return a } -func (engine *arithEngine) Sub(a, b *constraint.Coeff) { +func (engine *field) Sub(a, b constraint.Element) constraint.Element { _a := (*fr.Element)(a[:]) _b := (*fr.Element)(b[:]) _a.Sub(_a, _b) + return a } -func (engine *arithEngine) Neg(a *constraint.Coeff) { +func (engine *field) Neg(a constraint.Element) constraint.Element { e := (*fr.Element)(a[:]) e.Neg(e) + return a } -func (engine *arithEngine) Inverse(a *constraint.Coeff) { +func (engine *field) Inverse(a constraint.Element) (constraint.Element, bool) { + if a.IsZero() { + return a, false + } e := (*fr.Element)(a[:]) + if e.IsZero() { + return a, false + } else if e.IsOne() { + return a, true + } + var t fr.Element + t.Neg(e) + if t.IsOne() { + return a, true + } + e.Inverse(e) + return a, true } -func (engine *arithEngine) IsOne(a *constraint.Coeff) bool { +func (engine *field) IsOne(a constraint.Element) bool { e := (*fr.Element)(a[:]) return e.IsOne() } -func (engine *arithEngine) One() constraint.Coeff { +func (engine *field) One() constraint.Element { e := fr.One() - var r constraint.Coeff + var r constraint.Element copy(r[:], e[:]) return r } -func (engine *arithEngine) String(a *constraint.Coeff) string { +func (engine *field) String(a constraint.Element) string { e := (*fr.Element)(a[:]) return e.String() } diff --git a/constraint/bn254/r1cs.go b/constraint/bn254/r1cs.go deleted file mode 100644 index 36a9fa2b28..0000000000 --- a/constraint/bn254/r1cs.go +++ /dev/null @@ -1,467 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// 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. - -// Code generated by gnark DO NOT EDIT - -package cs - -import ( - "errors" - "fmt" - "github.com/fxamacker/cbor/v2" - "io" - "runtime" - "sync" - "time" - - "github.com/consensys/gnark/backend/witness" - "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/internal/backend/ioutils" - "github.com/consensys/gnark/logger" - "github.com/consensys/gnark/profile" - - "github.com/consensys/gnark-crypto/ecc" - "math" - - "github.com/consensys/gnark-crypto/ecc/bn254/fr" -) - -// R1CS describes a set of R1CS constraint -type R1CS struct { - constraint.R1CSCore - CoeffTable - arithEngine -} - -// NewR1CS returns a new R1CS and sets cs.Coefficient (fr.Element) from provided big.Int values -// -// capacity pre-allocates memory for capacity nbConstraints -func NewR1CS(capacity int) *R1CS { - r := R1CS{ - R1CSCore: constraint.R1CSCore{ - System: constraint.NewSystem(fr.Modulus()), - Constraints: make([]constraint.R1C, 0, capacity), - }, - CoeffTable: newCoeffTable(capacity / 10), - } - return &r -} - -func (cs *R1CS) AddConstraint(r1c constraint.R1C, debugInfo ...constraint.DebugInfo) int { - profile.RecordConstraint() - cs.Constraints = append(cs.Constraints, r1c) - cID := len(cs.Constraints) - 1 - if len(debugInfo) == 1 { - cs.DebugInfo = append(cs.DebugInfo, constraint.LogEntry(debugInfo[0])) - cs.MDebug[cID] = len(cs.DebugInfo) - 1 - } - - cs.UpdateLevel(cID, &r1c) - - return cID -} - -// Solve returns the vector w solution to the system, that is -// Aw o Bw - Cw = 0 -func (cs *R1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { - opt, err := solver.NewConfig(opts...) - if err != nil { - return nil, err - } - - var res R1CSSolution - - s := ecc.NextPowerOfTwo(uint64(len(cs.Constraints))) - res.A = make(fr.Vector, len(cs.Constraints), s) - res.B = make(fr.Vector, len(cs.Constraints), s) - res.C = make(fr.Vector, len(cs.Constraints), s) - - v := witness.Vector().(fr.Vector) - - res.W, err = cs.solve(v, res.A, res.B, res.C, opt) - if err != nil { - return nil, err - } - - return &res, nil -} - -// Solve sets all the wires and returns the a, b, c vectors. -// the cs system should have been compiled before. The entries in a, b, c are in Montgomery form. -// a, b, c vectors: ab-c = hz -// witness = [publicWires | secretWires] (without the ONE_WIRE !) -// returns [publicWires | secretWires | internalWires ] -func (cs *R1CS) solve(witness, a, b, c fr.Vector, opt solver.Config) (fr.Vector, error) { - log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() - - nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - solution, err := newSolution(&cs.System, nbWires, opt.HintFunctions, cs.Coefficients) - if err != nil { - return make(fr.Vector, nbWires), err - } - start := time.Now() - - if len(witness) != len(cs.Public)-1+len(cs.Secret) { // - 1 for ONE_WIRE - err = fmt.Errorf("invalid witness size, got %d, expected %d = %d (public) + %d (secret)", len(witness), int(len(cs.Public)-1+len(cs.Secret)), len(cs.Public)-1, len(cs.Secret)) - log.Err(err).Send() - return solution.values, err - } - - // compute the wires and the a, b, c polynomials - if len(a) != len(cs.Constraints) || len(b) != len(cs.Constraints) || len(c) != len(cs.Constraints) { - err = errors.New("invalid input size: len(a, b, c) == len(Constraints)") - log.Err(err).Send() - return solution.values, err - } - - solution.solved[0] = true // ONE_WIRE - solution.values[0].SetOne() - copy(solution.values[1:], witness) - for i := range witness { - solution.solved[i+1] = true - } - - // keep track of the number of wire instantiations we do, for a sanity check to ensure - // we instantiated all wires - solution.nbSolved += uint64(len(witness) + 1) - - // now that we know all inputs are set, defer log printing once all solution.values are computed - // (or sooner, if a constraint is not satisfied) - defer solution.printLogs(opt.Logger, cs.Logs) - - if err := cs.parallelSolve(a, b, c, &solution); err != nil { - if unsatisfiedErr, ok := err.(*UnsatisfiedConstraintError); ok { - log.Err(errors.New("unsatisfied constraint")).Int("id", unsatisfiedErr.CID).Send() - } else { - log.Err(err).Send() - } - return solution.values, err - } - - // sanity check; ensure all wires are marked as "instantiated" - if !solution.isValid() { - log.Err(errors.New("solver didn't instantiate all wires")).Send() - panic("solver didn't instantiate all wires") - } - - log.Debug().Dur("took", time.Since(start)).Msg("constraint system solver done") - - return solution.values, nil -} - -func (cs *R1CS) parallelSolve(a, b, c fr.Vector, solution *solution) error { - // minWorkPerCPU is the minimum target number of constraint a task should hold - // in other words, if a level has less than minWorkPerCPU, it will not be parallelized and executed - // sequentially without sync. - const minWorkPerCPU = 50.0 - - // cs.Levels has a list of levels, where all constraints in a level l(n) are independent - // and may only have dependencies on previous levels - // for each constraint - // we are guaranteed that each R1C contains at most one unsolved wire - // first we solve the unsolved wire (if any) - // then we check that the constraint is valid - // if a[i] * b[i] != c[i]; it means the constraint is not satisfied - - var wg sync.WaitGroup - chTasks := make(chan []int, runtime.NumCPU()) - chError := make(chan *UnsatisfiedConstraintError, runtime.NumCPU()) - - // start a worker pool - // each worker wait on chTasks - // a task is a slice of constraint indexes to be solved - for i := 0; i < runtime.NumCPU(); i++ { - go func() { - for t := range chTasks { - for _, i := range t { - // for each constraint in the task, solve it. - if err := cs.solveConstraint(cs.Constraints[i], solution, &a[i], &b[i], &c[i]); err != nil { - var debugInfo *string - if dID, ok := cs.MDebug[i]; ok { - debugInfo = new(string) - *debugInfo = solution.logValue(cs.DebugInfo[dID]) - } - chError <- &UnsatisfiedConstraintError{CID: i, Err: err, DebugInfo: debugInfo} - wg.Done() - return - } - } - wg.Done() - } - }() - } - - // clean up pool go routines - defer func() { - close(chTasks) - close(chError) - }() - - // for each level, we push the tasks - for _, level := range cs.Levels { - - // max CPU to use - maxCPU := float64(len(level)) / minWorkPerCPU - - if maxCPU <= 1.0 { - // we do it sequentially - for _, i := range level { - if err := cs.solveConstraint(cs.Constraints[i], solution, &a[i], &b[i], &c[i]); err != nil { - var debugInfo *string - if dID, ok := cs.MDebug[i]; ok { - debugInfo = new(string) - *debugInfo = solution.logValue(cs.DebugInfo[dID]) - } - return &UnsatisfiedConstraintError{CID: i, Err: err, DebugInfo: debugInfo} - } - } - continue - } - - // number of tasks for this level is set to number of CPU - // but if we don't have enough work for all our CPU, it can be lower. - nbTasks := runtime.NumCPU() - maxTasks := int(math.Ceil(maxCPU)) - if nbTasks > maxTasks { - nbTasks = maxTasks - } - nbIterationsPerCpus := len(level) / nbTasks - - // more CPUs than tasks: a CPU will work on exactly one iteration - // note: this depends on minWorkPerCPU constant - if nbIterationsPerCpus < 1 { - nbIterationsPerCpus = 1 - nbTasks = len(level) - } - - extraTasks := len(level) - (nbTasks * nbIterationsPerCpus) - extraTasksOffset := 0 - - for i := 0; i < nbTasks; i++ { - wg.Add(1) - _start := i*nbIterationsPerCpus + extraTasksOffset - _end := _start + nbIterationsPerCpus - if extraTasks > 0 { - _end++ - extraTasks-- - extraTasksOffset++ - } - // since we're never pushing more than num CPU tasks - // we will never be blocked here - chTasks <- level[_start:_end] - } - - // wait for the level to be done - wg.Wait() - - if len(chError) > 0 { - return <-chError - } - } - - return nil -} - -// IsSolved -// Deprecated: use _, err := Solve(...) instead -func (cs *R1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { - _, err := cs.Solve(witness, opts...) - return err -} - -// divByCoeff sets res = res / t.Coeff -func (cs *R1CS) divByCoeff(res *fr.Element, t constraint.Term) { - cID := t.CoeffID() - switch cID { - case constraint.CoeffIdOne: - return - case constraint.CoeffIdMinusOne: - res.Neg(res) - case constraint.CoeffIdZero: - panic("division by 0") - default: - // this is slow, but shouldn't happen as divByCoeff is called to - // remove the coeff of an unsolved wire - // but unsolved wires are (in gnark frontend) systematically set with a coeff == 1 or -1 - res.Div(res, &cs.Coefficients[cID]) - } -} - -// solveConstraint compute unsolved wires in the constraint, if any and set the solution accordingly -// -// returns an error if the solver called a hint function that errored -// returns false, nil if there was no wire to solve -// returns true, nil if exactly one wire was solved. In that case, it is redundant to check that -// the constraint is satisfied later. -func (cs *R1CS) solveConstraint(r constraint.R1C, solution *solution, a, b, c *fr.Element) error { - - // the index of the non-zero entry shows if L, R or O has an uninstantiated wire - // the content is the ID of the wire non instantiated - var loc uint8 - - var termToCompute constraint.Term - - processLExp := func(l constraint.LinearExpression, val *fr.Element, locValue uint8) error { - for _, t := range l { - vID := t.WireID() - - // wire is already computed, we just accumulate in val - if solution.solved[vID] { - solution.accumulateInto(t, val) - continue - } - - // first we check if this is a hint wire - if hint, ok := cs.MHints[vID]; ok { - if err := solution.solveWithHint(vID, hint); err != nil { - return err - } - // now that the wire is saved, accumulate it into a, b or c - solution.accumulateInto(t, val) - continue - } - - if loc != 0 { - panic("found more than one wire to instantiate") - } - termToCompute = t - loc = locValue - } - return nil - } - - if err := processLExp(r.L, a, 1); err != nil { - return err - } - - if err := processLExp(r.R, b, 2); err != nil { - return err - } - - if err := processLExp(r.O, c, 3); err != nil { - return err - } - - if loc == 0 { - // there is nothing to solve, may happen if we have an assertion - // (ie a constraints that doesn't yield any output) - // or if we solved the unsolved wires with hint functions - var check fr.Element - if !check.Mul(a, b).Equal(c) { - return fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String()) - } - return nil - } - - // we compute the wire value and instantiate it - wID := termToCompute.WireID() - - // solver result - var wire fr.Element - - switch loc { - case 1: - if !b.IsZero() { - wire.Div(c, b). - Sub(&wire, a) - a.Add(a, &wire) - } else { - // we didn't actually ensure that a * b == c - var check fr.Element - if !check.Mul(a, b).Equal(c) { - return fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String()) - } - } - case 2: - if !a.IsZero() { - wire.Div(c, a). - Sub(&wire, b) - b.Add(b, &wire) - } else { - var check fr.Element - if !check.Mul(a, b).Equal(c) { - return fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String()) - } - } - case 3: - wire.Mul(a, b). - Sub(&wire, c) - - c.Add(c, &wire) - } - - // wire is the term (coeff * value) - // but in the solution we want to store the value only - // note that in gnark frontend, coeff here is always 1 or -1 - cs.divByCoeff(&wire, termToCompute) - solution.set(wID, wire) - - return nil -} - -// GetConstraints return the list of R1C and a coefficient resolver -func (cs *R1CS) GetConstraints() ([]constraint.R1C, constraint.Resolver) { - return cs.Constraints, cs -} - -// GetNbCoefficients return the number of unique coefficients needed in the R1CS -func (cs *R1CS) GetNbCoefficients() int { - return len(cs.Coefficients) -} - -// CurveID returns curve ID as defined in gnark-crypto -func (cs *R1CS) CurveID() ecc.ID { - return ecc.BN254 -} - -// WriteTo encodes R1CS into provided io.Writer using cbor -func (cs *R1CS) WriteTo(w io.Writer) (int64, error) { - _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written - enc, err := cbor.CoreDetEncOptions().EncMode() - if err != nil { - return 0, err - } - encoder := enc.NewEncoder(&_w) - - // encode our object - err = encoder.Encode(cs) - return _w.N, err -} - -// ReadFrom attempts to decode R1CS from io.Reader using cbor -func (cs *R1CS) ReadFrom(r io.Reader) (int64, error) { - dm, err := cbor.DecOptions{ - MaxArrayElements: 134217728, - MaxMapPairs: 134217728, - }.DecMode() - - if err != nil { - return 0, err - } - decoder := dm.NewDecoder(r) - - // initialize coeff table - cs.CoeffTable = newCoeffTable(0) - - if err := decoder.Decode(&cs); err != nil { - return int64(decoder.NumBytesRead()), err - } - - if err := cs.CheckSerializationHeader(); err != nil { - return int64(decoder.NumBytesRead()), err - } - - return int64(decoder.NumBytesRead()), nil -} diff --git a/constraint/bn254/r1cs_sparse.go b/constraint/bn254/r1cs_sparse.go deleted file mode 100644 index 260b2a141b..0000000000 --- a/constraint/bn254/r1cs_sparse.go +++ /dev/null @@ -1,533 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// 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. - -// Code generated by gnark DO NOT EDIT - -package cs - -import ( - "errors" - "fmt" - "github.com/consensys/gnark-crypto/ecc" - "github.com/fxamacker/cbor/v2" - "io" - "math" - "runtime" - "sync" - "time" - - "github.com/consensys/gnark/backend/witness" - "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/internal/backend/ioutils" - "github.com/consensys/gnark/logger" - "github.com/consensys/gnark/profile" - - "github.com/consensys/gnark-crypto/ecc/bn254/fr" -) - -// SparseR1CS represents a Plonk like circuit -type SparseR1CS struct { - constraint.SparseR1CSCore - CoeffTable - arithEngine -} - -// NewSparseR1CS returns a new SparseR1CS and sets r1cs.Coefficient (fr.Element) from provided big.Int values -func NewSparseR1CS(capacity int) *SparseR1CS { - cs := SparseR1CS{ - SparseR1CSCore: constraint.SparseR1CSCore{ - System: constraint.NewSystem(fr.Modulus()), - Constraints: make([]constraint.SparseR1C, 0, capacity), - }, - CoeffTable: newCoeffTable(capacity / 10), - } - - return &cs -} - -func (cs *SparseR1CS) AddConstraint(c constraint.SparseR1C, debugInfo ...constraint.DebugInfo) int { - profile.RecordConstraint() - cs.Constraints = append(cs.Constraints, c) - cID := len(cs.Constraints) - 1 - if len(debugInfo) == 1 { - cs.DebugInfo = append(cs.DebugInfo, constraint.LogEntry(debugInfo[0])) - cs.MDebug[cID] = len(cs.DebugInfo) - 1 - } - cs.UpdateLevel(cID, &c) - - return cID -} - -func (c *SparseR1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { - opt, err := solver.NewConfig(opts...) - if err != nil { - return nil, err - } - - // compute the constraint system solution - var solution []fr.Element - if solution, err = c.solve(witness.Vector().(fr.Vector), opt); err != nil { - return nil, err - } - - var res SparseR1CSSolution - // query l, r, o in Lagrange basis, not blinded - res.L, res.R, res.O = c.evaluateLROSmallDomain(solution) - - return &res, nil -} - -// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. -// solution = [ public | secret | internal ] -func (c *SparseR1CS) evaluateLROSmallDomain(solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { - - //s := int(pk.Domain[0].Cardinality) - s := c.GetNbConstraints() + len(c.Public) // len(spr.Public) is for the placeholder constraints - s = int(ecc.NextPowerOfTwo(uint64(s))) - - var l, r, o []fr.Element - l = make([]fr.Element, s) - r = make([]fr.Element, s) - o = make([]fr.Element, s) - s0 := solution[0] - - for i := 0; i < len(c.Public); i++ { // placeholders - l[i] = solution[i] - r[i] = s0 - o[i] = s0 - } - offset := len(c.Public) - for i := 0; i < len(c.Constraints); i++ { // constraints - l[offset+i] = solution[c.Constraints[i].L.WireID()] - r[offset+i] = solution[c.Constraints[i].R.WireID()] - o[offset+i] = solution[c.Constraints[i].O.WireID()] - } - offset += len(c.Constraints) - - for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) - l[offset+i] = s0 - r[offset+i] = s0 - o[offset+i] = s0 - } - - return l, r, o - -} - -// Solve sets all the wires. -// solution.values = [publicInputs | secretInputs | internalVariables ] -// witness: contains the input variables -// it returns the full slice of wires -func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, error) { - log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "plonk").Logger() - - // set the slices holding the solution.values and monitoring which variables have been solved - nbVariables := cs.NbInternalVariables + len(cs.Secret) + len(cs.Public) - - start := time.Now() - - expectedWitnessSize := len(cs.Public) + len(cs.Secret) - if len(witness) != expectedWitnessSize { - return make(fr.Vector, nbVariables), fmt.Errorf( - "invalid witness size, got %d, expected %d = %d (public) + %d (secret)", - len(witness), - expectedWitnessSize, - len(cs.Public), - len(cs.Secret), - ) - } - - // keep track of wire that have a value - solution, err := newSolution(&cs.System, nbVariables, opt.HintFunctions, cs.Coefficients) - if err != nil { - return solution.values, err - } - - // solution.values = [publicInputs | secretInputs | internalVariables ] -> we fill publicInputs | secretInputs - copy(solution.values, witness) - for i := 0; i < len(witness); i++ { - solution.solved[i] = true - } - - // keep track of the number of wire instantiations we do, for a sanity check to ensure - // we instantiated all wires - solution.nbSolved += uint64(len(witness)) - - // defer log printing once all solution.values are computed - defer solution.printLogs(opt.Logger, cs.Logs) - - // batch invert the coefficients to avoid many divisions in the solver - coefficientsNegInv := fr.BatchInvert(cs.Coefficients) - for i := 0; i < len(coefficientsNegInv); i++ { - coefficientsNegInv[i].Neg(&coefficientsNegInv[i]) - } - - if err := cs.parallelSolve(&solution, coefficientsNegInv); err != nil { - if unsatisfiedErr, ok := err.(*UnsatisfiedConstraintError); ok { - log.Err(errors.New("unsatisfied constraint")).Int("id", unsatisfiedErr.CID).Send() - } else { - log.Err(err).Send() - } - return solution.values, err - } - - // sanity check; ensure all wires are marked as "instantiated" - if !solution.isValid() { - log.Err(errors.New("solver didn't instantiate all wires")).Send() - panic("solver didn't instantiate all wires") - } - - log.Debug().Dur("took", time.Since(start)).Msg("constraint system solver done") - - return solution.values, nil - -} - -func (cs *SparseR1CS) parallelSolve(solution *solution, coefficientsNegInv fr.Vector) error { - // minWorkPerCPU is the minimum target number of constraint a task should hold - // in other words, if a level has less than minWorkPerCPU, it will not be parallelized and executed - // sequentially without sync. - const minWorkPerCPU = 50.0 - - // cs.Levels has a list of levels, where all constraints in a level l(n) are independent - // and may only have dependencies on previous levels - - var wg sync.WaitGroup - chTasks := make(chan []int, runtime.NumCPU()) - chError := make(chan *UnsatisfiedConstraintError, runtime.NumCPU()) - - // start a worker pool - // each worker wait on chTasks - // a task is a slice of constraint indexes to be solved - for i := 0; i < runtime.NumCPU(); i++ { - go func() { - for t := range chTasks { - for _, i := range t { - // for each constraint in the task, solve it. - if err := cs.solveConstraint(cs.Constraints[i], solution, coefficientsNegInv); err != nil { - chError <- &UnsatisfiedConstraintError{CID: i, Err: err} - wg.Done() - return - } - if err := cs.checkConstraint(cs.Constraints[i], solution); err != nil { - if dID, ok := cs.MDebug[i]; ok { - errMsg := solution.logValue(cs.DebugInfo[dID]) - chError <- &UnsatisfiedConstraintError{CID: i, DebugInfo: &errMsg} - } else { - chError <- &UnsatisfiedConstraintError{CID: i, Err: err} - } - wg.Done() - return - } - } - wg.Done() - } - }() - } - - // clean up pool go routines - defer func() { - close(chTasks) - close(chError) - }() - - // for each level, we push the tasks - for _, level := range cs.Levels { - - // max CPU to use - maxCPU := float64(len(level)) / minWorkPerCPU - - if maxCPU <= 1.0 { - // we do it sequentially - for _, i := range level { - if err := cs.solveConstraint(cs.Constraints[i], solution, coefficientsNegInv); err != nil { - return &UnsatisfiedConstraintError{CID: i, Err: err} - } - if err := cs.checkConstraint(cs.Constraints[i], solution); err != nil { - if dID, ok := cs.MDebug[i]; ok { - errMsg := solution.logValue(cs.DebugInfo[dID]) - return &UnsatisfiedConstraintError{CID: i, DebugInfo: &errMsg} - } - return &UnsatisfiedConstraintError{CID: i, Err: err} - } - } - continue - } - - // number of tasks for this level is set to number of CPU - // but if we don't have enough work for all our CPU, it can be lower. - nbTasks := runtime.NumCPU() - maxTasks := int(math.Ceil(maxCPU)) - if nbTasks > maxTasks { - nbTasks = maxTasks - } - nbIterationsPerCpus := len(level) / nbTasks - - // more CPUs than tasks: a CPU will work on exactly one iteration - // note: this depends on minWorkPerCPU constant - if nbIterationsPerCpus < 1 { - nbIterationsPerCpus = 1 - nbTasks = len(level) - } - - extraTasks := len(level) - (nbTasks * nbIterationsPerCpus) - extraTasksOffset := 0 - - for i := 0; i < nbTasks; i++ { - wg.Add(1) - _start := i*nbIterationsPerCpus + extraTasksOffset - _end := _start + nbIterationsPerCpus - if extraTasks > 0 { - _end++ - extraTasks-- - extraTasksOffset++ - } - // since we're never pushing more than num CPU tasks - // we will never be blocked here - chTasks <- level[_start:_end] - } - - // wait for the level to be done - wg.Wait() - - if len(chError) > 0 { - return <-chError - } - } - - return nil -} - -// computeHints computes wires associated with a hint function, if any -// if there is no remaining wire to solve, returns -1 -// else returns the wire position (L -> 0, R -> 1, O -> 2) -func (cs *SparseR1CS) computeHints(c constraint.SparseR1C, solution *solution) (int, error) { - r := -1 - lID, rID, oID := c.L.WireID(), c.R.WireID(), c.O.WireID() - - if (c.L.CoeffID() != 0 || c.M[0].CoeffID() != 0) && !solution.solved[lID] { - // check if it's a hint - if hint, ok := cs.MHints[lID]; ok { - if err := solution.solveWithHint(lID, hint); err != nil { - return -1, err - } - } else { - r = 0 - } - - } - - if (c.R.CoeffID() != 0 || c.M[1].CoeffID() != 0) && !solution.solved[rID] { - // check if it's a hint - if hint, ok := cs.MHints[rID]; ok { - if err := solution.solveWithHint(rID, hint); err != nil { - return -1, err - } - } else { - r = 1 - } - } - - if (c.O.CoeffID() != 0) && !solution.solved[oID] { - // check if it's a hint - if hint, ok := cs.MHints[oID]; ok { - if err := solution.solveWithHint(oID, hint); err != nil { - return -1, err - } - } else { - r = 2 - } - } - return r, nil -} - -// solveConstraint solve any unsolved wire in given constraint and update the solution -// a SparseR1C may have up to one unsolved wire (excluding hints) -// if it doesn't, then this function returns and does nothing -func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution, coefficientsNegInv fr.Vector) error { - - if c.Commitment == constraint.COMMITTED { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. - return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time - } - - lro, err := cs.computeHints(c, solution) - if err != nil { - return err - } - if lro == -1 { - // no unsolved wire - // can happen if the constraint contained only hint wires. - return nil - } - if lro == 1 { // we solve for R: u1L+u2R+u3LR+u4O+k=0 => R(u2+u3L)+u1L+u4O+k = 0 - if !solution.solved[c.L.WireID()] { - panic("L wire should be instantiated when we solve R") - } - var u1, u2, u3, den, num, v1, v2 fr.Element - u3.Mul(&cs.Coefficients[c.M[0].CoeffID()], &cs.Coefficients[c.M[1].CoeffID()]) - u1.Set(&cs.Coefficients[c.L.CoeffID()]) - u2.Set(&cs.Coefficients[c.R.CoeffID()]) - den.Mul(&u3, &solution.values[c.L.WireID()]).Add(&den, &u2) - - v1 = solution.computeTerm(c.L) - v2 = solution.computeTerm(c.O) - num.Add(&v1, &v2).Add(&num, &cs.Coefficients[c.K]) - - // TODO find a way to do lazy div (/ batch inversion) - num.Div(&num, &den).Neg(&num) - solution.set(c.L.WireID(), num) - return nil - } - - if lro == 0 { // we solve for L: u1L+u2R+u3LR+u4O+k=0 => L(u1+u3R)+u2R+u4O+k = 0 - if !solution.solved[c.R.WireID()] { - panic("R wire should be instantiated when we solve L") - } - var u1, u2, u3, den, num, v1, v2 fr.Element - u3.Mul(&cs.Coefficients[c.M[0].CoeffID()], &cs.Coefficients[c.M[1].CoeffID()]) - u1.Set(&cs.Coefficients[c.L.CoeffID()]) - u2.Set(&cs.Coefficients[c.R.CoeffID()]) - den.Mul(&u3, &solution.values[c.R.WireID()]).Add(&den, &u1) - - v1 = solution.computeTerm(c.R) - v2 = solution.computeTerm(c.O) - num.Add(&v1, &v2).Add(&num, &cs.Coefficients[c.K]) - - // TODO find a way to do lazy div (/ batch inversion) - num.Div(&num, &den).Neg(&num) - solution.set(c.L.WireID(), num) - return nil - - } - // O we solve for O - var o fr.Element - cID, vID := c.O.CoeffID(), c.O.WireID() - - l := solution.computeTerm(c.L) - r := solution.computeTerm(c.R) - m0 := solution.computeTerm(c.M[0]) - m1 := solution.computeTerm(c.M[1]) - - // o = - ((m0 * m1) + l + r + c.K) / c.O - o.Mul(&m0, &m1).Add(&o, &l).Add(&o, &r).Add(&o, &cs.Coefficients[c.K]) - o.Mul(&o, &coefficientsNegInv[cID]) - - solution.set(vID, o) - - return nil -} - -// IsSolved -// Deprecated: use _, err := Solve(...) instead -func (cs *SparseR1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { - _, err := cs.Solve(witness, opts...) - return err -} - -// GetConstraints return the list of SparseR1C and a coefficient resolver -func (cs *SparseR1CS) GetConstraints() ([]constraint.SparseR1C, constraint.Resolver) { - return cs.Constraints, cs -} - -func (cs *SparseR1CS) GetConstraint(i int) *constraint.SparseR1C { - if i < 0 || i >= len(cs.Constraints) { - return nil - } - return &cs.Constraints[i] -} - -func (cs *SparseR1CS) GetCoefficient(i int) (r constraint.Coeff) { - copy(r[:], cs.Coefficients[i][:]) - return -} - -// checkConstraint verifies that the constraint holds -func (cs *SparseR1CS) checkConstraint(c constraint.SparseR1C, solution *solution) error { - - if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. - return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time - } - - l := solution.computeTerm(c.L) - r := solution.computeTerm(c.R) - m0 := solution.computeTerm(c.M[0]) - m1 := solution.computeTerm(c.M[1]) - o := solution.computeTerm(c.O) - - // l + r + (m0 * m1) + o + c.K == 0 - var t fr.Element - t.Mul(&m0, &m1).Add(&t, &l).Add(&t, &r).Add(&t, &o).Add(&t, &cs.Coefficients[c.K]) - if !t.IsZero() { - return fmt.Errorf("qL⋅xa + qR⋅xb + qO⋅xc + qM⋅(xaxb) + qC != 0 → %s + %s + %s + (%s × %s) + %s != 0", - l.String(), - r.String(), - o.String(), - m0.String(), - m1.String(), - cs.Coefficients[c.K].String(), - ) - } - return nil - -} - -// GetNbCoefficients return the number of unique coefficients needed in the R1CS -func (cs *SparseR1CS) GetNbCoefficients() int { - return len(cs.Coefficients) -} - -// CurveID returns curve ID as defined in gnark-crypto (ecc.BN254) -func (cs *SparseR1CS) CurveID() ecc.ID { - return ecc.BN254 -} - -// WriteTo encodes SparseR1CS into provided io.Writer using cbor -func (cs *SparseR1CS) WriteTo(w io.Writer) (int64, error) { - _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written - enc, err := cbor.CoreDetEncOptions().EncMode() - if err != nil { - return 0, err - } - encoder := enc.NewEncoder(&_w) - - // encode our object - err = encoder.Encode(cs) - return _w.N, err -} - -// ReadFrom attempts to decode SparseR1CS from io.Reader using cbor -func (cs *SparseR1CS) ReadFrom(r io.Reader) (int64, error) { - dm, err := cbor.DecOptions{ - MaxArrayElements: 134217728, - MaxMapPairs: 134217728, - }.DecMode() - if err != nil { - return 0, err - } - decoder := dm.NewDecoder(r) - - // initialize coeff table - cs.CoeffTable = newCoeffTable(0) - - if err := decoder.Decode(cs); err != nil { - return int64(decoder.NumBytesRead()), err - } - - if err := cs.CheckSerializationHeader(); err != nil { - return int64(decoder.NumBytesRead()), err - } - - return int64(decoder.NumBytesRead()), nil -} diff --git a/constraint/bn254/r1cs_test.go b/constraint/bn254/r1cs_test.go index a772621bcc..f872b83a3f 100644 --- a/constraint/bn254/r1cs_test.go +++ b/constraint/bn254/r1cs_test.go @@ -20,6 +20,7 @@ import ( "bytes" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/frontend/cs/scs" "github.com/consensys/gnark/internal/backend/circuits" "reflect" "testing" @@ -76,10 +77,11 @@ func TestSerialization(t *testing.T) { if diff := cmp.Diff(r1cs1, &reconstructed, cmpopts.IgnoreFields(cs.R1CS{}, "System.q", - "arithEngine", + "field", "CoeffTable.mCoeffs", "System.lbWireLevel", "System.lbHints", + "System.genericHint", "System.SymbolTable", "System.lbOutputs", "System.bitLen")); diff != "" { @@ -147,12 +149,6 @@ func (circuit *circuit) Define(api frontend.API) error { func BenchmarkSolve(b *testing.B) { - var c circuit - ccs, err := frontend.Compile(fr.Modulus(), r1cs.NewBuilder, &c) - if err != nil { - b.Fatal(err) - } - var w circuit w.X = 1 w.Y = 1 @@ -161,8 +157,32 @@ func BenchmarkSolve(b *testing.B) { b.Fatal(err) } - b.ResetTimer() - for i := 0; i < b.N; i++ { - _ = ccs.IsSolved(witness) - } + b.Run("scs", func(b *testing.B) { + var c circuit + ccs, err := frontend.Compile(fr.Modulus(), scs.NewBuilder, &c) + if err != nil { + b.Fatal(err) + } + b.Log("scs nbConstraints", ccs.GetNbConstraints()) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = ccs.IsSolved(witness) + } + }) + + b.Run("r1cs", func(b *testing.B) { + var c circuit + ccs, err := frontend.Compile(fr.Modulus(), r1cs.NewBuilder, &c, frontend.WithCompressThreshold(10)) + if err != nil { + b.Fatal(err) + } + b.Log("r1cs nbConstraints", ccs.GetNbConstraints()) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = ccs.IsSolved(witness) + } + }) + } diff --git a/constraint/bn254/solution.go b/constraint/bn254/solution.go deleted file mode 100644 index bc1ea454c4..0000000000 --- a/constraint/bn254/solution.go +++ /dev/null @@ -1,383 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// 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. - -// Code generated by gnark DO NOT EDIT - -package cs - -import ( - "errors" - "fmt" - "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/debug" - "github.com/rs/zerolog" - "io" - "math/big" - "strconv" - "strings" - "sync/atomic" - - "github.com/consensys/gnark-crypto/ecc/bn254/fr" -) - -// solution represents elements needed to compute -// a solution to a R1CS or SparseR1CS -type solution struct { - values, coefficients []fr.Element - solved []bool - nbSolved uint64 - mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function - st *debug.SymbolTable - cs *constraint.System -} - -func newSolution(cs *constraint.System, nbWires int, hintFunctions map[solver.HintID]solver.Hint, coefficients []fr.Element) (solution, error) { - - s := solution{ - cs: cs, - st: &cs.SymbolTable, - values: make([]fr.Element, nbWires), - coefficients: coefficients, - solved: make([]bool, nbWires), - mHintsFunctions: hintFunctions, - } - - // hintsDependencies is from compile time; it contains the list of hints the solver **needs** - var missing []string - for hintUUID, hintID := range cs.MHintsDependencies { - if _, ok := s.mHintsFunctions[hintUUID]; !ok { - missing = append(missing, hintID) - } - } - - if len(missing) > 0 { - return s, fmt.Errorf("solver missing hint(s): %v", missing) - } - - return s, nil -} - -func (s *solution) set(id int, value fr.Element) { - if s.solved[id] { - panic("solving the same wire twice should never happen.") - } - s.values[id] = value - s.solved[id] = true - atomic.AddUint64(&s.nbSolved, 1) - // s.nbSolved++ -} - -func (s *solution) isValid() bool { - return int(s.nbSolved) == len(s.values) -} - -// computeTerm computes coeff*variable -func (s *solution) computeTerm(t constraint.Term) fr.Element { - cID, vID := t.CoeffID(), t.WireID() - if cID != 0 && !s.solved[vID] { - panic("computing a term with an unsolved wire") - } - switch cID { - case constraint.CoeffIdZero: - return fr.Element{} - case constraint.CoeffIdOne: - return s.values[vID] - case constraint.CoeffIdTwo: - var res fr.Element - res.Double(&s.values[vID]) - return res - case constraint.CoeffIdMinusOne: - var res fr.Element - res.Neg(&s.values[vID]) - return res - default: - var res fr.Element - res.Mul(&s.coefficients[cID], &s.values[vID]) - return res - } -} - -// r += (t.coeff*t.value) -func (s *solution) accumulateInto(t constraint.Term, r *fr.Element) { - cID := t.CoeffID() - - if t.IsConstant() { - // needed for logs, we may want to not put this in the hot path if we need to - // optimize constraint system solver further. - r.Add(r, &s.coefficients[cID]) - return - } - - vID := t.WireID() - switch cID { - case constraint.CoeffIdZero: - return - case constraint.CoeffIdOne: - r.Add(r, &s.values[vID]) - case constraint.CoeffIdTwo: - var res fr.Element - res.Double(&s.values[vID]) - r.Add(r, &res) - case constraint.CoeffIdMinusOne: - r.Sub(r, &s.values[vID]) - default: - var res fr.Element - res.Mul(&s.coefficients[cID], &s.values[vID]) - r.Add(r, &res) - } -} - -// solveHint compute solution.values[vID] using provided solver hint -func (s *solution) solveWithHint(vID int, hID int) error { - // skip if the wire is already solved by a call to the same hint - // function on the same inputs - if s.solved[vID] { - return nil - } - - h := &s.cs.HintMappings[hID] - - // ensure hint function was provided - f, ok := s.mHintsFunctions[h.HintID] - if !ok { - return errors.New("missing hint function") - } - - // tmp IO big int memory - nbInputs := len(h.Inputs) - nbOutputs := len(h.Outputs) - inputs := make([]*big.Int, nbInputs) - outputs := make([]*big.Int, nbOutputs) - for i := 0; i < nbOutputs; i++ { - outputs[i] = big.NewInt(0) - } - - q := fr.Modulus() - - // for each input, we set its big int value, IF all the wires are solved - // the only case where all wires may not be solved, is if one of the input of this hint - // is the output of another hint. - // it is safe to recursively solve this with the parallel solver, since all hints-output wires - // that we can solve this way are marked to be solved with the current constraint we are processing. - recursiveSolve := func(t constraint.Term) error { - if t.IsConstant() { - return nil - } - wID := t.WireID() - if s.solved[wID] { - return nil - } - // unsolved dependency - if h, ok := s.cs.MHints[wID]; ok { - // solve recursively. - return s.solveWithHint(wID, h) - } - - // it's not a hint, we panic. - panic("solver can't compute hint; one or more input wires are unsolved") - } - - for i := 0; i < nbInputs; i++ { - inputs[i] = big.NewInt(0) - - var v fr.Element - for _, term := range h.Inputs[i] { - if err := recursiveSolve(term); err != nil { - return err - } - s.accumulateInto(term, &v) - } - v.BigInt(inputs[i]) - } - - err := f(q, inputs, outputs) - - var v fr.Element - for i := range outputs { - v.SetBigInt(outputs[i]) - s.set(h.Outputs[i], v) - } - - return err -} - -func (s *solution) printLogs(log zerolog.Logger, logs []constraint.LogEntry) { - if log.GetLevel() == zerolog.Disabled { - return - } - - for i := 0; i < len(logs); i++ { - logLine := s.logValue(logs[i]) - log.Debug().Str(zerolog.CallerFieldName, logs[i].Caller).Msg(logLine) - } -} - -const unsolvedVariable = "" - -func (s *solution) logValue(log constraint.LogEntry) string { - var toResolve []interface{} - var ( - eval fr.Element - missingValue bool - ) - for j := 0; j < len(log.ToResolve); j++ { - // before eval le - - missingValue = false - eval.SetZero() - - for _, t := range log.ToResolve[j] { - // for each term in the linear expression - - cID, vID := t.CoeffID(), t.WireID() - if t.IsConstant() { - // just add the constant - eval.Add(&eval, &s.coefficients[cID]) - continue - } - - if !s.solved[vID] { - missingValue = true - break // stop the loop we can't evaluate. - } - - tv := s.computeTerm(t) - eval.Add(&eval, &tv) - } - - // after - if missingValue { - toResolve = append(toResolve, unsolvedVariable) - } else { - // we have to append our accumulator - toResolve = append(toResolve, eval.String()) - } - - } - if len(log.Stack) > 0 { - var sbb strings.Builder - for _, lID := range log.Stack { - location := s.st.Locations[lID] - function := s.st.Functions[location.FunctionID] - - sbb.WriteString(function.Name) - sbb.WriteByte('\n') - sbb.WriteByte('\t') - sbb.WriteString(function.Filename) - sbb.WriteByte(':') - sbb.WriteString(strconv.Itoa(int(location.Line))) - sbb.WriteByte('\n') - } - toResolve = append(toResolve, sbb.String()) - } - return fmt.Sprintf(log.Format, toResolve...) -} - -// UnsatisfiedConstraintError wraps an error with useful metadata on the unsatisfied constraint -type UnsatisfiedConstraintError struct { - Err error - CID int // constraint ID - DebugInfo *string // optional debug info -} - -func (r *UnsatisfiedConstraintError) Error() string { - if r.DebugInfo != nil { - return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, *r.DebugInfo) - } - return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, r.Err.Error()) -} - -// R1CSSolution represent a valid assignment to all the variables in the constraint system. -// The vector W such that Aw o Bw - Cw = 0 -type R1CSSolution struct { - W fr.Vector - A, B, C fr.Vector -} - -func (t *R1CSSolution) WriteTo(w io.Writer) (int64, error) { - n, err := t.W.WriteTo(w) - if err != nil { - return n, err - } - a, err := t.A.WriteTo(w) - n += a - if err != nil { - return n, err - } - a, err = t.B.WriteTo(w) - n += a - if err != nil { - return n, err - } - a, err = t.C.WriteTo(w) - n += a - return n, err -} - -func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { - n, err := t.W.ReadFrom(r) - if err != nil { - return n, err - } - a, err := t.A.ReadFrom(r) - a += n - if err != nil { - return n, err - } - a, err = t.B.ReadFrom(r) - a += n - if err != nil { - return n, err - } - a, err = t.C.ReadFrom(r) - n += a - return n, err -} - -// SparseR1CSSolution represent a valid assignment to all the variables in the constraint system. -type SparseR1CSSolution struct { - L, R, O fr.Vector -} - -func (t *SparseR1CSSolution) WriteTo(w io.Writer) (int64, error) { - n, err := t.L.WriteTo(w) - if err != nil { - return n, err - } - a, err := t.R.WriteTo(w) - n += a - if err != nil { - return n, err - } - a, err = t.O.WriteTo(w) - n += a - return n, err - -} - -func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { - n, err := t.L.ReadFrom(r) - if err != nil { - return n, err - } - a, err := t.R.ReadFrom(r) - a += n - if err != nil { - return n, err - } - a, err = t.O.ReadFrom(r) - a += n - return n, err -} diff --git a/constraint/bn254/solver.go b/constraint/bn254/solver.go new file mode 100644 index 0000000000..6e8b27587f --- /dev/null +++ b/constraint/bn254/solver.go @@ -0,0 +1,614 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package cs + +import ( + "errors" + "fmt" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/field/pool" + "github.com/consensys/gnark/constraint" + csolver "github.com/consensys/gnark/constraint/solver" + "github.com/rs/zerolog" + "math" + "math/big" + "runtime" + "strconv" + "strings" + "sync" + "sync/atomic" + + "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +// solver represent the state of the solver during a call to System.Solve(...) +type solver struct { + *system + + // values and solved are index by the wire (variable) id + values []fr.Element + solved []bool + nbSolved uint64 + + // maps hintID to hint function + mHintsFunctions map[csolver.HintID]csolver.Hint + + // used to out api.Println + logger zerolog.Logger + + a, b, c fr.Vector // R1CS solver will compute the a,b,c matrices + + q *big.Int +} + +func newSolver(cs *system, witness fr.Vector, opts ...csolver.Option) (*solver, error) { + // parse options + opt, err := csolver.NewConfig(opts...) + if err != nil { + return nil, err + } + + // check witness size + witnessOffset := 0 + if cs.Type == constraint.SystemR1CS { + witnessOffset++ + } + + nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables + expectedWitnessSize := len(cs.Public) - witnessOffset + len(cs.Secret) + + if len(witness) != expectedWitnessSize { + return nil, fmt.Errorf("invalid witness size, got %d, expected %d", len(witness), expectedWitnessSize) + } + + // check all hints are there + hintFunctions := opt.HintFunctions + + // hintsDependencies is from compile time; it contains the list of hints the solver **needs** + var missing []string + for hintUUID, hintID := range cs.MHintsDependencies { + if _, ok := hintFunctions[hintUUID]; !ok { + missing = append(missing, hintID) + } + } + + if len(missing) > 0 { + return nil, fmt.Errorf("solver missing hint(s): %v", missing) + } + + s := solver{ + system: cs, + values: make([]fr.Element, nbWires), + solved: make([]bool, nbWires), + mHintsFunctions: hintFunctions, + logger: opt.Logger, + q: cs.Field(), + } + + // set the witness indexes as solved + if witnessOffset == 1 { + s.solved[0] = true // ONE_WIRE + s.values[0].SetOne() + } + copy(s.values[witnessOffset:], witness) + for i := range witness { + s.solved[i+witnessOffset] = true + } + + // keep track of the number of wire instantiations we do, for a post solve sanity check + // to ensure we instantiated all wires + s.nbSolved += uint64(len(witness) + witnessOffset) + + if s.Type == constraint.SystemR1CS { + n := ecc.NextPowerOfTwo(uint64(cs.GetNbConstraints())) + s.a = make(fr.Vector, cs.GetNbConstraints(), n) + s.b = make(fr.Vector, cs.GetNbConstraints(), n) + s.c = make(fr.Vector, cs.GetNbConstraints(), n) + } + + return &s, nil +} + +func (s *solver) set(id int, value fr.Element) { + if s.solved[id] { + panic("solving the same wire twice should never happen.") + } + s.values[id] = value + s.solved[id] = true + atomic.AddUint64(&s.nbSolved, 1) +} + +// computeTerm computes coeff*variable +// TODO @gbotrel check if t is a Constant only +func (s *solver) computeTerm(t constraint.Term) fr.Element { + cID, vID := t.CoeffID(), t.WireID() + if cID != 0 && !s.solved[vID] { + panic("computing a term with an unsolved wire") + } + switch cID { + case constraint.CoeffIdZero: + return fr.Element{} + case constraint.CoeffIdOne: + return s.values[vID] + case constraint.CoeffIdTwo: + var res fr.Element + res.Double(&s.values[vID]) + return res + case constraint.CoeffIdMinusOne: + var res fr.Element + res.Neg(&s.values[vID]) + return res + default: + var res fr.Element + res.Mul(&s.Coefficients[cID], &s.values[vID]) + return res + } +} + +// r += (t.coeff*t.value) +// TODO @gbotrel check t.IsConstant on the caller side when necessary +func (s *solver) accumulateInto(t constraint.Term, r *fr.Element) { + cID := t.CoeffID() + vID := t.WireID() + + switch cID { + case constraint.CoeffIdZero: + return + case constraint.CoeffIdOne: + r.Add(r, &s.values[vID]) + case constraint.CoeffIdTwo: + var res fr.Element + res.Double(&s.values[vID]) + r.Add(r, &res) + case constraint.CoeffIdMinusOne: + r.Sub(r, &s.values[vID]) + default: + var res fr.Element + res.Mul(&s.Coefficients[cID], &s.values[vID]) + r.Add(r, &res) + } +} + +// solveWithHint executes a hint and assign the result to its defined outputs. +func (s *solver) solveWithHint(h *constraint.HintMapping) error { + // ensure hint function was provided + f, ok := s.mHintsFunctions[h.HintID] + if !ok { + return errors.New("missing hint function") + } + + // tmp IO big int memory + nbInputs := len(h.Inputs) + nbOutputs := int(h.OutputRange.End - h.OutputRange.Start) + inputs := make([]*big.Int, nbInputs) + outputs := make([]*big.Int, nbOutputs) + for i := 0; i < nbOutputs; i++ { + outputs[i] = pool.BigInt.Get() + outputs[i].SetUint64(0) + } + + q := pool.BigInt.Get() + q.Set(s.q) + + for i := 0; i < nbInputs; i++ { + var v fr.Element + for _, term := range h.Inputs[i] { + if term.IsConstant() { + v.Add(&v, &s.Coefficients[term.CoeffID()]) + continue + } + s.accumulateInto(term, &v) + } + inputs[i] = pool.BigInt.Get() + v.BigInt(inputs[i]) + } + + err := f(q, inputs, outputs) + + var v fr.Element + for i := range outputs { + v.SetBigInt(outputs[i]) + s.set(int(h.OutputRange.Start)+i, v) + pool.BigInt.Put(outputs[i]) + } + + for i := range inputs { + pool.BigInt.Put(inputs[i]) + } + + pool.BigInt.Put(q) + + return err +} + +func (s *solver) printLogs(logs []constraint.LogEntry) { + if s.logger.GetLevel() == zerolog.Disabled { + return + } + + for i := 0; i < len(logs); i++ { + logLine := s.logValue(logs[i]) + s.logger.Debug().Str(zerolog.CallerFieldName, logs[i].Caller).Msg(logLine) + } +} + +const unsolvedVariable = "" + +func (s *solver) logValue(log constraint.LogEntry) string { + var toResolve []interface{} + var ( + eval fr.Element + missingValue bool + ) + for j := 0; j < len(log.ToResolve); j++ { + // before eval le + + missingValue = false + eval.SetZero() + + for _, t := range log.ToResolve[j] { + // for each term in the linear expression + + cID, vID := t.CoeffID(), t.WireID() + if t.IsConstant() { + // just add the constant + eval.Add(&eval, &s.Coefficients[cID]) + continue + } + + if !s.solved[vID] { + missingValue = true + break // stop the loop we can't evaluate. + } + + tv := s.computeTerm(t) + eval.Add(&eval, &tv) + } + + // after + if missingValue { + toResolve = append(toResolve, unsolvedVariable) + } else { + // we have to append our accumulator + toResolve = append(toResolve, eval.String()) + } + + } + if len(log.Stack) > 0 { + var sbb strings.Builder + for _, lID := range log.Stack { + location := s.SymbolTable.Locations[lID] + function := s.SymbolTable.Functions[location.FunctionID] + + sbb.WriteString(function.Name) + sbb.WriteByte('\n') + sbb.WriteByte('\t') + sbb.WriteString(function.Filename) + sbb.WriteByte(':') + sbb.WriteString(strconv.Itoa(int(location.Line))) + sbb.WriteByte('\n') + } + toResolve = append(toResolve, sbb.String()) + } + return fmt.Sprintf(log.Format, toResolve...) +} + +// divByCoeff sets res = res / t.Coeff +func (solver *solver) divByCoeff(res *fr.Element, cID uint32) { + switch cID { + case constraint.CoeffIdOne: + return + case constraint.CoeffIdMinusOne: + res.Neg(res) + case constraint.CoeffIdZero: + panic("division by 0") + default: + // this is slow, but shouldn't happen as divByCoeff is called to + // remove the coeff of an unsolved wire + // but unsolved wires are (in gnark frontend) systematically set with a coeff == 1 or -1 + res.Div(res, &solver.Coefficients[cID]) + } +} + +// Implement constraint.Solver +func (s *solver) GetValue(cID, vID uint32) constraint.Element { + var r constraint.Element + e := s.computeTerm(constraint.Term{CID: cID, VID: vID}) + copy(r[:], e[:]) + return r +} +func (s *solver) GetCoeff(cID uint32) constraint.Element { + var r constraint.Element + copy(r[:], s.Coefficients[cID][:]) + return r +} +func (s *solver) SetValue(vID uint32, f constraint.Element) { + s.set(int(vID), *(*fr.Element)(f[:])) +} + +func (s *solver) IsSolved(vID uint32) bool { + return s.solved[vID] +} + +// processInstruction decodes the instruction and execute blueprint-defined logic. +// an instruction can encode a hint, a custom constraint or a generic constraint. +func (solver *solver) processInstruction(inst constraint.Instruction, scratch *scratch) error { + // fetch the blueprint + blueprint := solver.Blueprints[inst.BlueprintID] + calldata := solver.GetCallData(inst) + cID := inst.ConstraintOffset // here we have 1 constraint in the instruction only + + if solver.Type == constraint.SystemR1CS { + if bc, ok := blueprint.(constraint.BlueprintR1C); ok { + // TODO @gbotrel we use the solveR1C method for now, having user-defined + // blueprint for R1CS would require constraint.Solver interface to add methods + // to set a,b,c since it's more efficient to compute these while we solve. + bc.DecompressR1C(&scratch.tR1C, calldata) + return solver.solveR1C(cID, &scratch.tR1C) + } + } else if solver.Type == constraint.SystemSparseR1CS { + // blueprint declared "I know how to solve this." + if bc, ok := blueprint.(constraint.BlueprintSolvable); ok { + if err := bc.Solve(solver, calldata); err != nil { + return solver.wrapErrWithDebugInfo(cID, err) + } + return nil + } + } + + // blueprint encodes a hint, we execute. + // TODO @gbotrel may be worth it to move hint logic in blueprint "solve" + if bc, ok := blueprint.(constraint.BlueprintHint); ok { + bc.DecompressHint(&scratch.tHint, calldata) + return solver.solveWithHint(&scratch.tHint) + } + + return nil +} + +// run runs the solver. it return an error if a constraint is not satisfied or if not all wires +// were instantiated. +func (solver *solver) run() error { + // minWorkPerCPU is the minimum target number of constraint a task should hold + // in other words, if a level has less than minWorkPerCPU, it will not be parallelized and executed + // sequentially without sync. + const minWorkPerCPU = 50.0 // TODO @gbotrel revisit that with blocks. + + // cs.Levels has a list of levels, where all constraints in a level l(n) are independent + // and may only have dependencies on previous levels + // for each constraint + // we are guaranteed that each R1C contains at most one unsolved wire + // first we solve the unsolved wire (if any) + // then we check that the constraint is valid + // if a[i] * b[i] != c[i]; it means the constraint is not satisfied + var wg sync.WaitGroup + chTasks := make(chan []int, runtime.NumCPU()) + chError := make(chan error, runtime.NumCPU()) + + // start a worker pool + // each worker wait on chTasks + // a task is a slice of constraint indexes to be solved + for i := 0; i < runtime.NumCPU(); i++ { + go func() { + var scratch scratch + for t := range chTasks { + for _, i := range t { + if err := solver.processInstruction(solver.Instructions[i], &scratch); err != nil { + chError <- err + wg.Done() + return + } + } + wg.Done() + } + }() + } + + // clean up pool go routines + defer func() { + close(chTasks) + close(chError) + }() + + var scratch scratch + + // for each level, we push the tasks + for _, level := range solver.Levels { + + // max CPU to use + maxCPU := float64(len(level)) / minWorkPerCPU + + if maxCPU <= 1.0 { + // we do it sequentially + for _, i := range level { + if err := solver.processInstruction(solver.Instructions[i], &scratch); err != nil { + return err + } + } + continue + } + + // number of tasks for this level is set to number of CPU + // but if we don't have enough work for all our CPU, it can be lower. + nbTasks := runtime.NumCPU() + maxTasks := int(math.Ceil(maxCPU)) + if nbTasks > maxTasks { + nbTasks = maxTasks + } + nbIterationsPerCpus := len(level) / nbTasks + + // more CPUs than tasks: a CPU will work on exactly one iteration + // note: this depends on minWorkPerCPU constant + if nbIterationsPerCpus < 1 { + nbIterationsPerCpus = 1 + nbTasks = len(level) + } + + extraTasks := len(level) - (nbTasks * nbIterationsPerCpus) + extraTasksOffset := 0 + + for i := 0; i < nbTasks; i++ { + wg.Add(1) + _start := i*nbIterationsPerCpus + extraTasksOffset + _end := _start + nbIterationsPerCpus + if extraTasks > 0 { + _end++ + extraTasks-- + extraTasksOffset++ + } + // since we're never pushing more than num CPU tasks + // we will never be blocked here + chTasks <- level[_start:_end] + } + + // wait for the level to be done + wg.Wait() + + if len(chError) > 0 { + return <-chError + } + } + + if int(solver.nbSolved) != len(solver.values) { + return errors.New("solver didn't assign a value to all wires") + } + + return nil +} + +// solveR1C compute unsolved wires in the constraint, if any and set the solver accordingly +// +// returns an error if the solver called a hint function that errored +// returns false, nil if there was no wire to solve +// returns true, nil if exactly one wire was solved. In that case, it is redundant to check that +// the constraint is satisfied later. +func (solver *solver) solveR1C(cID uint32, r *constraint.R1C) error { + a, b, c := &solver.a[cID], &solver.b[cID], &solver.c[cID] + + // the index of the non-zero entry shows if L, R or O has an uninstantiated wire + // the content is the ID of the wire non instantiated + var loc uint8 + + var termToCompute constraint.Term + + processLExp := func(l constraint.LinearExpression, val *fr.Element, locValue uint8) { + for _, t := range l { + vID := t.WireID() + + // wire is already computed, we just accumulate in val + if solver.solved[vID] { + solver.accumulateInto(t, val) + continue + } + + if loc != 0 { + panic("found more than one wire to instantiate") + } + termToCompute = t + loc = locValue + } + } + + processLExp(r.L, a, 1) + processLExp(r.R, b, 2) + processLExp(r.O, c, 3) + + if loc == 0 { + // there is nothing to solve, may happen if we have an assertion + // (ie a constraints that doesn't yield any output) + // or if we solved the unsolved wires with hint functions + var check fr.Element + if !check.Mul(a, b).Equal(c) { + return solver.wrapErrWithDebugInfo(cID, fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String())) + } + return nil + } + + // we compute the wire value and instantiate it + wID := termToCompute.WireID() + + // solver result + var wire fr.Element + + switch loc { + case 1: + if !b.IsZero() { + wire.Div(c, b). + Sub(&wire, a) + a.Add(a, &wire) + } else { + // we didn't actually ensure that a * b == c + var check fr.Element + if !check.Mul(a, b).Equal(c) { + return solver.wrapErrWithDebugInfo(cID, fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String())) + } + } + case 2: + if !a.IsZero() { + wire.Div(c, a). + Sub(&wire, b) + b.Add(b, &wire) + } else { + var check fr.Element + if !check.Mul(a, b).Equal(c) { + return solver.wrapErrWithDebugInfo(cID, fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String())) + } + } + case 3: + wire.Mul(a, b). + Sub(&wire, c) + + c.Add(c, &wire) + } + + // wire is the term (coeff * value) + // but in the solver we want to store the value only + // note that in gnark frontend, coeff here is always 1 or -1 + solver.divByCoeff(&wire, termToCompute.CID) + solver.set(wID, wire) + + return nil +} + +// UnsatisfiedConstraintError wraps an error with useful metadata on the unsatisfied constraint +type UnsatisfiedConstraintError struct { + Err error + CID int // constraint ID + DebugInfo *string // optional debug info +} + +func (r *UnsatisfiedConstraintError) Error() string { + if r.DebugInfo != nil { + return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, *r.DebugInfo) + } + return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, r.Err.Error()) +} + +func (solver *solver) wrapErrWithDebugInfo(cID uint32, err error) *UnsatisfiedConstraintError { + var debugInfo *string + if dID, ok := solver.MDebug[int(cID)]; ok { + debugInfo = new(string) + *debugInfo = solver.logValue(solver.DebugInfo[dID]) + } + return &UnsatisfiedConstraintError{CID: int(cID), Err: err, DebugInfo: debugInfo} +} + +// temporary variables to avoid memallocs in hotloop +type scratch struct { + tR1C constraint.R1C + tHint constraint.HintMapping +} diff --git a/constraint/bn254/system.go b/constraint/bn254/system.go new file mode 100644 index 0000000000..7e861e9b6d --- /dev/null +++ b/constraint/bn254/system.go @@ -0,0 +1,365 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package cs + +import ( + "github.com/fxamacker/cbor/v2" + "io" + "time" + + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint" + csolver "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/internal/backend/ioutils" + "github.com/consensys/gnark/logger" + "reflect" + + "github.com/consensys/gnark-crypto/ecc" + + "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +type R1CS = system +type SparseR1CS = system + +// system is a curved-typed constraint.System with a concrete coefficient table (fr.Element) +type system struct { + constraint.System + CoeffTable + field +} + +func NewR1CS(capacity int) *R1CS { + return newSystem(capacity, constraint.SystemR1CS) +} + +func NewSparseR1CS(capacity int) *SparseR1CS { + return newSystem(capacity, constraint.SystemSparseR1CS) +} + +func newSystem(capacity int, t constraint.SystemType) *system { + return &system{ + System: constraint.NewSystem(fr.Modulus(), capacity, t), + CoeffTable: newCoeffTable(capacity / 10), + } +} + +// Solve solves the constraint system with provided witness. +// If it's a R1CS returns R1CSSolution +// If it's a SparseR1CS returns SparseR1CSSolution +func (cs *system) Solve(witness witness.Witness, opts ...csolver.Option) (any, error) { + log := logger.Logger().With().Int("nbConstraints", cs.GetNbConstraints()).Logger() + start := time.Now() + + v := witness.Vector().(fr.Vector) + + // init the solver + solver, err := newSolver(cs, v, opts...) + if err != nil { + log.Err(err).Send() + return nil, err + } + + // defer log printing once all solver.values are computed + // (or sooner, if a constraint is not satisfied) + defer solver.printLogs(cs.Logs) + + // run it. + if err := solver.run(); err != nil { + log.Err(err).Send() + return nil, err + } + + log.Debug().Dur("took", time.Since(start)).Msg("constraint system solver done") + + // format the solution + // TODO @gbotrel revisit post-refactor + if cs.Type == constraint.SystemR1CS { + var res R1CSSolution + res.W = solver.values + res.A = solver.a + res.B = solver.b + res.C = solver.c + return &res, nil + } else { + // sparse R1CS + var res SparseR1CSSolution + // query l, r, o in Lagrange basis, not blinded + res.L, res.R, res.O = evaluateLROSmallDomain(cs, solver.values) + + return &res, nil + } + +} + +// IsSolved +// Deprecated: use _, err := Solve(...) instead +func (cs *system) IsSolved(witness witness.Witness, opts ...csolver.Option) error { + _, err := cs.Solve(witness, opts...) + return err +} + +// GetR1Cs return the list of R1C +func (cs *system) GetR1Cs() []constraint.R1C { + toReturn := make([]constraint.R1C, 0, cs.GetNbConstraints()) + + for _, inst := range cs.Instructions { + blueprint := cs.Blueprints[inst.BlueprintID] + if bc, ok := blueprint.(constraint.BlueprintR1C); ok { + var r1c constraint.R1C + bc.DecompressR1C(&r1c, cs.GetCallData(inst)) + toReturn = append(toReturn, r1c) + } else { + panic("not implemented") + } + } + return toReturn +} + +// GetNbCoefficients return the number of unique coefficients needed in the R1CS +func (cs *system) GetNbCoefficients() int { + return len(cs.Coefficients) +} + +// CurveID returns curve ID as defined in gnark-crypto +func (cs *system) CurveID() ecc.ID { + return ecc.BN254 +} + +// WriteTo encodes R1CS into provided io.Writer using cbor +func (cs *system) WriteTo(w io.Writer) (int64, error) { + _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written + ts := getTagSet() + enc, err := cbor.CoreDetEncOptions().EncModeWithTags(ts) + if err != nil { + return 0, err + } + encoder := enc.NewEncoder(&_w) + + // encode our object + err = encoder.Encode(cs) + return _w.N, err +} + +// ReadFrom attempts to decode R1CS from io.Reader using cbor +func (cs *system) ReadFrom(r io.Reader) (int64, error) { + ts := getTagSet() + dm, err := cbor.DecOptions{ + MaxArrayElements: 134217728, + MaxMapPairs: 134217728, + }.DecModeWithTags(ts) + + if err != nil { + return 0, err + } + decoder := dm.NewDecoder(r) + + // initialize coeff table + cs.CoeffTable = newCoeffTable(0) + + if err := decoder.Decode(&cs); err != nil { + return int64(decoder.NumBytesRead()), err + } + + if err := cs.CheckSerializationHeader(); err != nil { + return int64(decoder.NumBytesRead()), err + } + + return int64(decoder.NumBytesRead()), nil +} + +func (cs *system) GetCoefficient(i int) (r constraint.Element) { + copy(r[:], cs.Coefficients[i][:]) + return +} + +// GetSparseR1Cs return the list of SparseR1C +func (cs *system) GetSparseR1Cs() []constraint.SparseR1C { + + toReturn := make([]constraint.SparseR1C, 0, cs.GetNbConstraints()) + + for _, inst := range cs.Instructions { + blueprint := cs.Blueprints[inst.BlueprintID] + if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { + var sparseR1C constraint.SparseR1C + calldata := cs.CallData[inst.StartCallData : inst.StartCallData+uint64(blueprint.NbInputs())] + bc.DecompressSparseR1C(&sparseR1C, calldata) + toReturn = append(toReturn, sparseR1C) + } else { + panic("not implemented") + } + } + return toReturn +} + +// evaluateLROSmallDomain extracts the solver l, r, o, and returns it in lagrange form. +// solver = [ public | secret | internal ] +// TODO @gbotrel refactor; this seems to be a small util function for plonk +func evaluateLROSmallDomain(cs *system, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { + + //s := int(pk.Domain[0].Cardinality) + s := cs.GetNbConstraints() + len(cs.Public) // len(spr.Public) is for the placeholder constraints + s = int(ecc.NextPowerOfTwo(uint64(s))) + + var l, r, o []fr.Element + l = make([]fr.Element, s) + r = make([]fr.Element, s) + o = make([]fr.Element, s) + s0 := solution[0] + + for i := 0; i < len(cs.Public); i++ { // placeholders + l[i] = solution[i] + r[i] = s0 + o[i] = s0 + } + offset := len(cs.Public) + nbConstraints := cs.GetNbConstraints() + + var sparseR1C constraint.SparseR1C + j := 0 + for _, inst := range cs.Instructions { + blueprint := cs.Blueprints[inst.BlueprintID] + if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { + bc.DecompressSparseR1C(&sparseR1C, cs.GetCallData(inst)) + + l[offset+j] = solution[sparseR1C.XA] + r[offset+j] = solution[sparseR1C.XB] + o[offset+j] = solution[sparseR1C.XC] + j++ + } + } + + offset += nbConstraints + + for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solver[0]) + l[offset+i] = s0 + r[offset+i] = s0 + o[offset+i] = s0 + } + + return l, r, o + +} + +// R1CSSolution represent a valid assignment to all the variables in the constraint system. +// The vector W such that Aw o Bw - Cw = 0 +type R1CSSolution struct { + W fr.Vector + A, B, C fr.Vector +} + +func (t *R1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.W.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.A.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.B.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.C.WriteTo(w) + n += a + return n, err +} + +func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.W.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.A.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.B.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.C.ReadFrom(r) + n += a + return n, err +} + +// SparseR1CSSolution represent a valid assignment to all the variables in the constraint system. +type SparseR1CSSolution struct { + L, R, O fr.Vector +} + +func (t *SparseR1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.L.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.R.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.O.WriteTo(w) + n += a + return n, err + +} + +func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.L.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.R.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.O.ReadFrom(r) + a += n + return n, err +} + +func getTagSet() cbor.TagSet { + // temporary for refactor + ts := cbor.NewTagSet() + // https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml + // 65536-15309735 Unassigned + tagNum := uint64(5309735) + addType := func(t reflect.Type) { + if err := ts.Add( + cbor.TagOptions{EncTag: cbor.EncTagRequired, DecTag: cbor.DecTagRequired}, + t, + tagNum, + ); err != nil { + panic(err) + } + tagNum++ + } + + addType(reflect.TypeOf(constraint.BlueprintGenericHint{})) + addType(reflect.TypeOf(constraint.BlueprintGenericR1C{})) + addType(reflect.TypeOf(constraint.BlueprintGenericSparseR1C{})) + addType(reflect.TypeOf(constraint.BlueprintSparseR1CAdd{})) + addType(reflect.TypeOf(constraint.BlueprintSparseR1CMul{})) + + return ts +} diff --git a/constraint/bw6-633/coeff.go b/constraint/bw6-633/coeff.go index 48b63963d7..01d84ce575 100644 --- a/constraint/bw6-633/coeff.go +++ b/constraint/bw6-633/coeff.go @@ -46,7 +46,7 @@ func newCoeffTable(capacity int) CoeffTable { } -func (ct *CoeffTable) MakeTerm(coeff *constraint.Coeff, variableID int) constraint.Term { +func (ct *CoeffTable) AddCoeff(coeff constraint.Element) uint32 { c := (*fr.Element)(coeff[:]) var cID uint32 if c.IsZero() { @@ -69,7 +69,11 @@ func (ct *CoeffTable) MakeTerm(coeff *constraint.Coeff, variableID int) constrai ct.mCoeffs[cc] = cID } } + return cID +} +func (ct *CoeffTable) MakeTerm(coeff *constraint.Element, variableID int) constraint.Term { + cID := ct.AddCoeff(*coeff) return constraint.Term{VID: uint32(variableID), CID: cID} } @@ -78,7 +82,10 @@ func (ct *CoeffTable) CoeffToString(cID int) string { return ct.Coefficients[cID].String() } -var _ constraint.CoeffEngine = &arithEngine{} +// implements constraint.Field +type field struct{} + +var _ constraint.Field = &field{} var ( two fr.Element @@ -94,10 +101,7 @@ func init() { minusTwo.Neg(&two) } -// implements constraint.CoeffEngine -type arithEngine struct{} - -func (engine *arithEngine) FromInterface(i interface{}) constraint.Coeff { +func (engine *field) FromInterface(i interface{}) constraint.Element { var e fr.Element if _, err := e.SetInterface(i); err != nil { // need to clean that --> some code path are dissimilar @@ -106,55 +110,75 @@ func (engine *arithEngine) FromInterface(i interface{}) constraint.Coeff { b := utils.FromInterface(i) e.SetBigInt(&b) } - var r constraint.Coeff + var r constraint.Element copy(r[:], e[:]) return r } -func (engine *arithEngine) ToBigInt(c *constraint.Coeff) *big.Int { +func (engine *field) ToBigInt(c constraint.Element) *big.Int { e := (*fr.Element)(c[:]) r := new(big.Int) e.BigInt(r) return r } -func (engine *arithEngine) Mul(a, b *constraint.Coeff) { +func (engine *field) Mul(a, b constraint.Element) constraint.Element { _a := (*fr.Element)(a[:]) _b := (*fr.Element)(b[:]) _a.Mul(_a, _b) + return a } -func (engine *arithEngine) Add(a, b *constraint.Coeff) { + +func (engine *field) Add(a, b constraint.Element) constraint.Element { _a := (*fr.Element)(a[:]) _b := (*fr.Element)(b[:]) _a.Add(_a, _b) + return a } -func (engine *arithEngine) Sub(a, b *constraint.Coeff) { +func (engine *field) Sub(a, b constraint.Element) constraint.Element { _a := (*fr.Element)(a[:]) _b := (*fr.Element)(b[:]) _a.Sub(_a, _b) + return a } -func (engine *arithEngine) Neg(a *constraint.Coeff) { +func (engine *field) Neg(a constraint.Element) constraint.Element { e := (*fr.Element)(a[:]) e.Neg(e) + return a } -func (engine *arithEngine) Inverse(a *constraint.Coeff) { +func (engine *field) Inverse(a constraint.Element) (constraint.Element, bool) { + if a.IsZero() { + return a, false + } e := (*fr.Element)(a[:]) + if e.IsZero() { + return a, false + } else if e.IsOne() { + return a, true + } + var t fr.Element + t.Neg(e) + if t.IsOne() { + return a, true + } + e.Inverse(e) + return a, true } -func (engine *arithEngine) IsOne(a *constraint.Coeff) bool { +func (engine *field) IsOne(a constraint.Element) bool { e := (*fr.Element)(a[:]) return e.IsOne() } -func (engine *arithEngine) One() constraint.Coeff { +func (engine *field) One() constraint.Element { e := fr.One() - var r constraint.Coeff + var r constraint.Element copy(r[:], e[:]) return r } -func (engine *arithEngine) String(a *constraint.Coeff) string { +func (engine *field) String(a constraint.Element) string { e := (*fr.Element)(a[:]) return e.String() } diff --git a/constraint/bw6-633/r1cs.go b/constraint/bw6-633/r1cs.go deleted file mode 100644 index 52500bfea7..0000000000 --- a/constraint/bw6-633/r1cs.go +++ /dev/null @@ -1,467 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// 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. - -// Code generated by gnark DO NOT EDIT - -package cs - -import ( - "errors" - "fmt" - "github.com/fxamacker/cbor/v2" - "io" - "runtime" - "sync" - "time" - - "github.com/consensys/gnark/backend/witness" - "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/internal/backend/ioutils" - "github.com/consensys/gnark/logger" - "github.com/consensys/gnark/profile" - - "github.com/consensys/gnark-crypto/ecc" - "math" - - "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" -) - -// R1CS describes a set of R1CS constraint -type R1CS struct { - constraint.R1CSCore - CoeffTable - arithEngine -} - -// NewR1CS returns a new R1CS and sets cs.Coefficient (fr.Element) from provided big.Int values -// -// capacity pre-allocates memory for capacity nbConstraints -func NewR1CS(capacity int) *R1CS { - r := R1CS{ - R1CSCore: constraint.R1CSCore{ - System: constraint.NewSystem(fr.Modulus()), - Constraints: make([]constraint.R1C, 0, capacity), - }, - CoeffTable: newCoeffTable(capacity / 10), - } - return &r -} - -func (cs *R1CS) AddConstraint(r1c constraint.R1C, debugInfo ...constraint.DebugInfo) int { - profile.RecordConstraint() - cs.Constraints = append(cs.Constraints, r1c) - cID := len(cs.Constraints) - 1 - if len(debugInfo) == 1 { - cs.DebugInfo = append(cs.DebugInfo, constraint.LogEntry(debugInfo[0])) - cs.MDebug[cID] = len(cs.DebugInfo) - 1 - } - - cs.UpdateLevel(cID, &r1c) - - return cID -} - -// Solve returns the vector w solution to the system, that is -// Aw o Bw - Cw = 0 -func (cs *R1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { - opt, err := solver.NewConfig(opts...) - if err != nil { - return nil, err - } - - var res R1CSSolution - - s := ecc.NextPowerOfTwo(uint64(len(cs.Constraints))) - res.A = make(fr.Vector, len(cs.Constraints), s) - res.B = make(fr.Vector, len(cs.Constraints), s) - res.C = make(fr.Vector, len(cs.Constraints), s) - - v := witness.Vector().(fr.Vector) - - res.W, err = cs.solve(v, res.A, res.B, res.C, opt) - if err != nil { - return nil, err - } - - return &res, nil -} - -// Solve sets all the wires and returns the a, b, c vectors. -// the cs system should have been compiled before. The entries in a, b, c are in Montgomery form. -// a, b, c vectors: ab-c = hz -// witness = [publicWires | secretWires] (without the ONE_WIRE !) -// returns [publicWires | secretWires | internalWires ] -func (cs *R1CS) solve(witness, a, b, c fr.Vector, opt solver.Config) (fr.Vector, error) { - log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() - - nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - solution, err := newSolution(&cs.System, nbWires, opt.HintFunctions, cs.Coefficients) - if err != nil { - return make(fr.Vector, nbWires), err - } - start := time.Now() - - if len(witness) != len(cs.Public)-1+len(cs.Secret) { // - 1 for ONE_WIRE - err = fmt.Errorf("invalid witness size, got %d, expected %d = %d (public) + %d (secret)", len(witness), int(len(cs.Public)-1+len(cs.Secret)), len(cs.Public)-1, len(cs.Secret)) - log.Err(err).Send() - return solution.values, err - } - - // compute the wires and the a, b, c polynomials - if len(a) != len(cs.Constraints) || len(b) != len(cs.Constraints) || len(c) != len(cs.Constraints) { - err = errors.New("invalid input size: len(a, b, c) == len(Constraints)") - log.Err(err).Send() - return solution.values, err - } - - solution.solved[0] = true // ONE_WIRE - solution.values[0].SetOne() - copy(solution.values[1:], witness) - for i := range witness { - solution.solved[i+1] = true - } - - // keep track of the number of wire instantiations we do, for a sanity check to ensure - // we instantiated all wires - solution.nbSolved += uint64(len(witness) + 1) - - // now that we know all inputs are set, defer log printing once all solution.values are computed - // (or sooner, if a constraint is not satisfied) - defer solution.printLogs(opt.Logger, cs.Logs) - - if err := cs.parallelSolve(a, b, c, &solution); err != nil { - if unsatisfiedErr, ok := err.(*UnsatisfiedConstraintError); ok { - log.Err(errors.New("unsatisfied constraint")).Int("id", unsatisfiedErr.CID).Send() - } else { - log.Err(err).Send() - } - return solution.values, err - } - - // sanity check; ensure all wires are marked as "instantiated" - if !solution.isValid() { - log.Err(errors.New("solver didn't instantiate all wires")).Send() - panic("solver didn't instantiate all wires") - } - - log.Debug().Dur("took", time.Since(start)).Msg("constraint system solver done") - - return solution.values, nil -} - -func (cs *R1CS) parallelSolve(a, b, c fr.Vector, solution *solution) error { - // minWorkPerCPU is the minimum target number of constraint a task should hold - // in other words, if a level has less than minWorkPerCPU, it will not be parallelized and executed - // sequentially without sync. - const minWorkPerCPU = 50.0 - - // cs.Levels has a list of levels, where all constraints in a level l(n) are independent - // and may only have dependencies on previous levels - // for each constraint - // we are guaranteed that each R1C contains at most one unsolved wire - // first we solve the unsolved wire (if any) - // then we check that the constraint is valid - // if a[i] * b[i] != c[i]; it means the constraint is not satisfied - - var wg sync.WaitGroup - chTasks := make(chan []int, runtime.NumCPU()) - chError := make(chan *UnsatisfiedConstraintError, runtime.NumCPU()) - - // start a worker pool - // each worker wait on chTasks - // a task is a slice of constraint indexes to be solved - for i := 0; i < runtime.NumCPU(); i++ { - go func() { - for t := range chTasks { - for _, i := range t { - // for each constraint in the task, solve it. - if err := cs.solveConstraint(cs.Constraints[i], solution, &a[i], &b[i], &c[i]); err != nil { - var debugInfo *string - if dID, ok := cs.MDebug[i]; ok { - debugInfo = new(string) - *debugInfo = solution.logValue(cs.DebugInfo[dID]) - } - chError <- &UnsatisfiedConstraintError{CID: i, Err: err, DebugInfo: debugInfo} - wg.Done() - return - } - } - wg.Done() - } - }() - } - - // clean up pool go routines - defer func() { - close(chTasks) - close(chError) - }() - - // for each level, we push the tasks - for _, level := range cs.Levels { - - // max CPU to use - maxCPU := float64(len(level)) / minWorkPerCPU - - if maxCPU <= 1.0 { - // we do it sequentially - for _, i := range level { - if err := cs.solveConstraint(cs.Constraints[i], solution, &a[i], &b[i], &c[i]); err != nil { - var debugInfo *string - if dID, ok := cs.MDebug[i]; ok { - debugInfo = new(string) - *debugInfo = solution.logValue(cs.DebugInfo[dID]) - } - return &UnsatisfiedConstraintError{CID: i, Err: err, DebugInfo: debugInfo} - } - } - continue - } - - // number of tasks for this level is set to number of CPU - // but if we don't have enough work for all our CPU, it can be lower. - nbTasks := runtime.NumCPU() - maxTasks := int(math.Ceil(maxCPU)) - if nbTasks > maxTasks { - nbTasks = maxTasks - } - nbIterationsPerCpus := len(level) / nbTasks - - // more CPUs than tasks: a CPU will work on exactly one iteration - // note: this depends on minWorkPerCPU constant - if nbIterationsPerCpus < 1 { - nbIterationsPerCpus = 1 - nbTasks = len(level) - } - - extraTasks := len(level) - (nbTasks * nbIterationsPerCpus) - extraTasksOffset := 0 - - for i := 0; i < nbTasks; i++ { - wg.Add(1) - _start := i*nbIterationsPerCpus + extraTasksOffset - _end := _start + nbIterationsPerCpus - if extraTasks > 0 { - _end++ - extraTasks-- - extraTasksOffset++ - } - // since we're never pushing more than num CPU tasks - // we will never be blocked here - chTasks <- level[_start:_end] - } - - // wait for the level to be done - wg.Wait() - - if len(chError) > 0 { - return <-chError - } - } - - return nil -} - -// IsSolved -// Deprecated: use _, err := Solve(...) instead -func (cs *R1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { - _, err := cs.Solve(witness, opts...) - return err -} - -// divByCoeff sets res = res / t.Coeff -func (cs *R1CS) divByCoeff(res *fr.Element, t constraint.Term) { - cID := t.CoeffID() - switch cID { - case constraint.CoeffIdOne: - return - case constraint.CoeffIdMinusOne: - res.Neg(res) - case constraint.CoeffIdZero: - panic("division by 0") - default: - // this is slow, but shouldn't happen as divByCoeff is called to - // remove the coeff of an unsolved wire - // but unsolved wires are (in gnark frontend) systematically set with a coeff == 1 or -1 - res.Div(res, &cs.Coefficients[cID]) - } -} - -// solveConstraint compute unsolved wires in the constraint, if any and set the solution accordingly -// -// returns an error if the solver called a hint function that errored -// returns false, nil if there was no wire to solve -// returns true, nil if exactly one wire was solved. In that case, it is redundant to check that -// the constraint is satisfied later. -func (cs *R1CS) solveConstraint(r constraint.R1C, solution *solution, a, b, c *fr.Element) error { - - // the index of the non-zero entry shows if L, R or O has an uninstantiated wire - // the content is the ID of the wire non instantiated - var loc uint8 - - var termToCompute constraint.Term - - processLExp := func(l constraint.LinearExpression, val *fr.Element, locValue uint8) error { - for _, t := range l { - vID := t.WireID() - - // wire is already computed, we just accumulate in val - if solution.solved[vID] { - solution.accumulateInto(t, val) - continue - } - - // first we check if this is a hint wire - if hint, ok := cs.MHints[vID]; ok { - if err := solution.solveWithHint(vID, hint); err != nil { - return err - } - // now that the wire is saved, accumulate it into a, b or c - solution.accumulateInto(t, val) - continue - } - - if loc != 0 { - panic("found more than one wire to instantiate") - } - termToCompute = t - loc = locValue - } - return nil - } - - if err := processLExp(r.L, a, 1); err != nil { - return err - } - - if err := processLExp(r.R, b, 2); err != nil { - return err - } - - if err := processLExp(r.O, c, 3); err != nil { - return err - } - - if loc == 0 { - // there is nothing to solve, may happen if we have an assertion - // (ie a constraints that doesn't yield any output) - // or if we solved the unsolved wires with hint functions - var check fr.Element - if !check.Mul(a, b).Equal(c) { - return fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String()) - } - return nil - } - - // we compute the wire value and instantiate it - wID := termToCompute.WireID() - - // solver result - var wire fr.Element - - switch loc { - case 1: - if !b.IsZero() { - wire.Div(c, b). - Sub(&wire, a) - a.Add(a, &wire) - } else { - // we didn't actually ensure that a * b == c - var check fr.Element - if !check.Mul(a, b).Equal(c) { - return fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String()) - } - } - case 2: - if !a.IsZero() { - wire.Div(c, a). - Sub(&wire, b) - b.Add(b, &wire) - } else { - var check fr.Element - if !check.Mul(a, b).Equal(c) { - return fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String()) - } - } - case 3: - wire.Mul(a, b). - Sub(&wire, c) - - c.Add(c, &wire) - } - - // wire is the term (coeff * value) - // but in the solution we want to store the value only - // note that in gnark frontend, coeff here is always 1 or -1 - cs.divByCoeff(&wire, termToCompute) - solution.set(wID, wire) - - return nil -} - -// GetConstraints return the list of R1C and a coefficient resolver -func (cs *R1CS) GetConstraints() ([]constraint.R1C, constraint.Resolver) { - return cs.Constraints, cs -} - -// GetNbCoefficients return the number of unique coefficients needed in the R1CS -func (cs *R1CS) GetNbCoefficients() int { - return len(cs.Coefficients) -} - -// CurveID returns curve ID as defined in gnark-crypto -func (cs *R1CS) CurveID() ecc.ID { - return ecc.BW6_633 -} - -// WriteTo encodes R1CS into provided io.Writer using cbor -func (cs *R1CS) WriteTo(w io.Writer) (int64, error) { - _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written - enc, err := cbor.CoreDetEncOptions().EncMode() - if err != nil { - return 0, err - } - encoder := enc.NewEncoder(&_w) - - // encode our object - err = encoder.Encode(cs) - return _w.N, err -} - -// ReadFrom attempts to decode R1CS from io.Reader using cbor -func (cs *R1CS) ReadFrom(r io.Reader) (int64, error) { - dm, err := cbor.DecOptions{ - MaxArrayElements: 134217728, - MaxMapPairs: 134217728, - }.DecMode() - - if err != nil { - return 0, err - } - decoder := dm.NewDecoder(r) - - // initialize coeff table - cs.CoeffTable = newCoeffTable(0) - - if err := decoder.Decode(&cs); err != nil { - return int64(decoder.NumBytesRead()), err - } - - if err := cs.CheckSerializationHeader(); err != nil { - return int64(decoder.NumBytesRead()), err - } - - return int64(decoder.NumBytesRead()), nil -} diff --git a/constraint/bw6-633/r1cs_sparse.go b/constraint/bw6-633/r1cs_sparse.go deleted file mode 100644 index a05dcca6f0..0000000000 --- a/constraint/bw6-633/r1cs_sparse.go +++ /dev/null @@ -1,533 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// 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. - -// Code generated by gnark DO NOT EDIT - -package cs - -import ( - "errors" - "fmt" - "github.com/consensys/gnark-crypto/ecc" - "github.com/fxamacker/cbor/v2" - "io" - "math" - "runtime" - "sync" - "time" - - "github.com/consensys/gnark/backend/witness" - "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/internal/backend/ioutils" - "github.com/consensys/gnark/logger" - "github.com/consensys/gnark/profile" - - "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" -) - -// SparseR1CS represents a Plonk like circuit -type SparseR1CS struct { - constraint.SparseR1CSCore - CoeffTable - arithEngine -} - -// NewSparseR1CS returns a new SparseR1CS and sets r1cs.Coefficient (fr.Element) from provided big.Int values -func NewSparseR1CS(capacity int) *SparseR1CS { - cs := SparseR1CS{ - SparseR1CSCore: constraint.SparseR1CSCore{ - System: constraint.NewSystem(fr.Modulus()), - Constraints: make([]constraint.SparseR1C, 0, capacity), - }, - CoeffTable: newCoeffTable(capacity / 10), - } - - return &cs -} - -func (cs *SparseR1CS) AddConstraint(c constraint.SparseR1C, debugInfo ...constraint.DebugInfo) int { - profile.RecordConstraint() - cs.Constraints = append(cs.Constraints, c) - cID := len(cs.Constraints) - 1 - if len(debugInfo) == 1 { - cs.DebugInfo = append(cs.DebugInfo, constraint.LogEntry(debugInfo[0])) - cs.MDebug[cID] = len(cs.DebugInfo) - 1 - } - cs.UpdateLevel(cID, &c) - - return cID -} - -func (c *SparseR1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { - opt, err := solver.NewConfig(opts...) - if err != nil { - return nil, err - } - - // compute the constraint system solution - var solution []fr.Element - if solution, err = c.solve(witness.Vector().(fr.Vector), opt); err != nil { - return nil, err - } - - var res SparseR1CSSolution - // query l, r, o in Lagrange basis, not blinded - res.L, res.R, res.O = c.evaluateLROSmallDomain(solution) - - return &res, nil -} - -// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. -// solution = [ public | secret | internal ] -func (c *SparseR1CS) evaluateLROSmallDomain(solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { - - //s := int(pk.Domain[0].Cardinality) - s := c.GetNbConstraints() + len(c.Public) // len(spr.Public) is for the placeholder constraints - s = int(ecc.NextPowerOfTwo(uint64(s))) - - var l, r, o []fr.Element - l = make([]fr.Element, s) - r = make([]fr.Element, s) - o = make([]fr.Element, s) - s0 := solution[0] - - for i := 0; i < len(c.Public); i++ { // placeholders - l[i] = solution[i] - r[i] = s0 - o[i] = s0 - } - offset := len(c.Public) - for i := 0; i < len(c.Constraints); i++ { // constraints - l[offset+i] = solution[c.Constraints[i].L.WireID()] - r[offset+i] = solution[c.Constraints[i].R.WireID()] - o[offset+i] = solution[c.Constraints[i].O.WireID()] - } - offset += len(c.Constraints) - - for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) - l[offset+i] = s0 - r[offset+i] = s0 - o[offset+i] = s0 - } - - return l, r, o - -} - -// Solve sets all the wires. -// solution.values = [publicInputs | secretInputs | internalVariables ] -// witness: contains the input variables -// it returns the full slice of wires -func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, error) { - log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "plonk").Logger() - - // set the slices holding the solution.values and monitoring which variables have been solved - nbVariables := cs.NbInternalVariables + len(cs.Secret) + len(cs.Public) - - start := time.Now() - - expectedWitnessSize := len(cs.Public) + len(cs.Secret) - if len(witness) != expectedWitnessSize { - return make(fr.Vector, nbVariables), fmt.Errorf( - "invalid witness size, got %d, expected %d = %d (public) + %d (secret)", - len(witness), - expectedWitnessSize, - len(cs.Public), - len(cs.Secret), - ) - } - - // keep track of wire that have a value - solution, err := newSolution(&cs.System, nbVariables, opt.HintFunctions, cs.Coefficients) - if err != nil { - return solution.values, err - } - - // solution.values = [publicInputs | secretInputs | internalVariables ] -> we fill publicInputs | secretInputs - copy(solution.values, witness) - for i := 0; i < len(witness); i++ { - solution.solved[i] = true - } - - // keep track of the number of wire instantiations we do, for a sanity check to ensure - // we instantiated all wires - solution.nbSolved += uint64(len(witness)) - - // defer log printing once all solution.values are computed - defer solution.printLogs(opt.Logger, cs.Logs) - - // batch invert the coefficients to avoid many divisions in the solver - coefficientsNegInv := fr.BatchInvert(cs.Coefficients) - for i := 0; i < len(coefficientsNegInv); i++ { - coefficientsNegInv[i].Neg(&coefficientsNegInv[i]) - } - - if err := cs.parallelSolve(&solution, coefficientsNegInv); err != nil { - if unsatisfiedErr, ok := err.(*UnsatisfiedConstraintError); ok { - log.Err(errors.New("unsatisfied constraint")).Int("id", unsatisfiedErr.CID).Send() - } else { - log.Err(err).Send() - } - return solution.values, err - } - - // sanity check; ensure all wires are marked as "instantiated" - if !solution.isValid() { - log.Err(errors.New("solver didn't instantiate all wires")).Send() - panic("solver didn't instantiate all wires") - } - - log.Debug().Dur("took", time.Since(start)).Msg("constraint system solver done") - - return solution.values, nil - -} - -func (cs *SparseR1CS) parallelSolve(solution *solution, coefficientsNegInv fr.Vector) error { - // minWorkPerCPU is the minimum target number of constraint a task should hold - // in other words, if a level has less than minWorkPerCPU, it will not be parallelized and executed - // sequentially without sync. - const minWorkPerCPU = 50.0 - - // cs.Levels has a list of levels, where all constraints in a level l(n) are independent - // and may only have dependencies on previous levels - - var wg sync.WaitGroup - chTasks := make(chan []int, runtime.NumCPU()) - chError := make(chan *UnsatisfiedConstraintError, runtime.NumCPU()) - - // start a worker pool - // each worker wait on chTasks - // a task is a slice of constraint indexes to be solved - for i := 0; i < runtime.NumCPU(); i++ { - go func() { - for t := range chTasks { - for _, i := range t { - // for each constraint in the task, solve it. - if err := cs.solveConstraint(cs.Constraints[i], solution, coefficientsNegInv); err != nil { - chError <- &UnsatisfiedConstraintError{CID: i, Err: err} - wg.Done() - return - } - if err := cs.checkConstraint(cs.Constraints[i], solution); err != nil { - if dID, ok := cs.MDebug[i]; ok { - errMsg := solution.logValue(cs.DebugInfo[dID]) - chError <- &UnsatisfiedConstraintError{CID: i, DebugInfo: &errMsg} - } else { - chError <- &UnsatisfiedConstraintError{CID: i, Err: err} - } - wg.Done() - return - } - } - wg.Done() - } - }() - } - - // clean up pool go routines - defer func() { - close(chTasks) - close(chError) - }() - - // for each level, we push the tasks - for _, level := range cs.Levels { - - // max CPU to use - maxCPU := float64(len(level)) / minWorkPerCPU - - if maxCPU <= 1.0 { - // we do it sequentially - for _, i := range level { - if err := cs.solveConstraint(cs.Constraints[i], solution, coefficientsNegInv); err != nil { - return &UnsatisfiedConstraintError{CID: i, Err: err} - } - if err := cs.checkConstraint(cs.Constraints[i], solution); err != nil { - if dID, ok := cs.MDebug[i]; ok { - errMsg := solution.logValue(cs.DebugInfo[dID]) - return &UnsatisfiedConstraintError{CID: i, DebugInfo: &errMsg} - } - return &UnsatisfiedConstraintError{CID: i, Err: err} - } - } - continue - } - - // number of tasks for this level is set to number of CPU - // but if we don't have enough work for all our CPU, it can be lower. - nbTasks := runtime.NumCPU() - maxTasks := int(math.Ceil(maxCPU)) - if nbTasks > maxTasks { - nbTasks = maxTasks - } - nbIterationsPerCpus := len(level) / nbTasks - - // more CPUs than tasks: a CPU will work on exactly one iteration - // note: this depends on minWorkPerCPU constant - if nbIterationsPerCpus < 1 { - nbIterationsPerCpus = 1 - nbTasks = len(level) - } - - extraTasks := len(level) - (nbTasks * nbIterationsPerCpus) - extraTasksOffset := 0 - - for i := 0; i < nbTasks; i++ { - wg.Add(1) - _start := i*nbIterationsPerCpus + extraTasksOffset - _end := _start + nbIterationsPerCpus - if extraTasks > 0 { - _end++ - extraTasks-- - extraTasksOffset++ - } - // since we're never pushing more than num CPU tasks - // we will never be blocked here - chTasks <- level[_start:_end] - } - - // wait for the level to be done - wg.Wait() - - if len(chError) > 0 { - return <-chError - } - } - - return nil -} - -// computeHints computes wires associated with a hint function, if any -// if there is no remaining wire to solve, returns -1 -// else returns the wire position (L -> 0, R -> 1, O -> 2) -func (cs *SparseR1CS) computeHints(c constraint.SparseR1C, solution *solution) (int, error) { - r := -1 - lID, rID, oID := c.L.WireID(), c.R.WireID(), c.O.WireID() - - if (c.L.CoeffID() != 0 || c.M[0].CoeffID() != 0) && !solution.solved[lID] { - // check if it's a hint - if hint, ok := cs.MHints[lID]; ok { - if err := solution.solveWithHint(lID, hint); err != nil { - return -1, err - } - } else { - r = 0 - } - - } - - if (c.R.CoeffID() != 0 || c.M[1].CoeffID() != 0) && !solution.solved[rID] { - // check if it's a hint - if hint, ok := cs.MHints[rID]; ok { - if err := solution.solveWithHint(rID, hint); err != nil { - return -1, err - } - } else { - r = 1 - } - } - - if (c.O.CoeffID() != 0) && !solution.solved[oID] { - // check if it's a hint - if hint, ok := cs.MHints[oID]; ok { - if err := solution.solveWithHint(oID, hint); err != nil { - return -1, err - } - } else { - r = 2 - } - } - return r, nil -} - -// solveConstraint solve any unsolved wire in given constraint and update the solution -// a SparseR1C may have up to one unsolved wire (excluding hints) -// if it doesn't, then this function returns and does nothing -func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution, coefficientsNegInv fr.Vector) error { - - if c.Commitment == constraint.COMMITTED { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. - return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time - } - - lro, err := cs.computeHints(c, solution) - if err != nil { - return err - } - if lro == -1 { - // no unsolved wire - // can happen if the constraint contained only hint wires. - return nil - } - if lro == 1 { // we solve for R: u1L+u2R+u3LR+u4O+k=0 => R(u2+u3L)+u1L+u4O+k = 0 - if !solution.solved[c.L.WireID()] { - panic("L wire should be instantiated when we solve R") - } - var u1, u2, u3, den, num, v1, v2 fr.Element - u3.Mul(&cs.Coefficients[c.M[0].CoeffID()], &cs.Coefficients[c.M[1].CoeffID()]) - u1.Set(&cs.Coefficients[c.L.CoeffID()]) - u2.Set(&cs.Coefficients[c.R.CoeffID()]) - den.Mul(&u3, &solution.values[c.L.WireID()]).Add(&den, &u2) - - v1 = solution.computeTerm(c.L) - v2 = solution.computeTerm(c.O) - num.Add(&v1, &v2).Add(&num, &cs.Coefficients[c.K]) - - // TODO find a way to do lazy div (/ batch inversion) - num.Div(&num, &den).Neg(&num) - solution.set(c.L.WireID(), num) - return nil - } - - if lro == 0 { // we solve for L: u1L+u2R+u3LR+u4O+k=0 => L(u1+u3R)+u2R+u4O+k = 0 - if !solution.solved[c.R.WireID()] { - panic("R wire should be instantiated when we solve L") - } - var u1, u2, u3, den, num, v1, v2 fr.Element - u3.Mul(&cs.Coefficients[c.M[0].CoeffID()], &cs.Coefficients[c.M[1].CoeffID()]) - u1.Set(&cs.Coefficients[c.L.CoeffID()]) - u2.Set(&cs.Coefficients[c.R.CoeffID()]) - den.Mul(&u3, &solution.values[c.R.WireID()]).Add(&den, &u1) - - v1 = solution.computeTerm(c.R) - v2 = solution.computeTerm(c.O) - num.Add(&v1, &v2).Add(&num, &cs.Coefficients[c.K]) - - // TODO find a way to do lazy div (/ batch inversion) - num.Div(&num, &den).Neg(&num) - solution.set(c.L.WireID(), num) - return nil - - } - // O we solve for O - var o fr.Element - cID, vID := c.O.CoeffID(), c.O.WireID() - - l := solution.computeTerm(c.L) - r := solution.computeTerm(c.R) - m0 := solution.computeTerm(c.M[0]) - m1 := solution.computeTerm(c.M[1]) - - // o = - ((m0 * m1) + l + r + c.K) / c.O - o.Mul(&m0, &m1).Add(&o, &l).Add(&o, &r).Add(&o, &cs.Coefficients[c.K]) - o.Mul(&o, &coefficientsNegInv[cID]) - - solution.set(vID, o) - - return nil -} - -// IsSolved -// Deprecated: use _, err := Solve(...) instead -func (cs *SparseR1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { - _, err := cs.Solve(witness, opts...) - return err -} - -// GetConstraints return the list of SparseR1C and a coefficient resolver -func (cs *SparseR1CS) GetConstraints() ([]constraint.SparseR1C, constraint.Resolver) { - return cs.Constraints, cs -} - -func (cs *SparseR1CS) GetConstraint(i int) *constraint.SparseR1C { - if i < 0 || i >= len(cs.Constraints) { - return nil - } - return &cs.Constraints[i] -} - -func (cs *SparseR1CS) GetCoefficient(i int) (r constraint.Coeff) { - copy(r[:], cs.Coefficients[i][:]) - return -} - -// checkConstraint verifies that the constraint holds -func (cs *SparseR1CS) checkConstraint(c constraint.SparseR1C, solution *solution) error { - - if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. - return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time - } - - l := solution.computeTerm(c.L) - r := solution.computeTerm(c.R) - m0 := solution.computeTerm(c.M[0]) - m1 := solution.computeTerm(c.M[1]) - o := solution.computeTerm(c.O) - - // l + r + (m0 * m1) + o + c.K == 0 - var t fr.Element - t.Mul(&m0, &m1).Add(&t, &l).Add(&t, &r).Add(&t, &o).Add(&t, &cs.Coefficients[c.K]) - if !t.IsZero() { - return fmt.Errorf("qL⋅xa + qR⋅xb + qO⋅xc + qM⋅(xaxb) + qC != 0 → %s + %s + %s + (%s × %s) + %s != 0", - l.String(), - r.String(), - o.String(), - m0.String(), - m1.String(), - cs.Coefficients[c.K].String(), - ) - } - return nil - -} - -// GetNbCoefficients return the number of unique coefficients needed in the R1CS -func (cs *SparseR1CS) GetNbCoefficients() int { - return len(cs.Coefficients) -} - -// CurveID returns curve ID as defined in gnark-crypto (ecc.BW6-633) -func (cs *SparseR1CS) CurveID() ecc.ID { - return ecc.BW6_633 -} - -// WriteTo encodes SparseR1CS into provided io.Writer using cbor -func (cs *SparseR1CS) WriteTo(w io.Writer) (int64, error) { - _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written - enc, err := cbor.CoreDetEncOptions().EncMode() - if err != nil { - return 0, err - } - encoder := enc.NewEncoder(&_w) - - // encode our object - err = encoder.Encode(cs) - return _w.N, err -} - -// ReadFrom attempts to decode SparseR1CS from io.Reader using cbor -func (cs *SparseR1CS) ReadFrom(r io.Reader) (int64, error) { - dm, err := cbor.DecOptions{ - MaxArrayElements: 134217728, - MaxMapPairs: 134217728, - }.DecMode() - if err != nil { - return 0, err - } - decoder := dm.NewDecoder(r) - - // initialize coeff table - cs.CoeffTable = newCoeffTable(0) - - if err := decoder.Decode(cs); err != nil { - return int64(decoder.NumBytesRead()), err - } - - if err := cs.CheckSerializationHeader(); err != nil { - return int64(decoder.NumBytesRead()), err - } - - return int64(decoder.NumBytesRead()), nil -} diff --git a/constraint/bw6-633/r1cs_test.go b/constraint/bw6-633/r1cs_test.go index 0e07d67a8a..954401f685 100644 --- a/constraint/bw6-633/r1cs_test.go +++ b/constraint/bw6-633/r1cs_test.go @@ -20,6 +20,7 @@ import ( "bytes" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/frontend/cs/scs" "github.com/consensys/gnark/internal/backend/circuits" "reflect" "testing" @@ -76,10 +77,11 @@ func TestSerialization(t *testing.T) { if diff := cmp.Diff(r1cs1, &reconstructed, cmpopts.IgnoreFields(cs.R1CS{}, "System.q", - "arithEngine", + "field", "CoeffTable.mCoeffs", "System.lbWireLevel", "System.lbHints", + "System.genericHint", "System.SymbolTable", "System.lbOutputs", "System.bitLen")); diff != "" { @@ -147,12 +149,6 @@ func (circuit *circuit) Define(api frontend.API) error { func BenchmarkSolve(b *testing.B) { - var c circuit - ccs, err := frontend.Compile(fr.Modulus(), r1cs.NewBuilder, &c) - if err != nil { - b.Fatal(err) - } - var w circuit w.X = 1 w.Y = 1 @@ -161,8 +157,32 @@ func BenchmarkSolve(b *testing.B) { b.Fatal(err) } - b.ResetTimer() - for i := 0; i < b.N; i++ { - _ = ccs.IsSolved(witness) - } + b.Run("scs", func(b *testing.B) { + var c circuit + ccs, err := frontend.Compile(fr.Modulus(), scs.NewBuilder, &c) + if err != nil { + b.Fatal(err) + } + b.Log("scs nbConstraints", ccs.GetNbConstraints()) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = ccs.IsSolved(witness) + } + }) + + b.Run("r1cs", func(b *testing.B) { + var c circuit + ccs, err := frontend.Compile(fr.Modulus(), r1cs.NewBuilder, &c, frontend.WithCompressThreshold(10)) + if err != nil { + b.Fatal(err) + } + b.Log("r1cs nbConstraints", ccs.GetNbConstraints()) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = ccs.IsSolved(witness) + } + }) + } diff --git a/constraint/bw6-633/solution.go b/constraint/bw6-633/solution.go deleted file mode 100644 index fb47c98e41..0000000000 --- a/constraint/bw6-633/solution.go +++ /dev/null @@ -1,383 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// 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. - -// Code generated by gnark DO NOT EDIT - -package cs - -import ( - "errors" - "fmt" - "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/debug" - "github.com/rs/zerolog" - "io" - "math/big" - "strconv" - "strings" - "sync/atomic" - - "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" -) - -// solution represents elements needed to compute -// a solution to a R1CS or SparseR1CS -type solution struct { - values, coefficients []fr.Element - solved []bool - nbSolved uint64 - mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function - st *debug.SymbolTable - cs *constraint.System -} - -func newSolution(cs *constraint.System, nbWires int, hintFunctions map[solver.HintID]solver.Hint, coefficients []fr.Element) (solution, error) { - - s := solution{ - cs: cs, - st: &cs.SymbolTable, - values: make([]fr.Element, nbWires), - coefficients: coefficients, - solved: make([]bool, nbWires), - mHintsFunctions: hintFunctions, - } - - // hintsDependencies is from compile time; it contains the list of hints the solver **needs** - var missing []string - for hintUUID, hintID := range cs.MHintsDependencies { - if _, ok := s.mHintsFunctions[hintUUID]; !ok { - missing = append(missing, hintID) - } - } - - if len(missing) > 0 { - return s, fmt.Errorf("solver missing hint(s): %v", missing) - } - - return s, nil -} - -func (s *solution) set(id int, value fr.Element) { - if s.solved[id] { - panic("solving the same wire twice should never happen.") - } - s.values[id] = value - s.solved[id] = true - atomic.AddUint64(&s.nbSolved, 1) - // s.nbSolved++ -} - -func (s *solution) isValid() bool { - return int(s.nbSolved) == len(s.values) -} - -// computeTerm computes coeff*variable -func (s *solution) computeTerm(t constraint.Term) fr.Element { - cID, vID := t.CoeffID(), t.WireID() - if cID != 0 && !s.solved[vID] { - panic("computing a term with an unsolved wire") - } - switch cID { - case constraint.CoeffIdZero: - return fr.Element{} - case constraint.CoeffIdOne: - return s.values[vID] - case constraint.CoeffIdTwo: - var res fr.Element - res.Double(&s.values[vID]) - return res - case constraint.CoeffIdMinusOne: - var res fr.Element - res.Neg(&s.values[vID]) - return res - default: - var res fr.Element - res.Mul(&s.coefficients[cID], &s.values[vID]) - return res - } -} - -// r += (t.coeff*t.value) -func (s *solution) accumulateInto(t constraint.Term, r *fr.Element) { - cID := t.CoeffID() - - if t.IsConstant() { - // needed for logs, we may want to not put this in the hot path if we need to - // optimize constraint system solver further. - r.Add(r, &s.coefficients[cID]) - return - } - - vID := t.WireID() - switch cID { - case constraint.CoeffIdZero: - return - case constraint.CoeffIdOne: - r.Add(r, &s.values[vID]) - case constraint.CoeffIdTwo: - var res fr.Element - res.Double(&s.values[vID]) - r.Add(r, &res) - case constraint.CoeffIdMinusOne: - r.Sub(r, &s.values[vID]) - default: - var res fr.Element - res.Mul(&s.coefficients[cID], &s.values[vID]) - r.Add(r, &res) - } -} - -// solveHint compute solution.values[vID] using provided solver hint -func (s *solution) solveWithHint(vID int, hID int) error { - // skip if the wire is already solved by a call to the same hint - // function on the same inputs - if s.solved[vID] { - return nil - } - - h := &s.cs.HintMappings[hID] - - // ensure hint function was provided - f, ok := s.mHintsFunctions[h.HintID] - if !ok { - return errors.New("missing hint function") - } - - // tmp IO big int memory - nbInputs := len(h.Inputs) - nbOutputs := len(h.Outputs) - inputs := make([]*big.Int, nbInputs) - outputs := make([]*big.Int, nbOutputs) - for i := 0; i < nbOutputs; i++ { - outputs[i] = big.NewInt(0) - } - - q := fr.Modulus() - - // for each input, we set its big int value, IF all the wires are solved - // the only case where all wires may not be solved, is if one of the input of this hint - // is the output of another hint. - // it is safe to recursively solve this with the parallel solver, since all hints-output wires - // that we can solve this way are marked to be solved with the current constraint we are processing. - recursiveSolve := func(t constraint.Term) error { - if t.IsConstant() { - return nil - } - wID := t.WireID() - if s.solved[wID] { - return nil - } - // unsolved dependency - if h, ok := s.cs.MHints[wID]; ok { - // solve recursively. - return s.solveWithHint(wID, h) - } - - // it's not a hint, we panic. - panic("solver can't compute hint; one or more input wires are unsolved") - } - - for i := 0; i < nbInputs; i++ { - inputs[i] = big.NewInt(0) - - var v fr.Element - for _, term := range h.Inputs[i] { - if err := recursiveSolve(term); err != nil { - return err - } - s.accumulateInto(term, &v) - } - v.BigInt(inputs[i]) - } - - err := f(q, inputs, outputs) - - var v fr.Element - for i := range outputs { - v.SetBigInt(outputs[i]) - s.set(h.Outputs[i], v) - } - - return err -} - -func (s *solution) printLogs(log zerolog.Logger, logs []constraint.LogEntry) { - if log.GetLevel() == zerolog.Disabled { - return - } - - for i := 0; i < len(logs); i++ { - logLine := s.logValue(logs[i]) - log.Debug().Str(zerolog.CallerFieldName, logs[i].Caller).Msg(logLine) - } -} - -const unsolvedVariable = "" - -func (s *solution) logValue(log constraint.LogEntry) string { - var toResolve []interface{} - var ( - eval fr.Element - missingValue bool - ) - for j := 0; j < len(log.ToResolve); j++ { - // before eval le - - missingValue = false - eval.SetZero() - - for _, t := range log.ToResolve[j] { - // for each term in the linear expression - - cID, vID := t.CoeffID(), t.WireID() - if t.IsConstant() { - // just add the constant - eval.Add(&eval, &s.coefficients[cID]) - continue - } - - if !s.solved[vID] { - missingValue = true - break // stop the loop we can't evaluate. - } - - tv := s.computeTerm(t) - eval.Add(&eval, &tv) - } - - // after - if missingValue { - toResolve = append(toResolve, unsolvedVariable) - } else { - // we have to append our accumulator - toResolve = append(toResolve, eval.String()) - } - - } - if len(log.Stack) > 0 { - var sbb strings.Builder - for _, lID := range log.Stack { - location := s.st.Locations[lID] - function := s.st.Functions[location.FunctionID] - - sbb.WriteString(function.Name) - sbb.WriteByte('\n') - sbb.WriteByte('\t') - sbb.WriteString(function.Filename) - sbb.WriteByte(':') - sbb.WriteString(strconv.Itoa(int(location.Line))) - sbb.WriteByte('\n') - } - toResolve = append(toResolve, sbb.String()) - } - return fmt.Sprintf(log.Format, toResolve...) -} - -// UnsatisfiedConstraintError wraps an error with useful metadata on the unsatisfied constraint -type UnsatisfiedConstraintError struct { - Err error - CID int // constraint ID - DebugInfo *string // optional debug info -} - -func (r *UnsatisfiedConstraintError) Error() string { - if r.DebugInfo != nil { - return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, *r.DebugInfo) - } - return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, r.Err.Error()) -} - -// R1CSSolution represent a valid assignment to all the variables in the constraint system. -// The vector W such that Aw o Bw - Cw = 0 -type R1CSSolution struct { - W fr.Vector - A, B, C fr.Vector -} - -func (t *R1CSSolution) WriteTo(w io.Writer) (int64, error) { - n, err := t.W.WriteTo(w) - if err != nil { - return n, err - } - a, err := t.A.WriteTo(w) - n += a - if err != nil { - return n, err - } - a, err = t.B.WriteTo(w) - n += a - if err != nil { - return n, err - } - a, err = t.C.WriteTo(w) - n += a - return n, err -} - -func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { - n, err := t.W.ReadFrom(r) - if err != nil { - return n, err - } - a, err := t.A.ReadFrom(r) - a += n - if err != nil { - return n, err - } - a, err = t.B.ReadFrom(r) - a += n - if err != nil { - return n, err - } - a, err = t.C.ReadFrom(r) - n += a - return n, err -} - -// SparseR1CSSolution represent a valid assignment to all the variables in the constraint system. -type SparseR1CSSolution struct { - L, R, O fr.Vector -} - -func (t *SparseR1CSSolution) WriteTo(w io.Writer) (int64, error) { - n, err := t.L.WriteTo(w) - if err != nil { - return n, err - } - a, err := t.R.WriteTo(w) - n += a - if err != nil { - return n, err - } - a, err = t.O.WriteTo(w) - n += a - return n, err - -} - -func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { - n, err := t.L.ReadFrom(r) - if err != nil { - return n, err - } - a, err := t.R.ReadFrom(r) - a += n - if err != nil { - return n, err - } - a, err = t.O.ReadFrom(r) - a += n - return n, err -} diff --git a/constraint/bw6-633/solver.go b/constraint/bw6-633/solver.go new file mode 100644 index 0000000000..67cb4d9d8e --- /dev/null +++ b/constraint/bw6-633/solver.go @@ -0,0 +1,614 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package cs + +import ( + "errors" + "fmt" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/field/pool" + "github.com/consensys/gnark/constraint" + csolver "github.com/consensys/gnark/constraint/solver" + "github.com/rs/zerolog" + "math" + "math/big" + "runtime" + "strconv" + "strings" + "sync" + "sync/atomic" + + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" +) + +// solver represent the state of the solver during a call to System.Solve(...) +type solver struct { + *system + + // values and solved are index by the wire (variable) id + values []fr.Element + solved []bool + nbSolved uint64 + + // maps hintID to hint function + mHintsFunctions map[csolver.HintID]csolver.Hint + + // used to out api.Println + logger zerolog.Logger + + a, b, c fr.Vector // R1CS solver will compute the a,b,c matrices + + q *big.Int +} + +func newSolver(cs *system, witness fr.Vector, opts ...csolver.Option) (*solver, error) { + // parse options + opt, err := csolver.NewConfig(opts...) + if err != nil { + return nil, err + } + + // check witness size + witnessOffset := 0 + if cs.Type == constraint.SystemR1CS { + witnessOffset++ + } + + nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables + expectedWitnessSize := len(cs.Public) - witnessOffset + len(cs.Secret) + + if len(witness) != expectedWitnessSize { + return nil, fmt.Errorf("invalid witness size, got %d, expected %d", len(witness), expectedWitnessSize) + } + + // check all hints are there + hintFunctions := opt.HintFunctions + + // hintsDependencies is from compile time; it contains the list of hints the solver **needs** + var missing []string + for hintUUID, hintID := range cs.MHintsDependencies { + if _, ok := hintFunctions[hintUUID]; !ok { + missing = append(missing, hintID) + } + } + + if len(missing) > 0 { + return nil, fmt.Errorf("solver missing hint(s): %v", missing) + } + + s := solver{ + system: cs, + values: make([]fr.Element, nbWires), + solved: make([]bool, nbWires), + mHintsFunctions: hintFunctions, + logger: opt.Logger, + q: cs.Field(), + } + + // set the witness indexes as solved + if witnessOffset == 1 { + s.solved[0] = true // ONE_WIRE + s.values[0].SetOne() + } + copy(s.values[witnessOffset:], witness) + for i := range witness { + s.solved[i+witnessOffset] = true + } + + // keep track of the number of wire instantiations we do, for a post solve sanity check + // to ensure we instantiated all wires + s.nbSolved += uint64(len(witness) + witnessOffset) + + if s.Type == constraint.SystemR1CS { + n := ecc.NextPowerOfTwo(uint64(cs.GetNbConstraints())) + s.a = make(fr.Vector, cs.GetNbConstraints(), n) + s.b = make(fr.Vector, cs.GetNbConstraints(), n) + s.c = make(fr.Vector, cs.GetNbConstraints(), n) + } + + return &s, nil +} + +func (s *solver) set(id int, value fr.Element) { + if s.solved[id] { + panic("solving the same wire twice should never happen.") + } + s.values[id] = value + s.solved[id] = true + atomic.AddUint64(&s.nbSolved, 1) +} + +// computeTerm computes coeff*variable +// TODO @gbotrel check if t is a Constant only +func (s *solver) computeTerm(t constraint.Term) fr.Element { + cID, vID := t.CoeffID(), t.WireID() + if cID != 0 && !s.solved[vID] { + panic("computing a term with an unsolved wire") + } + switch cID { + case constraint.CoeffIdZero: + return fr.Element{} + case constraint.CoeffIdOne: + return s.values[vID] + case constraint.CoeffIdTwo: + var res fr.Element + res.Double(&s.values[vID]) + return res + case constraint.CoeffIdMinusOne: + var res fr.Element + res.Neg(&s.values[vID]) + return res + default: + var res fr.Element + res.Mul(&s.Coefficients[cID], &s.values[vID]) + return res + } +} + +// r += (t.coeff*t.value) +// TODO @gbotrel check t.IsConstant on the caller side when necessary +func (s *solver) accumulateInto(t constraint.Term, r *fr.Element) { + cID := t.CoeffID() + vID := t.WireID() + + switch cID { + case constraint.CoeffIdZero: + return + case constraint.CoeffIdOne: + r.Add(r, &s.values[vID]) + case constraint.CoeffIdTwo: + var res fr.Element + res.Double(&s.values[vID]) + r.Add(r, &res) + case constraint.CoeffIdMinusOne: + r.Sub(r, &s.values[vID]) + default: + var res fr.Element + res.Mul(&s.Coefficients[cID], &s.values[vID]) + r.Add(r, &res) + } +} + +// solveWithHint executes a hint and assign the result to its defined outputs. +func (s *solver) solveWithHint(h *constraint.HintMapping) error { + // ensure hint function was provided + f, ok := s.mHintsFunctions[h.HintID] + if !ok { + return errors.New("missing hint function") + } + + // tmp IO big int memory + nbInputs := len(h.Inputs) + nbOutputs := int(h.OutputRange.End - h.OutputRange.Start) + inputs := make([]*big.Int, nbInputs) + outputs := make([]*big.Int, nbOutputs) + for i := 0; i < nbOutputs; i++ { + outputs[i] = pool.BigInt.Get() + outputs[i].SetUint64(0) + } + + q := pool.BigInt.Get() + q.Set(s.q) + + for i := 0; i < nbInputs; i++ { + var v fr.Element + for _, term := range h.Inputs[i] { + if term.IsConstant() { + v.Add(&v, &s.Coefficients[term.CoeffID()]) + continue + } + s.accumulateInto(term, &v) + } + inputs[i] = pool.BigInt.Get() + v.BigInt(inputs[i]) + } + + err := f(q, inputs, outputs) + + var v fr.Element + for i := range outputs { + v.SetBigInt(outputs[i]) + s.set(int(h.OutputRange.Start)+i, v) + pool.BigInt.Put(outputs[i]) + } + + for i := range inputs { + pool.BigInt.Put(inputs[i]) + } + + pool.BigInt.Put(q) + + return err +} + +func (s *solver) printLogs(logs []constraint.LogEntry) { + if s.logger.GetLevel() == zerolog.Disabled { + return + } + + for i := 0; i < len(logs); i++ { + logLine := s.logValue(logs[i]) + s.logger.Debug().Str(zerolog.CallerFieldName, logs[i].Caller).Msg(logLine) + } +} + +const unsolvedVariable = "" + +func (s *solver) logValue(log constraint.LogEntry) string { + var toResolve []interface{} + var ( + eval fr.Element + missingValue bool + ) + for j := 0; j < len(log.ToResolve); j++ { + // before eval le + + missingValue = false + eval.SetZero() + + for _, t := range log.ToResolve[j] { + // for each term in the linear expression + + cID, vID := t.CoeffID(), t.WireID() + if t.IsConstant() { + // just add the constant + eval.Add(&eval, &s.Coefficients[cID]) + continue + } + + if !s.solved[vID] { + missingValue = true + break // stop the loop we can't evaluate. + } + + tv := s.computeTerm(t) + eval.Add(&eval, &tv) + } + + // after + if missingValue { + toResolve = append(toResolve, unsolvedVariable) + } else { + // we have to append our accumulator + toResolve = append(toResolve, eval.String()) + } + + } + if len(log.Stack) > 0 { + var sbb strings.Builder + for _, lID := range log.Stack { + location := s.SymbolTable.Locations[lID] + function := s.SymbolTable.Functions[location.FunctionID] + + sbb.WriteString(function.Name) + sbb.WriteByte('\n') + sbb.WriteByte('\t') + sbb.WriteString(function.Filename) + sbb.WriteByte(':') + sbb.WriteString(strconv.Itoa(int(location.Line))) + sbb.WriteByte('\n') + } + toResolve = append(toResolve, sbb.String()) + } + return fmt.Sprintf(log.Format, toResolve...) +} + +// divByCoeff sets res = res / t.Coeff +func (solver *solver) divByCoeff(res *fr.Element, cID uint32) { + switch cID { + case constraint.CoeffIdOne: + return + case constraint.CoeffIdMinusOne: + res.Neg(res) + case constraint.CoeffIdZero: + panic("division by 0") + default: + // this is slow, but shouldn't happen as divByCoeff is called to + // remove the coeff of an unsolved wire + // but unsolved wires are (in gnark frontend) systematically set with a coeff == 1 or -1 + res.Div(res, &solver.Coefficients[cID]) + } +} + +// Implement constraint.Solver +func (s *solver) GetValue(cID, vID uint32) constraint.Element { + var r constraint.Element + e := s.computeTerm(constraint.Term{CID: cID, VID: vID}) + copy(r[:], e[:]) + return r +} +func (s *solver) GetCoeff(cID uint32) constraint.Element { + var r constraint.Element + copy(r[:], s.Coefficients[cID][:]) + return r +} +func (s *solver) SetValue(vID uint32, f constraint.Element) { + s.set(int(vID), *(*fr.Element)(f[:])) +} + +func (s *solver) IsSolved(vID uint32) bool { + return s.solved[vID] +} + +// processInstruction decodes the instruction and execute blueprint-defined logic. +// an instruction can encode a hint, a custom constraint or a generic constraint. +func (solver *solver) processInstruction(inst constraint.Instruction, scratch *scratch) error { + // fetch the blueprint + blueprint := solver.Blueprints[inst.BlueprintID] + calldata := solver.GetCallData(inst) + cID := inst.ConstraintOffset // here we have 1 constraint in the instruction only + + if solver.Type == constraint.SystemR1CS { + if bc, ok := blueprint.(constraint.BlueprintR1C); ok { + // TODO @gbotrel we use the solveR1C method for now, having user-defined + // blueprint for R1CS would require constraint.Solver interface to add methods + // to set a,b,c since it's more efficient to compute these while we solve. + bc.DecompressR1C(&scratch.tR1C, calldata) + return solver.solveR1C(cID, &scratch.tR1C) + } + } else if solver.Type == constraint.SystemSparseR1CS { + // blueprint declared "I know how to solve this." + if bc, ok := blueprint.(constraint.BlueprintSolvable); ok { + if err := bc.Solve(solver, calldata); err != nil { + return solver.wrapErrWithDebugInfo(cID, err) + } + return nil + } + } + + // blueprint encodes a hint, we execute. + // TODO @gbotrel may be worth it to move hint logic in blueprint "solve" + if bc, ok := blueprint.(constraint.BlueprintHint); ok { + bc.DecompressHint(&scratch.tHint, calldata) + return solver.solveWithHint(&scratch.tHint) + } + + return nil +} + +// run runs the solver. it return an error if a constraint is not satisfied or if not all wires +// were instantiated. +func (solver *solver) run() error { + // minWorkPerCPU is the minimum target number of constraint a task should hold + // in other words, if a level has less than minWorkPerCPU, it will not be parallelized and executed + // sequentially without sync. + const minWorkPerCPU = 50.0 // TODO @gbotrel revisit that with blocks. + + // cs.Levels has a list of levels, where all constraints in a level l(n) are independent + // and may only have dependencies on previous levels + // for each constraint + // we are guaranteed that each R1C contains at most one unsolved wire + // first we solve the unsolved wire (if any) + // then we check that the constraint is valid + // if a[i] * b[i] != c[i]; it means the constraint is not satisfied + var wg sync.WaitGroup + chTasks := make(chan []int, runtime.NumCPU()) + chError := make(chan error, runtime.NumCPU()) + + // start a worker pool + // each worker wait on chTasks + // a task is a slice of constraint indexes to be solved + for i := 0; i < runtime.NumCPU(); i++ { + go func() { + var scratch scratch + for t := range chTasks { + for _, i := range t { + if err := solver.processInstruction(solver.Instructions[i], &scratch); err != nil { + chError <- err + wg.Done() + return + } + } + wg.Done() + } + }() + } + + // clean up pool go routines + defer func() { + close(chTasks) + close(chError) + }() + + var scratch scratch + + // for each level, we push the tasks + for _, level := range solver.Levels { + + // max CPU to use + maxCPU := float64(len(level)) / minWorkPerCPU + + if maxCPU <= 1.0 { + // we do it sequentially + for _, i := range level { + if err := solver.processInstruction(solver.Instructions[i], &scratch); err != nil { + return err + } + } + continue + } + + // number of tasks for this level is set to number of CPU + // but if we don't have enough work for all our CPU, it can be lower. + nbTasks := runtime.NumCPU() + maxTasks := int(math.Ceil(maxCPU)) + if nbTasks > maxTasks { + nbTasks = maxTasks + } + nbIterationsPerCpus := len(level) / nbTasks + + // more CPUs than tasks: a CPU will work on exactly one iteration + // note: this depends on minWorkPerCPU constant + if nbIterationsPerCpus < 1 { + nbIterationsPerCpus = 1 + nbTasks = len(level) + } + + extraTasks := len(level) - (nbTasks * nbIterationsPerCpus) + extraTasksOffset := 0 + + for i := 0; i < nbTasks; i++ { + wg.Add(1) + _start := i*nbIterationsPerCpus + extraTasksOffset + _end := _start + nbIterationsPerCpus + if extraTasks > 0 { + _end++ + extraTasks-- + extraTasksOffset++ + } + // since we're never pushing more than num CPU tasks + // we will never be blocked here + chTasks <- level[_start:_end] + } + + // wait for the level to be done + wg.Wait() + + if len(chError) > 0 { + return <-chError + } + } + + if int(solver.nbSolved) != len(solver.values) { + return errors.New("solver didn't assign a value to all wires") + } + + return nil +} + +// solveR1C compute unsolved wires in the constraint, if any and set the solver accordingly +// +// returns an error if the solver called a hint function that errored +// returns false, nil if there was no wire to solve +// returns true, nil if exactly one wire was solved. In that case, it is redundant to check that +// the constraint is satisfied later. +func (solver *solver) solveR1C(cID uint32, r *constraint.R1C) error { + a, b, c := &solver.a[cID], &solver.b[cID], &solver.c[cID] + + // the index of the non-zero entry shows if L, R or O has an uninstantiated wire + // the content is the ID of the wire non instantiated + var loc uint8 + + var termToCompute constraint.Term + + processLExp := func(l constraint.LinearExpression, val *fr.Element, locValue uint8) { + for _, t := range l { + vID := t.WireID() + + // wire is already computed, we just accumulate in val + if solver.solved[vID] { + solver.accumulateInto(t, val) + continue + } + + if loc != 0 { + panic("found more than one wire to instantiate") + } + termToCompute = t + loc = locValue + } + } + + processLExp(r.L, a, 1) + processLExp(r.R, b, 2) + processLExp(r.O, c, 3) + + if loc == 0 { + // there is nothing to solve, may happen if we have an assertion + // (ie a constraints that doesn't yield any output) + // or if we solved the unsolved wires with hint functions + var check fr.Element + if !check.Mul(a, b).Equal(c) { + return solver.wrapErrWithDebugInfo(cID, fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String())) + } + return nil + } + + // we compute the wire value and instantiate it + wID := termToCompute.WireID() + + // solver result + var wire fr.Element + + switch loc { + case 1: + if !b.IsZero() { + wire.Div(c, b). + Sub(&wire, a) + a.Add(a, &wire) + } else { + // we didn't actually ensure that a * b == c + var check fr.Element + if !check.Mul(a, b).Equal(c) { + return solver.wrapErrWithDebugInfo(cID, fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String())) + } + } + case 2: + if !a.IsZero() { + wire.Div(c, a). + Sub(&wire, b) + b.Add(b, &wire) + } else { + var check fr.Element + if !check.Mul(a, b).Equal(c) { + return solver.wrapErrWithDebugInfo(cID, fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String())) + } + } + case 3: + wire.Mul(a, b). + Sub(&wire, c) + + c.Add(c, &wire) + } + + // wire is the term (coeff * value) + // but in the solver we want to store the value only + // note that in gnark frontend, coeff here is always 1 or -1 + solver.divByCoeff(&wire, termToCompute.CID) + solver.set(wID, wire) + + return nil +} + +// UnsatisfiedConstraintError wraps an error with useful metadata on the unsatisfied constraint +type UnsatisfiedConstraintError struct { + Err error + CID int // constraint ID + DebugInfo *string // optional debug info +} + +func (r *UnsatisfiedConstraintError) Error() string { + if r.DebugInfo != nil { + return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, *r.DebugInfo) + } + return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, r.Err.Error()) +} + +func (solver *solver) wrapErrWithDebugInfo(cID uint32, err error) *UnsatisfiedConstraintError { + var debugInfo *string + if dID, ok := solver.MDebug[int(cID)]; ok { + debugInfo = new(string) + *debugInfo = solver.logValue(solver.DebugInfo[dID]) + } + return &UnsatisfiedConstraintError{CID: int(cID), Err: err, DebugInfo: debugInfo} +} + +// temporary variables to avoid memallocs in hotloop +type scratch struct { + tR1C constraint.R1C + tHint constraint.HintMapping +} diff --git a/constraint/bw6-633/system.go b/constraint/bw6-633/system.go new file mode 100644 index 0000000000..676776d638 --- /dev/null +++ b/constraint/bw6-633/system.go @@ -0,0 +1,365 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package cs + +import ( + "github.com/fxamacker/cbor/v2" + "io" + "time" + + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint" + csolver "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/internal/backend/ioutils" + "github.com/consensys/gnark/logger" + "reflect" + + "github.com/consensys/gnark-crypto/ecc" + + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" +) + +type R1CS = system +type SparseR1CS = system + +// system is a curved-typed constraint.System with a concrete coefficient table (fr.Element) +type system struct { + constraint.System + CoeffTable + field +} + +func NewR1CS(capacity int) *R1CS { + return newSystem(capacity, constraint.SystemR1CS) +} + +func NewSparseR1CS(capacity int) *SparseR1CS { + return newSystem(capacity, constraint.SystemSparseR1CS) +} + +func newSystem(capacity int, t constraint.SystemType) *system { + return &system{ + System: constraint.NewSystem(fr.Modulus(), capacity, t), + CoeffTable: newCoeffTable(capacity / 10), + } +} + +// Solve solves the constraint system with provided witness. +// If it's a R1CS returns R1CSSolution +// If it's a SparseR1CS returns SparseR1CSSolution +func (cs *system) Solve(witness witness.Witness, opts ...csolver.Option) (any, error) { + log := logger.Logger().With().Int("nbConstraints", cs.GetNbConstraints()).Logger() + start := time.Now() + + v := witness.Vector().(fr.Vector) + + // init the solver + solver, err := newSolver(cs, v, opts...) + if err != nil { + log.Err(err).Send() + return nil, err + } + + // defer log printing once all solver.values are computed + // (or sooner, if a constraint is not satisfied) + defer solver.printLogs(cs.Logs) + + // run it. + if err := solver.run(); err != nil { + log.Err(err).Send() + return nil, err + } + + log.Debug().Dur("took", time.Since(start)).Msg("constraint system solver done") + + // format the solution + // TODO @gbotrel revisit post-refactor + if cs.Type == constraint.SystemR1CS { + var res R1CSSolution + res.W = solver.values + res.A = solver.a + res.B = solver.b + res.C = solver.c + return &res, nil + } else { + // sparse R1CS + var res SparseR1CSSolution + // query l, r, o in Lagrange basis, not blinded + res.L, res.R, res.O = evaluateLROSmallDomain(cs, solver.values) + + return &res, nil + } + +} + +// IsSolved +// Deprecated: use _, err := Solve(...) instead +func (cs *system) IsSolved(witness witness.Witness, opts ...csolver.Option) error { + _, err := cs.Solve(witness, opts...) + return err +} + +// GetR1Cs return the list of R1C +func (cs *system) GetR1Cs() []constraint.R1C { + toReturn := make([]constraint.R1C, 0, cs.GetNbConstraints()) + + for _, inst := range cs.Instructions { + blueprint := cs.Blueprints[inst.BlueprintID] + if bc, ok := blueprint.(constraint.BlueprintR1C); ok { + var r1c constraint.R1C + bc.DecompressR1C(&r1c, cs.GetCallData(inst)) + toReturn = append(toReturn, r1c) + } else { + panic("not implemented") + } + } + return toReturn +} + +// GetNbCoefficients return the number of unique coefficients needed in the R1CS +func (cs *system) GetNbCoefficients() int { + return len(cs.Coefficients) +} + +// CurveID returns curve ID as defined in gnark-crypto +func (cs *system) CurveID() ecc.ID { + return ecc.BW6_633 +} + +// WriteTo encodes R1CS into provided io.Writer using cbor +func (cs *system) WriteTo(w io.Writer) (int64, error) { + _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written + ts := getTagSet() + enc, err := cbor.CoreDetEncOptions().EncModeWithTags(ts) + if err != nil { + return 0, err + } + encoder := enc.NewEncoder(&_w) + + // encode our object + err = encoder.Encode(cs) + return _w.N, err +} + +// ReadFrom attempts to decode R1CS from io.Reader using cbor +func (cs *system) ReadFrom(r io.Reader) (int64, error) { + ts := getTagSet() + dm, err := cbor.DecOptions{ + MaxArrayElements: 134217728, + MaxMapPairs: 134217728, + }.DecModeWithTags(ts) + + if err != nil { + return 0, err + } + decoder := dm.NewDecoder(r) + + // initialize coeff table + cs.CoeffTable = newCoeffTable(0) + + if err := decoder.Decode(&cs); err != nil { + return int64(decoder.NumBytesRead()), err + } + + if err := cs.CheckSerializationHeader(); err != nil { + return int64(decoder.NumBytesRead()), err + } + + return int64(decoder.NumBytesRead()), nil +} + +func (cs *system) GetCoefficient(i int) (r constraint.Element) { + copy(r[:], cs.Coefficients[i][:]) + return +} + +// GetSparseR1Cs return the list of SparseR1C +func (cs *system) GetSparseR1Cs() []constraint.SparseR1C { + + toReturn := make([]constraint.SparseR1C, 0, cs.GetNbConstraints()) + + for _, inst := range cs.Instructions { + blueprint := cs.Blueprints[inst.BlueprintID] + if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { + var sparseR1C constraint.SparseR1C + calldata := cs.CallData[inst.StartCallData : inst.StartCallData+uint64(blueprint.NbInputs())] + bc.DecompressSparseR1C(&sparseR1C, calldata) + toReturn = append(toReturn, sparseR1C) + } else { + panic("not implemented") + } + } + return toReturn +} + +// evaluateLROSmallDomain extracts the solver l, r, o, and returns it in lagrange form. +// solver = [ public | secret | internal ] +// TODO @gbotrel refactor; this seems to be a small util function for plonk +func evaluateLROSmallDomain(cs *system, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { + + //s := int(pk.Domain[0].Cardinality) + s := cs.GetNbConstraints() + len(cs.Public) // len(spr.Public) is for the placeholder constraints + s = int(ecc.NextPowerOfTwo(uint64(s))) + + var l, r, o []fr.Element + l = make([]fr.Element, s) + r = make([]fr.Element, s) + o = make([]fr.Element, s) + s0 := solution[0] + + for i := 0; i < len(cs.Public); i++ { // placeholders + l[i] = solution[i] + r[i] = s0 + o[i] = s0 + } + offset := len(cs.Public) + nbConstraints := cs.GetNbConstraints() + + var sparseR1C constraint.SparseR1C + j := 0 + for _, inst := range cs.Instructions { + blueprint := cs.Blueprints[inst.BlueprintID] + if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { + bc.DecompressSparseR1C(&sparseR1C, cs.GetCallData(inst)) + + l[offset+j] = solution[sparseR1C.XA] + r[offset+j] = solution[sparseR1C.XB] + o[offset+j] = solution[sparseR1C.XC] + j++ + } + } + + offset += nbConstraints + + for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solver[0]) + l[offset+i] = s0 + r[offset+i] = s0 + o[offset+i] = s0 + } + + return l, r, o + +} + +// R1CSSolution represent a valid assignment to all the variables in the constraint system. +// The vector W such that Aw o Bw - Cw = 0 +type R1CSSolution struct { + W fr.Vector + A, B, C fr.Vector +} + +func (t *R1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.W.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.A.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.B.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.C.WriteTo(w) + n += a + return n, err +} + +func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.W.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.A.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.B.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.C.ReadFrom(r) + n += a + return n, err +} + +// SparseR1CSSolution represent a valid assignment to all the variables in the constraint system. +type SparseR1CSSolution struct { + L, R, O fr.Vector +} + +func (t *SparseR1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.L.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.R.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.O.WriteTo(w) + n += a + return n, err + +} + +func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.L.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.R.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.O.ReadFrom(r) + a += n + return n, err +} + +func getTagSet() cbor.TagSet { + // temporary for refactor + ts := cbor.NewTagSet() + // https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml + // 65536-15309735 Unassigned + tagNum := uint64(5309735) + addType := func(t reflect.Type) { + if err := ts.Add( + cbor.TagOptions{EncTag: cbor.EncTagRequired, DecTag: cbor.DecTagRequired}, + t, + tagNum, + ); err != nil { + panic(err) + } + tagNum++ + } + + addType(reflect.TypeOf(constraint.BlueprintGenericHint{})) + addType(reflect.TypeOf(constraint.BlueprintGenericR1C{})) + addType(reflect.TypeOf(constraint.BlueprintGenericSparseR1C{})) + addType(reflect.TypeOf(constraint.BlueprintSparseR1CAdd{})) + addType(reflect.TypeOf(constraint.BlueprintSparseR1CMul{})) + + return ts +} diff --git a/constraint/bw6-761/coeff.go b/constraint/bw6-761/coeff.go index e63c24f7ca..0206740d31 100644 --- a/constraint/bw6-761/coeff.go +++ b/constraint/bw6-761/coeff.go @@ -46,7 +46,7 @@ func newCoeffTable(capacity int) CoeffTable { } -func (ct *CoeffTable) MakeTerm(coeff *constraint.Coeff, variableID int) constraint.Term { +func (ct *CoeffTable) AddCoeff(coeff constraint.Element) uint32 { c := (*fr.Element)(coeff[:]) var cID uint32 if c.IsZero() { @@ -69,7 +69,11 @@ func (ct *CoeffTable) MakeTerm(coeff *constraint.Coeff, variableID int) constrai ct.mCoeffs[cc] = cID } } + return cID +} +func (ct *CoeffTable) MakeTerm(coeff *constraint.Element, variableID int) constraint.Term { + cID := ct.AddCoeff(*coeff) return constraint.Term{VID: uint32(variableID), CID: cID} } @@ -78,7 +82,10 @@ func (ct *CoeffTable) CoeffToString(cID int) string { return ct.Coefficients[cID].String() } -var _ constraint.CoeffEngine = &arithEngine{} +// implements constraint.Field +type field struct{} + +var _ constraint.Field = &field{} var ( two fr.Element @@ -94,10 +101,7 @@ func init() { minusTwo.Neg(&two) } -// implements constraint.CoeffEngine -type arithEngine struct{} - -func (engine *arithEngine) FromInterface(i interface{}) constraint.Coeff { +func (engine *field) FromInterface(i interface{}) constraint.Element { var e fr.Element if _, err := e.SetInterface(i); err != nil { // need to clean that --> some code path are dissimilar @@ -106,55 +110,75 @@ func (engine *arithEngine) FromInterface(i interface{}) constraint.Coeff { b := utils.FromInterface(i) e.SetBigInt(&b) } - var r constraint.Coeff + var r constraint.Element copy(r[:], e[:]) return r } -func (engine *arithEngine) ToBigInt(c *constraint.Coeff) *big.Int { +func (engine *field) ToBigInt(c constraint.Element) *big.Int { e := (*fr.Element)(c[:]) r := new(big.Int) e.BigInt(r) return r } -func (engine *arithEngine) Mul(a, b *constraint.Coeff) { +func (engine *field) Mul(a, b constraint.Element) constraint.Element { _a := (*fr.Element)(a[:]) _b := (*fr.Element)(b[:]) _a.Mul(_a, _b) + return a } -func (engine *arithEngine) Add(a, b *constraint.Coeff) { + +func (engine *field) Add(a, b constraint.Element) constraint.Element { _a := (*fr.Element)(a[:]) _b := (*fr.Element)(b[:]) _a.Add(_a, _b) + return a } -func (engine *arithEngine) Sub(a, b *constraint.Coeff) { +func (engine *field) Sub(a, b constraint.Element) constraint.Element { _a := (*fr.Element)(a[:]) _b := (*fr.Element)(b[:]) _a.Sub(_a, _b) + return a } -func (engine *arithEngine) Neg(a *constraint.Coeff) { +func (engine *field) Neg(a constraint.Element) constraint.Element { e := (*fr.Element)(a[:]) e.Neg(e) + return a } -func (engine *arithEngine) Inverse(a *constraint.Coeff) { +func (engine *field) Inverse(a constraint.Element) (constraint.Element, bool) { + if a.IsZero() { + return a, false + } e := (*fr.Element)(a[:]) + if e.IsZero() { + return a, false + } else if e.IsOne() { + return a, true + } + var t fr.Element + t.Neg(e) + if t.IsOne() { + return a, true + } + e.Inverse(e) + return a, true } -func (engine *arithEngine) IsOne(a *constraint.Coeff) bool { +func (engine *field) IsOne(a constraint.Element) bool { e := (*fr.Element)(a[:]) return e.IsOne() } -func (engine *arithEngine) One() constraint.Coeff { +func (engine *field) One() constraint.Element { e := fr.One() - var r constraint.Coeff + var r constraint.Element copy(r[:], e[:]) return r } -func (engine *arithEngine) String(a *constraint.Coeff) string { +func (engine *field) String(a constraint.Element) string { e := (*fr.Element)(a[:]) return e.String() } diff --git a/constraint/bw6-761/r1cs.go b/constraint/bw6-761/r1cs.go deleted file mode 100644 index eaa080c67b..0000000000 --- a/constraint/bw6-761/r1cs.go +++ /dev/null @@ -1,467 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// 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. - -// Code generated by gnark DO NOT EDIT - -package cs - -import ( - "errors" - "fmt" - "github.com/fxamacker/cbor/v2" - "io" - "runtime" - "sync" - "time" - - "github.com/consensys/gnark/backend/witness" - "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/internal/backend/ioutils" - "github.com/consensys/gnark/logger" - "github.com/consensys/gnark/profile" - - "github.com/consensys/gnark-crypto/ecc" - "math" - - "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" -) - -// R1CS describes a set of R1CS constraint -type R1CS struct { - constraint.R1CSCore - CoeffTable - arithEngine -} - -// NewR1CS returns a new R1CS and sets cs.Coefficient (fr.Element) from provided big.Int values -// -// capacity pre-allocates memory for capacity nbConstraints -func NewR1CS(capacity int) *R1CS { - r := R1CS{ - R1CSCore: constraint.R1CSCore{ - System: constraint.NewSystem(fr.Modulus()), - Constraints: make([]constraint.R1C, 0, capacity), - }, - CoeffTable: newCoeffTable(capacity / 10), - } - return &r -} - -func (cs *R1CS) AddConstraint(r1c constraint.R1C, debugInfo ...constraint.DebugInfo) int { - profile.RecordConstraint() - cs.Constraints = append(cs.Constraints, r1c) - cID := len(cs.Constraints) - 1 - if len(debugInfo) == 1 { - cs.DebugInfo = append(cs.DebugInfo, constraint.LogEntry(debugInfo[0])) - cs.MDebug[cID] = len(cs.DebugInfo) - 1 - } - - cs.UpdateLevel(cID, &r1c) - - return cID -} - -// Solve returns the vector w solution to the system, that is -// Aw o Bw - Cw = 0 -func (cs *R1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { - opt, err := solver.NewConfig(opts...) - if err != nil { - return nil, err - } - - var res R1CSSolution - - s := ecc.NextPowerOfTwo(uint64(len(cs.Constraints))) - res.A = make(fr.Vector, len(cs.Constraints), s) - res.B = make(fr.Vector, len(cs.Constraints), s) - res.C = make(fr.Vector, len(cs.Constraints), s) - - v := witness.Vector().(fr.Vector) - - res.W, err = cs.solve(v, res.A, res.B, res.C, opt) - if err != nil { - return nil, err - } - - return &res, nil -} - -// Solve sets all the wires and returns the a, b, c vectors. -// the cs system should have been compiled before. The entries in a, b, c are in Montgomery form. -// a, b, c vectors: ab-c = hz -// witness = [publicWires | secretWires] (without the ONE_WIRE !) -// returns [publicWires | secretWires | internalWires ] -func (cs *R1CS) solve(witness, a, b, c fr.Vector, opt solver.Config) (fr.Vector, error) { - log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() - - nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - solution, err := newSolution(&cs.System, nbWires, opt.HintFunctions, cs.Coefficients) - if err != nil { - return make(fr.Vector, nbWires), err - } - start := time.Now() - - if len(witness) != len(cs.Public)-1+len(cs.Secret) { // - 1 for ONE_WIRE - err = fmt.Errorf("invalid witness size, got %d, expected %d = %d (public) + %d (secret)", len(witness), int(len(cs.Public)-1+len(cs.Secret)), len(cs.Public)-1, len(cs.Secret)) - log.Err(err).Send() - return solution.values, err - } - - // compute the wires and the a, b, c polynomials - if len(a) != len(cs.Constraints) || len(b) != len(cs.Constraints) || len(c) != len(cs.Constraints) { - err = errors.New("invalid input size: len(a, b, c) == len(Constraints)") - log.Err(err).Send() - return solution.values, err - } - - solution.solved[0] = true // ONE_WIRE - solution.values[0].SetOne() - copy(solution.values[1:], witness) - for i := range witness { - solution.solved[i+1] = true - } - - // keep track of the number of wire instantiations we do, for a sanity check to ensure - // we instantiated all wires - solution.nbSolved += uint64(len(witness) + 1) - - // now that we know all inputs are set, defer log printing once all solution.values are computed - // (or sooner, if a constraint is not satisfied) - defer solution.printLogs(opt.Logger, cs.Logs) - - if err := cs.parallelSolve(a, b, c, &solution); err != nil { - if unsatisfiedErr, ok := err.(*UnsatisfiedConstraintError); ok { - log.Err(errors.New("unsatisfied constraint")).Int("id", unsatisfiedErr.CID).Send() - } else { - log.Err(err).Send() - } - return solution.values, err - } - - // sanity check; ensure all wires are marked as "instantiated" - if !solution.isValid() { - log.Err(errors.New("solver didn't instantiate all wires")).Send() - panic("solver didn't instantiate all wires") - } - - log.Debug().Dur("took", time.Since(start)).Msg("constraint system solver done") - - return solution.values, nil -} - -func (cs *R1CS) parallelSolve(a, b, c fr.Vector, solution *solution) error { - // minWorkPerCPU is the minimum target number of constraint a task should hold - // in other words, if a level has less than minWorkPerCPU, it will not be parallelized and executed - // sequentially without sync. - const minWorkPerCPU = 50.0 - - // cs.Levels has a list of levels, where all constraints in a level l(n) are independent - // and may only have dependencies on previous levels - // for each constraint - // we are guaranteed that each R1C contains at most one unsolved wire - // first we solve the unsolved wire (if any) - // then we check that the constraint is valid - // if a[i] * b[i] != c[i]; it means the constraint is not satisfied - - var wg sync.WaitGroup - chTasks := make(chan []int, runtime.NumCPU()) - chError := make(chan *UnsatisfiedConstraintError, runtime.NumCPU()) - - // start a worker pool - // each worker wait on chTasks - // a task is a slice of constraint indexes to be solved - for i := 0; i < runtime.NumCPU(); i++ { - go func() { - for t := range chTasks { - for _, i := range t { - // for each constraint in the task, solve it. - if err := cs.solveConstraint(cs.Constraints[i], solution, &a[i], &b[i], &c[i]); err != nil { - var debugInfo *string - if dID, ok := cs.MDebug[i]; ok { - debugInfo = new(string) - *debugInfo = solution.logValue(cs.DebugInfo[dID]) - } - chError <- &UnsatisfiedConstraintError{CID: i, Err: err, DebugInfo: debugInfo} - wg.Done() - return - } - } - wg.Done() - } - }() - } - - // clean up pool go routines - defer func() { - close(chTasks) - close(chError) - }() - - // for each level, we push the tasks - for _, level := range cs.Levels { - - // max CPU to use - maxCPU := float64(len(level)) / minWorkPerCPU - - if maxCPU <= 1.0 { - // we do it sequentially - for _, i := range level { - if err := cs.solveConstraint(cs.Constraints[i], solution, &a[i], &b[i], &c[i]); err != nil { - var debugInfo *string - if dID, ok := cs.MDebug[i]; ok { - debugInfo = new(string) - *debugInfo = solution.logValue(cs.DebugInfo[dID]) - } - return &UnsatisfiedConstraintError{CID: i, Err: err, DebugInfo: debugInfo} - } - } - continue - } - - // number of tasks for this level is set to number of CPU - // but if we don't have enough work for all our CPU, it can be lower. - nbTasks := runtime.NumCPU() - maxTasks := int(math.Ceil(maxCPU)) - if nbTasks > maxTasks { - nbTasks = maxTasks - } - nbIterationsPerCpus := len(level) / nbTasks - - // more CPUs than tasks: a CPU will work on exactly one iteration - // note: this depends on minWorkPerCPU constant - if nbIterationsPerCpus < 1 { - nbIterationsPerCpus = 1 - nbTasks = len(level) - } - - extraTasks := len(level) - (nbTasks * nbIterationsPerCpus) - extraTasksOffset := 0 - - for i := 0; i < nbTasks; i++ { - wg.Add(1) - _start := i*nbIterationsPerCpus + extraTasksOffset - _end := _start + nbIterationsPerCpus - if extraTasks > 0 { - _end++ - extraTasks-- - extraTasksOffset++ - } - // since we're never pushing more than num CPU tasks - // we will never be blocked here - chTasks <- level[_start:_end] - } - - // wait for the level to be done - wg.Wait() - - if len(chError) > 0 { - return <-chError - } - } - - return nil -} - -// IsSolved -// Deprecated: use _, err := Solve(...) instead -func (cs *R1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { - _, err := cs.Solve(witness, opts...) - return err -} - -// divByCoeff sets res = res / t.Coeff -func (cs *R1CS) divByCoeff(res *fr.Element, t constraint.Term) { - cID := t.CoeffID() - switch cID { - case constraint.CoeffIdOne: - return - case constraint.CoeffIdMinusOne: - res.Neg(res) - case constraint.CoeffIdZero: - panic("division by 0") - default: - // this is slow, but shouldn't happen as divByCoeff is called to - // remove the coeff of an unsolved wire - // but unsolved wires are (in gnark frontend) systematically set with a coeff == 1 or -1 - res.Div(res, &cs.Coefficients[cID]) - } -} - -// solveConstraint compute unsolved wires in the constraint, if any and set the solution accordingly -// -// returns an error if the solver called a hint function that errored -// returns false, nil if there was no wire to solve -// returns true, nil if exactly one wire was solved. In that case, it is redundant to check that -// the constraint is satisfied later. -func (cs *R1CS) solveConstraint(r constraint.R1C, solution *solution, a, b, c *fr.Element) error { - - // the index of the non-zero entry shows if L, R or O has an uninstantiated wire - // the content is the ID of the wire non instantiated - var loc uint8 - - var termToCompute constraint.Term - - processLExp := func(l constraint.LinearExpression, val *fr.Element, locValue uint8) error { - for _, t := range l { - vID := t.WireID() - - // wire is already computed, we just accumulate in val - if solution.solved[vID] { - solution.accumulateInto(t, val) - continue - } - - // first we check if this is a hint wire - if hint, ok := cs.MHints[vID]; ok { - if err := solution.solveWithHint(vID, hint); err != nil { - return err - } - // now that the wire is saved, accumulate it into a, b or c - solution.accumulateInto(t, val) - continue - } - - if loc != 0 { - panic("found more than one wire to instantiate") - } - termToCompute = t - loc = locValue - } - return nil - } - - if err := processLExp(r.L, a, 1); err != nil { - return err - } - - if err := processLExp(r.R, b, 2); err != nil { - return err - } - - if err := processLExp(r.O, c, 3); err != nil { - return err - } - - if loc == 0 { - // there is nothing to solve, may happen if we have an assertion - // (ie a constraints that doesn't yield any output) - // or if we solved the unsolved wires with hint functions - var check fr.Element - if !check.Mul(a, b).Equal(c) { - return fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String()) - } - return nil - } - - // we compute the wire value and instantiate it - wID := termToCompute.WireID() - - // solver result - var wire fr.Element - - switch loc { - case 1: - if !b.IsZero() { - wire.Div(c, b). - Sub(&wire, a) - a.Add(a, &wire) - } else { - // we didn't actually ensure that a * b == c - var check fr.Element - if !check.Mul(a, b).Equal(c) { - return fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String()) - } - } - case 2: - if !a.IsZero() { - wire.Div(c, a). - Sub(&wire, b) - b.Add(b, &wire) - } else { - var check fr.Element - if !check.Mul(a, b).Equal(c) { - return fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String()) - } - } - case 3: - wire.Mul(a, b). - Sub(&wire, c) - - c.Add(c, &wire) - } - - // wire is the term (coeff * value) - // but in the solution we want to store the value only - // note that in gnark frontend, coeff here is always 1 or -1 - cs.divByCoeff(&wire, termToCompute) - solution.set(wID, wire) - - return nil -} - -// GetConstraints return the list of R1C and a coefficient resolver -func (cs *R1CS) GetConstraints() ([]constraint.R1C, constraint.Resolver) { - return cs.Constraints, cs -} - -// GetNbCoefficients return the number of unique coefficients needed in the R1CS -func (cs *R1CS) GetNbCoefficients() int { - return len(cs.Coefficients) -} - -// CurveID returns curve ID as defined in gnark-crypto -func (cs *R1CS) CurveID() ecc.ID { - return ecc.BW6_761 -} - -// WriteTo encodes R1CS into provided io.Writer using cbor -func (cs *R1CS) WriteTo(w io.Writer) (int64, error) { - _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written - enc, err := cbor.CoreDetEncOptions().EncMode() - if err != nil { - return 0, err - } - encoder := enc.NewEncoder(&_w) - - // encode our object - err = encoder.Encode(cs) - return _w.N, err -} - -// ReadFrom attempts to decode R1CS from io.Reader using cbor -func (cs *R1CS) ReadFrom(r io.Reader) (int64, error) { - dm, err := cbor.DecOptions{ - MaxArrayElements: 134217728, - MaxMapPairs: 134217728, - }.DecMode() - - if err != nil { - return 0, err - } - decoder := dm.NewDecoder(r) - - // initialize coeff table - cs.CoeffTable = newCoeffTable(0) - - if err := decoder.Decode(&cs); err != nil { - return int64(decoder.NumBytesRead()), err - } - - if err := cs.CheckSerializationHeader(); err != nil { - return int64(decoder.NumBytesRead()), err - } - - return int64(decoder.NumBytesRead()), nil -} diff --git a/constraint/bw6-761/r1cs_sparse.go b/constraint/bw6-761/r1cs_sparse.go deleted file mode 100644 index a20aa0d35b..0000000000 --- a/constraint/bw6-761/r1cs_sparse.go +++ /dev/null @@ -1,533 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// 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. - -// Code generated by gnark DO NOT EDIT - -package cs - -import ( - "errors" - "fmt" - "github.com/consensys/gnark-crypto/ecc" - "github.com/fxamacker/cbor/v2" - "io" - "math" - "runtime" - "sync" - "time" - - "github.com/consensys/gnark/backend/witness" - "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/internal/backend/ioutils" - "github.com/consensys/gnark/logger" - "github.com/consensys/gnark/profile" - - "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" -) - -// SparseR1CS represents a Plonk like circuit -type SparseR1CS struct { - constraint.SparseR1CSCore - CoeffTable - arithEngine -} - -// NewSparseR1CS returns a new SparseR1CS and sets r1cs.Coefficient (fr.Element) from provided big.Int values -func NewSparseR1CS(capacity int) *SparseR1CS { - cs := SparseR1CS{ - SparseR1CSCore: constraint.SparseR1CSCore{ - System: constraint.NewSystem(fr.Modulus()), - Constraints: make([]constraint.SparseR1C, 0, capacity), - }, - CoeffTable: newCoeffTable(capacity / 10), - } - - return &cs -} - -func (cs *SparseR1CS) AddConstraint(c constraint.SparseR1C, debugInfo ...constraint.DebugInfo) int { - profile.RecordConstraint() - cs.Constraints = append(cs.Constraints, c) - cID := len(cs.Constraints) - 1 - if len(debugInfo) == 1 { - cs.DebugInfo = append(cs.DebugInfo, constraint.LogEntry(debugInfo[0])) - cs.MDebug[cID] = len(cs.DebugInfo) - 1 - } - cs.UpdateLevel(cID, &c) - - return cID -} - -func (c *SparseR1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { - opt, err := solver.NewConfig(opts...) - if err != nil { - return nil, err - } - - // compute the constraint system solution - var solution []fr.Element - if solution, err = c.solve(witness.Vector().(fr.Vector), opt); err != nil { - return nil, err - } - - var res SparseR1CSSolution - // query l, r, o in Lagrange basis, not blinded - res.L, res.R, res.O = c.evaluateLROSmallDomain(solution) - - return &res, nil -} - -// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. -// solution = [ public | secret | internal ] -func (c *SparseR1CS) evaluateLROSmallDomain(solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { - - //s := int(pk.Domain[0].Cardinality) - s := c.GetNbConstraints() + len(c.Public) // len(spr.Public) is for the placeholder constraints - s = int(ecc.NextPowerOfTwo(uint64(s))) - - var l, r, o []fr.Element - l = make([]fr.Element, s) - r = make([]fr.Element, s) - o = make([]fr.Element, s) - s0 := solution[0] - - for i := 0; i < len(c.Public); i++ { // placeholders - l[i] = solution[i] - r[i] = s0 - o[i] = s0 - } - offset := len(c.Public) - for i := 0; i < len(c.Constraints); i++ { // constraints - l[offset+i] = solution[c.Constraints[i].L.WireID()] - r[offset+i] = solution[c.Constraints[i].R.WireID()] - o[offset+i] = solution[c.Constraints[i].O.WireID()] - } - offset += len(c.Constraints) - - for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) - l[offset+i] = s0 - r[offset+i] = s0 - o[offset+i] = s0 - } - - return l, r, o - -} - -// Solve sets all the wires. -// solution.values = [publicInputs | secretInputs | internalVariables ] -// witness: contains the input variables -// it returns the full slice of wires -func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, error) { - log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "plonk").Logger() - - // set the slices holding the solution.values and monitoring which variables have been solved - nbVariables := cs.NbInternalVariables + len(cs.Secret) + len(cs.Public) - - start := time.Now() - - expectedWitnessSize := len(cs.Public) + len(cs.Secret) - if len(witness) != expectedWitnessSize { - return make(fr.Vector, nbVariables), fmt.Errorf( - "invalid witness size, got %d, expected %d = %d (public) + %d (secret)", - len(witness), - expectedWitnessSize, - len(cs.Public), - len(cs.Secret), - ) - } - - // keep track of wire that have a value - solution, err := newSolution(&cs.System, nbVariables, opt.HintFunctions, cs.Coefficients) - if err != nil { - return solution.values, err - } - - // solution.values = [publicInputs | secretInputs | internalVariables ] -> we fill publicInputs | secretInputs - copy(solution.values, witness) - for i := 0; i < len(witness); i++ { - solution.solved[i] = true - } - - // keep track of the number of wire instantiations we do, for a sanity check to ensure - // we instantiated all wires - solution.nbSolved += uint64(len(witness)) - - // defer log printing once all solution.values are computed - defer solution.printLogs(opt.Logger, cs.Logs) - - // batch invert the coefficients to avoid many divisions in the solver - coefficientsNegInv := fr.BatchInvert(cs.Coefficients) - for i := 0; i < len(coefficientsNegInv); i++ { - coefficientsNegInv[i].Neg(&coefficientsNegInv[i]) - } - - if err := cs.parallelSolve(&solution, coefficientsNegInv); err != nil { - if unsatisfiedErr, ok := err.(*UnsatisfiedConstraintError); ok { - log.Err(errors.New("unsatisfied constraint")).Int("id", unsatisfiedErr.CID).Send() - } else { - log.Err(err).Send() - } - return solution.values, err - } - - // sanity check; ensure all wires are marked as "instantiated" - if !solution.isValid() { - log.Err(errors.New("solver didn't instantiate all wires")).Send() - panic("solver didn't instantiate all wires") - } - - log.Debug().Dur("took", time.Since(start)).Msg("constraint system solver done") - - return solution.values, nil - -} - -func (cs *SparseR1CS) parallelSolve(solution *solution, coefficientsNegInv fr.Vector) error { - // minWorkPerCPU is the minimum target number of constraint a task should hold - // in other words, if a level has less than minWorkPerCPU, it will not be parallelized and executed - // sequentially without sync. - const minWorkPerCPU = 50.0 - - // cs.Levels has a list of levels, where all constraints in a level l(n) are independent - // and may only have dependencies on previous levels - - var wg sync.WaitGroup - chTasks := make(chan []int, runtime.NumCPU()) - chError := make(chan *UnsatisfiedConstraintError, runtime.NumCPU()) - - // start a worker pool - // each worker wait on chTasks - // a task is a slice of constraint indexes to be solved - for i := 0; i < runtime.NumCPU(); i++ { - go func() { - for t := range chTasks { - for _, i := range t { - // for each constraint in the task, solve it. - if err := cs.solveConstraint(cs.Constraints[i], solution, coefficientsNegInv); err != nil { - chError <- &UnsatisfiedConstraintError{CID: i, Err: err} - wg.Done() - return - } - if err := cs.checkConstraint(cs.Constraints[i], solution); err != nil { - if dID, ok := cs.MDebug[i]; ok { - errMsg := solution.logValue(cs.DebugInfo[dID]) - chError <- &UnsatisfiedConstraintError{CID: i, DebugInfo: &errMsg} - } else { - chError <- &UnsatisfiedConstraintError{CID: i, Err: err} - } - wg.Done() - return - } - } - wg.Done() - } - }() - } - - // clean up pool go routines - defer func() { - close(chTasks) - close(chError) - }() - - // for each level, we push the tasks - for _, level := range cs.Levels { - - // max CPU to use - maxCPU := float64(len(level)) / minWorkPerCPU - - if maxCPU <= 1.0 { - // we do it sequentially - for _, i := range level { - if err := cs.solveConstraint(cs.Constraints[i], solution, coefficientsNegInv); err != nil { - return &UnsatisfiedConstraintError{CID: i, Err: err} - } - if err := cs.checkConstraint(cs.Constraints[i], solution); err != nil { - if dID, ok := cs.MDebug[i]; ok { - errMsg := solution.logValue(cs.DebugInfo[dID]) - return &UnsatisfiedConstraintError{CID: i, DebugInfo: &errMsg} - } - return &UnsatisfiedConstraintError{CID: i, Err: err} - } - } - continue - } - - // number of tasks for this level is set to number of CPU - // but if we don't have enough work for all our CPU, it can be lower. - nbTasks := runtime.NumCPU() - maxTasks := int(math.Ceil(maxCPU)) - if nbTasks > maxTasks { - nbTasks = maxTasks - } - nbIterationsPerCpus := len(level) / nbTasks - - // more CPUs than tasks: a CPU will work on exactly one iteration - // note: this depends on minWorkPerCPU constant - if nbIterationsPerCpus < 1 { - nbIterationsPerCpus = 1 - nbTasks = len(level) - } - - extraTasks := len(level) - (nbTasks * nbIterationsPerCpus) - extraTasksOffset := 0 - - for i := 0; i < nbTasks; i++ { - wg.Add(1) - _start := i*nbIterationsPerCpus + extraTasksOffset - _end := _start + nbIterationsPerCpus - if extraTasks > 0 { - _end++ - extraTasks-- - extraTasksOffset++ - } - // since we're never pushing more than num CPU tasks - // we will never be blocked here - chTasks <- level[_start:_end] - } - - // wait for the level to be done - wg.Wait() - - if len(chError) > 0 { - return <-chError - } - } - - return nil -} - -// computeHints computes wires associated with a hint function, if any -// if there is no remaining wire to solve, returns -1 -// else returns the wire position (L -> 0, R -> 1, O -> 2) -func (cs *SparseR1CS) computeHints(c constraint.SparseR1C, solution *solution) (int, error) { - r := -1 - lID, rID, oID := c.L.WireID(), c.R.WireID(), c.O.WireID() - - if (c.L.CoeffID() != 0 || c.M[0].CoeffID() != 0) && !solution.solved[lID] { - // check if it's a hint - if hint, ok := cs.MHints[lID]; ok { - if err := solution.solveWithHint(lID, hint); err != nil { - return -1, err - } - } else { - r = 0 - } - - } - - if (c.R.CoeffID() != 0 || c.M[1].CoeffID() != 0) && !solution.solved[rID] { - // check if it's a hint - if hint, ok := cs.MHints[rID]; ok { - if err := solution.solveWithHint(rID, hint); err != nil { - return -1, err - } - } else { - r = 1 - } - } - - if (c.O.CoeffID() != 0) && !solution.solved[oID] { - // check if it's a hint - if hint, ok := cs.MHints[oID]; ok { - if err := solution.solveWithHint(oID, hint); err != nil { - return -1, err - } - } else { - r = 2 - } - } - return r, nil -} - -// solveConstraint solve any unsolved wire in given constraint and update the solution -// a SparseR1C may have up to one unsolved wire (excluding hints) -// if it doesn't, then this function returns and does nothing -func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution, coefficientsNegInv fr.Vector) error { - - if c.Commitment == constraint.COMMITTED { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. - return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time - } - - lro, err := cs.computeHints(c, solution) - if err != nil { - return err - } - if lro == -1 { - // no unsolved wire - // can happen if the constraint contained only hint wires. - return nil - } - if lro == 1 { // we solve for R: u1L+u2R+u3LR+u4O+k=0 => R(u2+u3L)+u1L+u4O+k = 0 - if !solution.solved[c.L.WireID()] { - panic("L wire should be instantiated when we solve R") - } - var u1, u2, u3, den, num, v1, v2 fr.Element - u3.Mul(&cs.Coefficients[c.M[0].CoeffID()], &cs.Coefficients[c.M[1].CoeffID()]) - u1.Set(&cs.Coefficients[c.L.CoeffID()]) - u2.Set(&cs.Coefficients[c.R.CoeffID()]) - den.Mul(&u3, &solution.values[c.L.WireID()]).Add(&den, &u2) - - v1 = solution.computeTerm(c.L) - v2 = solution.computeTerm(c.O) - num.Add(&v1, &v2).Add(&num, &cs.Coefficients[c.K]) - - // TODO find a way to do lazy div (/ batch inversion) - num.Div(&num, &den).Neg(&num) - solution.set(c.L.WireID(), num) - return nil - } - - if lro == 0 { // we solve for L: u1L+u2R+u3LR+u4O+k=0 => L(u1+u3R)+u2R+u4O+k = 0 - if !solution.solved[c.R.WireID()] { - panic("R wire should be instantiated when we solve L") - } - var u1, u2, u3, den, num, v1, v2 fr.Element - u3.Mul(&cs.Coefficients[c.M[0].CoeffID()], &cs.Coefficients[c.M[1].CoeffID()]) - u1.Set(&cs.Coefficients[c.L.CoeffID()]) - u2.Set(&cs.Coefficients[c.R.CoeffID()]) - den.Mul(&u3, &solution.values[c.R.WireID()]).Add(&den, &u1) - - v1 = solution.computeTerm(c.R) - v2 = solution.computeTerm(c.O) - num.Add(&v1, &v2).Add(&num, &cs.Coefficients[c.K]) - - // TODO find a way to do lazy div (/ batch inversion) - num.Div(&num, &den).Neg(&num) - solution.set(c.L.WireID(), num) - return nil - - } - // O we solve for O - var o fr.Element - cID, vID := c.O.CoeffID(), c.O.WireID() - - l := solution.computeTerm(c.L) - r := solution.computeTerm(c.R) - m0 := solution.computeTerm(c.M[0]) - m1 := solution.computeTerm(c.M[1]) - - // o = - ((m0 * m1) + l + r + c.K) / c.O - o.Mul(&m0, &m1).Add(&o, &l).Add(&o, &r).Add(&o, &cs.Coefficients[c.K]) - o.Mul(&o, &coefficientsNegInv[cID]) - - solution.set(vID, o) - - return nil -} - -// IsSolved -// Deprecated: use _, err := Solve(...) instead -func (cs *SparseR1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { - _, err := cs.Solve(witness, opts...) - return err -} - -// GetConstraints return the list of SparseR1C and a coefficient resolver -func (cs *SparseR1CS) GetConstraints() ([]constraint.SparseR1C, constraint.Resolver) { - return cs.Constraints, cs -} - -func (cs *SparseR1CS) GetConstraint(i int) *constraint.SparseR1C { - if i < 0 || i >= len(cs.Constraints) { - return nil - } - return &cs.Constraints[i] -} - -func (cs *SparseR1CS) GetCoefficient(i int) (r constraint.Coeff) { - copy(r[:], cs.Coefficients[i][:]) - return -} - -// checkConstraint verifies that the constraint holds -func (cs *SparseR1CS) checkConstraint(c constraint.SparseR1C, solution *solution) error { - - if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. - return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time - } - - l := solution.computeTerm(c.L) - r := solution.computeTerm(c.R) - m0 := solution.computeTerm(c.M[0]) - m1 := solution.computeTerm(c.M[1]) - o := solution.computeTerm(c.O) - - // l + r + (m0 * m1) + o + c.K == 0 - var t fr.Element - t.Mul(&m0, &m1).Add(&t, &l).Add(&t, &r).Add(&t, &o).Add(&t, &cs.Coefficients[c.K]) - if !t.IsZero() { - return fmt.Errorf("qL⋅xa + qR⋅xb + qO⋅xc + qM⋅(xaxb) + qC != 0 → %s + %s + %s + (%s × %s) + %s != 0", - l.String(), - r.String(), - o.String(), - m0.String(), - m1.String(), - cs.Coefficients[c.K].String(), - ) - } - return nil - -} - -// GetNbCoefficients return the number of unique coefficients needed in the R1CS -func (cs *SparseR1CS) GetNbCoefficients() int { - return len(cs.Coefficients) -} - -// CurveID returns curve ID as defined in gnark-crypto (ecc.BW6-761) -func (cs *SparseR1CS) CurveID() ecc.ID { - return ecc.BW6_761 -} - -// WriteTo encodes SparseR1CS into provided io.Writer using cbor -func (cs *SparseR1CS) WriteTo(w io.Writer) (int64, error) { - _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written - enc, err := cbor.CoreDetEncOptions().EncMode() - if err != nil { - return 0, err - } - encoder := enc.NewEncoder(&_w) - - // encode our object - err = encoder.Encode(cs) - return _w.N, err -} - -// ReadFrom attempts to decode SparseR1CS from io.Reader using cbor -func (cs *SparseR1CS) ReadFrom(r io.Reader) (int64, error) { - dm, err := cbor.DecOptions{ - MaxArrayElements: 134217728, - MaxMapPairs: 134217728, - }.DecMode() - if err != nil { - return 0, err - } - decoder := dm.NewDecoder(r) - - // initialize coeff table - cs.CoeffTable = newCoeffTable(0) - - if err := decoder.Decode(cs); err != nil { - return int64(decoder.NumBytesRead()), err - } - - if err := cs.CheckSerializationHeader(); err != nil { - return int64(decoder.NumBytesRead()), err - } - - return int64(decoder.NumBytesRead()), nil -} diff --git a/constraint/bw6-761/r1cs_test.go b/constraint/bw6-761/r1cs_test.go index ae50dafdc3..54309d49aa 100644 --- a/constraint/bw6-761/r1cs_test.go +++ b/constraint/bw6-761/r1cs_test.go @@ -20,6 +20,7 @@ import ( "bytes" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/frontend/cs/scs" "github.com/consensys/gnark/internal/backend/circuits" "reflect" "testing" @@ -79,10 +80,11 @@ func TestSerialization(t *testing.T) { if diff := cmp.Diff(r1cs1, &reconstructed, cmpopts.IgnoreFields(cs.R1CS{}, "System.q", - "arithEngine", + "field", "CoeffTable.mCoeffs", "System.lbWireLevel", "System.lbHints", + "System.genericHint", "System.SymbolTable", "System.lbOutputs", "System.bitLen")); diff != "" { @@ -150,12 +152,6 @@ func (circuit *circuit) Define(api frontend.API) error { func BenchmarkSolve(b *testing.B) { - var c circuit - ccs, err := frontend.Compile(fr.Modulus(), r1cs.NewBuilder, &c) - if err != nil { - b.Fatal(err) - } - var w circuit w.X = 1 w.Y = 1 @@ -164,8 +160,32 @@ func BenchmarkSolve(b *testing.B) { b.Fatal(err) } - b.ResetTimer() - for i := 0; i < b.N; i++ { - _ = ccs.IsSolved(witness) - } + b.Run("scs", func(b *testing.B) { + var c circuit + ccs, err := frontend.Compile(fr.Modulus(), scs.NewBuilder, &c) + if err != nil { + b.Fatal(err) + } + b.Log("scs nbConstraints", ccs.GetNbConstraints()) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = ccs.IsSolved(witness) + } + }) + + b.Run("r1cs", func(b *testing.B) { + var c circuit + ccs, err := frontend.Compile(fr.Modulus(), r1cs.NewBuilder, &c, frontend.WithCompressThreshold(10)) + if err != nil { + b.Fatal(err) + } + b.Log("r1cs nbConstraints", ccs.GetNbConstraints()) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = ccs.IsSolved(witness) + } + }) + } diff --git a/constraint/bw6-761/solution.go b/constraint/bw6-761/solution.go deleted file mode 100644 index 68d019734e..0000000000 --- a/constraint/bw6-761/solution.go +++ /dev/null @@ -1,383 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// 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. - -// Code generated by gnark DO NOT EDIT - -package cs - -import ( - "errors" - "fmt" - "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/debug" - "github.com/rs/zerolog" - "io" - "math/big" - "strconv" - "strings" - "sync/atomic" - - "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" -) - -// solution represents elements needed to compute -// a solution to a R1CS or SparseR1CS -type solution struct { - values, coefficients []fr.Element - solved []bool - nbSolved uint64 - mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function - st *debug.SymbolTable - cs *constraint.System -} - -func newSolution(cs *constraint.System, nbWires int, hintFunctions map[solver.HintID]solver.Hint, coefficients []fr.Element) (solution, error) { - - s := solution{ - cs: cs, - st: &cs.SymbolTable, - values: make([]fr.Element, nbWires), - coefficients: coefficients, - solved: make([]bool, nbWires), - mHintsFunctions: hintFunctions, - } - - // hintsDependencies is from compile time; it contains the list of hints the solver **needs** - var missing []string - for hintUUID, hintID := range cs.MHintsDependencies { - if _, ok := s.mHintsFunctions[hintUUID]; !ok { - missing = append(missing, hintID) - } - } - - if len(missing) > 0 { - return s, fmt.Errorf("solver missing hint(s): %v", missing) - } - - return s, nil -} - -func (s *solution) set(id int, value fr.Element) { - if s.solved[id] { - panic("solving the same wire twice should never happen.") - } - s.values[id] = value - s.solved[id] = true - atomic.AddUint64(&s.nbSolved, 1) - // s.nbSolved++ -} - -func (s *solution) isValid() bool { - return int(s.nbSolved) == len(s.values) -} - -// computeTerm computes coeff*variable -func (s *solution) computeTerm(t constraint.Term) fr.Element { - cID, vID := t.CoeffID(), t.WireID() - if cID != 0 && !s.solved[vID] { - panic("computing a term with an unsolved wire") - } - switch cID { - case constraint.CoeffIdZero: - return fr.Element{} - case constraint.CoeffIdOne: - return s.values[vID] - case constraint.CoeffIdTwo: - var res fr.Element - res.Double(&s.values[vID]) - return res - case constraint.CoeffIdMinusOne: - var res fr.Element - res.Neg(&s.values[vID]) - return res - default: - var res fr.Element - res.Mul(&s.coefficients[cID], &s.values[vID]) - return res - } -} - -// r += (t.coeff*t.value) -func (s *solution) accumulateInto(t constraint.Term, r *fr.Element) { - cID := t.CoeffID() - - if t.IsConstant() { - // needed for logs, we may want to not put this in the hot path if we need to - // optimize constraint system solver further. - r.Add(r, &s.coefficients[cID]) - return - } - - vID := t.WireID() - switch cID { - case constraint.CoeffIdZero: - return - case constraint.CoeffIdOne: - r.Add(r, &s.values[vID]) - case constraint.CoeffIdTwo: - var res fr.Element - res.Double(&s.values[vID]) - r.Add(r, &res) - case constraint.CoeffIdMinusOne: - r.Sub(r, &s.values[vID]) - default: - var res fr.Element - res.Mul(&s.coefficients[cID], &s.values[vID]) - r.Add(r, &res) - } -} - -// solveHint compute solution.values[vID] using provided solver hint -func (s *solution) solveWithHint(vID int, hID int) error { - // skip if the wire is already solved by a call to the same hint - // function on the same inputs - if s.solved[vID] { - return nil - } - - h := &s.cs.HintMappings[hID] - - // ensure hint function was provided - f, ok := s.mHintsFunctions[h.HintID] - if !ok { - return errors.New("missing hint function") - } - - // tmp IO big int memory - nbInputs := len(h.Inputs) - nbOutputs := len(h.Outputs) - inputs := make([]*big.Int, nbInputs) - outputs := make([]*big.Int, nbOutputs) - for i := 0; i < nbOutputs; i++ { - outputs[i] = big.NewInt(0) - } - - q := fr.Modulus() - - // for each input, we set its big int value, IF all the wires are solved - // the only case where all wires may not be solved, is if one of the input of this hint - // is the output of another hint. - // it is safe to recursively solve this with the parallel solver, since all hints-output wires - // that we can solve this way are marked to be solved with the current constraint we are processing. - recursiveSolve := func(t constraint.Term) error { - if t.IsConstant() { - return nil - } - wID := t.WireID() - if s.solved[wID] { - return nil - } - // unsolved dependency - if h, ok := s.cs.MHints[wID]; ok { - // solve recursively. - return s.solveWithHint(wID, h) - } - - // it's not a hint, we panic. - panic("solver can't compute hint; one or more input wires are unsolved") - } - - for i := 0; i < nbInputs; i++ { - inputs[i] = big.NewInt(0) - - var v fr.Element - for _, term := range h.Inputs[i] { - if err := recursiveSolve(term); err != nil { - return err - } - s.accumulateInto(term, &v) - } - v.BigInt(inputs[i]) - } - - err := f(q, inputs, outputs) - - var v fr.Element - for i := range outputs { - v.SetBigInt(outputs[i]) - s.set(h.Outputs[i], v) - } - - return err -} - -func (s *solution) printLogs(log zerolog.Logger, logs []constraint.LogEntry) { - if log.GetLevel() == zerolog.Disabled { - return - } - - for i := 0; i < len(logs); i++ { - logLine := s.logValue(logs[i]) - log.Debug().Str(zerolog.CallerFieldName, logs[i].Caller).Msg(logLine) - } -} - -const unsolvedVariable = "" - -func (s *solution) logValue(log constraint.LogEntry) string { - var toResolve []interface{} - var ( - eval fr.Element - missingValue bool - ) - for j := 0; j < len(log.ToResolve); j++ { - // before eval le - - missingValue = false - eval.SetZero() - - for _, t := range log.ToResolve[j] { - // for each term in the linear expression - - cID, vID := t.CoeffID(), t.WireID() - if t.IsConstant() { - // just add the constant - eval.Add(&eval, &s.coefficients[cID]) - continue - } - - if !s.solved[vID] { - missingValue = true - break // stop the loop we can't evaluate. - } - - tv := s.computeTerm(t) - eval.Add(&eval, &tv) - } - - // after - if missingValue { - toResolve = append(toResolve, unsolvedVariable) - } else { - // we have to append our accumulator - toResolve = append(toResolve, eval.String()) - } - - } - if len(log.Stack) > 0 { - var sbb strings.Builder - for _, lID := range log.Stack { - location := s.st.Locations[lID] - function := s.st.Functions[location.FunctionID] - - sbb.WriteString(function.Name) - sbb.WriteByte('\n') - sbb.WriteByte('\t') - sbb.WriteString(function.Filename) - sbb.WriteByte(':') - sbb.WriteString(strconv.Itoa(int(location.Line))) - sbb.WriteByte('\n') - } - toResolve = append(toResolve, sbb.String()) - } - return fmt.Sprintf(log.Format, toResolve...) -} - -// UnsatisfiedConstraintError wraps an error with useful metadata on the unsatisfied constraint -type UnsatisfiedConstraintError struct { - Err error - CID int // constraint ID - DebugInfo *string // optional debug info -} - -func (r *UnsatisfiedConstraintError) Error() string { - if r.DebugInfo != nil { - return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, *r.DebugInfo) - } - return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, r.Err.Error()) -} - -// R1CSSolution represent a valid assignment to all the variables in the constraint system. -// The vector W such that Aw o Bw - Cw = 0 -type R1CSSolution struct { - W fr.Vector - A, B, C fr.Vector -} - -func (t *R1CSSolution) WriteTo(w io.Writer) (int64, error) { - n, err := t.W.WriteTo(w) - if err != nil { - return n, err - } - a, err := t.A.WriteTo(w) - n += a - if err != nil { - return n, err - } - a, err = t.B.WriteTo(w) - n += a - if err != nil { - return n, err - } - a, err = t.C.WriteTo(w) - n += a - return n, err -} - -func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { - n, err := t.W.ReadFrom(r) - if err != nil { - return n, err - } - a, err := t.A.ReadFrom(r) - a += n - if err != nil { - return n, err - } - a, err = t.B.ReadFrom(r) - a += n - if err != nil { - return n, err - } - a, err = t.C.ReadFrom(r) - n += a - return n, err -} - -// SparseR1CSSolution represent a valid assignment to all the variables in the constraint system. -type SparseR1CSSolution struct { - L, R, O fr.Vector -} - -func (t *SparseR1CSSolution) WriteTo(w io.Writer) (int64, error) { - n, err := t.L.WriteTo(w) - if err != nil { - return n, err - } - a, err := t.R.WriteTo(w) - n += a - if err != nil { - return n, err - } - a, err = t.O.WriteTo(w) - n += a - return n, err - -} - -func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { - n, err := t.L.ReadFrom(r) - if err != nil { - return n, err - } - a, err := t.R.ReadFrom(r) - a += n - if err != nil { - return n, err - } - a, err = t.O.ReadFrom(r) - a += n - return n, err -} diff --git a/constraint/bw6-761/solver.go b/constraint/bw6-761/solver.go new file mode 100644 index 0000000000..bd1f54d2f3 --- /dev/null +++ b/constraint/bw6-761/solver.go @@ -0,0 +1,614 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package cs + +import ( + "errors" + "fmt" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/field/pool" + "github.com/consensys/gnark/constraint" + csolver "github.com/consensys/gnark/constraint/solver" + "github.com/rs/zerolog" + "math" + "math/big" + "runtime" + "strconv" + "strings" + "sync" + "sync/atomic" + + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" +) + +// solver represent the state of the solver during a call to System.Solve(...) +type solver struct { + *system + + // values and solved are index by the wire (variable) id + values []fr.Element + solved []bool + nbSolved uint64 + + // maps hintID to hint function + mHintsFunctions map[csolver.HintID]csolver.Hint + + // used to out api.Println + logger zerolog.Logger + + a, b, c fr.Vector // R1CS solver will compute the a,b,c matrices + + q *big.Int +} + +func newSolver(cs *system, witness fr.Vector, opts ...csolver.Option) (*solver, error) { + // parse options + opt, err := csolver.NewConfig(opts...) + if err != nil { + return nil, err + } + + // check witness size + witnessOffset := 0 + if cs.Type == constraint.SystemR1CS { + witnessOffset++ + } + + nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables + expectedWitnessSize := len(cs.Public) - witnessOffset + len(cs.Secret) + + if len(witness) != expectedWitnessSize { + return nil, fmt.Errorf("invalid witness size, got %d, expected %d", len(witness), expectedWitnessSize) + } + + // check all hints are there + hintFunctions := opt.HintFunctions + + // hintsDependencies is from compile time; it contains the list of hints the solver **needs** + var missing []string + for hintUUID, hintID := range cs.MHintsDependencies { + if _, ok := hintFunctions[hintUUID]; !ok { + missing = append(missing, hintID) + } + } + + if len(missing) > 0 { + return nil, fmt.Errorf("solver missing hint(s): %v", missing) + } + + s := solver{ + system: cs, + values: make([]fr.Element, nbWires), + solved: make([]bool, nbWires), + mHintsFunctions: hintFunctions, + logger: opt.Logger, + q: cs.Field(), + } + + // set the witness indexes as solved + if witnessOffset == 1 { + s.solved[0] = true // ONE_WIRE + s.values[0].SetOne() + } + copy(s.values[witnessOffset:], witness) + for i := range witness { + s.solved[i+witnessOffset] = true + } + + // keep track of the number of wire instantiations we do, for a post solve sanity check + // to ensure we instantiated all wires + s.nbSolved += uint64(len(witness) + witnessOffset) + + if s.Type == constraint.SystemR1CS { + n := ecc.NextPowerOfTwo(uint64(cs.GetNbConstraints())) + s.a = make(fr.Vector, cs.GetNbConstraints(), n) + s.b = make(fr.Vector, cs.GetNbConstraints(), n) + s.c = make(fr.Vector, cs.GetNbConstraints(), n) + } + + return &s, nil +} + +func (s *solver) set(id int, value fr.Element) { + if s.solved[id] { + panic("solving the same wire twice should never happen.") + } + s.values[id] = value + s.solved[id] = true + atomic.AddUint64(&s.nbSolved, 1) +} + +// computeTerm computes coeff*variable +// TODO @gbotrel check if t is a Constant only +func (s *solver) computeTerm(t constraint.Term) fr.Element { + cID, vID := t.CoeffID(), t.WireID() + if cID != 0 && !s.solved[vID] { + panic("computing a term with an unsolved wire") + } + switch cID { + case constraint.CoeffIdZero: + return fr.Element{} + case constraint.CoeffIdOne: + return s.values[vID] + case constraint.CoeffIdTwo: + var res fr.Element + res.Double(&s.values[vID]) + return res + case constraint.CoeffIdMinusOne: + var res fr.Element + res.Neg(&s.values[vID]) + return res + default: + var res fr.Element + res.Mul(&s.Coefficients[cID], &s.values[vID]) + return res + } +} + +// r += (t.coeff*t.value) +// TODO @gbotrel check t.IsConstant on the caller side when necessary +func (s *solver) accumulateInto(t constraint.Term, r *fr.Element) { + cID := t.CoeffID() + vID := t.WireID() + + switch cID { + case constraint.CoeffIdZero: + return + case constraint.CoeffIdOne: + r.Add(r, &s.values[vID]) + case constraint.CoeffIdTwo: + var res fr.Element + res.Double(&s.values[vID]) + r.Add(r, &res) + case constraint.CoeffIdMinusOne: + r.Sub(r, &s.values[vID]) + default: + var res fr.Element + res.Mul(&s.Coefficients[cID], &s.values[vID]) + r.Add(r, &res) + } +} + +// solveWithHint executes a hint and assign the result to its defined outputs. +func (s *solver) solveWithHint(h *constraint.HintMapping) error { + // ensure hint function was provided + f, ok := s.mHintsFunctions[h.HintID] + if !ok { + return errors.New("missing hint function") + } + + // tmp IO big int memory + nbInputs := len(h.Inputs) + nbOutputs := int(h.OutputRange.End - h.OutputRange.Start) + inputs := make([]*big.Int, nbInputs) + outputs := make([]*big.Int, nbOutputs) + for i := 0; i < nbOutputs; i++ { + outputs[i] = pool.BigInt.Get() + outputs[i].SetUint64(0) + } + + q := pool.BigInt.Get() + q.Set(s.q) + + for i := 0; i < nbInputs; i++ { + var v fr.Element + for _, term := range h.Inputs[i] { + if term.IsConstant() { + v.Add(&v, &s.Coefficients[term.CoeffID()]) + continue + } + s.accumulateInto(term, &v) + } + inputs[i] = pool.BigInt.Get() + v.BigInt(inputs[i]) + } + + err := f(q, inputs, outputs) + + var v fr.Element + for i := range outputs { + v.SetBigInt(outputs[i]) + s.set(int(h.OutputRange.Start)+i, v) + pool.BigInt.Put(outputs[i]) + } + + for i := range inputs { + pool.BigInt.Put(inputs[i]) + } + + pool.BigInt.Put(q) + + return err +} + +func (s *solver) printLogs(logs []constraint.LogEntry) { + if s.logger.GetLevel() == zerolog.Disabled { + return + } + + for i := 0; i < len(logs); i++ { + logLine := s.logValue(logs[i]) + s.logger.Debug().Str(zerolog.CallerFieldName, logs[i].Caller).Msg(logLine) + } +} + +const unsolvedVariable = "" + +func (s *solver) logValue(log constraint.LogEntry) string { + var toResolve []interface{} + var ( + eval fr.Element + missingValue bool + ) + for j := 0; j < len(log.ToResolve); j++ { + // before eval le + + missingValue = false + eval.SetZero() + + for _, t := range log.ToResolve[j] { + // for each term in the linear expression + + cID, vID := t.CoeffID(), t.WireID() + if t.IsConstant() { + // just add the constant + eval.Add(&eval, &s.Coefficients[cID]) + continue + } + + if !s.solved[vID] { + missingValue = true + break // stop the loop we can't evaluate. + } + + tv := s.computeTerm(t) + eval.Add(&eval, &tv) + } + + // after + if missingValue { + toResolve = append(toResolve, unsolvedVariable) + } else { + // we have to append our accumulator + toResolve = append(toResolve, eval.String()) + } + + } + if len(log.Stack) > 0 { + var sbb strings.Builder + for _, lID := range log.Stack { + location := s.SymbolTable.Locations[lID] + function := s.SymbolTable.Functions[location.FunctionID] + + sbb.WriteString(function.Name) + sbb.WriteByte('\n') + sbb.WriteByte('\t') + sbb.WriteString(function.Filename) + sbb.WriteByte(':') + sbb.WriteString(strconv.Itoa(int(location.Line))) + sbb.WriteByte('\n') + } + toResolve = append(toResolve, sbb.String()) + } + return fmt.Sprintf(log.Format, toResolve...) +} + +// divByCoeff sets res = res / t.Coeff +func (solver *solver) divByCoeff(res *fr.Element, cID uint32) { + switch cID { + case constraint.CoeffIdOne: + return + case constraint.CoeffIdMinusOne: + res.Neg(res) + case constraint.CoeffIdZero: + panic("division by 0") + default: + // this is slow, but shouldn't happen as divByCoeff is called to + // remove the coeff of an unsolved wire + // but unsolved wires are (in gnark frontend) systematically set with a coeff == 1 or -1 + res.Div(res, &solver.Coefficients[cID]) + } +} + +// Implement constraint.Solver +func (s *solver) GetValue(cID, vID uint32) constraint.Element { + var r constraint.Element + e := s.computeTerm(constraint.Term{CID: cID, VID: vID}) + copy(r[:], e[:]) + return r +} +func (s *solver) GetCoeff(cID uint32) constraint.Element { + var r constraint.Element + copy(r[:], s.Coefficients[cID][:]) + return r +} +func (s *solver) SetValue(vID uint32, f constraint.Element) { + s.set(int(vID), *(*fr.Element)(f[:])) +} + +func (s *solver) IsSolved(vID uint32) bool { + return s.solved[vID] +} + +// processInstruction decodes the instruction and execute blueprint-defined logic. +// an instruction can encode a hint, a custom constraint or a generic constraint. +func (solver *solver) processInstruction(inst constraint.Instruction, scratch *scratch) error { + // fetch the blueprint + blueprint := solver.Blueprints[inst.BlueprintID] + calldata := solver.GetCallData(inst) + cID := inst.ConstraintOffset // here we have 1 constraint in the instruction only + + if solver.Type == constraint.SystemR1CS { + if bc, ok := blueprint.(constraint.BlueprintR1C); ok { + // TODO @gbotrel we use the solveR1C method for now, having user-defined + // blueprint for R1CS would require constraint.Solver interface to add methods + // to set a,b,c since it's more efficient to compute these while we solve. + bc.DecompressR1C(&scratch.tR1C, calldata) + return solver.solveR1C(cID, &scratch.tR1C) + } + } else if solver.Type == constraint.SystemSparseR1CS { + // blueprint declared "I know how to solve this." + if bc, ok := blueprint.(constraint.BlueprintSolvable); ok { + if err := bc.Solve(solver, calldata); err != nil { + return solver.wrapErrWithDebugInfo(cID, err) + } + return nil + } + } + + // blueprint encodes a hint, we execute. + // TODO @gbotrel may be worth it to move hint logic in blueprint "solve" + if bc, ok := blueprint.(constraint.BlueprintHint); ok { + bc.DecompressHint(&scratch.tHint, calldata) + return solver.solveWithHint(&scratch.tHint) + } + + return nil +} + +// run runs the solver. it return an error if a constraint is not satisfied or if not all wires +// were instantiated. +func (solver *solver) run() error { + // minWorkPerCPU is the minimum target number of constraint a task should hold + // in other words, if a level has less than minWorkPerCPU, it will not be parallelized and executed + // sequentially without sync. + const minWorkPerCPU = 50.0 // TODO @gbotrel revisit that with blocks. + + // cs.Levels has a list of levels, where all constraints in a level l(n) are independent + // and may only have dependencies on previous levels + // for each constraint + // we are guaranteed that each R1C contains at most one unsolved wire + // first we solve the unsolved wire (if any) + // then we check that the constraint is valid + // if a[i] * b[i] != c[i]; it means the constraint is not satisfied + var wg sync.WaitGroup + chTasks := make(chan []int, runtime.NumCPU()) + chError := make(chan error, runtime.NumCPU()) + + // start a worker pool + // each worker wait on chTasks + // a task is a slice of constraint indexes to be solved + for i := 0; i < runtime.NumCPU(); i++ { + go func() { + var scratch scratch + for t := range chTasks { + for _, i := range t { + if err := solver.processInstruction(solver.Instructions[i], &scratch); err != nil { + chError <- err + wg.Done() + return + } + } + wg.Done() + } + }() + } + + // clean up pool go routines + defer func() { + close(chTasks) + close(chError) + }() + + var scratch scratch + + // for each level, we push the tasks + for _, level := range solver.Levels { + + // max CPU to use + maxCPU := float64(len(level)) / minWorkPerCPU + + if maxCPU <= 1.0 { + // we do it sequentially + for _, i := range level { + if err := solver.processInstruction(solver.Instructions[i], &scratch); err != nil { + return err + } + } + continue + } + + // number of tasks for this level is set to number of CPU + // but if we don't have enough work for all our CPU, it can be lower. + nbTasks := runtime.NumCPU() + maxTasks := int(math.Ceil(maxCPU)) + if nbTasks > maxTasks { + nbTasks = maxTasks + } + nbIterationsPerCpus := len(level) / nbTasks + + // more CPUs than tasks: a CPU will work on exactly one iteration + // note: this depends on minWorkPerCPU constant + if nbIterationsPerCpus < 1 { + nbIterationsPerCpus = 1 + nbTasks = len(level) + } + + extraTasks := len(level) - (nbTasks * nbIterationsPerCpus) + extraTasksOffset := 0 + + for i := 0; i < nbTasks; i++ { + wg.Add(1) + _start := i*nbIterationsPerCpus + extraTasksOffset + _end := _start + nbIterationsPerCpus + if extraTasks > 0 { + _end++ + extraTasks-- + extraTasksOffset++ + } + // since we're never pushing more than num CPU tasks + // we will never be blocked here + chTasks <- level[_start:_end] + } + + // wait for the level to be done + wg.Wait() + + if len(chError) > 0 { + return <-chError + } + } + + if int(solver.nbSolved) != len(solver.values) { + return errors.New("solver didn't assign a value to all wires") + } + + return nil +} + +// solveR1C compute unsolved wires in the constraint, if any and set the solver accordingly +// +// returns an error if the solver called a hint function that errored +// returns false, nil if there was no wire to solve +// returns true, nil if exactly one wire was solved. In that case, it is redundant to check that +// the constraint is satisfied later. +func (solver *solver) solveR1C(cID uint32, r *constraint.R1C) error { + a, b, c := &solver.a[cID], &solver.b[cID], &solver.c[cID] + + // the index of the non-zero entry shows if L, R or O has an uninstantiated wire + // the content is the ID of the wire non instantiated + var loc uint8 + + var termToCompute constraint.Term + + processLExp := func(l constraint.LinearExpression, val *fr.Element, locValue uint8) { + for _, t := range l { + vID := t.WireID() + + // wire is already computed, we just accumulate in val + if solver.solved[vID] { + solver.accumulateInto(t, val) + continue + } + + if loc != 0 { + panic("found more than one wire to instantiate") + } + termToCompute = t + loc = locValue + } + } + + processLExp(r.L, a, 1) + processLExp(r.R, b, 2) + processLExp(r.O, c, 3) + + if loc == 0 { + // there is nothing to solve, may happen if we have an assertion + // (ie a constraints that doesn't yield any output) + // or if we solved the unsolved wires with hint functions + var check fr.Element + if !check.Mul(a, b).Equal(c) { + return solver.wrapErrWithDebugInfo(cID, fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String())) + } + return nil + } + + // we compute the wire value and instantiate it + wID := termToCompute.WireID() + + // solver result + var wire fr.Element + + switch loc { + case 1: + if !b.IsZero() { + wire.Div(c, b). + Sub(&wire, a) + a.Add(a, &wire) + } else { + // we didn't actually ensure that a * b == c + var check fr.Element + if !check.Mul(a, b).Equal(c) { + return solver.wrapErrWithDebugInfo(cID, fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String())) + } + } + case 2: + if !a.IsZero() { + wire.Div(c, a). + Sub(&wire, b) + b.Add(b, &wire) + } else { + var check fr.Element + if !check.Mul(a, b).Equal(c) { + return solver.wrapErrWithDebugInfo(cID, fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String())) + } + } + case 3: + wire.Mul(a, b). + Sub(&wire, c) + + c.Add(c, &wire) + } + + // wire is the term (coeff * value) + // but in the solver we want to store the value only + // note that in gnark frontend, coeff here is always 1 or -1 + solver.divByCoeff(&wire, termToCompute.CID) + solver.set(wID, wire) + + return nil +} + +// UnsatisfiedConstraintError wraps an error with useful metadata on the unsatisfied constraint +type UnsatisfiedConstraintError struct { + Err error + CID int // constraint ID + DebugInfo *string // optional debug info +} + +func (r *UnsatisfiedConstraintError) Error() string { + if r.DebugInfo != nil { + return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, *r.DebugInfo) + } + return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, r.Err.Error()) +} + +func (solver *solver) wrapErrWithDebugInfo(cID uint32, err error) *UnsatisfiedConstraintError { + var debugInfo *string + if dID, ok := solver.MDebug[int(cID)]; ok { + debugInfo = new(string) + *debugInfo = solver.logValue(solver.DebugInfo[dID]) + } + return &UnsatisfiedConstraintError{CID: int(cID), Err: err, DebugInfo: debugInfo} +} + +// temporary variables to avoid memallocs in hotloop +type scratch struct { + tR1C constraint.R1C + tHint constraint.HintMapping +} diff --git a/constraint/bw6-761/system.go b/constraint/bw6-761/system.go new file mode 100644 index 0000000000..68fe2a9e3e --- /dev/null +++ b/constraint/bw6-761/system.go @@ -0,0 +1,365 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package cs + +import ( + "github.com/fxamacker/cbor/v2" + "io" + "time" + + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint" + csolver "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/internal/backend/ioutils" + "github.com/consensys/gnark/logger" + "reflect" + + "github.com/consensys/gnark-crypto/ecc" + + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" +) + +type R1CS = system +type SparseR1CS = system + +// system is a curved-typed constraint.System with a concrete coefficient table (fr.Element) +type system struct { + constraint.System + CoeffTable + field +} + +func NewR1CS(capacity int) *R1CS { + return newSystem(capacity, constraint.SystemR1CS) +} + +func NewSparseR1CS(capacity int) *SparseR1CS { + return newSystem(capacity, constraint.SystemSparseR1CS) +} + +func newSystem(capacity int, t constraint.SystemType) *system { + return &system{ + System: constraint.NewSystem(fr.Modulus(), capacity, t), + CoeffTable: newCoeffTable(capacity / 10), + } +} + +// Solve solves the constraint system with provided witness. +// If it's a R1CS returns R1CSSolution +// If it's a SparseR1CS returns SparseR1CSSolution +func (cs *system) Solve(witness witness.Witness, opts ...csolver.Option) (any, error) { + log := logger.Logger().With().Int("nbConstraints", cs.GetNbConstraints()).Logger() + start := time.Now() + + v := witness.Vector().(fr.Vector) + + // init the solver + solver, err := newSolver(cs, v, opts...) + if err != nil { + log.Err(err).Send() + return nil, err + } + + // defer log printing once all solver.values are computed + // (or sooner, if a constraint is not satisfied) + defer solver.printLogs(cs.Logs) + + // run it. + if err := solver.run(); err != nil { + log.Err(err).Send() + return nil, err + } + + log.Debug().Dur("took", time.Since(start)).Msg("constraint system solver done") + + // format the solution + // TODO @gbotrel revisit post-refactor + if cs.Type == constraint.SystemR1CS { + var res R1CSSolution + res.W = solver.values + res.A = solver.a + res.B = solver.b + res.C = solver.c + return &res, nil + } else { + // sparse R1CS + var res SparseR1CSSolution + // query l, r, o in Lagrange basis, not blinded + res.L, res.R, res.O = evaluateLROSmallDomain(cs, solver.values) + + return &res, nil + } + +} + +// IsSolved +// Deprecated: use _, err := Solve(...) instead +func (cs *system) IsSolved(witness witness.Witness, opts ...csolver.Option) error { + _, err := cs.Solve(witness, opts...) + return err +} + +// GetR1Cs return the list of R1C +func (cs *system) GetR1Cs() []constraint.R1C { + toReturn := make([]constraint.R1C, 0, cs.GetNbConstraints()) + + for _, inst := range cs.Instructions { + blueprint := cs.Blueprints[inst.BlueprintID] + if bc, ok := blueprint.(constraint.BlueprintR1C); ok { + var r1c constraint.R1C + bc.DecompressR1C(&r1c, cs.GetCallData(inst)) + toReturn = append(toReturn, r1c) + } else { + panic("not implemented") + } + } + return toReturn +} + +// GetNbCoefficients return the number of unique coefficients needed in the R1CS +func (cs *system) GetNbCoefficients() int { + return len(cs.Coefficients) +} + +// CurveID returns curve ID as defined in gnark-crypto +func (cs *system) CurveID() ecc.ID { + return ecc.BW6_761 +} + +// WriteTo encodes R1CS into provided io.Writer using cbor +func (cs *system) WriteTo(w io.Writer) (int64, error) { + _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written + ts := getTagSet() + enc, err := cbor.CoreDetEncOptions().EncModeWithTags(ts) + if err != nil { + return 0, err + } + encoder := enc.NewEncoder(&_w) + + // encode our object + err = encoder.Encode(cs) + return _w.N, err +} + +// ReadFrom attempts to decode R1CS from io.Reader using cbor +func (cs *system) ReadFrom(r io.Reader) (int64, error) { + ts := getTagSet() + dm, err := cbor.DecOptions{ + MaxArrayElements: 134217728, + MaxMapPairs: 134217728, + }.DecModeWithTags(ts) + + if err != nil { + return 0, err + } + decoder := dm.NewDecoder(r) + + // initialize coeff table + cs.CoeffTable = newCoeffTable(0) + + if err := decoder.Decode(&cs); err != nil { + return int64(decoder.NumBytesRead()), err + } + + if err := cs.CheckSerializationHeader(); err != nil { + return int64(decoder.NumBytesRead()), err + } + + return int64(decoder.NumBytesRead()), nil +} + +func (cs *system) GetCoefficient(i int) (r constraint.Element) { + copy(r[:], cs.Coefficients[i][:]) + return +} + +// GetSparseR1Cs return the list of SparseR1C +func (cs *system) GetSparseR1Cs() []constraint.SparseR1C { + + toReturn := make([]constraint.SparseR1C, 0, cs.GetNbConstraints()) + + for _, inst := range cs.Instructions { + blueprint := cs.Blueprints[inst.BlueprintID] + if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { + var sparseR1C constraint.SparseR1C + calldata := cs.CallData[inst.StartCallData : inst.StartCallData+uint64(blueprint.NbInputs())] + bc.DecompressSparseR1C(&sparseR1C, calldata) + toReturn = append(toReturn, sparseR1C) + } else { + panic("not implemented") + } + } + return toReturn +} + +// evaluateLROSmallDomain extracts the solver l, r, o, and returns it in lagrange form. +// solver = [ public | secret | internal ] +// TODO @gbotrel refactor; this seems to be a small util function for plonk +func evaluateLROSmallDomain(cs *system, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { + + //s := int(pk.Domain[0].Cardinality) + s := cs.GetNbConstraints() + len(cs.Public) // len(spr.Public) is for the placeholder constraints + s = int(ecc.NextPowerOfTwo(uint64(s))) + + var l, r, o []fr.Element + l = make([]fr.Element, s) + r = make([]fr.Element, s) + o = make([]fr.Element, s) + s0 := solution[0] + + for i := 0; i < len(cs.Public); i++ { // placeholders + l[i] = solution[i] + r[i] = s0 + o[i] = s0 + } + offset := len(cs.Public) + nbConstraints := cs.GetNbConstraints() + + var sparseR1C constraint.SparseR1C + j := 0 + for _, inst := range cs.Instructions { + blueprint := cs.Blueprints[inst.BlueprintID] + if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { + bc.DecompressSparseR1C(&sparseR1C, cs.GetCallData(inst)) + + l[offset+j] = solution[sparseR1C.XA] + r[offset+j] = solution[sparseR1C.XB] + o[offset+j] = solution[sparseR1C.XC] + j++ + } + } + + offset += nbConstraints + + for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solver[0]) + l[offset+i] = s0 + r[offset+i] = s0 + o[offset+i] = s0 + } + + return l, r, o + +} + +// R1CSSolution represent a valid assignment to all the variables in the constraint system. +// The vector W such that Aw o Bw - Cw = 0 +type R1CSSolution struct { + W fr.Vector + A, B, C fr.Vector +} + +func (t *R1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.W.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.A.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.B.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.C.WriteTo(w) + n += a + return n, err +} + +func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.W.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.A.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.B.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.C.ReadFrom(r) + n += a + return n, err +} + +// SparseR1CSSolution represent a valid assignment to all the variables in the constraint system. +type SparseR1CSSolution struct { + L, R, O fr.Vector +} + +func (t *SparseR1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.L.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.R.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.O.WriteTo(w) + n += a + return n, err + +} + +func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.L.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.R.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.O.ReadFrom(r) + a += n + return n, err +} + +func getTagSet() cbor.TagSet { + // temporary for refactor + ts := cbor.NewTagSet() + // https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml + // 65536-15309735 Unassigned + tagNum := uint64(5309735) + addType := func(t reflect.Type) { + if err := ts.Add( + cbor.TagOptions{EncTag: cbor.EncTagRequired, DecTag: cbor.DecTagRequired}, + t, + tagNum, + ); err != nil { + panic(err) + } + tagNum++ + } + + addType(reflect.TypeOf(constraint.BlueprintGenericHint{})) + addType(reflect.TypeOf(constraint.BlueprintGenericR1C{})) + addType(reflect.TypeOf(constraint.BlueprintGenericSparseR1C{})) + addType(reflect.TypeOf(constraint.BlueprintSparseR1CAdd{})) + addType(reflect.TypeOf(constraint.BlueprintSparseR1CMul{})) + + return ts +} diff --git a/constraint/coeff.go b/constraint/coeff.go deleted file mode 100644 index 434919269f..0000000000 --- a/constraint/coeff.go +++ /dev/null @@ -1,39 +0,0 @@ -package constraint - -import ( - "math/big" -) - -// Coeff represents a term coefficient data. It is instantiated by the concrete -// constraint system implementation. -// Most of the scalar field used in gnark are on 4 uint64, so we have a clear memory overhead here. -type Coeff [6]uint64 - -// IsZero returns true if coefficient == 0 -func (z *Coeff) IsZero() bool { - return (z[5] | z[4] | z[3] | z[2] | z[1] | z[0]) == 0 -} - -// CoeffEngine capability to perform arithmetic on Coeff -type CoeffEngine interface { - FromInterface(interface{}) Coeff - ToBigInt(*Coeff) *big.Int - Mul(a, b *Coeff) - Add(a, b *Coeff) - Sub(a, b *Coeff) - Neg(a *Coeff) - Inverse(a *Coeff) - One() Coeff - IsOne(*Coeff) bool - String(*Coeff) string -} - -// ids of the coefficients with simple values in any cs.coeffs slice. -// TODO @gbotrel let's keep that here for the refactoring -- and move it to concrete cs package after -const ( - CoeffIdZero = 0 - CoeffIdOne = 1 - CoeffIdTwo = 2 - CoeffIdMinusOne = 3 - CoeffIdMinusTwo = 4 -) diff --git a/constraint/core.go b/constraint/core.go new file mode 100644 index 0000000000..2bc71f49bb --- /dev/null +++ b/constraint/core.go @@ -0,0 +1,374 @@ +package constraint + +import ( + "fmt" + "math/big" + + "github.com/blang/semver/v4" + "github.com/consensys/gnark" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/debug" + "github.com/consensys/gnark/internal/tinyfield" + "github.com/consensys/gnark/internal/utils" + "github.com/consensys/gnark/logger" + "github.com/consensys/gnark/profile" +) + +type SystemType uint16 + +const ( + SystemUnknown SystemType = iota + SystemR1CS + SystemSparseR1CS +) + +// Instruction is the lowest element of a constraint system. It stores just enough data to +// reconstruct a constraint of any shape or a hint at solving time. +type Instruction struct { + // BlueprintID maps this instruction to a blueprint + BlueprintID BlueprintID + + // ConstraintOffset stores the starting constraint ID of this instruction. + // Might not be strictly necessary; but speeds up solver for instructions that represents + // multiple constraints. + ConstraintOffset uint32 + + // The constraint system stores a single []uint32 calldata slice. StartCallData + // points to the starting index in the mentioned slice. This avoid storing a slice per + // instruction (3 * uint64 in memory). + StartCallData uint64 +} + +// System contains core elements for a constraint System +type System struct { + // serialization header + GnarkVersion string + ScalarField string + + Type SystemType + + Instructions []Instruction + Blueprints []Blueprint + CallData []uint32 // huge slice. + + // can be != than len(instructions) + NbConstraints int + + // number of internal wires + NbInternalVariables int + + // input wires names + Public, Secret []string + + // logs (added with system.Println, resolved when solver sets a value to a wire) + Logs []LogEntry + + // debug info contains stack trace (including line number) of a call to a system.API that + // results in an unsolved constraint + DebugInfo []LogEntry + SymbolTable debug.SymbolTable + // maps constraint id to debugInfo id + // several constraints may point to the same debug info + MDebug map[int]int + + // maps hintID to hint string identifier + MHintsDependencies map[solver.HintID]string + + // each level contains independent constraints and can be parallelized + // it is guaranteed that all dependencies for constraints in a level l are solved + // in previous levels + // TODO @gbotrel these are currently updated after we add a constraint. + // but in case the object is built from a serialized representation + // we need to init the level builder lbWireLevel from the existing constraints. + Levels [][]int + + // scalar field + q *big.Int `cbor:"-"` + bitLen int `cbor:"-"` + + // level builder + lbWireLevel []int `cbor:"-"` // at which level we solve a wire. init at -1. + lbOutputs []uint32 `cbor:"-"` // wire outputs for current constraint. + lbHints map[int]struct{} `cbor:"-"` // hints we processed in current round + + CommitmentInfo Commitment + + genericHint BlueprintID +} + +// NewSystem initialize the common structure among constraint system +func NewSystem(scalarField *big.Int, capacity int, t SystemType) System { + system := System{ + Type: t, + SymbolTable: debug.NewSymbolTable(), + MDebug: map[int]int{}, + GnarkVersion: gnark.Version.String(), + ScalarField: scalarField.Text(16), + MHintsDependencies: make(map[solver.HintID]string), + q: new(big.Int).Set(scalarField), + bitLen: scalarField.BitLen(), + lbHints: map[int]struct{}{}, + Instructions: make([]Instruction, 0, capacity), + CallData: make([]uint32, 0, capacity*2), + } + system.genericHint = system.AddBlueprint(&BlueprintGenericHint{}) + return system +} + +func (system *System) GetNbInstructions() int { + return len(system.Instructions) +} + +func (system *System) GetInstruction(id int) Instruction { + return system.Instructions[id] +} + +func (system *System) AddBlueprint(b Blueprint) BlueprintID { + system.Blueprints = append(system.Blueprints, b) + return BlueprintID(len(system.Blueprints) - 1) +} + +func (system *System) GetNbSecretVariables() int { + return len(system.Secret) +} +func (system *System) GetNbPublicVariables() int { + return len(system.Public) +} +func (system *System) GetNbInternalVariables() int { + return system.NbInternalVariables +} + +// CheckSerializationHeader parses the scalar field and gnark version headers +// +// This is meant to be use at the deserialization step, and will error for illegal values +func (system *System) CheckSerializationHeader() error { + // check gnark version + binaryVersion := gnark.Version + objectVersion, err := semver.Parse(system.GnarkVersion) + if err != nil { + return fmt.Errorf("when parsing gnark version: %w", err) + } + + if binaryVersion.Compare(objectVersion) != 0 { + log := logger.Logger() + log.Warn().Str("binary", binaryVersion.String()).Str("object", objectVersion.String()).Msg("gnark version (binary) mismatch with constraint system. there are no guarantees on compatibilty") + } + + // TODO @gbotrel maintain version changes and compare versions properly + // (ie if major didn't change,we shouldn't have a compatibility issue) + + scalarField := new(big.Int) + _, ok := scalarField.SetString(system.ScalarField, 16) + if !ok { + return fmt.Errorf("when parsing serialized modulus: %s", system.ScalarField) + } + curveID := utils.FieldToCurve(scalarField) + if curveID == ecc.UNKNOWN && scalarField.Cmp(tinyfield.Modulus()) != 0 { + return fmt.Errorf("unsupported scalar field %s", scalarField.Text(16)) + } + system.q = new(big.Int).Set(scalarField) + system.bitLen = system.q.BitLen() + return nil +} + +// GetNbVariables return number of internal, secret and public variables +func (system *System) GetNbVariables() (internal, secret, public int) { + return system.NbInternalVariables, system.GetNbSecretVariables(), system.GetNbPublicVariables() +} + +func (system *System) Field() *big.Int { + return new(big.Int).Set(system.q) +} + +// bitLen returns the number of bits needed to represent a fr.Element +func (system *System) FieldBitLen() int { + return system.bitLen +} + +func (system *System) AddInternalVariable() (idx int) { + idx = system.NbInternalVariables + system.GetNbPublicVariables() + system.GetNbSecretVariables() + system.NbInternalVariables++ + return idx +} + +func (system *System) AddPublicVariable(name string) (idx int) { + idx = system.GetNbPublicVariables() + system.Public = append(system.Public, name) + return idx +} + +func (system *System) AddSecretVariable(name string) (idx int) { + idx = system.GetNbSecretVariables() + system.GetNbPublicVariables() + system.Secret = append(system.Secret, name) + return idx +} + +func (system *System) AddSolverHint(f solver.Hint, input []LinearExpression, nbOutput int) (internalVariables []int, err error) { + if nbOutput <= 0 { + return nil, fmt.Errorf("hint function must return at least one output") + } + + // register the hint as dependency + hintUUID, hintID := solver.GetHintID(f), solver.GetHintName(f) + if id, ok := system.MHintsDependencies[hintUUID]; ok { + // hint already registered, let's ensure string id matches + if id != hintID { + return nil, fmt.Errorf("hint dependency registration failed; %s previously register with same UUID as %s", hintID, id) + } + } else { + system.MHintsDependencies[hintUUID] = hintID + } + + // prepare wires + internalVariables = make([]int, nbOutput) + for i := 0; i < len(internalVariables); i++ { + internalVariables[i] = system.AddInternalVariable() + } + + // associate these wires with the solver hint + hm := HintMapping{ + HintID: hintUUID, + Inputs: input, + OutputRange: struct { + Start uint32 + End uint32 + }{ + uint32(internalVariables[0]), + uint32(internalVariables[len(internalVariables)-1]) + 1, + }, + } + + instruction := system.compressHint(hm, system.genericHint) + system.Instructions = append(system.Instructions, instruction) + + system.updateLevel(len(system.Instructions)-1, &hm) + + return +} + +func (system *System) AddCommitment(c Commitment) error { + if system.CommitmentInfo.Is() { + return fmt.Errorf("currently only one commitment per circuit is supported") + } + + system.CommitmentInfo = c + + return nil +} + +func (system *System) AddLog(l LogEntry) { + system.Logs = append(system.Logs, l) +} + +func (system *System) AttachDebugInfo(debugInfo DebugInfo, constraintID []int) { + system.DebugInfo = append(system.DebugInfo, LogEntry(debugInfo)) + id := len(system.DebugInfo) - 1 + for _, cID := range constraintID { + system.MDebug[cID] = id + } +} + +// VariableToString implements Resolver +func (system *System) VariableToString(vID int) string { + nbPublic := system.GetNbPublicVariables() + nbSecret := system.GetNbSecretVariables() + + if vID < nbPublic { + return system.Public[vID] + } + vID -= nbPublic + if vID < nbSecret { + return system.Secret[vID] + } + vID -= nbSecret + return fmt.Sprintf("v%d", vID) // TODO @gbotrel vs strconv.Itoa. +} + +// GetCallData re-slice the constraint system full calldata slice with the portion +// related to the instruction. This does not copy and caller should not modify. +func (cs *System) GetCallData(instruction Instruction) []uint32 { + blueprint := cs.Blueprints[instruction.BlueprintID] + nbInputs := blueprint.NbInputs() + if nbInputs < 0 { + // by convention, we store nbInputs < 0 for non-static input length. + nbInputs = int(cs.CallData[instruction.StartCallData]) + } + return cs.CallData[instruction.StartCallData : instruction.StartCallData+uint64(nbInputs)] +} + +func (cs *System) AddR1C(c R1C, bID BlueprintID) int { + profile.RecordConstraint() + instruction := cs.compressR1C(&c, bID) + cs.Instructions = append(cs.Instructions, instruction) + + cs.updateLevel(len(cs.Instructions)-1, &c) + + return cs.NbConstraints - 1 +} + +func (cs *System) AddSparseR1C(c SparseR1C, bID BlueprintID) int { + profile.RecordConstraint() + instruction := cs.compressSparseR1C(&c, bID) + cs.Instructions = append(cs.Instructions, instruction) + + cs.updateLevel(len(cs.Instructions)-1, &c) + + return cs.NbConstraints - 1 +} + +func (cs *System) compressSparseR1C(c *SparseR1C, bID BlueprintID) Instruction { + inst := Instruction{ + StartCallData: uint64(len(cs.CallData)), + ConstraintOffset: uint32(cs.NbConstraints), + BlueprintID: bID, + } + blueprint := cs.Blueprints[bID] + calldata := blueprint.(BlueprintSparseR1C).CompressSparseR1C(c) + cs.CallData = append(cs.CallData, calldata...) + cs.NbConstraints += blueprint.NbConstraints() + return inst +} + +func (cs *System) compressR1C(c *R1C, bID BlueprintID) Instruction { + inst := Instruction{ + StartCallData: uint64(len(cs.CallData)), + ConstraintOffset: uint32(cs.NbConstraints), + BlueprintID: bID, + } + blueprint := cs.Blueprints[bID] + calldata := blueprint.(BlueprintR1C).CompressR1C(c) + cs.CallData = append(cs.CallData, calldata...) + cs.NbConstraints += blueprint.NbConstraints() + return inst +} + +func (cs *System) compressHint(hm HintMapping, bID BlueprintID) Instruction { + inst := Instruction{ + StartCallData: uint64(len(cs.CallData)), + ConstraintOffset: uint32(cs.NbConstraints), // unused. + BlueprintID: bID, + } + blueprint := cs.Blueprints[bID] + calldata := blueprint.(BlueprintHint).CompressHint(hm) + cs.CallData = append(cs.CallData, calldata...) + return inst +} + +// GetNbConstraints returns the number of constraints +func (cs *System) GetNbConstraints() int { + return cs.NbConstraints +} + +func (cs *System) CheckUnconstrainedWires() error { + // TODO @gbotrel + return nil +} + +func (cs *System) GetR1CIterator() R1CIterator { + return R1CIterator{cs: cs} +} + +func (cs *System) GetSparseR1CIterator() SparseR1CIterator { + return SparseR1CIterator{cs: cs} +} diff --git a/constraint/field.go b/constraint/field.go new file mode 100644 index 0000000000..983d7e0d10 --- /dev/null +++ b/constraint/field.go @@ -0,0 +1,29 @@ +package constraint + +import ( + "math/big" +) + +// Element represents a term coefficient data. It is instantiated by the concrete +// constraint system implementation. +// Most of the scalar field used in gnark are on 4 uint64, so we have a clear memory overhead here. +type Element [6]uint64 + +// IsZero returns true if coefficient == 0 +func (z *Element) IsZero() bool { + return (z[5] | z[4] | z[3] | z[2] | z[1] | z[0]) == 0 +} + +// Field capability to perform arithmetic on Coeff +type Field interface { + FromInterface(interface{}) Element + ToBigInt(Element) *big.Int + Mul(a, b Element) Element + Add(a, b Element) Element + Sub(a, b Element) Element + Neg(a Element) Element + Inverse(a Element) (Element, bool) + One() Element + IsOne(Element) bool + String(Element) string +} diff --git a/constraint/hint.go b/constraint/hint.go index 9085e5eb9e..e8c9f91738 100644 --- a/constraint/hint.go +++ b/constraint/hint.go @@ -1,10 +1,47 @@ package constraint -import "github.com/consensys/gnark/constraint/solver" +import ( + "github.com/consensys/gnark/constraint/solver" +) // HintMapping mark a list of output variables to be computed using provided hint and inputs. type HintMapping struct { - HintID solver.HintID // Hint function id - Inputs []LinearExpression // Terms to inject in the hint function - Outputs []int // IDs of wires the hint outputs map to + HintID solver.HintID // Hint function id + Inputs []LinearExpression // Terms to inject in the hint function + OutputRange struct { // IDs of wires the hint outputs map to + Start, End uint32 + } +} + +// WireIterator implements constraint.Iterable +// returns all the wires referenced by the hint. +func (h *HintMapping) WireIterator() func() int { + curr := 0 + n := 0 + for i := 0; i < len(h.Inputs); i++ { + n += len(h.Inputs[i]) + } + inputs := make([]int, 0, n) + for i := 0; i < len(h.Inputs); i++ { + for j := 0; j < len(h.Inputs[i]); j++ { + term := h.Inputs[i][j] + if term.IsConstant() { + continue + } + inputs = append(inputs, int(term.VID)) + } + } + lenOutputs := int(h.OutputRange.End - h.OutputRange.Start) + + return func() int { + if curr < lenOutputs { + curr++ + return int(h.OutputRange.Start) + curr - 1 + } + if curr < lenOutputs+len(inputs) { + curr++ + return inputs[curr-1-lenOutputs] + } + return -1 + } } diff --git a/constraint/level_builder.go b/constraint/level_builder.go index e558477cad..052d456809 100644 --- a/constraint/level_builder.go +++ b/constraint/level_builder.go @@ -8,12 +8,12 @@ package constraint // // We build a graph of dependency; we say that a wire is solved at a level l // --> l = max(level_of_dependencies(wire)) + 1 -func (system *System) updateLevel(cID int, c Iterable) { +func (system *System) updateLevel(iID int, c Iterable) { level := -1 wireIterator := c.WireIterator() for wID := wireIterator(); wID != -1; wID = wireIterator() { - // iterate over all wires of the R1C + // iterate over all wires of the instruction system.processWire(uint32(wID), &level) } @@ -22,18 +22,14 @@ func (system *System) updateLevel(cID int, c Iterable) { // mark output wire with level for _, wireID := range system.lbOutputs { - for int(wireID) >= len(system.lbWireLevel) { - // we didn't encounter this wire yet, we need to grow b.wireLevels - system.lbWireLevel = append(system.lbWireLevel, -1) - } system.lbWireLevel[wireID] = level } // we can't skip levels, so appending is fine. if level >= len(system.Levels) { - system.Levels = append(system.Levels, []int{cID}) + system.Levels = append(system.Levels, []int{iID}) } else { - system.Levels[level] = append(system.Levels[level], cID) + system.Levels[level] = append(system.Levels[level], iID) } // clean the table. NB! Do not remove or move, this is required to make the // compilation deterministic. @@ -56,33 +52,6 @@ func (system *System) processWire(wireID uint32, maxLevel *int) { } return } - // we don't know how to solve this wire; it's either THE wire we have to solve or a hint. - if hID, ok := system.MHints[int(wireID)]; ok { - // check that we didn't process that hint already; performance wise, if many wires in a - // constraint are the output of the same hint, and input to parent hint are themselves - // computed with a hint, we can suffer. - // (nominal case: not too many different hints involved for a single constraint) - if _, ok := system.lbHints[hID]; ok { - // skip - return - } - system.lbHints[hID] = struct{}{} - h := &system.HintMappings[hID] - - for _, hwid := range h.Outputs { - system.lbOutputs = append(system.lbOutputs, uint32(hwid)) - } - for _, in := range h.Inputs { - for _, t := range in { - if !t.IsConstant() { - system.processWire(t.VID, maxLevel) - } - } - } - - return - } - - // it's the missing wire + // this wire is an output to the instruction system.lbOutputs = append(system.lbOutputs, wireID) } diff --git a/constraint/r1cs.go b/constraint/r1cs.go index 02c327e30e..49556c9bc8 100644 --- a/constraint/r1cs.go +++ b/constraint/r1cs.go @@ -14,136 +14,138 @@ package constraint -import ( - "errors" - "strconv" - "strings" - - "github.com/consensys/gnark/logger" -) - type R1CS interface { ConstraintSystem - // AddConstraint adds a constraint to the system and returns its id + // AddR1C adds a constraint to the system and returns its id // This does not check for validity of the constraint. - // If a debugInfo parameter is provided, it will be appended to the debug info structure - // and will grow the memory usage of the constraint system. - AddConstraint(r1c R1C, debugInfo ...DebugInfo) int + AddR1C(r1c R1C, bID BlueprintID) int - // GetConstraints return the list of R1C and a helper for pretty printing. + // GetR1Cs return the list of R1C // See StringBuilder for more info. // ! this is an experimental API. - GetConstraints() ([]R1C, Resolver) -} + GetR1Cs() []R1C -// R1CS describes a set of R1C constraint -type R1CSCore struct { - System - Constraints []R1C + // GetR1CIterator returns an R1CIterator to iterate on the R1C constraints of the system. + GetR1CIterator() R1CIterator } -// GetNbConstraints returns the number of constraints -func (r1cs *R1CSCore) GetNbConstraints() int { - return len(r1cs.Constraints) +// R1CIterator facilitates iterating through R1C constraints. +type R1CIterator struct { + R1C + cs *System + n int } -func (r1cs *R1CSCore) UpdateLevel(cID int, c Iterable) { - r1cs.updateLevel(cID, c) -} - -// IsValid perform post compilation checks on the Variables -// -// 1. checks that all user inputs are referenced in at least one constraint -// 2. checks that all hints are constrained -func (r1cs *R1CSCore) CheckUnconstrainedWires() error { - - // TODO @gbotrel add unit test for that. - - inputConstrained := make([]bool, r1cs.GetNbSecretVariables()+r1cs.GetNbPublicVariables()) - // one wire does not need to be constrained - inputConstrained[0] = true - cptInputs := len(inputConstrained) - 1 // marking 1 wire as already constrained // TODO @gbotrel check that - if cptInputs == 0 { - return errors.New("invalid constraint system: no input defined") - } - - cptHints := len(r1cs.MHints) - mHintsConstrained := make(map[int]bool) - - // for each constraint, we check the linear expressions and mark our inputs / hints as constrained - processLinearExpression := func(l LinearExpression) { - for _, t := range l { - if t.CoeffID() == CoeffIdZero { - // ignore zero coefficient, as it does not constraint the Variable - // though, we may want to flag that IF the Variable doesn't appear else where - continue - } - vID := t.WireID() - if vID < len(inputConstrained) { - if !inputConstrained[vID] { - inputConstrained[vID] = true - cptInputs-- - } - } else { - // internal variable, let's check if it's a hint - if _, ok := r1cs.MHints[vID]; ok { - if !mHintsConstrained[vID] { - mHintsConstrained[vID] = true - cptHints-- - } - } - } - - } - } - for _, r1c := range r1cs.Constraints { - processLinearExpression(r1c.L) - processLinearExpression(r1c.R) - processLinearExpression(r1c.O) - - if cptHints|cptInputs == 0 { - return nil // we can stop. - } - - } - - // something is a miss, we build the error string - var sbb strings.Builder - if cptInputs != 0 { - sbb.WriteString(strconv.Itoa(cptInputs)) - sbb.WriteString(" unconstrained input(s):") - sbb.WriteByte('\n') - for i := 0; i < len(inputConstrained) && cptInputs != 0; i++ { - if !inputConstrained[i] { - if i < len(r1cs.Public) { - sbb.WriteString(r1cs.Public[i]) - } else { - sbb.WriteString(r1cs.Secret[i-len(r1cs.Public)]) - } - - sbb.WriteByte('\n') - cptInputs-- - } - } - sbb.WriteByte('\n') - return errors.New(sbb.String()) - } - - if cptHints != 0 { - // TODO @gbotrel @ivokub investigate --> emulated hints seems to go in this path a lot. - sbb.WriteString(strconv.Itoa(cptHints)) - sbb.WriteString(" unconstrained hints; i.e. wire created through NewHint() but doesn't not appear in the constraint system") - sbb.WriteByte('\n') - log := logger.Logger() - log.Warn().Err(errors.New(sbb.String())).Send() +// Next returns the next R1C or nil if end. Caller must not store the result since the +// same memory space is re-used for subsequent calls to Next. +func (it *R1CIterator) Next() *R1C { + if it.n >= it.cs.GetNbInstructions() { return nil - // TODO we may add more debug info here → idea, in NewHint, take the debug stack, and store in the hint map some - // debugInfo to find where a hint was declared (and not constrained) } - return errors.New(sbb.String()) + inst := it.cs.Instructions[it.n] + it.n++ + blueprint := it.cs.Blueprints[inst.BlueprintID] + if bc, ok := blueprint.(BlueprintR1C); ok { + bc.DecompressR1C(&it.R1C, it.cs.GetCallData(inst)) + return &it.R1C + } + return it.Next() } +// // IsValid perform post compilation checks on the Variables +// // +// // 1. checks that all user inputs are referenced in at least one constraint +// // 2. checks that all hints are constrained +// func (r1cs *R1CSCore) CheckUnconstrainedWires() error { +// return nil + +// // TODO @gbotrel add unit test for that. + +// inputConstrained := make([]bool, r1cs.GetNbSecretVariables()+r1cs.GetNbPublicVariables()) +// // one wire does not need to be constrained +// inputConstrained[0] = true +// cptInputs := len(inputConstrained) - 1 // marking 1 wire as already constrained // TODO @gbotrel check that +// if cptInputs == 0 { +// return errors.New("invalid constraint system: no input defined") +// } + +// cptHints := len(r1cs.MHints) +// mHintsConstrained := make(map[int]bool) + +// // for each constraint, we check the linear expressions and mark our inputs / hints as constrained +// processLinearExpression := func(l LinearExpression) { +// for _, t := range l { +// if t.CoeffID() == CoeffIdZero { +// // ignore zero coefficient, as it does not constraint the Variable +// // though, we may want to flag that IF the Variable doesn't appear else where +// continue +// } +// vID := t.WireID() +// if vID < len(inputConstrained) { +// if !inputConstrained[vID] { +// inputConstrained[vID] = true +// cptInputs-- +// } +// } else { +// // internal variable, let's check if it's a hint +// if _, ok := r1cs.MHints[vID]; ok { +// if !mHintsConstrained[vID] { +// mHintsConstrained[vID] = true +// cptHints-- +// } +// } +// } + +// } +// } +// for _, r1c := range r1cs.Constraints { +// processLinearExpression(r1c.L) +// processLinearExpression(r1c.R) +// processLinearExpression(r1c.O) + +// if cptHints|cptInputs == 0 { +// return nil // we can stop. +// } + +// } + +// // something is a miss, we build the error string +// var sbb strings.Builder +// if cptInputs != 0 { +// sbb.WriteString(strconv.Itoa(cptInputs)) +// sbb.WriteString(" unconstrained input(s):") +// sbb.WriteByte('\n') +// for i := 0; i < len(inputConstrained) && cptInputs != 0; i++ { +// if !inputConstrained[i] { +// if i < len(r1cs.Public) { +// sbb.WriteString(r1cs.Public[i]) +// } else { +// sbb.WriteString(r1cs.Secret[i-len(r1cs.Public)]) +// } + +// sbb.WriteByte('\n') +// cptInputs-- +// } +// } +// sbb.WriteByte('\n') +// return errors.New(sbb.String()) +// } + +// if cptHints != 0 { +// // TODO @gbotrel @ivokub investigate --> emulated hints seems to go in this path a lot. +// sbb.WriteString(strconv.Itoa(cptHints)) +// sbb.WriteString(" unconstrained hints; i.e. wire created through NewHint() but doesn't not appear in the constraint system") +// sbb.WriteByte('\n') +// log := logger.Logger() +// log.Warn().Err(errors.New(sbb.String())).Send() +// return nil +// // TODO we may add more debug info here → idea, in NewHint, take the debug stack, and store in the hint map some +// // debugInfo to find where a hint was declared (and not constrained) +// } +// return errors.New(sbb.String()) +// } + // R1C used to compute the wires type R1C struct { L, R, O LinearExpression diff --git a/constraint/r1cs_sparse.go b/constraint/r1cs_sparse.go index fab491c488..ea5af900f3 100644 --- a/constraint/r1cs_sparse.go +++ b/constraint/r1cs_sparse.go @@ -14,129 +14,123 @@ package constraint -import ( - "errors" - "strconv" - "strings" -) - type SparseR1CS interface { ConstraintSystem - // AddConstraint adds a constraint to the sytem and returns its id - // This does not check for validity of the constraint. - // If a debugInfo parameter is provided, it will be appended to the debug info structure - // and will grow the memory usage of the constraint system. - AddConstraint(c SparseR1C, debugInfo ...DebugInfo) int - - // GetConstraint return a pointer to the constraint at index i, or nil if out of bounds. - GetConstraint(i int) *SparseR1C + // AddSparseR1C adds a constraint to the constraint system. + AddSparseR1C(c SparseR1C, bID BlueprintID) int - // GetCoefficient returns coefficient with given id in the coeff table. - // calls panic if i is out of bounds, because this is called in the hot path of the compiler. - GetCoefficient(i int) Coeff - - // GetConstraints return the list of SparseR1C and a helper for pretty printing. + // GetSparseR1Cs return the list of SparseR1C // See StringBuilder for more info. // ! this is an experimental API. - GetConstraints() ([]SparseR1C, Resolver) -} + GetSparseR1Cs() []SparseR1C -// R1CS describes a set of SparseR1C constraint -// TODO @gbotrel maybe SparseR1CSCore and R1CSCore should go in code generation directly to avoid confusing this package. -type SparseR1CSCore struct { - System - Constraints []SparseR1C + // GetSparseR1CIterator returns an SparseR1CIterator to iterate on the SparseR1C constraints of the system. + GetSparseR1CIterator() SparseR1CIterator } -// GetNbConstraints returns the number of constraints -func (cs *SparseR1CSCore) GetNbConstraints() int { - return len(cs.Constraints) +// SparseR1CIterator facilitates iterating through SparseR1C constraints. +type SparseR1CIterator struct { + SparseR1C + cs *System + n int } -func (cs *SparseR1CSCore) UpdateLevel(cID int, c Iterable) { - cs.updateLevel(cID, c) -} - -func (system *SparseR1CSCore) CheckUnconstrainedWires() error { - // TODO @gbotrel add unit test for that. - - inputConstrained := make([]bool, system.GetNbSecretVariables()+system.GetNbPublicVariables()) - cptInputs := len(inputConstrained) - if cptInputs == 0 { - return errors.New("invalid constraint system: no input defined") +// Next returns the next SparseR1C or nil if end. Caller must not store the result since the +// same memory space is re-used for subsequent calls to Next. +func (it *SparseR1CIterator) Next() *SparseR1C { + if it.n >= it.cs.GetNbInstructions() { + return nil } - - cptHints := len(system.MHints) - mHintsConstrained := make(map[int]bool) - - // for each constraint, we check the terms and mark our inputs / hints as constrained - processTerm := func(t Term) { - - // L and M[0] handles the same wire but with a different coeff - vID := t.WireID() - if t.CoeffID() != CoeffIdZero { - if vID < len(inputConstrained) { - if !inputConstrained[vID] { - inputConstrained[vID] = true - cptInputs-- - } - } else { - // internal variable, let's check if it's a hint - if _, ok := system.MHints[vID]; ok { - vID -= (system.GetNbPublicVariables() + system.GetNbSecretVariables()) - if !mHintsConstrained[vID] { - mHintsConstrained[vID] = true - cptHints-- - } - } - } - } - + inst := it.cs.Instructions[it.n] + it.n++ + blueprint := it.cs.Blueprints[inst.BlueprintID] + if bc, ok := blueprint.(BlueprintSparseR1C); ok { + bc.DecompressSparseR1C(&it.SparseR1C, it.cs.GetCallData(inst)) + return &it.SparseR1C } - for _, c := range system.Constraints { - processTerm(c.L) - processTerm(c.R) - processTerm(c.M[0]) - processTerm(c.M[1]) - processTerm(c.O) - if cptHints|cptInputs == 0 { - return nil // we can stop. - } - - } - - // something is a miss, we build the error string - var sbb strings.Builder - if cptInputs != 0 { - sbb.WriteString(strconv.Itoa(cptInputs)) - sbb.WriteString(" unconstrained input(s):") - sbb.WriteByte('\n') - for i := 0; i < len(inputConstrained) && cptInputs != 0; i++ { - if !inputConstrained[i] { - if i < len(system.Public) { - sbb.WriteString(system.Public[i]) - } else { - sbb.WriteString(system.Secret[i-len(system.Public)]) - } - sbb.WriteByte('\n') - cptInputs-- - } - } - sbb.WriteByte('\n') - } - - if cptHints != 0 { - sbb.WriteString(strconv.Itoa(cptHints)) - sbb.WriteString(" unconstrained hints") - sbb.WriteByte('\n') - // TODO we may add more debug info here → idea, in NewHint, take the debug stack, and store in the hint map some - // debugInfo to find where a hint was declared (and not constrained) - } - return errors.New(sbb.String()) + return it.Next() } -type CommitmentConstraint byte +// func (system *SparseR1CSCore) CheckUnconstrainedWires() error { +// // TODO @gbotrel add unit test for that. +// return nil +// inputConstrained := make([]bool, system.GetNbSecretVariables()+system.GetNbPublicVariables()) +// cptInputs := len(inputConstrained) +// if cptInputs == 0 { +// return errors.New("invalid constraint system: no input defined") +// } + +// cptHints := len(system.MHints) +// mHintsConstrained := make(map[int]bool) + +// // for each constraint, we check the terms and mark our inputs / hints as constrained +// processTerm := func(t Term) { + +// // L and M[0] handles the same wire but with a different coeff +// vID := t.WireID() +// if t.CoeffID() != CoeffIdZero { +// if vID < len(inputConstrained) { +// if !inputConstrained[vID] { +// inputConstrained[vID] = true +// cptInputs-- +// } +// } else { +// // internal variable, let's check if it's a hint +// if _, ok := system.MHints[vID]; ok { +// vID -= (system.GetNbPublicVariables() + system.GetNbSecretVariables()) +// if !mHintsConstrained[vID] { +// mHintsConstrained[vID] = true +// cptHints-- +// } +// } +// } +// } + +// } +// for _, c := range system.Constraints { +// processTerm(c.L) +// processTerm(c.R) +// processTerm(c.M[0]) +// processTerm(c.M[1]) +// processTerm(c.O) +// if cptHints|cptInputs == 0 { +// return nil // we can stop. +// } + +// } + +// // something is a miss, we build the error string +// var sbb strings.Builder +// if cptInputs != 0 { +// sbb.WriteString(strconv.Itoa(cptInputs)) +// sbb.WriteString(" unconstrained input(s):") +// sbb.WriteByte('\n') +// for i := 0; i < len(inputConstrained) && cptInputs != 0; i++ { +// if !inputConstrained[i] { +// if i < len(system.Public) { +// sbb.WriteString(system.Public[i]) +// } else { +// sbb.WriteString(system.Secret[i-len(system.Public)]) +// } +// sbb.WriteByte('\n') +// cptInputs-- +// } +// } +// sbb.WriteByte('\n') +// } + +// if cptHints != 0 { +// sbb.WriteString(strconv.Itoa(cptHints)) +// sbb.WriteString(" unconstrained hints") +// sbb.WriteByte('\n') +// // TODO we may add more debug info here → idea, in NewHint, take the debug stack, and store in the hint map some +// // debugInfo to find where a hint was declared (and not constrained) +// } +// return errors.New(sbb.String()) +// } + +type CommitmentConstraint uint32 const ( NOT CommitmentConstraint = 0 @@ -144,14 +138,16 @@ const ( COMMITMENT CommitmentConstraint = 2 ) -// SparseR1C used to compute the wires -// L+R+M[0]M[1]+O+k-committed?*PI2-commitment?*commitmentValue=0 -// if a Term is zero, it means the field doesn't exist (ex M=[0,0] means there is no multiplicative term) +// SparseR1C represent a PlonK-ish constraint +// qL⋅xa + qR⋅xb + qO⋅xc + qM⋅(xaxb) + qC -committed?*PI2-commitment?*commitmentValue == 0 type SparseR1C struct { - L, R, O Term - M [2]Term - K int // stores only the ID of the constant term that is used - Commitment CommitmentConstraint + XA, XB, XC uint32 + QL, QR, QO, QM, QC uint32 + Commitment CommitmentConstraint +} + +func (c *SparseR1C) Clear() { + *c = SparseR1C{} } // WireIterator implements constraint.Iterable @@ -161,13 +157,13 @@ func (c *SparseR1C) WireIterator() func() int { switch curr { case 0: curr++ - return c.L.WireID() + return int(c.XA) case 1: curr++ - return c.R.WireID() + return int(c.XB) case 2: curr++ - return c.O.WireID() + return int(c.XC) } return -1 } @@ -176,14 +172,14 @@ func (c *SparseR1C) WireIterator() func() int { // String formats the constraint as qL⋅xa + qR⋅xb + qO⋅xc + qM⋅(xaxb) + qC == 0 func (c *SparseR1C) String(r Resolver) string { sbb := NewStringBuilder(r) - sbb.WriteTerm(c.L) + sbb.WriteTerm(Term{CID: c.QL, VID: c.XA}) sbb.WriteString(" + ") - sbb.WriteTerm(c.R) + sbb.WriteTerm(Term{CID: c.QR, VID: c.XB}) sbb.WriteString(" + ") - sbb.WriteTerm(c.O) - if qM := sbb.CoeffToString(c.M[0].CoeffID()); qM != "0" { - xa := sbb.VariableToString(c.M[0].WireID()) - xb := sbb.VariableToString(c.M[1].WireID()) + sbb.WriteTerm(Term{CID: c.QO, VID: c.XC}) + if qM := sbb.CoeffToString(int(c.QM)); qM != "0" { + xa := sbb.VariableToString(int(c.XA)) + xb := sbb.VariableToString(int(c.XB)) sbb.WriteString(" + ") sbb.WriteString(qM) sbb.WriteString("⋅(") @@ -193,7 +189,7 @@ func (c *SparseR1C) String(r Resolver) string { sbb.WriteByte(')') } sbb.WriteString(" + ") - sbb.WriteString(r.CoeffToString(c.K)) + sbb.WriteString(r.CoeffToString(int(c.QC))) sbb.WriteString(" == 0") return sbb.String() } diff --git a/constraint/r1cs_sparse_test.go b/constraint/r1cs_sparse_test.go index 024560ff93..5a0bfd647c 100644 --- a/constraint/r1cs_sparse_test.go +++ b/constraint/r1cs_sparse_test.go @@ -7,12 +7,13 @@ import ( cs "github.com/consensys/gnark/constraint/bn254" ) -func ExampleSparseR1CS_GetConstraints() { +func ExampleSparseR1CS_GetSparseR1Cs() { // build a constraint system; this is (usually) done by the frontend package // for this Example we want to manipulate the constraints and output a string representation // and build the linear expressions "manually". // note: R1CS apis are more mature; SparseR1CS apis are going to change in the next release(s). scs := cs.NewSparseR1CS(0) + blueprint := scs.AddBlueprint(&constraint.BlueprintGenericSparseR1C{}) Y := scs.AddPublicVariable("Y") X := scs.AddSecretVariable("X") @@ -20,40 +21,34 @@ func ExampleSparseR1CS_GetConstraints() { v0 := scs.AddInternalVariable() // X² // coefficients - cZero := scs.FromInterface(0) cOne := scs.FromInterface(1) - cMinusOne := scs.FromInterface(-1) cFive := scs.FromInterface(5) // X² == X * X - scs.AddConstraint(constraint.SparseR1C{ - L: scs.MakeTerm(&cZero, X), - R: scs.MakeTerm(&cZero, X), - O: scs.MakeTerm(&cMinusOne, v0), - M: [2]constraint.Term{ - scs.MakeTerm(&cOne, X), - scs.MakeTerm(&cOne, X), - }, - K: int(scs.MakeTerm(&cZero, 0).CID), - }) + scs.AddSparseR1C(constraint.SparseR1C{ + XA: uint32(X), + XB: uint32(X), + XC: uint32(v0), + QO: constraint.CoeffIdMinusOne, + QM: constraint.CoeffIdOne, + }, blueprint) // X² + 5X + 5 == Y - scs.AddConstraint(constraint.SparseR1C{ - R: scs.MakeTerm(&cOne, v0), - L: scs.MakeTerm(&cFive, X), - O: scs.MakeTerm(&cMinusOne, Y), - M: [2]constraint.Term{ - scs.MakeTerm(&cZero, v0), - scs.MakeTerm(&cZero, X), - }, - K: int(scs.MakeTerm(&cFive, 0).CID), - }) + scs.AddSparseR1C(constraint.SparseR1C{ + XA: uint32(X), + XB: uint32(v0), + XC: uint32(Y), + QO: constraint.CoeffIdMinusOne, + QL: scs.AddCoeff(cFive), + QR: scs.AddCoeff(cOne), + QC: scs.AddCoeff(cFive), + }, blueprint) // get the constraints - constraints, r := scs.GetConstraints() + constraints := scs.GetSparseR1Cs() for _, c := range constraints { - fmt.Println(c.String(r)) + fmt.Println(c.String(scs)) // for more granularity use constraint.NewStringBuilder(r) that embeds a string.Builder // and has WriteLinearExpression and WriteTerm methods. } diff --git a/constraint/r1cs_test.go b/constraint/r1cs_test.go index aa2c06fe27..4a82ca79d5 100644 --- a/constraint/r1cs_test.go +++ b/constraint/r1cs_test.go @@ -10,12 +10,14 @@ import ( "github.com/consensys/gnark/frontend/cs/r1cs" ) -func ExampleR1CS_GetConstraints() { +func ExampleR1CS_GetR1Cs() { // build a constraint system; this is (usually) done by the frontend package // for this Example we want to manipulate the constraints and output a string representation // and build the linear expressions "manually". r1cs := cs.NewR1CS(0) + blueprint := r1cs.AddBlueprint(&constraint.BlueprintGenericR1C{}) + ONE := r1cs.AddPublicVariable("1") // the "ONE" wire Y := r1cs.AddPublicVariable("Y") X := r1cs.AddSecretVariable("X") @@ -28,21 +30,21 @@ func ExampleR1CS_GetConstraints() { cFive := r1cs.FromInterface(5) // X² == X * X - r1cs.AddConstraint(constraint.R1C{ + r1cs.AddR1C(constraint.R1C{ L: constraint.LinearExpression{r1cs.MakeTerm(&cOne, X)}, R: constraint.LinearExpression{r1cs.MakeTerm(&cOne, X)}, O: constraint.LinearExpression{r1cs.MakeTerm(&cOne, v0)}, - }) + }, blueprint) // X³ == X² * X - r1cs.AddConstraint(constraint.R1C{ + r1cs.AddR1C(constraint.R1C{ L: constraint.LinearExpression{r1cs.MakeTerm(&cOne, v0)}, R: constraint.LinearExpression{r1cs.MakeTerm(&cOne, X)}, O: constraint.LinearExpression{r1cs.MakeTerm(&cOne, v1)}, - }) + }, blueprint) // Y == X³ + X + 5 - r1cs.AddConstraint(constraint.R1C{ + r1cs.AddR1C(constraint.R1C{ R: constraint.LinearExpression{r1cs.MakeTerm(&cOne, ONE)}, L: constraint.LinearExpression{r1cs.MakeTerm(&cOne, Y)}, O: constraint.LinearExpression{ @@ -50,13 +52,13 @@ func ExampleR1CS_GetConstraints() { r1cs.MakeTerm(&cOne, X), r1cs.MakeTerm(&cOne, v1), }, - }) + }, blueprint) // get the constraints - constraints, r := r1cs.GetConstraints() + constraints := r1cs.GetR1Cs() for _, r1c := range constraints { - fmt.Println(r1c.String(r)) + fmt.Println(r1c.String(r1cs)) // for more granularity use constraint.NewStringBuilder(r) that embeds a string.Builder // and has WriteLinearExpression and WriteTerm methods. } diff --git a/constraint/system.go b/constraint/system.go index 2b3ada4a60..fae9782eb9 100644 --- a/constraint/system.go +++ b/constraint/system.go @@ -1,26 +1,19 @@ package constraint import ( - "fmt" "io" "math/big" - "github.com/blang/semver/v4" - "github.com/consensys/gnark" - "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/debug" - "github.com/consensys/gnark/internal/tinyfield" - "github.com/consensys/gnark/internal/utils" - "github.com/consensys/gnark/logger" ) // ConstraintSystem interface that all constraint systems implement. type ConstraintSystem interface { io.WriterTo io.ReaderFrom - CoeffEngine + Field + Resolver // IsSolved returns nil if given witness solves the constraint system and error otherwise // Deprecated: use _, err := Solve(...) instead @@ -39,6 +32,7 @@ type ConstraintSystem interface { GetNbSecretVariables() int GetNbPublicVariables() int + GetNbInstructions() int GetNbConstraints() int GetNbCoefficients() int @@ -59,18 +53,33 @@ type ConstraintSystem interface { // MakeTerm returns a new Term. The constraint system may store coefficients in a map, so // calls to this function will grow the memory usage of the constraint system. - MakeTerm(coeff *Coeff, variableID int) Term + MakeTerm(coeff *Element, variableID int) Term + + // AddCoeff adds a coefficient to the underlying constraint system. The system will not store duplicate, + // but is not purging for unused coeff either, so this grows memory usage. + AddCoeff(coeff Element) uint32 NewDebugInfo(errName string, i ...interface{}) DebugInfo // AttachDebugInfo enables attaching debug information to multiple constraints. - // This is more efficient than using the AddConstraint(.., debugInfo) since it will store the + // This is more efficient than using the AddR1C(.., debugInfo) since it will store the // debug information only once. AttachDebugInfo(debugInfo DebugInfo, constraintID []int) // CheckUnconstrainedWires returns and error if the constraint system has wires that are not uniquely constrained. // This is experimental. CheckUnconstrainedWires() error + + // AddBlueprint registers the given blueprint and returns its id. This should be called only once per blueprint. + AddBlueprint(b Blueprint) BlueprintID + + GetInstruction(int) Instruction + + GetCoefficient(i int) Element + + // GetCallData re-slice the constraint system full calldata slice with the portion + // related to the instruction. This does not copy and caller should not modify. + GetCallData(instruction Instruction) []uint32 } type Iterable interface { @@ -86,211 +95,3 @@ type Iterable interface { var _ Iterable = &SparseR1C{} var _ Iterable = &R1C{} - -// System contains core elements for a constraint System -type System struct { - // serialization header - GnarkVersion string - ScalarField string - - // number of internal wires - NbInternalVariables int - - // input wires names - Public, Secret []string - - // logs (added with system.Println, resolved when solver sets a value to a wire) - Logs []LogEntry - - // debug info contains stack trace (including line number) of a call to a system.API that - // results in an unsolved constraint - DebugInfo []LogEntry - SymbolTable debug.SymbolTable - // maps constraint id to debugInfo id - // several constraints may point to the same debug info - MDebug map[int]int - - HintMappings []HintMapping - MHints map[int]int // maps wireID to hint - MHintsDependencies map[solver.HintID]string // maps hintID to hint string identifier - - // each level contains independent constraints and can be parallelized - // it is guaranteed that all dependencies for constraints in a level l are solved - // in previous levels - // TODO @gbotrel these are currently updated after we add a constraint. - // but in case the object is built from a serialized representation - // we need to init the level builder lbWireLevel from the existing constraints. - Levels [][]int - - // scalar field - q *big.Int `cbor:"-"` - bitLen int `cbor:"-"` - - // level builder - lbWireLevel []int `cbor:"-"` // at which level we solve a wire. init at -1. - lbOutputs []uint32 `cbor:"-"` // wire outputs for current constraint. - lbHints map[int]struct{} `cbor:"-"` // hints we processed in current round - - CommitmentInfo Commitment -} - -// NewSystem initialize the common structure among constraint system -func NewSystem(scalarField *big.Int) System { - return System{ - SymbolTable: debug.NewSymbolTable(), - MDebug: map[int]int{}, - GnarkVersion: gnark.Version.String(), - ScalarField: scalarField.Text(16), - MHints: make(map[int]int), - MHintsDependencies: make(map[solver.HintID]string), - q: new(big.Int).Set(scalarField), - bitLen: scalarField.BitLen(), - lbHints: map[int]struct{}{}, - } -} - -func (system *System) GetNbSecretVariables() int { - return len(system.Secret) -} -func (system *System) GetNbPublicVariables() int { - return len(system.Public) -} -func (system *System) GetNbInternalVariables() int { - return system.NbInternalVariables -} - -// CheckSerializationHeader parses the scalar field and gnark version headers -// -// This is meant to be use at the deserialization step, and will error for illegal values -func (system *System) CheckSerializationHeader() error { - // check gnark version - binaryVersion := gnark.Version - objectVersion, err := semver.Parse(system.GnarkVersion) - if err != nil { - return fmt.Errorf("when parsing gnark version: %w", err) - } - - if binaryVersion.Compare(objectVersion) != 0 { - log := logger.Logger() - log.Warn().Str("binary", binaryVersion.String()).Str("object", objectVersion.String()).Msg("gnark version (binary) mismatch with constraint system. there are no guarantees on compatibilty") - } - - // TODO @gbotrel maintain version changes and compare versions properly - // (ie if major didn't change,we shouldn't have a compatibility issue) - - scalarField := new(big.Int) - _, ok := scalarField.SetString(system.ScalarField, 16) - if !ok { - return fmt.Errorf("when parsing serialized modulus: %s", system.ScalarField) - } - curveID := utils.FieldToCurve(scalarField) - if curveID == ecc.UNKNOWN && scalarField.Cmp(tinyfield.Modulus()) != 0 { - return fmt.Errorf("unsupported scalar field %s", scalarField.Text(16)) - } - system.q = new(big.Int).Set(scalarField) - system.bitLen = system.q.BitLen() - return nil -} - -// GetNbVariables return number of internal, secret and public variables -func (system *System) GetNbVariables() (internal, secret, public int) { - return system.NbInternalVariables, system.GetNbSecretVariables(), system.GetNbPublicVariables() -} - -func (system *System) Field() *big.Int { - return new(big.Int).Set(system.q) -} - -// bitLen returns the number of bits needed to represent a fr.Element -func (system *System) FieldBitLen() int { - return system.bitLen -} - -func (system *System) AddInternalVariable() (idx int) { - idx = system.NbInternalVariables + system.GetNbPublicVariables() + system.GetNbSecretVariables() - system.NbInternalVariables++ - return idx -} - -func (system *System) AddPublicVariable(name string) (idx int) { - idx = system.GetNbPublicVariables() - system.Public = append(system.Public, name) - return idx -} - -func (system *System) AddSecretVariable(name string) (idx int) { - idx = system.GetNbSecretVariables() + system.GetNbPublicVariables() - system.Secret = append(system.Secret, name) - return idx -} - -func (system *System) AddSolverHint(f solver.Hint, input []LinearExpression, nbOutput int) (internalVariables []int, err error) { - if nbOutput <= 0 { - return nil, fmt.Errorf("hint function must return at least one output") - } - - // register the hint as dependency - hintUUID, hintID := solver.GetHintID(f), solver.GetHintName(f) - if id, ok := system.MHintsDependencies[hintUUID]; ok { - // hint already registered, let's ensure string id matches - if id != hintID { - return nil, fmt.Errorf("hint dependency registration failed; %s previously register with same UUID as %s", hintID, id) - } - } else { - system.MHintsDependencies[hintUUID] = hintID - } - - // prepare wires - internalVariables = make([]int, nbOutput) - for i := 0; i < len(internalVariables); i++ { - internalVariables[i] = system.AddInternalVariable() - } - - // associate these wires with the solver hint - hm := HintMapping{HintID: hintUUID, Inputs: input, Outputs: internalVariables} - system.HintMappings = append(system.HintMappings, hm) - n := len(system.HintMappings) - 1 - for _, vID := range internalVariables { - system.MHints[vID] = n - } - - return -} - -func (system *System) AddCommitment(c Commitment) error { - if system.CommitmentInfo.Is() { - return fmt.Errorf("currently only one commitment per circuit is supported") - } - - system.CommitmentInfo = c - - return nil -} - -func (system *System) AddLog(l LogEntry) { - system.Logs = append(system.Logs, l) -} - -func (system *System) AttachDebugInfo(debugInfo DebugInfo, constraintID []int) { - system.DebugInfo = append(system.DebugInfo, LogEntry(debugInfo)) - id := len(system.DebugInfo) - 1 - for _, cID := range constraintID { - system.MDebug[cID] = id - } -} - -// VariableToString implements Resolver -func (system *System) VariableToString(vID int) string { - nbPublic := system.GetNbPublicVariables() - nbSecret := system.GetNbSecretVariables() - - if vID < nbPublic { - return system.Public[vID] - } - vID -= nbPublic - if vID < nbSecret { - return system.Secret[vID] - } - vID -= nbSecret - return fmt.Sprintf("v%d", vID) // TODO @gbotrel vs strconv.Itoa. -} diff --git a/constraint/term.go b/constraint/term.go index 182329e576..de1c37879e 100644 --- a/constraint/term.go +++ b/constraint/term.go @@ -18,6 +18,15 @@ import ( "math" ) +// ids of the coefficients with simple values in any cs.coeffs slice. +const ( + CoeffIdZero = iota + CoeffIdOne + CoeffIdTwo + CoeffIdMinusOne + CoeffIdMinusTwo +) + // Term represents a coeff * variable in a constraint system type Term struct { CID, VID uint32 diff --git a/constraint/tinyfield/coeff.go b/constraint/tinyfield/coeff.go index 3bd799d820..f81f7b969f 100644 --- a/constraint/tinyfield/coeff.go +++ b/constraint/tinyfield/coeff.go @@ -46,7 +46,7 @@ func newCoeffTable(capacity int) CoeffTable { } -func (ct *CoeffTable) MakeTerm(coeff *constraint.Coeff, variableID int) constraint.Term { +func (ct *CoeffTable) AddCoeff(coeff constraint.Element) uint32 { c := (*fr.Element)(coeff[:]) var cID uint32 if c.IsZero() { @@ -69,7 +69,11 @@ func (ct *CoeffTable) MakeTerm(coeff *constraint.Coeff, variableID int) constrai ct.mCoeffs[cc] = cID } } + return cID +} +func (ct *CoeffTable) MakeTerm(coeff *constraint.Element, variableID int) constraint.Term { + cID := ct.AddCoeff(*coeff) return constraint.Term{VID: uint32(variableID), CID: cID} } @@ -78,7 +82,10 @@ func (ct *CoeffTable) CoeffToString(cID int) string { return ct.Coefficients[cID].String() } -var _ constraint.CoeffEngine = &arithEngine{} +// implements constraint.Field +type field struct{} + +var _ constraint.Field = &field{} var ( two fr.Element @@ -94,10 +101,7 @@ func init() { minusTwo.Neg(&two) } -// implements constraint.CoeffEngine -type arithEngine struct{} - -func (engine *arithEngine) FromInterface(i interface{}) constraint.Coeff { +func (engine *field) FromInterface(i interface{}) constraint.Element { var e fr.Element if _, err := e.SetInterface(i); err != nil { // need to clean that --> some code path are dissimilar @@ -106,55 +110,75 @@ func (engine *arithEngine) FromInterface(i interface{}) constraint.Coeff { b := utils.FromInterface(i) e.SetBigInt(&b) } - var r constraint.Coeff + var r constraint.Element copy(r[:], e[:]) return r } -func (engine *arithEngine) ToBigInt(c *constraint.Coeff) *big.Int { +func (engine *field) ToBigInt(c constraint.Element) *big.Int { e := (*fr.Element)(c[:]) r := new(big.Int) e.BigInt(r) return r } -func (engine *arithEngine) Mul(a, b *constraint.Coeff) { +func (engine *field) Mul(a, b constraint.Element) constraint.Element { _a := (*fr.Element)(a[:]) _b := (*fr.Element)(b[:]) _a.Mul(_a, _b) + return a } -func (engine *arithEngine) Add(a, b *constraint.Coeff) { + +func (engine *field) Add(a, b constraint.Element) constraint.Element { _a := (*fr.Element)(a[:]) _b := (*fr.Element)(b[:]) _a.Add(_a, _b) + return a } -func (engine *arithEngine) Sub(a, b *constraint.Coeff) { +func (engine *field) Sub(a, b constraint.Element) constraint.Element { _a := (*fr.Element)(a[:]) _b := (*fr.Element)(b[:]) _a.Sub(_a, _b) + return a } -func (engine *arithEngine) Neg(a *constraint.Coeff) { +func (engine *field) Neg(a constraint.Element) constraint.Element { e := (*fr.Element)(a[:]) e.Neg(e) + return a } -func (engine *arithEngine) Inverse(a *constraint.Coeff) { +func (engine *field) Inverse(a constraint.Element) (constraint.Element, bool) { + if a.IsZero() { + return a, false + } e := (*fr.Element)(a[:]) + if e.IsZero() { + return a, false + } else if e.IsOne() { + return a, true + } + var t fr.Element + t.Neg(e) + if t.IsOne() { + return a, true + } + e.Inverse(e) + return a, true } -func (engine *arithEngine) IsOne(a *constraint.Coeff) bool { +func (engine *field) IsOne(a constraint.Element) bool { e := (*fr.Element)(a[:]) return e.IsOne() } -func (engine *arithEngine) One() constraint.Coeff { +func (engine *field) One() constraint.Element { e := fr.One() - var r constraint.Coeff + var r constraint.Element copy(r[:], e[:]) return r } -func (engine *arithEngine) String(a *constraint.Coeff) string { +func (engine *field) String(a constraint.Element) string { e := (*fr.Element)(a[:]) return e.String() } diff --git a/constraint/tinyfield/r1cs.go b/constraint/tinyfield/r1cs.go deleted file mode 100644 index 21af84a24a..0000000000 --- a/constraint/tinyfield/r1cs.go +++ /dev/null @@ -1,467 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// 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. - -// Code generated by gnark DO NOT EDIT - -package cs - -import ( - "errors" - "fmt" - "github.com/fxamacker/cbor/v2" - "io" - "runtime" - "sync" - "time" - - "github.com/consensys/gnark/backend/witness" - "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/internal/backend/ioutils" - "github.com/consensys/gnark/logger" - "github.com/consensys/gnark/profile" - - "github.com/consensys/gnark-crypto/ecc" - "math" - - fr "github.com/consensys/gnark/internal/tinyfield" -) - -// R1CS describes a set of R1CS constraint -type R1CS struct { - constraint.R1CSCore - CoeffTable - arithEngine -} - -// NewR1CS returns a new R1CS and sets cs.Coefficient (fr.Element) from provided big.Int values -// -// capacity pre-allocates memory for capacity nbConstraints -func NewR1CS(capacity int) *R1CS { - r := R1CS{ - R1CSCore: constraint.R1CSCore{ - System: constraint.NewSystem(fr.Modulus()), - Constraints: make([]constraint.R1C, 0, capacity), - }, - CoeffTable: newCoeffTable(capacity / 10), - } - return &r -} - -func (cs *R1CS) AddConstraint(r1c constraint.R1C, debugInfo ...constraint.DebugInfo) int { - profile.RecordConstraint() - cs.Constraints = append(cs.Constraints, r1c) - cID := len(cs.Constraints) - 1 - if len(debugInfo) == 1 { - cs.DebugInfo = append(cs.DebugInfo, constraint.LogEntry(debugInfo[0])) - cs.MDebug[cID] = len(cs.DebugInfo) - 1 - } - - cs.UpdateLevel(cID, &r1c) - - return cID -} - -// Solve returns the vector w solution to the system, that is -// Aw o Bw - Cw = 0 -func (cs *R1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { - opt, err := solver.NewConfig(opts...) - if err != nil { - return nil, err - } - - var res R1CSSolution - - s := ecc.NextPowerOfTwo(uint64(len(cs.Constraints))) - res.A = make(fr.Vector, len(cs.Constraints), s) - res.B = make(fr.Vector, len(cs.Constraints), s) - res.C = make(fr.Vector, len(cs.Constraints), s) - - v := witness.Vector().(fr.Vector) - - res.W, err = cs.solve(v, res.A, res.B, res.C, opt) - if err != nil { - return nil, err - } - - return &res, nil -} - -// Solve sets all the wires and returns the a, b, c vectors. -// the cs system should have been compiled before. The entries in a, b, c are in Montgomery form. -// a, b, c vectors: ab-c = hz -// witness = [publicWires | secretWires] (without the ONE_WIRE !) -// returns [publicWires | secretWires | internalWires ] -func (cs *R1CS) solve(witness, a, b, c fr.Vector, opt solver.Config) (fr.Vector, error) { - log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() - - nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - solution, err := newSolution(&cs.System, nbWires, opt.HintFunctions, cs.Coefficients) - if err != nil { - return make(fr.Vector, nbWires), err - } - start := time.Now() - - if len(witness) != len(cs.Public)-1+len(cs.Secret) { // - 1 for ONE_WIRE - err = fmt.Errorf("invalid witness size, got %d, expected %d = %d (public) + %d (secret)", len(witness), int(len(cs.Public)-1+len(cs.Secret)), len(cs.Public)-1, len(cs.Secret)) - log.Err(err).Send() - return solution.values, err - } - - // compute the wires and the a, b, c polynomials - if len(a) != len(cs.Constraints) || len(b) != len(cs.Constraints) || len(c) != len(cs.Constraints) { - err = errors.New("invalid input size: len(a, b, c) == len(Constraints)") - log.Err(err).Send() - return solution.values, err - } - - solution.solved[0] = true // ONE_WIRE - solution.values[0].SetOne() - copy(solution.values[1:], witness) - for i := range witness { - solution.solved[i+1] = true - } - - // keep track of the number of wire instantiations we do, for a sanity check to ensure - // we instantiated all wires - solution.nbSolved += uint64(len(witness) + 1) - - // now that we know all inputs are set, defer log printing once all solution.values are computed - // (or sooner, if a constraint is not satisfied) - defer solution.printLogs(opt.Logger, cs.Logs) - - if err := cs.parallelSolve(a, b, c, &solution); err != nil { - if unsatisfiedErr, ok := err.(*UnsatisfiedConstraintError); ok { - log.Err(errors.New("unsatisfied constraint")).Int("id", unsatisfiedErr.CID).Send() - } else { - log.Err(err).Send() - } - return solution.values, err - } - - // sanity check; ensure all wires are marked as "instantiated" - if !solution.isValid() { - log.Err(errors.New("solver didn't instantiate all wires")).Send() - panic("solver didn't instantiate all wires") - } - - log.Debug().Dur("took", time.Since(start)).Msg("constraint system solver done") - - return solution.values, nil -} - -func (cs *R1CS) parallelSolve(a, b, c fr.Vector, solution *solution) error { - // minWorkPerCPU is the minimum target number of constraint a task should hold - // in other words, if a level has less than minWorkPerCPU, it will not be parallelized and executed - // sequentially without sync. - const minWorkPerCPU = 50.0 - - // cs.Levels has a list of levels, where all constraints in a level l(n) are independent - // and may only have dependencies on previous levels - // for each constraint - // we are guaranteed that each R1C contains at most one unsolved wire - // first we solve the unsolved wire (if any) - // then we check that the constraint is valid - // if a[i] * b[i] != c[i]; it means the constraint is not satisfied - - var wg sync.WaitGroup - chTasks := make(chan []int, runtime.NumCPU()) - chError := make(chan *UnsatisfiedConstraintError, runtime.NumCPU()) - - // start a worker pool - // each worker wait on chTasks - // a task is a slice of constraint indexes to be solved - for i := 0; i < runtime.NumCPU(); i++ { - go func() { - for t := range chTasks { - for _, i := range t { - // for each constraint in the task, solve it. - if err := cs.solveConstraint(cs.Constraints[i], solution, &a[i], &b[i], &c[i]); err != nil { - var debugInfo *string - if dID, ok := cs.MDebug[i]; ok { - debugInfo = new(string) - *debugInfo = solution.logValue(cs.DebugInfo[dID]) - } - chError <- &UnsatisfiedConstraintError{CID: i, Err: err, DebugInfo: debugInfo} - wg.Done() - return - } - } - wg.Done() - } - }() - } - - // clean up pool go routines - defer func() { - close(chTasks) - close(chError) - }() - - // for each level, we push the tasks - for _, level := range cs.Levels { - - // max CPU to use - maxCPU := float64(len(level)) / minWorkPerCPU - - if maxCPU <= 1.0 { - // we do it sequentially - for _, i := range level { - if err := cs.solveConstraint(cs.Constraints[i], solution, &a[i], &b[i], &c[i]); err != nil { - var debugInfo *string - if dID, ok := cs.MDebug[i]; ok { - debugInfo = new(string) - *debugInfo = solution.logValue(cs.DebugInfo[dID]) - } - return &UnsatisfiedConstraintError{CID: i, Err: err, DebugInfo: debugInfo} - } - } - continue - } - - // number of tasks for this level is set to number of CPU - // but if we don't have enough work for all our CPU, it can be lower. - nbTasks := runtime.NumCPU() - maxTasks := int(math.Ceil(maxCPU)) - if nbTasks > maxTasks { - nbTasks = maxTasks - } - nbIterationsPerCpus := len(level) / nbTasks - - // more CPUs than tasks: a CPU will work on exactly one iteration - // note: this depends on minWorkPerCPU constant - if nbIterationsPerCpus < 1 { - nbIterationsPerCpus = 1 - nbTasks = len(level) - } - - extraTasks := len(level) - (nbTasks * nbIterationsPerCpus) - extraTasksOffset := 0 - - for i := 0; i < nbTasks; i++ { - wg.Add(1) - _start := i*nbIterationsPerCpus + extraTasksOffset - _end := _start + nbIterationsPerCpus - if extraTasks > 0 { - _end++ - extraTasks-- - extraTasksOffset++ - } - // since we're never pushing more than num CPU tasks - // we will never be blocked here - chTasks <- level[_start:_end] - } - - // wait for the level to be done - wg.Wait() - - if len(chError) > 0 { - return <-chError - } - } - - return nil -} - -// IsSolved -// Deprecated: use _, err := Solve(...) instead -func (cs *R1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { - _, err := cs.Solve(witness, opts...) - return err -} - -// divByCoeff sets res = res / t.Coeff -func (cs *R1CS) divByCoeff(res *fr.Element, t constraint.Term) { - cID := t.CoeffID() - switch cID { - case constraint.CoeffIdOne: - return - case constraint.CoeffIdMinusOne: - res.Neg(res) - case constraint.CoeffIdZero: - panic("division by 0") - default: - // this is slow, but shouldn't happen as divByCoeff is called to - // remove the coeff of an unsolved wire - // but unsolved wires are (in gnark frontend) systematically set with a coeff == 1 or -1 - res.Div(res, &cs.Coefficients[cID]) - } -} - -// solveConstraint compute unsolved wires in the constraint, if any and set the solution accordingly -// -// returns an error if the solver called a hint function that errored -// returns false, nil if there was no wire to solve -// returns true, nil if exactly one wire was solved. In that case, it is redundant to check that -// the constraint is satisfied later. -func (cs *R1CS) solveConstraint(r constraint.R1C, solution *solution, a, b, c *fr.Element) error { - - // the index of the non-zero entry shows if L, R or O has an uninstantiated wire - // the content is the ID of the wire non instantiated - var loc uint8 - - var termToCompute constraint.Term - - processLExp := func(l constraint.LinearExpression, val *fr.Element, locValue uint8) error { - for _, t := range l { - vID := t.WireID() - - // wire is already computed, we just accumulate in val - if solution.solved[vID] { - solution.accumulateInto(t, val) - continue - } - - // first we check if this is a hint wire - if hint, ok := cs.MHints[vID]; ok { - if err := solution.solveWithHint(vID, hint); err != nil { - return err - } - // now that the wire is saved, accumulate it into a, b or c - solution.accumulateInto(t, val) - continue - } - - if loc != 0 { - panic("found more than one wire to instantiate") - } - termToCompute = t - loc = locValue - } - return nil - } - - if err := processLExp(r.L, a, 1); err != nil { - return err - } - - if err := processLExp(r.R, b, 2); err != nil { - return err - } - - if err := processLExp(r.O, c, 3); err != nil { - return err - } - - if loc == 0 { - // there is nothing to solve, may happen if we have an assertion - // (ie a constraints that doesn't yield any output) - // or if we solved the unsolved wires with hint functions - var check fr.Element - if !check.Mul(a, b).Equal(c) { - return fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String()) - } - return nil - } - - // we compute the wire value and instantiate it - wID := termToCompute.WireID() - - // solver result - var wire fr.Element - - switch loc { - case 1: - if !b.IsZero() { - wire.Div(c, b). - Sub(&wire, a) - a.Add(a, &wire) - } else { - // we didn't actually ensure that a * b == c - var check fr.Element - if !check.Mul(a, b).Equal(c) { - return fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String()) - } - } - case 2: - if !a.IsZero() { - wire.Div(c, a). - Sub(&wire, b) - b.Add(b, &wire) - } else { - var check fr.Element - if !check.Mul(a, b).Equal(c) { - return fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String()) - } - } - case 3: - wire.Mul(a, b). - Sub(&wire, c) - - c.Add(c, &wire) - } - - // wire is the term (coeff * value) - // but in the solution we want to store the value only - // note that in gnark frontend, coeff here is always 1 or -1 - cs.divByCoeff(&wire, termToCompute) - solution.set(wID, wire) - - return nil -} - -// GetConstraints return the list of R1C and a coefficient resolver -func (cs *R1CS) GetConstraints() ([]constraint.R1C, constraint.Resolver) { - return cs.Constraints, cs -} - -// GetNbCoefficients return the number of unique coefficients needed in the R1CS -func (cs *R1CS) GetNbCoefficients() int { - return len(cs.Coefficients) -} - -// CurveID returns curve ID as defined in gnark-crypto -func (cs *R1CS) CurveID() ecc.ID { - return ecc.UNKNOWN -} - -// WriteTo encodes R1CS into provided io.Writer using cbor -func (cs *R1CS) WriteTo(w io.Writer) (int64, error) { - _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written - enc, err := cbor.CoreDetEncOptions().EncMode() - if err != nil { - return 0, err - } - encoder := enc.NewEncoder(&_w) - - // encode our object - err = encoder.Encode(cs) - return _w.N, err -} - -// ReadFrom attempts to decode R1CS from io.Reader using cbor -func (cs *R1CS) ReadFrom(r io.Reader) (int64, error) { - dm, err := cbor.DecOptions{ - MaxArrayElements: 134217728, - MaxMapPairs: 134217728, - }.DecMode() - - if err != nil { - return 0, err - } - decoder := dm.NewDecoder(r) - - // initialize coeff table - cs.CoeffTable = newCoeffTable(0) - - if err := decoder.Decode(&cs); err != nil { - return int64(decoder.NumBytesRead()), err - } - - if err := cs.CheckSerializationHeader(); err != nil { - return int64(decoder.NumBytesRead()), err - } - - return int64(decoder.NumBytesRead()), nil -} diff --git a/constraint/tinyfield/r1cs_sparse.go b/constraint/tinyfield/r1cs_sparse.go deleted file mode 100644 index cd7ff1de1c..0000000000 --- a/constraint/tinyfield/r1cs_sparse.go +++ /dev/null @@ -1,533 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// 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. - -// Code generated by gnark DO NOT EDIT - -package cs - -import ( - "errors" - "fmt" - "github.com/consensys/gnark-crypto/ecc" - "github.com/fxamacker/cbor/v2" - "io" - "math" - "runtime" - "sync" - "time" - - "github.com/consensys/gnark/backend/witness" - "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/internal/backend/ioutils" - "github.com/consensys/gnark/logger" - "github.com/consensys/gnark/profile" - - fr "github.com/consensys/gnark/internal/tinyfield" -) - -// SparseR1CS represents a Plonk like circuit -type SparseR1CS struct { - constraint.SparseR1CSCore - CoeffTable - arithEngine -} - -// NewSparseR1CS returns a new SparseR1CS and sets r1cs.Coefficient (fr.Element) from provided big.Int values -func NewSparseR1CS(capacity int) *SparseR1CS { - cs := SparseR1CS{ - SparseR1CSCore: constraint.SparseR1CSCore{ - System: constraint.NewSystem(fr.Modulus()), - Constraints: make([]constraint.SparseR1C, 0, capacity), - }, - CoeffTable: newCoeffTable(capacity / 10), - } - - return &cs -} - -func (cs *SparseR1CS) AddConstraint(c constraint.SparseR1C, debugInfo ...constraint.DebugInfo) int { - profile.RecordConstraint() - cs.Constraints = append(cs.Constraints, c) - cID := len(cs.Constraints) - 1 - if len(debugInfo) == 1 { - cs.DebugInfo = append(cs.DebugInfo, constraint.LogEntry(debugInfo[0])) - cs.MDebug[cID] = len(cs.DebugInfo) - 1 - } - cs.UpdateLevel(cID, &c) - - return cID -} - -func (c *SparseR1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { - opt, err := solver.NewConfig(opts...) - if err != nil { - return nil, err - } - - // compute the constraint system solution - var solution []fr.Element - if solution, err = c.solve(witness.Vector().(fr.Vector), opt); err != nil { - return nil, err - } - - var res SparseR1CSSolution - // query l, r, o in Lagrange basis, not blinded - res.L, res.R, res.O = c.evaluateLROSmallDomain(solution) - - return &res, nil -} - -// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. -// solution = [ public | secret | internal ] -func (c *SparseR1CS) evaluateLROSmallDomain(solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { - - //s := int(pk.Domain[0].Cardinality) - s := c.GetNbConstraints() + len(c.Public) // len(spr.Public) is for the placeholder constraints - s = int(ecc.NextPowerOfTwo(uint64(s))) - - var l, r, o []fr.Element - l = make([]fr.Element, s) - r = make([]fr.Element, s) - o = make([]fr.Element, s) - s0 := solution[0] - - for i := 0; i < len(c.Public); i++ { // placeholders - l[i] = solution[i] - r[i] = s0 - o[i] = s0 - } - offset := len(c.Public) - for i := 0; i < len(c.Constraints); i++ { // constraints - l[offset+i] = solution[c.Constraints[i].L.WireID()] - r[offset+i] = solution[c.Constraints[i].R.WireID()] - o[offset+i] = solution[c.Constraints[i].O.WireID()] - } - offset += len(c.Constraints) - - for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) - l[offset+i] = s0 - r[offset+i] = s0 - o[offset+i] = s0 - } - - return l, r, o - -} - -// Solve sets all the wires. -// solution.values = [publicInputs | secretInputs | internalVariables ] -// witness: contains the input variables -// it returns the full slice of wires -func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, error) { - log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "plonk").Logger() - - // set the slices holding the solution.values and monitoring which variables have been solved - nbVariables := cs.NbInternalVariables + len(cs.Secret) + len(cs.Public) - - start := time.Now() - - expectedWitnessSize := len(cs.Public) + len(cs.Secret) - if len(witness) != expectedWitnessSize { - return make(fr.Vector, nbVariables), fmt.Errorf( - "invalid witness size, got %d, expected %d = %d (public) + %d (secret)", - len(witness), - expectedWitnessSize, - len(cs.Public), - len(cs.Secret), - ) - } - - // keep track of wire that have a value - solution, err := newSolution(&cs.System, nbVariables, opt.HintFunctions, cs.Coefficients) - if err != nil { - return solution.values, err - } - - // solution.values = [publicInputs | secretInputs | internalVariables ] -> we fill publicInputs | secretInputs - copy(solution.values, witness) - for i := 0; i < len(witness); i++ { - solution.solved[i] = true - } - - // keep track of the number of wire instantiations we do, for a sanity check to ensure - // we instantiated all wires - solution.nbSolved += uint64(len(witness)) - - // defer log printing once all solution.values are computed - defer solution.printLogs(opt.Logger, cs.Logs) - - // batch invert the coefficients to avoid many divisions in the solver - coefficientsNegInv := fr.BatchInvert(cs.Coefficients) - for i := 0; i < len(coefficientsNegInv); i++ { - coefficientsNegInv[i].Neg(&coefficientsNegInv[i]) - } - - if err := cs.parallelSolve(&solution, coefficientsNegInv); err != nil { - if unsatisfiedErr, ok := err.(*UnsatisfiedConstraintError); ok { - log.Err(errors.New("unsatisfied constraint")).Int("id", unsatisfiedErr.CID).Send() - } else { - log.Err(err).Send() - } - return solution.values, err - } - - // sanity check; ensure all wires are marked as "instantiated" - if !solution.isValid() { - log.Err(errors.New("solver didn't instantiate all wires")).Send() - panic("solver didn't instantiate all wires") - } - - log.Debug().Dur("took", time.Since(start)).Msg("constraint system solver done") - - return solution.values, nil - -} - -func (cs *SparseR1CS) parallelSolve(solution *solution, coefficientsNegInv fr.Vector) error { - // minWorkPerCPU is the minimum target number of constraint a task should hold - // in other words, if a level has less than minWorkPerCPU, it will not be parallelized and executed - // sequentially without sync. - const minWorkPerCPU = 50.0 - - // cs.Levels has a list of levels, where all constraints in a level l(n) are independent - // and may only have dependencies on previous levels - - var wg sync.WaitGroup - chTasks := make(chan []int, runtime.NumCPU()) - chError := make(chan *UnsatisfiedConstraintError, runtime.NumCPU()) - - // start a worker pool - // each worker wait on chTasks - // a task is a slice of constraint indexes to be solved - for i := 0; i < runtime.NumCPU(); i++ { - go func() { - for t := range chTasks { - for _, i := range t { - // for each constraint in the task, solve it. - if err := cs.solveConstraint(cs.Constraints[i], solution, coefficientsNegInv); err != nil { - chError <- &UnsatisfiedConstraintError{CID: i, Err: err} - wg.Done() - return - } - if err := cs.checkConstraint(cs.Constraints[i], solution); err != nil { - if dID, ok := cs.MDebug[i]; ok { - errMsg := solution.logValue(cs.DebugInfo[dID]) - chError <- &UnsatisfiedConstraintError{CID: i, DebugInfo: &errMsg} - } else { - chError <- &UnsatisfiedConstraintError{CID: i, Err: err} - } - wg.Done() - return - } - } - wg.Done() - } - }() - } - - // clean up pool go routines - defer func() { - close(chTasks) - close(chError) - }() - - // for each level, we push the tasks - for _, level := range cs.Levels { - - // max CPU to use - maxCPU := float64(len(level)) / minWorkPerCPU - - if maxCPU <= 1.0 { - // we do it sequentially - for _, i := range level { - if err := cs.solveConstraint(cs.Constraints[i], solution, coefficientsNegInv); err != nil { - return &UnsatisfiedConstraintError{CID: i, Err: err} - } - if err := cs.checkConstraint(cs.Constraints[i], solution); err != nil { - if dID, ok := cs.MDebug[i]; ok { - errMsg := solution.logValue(cs.DebugInfo[dID]) - return &UnsatisfiedConstraintError{CID: i, DebugInfo: &errMsg} - } - return &UnsatisfiedConstraintError{CID: i, Err: err} - } - } - continue - } - - // number of tasks for this level is set to number of CPU - // but if we don't have enough work for all our CPU, it can be lower. - nbTasks := runtime.NumCPU() - maxTasks := int(math.Ceil(maxCPU)) - if nbTasks > maxTasks { - nbTasks = maxTasks - } - nbIterationsPerCpus := len(level) / nbTasks - - // more CPUs than tasks: a CPU will work on exactly one iteration - // note: this depends on minWorkPerCPU constant - if nbIterationsPerCpus < 1 { - nbIterationsPerCpus = 1 - nbTasks = len(level) - } - - extraTasks := len(level) - (nbTasks * nbIterationsPerCpus) - extraTasksOffset := 0 - - for i := 0; i < nbTasks; i++ { - wg.Add(1) - _start := i*nbIterationsPerCpus + extraTasksOffset - _end := _start + nbIterationsPerCpus - if extraTasks > 0 { - _end++ - extraTasks-- - extraTasksOffset++ - } - // since we're never pushing more than num CPU tasks - // we will never be blocked here - chTasks <- level[_start:_end] - } - - // wait for the level to be done - wg.Wait() - - if len(chError) > 0 { - return <-chError - } - } - - return nil -} - -// computeHints computes wires associated with a hint function, if any -// if there is no remaining wire to solve, returns -1 -// else returns the wire position (L -> 0, R -> 1, O -> 2) -func (cs *SparseR1CS) computeHints(c constraint.SparseR1C, solution *solution) (int, error) { - r := -1 - lID, rID, oID := c.L.WireID(), c.R.WireID(), c.O.WireID() - - if (c.L.CoeffID() != 0 || c.M[0].CoeffID() != 0) && !solution.solved[lID] { - // check if it's a hint - if hint, ok := cs.MHints[lID]; ok { - if err := solution.solveWithHint(lID, hint); err != nil { - return -1, err - } - } else { - r = 0 - } - - } - - if (c.R.CoeffID() != 0 || c.M[1].CoeffID() != 0) && !solution.solved[rID] { - // check if it's a hint - if hint, ok := cs.MHints[rID]; ok { - if err := solution.solveWithHint(rID, hint); err != nil { - return -1, err - } - } else { - r = 1 - } - } - - if (c.O.CoeffID() != 0) && !solution.solved[oID] { - // check if it's a hint - if hint, ok := cs.MHints[oID]; ok { - if err := solution.solveWithHint(oID, hint); err != nil { - return -1, err - } - } else { - r = 2 - } - } - return r, nil -} - -// solveConstraint solve any unsolved wire in given constraint and update the solution -// a SparseR1C may have up to one unsolved wire (excluding hints) -// if it doesn't, then this function returns and does nothing -func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution, coefficientsNegInv fr.Vector) error { - - if c.Commitment == constraint.COMMITTED { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. - return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time - } - - lro, err := cs.computeHints(c, solution) - if err != nil { - return err - } - if lro == -1 { - // no unsolved wire - // can happen if the constraint contained only hint wires. - return nil - } - if lro == 1 { // we solve for R: u1L+u2R+u3LR+u4O+k=0 => R(u2+u3L)+u1L+u4O+k = 0 - if !solution.solved[c.L.WireID()] { - panic("L wire should be instantiated when we solve R") - } - var u1, u2, u3, den, num, v1, v2 fr.Element - u3.Mul(&cs.Coefficients[c.M[0].CoeffID()], &cs.Coefficients[c.M[1].CoeffID()]) - u1.Set(&cs.Coefficients[c.L.CoeffID()]) - u2.Set(&cs.Coefficients[c.R.CoeffID()]) - den.Mul(&u3, &solution.values[c.L.WireID()]).Add(&den, &u2) - - v1 = solution.computeTerm(c.L) - v2 = solution.computeTerm(c.O) - num.Add(&v1, &v2).Add(&num, &cs.Coefficients[c.K]) - - // TODO find a way to do lazy div (/ batch inversion) - num.Div(&num, &den).Neg(&num) - solution.set(c.L.WireID(), num) - return nil - } - - if lro == 0 { // we solve for L: u1L+u2R+u3LR+u4O+k=0 => L(u1+u3R)+u2R+u4O+k = 0 - if !solution.solved[c.R.WireID()] { - panic("R wire should be instantiated when we solve L") - } - var u1, u2, u3, den, num, v1, v2 fr.Element - u3.Mul(&cs.Coefficients[c.M[0].CoeffID()], &cs.Coefficients[c.M[1].CoeffID()]) - u1.Set(&cs.Coefficients[c.L.CoeffID()]) - u2.Set(&cs.Coefficients[c.R.CoeffID()]) - den.Mul(&u3, &solution.values[c.R.WireID()]).Add(&den, &u1) - - v1 = solution.computeTerm(c.R) - v2 = solution.computeTerm(c.O) - num.Add(&v1, &v2).Add(&num, &cs.Coefficients[c.K]) - - // TODO find a way to do lazy div (/ batch inversion) - num.Div(&num, &den).Neg(&num) - solution.set(c.L.WireID(), num) - return nil - - } - // O we solve for O - var o fr.Element - cID, vID := c.O.CoeffID(), c.O.WireID() - - l := solution.computeTerm(c.L) - r := solution.computeTerm(c.R) - m0 := solution.computeTerm(c.M[0]) - m1 := solution.computeTerm(c.M[1]) - - // o = - ((m0 * m1) + l + r + c.K) / c.O - o.Mul(&m0, &m1).Add(&o, &l).Add(&o, &r).Add(&o, &cs.Coefficients[c.K]) - o.Mul(&o, &coefficientsNegInv[cID]) - - solution.set(vID, o) - - return nil -} - -// IsSolved -// Deprecated: use _, err := Solve(...) instead -func (cs *SparseR1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { - _, err := cs.Solve(witness, opts...) - return err -} - -// GetConstraints return the list of SparseR1C and a coefficient resolver -func (cs *SparseR1CS) GetConstraints() ([]constraint.SparseR1C, constraint.Resolver) { - return cs.Constraints, cs -} - -func (cs *SparseR1CS) GetConstraint(i int) *constraint.SparseR1C { - if i < 0 || i >= len(cs.Constraints) { - return nil - } - return &cs.Constraints[i] -} - -func (cs *SparseR1CS) GetCoefficient(i int) (r constraint.Coeff) { - copy(r[:], cs.Coefficients[i][:]) - return -} - -// checkConstraint verifies that the constraint holds -func (cs *SparseR1CS) checkConstraint(c constraint.SparseR1C, solution *solution) error { - - if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. - return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time - } - - l := solution.computeTerm(c.L) - r := solution.computeTerm(c.R) - m0 := solution.computeTerm(c.M[0]) - m1 := solution.computeTerm(c.M[1]) - o := solution.computeTerm(c.O) - - // l + r + (m0 * m1) + o + c.K == 0 - var t fr.Element - t.Mul(&m0, &m1).Add(&t, &l).Add(&t, &r).Add(&t, &o).Add(&t, &cs.Coefficients[c.K]) - if !t.IsZero() { - return fmt.Errorf("qL⋅xa + qR⋅xb + qO⋅xc + qM⋅(xaxb) + qC != 0 → %s + %s + %s + (%s × %s) + %s != 0", - l.String(), - r.String(), - o.String(), - m0.String(), - m1.String(), - cs.Coefficients[c.K].String(), - ) - } - return nil - -} - -// GetNbCoefficients return the number of unique coefficients needed in the R1CS -func (cs *SparseR1CS) GetNbCoefficients() int { - return len(cs.Coefficients) -} - -// CurveID returns curve ID as defined in gnark-crypto (ecc.tinyfield) -func (cs *SparseR1CS) CurveID() ecc.ID { - return ecc.UNKNOWN -} - -// WriteTo encodes SparseR1CS into provided io.Writer using cbor -func (cs *SparseR1CS) WriteTo(w io.Writer) (int64, error) { - _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written - enc, err := cbor.CoreDetEncOptions().EncMode() - if err != nil { - return 0, err - } - encoder := enc.NewEncoder(&_w) - - // encode our object - err = encoder.Encode(cs) - return _w.N, err -} - -// ReadFrom attempts to decode SparseR1CS from io.Reader using cbor -func (cs *SparseR1CS) ReadFrom(r io.Reader) (int64, error) { - dm, err := cbor.DecOptions{ - MaxArrayElements: 134217728, - MaxMapPairs: 134217728, - }.DecMode() - if err != nil { - return 0, err - } - decoder := dm.NewDecoder(r) - - // initialize coeff table - cs.CoeffTable = newCoeffTable(0) - - if err := decoder.Decode(cs); err != nil { - return int64(decoder.NumBytesRead()), err - } - - if err := cs.CheckSerializationHeader(); err != nil { - return int64(decoder.NumBytesRead()), err - } - - return int64(decoder.NumBytesRead()), nil -} diff --git a/constraint/tinyfield/r1cs_test.go b/constraint/tinyfield/r1cs_test.go index 09bb5f0968..44b9e76772 100644 --- a/constraint/tinyfield/r1cs_test.go +++ b/constraint/tinyfield/r1cs_test.go @@ -20,6 +20,7 @@ import ( "bytes" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/frontend/cs/scs" "github.com/consensys/gnark/internal/backend/circuits" "reflect" "testing" @@ -79,10 +80,11 @@ func TestSerialization(t *testing.T) { if diff := cmp.Diff(r1cs1, &reconstructed, cmpopts.IgnoreFields(cs.R1CS{}, "System.q", - "arithEngine", + "field", "CoeffTable.mCoeffs", "System.lbWireLevel", "System.lbHints", + "System.genericHint", "System.SymbolTable", "System.lbOutputs", "System.bitLen")); diff != "" { @@ -150,12 +152,6 @@ func (circuit *circuit) Define(api frontend.API) error { func BenchmarkSolve(b *testing.B) { - var c circuit - ccs, err := frontend.Compile(fr.Modulus(), r1cs.NewBuilder, &c) - if err != nil { - b.Fatal(err) - } - var w circuit w.X = 1 w.Y = 1 @@ -164,8 +160,32 @@ func BenchmarkSolve(b *testing.B) { b.Fatal(err) } - b.ResetTimer() - for i := 0; i < b.N; i++ { - _ = ccs.IsSolved(witness) - } + b.Run("scs", func(b *testing.B) { + var c circuit + ccs, err := frontend.Compile(fr.Modulus(), scs.NewBuilder, &c) + if err != nil { + b.Fatal(err) + } + b.Log("scs nbConstraints", ccs.GetNbConstraints()) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = ccs.IsSolved(witness) + } + }) + + b.Run("r1cs", func(b *testing.B) { + var c circuit + ccs, err := frontend.Compile(fr.Modulus(), r1cs.NewBuilder, &c, frontend.WithCompressThreshold(10)) + if err != nil { + b.Fatal(err) + } + b.Log("r1cs nbConstraints", ccs.GetNbConstraints()) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = ccs.IsSolved(witness) + } + }) + } diff --git a/constraint/tinyfield/solution.go b/constraint/tinyfield/solution.go deleted file mode 100644 index b514905da4..0000000000 --- a/constraint/tinyfield/solution.go +++ /dev/null @@ -1,383 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// 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. - -// Code generated by gnark DO NOT EDIT - -package cs - -import ( - "errors" - "fmt" - "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/debug" - "github.com/rs/zerolog" - "io" - "math/big" - "strconv" - "strings" - "sync/atomic" - - fr "github.com/consensys/gnark/internal/tinyfield" -) - -// solution represents elements needed to compute -// a solution to a R1CS or SparseR1CS -type solution struct { - values, coefficients []fr.Element - solved []bool - nbSolved uint64 - mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function - st *debug.SymbolTable - cs *constraint.System -} - -func newSolution(cs *constraint.System, nbWires int, hintFunctions map[solver.HintID]solver.Hint, coefficients []fr.Element) (solution, error) { - - s := solution{ - cs: cs, - st: &cs.SymbolTable, - values: make([]fr.Element, nbWires), - coefficients: coefficients, - solved: make([]bool, nbWires), - mHintsFunctions: hintFunctions, - } - - // hintsDependencies is from compile time; it contains the list of hints the solver **needs** - var missing []string - for hintUUID, hintID := range cs.MHintsDependencies { - if _, ok := s.mHintsFunctions[hintUUID]; !ok { - missing = append(missing, hintID) - } - } - - if len(missing) > 0 { - return s, fmt.Errorf("solver missing hint(s): %v", missing) - } - - return s, nil -} - -func (s *solution) set(id int, value fr.Element) { - if s.solved[id] { - panic("solving the same wire twice should never happen.") - } - s.values[id] = value - s.solved[id] = true - atomic.AddUint64(&s.nbSolved, 1) - // s.nbSolved++ -} - -func (s *solution) isValid() bool { - return int(s.nbSolved) == len(s.values) -} - -// computeTerm computes coeff*variable -func (s *solution) computeTerm(t constraint.Term) fr.Element { - cID, vID := t.CoeffID(), t.WireID() - if cID != 0 && !s.solved[vID] { - panic("computing a term with an unsolved wire") - } - switch cID { - case constraint.CoeffIdZero: - return fr.Element{} - case constraint.CoeffIdOne: - return s.values[vID] - case constraint.CoeffIdTwo: - var res fr.Element - res.Double(&s.values[vID]) - return res - case constraint.CoeffIdMinusOne: - var res fr.Element - res.Neg(&s.values[vID]) - return res - default: - var res fr.Element - res.Mul(&s.coefficients[cID], &s.values[vID]) - return res - } -} - -// r += (t.coeff*t.value) -func (s *solution) accumulateInto(t constraint.Term, r *fr.Element) { - cID := t.CoeffID() - - if t.IsConstant() { - // needed for logs, we may want to not put this in the hot path if we need to - // optimize constraint system solver further. - r.Add(r, &s.coefficients[cID]) - return - } - - vID := t.WireID() - switch cID { - case constraint.CoeffIdZero: - return - case constraint.CoeffIdOne: - r.Add(r, &s.values[vID]) - case constraint.CoeffIdTwo: - var res fr.Element - res.Double(&s.values[vID]) - r.Add(r, &res) - case constraint.CoeffIdMinusOne: - r.Sub(r, &s.values[vID]) - default: - var res fr.Element - res.Mul(&s.coefficients[cID], &s.values[vID]) - r.Add(r, &res) - } -} - -// solveHint compute solution.values[vID] using provided solver hint -func (s *solution) solveWithHint(vID int, hID int) error { - // skip if the wire is already solved by a call to the same hint - // function on the same inputs - if s.solved[vID] { - return nil - } - - h := &s.cs.HintMappings[hID] - - // ensure hint function was provided - f, ok := s.mHintsFunctions[h.HintID] - if !ok { - return errors.New("missing hint function") - } - - // tmp IO big int memory - nbInputs := len(h.Inputs) - nbOutputs := len(h.Outputs) - inputs := make([]*big.Int, nbInputs) - outputs := make([]*big.Int, nbOutputs) - for i := 0; i < nbOutputs; i++ { - outputs[i] = big.NewInt(0) - } - - q := fr.Modulus() - - // for each input, we set its big int value, IF all the wires are solved - // the only case where all wires may not be solved, is if one of the input of this hint - // is the output of another hint. - // it is safe to recursively solve this with the parallel solver, since all hints-output wires - // that we can solve this way are marked to be solved with the current constraint we are processing. - recursiveSolve := func(t constraint.Term) error { - if t.IsConstant() { - return nil - } - wID := t.WireID() - if s.solved[wID] { - return nil - } - // unsolved dependency - if h, ok := s.cs.MHints[wID]; ok { - // solve recursively. - return s.solveWithHint(wID, h) - } - - // it's not a hint, we panic. - panic("solver can't compute hint; one or more input wires are unsolved") - } - - for i := 0; i < nbInputs; i++ { - inputs[i] = big.NewInt(0) - - var v fr.Element - for _, term := range h.Inputs[i] { - if err := recursiveSolve(term); err != nil { - return err - } - s.accumulateInto(term, &v) - } - v.BigInt(inputs[i]) - } - - err := f(q, inputs, outputs) - - var v fr.Element - for i := range outputs { - v.SetBigInt(outputs[i]) - s.set(h.Outputs[i], v) - } - - return err -} - -func (s *solution) printLogs(log zerolog.Logger, logs []constraint.LogEntry) { - if log.GetLevel() == zerolog.Disabled { - return - } - - for i := 0; i < len(logs); i++ { - logLine := s.logValue(logs[i]) - log.Debug().Str(zerolog.CallerFieldName, logs[i].Caller).Msg(logLine) - } -} - -const unsolvedVariable = "" - -func (s *solution) logValue(log constraint.LogEntry) string { - var toResolve []interface{} - var ( - eval fr.Element - missingValue bool - ) - for j := 0; j < len(log.ToResolve); j++ { - // before eval le - - missingValue = false - eval.SetZero() - - for _, t := range log.ToResolve[j] { - // for each term in the linear expression - - cID, vID := t.CoeffID(), t.WireID() - if t.IsConstant() { - // just add the constant - eval.Add(&eval, &s.coefficients[cID]) - continue - } - - if !s.solved[vID] { - missingValue = true - break // stop the loop we can't evaluate. - } - - tv := s.computeTerm(t) - eval.Add(&eval, &tv) - } - - // after - if missingValue { - toResolve = append(toResolve, unsolvedVariable) - } else { - // we have to append our accumulator - toResolve = append(toResolve, eval.String()) - } - - } - if len(log.Stack) > 0 { - var sbb strings.Builder - for _, lID := range log.Stack { - location := s.st.Locations[lID] - function := s.st.Functions[location.FunctionID] - - sbb.WriteString(function.Name) - sbb.WriteByte('\n') - sbb.WriteByte('\t') - sbb.WriteString(function.Filename) - sbb.WriteByte(':') - sbb.WriteString(strconv.Itoa(int(location.Line))) - sbb.WriteByte('\n') - } - toResolve = append(toResolve, sbb.String()) - } - return fmt.Sprintf(log.Format, toResolve...) -} - -// UnsatisfiedConstraintError wraps an error with useful metadata on the unsatisfied constraint -type UnsatisfiedConstraintError struct { - Err error - CID int // constraint ID - DebugInfo *string // optional debug info -} - -func (r *UnsatisfiedConstraintError) Error() string { - if r.DebugInfo != nil { - return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, *r.DebugInfo) - } - return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, r.Err.Error()) -} - -// R1CSSolution represent a valid assignment to all the variables in the constraint system. -// The vector W such that Aw o Bw - Cw = 0 -type R1CSSolution struct { - W fr.Vector - A, B, C fr.Vector -} - -func (t *R1CSSolution) WriteTo(w io.Writer) (int64, error) { - n, err := t.W.WriteTo(w) - if err != nil { - return n, err - } - a, err := t.A.WriteTo(w) - n += a - if err != nil { - return n, err - } - a, err = t.B.WriteTo(w) - n += a - if err != nil { - return n, err - } - a, err = t.C.WriteTo(w) - n += a - return n, err -} - -func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { - n, err := t.W.ReadFrom(r) - if err != nil { - return n, err - } - a, err := t.A.ReadFrom(r) - a += n - if err != nil { - return n, err - } - a, err = t.B.ReadFrom(r) - a += n - if err != nil { - return n, err - } - a, err = t.C.ReadFrom(r) - n += a - return n, err -} - -// SparseR1CSSolution represent a valid assignment to all the variables in the constraint system. -type SparseR1CSSolution struct { - L, R, O fr.Vector -} - -func (t *SparseR1CSSolution) WriteTo(w io.Writer) (int64, error) { - n, err := t.L.WriteTo(w) - if err != nil { - return n, err - } - a, err := t.R.WriteTo(w) - n += a - if err != nil { - return n, err - } - a, err = t.O.WriteTo(w) - n += a - return n, err - -} - -func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { - n, err := t.L.ReadFrom(r) - if err != nil { - return n, err - } - a, err := t.R.ReadFrom(r) - a += n - if err != nil { - return n, err - } - a, err = t.O.ReadFrom(r) - a += n - return n, err -} diff --git a/constraint/tinyfield/solver.go b/constraint/tinyfield/solver.go new file mode 100644 index 0000000000..35bd9e6c7b --- /dev/null +++ b/constraint/tinyfield/solver.go @@ -0,0 +1,614 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package cs + +import ( + "errors" + "fmt" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/field/pool" + "github.com/consensys/gnark/constraint" + csolver "github.com/consensys/gnark/constraint/solver" + "github.com/rs/zerolog" + "math" + "math/big" + "runtime" + "strconv" + "strings" + "sync" + "sync/atomic" + + fr "github.com/consensys/gnark/internal/tinyfield" +) + +// solver represent the state of the solver during a call to System.Solve(...) +type solver struct { + *system + + // values and solved are index by the wire (variable) id + values []fr.Element + solved []bool + nbSolved uint64 + + // maps hintID to hint function + mHintsFunctions map[csolver.HintID]csolver.Hint + + // used to out api.Println + logger zerolog.Logger + + a, b, c fr.Vector // R1CS solver will compute the a,b,c matrices + + q *big.Int +} + +func newSolver(cs *system, witness fr.Vector, opts ...csolver.Option) (*solver, error) { + // parse options + opt, err := csolver.NewConfig(opts...) + if err != nil { + return nil, err + } + + // check witness size + witnessOffset := 0 + if cs.Type == constraint.SystemR1CS { + witnessOffset++ + } + + nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables + expectedWitnessSize := len(cs.Public) - witnessOffset + len(cs.Secret) + + if len(witness) != expectedWitnessSize { + return nil, fmt.Errorf("invalid witness size, got %d, expected %d", len(witness), expectedWitnessSize) + } + + // check all hints are there + hintFunctions := opt.HintFunctions + + // hintsDependencies is from compile time; it contains the list of hints the solver **needs** + var missing []string + for hintUUID, hintID := range cs.MHintsDependencies { + if _, ok := hintFunctions[hintUUID]; !ok { + missing = append(missing, hintID) + } + } + + if len(missing) > 0 { + return nil, fmt.Errorf("solver missing hint(s): %v", missing) + } + + s := solver{ + system: cs, + values: make([]fr.Element, nbWires), + solved: make([]bool, nbWires), + mHintsFunctions: hintFunctions, + logger: opt.Logger, + q: cs.Field(), + } + + // set the witness indexes as solved + if witnessOffset == 1 { + s.solved[0] = true // ONE_WIRE + s.values[0].SetOne() + } + copy(s.values[witnessOffset:], witness) + for i := range witness { + s.solved[i+witnessOffset] = true + } + + // keep track of the number of wire instantiations we do, for a post solve sanity check + // to ensure we instantiated all wires + s.nbSolved += uint64(len(witness) + witnessOffset) + + if s.Type == constraint.SystemR1CS { + n := ecc.NextPowerOfTwo(uint64(cs.GetNbConstraints())) + s.a = make(fr.Vector, cs.GetNbConstraints(), n) + s.b = make(fr.Vector, cs.GetNbConstraints(), n) + s.c = make(fr.Vector, cs.GetNbConstraints(), n) + } + + return &s, nil +} + +func (s *solver) set(id int, value fr.Element) { + if s.solved[id] { + panic("solving the same wire twice should never happen.") + } + s.values[id] = value + s.solved[id] = true + atomic.AddUint64(&s.nbSolved, 1) +} + +// computeTerm computes coeff*variable +// TODO @gbotrel check if t is a Constant only +func (s *solver) computeTerm(t constraint.Term) fr.Element { + cID, vID := t.CoeffID(), t.WireID() + if cID != 0 && !s.solved[vID] { + panic("computing a term with an unsolved wire") + } + switch cID { + case constraint.CoeffIdZero: + return fr.Element{} + case constraint.CoeffIdOne: + return s.values[vID] + case constraint.CoeffIdTwo: + var res fr.Element + res.Double(&s.values[vID]) + return res + case constraint.CoeffIdMinusOne: + var res fr.Element + res.Neg(&s.values[vID]) + return res + default: + var res fr.Element + res.Mul(&s.Coefficients[cID], &s.values[vID]) + return res + } +} + +// r += (t.coeff*t.value) +// TODO @gbotrel check t.IsConstant on the caller side when necessary +func (s *solver) accumulateInto(t constraint.Term, r *fr.Element) { + cID := t.CoeffID() + vID := t.WireID() + + switch cID { + case constraint.CoeffIdZero: + return + case constraint.CoeffIdOne: + r.Add(r, &s.values[vID]) + case constraint.CoeffIdTwo: + var res fr.Element + res.Double(&s.values[vID]) + r.Add(r, &res) + case constraint.CoeffIdMinusOne: + r.Sub(r, &s.values[vID]) + default: + var res fr.Element + res.Mul(&s.Coefficients[cID], &s.values[vID]) + r.Add(r, &res) + } +} + +// solveWithHint executes a hint and assign the result to its defined outputs. +func (s *solver) solveWithHint(h *constraint.HintMapping) error { + // ensure hint function was provided + f, ok := s.mHintsFunctions[h.HintID] + if !ok { + return errors.New("missing hint function") + } + + // tmp IO big int memory + nbInputs := len(h.Inputs) + nbOutputs := int(h.OutputRange.End - h.OutputRange.Start) + inputs := make([]*big.Int, nbInputs) + outputs := make([]*big.Int, nbOutputs) + for i := 0; i < nbOutputs; i++ { + outputs[i] = pool.BigInt.Get() + outputs[i].SetUint64(0) + } + + q := pool.BigInt.Get() + q.Set(s.q) + + for i := 0; i < nbInputs; i++ { + var v fr.Element + for _, term := range h.Inputs[i] { + if term.IsConstant() { + v.Add(&v, &s.Coefficients[term.CoeffID()]) + continue + } + s.accumulateInto(term, &v) + } + inputs[i] = pool.BigInt.Get() + v.BigInt(inputs[i]) + } + + err := f(q, inputs, outputs) + + var v fr.Element + for i := range outputs { + v.SetBigInt(outputs[i]) + s.set(int(h.OutputRange.Start)+i, v) + pool.BigInt.Put(outputs[i]) + } + + for i := range inputs { + pool.BigInt.Put(inputs[i]) + } + + pool.BigInt.Put(q) + + return err +} + +func (s *solver) printLogs(logs []constraint.LogEntry) { + if s.logger.GetLevel() == zerolog.Disabled { + return + } + + for i := 0; i < len(logs); i++ { + logLine := s.logValue(logs[i]) + s.logger.Debug().Str(zerolog.CallerFieldName, logs[i].Caller).Msg(logLine) + } +} + +const unsolvedVariable = "" + +func (s *solver) logValue(log constraint.LogEntry) string { + var toResolve []interface{} + var ( + eval fr.Element + missingValue bool + ) + for j := 0; j < len(log.ToResolve); j++ { + // before eval le + + missingValue = false + eval.SetZero() + + for _, t := range log.ToResolve[j] { + // for each term in the linear expression + + cID, vID := t.CoeffID(), t.WireID() + if t.IsConstant() { + // just add the constant + eval.Add(&eval, &s.Coefficients[cID]) + continue + } + + if !s.solved[vID] { + missingValue = true + break // stop the loop we can't evaluate. + } + + tv := s.computeTerm(t) + eval.Add(&eval, &tv) + } + + // after + if missingValue { + toResolve = append(toResolve, unsolvedVariable) + } else { + // we have to append our accumulator + toResolve = append(toResolve, eval.String()) + } + + } + if len(log.Stack) > 0 { + var sbb strings.Builder + for _, lID := range log.Stack { + location := s.SymbolTable.Locations[lID] + function := s.SymbolTable.Functions[location.FunctionID] + + sbb.WriteString(function.Name) + sbb.WriteByte('\n') + sbb.WriteByte('\t') + sbb.WriteString(function.Filename) + sbb.WriteByte(':') + sbb.WriteString(strconv.Itoa(int(location.Line))) + sbb.WriteByte('\n') + } + toResolve = append(toResolve, sbb.String()) + } + return fmt.Sprintf(log.Format, toResolve...) +} + +// divByCoeff sets res = res / t.Coeff +func (solver *solver) divByCoeff(res *fr.Element, cID uint32) { + switch cID { + case constraint.CoeffIdOne: + return + case constraint.CoeffIdMinusOne: + res.Neg(res) + case constraint.CoeffIdZero: + panic("division by 0") + default: + // this is slow, but shouldn't happen as divByCoeff is called to + // remove the coeff of an unsolved wire + // but unsolved wires are (in gnark frontend) systematically set with a coeff == 1 or -1 + res.Div(res, &solver.Coefficients[cID]) + } +} + +// Implement constraint.Solver +func (s *solver) GetValue(cID, vID uint32) constraint.Element { + var r constraint.Element + e := s.computeTerm(constraint.Term{CID: cID, VID: vID}) + copy(r[:], e[:]) + return r +} +func (s *solver) GetCoeff(cID uint32) constraint.Element { + var r constraint.Element + copy(r[:], s.Coefficients[cID][:]) + return r +} +func (s *solver) SetValue(vID uint32, f constraint.Element) { + s.set(int(vID), *(*fr.Element)(f[:])) +} + +func (s *solver) IsSolved(vID uint32) bool { + return s.solved[vID] +} + +// processInstruction decodes the instruction and execute blueprint-defined logic. +// an instruction can encode a hint, a custom constraint or a generic constraint. +func (solver *solver) processInstruction(inst constraint.Instruction, scratch *scratch) error { + // fetch the blueprint + blueprint := solver.Blueprints[inst.BlueprintID] + calldata := solver.GetCallData(inst) + cID := inst.ConstraintOffset // here we have 1 constraint in the instruction only + + if solver.Type == constraint.SystemR1CS { + if bc, ok := blueprint.(constraint.BlueprintR1C); ok { + // TODO @gbotrel we use the solveR1C method for now, having user-defined + // blueprint for R1CS would require constraint.Solver interface to add methods + // to set a,b,c since it's more efficient to compute these while we solve. + bc.DecompressR1C(&scratch.tR1C, calldata) + return solver.solveR1C(cID, &scratch.tR1C) + } + } else if solver.Type == constraint.SystemSparseR1CS { + // blueprint declared "I know how to solve this." + if bc, ok := blueprint.(constraint.BlueprintSolvable); ok { + if err := bc.Solve(solver, calldata); err != nil { + return solver.wrapErrWithDebugInfo(cID, err) + } + return nil + } + } + + // blueprint encodes a hint, we execute. + // TODO @gbotrel may be worth it to move hint logic in blueprint "solve" + if bc, ok := blueprint.(constraint.BlueprintHint); ok { + bc.DecompressHint(&scratch.tHint, calldata) + return solver.solveWithHint(&scratch.tHint) + } + + return nil +} + +// run runs the solver. it return an error if a constraint is not satisfied or if not all wires +// were instantiated. +func (solver *solver) run() error { + // minWorkPerCPU is the minimum target number of constraint a task should hold + // in other words, if a level has less than minWorkPerCPU, it will not be parallelized and executed + // sequentially without sync. + const minWorkPerCPU = 50.0 // TODO @gbotrel revisit that with blocks. + + // cs.Levels has a list of levels, where all constraints in a level l(n) are independent + // and may only have dependencies on previous levels + // for each constraint + // we are guaranteed that each R1C contains at most one unsolved wire + // first we solve the unsolved wire (if any) + // then we check that the constraint is valid + // if a[i] * b[i] != c[i]; it means the constraint is not satisfied + var wg sync.WaitGroup + chTasks := make(chan []int, runtime.NumCPU()) + chError := make(chan error, runtime.NumCPU()) + + // start a worker pool + // each worker wait on chTasks + // a task is a slice of constraint indexes to be solved + for i := 0; i < runtime.NumCPU(); i++ { + go func() { + var scratch scratch + for t := range chTasks { + for _, i := range t { + if err := solver.processInstruction(solver.Instructions[i], &scratch); err != nil { + chError <- err + wg.Done() + return + } + } + wg.Done() + } + }() + } + + // clean up pool go routines + defer func() { + close(chTasks) + close(chError) + }() + + var scratch scratch + + // for each level, we push the tasks + for _, level := range solver.Levels { + + // max CPU to use + maxCPU := float64(len(level)) / minWorkPerCPU + + if maxCPU <= 1.0 { + // we do it sequentially + for _, i := range level { + if err := solver.processInstruction(solver.Instructions[i], &scratch); err != nil { + return err + } + } + continue + } + + // number of tasks for this level is set to number of CPU + // but if we don't have enough work for all our CPU, it can be lower. + nbTasks := runtime.NumCPU() + maxTasks := int(math.Ceil(maxCPU)) + if nbTasks > maxTasks { + nbTasks = maxTasks + } + nbIterationsPerCpus := len(level) / nbTasks + + // more CPUs than tasks: a CPU will work on exactly one iteration + // note: this depends on minWorkPerCPU constant + if nbIterationsPerCpus < 1 { + nbIterationsPerCpus = 1 + nbTasks = len(level) + } + + extraTasks := len(level) - (nbTasks * nbIterationsPerCpus) + extraTasksOffset := 0 + + for i := 0; i < nbTasks; i++ { + wg.Add(1) + _start := i*nbIterationsPerCpus + extraTasksOffset + _end := _start + nbIterationsPerCpus + if extraTasks > 0 { + _end++ + extraTasks-- + extraTasksOffset++ + } + // since we're never pushing more than num CPU tasks + // we will never be blocked here + chTasks <- level[_start:_end] + } + + // wait for the level to be done + wg.Wait() + + if len(chError) > 0 { + return <-chError + } + } + + if int(solver.nbSolved) != len(solver.values) { + return errors.New("solver didn't assign a value to all wires") + } + + return nil +} + +// solveR1C compute unsolved wires in the constraint, if any and set the solver accordingly +// +// returns an error if the solver called a hint function that errored +// returns false, nil if there was no wire to solve +// returns true, nil if exactly one wire was solved. In that case, it is redundant to check that +// the constraint is satisfied later. +func (solver *solver) solveR1C(cID uint32, r *constraint.R1C) error { + a, b, c := &solver.a[cID], &solver.b[cID], &solver.c[cID] + + // the index of the non-zero entry shows if L, R or O has an uninstantiated wire + // the content is the ID of the wire non instantiated + var loc uint8 + + var termToCompute constraint.Term + + processLExp := func(l constraint.LinearExpression, val *fr.Element, locValue uint8) { + for _, t := range l { + vID := t.WireID() + + // wire is already computed, we just accumulate in val + if solver.solved[vID] { + solver.accumulateInto(t, val) + continue + } + + if loc != 0 { + panic("found more than one wire to instantiate") + } + termToCompute = t + loc = locValue + } + } + + processLExp(r.L, a, 1) + processLExp(r.R, b, 2) + processLExp(r.O, c, 3) + + if loc == 0 { + // there is nothing to solve, may happen if we have an assertion + // (ie a constraints that doesn't yield any output) + // or if we solved the unsolved wires with hint functions + var check fr.Element + if !check.Mul(a, b).Equal(c) { + return solver.wrapErrWithDebugInfo(cID, fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String())) + } + return nil + } + + // we compute the wire value and instantiate it + wID := termToCompute.WireID() + + // solver result + var wire fr.Element + + switch loc { + case 1: + if !b.IsZero() { + wire.Div(c, b). + Sub(&wire, a) + a.Add(a, &wire) + } else { + // we didn't actually ensure that a * b == c + var check fr.Element + if !check.Mul(a, b).Equal(c) { + return solver.wrapErrWithDebugInfo(cID, fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String())) + } + } + case 2: + if !a.IsZero() { + wire.Div(c, a). + Sub(&wire, b) + b.Add(b, &wire) + } else { + var check fr.Element + if !check.Mul(a, b).Equal(c) { + return solver.wrapErrWithDebugInfo(cID, fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String())) + } + } + case 3: + wire.Mul(a, b). + Sub(&wire, c) + + c.Add(c, &wire) + } + + // wire is the term (coeff * value) + // but in the solver we want to store the value only + // note that in gnark frontend, coeff here is always 1 or -1 + solver.divByCoeff(&wire, termToCompute.CID) + solver.set(wID, wire) + + return nil +} + +// UnsatisfiedConstraintError wraps an error with useful metadata on the unsatisfied constraint +type UnsatisfiedConstraintError struct { + Err error + CID int // constraint ID + DebugInfo *string // optional debug info +} + +func (r *UnsatisfiedConstraintError) Error() string { + if r.DebugInfo != nil { + return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, *r.DebugInfo) + } + return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, r.Err.Error()) +} + +func (solver *solver) wrapErrWithDebugInfo(cID uint32, err error) *UnsatisfiedConstraintError { + var debugInfo *string + if dID, ok := solver.MDebug[int(cID)]; ok { + debugInfo = new(string) + *debugInfo = solver.logValue(solver.DebugInfo[dID]) + } + return &UnsatisfiedConstraintError{CID: int(cID), Err: err, DebugInfo: debugInfo} +} + +// temporary variables to avoid memallocs in hotloop +type scratch struct { + tR1C constraint.R1C + tHint constraint.HintMapping +} diff --git a/constraint/tinyfield/system.go b/constraint/tinyfield/system.go new file mode 100644 index 0000000000..05f7fbefaf --- /dev/null +++ b/constraint/tinyfield/system.go @@ -0,0 +1,365 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package cs + +import ( + "github.com/fxamacker/cbor/v2" + "io" + "time" + + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint" + csolver "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/internal/backend/ioutils" + "github.com/consensys/gnark/logger" + "reflect" + + "github.com/consensys/gnark-crypto/ecc" + + fr "github.com/consensys/gnark/internal/tinyfield" +) + +type R1CS = system +type SparseR1CS = system + +// system is a curved-typed constraint.System with a concrete coefficient table (fr.Element) +type system struct { + constraint.System + CoeffTable + field +} + +func NewR1CS(capacity int) *R1CS { + return newSystem(capacity, constraint.SystemR1CS) +} + +func NewSparseR1CS(capacity int) *SparseR1CS { + return newSystem(capacity, constraint.SystemSparseR1CS) +} + +func newSystem(capacity int, t constraint.SystemType) *system { + return &system{ + System: constraint.NewSystem(fr.Modulus(), capacity, t), + CoeffTable: newCoeffTable(capacity / 10), + } +} + +// Solve solves the constraint system with provided witness. +// If it's a R1CS returns R1CSSolution +// If it's a SparseR1CS returns SparseR1CSSolution +func (cs *system) Solve(witness witness.Witness, opts ...csolver.Option) (any, error) { + log := logger.Logger().With().Int("nbConstraints", cs.GetNbConstraints()).Logger() + start := time.Now() + + v := witness.Vector().(fr.Vector) + + // init the solver + solver, err := newSolver(cs, v, opts...) + if err != nil { + log.Err(err).Send() + return nil, err + } + + // defer log printing once all solver.values are computed + // (or sooner, if a constraint is not satisfied) + defer solver.printLogs(cs.Logs) + + // run it. + if err := solver.run(); err != nil { + log.Err(err).Send() + return nil, err + } + + log.Debug().Dur("took", time.Since(start)).Msg("constraint system solver done") + + // format the solution + // TODO @gbotrel revisit post-refactor + if cs.Type == constraint.SystemR1CS { + var res R1CSSolution + res.W = solver.values + res.A = solver.a + res.B = solver.b + res.C = solver.c + return &res, nil + } else { + // sparse R1CS + var res SparseR1CSSolution + // query l, r, o in Lagrange basis, not blinded + res.L, res.R, res.O = evaluateLROSmallDomain(cs, solver.values) + + return &res, nil + } + +} + +// IsSolved +// Deprecated: use _, err := Solve(...) instead +func (cs *system) IsSolved(witness witness.Witness, opts ...csolver.Option) error { + _, err := cs.Solve(witness, opts...) + return err +} + +// GetR1Cs return the list of R1C +func (cs *system) GetR1Cs() []constraint.R1C { + toReturn := make([]constraint.R1C, 0, cs.GetNbConstraints()) + + for _, inst := range cs.Instructions { + blueprint := cs.Blueprints[inst.BlueprintID] + if bc, ok := blueprint.(constraint.BlueprintR1C); ok { + var r1c constraint.R1C + bc.DecompressR1C(&r1c, cs.GetCallData(inst)) + toReturn = append(toReturn, r1c) + } else { + panic("not implemented") + } + } + return toReturn +} + +// GetNbCoefficients return the number of unique coefficients needed in the R1CS +func (cs *system) GetNbCoefficients() int { + return len(cs.Coefficients) +} + +// CurveID returns curve ID as defined in gnark-crypto +func (cs *system) CurveID() ecc.ID { + return ecc.UNKNOWN +} + +// WriteTo encodes R1CS into provided io.Writer using cbor +func (cs *system) WriteTo(w io.Writer) (int64, error) { + _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written + ts := getTagSet() + enc, err := cbor.CoreDetEncOptions().EncModeWithTags(ts) + if err != nil { + return 0, err + } + encoder := enc.NewEncoder(&_w) + + // encode our object + err = encoder.Encode(cs) + return _w.N, err +} + +// ReadFrom attempts to decode R1CS from io.Reader using cbor +func (cs *system) ReadFrom(r io.Reader) (int64, error) { + ts := getTagSet() + dm, err := cbor.DecOptions{ + MaxArrayElements: 134217728, + MaxMapPairs: 134217728, + }.DecModeWithTags(ts) + + if err != nil { + return 0, err + } + decoder := dm.NewDecoder(r) + + // initialize coeff table + cs.CoeffTable = newCoeffTable(0) + + if err := decoder.Decode(&cs); err != nil { + return int64(decoder.NumBytesRead()), err + } + + if err := cs.CheckSerializationHeader(); err != nil { + return int64(decoder.NumBytesRead()), err + } + + return int64(decoder.NumBytesRead()), nil +} + +func (cs *system) GetCoefficient(i int) (r constraint.Element) { + copy(r[:], cs.Coefficients[i][:]) + return +} + +// GetSparseR1Cs return the list of SparseR1C +func (cs *system) GetSparseR1Cs() []constraint.SparseR1C { + + toReturn := make([]constraint.SparseR1C, 0, cs.GetNbConstraints()) + + for _, inst := range cs.Instructions { + blueprint := cs.Blueprints[inst.BlueprintID] + if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { + var sparseR1C constraint.SparseR1C + calldata := cs.CallData[inst.StartCallData : inst.StartCallData+uint64(blueprint.NbInputs())] + bc.DecompressSparseR1C(&sparseR1C, calldata) + toReturn = append(toReturn, sparseR1C) + } else { + panic("not implemented") + } + } + return toReturn +} + +// evaluateLROSmallDomain extracts the solver l, r, o, and returns it in lagrange form. +// solver = [ public | secret | internal ] +// TODO @gbotrel refactor; this seems to be a small util function for plonk +func evaluateLROSmallDomain(cs *system, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { + + //s := int(pk.Domain[0].Cardinality) + s := cs.GetNbConstraints() + len(cs.Public) // len(spr.Public) is for the placeholder constraints + s = int(ecc.NextPowerOfTwo(uint64(s))) + + var l, r, o []fr.Element + l = make([]fr.Element, s) + r = make([]fr.Element, s) + o = make([]fr.Element, s) + s0 := solution[0] + + for i := 0; i < len(cs.Public); i++ { // placeholders + l[i] = solution[i] + r[i] = s0 + o[i] = s0 + } + offset := len(cs.Public) + nbConstraints := cs.GetNbConstraints() + + var sparseR1C constraint.SparseR1C + j := 0 + for _, inst := range cs.Instructions { + blueprint := cs.Blueprints[inst.BlueprintID] + if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { + bc.DecompressSparseR1C(&sparseR1C, cs.GetCallData(inst)) + + l[offset+j] = solution[sparseR1C.XA] + r[offset+j] = solution[sparseR1C.XB] + o[offset+j] = solution[sparseR1C.XC] + j++ + } + } + + offset += nbConstraints + + for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solver[0]) + l[offset+i] = s0 + r[offset+i] = s0 + o[offset+i] = s0 + } + + return l, r, o + +} + +// R1CSSolution represent a valid assignment to all the variables in the constraint system. +// The vector W such that Aw o Bw - Cw = 0 +type R1CSSolution struct { + W fr.Vector + A, B, C fr.Vector +} + +func (t *R1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.W.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.A.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.B.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.C.WriteTo(w) + n += a + return n, err +} + +func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.W.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.A.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.B.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.C.ReadFrom(r) + n += a + return n, err +} + +// SparseR1CSSolution represent a valid assignment to all the variables in the constraint system. +type SparseR1CSSolution struct { + L, R, O fr.Vector +} + +func (t *SparseR1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.L.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.R.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.O.WriteTo(w) + n += a + return n, err + +} + +func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.L.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.R.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.O.ReadFrom(r) + a += n + return n, err +} + +func getTagSet() cbor.TagSet { + // temporary for refactor + ts := cbor.NewTagSet() + // https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml + // 65536-15309735 Unassigned + tagNum := uint64(5309735) + addType := func(t reflect.Type) { + if err := ts.Add( + cbor.TagOptions{EncTag: cbor.EncTagRequired, DecTag: cbor.DecTagRequired}, + t, + tagNum, + ); err != nil { + panic(err) + } + tagNum++ + } + + addType(reflect.TypeOf(constraint.BlueprintGenericHint{})) + addType(reflect.TypeOf(constraint.BlueprintGenericR1C{})) + addType(reflect.TypeOf(constraint.BlueprintGenericSparseR1C{})) + addType(reflect.TypeOf(constraint.BlueprintSparseR1CAdd{})) + addType(reflect.TypeOf(constraint.BlueprintSparseR1CMul{})) + + return ts +} diff --git a/debug_test.go b/debug_test.go index 34d4d075bf..620e9860d0 100644 --- a/debug_test.go +++ b/debug_test.go @@ -10,6 +10,7 @@ import ( "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/backend/plonk" "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/debug" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/consensys/gnark/frontend/cs/scs" @@ -47,11 +48,11 @@ func TestPrintln(t *testing.T) { witness.B = 11 var expected bytes.Buffer - expected.WriteString("debug_test.go:29 > 13 is the addition\n") - expected.WriteString("debug_test.go:31 > 26 42\n") - expected.WriteString("debug_test.go:33 > bits 1\n") - expected.WriteString("debug_test.go:34 > circuit {A: 2, B: 11}\n") - expected.WriteString("debug_test.go:38 > m .*\n") + expected.WriteString("debug_test.go:30 > 13 is the addition\n") + expected.WriteString("debug_test.go:32 > 26 42\n") + expected.WriteString("debug_test.go:34 > bits 1\n") + expected.WriteString("debug_test.go:35 > circuit {A: 2, B: 11}\n") + expected.WriteString("debug_test.go:39 > m .*\n") { trace, _ := getGroth16Trace(&circuit, &witness) @@ -95,9 +96,14 @@ func TestTraceDivBy0(t *testing.T) { { _, err := getPlonkTrace(&circuit, &witness) assert.Error(err) - assert.Contains(err.Error(), "constraint #1 is not satisfied: [inverse] 1/0 < ∞") - assert.Contains(err.Error(), "(*divBy0Trace).Define") - assert.Contains(err.Error(), "debug_test.go:") + if debug.Debug { + assert.Contains(err.Error(), "constraint #1 is not satisfied: [inverse] 1/0 < ∞") + assert.Contains(err.Error(), "(*divBy0Trace).Define") + assert.Contains(err.Error(), "debug_test.go:") + } else { + assert.Contains(err.Error(), "constraint #1 is not satisfied: division by 0") + } + } } @@ -124,17 +130,26 @@ func TestTraceNotEqual(t *testing.T) { { _, err := getGroth16Trace(&circuit, &witness) assert.Error(err) - assert.Contains(err.Error(), "constraint #0 is not satisfied: [assertIsEqual] 1 == 66") - assert.Contains(err.Error(), "(*notEqualTrace).Define") - assert.Contains(err.Error(), "debug_test.go:") + if debug.Debug { + assert.Contains(err.Error(), "constraint #0 is not satisfied: [assertIsEqual] 1 == 66") + assert.Contains(err.Error(), "(*notEqualTrace).Define") + assert.Contains(err.Error(), "debug_test.go:") + } else { + assert.Contains(err.Error(), "constraint #0 is not satisfied: 1 ⋅ 1 != 66") + } } { _, err := getPlonkTrace(&circuit, &witness) assert.Error(err) - assert.Contains(err.Error(), "constraint #1 is not satisfied: [assertIsEqual] 1 == 66") - assert.Contains(err.Error(), "(*notEqualTrace).Define") - assert.Contains(err.Error(), "debug_test.go:") + if debug.Debug { + assert.Contains(err.Error(), "constraint #1 is not satisfied: [assertIsEqual] 1 == 66") + assert.Contains(err.Error(), "(*notEqualTrace).Define") + assert.Contains(err.Error(), "debug_test.go:") + } else { + assert.Contains(err.Error(), "constraint #1 is not satisfied: qL⋅xa + qR⋅xb + qO⋅xc + qM⋅(xaxb) + qC != 0 → 1 + -66 + 0 + 0 + 0 != 0") + } + } } diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index 84e86052fe..76e4db5de5 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -19,12 +19,14 @@ package r1cs import ( "errors" "fmt" - "github.com/consensys/gnark/frontend/cs" "path/filepath" "reflect" "runtime" "strings" + "github.com/consensys/gnark/debug" + "github.com/consensys/gnark/frontend/cs" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" @@ -55,14 +57,14 @@ func (builder *builder) MulAcc(a, b, c frontend.Variable) frontend.Variable { // v1 and v2 are both unknown, this is the only case we add a constraint if !v1Constant && !v2Constant { res := builder.newInternalVariable() - builder.cs.AddConstraint(builder.newR1C(b, c, res)) + builder.cs.AddR1C(builder.newR1C(b, c, res), builder.genericGate) builder.mbuf1 = append(builder.mbuf1, res...) return } // v1 and v2 are constants, we multiply big.Int values and return resulting constant if v1Constant && v2Constant { - builder.cs.Mul(&n1, &n2) + n1 = builder.cs.Mul(n1, n2) builder.mbuf1 = append(builder.mbuf1, expr.NewTerm(0, n1)) return } @@ -143,9 +145,9 @@ func (builder *builder) add(vars []expr.LinearExpression, sub bool, capacity int if curr != -1 && t.VID == (*res)[curr].VID { // accumulate, it's the same variable ID if sub && lID != 0 { - builder.cs.Sub(&(*res)[curr].Coeff, &t.Coeff) + (*res)[curr].Coeff = builder.cs.Sub((*res)[curr].Coeff, t.Coeff) } else { - builder.cs.Add(&(*res)[curr].Coeff, &t.Coeff) + (*res)[curr].Coeff = builder.cs.Add((*res)[curr].Coeff, t.Coeff) } if (*res)[curr].Coeff.IsZero() { // remove self. @@ -157,14 +159,14 @@ func (builder *builder) add(vars []expr.LinearExpression, sub bool, capacity int (*res) = append((*res), *t) curr++ if sub && lID != 0 { - builder.cs.Neg(&(*res)[curr].Coeff) + (*res)[curr].Coeff = builder.cs.Neg((*res)[curr].Coeff) } } } if len((*res)) == 0 { // keep the linear expression valid (assertIsSet) - (*res) = append((*res), expr.NewTerm(0, constraint.Coeff{})) + (*res) = append((*res), expr.NewTerm(0, constraint.Element{})) } // if the linear expression LE is too long then record an equality // constraint LE * 1 = t and return short linear expression instead. @@ -183,7 +185,7 @@ func (builder *builder) Neg(i frontend.Variable) frontend.Variable { v := builder.toVariable(i) if n, ok := builder.constantValue(v); ok { - builder.cs.Neg(&n) + n = builder.cs.Neg(n) return expr.NewLinearExpression(0, n) } @@ -202,13 +204,13 @@ func (builder *builder) Mul(i1, i2 frontend.Variable, in ...frontend.Variable) f // v1 and v2 are both unknown, this is the only case we add a constraint if !v1Constant && !v2Constant { res := builder.newInternalVariable() - builder.cs.AddConstraint(builder.newR1C(v1, v2, res)) + builder.cs.AddR1C(builder.newR1C(v1, v2, res), builder.genericGate) return res } // v1 and v2 are constants, we multiply big.Int values and return resulting constant if v1Constant && v2Constant { - builder.cs.Mul(&n1, &n2) + n1 = builder.cs.Mul(n1, n2) return expr.NewLinearExpression(0, n1) } @@ -227,7 +229,7 @@ func (builder *builder) Mul(i1, i2 frontend.Variable, in ...frontend.Variable) f return res } -func (builder *builder) mulConstant(v1 expr.LinearExpression, lambda constraint.Coeff, inPlace bool) expr.LinearExpression { +func (builder *builder) mulConstant(v1 expr.LinearExpression, lambda constraint.Element, inPlace bool) expr.LinearExpression { // multiplying a frontend.Variable by a constant -> we updated the coefficients in the linear expression // leading to that frontend.Variable var res expr.LinearExpression @@ -238,7 +240,7 @@ func (builder *builder) mulConstant(v1 expr.LinearExpression, lambda constraint. } for i := 0; i < len(res); i++ { - builder.cs.Mul(&res[i].Coeff, &lambda) + res[i].Coeff = builder.cs.Mul(res[i].Coeff, lambda) } return res } @@ -254,9 +256,12 @@ func (builder *builder) DivUnchecked(i1, i2 frontend.Variable) frontend.Variable if !v2Constant { res := builder.newInternalVariable() - debug := builder.newDebugInfo("div", v1, "/", v2, " == ", res) // note that here we don't ensure that divisor is != 0 - builder.cs.AddConstraint(builder.newR1C(v2, res, v1), debug) + cID := builder.cs.AddR1C(builder.newR1C(v2, res, v1), builder.genericGate) + if debug.Debug { + debug := builder.newDebugInfo("div", v1, "/", v2, " == ", res) + builder.cs.AttachDebugInfo(debug, []int{cID}) + } return res } @@ -264,12 +269,10 @@ func (builder *builder) DivUnchecked(i1, i2 frontend.Variable) frontend.Variable if n2.IsZero() { panic("div by constant(0)") } - // q := builder.q - builder.cs.Inverse(&n2) - // n2.ModInverse(n2, q) + n2, _ = builder.cs.Inverse(n2) if v1Constant { - builder.cs.Mul(&n2, &n1) + n2 = builder.cs.Mul(n2, n1) return expr.NewLinearExpression(0, n2) } @@ -292,8 +295,8 @@ func (builder *builder) Div(i1, i2 frontend.Variable) frontend.Variable { debug := builder.newDebugInfo("div", v1, "/", v2, " == ", res) v2Inv := builder.newInternalVariable() // note that here we ensure that v2 can't be 0, but it costs us one extra constraint - c1 := builder.cs.AddConstraint(builder.newR1C(v2, v2Inv, builder.cstOne())) - c2 := builder.cs.AddConstraint(builder.newR1C(v1, v2Inv, res)) + c1 := builder.cs.AddR1C(builder.newR1C(v2, v2Inv, builder.cstOne()), builder.genericGate) + c2 := builder.cs.AddR1C(builder.newR1C(v1, v2Inv, res), builder.genericGate) builder.cs.AttachDebugInfo(debug, []int{c1, c2}) return res } @@ -302,10 +305,10 @@ func (builder *builder) Div(i1, i2 frontend.Variable) frontend.Variable { if n2.IsZero() { panic("div by constant(0)") } - builder.cs.Inverse(&n2) + n2, _ = builder.cs.Inverse(n2) if v1Constant { - builder.cs.Mul(&n2, &n1) + n2 = builder.cs.Mul(n2, n1) return expr.NewLinearExpression(0, n2) } @@ -322,15 +325,18 @@ func (builder *builder) Inverse(i1 frontend.Variable) frontend.Variable { panic("inverse by constant(0)") } - builder.cs.Inverse(&c) + c, _ = builder.cs.Inverse(c) return expr.NewLinearExpression(0, c) } // allocate resulting frontend.Variable res := builder.newInternalVariable() - debug := builder.newDebugInfo("inverse", vars[0], "*", res, " == 1") - builder.cs.AddConstraint(builder.newR1C(res, vars[0], builder.cstOne()), debug) + cID := builder.cs.AddR1C(builder.newR1C(res, vars[0], builder.cstOne()), builder.genericGate) + if debug.Debug { + debug := builder.newDebugInfo("inverse", vars[0], "*", res, " == 1") + builder.cs.AttachDebugInfo(debug, []int{cID}) + } return res } @@ -406,7 +412,7 @@ func (builder *builder) Or(_a, _b frontend.Variable) frontend.Variable { c = append(c, a...) c = append(c, b...) - builder.cs.AddConstraint(builder.newR1C(a, b, c)) + builder.cs.AddR1C(builder.newR1C(a, b, c), builder.genericGate) return res } @@ -441,7 +447,7 @@ func (builder *builder) Select(i0, i1, i2 frontend.Variable) frontend.Variable { if c, ok := builder.constantValue(cond); ok { // condition is a constant return i1 if true, i2 if false - if builder.isCstOne(&c) { + if builder.isCstOne(c) { return vars[1] } return vars[2] @@ -451,7 +457,7 @@ func (builder *builder) Select(i0, i1, i2 frontend.Variable) frontend.Variable { n2, ok2 := builder.constantValue(vars[2]) if ok1 && ok2 { - builder.cs.Sub(&n1, &n2) + n1 = builder.cs.Sub(n1, n2) res := builder.Mul(cond, n1) // no constraint is recorded res = builder.Add(res, vars[2]) // no constraint is recorded return res @@ -488,8 +494,8 @@ func (builder *builder) Lookup2(b0, b1 frontend.Variable, i0, i1, i2, i3 fronten c1, b1IsConstant := builder.constantValue(s1) if b0IsConstant && b1IsConstant { - b0 := builder.isCstOne(&c0) - b1 := builder.isCstOne(&c1) + b0 := builder.isCstOne(c0) + b1 := builder.isCstOne(c1) if !b0 && !b1 { return in0 @@ -550,10 +556,10 @@ func (builder *builder) IsZero(i1 frontend.Variable) frontend.Variable { } // m = -a*x + 1 // constrain m to be 1 if a == 0 - c1 := builder.cs.AddConstraint(builder.newR1C(builder.Neg(a), x[0], builder.Sub(m, 1))) + c1 := builder.cs.AddR1C(builder.newR1C(builder.Neg(a), x[0], builder.Sub(m, 1)), builder.genericGate) // a * m = 0 // constrain m to be 0 if a != 0 - c2 := builder.cs.AddConstraint(builder.newR1C(a, m, builder.cstZero())) + c2 := builder.cs.AddR1C(builder.newR1C(a, m, builder.cstZero()), builder.genericGate) builder.cs.AttachDebugInfo(debug, []int{c1, c2}) @@ -660,7 +666,7 @@ func (builder *builder) negateLinExp(l expr.LinearExpression) expr.LinearExpress res := make(expr.LinearExpression, len(l)) copy(res, l) for i := 0; i < len(res); i++ { - builder.cs.Neg(&res[i].Coeff) + res[i].Coeff = builder.cs.Neg(res[i].Coeff) } return res } diff --git a/frontend/cs/r1cs/api_assertions.go b/frontend/cs/r1cs/api_assertions.go index dd1d155aa3..3c249f4845 100644 --- a/frontend/cs/r1cs/api_assertions.go +++ b/frontend/cs/r1cs/api_assertions.go @@ -32,9 +32,12 @@ func (builder *builder) AssertIsEqual(i1, i2 frontend.Variable) { r := builder.getLinearExpression(builder.toVariable(i1)) o := builder.getLinearExpression(builder.toVariable(i2)) - debug := builder.newDebugInfo("assertIsEqual", r, " == ", o) + cID := builder.cs.AddR1C(builder.newR1C(builder.cstOne(), r, o), builder.genericGate) - builder.cs.AddConstraint(builder.newR1C(builder.cstOne(), r, o), debug) + if debug.Debug { + debug := builder.newDebugInfo("assertIsEqual", r, " == ", o) + builder.cs.AttachDebugInfo(debug, []int{cID}) + } } // AssertIsDifferent constrain i1 and i2 to be different @@ -53,7 +56,7 @@ func (builder *builder) AssertIsBoolean(i1 frontend.Variable) { v := builder.toVariable(i1) if b, ok := builder.constantValue(v); ok { - if !(builder.isCstZero(&b) || builder.isCstOne(&b)) { + if !(b.IsZero() || builder.isCstOne(b)) { panic("assertIsBoolean failed: constant is not 0 or 1") // TODO @gbotrel print } return @@ -71,11 +74,10 @@ func (builder *builder) AssertIsBoolean(i1 frontend.Variable) { V := builder.getLinearExpression(v) + cID := builder.cs.AddR1C(builder.newR1C(V, _v, o), builder.genericGate) if debug.Debug { debug := builder.newDebugInfo("assertIsBoolean", V, " == (0|1)") - builder.cs.AddConstraint(builder.newR1C(V, _v, o), debug) - } else { - builder.cs.AddConstraint(builder.newR1C(V, _v, o)) + builder.cs.AttachDebugInfo(debug, []int{cID}) } } @@ -91,7 +93,7 @@ func (builder *builder) AssertIsLessOrEqual(v frontend.Variable, bound frontend. // both inputs are constants if vConst && bConst { - bv, bb := builder.cs.ToBigInt(&cv), builder.cs.ToBigInt(&cb) + bv, bb := builder.cs.ToBigInt(cv), builder.cs.ToBigInt(cb) if bv.Cmp(bb) == 1 { panic(fmt.Sprintf("AssertIsLessOrEqual: %s > %s", bv.String(), bb.String())) } @@ -100,7 +102,7 @@ func (builder *builder) AssertIsLessOrEqual(v frontend.Variable, bound frontend. // bound is constant if bConst { vv := builder.toVariable(v) - builder.mustBeLessOrEqCst(vv, builder.cs.ToBigInt(&cb)) + builder.mustBeLessOrEqCst(vv, builder.cs.ToBigInt(cb)) return } @@ -153,9 +155,10 @@ func (builder *builder) mustBeLessOrEqVar(a, bound frontend.Variable) { if aConst { // aBits[i] is a constant; l = builder.Mul(l, aBits[i]) - added = append(added, builder.cs.AddConstraint(builder.newR1C(l, zero, zero))) + // TODO @gbotrel this constraint seems useless. + added = append(added, builder.cs.AddR1C(builder.newR1C(l, zero, zero), builder.genericGate)) } else { - added = append(added, builder.cs.AddConstraint(builder.newR1C(l, aBits[i], zero))) + added = append(added, builder.cs.AddR1C(builder.newR1C(l, aBits[i], zero), builder.genericGate)) } } @@ -212,7 +215,7 @@ func (builder *builder) mustBeLessOrEqCst(a expr.LinearExpression, bound *big.In l := builder.Sub(1, p[i+1]) l = builder.Sub(l, aBits[i]) - added = append(added, builder.cs.AddConstraint(builder.newR1C(l, aBits[i], builder.cstZero()))) + added = append(added, builder.cs.AddR1C(builder.newR1C(l, aBits[i], builder.cstZero()), builder.genericGate)) } else { builder.AssertIsBoolean(aBits[i]) } diff --git a/frontend/cs/r1cs/builder.go b/frontend/cs/r1cs/builder.go index 6d085e41fc..8fa82209a0 100644 --- a/frontend/cs/r1cs/builder.go +++ b/frontend/cs/r1cs/builder.go @@ -60,7 +60,9 @@ type builder struct { // map for recording boolean constrained variables (to not constrain them twice) mtBooleans map[uint64][]expr.LinearExpression - tOne constraint.Coeff + tOne constraint.Element + eZero, eOne expr.LinearExpression + cZero, cOne constraint.LinearExpression // helps merge k sorted linear expressions heap minHeap @@ -68,6 +70,8 @@ type builder struct { // buffers used to do in place api.MAC mbuf1 expr.LinearExpression mbuf2 expr.LinearExpression + + genericGate constraint.BlueprintID } // initialCapacity has quite some impact on frontend performance, especially on large circuits size @@ -116,6 +120,14 @@ func newBuilder(field *big.Int, config frontend.CompileConfig) *builder { builder.tOne = builder.cs.One() builder.cs.AddPublicVariable("1") + builder.genericGate = builder.cs.AddBlueprint(&constraint.BlueprintGenericR1C{}) + + builder.eZero = expr.NewLinearExpression(0, constraint.Element{}) + builder.eOne = expr.NewLinearExpression(0, builder.tOne) + + builder.cOne = constraint.LinearExpression{constraint.Term{VID: 0, CID: constraint.CoeffIdOne}} + builder.cZero = constraint.LinearExpression{constraint.Term{VID: 0, CID: constraint.CoeffIdZero}} + return &builder } @@ -140,19 +152,15 @@ func (builder *builder) SecretVariable(f schema.LeafInfo) frontend.Variable { // cstOne return the one constant func (builder *builder) cstOne() expr.LinearExpression { - return expr.NewLinearExpression(0, builder.tOne) + return builder.eOne } // cstZero return the zero constant func (builder *builder) cstZero() expr.LinearExpression { - return expr.NewLinearExpression(0, constraint.Coeff{}) + return builder.eZero } -func (builder *builder) isCstZero(c *constraint.Coeff) bool { - return c.IsZero() -} - -func (builder *builder) isCstOne(c *constraint.Coeff) bool { +func (builder *builder) isCstOne(c constraint.Element) bool { return builder.cs.IsOne(c) } @@ -189,6 +197,13 @@ func (builder *builder) getLinearExpression(_l interface{}) constraint.LinearExp var L constraint.LinearExpression switch tl := _l.(type) { case expr.LinearExpression: + if len(tl) == 1 && tl[0].VID == 0 { + if tl[0].Coeff.IsZero() { + return builder.cZero + } else if tl[0].Coeff == builder.tOne { + return builder.cOne + } + } L = make(constraint.LinearExpression, 0, len(tl)) for _, t := range tl { L = append(L, builder.cs.MakeTerm(&t.Coeff, t.VID)) @@ -209,7 +224,7 @@ func (builder *builder) getLinearExpression(_l interface{}) constraint.LinearExp // that is not api.AssertIsBoolean. If v is a constant, this is a no-op. func (builder *builder) MarkBoolean(v frontend.Variable) { if b, ok := builder.constantValue(v); ok { - if !(builder.isCstZero(&b) || builder.isCstOne(&b)) { + if !(b.IsZero() || builder.isCstOne(b)) { panic("MarkBoolean called a non-boolean constant") } return @@ -229,7 +244,7 @@ func (builder *builder) MarkBoolean(v frontend.Variable) { // This returns true if the v is a constant and v == 0 || v == 1. func (builder *builder) IsBoolean(v frontend.Variable) bool { if b, ok := builder.constantValue(v); ok { - return (builder.isCstZero(&b) || builder.isCstOne(&b)) + return (b.IsZero() || builder.isCstOne(b)) } // v is a linear expression l := v.(expr.LinearExpression) @@ -281,20 +296,20 @@ func (builder *builder) ConstantValue(v frontend.Variable) (*big.Int, bool) { if !ok { return nil, false } - return builder.cs.ToBigInt(&coeff), true + return builder.cs.ToBigInt(coeff), true } -func (builder *builder) constantValue(v frontend.Variable) (constraint.Coeff, bool) { +func (builder *builder) constantValue(v frontend.Variable) (constraint.Element, bool) { if _v, ok := v.(expr.LinearExpression); ok { assertIsSet(_v) if len(_v) != 1 { // TODO @gbotrel this assumes linear expressions of coeff are not possible // and are always reduced to one element. may not always be true? - return constraint.Coeff{}, false + return constraint.Element{}, false } if !(_v[0].WireID() == 0) { // public ONE WIRE - return constraint.Coeff{}, false + return constraint.Element{}, false } return _v[0].Coeff, true } @@ -315,9 +330,9 @@ func (builder *builder) toVariable(input interface{}) expr.LinearExpression { case *expr.LinearExpression: assertIsSet(*t) return *t - case constraint.Coeff: + case constraint.Element: return expr.NewLinearExpression(0, t) - case *constraint.Coeff: + case *constraint.Element: return expr.NewLinearExpression(0, *t) default: // try to make it into a constant @@ -424,10 +439,10 @@ func (builder *builder) newDebugInfo(errName string, in ...interface{}) constrai in[i] = builder.getLinearExpression(expr.LinearExpression{t}) case *expr.Term: in[i] = builder.getLinearExpression(expr.LinearExpression{*t}) - case constraint.Coeff: - in[i] = builder.cs.String(&t) - case *constraint.Coeff: + case constraint.Element: in[i] = builder.cs.String(t) + case *constraint.Element: + in[i] = builder.cs.String(*t) } } @@ -446,7 +461,7 @@ func (builder *builder) compress(le expr.LinearExpression) expr.LinearExpression one := builder.cstOne() t := builder.newInternalVariable() - builder.cs.AddConstraint(builder.newR1C(le, one, t)) + builder.cs.AddR1C(builder.newR1C(le, one, t), builder.genericGate) return t } diff --git a/frontend/cs/r1cs/r1cs_test.go b/frontend/cs/r1cs/r1cs_test.go index b7519e8f3a..ceb965322c 100644 --- a/frontend/cs/r1cs/r1cs_test.go +++ b/frontend/cs/r1cs/r1cs_test.go @@ -99,7 +99,7 @@ func BenchmarkReduce(b *testing.B) { // Add few large linear expressions // Add many large linear expressions // Doubling of large linear expressions - rand.Seed(time.Now().Unix()) + rand := rand.New(rand.NewSource(time.Now().Unix())) //#nosec G404 weak rng is fine here const nbTerms = 100000 terms := make([]frontend.Variable, nbTerms) for i := 0; i < len(terms); i++ { diff --git a/frontend/cs/scs/api.go b/frontend/cs/scs/api.go index f2e67b3cfe..1e932a34a2 100644 --- a/frontend/cs/scs/api.go +++ b/frontend/cs/scs/api.go @@ -18,12 +18,13 @@ package scs import ( "fmt" - "github.com/consensys/gnark/frontend/cs" "path/filepath" "reflect" "runtime" "strings" + "github.com/consensys/gnark/frontend/cs" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" @@ -40,7 +41,7 @@ func (builder *builder) Add(i1, i2 frontend.Variable, in ...frontend.Variable) f if len(vars) == 0 { // no variables, we return the constant. - return builder.cs.ToBigInt(&k) + return builder.cs.ToBigInt(k) } vars = builder.reduce(vars) @@ -75,11 +76,11 @@ func (builder *builder) Sub(i1, i2 frontend.Variable, in ...frontend.Variable) f // Neg returns -i func (builder *builder) Neg(i1 frontend.Variable) frontend.Variable { if n, ok := builder.constantValue(i1); ok { - builder.cs.Neg(&n) - return builder.cs.ToBigInt(&n) + n = builder.cs.Neg(n) + return builder.cs.ToBigInt(n) } v := i1.(expr.Term) - builder.cs.Neg(&v.Coeff) + v.Coeff = builder.cs.Neg(v.Coeff) return v } @@ -87,16 +88,16 @@ func (builder *builder) Neg(i1 frontend.Variable) frontend.Variable { func (builder *builder) Mul(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { vars, k := builder.filterConstantProd(append([]frontend.Variable{i1, i2}, in...)) if len(vars) == 0 { - return builder.cs.ToBigInt(&k) + return builder.cs.ToBigInt(k) } - l := builder.mulConstant(vars[0], &k) + l := builder.mulConstant(vars[0], k) return builder.splitProd(l, vars[1:]) } // returns t*m -func (builder *builder) mulConstant(t expr.Term, m *constraint.Coeff) expr.Term { - builder.cs.Mul(&t.Coeff, m) +func (builder *builder) mulConstant(t expr.Term, m constraint.Element) expr.Term { + t.Coeff = builder.cs.Mul(t.Coeff, m) return t } @@ -109,25 +110,32 @@ func (builder *builder) DivUnchecked(i1, i2 frontend.Variable) frontend.Variable if c2.IsZero() { panic("inverse by constant(0)") } - builder.cs.Inverse(&c2) - builder.cs.Mul(&c2, &c1) - return builder.cs.ToBigInt(&c2) + c2, _ = builder.cs.Inverse(c2) + c2 = builder.cs.Mul(c2, c1) + return builder.cs.ToBigInt(c2) } if i2Constant { if c2.IsZero() { panic("inverse by constant(0)") } - builder.cs.Inverse(&c2) - return builder.mulConstant(i1.(expr.Term), &c2) + c2, _ = builder.cs.Inverse(c2) + return builder.mulConstant(i1.(expr.Term), c2) } if i1Constant { res := builder.Inverse(i2) - return builder.mulConstant(res.(expr.Term), &c1) + return builder.mulConstant(res.(expr.Term), c1) } // res * i2 == i1 res := builder.newInternalVariable() - builder.addMulGate(res, i2.(expr.Term), i1.(expr.Term)) + builder.addPlonkConstraint(sparseR1C{ + xa: res.VID, + xb: i2.(expr.Term).VID, + xc: i1.(expr.Term).VID, + qM: i2.(expr.Term).Coeff, + qO: builder.cs.Neg(i1.(expr.Term).Coeff), + }) + return res } @@ -145,8 +153,8 @@ func (builder *builder) Inverse(i1 frontend.Variable) frontend.Variable { if c.IsZero() { panic("inverse by constant(0)") } - builder.cs.Inverse(&c) - return builder.cs.ToBigInt(&c) + c, _ = builder.cs.Inverse(c) + return builder.cs.ToBigInt(c) } t := i1.(expr.Term) debug := builder.newDebugInfo("inverse", "1/", i1, " < ∞") @@ -202,10 +210,10 @@ func (builder *builder) Xor(a, b frontend.Variable) frontend.Variable { if aConstant && bConstant { b0 := 0 b1 := 0 - if builder.cs.IsOne(&_a) { + if builder.cs.IsOne(_a) { b0 = 1 } - if builder.cs.IsOne(&_b) { + if builder.cs.IsOne(_b) { b1 = 1 } return b0 ^ b1 @@ -224,9 +232,9 @@ func (builder *builder) Xor(a, b frontend.Variable) frontend.Variable { xa := a.(expr.Term) // 1 - 2b qL := builder.tOne - builder.cs.Sub(&qL, &_b) - builder.cs.Sub(&qL, &_b) - builder.cs.Mul(&qL, &xa.Coeff) + qL = builder.cs.Sub(qL, _b) + qL = builder.cs.Sub(qL, _b) + qL = builder.cs.Mul(qL, xa.Coeff) // (1-2b)a + b == res builder.addPlonkConstraint(sparseR1C{ @@ -244,15 +252,12 @@ func (builder *builder) Xor(a, b frontend.Variable) frontend.Variable { // -a - b + 2ab + res == 0 qM := builder.tOne - builder.cs.Add(&qM, &qM) - builder.cs.Mul(&qM, &xa.Coeff) - builder.cs.Mul(&qM, &xb.Coeff) + qM = builder.cs.Add(qM, qM) + qM = builder.cs.Mul(qM, xa.Coeff) + qM = builder.cs.Mul(qM, xb.Coeff) - qL := xa.Coeff - qR := xb.Coeff - - builder.cs.Neg(&qL) - builder.cs.Neg(&qR) + qL := builder.cs.Neg(xa.Coeff) + qR := builder.cs.Neg(xb.Coeff) builder.addPlonkConstraint(sparseR1C{ xa: xa.VID, @@ -277,7 +282,7 @@ func (builder *builder) Or(a, b frontend.Variable) frontend.Variable { _b, bConstant := builder.constantValue(b) if aConstant && bConstant { - if builder.cs.IsOne(&_a) || builder.cs.IsOne(&_b) { + if builder.cs.IsOne(_a) || builder.cs.IsOne(_b) { return 1 } return 0 @@ -297,8 +302,8 @@ func (builder *builder) Or(a, b frontend.Variable) frontend.Variable { xa := a.(expr.Term) // b = b - 1 qL := _b - builder.cs.Sub(&qL, &builder.tOne) - builder.cs.Mul(&qL, &xa.Coeff) + qL = builder.cs.Sub(qL, builder.tOne) + qL = builder.cs.Mul(qL, xa.Coeff) // a * (b-1) + res == 0 builder.addPlonkConstraint(sparseR1C{ xa: xa.VID, @@ -312,14 +317,10 @@ func (builder *builder) Or(a, b frontend.Variable) frontend.Variable { xb := b.(expr.Term) // -a - b + ab + res == 0 - qM := xa.Coeff - builder.cs.Mul(&qM, &xb.Coeff) - - qL := xa.Coeff - qR := xb.Coeff + qM := builder.cs.Mul(xa.Coeff, xb.Coeff) - builder.cs.Neg(&qL) - builder.cs.Neg(&qR) + qL := builder.cs.Neg(xa.Coeff) + qR := builder.cs.Neg(xb.Coeff) builder.addPlonkConstraint(sparseR1C{ xa: xa.VID, @@ -352,7 +353,7 @@ func (builder *builder) Select(b frontend.Variable, i1, i2 frontend.Variable) fr if bConstant { if !builder.IsBoolean(b) { - panic(fmt.Sprintf("%s should be 0 or 1", builder.cs.String(&_b))) + panic(fmt.Sprintf("%s should be 0 or 1", builder.cs.String(_b))) } if _b.IsZero() { return i2 @@ -379,8 +380,8 @@ func (builder *builder) Lookup2(b0, b1 frontend.Variable, i0, i1, i2, i3 fronten c1, b1IsConstant := builder.constantValue(b1) if b0IsConstant && b1IsConstant { - b0 := builder.cs.IsOne(&c0) - b1 := builder.cs.IsOne(&c1) + b0 := builder.cs.IsOne(c0) + b1 := builder.cs.IsOne(c1) if !b0 && !b1 { return i0 diff --git a/frontend/cs/scs/api_assertions.go b/frontend/cs/scs/api_assertions.go index 2137d5da0b..41b6d51b3a 100644 --- a/frontend/cs/scs/api_assertions.go +++ b/frontend/cs/scs/api_assertions.go @@ -46,7 +46,7 @@ func (builder *builder) AssertIsEqual(i1, i2 frontend.Variable) { } if i2Constant { xa := i1.(expr.Term) - builder.cs.Neg(&c2) + c2 := builder.cs.Neg(c2) debug := builder.newDebugInfo("assertIsEqual", xa, "==", i2) // xa - i2 == 0 @@ -62,7 +62,7 @@ func (builder *builder) AssertIsEqual(i1, i2 frontend.Variable) { debug := builder.newDebugInfo("assertIsEqual", xa, " == ", xb) - builder.cs.Neg(&xb.Coeff) + xb.Coeff = builder.cs.Neg(xb.Coeff) // xa - xb == 0 builder.addPlonkConstraint(sparseR1C{ xa: xa.VID, @@ -86,8 +86,8 @@ func (builder *builder) AssertIsDifferent(i1, i2 frontend.Variable) { // AssertIsBoolean fails if v != 0 ∥ v != 1 func (builder *builder) AssertIsBoolean(i1 frontend.Variable) { if c, ok := builder.constantValue(i1); ok { - if !(c.IsZero() || builder.cs.IsOne(&c)) { - panic(fmt.Sprintf("assertIsBoolean failed: constant(%s)", builder.cs.String(&c))) + if !(c.IsZero() || builder.cs.IsOne(c)) { + panic(fmt.Sprintf("assertIsBoolean failed: constant(%s)", builder.cs.String(c))) } return } @@ -101,20 +101,18 @@ func (builder *builder) AssertIsBoolean(i1 frontend.Variable) { // ensure v * (1 - v) == 0 // that is v + -v*v == 0 // qM = -v.Coeff*v.Coeff - qM := v.Coeff - builder.cs.Neg(&qM) - builder.cs.Mul(&qM, &v.Coeff) + qM := builder.cs.Neg(v.Coeff) + qM = builder.cs.Mul(qM, v.Coeff) toAdd := sparseR1C{ xa: v.VID, - xb: v.VID, qL: v.Coeff, qM: qM, } if debug.Debug { debug := builder.newDebugInfo("assertIsBoolean", v, " == (0|1)") - builder.addPlonkConstraint(toAdd, debug) + builder.addBoolGate(toAdd, debug) } else { - builder.addPlonkConstraint(toAdd) + builder.addBoolGate(toAdd) } } @@ -163,7 +161,7 @@ func (builder *builder) mustBeLessOrEqVar(a frontend.Variable, bound expr.Term) if ai, ok := builder.constantValue(aBits[i]); ok { // a is constant; ensure l == 0 - builder.cs.Mul(&l.Coeff, &ai) + l.Coeff = builder.cs.Mul(l.Coeff, ai) builder.addPlonkConstraint(sparseR1C{ xa: l.VID, qL: l.Coeff, @@ -195,7 +193,7 @@ func (builder *builder) mustBeLessOrEqCst(a frontend.Variable, bound big.Int) { if ca, ok := builder.constantValue(a); ok { // a is constant, compare the big int values - ba := builder.cs.ToBigInt(&ca) + ba := builder.cs.ToBigInt(ca) if ba.Cmp(&bound) == 1 { panic(fmt.Sprintf("AssertIsLessOrEqual: %s > %s", ba.String(), bound.String())) } diff --git a/frontend/cs/scs/builder.go b/frontend/cs/scs/builder.go index d0586647a4..53604b2db4 100644 --- a/frontend/cs/scs/builder.go +++ b/frontend/cs/scs/builder.go @@ -23,6 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/debug" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/internal/expr" "github.com/consensys/gnark/frontend/schema" @@ -57,25 +58,28 @@ type builder struct { // records multiplications constraint to avoid duplicate. // see mulConstraintExist(...) - mMulConstraints map[uint64]int + mMulInstructions map[uint64]int // same thing for addition gates // see addConstraintExist(...) - mAddConstraints map[uint64]int + mAddInstructions map[uint64]int // frequently used coefficients - tOne, tMinusOne constraint.Coeff + tOne, tMinusOne constraint.Element + + genericGate constraint.BlueprintID + mulGate, addGate, boolGate constraint.BlueprintID } // initialCapacity has quite some impact on frontend performance, especially on large circuits size // we may want to add build tags to tune that func newBuilder(field *big.Int, config frontend.CompileConfig) *builder { b := builder{ - mtBooleans: make(map[expr.Term]struct{}), - mMulConstraints: make(map[uint64]int, config.Capacity/2), - mAddConstraints: make(map[uint64]int, config.Capacity/2), - config: config, - Store: kvstore.New(), + mtBooleans: make(map[expr.Term]struct{}), + mMulInstructions: make(map[uint64]int, config.Capacity/2), + mAddInstructions: make(map[uint64]int, config.Capacity/2), + config: config, + Store: kvstore.New(), } curve := utils.FieldToCurve(field) @@ -106,6 +110,11 @@ func newBuilder(field *big.Int, config frontend.CompileConfig) *builder { b.tOne = b.cs.One() b.tMinusOne = b.cs.FromInterface(-1) + b.genericGate = b.cs.AddBlueprint(&constraint.BlueprintGenericSparseR1C{}) + b.mulGate = b.cs.AddBlueprint(&constraint.BlueprintSparseR1CMul{}) + b.addGate = b.cs.AddBlueprint(&constraint.BlueprintSparseR1CAdd{}) + b.boolGate = b.cs.AddBlueprint(&constraint.BlueprintSparseR1CBool{}) + return &b } @@ -120,47 +129,82 @@ func (builder *builder) FieldBitLen() int { // TODO @gbotrel doing a 2-step refactoring for now, frontend only. need to update constraint/SparseR1C. // qL⋅xa + qR⋅xb + qO⋅xc + qM⋅(xaxb) + qC == 0 type sparseR1C struct { - xa, xb, xc int // wires - qL, qR, qO, qM, qC constraint.Coeff // coefficients + xa, xb, xc int // wires + qL, qR, qO, qM, qC constraint.Element // coefficients commitment constraint.CommitmentConstraint } // a * b == c -func (builder *builder) addMulGate(a, b, c expr.Term, debug ...constraint.DebugInfo) { - qO := builder.tMinusOne - if c.Coeff != builder.tOne { - // slow path - t := c.Coeff - builder.cs.Neg(&t) - qO = t +func (builder *builder) addMulGate(a, b, c expr.Term) { + qM := builder.cs.Mul(a.Coeff, b.Coeff) + QM := builder.cs.AddCoeff(qM) + + builder.cs.AddSparseR1C(constraint.SparseR1C{ + XA: uint32(a.VID), + XB: uint32(b.VID), + XC: uint32(c.VID), + QM: QM, + QO: constraint.CoeffIdMinusOne, + }, builder.mulGate) +} + +// a + b + k == c +func (builder *builder) addAddGate(a, b expr.Term, xc uint32, k constraint.Element) { + qL := builder.cs.AddCoeff(a.Coeff) + qR := builder.cs.AddCoeff(b.Coeff) + qC := builder.cs.AddCoeff(k) + + builder.cs.AddSparseR1C(constraint.SparseR1C{ + XA: uint32(a.VID), + XB: uint32(b.VID), + XC: xc, + QL: qL, + QR: qR, + QC: qC, + QO: constraint.CoeffIdMinusOne, + }, builder.addGate) +} + +func (builder *builder) addBoolGate(c sparseR1C, debugInfo ...constraint.DebugInfo) { + QL := builder.cs.AddCoeff(c.qL) + QM := builder.cs.AddCoeff(c.qM) + + cID := builder.cs.AddSparseR1C(constraint.SparseR1C{ + XA: uint32(c.xa), + QL: QL, + QM: QM}, + builder.boolGate) + if debug.Debug && len(debugInfo) == 1 { + builder.cs.AttachDebugInfo(debugInfo[0], []int{cID}) } - qM := a.Coeff - builder.cs.Mul(&qM, &b.Coeff) - builder.addPlonkConstraint(sparseR1C{ - xa: a.VID, - xb: b.VID, - xc: c.VID, - qM: qM, - qO: qO, - }, debug...) } // addPlonkConstraint adds a sparseR1C to the underlying constraint system -func (builder *builder) addPlonkConstraint(c sparseR1C, debug ...constraint.DebugInfo) { +func (builder *builder) addPlonkConstraint(c sparseR1C, debugInfo ...constraint.DebugInfo) { if !c.qM.IsZero() && (c.xa == 0 || c.xb == 0) { // TODO this is internal but not easy to detect; if qM is set, but one or both of xa / xb is not, // since wireID == 0 is a valid wire, it may trigger unexpected behavior. log := logger.Logger() log.Warn().Msg("adding a plonk constraint with qM set but xa or xb == 0 (wire 0)") } - L := builder.cs.MakeTerm(&c.qL, c.xa) - R := builder.cs.MakeTerm(&c.qR, c.xb) - O := builder.cs.MakeTerm(&c.qO, c.xc) - U := builder.cs.MakeTerm(&c.qM, c.xa) - V := builder.cs.MakeTerm(&builder.tOne, c.xb) - K := builder.cs.MakeTerm(&c.qC, 0) - K.MarkConstant() - builder.cs.AddConstraint(constraint.SparseR1C{L: L, R: R, O: O, M: [2]constraint.Term{U, V}, K: K.CoeffID(), Commitment: c.commitment}, debug...) + QL := builder.cs.AddCoeff(c.qL) + QR := builder.cs.AddCoeff(c.qR) + QO := builder.cs.AddCoeff(c.qO) + QM := builder.cs.AddCoeff(c.qM) + QC := builder.cs.AddCoeff(c.qC) + + cID := builder.cs.AddSparseR1C(constraint.SparseR1C{ + XA: uint32(c.xa), + XB: uint32(c.xb), + XC: uint32(c.xc), + QL: QL, + QR: QR, + QO: QO, + QM: QM, + QC: QC, Commitment: c.commitment}, builder.genericGate) + if debug.Debug && len(debugInfo) == 1 { + builder.cs.AttachDebugInfo(debugInfo[0], []int{cID}) + } } // newInternalVariable creates a new wire, appends it on the list of wires of the circuit, sets @@ -194,7 +238,7 @@ func (builder *builder) reduce(l expr.LinearExpression) expr.LinearExpression { for i := 1; i < len(l); i++ { if l[i-1].VID == l[i].VID { // we have redundancy - builder.cs.Add(&l[i-1].Coeff, &l[i].Coeff) + l[i-1].Coeff = builder.cs.Add(l[i-1].Coeff, l[i].Coeff) l = append(l[:i], l[i+1:]...) i-- } @@ -207,7 +251,7 @@ func (builder *builder) reduce(l expr.LinearExpression) expr.LinearExpression { // This returns true if the v is a constant and v == 0 || v == 1. func (builder *builder) IsBoolean(v frontend.Variable) bool { if b, ok := builder.constantValue(v); ok { - return (b.IsZero() || builder.cs.IsOne(&b)) + return (b.IsZero() || builder.cs.IsOne(b)) } _, ok := builder.mtBooleans[v.(expr.Term)] return ok @@ -257,12 +301,12 @@ func (builder *builder) ConstantValue(v frontend.Variable) (*big.Int, bool) { if !ok { return nil, false } - return builder.cs.ToBigInt(&coeff), true + return builder.cs.ToBigInt(coeff), true } -func (builder *builder) constantValue(v frontend.Variable) (constraint.Coeff, bool) { +func (builder *builder) constantValue(v frontend.Variable) (constraint.Element, bool) { if _, ok := v.(expr.Term); ok { - return constraint.Coeff{}, false + return constraint.Element{}, false } return builder.cs.FromInterface(v), true } @@ -310,12 +354,12 @@ func (builder *builder) NewHint(f solver.Hint, nbOutputs int, inputs ...frontend } // returns in split into a slice of compiledTerm and the sum of all constants in in as a bigInt -func (builder *builder) filterConstantSum(in []frontend.Variable) (expr.LinearExpression, constraint.Coeff) { +func (builder *builder) filterConstantSum(in []frontend.Variable) (expr.LinearExpression, constraint.Element) { res := make(expr.LinearExpression, 0, len(in)) - b := constraint.Coeff{} + b := constraint.Element{} for i := 0; i < len(in); i++ { if c, ok := builder.constantValue(in[i]); ok { - builder.cs.Add(&b, &c) + b = builder.cs.Add(b, c) } else { res = append(res, in[i].(expr.Term)) } @@ -324,12 +368,12 @@ func (builder *builder) filterConstantSum(in []frontend.Variable) (expr.LinearEx } // returns in split into a slice of compiledTerm and the product of all constants in in as a coeff -func (builder *builder) filterConstantProd(in []frontend.Variable) (expr.LinearExpression, constraint.Coeff) { +func (builder *builder) filterConstantProd(in []frontend.Variable) (expr.LinearExpression, constraint.Element) { res := make(expr.LinearExpression, 0, len(in)) b := builder.tOne for i := 0; i < len(in); i++ { if c, ok := builder.constantValue(in[i]); ok { - builder.cs.Mul(&b, &c) + b = builder.cs.Mul(b, c) } else { res = append(res, in[i].(expr.Term)) } @@ -337,7 +381,7 @@ func (builder *builder) filterConstantProd(in []frontend.Variable) (expr.LinearE return res, b } -func (builder *builder) splitSum(acc expr.Term, r expr.LinearExpression, k *constraint.Coeff) expr.Term { +func (builder *builder) splitSum(acc expr.Term, r expr.LinearExpression, k *constraint.Element) expr.Term { // floor case if len(r) == 0 { if k != nil { @@ -345,13 +389,7 @@ func (builder *builder) splitSum(acc expr.Term, r expr.LinearExpression, k *cons o, found := builder.addConstraintExist(acc, expr.Term{}, *k) if !found { o = builder.newInternalVariable() - builder.addPlonkConstraint(sparseR1C{ - xa: acc.VID, - xc: o.VID, - qL: acc.Coeff, - qO: builder.tMinusOne, - qC: *k, - }) + builder.addAddGate(acc, expr.Term{}, uint32(o.VID), *k) } return o @@ -360,23 +398,14 @@ func (builder *builder) splitSum(acc expr.Term, r expr.LinearExpression, k *cons } // constraint to add: acc + r[0] (+ k) == o - qC := constraint.Coeff{} + qC := constraint.Element{} if k != nil { qC = *k } o, found := builder.addConstraintExist(acc, r[0], qC) if !found { o = builder.newInternalVariable() - - builder.addPlonkConstraint(sparseR1C{ - xa: acc.VID, - xb: r[0].VID, - xc: o.VID, - qL: acc.Coeff, - qR: r[0].Coeff, - qO: builder.tMinusOne, - qC: qC, - }) + builder.addAddGate(acc, r[0], uint32(o.VID), qC) } return builder.splitSum(o, r[1:], nil) @@ -400,84 +429,76 @@ func (builder *builder) splitSum(acc expr.Term, r expr.LinearExpression, k *cons // not going to catch these duplicates. // 2. this piece of code assumes some behavior from constraint/ package (like coeffIDs, or append-style // constraint management) -func (builder *builder) addConstraintExist(a, b expr.Term, k constraint.Coeff) (expr.Term, bool) { +func (builder *builder) addConstraintExist(a, b expr.Term, k constraint.Element) (expr.Term, bool) { // ensure deterministic combined identifier; if a.VID < b.VID { a, b = b, a } h := uint64(a.WireID()) | uint64(b.WireID()<<32) - if cID, ok := builder.mAddConstraints[h]; ok { - // seems likely we have a fit, let's double check - if c := builder.cs.GetConstraint(cID); c != nil { - if c.M[0].CoeffID() != constraint.CoeffIdZero { - panic("sanity check failed; recorded a add constraint with qM set") - } + if iID, ok := builder.mAddInstructions[h]; ok { + // if we do custom gates with slices in the constraint + // should use a shared object here to avoid allocs. + var c constraint.SparseR1C - if a.WireID() == c.R.WireID() { - a, b = b, a // ensure a is in qL - } - if (a.WireID() != c.L.WireID()) || (b.WireID() != c.R.WireID()) { - // that shouldn't happen; it means we added an entry in the duplicate add constraint - // map with a key that don't match the entries. - log := logger.Logger() - log.Error().Msg("mAddConstraints entry doesn't match key") - return expr.Term{}, false - } + // seems likely we have a fit, let's double check + inst := builder.cs.GetInstruction(iID) + // we know the blueprint we added it. + blueprint := constraint.BlueprintSparseR1CAdd{} + blueprint.DecompressSparseR1C(&c, builder.cs.GetCallData(inst)) + + // qO == -1 + if a.WireID() == int(c.XB) { + a, b = b, a // ensure a is in qL + } - // qO == -1 - if c.O.CoeffID() != constraint.CoeffIdMinusOne { - // we could probably handle that case, but it shouldn't - // happen with our current APIs --> each time we record a add gate in the duplicate - // map qO == -1 - return expr.Term{}, false - } + tk := builder.cs.MakeTerm(&k, 0) + if tk.CoeffID() != int(c.QC) { + // the constant part of the addition differs, no point going forward + // since we will need to add a new constraint anyway. + return expr.Term{}, false + } - tk := builder.cs.MakeTerm(&k, 0) - if tk.CoeffID() != c.K { - // the constant part of the addition differs, no point going forward - // since we will need to add a new constraint anyway. + // check that the coeff matches + qL := a.Coeff + qR := b.Coeff + ta := builder.cs.MakeTerm(&qL, 0) + tb := builder.cs.MakeTerm(&qR, 0) + if int(c.QL) != ta.CoeffID() || int(c.QR) != tb.CoeffID() { + if !k.IsZero() { + // may be for some edge cases we could avoid adding a constraint here. return expr.Term{}, false } - - // check that the coeff matches - qL := a.Coeff - qR := b.Coeff - ta := builder.cs.MakeTerm(&qL, 0) - tb := builder.cs.MakeTerm(&qR, 0) - if c.L.CoeffID() != ta.CoeffID() || c.R.CoeffID() != tb.CoeffID() { - if !k.IsZero() { - // may be for some edge cases we could avoid adding a constraint here. - return expr.Term{}, false - } - // we recorded an addition in the form q1*a + q2*b == c - // we want to record a new one in the form q3*a + q4*b == n*c - // question is; can we re-use c to avoid introducing a new wire & new constraint - // this is possible only if n == q3/q1 == q4/q2, that is, q3q2 == q1q4 - q1 := builder.cs.GetCoefficient(c.L.CoeffID()) - q2 := builder.cs.GetCoefficient(c.R.CoeffID()) - q3 := qL - q4 := qR - builder.cs.Mul(&q3, &q2) - builder.cs.Mul(&q1, &q4) - if q1 == q3 { - // no need to introduce a new constraint; - // compute n, the coefficient for the output wire - builder.cs.Inverse(&q2) - builder.cs.Mul(&q2, &q4) - return expr.NewTerm(c.O.WireID(), q2), true + // we recorded an addition in the form q1*a + q2*b == c + // we want to record a new one in the form q3*a + q4*b == n*c + // question is; can we re-use c to avoid introducing a new wire & new constraint + // this is possible only if n == q3/q1 == q4/q2, that is, q3q2 == q1q4 + q1 := builder.cs.GetCoefficient(int(c.QL)) + q2 := builder.cs.GetCoefficient(int(c.QR)) + q3 := qL + q4 := qR + q3 = builder.cs.Mul(q3, q2) + q1 = builder.cs.Mul(q1, q4) + if q1 == q3 { + // no need to introduce a new constraint; + // compute n, the coefficient for the output wire + q2, ok = builder.cs.Inverse(q2) + if !ok { + panic("div by 0") // shouldn't happen } - // we will need an additional constraint - return expr.Term{}, false + q2 = builder.cs.Mul(q2, q4) + return expr.NewTerm(int(c.XC), q2), true } - - // we found the same constraint! - return expr.NewTerm(c.O.WireID(), builder.tOne), true + // we will need an additional constraint + return expr.Term{}, false } + + // we found the same constraint! + return expr.NewTerm(int(c.XC), builder.tOne), true } // we are going to add this constraint, so we mark it. - // ! assumes the caller add a constraint immediately after the call to this function - builder.mAddConstraints[h] = builder.cs.GetNbConstraints() + // ! assumes the caller add an instruction immediately after the call to this function + builder.mAddInstructions[h] = builder.cs.GetNbInstructions() return expr.Term{}, false } @@ -502,62 +523,51 @@ func (builder *builder) mulConstraintExist(a, b expr.Term) (expr.Term, bool) { a, b = b, a } h := uint64(a.WireID()) | uint64(b.WireID()<<32) - if a.VID < b.VID { - a, b = b, a - } - if cID, ok := builder.mMulConstraints[h]; ok { + if iID, ok := builder.mMulInstructions[h]; ok { + // if we do custom gates with slices in the constraint + // should use a shared object here to avoid allocs. + var c constraint.SparseR1C + // seems likely we have a fit, let's double check - if c := builder.cs.GetConstraint(cID); c != nil { - if !(c.K|c.L.CoeffID()|c.R.CoeffID() == constraint.CoeffIdZero) { - panic("sanity check failed; recorded a mul constraint with qL, qR or qC set") - } + inst := builder.cs.GetInstruction(iID) + // we know the blueprint we added it. + blueprint := constraint.BlueprintSparseR1CMul{} + blueprint.DecompressSparseR1C(&c, builder.cs.GetCallData(inst)) - // qO == -1 - if c.O.CoeffID() != constraint.CoeffIdMinusOne { - // we could probably handle that case, but it shouldn't - // happen with our current APIs --> each time we record a mul gate in the duplicate - // map qO == -1 - return expr.Term{}, false - } + // qO == -1 - if a.WireID() == c.R.WireID() { - a, b = b, a // ensure a is in qL - } - if (a.WireID() != c.L.WireID()) || (b.WireID() != c.R.WireID()) { - // that shouldn't happen; it means we added an entry in the duplicate mul constraint - // map with a key that don't match the entries. - log := logger.Logger() - log.Error().Msg("mMulConstraints entry doesn't match key") - return expr.Term{}, false - } + if a.WireID() == int(c.XB) { + a, b = b, a // ensure a is in qL + } - // recompute the qM coeff and check that it matches; - qM := a.Coeff - builder.cs.Mul(&qM, &b.Coeff) - tm := builder.cs.MakeTerm(&qM, 0) - if c.M[0].CoeffID() != tm.CoeffID() { - // so we wanted to compute - // N * xC == qM*xA*xB - // but found a constraint - // xC == qM'*xA*xB - // the coefficient for our resulting wire is different; - // N = qM / qM' - N := builder.cs.GetCoefficient(c.M[0].CoeffID()) - builder.cs.Inverse(&N) - builder.cs.Mul(&N, &qM) - - return expr.NewTerm(c.O.WireID(), N), true + // recompute the qM coeff and check that it matches; + qM := builder.cs.Mul(a.Coeff, b.Coeff) + tm := builder.cs.MakeTerm(&qM, 0) + if int(c.QM) != tm.CoeffID() { + // so we wanted to compute + // N * xC == qM*xA*xB + // but found a constraint + // xC == qM'*xA*xB + // the coefficient for our resulting wire is different; + // N = qM / qM' + N := builder.cs.GetCoefficient(int(c.QM)) + N, ok := builder.cs.Inverse(N) + if !ok { + panic("div by 0") // sanity check. } + N = builder.cs.Mul(N, qM) - // we found the exact same constraint - return expr.NewTerm(c.O.WireID(), builder.tOne), true + return expr.NewTerm(int(c.XC), N), true } + + // we found the exact same constraint + return expr.NewTerm(int(c.XC), builder.tOne), true } // we are going to add this constraint, so we mark it. - // ! assumes the caller add a constraint immediately after the call to this function - builder.mMulConstraints[h] = builder.cs.GetNbConstraints() + // ! assumes the caller add an instruction immediately after the call to this function + builder.mMulInstructions[h] = builder.cs.GetNbInstructions() return expr.Term{}, false } @@ -595,10 +605,10 @@ func (builder *builder) newDebugInfo(errName string, in ...interface{}) constrai in[i] = builder.cs.MakeTerm(&t.Coeff, t.VID) case *expr.Term: in[i] = builder.cs.MakeTerm(&t.Coeff, t.VID) - case constraint.Coeff: - in[i] = builder.cs.String(&t) - case *constraint.Coeff: + case constraint.Element: in[i] = builder.cs.String(t) + case *constraint.Element: + in[i] = builder.cs.String(*t) } } diff --git a/frontend/internal/expr/linear_expression.go b/frontend/internal/expr/linear_expression.go index 21b3b8f17b..b1022fe52a 100644 --- a/frontend/internal/expr/linear_expression.go +++ b/frontend/internal/expr/linear_expression.go @@ -17,22 +17,24 @@ func (l LinearExpression) Clone() LinearExpression { } // NewLinearExpression helper to initialize a linear expression with one term -func NewLinearExpression(vID int, cID constraint.Coeff) LinearExpression { +func NewLinearExpression(vID int, cID constraint.Element) LinearExpression { return LinearExpression{Term{Coeff: cID, VID: vID}} } -func NewTerm(vID int, cID constraint.Coeff) Term { +func NewTerm(vID int, cID constraint.Element) Term { return Term{Coeff: cID, VID: vID} } type Term struct { VID int - Coeff constraint.Coeff + Coeff constraint.Element } -func (t *Term) SetCoeff(c constraint.Coeff) { +func (t *Term) SetCoeff(c constraint.Element) { t.Coeff = c } + +// TODO @gbotrel make that return a uint32 func (t Term) WireID() int { return t.VID } diff --git a/go.mod b/go.mod index 196602a5bd..617eafc6b8 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/consensys/gnark -go 1.18 +go 1.19 require ( github.com/bits-and-blooms/bitset v1.5.0 diff --git a/internal/generator/backend/main.go b/internal/generator/backend/main.go index 5b59be8e69..4e79e1eb88 100644 --- a/internal/generator/backend/main.go +++ b/internal/generator/backend/main.go @@ -121,10 +121,9 @@ func main() { // constraint systems entries := []bavard.Entry{ - {File: filepath.Join(csDir, "r1cs.go"), Templates: []string{"r1cs.go.tmpl", importCurve}}, + {File: filepath.Join(csDir, "system.go"), Templates: []string{"system.go.tmpl", importCurve}}, {File: filepath.Join(csDir, "coeff.go"), Templates: []string{"coeff.go.tmpl", importCurve}}, - {File: filepath.Join(csDir, "r1cs_sparse.go"), Templates: []string{"r1cs.sparse.go.tmpl", importCurve}}, - {File: filepath.Join(csDir, "solution.go"), Templates: []string{"solution.go.tmpl", importCurve}}, + {File: filepath.Join(csDir, "solver.go"), Templates: []string{"solver.go.tmpl", importCurve}}, } if err := bgen.Generate(d, "cs", "./template/representations/", entries...); err != nil { panic(err) diff --git a/internal/generator/backend/template/representations/coeff.go.tmpl b/internal/generator/backend/template/representations/coeff.go.tmpl index 9ebe15314e..3275becce4 100644 --- a/internal/generator/backend/template/representations/coeff.go.tmpl +++ b/internal/generator/backend/template/representations/coeff.go.tmpl @@ -1,7 +1,7 @@ import ( "github.com/consensys/gnark/constraint" - "math/big" "github.com/consensys/gnark/internal/utils" + "math/big" {{ template "import_fr" . }} ) @@ -27,8 +27,7 @@ func newCoeffTable(capacity int) CoeffTable { } - -func (ct *CoeffTable) MakeTerm(coeff *constraint.Coeff, variableID int) constraint.Term { +func (ct *CoeffTable) AddCoeff(coeff constraint.Element) uint32 { c := (*fr.Element)(coeff[:]) var cID uint32 if c.IsZero() { @@ -51,7 +50,12 @@ func (ct *CoeffTable) MakeTerm(coeff *constraint.Coeff, variableID int) constrai ct.mCoeffs[cc] = cID } } - + return cID +} + + +func (ct *CoeffTable) MakeTerm(coeff *constraint.Element, variableID int) constraint.Term { + cID := ct.AddCoeff(*coeff) return constraint.Term{VID: uint32(variableID), CID: cID} } @@ -61,7 +65,12 @@ func (ct *CoeffTable) CoeffToString(cID int) string { } -var _ constraint.CoeffEngine = &arithEngine{} + + +// implements constraint.Field +type field struct{} + +var _ constraint.Field = &field{} var ( two fr.Element @@ -78,11 +87,9 @@ func init() { } -// implements constraint.CoeffEngine -type arithEngine struct{} -func (engine *arithEngine) FromInterface(i interface{}) constraint.Coeff { +func (engine *field) FromInterface(i interface{}) constraint.Element { var e fr.Element if _, err := e.SetInterface(i); err != nil { // need to clean that --> some code path are dissimilar @@ -91,55 +98,75 @@ func (engine *arithEngine) FromInterface(i interface{}) constraint.Coeff { b := utils.FromInterface(i) e.SetBigInt(&b) } - var r constraint.Coeff + var r constraint.Element copy(r[:], e[:]) return r } -func (engine *arithEngine) ToBigInt(c *constraint.Coeff) *big.Int { +func (engine *field) ToBigInt(c constraint.Element) *big.Int { e := (*fr.Element)(c[:]) r := new(big.Int) e.BigInt(r) return r } -func (engine *arithEngine) Mul(a, b *constraint.Coeff) { +func (engine *field) Mul(a, b constraint.Element) constraint.Element { _a := (*fr.Element)(a[:]) _b := (*fr.Element)(b[:]) _a.Mul(_a, _b) + return a } -func (engine *arithEngine) Add(a, b *constraint.Coeff) { + +func (engine *field) Add(a, b constraint.Element) constraint.Element { _a := (*fr.Element)(a[:]) _b := (*fr.Element)(b[:]) _a.Add(_a, _b) + return a } -func (engine *arithEngine) Sub(a, b *constraint.Coeff) { +func (engine *field) Sub(a, b constraint.Element) constraint.Element { _a := (*fr.Element)(a[:]) _b := (*fr.Element)(b[:]) _a.Sub(_a, _b) + return a } -func (engine *arithEngine) Neg(a *constraint.Coeff) { +func (engine *field) Neg(a constraint.Element) constraint.Element { e := (*fr.Element)(a[:]) e.Neg(e) + return a } -func (engine *arithEngine) Inverse(a *constraint.Coeff) { +func (engine *field) Inverse(a constraint.Element) (constraint.Element, bool) { + if a.IsZero() { + return a, false + } e := (*fr.Element)(a[:]) + if e.IsZero() { + return a, false + } else if e.IsOne() { + return a, true + } + var t fr.Element + t.Neg(e) + if t.IsOne() { + return a, true + } + e.Inverse(e) + return a, true } -func (engine *arithEngine) IsOne(a *constraint.Coeff) bool { +func (engine *field) IsOne(a constraint.Element) bool { e := (*fr.Element)(a[:]) return e.IsOne() } -func (engine *arithEngine) One() constraint.Coeff { +func (engine *field) One() constraint.Element { e := fr.One() - var r constraint.Coeff + var r constraint.Element copy(r[:], e[:]) return r } -func (engine *arithEngine) String(a *constraint.Coeff) string { +func (engine *field) String(a constraint.Element) string { e := (*fr.Element)(a[:]) return e.String() } \ No newline at end of file diff --git a/internal/generator/backend/template/representations/r1cs.go.tmpl b/internal/generator/backend/template/representations/r1cs.go.tmpl deleted file mode 100644 index d481bd0e18..0000000000 --- a/internal/generator/backend/template/representations/r1cs.go.tmpl +++ /dev/null @@ -1,463 +0,0 @@ -import ( - "errors" - "fmt" - "io" - "runtime" - "time" - "sync" - "github.com/fxamacker/cbor/v2" - - "github.com/consensys/gnark/internal/backend/ioutils" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/logger" - "github.com/consensys/gnark/profile" - "github.com/consensys/gnark/backend/witness" - - "math" - "github.com/consensys/gnark-crypto/ecc" - - {{ template "import_fr" . }} -) - -// R1CS describes a set of R1CS constraint -type R1CS struct { - constraint.R1CSCore - CoeffTable - arithEngine -} - -// NewR1CS returns a new R1CS and sets cs.Coefficient (fr.Element) from provided big.Int values -// -// capacity pre-allocates memory for capacity nbConstraints -func NewR1CS(capacity int) *R1CS { - r := R1CS{ - R1CSCore: constraint.R1CSCore{ - System: constraint.NewSystem(fr.Modulus()), - Constraints: make([]constraint.R1C, 0, capacity), - }, - CoeffTable: newCoeffTable(capacity / 10), - } - return &r -} - - -func (cs *R1CS) AddConstraint(r1c constraint.R1C, debugInfo ...constraint.DebugInfo) int { - profile.RecordConstraint() - cs.Constraints = append(cs.Constraints, r1c) - cID := len(cs.Constraints) - 1 - if len(debugInfo) == 1 { - cs.DebugInfo = append(cs.DebugInfo, constraint.LogEntry(debugInfo[0])) - cs.MDebug[cID] = len(cs.DebugInfo) - 1 - } - - cs.UpdateLevel(cID, &r1c) - - return cID -} - - -// Solve returns the vector w solution to the system, that is -// Aw o Bw - Cw = 0 -func (cs *R1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { - opt, err := solver.NewConfig(opts...) - if err != nil { - return nil, err - } - - var res R1CSSolution - - s := ecc.NextPowerOfTwo(uint64(len(cs.Constraints))) - res.A = make(fr.Vector, len(cs.Constraints), s) - res.B = make(fr.Vector, len(cs.Constraints), s) - res.C = make(fr.Vector, len(cs.Constraints), s) - - v := witness.Vector().(fr.Vector) - - res.W, err = cs.solve(v, res.A, res.B, res.C, opt) - if err != nil { - return nil, err - } - - return &res, nil -} - -// Solve sets all the wires and returns the a, b, c vectors. -// the cs system should have been compiled before. The entries in a, b, c are in Montgomery form. -// a, b, c vectors: ab-c = hz -// witness = [publicWires | secretWires] (without the ONE_WIRE !) -// returns [publicWires | secretWires | internalWires ] -func (cs *R1CS) solve(witness, a, b, c fr.Vector, opt solver.Config) (fr.Vector, error) { - log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() - - nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - solution, err := newSolution(&cs.System, nbWires, opt.HintFunctions, cs.Coefficients) - if err != nil { - return make(fr.Vector, nbWires), err - } - start := time.Now() - - if len(witness) != len(cs.Public)-1+len(cs.Secret) { // - 1 for ONE_WIRE - err = fmt.Errorf("invalid witness size, got %d, expected %d = %d (public) + %d (secret)", len(witness), int(len(cs.Public)-1+len(cs.Secret)), len(cs.Public)-1, len(cs.Secret)) - log.Err(err).Send() - return solution.values, err - } - - // compute the wires and the a, b, c polynomials - if len(a) != len(cs.Constraints) || len(b) != len(cs.Constraints) || len(c) != len(cs.Constraints) { - err = errors.New("invalid input size: len(a, b, c) == len(Constraints)") - log.Err(err).Send() - return solution.values, err - } - - solution.solved[0] = true // ONE_WIRE - solution.values[0].SetOne() - copy(solution.values[1:], witness) - for i := range witness { - solution.solved[i+1] = true - } - - // keep track of the number of wire instantiations we do, for a sanity check to ensure - // we instantiated all wires - solution.nbSolved += uint64(len(witness) + 1) - - // now that we know all inputs are set, defer log printing once all solution.values are computed - // (or sooner, if a constraint is not satisfied) - defer solution.printLogs(opt.Logger, cs.Logs) - - if err := cs.parallelSolve(a, b, c, &solution); err != nil { - if unsatisfiedErr, ok := err.(*UnsatisfiedConstraintError); ok { - log.Err(errors.New("unsatisfied constraint")).Int("id", unsatisfiedErr.CID).Send() - } else { - log.Err(err).Send() - } - return solution.values, err - } - - // sanity check; ensure all wires are marked as "instantiated" - if !solution.isValid() { - log.Err(errors.New("solver didn't instantiate all wires")).Send() - panic("solver didn't instantiate all wires") - } - - - log.Debug().Dur("took", time.Since(start)).Msg("constraint system solver done") - - return solution.values, nil -} - - - -func (cs *R1CS) parallelSolve(a, b, c fr.Vector, solution *solution) error { - // minWorkPerCPU is the minimum target number of constraint a task should hold - // in other words, if a level has less than minWorkPerCPU, it will not be parallelized and executed - // sequentially without sync. - const minWorkPerCPU = 50.0 - - // cs.Levels has a list of levels, where all constraints in a level l(n) are independent - // and may only have dependencies on previous levels - // for each constraint - // we are guaranteed that each R1C contains at most one unsolved wire - // first we solve the unsolved wire (if any) - // then we check that the constraint is valid - // if a[i] * b[i] != c[i]; it means the constraint is not satisfied - - - var wg sync.WaitGroup - chTasks := make(chan []int, runtime.NumCPU()) - chError := make(chan *UnsatisfiedConstraintError, runtime.NumCPU()) - - // start a worker pool - // each worker wait on chTasks - // a task is a slice of constraint indexes to be solved - for i := 0; i < runtime.NumCPU(); i++ { - go func() { - for t := range chTasks { - for _, i := range t { - // for each constraint in the task, solve it. - if err := cs.solveConstraint(cs.Constraints[i], solution, &a[i], &b[i], &c[i]); err != nil { - var debugInfo *string - if dID, ok := cs.MDebug[i]; ok { - debugInfo = new(string) - *debugInfo = solution.logValue(cs.DebugInfo[dID]) - } - chError <- &UnsatisfiedConstraintError{CID: i, Err: err, DebugInfo: debugInfo} - wg.Done() - return - } - } - wg.Done() - } - }() - } - - // clean up pool go routines - defer func() { - close(chTasks) - close(chError) - }() - - // for each level, we push the tasks - for _, level := range cs.Levels { - - // max CPU to use - maxCPU := float64(len(level)) / minWorkPerCPU - - if maxCPU <= 1.0 { - // we do it sequentially - for _, i := range level { - if err := cs.solveConstraint(cs.Constraints[i], solution, &a[i], &b[i], &c[i]); err != nil { - var debugInfo *string - if dID, ok := cs.MDebug[i]; ok { - debugInfo = new(string) - *debugInfo = solution.logValue(cs.DebugInfo[dID]) - } - return &UnsatisfiedConstraintError{CID: i, Err: err, DebugInfo: debugInfo} - } - } - continue - } - - // number of tasks for this level is set to number of CPU - // but if we don't have enough work for all our CPU, it can be lower. - nbTasks := runtime.NumCPU() - maxTasks := int(math.Ceil(maxCPU)) - if nbTasks > maxTasks { - nbTasks = maxTasks - } - nbIterationsPerCpus := len(level) / nbTasks - - // more CPUs than tasks: a CPU will work on exactly one iteration - // note: this depends on minWorkPerCPU constant - if nbIterationsPerCpus < 1 { - nbIterationsPerCpus = 1 - nbTasks = len(level) - } - - - extraTasks := len(level) - (nbTasks * nbIterationsPerCpus) - extraTasksOffset := 0 - - for i := 0; i < nbTasks; i++ { - wg.Add(1) - _start := i*nbIterationsPerCpus + extraTasksOffset - _end := _start + nbIterationsPerCpus - if extraTasks > 0 { - _end++ - extraTasks-- - extraTasksOffset++ - } - // since we're never pushing more than num CPU tasks - // we will never be blocked here - chTasks <- level[_start:_end] - } - - // wait for the level to be done - wg.Wait() - - if len(chError) > 0 { - return <-chError - } - } - - return nil -} - -// IsSolved -// Deprecated: use _, err := Solve(...) instead -func (cs *R1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { - _, err := cs.Solve(witness, opts...) - return err -} - -// divByCoeff sets res = res / t.Coeff -func (cs *R1CS) divByCoeff(res *fr.Element, t constraint.Term) { - cID := t.CoeffID() - switch cID { - case constraint.CoeffIdOne: - return - case constraint.CoeffIdMinusOne: - res.Neg(res) - case constraint.CoeffIdZero: - panic("division by 0") - default: - // this is slow, but shouldn't happen as divByCoeff is called to - // remove the coeff of an unsolved wire - // but unsolved wires are (in gnark frontend) systematically set with a coeff == 1 or -1 - res.Div(res, &cs.Coefficients[cID]) - } -} - - - -// solveConstraint compute unsolved wires in the constraint, if any and set the solution accordingly -// -// returns an error if the solver called a hint function that errored -// returns false, nil if there was no wire to solve -// returns true, nil if exactly one wire was solved. In that case, it is redundant to check that -// the constraint is satisfied later. -func (cs *R1CS) solveConstraint(r constraint.R1C, solution *solution, a,b,c *fr.Element) error { - - // the index of the non-zero entry shows if L, R or O has an uninstantiated wire - // the content is the ID of the wire non instantiated - var loc uint8 - - var termToCompute constraint.Term - - processLExp := func(l constraint.LinearExpression, val *fr.Element, locValue uint8) error { - for _, t := range l { - vID := t.WireID() - - // wire is already computed, we just accumulate in val - if solution.solved[vID] { - solution.accumulateInto(t, val) - continue - } - - // first we check if this is a hint wire - if hint, ok := cs.MHints[vID]; ok { - if err := solution.solveWithHint(vID, hint); err != nil { - return err - } - // now that the wire is saved, accumulate it into a, b or c - solution.accumulateInto(t, val) - continue - } - - if loc != 0 { - panic("found more than one wire to instantiate") - } - termToCompute = t - loc = locValue - } - return nil - } - - if err := processLExp(r.L, a, 1); err != nil { - return err - } - - if err := processLExp(r.R, b, 2); err != nil { - return err - } - - if err := processLExp(r.O, c, 3); err != nil { - return err - } - - if loc == 0 { - // there is nothing to solve, may happen if we have an assertion - // (ie a constraints that doesn't yield any output) - // or if we solved the unsolved wires with hint functions - var check fr.Element - if !check.Mul(a, b).Equal(c) { - return fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String()) - } - return nil - } - - // we compute the wire value and instantiate it - wID := termToCompute.WireID() - - // solver result - var wire fr.Element - - - switch loc { - case 1: - if !b.IsZero() { - wire.Div(c, b). - Sub(&wire, a) - a.Add(a, &wire) - } else { - // we didn't actually ensure that a * b == c - var check fr.Element - if !check.Mul(a, b).Equal(c) { - return fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String()) - } - } - case 2: - if !a.IsZero() { - wire.Div(c, a). - Sub(&wire, b) - b.Add(b, &wire) - } else { - var check fr.Element - if !check.Mul(a, b).Equal(c) { - return fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String()) - } - } - case 3: - wire.Mul(a, b). - Sub(&wire, c) - - c.Add(c, &wire) - } - - // wire is the term (coeff * value) - // but in the solution we want to store the value only - // note that in gnark frontend, coeff here is always 1 or -1 - cs.divByCoeff(&wire, termToCompute) - solution.set(wID, wire) - - - return nil -} - -// GetConstraints return the list of R1C and a coefficient resolver -func (cs *R1CS) GetConstraints() ([]constraint.R1C, constraint.Resolver) { - return cs.Constraints, cs -} - -// GetNbCoefficients return the number of unique coefficients needed in the R1CS -func (cs *R1CS) GetNbCoefficients() int { - return len(cs.Coefficients) -} - -// CurveID returns curve ID as defined in gnark-crypto -func (cs *R1CS) CurveID() ecc.ID { - return ecc.{{.CurveID}} -} - -// WriteTo encodes R1CS into provided io.Writer using cbor -func (cs *R1CS) WriteTo(w io.Writer) (int64, error) { - _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written - enc, err := cbor.CoreDetEncOptions().EncMode() - if err != nil { - return 0, err - } - encoder := enc.NewEncoder(&_w) - - // encode our object - err = encoder.Encode(cs) - return _w.N, err -} - -// ReadFrom attempts to decode R1CS from io.Reader using cbor -func (cs *R1CS) ReadFrom(r io.Reader) (int64, error) { - dm, err := cbor.DecOptions{ - MaxArrayElements: 134217728, - MaxMapPairs: 134217728, - }.DecMode() - - if err != nil { - return 0, err - } - decoder := dm.NewDecoder(r) - - // initialize coeff table - cs.CoeffTable = newCoeffTable(0) - - if err := decoder.Decode(&cs); err != nil { - return int64(decoder.NumBytesRead()), err - } - - - if err := cs.CheckSerializationHeader(); err != nil { - return int64(decoder.NumBytesRead()), err - } - - - return int64(decoder.NumBytesRead()), nil -} - diff --git a/internal/generator/backend/template/representations/r1cs.sparse.go.tmpl b/internal/generator/backend/template/representations/r1cs.sparse.go.tmpl deleted file mode 100644 index 54553702c1..0000000000 --- a/internal/generator/backend/template/representations/r1cs.sparse.go.tmpl +++ /dev/null @@ -1,524 +0,0 @@ -import ( - "fmt" - "io" - "github.com/fxamacker/cbor/v2" - "github.com/consensys/gnark-crypto/ecc" - "sync" - "runtime" - "math" - "errors" - "time" - - "github.com/consensys/gnark/internal/backend/ioutils" - "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/logger" - "github.com/consensys/gnark/profile" - "github.com/consensys/gnark/backend/witness" - - {{ template "import_fr" . }} -) - -// SparseR1CS represents a Plonk like circuit -type SparseR1CS struct { - constraint.SparseR1CSCore - CoeffTable - arithEngine -} - -// NewSparseR1CS returns a new SparseR1CS and sets r1cs.Coefficient (fr.Element) from provided big.Int values -func NewSparseR1CS(capacity int) *SparseR1CS { - cs := SparseR1CS{ - SparseR1CSCore: constraint.SparseR1CSCore{ - System: constraint.NewSystem(fr.Modulus()), - Constraints: make([]constraint.SparseR1C, 0, capacity), - }, - CoeffTable: newCoeffTable(capacity / 10), - } - - return &cs -} - - -func (cs *SparseR1CS) AddConstraint(c constraint.SparseR1C, debugInfo ...constraint.DebugInfo) int { - profile.RecordConstraint() - cs.Constraints = append(cs.Constraints, c) - cID := len(cs.Constraints) - 1 - if len(debugInfo) == 1 { - cs.DebugInfo = append(cs.DebugInfo, constraint.LogEntry(debugInfo[0])) - cs.MDebug[cID] = len(cs.DebugInfo) - 1 - } - cs.UpdateLevel(cID, &c) - - return cID -} - -func (c *SparseR1CS) Solve(witness witness.Witness, opts ...solver.Option) (any, error) { - opt, err := solver.NewConfig(opts...) - if err != nil { - return nil, err - } - - // compute the constraint system solution - var solution []fr.Element - if solution, err = c.solve(witness.Vector().(fr.Vector), opt); err != nil { - return nil, err - } - - var res SparseR1CSSolution - // query l, r, o in Lagrange basis, not blinded - res.L, res.R, res.O = c.evaluateLROSmallDomain(solution) - - return &res, nil -} - -// evaluateLROSmallDomain extracts the solution l, r, o, and returns it in lagrange form. -// solution = [ public | secret | internal ] -func (c *SparseR1CS) evaluateLROSmallDomain(solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { - - //s := int(pk.Domain[0].Cardinality) - s := c.GetNbConstraints() + len(c.Public) // len(spr.Public) is for the placeholder constraints - s = int(ecc.NextPowerOfTwo(uint64(s))) - - var l, r, o []fr.Element - l = make([]fr.Element, s) - r = make([]fr.Element, s) - o = make([]fr.Element, s) - s0 := solution[0] - - for i := 0; i < len(c.Public); i++ { // placeholders - l[i] = solution[i] - r[i] = s0 - o[i] = s0 - } - offset := len(c.Public) - for i := 0; i < len(c.Constraints); i++ { // constraints - l[offset+i] = solution[c.Constraints[i].L.WireID()] - r[offset+i] = solution[c.Constraints[i].R.WireID()] - o[offset+i] = solution[c.Constraints[i].O.WireID()] - } - offset += len(c.Constraints) - - for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solution[0]) - l[offset+i] = s0 - r[offset+i] = s0 - o[offset+i] = s0 - } - - return l, r, o - -} - - -// Solve sets all the wires. -// solution.values = [publicInputs | secretInputs | internalVariables ] -// witness: contains the input variables -// it returns the full slice of wires -func (cs *SparseR1CS) solve(witness fr.Vector, opt solver.Config) (fr.Vector, error) { - log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "plonk").Logger() - - // set the slices holding the solution.values and monitoring which variables have been solved - nbVariables := cs.NbInternalVariables + len(cs.Secret) + len(cs.Public) - - start := time.Now() - - expectedWitnessSize := len(cs.Public) + len(cs.Secret) - if len(witness) != expectedWitnessSize { - return make(fr.Vector, nbVariables), fmt.Errorf( - "invalid witness size, got %d, expected %d = %d (public) + %d (secret)", - len(witness), - expectedWitnessSize, - len(cs.Public), - len(cs.Secret), - ) - } - - // keep track of wire that have a value - solution, err := newSolution(&cs.System, nbVariables, opt.HintFunctions, cs.Coefficients) - if err != nil { - return solution.values, err - } - - - // solution.values = [publicInputs | secretInputs | internalVariables ] -> we fill publicInputs | secretInputs - copy(solution.values, witness) - for i := 0; i < len(witness); i++ { - solution.solved[i] = true - } - - // keep track of the number of wire instantiations we do, for a sanity check to ensure - // we instantiated all wires - solution.nbSolved += uint64(len(witness)) - - // defer log printing once all solution.values are computed - defer solution.printLogs(opt.Logger, cs.Logs) - - // batch invert the coefficients to avoid many divisions in the solver - coefficientsNegInv := fr.BatchInvert(cs.Coefficients) - for i:=0; i < len(coefficientsNegInv);i++ { - coefficientsNegInv[i].Neg(&coefficientsNegInv[i]) - } - - if err := cs.parallelSolve(&solution, coefficientsNegInv); err != nil { - if unsatisfiedErr, ok := err.(*UnsatisfiedConstraintError); ok { - log.Err(errors.New("unsatisfied constraint")).Int("id", unsatisfiedErr.CID).Send() - } else { - log.Err(err).Send() - } - return solution.values, err - } - - // sanity check; ensure all wires are marked as "instantiated" - if !solution.isValid() { - log.Err(errors.New("solver didn't instantiate all wires")).Send() - panic("solver didn't instantiate all wires") - } - - log.Debug().Dur("took", time.Since(start)).Msg("constraint system solver done") - - return solution.values, nil - -} - - -func (cs *SparseR1CS) parallelSolve(solution *solution, coefficientsNegInv fr.Vector) error { - // minWorkPerCPU is the minimum target number of constraint a task should hold - // in other words, if a level has less than minWorkPerCPU, it will not be parallelized and executed - // sequentially without sync. - const minWorkPerCPU = 50.0 - - // cs.Levels has a list of levels, where all constraints in a level l(n) are independent - // and may only have dependencies on previous levels - - var wg sync.WaitGroup - chTasks := make(chan []int, runtime.NumCPU()) - chError := make(chan *UnsatisfiedConstraintError, runtime.NumCPU()) - - // start a worker pool - // each worker wait on chTasks - // a task is a slice of constraint indexes to be solved - for i := 0; i < runtime.NumCPU(); i++ { - go func() { - for t := range chTasks { - for _, i := range t { - // for each constraint in the task, solve it. - if err := cs.solveConstraint(cs.Constraints[i], solution, coefficientsNegInv); err != nil { - chError <- &UnsatisfiedConstraintError{CID: i, Err: err} - wg.Done() - return - } - if err := cs.checkConstraint(cs.Constraints[i], solution); err != nil { - if dID, ok := cs.MDebug[i]; ok { - errMsg := solution.logValue(cs.DebugInfo[dID]) - chError <- &UnsatisfiedConstraintError{CID: i, DebugInfo: &errMsg} - } else { - chError <- &UnsatisfiedConstraintError{CID: i, Err: err} - } - wg.Done() - return - } - } - wg.Done() - } - }() - } - - // clean up pool go routines - defer func() { - close(chTasks) - close(chError) - }() - - // for each level, we push the tasks - for _, level := range cs.Levels { - - // max CPU to use - maxCPU := float64(len(level)) / minWorkPerCPU - - if maxCPU <= 1.0 { - // we do it sequentially - for _, i := range level { - if err := cs.solveConstraint(cs.Constraints[i], solution, coefficientsNegInv); err != nil { - return &UnsatisfiedConstraintError{CID: i, Err: err} - } - if err := cs.checkConstraint(cs.Constraints[i], solution); err != nil { - if dID, ok := cs.MDebug[i]; ok { - errMsg := solution.logValue(cs.DebugInfo[dID]) - return &UnsatisfiedConstraintError{CID: i, DebugInfo: &errMsg} - } - return &UnsatisfiedConstraintError{CID: i, Err: err} - } - } - continue - } - - // number of tasks for this level is set to number of CPU - // but if we don't have enough work for all our CPU, it can be lower. - nbTasks := runtime.NumCPU() - maxTasks := int(math.Ceil(maxCPU)) - if nbTasks > maxTasks { - nbTasks = maxTasks - } - nbIterationsPerCpus := len(level) / nbTasks - - // more CPUs than tasks: a CPU will work on exactly one iteration - // note: this depends on minWorkPerCPU constant - if nbIterationsPerCpus < 1 { - nbIterationsPerCpus = 1 - nbTasks = len(level) - } - - - extraTasks := len(level) - (nbTasks * nbIterationsPerCpus) - extraTasksOffset := 0 - - for i := 0; i < nbTasks; i++ { - wg.Add(1) - _start := i*nbIterationsPerCpus + extraTasksOffset - _end := _start + nbIterationsPerCpus - if extraTasks > 0 { - _end++ - extraTasks-- - extraTasksOffset++ - } - // since we're never pushing more than num CPU tasks - // we will never be blocked here - chTasks <- level[_start:_end] - } - - // wait for the level to be done - wg.Wait() - - if len(chError) > 0 { - return <-chError - } - } - - return nil -} - - - -// computeHints computes wires associated with a hint function, if any -// if there is no remaining wire to solve, returns -1 -// else returns the wire position (L -> 0, R -> 1, O -> 2) -func (cs *SparseR1CS) computeHints(c constraint.SparseR1C, solution *solution) ( int, error) { - r := -1 - lID, rID, oID := c.L.WireID(), c.R.WireID(), c.O.WireID() - - if (c.L.CoeffID() != 0 || c.M[0].CoeffID() != 0) && !solution.solved[lID] { - // check if it's a hint - if hint, ok := cs.MHints[lID]; ok { - if err := solution.solveWithHint(lID, hint); err != nil { - return -1, err - } - } else { - r = 0 - } - - } - - if (c.R.CoeffID() != 0 || c.M[1].CoeffID() != 0) && !solution.solved[rID] { - // check if it's a hint - if hint, ok := cs.MHints[rID]; ok { - if err := solution.solveWithHint(rID, hint); err != nil { - return -1, err - } - } else { - r = 1 - } - } - - if (c.O.CoeffID() != 0) && !solution.solved[oID] { - // check if it's a hint - if hint, ok := cs.MHints[oID]; ok { - if err := solution.solveWithHint(oID, hint); err != nil { - return -1, err - } - } else { - r = 2 - } - } - return r, nil -} - - -// solveConstraint solve any unsolved wire in given constraint and update the solution -// a SparseR1C may have up to one unsolved wire (excluding hints) -// if it doesn't, then this function returns and does nothing -func (cs *SparseR1CS) solveConstraint(c constraint.SparseR1C, solution *solution, coefficientsNegInv fr.Vector) error { - - if c.Commitment == constraint.COMMITTED { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. - return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time - } - - lro, err := cs.computeHints(c, solution) - if err != nil { - return err - } - if lro == -1 { - // no unsolved wire - // can happen if the constraint contained only hint wires. - return nil - } - if lro == 1 { // we solve for R: u1L+u2R+u3LR+u4O+k=0 => R(u2+u3L)+u1L+u4O+k = 0 - if !solution.solved[c.L.WireID()] { - panic("L wire should be instantiated when we solve R") - } - var u1, u2, u3, den, num, v1, v2 fr.Element - u3.Mul(&cs.Coefficients[c.M[0].CoeffID()], &cs.Coefficients[c.M[1].CoeffID()]) - u1.Set(&cs.Coefficients[c.L.CoeffID()]) - u2.Set(&cs.Coefficients[c.R.CoeffID()]) - den.Mul(&u3, &solution.values[c.L.WireID()]).Add(&den, &u2) - - v1 = solution.computeTerm(c.L) - v2 = solution.computeTerm(c.O) - num.Add(&v1, &v2).Add(&num, &cs.Coefficients[c.K]) - - // TODO find a way to do lazy div (/ batch inversion) - num.Div(&num, &den).Neg(&num) - solution.set(c.L.WireID(), num) - return nil - } - - if lro == 0 { // we solve for L: u1L+u2R+u3LR+u4O+k=0 => L(u1+u3R)+u2R+u4O+k = 0 - if !solution.solved[c.R.WireID()] { - panic("R wire should be instantiated when we solve L") - } - var u1, u2, u3, den, num, v1, v2 fr.Element - u3.Mul(&cs.Coefficients[c.M[0].CoeffID()], &cs.Coefficients[c.M[1].CoeffID()]) - u1.Set(&cs.Coefficients[c.L.CoeffID()]) - u2.Set(&cs.Coefficients[c.R.CoeffID()]) - den.Mul(&u3, &solution.values[c.R.WireID()]).Add(&den, &u1) - - v1 = solution.computeTerm(c.R) - v2 = solution.computeTerm(c.O) - num.Add(&v1, &v2).Add(&num, &cs.Coefficients[c.K]) - - // TODO find a way to do lazy div (/ batch inversion) - num.Div(&num, &den).Neg(&num) - solution.set(c.L.WireID(), num) - return nil - - } - // O we solve for O - var o fr.Element - cID, vID := c.O.CoeffID(), c.O.WireID() - - l := solution.computeTerm(c.L) - r := solution.computeTerm(c.R) - m0 := solution.computeTerm(c.M[0]) - m1 := solution.computeTerm(c.M[1]) - - // o = - ((m0 * m1) + l + r + c.K) / c.O - o.Mul(&m0, &m1).Add(&o, &l).Add(&o, &r).Add(&o, &cs.Coefficients[c.K]) - o.Mul(&o, &coefficientsNegInv[cID]) - - solution.set(vID, o) - - return nil -} - -// IsSolved -// Deprecated: use _, err := Solve(...) instead -func (cs *SparseR1CS) IsSolved(witness witness.Witness, opts ...solver.Option) error { - _, err := cs.Solve(witness, opts...) - return err -} - -// GetConstraints return the list of SparseR1C and a coefficient resolver -func (cs *SparseR1CS) GetConstraints() ([]constraint.SparseR1C, constraint.Resolver) { - return cs.Constraints, cs -} - -func (cs *SparseR1CS) GetConstraint(i int) (*constraint.SparseR1C) { - if i < 0 ||i >= len(cs.Constraints) { - return nil - } - return &cs.Constraints[i] -} - -func (cs *SparseR1CS) GetCoefficient(i int) (r constraint.Coeff) { - copy(r[:], cs.Coefficients[i][:]) - return -} - -// checkConstraint verifies that the constraint holds -func (cs *SparseR1CS) checkConstraint(c constraint.SparseR1C, solution *solution) error { - - if c.Commitment != constraint.NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. - return nil // these are there for enforcing the correctness of the commitment and can be skipped in solving time - } - - l := solution.computeTerm(c.L) - r := solution.computeTerm(c.R) - m0 := solution.computeTerm(c.M[0]) - m1 := solution.computeTerm(c.M[1]) - o := solution.computeTerm(c.O) - - // l + r + (m0 * m1) + o + c.K == 0 - var t fr.Element - t.Mul(&m0, &m1).Add(&t, &l).Add(&t, &r).Add(&t, &o).Add(&t, &cs.Coefficients[c.K]) - if !t.IsZero() { - return fmt.Errorf("qL⋅xa + qR⋅xb + qO⋅xc + qM⋅(xaxb) + qC != 0 → %s + %s + %s + (%s × %s) + %s != 0", - l.String(), - r.String(), - o.String(), - m0.String(), - m1.String(), - cs.Coefficients[c.K].String(), - ) - } - return nil - -} - -// GetNbCoefficients return the number of unique coefficients needed in the R1CS -func (cs *SparseR1CS) GetNbCoefficients() int { - return len(cs.Coefficients) -} - -// CurveID returns curve ID as defined in gnark-crypto (ecc.{{.Curve}}) -func (cs *SparseR1CS) CurveID() ecc.ID { - return ecc.{{.CurveID}} -} - -// WriteTo encodes SparseR1CS into provided io.Writer using cbor -func (cs *SparseR1CS) WriteTo(w io.Writer) (int64, error) { - _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written - enc, err := cbor.CoreDetEncOptions().EncMode() - if err != nil { - return 0, err - } - encoder := enc.NewEncoder(&_w) - - // encode our object - err = encoder.Encode(cs) - return _w.N, err -} - - -// ReadFrom attempts to decode SparseR1CS from io.Reader using cbor -func (cs *SparseR1CS) ReadFrom(r io.Reader) (int64, error) { - dm, err := cbor.DecOptions{ - MaxArrayElements: 134217728, - MaxMapPairs: 134217728, - }.DecMode() - if err != nil { - return 0, err - } - decoder := dm.NewDecoder(r) - - // initialize coeff table - cs.CoeffTable = newCoeffTable(0) - - if err := decoder.Decode(cs); err != nil { - return int64(decoder.NumBytesRead()), err - } - - if err := cs.CheckSerializationHeader(); err != nil { - return int64(decoder.NumBytesRead()), err - } - - return int64(decoder.NumBytesRead()), nil -} diff --git a/internal/generator/backend/template/representations/solution.go.tmpl b/internal/generator/backend/template/representations/solution.go.tmpl deleted file mode 100644 index f083181786..0000000000 --- a/internal/generator/backend/template/representations/solution.go.tmpl +++ /dev/null @@ -1,370 +0,0 @@ -import ( - "errors" - "fmt" - "math/big" - "sync/atomic" - "strings" - "strconv" - "io" - "github.com/consensys/gnark/debug" - "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/solver" - "github.com/rs/zerolog" - {{ template "import_fr" . }} -) - -// solution represents elements needed to compute -// a solution to a R1CS or SparseR1CS -type solution struct { - values, coefficients []fr.Element - solved []bool - nbSolved uint64 - mHintsFunctions map[solver.HintID]solver.Hint // maps hintID to hint function - st *debug.SymbolTable - cs *constraint.System -} - -func newSolution(cs *constraint.System, nbWires int, hintFunctions map[solver.HintID]solver.Hint, coefficients []fr.Element) (solution, error) { - - s := solution{ - cs: cs, - st: &cs.SymbolTable, - values: make([]fr.Element, nbWires), - coefficients: coefficients, - solved: make([]bool, nbWires), - mHintsFunctions: hintFunctions, - } - - // hintsDependencies is from compile time; it contains the list of hints the solver **needs** - var missing []string - for hintUUID, hintID := range cs.MHintsDependencies { - if _, ok := s.mHintsFunctions[hintUUID]; !ok { - missing = append(missing, hintID) - } - } - - if len(missing) > 0 { - return s, fmt.Errorf("solver missing hint(s): %v", missing) - } - - return s, nil -} - -func (s *solution) set(id int, value fr.Element) { - if s.solved[id] { - panic("solving the same wire twice should never happen.") - } - s.values[id] = value - s.solved[id] = true - atomic.AddUint64(&s.nbSolved, 1) - // s.nbSolved++ -} - -func (s *solution) isValid() bool { - return int(s.nbSolved) == len(s.values) -} - -// computeTerm computes coeff*variable -func (s *solution) computeTerm(t constraint.Term) fr.Element { - cID, vID := t.CoeffID(), t.WireID() - if cID != 0 && !s.solved[vID] { - panic("computing a term with an unsolved wire") - } - switch cID { - case constraint.CoeffIdZero: - return fr.Element{} - case constraint.CoeffIdOne: - return s.values[vID] - case constraint.CoeffIdTwo: - var res fr.Element - res.Double(&s.values[vID]) - return res - case constraint.CoeffIdMinusOne: - var res fr.Element - res.Neg(&s.values[vID]) - return res - default: - var res fr.Element - res.Mul(&s.coefficients[cID], &s.values[vID]) - return res - } -} - -// r += (t.coeff*t.value) -func (s *solution) accumulateInto(t constraint.Term, r *fr.Element) { - cID := t.CoeffID() - - if t.IsConstant() { - // needed for logs, we may want to not put this in the hot path if we need to - // optimize constraint system solver further. - r.Add(r, &s.coefficients[cID]) - return - } - - vID := t.WireID() - switch cID { - case constraint.CoeffIdZero: - return - case constraint.CoeffIdOne: - r.Add(r, &s.values[vID]) - case constraint.CoeffIdTwo: - var res fr.Element - res.Double(&s.values[vID]) - r.Add(r, &res) - case constraint.CoeffIdMinusOne: - r.Sub(r, &s.values[vID]) - default: - var res fr.Element - res.Mul(&s.coefficients[cID], &s.values[vID]) - r.Add(r, &res) - } -} - -// solveHint compute solution.values[vID] using provided solver hint -func (s *solution) solveWithHint(vID int, hID int) error { - // skip if the wire is already solved by a call to the same hint - // function on the same inputs - if s.solved[vID] { - return nil - } - - h := &s.cs.HintMappings[hID] - - // ensure hint function was provided - f, ok := s.mHintsFunctions[h.HintID] - if !ok { - return errors.New("missing hint function") - } - - // tmp IO big int memory - nbInputs := len(h.Inputs) - nbOutputs := len(h.Outputs) - inputs := make([]*big.Int, nbInputs) - outputs := make([]*big.Int, nbOutputs) - for i :=0; i < nbOutputs; i++ { - outputs[i] = big.NewInt(0) - } - - q := fr.Modulus() - - // for each input, we set its big int value, IF all the wires are solved - // the only case where all wires may not be solved, is if one of the input of this hint - // is the output of another hint. - // it is safe to recursively solve this with the parallel solver, since all hints-output wires - // that we can solve this way are marked to be solved with the current constraint we are processing. - recursiveSolve := func(t constraint.Term) error { - if t.IsConstant() { - return nil - } - wID := t.WireID() - if s.solved[wID] { - return nil - } - // unsolved dependency - if h, ok := s.cs.MHints[wID]; ok { - // solve recursively. - return s.solveWithHint(wID, h) - } - - // it's not a hint, we panic. - panic("solver can't compute hint; one or more input wires are unsolved") - } - - for i := 0; i < nbInputs; i++ { - inputs[i] = big.NewInt(0) - - var v fr.Element - for _, term := range h.Inputs[i] { - if err := recursiveSolve(term); err != nil { - return err - } - s.accumulateInto(term, &v) - } - v.BigInt(inputs[i]) - } - - - err := f(q, inputs, outputs) - - var v fr.Element - for i := range outputs { - v.SetBigInt(outputs[i]) - s.set(h.Outputs[i], v) - } - - return err -} - -func (s *solution) printLogs(log zerolog.Logger, logs []constraint.LogEntry) { - if log.GetLevel() == zerolog.Disabled { - return - } - - for i := 0; i < len(logs); i++ { - logLine := s.logValue(logs[i]) - log.Debug().Str(zerolog.CallerFieldName, logs[i].Caller).Msg(logLine) - } -} - -const unsolvedVariable = "" - -func (s *solution) logValue(log constraint.LogEntry) string { - var toResolve []interface{} - var ( - eval fr.Element - missingValue bool - ) - for j := 0; j < len(log.ToResolve); j++ { - // before eval le - - missingValue = false - eval.SetZero() - - for _, t := range log.ToResolve[j] { - // for each term in the linear expression - - cID, vID := t.CoeffID(), t.WireID() - if t.IsConstant() { - // just add the constant - eval.Add(&eval, &s.coefficients[cID]) - continue - } - - if !s.solved[vID] { - missingValue = true - break // stop the loop we can't evaluate. - } - - tv := s.computeTerm(t) - eval.Add(&eval, &tv) - } - - - // after - if missingValue { - toResolve = append(toResolve, unsolvedVariable) - } else { - // we have to append our accumulator - toResolve = append(toResolve, eval.String()) - } - - } - if len(log.Stack) > 0 { - var sbb strings.Builder - for _, lID := range log.Stack { - location := s.st.Locations[lID] - function := s.st.Functions[location.FunctionID] - - sbb.WriteString(function.Name) - sbb.WriteByte('\n') - sbb.WriteByte('\t') - sbb.WriteString(function.Filename) - sbb.WriteByte(':') - sbb.WriteString(strconv.Itoa(int(location.Line))) - sbb.WriteByte('\n') - } - toResolve = append(toResolve, sbb.String()) - } - return fmt.Sprintf(log.Format, toResolve...) -} - -// UnsatisfiedConstraintError wraps an error with useful metadata on the unsatisfied constraint -type UnsatisfiedConstraintError struct { - Err error - CID int // constraint ID - DebugInfo *string // optional debug info -} - -func (r *UnsatisfiedConstraintError) Error() string { - if r.DebugInfo != nil { - return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, *r.DebugInfo) - } - return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, r.Err.Error()) -} - - - -// R1CSSolution represent a valid assignment to all the variables in the constraint system. -// The vector W such that Aw o Bw - Cw = 0 -type R1CSSolution struct { - W fr.Vector - A, B, C fr.Vector -} - -func (t *R1CSSolution) WriteTo(w io.Writer) (int64, error) { - n, err := t.W.WriteTo(w) - if err != nil { - return n, err - } - a, err := t.A.WriteTo(w) - n += a - if err != nil { - return n, err - } - a, err = t.B.WriteTo(w) - n += a - if err != nil { - return n, err - } - a, err = t.C.WriteTo(w) - n += a - return n, err -} - -func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { - n, err := t.W.ReadFrom(r) - if err != nil { - return n, err - } - a, err := t.A.ReadFrom(r) - a += n - if err != nil { - return n, err - } - a, err = t.B.ReadFrom(r) - a += n - if err != nil { - return n, err - } - a, err = t.C.ReadFrom(r) - n += a - return n, err -} - - - -// SparseR1CSSolution represent a valid assignment to all the variables in the constraint system. -type SparseR1CSSolution struct { - L, R, O fr.Vector -} - -func (t *SparseR1CSSolution) WriteTo(w io.Writer) (int64, error) { - n, err := t.L.WriteTo(w) - if err != nil { - return n, err - } - a, err := t.R.WriteTo(w) - n += a - if err != nil { - return n, err - } - a, err = t.O.WriteTo(w) - n += a - return n, err - -} - -func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { - n, err := t.L.ReadFrom(r) - if err != nil { - return n, err - } - a, err := t.R.ReadFrom(r) - a += n - if err != nil { - return n, err - } - a, err = t.O.ReadFrom(r) - a += n - return n, err -} diff --git a/internal/generator/backend/template/representations/solver.go.tmpl b/internal/generator/backend/template/representations/solver.go.tmpl new file mode 100644 index 0000000000..75b7a9d216 --- /dev/null +++ b/internal/generator/backend/template/representations/solver.go.tmpl @@ -0,0 +1,618 @@ +import ( + "errors" + "fmt" + "math/big" + "sync/atomic" + "strings" + "strconv" + "runtime" + "sync" + "math" + "github.com/consensys/gnark/constraint" + csolver "github.com/consensys/gnark/constraint/solver" + "github.com/rs/zerolog" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/field/pool" + {{ template "import_fr" . }} +) + +// solver represent the state of the solver during a call to System.Solve(...) +type solver struct { + *system + + // values and solved are index by the wire (variable) id + values []fr.Element + solved []bool + nbSolved uint64 + + // maps hintID to hint function + mHintsFunctions map[csolver.HintID]csolver.Hint + + // used to out api.Println + logger zerolog.Logger + + a,b,c fr.Vector // R1CS solver will compute the a,b,c matrices + + q *big.Int +} + +func newSolver(cs *system, witness fr.Vector, opts ...csolver.Option) (*solver, error) { + // parse options + opt, err := csolver.NewConfig(opts...) + if err != nil { + return nil, err + } + + // check witness size + witnessOffset := 0 + if cs.Type == constraint.SystemR1CS { + witnessOffset++ + } + + nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables + expectedWitnessSize := len(cs.Public)-witnessOffset+len(cs.Secret) + + if len(witness) != expectedWitnessSize { + return nil, fmt.Errorf("invalid witness size, got %d, expected %d", len(witness), expectedWitnessSize) + } + + // check all hints are there + hintFunctions := opt.HintFunctions + + // hintsDependencies is from compile time; it contains the list of hints the solver **needs** + var missing []string + for hintUUID, hintID := range cs.MHintsDependencies { + if _, ok := hintFunctions[hintUUID]; !ok { + missing = append(missing, hintID) + } + } + + if len(missing) > 0 { + return nil, fmt.Errorf("solver missing hint(s): %v", missing) + } + + s := solver{ + system: cs, + values: make([]fr.Element, nbWires), + solved: make([]bool, nbWires), + mHintsFunctions: hintFunctions, + logger: opt.Logger, + q: cs.Field(), + } + + // set the witness indexes as solved + if witnessOffset == 1 { + s.solved[0] = true // ONE_WIRE + s.values[0].SetOne() + } + copy(s.values[witnessOffset:], witness) + for i := range witness { + s.solved[i+witnessOffset] = true + } + + // keep track of the number of wire instantiations we do, for a post solve sanity check + // to ensure we instantiated all wires + s.nbSolved += uint64(len(witness) + witnessOffset) + + + + if s.Type == constraint.SystemR1CS { + n := ecc.NextPowerOfTwo(uint64(cs.GetNbConstraints())) + s.a = make(fr.Vector, cs.GetNbConstraints(), n) + s.b = make(fr.Vector, cs.GetNbConstraints(), n) + s.c = make(fr.Vector, cs.GetNbConstraints(), n) + } + + return &s, nil +} + + +func (s *solver) set(id int, value fr.Element) { + if s.solved[id] { + panic("solving the same wire twice should never happen.") + } + s.values[id] = value + s.solved[id] = true + atomic.AddUint64(&s.nbSolved, 1) +} + + +// computeTerm computes coeff*variable +// TODO @gbotrel check if t is a Constant only +func (s *solver) computeTerm(t constraint.Term) fr.Element { + cID, vID := t.CoeffID(), t.WireID() + if cID != 0 && !s.solved[vID] { + panic("computing a term with an unsolved wire") + } + switch cID { + case constraint.CoeffIdZero: + return fr.Element{} + case constraint.CoeffIdOne: + return s.values[vID] + case constraint.CoeffIdTwo: + var res fr.Element + res.Double(&s.values[vID]) + return res + case constraint.CoeffIdMinusOne: + var res fr.Element + res.Neg(&s.values[vID]) + return res + default: + var res fr.Element + res.Mul(&s.Coefficients[cID], &s.values[vID]) + return res + } +} + +// r += (t.coeff*t.value) +// TODO @gbotrel check t.IsConstant on the caller side when necessary +func (s *solver) accumulateInto(t constraint.Term, r *fr.Element) { + cID := t.CoeffID() + vID := t.WireID() + + switch cID { + case constraint.CoeffIdZero: + return + case constraint.CoeffIdOne: + r.Add(r, &s.values[vID]) + case constraint.CoeffIdTwo: + var res fr.Element + res.Double(&s.values[vID]) + r.Add(r, &res) + case constraint.CoeffIdMinusOne: + r.Sub(r, &s.values[vID]) + default: + var res fr.Element + res.Mul(&s.Coefficients[cID], &s.values[vID]) + r.Add(r, &res) + } +} + +// solveWithHint executes a hint and assign the result to its defined outputs. +func (s *solver) solveWithHint(h *constraint.HintMapping) error { + // ensure hint function was provided + f, ok := s.mHintsFunctions[h.HintID] + if !ok { + return errors.New("missing hint function") + } + + // tmp IO big int memory + nbInputs := len(h.Inputs) + nbOutputs := int(h.OutputRange.End - h.OutputRange.Start) + inputs := make([]*big.Int, nbInputs) + outputs := make([]*big.Int, nbOutputs) + for i :=0; i < nbOutputs; i++ { + outputs[i] = pool.BigInt.Get() + outputs[i].SetUint64(0) + } + + q := pool.BigInt.Get() + q.Set(s.q) + + for i := 0; i < nbInputs; i++ { + var v fr.Element + for _, term := range h.Inputs[i] { + if term.IsConstant() { + v.Add(&v, &s.Coefficients[term.CoeffID()]) + continue + } + s.accumulateInto(term, &v) + } + inputs[i] = pool.BigInt.Get() + v.BigInt(inputs[i]) + } + + + err := f(q, inputs, outputs) + + var v fr.Element + for i := range outputs { + v.SetBigInt(outputs[i]) + s.set(int(h.OutputRange.Start) + i, v) + pool.BigInt.Put(outputs[i]) + } + + for i := range inputs { + pool.BigInt.Put(inputs[i]) + } + + pool.BigInt.Put(q) + + return err +} + +func (s *solver) printLogs(logs []constraint.LogEntry) { + if s.logger.GetLevel() == zerolog.Disabled { + return + } + + for i := 0; i < len(logs); i++ { + logLine := s.logValue(logs[i]) + s.logger.Debug().Str(zerolog.CallerFieldName, logs[i].Caller).Msg(logLine) + } +} + +const unsolvedVariable = "" + +func (s *solver) logValue(log constraint.LogEntry) string { + var toResolve []interface{} + var ( + eval fr.Element + missingValue bool + ) + for j := 0; j < len(log.ToResolve); j++ { + // before eval le + + missingValue = false + eval.SetZero() + + for _, t := range log.ToResolve[j] { + // for each term in the linear expression + + cID, vID := t.CoeffID(), t.WireID() + if t.IsConstant() { + // just add the constant + eval.Add(&eval, &s.Coefficients[cID]) + continue + } + + if !s.solved[vID] { + missingValue = true + break // stop the loop we can't evaluate. + } + + tv := s.computeTerm(t) + eval.Add(&eval, &tv) + } + + + // after + if missingValue { + toResolve = append(toResolve, unsolvedVariable) + } else { + // we have to append our accumulator + toResolve = append(toResolve, eval.String()) + } + + } + if len(log.Stack) > 0 { + var sbb strings.Builder + for _, lID := range log.Stack { + location := s.SymbolTable.Locations[lID] + function := s.SymbolTable.Functions[location.FunctionID] + + sbb.WriteString(function.Name) + sbb.WriteByte('\n') + sbb.WriteByte('\t') + sbb.WriteString(function.Filename) + sbb.WriteByte(':') + sbb.WriteString(strconv.Itoa(int(location.Line))) + sbb.WriteByte('\n') + } + toResolve = append(toResolve, sbb.String()) + } + return fmt.Sprintf(log.Format, toResolve...) +} + + +// divByCoeff sets res = res / t.Coeff +func (solver *solver) divByCoeff(res *fr.Element, cID uint32) { + switch cID { + case constraint.CoeffIdOne: + return + case constraint.CoeffIdMinusOne: + res.Neg(res) + case constraint.CoeffIdZero: + panic("division by 0") + default: + // this is slow, but shouldn't happen as divByCoeff is called to + // remove the coeff of an unsolved wire + // but unsolved wires are (in gnark frontend) systematically set with a coeff == 1 or -1 + res.Div(res, &solver.Coefficients[cID]) + } +} + + + + +// Implement constraint.Solver +func (s *solver) GetValue(cID, vID uint32) constraint.Element { + var r constraint.Element + e := s.computeTerm(constraint.Term{CID:cID,VID: vID}) + copy(r[:], e[:]) + return r +} +func (s *solver) GetCoeff(cID uint32) constraint.Element { + var r constraint.Element + copy(r[:], s.Coefficients[cID][:]) + return r +} +func (s *solver) SetValue(vID uint32, f constraint.Element) { + s.set(int(vID), *(*fr.Element)(f[:])) +} + +func (s *solver) IsSolved(vID uint32) bool { + return s.solved[vID] +} + + + + +// processInstruction decodes the instruction and execute blueprint-defined logic. +// an instruction can encode a hint, a custom constraint or a generic constraint. +func (solver *solver) processInstruction(inst constraint.Instruction, scratch *scratch) error { + // fetch the blueprint + blueprint := solver.Blueprints[inst.BlueprintID] + calldata := solver.GetCallData(inst) + cID := inst.ConstraintOffset // here we have 1 constraint in the instruction only + + if solver.Type == constraint.SystemR1CS { + if bc, ok := blueprint.(constraint.BlueprintR1C); ok { + // TODO @gbotrel we use the solveR1C method for now, having user-defined + // blueprint for R1CS would require constraint.Solver interface to add methods + // to set a,b,c since it's more efficient to compute these while we solve. + bc.DecompressR1C(&scratch.tR1C, calldata) + return solver.solveR1C(cID, &scratch.tR1C) + } + } else if solver.Type == constraint.SystemSparseR1CS { + // blueprint declared "I know how to solve this." + if bc, ok := blueprint.(constraint.BlueprintSolvable); ok { + if err := bc.Solve(solver, calldata); err != nil { + return solver.wrapErrWithDebugInfo(cID, err) + } + return nil + } + } + + // blueprint encodes a hint, we execute. + // TODO @gbotrel may be worth it to move hint logic in blueprint "solve" + if bc, ok := blueprint.(constraint.BlueprintHint); ok { + bc.DecompressHint(&scratch.tHint, calldata) + return solver.solveWithHint(&scratch.tHint) + } + + + return nil +} + + +// run runs the solver. it return an error if a constraint is not satisfied or if not all wires +// were instantiated. +func (solver *solver) run() error { + // minWorkPerCPU is the minimum target number of constraint a task should hold + // in other words, if a level has less than minWorkPerCPU, it will not be parallelized and executed + // sequentially without sync. + const minWorkPerCPU = 50.0 // TODO @gbotrel revisit that with blocks. + + // cs.Levels has a list of levels, where all constraints in a level l(n) are independent + // and may only have dependencies on previous levels + // for each constraint + // we are guaranteed that each R1C contains at most one unsolved wire + // first we solve the unsolved wire (if any) + // then we check that the constraint is valid + // if a[i] * b[i] != c[i]; it means the constraint is not satisfied + var wg sync.WaitGroup + chTasks := make(chan []int, runtime.NumCPU()) + chError := make(chan error, runtime.NumCPU()) + + // start a worker pool + // each worker wait on chTasks + // a task is a slice of constraint indexes to be solved + for i := 0; i < runtime.NumCPU(); i++ { + go func() { + var scratch scratch + for t := range chTasks { + for _, i := range t { + if err := solver.processInstruction(solver.Instructions[i], &scratch); err != nil { + chError <- err + wg.Done() + return + } + } + wg.Done() + } + }() + } + + // clean up pool go routines + defer func() { + close(chTasks) + close(chError) + }() + + var scratch scratch + + // for each level, we push the tasks + for _, level := range solver.Levels { + + // max CPU to use + maxCPU := float64(len(level)) / minWorkPerCPU + + if maxCPU <= 1.0 { + // we do it sequentially + for _, i := range level { + if err := solver.processInstruction(solver.Instructions[i], &scratch); err != nil { + return err + } + } + continue + } + + // number of tasks for this level is set to number of CPU + // but if we don't have enough work for all our CPU, it can be lower. + nbTasks := runtime.NumCPU() + maxTasks := int(math.Ceil(maxCPU)) + if nbTasks > maxTasks { + nbTasks = maxTasks + } + nbIterationsPerCpus := len(level) / nbTasks + + // more CPUs than tasks: a CPU will work on exactly one iteration + // note: this depends on minWorkPerCPU constant + if nbIterationsPerCpus < 1 { + nbIterationsPerCpus = 1 + nbTasks = len(level) + } + + + extraTasks := len(level) - (nbTasks * nbIterationsPerCpus) + extraTasksOffset := 0 + + for i := 0; i < nbTasks; i++ { + wg.Add(1) + _start := i*nbIterationsPerCpus + extraTasksOffset + _end := _start + nbIterationsPerCpus + if extraTasks > 0 { + _end++ + extraTasks-- + extraTasksOffset++ + } + // since we're never pushing more than num CPU tasks + // we will never be blocked here + chTasks <- level[_start:_end] + } + + // wait for the level to be done + wg.Wait() + + if len(chError) > 0 { + return <-chError + } + } + + if int(solver.nbSolved) != len(solver.values) { + return errors.New("solver didn't assign a value to all wires") + } + + return nil +} + + + +// solveR1C compute unsolved wires in the constraint, if any and set the solver accordingly +// +// returns an error if the solver called a hint function that errored +// returns false, nil if there was no wire to solve +// returns true, nil if exactly one wire was solved. In that case, it is redundant to check that +// the constraint is satisfied later. +func (solver *solver) solveR1C(cID uint32, r *constraint.R1C) error { + a, b, c := &solver.a[cID],&solver.b[cID], &solver.c[cID] + + // the index of the non-zero entry shows if L, R or O has an uninstantiated wire + // the content is the ID of the wire non instantiated + var loc uint8 + + var termToCompute constraint.Term + + processLExp := func(l constraint.LinearExpression, val *fr.Element, locValue uint8) { + for _, t := range l { + vID := t.WireID() + + // wire is already computed, we just accumulate in val + if solver.solved[vID] { + solver.accumulateInto(t, val) + continue + } + + if loc != 0 { + panic("found more than one wire to instantiate") + } + termToCompute = t + loc = locValue + } + } + + processLExp(r.L, a, 1) + processLExp(r.R, b, 2) + processLExp(r.O, c, 3) + + + + if loc == 0 { + // there is nothing to solve, may happen if we have an assertion + // (ie a constraints that doesn't yield any output) + // or if we solved the unsolved wires with hint functions + var check fr.Element + if !check.Mul(a, b).Equal(c) { + return solver.wrapErrWithDebugInfo(cID, fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String())) + } + return nil + } + + // we compute the wire value and instantiate it + wID := termToCompute.WireID() + + // solver result + var wire fr.Element + + + switch loc { + case 1: + if !b.IsZero() { + wire.Div(c, b). + Sub(&wire, a) + a.Add(a, &wire) + } else { + // we didn't actually ensure that a * b == c + var check fr.Element + if !check.Mul(a, b).Equal(c) { + return solver.wrapErrWithDebugInfo(cID, fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String())) + } + } + case 2: + if !a.IsZero() { + wire.Div(c, a). + Sub(&wire, b) + b.Add(b, &wire) + } else { + var check fr.Element + if !check.Mul(a, b).Equal(c) { + return solver.wrapErrWithDebugInfo(cID, fmt.Errorf("%s ⋅ %s != %s", a.String(), b.String(), c.String())) + } + } + case 3: + wire.Mul(a, b). + Sub(&wire, c) + + c.Add(c, &wire) + } + + // wire is the term (coeff * value) + // but in the solver we want to store the value only + // note that in gnark frontend, coeff here is always 1 or -1 + solver.divByCoeff(&wire, termToCompute.CID) + solver.set(wID, wire) + + return nil +} + +// UnsatisfiedConstraintError wraps an error with useful metadata on the unsatisfied constraint +type UnsatisfiedConstraintError struct { + Err error + CID int // constraint ID + DebugInfo *string // optional debug info +} + +func (r *UnsatisfiedConstraintError) Error() string { + if r.DebugInfo != nil { + return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, *r.DebugInfo) + } + return fmt.Sprintf("constraint #%d is not satisfied: %s", r.CID, r.Err.Error()) +} + + +func (solver *solver) wrapErrWithDebugInfo(cID uint32, err error) *UnsatisfiedConstraintError { + var debugInfo *string + if dID, ok := solver.MDebug[int(cID)]; ok { + debugInfo = new(string) + *debugInfo = solver.logValue(solver.DebugInfo[dID]) + } + return &UnsatisfiedConstraintError{CID: int(cID), Err: err, DebugInfo: debugInfo} +} + +// temporary variables to avoid memallocs in hotloop +type scratch struct { + tR1C constraint.R1C + tHint constraint.HintMapping +} + diff --git a/internal/generator/backend/template/representations/system.go.tmpl b/internal/generator/backend/template/representations/system.go.tmpl new file mode 100644 index 0000000000..4a1bd0355a --- /dev/null +++ b/internal/generator/backend/template/representations/system.go.tmpl @@ -0,0 +1,363 @@ +import ( + "io" + "time" + "github.com/fxamacker/cbor/v2" + + "github.com/consensys/gnark/internal/backend/ioutils" + csolver "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/logger" + "github.com/consensys/gnark/backend/witness" + "reflect" + + "github.com/consensys/gnark-crypto/ecc" + + {{ template "import_fr" . }} +) + +type R1CS = system +type SparseR1CS = system + +// system is a curved-typed constraint.System with a concrete coefficient table (fr.Element) +type system struct { + constraint.System + CoeffTable + field +} + + +func NewR1CS(capacity int) *R1CS { + return newSystem(capacity, constraint.SystemR1CS) +} + +func NewSparseR1CS(capacity int) *SparseR1CS { + return newSystem(capacity, constraint.SystemSparseR1CS) +} + +func newSystem(capacity int, t constraint.SystemType) *system { + return &system{ + System: constraint.NewSystem(fr.Modulus(), capacity, t), + CoeffTable: newCoeffTable(capacity / 10), + } +} + + +// Solve solves the constraint system with provided witness. +// If it's a R1CS returns R1CSSolution +// If it's a SparseR1CS returns SparseR1CSSolution +func (cs *system) Solve(witness witness.Witness, opts ...csolver.Option) (any, error) { + log := logger.Logger().With().Int("nbConstraints", cs.GetNbConstraints()).Logger() + start := time.Now() + + + v := witness.Vector().(fr.Vector) + + // init the solver + solver, err := newSolver(cs, v, opts...) + if err != nil { + log.Err(err).Send() + return nil, err + } + + // defer log printing once all solver.values are computed + // (or sooner, if a constraint is not satisfied) + defer solver.printLogs(cs.Logs) + + // run it. + if err := solver.run(); err != nil { + log.Err(err).Send() + return nil, err + } + + log.Debug().Dur("took", time.Since(start)).Msg("constraint system solver done") + + // format the solution + // TODO @gbotrel revisit post-refactor + if cs.Type == constraint.SystemR1CS { + var res R1CSSolution + res.W = solver.values + res.A = solver.a + res.B = solver.b + res.C = solver.c + return &res, nil + } else { + // sparse R1CS + var res SparseR1CSSolution + // query l, r, o in Lagrange basis, not blinded + res.L, res.R, res.O = evaluateLROSmallDomain(cs, solver.values) + + return &res, nil + } + +} + +// IsSolved +// Deprecated: use _, err := Solve(...) instead +func (cs *system) IsSolved(witness witness.Witness, opts ...csolver.Option) error { + _, err := cs.Solve(witness, opts...) + return err +} + + +// GetR1Cs return the list of R1C +func (cs *system) GetR1Cs() []constraint.R1C { + toReturn := make([]constraint.R1C, 0, cs.GetNbConstraints()) + + for _, inst := range cs.Instructions { + blueprint := cs.Blueprints[inst.BlueprintID] + if bc, ok := blueprint.(constraint.BlueprintR1C); ok { + var r1c constraint.R1C + bc.DecompressR1C(&r1c, cs.GetCallData(inst)) + toReturn = append(toReturn, r1c) + } else { + panic("not implemented") + } + } + return toReturn +} + +// GetNbCoefficients return the number of unique coefficients needed in the R1CS +func (cs *system) GetNbCoefficients() int { + return len(cs.Coefficients) +} + +// CurveID returns curve ID as defined in gnark-crypto +func (cs *system) CurveID() ecc.ID { + return ecc.{{.CurveID}} +} + +// WriteTo encodes R1CS into provided io.Writer using cbor +func (cs *system) WriteTo(w io.Writer) (int64, error) { + _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written + ts := getTagSet() + enc, err := cbor.CoreDetEncOptions().EncModeWithTags(ts) + if err != nil { + return 0, err + } + encoder := enc.NewEncoder(&_w) + + // encode our object + err = encoder.Encode(cs) + return _w.N, err +} + +// ReadFrom attempts to decode R1CS from io.Reader using cbor +func (cs *system) ReadFrom(r io.Reader) (int64, error) { + ts := getTagSet() + dm, err := cbor.DecOptions{ + MaxArrayElements: 134217728, + MaxMapPairs: 134217728, + }.DecModeWithTags(ts) + + if err != nil { + return 0, err + } + decoder := dm.NewDecoder(r) + + // initialize coeff table + cs.CoeffTable = newCoeffTable(0) + + if err := decoder.Decode(&cs); err != nil { + return int64(decoder.NumBytesRead()), err + } + + + if err := cs.CheckSerializationHeader(); err != nil { + return int64(decoder.NumBytesRead()), err + } + + + return int64(decoder.NumBytesRead()), nil +} + +func (cs *system) GetCoefficient(i int) (r constraint.Element) { + copy(r[:], cs.Coefficients[i][:]) + return +} + + +// GetSparseR1Cs return the list of SparseR1C +func (cs *system) GetSparseR1Cs() []constraint.SparseR1C { + + toReturn := make([]constraint.SparseR1C, 0, cs.GetNbConstraints()) + + for _, inst := range cs.Instructions { + blueprint := cs.Blueprints[inst.BlueprintID] + if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { + var sparseR1C constraint.SparseR1C + calldata := cs.CallData[inst.StartCallData:inst.StartCallData+uint64(blueprint.NbInputs())] + bc.DecompressSparseR1C(&sparseR1C, calldata) + toReturn = append(toReturn, sparseR1C) + } else { + panic("not implemented") + } + } + return toReturn +} + + + +// evaluateLROSmallDomain extracts the solver l, r, o, and returns it in lagrange form. +// solver = [ public | secret | internal ] +// TODO @gbotrel refactor; this seems to be a small util function for plonk +func evaluateLROSmallDomain(cs *system, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { + + //s := int(pk.Domain[0].Cardinality) + s := cs.GetNbConstraints() + len(cs.Public) // len(spr.Public) is for the placeholder constraints + s = int(ecc.NextPowerOfTwo(uint64(s))) + + var l, r, o []fr.Element + l = make([]fr.Element, s) + r = make([]fr.Element, s) + o = make([]fr.Element, s) + s0 := solution[0] + + for i := 0; i < len(cs.Public); i++ { // placeholders + l[i] = solution[i] + r[i] = s0 + o[i] = s0 + } + offset := len(cs.Public) + nbConstraints := cs.GetNbConstraints() + + + var sparseR1C constraint.SparseR1C + j := 0 + for _, inst := range cs.Instructions { + blueprint := cs.Blueprints[inst.BlueprintID] + if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { + bc.DecompressSparseR1C(&sparseR1C, cs.GetCallData(inst)) + + l[offset+j] = solution[sparseR1C.XA] + r[offset+j] = solution[sparseR1C.XB] + o[offset+j] = solution[sparseR1C.XC] + j++ + } + } + + + offset += nbConstraints + + for i := 0; i < s-offset; i++ { // offset to reach 2**n constraints (where the id of l,r,o is 0, so we assign solver[0]) + l[offset+i] = s0 + r[offset+i] = s0 + o[offset+i] = s0 + } + + return l, r, o + +} + + + +// R1CSSolution represent a valid assignment to all the variables in the constraint system. +// The vector W such that Aw o Bw - Cw = 0 +type R1CSSolution struct { + W fr.Vector + A, B, C fr.Vector +} + +func (t *R1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.W.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.A.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.B.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.C.WriteTo(w) + n += a + return n, err +} + +func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.W.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.A.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.B.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.C.ReadFrom(r) + n += a + return n, err +} + + + +// SparseR1CSSolution represent a valid assignment to all the variables in the constraint system. +type SparseR1CSSolution struct { + L, R, O fr.Vector +} + +func (t *SparseR1CSSolution) WriteTo(w io.Writer) (int64, error) { + n, err := t.L.WriteTo(w) + if err != nil { + return n, err + } + a, err := t.R.WriteTo(w) + n += a + if err != nil { + return n, err + } + a, err = t.O.WriteTo(w) + n += a + return n, err + +} + +func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { + n, err := t.L.ReadFrom(r) + if err != nil { + return n, err + } + a, err := t.R.ReadFrom(r) + a += n + if err != nil { + return n, err + } + a, err = t.O.ReadFrom(r) + a += n + return n, err +} + + +func getTagSet() cbor.TagSet { + // temporary for refactor + ts := cbor.NewTagSet() + // https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml + // 65536-15309735 Unassigned + tagNum := uint64(5309735) + addType := func(t reflect.Type) { + if err := ts.Add( + cbor.TagOptions{EncTag: cbor.EncTagRequired, DecTag: cbor.DecTagRequired}, + t, + tagNum, + ); err != nil { + panic(err) + } + tagNum++ + } + + addType(reflect.TypeOf(constraint.BlueprintGenericHint{})) + addType(reflect.TypeOf(constraint.BlueprintGenericR1C{})) + addType(reflect.TypeOf(constraint.BlueprintGenericSparseR1C{})) + addType(reflect.TypeOf(constraint.BlueprintSparseR1CAdd{})) + addType(reflect.TypeOf(constraint.BlueprintSparseR1CMul{})) + + return ts +} diff --git a/internal/generator/backend/template/representations/tests/r1cs.go.tmpl b/internal/generator/backend/template/representations/tests/r1cs.go.tmpl index c312e2f48b..5b583e6d80 100644 --- a/internal/generator/backend/template/representations/tests/r1cs.go.tmpl +++ b/internal/generator/backend/template/representations/tests/r1cs.go.tmpl @@ -5,6 +5,7 @@ import ( "reflect" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/frontend/cs/scs" "github.com/consensys/gnark/internal/backend/circuits" "github.com/google/go-cmp/cmp" @@ -67,10 +68,11 @@ func TestSerialization(t *testing.T) { if diff := cmp.Diff(r1cs1, &reconstructed, cmpopts.IgnoreFields(cs.R1CS{}, "System.q", - "arithEngine", + "field", "CoeffTable.mCoeffs", "System.lbWireLevel", "System.lbHints", + "System.genericHint", "System.SymbolTable", "System.lbOutputs", "System.bitLen")); diff != "" { @@ -139,11 +141,6 @@ func (circuit *circuit) Define(api frontend.API) error { func BenchmarkSolve(b *testing.B) { - var c circuit - ccs, err := frontend.Compile(fr.Modulus(),r1cs.NewBuilder, &c) - if err != nil { - b.Fatal(err) - } var w circuit w.X = 1 @@ -153,9 +150,32 @@ func BenchmarkSolve(b *testing.B) { b.Fatal(err) } + b.Run("scs", func(b *testing.B) { + var c circuit + ccs, err := frontend.Compile(fr.Modulus(),scs.NewBuilder, &c) + if err != nil { + b.Fatal(err) + } + b.Log("scs nbConstraints", ccs.GetNbConstraints()) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = ccs.IsSolved(witness) + } + }) + + b.Run("r1cs", func(b *testing.B) { + var c circuit + ccs, err := frontend.Compile(fr.Modulus(),r1cs.NewBuilder, &c, frontend.WithCompressThreshold(10)) + if err != nil { + b.Fatal(err) + } + b.Log("r1cs nbConstraints", ccs.GetNbConstraints()) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = ccs.IsSolved(witness) + } + }) - b.ResetTimer() - for i := 0; i < b.N; i++ { - _ = ccs.IsSolved(witness) - } } \ No newline at end of file diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl index 1654735bfa..3825d4b5fd 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl @@ -42,7 +42,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return nil, err } - log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", len(r1cs.Constraints)).Str("backend", "groth16").Logger() + log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() proof := &Proof{} diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl index ee62876564..bb10798030 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl @@ -85,7 +85,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } // Setting group for fft - domain := fft.NewDomain(uint64(len(r1cs.Constraints))) + domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) // samples toxic waste toxicWaste, err := sampleToxicWaste() @@ -316,7 +316,7 @@ func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr. var w fr.Element w.Set(&domain.Generator) wi := fr.One() - t := make([]fr.Element, len(r1cs.Constraints)+1) + t := make([]fr.Element, r1cs.GetNbConstraints()+1) for i := 0; i < len(t); i++ { t[i].Sub(&toxicWaste.t, &wi) wi.Mul(&wi, &w) // TODO this is already pre computed in fft.Domain @@ -360,8 +360,10 @@ func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr. // for each term appearing in the linear expression, // we compute term.Coefficient * L, and cumulate it in // A, B or C at the index of the variable - for i, c := range r1cs.Constraints { + j := 0 + it := r1cs.GetR1CIterator() + for c := it.Next(); c!=nil; c = it.Next() { for _, t := range c.L { accumulate(&A[t.WireID()], t, &L) } @@ -374,9 +376,12 @@ func setupABC(r1cs *cs.R1CS, domain *fft.Domain, toxicWaste toxicWaste) (A []fr. // Li+1 = w*Li*(t-w^i)/(t-w^(i+1)) L.Mul(&L, &w) - L.Mul(&L, &t[i]) - L.Mul(&L, &tInv[i+1]) + L.Mul(&L, &t[j]) + L.Mul(&L, &tInv[j+1]) + + j++ } + return } @@ -430,7 +435,7 @@ func sampleToxicWaste() (toxicWaste, error) { func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbConstraints := len(r1cs.Constraints) + nbConstraints := r1cs.GetNbConstraints() // Setting group for fft domain := fft.NewDomain(uint64(nbConstraints)) @@ -508,7 +513,9 @@ func dummyInfinityCount(r1cs *cs.R1CS) (nbZeroesA, nbZeroesB int) { A := make([]bool, nbWires) B := make([]bool, nbWires) - for _, c := range r1cs.Constraints { + + it := r1cs.GetR1CIterator() + for c := it.Next(); c!=nil; c = it.Next() { for _, t := range c.L { A[t.WireID()] = true } @@ -516,6 +523,8 @@ func dummyInfinityCount(r1cs *cs.R1CS) (nbZeroesA, nbZeroesB int) { B[t.WireID()] = true } } + + for i := 0; i < nbWires; i++ { if !A[i] { nbZeroesA++ diff --git a/internal/generator/backend/template/zkpschemes/groth16/mpcsetup/phase2.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/mpcsetup/phase2.go.tmpl index ba43428580..0afb32db79 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/mpcsetup/phase2.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/mpcsetup/phase2.go.tmpl @@ -98,7 +98,12 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { bA := make([]curve.G1Affine, nWires) aB := make([]curve.G1Affine, nWires) C := make([]curve.G1Affine, nWires) - for i, c := range r1cs.Constraints { + + // TODO @gbotrel use constraint iterator when available. + + i := 0 + it := r1cs.GetR1CIterator() + for c := it.Next(); c!=nil; c = it.Next() { // A for _, t := range c.L { accumulateG1(&evals.G1.A[t.WireID()], t, &coeffTau1[i]) @@ -114,8 +119,9 @@ func InitPhase2(r1cs *cs.R1CS, srs1 *Phase1) (Phase2, Phase2Evaluations) { for _, t := range c.O { accumulateG1(&C[t.WireID()], t, &coeffTau1[i]) } + i++ } - + // Prepare default contribution _, _, g1, g2 := curve.Generators() c2.Parameters.G1.Delta = g1 diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl index adb6ca524f..68cbaf556f 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl @@ -44,7 +44,7 @@ type Proof struct { func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { - log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", len(spr.Constraints)).Str("backend", "plonk").Logger() + log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", spr.GetNbConstraints()).Str("backend", "plonk").Logger() opt, err := backend.NewProverConfig(opts...) if err != nil { @@ -79,7 +79,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } - if _, err = pi2[offset+len(spr.Constraints)-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding + if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding return err } pi2iop := iop.NewPolynomial(&pi2, lagReg) diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl index 7b03b94c32..0e907a39f9 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl @@ -223,7 +223,7 @@ func (vk *VerifyingKey) InitKZG(srs kzgg.SRS) error { // Size is the size of the system that is nb_constraints+nb_public_variables func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { - nbConstraints := len(spr.Constraints) + nbConstraints := spr.GetNbConstraints() sizeSystem := uint64(nbConstraints + len(spr.Public)) size := ecc.NextPowerOfTwo(sizeSystem) @@ -242,15 +242,20 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qk[i].SetZero() // → to be completed by the prover } offset := len(spr.Public) - for i := 0; i < nbConstraints; i++ { // constraints - - ql[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) - qr[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) - qm[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). - Mul(&qm[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) - qo[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) - qk[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) + + + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c!=nil; c = it.Next() { + ql[offset+j].Set(&spr.Coefficients[c.QL]) + qr[offset+j].Set(&spr.Coefficients[c.QR]) + qm[offset+j].Set(&spr.Coefficients[c.QM]) + qo[offset+j].Set(&spr.Coefficients[c.QO]) + qk[offset+j].Set(&spr.Coefficients[c.QC]) + j++ } + for _, committed := range spr.CommitmentInfo.Committed { qcp[offset+committed].SetOne() } @@ -313,7 +318,7 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { func (pk *ProvingKey) initDomains(spr *cs.SparseR1CS) { - nbConstraints := len(spr.Constraints) + nbConstraints := spr.GetNbConstraints() sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints pk.Domain[0] = *fft.NewDomain(sizeSystem) @@ -359,12 +364,18 @@ func buildPermutation(spr *cs.SparseR1CS, pt *Trace, nbVariables int) { } offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // IDs of LRO associated to constraints - lro[offset+i] = spr.Constraints[i].L.WireID() - lro[sizeSolution+offset+i] = spr.Constraints[i].R.WireID() - lro[2*sizeSolution+offset+i] = spr.Constraints[i].O.WireID() + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c!=nil; c = it.Next() { + lro[offset+j] = int(c.XA) + lro[sizeSolution+offset+j] = int(c.XB) + lro[2*sizeSolution+offset+j] = int(c.XC) + + j++ } + // init cycle: // map ID -> last position the ID was seen cycle := make([]int64, nbVariables) diff --git a/internal/generator/backend/template/zkpschemes/plonkfri/plonk.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/plonkfri/plonk.setup.go.tmpl index f07ad840ba..8e37dc17a1 100644 --- a/internal/generator/backend/template/zkpschemes/plonkfri/plonk.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonkfri/plonk.setup.go.tmpl @@ -1,6 +1,7 @@ import ( "crypto/sha256" + {{- template "import_fri" . }} {{- template "import_fr" . }} {{- template "import_fft" . }} @@ -89,7 +90,7 @@ func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { // The verifying key shares data with the proving key pk.Vk = &vk - nbConstraints := len(spr.Constraints) + nbConstraints := spr.GetNbConstraints() // fft domains sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints @@ -139,17 +140,21 @@ func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { pk.CQkIncomplete[i].Set(&pk.LQkIncompleteDomainSmall[i]) // --> to be completed by the prover } offset := len(spr.Public) - for i := 0; i < nbConstraints; i++ { // constraints - - pk.EvaluationQlDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].L.CoeffID()]) - pk.EvaluationQrDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].R.CoeffID()]) - pk.EvaluationQmDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].M[0].CoeffID()]). - Mul(&pk.EvaluationQmDomainBigBitReversed[offset+i], &spr.Coefficients[spr.Constraints[i].M[1].CoeffID()]) - pk.EvaluationQoDomainBigBitReversed[offset+i].Set(&spr.Coefficients[spr.Constraints[i].O.CoeffID()]) - pk.LQkIncompleteDomainSmall[offset+i].Set(&spr.Coefficients[spr.Constraints[i].K]) - pk.CQkIncomplete[offset+i].Set(&pk.LQkIncompleteDomainSmall[offset+i]) + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c!=nil; c = it.Next() { + pk.EvaluationQlDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QL]) + pk.EvaluationQrDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QR]) + pk.EvaluationQmDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QM]) + pk.EvaluationQoDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QO]) + pk.LQkIncompleteDomainSmall[offset+j].Set(&spr.Coefficients[c.QC]) + pk.CQkIncomplete[offset+j].Set(&pk.LQkIncompleteDomainSmall[offset+j]) + + j++ } + pk.Domain[0].FFTInverse(pk.EvaluationQlDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) pk.Domain[0].FFTInverse(pk.EvaluationQrDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) pk.Domain[0].FFTInverse(pk.EvaluationQmDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) @@ -240,10 +245,14 @@ func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { } offset := len(spr.Public) - for i := 0; i < len(spr.Constraints); i++ { // IDs of LRO associated to constraints - lro[offset+i] = spr.Constraints[i].L.WireID() - lro[sizeSolution+offset+i] = spr.Constraints[i].R.WireID() - lro[2*sizeSolution+offset+i] = spr.Constraints[i].O.WireID() + + j := 0 + it := spr.GetSparseR1CIterator() + for c := it.Next(); c!=nil; c = it.Next() { + lro[offset+j] = int(c.XA) + lro[sizeSolution+offset+j] = int(c.XB) + lro[2*sizeSolution+offset+j] = int(c.XC) + j++ } // init cycle: diff --git a/profile/profile_test.go b/profile/profile_test.go index 04d5c3ebc7..f198f370e1 100644 --- a/profile/profile_test.go +++ b/profile/profile_test.go @@ -39,7 +39,7 @@ func Example() { _, _ = frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &Circuit{}) p.Stop() - // expected output + // expected output fmt.Println(p.Top()) const _ = `Showing nodes accounting for 2, 100% of 2 total ----------------------------------------------------------+------------- flat flat% sum% cum cum% calls calls% + context diff --git a/std/algebra/emulated/sw_bn254/pairing_test.go b/std/algebra/emulated/sw_bn254/pairing_test.go index 1d76ca0d45..90234b63d2 100644 --- a/std/algebra/emulated/sw_bn254/pairing_test.go +++ b/std/algebra/emulated/sw_bn254/pairing_test.go @@ -1,23 +1,31 @@ package sw_bn254 import ( + "bytes" "crypto/rand" "fmt" "testing" "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/frontend/cs/scs" "github.com/consensys/gnark/test" ) -func randomG1G2Affines(assert *test.Assert) (bn254.G1Affine, bn254.G2Affine) { +func randomG1G2Affines() (bn254.G1Affine, bn254.G2Affine) { _, _, G1AffGen, G2AffGen := bn254.Generators() mod := bn254.ID.ScalarField() s1, err := rand.Int(rand.Reader, mod) - assert.NoError(err) + if err != nil { + panic(err) + } s2, err := rand.Int(rand.Reader, mod) - assert.NoError(err) + if err != nil { + panic(err) + } var p bn254.G1Affine p.ScalarMultiplication(&G1AffGen, s1) var q bn254.G2Affine @@ -76,7 +84,7 @@ func (c *PairCircuit) Define(api frontend.API) error { func TestPairTestSolve(t *testing.T) { assert := test.NewAssert(t) - p, q := randomG1G2Affines(assert) + p, q := randomG1G2Affines() res, err := bn254.Pair([]bn254.G1Affine{p}, []bn254.G2Affine{q}) assert.NoError(err) witness := PairCircuit{ @@ -111,8 +119,8 @@ func (c *MultiPairCircuit) Define(api frontend.API) error { func TestMultiPairTestSolve(t *testing.T) { assert := test.NewAssert(t) - p1, q1 := randomG1G2Affines(assert) - p2, q2 := randomG1G2Affines(assert) + p1, q1 := randomG1G2Affines() + p2, q2 := randomG1G2Affines() res, err := bn254.Pair([]bn254.G1Affine{p1, p1, p2, p2}, []bn254.G2Affine{q1, q2, q1, q2}) assert.NoError(err) witness := MultiPairCircuit{ @@ -147,8 +155,8 @@ func (c *PairingCheckCircuit) Define(api frontend.API) error { func TestPairingCheckTestSolve(t *testing.T) { assert := test.NewAssert(t) - p1, q1 := randomG1G2Affines(assert) - _, q2 := randomG1G2Affines(assert) + p1, q1 := randomG1G2Affines() + _, q2 := randomG1G2Affines() var p2 bn254.G1Affine p2.Neg(&p1) witness := PairingCheckCircuit{ @@ -196,3 +204,67 @@ func TestFinalExponentiationSafeCircuit(t *testing.T) { }, ecc.BN254.ScalarField()) assert.NoError(err) } + +func BenchmarkPairing(b *testing.B) { + + p1, q1 := randomG1G2Affines() + _, q2 := randomG1G2Affines() + var p2 bn254.G1Affine + p2.Neg(&p1) + witness := PairingCheckCircuit{ + In1G1: NewG1Affine(p1), + In1G2: NewG2Affine(q1), + In2G1: NewG1Affine(p2), + In2G2: NewG2Affine(q2), + } + w, err := frontend.NewWitness(&witness, ecc.BN254.ScalarField()) + if err != nil { + b.Fatal(err) + } + var ccs constraint.ConstraintSystem + b.Run("compile scs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + if ccs, err = frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, &PairingCheckCircuit{}); err != nil { + b.Fatal(err) + } + } + }) + var buf bytes.Buffer + _, err = ccs.WriteTo(&buf) + if err != nil { + b.Fatal(err) + } + b.Logf("scs size: %d (bytes), nb constraints %d, nbInstructions: %d", buf.Len(), ccs.GetNbConstraints(), ccs.GetNbInstructions()) + b.Run("solve scs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + if _, err := ccs.Solve(w); err != nil { + b.Fatal(err) + } + } + }) + b.Run("compile r1cs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + if ccs, err = frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &PairingCheckCircuit{}); err != nil { + b.Fatal(err) + } + } + }) + buf.Reset() + _, err = ccs.WriteTo(&buf) + if err != nil { + b.Fatal(err) + } + b.Logf("r1cs size: %d (bytes), nb constraints %d, nbInstructions: %d", buf.Len(), ccs.GetNbConstraints(), ccs.GetNbInstructions()) + + b.Run("solve r1cs", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + if _, err := ccs.Solve(w); err != nil { + b.Fatal(err) + } + } + }) +} diff --git a/std/lookup/logderivlookup/logderivlookup.go b/std/lookup/logderivlookup/logderivlookup.go index 461500f732..4e5be350e6 100644 --- a/std/lookup/logderivlookup/logderivlookup.go +++ b/std/lookup/logderivlookup/logderivlookup.go @@ -135,7 +135,7 @@ func lookupHint(_ *big.Int, in []*big.Int, out []*big.Int) error { if ptr >= nbTable { return fmt.Errorf("lookup query %d outside table size %d", ptr, nbTable) } - out[i] = in[ptr] + out[i].Set(in[ptr]) } return nil } diff --git a/test/fuzz.go b/test/fuzz.go index a4c59eb69f..60a43a7471 100644 --- a/test/fuzz.go +++ b/test/fuzz.go @@ -74,7 +74,7 @@ func zeroFiller(w frontend.Circuit, curve ecc.ID) { } func binaryFiller(w frontend.Circuit, curve ecc.ID) { - mrand.Seed(time.Now().Unix()) + mrand := mrand.New(mrand.NewSource(time.Now().Unix())) //#nosec G404 weak rng is fine here fill(w, func() interface{} { return int(mrand.Uint32() % 2) //#nosec G404 weak rng is fine here @@ -83,7 +83,7 @@ func binaryFiller(w frontend.Circuit, curve ecc.ID) { func seedFiller(w frontend.Circuit, curve ecc.ID) { - mrand.Seed(time.Now().Unix()) + mrand := mrand.New(mrand.NewSource(time.Now().Unix())) //#nosec G404 weak rng is fine here m := curve.ScalarField() @@ -96,8 +96,6 @@ func seedFiller(w frontend.Circuit, curve ecc.ID) { func randomFiller(w frontend.Circuit, curve ecc.ID) { - mrand.Seed(time.Now().Unix()) - r := mrand.New(mrand.NewSource(time.Now().Unix())) //#nosec G404 weak rng is fine here m := curve.ScalarField() From 504884a78d73af24766c485a1e35d2d8c38afc19 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Sat, 22 Apr 2023 13:06:26 +0200 Subject: [PATCH 292/464] perf(2-chains/kzg): tradeoffs G2 scalarMul for G1 in single point verif --- std/commitments/kzg_bls12377/verifier.go | 15 +++++++-------- std/commitments/kzg_bls24315/verifier.go | 15 +++++++-------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/std/commitments/kzg_bls12377/verifier.go b/std/commitments/kzg_bls12377/verifier.go index 43dd15a83a..e7cffd85a3 100644 --- a/std/commitments/kzg_bls12377/verifier.go +++ b/std/commitments/kzg_bls12377/verifier.go @@ -63,17 +63,16 @@ func Verify(api frontend.API, commitment Digest, proof OpeningProof, point front var negH sw_bls12377.G1Affine negH.Neg(api, proof.H) - // [α-a]G₂ - var alphaMinusaG2 sw_bls12377.G2Affine - alphaMinusaG2.ScalarMulBase(api, point). - Neg(api, alphaMinusaG2). - AddAssign(api, srs.G2[1]) + // [f(α) - f(a) + a*H(α)]G₁ + var totalG1 sw_bls12377.G1Affine + totalG1.ScalarMul(api, proof.H, point). + AddAssign(api, fminusfaG1) - // e([f(α) - f(a)]G₁, G₂).e([-H(α)]G₁, [α-a]G₂) ==? 1 + // e([f(α)-f(a)+aH(α)]G₁], G₂).e([-H(α)]G₁, [α]G₂) == 1 resPairing, _ := sw_bls12377.Pair( api, - []sw_bls12377.G1Affine{fminusfaG1, negH}, - []sw_bls12377.G2Affine{srs.G2[0], alphaMinusaG2}, + []sw_bls12377.G1Affine{totalG1, negH}, + []sw_bls12377.G2Affine{srs.G2[0], srs.G2[1]}, ) var one fields_bls12377.E12 diff --git a/std/commitments/kzg_bls24315/verifier.go b/std/commitments/kzg_bls24315/verifier.go index 4d6680c072..260064b691 100644 --- a/std/commitments/kzg_bls24315/verifier.go +++ b/std/commitments/kzg_bls24315/verifier.go @@ -63,17 +63,16 @@ func Verify(api frontend.API, commitment Digest, proof OpeningProof, point front var negH sw_bls24315.G1Affine negH.Neg(api, proof.H) - // [α-a]G₂ - var alphaMinusaG2 sw_bls24315.G2Affine - alphaMinusaG2.ScalarMulBase(api, point). - Neg(api, alphaMinusaG2). - AddAssign(api, srs.G2[1]) + // [f(α) - f(a) + a*H(α)]G₁ + var totalG1 sw_bls24315.G1Affine + totalG1.ScalarMul(api, proof.H, point). + AddAssign(api, fminusfaG1) - // e([f(α) - f(a)]G₁, G₂).e([-H(α)]G₁, [α-a]G₂) ==? 1 + // e([f(α)-f(a)+aH(α)]G₁], G₂).e([-H(α)]G₁, [α]G₂) == 1 resPairing, _ := sw_bls24315.Pair( api, - []sw_bls24315.G1Affine{fminusfaG1, negH}, - []sw_bls24315.G2Affine{srs.G2[0], alphaMinusaG2}, + []sw_bls24315.G1Affine{totalG1, negH}, + []sw_bls24315.G2Affine{srs.G2[0], srs.G2[1]}, ) var one fields_bls24315.E24 From 462d04f1df5552f528cdbac6ca900c1bd2788a87 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 25 Apr 2023 15:23:53 +0200 Subject: [PATCH 293/464] docs: typo --- std/evmprecompiles/06-bnadd.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/evmprecompiles/06-bnadd.go b/std/evmprecompiles/06-bnadd.go index ed40938a2f..ff6c397fc9 100644 --- a/std/evmprecompiles/06-bnadd.go +++ b/std/evmprecompiles/06-bnadd.go @@ -15,7 +15,7 @@ func ECAdd(api frontend.API, P, Q *sw_emulated.AffinePoint[emulated.BN254Fp]) *s panic(err) } // Check that P and Q are on the curve (done in the zkEVM ⚠️ ) - // We use AddUnified because P can be equal to Q, -Q and eithier or both can be (0,0) + // We use AddUnified because P can be equal to Q, -Q and either or both can be (0,0) res := curve.AddUnified(P, Q) return res } From 94f1ddc220e2d22832e4c6394c103d983c5cb116 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Tue, 25 Apr 2023 10:00:21 -0500 Subject: [PATCH 294/464] perf: reduce mem allocs in scs frontend (#654) * perf: avoid []uint32 alloc when compressing constraints * perf: reduce allocs in scs frontend * fix: remove System.lbHints from go-cmp test --- constraint/bls12-377/coeff.go | 4 +- constraint/bls12-377/r1cs_test.go | 1 - constraint/bls12-381/coeff.go | 4 +- constraint/bls12-381/r1cs_test.go | 1 - constraint/bls24-315/coeff.go | 4 +- constraint/bls24-315/r1cs_test.go | 1 - constraint/bls24-317/coeff.go | 4 +- constraint/bls24-317/r1cs_test.go | 1 - constraint/blueprint_hint.go | 2 +- constraint/blueprint_r1cs.go | 16 ++++- constraint/blueprint_scs.go | 63 ++++++++++--------- constraint/bn254/coeff.go | 4 +- constraint/bn254/r1cs_test.go | 1 - constraint/bw6-633/coeff.go | 4 +- constraint/bw6-633/r1cs_test.go | 1 - constraint/bw6-761/coeff.go | 4 +- constraint/bw6-761/r1cs_test.go | 1 - constraint/core.go | 11 ++-- constraint/hint.go | 6 +- constraint/level_builder.go | 1 - constraint/r1cs_test.go | 22 +++---- constraint/system.go | 2 +- constraint/tinyfield/coeff.go | 4 +- constraint/tinyfield/r1cs_test.go | 1 - frontend/cs/r1cs/builder.go | 4 +- frontend/cs/scs/api.go | 18 ++++-- frontend/cs/scs/api_assertions.go | 25 +++++--- frontend/cs/scs/builder.go | 57 +++++++++++++---- .../template/representations/coeff.go.tmpl | 8 +-- .../representations/tests/r1cs.go.tmpl | 1 - 30 files changed, 165 insertions(+), 111 deletions(-) diff --git a/constraint/bls12-377/coeff.go b/constraint/bls12-377/coeff.go index 5b4034aaab..d7aa2403b8 100644 --- a/constraint/bls12-377/coeff.go +++ b/constraint/bls12-377/coeff.go @@ -72,8 +72,8 @@ func (ct *CoeffTable) AddCoeff(coeff constraint.Element) uint32 { return cID } -func (ct *CoeffTable) MakeTerm(coeff *constraint.Element, variableID int) constraint.Term { - cID := ct.AddCoeff(*coeff) +func (ct *CoeffTable) MakeTerm(coeff constraint.Element, variableID int) constraint.Term { + cID := ct.AddCoeff(coeff) return constraint.Term{VID: uint32(variableID), CID: cID} } diff --git a/constraint/bls12-377/r1cs_test.go b/constraint/bls12-377/r1cs_test.go index 99c531bf98..f789c5f50b 100644 --- a/constraint/bls12-377/r1cs_test.go +++ b/constraint/bls12-377/r1cs_test.go @@ -80,7 +80,6 @@ func TestSerialization(t *testing.T) { "field", "CoeffTable.mCoeffs", "System.lbWireLevel", - "System.lbHints", "System.genericHint", "System.SymbolTable", "System.lbOutputs", diff --git a/constraint/bls12-381/coeff.go b/constraint/bls12-381/coeff.go index 2d27dc0b02..55328ca99a 100644 --- a/constraint/bls12-381/coeff.go +++ b/constraint/bls12-381/coeff.go @@ -72,8 +72,8 @@ func (ct *CoeffTable) AddCoeff(coeff constraint.Element) uint32 { return cID } -func (ct *CoeffTable) MakeTerm(coeff *constraint.Element, variableID int) constraint.Term { - cID := ct.AddCoeff(*coeff) +func (ct *CoeffTable) MakeTerm(coeff constraint.Element, variableID int) constraint.Term { + cID := ct.AddCoeff(coeff) return constraint.Term{VID: uint32(variableID), CID: cID} } diff --git a/constraint/bls12-381/r1cs_test.go b/constraint/bls12-381/r1cs_test.go index 98830260bc..3a7e10de55 100644 --- a/constraint/bls12-381/r1cs_test.go +++ b/constraint/bls12-381/r1cs_test.go @@ -80,7 +80,6 @@ func TestSerialization(t *testing.T) { "field", "CoeffTable.mCoeffs", "System.lbWireLevel", - "System.lbHints", "System.genericHint", "System.SymbolTable", "System.lbOutputs", diff --git a/constraint/bls24-315/coeff.go b/constraint/bls24-315/coeff.go index 3f117c9b0f..dd3f16bea7 100644 --- a/constraint/bls24-315/coeff.go +++ b/constraint/bls24-315/coeff.go @@ -72,8 +72,8 @@ func (ct *CoeffTable) AddCoeff(coeff constraint.Element) uint32 { return cID } -func (ct *CoeffTable) MakeTerm(coeff *constraint.Element, variableID int) constraint.Term { - cID := ct.AddCoeff(*coeff) +func (ct *CoeffTable) MakeTerm(coeff constraint.Element, variableID int) constraint.Term { + cID := ct.AddCoeff(coeff) return constraint.Term{VID: uint32(variableID), CID: cID} } diff --git a/constraint/bls24-315/r1cs_test.go b/constraint/bls24-315/r1cs_test.go index a1baa6474c..bf09d377f8 100644 --- a/constraint/bls24-315/r1cs_test.go +++ b/constraint/bls24-315/r1cs_test.go @@ -80,7 +80,6 @@ func TestSerialization(t *testing.T) { "field", "CoeffTable.mCoeffs", "System.lbWireLevel", - "System.lbHints", "System.genericHint", "System.SymbolTable", "System.lbOutputs", diff --git a/constraint/bls24-317/coeff.go b/constraint/bls24-317/coeff.go index 20cbf188d7..15c2373224 100644 --- a/constraint/bls24-317/coeff.go +++ b/constraint/bls24-317/coeff.go @@ -72,8 +72,8 @@ func (ct *CoeffTable) AddCoeff(coeff constraint.Element) uint32 { return cID } -func (ct *CoeffTable) MakeTerm(coeff *constraint.Element, variableID int) constraint.Term { - cID := ct.AddCoeff(*coeff) +func (ct *CoeffTable) MakeTerm(coeff constraint.Element, variableID int) constraint.Term { + cID := ct.AddCoeff(coeff) return constraint.Term{VID: uint32(variableID), CID: cID} } diff --git a/constraint/bls24-317/r1cs_test.go b/constraint/bls24-317/r1cs_test.go index ef2a685d08..124f6403f0 100644 --- a/constraint/bls24-317/r1cs_test.go +++ b/constraint/bls24-317/r1cs_test.go @@ -80,7 +80,6 @@ func TestSerialization(t *testing.T) { "field", "CoeffTable.mCoeffs", "System.lbWireLevel", - "System.lbHints", "System.genericHint", "System.SymbolTable", "System.lbOutputs", diff --git a/constraint/blueprint_hint.go b/constraint/blueprint_hint.go index bc171232ac..159cb6042e 100644 --- a/constraint/blueprint_hint.go +++ b/constraint/blueprint_hint.go @@ -43,7 +43,7 @@ func (b *BlueprintGenericHint) CompressHint(h HintMapping) []uint32 { nbInputs += 2 // output range start / end - r := make([]uint32, 0, nbInputs) + r := getBuffer(nbInputs) r = append(r, uint32(nbInputs)) r = append(r, uint32(h.HintID)) r = append(r, uint32(len(h.Inputs))) diff --git a/constraint/blueprint_r1cs.go b/constraint/blueprint_r1cs.go index 936a15cc07..b274397b28 100644 --- a/constraint/blueprint_r1cs.go +++ b/constraint/blueprint_r1cs.go @@ -17,7 +17,7 @@ func (b *BlueprintGenericR1C) NbConstraints() int { func (b *BlueprintGenericR1C) CompressR1C(c *R1C) []uint32 { // we store total nb inputs, len L, len R, len O, and then the "flatten" linear expressions nbInputs := 4 + 2*(len(c.L)+len(c.R)+len(c.O)) - r := make([]uint32, 0, nbInputs) + r := getBuffer(nbInputs) r = append(r, uint32(nbInputs)) r = append(r, uint32(len(c.L)), uint32(len(c.R)), uint32(len(c.O))) for _, t := range c.L { @@ -56,3 +56,17 @@ func (b *BlueprintGenericR1C) DecompressR1C(c *R1C, calldata []uint32) { copySlice(&c.R, lenR, offset+2*lenL) copySlice(&c.O, lenO, offset+2*(lenL+lenR)) } + +// since frontend is single threaded, to avoid allocating slices at each compress call +// we transit the compressed output through here +var bufCalldata []uint32 + +// getBuffer return a slice with at least the given capacity to use in Compress methods +// this is obviously not thread safe, but the frontend is single threaded anyway. +func getBuffer(size int) []uint32 { + if cap(bufCalldata) < size { + bufCalldata = make([]uint32, 0, size*2) + } + bufCalldata = bufCalldata[:0] + return bufCalldata +} diff --git a/constraint/blueprint_scs.go b/constraint/blueprint_scs.go index f12584289b..90ede13fb7 100644 --- a/constraint/blueprint_scs.go +++ b/constraint/blueprint_scs.go @@ -14,7 +14,8 @@ var ( // Encodes // // qL⋅xa + qR⋅xb + qO⋅xc + qM⋅(xaxb) + qC == 0 -type BlueprintGenericSparseR1C struct{} +type BlueprintGenericSparseR1C struct { +} func (b *BlueprintGenericSparseR1C) NbInputs() int { return 9 // number of fields in SparseR1C @@ -24,17 +25,16 @@ func (b *BlueprintGenericSparseR1C) NbConstraints() int { } func (b *BlueprintGenericSparseR1C) CompressSparseR1C(c *SparseR1C) []uint32 { - return []uint32{ - c.XA, - c.XB, - c.XC, - c.QL, - c.QR, - c.QO, - c.QM, - c.QC, - uint32(c.Commitment), - } + bufSCS[0] = c.XA + bufSCS[1] = c.XB + bufSCS[2] = c.XC + bufSCS[3] = c.QL + bufSCS[4] = c.QR + bufSCS[5] = c.QO + bufSCS[6] = c.QM + bufSCS[7] = c.QC + bufSCS[8] = uint32(c.Commitment) + return bufSCS[:] } func (b *BlueprintGenericSparseR1C) DecompressSparseR1C(c *SparseR1C, calldata []uint32) { @@ -167,12 +167,11 @@ func (b *BlueprintSparseR1CMul) NbConstraints() int { } func (b *BlueprintSparseR1CMul) CompressSparseR1C(c *SparseR1C) []uint32 { - return []uint32{ - c.XA, - c.XB, - c.XC, - c.QM, - } + bufSCS[0] = c.XA + bufSCS[1] = c.XB + bufSCS[2] = c.XC + bufSCS[3] = c.QM + return bufSCS[:4] } func (b *BlueprintSparseR1CMul) Solve(s Solver, calldata []uint32) error { @@ -209,14 +208,13 @@ func (b *BlueprintSparseR1CAdd) NbConstraints() int { } func (b *BlueprintSparseR1CAdd) CompressSparseR1C(c *SparseR1C) []uint32 { - return []uint32{ - c.XA, - c.XB, - c.XC, - c.QL, - c.QR, - c.QC, - } + bufSCS[0] = c.XA + bufSCS[1] = c.XB + bufSCS[2] = c.XC + bufSCS[3] = c.QL + bufSCS[4] = c.QR + bufSCS[5] = c.QC + return bufSCS[:6] } func (blueprint *BlueprintSparseR1CAdd) Solve(s Solver, calldata []uint32) error { @@ -258,11 +256,10 @@ func (b *BlueprintSparseR1CBool) NbConstraints() int { } func (b *BlueprintSparseR1CBool) CompressSparseR1C(c *SparseR1C) []uint32 { - return []uint32{ - c.XA, - c.QL, - c.QM, - } + bufSCS[0] = c.XA + bufSCS[1] = c.QL + bufSCS[2] = c.QM + return bufSCS[:3] } func (blueprint *BlueprintSparseR1CBool) Solve(s Solver, calldata []uint32) error { @@ -285,3 +282,7 @@ func (b *BlueprintSparseR1CBool) DecompressSparseR1C(c *SparseR1C, calldata []ui c.QL = calldata[1] c.QM = calldata[2] } + +// since frontend is single threaded, to avoid allocating slices at each compress call +// we transit the compressed output through here +var bufSCS [9]uint32 diff --git a/constraint/bn254/coeff.go b/constraint/bn254/coeff.go index b4d06ad0a6..0ce316660d 100644 --- a/constraint/bn254/coeff.go +++ b/constraint/bn254/coeff.go @@ -72,8 +72,8 @@ func (ct *CoeffTable) AddCoeff(coeff constraint.Element) uint32 { return cID } -func (ct *CoeffTable) MakeTerm(coeff *constraint.Element, variableID int) constraint.Term { - cID := ct.AddCoeff(*coeff) +func (ct *CoeffTable) MakeTerm(coeff constraint.Element, variableID int) constraint.Term { + cID := ct.AddCoeff(coeff) return constraint.Term{VID: uint32(variableID), CID: cID} } diff --git a/constraint/bn254/r1cs_test.go b/constraint/bn254/r1cs_test.go index f872b83a3f..e7ca65cfd8 100644 --- a/constraint/bn254/r1cs_test.go +++ b/constraint/bn254/r1cs_test.go @@ -80,7 +80,6 @@ func TestSerialization(t *testing.T) { "field", "CoeffTable.mCoeffs", "System.lbWireLevel", - "System.lbHints", "System.genericHint", "System.SymbolTable", "System.lbOutputs", diff --git a/constraint/bw6-633/coeff.go b/constraint/bw6-633/coeff.go index 01d84ce575..fd9a96465c 100644 --- a/constraint/bw6-633/coeff.go +++ b/constraint/bw6-633/coeff.go @@ -72,8 +72,8 @@ func (ct *CoeffTable) AddCoeff(coeff constraint.Element) uint32 { return cID } -func (ct *CoeffTable) MakeTerm(coeff *constraint.Element, variableID int) constraint.Term { - cID := ct.AddCoeff(*coeff) +func (ct *CoeffTable) MakeTerm(coeff constraint.Element, variableID int) constraint.Term { + cID := ct.AddCoeff(coeff) return constraint.Term{VID: uint32(variableID), CID: cID} } diff --git a/constraint/bw6-633/r1cs_test.go b/constraint/bw6-633/r1cs_test.go index 954401f685..e63b4d8a5e 100644 --- a/constraint/bw6-633/r1cs_test.go +++ b/constraint/bw6-633/r1cs_test.go @@ -80,7 +80,6 @@ func TestSerialization(t *testing.T) { "field", "CoeffTable.mCoeffs", "System.lbWireLevel", - "System.lbHints", "System.genericHint", "System.SymbolTable", "System.lbOutputs", diff --git a/constraint/bw6-761/coeff.go b/constraint/bw6-761/coeff.go index 0206740d31..c23fff8258 100644 --- a/constraint/bw6-761/coeff.go +++ b/constraint/bw6-761/coeff.go @@ -72,8 +72,8 @@ func (ct *CoeffTable) AddCoeff(coeff constraint.Element) uint32 { return cID } -func (ct *CoeffTable) MakeTerm(coeff *constraint.Element, variableID int) constraint.Term { - cID := ct.AddCoeff(*coeff) +func (ct *CoeffTable) MakeTerm(coeff constraint.Element, variableID int) constraint.Term { + cID := ct.AddCoeff(coeff) return constraint.Term{VID: uint32(variableID), CID: cID} } diff --git a/constraint/bw6-761/r1cs_test.go b/constraint/bw6-761/r1cs_test.go index 54309d49aa..32136c08b3 100644 --- a/constraint/bw6-761/r1cs_test.go +++ b/constraint/bw6-761/r1cs_test.go @@ -83,7 +83,6 @@ func TestSerialization(t *testing.T) { "field", "CoeffTable.mCoeffs", "System.lbWireLevel", - "System.lbHints", "System.genericHint", "System.SymbolTable", "System.lbOutputs", diff --git a/constraint/core.go b/constraint/core.go index 2bc71f49bb..6efb8d911f 100644 --- a/constraint/core.go +++ b/constraint/core.go @@ -88,9 +88,8 @@ type System struct { bitLen int `cbor:"-"` // level builder - lbWireLevel []int `cbor:"-"` // at which level we solve a wire. init at -1. - lbOutputs []uint32 `cbor:"-"` // wire outputs for current constraint. - lbHints map[int]struct{} `cbor:"-"` // hints we processed in current round + lbWireLevel []int `cbor:"-"` // at which level we solve a wire. init at -1. + lbOutputs []uint32 `cbor:"-"` // wire outputs for current constraint. CommitmentInfo Commitment @@ -108,9 +107,11 @@ func NewSystem(scalarField *big.Int, capacity int, t SystemType) System { MHintsDependencies: make(map[solver.HintID]string), q: new(big.Int).Set(scalarField), bitLen: scalarField.BitLen(), - lbHints: map[int]struct{}{}, Instructions: make([]Instruction, 0, capacity), - CallData: make([]uint32, 0, capacity*2), + CallData: make([]uint32, 0, capacity*8), + lbOutputs: make([]uint32, 0, 256), + lbWireLevel: make([]int, 0, capacity), + Levels: make([][]int, 0, capacity/2), } system.genericHint = system.AddBlueprint(&BlueprintGenericHint{}) return system diff --git a/constraint/hint.go b/constraint/hint.go index e8c9f91738..a79bfea41d 100644 --- a/constraint/hint.go +++ b/constraint/hint.go @@ -21,14 +21,14 @@ func (h *HintMapping) WireIterator() func() int { for i := 0; i < len(h.Inputs); i++ { n += len(h.Inputs[i]) } - inputs := make([]int, 0, n) + inputs := getBuffer(n) for i := 0; i < len(h.Inputs); i++ { for j := 0; j < len(h.Inputs[i]); j++ { term := h.Inputs[i][j] if term.IsConstant() { continue } - inputs = append(inputs, int(term.VID)) + inputs = append(inputs, term.VID) } } lenOutputs := int(h.OutputRange.End - h.OutputRange.Start) @@ -40,7 +40,7 @@ func (h *HintMapping) WireIterator() func() int { } if curr < lenOutputs+len(inputs) { curr++ - return inputs[curr-1-lenOutputs] + return int(inputs[curr-1-lenOutputs]) } return -1 } diff --git a/constraint/level_builder.go b/constraint/level_builder.go index 052d456809..f29c69f769 100644 --- a/constraint/level_builder.go +++ b/constraint/level_builder.go @@ -34,7 +34,6 @@ func (system *System) updateLevel(iID int, c Iterable) { // clean the table. NB! Do not remove or move, this is required to make the // compilation deterministic. system.lbOutputs = system.lbOutputs[:0] - system.lbHints = map[int]struct{}{} } func (system *System) processWire(wireID uint32, maxLevel *int) { diff --git a/constraint/r1cs_test.go b/constraint/r1cs_test.go index 4a82ca79d5..9444b5ef53 100644 --- a/constraint/r1cs_test.go +++ b/constraint/r1cs_test.go @@ -31,26 +31,26 @@ func ExampleR1CS_GetR1Cs() { // X² == X * X r1cs.AddR1C(constraint.R1C{ - L: constraint.LinearExpression{r1cs.MakeTerm(&cOne, X)}, - R: constraint.LinearExpression{r1cs.MakeTerm(&cOne, X)}, - O: constraint.LinearExpression{r1cs.MakeTerm(&cOne, v0)}, + L: constraint.LinearExpression{r1cs.MakeTerm(cOne, X)}, + R: constraint.LinearExpression{r1cs.MakeTerm(cOne, X)}, + O: constraint.LinearExpression{r1cs.MakeTerm(cOne, v0)}, }, blueprint) // X³ == X² * X r1cs.AddR1C(constraint.R1C{ - L: constraint.LinearExpression{r1cs.MakeTerm(&cOne, v0)}, - R: constraint.LinearExpression{r1cs.MakeTerm(&cOne, X)}, - O: constraint.LinearExpression{r1cs.MakeTerm(&cOne, v1)}, + L: constraint.LinearExpression{r1cs.MakeTerm(cOne, v0)}, + R: constraint.LinearExpression{r1cs.MakeTerm(cOne, X)}, + O: constraint.LinearExpression{r1cs.MakeTerm(cOne, v1)}, }, blueprint) // Y == X³ + X + 5 r1cs.AddR1C(constraint.R1C{ - R: constraint.LinearExpression{r1cs.MakeTerm(&cOne, ONE)}, - L: constraint.LinearExpression{r1cs.MakeTerm(&cOne, Y)}, + R: constraint.LinearExpression{r1cs.MakeTerm(cOne, ONE)}, + L: constraint.LinearExpression{r1cs.MakeTerm(cOne, Y)}, O: constraint.LinearExpression{ - r1cs.MakeTerm(&cFive, ONE), - r1cs.MakeTerm(&cOne, X), - r1cs.MakeTerm(&cOne, v1), + r1cs.MakeTerm(cFive, ONE), + r1cs.MakeTerm(cOne, X), + r1cs.MakeTerm(cOne, v1), }, }, blueprint) diff --git a/constraint/system.go b/constraint/system.go index fae9782eb9..964838485d 100644 --- a/constraint/system.go +++ b/constraint/system.go @@ -53,7 +53,7 @@ type ConstraintSystem interface { // MakeTerm returns a new Term. The constraint system may store coefficients in a map, so // calls to this function will grow the memory usage of the constraint system. - MakeTerm(coeff *Element, variableID int) Term + MakeTerm(coeff Element, variableID int) Term // AddCoeff adds a coefficient to the underlying constraint system. The system will not store duplicate, // but is not purging for unused coeff either, so this grows memory usage. diff --git a/constraint/tinyfield/coeff.go b/constraint/tinyfield/coeff.go index f81f7b969f..0cdeb84a93 100644 --- a/constraint/tinyfield/coeff.go +++ b/constraint/tinyfield/coeff.go @@ -72,8 +72,8 @@ func (ct *CoeffTable) AddCoeff(coeff constraint.Element) uint32 { return cID } -func (ct *CoeffTable) MakeTerm(coeff *constraint.Element, variableID int) constraint.Term { - cID := ct.AddCoeff(*coeff) +func (ct *CoeffTable) MakeTerm(coeff constraint.Element, variableID int) constraint.Term { + cID := ct.AddCoeff(coeff) return constraint.Term{VID: uint32(variableID), CID: cID} } diff --git a/constraint/tinyfield/r1cs_test.go b/constraint/tinyfield/r1cs_test.go index 44b9e76772..632222a0fa 100644 --- a/constraint/tinyfield/r1cs_test.go +++ b/constraint/tinyfield/r1cs_test.go @@ -83,7 +83,6 @@ func TestSerialization(t *testing.T) { "field", "CoeffTable.mCoeffs", "System.lbWireLevel", - "System.lbHints", "System.genericHint", "System.SymbolTable", "System.lbOutputs", diff --git a/frontend/cs/r1cs/builder.go b/frontend/cs/r1cs/builder.go index 8fa82209a0..b8036314fe 100644 --- a/frontend/cs/r1cs/builder.go +++ b/frontend/cs/r1cs/builder.go @@ -206,7 +206,7 @@ func (builder *builder) getLinearExpression(_l interface{}) constraint.LinearExp } L = make(constraint.LinearExpression, 0, len(tl)) for _, t := range tl { - L = append(L, builder.cs.MakeTerm(&t.Coeff, t.VID)) + L = append(L, builder.cs.MakeTerm(t.Coeff, t.VID)) } case constraint.LinearExpression: L = tl @@ -381,7 +381,7 @@ func (builder *builder) NewHint(f solver.Hint, nbOutputs int, inputs ...frontend hintInputs[i] = builder.getLinearExpression(t) } else { c := builder.cs.FromInterface(in) - term := builder.cs.MakeTerm(&c, 0) + term := builder.cs.MakeTerm(c, 0) term.MarkConstant() hintInputs[i] = constraint.LinearExpression{term} } diff --git a/frontend/cs/scs/api.go b/frontend/cs/scs/api.go index 1e932a34a2..c542a2752b 100644 --- a/frontend/cs/scs/api.go +++ b/frontend/cs/scs/api.go @@ -23,6 +23,7 @@ import ( "runtime" "strings" + "github.com/consensys/gnark/debug" "github.com/consensys/gnark/frontend/cs" "github.com/consensys/gnark/constraint" @@ -157,16 +158,23 @@ func (builder *builder) Inverse(i1 frontend.Variable) frontend.Variable { return builder.cs.ToBigInt(c) } t := i1.(expr.Term) - debug := builder.newDebugInfo("inverse", "1/", i1, " < ∞") res := builder.newInternalVariable() // res * i1 - 1 == 0 - builder.addPlonkConstraint(sparseR1C{ + constraint := sparseR1C{ xa: res.VID, xb: t.VID, qM: t.Coeff, qC: builder.tMinusOne, - }, debug) + } + + if debug.Debug { + debug := builder.newDebugInfo("inverse", "1/", i1, " < ∞") + builder.addPlonkConstraint(constraint, debug) + } else { + builder.addPlonkConstraint(constraint) + } + return res } @@ -513,7 +521,7 @@ func (builder *builder) Println(a ...frontend.Variable) { sbb.WriteString("%s") // we set limits to the linear expression, so that the log printer // can evaluate it before printing it - log.ToResolve = append(log.ToResolve, constraint.LinearExpression{builder.cs.MakeTerm(&v.Coeff, v.VID)}) + log.ToResolve = append(log.ToResolve, constraint.LinearExpression{builder.cs.MakeTerm(v.Coeff, v.VID)}) } else { builder.printArg(&log, &sbb, arg) } @@ -549,7 +557,7 @@ func (builder *builder) printArg(log *constraint.LogEntry, sbb *strings.Builder, v := tValue.Interface().(expr.Term) // we set limits to the linear expression, so that the log printer // can evaluate it before printing it - log.ToResolve = append(log.ToResolve, constraint.LinearExpression{builder.cs.MakeTerm(&v.Coeff, v.VID)}) + log.ToResolve = append(log.ToResolve, constraint.LinearExpression{builder.cs.MakeTerm(v.Coeff, v.VID)}) return nil } // ignoring error, printer() doesn't return errors diff --git a/frontend/cs/scs/api_assertions.go b/frontend/cs/scs/api_assertions.go index 41b6d51b3a..a4e4447b17 100644 --- a/frontend/cs/scs/api_assertions.go +++ b/frontend/cs/scs/api_assertions.go @@ -47,29 +47,40 @@ func (builder *builder) AssertIsEqual(i1, i2 frontend.Variable) { if i2Constant { xa := i1.(expr.Term) c2 := builder.cs.Neg(c2) - debug := builder.newDebugInfo("assertIsEqual", xa, "==", i2) // xa - i2 == 0 - builder.addPlonkConstraint(sparseR1C{ + toAdd := sparseR1C{ xa: xa.VID, qL: xa.Coeff, qC: c2, - }, debug) + } + + if debug.Debug { + debug := builder.newDebugInfo("assertIsEqual", xa, "==", i2) + builder.addPlonkConstraint(toAdd, debug) + } else { + builder.addPlonkConstraint(toAdd) + } return } xa := i1.(expr.Term) xb := i2.(expr.Term) - debug := builder.newDebugInfo("assertIsEqual", xa, " == ", xb) - xb.Coeff = builder.cs.Neg(xb.Coeff) // xa - xb == 0 - builder.addPlonkConstraint(sparseR1C{ + toAdd := sparseR1C{ xa: xa.VID, xb: xb.VID, qL: xa.Coeff, qR: xb.Coeff, - }, debug) + } + + if debug.Debug { + debug := builder.newDebugInfo("assertIsEqual", xa, " == ", xb) + builder.addPlonkConstraint(toAdd, debug) + } else { + builder.addPlonkConstraint(toAdd) + } } // AssertIsDifferent fails if i1 == i2 diff --git a/frontend/cs/scs/builder.go b/frontend/cs/scs/builder.go index 53604b2db4..eca3f32a4b 100644 --- a/frontend/cs/scs/builder.go +++ b/frontend/cs/scs/builder.go @@ -69,6 +69,10 @@ type builder struct { genericGate constraint.BlueprintID mulGate, addGate, boolGate constraint.BlueprintID + + // used to avoid repeated allocations + bufL expr.LinearExpression + bufH []constraint.LinearExpression } // initialCapacity has quite some impact on frontend performance, especially on large circuits size @@ -80,7 +84,10 @@ func newBuilder(field *big.Int, config frontend.CompileConfig) *builder { mAddInstructions: make(map[uint64]int, config.Capacity/2), config: config, Store: kvstore.New(), + bufL: make(expr.LinearExpression, 20), } + // init hint buffer. + _ = b.hintBuffer(256) curve := utils.FieldToCurve(field) @@ -311,6 +318,17 @@ func (builder *builder) constantValue(v frontend.Variable) (constraint.Element, return builder.cs.FromInterface(v), true } +func (builder *builder) hintBuffer(size int) []constraint.LinearExpression { + if cap(builder.bufH) < size { + builder.bufH = make([]constraint.LinearExpression, 2*size) + for i := 0; i < len(builder.bufH); i++ { + builder.bufH[i] = make(constraint.LinearExpression, 1) + } + } + + return builder.bufH[:size] +} + // NewHint initializes internal variables whose value will be evaluated using // the provided hint function at run time from the inputs. Inputs must be either // variables or convertible to *big.Int. The function returns an error if the @@ -324,18 +342,19 @@ func (builder *builder) constantValue(v frontend.Variable) (constraint.Element, // No new constraints are added to the newly created wire and must be added // manually in the circuit. Failing to do so leads to solver failure. func (builder *builder) NewHint(f solver.Hint, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { - hintInputs := make([]constraint.LinearExpression, len(inputs)) + + hintInputs := builder.hintBuffer(len(inputs)) // ensure inputs are set and pack them in a []uint64 for i, in := range inputs { switch t := in.(type) { case expr.Term: - hintInputs[i] = constraint.LinearExpression{builder.cs.MakeTerm(&t.Coeff, t.VID)} + hintInputs[i][0] = builder.cs.MakeTerm(t.Coeff, t.VID) default: c := builder.cs.FromInterface(in) - term := builder.cs.MakeTerm(&c, 0) + term := builder.cs.MakeTerm(c, 0) term.MarkConstant() - hintInputs[i] = constraint.LinearExpression{term} + hintInputs[i][0] = term } } @@ -355,7 +374,14 @@ func (builder *builder) NewHint(f solver.Hint, nbOutputs int, inputs ...frontend // returns in split into a slice of compiledTerm and the sum of all constants in in as a bigInt func (builder *builder) filterConstantSum(in []frontend.Variable) (expr.LinearExpression, constraint.Element) { - res := make(expr.LinearExpression, 0, len(in)) + var res expr.LinearExpression + if len(in) <= cap(builder.bufL) { + // we can use the temp buffer + res = builder.bufL[:0] + } else { + res = make(expr.LinearExpression, 0, len(in)) + } + b := constraint.Element{} for i := 0; i < len(in); i++ { if c, ok := builder.constantValue(in[i]); ok { @@ -369,7 +395,14 @@ func (builder *builder) filterConstantSum(in []frontend.Variable) (expr.LinearEx // returns in split into a slice of compiledTerm and the product of all constants in in as a coeff func (builder *builder) filterConstantProd(in []frontend.Variable) (expr.LinearExpression, constraint.Element) { - res := make(expr.LinearExpression, 0, len(in)) + var res expr.LinearExpression + if len(in) <= cap(builder.bufL) { + // we can use the temp buffer + res = builder.bufL[:0] + } else { + res = make(expr.LinearExpression, 0, len(in)) + } + b := builder.tOne for i := 0; i < len(in); i++ { if c, ok := builder.constantValue(in[i]); ok { @@ -452,7 +485,7 @@ func (builder *builder) addConstraintExist(a, b expr.Term, k constraint.Element) a, b = b, a // ensure a is in qL } - tk := builder.cs.MakeTerm(&k, 0) + tk := builder.cs.MakeTerm(k, 0) if tk.CoeffID() != int(c.QC) { // the constant part of the addition differs, no point going forward // since we will need to add a new constraint anyway. @@ -462,8 +495,8 @@ func (builder *builder) addConstraintExist(a, b expr.Term, k constraint.Element) // check that the coeff matches qL := a.Coeff qR := b.Coeff - ta := builder.cs.MakeTerm(&qL, 0) - tb := builder.cs.MakeTerm(&qR, 0) + ta := builder.cs.MakeTerm(qL, 0) + tb := builder.cs.MakeTerm(qR, 0) if int(c.QL) != ta.CoeffID() || int(c.QR) != tb.CoeffID() { if !k.IsZero() { // may be for some edge cases we could avoid adding a constraint here. @@ -543,7 +576,7 @@ func (builder *builder) mulConstraintExist(a, b expr.Term) (expr.Term, bool) { // recompute the qM coeff and check that it matches; qM := builder.cs.Mul(a.Coeff, b.Coeff) - tm := builder.cs.MakeTerm(&qM, 0) + tm := builder.cs.MakeTerm(qM, 0) if int(c.QM) != tm.CoeffID() { // so we wanted to compute // N * xC == qM*xA*xB @@ -602,9 +635,9 @@ func (builder *builder) newDebugInfo(errName string, in ...interface{}) constrai case *expr.LinearExpression, expr.LinearExpression: // shouldn't happen case expr.Term: - in[i] = builder.cs.MakeTerm(&t.Coeff, t.VID) + in[i] = builder.cs.MakeTerm(t.Coeff, t.VID) case *expr.Term: - in[i] = builder.cs.MakeTerm(&t.Coeff, t.VID) + in[i] = builder.cs.MakeTerm(t.Coeff, t.VID) case constraint.Element: in[i] = builder.cs.String(t) case *constraint.Element: diff --git a/internal/generator/backend/template/representations/coeff.go.tmpl b/internal/generator/backend/template/representations/coeff.go.tmpl index 3275becce4..637fd7cf29 100644 --- a/internal/generator/backend/template/representations/coeff.go.tmpl +++ b/internal/generator/backend/template/representations/coeff.go.tmpl @@ -53,9 +53,8 @@ func (ct *CoeffTable) AddCoeff(coeff constraint.Element) uint32 { return cID } - -func (ct *CoeffTable) MakeTerm(coeff *constraint.Element, variableID int) constraint.Term { - cID := ct.AddCoeff(*coeff) +func (ct *CoeffTable) MakeTerm(coeff constraint.Element, variableID int) constraint.Term { + cID := ct.AddCoeff(coeff) return constraint.Term{VID: uint32(variableID), CID: cID} } @@ -64,9 +63,6 @@ func (ct *CoeffTable) CoeffToString(cID int) string { return ct.Coefficients[cID].String() } - - - // implements constraint.Field type field struct{} diff --git a/internal/generator/backend/template/representations/tests/r1cs.go.tmpl b/internal/generator/backend/template/representations/tests/r1cs.go.tmpl index 5b583e6d80..3c5c9a8be4 100644 --- a/internal/generator/backend/template/representations/tests/r1cs.go.tmpl +++ b/internal/generator/backend/template/representations/tests/r1cs.go.tmpl @@ -71,7 +71,6 @@ func TestSerialization(t *testing.T) { "field", "CoeffTable.mCoeffs", "System.lbWireLevel", - "System.lbHints", "System.genericHint", "System.SymbolTable", "System.lbOutputs", From 07416c77e302a141a9796fe411df6afa27554e18 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 25 Apr 2023 19:47:37 +0200 Subject: [PATCH 295/464] test: use assertless sampling --- std/algebra/emulated/sw_bn254/g2_test.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/std/algebra/emulated/sw_bn254/g2_test.go b/std/algebra/emulated/sw_bn254/g2_test.go index 1b189abc5b..3e61f05cc4 100644 --- a/std/algebra/emulated/sw_bn254/g2_test.go +++ b/std/algebra/emulated/sw_bn254/g2_test.go @@ -24,8 +24,8 @@ func (c *addG2Circuit) Define(api frontend.API) error { func TestAddG2TestSolve(t *testing.T) { assert := test.NewAssert(t) - _, in1 := randomG1G2Affines(assert) - _, in2 := randomG1G2Affines(assert) + _, in1 := randomG1G2Affines() + _, in2 := randomG1G2Affines() var res bn254.G2Affine res.Add(&in1, &in2) witness := addG2Circuit{ @@ -51,7 +51,7 @@ func (c *doubleG2Circuit) Define(api frontend.API) error { func TestDoubleG2TestSolve(t *testing.T) { assert := test.NewAssert(t) - _, in1 := randomG1G2Affines(assert) + _, in1 := randomG1G2Affines() var res bn254.G2Affine var in1Jac, resJac bn254.G2Jac in1Jac.FromAffine(&in1) @@ -79,8 +79,8 @@ func (c *doubleAndAddG2Circuit) Define(api frontend.API) error { func TestDoubleAndAddG2TestSolve(t *testing.T) { assert := test.NewAssert(t) - _, in1 := randomG1G2Affines(assert) - _, in2 := randomG1G2Affines(assert) + _, in1 := randomG1G2Affines() + _, in2 := randomG1G2Affines() var res bn254.G2Affine res.Double(&in1). Add(&res, &in2) @@ -107,7 +107,7 @@ func (c *scalarMulG2BySeedCircuit) Define(api frontend.API) error { func TestScalarMulG2BySeedTestSolve(t *testing.T) { assert := test.NewAssert(t) - _, in1 := randomG1G2Affines(assert) + _, in1 := randomG1G2Affines() var res bn254.G2Affine x0, _ := new(big.Int).SetString("4965661367192848881", 10) res.ScalarMultiplication(&in1, x0) @@ -135,7 +135,7 @@ func (c *endomorphismG2Circuit) Define(api frontend.API) error { func TestEndomorphismG2TestSolve(t *testing.T) { assert := test.NewAssert(t) - _, in1 := randomG1G2Affines(assert) + _, in1 := randomG1G2Affines() witness := endomorphismG2Circuit{ In1: NewG2Affine(in1), } From 926ad6294a89aaecad9e5e3705f2ecc21a3dfbda Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Wed, 26 Apr 2023 11:04:40 +0200 Subject: [PATCH 296/464] fix: assert oddity of y coordinate from v instead of high bit (#655) * chore: update gnark-crypto dependency * fix: assert oddity of y from v * chore: gnark-crypto develop dep --- go.mod | 3 +-- go.sum | 10 ++-------- std/evmprecompiles/01-ecrecover.go | 4 ++-- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 06b593ffd4..94c31f282d 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/bits-and-blooms/bitset v1.5.0 github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 - github.com/consensys/gnark-crypto v0.10.1-0.20230420183752-ed3709c81831 + github.com/consensys/gnark-crypto v0.10.1-0.20230426090045-2a781ae21a86 github.com/fxamacker/cbor/v2 v2.4.0 github.com/google/go-cmp v0.5.9 github.com/google/pprof v0.0.0-20230309165930-d61513b1440d @@ -19,7 +19,6 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect - github.com/go-test/deep v1.1.0 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect diff --git a/go.sum b/go.sum index 8b9f7a7bfc..6dc974488d 100644 --- a/go.sum +++ b/go.sum @@ -4,12 +4,8 @@ github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.10.1-0.20230408232650-7fda2542de4d h1:TJ2dYEdgx8dVt4Jv/ftodldmVkQK3R4ntCGyo1u0v3U= -github.com/consensys/gnark-crypto v0.10.1-0.20230408232650-7fda2542de4d/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= -github.com/consensys/gnark-crypto v0.10.1-0.20230420025556-eaeb6db64ed7 h1:5OAqdipDbuXlHzpJY2xDjef1jn4gkdOpf4zRQB6WPaU= -github.com/consensys/gnark-crypto v0.10.1-0.20230420025556-eaeb6db64ed7/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= -github.com/consensys/gnark-crypto v0.10.1-0.20230420183752-ed3709c81831 h1:2y5CcR1Ww4wJxCZX4psdiIqdaNb7Kd4WM8YfPqQb6yY= -github.com/consensys/gnark-crypto v0.10.1-0.20230420183752-ed3709c81831/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= +github.com/consensys/gnark-crypto v0.10.1-0.20230426090045-2a781ae21a86 h1:Qvm/R59xXUiB7oM9v53kgN7JRn3yIGeGV9mninTVzWs= +github.com/consensys/gnark-crypto v0.10.1-0.20230426090045-2a781ae21a86/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -17,8 +13,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88= github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= -github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= -github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= diff --git a/std/evmprecompiles/01-ecrecover.go b/std/evmprecompiles/01-ecrecover.go index 0c3b6df724..00212b8468 100644 --- a/std/evmprecompiles/01-ecrecover.go +++ b/std/evmprecompiles/01-ecrecover.go @@ -59,10 +59,10 @@ func ECRecover(api frontend.API, msg emulated.Element[emulated.Secp256k1Fr], rfp := fpField.FromBits(rbits...) tmp = fpField.Add(rfp, tmp) fpField.AssertIsEqual(tmp, &R.X) - // check that Ry is correct: highbit(y) = v[0] + // check that Ry is correct: oddity(y) = v[0] Rynormal := fpField.Reduce(&R.Y) Rybits := fpField.ToBits(Rynormal) - api.AssertIsEqual(vbits[0], Rybits[emfp.Modulus().BitLen()-1]) + api.AssertIsEqual(vbits[0], Rybits[0]) // compute rinv = r^{-1} mod fr rinv := frField.Inverse(&r) // compute u1 = -msg * rinv From 7a5b6fdea6def2555e8eb8cc9dfddaface1a176a Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 26 Apr 2023 12:47:56 +0200 Subject: [PATCH 297/464] perf(ecdsa): JoinScalarMulBase avoids 0 edge-cases --- std/algebra/emulated/sw_emulated/point.go | 70 +++++++++++++++++++++++ std/evmprecompiles/01-ecrecover.go | 4 +- std/signature/ecdsa/ecdsa.go | 5 +- 3 files changed, 73 insertions(+), 6 deletions(-) diff --git a/std/algebra/emulated/sw_emulated/point.go b/std/algebra/emulated/sw_emulated/point.go index 7f4dc1dda5..7338bff86c 100644 --- a/std/algebra/emulated/sw_emulated/point.go +++ b/std/algebra/emulated/sw_emulated/point.go @@ -461,3 +461,73 @@ func (c *Curve[B, S]) ScalarMulBase(s *emulated.Element[S]) *AffinePoint[B] { return res } + +// JointScalarMulBase computes s2 * p + s1 * g and returns it, where g is the +// fixed generator. It doesn't modify p, s1 and s2. +// +// ⚠️ p must NOT be (0,0). +// ⚠️ s1 and s2 must NOT be 0. +// +// JointScalarMulBase is used to verify an ECDSA signature (r,s) on the +// secp256k1 curve. In this case, p is a public key, s2=r/s and s1=hash/s. +// - hash cannot be 0, because of pre-image resistance. +// - r cannot be 0, because r is the x coordinate of a random point on +// secp256k1 (y²=x³+7 mod p) and 7 is not a square mod p. For any other +// curve, (_,0) is a point of order 2 which is not the prime subgroup. +// - (0,0) is not a valid public key. +// +// The [EVM] specifies these checks, wich are performed on the zkEVM +// arithmetization side before calling the circuit that uses this method. +// +// This saves the Select logic related to (0,0) and the use of AddUnified to +// handle the 0-scalar edge case. +func (c *Curve[B, S]) JointScalarMulBase(p *AffinePoint[B], s2, s1 *emulated.Element[S]) *AffinePoint[B] { + g := c.Generator() + gm := c.GeneratorMultiples() + + var st S + s1r := c.scalarApi.Reduce(s1) + s1Bits := c.scalarApi.ToBits(s1r) + s2r := c.scalarApi.Reduce(s2) + s2Bits := c.scalarApi.ToBits(s2r) + n := st.Modulus().BitLen() + + // i = 1, 2 + // gm[0] = 3g, gm[1] = 5g, gm[2] = 7g + res1 := c.Lookup2(s1Bits[1], s1Bits[2], g, &gm[0], &gm[1], &gm[2]) + tmp2 := c.triple(p) + res2 := c.Select(s2Bits[1], tmp2, p) + acc := c.add(tmp2, p) + tmp2 = c.add(res2, acc) + res2 = c.Select(s2Bits[2], tmp2, res2) + acc = c.double(acc) + + for i := 3; i <= n-3; i++ { + // gm[i] = [2^i]g + tmp1 := c.add(res1, &gm[i]) + res1 = c.Select(s1Bits[i], tmp1, res1) + tmp2 = c.add(res2, acc) + res2 = c.Select(s2Bits[i], tmp2, res2) + acc = c.double(acc) + } + + // i = 0 + tmp1 := c.add(res1, c.Neg(g)) + res1 = c.Select(s1Bits[0], res1, tmp1) + tmp2 = c.add(res2, c.Neg(p)) + res2 = c.Select(s2Bits[0], res2, tmp2) + + // i = n-2 + tmp1 = c.add(res1, &gm[n-2]) + res1 = c.Select(s1Bits[n-2], tmp1, res1) + tmp2 = c.add(res2, acc) + res2 = c.Select(s2Bits[n-2], tmp2, res2) + + // i = n-1 + tmp1 = c.add(res1, &gm[n-1]) + res1 = c.Select(s1Bits[n-1], tmp1, res1) + tmp2 = c.doubleAndAdd(acc, res2) + res2 = c.Select(s2Bits[n-1], tmp2, res2) + + return c.add(res1, res2) +} diff --git a/std/evmprecompiles/01-ecrecover.go b/std/evmprecompiles/01-ecrecover.go index 00212b8468..1748a24295 100644 --- a/std/evmprecompiles/01-ecrecover.go +++ b/std/evmprecompiles/01-ecrecover.go @@ -71,9 +71,7 @@ func ECRecover(api frontend.API, msg emulated.Element[emulated.Secp256k1Fr], // compute u2 = s * rinv u2 := frField.MulMod(&s, rinv) // check u1 * G + u2 R == P - A := curve.ScalarMulBase(u1) - B := curve.ScalarMul(&R, u2) - C := curve.AddUnified(A, B) + C := curve.JointScalarMulBase(&R, u2, u1) curve.AssertIsEqual(C, &P) return &P } diff --git a/std/signature/ecdsa/ecdsa.go b/std/signature/ecdsa/ecdsa.go index 72495b303f..cac32d7db1 100644 --- a/std/signature/ecdsa/ecdsa.go +++ b/std/signature/ecdsa/ecdsa.go @@ -50,9 +50,8 @@ func (pk PublicKey[T, S]) Verify(api frontend.API, params sw_emulated.CurveParam msInv := scalarApi.MulMod(msg, sInv) rsInv := scalarApi.MulMod(&sig.R, sInv) - qa := cr.ScalarMulBase(msInv) - qb := cr.ScalarMul(&pkpt, rsInv) - q := cr.AddUnified(qa, qb) + // q = [rsInv]pkpt + [msInv]g + q := cr.JointScalarMulBase(&pkpt, rsInv, msInv) qx := baseApi.Reduce(&q.X) qxBits := baseApi.ToBits(qx) rbits := scalarApi.ToBits(&sig.R) From e90a08288d9c2b15c60823399d3ed6b28159fbea Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 26 Apr 2023 12:27:14 -0500 Subject: [PATCH 298/464] refactor: limit commitment info in groth16 ver --- backend/groth16/bn254/commitment.go | 4 ++-- backend/groth16/bn254/prove.go | 2 +- backend/groth16/bn254/setup.go | 8 +++++--- backend/groth16/bn254/verify.go | 12 ++++++------ backend/plonk/bn254/setup.go | 2 +- constraint/commitment.go | 6 +++++- 6 files changed, 20 insertions(+), 14 deletions(-) diff --git a/backend/groth16/bn254/commitment.go b/backend/groth16/bn254/commitment.go index d3930c0f08..435a7c058c 100644 --- a/backend/groth16/bn254/commitment.go +++ b/backend/groth16/bn254/commitment.go @@ -23,7 +23,7 @@ import ( "math/big" ) -func solveCommitmentWire(commitmentInfo *constraint.Commitment, commitment *curve.G1Affine, publicCommitted []*big.Int) (fr.Element, error) { - res, err := fr.Hash(commitmentInfo.SerializeCommitment(commitment.Marshal(), publicCommitted, (fr.Bits-1)/8+1), []byte(constraint.CommitmentDst), 1) +func solveCommitmentWire(commitment *curve.G1Affine, publicCommitted []*big.Int) (fr.Element, error) { + res, err := fr.Hash(constraint.SerializeCommitment(commitment.Marshal(), publicCommitted, (fr.Bits-1)/8+1), []byte(constraint.CommitmentDst), 1) return res[0], err } diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index abda2496c5..ce6da1e350 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -86,7 +86,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var res fr.Element - res, err = solveCommitmentWire(&r1cs.CommitmentInfo, &proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) res.BigInt(out[0]) return err })) diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index 5262bf241e..f66c9b0ef2 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -75,8 +75,9 @@ type VerifyingKey struct { // e(α, β) e curve.GT // not serialized - CommitmentKey pedersen.VerifyingKey - CommitmentInfo constraint.Commitment // since the verifier doesn't input a constraint system, this needs to be provided here + CommitmentKey pedersen.VerifyingKey + HasCommitment bool // TODO: Make CommitmentKey nullable instead + PublicCommitted []int // indexes of public committed variables } // Setup constructs the SRS @@ -262,7 +263,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - vk.CommitmentInfo = r1cs.CommitmentInfo // unfortunate but necessary + vk.HasCommitment = r1cs.CommitmentInfo.Is() + vk.PublicCommitted = r1cs.CommitmentInfo.PrivateCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bn254/verify.go b/backend/groth16/bn254/verify.go index a5a5b544ba..e5310d0624 100644 --- a/backend/groth16/bn254/verify.go +++ b/backend/groth16/bn254/verify.go @@ -38,7 +38,7 @@ var ( func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { nbPublicVars := len(vk.G1.K) - if vk.CommitmentInfo.Is() { + if vk.HasCommitment { nbPublicVars-- } if len(publicWitness) != nbPublicVars-1 { @@ -63,20 +63,20 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() - if vk.CommitmentInfo.Is() { + if vk.HasCommitment { if err := vk.CommitmentKey.Verify(proof.Commitment, proof.CommitmentPok); err != nil { return err } - publicCommitted := make([]*big.Int, vk.CommitmentInfo.NbPublicCommitted()) + publicCommitted := make([]*big.Int, len(vk.PublicCommitted)) for i := range publicCommitted { var b big.Int - publicWitness[vk.CommitmentInfo.Committed[i]-1].BigInt(&b) + publicWitness[vk.PublicCommitted[i]-1].BigInt(&b) publicCommitted[i] = &b } - if res, err := solveCommitmentWire(&vk.CommitmentInfo, &proof.Commitment, publicCommitted); err == nil { + if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err == nil { publicWitness = append(publicWitness, res) } } @@ -88,7 +88,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } kSum.AddMixed(&vk.G1.K[0]) - if vk.CommitmentInfo.Is() { + if vk.HasCommitment { kSum.AddMixed(&proof.Commitment) } diff --git a/backend/plonk/bn254/setup.go b/backend/plonk/bn254/setup.go index ba3f0333ff..b98a99b06f 100644 --- a/backend/plonk/bn254/setup.go +++ b/backend/plonk/bn254/setup.go @@ -264,7 +264,7 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { } -// commitTrace commits to every polynomials in the trace, and put +// commitTrace commits to every polynomial in the trace, and put // the commitments int the verifying key. func commitTrace(trace *Trace, pk *ProvingKey) error { diff --git a/constraint/commitment.go b/constraint/commitment.go index ec3786b559..1b5b51c864 100644 --- a/constraint/commitment.go +++ b/constraint/commitment.go @@ -38,7 +38,7 @@ func NewCommitment(committed []int, nbPublicCommitted int) Commitment { } } -func (i *Commitment) SerializeCommitment(privateCommitment []byte, publicCommitted []*big.Int, fieldByteLen int) []byte { +func SerializeCommitment(privateCommitment []byte, publicCommitted []*big.Int, fieldByteLen int) []byte { res := make([]byte, len(privateCommitment)+len(publicCommitted)*fieldByteLen) copy(res, privateCommitment) @@ -60,3 +60,7 @@ func (i *Commitment) PrivateToPublic() []int { func (i *Commitment) PrivateCommitted() []int { return i.Committed[i.NbPublicCommitted():] } + +func (i *Commitment) PublicCommitted() []int { + return i.Committed[:i.NbPublicCommitted()] +} From a51cc58763aafe5ef855319a508feb5dcd8b04dd Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 26 Apr 2023 12:33:45 -0500 Subject: [PATCH 299/464] build: generify bn254 changes --- backend/groth16/bls12-377/commitment.go | 4 ++-- backend/groth16/bls12-377/prove.go | 2 +- backend/groth16/bls12-377/setup.go | 8 +++++--- backend/groth16/bls12-377/verify.go | 12 ++++++------ backend/groth16/bls12-381/commitment.go | 4 ++-- backend/groth16/bls12-381/prove.go | 2 +- backend/groth16/bls12-381/setup.go | 8 +++++--- backend/groth16/bls12-381/verify.go | 12 ++++++------ backend/groth16/bls24-315/commitment.go | 4 ++-- backend/groth16/bls24-315/prove.go | 2 +- backend/groth16/bls24-315/setup.go | 8 +++++--- backend/groth16/bls24-315/verify.go | 12 ++++++------ backend/groth16/bls24-317/commitment.go | 4 ++-- backend/groth16/bls24-317/prove.go | 2 +- backend/groth16/bls24-317/setup.go | 8 +++++--- backend/groth16/bls24-317/verify.go | 12 ++++++------ backend/groth16/bw6-633/commitment.go | 4 ++-- backend/groth16/bw6-633/prove.go | 2 +- backend/groth16/bw6-633/setup.go | 8 +++++--- backend/groth16/bw6-633/verify.go | 12 ++++++------ backend/groth16/bw6-761/commitment.go | 4 ++-- backend/groth16/bw6-761/prove.go | 2 +- backend/groth16/bw6-761/setup.go | 8 +++++--- backend/groth16/bw6-761/verify.go | 12 ++++++------ backend/plonk/bn254/setup.go | 2 +- .../zkpschemes/groth16/groth16.commitment.go.tmpl | 4 ++-- .../zkpschemes/groth16/groth16.prove.go.tmpl | 2 +- .../zkpschemes/groth16/groth16.setup.go.tmpl | 8 +++++--- .../zkpschemes/groth16/groth16.verify.go.tmpl | 12 ++++++------ 29 files changed, 99 insertions(+), 85 deletions(-) diff --git a/backend/groth16/bls12-377/commitment.go b/backend/groth16/bls12-377/commitment.go index 72506760a4..c267e8a99b 100644 --- a/backend/groth16/bls12-377/commitment.go +++ b/backend/groth16/bls12-377/commitment.go @@ -23,7 +23,7 @@ import ( "math/big" ) -func solveCommitmentWire(commitmentInfo *constraint.Commitment, commitment *curve.G1Affine, publicCommitted []*big.Int) (fr.Element, error) { - res, err := fr.Hash(commitmentInfo.SerializeCommitment(commitment.Marshal(), publicCommitted, (fr.Bits-1)/8+1), []byte(constraint.CommitmentDst), 1) +func solveCommitmentWire(commitment *curve.G1Affine, publicCommitted []*big.Int) (fr.Element, error) { + res, err := fr.Hash(constraint.SerializeCommitment(commitment.Marshal(), publicCommitted, (fr.Bits-1)/8+1), []byte(constraint.CommitmentDst), 1) return res[0], err } diff --git a/backend/groth16/bls12-377/prove.go b/backend/groth16/bls12-377/prove.go index 9fbb3d06ef..b38ed7f38c 100644 --- a/backend/groth16/bls12-377/prove.go +++ b/backend/groth16/bls12-377/prove.go @@ -86,7 +86,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var res fr.Element - res, err = solveCommitmentWire(&r1cs.CommitmentInfo, &proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) res.BigInt(out[0]) return err })) diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index fd455474d8..fc4b751954 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -75,8 +75,9 @@ type VerifyingKey struct { // e(α, β) e curve.GT // not serialized - CommitmentKey pedersen.VerifyingKey - CommitmentInfo constraint.Commitment // since the verifier doesn't input a constraint system, this needs to be provided here + CommitmentKey pedersen.VerifyingKey + HasCommitment bool // TODO: Make CommitmentKey nullable instead + PublicCommitted []int // indexes of public committed variables } // Setup constructs the SRS @@ -262,7 +263,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - vk.CommitmentInfo = r1cs.CommitmentInfo // unfortunate but necessary + vk.HasCommitment = r1cs.CommitmentInfo.Is() + vk.PublicCommitted = r1cs.CommitmentInfo.PrivateCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bls12-377/verify.go b/backend/groth16/bls12-377/verify.go index dc4be62f06..d1d18caeb7 100644 --- a/backend/groth16/bls12-377/verify.go +++ b/backend/groth16/bls12-377/verify.go @@ -37,7 +37,7 @@ var ( func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { nbPublicVars := len(vk.G1.K) - if vk.CommitmentInfo.Is() { + if vk.HasCommitment { nbPublicVars-- } if len(publicWitness) != nbPublicVars-1 { @@ -62,20 +62,20 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() - if vk.CommitmentInfo.Is() { + if vk.HasCommitment { if err := vk.CommitmentKey.Verify(proof.Commitment, proof.CommitmentPok); err != nil { return err } - publicCommitted := make([]*big.Int, vk.CommitmentInfo.NbPublicCommitted()) + publicCommitted := make([]*big.Int, len(vk.PublicCommitted)) for i := range publicCommitted { var b big.Int - publicWitness[vk.CommitmentInfo.Committed[i]-1].BigInt(&b) + publicWitness[vk.PublicCommitted[i]-1].BigInt(&b) publicCommitted[i] = &b } - if res, err := solveCommitmentWire(&vk.CommitmentInfo, &proof.Commitment, publicCommitted); err == nil { + if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err == nil { publicWitness = append(publicWitness, res) } } @@ -87,7 +87,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } kSum.AddMixed(&vk.G1.K[0]) - if vk.CommitmentInfo.Is() { + if vk.HasCommitment { kSum.AddMixed(&proof.Commitment) } diff --git a/backend/groth16/bls12-381/commitment.go b/backend/groth16/bls12-381/commitment.go index 680f862419..6fcc533b5b 100644 --- a/backend/groth16/bls12-381/commitment.go +++ b/backend/groth16/bls12-381/commitment.go @@ -23,7 +23,7 @@ import ( "math/big" ) -func solveCommitmentWire(commitmentInfo *constraint.Commitment, commitment *curve.G1Affine, publicCommitted []*big.Int) (fr.Element, error) { - res, err := fr.Hash(commitmentInfo.SerializeCommitment(commitment.Marshal(), publicCommitted, (fr.Bits-1)/8+1), []byte(constraint.CommitmentDst), 1) +func solveCommitmentWire(commitment *curve.G1Affine, publicCommitted []*big.Int) (fr.Element, error) { + res, err := fr.Hash(constraint.SerializeCommitment(commitment.Marshal(), publicCommitted, (fr.Bits-1)/8+1), []byte(constraint.CommitmentDst), 1) return res[0], err } diff --git a/backend/groth16/bls12-381/prove.go b/backend/groth16/bls12-381/prove.go index 254489f6f5..163545d8cd 100644 --- a/backend/groth16/bls12-381/prove.go +++ b/backend/groth16/bls12-381/prove.go @@ -86,7 +86,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var res fr.Element - res, err = solveCommitmentWire(&r1cs.CommitmentInfo, &proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) res.BigInt(out[0]) return err })) diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index ecc666ba43..4077b0fca9 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -75,8 +75,9 @@ type VerifyingKey struct { // e(α, β) e curve.GT // not serialized - CommitmentKey pedersen.VerifyingKey - CommitmentInfo constraint.Commitment // since the verifier doesn't input a constraint system, this needs to be provided here + CommitmentKey pedersen.VerifyingKey + HasCommitment bool // TODO: Make CommitmentKey nullable instead + PublicCommitted []int // indexes of public committed variables } // Setup constructs the SRS @@ -262,7 +263,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - vk.CommitmentInfo = r1cs.CommitmentInfo // unfortunate but necessary + vk.HasCommitment = r1cs.CommitmentInfo.Is() + vk.PublicCommitted = r1cs.CommitmentInfo.PrivateCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bls12-381/verify.go b/backend/groth16/bls12-381/verify.go index dd2c057ebb..4bdb023b5a 100644 --- a/backend/groth16/bls12-381/verify.go +++ b/backend/groth16/bls12-381/verify.go @@ -37,7 +37,7 @@ var ( func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { nbPublicVars := len(vk.G1.K) - if vk.CommitmentInfo.Is() { + if vk.HasCommitment { nbPublicVars-- } if len(publicWitness) != nbPublicVars-1 { @@ -62,20 +62,20 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() - if vk.CommitmentInfo.Is() { + if vk.HasCommitment { if err := vk.CommitmentKey.Verify(proof.Commitment, proof.CommitmentPok); err != nil { return err } - publicCommitted := make([]*big.Int, vk.CommitmentInfo.NbPublicCommitted()) + publicCommitted := make([]*big.Int, len(vk.PublicCommitted)) for i := range publicCommitted { var b big.Int - publicWitness[vk.CommitmentInfo.Committed[i]-1].BigInt(&b) + publicWitness[vk.PublicCommitted[i]-1].BigInt(&b) publicCommitted[i] = &b } - if res, err := solveCommitmentWire(&vk.CommitmentInfo, &proof.Commitment, publicCommitted); err == nil { + if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err == nil { publicWitness = append(publicWitness, res) } } @@ -87,7 +87,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } kSum.AddMixed(&vk.G1.K[0]) - if vk.CommitmentInfo.Is() { + if vk.HasCommitment { kSum.AddMixed(&proof.Commitment) } diff --git a/backend/groth16/bls24-315/commitment.go b/backend/groth16/bls24-315/commitment.go index 3cb966f8f0..fc1a3def96 100644 --- a/backend/groth16/bls24-315/commitment.go +++ b/backend/groth16/bls24-315/commitment.go @@ -23,7 +23,7 @@ import ( "math/big" ) -func solveCommitmentWire(commitmentInfo *constraint.Commitment, commitment *curve.G1Affine, publicCommitted []*big.Int) (fr.Element, error) { - res, err := fr.Hash(commitmentInfo.SerializeCommitment(commitment.Marshal(), publicCommitted, (fr.Bits-1)/8+1), []byte(constraint.CommitmentDst), 1) +func solveCommitmentWire(commitment *curve.G1Affine, publicCommitted []*big.Int) (fr.Element, error) { + res, err := fr.Hash(constraint.SerializeCommitment(commitment.Marshal(), publicCommitted, (fr.Bits-1)/8+1), []byte(constraint.CommitmentDst), 1) return res[0], err } diff --git a/backend/groth16/bls24-315/prove.go b/backend/groth16/bls24-315/prove.go index 9f9b876250..4154717864 100644 --- a/backend/groth16/bls24-315/prove.go +++ b/backend/groth16/bls24-315/prove.go @@ -86,7 +86,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var res fr.Element - res, err = solveCommitmentWire(&r1cs.CommitmentInfo, &proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) res.BigInt(out[0]) return err })) diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index 799ae47efb..b3ebb1c5f9 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -75,8 +75,9 @@ type VerifyingKey struct { // e(α, β) e curve.GT // not serialized - CommitmentKey pedersen.VerifyingKey - CommitmentInfo constraint.Commitment // since the verifier doesn't input a constraint system, this needs to be provided here + CommitmentKey pedersen.VerifyingKey + HasCommitment bool // TODO: Make CommitmentKey nullable instead + PublicCommitted []int // indexes of public committed variables } // Setup constructs the SRS @@ -262,7 +263,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - vk.CommitmentInfo = r1cs.CommitmentInfo // unfortunate but necessary + vk.HasCommitment = r1cs.CommitmentInfo.Is() + vk.PublicCommitted = r1cs.CommitmentInfo.PrivateCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bls24-315/verify.go b/backend/groth16/bls24-315/verify.go index b9bd2e2c84..c44e9eab72 100644 --- a/backend/groth16/bls24-315/verify.go +++ b/backend/groth16/bls24-315/verify.go @@ -37,7 +37,7 @@ var ( func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { nbPublicVars := len(vk.G1.K) - if vk.CommitmentInfo.Is() { + if vk.HasCommitment { nbPublicVars-- } if len(publicWitness) != nbPublicVars-1 { @@ -62,20 +62,20 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() - if vk.CommitmentInfo.Is() { + if vk.HasCommitment { if err := vk.CommitmentKey.Verify(proof.Commitment, proof.CommitmentPok); err != nil { return err } - publicCommitted := make([]*big.Int, vk.CommitmentInfo.NbPublicCommitted()) + publicCommitted := make([]*big.Int, len(vk.PublicCommitted)) for i := range publicCommitted { var b big.Int - publicWitness[vk.CommitmentInfo.Committed[i]-1].BigInt(&b) + publicWitness[vk.PublicCommitted[i]-1].BigInt(&b) publicCommitted[i] = &b } - if res, err := solveCommitmentWire(&vk.CommitmentInfo, &proof.Commitment, publicCommitted); err == nil { + if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err == nil { publicWitness = append(publicWitness, res) } } @@ -87,7 +87,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } kSum.AddMixed(&vk.G1.K[0]) - if vk.CommitmentInfo.Is() { + if vk.HasCommitment { kSum.AddMixed(&proof.Commitment) } diff --git a/backend/groth16/bls24-317/commitment.go b/backend/groth16/bls24-317/commitment.go index 00b3713dd6..05d71ba172 100644 --- a/backend/groth16/bls24-317/commitment.go +++ b/backend/groth16/bls24-317/commitment.go @@ -23,7 +23,7 @@ import ( "math/big" ) -func solveCommitmentWire(commitmentInfo *constraint.Commitment, commitment *curve.G1Affine, publicCommitted []*big.Int) (fr.Element, error) { - res, err := fr.Hash(commitmentInfo.SerializeCommitment(commitment.Marshal(), publicCommitted, (fr.Bits-1)/8+1), []byte(constraint.CommitmentDst), 1) +func solveCommitmentWire(commitment *curve.G1Affine, publicCommitted []*big.Int) (fr.Element, error) { + res, err := fr.Hash(constraint.SerializeCommitment(commitment.Marshal(), publicCommitted, (fr.Bits-1)/8+1), []byte(constraint.CommitmentDst), 1) return res[0], err } diff --git a/backend/groth16/bls24-317/prove.go b/backend/groth16/bls24-317/prove.go index 68a6a80896..b218b50a58 100644 --- a/backend/groth16/bls24-317/prove.go +++ b/backend/groth16/bls24-317/prove.go @@ -86,7 +86,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var res fr.Element - res, err = solveCommitmentWire(&r1cs.CommitmentInfo, &proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) res.BigInt(out[0]) return err })) diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index b6df9de83e..8f31584f30 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -75,8 +75,9 @@ type VerifyingKey struct { // e(α, β) e curve.GT // not serialized - CommitmentKey pedersen.VerifyingKey - CommitmentInfo constraint.Commitment // since the verifier doesn't input a constraint system, this needs to be provided here + CommitmentKey pedersen.VerifyingKey + HasCommitment bool // TODO: Make CommitmentKey nullable instead + PublicCommitted []int // indexes of public committed variables } // Setup constructs the SRS @@ -262,7 +263,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - vk.CommitmentInfo = r1cs.CommitmentInfo // unfortunate but necessary + vk.HasCommitment = r1cs.CommitmentInfo.Is() + vk.PublicCommitted = r1cs.CommitmentInfo.PrivateCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bls24-317/verify.go b/backend/groth16/bls24-317/verify.go index 5d73519cc6..09affc8070 100644 --- a/backend/groth16/bls24-317/verify.go +++ b/backend/groth16/bls24-317/verify.go @@ -37,7 +37,7 @@ var ( func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { nbPublicVars := len(vk.G1.K) - if vk.CommitmentInfo.Is() { + if vk.HasCommitment { nbPublicVars-- } if len(publicWitness) != nbPublicVars-1 { @@ -62,20 +62,20 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() - if vk.CommitmentInfo.Is() { + if vk.HasCommitment { if err := vk.CommitmentKey.Verify(proof.Commitment, proof.CommitmentPok); err != nil { return err } - publicCommitted := make([]*big.Int, vk.CommitmentInfo.NbPublicCommitted()) + publicCommitted := make([]*big.Int, len(vk.PublicCommitted)) for i := range publicCommitted { var b big.Int - publicWitness[vk.CommitmentInfo.Committed[i]-1].BigInt(&b) + publicWitness[vk.PublicCommitted[i]-1].BigInt(&b) publicCommitted[i] = &b } - if res, err := solveCommitmentWire(&vk.CommitmentInfo, &proof.Commitment, publicCommitted); err == nil { + if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err == nil { publicWitness = append(publicWitness, res) } } @@ -87,7 +87,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } kSum.AddMixed(&vk.G1.K[0]) - if vk.CommitmentInfo.Is() { + if vk.HasCommitment { kSum.AddMixed(&proof.Commitment) } diff --git a/backend/groth16/bw6-633/commitment.go b/backend/groth16/bw6-633/commitment.go index d1243f342c..f8af92e4fc 100644 --- a/backend/groth16/bw6-633/commitment.go +++ b/backend/groth16/bw6-633/commitment.go @@ -23,7 +23,7 @@ import ( "math/big" ) -func solveCommitmentWire(commitmentInfo *constraint.Commitment, commitment *curve.G1Affine, publicCommitted []*big.Int) (fr.Element, error) { - res, err := fr.Hash(commitmentInfo.SerializeCommitment(commitment.Marshal(), publicCommitted, (fr.Bits-1)/8+1), []byte(constraint.CommitmentDst), 1) +func solveCommitmentWire(commitment *curve.G1Affine, publicCommitted []*big.Int) (fr.Element, error) { + res, err := fr.Hash(constraint.SerializeCommitment(commitment.Marshal(), publicCommitted, (fr.Bits-1)/8+1), []byte(constraint.CommitmentDst), 1) return res[0], err } diff --git a/backend/groth16/bw6-633/prove.go b/backend/groth16/bw6-633/prove.go index c05c73c5b4..a85bcddf76 100644 --- a/backend/groth16/bw6-633/prove.go +++ b/backend/groth16/bw6-633/prove.go @@ -86,7 +86,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var res fr.Element - res, err = solveCommitmentWire(&r1cs.CommitmentInfo, &proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) res.BigInt(out[0]) return err })) diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index eb27cb926d..5a3de2d680 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -75,8 +75,9 @@ type VerifyingKey struct { // e(α, β) e curve.GT // not serialized - CommitmentKey pedersen.VerifyingKey - CommitmentInfo constraint.Commitment // since the verifier doesn't input a constraint system, this needs to be provided here + CommitmentKey pedersen.VerifyingKey + HasCommitment bool // TODO: Make CommitmentKey nullable instead + PublicCommitted []int // indexes of public committed variables } // Setup constructs the SRS @@ -262,7 +263,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - vk.CommitmentInfo = r1cs.CommitmentInfo // unfortunate but necessary + vk.HasCommitment = r1cs.CommitmentInfo.Is() + vk.PublicCommitted = r1cs.CommitmentInfo.PrivateCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bw6-633/verify.go b/backend/groth16/bw6-633/verify.go index 7b3dbf3807..7bed98172f 100644 --- a/backend/groth16/bw6-633/verify.go +++ b/backend/groth16/bw6-633/verify.go @@ -37,7 +37,7 @@ var ( func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { nbPublicVars := len(vk.G1.K) - if vk.CommitmentInfo.Is() { + if vk.HasCommitment { nbPublicVars-- } if len(publicWitness) != nbPublicVars-1 { @@ -62,20 +62,20 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() - if vk.CommitmentInfo.Is() { + if vk.HasCommitment { if err := vk.CommitmentKey.Verify(proof.Commitment, proof.CommitmentPok); err != nil { return err } - publicCommitted := make([]*big.Int, vk.CommitmentInfo.NbPublicCommitted()) + publicCommitted := make([]*big.Int, len(vk.PublicCommitted)) for i := range publicCommitted { var b big.Int - publicWitness[vk.CommitmentInfo.Committed[i]-1].BigInt(&b) + publicWitness[vk.PublicCommitted[i]-1].BigInt(&b) publicCommitted[i] = &b } - if res, err := solveCommitmentWire(&vk.CommitmentInfo, &proof.Commitment, publicCommitted); err == nil { + if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err == nil { publicWitness = append(publicWitness, res) } } @@ -87,7 +87,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } kSum.AddMixed(&vk.G1.K[0]) - if vk.CommitmentInfo.Is() { + if vk.HasCommitment { kSum.AddMixed(&proof.Commitment) } diff --git a/backend/groth16/bw6-761/commitment.go b/backend/groth16/bw6-761/commitment.go index c332669a12..5c357c24ad 100644 --- a/backend/groth16/bw6-761/commitment.go +++ b/backend/groth16/bw6-761/commitment.go @@ -23,7 +23,7 @@ import ( "math/big" ) -func solveCommitmentWire(commitmentInfo *constraint.Commitment, commitment *curve.G1Affine, publicCommitted []*big.Int) (fr.Element, error) { - res, err := fr.Hash(commitmentInfo.SerializeCommitment(commitment.Marshal(), publicCommitted, (fr.Bits-1)/8+1), []byte(constraint.CommitmentDst), 1) +func solveCommitmentWire(commitment *curve.G1Affine, publicCommitted []*big.Int) (fr.Element, error) { + res, err := fr.Hash(constraint.SerializeCommitment(commitment.Marshal(), publicCommitted, (fr.Bits-1)/8+1), []byte(constraint.CommitmentDst), 1) return res[0], err } diff --git a/backend/groth16/bw6-761/prove.go b/backend/groth16/bw6-761/prove.go index 749f4df497..6264dbaf8d 100644 --- a/backend/groth16/bw6-761/prove.go +++ b/backend/groth16/bw6-761/prove.go @@ -86,7 +86,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var res fr.Element - res, err = solveCommitmentWire(&r1cs.CommitmentInfo, &proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) res.BigInt(out[0]) return err })) diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index 614d06c1ad..522b5896de 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -75,8 +75,9 @@ type VerifyingKey struct { // e(α, β) e curve.GT // not serialized - CommitmentKey pedersen.VerifyingKey - CommitmentInfo constraint.Commitment // since the verifier doesn't input a constraint system, this needs to be provided here + CommitmentKey pedersen.VerifyingKey + HasCommitment bool // TODO: Make CommitmentKey nullable instead + PublicCommitted []int // indexes of public committed variables } // Setup constructs the SRS @@ -262,7 +263,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - vk.CommitmentInfo = r1cs.CommitmentInfo // unfortunate but necessary + vk.HasCommitment = r1cs.CommitmentInfo.Is() + vk.PublicCommitted = r1cs.CommitmentInfo.PrivateCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bw6-761/verify.go b/backend/groth16/bw6-761/verify.go index 5768e38c5a..b30724bef0 100644 --- a/backend/groth16/bw6-761/verify.go +++ b/backend/groth16/bw6-761/verify.go @@ -37,7 +37,7 @@ var ( func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { nbPublicVars := len(vk.G1.K) - if vk.CommitmentInfo.Is() { + if vk.HasCommitment { nbPublicVars-- } if len(publicWitness) != nbPublicVars-1 { @@ -62,20 +62,20 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() - if vk.CommitmentInfo.Is() { + if vk.HasCommitment { if err := vk.CommitmentKey.Verify(proof.Commitment, proof.CommitmentPok); err != nil { return err } - publicCommitted := make([]*big.Int, vk.CommitmentInfo.NbPublicCommitted()) + publicCommitted := make([]*big.Int, len(vk.PublicCommitted)) for i := range publicCommitted { var b big.Int - publicWitness[vk.CommitmentInfo.Committed[i]-1].BigInt(&b) + publicWitness[vk.PublicCommitted[i]-1].BigInt(&b) publicCommitted[i] = &b } - if res, err := solveCommitmentWire(&vk.CommitmentInfo, &proof.Commitment, publicCommitted); err == nil { + if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err == nil { publicWitness = append(publicWitness, res) } } @@ -87,7 +87,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } kSum.AddMixed(&vk.G1.K[0]) - if vk.CommitmentInfo.Is() { + if vk.HasCommitment { kSum.AddMixed(&proof.Commitment) } diff --git a/backend/plonk/bn254/setup.go b/backend/plonk/bn254/setup.go index b98a99b06f..ba3f0333ff 100644 --- a/backend/plonk/bn254/setup.go +++ b/backend/plonk/bn254/setup.go @@ -264,7 +264,7 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { } -// commitTrace commits to every polynomial in the trace, and put +// commitTrace commits to every polynomials in the trace, and put // the commitments int the verifying key. func commitTrace(trace *Trace, pk *ProvingKey) error { diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.commitment.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.commitment.go.tmpl index da74e65321..aec745a7d6 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.commitment.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.commitment.go.tmpl @@ -5,7 +5,7 @@ import ( "math/big" ) -func solveCommitmentWire(commitmentInfo *constraint.Commitment, commitment *curve.G1Affine, publicCommitted []*big.Int) (fr.Element, error) { - res, err := fr.Hash(commitmentInfo.SerializeCommitment(commitment.Marshal(), publicCommitted, (fr.Bits-1)/8+1), []byte(constraint.CommitmentDst), 1) +func solveCommitmentWire(commitment *curve.G1Affine, publicCommitted []*big.Int) (fr.Element, error) { + res, err := fr.Hash(constraint.SerializeCommitment(commitment.Marshal(), publicCommitted, (fr.Bits-1)/8+1), []byte(constraint.CommitmentDst), 1) return res[0], err } \ No newline at end of file diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl index 3825d4b5fd..8a473ccd97 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl @@ -69,7 +69,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var res fr.Element - res, err = solveCommitmentWire(&r1cs.CommitmentInfo, &proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) res.BigInt(out[0]) return err } )) diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl index ab23e951e3..80790449c7 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl @@ -57,8 +57,9 @@ type VerifyingKey struct { // e(α, β) e curve.GT // not serialized - CommitmentKey pedersen.VerifyingKey - CommitmentInfo constraint.Commitment // since the verifier doesn't input a constraint system, this needs to be provided here + CommitmentKey pedersen.VerifyingKey + HasCommitment bool // TODO: Make CommitmentKey nullable instead + PublicCommitted []int // indexes of public committed variables } // Setup constructs the SRS @@ -244,7 +245,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - vk.CommitmentInfo = r1cs.CommitmentInfo // unfortunate but necessary + vk.HasCommitment = r1cs.CommitmentInfo.Is() + vk.PublicCommitted = r1cs.CommitmentInfo.PrivateCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl index 93767fedfe..307b82f0bf 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl @@ -22,7 +22,7 @@ var ( func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { nbPublicVars := len(vk.G1.K) - if vk.CommitmentInfo.Is() { + if vk.HasCommitment { nbPublicVars-- } if len(publicWitness) != nbPublicVars-1 { @@ -47,20 +47,20 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() - if vk.CommitmentInfo.Is() { + if vk.HasCommitment { if err := vk.CommitmentKey.Verify(proof.Commitment, proof.CommitmentPok); err != nil { return err } - publicCommitted := make([]*big.Int, vk.CommitmentInfo.NbPublicCommitted()) + publicCommitted := make([]*big.Int, len(vk.PublicCommitted)) for i := range publicCommitted { var b big.Int - publicWitness[vk.CommitmentInfo.Committed[i]-1].BigInt(&b) + publicWitness[vk.PublicCommitted[i]-1].BigInt(&b) publicCommitted[i] = &b } - if res, err := solveCommitmentWire(&vk.CommitmentInfo, &proof.Commitment, publicCommitted); err == nil { + if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err == nil { publicWitness = append(publicWitness, res) } } @@ -72,7 +72,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } kSum.AddMixed(&vk.G1.K[0]) - if vk.CommitmentInfo.Is() { + if vk.HasCommitment { kSum.AddMixed(&proof.Commitment) } From 9847f0b0a00fea6015e90df59263207ab44a2c2a Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 26 Apr 2023 12:38:24 -0500 Subject: [PATCH 300/464] fix: private -> public --- backend/groth16/bls12-377/setup.go | 2 +- backend/groth16/bls12-381/setup.go | 2 +- backend/groth16/bls24-315/setup.go | 2 +- backend/groth16/bls24-317/setup.go | 2 +- backend/groth16/bn254/setup.go | 2 +- backend/groth16/bw6-633/setup.go | 2 +- backend/groth16/bw6-761/setup.go | 2 +- .../backend/template/zkpschemes/groth16/groth16.setup.go.tmpl | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index fc4b751954..63ef723cde 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -264,7 +264,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } vk.HasCommitment = r1cs.CommitmentInfo.Is() - vk.PublicCommitted = r1cs.CommitmentInfo.PrivateCommitted() + vk.PublicCommitted = r1cs.CommitmentInfo.PublicCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index 4077b0fca9..a0b185e2f0 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -264,7 +264,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } vk.HasCommitment = r1cs.CommitmentInfo.Is() - vk.PublicCommitted = r1cs.CommitmentInfo.PrivateCommitted() + vk.PublicCommitted = r1cs.CommitmentInfo.PublicCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index b3ebb1c5f9..c06ccdc4f9 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -264,7 +264,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } vk.HasCommitment = r1cs.CommitmentInfo.Is() - vk.PublicCommitted = r1cs.CommitmentInfo.PrivateCommitted() + vk.PublicCommitted = r1cs.CommitmentInfo.PublicCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index 8f31584f30..3566117413 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -264,7 +264,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } vk.HasCommitment = r1cs.CommitmentInfo.Is() - vk.PublicCommitted = r1cs.CommitmentInfo.PrivateCommitted() + vk.PublicCommitted = r1cs.CommitmentInfo.PublicCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index f66c9b0ef2..a91f1162e0 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -264,7 +264,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } vk.HasCommitment = r1cs.CommitmentInfo.Is() - vk.PublicCommitted = r1cs.CommitmentInfo.PrivateCommitted() + vk.PublicCommitted = r1cs.CommitmentInfo.PublicCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index 5a3de2d680..355da54859 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -264,7 +264,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } vk.HasCommitment = r1cs.CommitmentInfo.Is() - vk.PublicCommitted = r1cs.CommitmentInfo.PrivateCommitted() + vk.PublicCommitted = r1cs.CommitmentInfo.PublicCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index 522b5896de..606b57c31d 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -264,7 +264,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } vk.HasCommitment = r1cs.CommitmentInfo.Is() - vk.PublicCommitted = r1cs.CommitmentInfo.PrivateCommitted() + vk.PublicCommitted = r1cs.CommitmentInfo.PublicCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl index 80790449c7..81164025f1 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl @@ -246,7 +246,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } vk.HasCommitment = r1cs.CommitmentInfo.Is() - vk.PublicCommitted = r1cs.CommitmentInfo.PrivateCommitted() + vk.PublicCommitted = r1cs.CommitmentInfo.PublicCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars From 86e8c6afbe87f0d0585d7d514896a46531ccec42 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 26 Apr 2023 12:58:31 -0500 Subject: [PATCH 301/464] refactor: get rid of CommittedAndCommitment --- backend/groth16/bls12-377/prove.go | 2 +- backend/groth16/bls12-381/prove.go | 2 +- backend/groth16/bls24-315/prove.go | 2 +- backend/groth16/bls24-317/prove.go | 2 +- backend/groth16/bn254/prove.go | 2 +- backend/groth16/bw6-633/prove.go | 2 +- backend/groth16/bw6-761/prove.go | 2 +- constraint/commitment.go | 21 +++++++++++-------- frontend/cs/r1cs/api.go | 2 -- .../zkpschemes/groth16/groth16.prove.go.tmpl | 2 +- 10 files changed, 20 insertions(+), 19 deletions(-) diff --git a/backend/groth16/bls12-377/prove.go b/backend/groth16/bls12-377/prove.go index b38ed7f38c..3657d798d3 100644 --- a/backend/groth16/bls12-377/prove.go +++ b/backend/groth16/bls12-377/prove.go @@ -203,7 +203,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed; - _wireValues := filter(wireValues, r1cs.CommitmentInfo.PrivateToPublic()) + _wireValues := filter(wireValues, r1cs.CommitmentInfo.PrivateToPublicGroth16()) if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err diff --git a/backend/groth16/bls12-381/prove.go b/backend/groth16/bls12-381/prove.go index 163545d8cd..1ba992e545 100644 --- a/backend/groth16/bls12-381/prove.go +++ b/backend/groth16/bls12-381/prove.go @@ -203,7 +203,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed; - _wireValues := filter(wireValues, r1cs.CommitmentInfo.PrivateToPublic()) + _wireValues := filter(wireValues, r1cs.CommitmentInfo.PrivateToPublicGroth16()) if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err diff --git a/backend/groth16/bls24-315/prove.go b/backend/groth16/bls24-315/prove.go index 4154717864..9a3bf927e8 100644 --- a/backend/groth16/bls24-315/prove.go +++ b/backend/groth16/bls24-315/prove.go @@ -203,7 +203,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed; - _wireValues := filter(wireValues, r1cs.CommitmentInfo.PrivateToPublic()) + _wireValues := filter(wireValues, r1cs.CommitmentInfo.PrivateToPublicGroth16()) if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err diff --git a/backend/groth16/bls24-317/prove.go b/backend/groth16/bls24-317/prove.go index b218b50a58..6e5b7f44d7 100644 --- a/backend/groth16/bls24-317/prove.go +++ b/backend/groth16/bls24-317/prove.go @@ -203,7 +203,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed; - _wireValues := filter(wireValues, r1cs.CommitmentInfo.PrivateToPublic()) + _wireValues := filter(wireValues, r1cs.CommitmentInfo.PrivateToPublicGroth16()) if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index ce6da1e350..77f9a200a8 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -203,7 +203,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed; - _wireValues := filter(wireValues, r1cs.CommitmentInfo.PrivateToPublic()) + _wireValues := filter(wireValues, r1cs.CommitmentInfo.PrivateToPublicGroth16()) if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err diff --git a/backend/groth16/bw6-633/prove.go b/backend/groth16/bw6-633/prove.go index a85bcddf76..0d97c60bb6 100644 --- a/backend/groth16/bw6-633/prove.go +++ b/backend/groth16/bw6-633/prove.go @@ -203,7 +203,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed; - _wireValues := filter(wireValues, r1cs.CommitmentInfo.PrivateToPublic()) + _wireValues := filter(wireValues, r1cs.CommitmentInfo.PrivateToPublicGroth16()) if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err diff --git a/backend/groth16/bw6-761/prove.go b/backend/groth16/bw6-761/prove.go index 6264dbaf8d..c81880f497 100644 --- a/backend/groth16/bw6-761/prove.go +++ b/backend/groth16/bw6-761/prove.go @@ -203,7 +203,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed; - _wireValues := filter(wireValues, r1cs.CommitmentInfo.PrivateToPublic()) + _wireValues := filter(wireValues, r1cs.CommitmentInfo.PrivateToPublicGroth16()) if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err diff --git a/constraint/commitment.go b/constraint/commitment.go index 1b5b51c864..b7615a1713 100644 --- a/constraint/commitment.go +++ b/constraint/commitment.go @@ -9,11 +9,10 @@ import ( const CommitmentDst = "bsb22-commitment" type Commitment struct { - Committed []int // sorted list of id's of committed variables in groth16. in plonk, list of indexes of constraints defining committed values - NbPrivateCommitted int - HintID solver.HintID // TODO @gbotrel we probably don't need that here - CommitmentIndex int // in groth16, CommitmentIndex is the wire index. in plonk, it's the constraint defining it - CommittedAndCommitment []int // sorted list of id's of committed variables AND the commitment itself + Committed []int // sorted list of id's of committed variables in groth16. in plonk, list of indexes of constraints defining committed values + NbPrivateCommitted int + HintID solver.HintID // TODO @gbotrel we probably don't need that here + CommitmentIndex int // in groth16, CommitmentIndex is the wire index. in plonk, it's the constraint defining it } func (i *Commitment) NbPublicCommitted() int { @@ -30,7 +29,7 @@ func (i *Commitment) Is() bool { // NewCommitment initialize a Commitment object // - committed are the sorted wireID to commit to (without duplicate) -// - nbPublicCommited is the number of public inputs among the commited wireIDs +// - nbPublicCommitted is the number of public inputs among the committed wireIDs func NewCommitment(committed []int, nbPublicCommitted int) Commitment { return Commitment{ Committed: committed, @@ -52,9 +51,13 @@ func SerializeCommitment(privateCommitment []byte, publicCommitted []*big.Int, f return res } -// PrivateToPublic returns indexes of variables which are private to the constraint system, but public to Groth16. That is, private committed variables and the commitment itself -func (i *Commitment) PrivateToPublic() []int { - return i.CommittedAndCommitment[i.NbPublicCommitted():] +// PrivateToPublicGroth16 returns indexes of variables which are private to the constraint system, but public to Groth16. That is, private committed variables and the commitment itself +// TODO Perhaps move it elsewhere since it's specific to groth16 +func (i *Commitment) PrivateToPublicGroth16() []int { + res := make([]int, i.NbPrivateCommitted+1) + copy(res, i.PrivateCommitted()) + res[i.NbPrivateCommitted] = i.CommitmentIndex + return res } func (i *Commitment) PrivateCommitted() []int { diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index 76e4db5de5..c0513c01ed 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -741,8 +741,6 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error commitment.CommitmentIndex = (cVar.(expr.LinearExpression))[0].WireID() - // TODO @Tabaie Get rid of this field - commitment.CommittedAndCommitment = append(commitment.Committed, commitment.CommitmentIndex) if commitment.CommitmentIndex <= commitment.Committed[len(commitment.Committed)-1] { return nil, fmt.Errorf("commitment variable index smaller than some committed variable indices") } diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl index 8a473ccd97..2e7b63e1b9 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl @@ -186,7 +186,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed; - _wireValues := filter(wireValues, r1cs.CommitmentInfo.PrivateToPublic()) + _wireValues := filter(wireValues, r1cs.CommitmentInfo.PrivateToPublicGroth16()) if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err From 016eb0f19ede25694ef6d98172831677b8a1a61e Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 26 Apr 2023 13:15:31 -0500 Subject: [PATCH 302/464] fix: in case no commitment --- constraint/commitment.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/constraint/commitment.go b/constraint/commitment.go index b7615a1713..475c36866d 100644 --- a/constraint/commitment.go +++ b/constraint/commitment.go @@ -54,6 +54,9 @@ func SerializeCommitment(privateCommitment []byte, publicCommitted []*big.Int, f // PrivateToPublicGroth16 returns indexes of variables which are private to the constraint system, but public to Groth16. That is, private committed variables and the commitment itself // TODO Perhaps move it elsewhere since it's specific to groth16 func (i *Commitment) PrivateToPublicGroth16() []int { + if !i.Is() { + return nil + } res := make([]int, i.NbPrivateCommitted+1) copy(res, i.PrivateCommitted()) res[i.NbPrivateCommitted] = i.CommitmentIndex From a1686686414e844c7f70901c26703390155ae135 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 26 Apr 2023 14:24:25 -0500 Subject: [PATCH 303/464] feat: multi-commits in constraint system data structures --- backend/plonk/bw6-633/prove.go | 14 +++++++------- constraint/commitment.go | 4 ---- constraint/core.go | 13 ++++++------- constraint/system.go | 1 + frontend/cs/scs/api.go | 5 +++++ 5 files changed, 19 insertions(+), 18 deletions(-) diff --git a/backend/plonk/bw6-633/prove.go b/backend/plonk/bw6-633/prove.go index 790cc6b6da..dbb1b89f53 100644 --- a/backend/plonk/bw6-633/prove.go +++ b/backend/plonk/bw6-633/prove.go @@ -87,18 +87,18 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wpi2iop *iop.Polynomial // canonical commitmentVal fr.Element // TODO @Tabaie get rid of this ) - if spr.CommitmentInfo.Is() { - opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo.HintID, func(_ *big.Int, ins, outs []*big.Int) error { + if spr.HasCommitment() { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[0].HintID, func(_ *big.Int, ins, outs []*big.Int) error { pi2 := make([]fr.Element, pk.Domain[0].Cardinality) offset := spr.GetNbPublicVariables() for i := range ins { - pi2[offset+spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) + pi2[offset+spr.CommitmentInfo[0].Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + if _, err = pi2[offset+spr.CommitmentInfo[0].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding @@ -133,7 +133,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // TODO @gbotrel deal with that conversion lazily var lcpi2iop *iop.Polynomial - if spr.CommitmentInfo.Is() { + if spr.HasCommitment() { lcpi2iop = wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form } else { coeffs := make([]fr.Element, pk.Domain[1].Cardinality) @@ -188,8 +188,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) - if spr.CommitmentInfo.Is() { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal + if spr.HasCommitment() { + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[0].CommitmentIndex] = commitmentVal } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) diff --git a/constraint/commitment.go b/constraint/commitment.go index 475c36866d..f0e6e56496 100644 --- a/constraint/commitment.go +++ b/constraint/commitment.go @@ -23,10 +23,6 @@ func (i *Commitment) NbCommitted() int { return len(i.Committed) } -func (i *Commitment) Is() bool { - return len(i.Committed) != 0 -} - // NewCommitment initialize a Commitment object // - committed are the sorted wireID to commit to (without duplicate) // - nbPublicCommitted is the number of public inputs among the committed wireIDs diff --git a/constraint/core.go b/constraint/core.go index 6efb8d911f..dedcca39d5 100644 --- a/constraint/core.go +++ b/constraint/core.go @@ -91,7 +91,7 @@ type System struct { lbWireLevel []int `cbor:"-"` // at which level we solve a wire. init at -1. lbOutputs []uint32 `cbor:"-"` // wire outputs for current constraint. - CommitmentInfo Commitment + CommitmentInfo []Commitment genericHint BlueprintID } @@ -249,12 +249,7 @@ func (system *System) AddSolverHint(f solver.Hint, input []LinearExpression, nbO } func (system *System) AddCommitment(c Commitment) error { - if system.CommitmentInfo.Is() { - return fmt.Errorf("currently only one commitment per circuit is supported") - } - - system.CommitmentInfo = c - + system.CommitmentInfo = append(system.CommitmentInfo, c) return nil } @@ -373,3 +368,7 @@ func (cs *System) GetR1CIterator() R1CIterator { func (cs *System) GetSparseR1CIterator() SparseR1CIterator { return SparseR1CIterator{cs: cs} } + +func (cs *System) HasCommitment() bool { + return len(cs.CommitmentInfo) != 0 +} diff --git a/constraint/system.go b/constraint/system.go index 964838485d..60da891b22 100644 --- a/constraint/system.go +++ b/constraint/system.go @@ -48,6 +48,7 @@ type ConstraintSystem interface { AddSolverHint(f solver.Hint, input []LinearExpression, nbOutput int) (internalVariables []int, err error) AddCommitment(c Commitment) error + HasCommitment() bool // TODO: Erase once multi-commits are implemented in Groth16 AddLog(l LogEntry) diff --git a/frontend/cs/scs/api.go b/frontend/cs/scs/api.go index c542a2752b..89e280ad42 100644 --- a/frontend/cs/scs/api.go +++ b/frontend/cs/scs/api.go @@ -17,6 +17,7 @@ limitations under the License. package scs import ( + "errors" "fmt" "path/filepath" "reflect" @@ -571,6 +572,10 @@ func (builder *builder) Compiler() frontend.Compiler { func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error) { + if builder.cs.HasCommitment() { + return nil, errors.New("multi-commits not available for groth16 - yet") + } + v = filterConstants(v) // TODO: @Tabaie Settle on a way to represent even constants; conventional hash? committed := make([]int, len(v)) From a4f416e55d35f5416902059d9a517062d7e51f8e Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 26 Apr 2023 14:29:26 -0500 Subject: [PATCH 304/464] refactor: commitmentinfo array in plonk prover --- backend/plonk/bls12-377/prove.go | 14 +++++++------- backend/plonk/bls12-381/prove.go | 14 +++++++------- backend/plonk/bls24-315/prove.go | 14 +++++++------- backend/plonk/bls24-317/prove.go | 14 +++++++------- backend/plonk/bn254/prove.go | 14 +++++++------- backend/plonk/bw6-633/prove.go | 6 +++--- backend/plonk/bw6-761/prove.go | 14 +++++++------- constraint/commitment.go | 3 --- .../template/zkpschemes/plonk/plonk.prove.go.tmpl | 14 +++++++------- 9 files changed, 52 insertions(+), 55 deletions(-) diff --git a/backend/plonk/bls12-377/prove.go b/backend/plonk/bls12-377/prove.go index dcc8bec681..14711003cf 100644 --- a/backend/plonk/bls12-377/prove.go +++ b/backend/plonk/bls12-377/prove.go @@ -87,18 +87,18 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wpi2iop *iop.Polynomial // canonical commitmentVal fr.Element // TODO @Tabaie get rid of this ) - if spr.CommitmentInfo.Is() { - opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo.HintID, func(_ *big.Int, ins, outs []*big.Int) error { + if len(spr.CommitmentInfo) != 0 { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[0].HintID, func(_ *big.Int, ins, outs []*big.Int) error { pi2 := make([]fr.Element, pk.Domain[0].Cardinality) offset := spr.GetNbPublicVariables() for i := range ins { - pi2[offset+spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) + pi2[offset+spr.CommitmentInfo[0].Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + if _, err = pi2[offset+spr.CommitmentInfo[0].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding @@ -133,7 +133,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // TODO @gbotrel deal with that conversion lazily var lcpi2iop *iop.Polynomial - if spr.CommitmentInfo.Is() { + if len(spr.CommitmentInfo) != 0 { lcpi2iop = wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form } else { coeffs := make([]fr.Element, pk.Domain[1].Cardinality) @@ -188,8 +188,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) - if spr.CommitmentInfo.Is() { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal + if len(spr.CommitmentInfo) != 0 { + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[0].CommitmentIndex] = commitmentVal } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) diff --git a/backend/plonk/bls12-381/prove.go b/backend/plonk/bls12-381/prove.go index e843401352..cd41e8073b 100644 --- a/backend/plonk/bls12-381/prove.go +++ b/backend/plonk/bls12-381/prove.go @@ -87,18 +87,18 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wpi2iop *iop.Polynomial // canonical commitmentVal fr.Element // TODO @Tabaie get rid of this ) - if spr.CommitmentInfo.Is() { - opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo.HintID, func(_ *big.Int, ins, outs []*big.Int) error { + if len(spr.CommitmentInfo) != 0 { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[0].HintID, func(_ *big.Int, ins, outs []*big.Int) error { pi2 := make([]fr.Element, pk.Domain[0].Cardinality) offset := spr.GetNbPublicVariables() for i := range ins { - pi2[offset+spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) + pi2[offset+spr.CommitmentInfo[0].Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + if _, err = pi2[offset+spr.CommitmentInfo[0].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding @@ -133,7 +133,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // TODO @gbotrel deal with that conversion lazily var lcpi2iop *iop.Polynomial - if spr.CommitmentInfo.Is() { + if len(spr.CommitmentInfo) != 0 { lcpi2iop = wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form } else { coeffs := make([]fr.Element, pk.Domain[1].Cardinality) @@ -188,8 +188,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) - if spr.CommitmentInfo.Is() { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal + if len(spr.CommitmentInfo) != 0 { + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[0].CommitmentIndex] = commitmentVal } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) diff --git a/backend/plonk/bls24-315/prove.go b/backend/plonk/bls24-315/prove.go index 4b5fd77a78..406033c82a 100644 --- a/backend/plonk/bls24-315/prove.go +++ b/backend/plonk/bls24-315/prove.go @@ -87,18 +87,18 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wpi2iop *iop.Polynomial // canonical commitmentVal fr.Element // TODO @Tabaie get rid of this ) - if spr.CommitmentInfo.Is() { - opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo.HintID, func(_ *big.Int, ins, outs []*big.Int) error { + if len(spr.CommitmentInfo) != 0 { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[0].HintID, func(_ *big.Int, ins, outs []*big.Int) error { pi2 := make([]fr.Element, pk.Domain[0].Cardinality) offset := spr.GetNbPublicVariables() for i := range ins { - pi2[offset+spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) + pi2[offset+spr.CommitmentInfo[0].Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + if _, err = pi2[offset+spr.CommitmentInfo[0].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding @@ -133,7 +133,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // TODO @gbotrel deal with that conversion lazily var lcpi2iop *iop.Polynomial - if spr.CommitmentInfo.Is() { + if len(spr.CommitmentInfo) != 0 { lcpi2iop = wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form } else { coeffs := make([]fr.Element, pk.Domain[1].Cardinality) @@ -188,8 +188,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) - if spr.CommitmentInfo.Is() { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal + if len(spr.CommitmentInfo) != 0 { + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[0].CommitmentIndex] = commitmentVal } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) diff --git a/backend/plonk/bls24-317/prove.go b/backend/plonk/bls24-317/prove.go index 5ba2b1d2c2..85f0e7fb31 100644 --- a/backend/plonk/bls24-317/prove.go +++ b/backend/plonk/bls24-317/prove.go @@ -87,18 +87,18 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wpi2iop *iop.Polynomial // canonical commitmentVal fr.Element // TODO @Tabaie get rid of this ) - if spr.CommitmentInfo.Is() { - opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo.HintID, func(_ *big.Int, ins, outs []*big.Int) error { + if len(spr.CommitmentInfo) != 0 { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[0].HintID, func(_ *big.Int, ins, outs []*big.Int) error { pi2 := make([]fr.Element, pk.Domain[0].Cardinality) offset := spr.GetNbPublicVariables() for i := range ins { - pi2[offset+spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) + pi2[offset+spr.CommitmentInfo[0].Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + if _, err = pi2[offset+spr.CommitmentInfo[0].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding @@ -133,7 +133,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // TODO @gbotrel deal with that conversion lazily var lcpi2iop *iop.Polynomial - if spr.CommitmentInfo.Is() { + if len(spr.CommitmentInfo) != 0 { lcpi2iop = wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form } else { coeffs := make([]fr.Element, pk.Domain[1].Cardinality) @@ -188,8 +188,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) - if spr.CommitmentInfo.Is() { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal + if len(spr.CommitmentInfo) != 0 { + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[0].CommitmentIndex] = commitmentVal } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index 92f3af28df..f14ee25592 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -87,18 +87,18 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wpi2iop *iop.Polynomial // canonical commitmentVal fr.Element // TODO @Tabaie get rid of this ) - if spr.CommitmentInfo.Is() { - opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo.HintID, func(_ *big.Int, ins, outs []*big.Int) error { + if len(spr.CommitmentInfo) != 0 { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[0].HintID, func(_ *big.Int, ins, outs []*big.Int) error { pi2 := make([]fr.Element, pk.Domain[0].Cardinality) offset := spr.GetNbPublicVariables() for i := range ins { - pi2[offset+spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) + pi2[offset+spr.CommitmentInfo[0].Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + if _, err = pi2[offset+spr.CommitmentInfo[0].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding @@ -133,7 +133,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // TODO @gbotrel deal with that conversion lazily var lcpi2iop *iop.Polynomial - if spr.CommitmentInfo.Is() { + if len(spr.CommitmentInfo) != 0 { lcpi2iop = wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form } else { coeffs := make([]fr.Element, pk.Domain[1].Cardinality) @@ -188,8 +188,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) - if spr.CommitmentInfo.Is() { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal + if len(spr.CommitmentInfo) != 0 { + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[0].CommitmentIndex] = commitmentVal } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) diff --git a/backend/plonk/bw6-633/prove.go b/backend/plonk/bw6-633/prove.go index dbb1b89f53..dd2fea5f3e 100644 --- a/backend/plonk/bw6-633/prove.go +++ b/backend/plonk/bw6-633/prove.go @@ -87,7 +87,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wpi2iop *iop.Polynomial // canonical commitmentVal fr.Element // TODO @Tabaie get rid of this ) - if spr.HasCommitment() { + if len(spr.CommitmentInfo) != 0 { opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[0].HintID, func(_ *big.Int, ins, outs []*big.Int) error { pi2 := make([]fr.Element, pk.Domain[0].Cardinality) offset := spr.GetNbPublicVariables() @@ -133,7 +133,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // TODO @gbotrel deal with that conversion lazily var lcpi2iop *iop.Polynomial - if spr.HasCommitment() { + if len(spr.CommitmentInfo) != 0 { lcpi2iop = wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form } else { coeffs := make([]fr.Element, pk.Domain[1].Cardinality) @@ -188,7 +188,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) - if spr.HasCommitment() { + if len(spr.CommitmentInfo) != 0 { qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[0].CommitmentIndex] = commitmentVal } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) diff --git a/backend/plonk/bw6-761/prove.go b/backend/plonk/bw6-761/prove.go index 10f1b7598b..e349bbc222 100644 --- a/backend/plonk/bw6-761/prove.go +++ b/backend/plonk/bw6-761/prove.go @@ -87,18 +87,18 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wpi2iop *iop.Polynomial // canonical commitmentVal fr.Element // TODO @Tabaie get rid of this ) - if spr.CommitmentInfo.Is() { - opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo.HintID, func(_ *big.Int, ins, outs []*big.Int) error { + if len(spr.CommitmentInfo) != 0 { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[0].HintID, func(_ *big.Int, ins, outs []*big.Int) error { pi2 := make([]fr.Element, pk.Domain[0].Cardinality) offset := spr.GetNbPublicVariables() for i := range ins { - pi2[offset+spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) + pi2[offset+spr.CommitmentInfo[0].Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + if _, err = pi2[offset+spr.CommitmentInfo[0].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding @@ -133,7 +133,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // TODO @gbotrel deal with that conversion lazily var lcpi2iop *iop.Polynomial - if spr.CommitmentInfo.Is() { + if len(spr.CommitmentInfo) != 0 { lcpi2iop = wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form } else { coeffs := make([]fr.Element, pk.Domain[1].Cardinality) @@ -188,8 +188,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) - if spr.CommitmentInfo.Is() { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal + if len(spr.CommitmentInfo) != 0 { + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[0].CommitmentIndex] = commitmentVal } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) diff --git a/constraint/commitment.go b/constraint/commitment.go index f0e6e56496..7bf2ef43a6 100644 --- a/constraint/commitment.go +++ b/constraint/commitment.go @@ -50,9 +50,6 @@ func SerializeCommitment(privateCommitment []byte, publicCommitted []*big.Int, f // PrivateToPublicGroth16 returns indexes of variables which are private to the constraint system, but public to Groth16. That is, private committed variables and the commitment itself // TODO Perhaps move it elsewhere since it's specific to groth16 func (i *Commitment) PrivateToPublicGroth16() []int { - if !i.Is() { - return nil - } res := make([]int, i.NbPrivateCommitted+1) copy(res, i.PrivateCommitted()) res[i.NbPrivateCommitted] = i.CommitmentIndex diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl index 696cfdbdb6..f3ac55cec8 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl @@ -65,18 +65,18 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wpi2iop *iop.Polynomial // canonical commitmentVal fr.Element // TODO @Tabaie get rid of this ) - if spr.CommitmentInfo.Is() { - opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo.HintID, func(_ *big.Int, ins, outs []*big.Int) error { + if len(spr.CommitmentInfo) != 0 { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[0].HintID, func(_ *big.Int, ins, outs []*big.Int) error { pi2 := make([]fr.Element, pk.Domain[0].Cardinality) offset := spr.GetNbPublicVariables() for i := range ins { - pi2[offset+spr.CommitmentInfo.Committed[i]].SetBigInt(ins[i]) + pi2[offset+spr.CommitmentInfo[0].Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - if _, err = pi2[offset+spr.CommitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + if _, err = pi2[offset+spr.CommitmentInfo[0].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding @@ -111,7 +111,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // TODO @gbotrel deal with that conversion lazily var lcpi2iop *iop.Polynomial - if spr.CommitmentInfo.Is() { + if len(spr.CommitmentInfo) != 0 { lcpi2iop = wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form } else { coeffs := make([]fr.Element, pk.Domain[1].Cardinality) @@ -168,8 +168,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) - if spr.CommitmentInfo.Is() { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo.CommitmentIndex] = commitmentVal + if len(spr.CommitmentInfo) != 0 { + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[0].CommitmentIndex] = commitmentVal } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) From f9245c46b258c0a0ca2f8b84604d797d50034996 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 26 Apr 2023 14:37:38 -0500 Subject: [PATCH 305/464] refactor: commitmentInfo array in plonk setup --- backend/plonk/bls12-377/setup.go | 11 ++++++----- backend/plonk/bls12-381/setup.go | 11 ++++++----- backend/plonk/bls24-315/setup.go | 11 ++++++----- backend/plonk/bls24-317/setup.go | 11 ++++++----- backend/plonk/bn254/setup.go | 11 ++++++----- backend/plonk/bw6-633/setup.go | 11 ++++++----- backend/plonk/bw6-761/setup.go | 11 ++++++----- constraint/commitment.go | 8 ++++++++ .../template/zkpschemes/plonk/plonk.setup.go.tmpl | 9 +++++---- 9 files changed, 55 insertions(+), 39 deletions(-) diff --git a/backend/plonk/bls12-377/setup.go b/backend/plonk/bls12-377/setup.go index c24e78af72..15b25e9ad6 100644 --- a/backend/plonk/bls12-377/setup.go +++ b/backend/plonk/bls12-377/setup.go @@ -23,6 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/iop" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/kzg" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls12-377" ) @@ -121,9 +122,7 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - if spr.CommitmentInfo.Is() { - vk.CommitmentConstraintIndexes = []uint64{uint64(spr.CommitmentInfo.CommitmentIndex)} - } + vk.CommitmentConstraintIndexes = constraint.CommitmentIndexes(spr.CommitmentInfo) // nbConstraints := len(spr.Constraints) // step 0: set the fft domains @@ -249,8 +248,10 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { j++ } - for _, committed := range spr.CommitmentInfo.Committed { - qcp[offset+committed].SetOne() + if len(spr.CommitmentInfo) != 0 { + for _, committed := range spr.CommitmentInfo[0].Committed { + qcp[offset+committed].SetOne() + } } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} diff --git a/backend/plonk/bls12-381/setup.go b/backend/plonk/bls12-381/setup.go index 21bbafb498..7f35b7dfd1 100644 --- a/backend/plonk/bls12-381/setup.go +++ b/backend/plonk/bls12-381/setup.go @@ -23,6 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/iop" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/kzg" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls12-381" ) @@ -121,9 +122,7 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - if spr.CommitmentInfo.Is() { - vk.CommitmentConstraintIndexes = []uint64{uint64(spr.CommitmentInfo.CommitmentIndex)} - } + vk.CommitmentConstraintIndexes = constraint.CommitmentIndexes(spr.CommitmentInfo) // nbConstraints := len(spr.Constraints) // step 0: set the fft domains @@ -249,8 +248,10 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { j++ } - for _, committed := range spr.CommitmentInfo.Committed { - qcp[offset+committed].SetOne() + if len(spr.CommitmentInfo) != 0 { + for _, committed := range spr.CommitmentInfo[0].Committed { + qcp[offset+committed].SetOne() + } } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} diff --git a/backend/plonk/bls24-315/setup.go b/backend/plonk/bls24-315/setup.go index 5cbf951be3..f8ad8640c3 100644 --- a/backend/plonk/bls24-315/setup.go +++ b/backend/plonk/bls24-315/setup.go @@ -23,6 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/iop" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/kzg" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls24-315" ) @@ -121,9 +122,7 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - if spr.CommitmentInfo.Is() { - vk.CommitmentConstraintIndexes = []uint64{uint64(spr.CommitmentInfo.CommitmentIndex)} - } + vk.CommitmentConstraintIndexes = constraint.CommitmentIndexes(spr.CommitmentInfo) // nbConstraints := len(spr.Constraints) // step 0: set the fft domains @@ -249,8 +248,10 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { j++ } - for _, committed := range spr.CommitmentInfo.Committed { - qcp[offset+committed].SetOne() + if len(spr.CommitmentInfo) != 0 { + for _, committed := range spr.CommitmentInfo[0].Committed { + qcp[offset+committed].SetOne() + } } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} diff --git a/backend/plonk/bls24-317/setup.go b/backend/plonk/bls24-317/setup.go index fffce8b578..d15a30109f 100644 --- a/backend/plonk/bls24-317/setup.go +++ b/backend/plonk/bls24-317/setup.go @@ -23,6 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/iop" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/kzg" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls24-317" ) @@ -121,9 +122,7 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - if spr.CommitmentInfo.Is() { - vk.CommitmentConstraintIndexes = []uint64{uint64(spr.CommitmentInfo.CommitmentIndex)} - } + vk.CommitmentConstraintIndexes = constraint.CommitmentIndexes(spr.CommitmentInfo) // nbConstraints := len(spr.Constraints) // step 0: set the fft domains @@ -249,8 +248,10 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { j++ } - for _, committed := range spr.CommitmentInfo.Committed { - qcp[offset+committed].SetOne() + if len(spr.CommitmentInfo) != 0 { + for _, committed := range spr.CommitmentInfo[0].Committed { + qcp[offset+committed].SetOne() + } } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} diff --git a/backend/plonk/bn254/setup.go b/backend/plonk/bn254/setup.go index ba3f0333ff..5d68c801f2 100644 --- a/backend/plonk/bn254/setup.go +++ b/backend/plonk/bn254/setup.go @@ -23,6 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" "github.com/consensys/gnark-crypto/ecc/bn254/fr/iop" "github.com/consensys/gnark-crypto/ecc/bn254/fr/kzg" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bn254" ) @@ -121,9 +122,7 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - if spr.CommitmentInfo.Is() { - vk.CommitmentConstraintIndexes = []uint64{uint64(spr.CommitmentInfo.CommitmentIndex)} - } + vk.CommitmentConstraintIndexes = constraint.CommitmentIndexes(spr.CommitmentInfo) // nbConstraints := len(spr.Constraints) // step 0: set the fft domains @@ -249,8 +248,10 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { j++ } - for _, committed := range spr.CommitmentInfo.Committed { - qcp[offset+committed].SetOne() + if len(spr.CommitmentInfo) != 0 { + for _, committed := range spr.CommitmentInfo[0].Committed { + qcp[offset+committed].SetOne() + } } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} diff --git a/backend/plonk/bw6-633/setup.go b/backend/plonk/bw6-633/setup.go index c98cdfec61..a84d4d334e 100644 --- a/backend/plonk/bw6-633/setup.go +++ b/backend/plonk/bw6-633/setup.go @@ -23,6 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/fft" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/iop" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/kzg" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bw6-633" ) @@ -121,9 +122,7 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - if spr.CommitmentInfo.Is() { - vk.CommitmentConstraintIndexes = []uint64{uint64(spr.CommitmentInfo.CommitmentIndex)} - } + vk.CommitmentConstraintIndexes = constraint.CommitmentIndexes(spr.CommitmentInfo) // nbConstraints := len(spr.Constraints) // step 0: set the fft domains @@ -249,8 +248,10 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { j++ } - for _, committed := range spr.CommitmentInfo.Committed { - qcp[offset+committed].SetOne() + if len(spr.CommitmentInfo) != 0 { + for _, committed := range spr.CommitmentInfo[0].Committed { + qcp[offset+committed].SetOne() + } } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} diff --git a/backend/plonk/bw6-761/setup.go b/backend/plonk/bw6-761/setup.go index b042c3065b..a14071de61 100644 --- a/backend/plonk/bw6-761/setup.go +++ b/backend/plonk/bw6-761/setup.go @@ -23,6 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/fft" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/iop" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/kzg" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bw6-761" ) @@ -121,9 +122,7 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - if spr.CommitmentInfo.Is() { - vk.CommitmentConstraintIndexes = []uint64{uint64(spr.CommitmentInfo.CommitmentIndex)} - } + vk.CommitmentConstraintIndexes = constraint.CommitmentIndexes(spr.CommitmentInfo) // nbConstraints := len(spr.Constraints) // step 0: set the fft domains @@ -249,8 +248,10 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { j++ } - for _, committed := range spr.CommitmentInfo.Committed { - qcp[offset+committed].SetOne() + if len(spr.CommitmentInfo) != 0 { + for _, committed := range spr.CommitmentInfo[0].Committed { + qcp[offset+committed].SetOne() + } } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} diff --git a/constraint/commitment.go b/constraint/commitment.go index 7bf2ef43a6..4291869541 100644 --- a/constraint/commitment.go +++ b/constraint/commitment.go @@ -63,3 +63,11 @@ func (i *Commitment) PrivateCommitted() []int { func (i *Commitment) PublicCommitted() []int { return i.Committed[:i.NbPublicCommitted()] } + +func CommitmentIndexes(commitments []Commitment) []uint64 { + res := make([]uint64, len(commitments)) + for i := range res { + res[i] = uint64(commitments[i].CommitmentIndex) + } + return res +} diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl index 3bc440c380..f2cc8448bd 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl @@ -6,6 +6,7 @@ import ( {{- template "import_backend_cs" . }} "github.com/consensys/gnark-crypto/ecc/{{toLower .Curve}}/fr/iop" "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/constraint" ) // Trace stores a plonk trace as columns @@ -103,9 +104,7 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - if spr.CommitmentInfo.Is() { - vk.CommitmentConstraintIndexes = []uint64{uint64(spr.CommitmentInfo.CommitmentIndex)} - } + vk.CommitmentConstraintIndexes = constraint.CommitmentIndexes(spr.CommitmentInfo) // nbConstraints := len(spr.Constraints) // step 0: set the fft domains @@ -233,9 +232,11 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { j++ } - for _, committed := range spr.CommitmentInfo.Committed { + if len(spr.CommitmentInfo) != 0 { + for _, committed := range spr.CommitmentInfo[0].Committed { qcp[offset+committed].SetOne() } + } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} From 7237f15c8c7e4570acc07eabbedff28f668121bb Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 26 Apr 2023 14:54:42 -0500 Subject: [PATCH 306/464] refactor: commitmentInfo array for groth16 bn254 --- backend/groth16/bn254/prove.go | 17 ++++++++++------- backend/groth16/bn254/setup.go | 19 +++++++++++++------ 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index 77f9a200a8..c70fc9a242 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -65,14 +65,14 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.CommitmentInfo.Is() { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo.HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { + if r1cs.HasCommitment() { + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function - if len(in) != r1cs.CommitmentInfo.NbCommitted() { // TODO: Remove + if len(in) != r1cs.CommitmentInfo[0].NbCommitted() { // TODO: Remove return fmt.Errorf("unexpected number of committed variables") } - values := make([]fr.Element, r1cs.CommitmentInfo.NbPrivateCommitted) + values := make([]fr.Element, r1cs.CommitmentInfo[0].NbPrivateCommitted) nbPublicCommitted := len(in) - len(values) inPrivate := in[nbPublicCommitted:] for i, inI := range inPrivate { @@ -86,7 +86,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[0].NbPublicCommitted()]) res.BigInt(out[0]) return err })) @@ -202,8 +202,11 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b chKrs2Done <- err }() - // filter the wire values if needed; - _wireValues := filter(wireValues, r1cs.CommitmentInfo.PrivateToPublicGroth16()) + // filter the wire values if needed + _wireValues := wireValues + if r1cs.HasCommitment() { + _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) + } if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index a91f1162e0..b5cbddfae7 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -94,11 +94,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbPrivateCommittedWires := r1cs.CommitmentInfo.NbPrivateCommitted + nbPrivateCommittedWires := 0 + if r1cs.HasCommitment() { + nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted + } nbPublicWires := r1cs.GetNbPublicVariables() nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.CommitmentInfo.Is() { // the commitment itself is defined by a hint so the prover considers it private + if r1cs.HasCommitment() { // the commitment itself is defined by a hint so the prover considers it private nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 nbPrivateWires-- // level it must be considered public } @@ -151,11 +154,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } vI, cI := 0, 0 - privateCommitted := r1cs.CommitmentInfo.PrivateCommitted() + var privateCommitted []int + if r1cs.HasCommitment() { + privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() + } for i := range A { isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.CommitmentInfo.Is() && i == r1cs.CommitmentInfo.CommitmentIndex + isCommitment := r1cs.HasCommitment() && i == r1cs.CommitmentInfo[0].CommitmentIndex isPublic := i < r1cs.GetNbPublicVariables() if isPublic || isCommittedPrivate || isCommitment { @@ -263,8 +269,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - vk.HasCommitment = r1cs.CommitmentInfo.Is() - vk.PublicCommitted = r1cs.CommitmentInfo.PublicCommitted() + if vk.HasCommitment = r1cs.HasCommitment(); vk.HasCommitment { + vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() + } // --------------------------------------------------------------------------------------------- // G2 scalars From 4448eb822c03a7d1266d32a365378392c84df5fb Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 26 Apr 2023 15:48:07 -0500 Subject: [PATCH 307/464] build: generify bn254 changes --- backend/groth16/bls12-377/prove.go | 17 ++++++++++------- backend/groth16/bls12-377/setup.go | 19 +++++++++++++------ backend/groth16/bls12-381/prove.go | 17 ++++++++++------- backend/groth16/bls12-381/setup.go | 19 +++++++++++++------ backend/groth16/bls24-315/prove.go | 17 ++++++++++------- backend/groth16/bls24-315/setup.go | 19 +++++++++++++------ backend/groth16/bls24-317/prove.go | 17 ++++++++++------- backend/groth16/bls24-317/setup.go | 19 +++++++++++++------ backend/groth16/bw6-633/prove.go | 17 ++++++++++------- backend/groth16/bw6-633/setup.go | 19 +++++++++++++------ backend/groth16/bw6-761/prove.go | 17 ++++++++++------- backend/groth16/bw6-761/setup.go | 19 +++++++++++++------ .../zkpschemes/groth16/groth16.prove.go.tmpl | 17 ++++++++++------- .../zkpschemes/groth16/groth16.setup.go.tmpl | 19 +++++++++++++------ 14 files changed, 161 insertions(+), 91 deletions(-) diff --git a/backend/groth16/bls12-377/prove.go b/backend/groth16/bls12-377/prove.go index 3657d798d3..32a94e9316 100644 --- a/backend/groth16/bls12-377/prove.go +++ b/backend/groth16/bls12-377/prove.go @@ -65,14 +65,14 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.CommitmentInfo.Is() { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo.HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { + if r1cs.HasCommitment() { + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function - if len(in) != r1cs.CommitmentInfo.NbCommitted() { // TODO: Remove + if len(in) != r1cs.CommitmentInfo[0].NbCommitted() { // TODO: Remove return fmt.Errorf("unexpected number of committed variables") } - values := make([]fr.Element, r1cs.CommitmentInfo.NbPrivateCommitted) + values := make([]fr.Element, r1cs.CommitmentInfo[0].NbPrivateCommitted) nbPublicCommitted := len(in) - len(values) inPrivate := in[nbPublicCommitted:] for i, inI := range inPrivate { @@ -86,7 +86,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[0].NbPublicCommitted()]) res.BigInt(out[0]) return err })) @@ -202,8 +202,11 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b chKrs2Done <- err }() - // filter the wire values if needed; - _wireValues := filter(wireValues, r1cs.CommitmentInfo.PrivateToPublicGroth16()) + // filter the wire values if needed + _wireValues := wireValues + if r1cs.HasCommitment() { + _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) + } if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index 63ef723cde..e9b3a84aba 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -94,11 +94,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbPrivateCommittedWires := r1cs.CommitmentInfo.NbPrivateCommitted + nbPrivateCommittedWires := 0 + if r1cs.HasCommitment() { + nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted + } nbPublicWires := r1cs.GetNbPublicVariables() nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.CommitmentInfo.Is() { // the commitment itself is defined by a hint so the prover considers it private + if r1cs.HasCommitment() { // the commitment itself is defined by a hint so the prover considers it private nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 nbPrivateWires-- // level it must be considered public } @@ -151,11 +154,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } vI, cI := 0, 0 - privateCommitted := r1cs.CommitmentInfo.PrivateCommitted() + var privateCommitted []int + if r1cs.HasCommitment() { + privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() + } for i := range A { isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.CommitmentInfo.Is() && i == r1cs.CommitmentInfo.CommitmentIndex + isCommitment := r1cs.HasCommitment() && i == r1cs.CommitmentInfo[0].CommitmentIndex isPublic := i < r1cs.GetNbPublicVariables() if isPublic || isCommittedPrivate || isCommitment { @@ -263,8 +269,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - vk.HasCommitment = r1cs.CommitmentInfo.Is() - vk.PublicCommitted = r1cs.CommitmentInfo.PublicCommitted() + if vk.HasCommitment = r1cs.HasCommitment(); vk.HasCommitment { + vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() + } // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bls12-381/prove.go b/backend/groth16/bls12-381/prove.go index 1ba992e545..fb5417f747 100644 --- a/backend/groth16/bls12-381/prove.go +++ b/backend/groth16/bls12-381/prove.go @@ -65,14 +65,14 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.CommitmentInfo.Is() { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo.HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { + if r1cs.HasCommitment() { + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function - if len(in) != r1cs.CommitmentInfo.NbCommitted() { // TODO: Remove + if len(in) != r1cs.CommitmentInfo[0].NbCommitted() { // TODO: Remove return fmt.Errorf("unexpected number of committed variables") } - values := make([]fr.Element, r1cs.CommitmentInfo.NbPrivateCommitted) + values := make([]fr.Element, r1cs.CommitmentInfo[0].NbPrivateCommitted) nbPublicCommitted := len(in) - len(values) inPrivate := in[nbPublicCommitted:] for i, inI := range inPrivate { @@ -86,7 +86,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[0].NbPublicCommitted()]) res.BigInt(out[0]) return err })) @@ -202,8 +202,11 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b chKrs2Done <- err }() - // filter the wire values if needed; - _wireValues := filter(wireValues, r1cs.CommitmentInfo.PrivateToPublicGroth16()) + // filter the wire values if needed + _wireValues := wireValues + if r1cs.HasCommitment() { + _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) + } if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index a0b185e2f0..8cc83943c4 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -94,11 +94,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbPrivateCommittedWires := r1cs.CommitmentInfo.NbPrivateCommitted + nbPrivateCommittedWires := 0 + if r1cs.HasCommitment() { + nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted + } nbPublicWires := r1cs.GetNbPublicVariables() nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.CommitmentInfo.Is() { // the commitment itself is defined by a hint so the prover considers it private + if r1cs.HasCommitment() { // the commitment itself is defined by a hint so the prover considers it private nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 nbPrivateWires-- // level it must be considered public } @@ -151,11 +154,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } vI, cI := 0, 0 - privateCommitted := r1cs.CommitmentInfo.PrivateCommitted() + var privateCommitted []int + if r1cs.HasCommitment() { + privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() + } for i := range A { isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.CommitmentInfo.Is() && i == r1cs.CommitmentInfo.CommitmentIndex + isCommitment := r1cs.HasCommitment() && i == r1cs.CommitmentInfo[0].CommitmentIndex isPublic := i < r1cs.GetNbPublicVariables() if isPublic || isCommittedPrivate || isCommitment { @@ -263,8 +269,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - vk.HasCommitment = r1cs.CommitmentInfo.Is() - vk.PublicCommitted = r1cs.CommitmentInfo.PublicCommitted() + if vk.HasCommitment = r1cs.HasCommitment(); vk.HasCommitment { + vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() + } // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bls24-315/prove.go b/backend/groth16/bls24-315/prove.go index 9a3bf927e8..0305ab7bd2 100644 --- a/backend/groth16/bls24-315/prove.go +++ b/backend/groth16/bls24-315/prove.go @@ -65,14 +65,14 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.CommitmentInfo.Is() { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo.HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { + if r1cs.HasCommitment() { + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function - if len(in) != r1cs.CommitmentInfo.NbCommitted() { // TODO: Remove + if len(in) != r1cs.CommitmentInfo[0].NbCommitted() { // TODO: Remove return fmt.Errorf("unexpected number of committed variables") } - values := make([]fr.Element, r1cs.CommitmentInfo.NbPrivateCommitted) + values := make([]fr.Element, r1cs.CommitmentInfo[0].NbPrivateCommitted) nbPublicCommitted := len(in) - len(values) inPrivate := in[nbPublicCommitted:] for i, inI := range inPrivate { @@ -86,7 +86,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[0].NbPublicCommitted()]) res.BigInt(out[0]) return err })) @@ -202,8 +202,11 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b chKrs2Done <- err }() - // filter the wire values if needed; - _wireValues := filter(wireValues, r1cs.CommitmentInfo.PrivateToPublicGroth16()) + // filter the wire values if needed + _wireValues := wireValues + if r1cs.HasCommitment() { + _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) + } if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index c06ccdc4f9..7fae66e607 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -94,11 +94,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbPrivateCommittedWires := r1cs.CommitmentInfo.NbPrivateCommitted + nbPrivateCommittedWires := 0 + if r1cs.HasCommitment() { + nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted + } nbPublicWires := r1cs.GetNbPublicVariables() nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.CommitmentInfo.Is() { // the commitment itself is defined by a hint so the prover considers it private + if r1cs.HasCommitment() { // the commitment itself is defined by a hint so the prover considers it private nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 nbPrivateWires-- // level it must be considered public } @@ -151,11 +154,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } vI, cI := 0, 0 - privateCommitted := r1cs.CommitmentInfo.PrivateCommitted() + var privateCommitted []int + if r1cs.HasCommitment() { + privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() + } for i := range A { isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.CommitmentInfo.Is() && i == r1cs.CommitmentInfo.CommitmentIndex + isCommitment := r1cs.HasCommitment() && i == r1cs.CommitmentInfo[0].CommitmentIndex isPublic := i < r1cs.GetNbPublicVariables() if isPublic || isCommittedPrivate || isCommitment { @@ -263,8 +269,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - vk.HasCommitment = r1cs.CommitmentInfo.Is() - vk.PublicCommitted = r1cs.CommitmentInfo.PublicCommitted() + if vk.HasCommitment = r1cs.HasCommitment(); vk.HasCommitment { + vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() + } // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bls24-317/prove.go b/backend/groth16/bls24-317/prove.go index 6e5b7f44d7..5abdea890c 100644 --- a/backend/groth16/bls24-317/prove.go +++ b/backend/groth16/bls24-317/prove.go @@ -65,14 +65,14 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.CommitmentInfo.Is() { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo.HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { + if r1cs.HasCommitment() { + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function - if len(in) != r1cs.CommitmentInfo.NbCommitted() { // TODO: Remove + if len(in) != r1cs.CommitmentInfo[0].NbCommitted() { // TODO: Remove return fmt.Errorf("unexpected number of committed variables") } - values := make([]fr.Element, r1cs.CommitmentInfo.NbPrivateCommitted) + values := make([]fr.Element, r1cs.CommitmentInfo[0].NbPrivateCommitted) nbPublicCommitted := len(in) - len(values) inPrivate := in[nbPublicCommitted:] for i, inI := range inPrivate { @@ -86,7 +86,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[0].NbPublicCommitted()]) res.BigInt(out[0]) return err })) @@ -202,8 +202,11 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b chKrs2Done <- err }() - // filter the wire values if needed; - _wireValues := filter(wireValues, r1cs.CommitmentInfo.PrivateToPublicGroth16()) + // filter the wire values if needed + _wireValues := wireValues + if r1cs.HasCommitment() { + _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) + } if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index 3566117413..17a45d0f4c 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -94,11 +94,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbPrivateCommittedWires := r1cs.CommitmentInfo.NbPrivateCommitted + nbPrivateCommittedWires := 0 + if r1cs.HasCommitment() { + nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted + } nbPublicWires := r1cs.GetNbPublicVariables() nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.CommitmentInfo.Is() { // the commitment itself is defined by a hint so the prover considers it private + if r1cs.HasCommitment() { // the commitment itself is defined by a hint so the prover considers it private nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 nbPrivateWires-- // level it must be considered public } @@ -151,11 +154,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } vI, cI := 0, 0 - privateCommitted := r1cs.CommitmentInfo.PrivateCommitted() + var privateCommitted []int + if r1cs.HasCommitment() { + privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() + } for i := range A { isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.CommitmentInfo.Is() && i == r1cs.CommitmentInfo.CommitmentIndex + isCommitment := r1cs.HasCommitment() && i == r1cs.CommitmentInfo[0].CommitmentIndex isPublic := i < r1cs.GetNbPublicVariables() if isPublic || isCommittedPrivate || isCommitment { @@ -263,8 +269,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - vk.HasCommitment = r1cs.CommitmentInfo.Is() - vk.PublicCommitted = r1cs.CommitmentInfo.PublicCommitted() + if vk.HasCommitment = r1cs.HasCommitment(); vk.HasCommitment { + vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() + } // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bw6-633/prove.go b/backend/groth16/bw6-633/prove.go index 0d97c60bb6..97303aca05 100644 --- a/backend/groth16/bw6-633/prove.go +++ b/backend/groth16/bw6-633/prove.go @@ -65,14 +65,14 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.CommitmentInfo.Is() { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo.HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { + if r1cs.HasCommitment() { + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function - if len(in) != r1cs.CommitmentInfo.NbCommitted() { // TODO: Remove + if len(in) != r1cs.CommitmentInfo[0].NbCommitted() { // TODO: Remove return fmt.Errorf("unexpected number of committed variables") } - values := make([]fr.Element, r1cs.CommitmentInfo.NbPrivateCommitted) + values := make([]fr.Element, r1cs.CommitmentInfo[0].NbPrivateCommitted) nbPublicCommitted := len(in) - len(values) inPrivate := in[nbPublicCommitted:] for i, inI := range inPrivate { @@ -86,7 +86,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[0].NbPublicCommitted()]) res.BigInt(out[0]) return err })) @@ -202,8 +202,11 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b chKrs2Done <- err }() - // filter the wire values if needed; - _wireValues := filter(wireValues, r1cs.CommitmentInfo.PrivateToPublicGroth16()) + // filter the wire values if needed + _wireValues := wireValues + if r1cs.HasCommitment() { + _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) + } if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index 355da54859..d778c929a7 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -94,11 +94,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbPrivateCommittedWires := r1cs.CommitmentInfo.NbPrivateCommitted + nbPrivateCommittedWires := 0 + if r1cs.HasCommitment() { + nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted + } nbPublicWires := r1cs.GetNbPublicVariables() nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.CommitmentInfo.Is() { // the commitment itself is defined by a hint so the prover considers it private + if r1cs.HasCommitment() { // the commitment itself is defined by a hint so the prover considers it private nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 nbPrivateWires-- // level it must be considered public } @@ -151,11 +154,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } vI, cI := 0, 0 - privateCommitted := r1cs.CommitmentInfo.PrivateCommitted() + var privateCommitted []int + if r1cs.HasCommitment() { + privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() + } for i := range A { isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.CommitmentInfo.Is() && i == r1cs.CommitmentInfo.CommitmentIndex + isCommitment := r1cs.HasCommitment() && i == r1cs.CommitmentInfo[0].CommitmentIndex isPublic := i < r1cs.GetNbPublicVariables() if isPublic || isCommittedPrivate || isCommitment { @@ -263,8 +269,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - vk.HasCommitment = r1cs.CommitmentInfo.Is() - vk.PublicCommitted = r1cs.CommitmentInfo.PublicCommitted() + if vk.HasCommitment = r1cs.HasCommitment(); vk.HasCommitment { + vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() + } // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bw6-761/prove.go b/backend/groth16/bw6-761/prove.go index c81880f497..db26808f87 100644 --- a/backend/groth16/bw6-761/prove.go +++ b/backend/groth16/bw6-761/prove.go @@ -65,14 +65,14 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.CommitmentInfo.Is() { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo.HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { + if r1cs.HasCommitment() { + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function - if len(in) != r1cs.CommitmentInfo.NbCommitted() { // TODO: Remove + if len(in) != r1cs.CommitmentInfo[0].NbCommitted() { // TODO: Remove return fmt.Errorf("unexpected number of committed variables") } - values := make([]fr.Element, r1cs.CommitmentInfo.NbPrivateCommitted) + values := make([]fr.Element, r1cs.CommitmentInfo[0].NbPrivateCommitted) nbPublicCommitted := len(in) - len(values) inPrivate := in[nbPublicCommitted:] for i, inI := range inPrivate { @@ -86,7 +86,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[0].NbPublicCommitted()]) res.BigInt(out[0]) return err })) @@ -202,8 +202,11 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b chKrs2Done <- err }() - // filter the wire values if needed; - _wireValues := filter(wireValues, r1cs.CommitmentInfo.PrivateToPublicGroth16()) + // filter the wire values if needed + _wireValues := wireValues + if r1cs.HasCommitment() { + _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) + } if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index 606b57c31d..fe6b4a7a46 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -94,11 +94,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbPrivateCommittedWires := r1cs.CommitmentInfo.NbPrivateCommitted + nbPrivateCommittedWires := 0 + if r1cs.HasCommitment() { + nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted + } nbPublicWires := r1cs.GetNbPublicVariables() nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.CommitmentInfo.Is() { // the commitment itself is defined by a hint so the prover considers it private + if r1cs.HasCommitment() { // the commitment itself is defined by a hint so the prover considers it private nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 nbPrivateWires-- // level it must be considered public } @@ -151,11 +154,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } vI, cI := 0, 0 - privateCommitted := r1cs.CommitmentInfo.PrivateCommitted() + var privateCommitted []int + if r1cs.HasCommitment() { + privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() + } for i := range A { isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.CommitmentInfo.Is() && i == r1cs.CommitmentInfo.CommitmentIndex + isCommitment := r1cs.HasCommitment() && i == r1cs.CommitmentInfo[0].CommitmentIndex isPublic := i < r1cs.GetNbPublicVariables() if isPublic || isCommittedPrivate || isCommitment { @@ -263,8 +269,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - vk.HasCommitment = r1cs.CommitmentInfo.Is() - vk.PublicCommitted = r1cs.CommitmentInfo.PublicCommitted() + if vk.HasCommitment = r1cs.HasCommitment(); vk.HasCommitment { + vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() + } // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl index 2e7b63e1b9..d80a139443 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl @@ -48,14 +48,14 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.CommitmentInfo.Is() { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo.HintID,func(_ *big.Int, in []*big.Int, out []*big.Int) error { + if r1cs.HasCommitment() { + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID,func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function - if len(in) != r1cs.CommitmentInfo.NbCommitted() { // TODO: Remove + if len(in) != r1cs.CommitmentInfo[0].NbCommitted() { // TODO: Remove return fmt.Errorf("unexpected number of committed variables") } - values := make([]fr.Element, r1cs.CommitmentInfo.NbPrivateCommitted) + values := make([]fr.Element, r1cs.CommitmentInfo[0].NbPrivateCommitted) nbPublicCommitted := len(in) - len(values) inPrivate := in[nbPublicCommitted:] for i, inI := range inPrivate { @@ -69,7 +69,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[0].NbPublicCommitted()]) res.BigInt(out[0]) return err } )) @@ -185,8 +185,11 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b chKrs2Done <- err }() - // filter the wire values if needed; - _wireValues := filter(wireValues, r1cs.CommitmentInfo.PrivateToPublicGroth16()) + // filter the wire values if needed + _wireValues := wireValues + if r1cs.HasCommitment() { + _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) + } if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl index 81164025f1..a7fb6512b8 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl @@ -76,11 +76,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbPrivateCommittedWires := r1cs.CommitmentInfo.NbPrivateCommitted + nbPrivateCommittedWires := 0 + if r1cs.HasCommitment() { + nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted + } nbPublicWires := r1cs.GetNbPublicVariables() nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.CommitmentInfo.Is() { // the commitment itself is defined by a hint so the prover considers it private + if r1cs.HasCommitment() { // the commitment itself is defined by a hint so the prover considers it private nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 nbPrivateWires-- // level it must be considered public } @@ -133,11 +136,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } vI, cI := 0, 0 - privateCommitted := r1cs.CommitmentInfo.PrivateCommitted() + var privateCommitted []int + if r1cs.HasCommitment() { + privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() + } for i := range A { isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.CommitmentInfo.Is() && i == r1cs.CommitmentInfo.CommitmentIndex + isCommitment := r1cs.HasCommitment() && i == r1cs.CommitmentInfo[0].CommitmentIndex isPublic := i < r1cs.GetNbPublicVariables() if isPublic || isCommittedPrivate || isCommitment { @@ -245,8 +251,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - vk.HasCommitment = r1cs.CommitmentInfo.Is() - vk.PublicCommitted = r1cs.CommitmentInfo.PublicCommitted() + if vk.HasCommitment = r1cs.HasCommitment(); vk.HasCommitment { + vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() + } // --------------------------------------------------------------------------------------------- // G2 scalars From 18bb44a3b7c02ca0de7421b2dbf16a6d58792d5c Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 28 Apr 2023 18:07:49 -0500 Subject: [PATCH 308/464] fix: multi-commit unsupported error messages --- frontend/cs/r1cs/api.go | 5 +++++ frontend/cs/scs/api.go | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index c0513c01ed..e4e5dd509f 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -676,6 +676,11 @@ func (builder *builder) Compiler() frontend.Compiler { } func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error) { + + if builder.cs.HasCommitment() { + return nil, errors.New("multi-commits not available for groth16 - yet") + } + // we want to build a sorted slice of committed variables, without duplicates // this is the same algorithm as builder.add(...); but we expect len(v) to be quite large. diff --git a/frontend/cs/scs/api.go b/frontend/cs/scs/api.go index 89e280ad42..e47c16bc50 100644 --- a/frontend/cs/scs/api.go +++ b/frontend/cs/scs/api.go @@ -573,7 +573,7 @@ func (builder *builder) Compiler() frontend.Compiler { func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error) { if builder.cs.HasCommitment() { - return nil, errors.New("multi-commits not available for groth16 - yet") + return nil, errors.New("multi-commits not available for plonk - yet") } v = filterConstants(v) // TODO: @Tabaie Settle on a way to represent even constants; conventional hash? From fac1c621c65e68967d4a1e70fb6ce9d3a2f8fe30 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Sat, 29 Apr 2023 18:39:03 -0500 Subject: [PATCH 309/464] feat: hint name options --- constraint/core.go | 19 ++++-- constraint/hint.go | 19 ++++++ constraint/solver/hint_registry.go | 24 +++++++ constraint/solver/options.go | 6 +- constraint/system.go | 2 +- frontend/builder.go | 1 + frontend/cs/r1cs/builder.go | 15 ++++- frontend/cs/scs/builder.go | 14 +++- test/commitments_test.go | 24 +++---- test/engine.go | 7 +- test/hint_test.go | 102 +++++++++++++++++++++++++++++ 11 files changed, 205 insertions(+), 28 deletions(-) create mode 100644 test/hint_test.go diff --git a/constraint/core.go b/constraint/core.go index 6efb8d911f..0096ad604d 100644 --- a/constraint/core.go +++ b/constraint/core.go @@ -205,20 +205,25 @@ func (system *System) AddSecretVariable(name string) (idx int) { return idx } -func (system *System) AddSolverHint(f solver.Hint, input []LinearExpression, nbOutput int) (internalVariables []int, err error) { +func (system *System) AddSolverHint(f solver.Hint, input []LinearExpression, nbOutput int, options ...HintIdOption) (internalVariables []int, err error) { if nbOutput <= 0 { return nil, fmt.Errorf("hint function must return at least one output") } // register the hint as dependency - hintUUID, hintID := solver.GetHintID(f), solver.GetHintName(f) - if id, ok := system.MHintsDependencies[hintUUID]; ok { + ID := HintIds{solver.GetHintID(f), solver.GetHintName(f)} + + for i := range options { + options[i](&ID) + } + + if id, ok := system.MHintsDependencies[ID.UUID]; ok { // hint already registered, let's ensure string id matches - if id != hintID { - return nil, fmt.Errorf("hint dependency registration failed; %s previously register with same UUID as %s", hintID, id) + if id != ID.Name { + return nil, fmt.Errorf("hint dependency registration failed; %s previously register with same UUID as %s", ID.Name, id) } } else { - system.MHintsDependencies[hintUUID] = hintID + system.MHintsDependencies[ID.UUID] = ID.Name } // prepare wires @@ -229,7 +234,7 @@ func (system *System) AddSolverHint(f solver.Hint, input []LinearExpression, nbO // associate these wires with the solver hint hm := HintMapping{ - HintID: hintUUID, + HintID: ID.UUID, Inputs: input, OutputRange: struct { Start uint32 diff --git a/constraint/hint.go b/constraint/hint.go index a79bfea41d..e2455a0c48 100644 --- a/constraint/hint.go +++ b/constraint/hint.go @@ -4,6 +4,25 @@ import ( "github.com/consensys/gnark/constraint/solver" ) +type HintIds struct { + UUID solver.HintID + Name string +} + +type HintIdOption func(*HintIds) + +func WithHintId(id solver.HintID) HintIdOption { + return func(_id *HintIds) { + _id.UUID = id + } +} + +func WithHintName(name string) HintIdOption { + return func(id *HintIds) { + id.Name = name + } +} + // HintMapping mark a list of output variables to be computed using provided hint and inputs. type HintMapping struct { HintID solver.HintID // Hint function id diff --git a/constraint/solver/hint_registry.go b/constraint/solver/hint_registry.go index d9f412839f..b5451bc50e 100644 --- a/constraint/solver/hint_registry.go +++ b/constraint/solver/hint_registry.go @@ -1,6 +1,7 @@ package solver import ( + "fmt" "math/big" "sync" @@ -32,6 +33,15 @@ func RegisterHint(hintFns ...Hint) { } } +func RegisterNamedHint(hintFn Hint, key HintID) { + registryM.Lock() + defer registryM.Unlock() + if _, ok := registry[key]; ok { + panic(fmt.Errorf("hint id %d already taken", key)) + } + registry[key] = hintFn +} + // GetRegisteredHints returns all registered hint functions. func GetRegisteredHints() []Hint { registryM.RLock() @@ -43,6 +53,20 @@ func GetRegisteredHints() []Hint { return ret } +func cloneMap[K comparable, V any](src map[K]V) map[K]V { + res := make(map[K]V, len(registry)) + for k, v := range src { + res[k] = v + } + return res +} + +func cloneHintRegistry() map[HintID]Hint { + registryM.Lock() + defer registryM.Unlock() + return cloneMap(registry) +} + // InvZeroHint computes the value 1/a for the single input a. If a == 0, returns 0. func InvZeroHint(q *big.Int, inputs []*big.Int, results []*big.Int) error { result := results[0] diff --git a/constraint/solver/options.go b/constraint/solver/options.go index 368eff3f56..d7aa7cac4e 100644 --- a/constraint/solver/options.go +++ b/constraint/solver/options.go @@ -56,10 +56,8 @@ func WithLogger(l zerolog.Logger) Option { // NewConfig returns a default SolverConfig with given prover options opts applied. func NewConfig(opts ...Option) (Config, error) { log := logger.Logger() - opt := Config{Logger: log, HintFunctions: make(map[HintID]Hint)} - for _, v := range GetRegisteredHints() { - opt.HintFunctions[GetHintID(v)] = v - } + opt := Config{Logger: log} + opt.HintFunctions = cloneHintRegistry() for _, option := range opts { if err := option(&opt); err != nil { return Config{}, err diff --git a/constraint/system.go b/constraint/system.go index 964838485d..7e6ba3eda8 100644 --- a/constraint/system.go +++ b/constraint/system.go @@ -45,7 +45,7 @@ type ConstraintSystem interface { // AddSolverHint adds a hint to the solver such that the output variables will be computed // using a call to output := f(input...) at solve time. - AddSolverHint(f solver.Hint, input []LinearExpression, nbOutput int) (internalVariables []int, err error) + AddSolverHint(f solver.Hint, input []LinearExpression, nbOutput int, options ...HintIdOption) (internalVariables []int, err error) AddCommitment(c Commitment) error diff --git a/frontend/builder.go b/frontend/builder.go index cd52e71169..3cc17a4a44 100644 --- a/frontend/builder.go +++ b/frontend/builder.go @@ -37,6 +37,7 @@ type Compiler interface { // // If nbOutputs is specified, it must be >= 1 and <= f.NbOutputs NewHint(f solver.Hint, nbOutputs int, inputs ...Variable) ([]Variable, error) + NewNamedHint(f solver.Hint, nameOptions *constraint.HintIds, nbOutputs int, inputs ...Variable) ([]Variable, error) // ConstantValue returns the big.Int value of v and true if op is a success. // nil and false if failure. This API returns a boolean to allow for future refactoring diff --git a/frontend/cs/r1cs/builder.go b/frontend/cs/r1cs/builder.go index b8036314fe..ed3beb9c9c 100644 --- a/frontend/cs/r1cs/builder.go +++ b/frontend/cs/r1cs/builder.go @@ -371,6 +371,10 @@ func (builder *builder) toVariables(in ...frontend.Variable) ([]expr.LinearExpre // No new constraints are added to the newly created wire and must be added // manually in the circuit. Failing to do so leads to solver failure. func (builder *builder) NewHint(f solver.Hint, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { + return builder.NewNamedHint(f, nil, nbOutputs, inputs...) +} + +func (builder *builder) NewNamedHint(f solver.Hint, nameOptions *constraint.HintIds, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { hintInputs := make([]constraint.LinearExpression, len(inputs)) // TODO @gbotrel hint input pass @@ -387,7 +391,15 @@ func (builder *builder) NewHint(f solver.Hint, nbOutputs int, inputs ...frontend } } - internalVariables, err := builder.cs.AddSolverHint(f, hintInputs, nbOutputs) + var options []constraint.HintIdOption + if nameOptions != nil { + options = []constraint.HintIdOption{ + constraint.WithHintId(nameOptions.UUID), + constraint.WithHintName(nameOptions.Name), + } + } + + internalVariables, err := builder.cs.AddSolverHint(f, hintInputs, nbOutputs, options...) if err != nil { return nil, err } @@ -398,7 +410,6 @@ func (builder *builder) NewHint(f solver.Hint, nbOutputs int, inputs ...frontend res[i] = expr.NewLinearExpression(idx, builder.tOne) } return res, nil - } // assertIsSet panics if the variable is unset diff --git a/frontend/cs/scs/builder.go b/frontend/cs/scs/builder.go index eca3f32a4b..cd977c1a6f 100644 --- a/frontend/cs/scs/builder.go +++ b/frontend/cs/scs/builder.go @@ -342,6 +342,10 @@ func (builder *builder) hintBuffer(size int) []constraint.LinearExpression { // No new constraints are added to the newly created wire and must be added // manually in the circuit. Failing to do so leads to solver failure. func (builder *builder) NewHint(f solver.Hint, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { + return builder.NewNamedHint(f, nil, nbOutputs, inputs...) +} + +func (builder *builder) NewNamedHint(f solver.Hint, nameOptions *constraint.HintIds, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { hintInputs := builder.hintBuffer(len(inputs)) @@ -358,7 +362,15 @@ func (builder *builder) NewHint(f solver.Hint, nbOutputs int, inputs ...frontend } } - internalVariables, err := builder.cs.AddSolverHint(f, hintInputs, nbOutputs) + var options []constraint.HintIdOption + if nameOptions != nil { + options = []constraint.HintIdOption{ + constraint.WithHintId(nameOptions.UUID), + constraint.WithHintName(nameOptions.Name), + } + } + + internalVariables, err := builder.cs.AddSolverHint(f, hintInputs, nbOutputs, options...) if err != nil { return nil, err } diff --git a/test/commitments_test.go b/test/commitments_test.go index 49f77329fe..37e8d1fafd 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -74,19 +74,19 @@ func TestNoCommitmentCircuitPlonk(t *testing.T) { plonkTest(t, &noCommitmentCircuit{}, &noCommitmentCircuit{1}) } -func plonkTest(t *testing.T, circuit, assignment frontend.Circuit) { +var fr = []ecc.ID{ + ecc.BN254, + ecc.BLS12_381, + ecc.BLS12_377, + ecc.BLS24_315, + //ecc.BLS12_378, TODO: @Tabaie Not autogenerated? + ecc.BLS24_317, + ecc.BW6_633, + //ecc.BW6_756, TODO: @Tabaie Not autogenerated? + ecc.BW6_761, +} - fr := []ecc.ID{ - ecc.BN254, - ecc.BLS12_381, - ecc.BLS12_377, - ecc.BLS24_315, - //ecc.BLS12_378, TODO: @Tabaie Not autogenerated? - ecc.BLS24_317, - ecc.BW6_633, - //ecc.BW6_756, TODO: @Tabaie Not autogenerated? - ecc.BW6_761, - } +func plonkTest(t *testing.T, circuit, assignment frontend.Circuit) { run := func(mod *big.Int) func(t *testing.T) { return func(t *testing.T) { diff --git a/test/engine.go b/test/engine.go index 0691b9335e..841a4e238e 100644 --- a/test/engine.go +++ b/test/engine.go @@ -18,6 +18,7 @@ package test import ( "fmt" + "github.com/consensys/gnark/constraint" "math/big" "path/filepath" "reflect" @@ -485,6 +486,10 @@ func (e *engine) NewHint(f solver.Hint, nbOutputs int, inputs ...frontend.Variab return out, nil } +func (e *engine) NewNamedHint(f solver.Hint, _ *constraint.HintIds, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { + return e.NewHint(f, nbOutputs, inputs...) +} + // IsConstant returns true if v is a constant known at compile time func (e *engine) IsConstant(v frontend.Variable) bool { return e.constVars @@ -520,7 +525,7 @@ func (e *engine) toBigInt(i1 frontend.Variable) *big.Int { } } -// bitLen returns the number of bits needed to represent a fr.Element +// FieldBitLen returns the number of bits needed to represent a fr.Element func (e *engine) FieldBitLen() int { return e.q.BitLen() } diff --git a/test/hint_test.go b/test/hint_test.go new file mode 100644 index 0000000000..4a74301944 --- /dev/null +++ b/test/hint_test.go @@ -0,0 +1,102 @@ +package test + +import ( + "fmt" + "github.com/consensys/gnark/backend/groth16" + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/stretchr/testify/assert" + "math/big" + "testing" +) + +const name = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." +const id = solver.HintID(123454321) + +func identityHint(_ *big.Int, in, out []*big.Int) error { + if len(in) != len(out) { + return fmt.Errorf("len(in) = %d ≠ %d = len(out)", len(in), len(out)) + } + for i := range in { + out[i].Set(in[i]) + } + return nil +} + +type customNamedHintCircuit struct { + X []frontend.Variable +} + +func (c *customNamedHintCircuit) Define(api frontend.API) error { + y, err := api.Compiler().NewNamedHint(identityHint, + &constraint.HintIds{ + UUID: id, + Name: name, + }, + len(c.X), c.X..., + ) + + if err != nil { + return err + } + for i := range y { + api.AssertIsEqual(c.X[i], y[i]) + } + + return nil +} + +var assignment, circuit customNamedHintCircuit + +func init() { + solver.RegisterNamedHint(identityHint, id) + assignment = customNamedHintCircuit{X: []frontend.Variable{1, 2, 3, 4, 5}} + circuit = customNamedHintCircuit{X: make([]frontend.Variable, len(assignment.X))} +} + +func TestHintWithCustomNamePlonk(t *testing.T) { + plonkTest(t, &circuit, &assignment) +} + +func TestHintWithCustomNameGroth16(t *testing.T) { + groth16Test(t, &circuit, &assignment) +} + +func TestHintWithCustomNameEngine(t *testing.T) { + NewAssert(t).SolvingSucceeded(&circuit, &assignment) +} + +func groth16Test(t *testing.T, circuit, assignment frontend.Circuit) { + run := func(mod *big.Int) func(*testing.T) { + return func(t *testing.T) { + cs, err := frontend.Compile(mod, r1cs.NewBuilder, circuit) + assert.NoError(t, err) + var ( + pk groth16.ProvingKey + vk groth16.VerifyingKey + w, pw witness.Witness + proof groth16.Proof + ) + pk, vk, err = groth16.Setup(cs) + assert.NoError(t, err) + + w, err = frontend.NewWitness(assignment, mod) + assert.NoError(t, err) + + proof, err = groth16.Prove(cs, pk, w) + assert.NoError(t, err) + + pw, err = w.Public() + assert.NoError(t, err) + + assert.NoError(t, groth16.Verify(proof, vk, pw)) + } + } + + for _, id := range fr { + t.Run(id.String(), run(id.ScalarField())) + } +} From 551c1b0c6906cd650a9ca2da94ddb549eb6641d9 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Sun, 30 Apr 2023 12:07:16 -0500 Subject: [PATCH 310/464] feat: compilation side - plonk multicommits --- backend/groth16/bls12-377/prove.go | 4 ++-- backend/groth16/bls12-377/setup.go | 6 +++--- backend/groth16/bls12-381/prove.go | 4 ++-- backend/groth16/bls12-381/setup.go | 6 +++--- backend/groth16/bls24-315/prove.go | 4 ++-- backend/groth16/bls24-315/setup.go | 6 +++--- backend/groth16/bls24-317/prove.go | 4 ++-- backend/groth16/bls24-317/setup.go | 6 +++--- backend/groth16/bn254/prove.go | 4 ++-- backend/groth16/bn254/setup.go | 6 +++--- backend/groth16/bw6-633/prove.go | 4 ++-- backend/groth16/bw6-633/setup.go | 6 +++--- backend/groth16/bw6-761/prove.go | 4 ++-- backend/groth16/bw6-761/setup.go | 6 +++--- constraint/core.go | 4 ++-- constraint/system.go | 2 +- frontend/cs/r1cs/api.go | 2 +- frontend/cs/scs/api.go | 15 +++++++++------ .../zkpschemes/groth16/groth16.prove.go.tmpl | 4 ++-- .../zkpschemes/groth16/groth16.setup.go.tmpl | 6 +++--- 20 files changed, 53 insertions(+), 50 deletions(-) diff --git a/backend/groth16/bls12-377/prove.go b/backend/groth16/bls12-377/prove.go index 32a94e9316..aff06a36dd 100644 --- a/backend/groth16/bls12-377/prove.go +++ b/backend/groth16/bls12-377/prove.go @@ -65,7 +65,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function @@ -204,7 +204,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed _wireValues := wireValues - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) } diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index e9b3a84aba..e3c5201647 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -95,13 +95,13 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbPrivateCommittedWires := 0 - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted } nbPublicWires := r1cs.GetNbPublicVariables() nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.HasCommitment() { // the commitment itself is defined by a hint so the prover considers it private + if r1cs.NbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 nbPrivateWires-- // level it must be considered public } @@ -155,7 +155,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vI, cI := 0, 0 var privateCommitted []int - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() } diff --git a/backend/groth16/bls12-381/prove.go b/backend/groth16/bls12-381/prove.go index fb5417f747..6fe341c0c4 100644 --- a/backend/groth16/bls12-381/prove.go +++ b/backend/groth16/bls12-381/prove.go @@ -65,7 +65,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function @@ -204,7 +204,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed _wireValues := wireValues - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) } diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index 8cc83943c4..03f3e8564d 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -95,13 +95,13 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbPrivateCommittedWires := 0 - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted } nbPublicWires := r1cs.GetNbPublicVariables() nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.HasCommitment() { // the commitment itself is defined by a hint so the prover considers it private + if r1cs.NbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 nbPrivateWires-- // level it must be considered public } @@ -155,7 +155,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vI, cI := 0, 0 var privateCommitted []int - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() } diff --git a/backend/groth16/bls24-315/prove.go b/backend/groth16/bls24-315/prove.go index 0305ab7bd2..c8c6db8d14 100644 --- a/backend/groth16/bls24-315/prove.go +++ b/backend/groth16/bls24-315/prove.go @@ -65,7 +65,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function @@ -204,7 +204,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed _wireValues := wireValues - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) } diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index 7fae66e607..4b69d2e8fc 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -95,13 +95,13 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbPrivateCommittedWires := 0 - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted } nbPublicWires := r1cs.GetNbPublicVariables() nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.HasCommitment() { // the commitment itself is defined by a hint so the prover considers it private + if r1cs.NbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 nbPrivateWires-- // level it must be considered public } @@ -155,7 +155,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vI, cI := 0, 0 var privateCommitted []int - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() } diff --git a/backend/groth16/bls24-317/prove.go b/backend/groth16/bls24-317/prove.go index 5abdea890c..c443421566 100644 --- a/backend/groth16/bls24-317/prove.go +++ b/backend/groth16/bls24-317/prove.go @@ -65,7 +65,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function @@ -204,7 +204,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed _wireValues := wireValues - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) } diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index 17a45d0f4c..58b66e1829 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -95,13 +95,13 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbPrivateCommittedWires := 0 - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted } nbPublicWires := r1cs.GetNbPublicVariables() nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.HasCommitment() { // the commitment itself is defined by a hint so the prover considers it private + if r1cs.NbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 nbPrivateWires-- // level it must be considered public } @@ -155,7 +155,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vI, cI := 0, 0 var privateCommitted []int - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() } diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index c70fc9a242..80be446e44 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -65,7 +65,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function @@ -204,7 +204,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed _wireValues := wireValues - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) } diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index b5cbddfae7..12361b2041 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -95,13 +95,13 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbPrivateCommittedWires := 0 - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted } nbPublicWires := r1cs.GetNbPublicVariables() nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.HasCommitment() { // the commitment itself is defined by a hint so the prover considers it private + if r1cs.NbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 nbPrivateWires-- // level it must be considered public } @@ -155,7 +155,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vI, cI := 0, 0 var privateCommitted []int - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() } diff --git a/backend/groth16/bw6-633/prove.go b/backend/groth16/bw6-633/prove.go index 97303aca05..42600d3aab 100644 --- a/backend/groth16/bw6-633/prove.go +++ b/backend/groth16/bw6-633/prove.go @@ -65,7 +65,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function @@ -204,7 +204,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed _wireValues := wireValues - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) } diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index d778c929a7..dfdde255b9 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -95,13 +95,13 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbPrivateCommittedWires := 0 - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted } nbPublicWires := r1cs.GetNbPublicVariables() nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.HasCommitment() { // the commitment itself is defined by a hint so the prover considers it private + if r1cs.NbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 nbPrivateWires-- // level it must be considered public } @@ -155,7 +155,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vI, cI := 0, 0 var privateCommitted []int - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() } diff --git a/backend/groth16/bw6-761/prove.go b/backend/groth16/bw6-761/prove.go index db26808f87..ac17663e05 100644 --- a/backend/groth16/bw6-761/prove.go +++ b/backend/groth16/bw6-761/prove.go @@ -65,7 +65,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function @@ -204,7 +204,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed _wireValues := wireValues - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) } diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index fe6b4a7a46..1586dfb9db 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -95,13 +95,13 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbPrivateCommittedWires := 0 - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted } nbPublicWires := r1cs.GetNbPublicVariables() nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.HasCommitment() { // the commitment itself is defined by a hint so the prover considers it private + if r1cs.NbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 nbPrivateWires-- // level it must be considered public } @@ -155,7 +155,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vI, cI := 0, 0 var privateCommitted []int - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() } diff --git a/constraint/core.go b/constraint/core.go index 5d7fe476de..5d75b14a41 100644 --- a/constraint/core.go +++ b/constraint/core.go @@ -374,6 +374,6 @@ func (cs *System) GetSparseR1CIterator() SparseR1CIterator { return SparseR1CIterator{cs: cs} } -func (cs *System) HasCommitment() bool { - return len(cs.CommitmentInfo) != 0 +func (cs *System) NbCommitments() int { + return len(cs.CommitmentInfo) } diff --git a/constraint/system.go b/constraint/system.go index 1275d4f641..47c05848e7 100644 --- a/constraint/system.go +++ b/constraint/system.go @@ -48,7 +48,7 @@ type ConstraintSystem interface { AddSolverHint(f solver.Hint, input []LinearExpression, nbOutput int, options ...HintIdOption) (internalVariables []int, err error) AddCommitment(c Commitment) error - HasCommitment() bool // TODO: Erase once multi-commits are implemented in Groth16 + NbCommitments() int // TODO: Erase once multi-commits are implemented in Groth16 AddLog(l LogEntry) diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index e4e5dd509f..9a3241589b 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -677,7 +677,7 @@ func (builder *builder) Compiler() frontend.Compiler { func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error) { - if builder.cs.HasCommitment() { + if builder.cs.NbCommitments() != 0 { return nil, errors.New("multi-commits not available for groth16 - yet") } diff --git a/frontend/cs/scs/api.go b/frontend/cs/scs/api.go index e47c16bc50..34860cfc96 100644 --- a/frontend/cs/scs/api.go +++ b/frontend/cs/scs/api.go @@ -17,11 +17,12 @@ limitations under the License. package scs import ( - "errors" "fmt" + "math/rand" "path/filepath" "reflect" "runtime" + "strconv" "strings" "github.com/consensys/gnark/debug" @@ -572,10 +573,6 @@ func (builder *builder) Compiler() frontend.Compiler { func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error) { - if builder.cs.HasCommitment() { - return nil, errors.New("multi-commits not available for plonk - yet") - } - v = filterConstants(v) // TODO: @Tabaie Settle on a way to represent even constants; conventional hash? committed := make([]int, len(v)) @@ -587,7 +584,13 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error // - v + comm(n) = 0 builder.addPlonkConstraint(sparseR1C{xa: vINeg.VID, qL: vINeg.Coeff, commitment: constraint.COMMITTED}) } - outs, err := builder.NewHint(cs.Bsb22CommitmentComputePlaceholder, 1, v...) + + hintName := constraint.HintIds{ + UUID: solver.HintID(rand.Uint32()), + Name: "bsb22 commitment #" + strconv.Itoa(builder.cs.NbCommitments()), + } + outs, err := builder.NewNamedHint(cs.Bsb22CommitmentComputePlaceholder, &hintName, 1, v...) + if err != nil { return nil, err } diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl index d80a139443..c4dfd7ad0d 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl @@ -48,7 +48,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID,func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function @@ -187,7 +187,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed _wireValues := wireValues - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) } diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl index a7fb6512b8..30da263aa1 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl @@ -77,13 +77,13 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbPrivateCommittedWires := 0 - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted } nbPublicWires := r1cs.GetNbPublicVariables() nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.HasCommitment() { // the commitment itself is defined by a hint so the prover considers it private + if r1cs.NbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 nbPrivateWires-- // level it must be considered public } @@ -137,7 +137,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vI, cI := 0, 0 var privateCommitted []int - if r1cs.HasCommitment() { + if r1cs.NbCommitments() != 0 { privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() } From 1d2385910c2a95617a2a7b7f0bd46703d4ec54b8 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Sun, 30 Apr 2023 12:08:47 -0500 Subject: [PATCH 311/464] fix: HasCommitment -> NbCommitments --- backend/groth16/bls12-377/setup.go | 4 ++-- backend/groth16/bls12-381/setup.go | 4 ++-- backend/groth16/bls24-315/setup.go | 4 ++-- backend/groth16/bls24-317/setup.go | 4 ++-- backend/groth16/bn254/setup.go | 4 ++-- backend/groth16/bw6-633/setup.go | 4 ++-- backend/groth16/bw6-761/setup.go | 4 ++-- .../backend/template/zkpschemes/groth16/groth16.setup.go.tmpl | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index e3c5201647..3ad2ad7015 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -161,7 +161,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { for i := range A { isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.HasCommitment() && i == r1cs.CommitmentInfo[0].CommitmentIndex + isCommitment := r1cs.NbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex isPublic := i < r1cs.GetNbPublicVariables() if isPublic || isCommittedPrivate || isCommitment { @@ -269,7 +269,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - if vk.HasCommitment = r1cs.HasCommitment(); vk.HasCommitment { + if vk.HasCommitment = r1cs.NbCommitments() != 0; vk.HasCommitment { vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() } diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index 03f3e8564d..b2c027de29 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -161,7 +161,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { for i := range A { isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.HasCommitment() && i == r1cs.CommitmentInfo[0].CommitmentIndex + isCommitment := r1cs.NbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex isPublic := i < r1cs.GetNbPublicVariables() if isPublic || isCommittedPrivate || isCommitment { @@ -269,7 +269,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - if vk.HasCommitment = r1cs.HasCommitment(); vk.HasCommitment { + if vk.HasCommitment = r1cs.NbCommitments() != 0; vk.HasCommitment { vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() } diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index 4b69d2e8fc..ee3a8cf144 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -161,7 +161,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { for i := range A { isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.HasCommitment() && i == r1cs.CommitmentInfo[0].CommitmentIndex + isCommitment := r1cs.NbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex isPublic := i < r1cs.GetNbPublicVariables() if isPublic || isCommittedPrivate || isCommitment { @@ -269,7 +269,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - if vk.HasCommitment = r1cs.HasCommitment(); vk.HasCommitment { + if vk.HasCommitment = r1cs.NbCommitments() != 0; vk.HasCommitment { vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() } diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index 58b66e1829..ab3db8daad 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -161,7 +161,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { for i := range A { isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.HasCommitment() && i == r1cs.CommitmentInfo[0].CommitmentIndex + isCommitment := r1cs.NbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex isPublic := i < r1cs.GetNbPublicVariables() if isPublic || isCommittedPrivate || isCommitment { @@ -269,7 +269,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - if vk.HasCommitment = r1cs.HasCommitment(); vk.HasCommitment { + if vk.HasCommitment = r1cs.NbCommitments() != 0; vk.HasCommitment { vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() } diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index 12361b2041..635a07deb0 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -161,7 +161,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { for i := range A { isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.HasCommitment() && i == r1cs.CommitmentInfo[0].CommitmentIndex + isCommitment := r1cs.NbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex isPublic := i < r1cs.GetNbPublicVariables() if isPublic || isCommittedPrivate || isCommitment { @@ -269,7 +269,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - if vk.HasCommitment = r1cs.HasCommitment(); vk.HasCommitment { + if vk.HasCommitment = r1cs.NbCommitments() != 0; vk.HasCommitment { vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() } diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index dfdde255b9..dadc067c71 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -161,7 +161,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { for i := range A { isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.HasCommitment() && i == r1cs.CommitmentInfo[0].CommitmentIndex + isCommitment := r1cs.NbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex isPublic := i < r1cs.GetNbPublicVariables() if isPublic || isCommittedPrivate || isCommitment { @@ -269,7 +269,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - if vk.HasCommitment = r1cs.HasCommitment(); vk.HasCommitment { + if vk.HasCommitment = r1cs.NbCommitments() != 0; vk.HasCommitment { vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() } diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index 1586dfb9db..c0be0bfee0 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -161,7 +161,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { for i := range A { isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.HasCommitment() && i == r1cs.CommitmentInfo[0].CommitmentIndex + isCommitment := r1cs.NbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex isPublic := i < r1cs.GetNbPublicVariables() if isPublic || isCommittedPrivate || isCommitment { @@ -269,7 +269,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - if vk.HasCommitment = r1cs.HasCommitment(); vk.HasCommitment { + if vk.HasCommitment = r1cs.NbCommitments() != 0; vk.HasCommitment { vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() } diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl index 30da263aa1..875011796d 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl @@ -143,7 +143,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { for i := range A { isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.HasCommitment() && i == r1cs.CommitmentInfo[0].CommitmentIndex + isCommitment := r1cs.NbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex isPublic := i < r1cs.GetNbPublicVariables() if isPublic || isCommittedPrivate || isCommitment { @@ -251,7 +251,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - if vk.HasCommitment = r1cs.HasCommitment(); vk.HasCommitment { + if vk.HasCommitment = r1cs.NbCommitments() != 0; vk.HasCommitment { vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() } From a100e2ca5876c5237240f5fb55ce50a127f10524 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Sun, 30 Apr 2023 14:45:53 -0500 Subject: [PATCH 312/464] feat: sr1cs multicommits --- backend/groth16/bls12-377/prove.go | 4 +-- backend/groth16/bls12-377/setup.go | 10 +++--- backend/groth16/bls12-381/prove.go | 4 +-- backend/groth16/bls12-381/setup.go | 10 +++--- backend/groth16/bls24-315/prove.go | 4 +-- backend/groth16/bls24-315/setup.go | 10 +++--- backend/groth16/bls24-317/prove.go | 4 +-- backend/groth16/bls24-317/setup.go | 10 +++--- backend/groth16/bn254/prove.go | 4 +-- backend/groth16/bn254/setup.go | 10 +++--- backend/groth16/bw6-633/prove.go | 4 +-- backend/groth16/bw6-633/setup.go | 10 +++--- backend/groth16/bw6-761/prove.go | 4 +-- backend/groth16/bw6-761/setup.go | 10 +++--- constraint/bn254/solver.go | 6 ++-- constraint/bn254/system.go | 32 +++++++++---------- constraint/core.go | 4 +-- constraint/system.go | 2 +- frontend/cs/r1cs/api.go | 2 +- frontend/cs/scs/api.go | 15 ++++++--- .../zkpschemes/groth16/groth16.prove.go.tmpl | 4 +-- .../zkpschemes/groth16/groth16.setup.go.tmpl | 10 +++--- std/evmprecompiles/bn_test.go | 6 ++-- 23 files changed, 93 insertions(+), 86 deletions(-) diff --git a/backend/groth16/bls12-377/prove.go b/backend/groth16/bls12-377/prove.go index aff06a36dd..df171ff680 100644 --- a/backend/groth16/bls12-377/prove.go +++ b/backend/groth16/bls12-377/prove.go @@ -65,7 +65,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function @@ -204,7 +204,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed _wireValues := wireValues - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) } diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index 3ad2ad7015..4e4c782a54 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -95,13 +95,13 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbPrivateCommittedWires := 0 - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted } nbPublicWires := r1cs.GetNbPublicVariables() nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.NbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private + if r1cs.GetNbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 nbPrivateWires-- // level it must be considered public } @@ -155,13 +155,13 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vI, cI := 0, 0 var privateCommitted []int - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() } for i := range A { isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.NbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex + isCommitment := r1cs.GetNbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex isPublic := i < r1cs.GetNbPublicVariables() if isPublic || isCommittedPrivate || isCommitment { @@ -269,7 +269,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - if vk.HasCommitment = r1cs.NbCommitments() != 0; vk.HasCommitment { + if vk.HasCommitment = r1cs.GetNbCommitments() != 0; vk.HasCommitment { vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() } diff --git a/backend/groth16/bls12-381/prove.go b/backend/groth16/bls12-381/prove.go index 6fe341c0c4..ae0919e89a 100644 --- a/backend/groth16/bls12-381/prove.go +++ b/backend/groth16/bls12-381/prove.go @@ -65,7 +65,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function @@ -204,7 +204,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed _wireValues := wireValues - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) } diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index b2c027de29..3e870a0084 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -95,13 +95,13 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbPrivateCommittedWires := 0 - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted } nbPublicWires := r1cs.GetNbPublicVariables() nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.NbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private + if r1cs.GetNbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 nbPrivateWires-- // level it must be considered public } @@ -155,13 +155,13 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vI, cI := 0, 0 var privateCommitted []int - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() } for i := range A { isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.NbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex + isCommitment := r1cs.GetNbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex isPublic := i < r1cs.GetNbPublicVariables() if isPublic || isCommittedPrivate || isCommitment { @@ -269,7 +269,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - if vk.HasCommitment = r1cs.NbCommitments() != 0; vk.HasCommitment { + if vk.HasCommitment = r1cs.GetNbCommitments() != 0; vk.HasCommitment { vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() } diff --git a/backend/groth16/bls24-315/prove.go b/backend/groth16/bls24-315/prove.go index c8c6db8d14..210da74522 100644 --- a/backend/groth16/bls24-315/prove.go +++ b/backend/groth16/bls24-315/prove.go @@ -65,7 +65,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function @@ -204,7 +204,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed _wireValues := wireValues - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) } diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index ee3a8cf144..99b87fdc15 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -95,13 +95,13 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbPrivateCommittedWires := 0 - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted } nbPublicWires := r1cs.GetNbPublicVariables() nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.NbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private + if r1cs.GetNbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 nbPrivateWires-- // level it must be considered public } @@ -155,13 +155,13 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vI, cI := 0, 0 var privateCommitted []int - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() } for i := range A { isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.NbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex + isCommitment := r1cs.GetNbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex isPublic := i < r1cs.GetNbPublicVariables() if isPublic || isCommittedPrivate || isCommitment { @@ -269,7 +269,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - if vk.HasCommitment = r1cs.NbCommitments() != 0; vk.HasCommitment { + if vk.HasCommitment = r1cs.GetNbCommitments() != 0; vk.HasCommitment { vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() } diff --git a/backend/groth16/bls24-317/prove.go b/backend/groth16/bls24-317/prove.go index c443421566..44dda05c90 100644 --- a/backend/groth16/bls24-317/prove.go +++ b/backend/groth16/bls24-317/prove.go @@ -65,7 +65,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function @@ -204,7 +204,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed _wireValues := wireValues - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) } diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index ab3db8daad..77870e62bb 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -95,13 +95,13 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbPrivateCommittedWires := 0 - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted } nbPublicWires := r1cs.GetNbPublicVariables() nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.NbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private + if r1cs.GetNbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 nbPrivateWires-- // level it must be considered public } @@ -155,13 +155,13 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vI, cI := 0, 0 var privateCommitted []int - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() } for i := range A { isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.NbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex + isCommitment := r1cs.GetNbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex isPublic := i < r1cs.GetNbPublicVariables() if isPublic || isCommittedPrivate || isCommitment { @@ -269,7 +269,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - if vk.HasCommitment = r1cs.NbCommitments() != 0; vk.HasCommitment { + if vk.HasCommitment = r1cs.GetNbCommitments() != 0; vk.HasCommitment { vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() } diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index 80be446e44..4dc62f6f3f 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -65,7 +65,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function @@ -204,7 +204,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed _wireValues := wireValues - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) } diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index 635a07deb0..e2b6800a98 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -95,13 +95,13 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbPrivateCommittedWires := 0 - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted } nbPublicWires := r1cs.GetNbPublicVariables() nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.NbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private + if r1cs.GetNbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 nbPrivateWires-- // level it must be considered public } @@ -155,13 +155,13 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vI, cI := 0, 0 var privateCommitted []int - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() } for i := range A { isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.NbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex + isCommitment := r1cs.GetNbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex isPublic := i < r1cs.GetNbPublicVariables() if isPublic || isCommittedPrivate || isCommitment { @@ -269,7 +269,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - if vk.HasCommitment = r1cs.NbCommitments() != 0; vk.HasCommitment { + if vk.HasCommitment = r1cs.GetNbCommitments() != 0; vk.HasCommitment { vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() } diff --git a/backend/groth16/bw6-633/prove.go b/backend/groth16/bw6-633/prove.go index 42600d3aab..971872aee4 100644 --- a/backend/groth16/bw6-633/prove.go +++ b/backend/groth16/bw6-633/prove.go @@ -65,7 +65,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function @@ -204,7 +204,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed _wireValues := wireValues - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) } diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index dadc067c71..5b8ba4e712 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -95,13 +95,13 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbPrivateCommittedWires := 0 - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted } nbPublicWires := r1cs.GetNbPublicVariables() nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.NbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private + if r1cs.GetNbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 nbPrivateWires-- // level it must be considered public } @@ -155,13 +155,13 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vI, cI := 0, 0 var privateCommitted []int - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() } for i := range A { isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.NbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex + isCommitment := r1cs.GetNbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex isPublic := i < r1cs.GetNbPublicVariables() if isPublic || isCommittedPrivate || isCommitment { @@ -269,7 +269,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - if vk.HasCommitment = r1cs.NbCommitments() != 0; vk.HasCommitment { + if vk.HasCommitment = r1cs.GetNbCommitments() != 0; vk.HasCommitment { vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() } diff --git a/backend/groth16/bw6-761/prove.go b/backend/groth16/bw6-761/prove.go index ac17663e05..ef5a998a7e 100644 --- a/backend/groth16/bw6-761/prove.go +++ b/backend/groth16/bw6-761/prove.go @@ -65,7 +65,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function @@ -204,7 +204,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed _wireValues := wireValues - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) } diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index c0be0bfee0..26ec2f0d56 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -95,13 +95,13 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbPrivateCommittedWires := 0 - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted } nbPublicWires := r1cs.GetNbPublicVariables() nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.NbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private + if r1cs.GetNbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 nbPrivateWires-- // level it must be considered public } @@ -155,13 +155,13 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vI, cI := 0, 0 var privateCommitted []int - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() } for i := range A { isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.NbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex + isCommitment := r1cs.GetNbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex isPublic := i < r1cs.GetNbPublicVariables() if isPublic || isCommittedPrivate || isCommitment { @@ -269,7 +269,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - if vk.HasCommitment = r1cs.NbCommitments() != 0; vk.HasCommitment { + if vk.HasCommitment = r1cs.GetNbCommitments() != 0; vk.HasCommitment { vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() } diff --git a/constraint/bn254/solver.go b/constraint/bn254/solver.go index 6e8b27587f..e34b4e2c97 100644 --- a/constraint/bn254/solver.go +++ b/constraint/bn254/solver.go @@ -37,7 +37,7 @@ import ( // solver represent the state of the solver during a call to System.Solve(...) type solver struct { - *system + *System // values and solved are index by the wire (variable) id values []fr.Element @@ -55,7 +55,7 @@ type solver struct { q *big.Int } -func newSolver(cs *system, witness fr.Vector, opts ...csolver.Option) (*solver, error) { +func newSolver(cs *System, witness fr.Vector, opts ...csolver.Option) (*solver, error) { // parse options opt, err := csolver.NewConfig(opts...) if err != nil { @@ -91,7 +91,7 @@ func newSolver(cs *system, witness fr.Vector, opts ...csolver.Option) (*solver, } s := solver{ - system: cs, + System: cs, values: make([]fr.Element, nbWires), solved: make([]bool, nbWires), mHintsFunctions: hintFunctions, diff --git a/constraint/bn254/system.go b/constraint/bn254/system.go index 7e861e9b6d..f2be78a8e3 100644 --- a/constraint/bn254/system.go +++ b/constraint/bn254/system.go @@ -33,11 +33,11 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr" ) -type R1CS = system -type SparseR1CS = system +type R1CS = System +type SparseR1CS = System -// system is a curved-typed constraint.System with a concrete coefficient table (fr.Element) -type system struct { +// System is a curved-typed constraint.System with a concrete coefficient table (fr.Element) +type System struct { constraint.System CoeffTable field @@ -51,8 +51,8 @@ func NewSparseR1CS(capacity int) *SparseR1CS { return newSystem(capacity, constraint.SystemSparseR1CS) } -func newSystem(capacity int, t constraint.SystemType) *system { - return &system{ +func newSystem(capacity int, t constraint.SystemType) *System { + return &System{ System: constraint.NewSystem(fr.Modulus(), capacity, t), CoeffTable: newCoeffTable(capacity / 10), } @@ -61,7 +61,7 @@ func newSystem(capacity int, t constraint.SystemType) *system { // Solve solves the constraint system with provided witness. // If it's a R1CS returns R1CSSolution // If it's a SparseR1CS returns SparseR1CSSolution -func (cs *system) Solve(witness witness.Witness, opts ...csolver.Option) (any, error) { +func (cs *System) Solve(witness witness.Witness, opts ...csolver.Option) (any, error) { log := logger.Logger().With().Int("nbConstraints", cs.GetNbConstraints()).Logger() start := time.Now() @@ -108,13 +108,13 @@ func (cs *system) Solve(witness witness.Witness, opts ...csolver.Option) (any, e // IsSolved // Deprecated: use _, err := Solve(...) instead -func (cs *system) IsSolved(witness witness.Witness, opts ...csolver.Option) error { +func (cs *System) IsSolved(witness witness.Witness, opts ...csolver.Option) error { _, err := cs.Solve(witness, opts...) return err } // GetR1Cs return the list of R1C -func (cs *system) GetR1Cs() []constraint.R1C { +func (cs *System) GetR1Cs() []constraint.R1C { toReturn := make([]constraint.R1C, 0, cs.GetNbConstraints()) for _, inst := range cs.Instructions { @@ -131,17 +131,17 @@ func (cs *system) GetR1Cs() []constraint.R1C { } // GetNbCoefficients return the number of unique coefficients needed in the R1CS -func (cs *system) GetNbCoefficients() int { +func (cs *System) GetNbCoefficients() int { return len(cs.Coefficients) } // CurveID returns curve ID as defined in gnark-crypto -func (cs *system) CurveID() ecc.ID { +func (cs *System) CurveID() ecc.ID { return ecc.BN254 } // WriteTo encodes R1CS into provided io.Writer using cbor -func (cs *system) WriteTo(w io.Writer) (int64, error) { +func (cs *System) WriteTo(w io.Writer) (int64, error) { _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written ts := getTagSet() enc, err := cbor.CoreDetEncOptions().EncModeWithTags(ts) @@ -156,7 +156,7 @@ func (cs *system) WriteTo(w io.Writer) (int64, error) { } // ReadFrom attempts to decode R1CS from io.Reader using cbor -func (cs *system) ReadFrom(r io.Reader) (int64, error) { +func (cs *System) ReadFrom(r io.Reader) (int64, error) { ts := getTagSet() dm, err := cbor.DecOptions{ MaxArrayElements: 134217728, @@ -182,13 +182,13 @@ func (cs *system) ReadFrom(r io.Reader) (int64, error) { return int64(decoder.NumBytesRead()), nil } -func (cs *system) GetCoefficient(i int) (r constraint.Element) { +func (cs *System) GetCoefficient(i int) (r constraint.Element) { copy(r[:], cs.Coefficients[i][:]) return } // GetSparseR1Cs return the list of SparseR1C -func (cs *system) GetSparseR1Cs() []constraint.SparseR1C { +func (cs *System) GetSparseR1Cs() []constraint.SparseR1C { toReturn := make([]constraint.SparseR1C, 0, cs.GetNbConstraints()) @@ -209,7 +209,7 @@ func (cs *system) GetSparseR1Cs() []constraint.SparseR1C { // evaluateLROSmallDomain extracts the solver l, r, o, and returns it in lagrange form. // solver = [ public | secret | internal ] // TODO @gbotrel refactor; this seems to be a small util function for plonk -func evaluateLROSmallDomain(cs *system, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { +func evaluateLROSmallDomain(cs *System, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { //s := int(pk.Domain[0].Cardinality) s := cs.GetNbConstraints() + len(cs.Public) // len(spr.Public) is for the placeholder constraints diff --git a/constraint/core.go b/constraint/core.go index 5d75b14a41..99343ec85f 100644 --- a/constraint/core.go +++ b/constraint/core.go @@ -210,13 +210,13 @@ func (system *System) AddSolverHint(f solver.Hint, input []LinearExpression, nbO return nil, fmt.Errorf("hint function must return at least one output") } - // register the hint as dependency ID := HintIds{solver.GetHintID(f), solver.GetHintName(f)} for i := range options { options[i](&ID) } + // register the hint as dependency if id, ok := system.MHintsDependencies[ID.UUID]; ok { // hint already registered, let's ensure string id matches if id != ID.Name { @@ -374,6 +374,6 @@ func (cs *System) GetSparseR1CIterator() SparseR1CIterator { return SparseR1CIterator{cs: cs} } -func (cs *System) NbCommitments() int { +func (cs *System) GetNbCommitments() int { return len(cs.CommitmentInfo) } diff --git a/constraint/system.go b/constraint/system.go index 47c05848e7..76f384291b 100644 --- a/constraint/system.go +++ b/constraint/system.go @@ -48,7 +48,7 @@ type ConstraintSystem interface { AddSolverHint(f solver.Hint, input []LinearExpression, nbOutput int, options ...HintIdOption) (internalVariables []int, err error) AddCommitment(c Commitment) error - NbCommitments() int // TODO: Erase once multi-commits are implemented in Groth16 + GetNbCommitments() int // TODO: Erase once multi-commits are implemented in Groth16 AddLog(l LogEntry) diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index 9a3241589b..9e71789321 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -677,7 +677,7 @@ func (builder *builder) Compiler() frontend.Compiler { func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error) { - if builder.cs.NbCommitments() != 0 { + if builder.cs.GetNbCommitments() != 0 { return nil, errors.New("multi-commits not available for groth16 - yet") } diff --git a/frontend/cs/scs/api.go b/frontend/cs/scs/api.go index 34860cfc96..aeae83f5a8 100644 --- a/frontend/cs/scs/api.go +++ b/frontend/cs/scs/api.go @@ -18,7 +18,7 @@ package scs import ( "fmt" - "math/rand" + "hash/fnv" "path/filepath" "reflect" "runtime" @@ -586,9 +586,16 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error } hintName := constraint.HintIds{ - UUID: solver.HintID(rand.Uint32()), - Name: "bsb22 commitment #" + strconv.Itoa(builder.cs.NbCommitments()), + Name: "bsb22 commitment #" + strconv.Itoa(builder.cs.GetNbCommitments()), } + + // mimic solver.GetHintID + hf := fnv.New32a() + if _, err := hf.Write([]byte(hintName.Name)); err != nil { + return nil, err + } + hintName.UUID = solver.HintID(hf.Sum32()) + outs, err := builder.NewNamedHint(cs.Bsb22CommitmentComputePlaceholder, &hintName, 1, v...) if err != nil { @@ -600,7 +607,7 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error builder.addPlonkConstraint(sparseR1C{xa: commitmentVar.VID, qL: commitmentVar.Coeff, commitment: constraint.COMMITMENT}) // value will be injected later return outs[0], builder.cs.AddCommitment(constraint.Commitment{ - HintID: solver.GetHintID(cs.Bsb22CommitmentComputePlaceholder), + HintID: hintName.UUID, CommitmentIndex: commitmentConstraintIndex, Committed: committed, }) diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl index c4dfd7ad0d..a9781466a0 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl @@ -48,7 +48,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID,func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function @@ -187,7 +187,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed _wireValues := wireValues - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) } diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl index 875011796d..e83401e5dd 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl @@ -77,13 +77,13 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbPrivateCommittedWires := 0 - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted } nbPublicWires := r1cs.GetNbPublicVariables() nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.NbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private + if r1cs.GetNbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 nbPrivateWires-- // level it must be considered public } @@ -137,13 +137,13 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vI, cI := 0, 0 var privateCommitted []int - if r1cs.NbCommitments() != 0 { + if r1cs.GetNbCommitments() != 0 { privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() } for i := range A { isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.NbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex + isCommitment := r1cs.GetNbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex isPublic := i < r1cs.GetNbPublicVariables() if isPublic || isCommittedPrivate || isCommitment { @@ -251,7 +251,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - if vk.HasCommitment = r1cs.NbCommitments() != 0; vk.HasCommitment { + if vk.HasCommitment = r1cs.GetNbCommitments() != 0; vk.HasCommitment { vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() } diff --git a/std/evmprecompiles/bn_test.go b/std/evmprecompiles/bn_test.go index 748155624f..f5efe1baa3 100644 --- a/std/evmprecompiles/bn_test.go +++ b/std/evmprecompiles/bn_test.go @@ -31,7 +31,7 @@ func (c *ecaddCircuit) Define(api frontend.API) error { return nil } -func testRoutineECAdd(t *testing.T) (circ, wit frontend.Circuit) { +func testRoutineECAdd() (circ, wit frontend.Circuit) { _, _, G, _ := bn254.Generators() var u, v fr.Element u.SetRandom() @@ -61,14 +61,14 @@ func testRoutineECAdd(t *testing.T) (circ, wit frontend.Circuit) { func TestECAddCircuitShort(t *testing.T) { assert := test.NewAssert(t) - circuit, witness := testRoutineECAdd(t) + circuit, witness := testRoutineECAdd() err := test.IsSolved(circuit, witness, ecc.BN254.ScalarField()) assert.NoError(err) } func TestECAddCircuitFull(t *testing.T) { assert := test.NewAssert(t) - circuit, witness := testRoutineECAdd(t) + circuit, witness := testRoutineECAdd() assert.ProverSucceeded(circuit, witness, test.NoFuzzing(), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK), test.WithCurves(ecc.BN254), From 70ffa02faf8e38bcac59e58a8d78cb6dfbe56d96 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Sun, 30 Apr 2023 15:42:07 -0500 Subject: [PATCH 313/464] build: remove debugging modifications --- constraint/bn254/solver.go | 6 +++--- constraint/bn254/system.go | 32 ++++++++++++++++---------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/constraint/bn254/solver.go b/constraint/bn254/solver.go index e34b4e2c97..6e8b27587f 100644 --- a/constraint/bn254/solver.go +++ b/constraint/bn254/solver.go @@ -37,7 +37,7 @@ import ( // solver represent the state of the solver during a call to System.Solve(...) type solver struct { - *System + *system // values and solved are index by the wire (variable) id values []fr.Element @@ -55,7 +55,7 @@ type solver struct { q *big.Int } -func newSolver(cs *System, witness fr.Vector, opts ...csolver.Option) (*solver, error) { +func newSolver(cs *system, witness fr.Vector, opts ...csolver.Option) (*solver, error) { // parse options opt, err := csolver.NewConfig(opts...) if err != nil { @@ -91,7 +91,7 @@ func newSolver(cs *System, witness fr.Vector, opts ...csolver.Option) (*solver, } s := solver{ - System: cs, + system: cs, values: make([]fr.Element, nbWires), solved: make([]bool, nbWires), mHintsFunctions: hintFunctions, diff --git a/constraint/bn254/system.go b/constraint/bn254/system.go index f2be78a8e3..7e861e9b6d 100644 --- a/constraint/bn254/system.go +++ b/constraint/bn254/system.go @@ -33,11 +33,11 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr" ) -type R1CS = System -type SparseR1CS = System +type R1CS = system +type SparseR1CS = system -// System is a curved-typed constraint.System with a concrete coefficient table (fr.Element) -type System struct { +// system is a curved-typed constraint.System with a concrete coefficient table (fr.Element) +type system struct { constraint.System CoeffTable field @@ -51,8 +51,8 @@ func NewSparseR1CS(capacity int) *SparseR1CS { return newSystem(capacity, constraint.SystemSparseR1CS) } -func newSystem(capacity int, t constraint.SystemType) *System { - return &System{ +func newSystem(capacity int, t constraint.SystemType) *system { + return &system{ System: constraint.NewSystem(fr.Modulus(), capacity, t), CoeffTable: newCoeffTable(capacity / 10), } @@ -61,7 +61,7 @@ func newSystem(capacity int, t constraint.SystemType) *System { // Solve solves the constraint system with provided witness. // If it's a R1CS returns R1CSSolution // If it's a SparseR1CS returns SparseR1CSSolution -func (cs *System) Solve(witness witness.Witness, opts ...csolver.Option) (any, error) { +func (cs *system) Solve(witness witness.Witness, opts ...csolver.Option) (any, error) { log := logger.Logger().With().Int("nbConstraints", cs.GetNbConstraints()).Logger() start := time.Now() @@ -108,13 +108,13 @@ func (cs *System) Solve(witness witness.Witness, opts ...csolver.Option) (any, e // IsSolved // Deprecated: use _, err := Solve(...) instead -func (cs *System) IsSolved(witness witness.Witness, opts ...csolver.Option) error { +func (cs *system) IsSolved(witness witness.Witness, opts ...csolver.Option) error { _, err := cs.Solve(witness, opts...) return err } // GetR1Cs return the list of R1C -func (cs *System) GetR1Cs() []constraint.R1C { +func (cs *system) GetR1Cs() []constraint.R1C { toReturn := make([]constraint.R1C, 0, cs.GetNbConstraints()) for _, inst := range cs.Instructions { @@ -131,17 +131,17 @@ func (cs *System) GetR1Cs() []constraint.R1C { } // GetNbCoefficients return the number of unique coefficients needed in the R1CS -func (cs *System) GetNbCoefficients() int { +func (cs *system) GetNbCoefficients() int { return len(cs.Coefficients) } // CurveID returns curve ID as defined in gnark-crypto -func (cs *System) CurveID() ecc.ID { +func (cs *system) CurveID() ecc.ID { return ecc.BN254 } // WriteTo encodes R1CS into provided io.Writer using cbor -func (cs *System) WriteTo(w io.Writer) (int64, error) { +func (cs *system) WriteTo(w io.Writer) (int64, error) { _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written ts := getTagSet() enc, err := cbor.CoreDetEncOptions().EncModeWithTags(ts) @@ -156,7 +156,7 @@ func (cs *System) WriteTo(w io.Writer) (int64, error) { } // ReadFrom attempts to decode R1CS from io.Reader using cbor -func (cs *System) ReadFrom(r io.Reader) (int64, error) { +func (cs *system) ReadFrom(r io.Reader) (int64, error) { ts := getTagSet() dm, err := cbor.DecOptions{ MaxArrayElements: 134217728, @@ -182,13 +182,13 @@ func (cs *System) ReadFrom(r io.Reader) (int64, error) { return int64(decoder.NumBytesRead()), nil } -func (cs *System) GetCoefficient(i int) (r constraint.Element) { +func (cs *system) GetCoefficient(i int) (r constraint.Element) { copy(r[:], cs.Coefficients[i][:]) return } // GetSparseR1Cs return the list of SparseR1C -func (cs *System) GetSparseR1Cs() []constraint.SparseR1C { +func (cs *system) GetSparseR1Cs() []constraint.SparseR1C { toReturn := make([]constraint.SparseR1C, 0, cs.GetNbConstraints()) @@ -209,7 +209,7 @@ func (cs *System) GetSparseR1Cs() []constraint.SparseR1C { // evaluateLROSmallDomain extracts the solver l, r, o, and returns it in lagrange form. // solver = [ public | secret | internal ] // TODO @gbotrel refactor; this seems to be a small util function for plonk -func evaluateLROSmallDomain(cs *System, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { +func evaluateLROSmallDomain(cs *system, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { //s := int(pk.Domain[0].Cardinality) s := cs.GetNbConstraints() + len(cs.Public) // len(spr.Public) is for the placeholder constraints From 3d25fbf89572d3fd21a9424f5482bfb518a31279 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Sun, 30 Apr 2023 17:26:12 -0500 Subject: [PATCH 314/464] feat: bn254 plonk multicommit backend --- backend/plonk/bn254/prove.go | 111 ++++++++++++++++++---------------- backend/plonk/bn254/setup.go | 41 ++++++++----- backend/plonk/bn254/verify.go | 21 ++++--- 3 files changed, 94 insertions(+), 79 deletions(-) diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index f14ee25592..7d485296f7 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -55,7 +55,7 @@ type Proof struct { H [3]kzg.Digest // PI2, the BSB22 commitment - PI2 kzg.Digest + PI2 []kzg.Digest // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2, qCPrime BatchedProof kzg.BatchOpeningProof @@ -83,47 +83,38 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // result proof := &Proof{} lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} - var ( - wpi2iop *iop.Polynomial // canonical - commitmentVal fr.Element // TODO @Tabaie get rid of this - ) - if len(spr.CommitmentInfo) != 0 { - opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[0].HintID, func(_ *big.Int, ins, outs []*big.Int) error { + var commitmentVal fr.Element // TODO @Tabaie get rid of this + wpi2iop := make([]*iop.Polynomial, len(spr.CommitmentInfo)) + for i := range spr.CommitmentInfo { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[i].HintID, func(_ *big.Int, ins, outs []*big.Int) error { pi2 := make([]fr.Element, pk.Domain[0].Cardinality) offset := spr.GetNbPublicVariables() for i := range ins { - pi2[offset+spr.CommitmentInfo[0].Committed[i]].SetBigInt(ins[i]) + pi2[offset+spr.CommitmentInfo[i].Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - if _, err = pi2[offset+spr.CommitmentInfo[0].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + if _, err = pi2[offset+spr.CommitmentInfo[i].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding return err } pi2iop := iop.NewPolynomial(&pi2, lagReg) - wpi2iop = pi2iop.ShallowClone() - wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() - if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Kzg); err != nil { + wpi2iop[i] = pi2iop.ShallowClone() + wpi2iop[i].ToCanonical(&pk.Domain[0]).ToRegular() + if proof.PI2[i], err = kzg.Commit(wpi2iop[i].Coefficients(), pk.Kzg); err != nil { return err } - if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + if hashRes, err = fr.Hash(proof.PI2[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } commitmentVal = hashRes[0] // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses commitmentVal.BigInt(outs[0]) return nil })) - } else { - // TODO Leaving pi2 in for testing. In the future, bypass when no commitment present - pi2 := make([]fr.Element, pk.Domain[0].Cardinality) - - pi2iop := iop.NewPolynomial(&pi2, lagReg) - wpi2iop = pi2iop.ShallowClone() - // wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() } // query l, r, o in Lagrange basis, not blinded @@ -132,12 +123,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } // TODO @gbotrel deal with that conversion lazily - var lcpi2iop *iop.Polynomial - if len(spr.CommitmentInfo) != 0 { - lcpi2iop = wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form - } else { - coeffs := make([]fr.Element, pk.Domain[1].Cardinality) - lcpi2iop = iop.NewPolynomial(&coeffs, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.Regular}) + var lcpi2iop []*iop.Polynomial + for i := range wpi2iop { + lcpi2iop[i] = wpi2iop[i].Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form } solution := _solution.(*cs.SparseR1CSSolution) evaluationLDomainSmall := []fr.Element(solution.L) @@ -285,7 +273,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts }() // Full capture using latest gnark crypto... - fic := func(fql, fqr, fqm, fqo, fqk, fqCPrime, l, r, o, pi2 fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary + fic := func(fql, fqr, fqm, fqo, fqk, l, r, o fr.Element, pi2QcPrime []fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary var ic, tmp fr.Element @@ -296,8 +284,12 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ic.Add(&ic, &tmp) tmp.Mul(&fqo, &o) ic.Add(&ic, &tmp).Add(&ic, &fqk) - tmp.Mul(&fqCPrime, &pi2) - ic.Add(&ic, &tmp) + + nbComms := len(spr.CommitmentInfo) + for i := range spr.CommitmentInfo { + tmp.Mul(&pi2QcPrime[i], &pi2QcPrime[i+nbComms]) + ic.Add(&ic, &tmp) + } return ic } @@ -330,13 +322,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return one } - // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15 , 16 - // l , r , o, id, s1, s2, s3, z, zs, PI2, ql, qr, qm, qo, qk, qCPrime, lone + // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm + // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, PI2 , qCPrime fm := func(x ...fr.Element) fr.Element { - a := fic(x[10], x[11], x[12], x[13], x[14], x[15], x[0], x[1], x[2], x[9]) + a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2], x[15:]) b := fo(x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8]) - c := fone(x[7], x[16]) + c := fone(x[7], x[14]) c.Mul(&c, &alpha).Add(&c, &b).Mul(&c, &alpha).Add(&c, &a) @@ -354,7 +346,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // wait for l, r o lagrange coset conversion wgLRO.Wait() - systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, + toEval := []*iop.Polynomial{ bwliop, bwriop, bwoiop, @@ -364,15 +356,16 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pk.lcS3, bwziop, bwsziop, - lcpi2iop, pk.lcQl, pk.lcQr, pk.lcQm, pk.lcQo, lcqk, - pk.lcQcp, pk.lLoneIOP, - ) + } + toEval = append(toEval, lcpi2iop...) + toEval = append(toEval, pk.lcQcp...) + systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, toEval...) if err != nil { return nil, err } @@ -404,10 +397,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // compute evaluations of (blinded version of) l, r, o, z, qCPrime at zeta - var blzeta, brzeta, bozeta, qcpzeta fr.Element + var blzeta, brzeta, bozeta fr.Element + qcpzeta := make([]fr.Element, len(spr.CommitmentInfo)) var wgEvals sync.WaitGroup - wgEvals.Add(4) + wgEvals.Add(3) evalAtZeta := func(poly *iop.Polynomial, res *fr.Element) { poly.ToCanonical(&pk.Domain[1]).ToRegular() *res = poly.Evaluate(zeta) @@ -416,10 +410,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts go evalAtZeta(bwliop, &blzeta) go evalAtZeta(bwriop, &brzeta) go evalAtZeta(bwoiop, &bozeta) - go func() { - qcpzeta = pk.trace.Qcp.Evaluate(zeta) - wgEvals.Done() - }() + + evalQcpAtZeta := func(begin, end int) { + for i := begin; i < end; i++ { + qcpzeta[i] = pk.trace.Qcp[i].Evaluate(zeta) + } + } + utils.Parallelize(len(spr.CommitmentInfo), evalQcpAtZeta) var zetaShifted fr.Element zetaShifted.Mul(&zeta, &pk.Vk.Generator) @@ -490,7 +487,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bzuzeta, qcpzeta, bwziop.Coefficients()[:bwziop.BlindedSize()], - wpi2iop.Coefficients(), + coefficients(wpi2iop), pk, ) @@ -506,7 +503,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // Batch open the first list of polynomials proof.BatchedProof, err = kzg.BatchOpenSinglePoint( - [][]fr.Element{ + append(coefficients(pk.trace.Qcp), foldedH, linearizedPolynomialCanonical, bwliop.Coefficients()[:bwliop.BlindedSize()], @@ -514,9 +511,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.Coefficients()[:bwoiop.BlindedSize()], pk.trace.S1.Coefficients(), pk.trace.S2.Coefficients(), - pk.trace.Qcp.Coefficients(), - }, - []kzg.Digest{ + ), + append(pk.Vk.Qcp, foldedHDigest, linearizedPolynomialDigest, proof.LRO[0], @@ -524,8 +520,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.LRO[2], pk.Vk.S[0], pk.Vk.S[1], - pk.Vk.Qcp, - }, + ), zeta, hFunc, pk.Kzg, @@ -541,6 +536,14 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } +func coefficients(p []*iop.Polynomial) [][]fr.Element { + res := make([][]fr.Element, len(p)) + for i, pI := range p { + res[i] = pI.Coefficients() + } + return res +} + // fills proof.LRO with kzg commits of bcl, bcr and bco func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, kzgPk kzg.ProvingKey) error { n := runtime.NumCPU() @@ -605,7 +608,7 @@ func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, kzgPk kzg.ProvingKe // α²*L₁(ζ)*Z(X) // + α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*id1(ζ)+γ)*(r(ζ)+β*id2(ζ)+γ)*(o(ζ)+β*id3(ζ)+γ)) // + l(ζ)*Ql(X) + l(ζ)r(ζ)*Qm(X) + r(ζ)*Qr(X) + o(ζ)*Qo(X) + Qk(X) -func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu, qcpZeta fr.Element, blindedZCanonical []fr.Element, pi2Canonical []fr.Element, pk *ProvingKey) []fr.Element { +func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu fr.Element, qcpZeta, blindedZCanonical []fr.Element, pi2Canonical [][]fr.Element, pk *ProvingKey) []fr.Element { // first part: individual constraints var rl fr.Element @@ -688,8 +691,10 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, t0.Mul(&cqo[i], &oZeta).Add(&t0, &cqk[i]) t.Add(&t, &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) - t0.Mul(&pi2Canonical[i], &qcpZeta) - t.Add(&t, &t0) + for j := range qcpZeta { + t0.Mul(&pi2Canonical[j][i], &qcpZeta[j]) + t.Add(&t, &t0) + } } t0.Mul(&blindedZCanonical[i], &lagrangeZeta) diff --git a/backend/plonk/bn254/setup.go b/backend/plonk/bn254/setup.go index 5d68c801f2..116c4f664a 100644 --- a/backend/plonk/bn254/setup.go +++ b/backend/plonk/bn254/setup.go @@ -35,7 +35,8 @@ type Trace struct { // completed by the prover. At those indices i (so from 0 to nb_public_variables), LQl[i]=-1 // so the first nb_public_variables constraints look like this: // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. - Ql, Qr, Qm, Qo, Qk, Qcp *iop.Polynomial + Ql, Qr, Qm, Qo, Qk *iop.Polynomial + Qcp []*iop.Polynomial // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. // The set of interpolation is of size N, so to represent the permutation S we let S acts on the @@ -72,7 +73,8 @@ type VerifyingKey struct { // Commitments to ql, qr, qm, qo, qcp prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk, Qcp kzg.Digest + Ql, Qr, Qm, Qo, Qk kzg.Digest + Qcp []kzg.Digest CommitmentConstraintIndexes []uint64 } @@ -100,7 +102,8 @@ type ProvingKey struct { Vk *VerifyingKey // qr,ql,qm,qo,qcp in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo, Qcp once. - lcQl, lcQr, lcQm, lcQo, lcQcp *iop.Polynomial + lcQl, lcQr, lcQm, lcQo *iop.Polynomial + lcQcp []*iop.Polynomial // LQk qk in Lagrange form -> to be completed by the prover. After being completed, lQk *iop.Polynomial @@ -173,7 +176,10 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro // computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset // basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. func (pk *ProvingKey) computeLagrangeCosetPolys() { - pk.lcQcp = pk.trace.Qcp.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQcp = make([]*iop.Polynomial, len(pk.trace.Qcp)) + for i, qcpI := range pk.trace.Qcp { + pk.lcQcp[i] = qcpI.Clone().ToLagrangeCoset(&pk.Domain[1]) + } pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) @@ -226,7 +232,7 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qm := make([]fr.Element, size) qo := make([]fr.Element, size) qk := make([]fr.Element, size) - qcp := make([]fr.Element, size) + qcp := make([][]fr.Element, len(spr.CommitmentInfo)) for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent ql[i].SetOne().Neg(&ql[i]) @@ -248,12 +254,6 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { j++ } - if len(spr.CommitmentInfo) != 0 { - for _, committed := range spr.CommitmentInfo[0].Committed { - qcp[offset+committed].SetOne() - } - } - lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} pt.Ql = iop.NewPolynomial(&ql, lagReg) @@ -261,8 +261,14 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { pt.Qm = iop.NewPolynomial(&qm, lagReg) pt.Qo = iop.NewPolynomial(&qo, lagReg) pt.Qk = iop.NewPolynomial(&qk, lagReg) - pt.Qcp = iop.NewPolynomial(&qcp, lagReg) + pt.Qcp = make([]*iop.Polynomial, len(qcp)) + for i := range spr.CommitmentInfo { + for _, committed := range spr.CommitmentInfo[i].Committed { + qcp[i][offset+committed].SetOne() + } + pt.Qcp[i] = iop.NewPolynomial(&qcp[i], lagReg) + } } // commitTrace commits to every polynomials in the trace, and put @@ -274,12 +280,17 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { trace.Qm.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qo.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qk.ToCanonical(&pk.Domain[0]).ToRegular() // -> qk is not complete - trace.Qcp.ToCanonical(&pk.Domain[0]).ToRegular() trace.S1.ToCanonical(&pk.Domain[0]).ToRegular() trace.S2.ToCanonical(&pk.Domain[0]).ToRegular() trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() var err error + for i := range trace.Qcp { + trace.Qcp[i].ToCanonical(&pk.Domain[0]).ToRegular() + if pk.Vk.Qcp[i], err = kzg.Commit(pk.trace.Qcp[i].Coefficients(), pk.Kzg); err != nil { + return err + } + } if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Kzg); err != nil { return err } @@ -295,9 +306,7 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Kzg); err != nil { - return err - } + if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Kzg); err != nil { return err } diff --git a/backend/plonk/bn254/verify.go b/backend/plonk/bn254/verify.go index ce35c937e8..4850e2dd7a 100644 --- a/backend/plonk/bn254/verify.go +++ b/backend/plonk/bn254/verify.go @@ -114,7 +114,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { for i := range vk.CommitmentConstraintIndexes { var hashRes []fr.Element // TODO: when multi commits are implemented: PI2 -> PI2[i] - if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + if hashRes, err = fr.Hash(proof.PI2[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } @@ -215,10 +215,10 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // note since third part = α²*L₁(ζ)*Z _s2.Mul(&_s2, &alpha).Add(&_s2, &alphaSquareLagrange) // -α*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + α²*L₁(ζ) - points := []curve.G1Affine{ - vk.Ql, vk.Qr, vk.Qm, vk.Qo, vk.Qk, proof.PI2, // first part + points := append(proof.PI2, + vk.Ql, vk.Qr, vk.Qm, vk.Qo, vk.Qk, // first part vk.S[2], proof.Z, // second & third part - } + ) scalars := []fr.Element{ l, r, rl, o, one /* TODO Perf @Tabaie Consider just adding Qk instead */, qC, // first part @@ -229,7 +229,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } // Fold the first proof - foldedProof, foldedDigest, err := kzg.FoldProof([]kzg.Digest{ + foldedProof, foldedDigest, err := kzg.FoldProof(append(vk.Qcp, foldedH, linearizedPolynomialDigest, proof.LRO[0], @@ -237,8 +237,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { proof.LRO[2], vk.S[0], vk.S[1], - vk.Qcp, - }, + ), &proof.BatchedProof, zeta, hFunc, @@ -270,7 +269,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } -func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element, pi2 kzg.Digest) error { +func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element, pi2 []kzg.Digest) error { // permutation if err := fs.Bind(challenge, vk.S[0].Marshal()); err != nil { @@ -308,8 +307,10 @@ func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey } // bsb22 commitment - if err := fs.Bind(challenge, pi2.Marshal()); err != nil { - return err + for i := range pi2 { + if err := fs.Bind(challenge, pi2[i].Marshal()); err != nil { + return err + } } return nil From 8cbc97429a80f19d769e097b4908d1f0304e6fe0 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 2 May 2023 13:01:52 -0500 Subject: [PATCH 315/464] fix: register commitment func with new name --- frontend/cs/commitment.go | 21 +++++++++++++++++++++ frontend/cs/scs/api.go | 18 +++++------------- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/frontend/cs/commitment.go b/frontend/cs/commitment.go index 04c954a6b9..4be43bb6bd 100644 --- a/frontend/cs/commitment.go +++ b/frontend/cs/commitment.go @@ -3,11 +3,14 @@ package cs import ( "crypto/sha256" "fmt" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/debug" "github.com/consensys/gnark/logger" + "hash/fnv" "math/big" "os" + "strconv" "strings" ) @@ -30,6 +33,24 @@ func Bsb22CommitmentComputePlaceholder(mod *big.Int, input []*big.Int, output [] return fmt.Errorf("placeholder function: to be replaced by commitment computation") } +var maxNbCommitments int + +func RegisterBsb22CommitmentComputePlaceholder(index int) (hintName constraint.HintIds, err error) { + hintName = constraint.HintIds{ + Name: "bsb22 commitment #" + strconv.Itoa(index), + } + // mimic solver.GetHintID + hf := fnv.New32a() + if _, err = hf.Write([]byte(hintName.Name)); err != nil { + return + } + hintName.UUID = solver.HintID(hf.Sum32()) + if maxNbCommitments == index { + maxNbCommitments++ + solver.RegisterNamedHint(Bsb22CommitmentComputePlaceholder, hintName.UUID) + } + return +} func init() { solver.RegisterHint(Bsb22CommitmentComputePlaceholder) } diff --git a/frontend/cs/scs/api.go b/frontend/cs/scs/api.go index aeae83f5a8..7482700e45 100644 --- a/frontend/cs/scs/api.go +++ b/frontend/cs/scs/api.go @@ -18,11 +18,9 @@ package scs import ( "fmt" - "hash/fnv" "path/filepath" "reflect" "runtime" - "strconv" "strings" "github.com/consensys/gnark/debug" @@ -585,22 +583,16 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error builder.addPlonkConstraint(sparseR1C{xa: vINeg.VID, qL: vINeg.Coeff, commitment: constraint.COMMITTED}) } - hintName := constraint.HintIds{ - Name: "bsb22 commitment #" + strconv.Itoa(builder.cs.GetNbCommitments()), - } - - // mimic solver.GetHintID - hf := fnv.New32a() - if _, err := hf.Write([]byte(hintName.Name)); err != nil { + hintName, err := cs.RegisterBsb22CommitmentComputePlaceholder(builder.cs.GetNbCommitments()) + if err != nil { return nil, err } - hintName.UUID = solver.HintID(hf.Sum32()) - outs, err := builder.NewNamedHint(cs.Bsb22CommitmentComputePlaceholder, &hintName, 1, v...) - - if err != nil { + var outs []frontend.Variable + if outs, err = builder.NewNamedHint(cs.Bsb22CommitmentComputePlaceholder, &hintName, 1, v...); err != nil { return nil, err } + commitmentVar := builder.Neg(outs[0]).(expr.Term) commitmentConstraintIndex := builder.cs.GetNbConstraints() // RHS will be provided by both prover and verifier independently, as for a public wire From fdc914fe22e58e5379c92a20e9252d3aec7e3eec Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 2 May 2023 13:27:17 -0500 Subject: [PATCH 316/464] test: multi commits in scs --- test/commitments_test.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/commitments_test.go b/test/commitments_test.go index 37e8d1fafd..100294398f 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -158,3 +158,26 @@ func tryCommit(api frontend.API, x ...frontend.Variable) (frontend.Variable, err } return committer.Commit(x...) } + +type twoCommitCircuit struct { + X []frontend.Variable + Y frontend.Variable +} + +func (c *twoCommitCircuit) Define(api frontend.API) error { + c0, err := api.(frontend.Committer).Commit(c.X...) + if err != nil { + return err + } + var c1 frontend.Variable + if c1, err = api.(frontend.Committer).Commit(c0, c.Y); err != nil { + return err + } + api.AssertIsDifferent(c1, c.Y) + return nil +} + +func TestTwoCommitEnginePlonk(t *testing.T) { + assignment := &twoCommitCircuit{X: []frontend.Variable{1, 2}, Y: 3} + NewAssert(t).SolvingSucceeded(&twoCommitCircuit{X: make([]frontend.Variable, len(assignment.X))}, assignment, WithBackends(backend.PLONK)) +} From b7a81f31e2c8c0ffc3b779d9179d595134761abe Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Thu, 4 May 2023 17:13:25 -0500 Subject: [PATCH 317/464] fix: added missing cbor tags for BlueprintSparseR1CBool --- constraint/bls12-377/system.go | 1 + constraint/bls12-381/system.go | 1 + constraint/bls24-315/system.go | 1 + constraint/bls24-317/system.go | 1 + constraint/bn254/system.go | 1 + constraint/bw6-633/system.go | 1 + constraint/bw6-761/system.go | 1 + constraint/tinyfield/system.go | 1 + .../generator/backend/template/representations/system.go.tmpl | 1 + 9 files changed, 9 insertions(+) diff --git a/constraint/bls12-377/system.go b/constraint/bls12-377/system.go index ffb212c059..aa49f52be2 100644 --- a/constraint/bls12-377/system.go +++ b/constraint/bls12-377/system.go @@ -360,6 +360,7 @@ func getTagSet() cbor.TagSet { addType(reflect.TypeOf(constraint.BlueprintGenericSparseR1C{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CAdd{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CMul{})) + addType(reflect.TypeOf(constraint.BlueprintSparseR1CBool{})) return ts } diff --git a/constraint/bls12-381/system.go b/constraint/bls12-381/system.go index beca1bfe0d..d8655280bd 100644 --- a/constraint/bls12-381/system.go +++ b/constraint/bls12-381/system.go @@ -360,6 +360,7 @@ func getTagSet() cbor.TagSet { addType(reflect.TypeOf(constraint.BlueprintGenericSparseR1C{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CAdd{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CMul{})) + addType(reflect.TypeOf(constraint.BlueprintSparseR1CBool{})) return ts } diff --git a/constraint/bls24-315/system.go b/constraint/bls24-315/system.go index cf42528f80..aa1da61879 100644 --- a/constraint/bls24-315/system.go +++ b/constraint/bls24-315/system.go @@ -360,6 +360,7 @@ func getTagSet() cbor.TagSet { addType(reflect.TypeOf(constraint.BlueprintGenericSparseR1C{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CAdd{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CMul{})) + addType(reflect.TypeOf(constraint.BlueprintSparseR1CBool{})) return ts } diff --git a/constraint/bls24-317/system.go b/constraint/bls24-317/system.go index 2730d2cf15..d0ea66cf21 100644 --- a/constraint/bls24-317/system.go +++ b/constraint/bls24-317/system.go @@ -360,6 +360,7 @@ func getTagSet() cbor.TagSet { addType(reflect.TypeOf(constraint.BlueprintGenericSparseR1C{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CAdd{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CMul{})) + addType(reflect.TypeOf(constraint.BlueprintSparseR1CBool{})) return ts } diff --git a/constraint/bn254/system.go b/constraint/bn254/system.go index 7e861e9b6d..c66609b432 100644 --- a/constraint/bn254/system.go +++ b/constraint/bn254/system.go @@ -360,6 +360,7 @@ func getTagSet() cbor.TagSet { addType(reflect.TypeOf(constraint.BlueprintGenericSparseR1C{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CAdd{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CMul{})) + addType(reflect.TypeOf(constraint.BlueprintSparseR1CBool{})) return ts } diff --git a/constraint/bw6-633/system.go b/constraint/bw6-633/system.go index 676776d638..afad46f5ce 100644 --- a/constraint/bw6-633/system.go +++ b/constraint/bw6-633/system.go @@ -360,6 +360,7 @@ func getTagSet() cbor.TagSet { addType(reflect.TypeOf(constraint.BlueprintGenericSparseR1C{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CAdd{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CMul{})) + addType(reflect.TypeOf(constraint.BlueprintSparseR1CBool{})) return ts } diff --git a/constraint/bw6-761/system.go b/constraint/bw6-761/system.go index 68fe2a9e3e..76959c7fe5 100644 --- a/constraint/bw6-761/system.go +++ b/constraint/bw6-761/system.go @@ -360,6 +360,7 @@ func getTagSet() cbor.TagSet { addType(reflect.TypeOf(constraint.BlueprintGenericSparseR1C{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CAdd{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CMul{})) + addType(reflect.TypeOf(constraint.BlueprintSparseR1CBool{})) return ts } diff --git a/constraint/tinyfield/system.go b/constraint/tinyfield/system.go index 05f7fbefaf..3d33968182 100644 --- a/constraint/tinyfield/system.go +++ b/constraint/tinyfield/system.go @@ -360,6 +360,7 @@ func getTagSet() cbor.TagSet { addType(reflect.TypeOf(constraint.BlueprintGenericSparseR1C{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CAdd{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CMul{})) + addType(reflect.TypeOf(constraint.BlueprintSparseR1CBool{})) return ts } diff --git a/internal/generator/backend/template/representations/system.go.tmpl b/internal/generator/backend/template/representations/system.go.tmpl index 4a1bd0355a..5533730197 100644 --- a/internal/generator/backend/template/representations/system.go.tmpl +++ b/internal/generator/backend/template/representations/system.go.tmpl @@ -358,6 +358,7 @@ func getTagSet() cbor.TagSet { addType(reflect.TypeOf(constraint.BlueprintGenericSparseR1C{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CAdd{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CMul{})) + addType(reflect.TypeOf(constraint.BlueprintSparseR1CBool{})) return ts } From 44b5223086447a2d27b0d3acabb2ed4858c23411 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 4 May 2023 20:49:57 -0500 Subject: [PATCH 318/464] test: failing on parallel --- constraint/tinyfield/solver.go | 6 +- constraint/tinyfield/system.go | 32 ++--- frontend/cs/commitment.go | 6 + test/solver_test.go | 221 ++++++++++++++++++++++++++++++++- 4 files changed, 241 insertions(+), 24 deletions(-) diff --git a/constraint/tinyfield/solver.go b/constraint/tinyfield/solver.go index 35bd9e6c7b..1d895c66b0 100644 --- a/constraint/tinyfield/solver.go +++ b/constraint/tinyfield/solver.go @@ -37,7 +37,7 @@ import ( // solver represent the state of the solver during a call to System.Solve(...) type solver struct { - *system + *System // values and solved are index by the wire (variable) id values []fr.Element @@ -55,7 +55,7 @@ type solver struct { q *big.Int } -func newSolver(cs *system, witness fr.Vector, opts ...csolver.Option) (*solver, error) { +func newSolver(cs *System, witness fr.Vector, opts ...csolver.Option) (*solver, error) { // parse options opt, err := csolver.NewConfig(opts...) if err != nil { @@ -91,7 +91,7 @@ func newSolver(cs *system, witness fr.Vector, opts ...csolver.Option) (*solver, } s := solver{ - system: cs, + System: cs, values: make([]fr.Element, nbWires), solved: make([]bool, nbWires), mHintsFunctions: hintFunctions, diff --git a/constraint/tinyfield/system.go b/constraint/tinyfield/system.go index 3d33968182..61cee247c8 100644 --- a/constraint/tinyfield/system.go +++ b/constraint/tinyfield/system.go @@ -33,11 +33,11 @@ import ( fr "github.com/consensys/gnark/internal/tinyfield" ) -type R1CS = system -type SparseR1CS = system +type R1CS = System +type SparseR1CS = System -// system is a curved-typed constraint.System with a concrete coefficient table (fr.Element) -type system struct { +// System is a curved-typed constraint.System with a concrete coefficient table (fr.Element) +type System struct { constraint.System CoeffTable field @@ -51,8 +51,8 @@ func NewSparseR1CS(capacity int) *SparseR1CS { return newSystem(capacity, constraint.SystemSparseR1CS) } -func newSystem(capacity int, t constraint.SystemType) *system { - return &system{ +func newSystem(capacity int, t constraint.SystemType) *System { + return &System{ System: constraint.NewSystem(fr.Modulus(), capacity, t), CoeffTable: newCoeffTable(capacity / 10), } @@ -61,7 +61,7 @@ func newSystem(capacity int, t constraint.SystemType) *system { // Solve solves the constraint system with provided witness. // If it's a R1CS returns R1CSSolution // If it's a SparseR1CS returns SparseR1CSSolution -func (cs *system) Solve(witness witness.Witness, opts ...csolver.Option) (any, error) { +func (cs *System) Solve(witness witness.Witness, opts ...csolver.Option) (any, error) { log := logger.Logger().With().Int("nbConstraints", cs.GetNbConstraints()).Logger() start := time.Now() @@ -108,13 +108,13 @@ func (cs *system) Solve(witness witness.Witness, opts ...csolver.Option) (any, e // IsSolved // Deprecated: use _, err := Solve(...) instead -func (cs *system) IsSolved(witness witness.Witness, opts ...csolver.Option) error { +func (cs *System) IsSolved(witness witness.Witness, opts ...csolver.Option) error { _, err := cs.Solve(witness, opts...) return err } // GetR1Cs return the list of R1C -func (cs *system) GetR1Cs() []constraint.R1C { +func (cs *System) GetR1Cs() []constraint.R1C { toReturn := make([]constraint.R1C, 0, cs.GetNbConstraints()) for _, inst := range cs.Instructions { @@ -131,17 +131,17 @@ func (cs *system) GetR1Cs() []constraint.R1C { } // GetNbCoefficients return the number of unique coefficients needed in the R1CS -func (cs *system) GetNbCoefficients() int { +func (cs *System) GetNbCoefficients() int { return len(cs.Coefficients) } // CurveID returns curve ID as defined in gnark-crypto -func (cs *system) CurveID() ecc.ID { +func (cs *System) CurveID() ecc.ID { return ecc.UNKNOWN } // WriteTo encodes R1CS into provided io.Writer using cbor -func (cs *system) WriteTo(w io.Writer) (int64, error) { +func (cs *System) WriteTo(w io.Writer) (int64, error) { _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written ts := getTagSet() enc, err := cbor.CoreDetEncOptions().EncModeWithTags(ts) @@ -156,7 +156,7 @@ func (cs *system) WriteTo(w io.Writer) (int64, error) { } // ReadFrom attempts to decode R1CS from io.Reader using cbor -func (cs *system) ReadFrom(r io.Reader) (int64, error) { +func (cs *System) ReadFrom(r io.Reader) (int64, error) { ts := getTagSet() dm, err := cbor.DecOptions{ MaxArrayElements: 134217728, @@ -182,13 +182,13 @@ func (cs *system) ReadFrom(r io.Reader) (int64, error) { return int64(decoder.NumBytesRead()), nil } -func (cs *system) GetCoefficient(i int) (r constraint.Element) { +func (cs *System) GetCoefficient(i int) (r constraint.Element) { copy(r[:], cs.Coefficients[i][:]) return } // GetSparseR1Cs return the list of SparseR1C -func (cs *system) GetSparseR1Cs() []constraint.SparseR1C { +func (cs *System) GetSparseR1Cs() []constraint.SparseR1C { toReturn := make([]constraint.SparseR1C, 0, cs.GetNbConstraints()) @@ -209,7 +209,7 @@ func (cs *system) GetSparseR1Cs() []constraint.SparseR1C { // evaluateLROSmallDomain extracts the solver l, r, o, and returns it in lagrange form. // solver = [ public | secret | internal ] // TODO @gbotrel refactor; this seems to be a small util function for plonk -func evaluateLROSmallDomain(cs *system, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { +func evaluateLROSmallDomain(cs *System, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { //s := int(pk.Domain[0].Cardinality) s := cs.GetNbConstraints() + len(cs.Public) // len(spr.Public) is for the placeholder constraints diff --git a/frontend/cs/commitment.go b/frontend/cs/commitment.go index 4be43bb6bd..21af93792a 100644 --- a/frontend/cs/commitment.go +++ b/frontend/cs/commitment.go @@ -12,6 +12,7 @@ import ( "os" "strconv" "strings" + "sync" ) func Bsb22CommitmentComputePlaceholder(mod *big.Int, input []*big.Int, output []*big.Int) error { @@ -34,6 +35,7 @@ func Bsb22CommitmentComputePlaceholder(mod *big.Int, input []*big.Int, output [] } var maxNbCommitments int +var m sync.Mutex // TODO: Remove; this is only used in the frontend which is not required to be thread-safe func RegisterBsb22CommitmentComputePlaceholder(index int) (hintName constraint.HintIds, err error) { hintName = constraint.HintIds{ @@ -45,10 +47,14 @@ func RegisterBsb22CommitmentComputePlaceholder(index int) (hintName constraint.H return } hintName.UUID = solver.HintID(hf.Sum32()) + + m.Lock() if maxNbCommitments == index { maxNbCommitments++ solver.RegisterNamedHint(Bsb22CommitmentComputePlaceholder, hintName.UUID) } + m.Unlock() + return } func init() { diff --git a/test/solver_test.go b/test/solver_test.go index af8adbe9c1..49b9e08d89 100644 --- a/test/solver_test.go +++ b/test/solver_test.go @@ -1,7 +1,15 @@ package test import ( + "bytes" + "encoding/hex" + "errors" "fmt" + cs "github.com/consensys/gnark/constraint/tinyfield" + "github.com/consensys/gnark/internal/backend/circuits" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/stretchr/testify/assert" "io" "math/big" "reflect" @@ -17,7 +25,6 @@ import ( "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/consensys/gnark/frontend/cs/scs" "github.com/consensys/gnark/frontend/schema" - "github.com/consensys/gnark/internal/backend/circuits" "github.com/consensys/gnark/internal/kvstore" "github.com/consensys/gnark/internal/tinyfield" "github.com/consensys/gnark/internal/utils" @@ -43,7 +50,9 @@ func TestSolverConsistency(t *testing.T) { // we generate witnesses and compare with the output of big.Int test engine against // R1CS and SparseR1CS solvers - for name := range circuits.Circuits { + names := map[string]interface{}{"and": nil, "or": nil} + + for name := range names /*circuits.Circuits*/ { t.Run(name, func(t *testing.T) { tc := circuits.Circuits[name] t.Parallel() @@ -56,7 +65,7 @@ func TestSolverConsistency(t *testing.T) { } // witness used for the permutter. It implements the Witness interface -// using mock methods (only the undererlying vector is required). +// using mock methods (only the underlying vector is required). type permutterWitness struct { vector any } @@ -221,7 +230,7 @@ func copyWitnessFromVector(to frontend.Circuit, from []tinyfield.Element) { i := 0 schema.Walk(to, tVariable, func(f schema.LeafInfo, tInput reflect.Value) error { if f.Visibility == schema.Public { - tInput.Set(reflect.ValueOf((from[i]))) + tInput.Set(reflect.ValueOf(from[i])) i++ } return nil @@ -229,13 +238,22 @@ func copyWitnessFromVector(to frontend.Circuit, from []tinyfield.Element) { schema.Walk(to, tVariable, func(f schema.LeafInfo, tInput reflect.Value) error { if f.Visibility == schema.Secret { - tInput.Set(reflect.ValueOf((from[i]))) + tInput.Set(reflect.ValueOf(from[i])) i++ } return nil }) } +func getCircuitName(circuit frontend.Circuit) string { + for name, c := range circuits.Circuits { + if c.Circuit == circuit { + return name + } + } + panic("not found") +} + // ConsistentSolver solves given circuit with all possible witness combinations using internal/tinyfield // // Since the goal of this method is to flag potential solver issues, it is not exposed as an API for now @@ -253,6 +271,23 @@ func consistentSolver(circuit frontend.Circuit, hintFunctions []solver.Hint) err if err != nil { return err } + + diff := diffCs(ccs, i, circuit) + + if diff != "" { + return errors.New(diff) + } + + writer := bytes.NewBuffer(make([]byte, 0)) + if _, err = ccs.WriteTo(writer); err != nil { + return err + } + csName := "r1cs" + if i == 1 { + csName = "scs" + } + fmt.Printf("%s, %s: %s\n", getCircuitName(circuit), csName, hex.EncodeToString(writer.Bytes())) + p.constraintSystems[i] = ccs if i == 0 { // the -1 is only for r1cs... @@ -281,3 +316,179 @@ func init() { builders[0] = r1cs.NewBuilder builders[1] = scs.NewBuilder } + +func removePrefix(hx string) string { + for hx[0] != ':' { + hx = hx[1:] + } + return hx[2:] +} + +func readR1csFromHex(t *testing.T, hx string) constraint.ConstraintSystem { + res := &cs.R1CS{} + b, err := hex.DecodeString(hx) + assert.NoError(t, err) + _, err = res.ReadFrom(bytes.NewReader(b)) + assert.NoError(t, err) + return res +} + +func readScsFromHex(t *testing.T, hx string) constraint.ConstraintSystem { + res := &cs.SparseR1CS{} + b, err := hex.DecodeString(hx) + assert.NoError(t, err) + _, err = res.ReadFrom(bytes.NewReader(b)) + assert.NoError(t, err) + return res +} + +const andR1cs = "b2644c6f6773f6645479706501664c6576656c7382830001028103664d4465627567a0665075626c69638161316653656372657483634f7031634f7032635265736843616c6c44617461982c0c01020101010100030100000c01020101020100030200000a0101010101010201040a010101010001040103694465627567496e666ff66a426c75657072696e747382da00510527a0da00510528a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944016d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944016d537461727443616c6c446174610c70436f6e73747261696e744f666673657401a36b426c75657072696e744944016d537461727443616c6c44617461181870436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c44617461182270436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301" +const andScs = "b2644c6f6773f6645479706502664c6576656c7382830001028103664d4465627567a0665075626c6963f66653656372657483634f7031634f7032635265736843616c6c446174619300010301010300010301030200010300000000694465627567496e666ff66a426c75657072696e747385da00510527a0da00510529a0da0051052ba0da0051052aa0da0051052ca06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944046d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944046d537461727443616c6c446174610370436f6e73747261696e744f666673657401a36b426c75657072696e744944026d537461727443616c6c446174610670436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c446174610a70436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301" +const orR1cs = "b2644c6f6773f6645479706501664c6576656c7382830001028103664d4465627567a0665075626c69638161316653656372657483634f7031634f7032635265736843616c6c4461746198300c01020101010100030100000c01020101020100030200000e010103010101020304010101020a010101010001040103694465627567496e666ff66a426c75657072696e747382da00510527a0da00510528a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944016d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944016d537461727443616c6c446174610c70436f6e73747261696e744f666673657401a36b426c75657072696e744944016d537461727443616c6c44617461181870436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c44617461182670436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301" +const orScs = "b2644c6f6773f6645479706502664c6576656c7382830001028103664d4465627567a0665075626c6963f66653656372657483634f7031634f7032635265736843616c6c446174619818000103010103000103030301010000030200010300000000694465627567496e666ff66a426c75657072696e747385da00510527a0da00510529a0da0051052ba0da0051052aa0da0051052ca06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944046d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944046d537461727443616c6c446174610370436f6e73747261696e744f666673657401a36b426c75657072696e744944016d537461727443616c6c446174610670436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c446174610f70436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301" + +func getCorrectCs(csIndex int, circuit frontend.Circuit) string { + switch csIndex { + case 0: + if circuit == circuits.Circuits["and"].Circuit { + return andR1cs + } + if circuit == circuits.Circuits["or"].Circuit { + return orR1cs + } + case 1: + if circuit == circuits.Circuits["and"].Circuit { + return andScs + } + if circuit == circuits.Circuits["or"].Circuit { + return orScs + } + } + return "unrecognized circuit/cs" +} + +func diffCs(__cs constraint.ConstraintSystem, csIndex int, circuit frontend.Circuit) string { + + _cs := __cs.(*cs.System) + + csHex := getCorrectCs(csIndex, circuit) + if csHex == "unrecognized circuit/cs" { + return csHex + } + var expectedCs cs.System + + b, err := hex.DecodeString(csHex) + if err != nil { + return err.Error() + } + _, err = expectedCs.ReadFrom(bytes.NewReader(b)) + if err != nil { + return err.Error() + } + + return cmp.Diff(_cs, &expectedCs, cmpopts.IgnoreFields(cs.System{}, diffIgnore...)) +} + +func TestPrintDiff(t *testing.T) { + seq := []string{ // first and, then or + "smRMb2dz9mRUeXBlAWZMZXZlbHOCgwABAoEDZk1EZWJ1Z6BmUHVibGljgWExZlNlY3JldINjT3AxY09wMmNSZXNoQ2FsbERhdGGYLAwBAgEBAQEAAwEAAAwBAgEBAgEAAwIAAAoBAQEBAQECAQQKAQEBAQABBAEDaURlYnVnSW5mb/ZqQmx1ZXByaW50c4LaAFEFJ6DaAFEFKKBrU2NhbGFyRmllbGRiMmZrU3ltYm9sVGFibGWiaUZ1bmN0aW9uc/ZpTG9jYXRpb25z9mxDb2VmZmljaWVudHOFgQCBGBmBA4EWgRgsbEduYXJrVmVyc2lvbmswLjguMS1hbHBoYWxJbnN0cnVjdGlvbnOEo2tCbHVlcHJpbnRJRAFtU3RhcnRDYWxsRGF0YQBwQ29uc3RyYWludE9mZnNldACja0JsdWVwcmludElEAW1TdGFydENhbGxEYXRhDHBDb25zdHJhaW50T2Zmc2V0AaNrQmx1ZXByaW50SUQBbVN0YXJ0Q2FsbERhdGEYGHBDb25zdHJhaW50T2Zmc2V0AqNrQmx1ZXByaW50SUQBbVN0YXJ0Q2FsbERhdGEYInBDb25zdHJhaW50T2Zmc2V0A21OYkNvbnN0cmFpbnRzBG5Db21taXRtZW50SW5mb/ZyTUhpbnRzRGVwZW5kZW5jaWVzoHNOYkludGVybmFsVmFyaWFibGVzAQ==", + "smRMb2dz9mRUeXBlAmZMZXZlbHOCgwABAoEDZk1EZWJ1Z6BmUHVibGlj9mZTZWNyZXSDY09wMWNPcDJjUmVzaENhbGxEYXRhkwABAwEBAwABAwEDAgABAwAAAABpRGVidWdJbmZv9mpCbHVlcHJpbnRzhdoAUQUnoNoAUQUpoNoAUQUroNoAUQUqoKBrU2NhbGFyRmllbGRiMmZrU3ltYm9sVGFibGWiaUZ1bmN0aW9uc/ZpTG9jYXRpb25z9mxDb2VmZmljaWVudHOFgQCBGBmBA4EWgRgsbEduYXJrVmVyc2lvbmswLjguMS1hbHBoYWxJbnN0cnVjdGlvbnOEo2tCbHVlcHJpbnRJRARtU3RhcnRDYWxsRGF0YQBwQ29uc3RyYWludE9mZnNldACja0JsdWVwcmludElEBG1TdGFydENhbGxEYXRhA3BDb25zdHJhaW50T2Zmc2V0AaNrQmx1ZXByaW50SUQCbVN0YXJ0Q2FsbERhdGEGcENvbnN0cmFpbnRPZmZzZXQCo2tCbHVlcHJpbnRJRAFtU3RhcnRDYWxsRGF0YQpwQ29uc3RyYWludE9mZnNldANtTmJDb25zdHJhaW50cwRuQ29tbWl0bWVudEluZm/2ck1IaW50c0RlcGVuZGVuY2llc6BzTmJJbnRlcm5hbFZhcmlhYmxlcwE=", + "smRMb2dz9mRUeXBlAWZMZXZlbHOCgwABAoEDZk1EZWJ1Z6BmUHVibGljgWExZlNlY3JldINjT3AxY09wMmNSZXNoQ2FsbERhdGGYMAwBAgEBAQEAAwEAAAwBAgEBAgEAAwIAAA4BAQMBAQECAwQBAQECCgEBAQEAAQQBA2lEZWJ1Z0luZm/2akJsdWVwcmludHOC2gBRBSeg2gBRBSiga1NjYWxhckZpZWxkYjJma1N5bWJvbFRhYmxlomlGdW5jdGlvbnP2aUxvY2F0aW9uc/ZsQ29lZmZpY2llbnRzhYEAgRgZgQOBFoEYLGxHbmFya1ZlcnNpb25rMC44LjEtYWxwaGFsSW5zdHJ1Y3Rpb25zhKNrQmx1ZXByaW50SUQBbVN0YXJ0Q2FsbERhdGEAcENvbnN0cmFpbnRPZmZzZXQAo2tCbHVlcHJpbnRJRAFtU3RhcnRDYWxsRGF0YQxwQ29uc3RyYWludE9mZnNldAGja0JsdWVwcmludElEAW1TdGFydENhbGxEYXRhGBhwQ29uc3RyYWludE9mZnNldAKja0JsdWVwcmludElEAW1TdGFydENhbGxEYXRhGCZwQ29uc3RyYWludE9mZnNldANtTmJDb25zdHJhaW50cwRuQ29tbWl0bWVudEluZm/2ck1IaW50c0RlcGVuZGVuY2llc6BzTmJJbnRlcm5hbFZhcmlhYmxlcwE=", + "smRMb2dz9mRUeXBlAmZMZXZlbHOCgwABAoEDZk1EZWJ1Z6BmUHVibGlj9mZTZWNyZXSDY09wMWNPcDJjUmVzaENhbGxEYXRhmBgAAQMBAQMAAQMDAwEBAAADAgABAwAAAABpRGVidWdJbmZv9mpCbHVlcHJpbnRzhdoAUQUnoNoAUQUpoNoAUQUroNoAUQUqoKBrU2NhbGFyRmllbGRiMmZrU3ltYm9sVGFibGWiaUZ1bmN0aW9uc/ZpTG9jYXRpb25z9mxDb2VmZmljaWVudHOFgQCBGBmBA4EWgRgsbEduYXJrVmVyc2lvbmswLjguMS1hbHBoYWxJbnN0cnVjdGlvbnOEo2tCbHVlcHJpbnRJRARtU3RhcnRDYWxsRGF0YQBwQ29uc3RyYWludE9mZnNldACja0JsdWVwcmludElEBG1TdGFydENhbGxEYXRhA3BDb25zdHJhaW50T2Zmc2V0AaNrQmx1ZXByaW50SUQBbVN0YXJ0Q2FsbERhdGEGcENvbnN0cmFpbnRPZmZzZXQCo2tCbHVlcHJpbnRJRAFtU3RhcnRDYWxsRGF0YQ9wQ29uc3RyYWludE9mZnNldANtTmJDb25zdHJhaW50cwRuQ29tbWl0bWVudEluZm/2ck1IaW50c0RlcGVuZGVuY2llc6BzTmJJbnRlcm5hbFZhcmlhYmxlcwE=", + } + //orSeq := []string{} + + parallel := []string{ + "or, r1cs: b2644c6f6773f6645479706501664c6576656c7382830001028103664d4465627567a0665075626c69638161316653656372657483634f7031634f7032635265736843616c6c4461746198300c01020101010100030100000a01010101010102010400000e010103010101020304010101020a010101010001040103694465627567496e666ff66a426c75657072696e747382da00510527a0da00510528a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944016d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944016d537461727443616c6c446174610c70436f6e73747261696e744f666673657401a36b426c75657072696e744944016d537461727443616c6c44617461181870436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c44617461182670436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301", + "and, r1cs: b2644c6f6773f6645479706501664c6576656c7382830001028103664d4465627567a0665075626c69638161316653656372657483634f7031634f7032635265736843616c6c44617461982c0c01020101010100030100000c01020101020100030200000a0101010101010201040a010101010001040103694465627567496e666ff66a426c75657072696e747382da00510527a0da00510528a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944016d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944016d537461727443616c6c446174610c70436f6e73747261696e744f666673657401a36b426c75657072696e744944016d537461727443616c6c44617461181870436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c44617461182270436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301", + "or, scs: b2644c6f6773f6645479706502664c6576656c7382830001028103664d4465627567a0665075626c6963f66653656372657483634f7031634f7032635265736843616c6c446174619818000103010103000103030301010000030200010300000000694465627567496e666ff66a426c75657072696e747385da00510527a0da00510529a0da0051052ba0da0051052aa0a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944046d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944046d537461727443616c6c446174610370436f6e73747261696e744f666673657401a36b426c75657072696e744944016d537461727443616c6c446174610670436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c446174610f70436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301", + "and, scs: b2644c6f6773f6645479706502664c6576656c7382830001028103664d4465627567a0665075626c6963f66653656372657483634f7031634f7032635265736843616c6c446174619300010301010300010301030200010300000000694465627567496e666ff66a426c75657072696e747385da00510527a0da00510529a0da0051052ba0da0051052aa0a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944046d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944046d537461727443616c6c446174610370436f6e73747261696e744f666673657401a36b426c75657072696e744944026d537461727443616c6c446174610670436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c446174610a70436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301", + } + + parallel1 := []string{ + "or, r1cs: b2644c6f6773f6645479706501664c6576656c7382830001028103664d4465627567a0665075626c69638161316653656372657483634f7031634f7032635265736843616c6c4461746198300c01020101010100030100000a01010101010102010400000e010103010101020304010101020a010101010001040103694465627567496e666ff66a426c75657072696e747382da00510527a0da00510528a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944016d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944016d537461727443616c6c446174610c70436f6e73747261696e744f666673657401a36b426c75657072696e744944016d537461727443616c6c44617461181870436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c44617461182670436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301", + "and, r1cs: b2644c6f6773f6645479706501664c6576656c7382830001028103664d4465627567a0665075626c69638161316653656372657483634f7031634f7032635265736843616c6c44617461982c0c01020101010100030100000c01020101020100030200000a0101010101010201040a010101010001040103694465627567496e666ff66a426c75657072696e747382da00510527a0da00510528a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944016d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944016d537461727443616c6c446174610c70436f6e73747261696e744f666673657401a36b426c75657072696e744944016d537461727443616c6c44617461181870436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c44617461182270436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301", + "or, scs: b2644c6f6773f6645479706502664c6576656c7382830001028103664d4465627567a0665075626c6963f66653656372657483634f7031634f7032635265736843616c6c446174619818000103010103000103030301010000030200010300000000694465627567496e666ff66a426c75657072696e747385da00510527a0da00510529a0da0051052ba0da0051052aa0a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944046d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944046d537461727443616c6c446174610370436f6e73747261696e744f666673657401a36b426c75657072696e744944016d537461727443616c6c446174610670436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c446174610f70436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301", + "and, scs: b2644c6f6773f6645479706502664c6576656c7382830001028103664d4465627567a0665075626c6963f66653656372657483634f7031634f7032635265736843616c6c446174619300010301010300010301030200010300000000694465627567496e666ff66a426c75657072696e747385da00510527a0da00510529a0da0051052ba0da0051052aa0a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944046d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944046d537461727443616c6c446174610370436f6e73747261696e744f666673657401a36b426c75657072696e744944026d537461727443616c6c446174610670436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c446174610a70436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301", + } + + parallel2 := []string{ + "or, r1cs: b2644c6f6773f6645479706501664c6576656c7382830001028103664d4465627567a0665075626c69638161316653656372657483634f7031634f7032635265736843616c6c4461746198300c01020101010100030100000c01020101020100030200000e010103010101020304010101020a010101010001040103694465627567496e666ff66a426c75657072696e747382da00510527a0da00510528a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944016d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944016d537461727443616c6c446174610c70436f6e73747261696e744f666673657401a36b426c75657072696e744944016d537461727443616c6c44617461181870436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c44617461182670436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301", + "and, r1cs: b2644c6f6773f6645479706501664c6576656c7382830001028103664d4465627567a0665075626c69638161316653656372657483634f7031634f7032635265736843616c6c44617461982c0c01020101010100030100000c01020101020100030200000a0101010101010201040a010101010001040103694465627567496e666ff66a426c75657072696e747382da00510527a0da00510528a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944016d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944016d537461727443616c6c446174610c70436f6e73747261696e744f666673657401a36b426c75657072696e744944016d537461727443616c6c44617461181870436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c44617461182270436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301", + "or, scs: b2644c6f6773f6645479706502664c6576656c7382830001028103664d4465627567a0665075626c6963f66653656372657483634f7031634f7032635265736843616c6c446174619818000103010103000103030301010000030200010300000000694465627567496e666ff66a426c75657072696e747385da00510527a0da00510529a0da0051052ba0da0051052aa0a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944046d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944046d537461727443616c6c446174610370436f6e73747261696e744f666673657401a36b426c75657072696e744944016d537461727443616c6c446174610670436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c446174610f70436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301", + "and, scs: b2644c6f6773f6645479706502664c6576656c7382830001028103664d4465627567a0665075626c6963f66653656372657483634f7031634f7032635265736843616c6c446174619300010301010300010301030200010300000000694465627567496e666ff66a426c75657072696e747385da00510527a0da00510529a0da0051052ba0da0051052aa0a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944046d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944046d537461727443616c6c446174610370436f6e73747261696e744f666673657401a36b426c75657072696e744944026d537461727443616c6c446174610670436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c446174610a70436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301", + } + + var cs0, cs1 constraint.ConstraintSystem + for i := range parallel1 { + if i/2 == 0 { + cs0 = readR1csFromHex(t, parallel1[i]) + cs1 = readR1csFromHex(t, parallel2[i]) + } else { + cs0 = readScsFromHex(t, parallel1[i]) + cs1 = readScsFromHex(t, parallel2[i]) + } + + fmt.Printf("\n\nparallel1 #%d vs parallel2 #%d\n", i, i) + printDiff(parallel1[i], parallel2[i]) + + fmt.Println(cmp.Diff(cs0, cs1, cmpopts.IgnoreFields(cs.System{}, + "System.SymbolTable.mFunctions", + "System.SymbolTable.mLocations", + "System.q", + "System.bitLen", + "System.lbWireLevel", + "System.lbOutputs", + "System.genericHint", + "CoeffTable.mCoeffs", + "field", + ))) + } + + for i := range seq { + for j := range parallel { + fmt.Printf("\n\nseq #%d vs parallel #%d\n", i, j) + printDiff(seq[i], parallel[j]) + } + } +} + +func printDiff(a, b string) { + colorReset := "\033[0m" + colorRed := "\033[31m" + colorGreen := "\033[32m" + + match := true + printDiff1 := func(a, b string) { + for i := range a { + colorParam := colorReset + if i >= len(b) || a[i] != b[i] { + match = false + colorParam = colorRed + } + fmt.Print(colorParam, string(a[i])) + } + fmt.Println() + } + + printDiff1(a, b) + printDiff1(b, a) + + if match { + fmt.Println(colorGreen, "MATCH!!") + } + + fmt.Print(colorReset) +} + +var diffIgnore = []string{ + "System.SymbolTable.mFunctions", + "System.SymbolTable.mLocations", + "System.q", + "System.bitLen", + "System.lbWireLevel", + "System.lbOutputs", + "System.genericHint", + "CoeffTable.mCoeffs", + "field", +} From 80252e0593c3de4408d9d32281f274f1e736cbad Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 4 May 2023 20:52:19 -0500 Subject: [PATCH 319/464] chore: delete unnecessary test cases --- test/solver_test.go | 132 +------------------------------------------- 1 file changed, 2 insertions(+), 130 deletions(-) diff --git a/test/solver_test.go b/test/solver_test.go index 49b9e08d89..e6eebfe31e 100644 --- a/test/solver_test.go +++ b/test/solver_test.go @@ -9,7 +9,6 @@ import ( "github.com/consensys/gnark/internal/backend/circuits" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "github.com/stretchr/testify/assert" "io" "math/big" "reflect" @@ -278,16 +277,6 @@ func consistentSolver(circuit frontend.Circuit, hintFunctions []solver.Hint) err return errors.New(diff) } - writer := bytes.NewBuffer(make([]byte, 0)) - if _, err = ccs.WriteTo(writer); err != nil { - return err - } - csName := "r1cs" - if i == 1 { - csName = "scs" - } - fmt.Printf("%s, %s: %s\n", getCircuitName(circuit), csName, hex.EncodeToString(writer.Bytes())) - p.constraintSystems[i] = ccs if i == 0 { // the -1 is only for r1cs... @@ -317,37 +306,12 @@ func init() { builders[1] = scs.NewBuilder } -func removePrefix(hx string) string { - for hx[0] != ':' { - hx = hx[1:] - } - return hx[2:] -} - -func readR1csFromHex(t *testing.T, hx string) constraint.ConstraintSystem { - res := &cs.R1CS{} - b, err := hex.DecodeString(hx) - assert.NoError(t, err) - _, err = res.ReadFrom(bytes.NewReader(b)) - assert.NoError(t, err) - return res -} - -func readScsFromHex(t *testing.T, hx string) constraint.ConstraintSystem { - res := &cs.SparseR1CS{} - b, err := hex.DecodeString(hx) - assert.NoError(t, err) - _, err = res.ReadFrom(bytes.NewReader(b)) - assert.NoError(t, err) - return res -} - const andR1cs = "b2644c6f6773f6645479706501664c6576656c7382830001028103664d4465627567a0665075626c69638161316653656372657483634f7031634f7032635265736843616c6c44617461982c0c01020101010100030100000c01020101020100030200000a0101010101010201040a010101010001040103694465627567496e666ff66a426c75657072696e747382da00510527a0da00510528a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944016d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944016d537461727443616c6c446174610c70436f6e73747261696e744f666673657401a36b426c75657072696e744944016d537461727443616c6c44617461181870436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c44617461182270436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301" const andScs = "b2644c6f6773f6645479706502664c6576656c7382830001028103664d4465627567a0665075626c6963f66653656372657483634f7031634f7032635265736843616c6c446174619300010301010300010301030200010300000000694465627567496e666ff66a426c75657072696e747385da00510527a0da00510529a0da0051052ba0da0051052aa0da0051052ca06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944046d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944046d537461727443616c6c446174610370436f6e73747261696e744f666673657401a36b426c75657072696e744944026d537461727443616c6c446174610670436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c446174610a70436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301" const orR1cs = "b2644c6f6773f6645479706501664c6576656c7382830001028103664d4465627567a0665075626c69638161316653656372657483634f7031634f7032635265736843616c6c4461746198300c01020101010100030100000c01020101020100030200000e010103010101020304010101020a010101010001040103694465627567496e666ff66a426c75657072696e747382da00510527a0da00510528a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944016d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944016d537461727443616c6c446174610c70436f6e73747261696e744f666673657401a36b426c75657072696e744944016d537461727443616c6c44617461181870436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c44617461182670436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301" const orScs = "b2644c6f6773f6645479706502664c6576656c7382830001028103664d4465627567a0665075626c6963f66653656372657483634f7031634f7032635265736843616c6c446174619818000103010103000103030301010000030200010300000000694465627567496e666ff66a426c75657072696e747385da00510527a0da00510529a0da0051052ba0da0051052aa0da0051052ca06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944046d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944046d537461727443616c6c446174610370436f6e73747261696e744f666673657401a36b426c75657072696e744944016d537461727443616c6c446174610670436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c446174610f70436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301" -func getCorrectCs(csIndex int, circuit frontend.Circuit) string { +func getCs(csIndex int, circuit frontend.Circuit) string { switch csIndex { case 0: if circuit == circuits.Circuits["and"].Circuit { @@ -371,7 +335,7 @@ func diffCs(__cs constraint.ConstraintSystem, csIndex int, circuit frontend.Circ _cs := __cs.(*cs.System) - csHex := getCorrectCs(csIndex, circuit) + csHex := getCs(csIndex, circuit) if csHex == "unrecognized circuit/cs" { return csHex } @@ -389,98 +353,6 @@ func diffCs(__cs constraint.ConstraintSystem, csIndex int, circuit frontend.Circ return cmp.Diff(_cs, &expectedCs, cmpopts.IgnoreFields(cs.System{}, diffIgnore...)) } -func TestPrintDiff(t *testing.T) { - seq := []string{ // first and, then or - "smRMb2dz9mRUeXBlAWZMZXZlbHOCgwABAoEDZk1EZWJ1Z6BmUHVibGljgWExZlNlY3JldINjT3AxY09wMmNSZXNoQ2FsbERhdGGYLAwBAgEBAQEAAwEAAAwBAgEBAgEAAwIAAAoBAQEBAQECAQQKAQEBAQABBAEDaURlYnVnSW5mb/ZqQmx1ZXByaW50c4LaAFEFJ6DaAFEFKKBrU2NhbGFyRmllbGRiMmZrU3ltYm9sVGFibGWiaUZ1bmN0aW9uc/ZpTG9jYXRpb25z9mxDb2VmZmljaWVudHOFgQCBGBmBA4EWgRgsbEduYXJrVmVyc2lvbmswLjguMS1hbHBoYWxJbnN0cnVjdGlvbnOEo2tCbHVlcHJpbnRJRAFtU3RhcnRDYWxsRGF0YQBwQ29uc3RyYWludE9mZnNldACja0JsdWVwcmludElEAW1TdGFydENhbGxEYXRhDHBDb25zdHJhaW50T2Zmc2V0AaNrQmx1ZXByaW50SUQBbVN0YXJ0Q2FsbERhdGEYGHBDb25zdHJhaW50T2Zmc2V0AqNrQmx1ZXByaW50SUQBbVN0YXJ0Q2FsbERhdGEYInBDb25zdHJhaW50T2Zmc2V0A21OYkNvbnN0cmFpbnRzBG5Db21taXRtZW50SW5mb/ZyTUhpbnRzRGVwZW5kZW5jaWVzoHNOYkludGVybmFsVmFyaWFibGVzAQ==", - "smRMb2dz9mRUeXBlAmZMZXZlbHOCgwABAoEDZk1EZWJ1Z6BmUHVibGlj9mZTZWNyZXSDY09wMWNPcDJjUmVzaENhbGxEYXRhkwABAwEBAwABAwEDAgABAwAAAABpRGVidWdJbmZv9mpCbHVlcHJpbnRzhdoAUQUnoNoAUQUpoNoAUQUroNoAUQUqoKBrU2NhbGFyRmllbGRiMmZrU3ltYm9sVGFibGWiaUZ1bmN0aW9uc/ZpTG9jYXRpb25z9mxDb2VmZmljaWVudHOFgQCBGBmBA4EWgRgsbEduYXJrVmVyc2lvbmswLjguMS1hbHBoYWxJbnN0cnVjdGlvbnOEo2tCbHVlcHJpbnRJRARtU3RhcnRDYWxsRGF0YQBwQ29uc3RyYWludE9mZnNldACja0JsdWVwcmludElEBG1TdGFydENhbGxEYXRhA3BDb25zdHJhaW50T2Zmc2V0AaNrQmx1ZXByaW50SUQCbVN0YXJ0Q2FsbERhdGEGcENvbnN0cmFpbnRPZmZzZXQCo2tCbHVlcHJpbnRJRAFtU3RhcnRDYWxsRGF0YQpwQ29uc3RyYWludE9mZnNldANtTmJDb25zdHJhaW50cwRuQ29tbWl0bWVudEluZm/2ck1IaW50c0RlcGVuZGVuY2llc6BzTmJJbnRlcm5hbFZhcmlhYmxlcwE=", - "smRMb2dz9mRUeXBlAWZMZXZlbHOCgwABAoEDZk1EZWJ1Z6BmUHVibGljgWExZlNlY3JldINjT3AxY09wMmNSZXNoQ2FsbERhdGGYMAwBAgEBAQEAAwEAAAwBAgEBAgEAAwIAAA4BAQMBAQECAwQBAQECCgEBAQEAAQQBA2lEZWJ1Z0luZm/2akJsdWVwcmludHOC2gBRBSeg2gBRBSiga1NjYWxhckZpZWxkYjJma1N5bWJvbFRhYmxlomlGdW5jdGlvbnP2aUxvY2F0aW9uc/ZsQ29lZmZpY2llbnRzhYEAgRgZgQOBFoEYLGxHbmFya1ZlcnNpb25rMC44LjEtYWxwaGFsSW5zdHJ1Y3Rpb25zhKNrQmx1ZXByaW50SUQBbVN0YXJ0Q2FsbERhdGEAcENvbnN0cmFpbnRPZmZzZXQAo2tCbHVlcHJpbnRJRAFtU3RhcnRDYWxsRGF0YQxwQ29uc3RyYWludE9mZnNldAGja0JsdWVwcmludElEAW1TdGFydENhbGxEYXRhGBhwQ29uc3RyYWludE9mZnNldAKja0JsdWVwcmludElEAW1TdGFydENhbGxEYXRhGCZwQ29uc3RyYWludE9mZnNldANtTmJDb25zdHJhaW50cwRuQ29tbWl0bWVudEluZm/2ck1IaW50c0RlcGVuZGVuY2llc6BzTmJJbnRlcm5hbFZhcmlhYmxlcwE=", - "smRMb2dz9mRUeXBlAmZMZXZlbHOCgwABAoEDZk1EZWJ1Z6BmUHVibGlj9mZTZWNyZXSDY09wMWNPcDJjUmVzaENhbGxEYXRhmBgAAQMBAQMAAQMDAwEBAAADAgABAwAAAABpRGVidWdJbmZv9mpCbHVlcHJpbnRzhdoAUQUnoNoAUQUpoNoAUQUroNoAUQUqoKBrU2NhbGFyRmllbGRiMmZrU3ltYm9sVGFibGWiaUZ1bmN0aW9uc/ZpTG9jYXRpb25z9mxDb2VmZmljaWVudHOFgQCBGBmBA4EWgRgsbEduYXJrVmVyc2lvbmswLjguMS1hbHBoYWxJbnN0cnVjdGlvbnOEo2tCbHVlcHJpbnRJRARtU3RhcnRDYWxsRGF0YQBwQ29uc3RyYWludE9mZnNldACja0JsdWVwcmludElEBG1TdGFydENhbGxEYXRhA3BDb25zdHJhaW50T2Zmc2V0AaNrQmx1ZXByaW50SUQBbVN0YXJ0Q2FsbERhdGEGcENvbnN0cmFpbnRPZmZzZXQCo2tCbHVlcHJpbnRJRAFtU3RhcnRDYWxsRGF0YQ9wQ29uc3RyYWludE9mZnNldANtTmJDb25zdHJhaW50cwRuQ29tbWl0bWVudEluZm/2ck1IaW50c0RlcGVuZGVuY2llc6BzTmJJbnRlcm5hbFZhcmlhYmxlcwE=", - } - //orSeq := []string{} - - parallel := []string{ - "or, r1cs: b2644c6f6773f6645479706501664c6576656c7382830001028103664d4465627567a0665075626c69638161316653656372657483634f7031634f7032635265736843616c6c4461746198300c01020101010100030100000a01010101010102010400000e010103010101020304010101020a010101010001040103694465627567496e666ff66a426c75657072696e747382da00510527a0da00510528a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944016d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944016d537461727443616c6c446174610c70436f6e73747261696e744f666673657401a36b426c75657072696e744944016d537461727443616c6c44617461181870436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c44617461182670436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301", - "and, r1cs: b2644c6f6773f6645479706501664c6576656c7382830001028103664d4465627567a0665075626c69638161316653656372657483634f7031634f7032635265736843616c6c44617461982c0c01020101010100030100000c01020101020100030200000a0101010101010201040a010101010001040103694465627567496e666ff66a426c75657072696e747382da00510527a0da00510528a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944016d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944016d537461727443616c6c446174610c70436f6e73747261696e744f666673657401a36b426c75657072696e744944016d537461727443616c6c44617461181870436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c44617461182270436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301", - "or, scs: b2644c6f6773f6645479706502664c6576656c7382830001028103664d4465627567a0665075626c6963f66653656372657483634f7031634f7032635265736843616c6c446174619818000103010103000103030301010000030200010300000000694465627567496e666ff66a426c75657072696e747385da00510527a0da00510529a0da0051052ba0da0051052aa0a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944046d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944046d537461727443616c6c446174610370436f6e73747261696e744f666673657401a36b426c75657072696e744944016d537461727443616c6c446174610670436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c446174610f70436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301", - "and, scs: b2644c6f6773f6645479706502664c6576656c7382830001028103664d4465627567a0665075626c6963f66653656372657483634f7031634f7032635265736843616c6c446174619300010301010300010301030200010300000000694465627567496e666ff66a426c75657072696e747385da00510527a0da00510529a0da0051052ba0da0051052aa0a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944046d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944046d537461727443616c6c446174610370436f6e73747261696e744f666673657401a36b426c75657072696e744944026d537461727443616c6c446174610670436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c446174610a70436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301", - } - - parallel1 := []string{ - "or, r1cs: b2644c6f6773f6645479706501664c6576656c7382830001028103664d4465627567a0665075626c69638161316653656372657483634f7031634f7032635265736843616c6c4461746198300c01020101010100030100000a01010101010102010400000e010103010101020304010101020a010101010001040103694465627567496e666ff66a426c75657072696e747382da00510527a0da00510528a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944016d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944016d537461727443616c6c446174610c70436f6e73747261696e744f666673657401a36b426c75657072696e744944016d537461727443616c6c44617461181870436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c44617461182670436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301", - "and, r1cs: b2644c6f6773f6645479706501664c6576656c7382830001028103664d4465627567a0665075626c69638161316653656372657483634f7031634f7032635265736843616c6c44617461982c0c01020101010100030100000c01020101020100030200000a0101010101010201040a010101010001040103694465627567496e666ff66a426c75657072696e747382da00510527a0da00510528a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944016d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944016d537461727443616c6c446174610c70436f6e73747261696e744f666673657401a36b426c75657072696e744944016d537461727443616c6c44617461181870436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c44617461182270436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301", - "or, scs: b2644c6f6773f6645479706502664c6576656c7382830001028103664d4465627567a0665075626c6963f66653656372657483634f7031634f7032635265736843616c6c446174619818000103010103000103030301010000030200010300000000694465627567496e666ff66a426c75657072696e747385da00510527a0da00510529a0da0051052ba0da0051052aa0a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944046d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944046d537461727443616c6c446174610370436f6e73747261696e744f666673657401a36b426c75657072696e744944016d537461727443616c6c446174610670436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c446174610f70436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301", - "and, scs: b2644c6f6773f6645479706502664c6576656c7382830001028103664d4465627567a0665075626c6963f66653656372657483634f7031634f7032635265736843616c6c446174619300010301010300010301030200010300000000694465627567496e666ff66a426c75657072696e747385da00510527a0da00510529a0da0051052ba0da0051052aa0a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944046d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944046d537461727443616c6c446174610370436f6e73747261696e744f666673657401a36b426c75657072696e744944026d537461727443616c6c446174610670436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c446174610a70436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301", - } - - parallel2 := []string{ - "or, r1cs: b2644c6f6773f6645479706501664c6576656c7382830001028103664d4465627567a0665075626c69638161316653656372657483634f7031634f7032635265736843616c6c4461746198300c01020101010100030100000c01020101020100030200000e010103010101020304010101020a010101010001040103694465627567496e666ff66a426c75657072696e747382da00510527a0da00510528a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944016d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944016d537461727443616c6c446174610c70436f6e73747261696e744f666673657401a36b426c75657072696e744944016d537461727443616c6c44617461181870436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c44617461182670436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301", - "and, r1cs: b2644c6f6773f6645479706501664c6576656c7382830001028103664d4465627567a0665075626c69638161316653656372657483634f7031634f7032635265736843616c6c44617461982c0c01020101010100030100000c01020101020100030200000a0101010101010201040a010101010001040103694465627567496e666ff66a426c75657072696e747382da00510527a0da00510528a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944016d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944016d537461727443616c6c446174610c70436f6e73747261696e744f666673657401a36b426c75657072696e744944016d537461727443616c6c44617461181870436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c44617461182270436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301", - "or, scs: b2644c6f6773f6645479706502664c6576656c7382830001028103664d4465627567a0665075626c6963f66653656372657483634f7031634f7032635265736843616c6c446174619818000103010103000103030301010000030200010300000000694465627567496e666ff66a426c75657072696e747385da00510527a0da00510529a0da0051052ba0da0051052aa0a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944046d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944046d537461727443616c6c446174610370436f6e73747261696e744f666673657401a36b426c75657072696e744944016d537461727443616c6c446174610670436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c446174610f70436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301", - "and, scs: b2644c6f6773f6645479706502664c6576656c7382830001028103664d4465627567a0665075626c6963f66653656372657483634f7031634f7032635265736843616c6c446174619300010301010300010301030200010300000000694465627567496e666ff66a426c75657072696e747385da00510527a0da00510529a0da0051052ba0da0051052aa0a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944046d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944046d537461727443616c6c446174610370436f6e73747261696e744f666673657401a36b426c75657072696e744944026d537461727443616c6c446174610670436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c446174610a70436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301", - } - - var cs0, cs1 constraint.ConstraintSystem - for i := range parallel1 { - if i/2 == 0 { - cs0 = readR1csFromHex(t, parallel1[i]) - cs1 = readR1csFromHex(t, parallel2[i]) - } else { - cs0 = readScsFromHex(t, parallel1[i]) - cs1 = readScsFromHex(t, parallel2[i]) - } - - fmt.Printf("\n\nparallel1 #%d vs parallel2 #%d\n", i, i) - printDiff(parallel1[i], parallel2[i]) - - fmt.Println(cmp.Diff(cs0, cs1, cmpopts.IgnoreFields(cs.System{}, - "System.SymbolTable.mFunctions", - "System.SymbolTable.mLocations", - "System.q", - "System.bitLen", - "System.lbWireLevel", - "System.lbOutputs", - "System.genericHint", - "CoeffTable.mCoeffs", - "field", - ))) - } - - for i := range seq { - for j := range parallel { - fmt.Printf("\n\nseq #%d vs parallel #%d\n", i, j) - printDiff(seq[i], parallel[j]) - } - } -} - -func printDiff(a, b string) { - colorReset := "\033[0m" - colorRed := "\033[31m" - colorGreen := "\033[32m" - - match := true - printDiff1 := func(a, b string) { - for i := range a { - colorParam := colorReset - if i >= len(b) || a[i] != b[i] { - match = false - colorParam = colorRed - } - fmt.Print(colorParam, string(a[i])) - } - fmt.Println() - } - - printDiff1(a, b) - printDiff1(b, a) - - if match { - fmt.Println(colorGreen, "MATCH!!") - } - - fmt.Print(colorReset) -} - var diffIgnore = []string{ "System.SymbolTable.mFunctions", "System.SymbolTable.mLocations", From e29da2227e9d5184715f19892855f7e180965329 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Fri, 5 May 2023 08:58:32 -0500 Subject: [PATCH 320/464] Adds ground work for custom blueprints. Fixes #660 (#673) * checkpoint * checkpoint * checkpoint * refactor: Instruction -> PackedInstruction * packed / unpacked constraints * refactor: got rid of calldata * refactor: got rid of WireIterator thing * feat: working version of custom blueprint for hints * style: code cleaning * style: cosmetic changes * fix: if we do call Solve, that helps... * fix: make linter happy * fix: address PR comments --- constraint/bls12-377/coeff.go | 8 + constraint/bls12-377/solver.go | 59 ++++++-- constraint/bls12-377/system.go | 7 +- constraint/bls12-381/coeff.go | 8 + constraint/bls12-381/solver.go | 59 ++++++-- constraint/bls12-381/system.go | 7 +- constraint/bls24-315/coeff.go | 8 + constraint/bls24-315/solver.go | 59 ++++++-- constraint/bls24-315/system.go | 7 +- constraint/bls24-317/coeff.go | 8 + constraint/bls24-317/solver.go | 59 ++++++-- constraint/bls24-317/system.go | 7 +- constraint/blueprint.go | 34 ++++- constraint/blueprint_hint.go | 46 ++++-- constraint/blueprint_r1cs.go | 38 ++++- constraint/blueprint_scs.go | 133 +++++++++++------ constraint/bn254/coeff.go | 8 + constraint/bn254/solver.go | 59 ++++++-- constraint/bn254/system.go | 7 +- constraint/bw6-633/coeff.go | 8 + constraint/bw6-633/solver.go | 59 ++++++-- constraint/bw6-633/system.go | 7 +- constraint/bw6-761/coeff.go | 8 + constraint/bw6-761/solver.go | 59 ++++++-- constraint/bw6-761/system.go | 7 +- constraint/core.go | 125 +++++++++------- constraint/field.go | 24 +++ constraint/hint.go | 33 ----- constraint/level_builder.go | 11 +- constraint/linear_expression.go | 7 + constraint/r1cs.go | 22 +-- constraint/r1cs_sparse.go | 21 +-- constraint/system.go | 27 +--- constraint/term.go | 9 ++ constraint/tinyfield/coeff.go | 8 + constraint/tinyfield/solver.go | 59 ++++++-- constraint/tinyfield/system.go | 7 +- frontend/builder.go | 18 +++ frontend/cs/r1cs/builder.go | 28 ++++ frontend/cs/scs/builder.go | 32 +++- frontend/internal/expr/linear_expression.go | 34 +---- frontend/internal/expr/term.go | 25 ++++ .../template/representations/coeff.go.tmpl | 8 + .../template/representations/solver.go.tmpl | 58 ++++++-- .../template/representations/system.go.tmpl | 7 +- std/hints.go | 2 - std/lookup/logderivlookup/blueprint.go | 125 ++++++++++++++++ std/lookup/logderivlookup/logderivlookup.go | 101 +++++++------ .../logderivlookup/logderivlookup_test.go | 14 ++ test/blueprint_solver.go | 140 ++++++++++++++++++ test/blueprint_solver_test.go | 64 ++++++++ test/engine.go | 61 ++++++++ 52 files changed, 1388 insertions(+), 451 deletions(-) create mode 100644 frontend/internal/expr/term.go create mode 100644 std/lookup/logderivlookup/blueprint.go create mode 100644 test/blueprint_solver.go create mode 100644 test/blueprint_solver_test.go diff --git a/constraint/bls12-377/coeff.go b/constraint/bls12-377/coeff.go index d7aa2403b8..a1b86b75c4 100644 --- a/constraint/bls12-377/coeff.go +++ b/constraint/bls12-377/coeff.go @@ -182,3 +182,11 @@ func (engine *field) String(a constraint.Element) string { e := (*fr.Element)(a[:]) return e.String() } + +func (engine *field) Uint64(a constraint.Element) (uint64, bool) { + e := (*fr.Element)(a[:]) + if !e.IsUint64() { + return 0, false + } + return e.Uint64(), true +} diff --git a/constraint/bls12-377/solver.go b/constraint/bls12-377/solver.go index acfd4fdb13..c992d55b4a 100644 --- a/constraint/bls12-377/solver.go +++ b/constraint/bls12-377/solver.go @@ -133,12 +133,17 @@ func (s *solver) set(id int, value fr.Element) { } // computeTerm computes coeff*variable -// TODO @gbotrel check if t is a Constant only func (s *solver) computeTerm(t constraint.Term) fr.Element { cID, vID := t.CoeffID(), t.WireID() + + if t.IsConstant() { + return s.Coefficients[cID] + } + if cID != 0 && !s.solved[vID] { panic("computing a term with an unsolved wire") } + switch cID { case constraint.CoeffIdZero: return fr.Element{} @@ -165,6 +170,11 @@ func (s *solver) accumulateInto(t constraint.Term, r *fr.Element) { cID := t.CoeffID() vID := t.WireID() + if t.IsConstant() { + r.Add(r, &s.Coefficients[cID]) + return + } + switch cID { case constraint.CoeffIdZero: return @@ -344,12 +354,35 @@ func (s *solver) IsSolved(vID uint32) bool { return s.solved[vID] } +// Read interprets input calldata as either a LinearExpression (if R1CS) or a Term (if Plonkish), +// evaluates it and return the result and the number of uint32 word read. +func (s *solver) Read(calldata []uint32) (constraint.Element, int) { + if s.Type == constraint.SystemSparseR1CS { + if calldata[0] != 1 { + panic("invalid calldata") + } + return s.GetValue(calldata[1], calldata[2]), 3 + } + var r fr.Element + n := int(calldata[0]) + j := 1 + for k := 0; k < n; k++ { + // we read k Terms + s.accumulateInto(constraint.Term{CID: calldata[j], VID: calldata[j+1]}, &r) + j += 2 + } + + var ret constraint.Element + copy(ret[:], r[:]) + return ret, j +} + // processInstruction decodes the instruction and execute blueprint-defined logic. // an instruction can encode a hint, a custom constraint or a generic constraint. -func (solver *solver) processInstruction(inst constraint.Instruction, scratch *scratch) error { +func (solver *solver) processInstruction(pi constraint.PackedInstruction, scratch *scratch) error { // fetch the blueprint - blueprint := solver.Blueprints[inst.BlueprintID] - calldata := solver.GetCallData(inst) + blueprint := solver.Blueprints[pi.BlueprintID] + inst := pi.Unpack(&solver.System) cID := inst.ConstraintOffset // here we have 1 constraint in the instruction only if solver.Type == constraint.SystemR1CS { @@ -357,23 +390,23 @@ func (solver *solver) processInstruction(inst constraint.Instruction, scratch *s // TODO @gbotrel we use the solveR1C method for now, having user-defined // blueprint for R1CS would require constraint.Solver interface to add methods // to set a,b,c since it's more efficient to compute these while we solve. - bc.DecompressR1C(&scratch.tR1C, calldata) + bc.DecompressR1C(&scratch.tR1C, inst) return solver.solveR1C(cID, &scratch.tR1C) } - } else if solver.Type == constraint.SystemSparseR1CS { - // blueprint declared "I know how to solve this." - if bc, ok := blueprint.(constraint.BlueprintSolvable); ok { - if err := bc.Solve(solver, calldata); err != nil { - return solver.wrapErrWithDebugInfo(cID, err) - } - return nil + } + + // blueprint declared "I know how to solve this." + if bc, ok := blueprint.(constraint.BlueprintSolvable); ok { + if err := bc.Solve(solver, inst); err != nil { + return solver.wrapErrWithDebugInfo(cID, err) } + return nil } // blueprint encodes a hint, we execute. // TODO @gbotrel may be worth it to move hint logic in blueprint "solve" if bc, ok := blueprint.(constraint.BlueprintHint); ok { - bc.DecompressHint(&scratch.tHint, calldata) + bc.DecompressHint(&scratch.tHint, inst) return solver.solveWithHint(&scratch.tHint) } diff --git a/constraint/bls12-377/system.go b/constraint/bls12-377/system.go index aa49f52be2..a2526acfd4 100644 --- a/constraint/bls12-377/system.go +++ b/constraint/bls12-377/system.go @@ -121,7 +121,7 @@ func (cs *system) GetR1Cs() []constraint.R1C { blueprint := cs.Blueprints[inst.BlueprintID] if bc, ok := blueprint.(constraint.BlueprintR1C); ok { var r1c constraint.R1C - bc.DecompressR1C(&r1c, cs.GetCallData(inst)) + bc.DecompressR1C(&r1c, inst.Unpack(&cs.System)) toReturn = append(toReturn, r1c) } else { panic("not implemented") @@ -196,8 +196,7 @@ func (cs *system) GetSparseR1Cs() []constraint.SparseR1C { blueprint := cs.Blueprints[inst.BlueprintID] if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { var sparseR1C constraint.SparseR1C - calldata := cs.CallData[inst.StartCallData : inst.StartCallData+uint64(blueprint.NbInputs())] - bc.DecompressSparseR1C(&sparseR1C, calldata) + bc.DecompressSparseR1C(&sparseR1C, inst.Unpack(&cs.System)) toReturn = append(toReturn, sparseR1C) } else { panic("not implemented") @@ -234,7 +233,7 @@ func evaluateLROSmallDomain(cs *system, solution []fr.Element) ([]fr.Element, [] for _, inst := range cs.Instructions { blueprint := cs.Blueprints[inst.BlueprintID] if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { - bc.DecompressSparseR1C(&sparseR1C, cs.GetCallData(inst)) + bc.DecompressSparseR1C(&sparseR1C, inst.Unpack(&cs.System)) l[offset+j] = solution[sparseR1C.XA] r[offset+j] = solution[sparseR1C.XB] diff --git a/constraint/bls12-381/coeff.go b/constraint/bls12-381/coeff.go index 55328ca99a..9eb3786806 100644 --- a/constraint/bls12-381/coeff.go +++ b/constraint/bls12-381/coeff.go @@ -182,3 +182,11 @@ func (engine *field) String(a constraint.Element) string { e := (*fr.Element)(a[:]) return e.String() } + +func (engine *field) Uint64(a constraint.Element) (uint64, bool) { + e := (*fr.Element)(a[:]) + if !e.IsUint64() { + return 0, false + } + return e.Uint64(), true +} diff --git a/constraint/bls12-381/solver.go b/constraint/bls12-381/solver.go index 316b69cce5..125ce56e8e 100644 --- a/constraint/bls12-381/solver.go +++ b/constraint/bls12-381/solver.go @@ -133,12 +133,17 @@ func (s *solver) set(id int, value fr.Element) { } // computeTerm computes coeff*variable -// TODO @gbotrel check if t is a Constant only func (s *solver) computeTerm(t constraint.Term) fr.Element { cID, vID := t.CoeffID(), t.WireID() + + if t.IsConstant() { + return s.Coefficients[cID] + } + if cID != 0 && !s.solved[vID] { panic("computing a term with an unsolved wire") } + switch cID { case constraint.CoeffIdZero: return fr.Element{} @@ -165,6 +170,11 @@ func (s *solver) accumulateInto(t constraint.Term, r *fr.Element) { cID := t.CoeffID() vID := t.WireID() + if t.IsConstant() { + r.Add(r, &s.Coefficients[cID]) + return + } + switch cID { case constraint.CoeffIdZero: return @@ -344,12 +354,35 @@ func (s *solver) IsSolved(vID uint32) bool { return s.solved[vID] } +// Read interprets input calldata as either a LinearExpression (if R1CS) or a Term (if Plonkish), +// evaluates it and return the result and the number of uint32 word read. +func (s *solver) Read(calldata []uint32) (constraint.Element, int) { + if s.Type == constraint.SystemSparseR1CS { + if calldata[0] != 1 { + panic("invalid calldata") + } + return s.GetValue(calldata[1], calldata[2]), 3 + } + var r fr.Element + n := int(calldata[0]) + j := 1 + for k := 0; k < n; k++ { + // we read k Terms + s.accumulateInto(constraint.Term{CID: calldata[j], VID: calldata[j+1]}, &r) + j += 2 + } + + var ret constraint.Element + copy(ret[:], r[:]) + return ret, j +} + // processInstruction decodes the instruction and execute blueprint-defined logic. // an instruction can encode a hint, a custom constraint or a generic constraint. -func (solver *solver) processInstruction(inst constraint.Instruction, scratch *scratch) error { +func (solver *solver) processInstruction(pi constraint.PackedInstruction, scratch *scratch) error { // fetch the blueprint - blueprint := solver.Blueprints[inst.BlueprintID] - calldata := solver.GetCallData(inst) + blueprint := solver.Blueprints[pi.BlueprintID] + inst := pi.Unpack(&solver.System) cID := inst.ConstraintOffset // here we have 1 constraint in the instruction only if solver.Type == constraint.SystemR1CS { @@ -357,23 +390,23 @@ func (solver *solver) processInstruction(inst constraint.Instruction, scratch *s // TODO @gbotrel we use the solveR1C method for now, having user-defined // blueprint for R1CS would require constraint.Solver interface to add methods // to set a,b,c since it's more efficient to compute these while we solve. - bc.DecompressR1C(&scratch.tR1C, calldata) + bc.DecompressR1C(&scratch.tR1C, inst) return solver.solveR1C(cID, &scratch.tR1C) } - } else if solver.Type == constraint.SystemSparseR1CS { - // blueprint declared "I know how to solve this." - if bc, ok := blueprint.(constraint.BlueprintSolvable); ok { - if err := bc.Solve(solver, calldata); err != nil { - return solver.wrapErrWithDebugInfo(cID, err) - } - return nil + } + + // blueprint declared "I know how to solve this." + if bc, ok := blueprint.(constraint.BlueprintSolvable); ok { + if err := bc.Solve(solver, inst); err != nil { + return solver.wrapErrWithDebugInfo(cID, err) } + return nil } // blueprint encodes a hint, we execute. // TODO @gbotrel may be worth it to move hint logic in blueprint "solve" if bc, ok := blueprint.(constraint.BlueprintHint); ok { - bc.DecompressHint(&scratch.tHint, calldata) + bc.DecompressHint(&scratch.tHint, inst) return solver.solveWithHint(&scratch.tHint) } diff --git a/constraint/bls12-381/system.go b/constraint/bls12-381/system.go index d8655280bd..53a4aec335 100644 --- a/constraint/bls12-381/system.go +++ b/constraint/bls12-381/system.go @@ -121,7 +121,7 @@ func (cs *system) GetR1Cs() []constraint.R1C { blueprint := cs.Blueprints[inst.BlueprintID] if bc, ok := blueprint.(constraint.BlueprintR1C); ok { var r1c constraint.R1C - bc.DecompressR1C(&r1c, cs.GetCallData(inst)) + bc.DecompressR1C(&r1c, inst.Unpack(&cs.System)) toReturn = append(toReturn, r1c) } else { panic("not implemented") @@ -196,8 +196,7 @@ func (cs *system) GetSparseR1Cs() []constraint.SparseR1C { blueprint := cs.Blueprints[inst.BlueprintID] if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { var sparseR1C constraint.SparseR1C - calldata := cs.CallData[inst.StartCallData : inst.StartCallData+uint64(blueprint.NbInputs())] - bc.DecompressSparseR1C(&sparseR1C, calldata) + bc.DecompressSparseR1C(&sparseR1C, inst.Unpack(&cs.System)) toReturn = append(toReturn, sparseR1C) } else { panic("not implemented") @@ -234,7 +233,7 @@ func evaluateLROSmallDomain(cs *system, solution []fr.Element) ([]fr.Element, [] for _, inst := range cs.Instructions { blueprint := cs.Blueprints[inst.BlueprintID] if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { - bc.DecompressSparseR1C(&sparseR1C, cs.GetCallData(inst)) + bc.DecompressSparseR1C(&sparseR1C, inst.Unpack(&cs.System)) l[offset+j] = solution[sparseR1C.XA] r[offset+j] = solution[sparseR1C.XB] diff --git a/constraint/bls24-315/coeff.go b/constraint/bls24-315/coeff.go index dd3f16bea7..084652f545 100644 --- a/constraint/bls24-315/coeff.go +++ b/constraint/bls24-315/coeff.go @@ -182,3 +182,11 @@ func (engine *field) String(a constraint.Element) string { e := (*fr.Element)(a[:]) return e.String() } + +func (engine *field) Uint64(a constraint.Element) (uint64, bool) { + e := (*fr.Element)(a[:]) + if !e.IsUint64() { + return 0, false + } + return e.Uint64(), true +} diff --git a/constraint/bls24-315/solver.go b/constraint/bls24-315/solver.go index 1bd1ddcc1f..41f89208ce 100644 --- a/constraint/bls24-315/solver.go +++ b/constraint/bls24-315/solver.go @@ -133,12 +133,17 @@ func (s *solver) set(id int, value fr.Element) { } // computeTerm computes coeff*variable -// TODO @gbotrel check if t is a Constant only func (s *solver) computeTerm(t constraint.Term) fr.Element { cID, vID := t.CoeffID(), t.WireID() + + if t.IsConstant() { + return s.Coefficients[cID] + } + if cID != 0 && !s.solved[vID] { panic("computing a term with an unsolved wire") } + switch cID { case constraint.CoeffIdZero: return fr.Element{} @@ -165,6 +170,11 @@ func (s *solver) accumulateInto(t constraint.Term, r *fr.Element) { cID := t.CoeffID() vID := t.WireID() + if t.IsConstant() { + r.Add(r, &s.Coefficients[cID]) + return + } + switch cID { case constraint.CoeffIdZero: return @@ -344,12 +354,35 @@ func (s *solver) IsSolved(vID uint32) bool { return s.solved[vID] } +// Read interprets input calldata as either a LinearExpression (if R1CS) or a Term (if Plonkish), +// evaluates it and return the result and the number of uint32 word read. +func (s *solver) Read(calldata []uint32) (constraint.Element, int) { + if s.Type == constraint.SystemSparseR1CS { + if calldata[0] != 1 { + panic("invalid calldata") + } + return s.GetValue(calldata[1], calldata[2]), 3 + } + var r fr.Element + n := int(calldata[0]) + j := 1 + for k := 0; k < n; k++ { + // we read k Terms + s.accumulateInto(constraint.Term{CID: calldata[j], VID: calldata[j+1]}, &r) + j += 2 + } + + var ret constraint.Element + copy(ret[:], r[:]) + return ret, j +} + // processInstruction decodes the instruction and execute blueprint-defined logic. // an instruction can encode a hint, a custom constraint or a generic constraint. -func (solver *solver) processInstruction(inst constraint.Instruction, scratch *scratch) error { +func (solver *solver) processInstruction(pi constraint.PackedInstruction, scratch *scratch) error { // fetch the blueprint - blueprint := solver.Blueprints[inst.BlueprintID] - calldata := solver.GetCallData(inst) + blueprint := solver.Blueprints[pi.BlueprintID] + inst := pi.Unpack(&solver.System) cID := inst.ConstraintOffset // here we have 1 constraint in the instruction only if solver.Type == constraint.SystemR1CS { @@ -357,23 +390,23 @@ func (solver *solver) processInstruction(inst constraint.Instruction, scratch *s // TODO @gbotrel we use the solveR1C method for now, having user-defined // blueprint for R1CS would require constraint.Solver interface to add methods // to set a,b,c since it's more efficient to compute these while we solve. - bc.DecompressR1C(&scratch.tR1C, calldata) + bc.DecompressR1C(&scratch.tR1C, inst) return solver.solveR1C(cID, &scratch.tR1C) } - } else if solver.Type == constraint.SystemSparseR1CS { - // blueprint declared "I know how to solve this." - if bc, ok := blueprint.(constraint.BlueprintSolvable); ok { - if err := bc.Solve(solver, calldata); err != nil { - return solver.wrapErrWithDebugInfo(cID, err) - } - return nil + } + + // blueprint declared "I know how to solve this." + if bc, ok := blueprint.(constraint.BlueprintSolvable); ok { + if err := bc.Solve(solver, inst); err != nil { + return solver.wrapErrWithDebugInfo(cID, err) } + return nil } // blueprint encodes a hint, we execute. // TODO @gbotrel may be worth it to move hint logic in blueprint "solve" if bc, ok := blueprint.(constraint.BlueprintHint); ok { - bc.DecompressHint(&scratch.tHint, calldata) + bc.DecompressHint(&scratch.tHint, inst) return solver.solveWithHint(&scratch.tHint) } diff --git a/constraint/bls24-315/system.go b/constraint/bls24-315/system.go index aa1da61879..c1a768f146 100644 --- a/constraint/bls24-315/system.go +++ b/constraint/bls24-315/system.go @@ -121,7 +121,7 @@ func (cs *system) GetR1Cs() []constraint.R1C { blueprint := cs.Blueprints[inst.BlueprintID] if bc, ok := blueprint.(constraint.BlueprintR1C); ok { var r1c constraint.R1C - bc.DecompressR1C(&r1c, cs.GetCallData(inst)) + bc.DecompressR1C(&r1c, inst.Unpack(&cs.System)) toReturn = append(toReturn, r1c) } else { panic("not implemented") @@ -196,8 +196,7 @@ func (cs *system) GetSparseR1Cs() []constraint.SparseR1C { blueprint := cs.Blueprints[inst.BlueprintID] if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { var sparseR1C constraint.SparseR1C - calldata := cs.CallData[inst.StartCallData : inst.StartCallData+uint64(blueprint.NbInputs())] - bc.DecompressSparseR1C(&sparseR1C, calldata) + bc.DecompressSparseR1C(&sparseR1C, inst.Unpack(&cs.System)) toReturn = append(toReturn, sparseR1C) } else { panic("not implemented") @@ -234,7 +233,7 @@ func evaluateLROSmallDomain(cs *system, solution []fr.Element) ([]fr.Element, [] for _, inst := range cs.Instructions { blueprint := cs.Blueprints[inst.BlueprintID] if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { - bc.DecompressSparseR1C(&sparseR1C, cs.GetCallData(inst)) + bc.DecompressSparseR1C(&sparseR1C, inst.Unpack(&cs.System)) l[offset+j] = solution[sparseR1C.XA] r[offset+j] = solution[sparseR1C.XB] diff --git a/constraint/bls24-317/coeff.go b/constraint/bls24-317/coeff.go index 15c2373224..5df92edf1b 100644 --- a/constraint/bls24-317/coeff.go +++ b/constraint/bls24-317/coeff.go @@ -182,3 +182,11 @@ func (engine *field) String(a constraint.Element) string { e := (*fr.Element)(a[:]) return e.String() } + +func (engine *field) Uint64(a constraint.Element) (uint64, bool) { + e := (*fr.Element)(a[:]) + if !e.IsUint64() { + return 0, false + } + return e.Uint64(), true +} diff --git a/constraint/bls24-317/solver.go b/constraint/bls24-317/solver.go index 17b06208d3..e1dcad13e9 100644 --- a/constraint/bls24-317/solver.go +++ b/constraint/bls24-317/solver.go @@ -133,12 +133,17 @@ func (s *solver) set(id int, value fr.Element) { } // computeTerm computes coeff*variable -// TODO @gbotrel check if t is a Constant only func (s *solver) computeTerm(t constraint.Term) fr.Element { cID, vID := t.CoeffID(), t.WireID() + + if t.IsConstant() { + return s.Coefficients[cID] + } + if cID != 0 && !s.solved[vID] { panic("computing a term with an unsolved wire") } + switch cID { case constraint.CoeffIdZero: return fr.Element{} @@ -165,6 +170,11 @@ func (s *solver) accumulateInto(t constraint.Term, r *fr.Element) { cID := t.CoeffID() vID := t.WireID() + if t.IsConstant() { + r.Add(r, &s.Coefficients[cID]) + return + } + switch cID { case constraint.CoeffIdZero: return @@ -344,12 +354,35 @@ func (s *solver) IsSolved(vID uint32) bool { return s.solved[vID] } +// Read interprets input calldata as either a LinearExpression (if R1CS) or a Term (if Plonkish), +// evaluates it and return the result and the number of uint32 word read. +func (s *solver) Read(calldata []uint32) (constraint.Element, int) { + if s.Type == constraint.SystemSparseR1CS { + if calldata[0] != 1 { + panic("invalid calldata") + } + return s.GetValue(calldata[1], calldata[2]), 3 + } + var r fr.Element + n := int(calldata[0]) + j := 1 + for k := 0; k < n; k++ { + // we read k Terms + s.accumulateInto(constraint.Term{CID: calldata[j], VID: calldata[j+1]}, &r) + j += 2 + } + + var ret constraint.Element + copy(ret[:], r[:]) + return ret, j +} + // processInstruction decodes the instruction and execute blueprint-defined logic. // an instruction can encode a hint, a custom constraint or a generic constraint. -func (solver *solver) processInstruction(inst constraint.Instruction, scratch *scratch) error { +func (solver *solver) processInstruction(pi constraint.PackedInstruction, scratch *scratch) error { // fetch the blueprint - blueprint := solver.Blueprints[inst.BlueprintID] - calldata := solver.GetCallData(inst) + blueprint := solver.Blueprints[pi.BlueprintID] + inst := pi.Unpack(&solver.System) cID := inst.ConstraintOffset // here we have 1 constraint in the instruction only if solver.Type == constraint.SystemR1CS { @@ -357,23 +390,23 @@ func (solver *solver) processInstruction(inst constraint.Instruction, scratch *s // TODO @gbotrel we use the solveR1C method for now, having user-defined // blueprint for R1CS would require constraint.Solver interface to add methods // to set a,b,c since it's more efficient to compute these while we solve. - bc.DecompressR1C(&scratch.tR1C, calldata) + bc.DecompressR1C(&scratch.tR1C, inst) return solver.solveR1C(cID, &scratch.tR1C) } - } else if solver.Type == constraint.SystemSparseR1CS { - // blueprint declared "I know how to solve this." - if bc, ok := blueprint.(constraint.BlueprintSolvable); ok { - if err := bc.Solve(solver, calldata); err != nil { - return solver.wrapErrWithDebugInfo(cID, err) - } - return nil + } + + // blueprint declared "I know how to solve this." + if bc, ok := blueprint.(constraint.BlueprintSolvable); ok { + if err := bc.Solve(solver, inst); err != nil { + return solver.wrapErrWithDebugInfo(cID, err) } + return nil } // blueprint encodes a hint, we execute. // TODO @gbotrel may be worth it to move hint logic in blueprint "solve" if bc, ok := blueprint.(constraint.BlueprintHint); ok { - bc.DecompressHint(&scratch.tHint, calldata) + bc.DecompressHint(&scratch.tHint, inst) return solver.solveWithHint(&scratch.tHint) } diff --git a/constraint/bls24-317/system.go b/constraint/bls24-317/system.go index d0ea66cf21..405924f0df 100644 --- a/constraint/bls24-317/system.go +++ b/constraint/bls24-317/system.go @@ -121,7 +121,7 @@ func (cs *system) GetR1Cs() []constraint.R1C { blueprint := cs.Blueprints[inst.BlueprintID] if bc, ok := blueprint.(constraint.BlueprintR1C); ok { var r1c constraint.R1C - bc.DecompressR1C(&r1c, cs.GetCallData(inst)) + bc.DecompressR1C(&r1c, inst.Unpack(&cs.System)) toReturn = append(toReturn, r1c) } else { panic("not implemented") @@ -196,8 +196,7 @@ func (cs *system) GetSparseR1Cs() []constraint.SparseR1C { blueprint := cs.Blueprints[inst.BlueprintID] if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { var sparseR1C constraint.SparseR1C - calldata := cs.CallData[inst.StartCallData : inst.StartCallData+uint64(blueprint.NbInputs())] - bc.DecompressSparseR1C(&sparseR1C, calldata) + bc.DecompressSparseR1C(&sparseR1C, inst.Unpack(&cs.System)) toReturn = append(toReturn, sparseR1C) } else { panic("not implemented") @@ -234,7 +233,7 @@ func evaluateLROSmallDomain(cs *system, solution []fr.Element) ([]fr.Element, [] for _, inst := range cs.Instructions { blueprint := cs.Blueprints[inst.BlueprintID] if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { - bc.DecompressSparseR1C(&sparseR1C, cs.GetCallData(inst)) + bc.DecompressSparseR1C(&sparseR1C, inst.Unpack(&cs.System)) l[offset+j] = solution[sparseR1C.XA] r[offset+j] = solution[sparseR1C.XB] diff --git a/constraint/blueprint.go b/constraint/blueprint.go index 8e7abe42ce..2ce8decf30 100644 --- a/constraint/blueprint.go +++ b/constraint/blueprint.go @@ -7,45 +7,67 @@ type BlueprintID uint32 // constraints or instructions, and specify for the solving (or zksnark setup) part how to // "decompress" and optionally "solve" the associated wires. type Blueprint interface { - // NbInputs return the number of calldata input this blueprint expects. + // CalldataSize return the number of calldata input this blueprint expects. // If this is unknown at compile time, implementation must return -1 and store // the actual number of inputs in the first index of the calldata. - NbInputs() int + CalldataSize() int // NbConstraints return the number of constraints this blueprint creates. NbConstraints() int + + // NbOutputs return the number of output wires this blueprint creates. + NbOutputs(inst Instruction) int + + // WireWalker returns a function that walks the wires appearing in the blueprint. + // This is used by the level builder to build a dependency graph between instructions. + WireWalker(inst Instruction) func(cb func(wire uint32)) } // Solver represents the state of a constraint system solver at runtime. Blueprint can interact // with this object to perform run time logic, solve constraints and assign values in the solution. type Solver interface { Field + GetValue(cID, vID uint32) Element GetCoeff(cID uint32) Element SetValue(vID uint32, f Element) IsSolved(vID uint32) bool + + // Read interprets input calldata as a LinearExpression, + // evaluates it and return the result and the number of uint32 word read. + Read(calldata []uint32) (Element, int) } // BlueprintSolvable represents a blueprint that knows how to solve itself. type BlueprintSolvable interface { + Blueprint // Solve may return an error if the decoded constraint / calldata is unsolvable. - Solve(s Solver, calldata []uint32) error + Solve(s Solver, instruction Instruction) error } // BlueprintR1C indicates that the blueprint and associated calldata encodes a R1C type BlueprintR1C interface { + Blueprint CompressR1C(c *R1C) []uint32 - DecompressR1C(into *R1C, calldata []uint32) + DecompressR1C(into *R1C, instruction Instruction) } // BlueprintSparseR1C indicates that the blueprint and associated calldata encodes a SparseR1C. type BlueprintSparseR1C interface { + Blueprint CompressSparseR1C(c *SparseR1C) []uint32 - DecompressSparseR1C(into *SparseR1C, calldata []uint32) + DecompressSparseR1C(into *SparseR1C, instruction Instruction) } // BlueprintHint indicates that the blueprint and associated calldata encodes a hint. type BlueprintHint interface { + Blueprint CompressHint(HintMapping) []uint32 - DecompressHint(h *HintMapping, calldata []uint32) + DecompressHint(h *HintMapping, instruction Instruction) +} + +// Compressable represent an object that knows how to encode itself as a []uint32. +type Compressable interface { + // Compress interprets the objects as a LinearExpression and encodes it as a []uint32. + Compress(to *[]uint32) } diff --git a/constraint/blueprint_hint.go b/constraint/blueprint_hint.go index 159cb6042e..acf3f36ae3 100644 --- a/constraint/blueprint_hint.go +++ b/constraint/blueprint_hint.go @@ -1,13 +1,15 @@ package constraint -import "github.com/consensys/gnark/constraint/solver" +import ( + "github.com/consensys/gnark/constraint/solver" +) type BlueprintGenericHint struct{} -func (b *BlueprintGenericHint) DecompressHint(h *HintMapping, calldata []uint32) { +func (b *BlueprintGenericHint) DecompressHint(h *HintMapping, inst Instruction) { // ignore first call data == nbInputs - h.HintID = solver.HintID(calldata[1]) - lenInputs := int(calldata[2]) + h.HintID = solver.HintID(inst.Calldata[1]) + lenInputs := int(inst.Calldata[2]) if cap(h.Inputs) >= lenInputs { h.Inputs = h.Inputs[:lenInputs] } else { @@ -16,7 +18,7 @@ func (b *BlueprintGenericHint) DecompressHint(h *HintMapping, calldata []uint32) j := 3 for i := 0; i < lenInputs; i++ { - n := int(calldata[j]) // len of linear expr + n := int(inst.Calldata[j]) // len of linear expr j++ if cap(h.Inputs[i]) >= n { h.Inputs[i] = h.Inputs[i][:0] @@ -24,12 +26,12 @@ func (b *BlueprintGenericHint) DecompressHint(h *HintMapping, calldata []uint32) h.Inputs[i] = make(LinearExpression, 0, n) } for k := 0; k < n; k++ { - h.Inputs[i] = append(h.Inputs[i], Term{CID: calldata[j], VID: calldata[j+1]}) + h.Inputs[i] = append(h.Inputs[i], Term{CID: inst.Calldata[j], VID: inst.Calldata[j+1]}) j += 2 } } - h.OutputRange.Start = calldata[j] - h.OutputRange.End = calldata[j+1] + h.OutputRange.Start = inst.Calldata[j] + h.OutputRange.End = inst.Calldata[j+1] } func (b *BlueprintGenericHint) CompressHint(h HintMapping) []uint32 { @@ -63,9 +65,35 @@ func (b *BlueprintGenericHint) CompressHint(h HintMapping) []uint32 { return r } -func (b *BlueprintGenericHint) NbInputs() int { +func (b *BlueprintGenericHint) CalldataSize() int { return -1 } func (b *BlueprintGenericHint) NbConstraints() int { return 0 } + +func (b *BlueprintGenericHint) NbOutputs(inst Instruction) int { + return 0 +} + +func (b *BlueprintGenericHint) WireWalker(inst Instruction) func(cb func(wire uint32)) { + return func(cb func(wire uint32)) { + lenInputs := int(inst.Calldata[2]) + j := 3 + for i := 0; i < lenInputs; i++ { + n := int(inst.Calldata[j]) // len of linear expr + j++ + + for k := 0; k < n; k++ { + t := Term{CID: inst.Calldata[j], VID: inst.Calldata[j+1]} + if !t.IsConstant() { + cb(t.VID) + } + j += 2 + } + } + for k := inst.Calldata[j]; k < inst.Calldata[j+1]; k++ { + cb(k) + } + } +} diff --git a/constraint/blueprint_r1cs.go b/constraint/blueprint_r1cs.go index b274397b28..ddd09e56ce 100644 --- a/constraint/blueprint_r1cs.go +++ b/constraint/blueprint_r1cs.go @@ -6,13 +6,16 @@ package constraint // L * R == 0 type BlueprintGenericR1C struct{} -func (b *BlueprintGenericR1C) NbInputs() int { +func (b *BlueprintGenericR1C) CalldataSize() int { // size of linear expressions are unknown. return -1 } func (b *BlueprintGenericR1C) NbConstraints() int { return 1 } +func (b *BlueprintGenericR1C) NbOutputs(inst Instruction) int { + return 0 +} func (b *BlueprintGenericR1C) CompressR1C(c *R1C) []uint32 { // we store total nb inputs, len L, len R, len O, and then the "flatten" linear expressions @@ -32,7 +35,7 @@ func (b *BlueprintGenericR1C) CompressR1C(c *R1C) []uint32 { return r } -func (b *BlueprintGenericR1C) DecompressR1C(c *R1C, calldata []uint32) { +func (b *BlueprintGenericR1C) DecompressR1C(c *R1C, inst Instruction) { copySlice := func(slice *LinearExpression, expectedLen, idx int) { if cap(*slice) >= expectedLen { (*slice) = (*slice)[:expectedLen] @@ -40,16 +43,16 @@ func (b *BlueprintGenericR1C) DecompressR1C(c *R1C, calldata []uint32) { (*slice) = make(LinearExpression, expectedLen, expectedLen*2) } for k := 0; k < expectedLen; k++ { - (*slice)[k].CID = calldata[idx] + (*slice)[k].CID = inst.Calldata[idx] idx++ - (*slice)[k].VID = calldata[idx] + (*slice)[k].VID = inst.Calldata[idx] idx++ } } - lenL := int(calldata[1]) - lenR := int(calldata[2]) - lenO := int(calldata[3]) + lenL := int(inst.Calldata[1]) + lenR := int(inst.Calldata[2]) + lenO := int(inst.Calldata[3]) const offset = 4 copySlice(&c.L, lenL, offset) @@ -57,6 +60,27 @@ func (b *BlueprintGenericR1C) DecompressR1C(c *R1C, calldata []uint32) { copySlice(&c.O, lenO, offset+2*(lenL+lenR)) } +func (b *BlueprintGenericR1C) WireWalker(inst Instruction) func(cb func(wire uint32)) { + return func(cb func(wire uint32)) { + lenL := int(inst.Calldata[1]) + lenR := int(inst.Calldata[2]) + lenO := int(inst.Calldata[3]) + + appendWires := func(expectedLen, idx int) { + for k := 0; k < expectedLen; k++ { + idx++ + cb(inst.Calldata[idx]) + idx++ + } + } + + const offset = 4 + appendWires(lenL, offset) + appendWires(lenR, offset+2*lenL) + appendWires(lenO, offset+2*(lenL+lenR)) + } +} + // since frontend is single threaded, to avoid allocating slices at each compress call // we transit the compressed output through here var bufCalldata []uint32 diff --git a/constraint/blueprint_scs.go b/constraint/blueprint_scs.go index 90ede13fb7..69fa67c55a 100644 --- a/constraint/blueprint_scs.go +++ b/constraint/blueprint_scs.go @@ -17,13 +17,25 @@ var ( type BlueprintGenericSparseR1C struct { } -func (b *BlueprintGenericSparseR1C) NbInputs() int { +func (b *BlueprintGenericSparseR1C) CalldataSize() int { return 9 // number of fields in SparseR1C } func (b *BlueprintGenericSparseR1C) NbConstraints() int { return 1 } +func (b *BlueprintGenericSparseR1C) NbOutputs(inst Instruction) int { + return 0 +} + +func (b *BlueprintGenericSparseR1C) WireWalker(inst Instruction) func(cb func(wire uint32)) { + return func(cb func(wire uint32)) { + cb(inst.Calldata[0]) // xa + cb(inst.Calldata[1]) // xb + cb(inst.Calldata[2]) // xc + } +} + func (b *BlueprintGenericSparseR1C) CompressSparseR1C(c *SparseR1C) []uint32 { bufSCS[0] = c.XA bufSCS[1] = c.XB @@ -37,23 +49,23 @@ func (b *BlueprintGenericSparseR1C) CompressSparseR1C(c *SparseR1C) []uint32 { return bufSCS[:] } -func (b *BlueprintGenericSparseR1C) DecompressSparseR1C(c *SparseR1C, calldata []uint32) { +func (b *BlueprintGenericSparseR1C) DecompressSparseR1C(c *SparseR1C, inst Instruction) { c.Clear() - c.XA = calldata[0] - c.XB = calldata[1] - c.XC = calldata[2] - c.QL = calldata[3] - c.QR = calldata[4] - c.QO = calldata[5] - c.QM = calldata[6] - c.QC = calldata[7] - c.Commitment = CommitmentConstraint(calldata[8]) + c.XA = inst.Calldata[0] + c.XB = inst.Calldata[1] + c.XC = inst.Calldata[2] + c.QL = inst.Calldata[3] + c.QR = inst.Calldata[4] + c.QO = inst.Calldata[5] + c.QM = inst.Calldata[6] + c.QC = inst.Calldata[7] + c.Commitment = CommitmentConstraint(inst.Calldata[8]) } -func (b *BlueprintGenericSparseR1C) Solve(s Solver, calldata []uint32) error { +func (b *BlueprintGenericSparseR1C) Solve(s Solver, inst Instruction) error { var c SparseR1C - b.DecompressSparseR1C(&c, calldata) + b.DecompressSparseR1C(&c, inst) if c.Commitment != NOT { // a constraint of the form f_L - PI_2 = 0 or f_L = Comm. // these are there for enforcing the correctness of the commitment and can be skipped in solving time @@ -159,12 +171,23 @@ func (b *BlueprintGenericSparseR1C) checkConstraint(c *SparseR1C, s Solver) erro // qM⋅(xaxb) == xc type BlueprintSparseR1CMul struct{} -func (b *BlueprintSparseR1CMul) NbInputs() int { +func (b *BlueprintSparseR1CMul) CalldataSize() int { return 4 } func (b *BlueprintSparseR1CMul) NbConstraints() int { return 1 } +func (b *BlueprintSparseR1CMul) NbOutputs(inst Instruction) int { + return 0 +} + +func (b *BlueprintSparseR1CMul) WireWalker(inst Instruction) func(cb func(wire uint32)) { + return func(cb func(wire uint32)) { + cb(inst.Calldata[0]) // xa + cb(inst.Calldata[1]) // xb + cb(inst.Calldata[2]) // xc + } +} func (b *BlueprintSparseR1CMul) CompressSparseR1C(c *SparseR1C) []uint32 { bufSCS[0] = c.XA @@ -174,24 +197,24 @@ func (b *BlueprintSparseR1CMul) CompressSparseR1C(c *SparseR1C) []uint32 { return bufSCS[:4] } -func (b *BlueprintSparseR1CMul) Solve(s Solver, calldata []uint32) error { +func (b *BlueprintSparseR1CMul) Solve(s Solver, inst Instruction) error { // qM⋅(xaxb) == xc - m0 := s.GetValue(calldata[3], calldata[0]) - m1 := s.GetValue(CoeffIdOne, calldata[1]) + m0 := s.GetValue(inst.Calldata[3], inst.Calldata[0]) + m1 := s.GetValue(CoeffIdOne, inst.Calldata[1]) m0 = s.Mul(m0, m1) - s.SetValue(calldata[2], m0) + s.SetValue(inst.Calldata[2], m0) return nil } -func (b *BlueprintSparseR1CMul) DecompressSparseR1C(c *SparseR1C, calldata []uint32) { +func (b *BlueprintSparseR1CMul) DecompressSparseR1C(c *SparseR1C, inst Instruction) { c.Clear() - c.XA = calldata[0] - c.XB = calldata[1] - c.XC = calldata[2] + c.XA = inst.Calldata[0] + c.XB = inst.Calldata[1] + c.XC = inst.Calldata[2] c.QO = CoeffIdMinusOne - c.QM = calldata[3] + c.QM = inst.Calldata[3] } // BlueprintSparseR1CAdd implements Blueprint, BlueprintSolvable and BlueprintSparseR1C. @@ -200,12 +223,23 @@ func (b *BlueprintSparseR1CMul) DecompressSparseR1C(c *SparseR1C, calldata []uin // qL⋅xa + qR⋅xb + qC == xc type BlueprintSparseR1CAdd struct{} -func (b *BlueprintSparseR1CAdd) NbInputs() int { +func (b *BlueprintSparseR1CAdd) CalldataSize() int { return 6 } func (b *BlueprintSparseR1CAdd) NbConstraints() int { return 1 } +func (b *BlueprintSparseR1CAdd) NbOutputs(inst Instruction) int { + return 0 +} + +func (b *BlueprintSparseR1CAdd) WireWalker(inst Instruction) func(cb func(wire uint32)) { + return func(cb func(wire uint32)) { + cb(inst.Calldata[0]) // xa + cb(inst.Calldata[1]) // xb + cb(inst.Calldata[2]) // xc + } +} func (b *BlueprintSparseR1CAdd) CompressSparseR1C(c *SparseR1C) []uint32 { bufSCS[0] = c.XA @@ -217,28 +251,28 @@ func (b *BlueprintSparseR1CAdd) CompressSparseR1C(c *SparseR1C) []uint32 { return bufSCS[:6] } -func (blueprint *BlueprintSparseR1CAdd) Solve(s Solver, calldata []uint32) error { +func (blueprint *BlueprintSparseR1CAdd) Solve(s Solver, inst Instruction) error { // a + b + k == c - a := s.GetValue(calldata[3], calldata[0]) - b := s.GetValue(calldata[4], calldata[1]) - k := s.GetCoeff(calldata[5]) + a := s.GetValue(inst.Calldata[3], inst.Calldata[0]) + b := s.GetValue(inst.Calldata[4], inst.Calldata[1]) + k := s.GetCoeff(inst.Calldata[5]) a = s.Add(a, b) a = s.Add(a, k) - s.SetValue(calldata[2], a) + s.SetValue(inst.Calldata[2], a) return nil } -func (b *BlueprintSparseR1CAdd) DecompressSparseR1C(c *SparseR1C, calldata []uint32) { +func (b *BlueprintSparseR1CAdd) DecompressSparseR1C(c *SparseR1C, inst Instruction) { c.Clear() - c.XA = calldata[0] - c.XB = calldata[1] - c.XC = calldata[2] - c.QL = calldata[3] - c.QR = calldata[4] + c.XA = inst.Calldata[0] + c.XB = inst.Calldata[1] + c.XC = inst.Calldata[2] + c.QL = inst.Calldata[3] + c.QR = inst.Calldata[4] c.QO = CoeffIdMinusOne - c.QC = calldata[5] + c.QC = inst.Calldata[5] } // BlueprintSparseR1CBool implements Blueprint, BlueprintSolvable and BlueprintSparseR1C. @@ -248,12 +282,21 @@ func (b *BlueprintSparseR1CAdd) DecompressSparseR1C(c *SparseR1C, calldata []uin // that is v + -v*v == 0 type BlueprintSparseR1CBool struct{} -func (b *BlueprintSparseR1CBool) NbInputs() int { +func (b *BlueprintSparseR1CBool) CalldataSize() int { return 3 } func (b *BlueprintSparseR1CBool) NbConstraints() int { return 1 } +func (b *BlueprintSparseR1CBool) NbOutputs(inst Instruction) int { + return 0 +} + +func (b *BlueprintSparseR1CBool) WireWalker(inst Instruction) func(cb func(wire uint32)) { + return func(cb func(wire uint32)) { + cb(inst.Calldata[0]) // xa + } +} func (b *BlueprintSparseR1CBool) CompressSparseR1C(c *SparseR1C) []uint32 { bufSCS[0] = c.XA @@ -262,11 +305,11 @@ func (b *BlueprintSparseR1CBool) CompressSparseR1C(c *SparseR1C) []uint32 { return bufSCS[:3] } -func (blueprint *BlueprintSparseR1CBool) Solve(s Solver, calldata []uint32) error { +func (blueprint *BlueprintSparseR1CBool) Solve(s Solver, inst Instruction) error { // all wires are already solved, we just check the constraint. - v1 := s.GetValue(calldata[1], calldata[0]) - v2 := s.GetValue(calldata[2], calldata[0]) - v := s.GetValue(CoeffIdOne, calldata[0]) + v1 := s.GetValue(inst.Calldata[1], inst.Calldata[0]) + v2 := s.GetValue(inst.Calldata[2], inst.Calldata[0]) + v := s.GetValue(CoeffIdOne, inst.Calldata[0]) v = s.Mul(v, v2) v = s.Add(v1, v) if !v.IsZero() { @@ -275,12 +318,12 @@ func (blueprint *BlueprintSparseR1CBool) Solve(s Solver, calldata []uint32) erro return nil } -func (b *BlueprintSparseR1CBool) DecompressSparseR1C(c *SparseR1C, calldata []uint32) { +func (b *BlueprintSparseR1CBool) DecompressSparseR1C(c *SparseR1C, inst Instruction) { c.Clear() - c.XA = calldata[0] + c.XA = inst.Calldata[0] c.XB = c.XA - c.QL = calldata[1] - c.QM = calldata[2] + c.QL = inst.Calldata[1] + c.QM = inst.Calldata[2] } // since frontend is single threaded, to avoid allocating slices at each compress call diff --git a/constraint/bn254/coeff.go b/constraint/bn254/coeff.go index 0ce316660d..da49b0e68b 100644 --- a/constraint/bn254/coeff.go +++ b/constraint/bn254/coeff.go @@ -182,3 +182,11 @@ func (engine *field) String(a constraint.Element) string { e := (*fr.Element)(a[:]) return e.String() } + +func (engine *field) Uint64(a constraint.Element) (uint64, bool) { + e := (*fr.Element)(a[:]) + if !e.IsUint64() { + return 0, false + } + return e.Uint64(), true +} diff --git a/constraint/bn254/solver.go b/constraint/bn254/solver.go index 6e8b27587f..5038f2ef4b 100644 --- a/constraint/bn254/solver.go +++ b/constraint/bn254/solver.go @@ -133,12 +133,17 @@ func (s *solver) set(id int, value fr.Element) { } // computeTerm computes coeff*variable -// TODO @gbotrel check if t is a Constant only func (s *solver) computeTerm(t constraint.Term) fr.Element { cID, vID := t.CoeffID(), t.WireID() + + if t.IsConstant() { + return s.Coefficients[cID] + } + if cID != 0 && !s.solved[vID] { panic("computing a term with an unsolved wire") } + switch cID { case constraint.CoeffIdZero: return fr.Element{} @@ -165,6 +170,11 @@ func (s *solver) accumulateInto(t constraint.Term, r *fr.Element) { cID := t.CoeffID() vID := t.WireID() + if t.IsConstant() { + r.Add(r, &s.Coefficients[cID]) + return + } + switch cID { case constraint.CoeffIdZero: return @@ -344,12 +354,35 @@ func (s *solver) IsSolved(vID uint32) bool { return s.solved[vID] } +// Read interprets input calldata as either a LinearExpression (if R1CS) or a Term (if Plonkish), +// evaluates it and return the result and the number of uint32 word read. +func (s *solver) Read(calldata []uint32) (constraint.Element, int) { + if s.Type == constraint.SystemSparseR1CS { + if calldata[0] != 1 { + panic("invalid calldata") + } + return s.GetValue(calldata[1], calldata[2]), 3 + } + var r fr.Element + n := int(calldata[0]) + j := 1 + for k := 0; k < n; k++ { + // we read k Terms + s.accumulateInto(constraint.Term{CID: calldata[j], VID: calldata[j+1]}, &r) + j += 2 + } + + var ret constraint.Element + copy(ret[:], r[:]) + return ret, j +} + // processInstruction decodes the instruction and execute blueprint-defined logic. // an instruction can encode a hint, a custom constraint or a generic constraint. -func (solver *solver) processInstruction(inst constraint.Instruction, scratch *scratch) error { +func (solver *solver) processInstruction(pi constraint.PackedInstruction, scratch *scratch) error { // fetch the blueprint - blueprint := solver.Blueprints[inst.BlueprintID] - calldata := solver.GetCallData(inst) + blueprint := solver.Blueprints[pi.BlueprintID] + inst := pi.Unpack(&solver.System) cID := inst.ConstraintOffset // here we have 1 constraint in the instruction only if solver.Type == constraint.SystemR1CS { @@ -357,23 +390,23 @@ func (solver *solver) processInstruction(inst constraint.Instruction, scratch *s // TODO @gbotrel we use the solveR1C method for now, having user-defined // blueprint for R1CS would require constraint.Solver interface to add methods // to set a,b,c since it's more efficient to compute these while we solve. - bc.DecompressR1C(&scratch.tR1C, calldata) + bc.DecompressR1C(&scratch.tR1C, inst) return solver.solveR1C(cID, &scratch.tR1C) } - } else if solver.Type == constraint.SystemSparseR1CS { - // blueprint declared "I know how to solve this." - if bc, ok := blueprint.(constraint.BlueprintSolvable); ok { - if err := bc.Solve(solver, calldata); err != nil { - return solver.wrapErrWithDebugInfo(cID, err) - } - return nil + } + + // blueprint declared "I know how to solve this." + if bc, ok := blueprint.(constraint.BlueprintSolvable); ok { + if err := bc.Solve(solver, inst); err != nil { + return solver.wrapErrWithDebugInfo(cID, err) } + return nil } // blueprint encodes a hint, we execute. // TODO @gbotrel may be worth it to move hint logic in blueprint "solve" if bc, ok := blueprint.(constraint.BlueprintHint); ok { - bc.DecompressHint(&scratch.tHint, calldata) + bc.DecompressHint(&scratch.tHint, inst) return solver.solveWithHint(&scratch.tHint) } diff --git a/constraint/bn254/system.go b/constraint/bn254/system.go index c66609b432..7fc39e7136 100644 --- a/constraint/bn254/system.go +++ b/constraint/bn254/system.go @@ -121,7 +121,7 @@ func (cs *system) GetR1Cs() []constraint.R1C { blueprint := cs.Blueprints[inst.BlueprintID] if bc, ok := blueprint.(constraint.BlueprintR1C); ok { var r1c constraint.R1C - bc.DecompressR1C(&r1c, cs.GetCallData(inst)) + bc.DecompressR1C(&r1c, inst.Unpack(&cs.System)) toReturn = append(toReturn, r1c) } else { panic("not implemented") @@ -196,8 +196,7 @@ func (cs *system) GetSparseR1Cs() []constraint.SparseR1C { blueprint := cs.Blueprints[inst.BlueprintID] if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { var sparseR1C constraint.SparseR1C - calldata := cs.CallData[inst.StartCallData : inst.StartCallData+uint64(blueprint.NbInputs())] - bc.DecompressSparseR1C(&sparseR1C, calldata) + bc.DecompressSparseR1C(&sparseR1C, inst.Unpack(&cs.System)) toReturn = append(toReturn, sparseR1C) } else { panic("not implemented") @@ -234,7 +233,7 @@ func evaluateLROSmallDomain(cs *system, solution []fr.Element) ([]fr.Element, [] for _, inst := range cs.Instructions { blueprint := cs.Blueprints[inst.BlueprintID] if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { - bc.DecompressSparseR1C(&sparseR1C, cs.GetCallData(inst)) + bc.DecompressSparseR1C(&sparseR1C, inst.Unpack(&cs.System)) l[offset+j] = solution[sparseR1C.XA] r[offset+j] = solution[sparseR1C.XB] diff --git a/constraint/bw6-633/coeff.go b/constraint/bw6-633/coeff.go index fd9a96465c..dd1d29ad18 100644 --- a/constraint/bw6-633/coeff.go +++ b/constraint/bw6-633/coeff.go @@ -182,3 +182,11 @@ func (engine *field) String(a constraint.Element) string { e := (*fr.Element)(a[:]) return e.String() } + +func (engine *field) Uint64(a constraint.Element) (uint64, bool) { + e := (*fr.Element)(a[:]) + if !e.IsUint64() { + return 0, false + } + return e.Uint64(), true +} diff --git a/constraint/bw6-633/solver.go b/constraint/bw6-633/solver.go index 67cb4d9d8e..948bb4a2e4 100644 --- a/constraint/bw6-633/solver.go +++ b/constraint/bw6-633/solver.go @@ -133,12 +133,17 @@ func (s *solver) set(id int, value fr.Element) { } // computeTerm computes coeff*variable -// TODO @gbotrel check if t is a Constant only func (s *solver) computeTerm(t constraint.Term) fr.Element { cID, vID := t.CoeffID(), t.WireID() + + if t.IsConstant() { + return s.Coefficients[cID] + } + if cID != 0 && !s.solved[vID] { panic("computing a term with an unsolved wire") } + switch cID { case constraint.CoeffIdZero: return fr.Element{} @@ -165,6 +170,11 @@ func (s *solver) accumulateInto(t constraint.Term, r *fr.Element) { cID := t.CoeffID() vID := t.WireID() + if t.IsConstant() { + r.Add(r, &s.Coefficients[cID]) + return + } + switch cID { case constraint.CoeffIdZero: return @@ -344,12 +354,35 @@ func (s *solver) IsSolved(vID uint32) bool { return s.solved[vID] } +// Read interprets input calldata as either a LinearExpression (if R1CS) or a Term (if Plonkish), +// evaluates it and return the result and the number of uint32 word read. +func (s *solver) Read(calldata []uint32) (constraint.Element, int) { + if s.Type == constraint.SystemSparseR1CS { + if calldata[0] != 1 { + panic("invalid calldata") + } + return s.GetValue(calldata[1], calldata[2]), 3 + } + var r fr.Element + n := int(calldata[0]) + j := 1 + for k := 0; k < n; k++ { + // we read k Terms + s.accumulateInto(constraint.Term{CID: calldata[j], VID: calldata[j+1]}, &r) + j += 2 + } + + var ret constraint.Element + copy(ret[:], r[:]) + return ret, j +} + // processInstruction decodes the instruction and execute blueprint-defined logic. // an instruction can encode a hint, a custom constraint or a generic constraint. -func (solver *solver) processInstruction(inst constraint.Instruction, scratch *scratch) error { +func (solver *solver) processInstruction(pi constraint.PackedInstruction, scratch *scratch) error { // fetch the blueprint - blueprint := solver.Blueprints[inst.BlueprintID] - calldata := solver.GetCallData(inst) + blueprint := solver.Blueprints[pi.BlueprintID] + inst := pi.Unpack(&solver.System) cID := inst.ConstraintOffset // here we have 1 constraint in the instruction only if solver.Type == constraint.SystemR1CS { @@ -357,23 +390,23 @@ func (solver *solver) processInstruction(inst constraint.Instruction, scratch *s // TODO @gbotrel we use the solveR1C method for now, having user-defined // blueprint for R1CS would require constraint.Solver interface to add methods // to set a,b,c since it's more efficient to compute these while we solve. - bc.DecompressR1C(&scratch.tR1C, calldata) + bc.DecompressR1C(&scratch.tR1C, inst) return solver.solveR1C(cID, &scratch.tR1C) } - } else if solver.Type == constraint.SystemSparseR1CS { - // blueprint declared "I know how to solve this." - if bc, ok := blueprint.(constraint.BlueprintSolvable); ok { - if err := bc.Solve(solver, calldata); err != nil { - return solver.wrapErrWithDebugInfo(cID, err) - } - return nil + } + + // blueprint declared "I know how to solve this." + if bc, ok := blueprint.(constraint.BlueprintSolvable); ok { + if err := bc.Solve(solver, inst); err != nil { + return solver.wrapErrWithDebugInfo(cID, err) } + return nil } // blueprint encodes a hint, we execute. // TODO @gbotrel may be worth it to move hint logic in blueprint "solve" if bc, ok := blueprint.(constraint.BlueprintHint); ok { - bc.DecompressHint(&scratch.tHint, calldata) + bc.DecompressHint(&scratch.tHint, inst) return solver.solveWithHint(&scratch.tHint) } diff --git a/constraint/bw6-633/system.go b/constraint/bw6-633/system.go index afad46f5ce..fc71ccce80 100644 --- a/constraint/bw6-633/system.go +++ b/constraint/bw6-633/system.go @@ -121,7 +121,7 @@ func (cs *system) GetR1Cs() []constraint.R1C { blueprint := cs.Blueprints[inst.BlueprintID] if bc, ok := blueprint.(constraint.BlueprintR1C); ok { var r1c constraint.R1C - bc.DecompressR1C(&r1c, cs.GetCallData(inst)) + bc.DecompressR1C(&r1c, inst.Unpack(&cs.System)) toReturn = append(toReturn, r1c) } else { panic("not implemented") @@ -196,8 +196,7 @@ func (cs *system) GetSparseR1Cs() []constraint.SparseR1C { blueprint := cs.Blueprints[inst.BlueprintID] if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { var sparseR1C constraint.SparseR1C - calldata := cs.CallData[inst.StartCallData : inst.StartCallData+uint64(blueprint.NbInputs())] - bc.DecompressSparseR1C(&sparseR1C, calldata) + bc.DecompressSparseR1C(&sparseR1C, inst.Unpack(&cs.System)) toReturn = append(toReturn, sparseR1C) } else { panic("not implemented") @@ -234,7 +233,7 @@ func evaluateLROSmallDomain(cs *system, solution []fr.Element) ([]fr.Element, [] for _, inst := range cs.Instructions { blueprint := cs.Blueprints[inst.BlueprintID] if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { - bc.DecompressSparseR1C(&sparseR1C, cs.GetCallData(inst)) + bc.DecompressSparseR1C(&sparseR1C, inst.Unpack(&cs.System)) l[offset+j] = solution[sparseR1C.XA] r[offset+j] = solution[sparseR1C.XB] diff --git a/constraint/bw6-761/coeff.go b/constraint/bw6-761/coeff.go index c23fff8258..506ee5e586 100644 --- a/constraint/bw6-761/coeff.go +++ b/constraint/bw6-761/coeff.go @@ -182,3 +182,11 @@ func (engine *field) String(a constraint.Element) string { e := (*fr.Element)(a[:]) return e.String() } + +func (engine *field) Uint64(a constraint.Element) (uint64, bool) { + e := (*fr.Element)(a[:]) + if !e.IsUint64() { + return 0, false + } + return e.Uint64(), true +} diff --git a/constraint/bw6-761/solver.go b/constraint/bw6-761/solver.go index bd1f54d2f3..803035e1a9 100644 --- a/constraint/bw6-761/solver.go +++ b/constraint/bw6-761/solver.go @@ -133,12 +133,17 @@ func (s *solver) set(id int, value fr.Element) { } // computeTerm computes coeff*variable -// TODO @gbotrel check if t is a Constant only func (s *solver) computeTerm(t constraint.Term) fr.Element { cID, vID := t.CoeffID(), t.WireID() + + if t.IsConstant() { + return s.Coefficients[cID] + } + if cID != 0 && !s.solved[vID] { panic("computing a term with an unsolved wire") } + switch cID { case constraint.CoeffIdZero: return fr.Element{} @@ -165,6 +170,11 @@ func (s *solver) accumulateInto(t constraint.Term, r *fr.Element) { cID := t.CoeffID() vID := t.WireID() + if t.IsConstant() { + r.Add(r, &s.Coefficients[cID]) + return + } + switch cID { case constraint.CoeffIdZero: return @@ -344,12 +354,35 @@ func (s *solver) IsSolved(vID uint32) bool { return s.solved[vID] } +// Read interprets input calldata as either a LinearExpression (if R1CS) or a Term (if Plonkish), +// evaluates it and return the result and the number of uint32 word read. +func (s *solver) Read(calldata []uint32) (constraint.Element, int) { + if s.Type == constraint.SystemSparseR1CS { + if calldata[0] != 1 { + panic("invalid calldata") + } + return s.GetValue(calldata[1], calldata[2]), 3 + } + var r fr.Element + n := int(calldata[0]) + j := 1 + for k := 0; k < n; k++ { + // we read k Terms + s.accumulateInto(constraint.Term{CID: calldata[j], VID: calldata[j+1]}, &r) + j += 2 + } + + var ret constraint.Element + copy(ret[:], r[:]) + return ret, j +} + // processInstruction decodes the instruction and execute blueprint-defined logic. // an instruction can encode a hint, a custom constraint or a generic constraint. -func (solver *solver) processInstruction(inst constraint.Instruction, scratch *scratch) error { +func (solver *solver) processInstruction(pi constraint.PackedInstruction, scratch *scratch) error { // fetch the blueprint - blueprint := solver.Blueprints[inst.BlueprintID] - calldata := solver.GetCallData(inst) + blueprint := solver.Blueprints[pi.BlueprintID] + inst := pi.Unpack(&solver.System) cID := inst.ConstraintOffset // here we have 1 constraint in the instruction only if solver.Type == constraint.SystemR1CS { @@ -357,23 +390,23 @@ func (solver *solver) processInstruction(inst constraint.Instruction, scratch *s // TODO @gbotrel we use the solveR1C method for now, having user-defined // blueprint for R1CS would require constraint.Solver interface to add methods // to set a,b,c since it's more efficient to compute these while we solve. - bc.DecompressR1C(&scratch.tR1C, calldata) + bc.DecompressR1C(&scratch.tR1C, inst) return solver.solveR1C(cID, &scratch.tR1C) } - } else if solver.Type == constraint.SystemSparseR1CS { - // blueprint declared "I know how to solve this." - if bc, ok := blueprint.(constraint.BlueprintSolvable); ok { - if err := bc.Solve(solver, calldata); err != nil { - return solver.wrapErrWithDebugInfo(cID, err) - } - return nil + } + + // blueprint declared "I know how to solve this." + if bc, ok := blueprint.(constraint.BlueprintSolvable); ok { + if err := bc.Solve(solver, inst); err != nil { + return solver.wrapErrWithDebugInfo(cID, err) } + return nil } // blueprint encodes a hint, we execute. // TODO @gbotrel may be worth it to move hint logic in blueprint "solve" if bc, ok := blueprint.(constraint.BlueprintHint); ok { - bc.DecompressHint(&scratch.tHint, calldata) + bc.DecompressHint(&scratch.tHint, inst) return solver.solveWithHint(&scratch.tHint) } diff --git a/constraint/bw6-761/system.go b/constraint/bw6-761/system.go index 76959c7fe5..6c636d147b 100644 --- a/constraint/bw6-761/system.go +++ b/constraint/bw6-761/system.go @@ -121,7 +121,7 @@ func (cs *system) GetR1Cs() []constraint.R1C { blueprint := cs.Blueprints[inst.BlueprintID] if bc, ok := blueprint.(constraint.BlueprintR1C); ok { var r1c constraint.R1C - bc.DecompressR1C(&r1c, cs.GetCallData(inst)) + bc.DecompressR1C(&r1c, inst.Unpack(&cs.System)) toReturn = append(toReturn, r1c) } else { panic("not implemented") @@ -196,8 +196,7 @@ func (cs *system) GetSparseR1Cs() []constraint.SparseR1C { blueprint := cs.Blueprints[inst.BlueprintID] if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { var sparseR1C constraint.SparseR1C - calldata := cs.CallData[inst.StartCallData : inst.StartCallData+uint64(blueprint.NbInputs())] - bc.DecompressSparseR1C(&sparseR1C, calldata) + bc.DecompressSparseR1C(&sparseR1C, inst.Unpack(&cs.System)) toReturn = append(toReturn, sparseR1C) } else { panic("not implemented") @@ -234,7 +233,7 @@ func evaluateLROSmallDomain(cs *system, solution []fr.Element) ([]fr.Element, [] for _, inst := range cs.Instructions { blueprint := cs.Blueprints[inst.BlueprintID] if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { - bc.DecompressSparseR1C(&sparseR1C, cs.GetCallData(inst)) + bc.DecompressSparseR1C(&sparseR1C, inst.Unpack(&cs.System)) l[offset+j] = solution[sparseR1C.XA] r[offset+j] = solution[sparseR1C.XB] diff --git a/constraint/core.go b/constraint/core.go index 6efb8d911f..15fabf2be0 100644 --- a/constraint/core.go +++ b/constraint/core.go @@ -23,9 +23,9 @@ const ( SystemSparseR1CS ) -// Instruction is the lowest element of a constraint system. It stores just enough data to +// PackedInstruction is the lowest element of a constraint system. It stores just enough data to // reconstruct a constraint of any shape or a hint at solving time. -type Instruction struct { +type PackedInstruction struct { // BlueprintID maps this instruction to a blueprint BlueprintID BlueprintID @@ -34,12 +34,43 @@ type Instruction struct { // multiple constraints. ConstraintOffset uint32 + // WireOffset stores the starting internal wire ID of this instruction. Blueprints may use this + // and refer to output wires by their offset. + // For example, if a blueprint declared 5 outputs, the first output wire will be WireOffset, + // the last one WireOffset+4. + WireOffset uint32 + // The constraint system stores a single []uint32 calldata slice. StartCallData // points to the starting index in the mentioned slice. This avoid storing a slice per // instruction (3 * uint64 in memory). StartCallData uint64 } +// Unpack returns the instruction corresponding to the packed instruction. +func (pi PackedInstruction) Unpack(cs *System) Instruction { + + blueprint := cs.Blueprints[pi.BlueprintID] + cSize := blueprint.CalldataSize() + if cSize < 0 { + // by convention, we store nbInputs < 0 for non-static input length. + cSize = int(cs.CallData[pi.StartCallData]) + } + + return Instruction{ + ConstraintOffset: pi.ConstraintOffset, + WireOffset: pi.WireOffset, + Calldata: cs.CallData[pi.StartCallData : pi.StartCallData+uint64(cSize)], + } +} + +// Instruction is the lowest element of a constraint system. It stores all the data needed to +// reconstruct a constraint of any shape or a hint at solving time. +type Instruction struct { + ConstraintOffset uint32 + WireOffset uint32 + Calldata []uint32 +} + // System contains core elements for a constraint System type System struct { // serialization header @@ -48,7 +79,7 @@ type System struct { Type SystemType - Instructions []Instruction + Instructions []PackedInstruction Blueprints []Blueprint CallData []uint32 // huge slice. @@ -107,7 +138,7 @@ func NewSystem(scalarField *big.Int, capacity int, t SystemType) System { MHintsDependencies: make(map[solver.HintID]string), q: new(big.Int).Set(scalarField), bitLen: scalarField.BitLen(), - Instructions: make([]Instruction, 0, capacity), + Instructions: make([]PackedInstruction, 0, capacity), CallData: make([]uint32, 0, capacity*8), lbOutputs: make([]uint32, 0, 256), lbWireLevel: make([]int, 0, capacity), @@ -117,14 +148,17 @@ func NewSystem(scalarField *big.Int, capacity int, t SystemType) System { return system } +// GetNbInstructions returns the number of instructions in the system func (system *System) GetNbInstructions() int { return len(system.Instructions) } +// GetInstruction returns the instruction at index id func (system *System) GetInstruction(id int) Instruction { - return system.Instructions[id] + return system.Instructions[id].Unpack(system) } +// AddBlueprint adds a blueprint to the system and returns its ID func (system *System) AddBlueprint(b Blueprint) BlueprintID { system.Blueprints = append(system.Blueprints, b) return BlueprintID(len(system.Blueprints) - 1) @@ -240,10 +274,10 @@ func (system *System) AddSolverHint(f solver.Hint, input []LinearExpression, nbO }, } - instruction := system.compressHint(hm, system.genericHint) - system.Instructions = append(system.Instructions, instruction) + blueprint := system.Blueprints[system.genericHint] + calldata := blueprint.(BlueprintHint).CompressHint(hm) - system.updateLevel(len(system.Instructions)-1, &hm) + system.AddInstruction(system.genericHint, calldata) return } @@ -286,74 +320,59 @@ func (system *System) VariableToString(vID int) string { return fmt.Sprintf("v%d", vID) // TODO @gbotrel vs strconv.Itoa. } -// GetCallData re-slice the constraint system full calldata slice with the portion -// related to the instruction. This does not copy and caller should not modify. -func (cs *System) GetCallData(instruction Instruction) []uint32 { - blueprint := cs.Blueprints[instruction.BlueprintID] - nbInputs := blueprint.NbInputs() - if nbInputs < 0 { - // by convention, we store nbInputs < 0 for non-static input length. - nbInputs = int(cs.CallData[instruction.StartCallData]) - } - return cs.CallData[instruction.StartCallData : instruction.StartCallData+uint64(nbInputs)] -} - func (cs *System) AddR1C(c R1C, bID BlueprintID) int { profile.RecordConstraint() - instruction := cs.compressR1C(&c, bID) - cs.Instructions = append(cs.Instructions, instruction) - cs.updateLevel(len(cs.Instructions)-1, &c) + blueprint := cs.Blueprints[bID] + calldata := blueprint.(BlueprintR1C).CompressR1C(&c) + + cs.AddInstruction(bID, calldata) return cs.NbConstraints - 1 } func (cs *System) AddSparseR1C(c SparseR1C, bID BlueprintID) int { profile.RecordConstraint() - instruction := cs.compressSparseR1C(&c, bID) - cs.Instructions = append(cs.Instructions, instruction) - cs.updateLevel(len(cs.Instructions)-1, &c) + blueprint := cs.Blueprints[bID] + calldata := blueprint.(BlueprintSparseR1C).CompressSparseR1C(&c) + + cs.AddInstruction(bID, calldata) return cs.NbConstraints - 1 } -func (cs *System) compressSparseR1C(c *SparseR1C, bID BlueprintID) Instruction { - inst := Instruction{ +func (cs *System) AddInstruction(bID BlueprintID, calldata []uint32) []uint32 { + // set the offsets + pi := PackedInstruction{ StartCallData: uint64(len(cs.CallData)), ConstraintOffset: uint32(cs.NbConstraints), + WireOffset: uint32(cs.NbInternalVariables + cs.GetNbPublicVariables() + cs.GetNbSecretVariables()), BlueprintID: bID, } - blueprint := cs.Blueprints[bID] - calldata := blueprint.(BlueprintSparseR1C).CompressSparseR1C(c) - cs.CallData = append(cs.CallData, calldata...) - cs.NbConstraints += blueprint.NbConstraints() - return inst -} -func (cs *System) compressR1C(c *R1C, bID BlueprintID) Instruction { - inst := Instruction{ - StartCallData: uint64(len(cs.CallData)), - ConstraintOffset: uint32(cs.NbConstraints), - BlueprintID: bID, - } - blueprint := cs.Blueprints[bID] - calldata := blueprint.(BlueprintR1C).CompressR1C(c) + // append the call data cs.CallData = append(cs.CallData, calldata...) + + // update the total number of constraints + blueprint := cs.Blueprints[pi.BlueprintID] cs.NbConstraints += blueprint.NbConstraints() - return inst -} -func (cs *System) compressHint(hm HintMapping, bID BlueprintID) Instruction { - inst := Instruction{ - StartCallData: uint64(len(cs.CallData)), - ConstraintOffset: uint32(cs.NbConstraints), // unused. - BlueprintID: bID, + // add the output wires + inst := pi.Unpack(cs) + nbOutputs := blueprint.NbOutputs(inst) + var wires []uint32 + for i := 0; i < nbOutputs; i++ { + wires = append(wires, uint32(cs.AddInternalVariable())) } - blueprint := cs.Blueprints[bID] - calldata := blueprint.(BlueprintHint).CompressHint(hm) - cs.CallData = append(cs.CallData, calldata...) - return inst + + // add the instruction + cs.Instructions = append(cs.Instructions, pi) + + // update the instruction dependency tree + cs.updateLevel(len(cs.Instructions)-1, blueprint.WireWalker(inst)) + + return wires } // GetNbConstraints returns the number of constraints diff --git a/constraint/field.go b/constraint/field.go index 983d7e0d10..f63bc910e2 100644 --- a/constraint/field.go +++ b/constraint/field.go @@ -1,6 +1,7 @@ package constraint import ( + "encoding/binary" "math/big" ) @@ -14,6 +15,28 @@ func (z *Element) IsZero() bool { return (z[5] | z[4] | z[3] | z[2] | z[1] | z[0]) == 0 } +// Bytes return the Element as a big-endian byte slice +func (z *Element) Bytes() [48]byte { + var b [48]byte + binary.BigEndian.PutUint64(b[40:48], z[0]) + binary.BigEndian.PutUint64(b[32:40], z[1]) + binary.BigEndian.PutUint64(b[24:32], z[2]) + binary.BigEndian.PutUint64(b[16:24], z[3]) + binary.BigEndian.PutUint64(b[8:16], z[4]) + binary.BigEndian.PutUint64(b[0:8], z[5]) + return b +} + +// SetBytes sets the Element from a big-endian byte slice +func (z *Element) SetBytes(b [48]byte) { + z[0] = binary.BigEndian.Uint64(b[40:48]) + z[1] = binary.BigEndian.Uint64(b[32:40]) + z[2] = binary.BigEndian.Uint64(b[24:32]) + z[3] = binary.BigEndian.Uint64(b[16:24]) + z[4] = binary.BigEndian.Uint64(b[8:16]) + z[5] = binary.BigEndian.Uint64(b[0:8]) +} + // Field capability to perform arithmetic on Coeff type Field interface { FromInterface(interface{}) Element @@ -26,4 +49,5 @@ type Field interface { One() Element IsOne(Element) bool String(Element) string + Uint64(Element) (uint64, bool) } diff --git a/constraint/hint.go b/constraint/hint.go index a79bfea41d..ac1dbf96ba 100644 --- a/constraint/hint.go +++ b/constraint/hint.go @@ -12,36 +12,3 @@ type HintMapping struct { Start, End uint32 } } - -// WireIterator implements constraint.Iterable -// returns all the wires referenced by the hint. -func (h *HintMapping) WireIterator() func() int { - curr := 0 - n := 0 - for i := 0; i < len(h.Inputs); i++ { - n += len(h.Inputs[i]) - } - inputs := getBuffer(n) - for i := 0; i < len(h.Inputs); i++ { - for j := 0; j < len(h.Inputs[i]); j++ { - term := h.Inputs[i][j] - if term.IsConstant() { - continue - } - inputs = append(inputs, term.VID) - } - } - lenOutputs := int(h.OutputRange.End - h.OutputRange.Start) - - return func() int { - if curr < lenOutputs { - curr++ - return int(h.OutputRange.Start) + curr - 1 - } - if curr < lenOutputs+len(inputs) { - curr++ - return int(inputs[curr-1-lenOutputs]) - } - return -1 - } -} diff --git a/constraint/level_builder.go b/constraint/level_builder.go index f29c69f769..e6cc47cbe6 100644 --- a/constraint/level_builder.go +++ b/constraint/level_builder.go @@ -8,14 +8,13 @@ package constraint // // We build a graph of dependency; we say that a wire is solved at a level l // --> l = max(level_of_dependencies(wire)) + 1 -func (system *System) updateLevel(iID int, c Iterable) { +func (system *System) updateLevel(iID int, walkWires func(cb func(wire uint32))) { level := -1 - wireIterator := c.WireIterator() - for wID := wireIterator(); wID != -1; wID = wireIterator() { - // iterate over all wires of the instruction - system.processWire(uint32(wID), &level) - } + // process all wires of the instruction + walkWires(func(wire uint32) { + system.processWire(wire, &level) + }) // level = max(dependencies) + 1 level++ diff --git a/constraint/linear_expression.go b/constraint/linear_expression.go index 32a66b7843..20fb9e9986 100644 --- a/constraint/linear_expression.go +++ b/constraint/linear_expression.go @@ -29,3 +29,10 @@ func (l LinearExpression) String(r Resolver) string { sbb.WriteLinearExpression(l) return sbb.String() } + +func (l LinearExpression) Compress(to *[]uint32) { + (*to) = append((*to), uint32(len(l))) + for i := 0; i < len(l); i++ { + (*to) = append((*to), l[i].CID, l[i].VID) + } +} diff --git a/constraint/r1cs.go b/constraint/r1cs.go index 49556c9bc8..b58ff95d40 100644 --- a/constraint/r1cs.go +++ b/constraint/r1cs.go @@ -47,7 +47,7 @@ func (it *R1CIterator) Next() *R1C { it.n++ blueprint := it.cs.Blueprints[inst.BlueprintID] if bc, ok := blueprint.(BlueprintR1C); ok { - bc.DecompressR1C(&it.R1C, it.cs.GetCallData(inst)) + bc.DecompressR1C(&it.R1C, inst.Unpack(it.cs)) return &it.R1C } return it.Next() @@ -151,26 +151,6 @@ type R1C struct { L, R, O LinearExpression } -// WireIterator implements constraint.Iterable -func (r1c *R1C) WireIterator() func() int { - curr := 0 - return func() int { - if curr < len(r1c.L) { - curr++ - return r1c.L[curr-1].WireID() - } - if curr < len(r1c.L)+len(r1c.R) { - curr++ - return r1c.R[curr-1-len(r1c.L)].WireID() - } - if curr < len(r1c.L)+len(r1c.R)+len(r1c.O) { - curr++ - return r1c.O[curr-1-len(r1c.L)-len(r1c.R)].WireID() - } - return -1 - } -} - // String formats a R1C as L⋅R == O func (r1c *R1C) String(r Resolver) string { sbb := NewStringBuilder(r) diff --git a/constraint/r1cs_sparse.go b/constraint/r1cs_sparse.go index ea5af900f3..d423d5b844 100644 --- a/constraint/r1cs_sparse.go +++ b/constraint/r1cs_sparse.go @@ -46,7 +46,7 @@ func (it *SparseR1CIterator) Next() *SparseR1C { it.n++ blueprint := it.cs.Blueprints[inst.BlueprintID] if bc, ok := blueprint.(BlueprintSparseR1C); ok { - bc.DecompressSparseR1C(&it.SparseR1C, it.cs.GetCallData(inst)) + bc.DecompressSparseR1C(&it.SparseR1C, inst.Unpack(it.cs)) return &it.SparseR1C } return it.Next() @@ -150,25 +150,6 @@ func (c *SparseR1C) Clear() { *c = SparseR1C{} } -// WireIterator implements constraint.Iterable -func (c *SparseR1C) WireIterator() func() int { - curr := 0 - return func() int { - switch curr { - case 0: - curr++ - return int(c.XA) - case 1: - curr++ - return int(c.XB) - case 2: - curr++ - return int(c.XC) - } - return -1 - } -} - // String formats the constraint as qL⋅xa + qR⋅xb + qO⋅xc + qM⋅(xaxb) + qC == 0 func (c *SparseR1C) String(r Resolver) string { sbb := NewStringBuilder(r) diff --git a/constraint/system.go b/constraint/system.go index 964838485d..d226530d38 100644 --- a/constraint/system.go +++ b/constraint/system.go @@ -14,6 +14,7 @@ type ConstraintSystem interface { io.ReaderFrom Field Resolver + CustomizableSystem // IsSolved returns nil if given witness solves the constraint system and error otherwise // Deprecated: use _, err := Solve(...) instead @@ -70,28 +71,16 @@ type ConstraintSystem interface { // This is experimental. CheckUnconstrainedWires() error - // AddBlueprint registers the given blueprint and returns its id. This should be called only once per blueprint. - AddBlueprint(b Blueprint) BlueprintID - GetInstruction(int) Instruction GetCoefficient(i int) Element - - // GetCallData re-slice the constraint system full calldata slice with the portion - // related to the instruction. This does not copy and caller should not modify. - GetCallData(instruction Instruction) []uint32 } -type Iterable interface { - // WireIterator returns a new iterator to iterate over the wires of the implementer (usually, a constraint) - // Call to next() returns the next wireID of the Iterable object and -1 when iteration is over. - // - // For example a R1C constraint with L, R, O linear expressions, each of size 2, calling several times - // next := r1c.WireIterator(); - // for wID := next(); wID != -1; wID = next() {} - // // will return in order L[0],L[1],R[0],R[1],O[0],O[1],-1 - WireIterator() (next func() int) -} +type CustomizableSystem interface { + // AddBlueprint registers the given blueprint and returns its id. This should be called only once per blueprint. + AddBlueprint(b Blueprint) BlueprintID -var _ Iterable = &SparseR1C{} -var _ Iterable = &R1C{} + // AddInstruction adds an instruction to the system and returns a list of created wires + // if the blueprint declared any outputs. + AddInstruction(bID BlueprintID, calldata []uint32) []uint32 +} diff --git a/constraint/term.go b/constraint/term.go index de1c37879e..857edd0da0 100644 --- a/constraint/term.go +++ b/constraint/term.go @@ -53,3 +53,12 @@ func (t Term) String(r Resolver) string { sbb.WriteTerm(t) return sbb.String() } + +// implements constraint.Compressable + +// Compress compresses the term into a slice of uint32 words. +// For compatibility with test engine and LinearExpression, the term is encoded as: +// 1, CID, VID (i.e a LinearExpression with a single term) +func (t Term) Compress(to *[]uint32) { + (*to) = append((*to), 1, t.CID, t.VID) +} diff --git a/constraint/tinyfield/coeff.go b/constraint/tinyfield/coeff.go index 0cdeb84a93..3aec8da553 100644 --- a/constraint/tinyfield/coeff.go +++ b/constraint/tinyfield/coeff.go @@ -182,3 +182,11 @@ func (engine *field) String(a constraint.Element) string { e := (*fr.Element)(a[:]) return e.String() } + +func (engine *field) Uint64(a constraint.Element) (uint64, bool) { + e := (*fr.Element)(a[:]) + if !e.IsUint64() { + return 0, false + } + return e.Uint64(), true +} diff --git a/constraint/tinyfield/solver.go b/constraint/tinyfield/solver.go index 35bd9e6c7b..7cb146906c 100644 --- a/constraint/tinyfield/solver.go +++ b/constraint/tinyfield/solver.go @@ -133,12 +133,17 @@ func (s *solver) set(id int, value fr.Element) { } // computeTerm computes coeff*variable -// TODO @gbotrel check if t is a Constant only func (s *solver) computeTerm(t constraint.Term) fr.Element { cID, vID := t.CoeffID(), t.WireID() + + if t.IsConstant() { + return s.Coefficients[cID] + } + if cID != 0 && !s.solved[vID] { panic("computing a term with an unsolved wire") } + switch cID { case constraint.CoeffIdZero: return fr.Element{} @@ -165,6 +170,11 @@ func (s *solver) accumulateInto(t constraint.Term, r *fr.Element) { cID := t.CoeffID() vID := t.WireID() + if t.IsConstant() { + r.Add(r, &s.Coefficients[cID]) + return + } + switch cID { case constraint.CoeffIdZero: return @@ -344,12 +354,35 @@ func (s *solver) IsSolved(vID uint32) bool { return s.solved[vID] } +// Read interprets input calldata as either a LinearExpression (if R1CS) or a Term (if Plonkish), +// evaluates it and return the result and the number of uint32 word read. +func (s *solver) Read(calldata []uint32) (constraint.Element, int) { + if s.Type == constraint.SystemSparseR1CS { + if calldata[0] != 1 { + panic("invalid calldata") + } + return s.GetValue(calldata[1], calldata[2]), 3 + } + var r fr.Element + n := int(calldata[0]) + j := 1 + for k := 0; k < n; k++ { + // we read k Terms + s.accumulateInto(constraint.Term{CID: calldata[j], VID: calldata[j+1]}, &r) + j += 2 + } + + var ret constraint.Element + copy(ret[:], r[:]) + return ret, j +} + // processInstruction decodes the instruction and execute blueprint-defined logic. // an instruction can encode a hint, a custom constraint or a generic constraint. -func (solver *solver) processInstruction(inst constraint.Instruction, scratch *scratch) error { +func (solver *solver) processInstruction(pi constraint.PackedInstruction, scratch *scratch) error { // fetch the blueprint - blueprint := solver.Blueprints[inst.BlueprintID] - calldata := solver.GetCallData(inst) + blueprint := solver.Blueprints[pi.BlueprintID] + inst := pi.Unpack(&solver.System) cID := inst.ConstraintOffset // here we have 1 constraint in the instruction only if solver.Type == constraint.SystemR1CS { @@ -357,23 +390,23 @@ func (solver *solver) processInstruction(inst constraint.Instruction, scratch *s // TODO @gbotrel we use the solveR1C method for now, having user-defined // blueprint for R1CS would require constraint.Solver interface to add methods // to set a,b,c since it's more efficient to compute these while we solve. - bc.DecompressR1C(&scratch.tR1C, calldata) + bc.DecompressR1C(&scratch.tR1C, inst) return solver.solveR1C(cID, &scratch.tR1C) } - } else if solver.Type == constraint.SystemSparseR1CS { - // blueprint declared "I know how to solve this." - if bc, ok := blueprint.(constraint.BlueprintSolvable); ok { - if err := bc.Solve(solver, calldata); err != nil { - return solver.wrapErrWithDebugInfo(cID, err) - } - return nil + } + + // blueprint declared "I know how to solve this." + if bc, ok := blueprint.(constraint.BlueprintSolvable); ok { + if err := bc.Solve(solver, inst); err != nil { + return solver.wrapErrWithDebugInfo(cID, err) } + return nil } // blueprint encodes a hint, we execute. // TODO @gbotrel may be worth it to move hint logic in blueprint "solve" if bc, ok := blueprint.(constraint.BlueprintHint); ok { - bc.DecompressHint(&scratch.tHint, calldata) + bc.DecompressHint(&scratch.tHint, inst) return solver.solveWithHint(&scratch.tHint) } diff --git a/constraint/tinyfield/system.go b/constraint/tinyfield/system.go index 3d33968182..396529971b 100644 --- a/constraint/tinyfield/system.go +++ b/constraint/tinyfield/system.go @@ -121,7 +121,7 @@ func (cs *system) GetR1Cs() []constraint.R1C { blueprint := cs.Blueprints[inst.BlueprintID] if bc, ok := blueprint.(constraint.BlueprintR1C); ok { var r1c constraint.R1C - bc.DecompressR1C(&r1c, cs.GetCallData(inst)) + bc.DecompressR1C(&r1c, inst.Unpack(&cs.System)) toReturn = append(toReturn, r1c) } else { panic("not implemented") @@ -196,8 +196,7 @@ func (cs *system) GetSparseR1Cs() []constraint.SparseR1C { blueprint := cs.Blueprints[inst.BlueprintID] if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { var sparseR1C constraint.SparseR1C - calldata := cs.CallData[inst.StartCallData : inst.StartCallData+uint64(blueprint.NbInputs())] - bc.DecompressSparseR1C(&sparseR1C, calldata) + bc.DecompressSparseR1C(&sparseR1C, inst.Unpack(&cs.System)) toReturn = append(toReturn, sparseR1C) } else { panic("not implemented") @@ -234,7 +233,7 @@ func evaluateLROSmallDomain(cs *system, solution []fr.Element) ([]fr.Element, [] for _, inst := range cs.Instructions { blueprint := cs.Blueprints[inst.BlueprintID] if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { - bc.DecompressSparseR1C(&sparseR1C, cs.GetCallData(inst)) + bc.DecompressSparseR1C(&sparseR1C, inst.Unpack(&cs.System)) l[offset+j] = solution[sparseR1C.XA] r[offset+j] = solution[sparseR1C.XB] diff --git a/frontend/builder.go b/frontend/builder.go index cd52e71169..b7ac985871 100644 --- a/frontend/builder.go +++ b/frontend/builder.go @@ -12,6 +12,8 @@ type NewBuilder func(*big.Int, CompileConfig) (Builder, error) // Compiler represents a constraint system compiler type Compiler interface { + constraint.CustomizableSystem + // MarkBoolean sets (but do not constraint!) v to be boolean // This is useful in scenarios where a variable is known to be boolean through a constraint // that is not api.AssertIsBoolean. If v is a constant, this is a no-op. @@ -53,6 +55,14 @@ type Compiler interface { // allows for the circuits to register callbacks which finalize batching // operations etc. Unlike Go defer, it is not locally scoped. Defer(cb func(api API) error) + + // InternalVariable returns the internal variable associated with the given wireID + // ! Experimental: use in conjunction with constraint.CustomizableSystem + InternalVariable(wireID uint32) Variable + + // ToCanonicalVariable converts a frontend.Variable to a constraint system specific Variable + // ! Experimental: use in conjunction with constraint.CustomizableSystem + ToCanonicalVariable(Variable) CanonicalVariable } // Builder represents a constraint system builder @@ -87,3 +97,11 @@ type Rangechecker interface { // Check checks that the given variable v has bit-length bits. Check(v Variable, bits int) } + +// CanonicalVariable represents a variable that's encoded in a constraint system specific way. +// For example a R1CS builder may represent this as a constraint.LinearExpression, +// a PLONK builder --> constraint.Term +// and the test/Engine --> ~*big.Int. +type CanonicalVariable interface { + constraint.Compressable +} diff --git a/frontend/cs/r1cs/builder.go b/frontend/cs/r1cs/builder.go index b8036314fe..2345d9664c 100644 --- a/frontend/cs/r1cs/builder.go +++ b/frontend/cs/r1cs/builder.go @@ -472,3 +472,31 @@ func (builder *builder) Defer(cb func(frontend.API) error) { func (*builder) FrontendType() frontendtype.Type { return frontendtype.R1CS } + +// AddInstruction is used to add custom instructions to the constraint system. +func (builder *builder) AddInstruction(bID constraint.BlueprintID, calldata []uint32) []uint32 { + return builder.cs.AddInstruction(bID, calldata) +} + +// AddBlueprint adds a custom blueprint to the constraint system. +func (builder *builder) AddBlueprint(b constraint.Blueprint) constraint.BlueprintID { + return builder.cs.AddBlueprint(b) +} + +func (builder *builder) InternalVariable(wireID uint32) frontend.Variable { + return expr.NewLinearExpression(int(wireID), builder.tOne) +} + +// ToCanonicalVariable converts a frontend.Variable to a constraint system specific Variable +// ! Experimental: use in conjunction with constraint.CustomizableSystem +func (builder *builder) ToCanonicalVariable(in frontend.Variable) frontend.CanonicalVariable { + if t, ok := in.(expr.LinearExpression); ok { + assertIsSet(t) + return builder.getLinearExpression(t) + } else { + c := builder.cs.FromInterface(in) + term := builder.cs.MakeTerm(c, 0) + term.MarkConstant() + return constraint.LinearExpression{term} + } +} diff --git a/frontend/cs/scs/builder.go b/frontend/cs/scs/builder.go index eca3f32a4b..87a69b3142 100644 --- a/frontend/cs/scs/builder.go +++ b/frontend/cs/scs/builder.go @@ -478,7 +478,7 @@ func (builder *builder) addConstraintExist(a, b expr.Term, k constraint.Element) inst := builder.cs.GetInstruction(iID) // we know the blueprint we added it. blueprint := constraint.BlueprintSparseR1CAdd{} - blueprint.DecompressSparseR1C(&c, builder.cs.GetCallData(inst)) + blueprint.DecompressSparseR1C(&c, inst) // qO == -1 if a.WireID() == int(c.XB) { @@ -566,7 +566,7 @@ func (builder *builder) mulConstraintExist(a, b expr.Term) (expr.Term, bool) { inst := builder.cs.GetInstruction(iID) // we know the blueprint we added it. blueprint := constraint.BlueprintSparseR1CMul{} - blueprint.DecompressSparseR1C(&c, builder.cs.GetCallData(inst)) + blueprint.DecompressSparseR1C(&c, inst) // qO == -1 @@ -652,3 +652,31 @@ func (builder *builder) newDebugInfo(errName string, in ...interface{}) constrai func (builder *builder) Defer(cb func(frontend.API) error) { circuitdefer.Put(builder, cb) } + +// AddInstruction is used to add custom instructions to the constraint system. +func (builder *builder) AddInstruction(bID constraint.BlueprintID, calldata []uint32) []uint32 { + return builder.cs.AddInstruction(bID, calldata) +} + +// AddBlueprint adds a custom blueprint to the constraint system. +func (builder *builder) AddBlueprint(b constraint.Blueprint) constraint.BlueprintID { + return builder.cs.AddBlueprint(b) +} + +func (builder *builder) InternalVariable(wireID uint32) frontend.Variable { + return expr.NewTerm(int(wireID), builder.tOne) +} + +// ToCanonicalVariable converts a frontend.Variable to a constraint system specific Variable +// ! Experimental: use in conjunction with constraint.CustomizableSystem +func (builder *builder) ToCanonicalVariable(v frontend.Variable) frontend.CanonicalVariable { + switch t := v.(type) { + case expr.Term: + return builder.cs.MakeTerm(t.Coeff, t.VID) + default: + c := builder.cs.FromInterface(v) + term := builder.cs.MakeTerm(c, 0) + term.MarkConstant() + return term + } +} diff --git a/frontend/internal/expr/linear_expression.go b/frontend/internal/expr/linear_expression.go index b1022fe52a..682bf0985d 100644 --- a/frontend/internal/expr/linear_expression.go +++ b/frontend/internal/expr/linear_expression.go @@ -4,43 +4,17 @@ import ( "github.com/consensys/gnark/constraint" ) -// TODO @gbotrel --> storing a UUID in the linear expressions would enable better perf -// in the frontend -> check a linear expression is boolean, or has been converted to a -// "backend" constraint.LinearExpresion ... and avoid duplicating work would be interesting. - type LinearExpression []Term -func (l LinearExpression) Clone() LinearExpression { - res := make(LinearExpression, len(l)) - copy(res, l) - return res -} - // NewLinearExpression helper to initialize a linear expression with one term func NewLinearExpression(vID int, cID constraint.Element) LinearExpression { return LinearExpression{Term{Coeff: cID, VID: vID}} } -func NewTerm(vID int, cID constraint.Element) Term { - return Term{Coeff: cID, VID: vID} -} - -type Term struct { - VID int - Coeff constraint.Element -} - -func (t *Term) SetCoeff(c constraint.Element) { - t.Coeff = c -} - -// TODO @gbotrel make that return a uint32 -func (t Term) WireID() int { - return t.VID -} - -func (t Term) HashCode() uint64 { - return t.Coeff[0]*29 + uint64(t.VID<<12) +func (l LinearExpression) Clone() LinearExpression { + res := make(LinearExpression, len(l)) + copy(res, l) + return res } // Len return the length of the Variable (implements Sort interface) diff --git a/frontend/internal/expr/term.go b/frontend/internal/expr/term.go new file mode 100644 index 0000000000..5c9ba5877c --- /dev/null +++ b/frontend/internal/expr/term.go @@ -0,0 +1,25 @@ +package expr + +import "github.com/consensys/gnark/constraint" + +type Term struct { + VID int + Coeff constraint.Element +} + +func NewTerm(vID int, cID constraint.Element) Term { + return Term{Coeff: cID, VID: vID} +} + +func (t *Term) SetCoeff(c constraint.Element) { + t.Coeff = c +} + +// TODO @gbotrel make that return a uint32 +func (t Term) WireID() int { + return t.VID +} + +func (t Term) HashCode() uint64 { + return t.Coeff[0]*29 + uint64(t.VID<<12) +} diff --git a/internal/generator/backend/template/representations/coeff.go.tmpl b/internal/generator/backend/template/representations/coeff.go.tmpl index 637fd7cf29..3ba357d1e6 100644 --- a/internal/generator/backend/template/representations/coeff.go.tmpl +++ b/internal/generator/backend/template/representations/coeff.go.tmpl @@ -165,4 +165,12 @@ func (engine *field) One() constraint.Element { func (engine *field) String(a constraint.Element) string { e := (*fr.Element)(a[:]) return e.String() +} + +func (engine *field) Uint64(a constraint.Element) (uint64, bool) { + e := (*fr.Element)(a[:]) + if !e.IsUint64() { + return 0, false + } + return e.Uint64(), true } \ No newline at end of file diff --git a/internal/generator/backend/template/representations/solver.go.tmpl b/internal/generator/backend/template/representations/solver.go.tmpl index 75b7a9d216..aa7b60cd4d 100644 --- a/internal/generator/backend/template/representations/solver.go.tmpl +++ b/internal/generator/backend/template/representations/solver.go.tmpl @@ -118,12 +118,17 @@ func (s *solver) set(id int, value fr.Element) { // computeTerm computes coeff*variable -// TODO @gbotrel check if t is a Constant only func (s *solver) computeTerm(t constraint.Term) fr.Element { cID, vID := t.CoeffID(), t.WireID() + + if t.IsConstant() { + return s.Coefficients[cID] + } + if cID != 0 && !s.solved[vID] { panic("computing a term with an unsolved wire") } + switch cID { case constraint.CoeffIdZero: return fr.Element{} @@ -150,6 +155,11 @@ func (s *solver) accumulateInto(t constraint.Term, r *fr.Element) { cID := t.CoeffID() vID := t.WireID() + if t.IsConstant() { + r.Add(r, &s.Coefficients[cID]) + return + } + switch cID { case constraint.CoeffIdZero: return @@ -335,15 +345,37 @@ func (s *solver) IsSolved(vID uint32) bool { return s.solved[vID] } +// Read interprets input calldata as either a LinearExpression (if R1CS) or a Term (if Plonkish), +// evaluates it and return the result and the number of uint32 word read. +func (s *solver) Read(calldata []uint32) (constraint.Element, int) { + if s.Type == constraint.SystemSparseR1CS { + if calldata[0] != 1 { + panic("invalid calldata") + } + return s.GetValue(calldata[1], calldata[2]), 3 + } + var r fr.Element + n := int(calldata[0]) + j := 1 + for k:= 0; k < n; k++ { + // we read k Terms + s.accumulateInto(constraint.Term{CID:calldata[j],VID: calldata[j+1]} , &r) + j+=2 + } + + var ret constraint.Element + copy(ret[:], r[:]) + return ret, j +} // processInstruction decodes the instruction and execute blueprint-defined logic. // an instruction can encode a hint, a custom constraint or a generic constraint. -func (solver *solver) processInstruction(inst constraint.Instruction, scratch *scratch) error { +func (solver *solver) processInstruction(pi constraint.PackedInstruction, scratch *scratch) error { // fetch the blueprint - blueprint := solver.Blueprints[inst.BlueprintID] - calldata := solver.GetCallData(inst) + blueprint := solver.Blueprints[pi.BlueprintID] + inst := pi.Unpack(&solver.System) cID := inst.ConstraintOffset // here we have 1 constraint in the instruction only if solver.Type == constraint.SystemR1CS { @@ -351,23 +383,23 @@ func (solver *solver) processInstruction(inst constraint.Instruction, scratch *s // TODO @gbotrel we use the solveR1C method for now, having user-defined // blueprint for R1CS would require constraint.Solver interface to add methods // to set a,b,c since it's more efficient to compute these while we solve. - bc.DecompressR1C(&scratch.tR1C, calldata) + bc.DecompressR1C(&scratch.tR1C, inst) return solver.solveR1C(cID, &scratch.tR1C) } - } else if solver.Type == constraint.SystemSparseR1CS { - // blueprint declared "I know how to solve this." - if bc, ok := blueprint.(constraint.BlueprintSolvable); ok { - if err := bc.Solve(solver, calldata); err != nil { - return solver.wrapErrWithDebugInfo(cID, err) - } - return nil + } + + // blueprint declared "I know how to solve this." + if bc, ok := blueprint.(constraint.BlueprintSolvable); ok { + if err := bc.Solve(solver, inst); err != nil { + return solver.wrapErrWithDebugInfo(cID, err) } + return nil } // blueprint encodes a hint, we execute. // TODO @gbotrel may be worth it to move hint logic in blueprint "solve" if bc, ok := blueprint.(constraint.BlueprintHint); ok { - bc.DecompressHint(&scratch.tHint, calldata) + bc.DecompressHint(&scratch.tHint,inst) return solver.solveWithHint(&scratch.tHint) } diff --git a/internal/generator/backend/template/representations/system.go.tmpl b/internal/generator/backend/template/representations/system.go.tmpl index 5533730197..2fdad80ca2 100644 --- a/internal/generator/backend/template/representations/system.go.tmpl +++ b/internal/generator/backend/template/representations/system.go.tmpl @@ -107,7 +107,7 @@ func (cs *system) GetR1Cs() []constraint.R1C { blueprint := cs.Blueprints[inst.BlueprintID] if bc, ok := blueprint.(constraint.BlueprintR1C); ok { var r1c constraint.R1C - bc.DecompressR1C(&r1c, cs.GetCallData(inst)) + bc.DecompressR1C(&r1c, inst.Unpack(&cs.System)) toReturn = append(toReturn, r1c) } else { panic("not implemented") @@ -185,8 +185,7 @@ func (cs *system) GetSparseR1Cs() []constraint.SparseR1C { blueprint := cs.Blueprints[inst.BlueprintID] if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { var sparseR1C constraint.SparseR1C - calldata := cs.CallData[inst.StartCallData:inst.StartCallData+uint64(blueprint.NbInputs())] - bc.DecompressSparseR1C(&sparseR1C, calldata) + bc.DecompressSparseR1C(&sparseR1C, inst.Unpack(&cs.System)) toReturn = append(toReturn, sparseR1C) } else { panic("not implemented") @@ -226,7 +225,7 @@ func evaluateLROSmallDomain(cs *system, solution []fr.Element) ([]fr.Element, [] for _, inst := range cs.Instructions { blueprint := cs.Blueprints[inst.BlueprintID] if bc, ok := blueprint.(constraint.BlueprintSparseR1C); ok { - bc.DecompressSparseR1C(&sparseR1C, cs.GetCallData(inst)) + bc.DecompressSparseR1C(&sparseR1C, inst.Unpack(&cs.System)) l[offset+j] = solution[sparseR1C.XA] r[offset+j] = solution[sparseR1C.XB] diff --git a/std/hints.go b/std/hints.go index 57fe3b5c7e..fae0ee91e3 100644 --- a/std/hints.go +++ b/std/hints.go @@ -8,7 +8,6 @@ import ( "github.com/consensys/gnark/std/algebra/native/sw_bls24315" "github.com/consensys/gnark/std/evmprecompiles" "github.com/consensys/gnark/std/internal/logderivarg" - "github.com/consensys/gnark/std/lookup/logderivlookup" "github.com/consensys/gnark/std/math/bits" "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/std/rangecheck" @@ -40,5 +39,4 @@ func registerHints() { solver.RegisterHint(rangecheck.GetHints()...) solver.RegisterHint(evmprecompiles.GetHints()...) solver.RegisterHint(logderivarg.GetHints()...) - solver.RegisterHint(logderivlookup.GetHints()...) } diff --git a/std/lookup/logderivlookup/blueprint.go b/std/lookup/logderivlookup/blueprint.go new file mode 100644 index 0000000000..dc49ee77ec --- /dev/null +++ b/std/lookup/logderivlookup/blueprint.go @@ -0,0 +1,125 @@ +package logderivlookup + +import ( + "fmt" + + "github.com/consensys/gnark/constraint" +) + +// BlueprintLookupHint is a blueprint that facilitates the lookup of values in a table. +// It is essentially a hint to the solver, but enables storing the table entries only once. +type BlueprintLookupHint struct { + EntriesCalldata []uint32 +} + +// ensures BlueprintLookupHint implements the BlueprintSolvable interface +var _ constraint.BlueprintSolvable = (*BlueprintLookupHint)(nil) + +// func lookupHint(_ *big.Int, in []*big.Int, out []*big.Int) error { +// nbTable := len(in) - len(out) +// for i := 0; i < len(in)-nbTable; i++ { +// if !in[nbTable+i].IsInt64() { +// return fmt.Errorf("lookup query not integer") +// } +// ptr := int(in[nbTable+i].Int64()) +// if ptr >= nbTable { +// return fmt.Errorf("lookup query %d outside table size %d", ptr, nbTable) +// } +// out[i].Set(in[ptr]) +// } +// return nil +// } + +func (b *BlueprintLookupHint) Solve(s constraint.Solver, inst constraint.Instruction) error { + nbEntries := int(inst.Calldata[1]) + entries := make([]constraint.Element, nbEntries) + + // read the static entries from the blueprint + // TODO @gbotrel cache that. + offset, delta := 0, 0 + for i := 0; i < nbEntries; i++ { + entries[i], delta = s.Read(b.EntriesCalldata[offset:]) + offset += delta + } + + nbInputs := int(inst.Calldata[2]) + + // read the inputs from the instruction + inputs := make([]constraint.Element, nbInputs) + offset = 3 + for i := 0; i < nbInputs; i++ { + inputs[i], delta = s.Read(inst.Calldata[offset:]) + offset += delta + } + + // set the outputs + nbOutputs := nbInputs + + for i := 0; i < nbOutputs; i++ { + idx, isUint64 := s.Uint64(inputs[i]) + if !isUint64 || idx >= uint64(len(entries)) { + return fmt.Errorf("lookup query too large") + } + // we set the output wire to the value of the entry + s.SetValue(uint32(i+int(inst.WireOffset)), entries[idx]) + } + return nil +} + +func (b *BlueprintLookupHint) CalldataSize() int { + // variable size + return -1 +} +func (b *BlueprintLookupHint) NbConstraints() int { + return 0 +} + +// NbOutputs return the number of output wires this blueprint creates. +func (b *BlueprintLookupHint) NbOutputs(inst constraint.Instruction) int { + return int(inst.Calldata[2]) +} + +// Wires returns a function that walks the wires appearing in the blueprint. +// This is used by the level builder to build a dependency graph between instructions. +func (b *BlueprintLookupHint) WireWalker(inst constraint.Instruction) func(cb func(wire uint32)) { + return func(cb func(wire uint32)) { + // depend on the table UP to the number of entries at time of instruction creation. + nbEntries := int(inst.Calldata[1]) + + // invoke the callback on each wire appearing in the table + j := 0 + for i := 0; i < nbEntries; i++ { + // first we have the length of the linear expression + n := int(b.EntriesCalldata[j]) + j++ + for k := 0; k < n; k++ { + t := constraint.Term{CID: b.EntriesCalldata[j], VID: b.EntriesCalldata[j+1]} + if !t.IsConstant() { + cb(t.VID) + } + j += 2 + } + } + + // invoke the callback on each wire appearing in the inputs + nbInputs := int(inst.Calldata[2]) + j = 3 + for i := 0; i < nbInputs; i++ { + // first we have the length of the linear expression + n := int(inst.Calldata[j]) + j++ + for k := 0; k < n; k++ { + t := constraint.Term{CID: inst.Calldata[j], VID: inst.Calldata[j+1]} + if !t.IsConstant() { + cb(t.VID) + } + j += 2 + } + } + + // finally we have the outputs + for i := 0; i < nbInputs; i++ { + cb(uint32(i + int(inst.WireOffset))) + } + } +} diff --git a/std/lookup/logderivlookup/logderivlookup.go b/std/lookup/logderivlookup/logderivlookup.go index 4e5be350e6..08116feaf4 100644 --- a/std/lookup/logderivlookup/logderivlookup.go +++ b/std/lookup/logderivlookup/logderivlookup.go @@ -19,23 +19,11 @@ package logderivlookup import ( - "fmt" - "math/big" - - "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/internal/logderivarg" ) -func init() { - solver.RegisterHint(GetHints()...) -} - -// GetHints returns all hints used in the package. -func GetHints() []solver.Hint { - return []solver.Hint{lookupHint} -} - // Table holds all the entries and queries. type Table struct { api frontend.API @@ -43,6 +31,12 @@ type Table struct { entries []frontend.Variable immutable bool results []result + + // each table has a unique blueprint + // the blueprint stores the lookup table entries once + // such that each query only need to store the indexes to lookup + bID constraint.BlueprintID + blueprint BlueprintLookupHint } type result struct { @@ -55,6 +49,9 @@ type result struct { func New(api frontend.API) *Table { t := &Table{api: api} api.Compiler().Defer(t.commit) + + // each table has a unique blueprint + t.bID = api.Compiler().AddBlueprint(&t.blueprint) return t } @@ -62,9 +59,14 @@ func New(api frontend.API) *Table { // constant. It panics if the table is already committed. func (t *Table) Insert(val frontend.Variable) (index int) { if t.immutable { - panic("inserting into commited lookup table") + panic("inserting into committed lookup table") } t.entries = append(t.entries, val) + + // each time we insert a new entry, we update the blueprint + v := t.api.Compiler().ToCanonicalVariable(val) + v.Compress(&t.blueprint.EntriesCalldata) + return len(t.entries) - 1 } @@ -74,7 +76,7 @@ func (t *Table) Insert(val frontend.Variable) (index int) { // when the index is out of bounds. func (t *Table) Lookup(inds ...frontend.Variable) (vals []frontend.Variable) { if t.immutable { - panic("looking up from a commited lookup table") + panic("looking up from a committed lookup table") } if len(inds) == 0 { return nil @@ -82,27 +84,51 @@ func (t *Table) Lookup(inds ...frontend.Variable) (vals []frontend.Variable) { if len(t.entries) == 0 { panic("looking up from empty table") } - return t.callLookupHint(inds) + return t.performLookup(inds) } -func (t *Table) callLookupHint(inds []frontend.Variable) []frontend.Variable { - inputs := make([]frontend.Variable, len(t.entries)+len(inds)) - copy(inputs[:len(t.entries)], t.entries) - for i := range inds { - inputs[len(t.entries)+i] = inds[i] +// performLookup performs the lookup and returns the resulting variables. +// underneath, it does use the blueprint to encode the lookup hint. +func (t *Table) performLookup(inds []frontend.Variable) []frontend.Variable { + // to build the instruction, we need to first encode its dependency as a calldata []uint32 slice. + // * calldata[0] is the length of the calldata, + // * calldata[1] is the number of entries in the table we consider. + // * calldata[2] is the number of queries (which is the number of indices we are looking up and the number of outputs we expect) + compiler := t.api.Compiler() + + calldata := make([]uint32, 3, 3+len(inds)*2+2) + calldata[1] = uint32(len(t.entries)) + calldata[2] = uint32(len(inds)) + + // encode inputs + for _, in := range inds { + v := compiler.ToCanonicalVariable(in) + v.Compress(&calldata) } - hintResp, err := t.api.NewHint(lookupHint, len(inds), inputs...) - if err != nil { - panic(fmt.Sprintf("lookup hint: %v", err)) + + // by convention, first calldata is len of inputs + calldata[0] = uint32(len(calldata)) + + // now what we are left to do is add an instruction to the constraint system + // such that at solving time the blueprint can properly execute the lookup logic. + outputs := compiler.AddInstruction(t.bID, calldata) + + // sanity check + if len(outputs) != len(inds) { + panic("sanity check") } - res := make([]frontend.Variable, len(inds)) - results := make([]result, len(inds)) + + // we need to return the variables corresponding to the outputs + internalVariables := make([]frontend.Variable, len(inds)) + lookupResult := make([]result, len(inds)) + + // we need to store the result of the lookup in the table for i := range inds { - res[i] = hintResp[i] - results[i] = result{ind: inds[i], val: hintResp[i]} + internalVariables[i] = compiler.InternalVariable(outputs[i]) + lookupResult[i] = result{ind: inds[i], val: internalVariables[i]} } - t.results = append(t.results, results...) - return res + t.results = append(t.results, lookupResult...) + return internalVariables } func (t *Table) entryTable() [][]frontend.Variable { @@ -124,18 +150,3 @@ func (t *Table) resultsTable() [][]frontend.Variable { func (t *Table) commit(api frontend.API) error { return logderivarg.Build(api, t.entryTable(), t.resultsTable()) } - -func lookupHint(_ *big.Int, in []*big.Int, out []*big.Int) error { - nbTable := len(in) - len(out) - for i := 0; i < len(in)-nbTable; i++ { - if !in[nbTable+i].IsInt64() { - return fmt.Errorf("lookup query not integer") - } - ptr := int(in[nbTable+i].Int64()) - if ptr >= nbTable { - return fmt.Errorf("lookup query %d outside table size %d", ptr, nbTable) - } - out[i].Set(in[ptr]) - } - return nil -} diff --git a/std/lookup/logderivlookup/logderivlookup_test.go b/std/lookup/logderivlookup/logderivlookup_test.go index 6f5041322a..0070f18352 100644 --- a/std/lookup/logderivlookup/logderivlookup_test.go +++ b/std/lookup/logderivlookup/logderivlookup_test.go @@ -9,6 +9,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/scs" "github.com/consensys/gnark/test" ) @@ -45,6 +46,19 @@ func TestLookup(t *testing.T) { witness.Queries[i] = q witness.Expected[i] = new(big.Int).Set(witness.Entries[q.Int64()].(*big.Int)) } + + ccs, err := frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, &LookupCircuit{}) + assert.NoError(err) + + w, err := frontend.NewWitness(&witness, ecc.BN254.ScalarField()) + assert.NoError(err) + + _, err = ccs.Solve(w) + assert.NoError(err) + + err = test.IsSolved(&LookupCircuit{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + assert.ProverSucceeded(&LookupCircuit{}, &witness, test.WithCurves(ecc.BN254), test.WithBackends(backend.GROTH16, backend.PLONK)) diff --git a/test/blueprint_solver.go b/test/blueprint_solver.go new file mode 100644 index 0000000000..9ced90ee6a --- /dev/null +++ b/test/blueprint_solver.go @@ -0,0 +1,140 @@ +package test + +import ( + "math/big" + + "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/internal/utils" +) + +// blueprintSolver is a constraint.Solver that can be used to test a circuit +// it is a separate type to avoid method collisions with the engine. +type blueprintSolver struct { + internalVariables []*big.Int + q *big.Int +} + +// implements constraint.Solver + +func (s *blueprintSolver) SetValue(vID uint32, f constraint.Element) { + if int(vID) > len(s.internalVariables) { + panic("out of bounds") + } + v := s.ToBigInt(f) + s.internalVariables[vID].Set(v) +} + +func (s *blueprintSolver) GetValue(cID, vID uint32) constraint.Element { + panic("not implemented in test.Engine") +} +func (s *blueprintSolver) GetCoeff(cID uint32) constraint.Element { + panic("not implemented in test.Engine") +} + +func (s *blueprintSolver) IsSolved(vID uint32) bool { + panic("not implemented in test.Engine") +} + +// implements constraint.Field + +func (s *blueprintSolver) FromInterface(i interface{}) constraint.Element { + b := utils.FromInterface(i) + return s.toElement(&b) +} + +func (s *blueprintSolver) ToBigInt(f constraint.Element) *big.Int { + r := new(big.Int) + fBytes := f.Bytes() + r.SetBytes(fBytes[:]) + return r +} +func (s *blueprintSolver) Mul(a, b constraint.Element) constraint.Element { + ba, bb := s.ToBigInt(a), s.ToBigInt(b) + ba.Mul(ba, bb).Mod(ba, s.q) + return s.toElement(ba) +} +func (s *blueprintSolver) Add(a, b constraint.Element) constraint.Element { + ba, bb := s.ToBigInt(a), s.ToBigInt(b) + ba.Add(ba, bb).Mod(ba, s.q) + return s.toElement(ba) +} +func (s *blueprintSolver) Sub(a, b constraint.Element) constraint.Element { + ba, bb := s.ToBigInt(a), s.ToBigInt(b) + ba.Sub(ba, bb).Mod(ba, s.q) + return s.toElement(ba) +} +func (s *blueprintSolver) Neg(a constraint.Element) constraint.Element { + ba := s.ToBigInt(a) + ba.Neg(ba).Mod(ba, s.q) + return s.toElement(ba) +} +func (s *blueprintSolver) Inverse(a constraint.Element) (constraint.Element, bool) { + ba := s.ToBigInt(a) + r := ba.ModInverse(ba, s.q) + return s.toElement(ba), r != nil +} +func (s *blueprintSolver) One() constraint.Element { + b := new(big.Int).SetUint64(1) + return s.toElement(b) +} +func (s *blueprintSolver) IsOne(a constraint.Element) bool { + b := s.ToBigInt(a) + return b.IsUint64() && b.Uint64() == 1 +} + +func (s *blueprintSolver) String(a constraint.Element) string { + b := s.ToBigInt(a) + return b.String() +} + +func (s *blueprintSolver) Uint64(a constraint.Element) (uint64, bool) { + b := s.ToBigInt(a) + return b.Uint64(), b.IsUint64() +} + +func (s *blueprintSolver) Read(calldata []uint32) (constraint.Element, int) { + // We encoded big.Int as constraint.Element on 12 uint32 words. + var r constraint.Element + for i := 0; i < len(r); i++ { + index := i * 2 + r[i] = uint64(calldata[index])<<32 | uint64(calldata[index+1]) + } + return r, len(r) * 2 +} + +func (s *blueprintSolver) toElement(b *big.Int) constraint.Element { + return bigIntToElement(b) +} + +func bigIntToElement(b *big.Int) constraint.Element { + if b.Sign() == -1 { + panic("negative value") + } + bytes := b.Bytes() + if len(bytes) > 48 { + panic("value too big") + } + var paddedBytes [48]byte + copy(paddedBytes[48-len(bytes):], bytes[:]) + + var r constraint.Element + r.SetBytes(paddedBytes) + + return r +} + +// wrappedBigInt is a wrapper around big.Int to implement the frontend.CanonicalVariable interface +type wrappedBigInt struct { + *big.Int +} + +func (w wrappedBigInt) Compress(to *[]uint32) { + // convert to Element. + e := bigIntToElement(w.Int) + + // append the uint32 words to the slice + for i := 0; i < len(e); i++ { + *to = append(*to, uint32(e[i]>>32)) + *to = append(*to, uint32(e[i]&0xffffffff)) + } +} diff --git a/test/blueprint_solver_test.go b/test/blueprint_solver_test.go new file mode 100644 index 0000000000..0cc42b6a27 --- /dev/null +++ b/test/blueprint_solver_test.go @@ -0,0 +1,64 @@ +package test + +import ( + "math/big" + "math/rand" + "testing" + "time" + + "github.com/consensys/gnark-crypto/ecc" +) + +func TestBigIntToElement(t *testing.T) { + t.Parallel() + // sample a random big.Int, convert it to an element, and back + // to a big.Int, and check that it's the same + s := blueprintSolver{q: ecc.BN254.ScalarField()} + b := big.NewInt(0) + for i := 0; i < 50; i++ { + b.Rand(rand.New(rand.NewSource(time.Now().Unix())), s.q) //#nosec G404 -- This is a false positive + e := s.toElement(b) + b2 := s.ToBigInt(e) + if b.Cmp(b2) != 0 { + t.Fatal("b != b2") + } + } + +} + +func TestBigIntToUint32Slice(t *testing.T) { + t.Parallel() + // sample a random big.Int, write it to a uint32 slice, and back + // to a big.Int, and check that it's the same + s := blueprintSolver{q: ecc.BN254.ScalarField()} + b1 := big.NewInt(0) + b2 := big.NewInt(0) + + for i := 0; i < 50; i++ { + b1.Rand(rand.New(rand.NewSource(time.Now().Unix())), s.q) //#nosec G404 -- This is a false positive + b2.Rand(rand.New(rand.NewSource(time.Now().Unix())), s.q) //#nosec G404 -- This is a false positive + wb1 := wrappedBigInt{b1} + wb2 := wrappedBigInt{b2} + var to []uint32 + wb1.Compress(&to) + wb2.Compress(&to) + + if len(to) != 24 { + t.Fatal("wrong length: expected 2*len of constraint.Element (uint32 words)") + } + + e1, n := s.Read(to) + if n != 12 { + t.Fatal("wrong length: expected 1 len of constraint.Element (uint32 words)") + } + e2, n := s.Read(to[n:]) + if n != 12 { + t.Fatal("wrong length: expected 1 len of constraint.Element (uint32 words)") + } + rb1, rb2 := s.ToBigInt(e1), s.ToBigInt(e2) + if rb1.Cmp(b1) != 0 || rb2.Cmp(b2) != 0 { + t.Fatal("rb1 != b1 || rb2 != b2") + } + } + +} diff --git a/test/engine.go b/test/engine.go index 0691b9335e..7a505a8af3 100644 --- a/test/engine.go +++ b/test/engine.go @@ -25,6 +25,7 @@ import ( "strconv" "strings" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/debug" "github.com/consensys/gnark/frontend/schema" @@ -53,6 +54,8 @@ type engine struct { // mHintsFunctions map[hint.ID]hintFunction constVars bool kvstore.Store + blueprints []constraint.Blueprint + internalVariables []*big.Int } // TestEngineOption defines an option for the test engine. @@ -608,3 +611,61 @@ func (e *engine) Commit(v ...frontend.Variable) (frontend.Variable, error) { func (e *engine) Defer(cb func(frontend.API) error) { circuitdefer.Put(e, cb) } + +// AddInstruction is used to add custom instructions to the constraint system. +// In constraint system, this is asynchronous. In here, we do it synchronously. +func (e *engine) AddInstruction(bID constraint.BlueprintID, calldata []uint32) []uint32 { + blueprint := e.blueprints[bID].(constraint.BlueprintSolvable) + + // create a dummy instruction + inst := constraint.Instruction{ + Calldata: calldata, + WireOffset: uint32(len(e.internalVariables)), + } + + // blueprint declared nbOutputs; add as many internal variables + // and return their indices + nbOutputs := blueprint.NbOutputs(inst) + var r []uint32 + for i := 0; i < nbOutputs; i++ { + r = append(r, uint32(len(e.internalVariables))) + e.internalVariables = append(e.internalVariables, new(big.Int)) + } + + // solve the blueprint synchronously + s := blueprintSolver{ + internalVariables: e.internalVariables, + q: e.q, + } + if err := blueprint.Solve(&s, inst); err != nil { + panic(err) + } + + return r +} + +// AddBlueprint adds a custom blueprint to the constraint system. +func (e *engine) AddBlueprint(b constraint.Blueprint) constraint.BlueprintID { + if _, ok := b.(constraint.BlueprintSolvable); !ok { + panic("unsupported blueprint in test engine") + } + e.blueprints = append(e.blueprints, b) + return constraint.BlueprintID(len(e.blueprints) - 1) +} + +// InternalVariable returns the value of an internal variable. This is used in custom blueprints. +// The variableID is the index of the variable in the internalVariables slice, as +// filled by AddInstruction. +func (e *engine) InternalVariable(vID uint32) frontend.Variable { + if vID >= uint32(len(e.internalVariables)) { + panic("internal variable not found") + } + return new(big.Int).Set(e.internalVariables[vID]) +} + +// ToCanonicalVariable converts a frontend.Variable to a frontend.CanonicalVariable +// this is used in custom blueprints to return a variable than can be encoded in blueprints +func (e *engine) ToCanonicalVariable(v frontend.Variable) frontend.CanonicalVariable { + r := e.toBigInt(v) + return wrappedBigInt{r} +} From 5dae2c51d8551b3632f8b5cb5d66db8195f46cc4 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Fri, 5 May 2023 09:45:52 -0500 Subject: [PATCH 321/464] fix: fix race condition when compiling circuits in parallel (#676) --- constraint/blueprint.go | 6 ++-- constraint/blueprint_hint.go | 21 +++++------- constraint/blueprint_r1cs.go | 28 ++++------------ constraint/blueprint_scs.go | 42 +++++------------------- constraint/core.go | 62 ++++++++++++++++++++++++++++++++---- test/engine.go | 19 +++++------ 6 files changed, 91 insertions(+), 87 deletions(-) diff --git a/constraint/blueprint.go b/constraint/blueprint.go index 2ce8decf30..1471d9d3e9 100644 --- a/constraint/blueprint.go +++ b/constraint/blueprint.go @@ -48,21 +48,21 @@ type BlueprintSolvable interface { // BlueprintR1C indicates that the blueprint and associated calldata encodes a R1C type BlueprintR1C interface { Blueprint - CompressR1C(c *R1C) []uint32 + CompressR1C(c *R1C, to *[]uint32) DecompressR1C(into *R1C, instruction Instruction) } // BlueprintSparseR1C indicates that the blueprint and associated calldata encodes a SparseR1C. type BlueprintSparseR1C interface { Blueprint - CompressSparseR1C(c *SparseR1C) []uint32 + CompressSparseR1C(c *SparseR1C, to *[]uint32) DecompressSparseR1C(into *SparseR1C, instruction Instruction) } // BlueprintHint indicates that the blueprint and associated calldata encodes a hint. type BlueprintHint interface { Blueprint - CompressHint(HintMapping) []uint32 + CompressHint(h HintMapping, to *[]uint32) DecompressHint(h *HintMapping, instruction Instruction) } diff --git a/constraint/blueprint_hint.go b/constraint/blueprint_hint.go index acf3f36ae3..ac96413ef0 100644 --- a/constraint/blueprint_hint.go +++ b/constraint/blueprint_hint.go @@ -34,7 +34,7 @@ func (b *BlueprintGenericHint) DecompressHint(h *HintMapping, inst Instruction) h.OutputRange.End = inst.Calldata[j+1] } -func (b *BlueprintGenericHint) CompressHint(h HintMapping) []uint32 { +func (b *BlueprintGenericHint) CompressHint(h HintMapping, to *[]uint32) { nbInputs := 1 // storing nb inputs nbInputs++ // hintID nbInputs++ // len(h.Inputs) @@ -45,24 +45,19 @@ func (b *BlueprintGenericHint) CompressHint(h HintMapping) []uint32 { nbInputs += 2 // output range start / end - r := getBuffer(nbInputs) - r = append(r, uint32(nbInputs)) - r = append(r, uint32(h.HintID)) - r = append(r, uint32(len(h.Inputs))) + (*to) = append((*to), uint32(nbInputs)) + (*to) = append((*to), uint32(h.HintID)) + (*to) = append((*to), uint32(len(h.Inputs))) for _, l := range h.Inputs { - r = append(r, uint32(len(l))) + (*to) = append((*to), uint32(len(l))) for _, t := range l { - r = append(r, uint32(t.CoeffID()), uint32(t.WireID())) + (*to) = append((*to), uint32(t.CoeffID()), uint32(t.WireID())) } } - r = append(r, h.OutputRange.Start) - r = append(r, h.OutputRange.End) - if len(r) != nbInputs { - panic("invalid") - } - return r + (*to) = append((*to), h.OutputRange.Start) + (*to) = append((*to), h.OutputRange.End) } func (b *BlueprintGenericHint) CalldataSize() int { diff --git a/constraint/blueprint_r1cs.go b/constraint/blueprint_r1cs.go index ddd09e56ce..b231eda067 100644 --- a/constraint/blueprint_r1cs.go +++ b/constraint/blueprint_r1cs.go @@ -17,22 +17,20 @@ func (b *BlueprintGenericR1C) NbOutputs(inst Instruction) int { return 0 } -func (b *BlueprintGenericR1C) CompressR1C(c *R1C) []uint32 { +func (b *BlueprintGenericR1C) CompressR1C(c *R1C, to *[]uint32) { // we store total nb inputs, len L, len R, len O, and then the "flatten" linear expressions nbInputs := 4 + 2*(len(c.L)+len(c.R)+len(c.O)) - r := getBuffer(nbInputs) - r = append(r, uint32(nbInputs)) - r = append(r, uint32(len(c.L)), uint32(len(c.R)), uint32(len(c.O))) + (*to) = append((*to), uint32(nbInputs)) + (*to) = append((*to), uint32(len(c.L)), uint32(len(c.R)), uint32(len(c.O))) for _, t := range c.L { - r = append(r, uint32(t.CoeffID()), uint32(t.WireID())) + (*to) = append((*to), uint32(t.CoeffID()), uint32(t.WireID())) } for _, t := range c.R { - r = append(r, uint32(t.CoeffID()), uint32(t.WireID())) + (*to) = append((*to), uint32(t.CoeffID()), uint32(t.WireID())) } for _, t := range c.O { - r = append(r, uint32(t.CoeffID()), uint32(t.WireID())) + (*to) = append((*to), uint32(t.CoeffID()), uint32(t.WireID())) } - return r } func (b *BlueprintGenericR1C) DecompressR1C(c *R1C, inst Instruction) { @@ -80,17 +78,3 @@ func (b *BlueprintGenericR1C) WireWalker(inst Instruction) func(cb func(wire uin appendWires(lenO, offset+2*(lenL+lenR)) } } - -// since frontend is single threaded, to avoid allocating slices at each compress call -// we transit the compressed output through here -var bufCalldata []uint32 - -// getBuffer return a slice with at least the given capacity to use in Compress methods -// this is obviously not thread safe, but the frontend is single threaded anyway. -func getBuffer(size int) []uint32 { - if cap(bufCalldata) < size { - bufCalldata = make([]uint32, 0, size*2) - } - bufCalldata = bufCalldata[:0] - return bufCalldata -} diff --git a/constraint/blueprint_scs.go b/constraint/blueprint_scs.go index 69fa67c55a..3f0973e234 100644 --- a/constraint/blueprint_scs.go +++ b/constraint/blueprint_scs.go @@ -36,17 +36,8 @@ func (b *BlueprintGenericSparseR1C) WireWalker(inst Instruction) func(cb func(wi } } -func (b *BlueprintGenericSparseR1C) CompressSparseR1C(c *SparseR1C) []uint32 { - bufSCS[0] = c.XA - bufSCS[1] = c.XB - bufSCS[2] = c.XC - bufSCS[3] = c.QL - bufSCS[4] = c.QR - bufSCS[5] = c.QO - bufSCS[6] = c.QM - bufSCS[7] = c.QC - bufSCS[8] = uint32(c.Commitment) - return bufSCS[:] +func (b *BlueprintGenericSparseR1C) CompressSparseR1C(c *SparseR1C, to *[]uint32) { + *to = append(*to, c.XA, c.XB, c.XC, c.QL, c.QR, c.QO, c.QM, c.QC, uint32(c.Commitment)) } func (b *BlueprintGenericSparseR1C) DecompressSparseR1C(c *SparseR1C, inst Instruction) { @@ -189,12 +180,8 @@ func (b *BlueprintSparseR1CMul) WireWalker(inst Instruction) func(cb func(wire u } } -func (b *BlueprintSparseR1CMul) CompressSparseR1C(c *SparseR1C) []uint32 { - bufSCS[0] = c.XA - bufSCS[1] = c.XB - bufSCS[2] = c.XC - bufSCS[3] = c.QM - return bufSCS[:4] +func (b *BlueprintSparseR1CMul) CompressSparseR1C(c *SparseR1C, to *[]uint32) { + *to = append(*to, c.XA, c.XB, c.XC, c.QM) } func (b *BlueprintSparseR1CMul) Solve(s Solver, inst Instruction) error { @@ -241,14 +228,8 @@ func (b *BlueprintSparseR1CAdd) WireWalker(inst Instruction) func(cb func(wire u } } -func (b *BlueprintSparseR1CAdd) CompressSparseR1C(c *SparseR1C) []uint32 { - bufSCS[0] = c.XA - bufSCS[1] = c.XB - bufSCS[2] = c.XC - bufSCS[3] = c.QL - bufSCS[4] = c.QR - bufSCS[5] = c.QC - return bufSCS[:6] +func (b *BlueprintSparseR1CAdd) CompressSparseR1C(c *SparseR1C, to *[]uint32) { + *to = append(*to, c.XA, c.XB, c.XC, c.QL, c.QR, c.QC) } func (blueprint *BlueprintSparseR1CAdd) Solve(s Solver, inst Instruction) error { @@ -298,11 +279,8 @@ func (b *BlueprintSparseR1CBool) WireWalker(inst Instruction) func(cb func(wire } } -func (b *BlueprintSparseR1CBool) CompressSparseR1C(c *SparseR1C) []uint32 { - bufSCS[0] = c.XA - bufSCS[1] = c.QL - bufSCS[2] = c.QM - return bufSCS[:3] +func (b *BlueprintSparseR1CBool) CompressSparseR1C(c *SparseR1C, to *[]uint32) { + *to = append(*to, c.XA, c.QL, c.QM) } func (blueprint *BlueprintSparseR1CBool) Solve(s Solver, inst Instruction) error { @@ -325,7 +303,3 @@ func (b *BlueprintSparseR1CBool) DecompressSparseR1C(c *SparseR1C, inst Instruct c.QL = inst.Calldata[1] c.QM = inst.Calldata[2] } - -// since frontend is single threaded, to avoid allocating slices at each compress call -// we transit the compressed output through here -var bufSCS [9]uint32 diff --git a/constraint/core.go b/constraint/core.go index 15fabf2be0..11912935f3 100644 --- a/constraint/core.go +++ b/constraint/core.go @@ -3,6 +3,7 @@ package constraint import ( "fmt" "math/big" + "sync" "github.com/blang/semver/v4" "github.com/consensys/gnark" @@ -275,9 +276,16 @@ func (system *System) AddSolverHint(f solver.Hint, input []LinearExpression, nbO } blueprint := system.Blueprints[system.genericHint] - calldata := blueprint.(BlueprintHint).CompressHint(hm) - system.AddInstruction(system.genericHint, calldata) + // get []uint32 from the pool + calldata := getBuffer() + + blueprint.(BlueprintHint).CompressHint(hm, calldata) + + system.AddInstruction(system.genericHint, *calldata) + + // return []uint32 to the pool + putBuffer(calldata) return } @@ -324,9 +332,16 @@ func (cs *System) AddR1C(c R1C, bID BlueprintID) int { profile.RecordConstraint() blueprint := cs.Blueprints[bID] - calldata := blueprint.(BlueprintR1C).CompressR1C(&c) - cs.AddInstruction(bID, calldata) + // get a []uint32 from a pool + calldata := getBuffer() + + // compress the R1C into a []uint32 and add the instruction + blueprint.(BlueprintR1C).CompressR1C(&c, calldata) + cs.AddInstruction(bID, *calldata) + + // release the []uint32 to the pool + putBuffer(calldata) return cs.NbConstraints - 1 } @@ -335,9 +350,17 @@ func (cs *System) AddSparseR1C(c SparseR1C, bID BlueprintID) int { profile.RecordConstraint() blueprint := cs.Blueprints[bID] - calldata := blueprint.(BlueprintSparseR1C).CompressSparseR1C(&c) - cs.AddInstruction(bID, calldata) + // get a []uint32 from a pool + calldata := getBuffer() + + // compress the SparceR1C into a []uint32 and add the instruction + blueprint.(BlueprintSparseR1C).CompressSparseR1C(&c, calldata) + + cs.AddInstruction(bID, *calldata) + + // release the []uint32 to the pool + putBuffer(calldata) return cs.NbConstraints - 1 } @@ -392,3 +415,30 @@ func (cs *System) GetR1CIterator() R1CIterator { func (cs *System) GetSparseR1CIterator() SparseR1CIterator { return SparseR1CIterator{cs: cs} } + +// bufPool is a pool of buffers used by getBuffer and putBuffer. +// It is used to avoid allocating buffers for each constraint. +var bufPool = sync.Pool{ + New: func() interface{} { + r := make([]uint32, 0, 20) + return &r + }, +} + +// getBuffer returns a buffer of at least the given size. +// The buffer is taken from the pool if it is large enough, +// otherwise a new buffer is allocated. +// Caller must call putBuffer when done with the buffer. +func getBuffer() *[]uint32 { + to := bufPool.Get().(*[]uint32) + *to = (*to)[:0] + return to +} + +// putBuffer returns a buffer to the pool. +func putBuffer(buf *[]uint32) { + if buf == nil { + panic("invalid entry in putBuffer") + } + bufPool.Put(buf) +} diff --git a/test/engine.go b/test/engine.go index 7a505a8af3..85e1f6af35 100644 --- a/test/engine.go +++ b/test/engine.go @@ -24,6 +24,7 @@ import ( "runtime" "strconv" "strings" + "sync/atomic" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/solver" @@ -154,11 +155,11 @@ func callDeferred(builder *engine) error { var cptAdd, cptMul, cptSub, cptToBinary, cptFromBinary, cptAssertIsEqual uint64 func (e *engine) Add(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { - cptAdd++ + atomic.AddUint64(&cptAdd, 1) res := new(big.Int) res.Add(e.toBigInt(i1), e.toBigInt(i2)) for i := 0; i < len(in); i++ { - cptAdd++ + atomic.AddUint64(&cptAdd, 1) res.Add(res, e.toBigInt(in[i])) } res.Mod(res, e.modulus()) @@ -178,11 +179,11 @@ func (e *engine) MulAcc(a, b, c frontend.Variable) frontend.Variable { } func (e *engine) Sub(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { - cptSub++ + atomic.AddUint64(&cptSub, 1) res := new(big.Int) res.Sub(e.toBigInt(i1), e.toBigInt(i2)) for i := 0; i < len(in); i++ { - cptSub++ + atomic.AddUint64(&cptSub, 1) res.Sub(res, e.toBigInt(in[i])) } res.Mod(res, e.modulus()) @@ -197,7 +198,7 @@ func (e *engine) Neg(i1 frontend.Variable) frontend.Variable { } func (e *engine) Mul(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { - cptMul++ + atomic.AddUint64(&cptMul, 1) b2 := e.toBigInt(i2) if len(in) == 0 && b2.IsUint64() && b2.Uint64() <= 1 { // special path to avoid useless allocations @@ -211,7 +212,7 @@ func (e *engine) Mul(i1, i2 frontend.Variable, in ...frontend.Variable) frontend res.Mul(b1, b2) res.Mod(res, e.modulus()) for i := 0; i < len(in); i++ { - cptMul++ + atomic.AddUint64(&cptMul, 1) res.Mul(res, e.toBigInt(in[i])) res.Mod(res, e.modulus()) } @@ -251,7 +252,7 @@ func (e *engine) Inverse(i1 frontend.Variable) frontend.Variable { } func (e *engine) ToBinary(i1 frontend.Variable, n ...int) []frontend.Variable { - cptToBinary++ + atomic.AddUint64(&cptToBinary, 1) nbBits := e.FieldBitLen() if len(n) == 1 { nbBits = n[0] @@ -283,7 +284,7 @@ func (e *engine) ToBinary(i1 frontend.Variable, n ...int) []frontend.Variable { } func (e *engine) FromBinary(v ...frontend.Variable) frontend.Variable { - cptFromBinary++ + atomic.AddUint64(&cptFromBinary, 1) bits := make([]bool, len(v)) for i := 0; i < len(v); i++ { be := e.toBigInt(v[i]) @@ -380,7 +381,7 @@ func (e *engine) Cmp(i1, i2 frontend.Variable) frontend.Variable { } func (e *engine) AssertIsEqual(i1, i2 frontend.Variable) { - cptAssertIsEqual++ + atomic.AddUint64(&cptAssertIsEqual, 1) b1, b2 := e.toBigInt(i1), e.toBigInt(i2) if b1.Cmp(b2) != 0 { panic(fmt.Sprintf("[assertIsEqual] %s == %s", b1.String(), b2.String())) From 7165274f61d206907bbf25e98739b4b97c82559c Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 5 May 2023 10:55:54 -0500 Subject: [PATCH 322/464] revert: unexport cs.system --- constraint/tinyfield/solver.go | 6 +++--- constraint/tinyfield/system.go | 32 ++++++++++++++++---------------- test/engine.go | 1 - 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/constraint/tinyfield/solver.go b/constraint/tinyfield/solver.go index 17a28c8368..7cb146906c 100644 --- a/constraint/tinyfield/solver.go +++ b/constraint/tinyfield/solver.go @@ -37,7 +37,7 @@ import ( // solver represent the state of the solver during a call to System.Solve(...) type solver struct { - *System + *system // values and solved are index by the wire (variable) id values []fr.Element @@ -55,7 +55,7 @@ type solver struct { q *big.Int } -func newSolver(cs *System, witness fr.Vector, opts ...csolver.Option) (*solver, error) { +func newSolver(cs *system, witness fr.Vector, opts ...csolver.Option) (*solver, error) { // parse options opt, err := csolver.NewConfig(opts...) if err != nil { @@ -91,7 +91,7 @@ func newSolver(cs *System, witness fr.Vector, opts ...csolver.Option) (*solver, } s := solver{ - System: cs, + system: cs, values: make([]fr.Element, nbWires), solved: make([]bool, nbWires), mHintsFunctions: hintFunctions, diff --git a/constraint/tinyfield/system.go b/constraint/tinyfield/system.go index b021d667b3..396529971b 100644 --- a/constraint/tinyfield/system.go +++ b/constraint/tinyfield/system.go @@ -33,11 +33,11 @@ import ( fr "github.com/consensys/gnark/internal/tinyfield" ) -type R1CS = System -type SparseR1CS = System +type R1CS = system +type SparseR1CS = system -// System is a curved-typed constraint.System with a concrete coefficient table (fr.Element) -type System struct { +// system is a curved-typed constraint.System with a concrete coefficient table (fr.Element) +type system struct { constraint.System CoeffTable field @@ -51,8 +51,8 @@ func NewSparseR1CS(capacity int) *SparseR1CS { return newSystem(capacity, constraint.SystemSparseR1CS) } -func newSystem(capacity int, t constraint.SystemType) *System { - return &System{ +func newSystem(capacity int, t constraint.SystemType) *system { + return &system{ System: constraint.NewSystem(fr.Modulus(), capacity, t), CoeffTable: newCoeffTable(capacity / 10), } @@ -61,7 +61,7 @@ func newSystem(capacity int, t constraint.SystemType) *System { // Solve solves the constraint system with provided witness. // If it's a R1CS returns R1CSSolution // If it's a SparseR1CS returns SparseR1CSSolution -func (cs *System) Solve(witness witness.Witness, opts ...csolver.Option) (any, error) { +func (cs *system) Solve(witness witness.Witness, opts ...csolver.Option) (any, error) { log := logger.Logger().With().Int("nbConstraints", cs.GetNbConstraints()).Logger() start := time.Now() @@ -108,13 +108,13 @@ func (cs *System) Solve(witness witness.Witness, opts ...csolver.Option) (any, e // IsSolved // Deprecated: use _, err := Solve(...) instead -func (cs *System) IsSolved(witness witness.Witness, opts ...csolver.Option) error { +func (cs *system) IsSolved(witness witness.Witness, opts ...csolver.Option) error { _, err := cs.Solve(witness, opts...) return err } // GetR1Cs return the list of R1C -func (cs *System) GetR1Cs() []constraint.R1C { +func (cs *system) GetR1Cs() []constraint.R1C { toReturn := make([]constraint.R1C, 0, cs.GetNbConstraints()) for _, inst := range cs.Instructions { @@ -131,17 +131,17 @@ func (cs *System) GetR1Cs() []constraint.R1C { } // GetNbCoefficients return the number of unique coefficients needed in the R1CS -func (cs *System) GetNbCoefficients() int { +func (cs *system) GetNbCoefficients() int { return len(cs.Coefficients) } // CurveID returns curve ID as defined in gnark-crypto -func (cs *System) CurveID() ecc.ID { +func (cs *system) CurveID() ecc.ID { return ecc.UNKNOWN } // WriteTo encodes R1CS into provided io.Writer using cbor -func (cs *System) WriteTo(w io.Writer) (int64, error) { +func (cs *system) WriteTo(w io.Writer) (int64, error) { _w := ioutils.WriterCounter{W: w} // wraps writer to count the bytes written ts := getTagSet() enc, err := cbor.CoreDetEncOptions().EncModeWithTags(ts) @@ -156,7 +156,7 @@ func (cs *System) WriteTo(w io.Writer) (int64, error) { } // ReadFrom attempts to decode R1CS from io.Reader using cbor -func (cs *System) ReadFrom(r io.Reader) (int64, error) { +func (cs *system) ReadFrom(r io.Reader) (int64, error) { ts := getTagSet() dm, err := cbor.DecOptions{ MaxArrayElements: 134217728, @@ -182,13 +182,13 @@ func (cs *System) ReadFrom(r io.Reader) (int64, error) { return int64(decoder.NumBytesRead()), nil } -func (cs *System) GetCoefficient(i int) (r constraint.Element) { +func (cs *system) GetCoefficient(i int) (r constraint.Element) { copy(r[:], cs.Coefficients[i][:]) return } // GetSparseR1Cs return the list of SparseR1C -func (cs *System) GetSparseR1Cs() []constraint.SparseR1C { +func (cs *system) GetSparseR1Cs() []constraint.SparseR1C { toReturn := make([]constraint.SparseR1C, 0, cs.GetNbConstraints()) @@ -208,7 +208,7 @@ func (cs *System) GetSparseR1Cs() []constraint.SparseR1C { // evaluateLROSmallDomain extracts the solver l, r, o, and returns it in lagrange form. // solver = [ public | secret | internal ] // TODO @gbotrel refactor; this seems to be a small util function for plonk -func evaluateLROSmallDomain(cs *System, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { +func evaluateLROSmallDomain(cs *system, solution []fr.Element) ([]fr.Element, []fr.Element, []fr.Element) { //s := int(pk.Domain[0].Cardinality) s := cs.GetNbConstraints() + len(cs.Public) // len(spr.Public) is for the placeholder constraints diff --git a/test/engine.go b/test/engine.go index 80ba6d0be4..9bf71509d7 100644 --- a/test/engine.go +++ b/test/engine.go @@ -27,7 +27,6 @@ import ( "strings" "sync/atomic" - "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/debug" "github.com/consensys/gnark/frontend/schema" From afaa527fb793b8c1fdd7922e60a0909fda8fed64 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 5 May 2023 11:00:18 -0500 Subject: [PATCH 323/464] revert: remove extra testing funcs --- test/solver_test.go | 71 --------------------------------------------- 1 file changed, 71 deletions(-) diff --git a/test/solver_test.go b/test/solver_test.go index e6eebfe31e..f91d6e607a 100644 --- a/test/solver_test.go +++ b/test/solver_test.go @@ -1,14 +1,8 @@ package test import ( - "bytes" - "encoding/hex" - "errors" "fmt" - cs "github.com/consensys/gnark/constraint/tinyfield" "github.com/consensys/gnark/internal/backend/circuits" - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" "io" "math/big" "reflect" @@ -271,12 +265,6 @@ func consistentSolver(circuit frontend.Circuit, hintFunctions []solver.Hint) err return err } - diff := diffCs(ccs, i, circuit) - - if diff != "" { - return errors.New(diff) - } - p.constraintSystems[i] = ccs if i == 0 { // the -1 is only for r1cs... @@ -305,62 +293,3 @@ func init() { builders[0] = r1cs.NewBuilder builders[1] = scs.NewBuilder } - -const andR1cs = "b2644c6f6773f6645479706501664c6576656c7382830001028103664d4465627567a0665075626c69638161316653656372657483634f7031634f7032635265736843616c6c44617461982c0c01020101010100030100000c01020101020100030200000a0101010101010201040a010101010001040103694465627567496e666ff66a426c75657072696e747382da00510527a0da00510528a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944016d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944016d537461727443616c6c446174610c70436f6e73747261696e744f666673657401a36b426c75657072696e744944016d537461727443616c6c44617461181870436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c44617461182270436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301" -const andScs = "b2644c6f6773f6645479706502664c6576656c7382830001028103664d4465627567a0665075626c6963f66653656372657483634f7031634f7032635265736843616c6c446174619300010301010300010301030200010300000000694465627567496e666ff66a426c75657072696e747385da00510527a0da00510529a0da0051052ba0da0051052aa0da0051052ca06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944046d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944046d537461727443616c6c446174610370436f6e73747261696e744f666673657401a36b426c75657072696e744944026d537461727443616c6c446174610670436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c446174610a70436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301" -const orR1cs = "b2644c6f6773f6645479706501664c6576656c7382830001028103664d4465627567a0665075626c69638161316653656372657483634f7031634f7032635265736843616c6c4461746198300c01020101010100030100000c01020101020100030200000e010103010101020304010101020a010101010001040103694465627567496e666ff66a426c75657072696e747382da00510527a0da00510528a06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944016d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944016d537461727443616c6c446174610c70436f6e73747261696e744f666673657401a36b426c75657072696e744944016d537461727443616c6c44617461181870436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c44617461182670436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301" -const orScs = "b2644c6f6773f6645479706502664c6576656c7382830001028103664d4465627567a0665075626c6963f66653656372657483634f7031634f7032635265736843616c6c446174619818000103010103000103030301010000030200010300000000694465627567496e666ff66a426c75657072696e747385da00510527a0da00510529a0da0051052ba0da0051052aa0da0051052ca06b5363616c61724669656c646232666b53796d626f6c5461626c65a26946756e6374696f6e73f6694c6f636174696f6e73f66c436f656666696369656e74738581008118198103811681182c6c476e61726b56657273696f6e6b302e382e312d616c7068616c496e737472756374696f6e7384a36b426c75657072696e744944046d537461727443616c6c446174610070436f6e73747261696e744f666673657400a36b426c75657072696e744944046d537461727443616c6c446174610370436f6e73747261696e744f666673657401a36b426c75657072696e744944016d537461727443616c6c446174610670436f6e73747261696e744f666673657402a36b426c75657072696e744944016d537461727443616c6c446174610f70436f6e73747261696e744f6666736574036d4e62436f6e73747261696e7473046e436f6d6d69746d656e74496e666ff6724d48696e7473446570656e64656e63696573a0734e62496e7465726e616c5661726961626c657301" - -func getCs(csIndex int, circuit frontend.Circuit) string { - switch csIndex { - case 0: - if circuit == circuits.Circuits["and"].Circuit { - return andR1cs - } - if circuit == circuits.Circuits["or"].Circuit { - return orR1cs - } - case 1: - if circuit == circuits.Circuits["and"].Circuit { - return andScs - } - if circuit == circuits.Circuits["or"].Circuit { - return orScs - } - } - return "unrecognized circuit/cs" -} - -func diffCs(__cs constraint.ConstraintSystem, csIndex int, circuit frontend.Circuit) string { - - _cs := __cs.(*cs.System) - - csHex := getCs(csIndex, circuit) - if csHex == "unrecognized circuit/cs" { - return csHex - } - var expectedCs cs.System - - b, err := hex.DecodeString(csHex) - if err != nil { - return err.Error() - } - _, err = expectedCs.ReadFrom(bytes.NewReader(b)) - if err != nil { - return err.Error() - } - - return cmp.Diff(_cs, &expectedCs, cmpopts.IgnoreFields(cs.System{}, diffIgnore...)) -} - -var diffIgnore = []string{ - "System.SymbolTable.mFunctions", - "System.SymbolTable.mLocations", - "System.q", - "System.bitLen", - "System.lbWireLevel", - "System.lbOutputs", - "System.genericHint", - "CoeffTable.mCoeffs", - "field", -} From 163b57711acdd3d85adfab5afaba854254f1ef7d Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 5 May 2023 12:04:55 -0500 Subject: [PATCH 324/464] dep update gnark-crypto --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 94c31f282d..5e789fba55 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/bits-and-blooms/bitset v1.5.0 github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 - github.com/consensys/gnark-crypto v0.10.1-0.20230426090045-2a781ae21a86 + github.com/consensys/gnark-crypto v0.11.1-0.20230504180944-3f61172c800b github.com/fxamacker/cbor/v2 v2.4.0 github.com/google/go-cmp v0.5.9 github.com/google/pprof v0.0.0-20230309165930-d61513b1440d diff --git a/go.sum b/go.sum index 6dc974488d..a76797f2c8 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/Yj github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= github.com/consensys/gnark-crypto v0.10.1-0.20230426090045-2a781ae21a86 h1:Qvm/R59xXUiB7oM9v53kgN7JRn3yIGeGV9mninTVzWs= github.com/consensys/gnark-crypto v0.10.1-0.20230426090045-2a781ae21a86/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= +github.com/consensys/gnark-crypto v0.11.1-0.20230504180944-3f61172c800b h1:tj7ZZ8oadsC+Y7u72mW8Q+afaCEDPDR9hN5+y2/peyU= +github.com/consensys/gnark-crypto v0.11.1-0.20230504180944-3f61172c800b/go.mod h1:6C2ytC8zmP8uH2GKVfPOjf0Vw3KwMAaUxlCPK5WQqmw= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= From 438ca9d127505b0d6f03d7f88d202acb86520c04 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 5 May 2023 12:13:48 -0500 Subject: [PATCH 325/464] feat: plonk provingkey marshaling with muticommits --- backend/plonk/bn254/marshal.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/backend/plonk/bn254/marshal.go b/backend/plonk/bn254/marshal.go index f523a7ed95..47220e3c6c 100644 --- a/backend/plonk/bn254/marshal.go +++ b/backend/plonk/bn254/marshal.go @@ -125,7 +125,7 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { pk.trace.Qm.Coefficients(), pk.trace.Qo.Coefficients(), pk.trace.Qk.Coefficients(), - pk.trace.Qcp.Coefficients(), + coefficients(pk.trace.Qcp), pk.lQk.Coefficients(), pk.trace.S1.Coefficients(), pk.trace.S2.Coefficients(), @@ -166,7 +166,8 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { dec := curve.NewDecoder(r) - var ql, qr, qm, qo, qk, qcp, lqk, s1, s2, s3 []fr.Element + var ql, qr, qm, qo, qk, lqk, s1, s2, s3 []fr.Element + var qcp [][]fr.Element toDecode := []interface{}{ &ql, &qr, @@ -193,11 +194,15 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) - pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + pk.trace.Qcp = make([]*iop.Polynomial, len(qcp)) + for i := range qcp { + pk.trace.Qcp[i] = iop.NewPolynomial(&qcp[i], canReg) + } + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} pk.lQk = iop.NewPolynomial(&lqk, lagReg) From 1f50f065ec71adf2a98443a362affbab8741f3a6 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Fri, 5 May 2023 16:00:25 -0500 Subject: [PATCH 326/464] ci: ensure linter runs on generated files + adjustements (#677) * build: ensure linter runs on generated files * build: make linter happier * experiment: try button to find failed workflow * experiment: revert * experiment: revert * experiment: revert * build: update to latest gnark crypto --- .github/workflows/pr.yml | 23 +++++-- .github/workflows/push.yml | 23 +++++-- backend/plonk/bls12-377/marshal_test.go | 8 +-- backend/plonk/bls12-381/marshal_test.go | 8 +-- backend/plonk/bls24-315/marshal_test.go | 8 +-- backend/plonk/bls24-317/marshal_test.go | 8 +-- backend/plonk/bn254/marshal_test.go | 8 +-- backend/plonk/bw6-633/marshal_test.go | 8 +-- backend/plonk/bw6-761/marshal_test.go | 8 +-- constraint/bls12-377/system.go | 8 +-- constraint/bls12-381/system.go | 8 +-- constraint/bls24-315/system.go | 8 +-- constraint/bls24-317/system.go | 8 +-- constraint/bn254/system.go | 8 +-- constraint/bw6-633/system.go | 8 +-- constraint/bw6-761/system.go | 8 +-- constraint/tinyfield/system.go | 8 +-- go.mod | 2 +- go.sum | 2 + .../template/representations/system.go.tmpl | 8 +-- .../zkpschemes/plonk/tests/marshal.go.tmpl | 8 +-- internal/tinyfield/element.go | 2 +- internal/tinyfield/element_test.go | 68 ++++++++++++------- 23 files changed, 148 insertions(+), 108 deletions(-) diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 0ce12537db..4ebfba8c25 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -22,10 +22,6 @@ jobs: key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go- - - name: golangci-lint - uses: golangci/golangci-lint-action@v3 - with: - args: --timeout=5m - name: install deps run: go install golang.org/x/tools/cmd/goimports@latest && go install github.com/klauspost/asmfmt/cmd/asmfmt@latest - name: gofmt @@ -35,7 +31,18 @@ jobs: go generate ./... git update-index --assume-unchanged go.mod git update-index --assume-unchanged go.sum - if [[ -n $(git status --porcelain) ]]; then echo "git repo is dirty after runing go generate -- please don't modify generated files"; echo $(git diff);echo $(git status --porcelain); exit 1; fi + if [[ -n $(git status --porcelain) ]]; then echo "git repo is dirty after running go generate -- please don't modify generated files"; echo $(git diff);echo $(git status --porcelain); exit 1; fi + + # hack to ensure golanglint process generated files + - name: remove "generated by" comments from generated files + run: | + find . -type f -name '*.go' -exec sed -i 's/Code generated by .* DO NOT EDIT/FOO/g' {} \; + # on macos: find . -type f -name '*.go' -exec sed -i '' -E 's/Code generated by .* DO NOT EDIT/FOO/g' {} \; + + - name: golangci-lint + uses: golangci/golangci-lint-action@v3 + with: + args: --timeout=5m test: strategy: @@ -67,6 +74,9 @@ jobs: - name: Test run: | go test -v -short -timeout=30m ./... + - name: Test race + run: | + go test -v -short -race -timeout=30m slack-workflow-status-failed: if: failure() @@ -86,7 +96,8 @@ jobs: "repo": "${{ github.repository }}", "status": "FAIL", "title": "${{ github.event.pull_request.title }}", - "pr": "${{ github.event.pull_request.head.ref }}" + "pr": "${{ github.event.pull_request.head.ref }}", + "failed_step_url": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/" } env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index c908d67ace..d894abb043 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -26,10 +26,8 @@ jobs: key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go- - - name: golangci-lint - uses: golangci/golangci-lint-action@v3 - with: - args: --timeout=5m + + - name: install deps run: go install golang.org/x/tools/cmd/goimports@latest && go install github.com/klauspost/asmfmt/cmd/asmfmt@latest - name: gofmt @@ -39,7 +37,19 @@ jobs: go generate ./... git update-index --assume-unchanged go.mod git update-index --assume-unchanged go.sum - if [[ -n $(git status --porcelain) ]]; then echo "git repo is dirty after runing go generate -- please don't modify generated files"; echo $(git diff);echo $(git status --porcelain); exit 1; fi + if [[ -n $(git status --porcelain) ]]; then echo "git repo is dirty after running go generate -- please don't modify generated files"; echo $(git diff);echo $(git status --porcelain); exit 1; fi + + # hack to ensure golanglint process generated files + - name: remove "generated by" comments from generated files + run: | + find . -type f -name '*.go' -exec sed -i 's/Code generated by .* DO NOT EDIT/FOO/g' {} \; + # on macos: find . -type f -name '*.go' -exec sed -i '' -E 's/Code generated by .* DO NOT EDIT/FOO/g' {} \; + + - name: golangci-lint + uses: golangci/golangci-lint-action@v3 + with: + args: --timeout=5m + test: strategy: @@ -94,7 +104,8 @@ jobs: "repo": "${{ github.repository }}", "status": "FAIL", "title": "push to ${{ github.event.push.base_ref }}", - "pr": "" + "pr": "", + "failed_step_url": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/" } env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/backend/plonk/bls12-377/marshal_test.go b/backend/plonk/bls12-377/marshal_test.go index bc928b6749..5f7c653446 100644 --- a/backend/plonk/bls12-377/marshal_test.go +++ b/backend/plonk/bls12-377/marshal_test.go @@ -148,11 +148,11 @@ func (pk *ProvingKey) randomize() { } func (vk *VerifyingKey) randomize() { - vk.Size = rand.Uint64() + vk.Size = rand.Uint64() //#nosec G404 weak rng is fine here vk.SizeInv.SetRandom() vk.Generator.SetRandom() - vk.NbPublicVariables = rand.Uint64() - vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} + vk.NbPublicVariables = rand.Uint64() //#nosec G404 weak rng is fine here + vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} //#nosec G404 weak rng is fine here vk.CosetShift.SetRandom() vk.S[0] = randomPoint() @@ -183,7 +183,7 @@ func (proof *Proof) randomize() { func randomPoint() curve.G1Affine { _, _, r, _ := curve.Generators() - r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) + r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) //#nosec G404 weak rng is fine here return r } diff --git a/backend/plonk/bls12-381/marshal_test.go b/backend/plonk/bls12-381/marshal_test.go index 6c86955b9f..7771d3595d 100644 --- a/backend/plonk/bls12-381/marshal_test.go +++ b/backend/plonk/bls12-381/marshal_test.go @@ -148,11 +148,11 @@ func (pk *ProvingKey) randomize() { } func (vk *VerifyingKey) randomize() { - vk.Size = rand.Uint64() + vk.Size = rand.Uint64() //#nosec G404 weak rng is fine here vk.SizeInv.SetRandom() vk.Generator.SetRandom() - vk.NbPublicVariables = rand.Uint64() - vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} + vk.NbPublicVariables = rand.Uint64() //#nosec G404 weak rng is fine here + vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} //#nosec G404 weak rng is fine here vk.CosetShift.SetRandom() vk.S[0] = randomPoint() @@ -183,7 +183,7 @@ func (proof *Proof) randomize() { func randomPoint() curve.G1Affine { _, _, r, _ := curve.Generators() - r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) + r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) //#nosec G404 weak rng is fine here return r } diff --git a/backend/plonk/bls24-315/marshal_test.go b/backend/plonk/bls24-315/marshal_test.go index bb4272dbee..133b7d8e43 100644 --- a/backend/plonk/bls24-315/marshal_test.go +++ b/backend/plonk/bls24-315/marshal_test.go @@ -148,11 +148,11 @@ func (pk *ProvingKey) randomize() { } func (vk *VerifyingKey) randomize() { - vk.Size = rand.Uint64() + vk.Size = rand.Uint64() //#nosec G404 weak rng is fine here vk.SizeInv.SetRandom() vk.Generator.SetRandom() - vk.NbPublicVariables = rand.Uint64() - vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} + vk.NbPublicVariables = rand.Uint64() //#nosec G404 weak rng is fine here + vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} //#nosec G404 weak rng is fine here vk.CosetShift.SetRandom() vk.S[0] = randomPoint() @@ -183,7 +183,7 @@ func (proof *Proof) randomize() { func randomPoint() curve.G1Affine { _, _, r, _ := curve.Generators() - r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) + r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) //#nosec G404 weak rng is fine here return r } diff --git a/backend/plonk/bls24-317/marshal_test.go b/backend/plonk/bls24-317/marshal_test.go index 2c40412336..fccc450173 100644 --- a/backend/plonk/bls24-317/marshal_test.go +++ b/backend/plonk/bls24-317/marshal_test.go @@ -148,11 +148,11 @@ func (pk *ProvingKey) randomize() { } func (vk *VerifyingKey) randomize() { - vk.Size = rand.Uint64() + vk.Size = rand.Uint64() //#nosec G404 weak rng is fine here vk.SizeInv.SetRandom() vk.Generator.SetRandom() - vk.NbPublicVariables = rand.Uint64() - vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} + vk.NbPublicVariables = rand.Uint64() //#nosec G404 weak rng is fine here + vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} //#nosec G404 weak rng is fine here vk.CosetShift.SetRandom() vk.S[0] = randomPoint() @@ -183,7 +183,7 @@ func (proof *Proof) randomize() { func randomPoint() curve.G1Affine { _, _, r, _ := curve.Generators() - r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) + r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) //#nosec G404 weak rng is fine here return r } diff --git a/backend/plonk/bn254/marshal_test.go b/backend/plonk/bn254/marshal_test.go index 0d82de6274..e07be1f6ff 100644 --- a/backend/plonk/bn254/marshal_test.go +++ b/backend/plonk/bn254/marshal_test.go @@ -148,11 +148,11 @@ func (pk *ProvingKey) randomize() { } func (vk *VerifyingKey) randomize() { - vk.Size = rand.Uint64() + vk.Size = rand.Uint64() //#nosec G404 weak rng is fine here vk.SizeInv.SetRandom() vk.Generator.SetRandom() - vk.NbPublicVariables = rand.Uint64() - vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} + vk.NbPublicVariables = rand.Uint64() //#nosec G404 weak rng is fine here + vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} //#nosec G404 weak rng is fine here vk.CosetShift.SetRandom() vk.S[0] = randomPoint() @@ -183,7 +183,7 @@ func (proof *Proof) randomize() { func randomPoint() curve.G1Affine { _, _, r, _ := curve.Generators() - r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) + r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) //#nosec G404 weak rng is fine here return r } diff --git a/backend/plonk/bw6-633/marshal_test.go b/backend/plonk/bw6-633/marshal_test.go index 04f36f8945..d0c3b3d29a 100644 --- a/backend/plonk/bw6-633/marshal_test.go +++ b/backend/plonk/bw6-633/marshal_test.go @@ -148,11 +148,11 @@ func (pk *ProvingKey) randomize() { } func (vk *VerifyingKey) randomize() { - vk.Size = rand.Uint64() + vk.Size = rand.Uint64() //#nosec G404 weak rng is fine here vk.SizeInv.SetRandom() vk.Generator.SetRandom() - vk.NbPublicVariables = rand.Uint64() - vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} + vk.NbPublicVariables = rand.Uint64() //#nosec G404 weak rng is fine here + vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} //#nosec G404 weak rng is fine here vk.CosetShift.SetRandom() vk.S[0] = randomPoint() @@ -183,7 +183,7 @@ func (proof *Proof) randomize() { func randomPoint() curve.G1Affine { _, _, r, _ := curve.Generators() - r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) + r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) //#nosec G404 weak rng is fine here return r } diff --git a/backend/plonk/bw6-761/marshal_test.go b/backend/plonk/bw6-761/marshal_test.go index 18e553b256..c0a61edf17 100644 --- a/backend/plonk/bw6-761/marshal_test.go +++ b/backend/plonk/bw6-761/marshal_test.go @@ -148,11 +148,11 @@ func (pk *ProvingKey) randomize() { } func (vk *VerifyingKey) randomize() { - vk.Size = rand.Uint64() + vk.Size = rand.Uint64() //#nosec G404 weak rng is fine here vk.SizeInv.SetRandom() vk.Generator.SetRandom() - vk.NbPublicVariables = rand.Uint64() - vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} + vk.NbPublicVariables = rand.Uint64() //#nosec G404 weak rng is fine here + vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} //#nosec G404 weak rng is fine here vk.CosetShift.SetRandom() vk.S[0] = randomPoint() @@ -183,7 +183,7 @@ func (proof *Proof) randomize() { func randomPoint() curve.G1Affine { _, _, r, _ := curve.Generators() - r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) + r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) //#nosec G404 weak rng is fine here return r } diff --git a/constraint/bls12-377/system.go b/constraint/bls12-377/system.go index a2526acfd4..275a559ccc 100644 --- a/constraint/bls12-377/system.go +++ b/constraint/bls12-377/system.go @@ -287,12 +287,12 @@ func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { return n, err } a, err := t.A.ReadFrom(r) - a += n + n += a if err != nil { return n, err } a, err = t.B.ReadFrom(r) - a += n + n += a if err != nil { return n, err } @@ -328,12 +328,12 @@ func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { return n, err } a, err := t.R.ReadFrom(r) - a += n + n += a if err != nil { return n, err } a, err = t.O.ReadFrom(r) - a += n + n += a return n, err } diff --git a/constraint/bls12-381/system.go b/constraint/bls12-381/system.go index 53a4aec335..79409d3d3c 100644 --- a/constraint/bls12-381/system.go +++ b/constraint/bls12-381/system.go @@ -287,12 +287,12 @@ func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { return n, err } a, err := t.A.ReadFrom(r) - a += n + n += a if err != nil { return n, err } a, err = t.B.ReadFrom(r) - a += n + n += a if err != nil { return n, err } @@ -328,12 +328,12 @@ func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { return n, err } a, err := t.R.ReadFrom(r) - a += n + n += a if err != nil { return n, err } a, err = t.O.ReadFrom(r) - a += n + n += a return n, err } diff --git a/constraint/bls24-315/system.go b/constraint/bls24-315/system.go index c1a768f146..6b991e5afa 100644 --- a/constraint/bls24-315/system.go +++ b/constraint/bls24-315/system.go @@ -287,12 +287,12 @@ func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { return n, err } a, err := t.A.ReadFrom(r) - a += n + n += a if err != nil { return n, err } a, err = t.B.ReadFrom(r) - a += n + n += a if err != nil { return n, err } @@ -328,12 +328,12 @@ func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { return n, err } a, err := t.R.ReadFrom(r) - a += n + n += a if err != nil { return n, err } a, err = t.O.ReadFrom(r) - a += n + n += a return n, err } diff --git a/constraint/bls24-317/system.go b/constraint/bls24-317/system.go index 405924f0df..65e5575b8e 100644 --- a/constraint/bls24-317/system.go +++ b/constraint/bls24-317/system.go @@ -287,12 +287,12 @@ func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { return n, err } a, err := t.A.ReadFrom(r) - a += n + n += a if err != nil { return n, err } a, err = t.B.ReadFrom(r) - a += n + n += a if err != nil { return n, err } @@ -328,12 +328,12 @@ func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { return n, err } a, err := t.R.ReadFrom(r) - a += n + n += a if err != nil { return n, err } a, err = t.O.ReadFrom(r) - a += n + n += a return n, err } diff --git a/constraint/bn254/system.go b/constraint/bn254/system.go index 7fc39e7136..46786c663f 100644 --- a/constraint/bn254/system.go +++ b/constraint/bn254/system.go @@ -287,12 +287,12 @@ func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { return n, err } a, err := t.A.ReadFrom(r) - a += n + n += a if err != nil { return n, err } a, err = t.B.ReadFrom(r) - a += n + n += a if err != nil { return n, err } @@ -328,12 +328,12 @@ func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { return n, err } a, err := t.R.ReadFrom(r) - a += n + n += a if err != nil { return n, err } a, err = t.O.ReadFrom(r) - a += n + n += a return n, err } diff --git a/constraint/bw6-633/system.go b/constraint/bw6-633/system.go index fc71ccce80..26ffb323c2 100644 --- a/constraint/bw6-633/system.go +++ b/constraint/bw6-633/system.go @@ -287,12 +287,12 @@ func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { return n, err } a, err := t.A.ReadFrom(r) - a += n + n += a if err != nil { return n, err } a, err = t.B.ReadFrom(r) - a += n + n += a if err != nil { return n, err } @@ -328,12 +328,12 @@ func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { return n, err } a, err := t.R.ReadFrom(r) - a += n + n += a if err != nil { return n, err } a, err = t.O.ReadFrom(r) - a += n + n += a return n, err } diff --git a/constraint/bw6-761/system.go b/constraint/bw6-761/system.go index 6c636d147b..049819c3da 100644 --- a/constraint/bw6-761/system.go +++ b/constraint/bw6-761/system.go @@ -287,12 +287,12 @@ func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { return n, err } a, err := t.A.ReadFrom(r) - a += n + n += a if err != nil { return n, err } a, err = t.B.ReadFrom(r) - a += n + n += a if err != nil { return n, err } @@ -328,12 +328,12 @@ func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { return n, err } a, err := t.R.ReadFrom(r) - a += n + n += a if err != nil { return n, err } a, err = t.O.ReadFrom(r) - a += n + n += a return n, err } diff --git a/constraint/tinyfield/system.go b/constraint/tinyfield/system.go index 396529971b..d8f7f0e383 100644 --- a/constraint/tinyfield/system.go +++ b/constraint/tinyfield/system.go @@ -287,12 +287,12 @@ func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { return n, err } a, err := t.A.ReadFrom(r) - a += n + n += a if err != nil { return n, err } a, err = t.B.ReadFrom(r) - a += n + n += a if err != nil { return n, err } @@ -328,12 +328,12 @@ func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { return n, err } a, err := t.R.ReadFrom(r) - a += n + n += a if err != nil { return n, err } a, err = t.O.ReadFrom(r) - a += n + n += a return n, err } diff --git a/go.mod b/go.mod index 94c31f282d..545a3fb6e2 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/bits-and-blooms/bitset v1.5.0 github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 - github.com/consensys/gnark-crypto v0.10.1-0.20230426090045-2a781ae21a86 + github.com/consensys/gnark-crypto v0.11.1-0.20230505203810-d11bbde7881b github.com/fxamacker/cbor/v2 v2.4.0 github.com/google/go-cmp v0.5.9 github.com/google/pprof v0.0.0-20230309165930-d61513b1440d diff --git a/go.sum b/go.sum index 6dc974488d..68376235d9 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/Yj github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= github.com/consensys/gnark-crypto v0.10.1-0.20230426090045-2a781ae21a86 h1:Qvm/R59xXUiB7oM9v53kgN7JRn3yIGeGV9mninTVzWs= github.com/consensys/gnark-crypto v0.10.1-0.20230426090045-2a781ae21a86/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= +github.com/consensys/gnark-crypto v0.11.1-0.20230505203810-d11bbde7881b h1:TZNIR/qAAR04IumwJPY2R1ILu9QOfvYLRrlA/oJYsk0= +github.com/consensys/gnark-crypto v0.11.1-0.20230505203810-d11bbde7881b/go.mod h1:6C2ytC8zmP8uH2GKVfPOjf0Vw3KwMAaUxlCPK5WQqmw= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/internal/generator/backend/template/representations/system.go.tmpl b/internal/generator/backend/template/representations/system.go.tmpl index 2fdad80ca2..2270319d9a 100644 --- a/internal/generator/backend/template/representations/system.go.tmpl +++ b/internal/generator/backend/template/representations/system.go.tmpl @@ -282,12 +282,12 @@ func (t *R1CSSolution) ReadFrom(r io.Reader) (int64, error) { return n, err } a, err := t.A.ReadFrom(r) - a += n + n += a if err != nil { return n, err } a, err = t.B.ReadFrom(r) - a += n + n += a if err != nil { return n, err } @@ -325,12 +325,12 @@ func (t *SparseR1CSSolution) ReadFrom(r io.Reader) (int64, error) { return n, err } a, err := t.R.ReadFrom(r) - a += n + n += a if err != nil { return n, err } a, err = t.O.ReadFrom(r) - a += n + n += a return n, err } diff --git a/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl index 63d96b40f0..233e588653 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl @@ -129,11 +129,11 @@ func (pk *ProvingKey) randomize() { } func (vk *VerifyingKey) randomize() { - vk.Size = rand.Uint64() + vk.Size = rand.Uint64() //#nosec G404 weak rng is fine here vk.SizeInv.SetRandom() vk.Generator.SetRandom() - vk.NbPublicVariables = rand.Uint64() - vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} + vk.NbPublicVariables = rand.Uint64() //#nosec G404 weak rng is fine here + vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} //#nosec G404 weak rng is fine here vk.CosetShift.SetRandom() vk.S[0] = randomPoint() @@ -164,7 +164,7 @@ func (proof *Proof) randomize() { func randomPoint() curve.G1Affine { _, _, r, _ := curve.Generators() - r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) + r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) //#nosec G404 weak rng is fine here return r } diff --git a/internal/tinyfield/element.go b/internal/tinyfield/element.go index 86f134f590..f987f62b2d 100644 --- a/internal/tinyfield/element.go +++ b/internal/tinyfield/element.go @@ -300,7 +300,7 @@ func (z *Element) SetRandom() (*Element, error) { return nil, err } - // Clear unused bits in in the most signicant byte to increase probability + // Clear unused bits in in the most significant byte to increase probability // that the candidate is < q. bytes[k-1] &= uint8(int(1< Date: Fri, 5 May 2023 16:10:24 -0500 Subject: [PATCH 327/464] fix: proof serialization --- backend/plonk/bn254/marshal.go | 25 ++++++++++++++++++++++--- backend/plonk/bn254/marshal_test.go | 20 ++++++++++++++++---- go.mod | 2 +- go.sum | 2 ++ 4 files changed, 41 insertions(+), 8 deletions(-) diff --git a/backend/plonk/bn254/marshal.go b/backend/plonk/bn254/marshal.go index 47220e3c6c..9ec8bb3089 100644 --- a/backend/plonk/bn254/marshal.go +++ b/backend/plonk/bn254/marshal.go @@ -17,7 +17,9 @@ package plonk import ( + "fmt" curve "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/kzg" "errors" "github.com/consensys/gnark-crypto/ecc/bn254/fr" @@ -36,6 +38,11 @@ func (proof *Proof) WriteTo(w io.Writer) (int64, error) { } func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64, error) { + pi2 := make([]curve.G1Affine, len(proof.PI2)) + for i := range pi2 { + pi2[i] = proof.PI2[i] + } + enc := curve.NewEncoder(w, options...) toEncode := []interface{}{ @@ -50,7 +57,7 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - &proof.PI2, + pi2, } for _, v := range toEncode { @@ -64,6 +71,9 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 // ReadFrom reads binary representation of Proof from r func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { + + var pi2 []curve.G1Affine + dec := curve.NewDecoder(r) toDecode := []interface{}{ &proof.LRO[0], @@ -77,15 +87,21 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { &proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - &proof.PI2, + &pi2, } - for _, v := range toDecode { + for i, v := range toDecode { if err := dec.Decode(v); err != nil { + fmt.Println("error at", i) return dec.BytesRead(), err } } + proof.PI2 = make([]kzg.Digest, len(pi2)) + for i := range pi2 { + proof.PI2[i] = pi2[i] + } + return dec.BytesRead(), nil } @@ -244,6 +260,9 @@ func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*curve.Encoder)) (n } for _, v := range toEncode { + if v == &vk.Qcp { + fmt.Println("yo") + } if err := enc.Encode(v); err != nil { return enc.BytesWritten(), err } diff --git a/backend/plonk/bn254/marshal_test.go b/backend/plonk/bn254/marshal_test.go index 0d82de6274..dab23970d6 100644 --- a/backend/plonk/bn254/marshal_test.go +++ b/backend/plonk/bn254/marshal_test.go @@ -121,7 +121,6 @@ func (pk *ProvingKey) randomize() { qo := randomScalars(n) qk := randomScalars(n) lqk := randomScalars(n) - qcp := randomScalars(n) s1 := randomScalars(n) s2 := randomScalars(n) s3 := randomScalars(n) @@ -132,11 +131,16 @@ func (pk *ProvingKey) randomize() { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) - pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + pk.trace.Qcp = make([]*iop.Polynomial, rand.Intn(4)) + for i := range pk.trace.Qcp { + qcp := randomScalars(rand.Intn(n / 4)) + pk.trace.Qcp[i] = iop.NewPolynomial(&qcp, canReg) + } + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) pk.trace.S[0] = -12 pk.trace.S[len(pk.trace.S)-1] = 8888 @@ -163,7 +167,7 @@ func (vk *VerifyingKey) randomize() { vk.Qm = randomPoint() vk.Qo = randomPoint() vk.Qk = randomPoint() - vk.Qcp = randomPoint() + vk.Qcp = randomPoints(rand.Intn(4)) } func (proof *Proof) randomize() { @@ -178,7 +182,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.PI2 = randomPoint() + proof.PI2 = randomPoints(rand.Intn(4)) } func randomPoint() curve.G1Affine { @@ -187,6 +191,14 @@ func randomPoint() curve.G1Affine { return r } +func randomPoints(n int) []curve.G1Affine { + res := make([]curve.G1Affine, n) + for i := range res { + res[i] = randomPoint() + } + return res +} + func randomScalars(n int) []fr.Element { v := make([]fr.Element, n) one := fr.One() diff --git a/go.mod b/go.mod index 5e789fba55..a5f011f377 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/bits-and-blooms/bitset v1.5.0 github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 - github.com/consensys/gnark-crypto v0.11.1-0.20230504180944-3f61172c800b + github.com/consensys/gnark-crypto v0.11.1-0.20230505210013-748abeca0330 github.com/fxamacker/cbor/v2 v2.4.0 github.com/google/go-cmp v0.5.9 github.com/google/pprof v0.0.0-20230309165930-d61513b1440d diff --git a/go.sum b/go.sum index a76797f2c8..45ea69adc2 100644 --- a/go.sum +++ b/go.sum @@ -8,6 +8,8 @@ github.com/consensys/gnark-crypto v0.10.1-0.20230426090045-2a781ae21a86 h1:Qvm/R github.com/consensys/gnark-crypto v0.10.1-0.20230426090045-2a781ae21a86/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= github.com/consensys/gnark-crypto v0.11.1-0.20230504180944-3f61172c800b h1:tj7ZZ8oadsC+Y7u72mW8Q+afaCEDPDR9hN5+y2/peyU= github.com/consensys/gnark-crypto v0.11.1-0.20230504180944-3f61172c800b/go.mod h1:6C2ytC8zmP8uH2GKVfPOjf0Vw3KwMAaUxlCPK5WQqmw= +github.com/consensys/gnark-crypto v0.11.1-0.20230505210013-748abeca0330 h1:ETzLrW3IXsETVT5zHPfb62V73ytyTEQzYP/T1Sbb5kI= +github.com/consensys/gnark-crypto v0.11.1-0.20230505210013-748abeca0330/go.mod h1:6C2ytC8zmP8uH2GKVfPOjf0Vw3KwMAaUxlCPK5WQqmw= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= From 5a8ef7452fb85f93a3312a3be117bbb91b9508e8 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 5 May 2023 16:16:03 -0500 Subject: [PATCH 328/464] fix: Proving key serialization --- backend/plonk/bn254/marshal.go | 2 +- backend/plonk/bn254/marshal_test.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/plonk/bn254/marshal.go b/backend/plonk/bn254/marshal.go index 9ec8bb3089..76e9cdb90c 100644 --- a/backend/plonk/bn254/marshal.go +++ b/backend/plonk/bn254/marshal.go @@ -255,7 +255,7 @@ func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*curve.Encoder)) (n &vk.Qm, &vk.Qo, &vk.Qk, - &vk.Qcp, + vk.Qcp, vk.CommitmentConstraintIndexes, } diff --git a/backend/plonk/bn254/marshal_test.go b/backend/plonk/bn254/marshal_test.go index dab23970d6..9f88f1610f 100644 --- a/backend/plonk/bn254/marshal_test.go +++ b/backend/plonk/bn254/marshal_test.go @@ -140,6 +140,7 @@ func (pk *ProvingKey) randomize() { qcp := randomScalars(rand.Intn(n / 4)) pk.trace.Qcp[i] = iop.NewPolynomial(&qcp, canReg) } + //pk.trace.Qcp = []*iop.Polynomial{} // TODO Remove pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) pk.trace.S[0] = -12 From 76901865912c5207ad226c09e33c98506285eda2 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 5 May 2023 17:17:08 -0500 Subject: [PATCH 329/464] fix: prover no longer errors; unexpected quotient for 2-commit --- backend/plonk/bn254/prove.go | 75 ++++++++++++++++++++---------------- backend/plonk/bn254/setup.go | 4 +- test/commitments_test.go | 8 +++- 3 files changed, 51 insertions(+), 36 deletions(-) diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index 7d485296f7..de1bd8da90 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -64,6 +64,38 @@ type Proof struct { ZShiftedOpening kzg.OpeningProof } +func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, wpi2iop []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { + return func(_ *big.Int, ins, outs []*big.Int) error { + pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + offset := spr.GetNbPublicVariables() + for i := range ins { + pi2[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) + } + var ( + err error + hashRes []fr.Element + ) + if _, err = pi2[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + return err + } + if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding + return err + } + pi2iop := iop.NewPolynomial(&pi2, iop.Form{Basis: iop.Lagrange, Layout: iop.Regular}) + wpi2iop[commDepth] = pi2iop.ShallowClone() + wpi2iop[commDepth].ToCanonical(&pk.Domain[0]).ToRegular() + if proof.PI2[commDepth], err = kzg.Commit(wpi2iop[commDepth].Coefficients(), pk.Kzg); err != nil { + return err + } + if hashRes, err = fr.Hash(proof.PI2[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + return err + } + res.Set(&hashRes[0]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses + res.BigInt(outs[0]) + return nil + } +} + func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", spr.GetNbConstraints()).Str("backend", "plonk").Logger() @@ -82,39 +114,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // result proof := &Proof{} - lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} - var commitmentVal fr.Element // TODO @Tabaie get rid of this + + commitmentVal := make([]fr.Element, len(spr.CommitmentInfo)) // TODO @Tabaie get rid of this wpi2iop := make([]*iop.Polynomial, len(spr.CommitmentInfo)) + proof.PI2 = make([]kzg.Digest, len(spr.CommitmentInfo)) for i := range spr.CommitmentInfo { - opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[i].HintID, func(_ *big.Int, ins, outs []*big.Int) error { - pi2 := make([]fr.Element, pk.Domain[0].Cardinality) - offset := spr.GetNbPublicVariables() - for i := range ins { - pi2[offset+spr.CommitmentInfo[i].Committed[i]].SetBigInt(ins[i]) - } - var ( - err error - hashRes []fr.Element - ) - if _, err = pi2[offset+spr.CommitmentInfo[i].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. - return err - } - if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding - return err - } - pi2iop := iop.NewPolynomial(&pi2, lagReg) - wpi2iop[i] = pi2iop.ShallowClone() - wpi2iop[i].ToCanonical(&pk.Domain[0]).ToRegular() - if proof.PI2[i], err = kzg.Commit(wpi2iop[i].Coefficients(), pk.Kzg); err != nil { - return err - } - if hashRes, err = fr.Hash(proof.PI2[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { - return err - } - commitmentVal = hashRes[0] // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses - commitmentVal.BigInt(outs[0]) - return nil - })) + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[i].HintID, + bsb22ComputeCommitmentHint(spr, pk, proof, wpi2iop, &commitmentVal[i], i))) } // query l, r, o in Lagrange basis, not blinded @@ -123,7 +129,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } // TODO @gbotrel deal with that conversion lazily - var lcpi2iop []*iop.Polynomial + lcpi2iop := make([]*iop.Polynomial, len(wpi2iop)) for i := range wpi2iop { lcpi2iop[i] = wpi2iop[i].Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form } @@ -132,6 +138,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts evaluationRDomainSmall := []fr.Element(solution.R) evaluationODomainSmall := []fr.Element(solution.O) + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} // l, r o and blinded versions var ( wliop, @@ -176,8 +183,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) - if len(spr.CommitmentInfo) != 0 { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[0].CommitmentIndex] = commitmentVal + for i := range spr.CommitmentInfo { + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[i].CommitmentIndex] = commitmentVal[i] } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) diff --git a/backend/plonk/bn254/setup.go b/backend/plonk/bn254/setup.go index 116c4f664a..c44f4a9aa1 100644 --- a/backend/plonk/bn254/setup.go +++ b/backend/plonk/bn254/setup.go @@ -264,6 +264,7 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { pt.Qcp = make([]*iop.Polynomial, len(qcp)) for i := range spr.CommitmentInfo { + qcp[i] = make([]fr.Element, size) for _, committed := range spr.CommitmentInfo[i].Committed { qcp[i][offset+committed].SetOne() } @@ -271,7 +272,7 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { } } -// commitTrace commits to every polynomials in the trace, and put +// commitTrace commits to every polynomial in the trace, and put // the commitments int the verifying key. func commitTrace(trace *Trace, pk *ProvingKey) error { @@ -285,6 +286,7 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() var err error + pk.Vk.Qcp = make([]kzg.Digest, len(trace.Qcp)) for i := range trace.Qcp { trace.Qcp[i].ToCanonical(&pk.Domain[0]).ToRegular() if pk.Vk.Qcp[i], err = kzg.Commit(pk.trace.Qcp[i].Coefficients(), pk.Kzg); err != nil { diff --git a/test/commitments_test.go b/test/commitments_test.go index 100294398f..5cf9a020a1 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -76,6 +76,7 @@ func TestNoCommitmentCircuitPlonk(t *testing.T) { var fr = []ecc.ID{ ecc.BN254, + /* TODO: Add back in ecc.BLS12_381, ecc.BLS12_377, ecc.BLS24_315, @@ -83,7 +84,7 @@ var fr = []ecc.ID{ ecc.BLS24_317, ecc.BW6_633, //ecc.BW6_756, TODO: @Tabaie Not autogenerated? - ecc.BW6_761, + ecc.BW6_761,*/ } func plonkTest(t *testing.T, circuit, assignment frontend.Circuit) { @@ -181,3 +182,8 @@ func TestTwoCommitEnginePlonk(t *testing.T) { assignment := &twoCommitCircuit{X: []frontend.Variable{1, 2}, Y: 3} NewAssert(t).SolvingSucceeded(&twoCommitCircuit{X: make([]frontend.Variable, len(assignment.X))}, assignment, WithBackends(backend.PLONK)) } + +func TestTwoCommitPlonk(t *testing.T) { + assignment := &twoCommitCircuit{X: []frontend.Variable{1, 2}, Y: 3} + plonkTest(t, &twoCommitCircuit{X: make([]frontend.Variable, len(assignment.X))}, assignment) +} From f0b797b4d7bcc124d961e4108edc52a0d53829d8 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 5 May 2023 17:21:47 -0500 Subject: [PATCH 330/464] fix: no commit test passes --- backend/plonk/bn254/verify.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/backend/plonk/bn254/verify.go b/backend/plonk/bn254/verify.go index 4850e2dd7a..ac2d0a495b 100644 --- a/backend/plonk/bn254/verify.go +++ b/backend/plonk/bn254/verify.go @@ -124,9 +124,9 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { den.Sub(&zeta, &wPowI) // ζ-wⁱ lagrange.SetOne(). - Sub(&zeta, &lagrange). // ζ-1 - Mul(&lagrange, &wPowI). // wⁱ(ζ-1) - Div(&lagrange, &den). // wⁱ(ζ-1)/(ζ-wⁱ) + Sub(&zeta, &lagrange). // ζ-1 + Mul(&lagrange, &wPowI). // wⁱ(ζ-1) + Div(&lagrange, &den). // wⁱ(ζ-1)/(ζ-wⁱ) Mul(&lagrange, &lagrangeOne) // wⁱ/n (ζⁿ-1)/(ζ-wⁱ) xiLi.Mul(&lagrange, &hashRes[0]) @@ -146,7 +146,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { o := proof.BatchedProof.ClaimedValues[4] s1 := proof.BatchedProof.ClaimedValues[5] s2 := proof.BatchedProof.ClaimedValues[6] - qC := proof.BatchedProof.ClaimedValues[7] + qC := proof.BatchedProof.ClaimedValues[7:] _s1.Mul(&s1, &beta).Add(&_s1, &l).Add(&_s1, &gamma) // (l(ζ)+β*s1(ζ)+γ) _s2.Mul(&s2, &beta).Add(&_s2, &r).Add(&_s2, &gamma) // (r(ζ)+β*s2(ζ)+γ) @@ -161,8 +161,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { Mul(&alphaSquareLagrange, &alpha) // α²*L₁(ζ) linearizedPolynomialZeta. - Add(&linearizedPolynomialZeta, &pi). // linearizedpolynomial + pi(zeta) - Add(&linearizedPolynomialZeta, &_s1). // linearizedpolynomial+pi(zeta)+α*(Z(μζ))*(l(ζ)+s1(ζ)+γ)*(r(ζ)+s2(ζ)+γ)*(o(ζ)+γ) + Add(&linearizedPolynomialZeta, &pi). // linearizedpolynomial + pi(zeta) + Add(&linearizedPolynomialZeta, &_s1). // linearizedpolynomial+pi(zeta)+α*(Z(μζ))*(l(ζ)+s1(ζ)+γ)*(r(ζ)+s2(ζ)+γ)*(o(ζ)+γ) Sub(&linearizedPolynomialZeta, &alphaSquareLagrange) // linearizedpolynomial+pi(zeta)+α*(Z(μζ))*(l(ζ)+s1(ζ)+γ)*(r(ζ)+s2(ζ)+γ)*(o(ζ)+γ)-α²*L₁(ζ) // Compute H(ζ) using the previous result: H(ζ) = prev_result/(ζⁿ-1) @@ -220,10 +220,10 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { vk.S[2], proof.Z, // second & third part ) - scalars := []fr.Element{ - l, r, rl, o, one /* TODO Perf @Tabaie Consider just adding Qk instead */, qC, // first part + scalars := append(qC, + l, r, rl, o, one /* TODO Perf @Tabaie Consider just adding Qk instead */, // first part _s1, _s2, // second & third part - } + ) if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{}); err != nil { return err } From 47d6375e667b83048d691ad4e79a7ca62d006a91 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 5 May 2023 18:00:41 -0500 Subject: [PATCH 331/464] test: pi is computed correctly --- backend/plonk/bn254/prove.go | 4 ++-- backend/plonk/bn254/verify.go | 19 +++++++++++++------ test/kzg_srs.go | 1 + 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index de1bd8da90..aacf0ddbaf 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -75,12 +75,12 @@ func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof err error hashRes []fr.Element ) - if _, err = pi2[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + /*if _, err = pi2[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding return err - } + }*/ pi2iop := iop.NewPolynomial(&pi2, iop.Form{Basis: iop.Lagrange, Layout: iop.Regular}) wpi2iop[commDepth] = pi2iop.ShallowClone() wpi2iop[commDepth].ToCanonical(&pk.Domain[0]).ToRegular() diff --git a/backend/plonk/bn254/verify.go b/backend/plonk/bn254/verify.go index ac2d0a495b..e27eb19104 100644 --- a/backend/plonk/bn254/verify.go +++ b/backend/plonk/bn254/verify.go @@ -19,6 +19,7 @@ package plonk import ( "crypto/sha256" "errors" + "fmt" "io" "math/big" "time" @@ -124,9 +125,9 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { den.Sub(&zeta, &wPowI) // ζ-wⁱ lagrange.SetOne(). - Sub(&zeta, &lagrange). // ζ-1 - Mul(&lagrange, &wPowI). // wⁱ(ζ-1) - Div(&lagrange, &den). // wⁱ(ζ-1)/(ζ-wⁱ) + Sub(&zeta, &lagrange). // ζ-1 + Mul(&lagrange, &wPowI). // wⁱ(ζ-1) + Div(&lagrange, &den). // wⁱ(ζ-1)/(ζ-wⁱ) Mul(&lagrange, &lagrangeOne) // wⁱ/n (ζⁿ-1)/(ζ-wⁱ) xiLi.Mul(&lagrange, &hashRes[0]) @@ -134,6 +135,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } } + fmt.Println("pi =", pi.Text(16)) + // linearizedpolynomial + pi(ζ) + α*(Z(μζ))*(l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*(o(ζ)+γ) - α²*L₁(ζ) var _s1, _s2, _o, alphaSquareLagrange fr.Element @@ -161,8 +164,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { Mul(&alphaSquareLagrange, &alpha) // α²*L₁(ζ) linearizedPolynomialZeta. - Add(&linearizedPolynomialZeta, &pi). // linearizedpolynomial + pi(zeta) - Add(&linearizedPolynomialZeta, &_s1). // linearizedpolynomial+pi(zeta)+α*(Z(μζ))*(l(ζ)+s1(ζ)+γ)*(r(ζ)+s2(ζ)+γ)*(o(ζ)+γ) + Add(&linearizedPolynomialZeta, &pi). // linearizedpolynomial + pi(zeta) + Add(&linearizedPolynomialZeta, &_s1). // linearizedpolynomial+pi(zeta)+α*(Z(μζ))*(l(ζ)+s1(ζ)+γ)*(r(ζ)+s2(ζ)+γ)*(o(ζ)+γ) Sub(&linearizedPolynomialZeta, &alphaSquareLagrange) // linearizedpolynomial+pi(zeta)+α*(Z(μζ))*(l(ζ)+s1(ζ)+γ)*(r(ζ)+s2(ζ)+γ)*(o(ζ)+γ)-α²*L₁(ζ) // Compute H(ζ) using the previous result: H(ζ) = prev_result/(ζⁿ-1) @@ -170,6 +173,9 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zetaPowerMMinusOne.Sub(&zetaPowerM, &one) linearizedPolynomialZeta.Div(&linearizedPolynomialZeta, &zetaPowerMMinusOne) + fmt.Println("claimed quotient =", claimedQuotient.Text(16)) + fmt.Println("computed quotient =", linearizedPolynomialZeta.Text(16)) + // check that H(ζ) is as claimed if !claimedQuotient.Equal(&linearizedPolynomialZeta) { return errWrongClaimedQuotient @@ -221,7 +227,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { ) scalars := append(qC, - l, r, rl, o, one /* TODO Perf @Tabaie Consider just adding Qk instead */, // first part + l, r, rl, o, one, /* TODO Perf @Tabaie Consider just adding Qk instead */ // first part _s1, _s2, // second & third part ) if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{}); err != nil { @@ -333,6 +339,7 @@ func deriveRandomness(fs *fiatshamir.Transcript, challenge string, points ...*cu if err != nil { return r, err } + return r, nil r.SetBytes(b) return r, nil } diff --git a/test/kzg_srs.go b/test/kzg_srs.go index c67b89be7f..f34a670d95 100644 --- a/test/kzg_srs.go +++ b/test/kzg_srs.go @@ -83,6 +83,7 @@ func newKZGSRS(curve ecc.ID, kzgSize uint64) (kzg.SRS, error) { if err != nil { return nil, err } + alpha.SetUint64(0) switch curve { case ecc.BN254: From a2dd1982eeb9e6086aab649ac865e42a18f1b553 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 5 May 2023 20:17:13 -0500 Subject: [PATCH 332/464] test: print commitment --- backend/plonk/bn254/prove.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index aacf0ddbaf..4d7fe88e3d 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -18,6 +18,7 @@ package plonk import ( "crypto/sha256" + "fmt" "math/big" "runtime" "sync" @@ -92,6 +93,9 @@ func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof } res.Set(&hashRes[0]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses res.BigInt(outs[0]) + + fmt.Println("computed commitment =", outs[0].Text(16)) + return nil } } @@ -658,9 +662,9 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, den.Sub(&zeta, &one). Inverse(&den) lagrangeZeta.Mul(&lagrangeZeta, &den). // L₁ = (ζⁿ⁻¹)/(ζ-1) - Mul(&lagrangeZeta, &alpha). - Mul(&lagrangeZeta, &alpha). - Mul(&lagrangeZeta, &pk.Domain[0].CardinalityInv) // (1/n)*α²*L₁(ζ) + Mul(&lagrangeZeta, &alpha). + Mul(&lagrangeZeta, &alpha). + Mul(&lagrangeZeta, &pk.Domain[0].CardinalityInv) // (1/n)*α²*L₁(ζ) s3canonical := pk.trace.S3.Coefficients() utils.Parallelize(len(blindedZCanonical), func(start, end int) { From 65331dd9b84cd76f79bcc632bcd484bc96670075 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 5 May 2023 20:46:30 -0500 Subject: [PATCH 333/464] test: don't parallelize --- backend/plonk/bn254/prove.go | 6 +++--- internal/utils/parallelize.go | 13 +++++++------ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index 4d7fe88e3d..ce5fb91feb 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -662,9 +662,9 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, den.Sub(&zeta, &one). Inverse(&den) lagrangeZeta.Mul(&lagrangeZeta, &den). // L₁ = (ζⁿ⁻¹)/(ζ-1) - Mul(&lagrangeZeta, &alpha). - Mul(&lagrangeZeta, &alpha). - Mul(&lagrangeZeta, &pk.Domain[0].CardinalityInv) // (1/n)*α²*L₁(ζ) + Mul(&lagrangeZeta, &alpha). + Mul(&lagrangeZeta, &alpha). + Mul(&lagrangeZeta, &pk.Domain[0].CardinalityInv) // (1/n)*α²*L₁(ζ) s3canonical := pk.trace.S3.Coefficients() utils.Parallelize(len(blindedZCanonical), func(start, end int) { diff --git a/internal/utils/parallelize.go b/internal/utils/parallelize.go index bc377cccec..8d44d909fd 100644 --- a/internal/utils/parallelize.go +++ b/internal/utils/parallelize.go @@ -1,12 +1,12 @@ package utils -import ( - "runtime" - "sync" -) - // Parallelize process in parallel the work function -func Parallelize(nbIterations int, work func(int, int), maxCpus ...int) { + +func Parallelize(nbIterations int, work func(int, int), _ ...int) { + work(0, nbIterations) +} + +/*func Parallelize(nbIterations int, work func(int, int), maxCpus ...int) { nbTasks := runtime.NumCPU() if len(maxCpus) == 1 { @@ -42,3 +42,4 @@ func Parallelize(nbIterations int, work func(int, int), maxCpus ...int) { wg.Wait() } +*/ From 968770785635a47ad7311e4311c868dd4a9bc0a2 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 5 May 2023 20:56:16 -0500 Subject: [PATCH 334/464] test: print some linpoly arguments --- backend/plonk/bn254/prove.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index ce5fb91feb..d4ef7078c4 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -621,6 +621,17 @@ func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, kzgPk kzg.ProvingKe // + l(ζ)*Ql(X) + l(ζ)r(ζ)*Qm(X) + r(ζ)*Qr(X) + o(ζ)*Qo(X) + Qk(X) func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu fr.Element, qcpZeta, blindedZCanonical []fr.Element, pi2Canonical [][]fr.Element, pk *ProvingKey) []fr.Element { + fmt.Println("lZeta =", lZeta.Text(16)) + fmt.Println("rZeta =", rZeta.Text(16)) + fmt.Println("oZeta =", oZeta.Text(16)) + fmt.Println("alpha =", alpha.Text(16)) + fmt.Println("beta =", beta.Text(16)) + fmt.Println("gamma =", gamma.Text(16)) + fmt.Println("zeta =", zeta.Text(16)) + fmt.Println("zu =", zu.Text(16)) + //fmt.Println("qcpZeta =", lZeta.Text(16)) + //fmt.Println("beta =", lZeta.Text(16)) + // first part: individual constraints var rl fr.Element rl.Mul(&rZeta, &lZeta) @@ -710,6 +721,8 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, t0.Mul(&blindedZCanonical[i], &lagrangeZeta) blindedZCanonical[i].Add(&t, &t0) // finish the computation + + fmt.Printf("linPoly[%d] = %s\n", i, blindedZCanonical[i].Text(16)) } }) return blindedZCanonical From 8ca02a0e4429f351b2e27aa9e93788e3189d9650 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Sat, 6 May 2023 17:24:05 -0500 Subject: [PATCH 335/464] test: print solution --- backend/plonk/bn254/prove.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index d4ef7078c4..07730e10f2 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -132,6 +132,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if err != nil { return nil, err } + + printSol(_solution.(*cs.SparseR1CSSolution)) + // TODO @gbotrel deal with that conversion lazily lcpi2iop := make([]*iop.Polynomial, len(wpi2iop)) for i := range wpi2iop { @@ -224,6 +227,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } var beta fr.Element beta.SetBytes(bbeta) + beta.SetZero() // l, r, o are already blinded wgLRO.Add(3) @@ -547,6 +551,12 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } +func printSol(solution *cs.SparseR1CSSolution) { + fmt.Println("Solution L:", solution.L.String()) + fmt.Println("Solution R:", solution.L.String()) + fmt.Println("Solution O:", solution.L.String()) +} + func coefficients(p []*iop.Polynomial) [][]fr.Element { res := make([][]fr.Element, len(p)) for i, pI := range p { From 41e6026ce9fb110a0e470d9c083985d773a0440c Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Sun, 7 May 2023 18:25:31 -0500 Subject: [PATCH 336/464] print lcp2iop --- backend/plonk/bn254/prove.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index 07730e10f2..4e30bb2be6 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -133,18 +133,19 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } - printSol(_solution.(*cs.SparseR1CSSolution)) - // TODO @gbotrel deal with that conversion lazily lcpi2iop := make([]*iop.Polynomial, len(wpi2iop)) for i := range wpi2iop { lcpi2iop[i] = wpi2iop[i].Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form + fmt.Println("lcp2iop =", fr.Vector(lcpi2iop[i].Coefficients()).String()) } solution := _solution.(*cs.SparseR1CSSolution) evaluationLDomainSmall := []fr.Element(solution.L) evaluationRDomainSmall := []fr.Element(solution.R) evaluationODomainSmall := []fr.Element(solution.O) + printSol(solution) + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} // l, r o and blinded versions var ( From b4fda615d7be817c76f3df6c51e54f9a0f9477cc Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Sun, 7 May 2023 18:46:14 -0500 Subject: [PATCH 337/464] remove lro blinding --- backend/plonk/bn254/prove.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index 4e30bb2be6..5635c5d35d 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -162,17 +162,17 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // we keep in lagrange regular form since iop.BuildRatioCopyConstraint prefers it in this form. wliop = iop.NewPolynomial(&evaluationLDomainSmall, lagReg) // we set the underlying slice capacity to domain[1].Cardinality to minimize mem moves. - bwliop = wliop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) + bwliop = wliop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular() //.Blind(1) wgLRO.Done() }() go func() { wriop = iop.NewPolynomial(&evaluationRDomainSmall, lagReg) - bwriop = wriop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) + bwriop = wriop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular() //.Blind(1) wgLRO.Done() }() go func() { woiop = iop.NewPolynomial(&evaluationODomainSmall, lagReg) - bwoiop = woiop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) + bwoiop = woiop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular() //.Blind(1) wgLRO.Done() }() @@ -362,6 +362,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // wait for l, r o lagrange coset conversion wgLRO.Wait() + fmt.Println("lagrange bwliop before batch eval =", fr.Vector(bwliop.Coefficients()).String()) + toEval := []*iop.Polynomial{ bwliop, bwriop, @@ -419,7 +421,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts var wgEvals sync.WaitGroup wgEvals.Add(3) evalAtZeta := func(poly *iop.Polynomial, res *fr.Element) { + if poly == bwliop { + fmt.Println("lagrange bwliop =", fr.Vector(bwliop.Coefficients()).String()) + } poly.ToCanonical(&pk.Domain[1]).ToRegular() + if poly == bwliop { + fmt.Println("canonical bwliop =", fr.Vector(bwliop.Coefficients()).String()) + } *res = poly.Evaluate(zeta) wgEvals.Done() } @@ -486,6 +494,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts errLPoly error ) + fmt.Println("blzeta =", blzeta.Text(16)) + // blinded z evaluated at u*zeta bzuzeta := proof.ZShiftedOpening.ClaimedValue From 0ec41b4867b235fd1e2c1536c58cb4bd6882227e Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Sun, 7 May 2023 18:57:49 -0500 Subject: [PATCH 338/464] don't blind bwziop --- backend/plonk/bn254/prove.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index 5635c5d35d..f2a930c17d 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -269,7 +269,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts var alpha fr.Element go func() { bwziop = ziop // iop.NewWrappedPolynomial(&ziop) - bwziop.Blind(2) + //bwziop.Blind(2) proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Kzg, runtime.NumCPU()*2) if err != nil { chZ <- err @@ -498,7 +498,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // blinded z evaluated at u*zeta bzuzeta := proof.ZShiftedOpening.ClaimedValue - + fmt.Println("bzuzeta =", bzuzeta.Text(16)) // compute the linearization polynomial r at zeta // (goal: save committing separately to z, ql, qr, qm, qo, k // note: we linearizedPolynomialCanonical reuses bwziop memory From 0d7ffac7a71012c502cda1f7e70904ddcf22232e Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Mon, 8 May 2023 11:50:23 -0500 Subject: [PATCH 339/464] fix: claimed quotient --- backend/plonk/bn254/verify.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/backend/plonk/bn254/verify.go b/backend/plonk/bn254/verify.go index e27eb19104..c5b54ce4d8 100644 --- a/backend/plonk/bn254/verify.go +++ b/backend/plonk/bn254/verify.go @@ -142,14 +142,15 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - claimedQuotient := proof.BatchedProof.ClaimedValues[0] - linearizedPolynomialZeta := proof.BatchedProof.ClaimedValues[1] - l := proof.BatchedProof.ClaimedValues[2] - r := proof.BatchedProof.ClaimedValues[3] - o := proof.BatchedProof.ClaimedValues[4] - s1 := proof.BatchedProof.ClaimedValues[5] - s2 := proof.BatchedProof.ClaimedValues[6] - qC := proof.BatchedProof.ClaimedValues[7:] + qC := proof.BatchedProof.ClaimedValues[:len(proof.PI2)] + claimedValues := proof.BatchedProof.ClaimedValues[len(proof.PI2):] + claimedQuotient := claimedValues[0] + linearizedPolynomialZeta := claimedValues[1] + l := claimedValues[2] + r := claimedValues[3] + o := claimedValues[4] + s1 := claimedValues[5] + s2 := claimedValues[6] _s1.Mul(&s1, &beta).Add(&_s1, &l).Add(&_s1, &gamma) // (l(ζ)+β*s1(ζ)+γ) _s2.Mul(&s2, &beta).Add(&_s2, &r).Add(&_s2, &gamma) // (r(ζ)+β*s2(ζ)+γ) From a677b59c94b76ba074171b804dfe11acc3a30b36 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Mon, 8 May 2023 12:05:11 -0500 Subject: [PATCH 340/464] test: proof is correct. verification failing --- backend/plonk/bn254/marshal.go | 4 +++- backend/plonk/bn254/prove.go | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/backend/plonk/bn254/marshal.go b/backend/plonk/bn254/marshal.go index 76e9cdb90c..38dceb2844 100644 --- a/backend/plonk/bn254/marshal.go +++ b/backend/plonk/bn254/marshal.go @@ -74,6 +74,8 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { var pi2 []curve.G1Affine + pi2 = make([]curve.G1Affine, 1) // TODO Remove + dec := curve.NewDecoder(r) toDecode := []interface{}{ &proof.LRO[0], @@ -87,7 +89,7 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { &proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - &pi2, + &pi2[0], // TODO Remove index } for i, v := range toDecode { diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index f2a930c17d..d92dbcf143 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -17,8 +17,11 @@ package plonk import ( + "bytes" "crypto/sha256" + "encoding/base64" "fmt" + "github.com/google/go-cmp/cmp" "math/big" "runtime" "sync" @@ -381,7 +384,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts lcqk, pk.lLoneIOP, } - toEval = append(toEval, lcpi2iop...) + toEval = append(toEval, lcpi2iop...) // TODO: Add this at beginning toEval = append(toEval, pk.lcQcp...) systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, toEval...) if err != nil { @@ -558,6 +561,16 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } + var goodB []byte + if goodB, err = base64.StdEncoding.DecodeString("hJl1Q3FUFttoNHBC1k42rGbUucAJ7eYJr3KDacCqby7H7J7uMGsM3GGuijBTNS7MP5LSoIarvlcuiox2QHoIVJwk464j2CsfiL3IYn3uooZ8yLWOhq6EdfRLoq3WynmOgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHmf0pEcTp/MMXyWlSfiLUi5DpFdl0JQs0b1apQb35IwUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADBCZLn7wU6waYNfji19EaLiHcUED4EXq5AzE1SvSZpXgAAAAgkSzrWKOU4H0o8NEjhIQJF3ibuNltLFGzy6Xgu9AAAAQdW1JVBMTyCInUD2DaU/wthD0kWpBC0dxVCXds7pMM0LYhjh7N9T4U4TaPwirHhwb0uLXEEE5ydUOsoypaE5JADS7B3MMzQLTmhFzN7D+JEKNa+B2gJYrkoeDm85b9eGxtVZ4IB62BkBVdwJGGV8WXyE9G3/nVTZq5SVgsvrLB7E7c9j10b5Dc5tcDJAPsjvp4QZeUOcdfFf6VpuBXWWD4YMic5cJjQGWynnFlri8PvvXlpteSj1nn3OJov66afpzBkTnLhMaApi18PzzEXEob1YXd0GqfvZ/ut+UsX3A2JQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcFEUCi4DHArBKbdB3F8kbGpWFSfTyGDMApxQh+FOhSs"); err != nil { + panic(err) + } + var goodProof Proof + if _, err = goodProof.ReadFrom(bytes.NewReader(goodB)); err != nil { + panic(err) + } + fmt.Println("diff =", cmp.Diff(*proof, goodProof)) + return proof, nil } From ff0720003c252e0967332ff3749832e67b2d24bb Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Mon, 8 May 2023 12:10:10 -0500 Subject: [PATCH 341/464] print foldedDigest --- backend/plonk/bn254/verify.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/backend/plonk/bn254/verify.go b/backend/plonk/bn254/verify.go index c5b54ce4d8..9d53e1aea4 100644 --- a/backend/plonk/bn254/verify.go +++ b/backend/plonk/bn254/verify.go @@ -125,9 +125,9 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { den.Sub(&zeta, &wPowI) // ζ-wⁱ lagrange.SetOne(). - Sub(&zeta, &lagrange). // ζ-1 - Mul(&lagrange, &wPowI). // wⁱ(ζ-1) - Div(&lagrange, &den). // wⁱ(ζ-1)/(ζ-wⁱ) + Sub(&zeta, &lagrange). // ζ-1 + Mul(&lagrange, &wPowI). // wⁱ(ζ-1) + Div(&lagrange, &den). // wⁱ(ζ-1)/(ζ-wⁱ) Mul(&lagrange, &lagrangeOne) // wⁱ/n (ζⁿ-1)/(ζ-wⁱ) xiLi.Mul(&lagrange, &hashRes[0]) @@ -165,8 +165,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { Mul(&alphaSquareLagrange, &alpha) // α²*L₁(ζ) linearizedPolynomialZeta. - Add(&linearizedPolynomialZeta, &pi). // linearizedpolynomial + pi(zeta) - Add(&linearizedPolynomialZeta, &_s1). // linearizedpolynomial+pi(zeta)+α*(Z(μζ))*(l(ζ)+s1(ζ)+γ)*(r(ζ)+s2(ζ)+γ)*(o(ζ)+γ) + Add(&linearizedPolynomialZeta, &pi). // linearizedpolynomial + pi(zeta) + Add(&linearizedPolynomialZeta, &_s1). // linearizedpolynomial+pi(zeta)+α*(Z(μζ))*(l(ζ)+s1(ζ)+γ)*(r(ζ)+s2(ζ)+γ)*(o(ζ)+γ) Sub(&linearizedPolynomialZeta, &alphaSquareLagrange) // linearizedpolynomial+pi(zeta)+α*(Z(μζ))*(l(ζ)+s1(ζ)+γ)*(r(ζ)+s2(ζ)+γ)*(o(ζ)+γ)-α²*L₁(ζ) // Compute H(ζ) using the previous result: H(ζ) = prev_result/(ζⁿ-1) @@ -256,6 +256,9 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // Batch verify var shiftedZeta fr.Element shiftedZeta.Mul(&zeta, &vk.Generator) + + fmt.Println("foldedDigest =", foldedDigest.String()) + err = kzg.BatchVerifyMultiPoints([]kzg.Digest{ foldedDigest, proof.Z, From c7dd394955e26cd08eb588872a677de9c1549cd9 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Mon, 8 May 2023 12:17:09 -0500 Subject: [PATCH 342/464] linPolyDigest is correct --- backend/plonk/bn254/verify.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/plonk/bn254/verify.go b/backend/plonk/bn254/verify.go index 9d53e1aea4..894594c69e 100644 --- a/backend/plonk/bn254/verify.go +++ b/backend/plonk/bn254/verify.go @@ -235,6 +235,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } + fmt.Println("linearizedPolynomialDigest =", linearizedPolynomialDigest.String()) + // Fold the first proof foldedProof, foldedDigest, err := kzg.FoldProof(append(vk.Qcp, foldedH, From d0b7998c6bcf638f01b23f26171e98fee00aa5cd Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Mon, 8 May 2023 12:27:14 -0500 Subject: [PATCH 343/464] print foldedH --- backend/plonk/bn254/verify.go | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/plonk/bn254/verify.go b/backend/plonk/bn254/verify.go index 894594c69e..6dac656d89 100644 --- a/backend/plonk/bn254/verify.go +++ b/backend/plonk/bn254/verify.go @@ -236,6 +236,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } fmt.Println("linearizedPolynomialDigest =", linearizedPolynomialDigest.String()) + fmt.Println("foldedH =", foldedH.String()) // Fold the first proof foldedProof, foldedDigest, err := kzg.FoldProof(append(vk.Qcp, From 5d298fe98142d24b945303f9b8c2300b5ffa292b Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Mon, 8 May 2023 12:34:28 -0500 Subject: [PATCH 344/464] use local gc --- go.mod | 2 ++ 1 file changed, 2 insertions(+) diff --git a/go.mod b/go.mod index a5f011f377..dc301ad036 100644 --- a/go.mod +++ b/go.mod @@ -30,3 +30,5 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect rsc.io/tmplfunc v0.0.3 // indirect ) + +replace "github.com/consensys/gnark-crypto" => "/Users/arya/gnark-crypto" \ No newline at end of file From df07749443ac04e58dea68844012c7ea3f8287e0 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Mon, 8 May 2023 15:03:38 -0500 Subject: [PATCH 345/464] diff with the working impl --- backend/plonk/good.go | 376 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 376 insertions(+) create mode 100644 backend/plonk/good.go diff --git a/backend/plonk/good.go b/backend/plonk/good.go new file mode 100644 index 0000000000..586ce4f5bf --- /dev/null +++ b/backend/plonk/good.go @@ -0,0 +1,376 @@ +package plonk + +import ( + "crypto/sha256" + "fmt" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/logger" + "io" + "math/big" + "time" +) + +// Copyright 2020 ConsenSys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT + +package plonk + +import ( +"crypto/sha256" +"errors" +"fmt" +"io" +"math/big" +"time" + +"github.com/consensys/gnark-crypto/ecc/bn254/fr" + +"github.com/consensys/gnark-crypto/ecc/bn254/fr/kzg" + +curve "github.com/consensys/gnark-crypto/ecc/bn254" + +"text/template" + +"github.com/consensys/gnark-crypto/ecc" +"github.com/consensys/gnark-crypto/fiat-shamir" +"github.com/consensys/gnark/logger" +) + +var ( + errWrongClaimedQuotient = errors.New("claimed quotient is not as expected") +) + +func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { + log := logger.Logger().With().Str("curve", "bn254").Str("backend", "plonk").Logger() + start := time.Now() + + // pick a hash function to derive the challenge (the same as in the prover) + hFunc := sha256.New() + + // transcript to derive the challenge + fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") + + // The first challenge is derived using the public data: the commitments to the permutation, + // the coefficients of the circuit, and the public inputs. + // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) + if err := bindPublicData(&fs, "gamma", *vk, publicWitness, proof.PI2); err != nil { + return err + } + gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) + if err != nil { + return err + } + + // derive beta from Comm(l), Comm(r), Comm(o) + beta, err := deriveRandomness(&fs, "beta") + if err != nil { + return err + } + + // derive alpha from Comm(l), Comm(r), Comm(o), Com(Z) + alpha, err := deriveRandomness(&fs, "alpha", &proof.Z) + if err != nil { + return err + } + + // derive zeta, the point of evaluation + zeta, err := deriveRandomness(&fs, "zeta", &proof.H[0], &proof.H[1], &proof.H[2]) + if err != nil { + return err + } + + // evaluation of Z=Xⁿ⁻¹ at ζ + var zetaPowerM, zzeta fr.Element + var bExpo big.Int + one := fr.One() + bExpo.SetUint64(vk.Size) + zetaPowerM.Exp(zeta, &bExpo) + zzeta.Sub(&zetaPowerM, &one) + + // compute PI = ∑_{i PI2[i] + if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + return err + } + + // Computing L_{CommitmentIndex} + + wPowI.Exp(vk.Generator, big.NewInt(int64(vk.NbPublicVariables)+int64(vk.CommitmentConstraintIndexes[i]))) + den.Sub(&zeta, &wPowI) // ζ-wⁱ + + lagrange.SetOne(). + Sub(&zeta, &lagrange). // ζ-1 + Mul(&lagrange, &wPowI). // wⁱ(ζ-1) + Div(&lagrange, &den). // wⁱ(ζ-1)/(ζ-wⁱ) + Mul(&lagrange, &lagrangeOne) // wⁱ/n (ζⁿ-1)/(ζ-wⁱ) + + xiLi.Mul(&lagrange, &hashRes[0]) + pi.Add(&pi, &xiLi) + } + } + + fmt.Println("pi =", pi.Text(16)) + + // linearizedpolynomial + pi(ζ) + α*(Z(μζ))*(l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*(o(ζ)+γ) - α²*L₁(ζ) + var _s1, _s2, _o, alphaSquareLagrange fr.Element + + zu := proof.ZShiftedOpening.ClaimedValue + + claimedQuotient := proof.BatchedProof.ClaimedValues[1] + linearizedPolynomialZeta := proof.BatchedProof.ClaimedValues[2] + l := proof.BatchedProof.ClaimedValues[3] + r := proof.BatchedProof.ClaimedValues[4] + o := proof.BatchedProof.ClaimedValues[5] + s1 := proof.BatchedProof.ClaimedValues[6] + s2 := proof.BatchedProof.ClaimedValues[7] + qC := proof.BatchedProof.ClaimedValues[0] + + _s1.Mul(&s1, &beta).Add(&_s1, &l).Add(&_s1, &gamma) // (l(ζ)+β*s1(ζ)+γ) + _s2.Mul(&s2, &beta).Add(&_s2, &r).Add(&_s2, &gamma) // (r(ζ)+β*s2(ζ)+γ) + _o.Add(&o, &gamma) // (o(ζ)+γ) + + _s1.Mul(&_s1, &_s2). + Mul(&_s1, &_o). + Mul(&_s1, &alpha). + Mul(&_s1, &zu) // α*(Z(μζ))*(l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*(o(ζ)+γ) + + alphaSquareLagrange.Mul(&lagrangeOne, &alpha). + Mul(&alphaSquareLagrange, &alpha) // α²*L₁(ζ) + + linearizedPolynomialZeta. + Add(&linearizedPolynomialZeta, &pi). // linearizedpolynomial + pi(zeta) + Add(&linearizedPolynomialZeta, &_s1). // linearizedpolynomial+pi(zeta)+α*(Z(μζ))*(l(ζ)+s1(ζ)+γ)*(r(ζ)+s2(ζ)+γ)*(o(ζ)+γ) + Sub(&linearizedPolynomialZeta, &alphaSquareLagrange) // linearizedpolynomial+pi(zeta)+α*(Z(μζ))*(l(ζ)+s1(ζ)+γ)*(r(ζ)+s2(ζ)+γ)*(o(ζ)+γ)-α²*L₁(ζ) + + // Compute H(ζ) using the previous result: H(ζ) = prev_result/(ζⁿ-1) + var zetaPowerMMinusOne fr.Element + zetaPowerMMinusOne.Sub(&zetaPowerM, &one) + linearizedPolynomialZeta.Div(&linearizedPolynomialZeta, &zetaPowerMMinusOne) + + // check that H(ζ) is as claimed + if !claimedQuotient.Equal(&linearizedPolynomialZeta) { + return errWrongClaimedQuotient + } + + fmt.Println("quotient =", claimedQuotient.Text(16)) + + // compute the folded commitment to H: Comm(h₁) + ζᵐ⁺²*Comm(h₂) + ζ²⁽ᵐ⁺²⁾*Comm(h₃) + mPlusTwo := big.NewInt(int64(vk.Size) + 2) + var zetaMPlusTwo fr.Element + zetaMPlusTwo.Exp(zeta, mPlusTwo) + var zetaMPlusTwoBigInt big.Int + zetaMPlusTwo.BigInt(&zetaMPlusTwoBigInt) + foldedH := proof.H[2] + foldedH.ScalarMultiplication(&foldedH, &zetaMPlusTwoBigInt) + foldedH.Add(&foldedH, &proof.H[1]) + foldedH.ScalarMultiplication(&foldedH, &zetaMPlusTwoBigInt) + foldedH.Add(&foldedH, &proof.H[0]) + + // Compute the commitment to the linearized polynomial + // linearizedPolynomialDigest = + // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+qc*PI2 + + // α*( Z(μζ)(l(ζ)+β*s₁(ζ)+γ)*(r(ζ)+β*s₂(ζ)+γ)*s₃(X)-Z(X)(l(ζ)+β*id_1(ζ)+γ)*(r(ζ)+β*id_2(ζ)+γ)*(o(ζ)+β*id_3(ζ)+γ) ) + + // α²*L₁(ζ)*Z + // first part: individual constraints + var rl fr.Element + rl.Mul(&l, &r) + + var linearizedPolynomialDigest curve.G1Affine + + // second part: α*( Z(μζ)(l(ζ)+β*s₁(ζ)+γ)*(r(ζ)+β*s₂(ζ)+γ)*β*s₃(X)-Z(X)(l(ζ)+β*id_1(ζ)+γ)*(r(ζ)+β*id_2(ζ)+γ)*(o(ζ)+β*id_3(ζ)+γ) ) ) + + var u, v, w, cosetsquare fr.Element + u.Mul(&zu, &beta) + v.Mul(&beta, &s1).Add(&v, &l).Add(&v, &gamma) + w.Mul(&beta, &s2).Add(&w, &r).Add(&w, &gamma) + _s1.Mul(&u, &v).Mul(&_s1, &w).Mul(&_s1, &alpha) // α*Z(μζ)(l(ζ)+β*s₁(ζ)+γ)*(r(ζ)+β*s₂(ζ)+γ)*β + + cosetsquare.Square(&vk.CosetShift) + u.Mul(&beta, &zeta).Add(&u, &l).Add(&u, &gamma) // (l(ζ)+β*ζ+γ) + v.Mul(&beta, &zeta).Mul(&v, &vk.CosetShift).Add(&v, &r).Add(&v, &gamma) // (r(ζ)+β*μ*ζ+γ) + w.Mul(&beta, &zeta).Mul(&w, &cosetsquare).Add(&w, &o).Add(&w, &gamma) // (o(ζ)+β*μ²*ζ+γ) + _s2.Mul(&u, &v).Mul(&_s2, &w).Neg(&_s2) // -(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + + // note since third part = α²*L₁(ζ)*Z + _s2.Mul(&_s2, &alpha).Add(&_s2, &alphaSquareLagrange) // -α*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + α²*L₁(ζ) + + points := []curve.G1Affine{ + vk.Ql, vk.Qr, vk.Qm, vk.Qo, vk.Qk, proof.PI2, // first part + vk.S[2], proof.Z, // second & third part + } + + scalars := []fr.Element{ + l, r, rl, o, one /* TODO Perf @Tabaie Consider just adding Qk instead */, qC, // first part + _s1, _s2, // second & third part + } + if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{}); err != nil { + return err + } + + fmt.Println("linearizedPolynomialDigest =", linearizedPolynomialDigest.String()) + fmt.Println("foldedH =", foldedH.String()) + + // Fold the first proof + foldedProof, foldedDigest, err := kzg.FoldProof([]kzg.Digest{ + vk.Qcp, + foldedH, + linearizedPolynomialDigest, + proof.LRO[0], + proof.LRO[1], + proof.LRO[2], + vk.S[0], + vk.S[1], + }, + &proof.BatchedProof, + zeta, + hFunc, + ) + if err != nil { + return err + } + + // Batch verify + var shiftedZeta fr.Element + shiftedZeta.Mul(&zeta, &vk.Generator) + + fmt.Println("foldedDigest =", foldedDigest.String()) + + err = kzg.BatchVerifyMultiPoints([]kzg.Digest{ + foldedDigest, + proof.Z, + }, + []kzg.OpeningProof{ + foldedProof, + proof.ZShiftedOpening, + }, + []fr.Element{ + zeta, + shiftedZeta, + }, + vk.Kzg, + ) + + log.Debug().Dur("took", time.Since(start)).Msg("verifier done") + + return err +} + +func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element, pi2 kzg.Digest) error { + + // permutation + if err := fs.Bind(challenge, vk.S[0].Marshal()); err != nil { + return err + } + if err := fs.Bind(challenge, vk.S[1].Marshal()); err != nil { + return err + } + if err := fs.Bind(challenge, vk.S[2].Marshal()); err != nil { + return err + } + + // coefficients + if err := fs.Bind(challenge, vk.Ql.Marshal()); err != nil { + return err + } + if err := fs.Bind(challenge, vk.Qr.Marshal()); err != nil { + return err + } + if err := fs.Bind(challenge, vk.Qm.Marshal()); err != nil { + return err + } + if err := fs.Bind(challenge, vk.Qo.Marshal()); err != nil { + return err + } + if err := fs.Bind(challenge, vk.Qk.Marshal()); err != nil { + return err + } + + // public inputs + for i := 0; i < len(publicInputs); i++ { + if err := fs.Bind(challenge, publicInputs[i].Marshal()); err != nil { + return err + } + } + + // bsb22 commitment + if err := fs.Bind(challenge, pi2.Marshal()); err != nil { + return err + } + + return nil + +} + +func deriveRandomness(fs *fiatshamir.Transcript, challenge string, points ...*curve.G1Affine) (fr.Element, error) { + + var buf [curve.SizeOfG1AffineUncompressed]byte + var r fr.Element + + for _, p := range points { + buf = p.RawBytes() + if err := fs.Bind(challenge, buf[:]); err != nil { + return r, err + } + } + + b, err := fs.ComputeChallenge(challenge) + if err != nil { + return r, err + } + + return r, nil + + r.SetBytes(b) + return r, nil +} + +// ExportSolidity exports the verifying key to a solidity smart contract. +// +// See https://github.com/ConsenSys/gnark-tests for example usage. +// +// Code has not been audited and is provided as-is, we make no guarantees or warranties to its safety and reliability. +func (vk *VerifyingKey) ExportSolidity(w io.Writer) error { + tmpl, err := template.New("").Parse(solidityTemplate) + if err != nil { + return err + } + return tmpl.Execute(w, vk) +} From e33668042511622e779ac4f405c82036ba04838d Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Mon, 8 May 2023 15:22:35 -0500 Subject: [PATCH 346/464] fix: one commit works --- backend/plonk/{good.go => bn254/good.txt} | 26 +++++++++++------------ backend/plonk/bn254/prove.go | 2 +- backend/plonk/bn254/verify.go | 23 ++++++++++++++------ 3 files changed, 30 insertions(+), 21 deletions(-) rename backend/plonk/{good.go => bn254/good.txt} (96%) diff --git a/backend/plonk/good.go b/backend/plonk/bn254/good.txt similarity index 96% rename from backend/plonk/good.go rename to backend/plonk/bn254/good.txt index 586ce4f5bf..7684d85212 100644 --- a/backend/plonk/good.go +++ b/backend/plonk/bn254/good.txt @@ -29,24 +29,24 @@ import ( package plonk import ( -"crypto/sha256" -"errors" -"fmt" -"io" -"math/big" -"time" + "crypto/sha256" + "errors" + "fmt" + "io" + "math/big" + "time" -"github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" -"github.com/consensys/gnark-crypto/ecc/bn254/fr/kzg" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/kzg" -curve "github.com/consensys/gnark-crypto/ecc/bn254" + curve "github.com/consensys/gnark-crypto/ecc/bn254" -"text/template" + "text/template" -"github.com/consensys/gnark-crypto/ecc" -"github.com/consensys/gnark-crypto/fiat-shamir" -"github.com/consensys/gnark/logger" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark/logger" ) var ( diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index d92dbcf143..b40013ed2e 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -569,7 +569,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if _, err = goodProof.ReadFrom(bytes.NewReader(goodB)); err != nil { panic(err) } - fmt.Println("diff =", cmp.Diff(*proof, goodProof)) + fmt.Println("proof diff =", cmp.Diff(*proof, goodProof)) return proof, nil diff --git a/backend/plonk/bn254/verify.go b/backend/plonk/bn254/verify.go index 6dac656d89..351f6b9d7e 100644 --- a/backend/plonk/bn254/verify.go +++ b/backend/plonk/bn254/verify.go @@ -42,6 +42,9 @@ var ( ) func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { + + kzg.DiffWithGoodClaimed(proof.BatchedProof.ClaimedValues) + log := logger.Logger().With().Str("curve", "bn254").Str("backend", "plonk").Logger() start := time.Now() @@ -125,9 +128,9 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { den.Sub(&zeta, &wPowI) // ζ-wⁱ lagrange.SetOne(). - Sub(&zeta, &lagrange). // ζ-1 - Mul(&lagrange, &wPowI). // wⁱ(ζ-1) - Div(&lagrange, &den). // wⁱ(ζ-1)/(ζ-wⁱ) + Sub(&zeta, &lagrange). // ζ-1 + Mul(&lagrange, &wPowI). // wⁱ(ζ-1) + Div(&lagrange, &den). // wⁱ(ζ-1)/(ζ-wⁱ) Mul(&lagrange, &lagrangeOne) // wⁱ/n (ζⁿ-1)/(ζ-wⁱ) xiLi.Mul(&lagrange, &hashRes[0]) @@ -142,7 +145,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - qC := proof.BatchedProof.ClaimedValues[:len(proof.PI2)] + qC := make([]fr.Element, len(proof.PI2)) + copy(qC, proof.BatchedProof.ClaimedValues) claimedValues := proof.BatchedProof.ClaimedValues[len(proof.PI2):] claimedQuotient := claimedValues[0] linearizedPolynomialZeta := claimedValues[1] @@ -152,6 +156,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { s1 := claimedValues[5] s2 := claimedValues[6] + kzg.DiffWithGoodClaimed(proof.BatchedProof.ClaimedValues) + _s1.Mul(&s1, &beta).Add(&_s1, &l).Add(&_s1, &gamma) // (l(ζ)+β*s1(ζ)+γ) _s2.Mul(&s2, &beta).Add(&_s2, &r).Add(&_s2, &gamma) // (r(ζ)+β*s2(ζ)+γ) _o.Add(&o, &gamma) // (o(ζ)+γ) @@ -165,8 +171,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { Mul(&alphaSquareLagrange, &alpha) // α²*L₁(ζ) linearizedPolynomialZeta. - Add(&linearizedPolynomialZeta, &pi). // linearizedpolynomial + pi(zeta) - Add(&linearizedPolynomialZeta, &_s1). // linearizedpolynomial+pi(zeta)+α*(Z(μζ))*(l(ζ)+s1(ζ)+γ)*(r(ζ)+s2(ζ)+γ)*(o(ζ)+γ) + Add(&linearizedPolynomialZeta, &pi). // linearizedpolynomial + pi(zeta) + Add(&linearizedPolynomialZeta, &_s1). // linearizedpolynomial+pi(zeta)+α*(Z(μζ))*(l(ζ)+s1(ζ)+γ)*(r(ζ)+s2(ζ)+γ)*(o(ζ)+γ) Sub(&linearizedPolynomialZeta, &alphaSquareLagrange) // linearizedpolynomial+pi(zeta)+α*(Z(μζ))*(l(ζ)+s1(ζ)+γ)*(r(ζ)+s2(ζ)+γ)*(o(ζ)+γ)-α²*L₁(ζ) // Compute H(ζ) using the previous result: H(ζ) = prev_result/(ζⁿ-1) @@ -176,6 +182,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { fmt.Println("claimed quotient =", claimedQuotient.Text(16)) fmt.Println("computed quotient =", linearizedPolynomialZeta.Text(16)) + kzg.DiffWithGoodClaimed(proof.BatchedProof.ClaimedValues) // check that H(ζ) is as claimed if !claimedQuotient.Equal(&linearizedPolynomialZeta) { @@ -227,6 +234,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { vk.S[2], proof.Z, // second & third part ) + kzg.DiffWithGoodClaimed(proof.BatchedProof.ClaimedValues) scalars := append(qC, l, r, rl, o, one, /* TODO Perf @Tabaie Consider just adding Qk instead */ // first part _s1, _s2, // second & third part @@ -234,7 +242,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{}); err != nil { return err } - + fmt.Println("multiexp") + kzg.DiffWithGoodClaimed(proof.BatchedProof.ClaimedValues) fmt.Println("linearizedPolynomialDigest =", linearizedPolynomialDigest.String()) fmt.Println("foldedH =", foldedH.String()) From fb7b86cb55b59aee18b21e67093014648b8fd31c Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Mon, 8 May 2023 16:51:31 -0500 Subject: [PATCH 347/464] build: generify some --- backend/plonk/bls12-377/marshal.go | 22 ++- backend/plonk/bls12-377/marshal_test.go | 20 ++- backend/plonk/bls12-377/prove.go | 167 +++++++++-------- backend/plonk/bls12-377/setup.go | 44 +++-- backend/plonk/bls12-377/verify.go | 45 ++--- backend/plonk/bls12-381/marshal.go | 22 ++- backend/plonk/bls12-381/marshal_test.go | 20 ++- backend/plonk/bls12-381/prove.go | 167 +++++++++-------- backend/plonk/bls12-381/setup.go | 44 +++-- backend/plonk/bls12-381/verify.go | 45 ++--- backend/plonk/bls24-315/marshal.go | 22 ++- backend/plonk/bls24-315/marshal_test.go | 20 ++- backend/plonk/bls24-315/prove.go | 167 +++++++++-------- backend/plonk/bls24-315/setup.go | 44 +++-- backend/plonk/bls24-315/verify.go | 45 ++--- backend/plonk/bls24-317/marshal.go | 22 ++- backend/plonk/bls24-317/marshal_test.go | 20 ++- backend/plonk/bls24-317/prove.go | 167 +++++++++-------- backend/plonk/bls24-317/setup.go | 44 +++-- backend/plonk/bls24-317/verify.go | 45 ++--- backend/plonk/bn254/marshal.go | 32 +--- backend/plonk/bn254/marshal_test.go | 1 - backend/plonk/bn254/prove.go | 64 +------ backend/plonk/bn254/setup.go | 1 - backend/plonk/bn254/verify.go | 21 --- backend/plonk/bw6-633/marshal.go | 22 ++- backend/plonk/bw6-633/marshal_test.go | 20 ++- backend/plonk/bw6-633/prove.go | 167 +++++++++-------- backend/plonk/bw6-633/setup.go | 44 +++-- backend/plonk/bw6-633/verify.go | 45 ++--- backend/plonk/bw6-761/marshal.go | 22 ++- backend/plonk/bw6-761/marshal_test.go | 20 ++- backend/plonk/bw6-761/prove.go | 167 +++++++++-------- backend/plonk/bw6-761/setup.go | 44 +++-- backend/plonk/bw6-761/verify.go | 45 ++--- go.mod | 4 +- go.sum | 9 +- .../zkpschemes/plonk/plonk.marshal.go.tmpl | 19 +- .../zkpschemes/plonk/plonk.prove.go.tmpl | 168 ++++++++++-------- .../zkpschemes/plonk/plonk.setup.go.tmpl | 44 +++-- .../zkpschemes/plonk/plonk.verify.go.tmpl | 45 ++--- .../zkpschemes/plonk/tests/marshal.go.tmpl | 20 ++- internal/stats/latest.stats | Bin 2803 -> 2803 bytes internal/tinyfield/element.go | 2 +- internal/tinyfield/element_test.go | 68 ++++--- 45 files changed, 1264 insertions(+), 1022 deletions(-) diff --git a/backend/plonk/bls12-377/marshal.go b/backend/plonk/bls12-377/marshal.go index 00119d94ad..b7a0e2b28b 100644 --- a/backend/plonk/bls12-377/marshal.go +++ b/backend/plonk/bls12-377/marshal.go @@ -19,9 +19,11 @@ package plonk import ( curve "github.com/consensys/gnark-crypto/ecc/bls12-377" - "errors" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + + "errors" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/iop" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/kzg" "io" ) @@ -50,7 +52,7 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - &proof.PI2, + proof.PI2, } for _, v := range toEncode { @@ -86,6 +88,10 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { } } + if proof.PI2 == nil { + proof.PI2 = []kzg.Digest{} + } + return dec.BytesRead(), nil } @@ -125,7 +131,7 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { pk.trace.Qm.Coefficients(), pk.trace.Qo.Coefficients(), pk.trace.Qk.Coefficients(), - pk.trace.Qcp.Coefficients(), + coefficients(pk.trace.Qcp), pk.lQk.Coefficients(), pk.trace.S1.Coefficients(), pk.trace.S2.Coefficients(), @@ -166,7 +172,8 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { dec := curve.NewDecoder(r) - var ql, qr, qm, qo, qk, qcp, lqk, s1, s2, s3 []fr.Element + var ql, qr, qm, qo, qk, lqk, s1, s2, s3 []fr.Element + var qcp [][]fr.Element toDecode := []interface{}{ &ql, &qr, @@ -193,11 +200,14 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) - pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + pk.trace.Qcp = make([]*iop.Polynomial, len(qcp)) + for i := range qcp { + pk.trace.Qcp[i] = iop.NewPolynomial(&qcp[i], canReg) + } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} pk.lQk = iop.NewPolynomial(&lqk, lagReg) @@ -234,7 +244,7 @@ func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*curve.Encoder)) (n &vk.Qm, &vk.Qo, &vk.Qk, - &vk.Qcp, + vk.Qcp, vk.CommitmentConstraintIndexes, } diff --git a/backend/plonk/bls12-377/marshal_test.go b/backend/plonk/bls12-377/marshal_test.go index bc928b6749..2dabbd5e27 100644 --- a/backend/plonk/bls12-377/marshal_test.go +++ b/backend/plonk/bls12-377/marshal_test.go @@ -121,7 +121,6 @@ func (pk *ProvingKey) randomize() { qo := randomScalars(n) qk := randomScalars(n) lqk := randomScalars(n) - qcp := randomScalars(n) s1 := randomScalars(n) s2 := randomScalars(n) s3 := randomScalars(n) @@ -132,11 +131,16 @@ func (pk *ProvingKey) randomize() { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) - pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + pk.trace.Qcp = make([]*iop.Polynomial, rand.Intn(4)) + for i := range pk.trace.Qcp { + qcp := randomScalars(rand.Intn(n / 4)) + pk.trace.Qcp[i] = iop.NewPolynomial(&qcp, canReg) + } + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) pk.trace.S[0] = -12 pk.trace.S[len(pk.trace.S)-1] = 8888 @@ -163,7 +167,7 @@ func (vk *VerifyingKey) randomize() { vk.Qm = randomPoint() vk.Qo = randomPoint() vk.Qk = randomPoint() - vk.Qcp = randomPoint() + vk.Qcp = randomPoints(rand.Intn(4)) } func (proof *Proof) randomize() { @@ -178,7 +182,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.PI2 = randomPoint() + proof.PI2 = randomPoints(rand.Intn(4)) } func randomPoint() curve.G1Affine { @@ -187,6 +191,14 @@ func randomPoint() curve.G1Affine { return r } +func randomPoints(n int) []curve.G1Affine { + res := make([]curve.G1Affine, n) + for i := range res { + res[i] = randomPoint() + } + return res +} + func randomScalars(n int) []fr.Element { v := make([]fr.Element, n) one := fr.One() diff --git a/backend/plonk/bls12-377/prove.go b/backend/plonk/bls12-377/prove.go index 14711003cf..e534ad200d 100644 --- a/backend/plonk/bls12-377/prove.go +++ b/backend/plonk/bls12-377/prove.go @@ -55,7 +55,7 @@ type Proof struct { H [3]kzg.Digest // PI2, the BSB22 commitment - PI2 kzg.Digest + PI2 []kzg.Digest // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2, qCPrime BatchedProof kzg.BatchOpeningProof @@ -64,6 +64,39 @@ type Proof struct { ZShiftedOpening kzg.OpeningProof } +func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, wpi2iop []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { + return func(_ *big.Int, ins, outs []*big.Int) error { + pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + offset := spr.GetNbPublicVariables() + for i := range ins { + pi2[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) + } + var ( + err error + hashRes []fr.Element + ) + /*if _, err = pi2[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + return err + } + if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding + return err + }*/ + pi2iop := iop.NewPolynomial(&pi2, iop.Form{Basis: iop.Lagrange, Layout: iop.Regular}) + wpi2iop[commDepth] = pi2iop.ShallowClone() + wpi2iop[commDepth].ToCanonical(&pk.Domain[0]).ToRegular() + if proof.PI2[commDepth], err = kzg.Commit(wpi2iop[commDepth].Coefficients(), pk.Kzg); err != nil { + return err + } + if hashRes, err = fr.Hash(proof.PI2[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + return err + } + res.Set(&hashRes[0]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses + res.BigInt(outs[0]) + + return nil + } +} + func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", spr.GetNbConstraints()).Str("backend", "plonk").Logger() @@ -82,48 +115,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // result proof := &Proof{} - lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} - var ( - wpi2iop *iop.Polynomial // canonical - commitmentVal fr.Element // TODO @Tabaie get rid of this - ) - if len(spr.CommitmentInfo) != 0 { - opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[0].HintID, func(_ *big.Int, ins, outs []*big.Int) error { - pi2 := make([]fr.Element, pk.Domain[0].Cardinality) - offset := spr.GetNbPublicVariables() - for i := range ins { - pi2[offset+spr.CommitmentInfo[0].Committed[i]].SetBigInt(ins[i]) - } - var ( - err error - hashRes []fr.Element - ) - if _, err = pi2[offset+spr.CommitmentInfo[0].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. - return err - } - if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding - return err - } - pi2iop := iop.NewPolynomial(&pi2, lagReg) - wpi2iop = pi2iop.ShallowClone() - wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() - if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Kzg); err != nil { - return err - } - if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { - return err - } - commitmentVal = hashRes[0] // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses - commitmentVal.BigInt(outs[0]) - return nil - })) - } else { - // TODO Leaving pi2 in for testing. In the future, bypass when no commitment present - pi2 := make([]fr.Element, pk.Domain[0].Cardinality) - pi2iop := iop.NewPolynomial(&pi2, lagReg) - wpi2iop = pi2iop.ShallowClone() - // wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + commitmentVal := make([]fr.Element, len(spr.CommitmentInfo)) // TODO @Tabaie get rid of this + wpi2iop := make([]*iop.Polynomial, len(spr.CommitmentInfo)) + proof.PI2 = make([]kzg.Digest, len(spr.CommitmentInfo)) + for i := range spr.CommitmentInfo { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[i].HintID, + bsb22ComputeCommitmentHint(spr, pk, proof, wpi2iop, &commitmentVal[i], i))) } // query l, r, o in Lagrange basis, not blinded @@ -132,19 +130,17 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } // TODO @gbotrel deal with that conversion lazily - var lcpi2iop *iop.Polynomial - if len(spr.CommitmentInfo) != 0 { - lcpi2iop = wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form - } else { - coeffs := make([]fr.Element, pk.Domain[1].Cardinality) - lcpi2iop = iop.NewPolynomial(&coeffs, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.Regular}) + lcpi2iop := make([]*iop.Polynomial, len(wpi2iop)) + for i := range wpi2iop { + lcpi2iop[i] = wpi2iop[i].Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form } solution := _solution.(*cs.SparseR1CSSolution) evaluationLDomainSmall := []fr.Element(solution.L) evaluationRDomainSmall := []fr.Element(solution.R) evaluationODomainSmall := []fr.Element(solution.O) - // l, r o and blinded versions + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + // l, r, o and blinded versions var ( wliop, wriop, @@ -188,8 +184,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) - if len(spr.CommitmentInfo) != 0 { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[0].CommitmentIndex] = commitmentVal + for i := range spr.CommitmentInfo { + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[i].CommitmentIndex] = commitmentVal[i] } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -285,7 +281,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts }() // Full capture using latest gnark crypto... - fic := func(fql, fqr, fqm, fqo, fqk, fqCPrime, l, r, o, pi2 fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary + fic := func(fql, fqr, fqm, fqo, fqk, l, r, o fr.Element, pi2QcPrime []fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary var ic, tmp fr.Element @@ -296,8 +292,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ic.Add(&ic, &tmp) tmp.Mul(&fqo, &o) ic.Add(&ic, &tmp).Add(&ic, &fqk) - tmp.Mul(&fqCPrime, &pi2) - ic.Add(&ic, &tmp) + nbComms := len(spr.CommitmentInfo) + for i := range spr.CommitmentInfo { + tmp.Mul(&pi2QcPrime[i], &pi2QcPrime[i+nbComms]) + ic.Add(&ic, &tmp) + } return ic } @@ -330,13 +329,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return one } - // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15 , 16 - // l , r , o, id, s1, s2, s3, z, zs, PI2, ql, qr, qm, qo, qk, qCPrime, lone + // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm + // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, PI2 , qCPrime fm := func(x ...fr.Element) fr.Element { - a := fic(x[10], x[11], x[12], x[13], x[14], x[15], x[0], x[1], x[2], x[9]) + a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2], x[15:]) b := fo(x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8]) - c := fone(x[7], x[16]) + c := fone(x[7], x[14]) c.Mul(&c, &alpha).Add(&c, &b).Mul(&c, &alpha).Add(&c, &a) @@ -354,7 +353,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // wait for l, r o lagrange coset conversion wgLRO.Wait() - systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, + toEval := []*iop.Polynomial{ bwliop, bwriop, bwoiop, @@ -364,15 +363,16 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pk.lcS3, bwziop, bwsziop, - lcpi2iop, pk.lcQl, pk.lcQr, pk.lcQm, pk.lcQo, lcqk, - pk.lcQcp, pk.lLoneIOP, - ) + } + toEval = append(toEval, lcpi2iop...) // TODO: Add this at beginning + toEval = append(toEval, pk.lcQcp...) + systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, toEval...) if err != nil { return nil, err } @@ -404,10 +404,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // compute evaluations of (blinded version of) l, r, o, z, qCPrime at zeta - var blzeta, brzeta, bozeta, qcpzeta fr.Element + var blzeta, brzeta, bozeta fr.Element + qcpzeta := make([]fr.Element, len(spr.CommitmentInfo)) var wgEvals sync.WaitGroup - wgEvals.Add(4) + wgEvals.Add(3) evalAtZeta := func(poly *iop.Polynomial, res *fr.Element) { poly.ToCanonical(&pk.Domain[1]).ToRegular() *res = poly.Evaluate(zeta) @@ -416,10 +417,12 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts go evalAtZeta(bwliop, &blzeta) go evalAtZeta(bwriop, &brzeta) go evalAtZeta(bwoiop, &bozeta) - go func() { - qcpzeta = pk.trace.Qcp.Evaluate(zeta) - wgEvals.Done() - }() + evalQcpAtZeta := func(begin, end int) { + for i := begin; i < end; i++ { + qcpzeta[i] = pk.trace.Qcp[i].Evaluate(zeta) + } + } + utils.Parallelize(len(spr.CommitmentInfo), evalQcpAtZeta) var zetaShifted fr.Element zetaShifted.Mul(&zeta, &pk.Vk.Generator) @@ -490,7 +493,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bzuzeta, qcpzeta, bwziop.Coefficients()[:bwziop.BlindedSize()], - wpi2iop.Coefficients(), + coefficients(wpi2iop), pk, ) @@ -506,7 +509,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // Batch open the first list of polynomials proof.BatchedProof, err = kzg.BatchOpenSinglePoint( - [][]fr.Element{ + append(coefficients(pk.trace.Qcp), foldedH, linearizedPolynomialCanonical, bwliop.Coefficients()[:bwliop.BlindedSize()], @@ -514,9 +517,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.Coefficients()[:bwoiop.BlindedSize()], pk.trace.S1.Coefficients(), pk.trace.S2.Coefficients(), - pk.trace.Qcp.Coefficients(), - }, - []kzg.Digest{ + ), + append(pk.Vk.Qcp, foldedHDigest, linearizedPolynomialDigest, proof.LRO[0], @@ -524,8 +526,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.LRO[2], pk.Vk.S[0], pk.Vk.S[1], - pk.Vk.Qcp, - }, + ), zeta, hFunc, pk.Kzg, @@ -541,6 +542,14 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } +func coefficients(p []*iop.Polynomial) [][]fr.Element { + res := make([][]fr.Element, len(p)) + for i, pI := range p { + res[i] = pI.Coefficients() + } + return res +} + // fills proof.LRO with kzg commits of bcl, bcr and bco func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, kzgPk kzg.ProvingKey) error { n := runtime.NumCPU() @@ -605,7 +614,7 @@ func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, kzgPk kzg.ProvingKe // α²*L₁(ζ)*Z(X) // + α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*id1(ζ)+γ)*(r(ζ)+β*id2(ζ)+γ)*(o(ζ)+β*id3(ζ)+γ)) // + l(ζ)*Ql(X) + l(ζ)r(ζ)*Qm(X) + r(ζ)*Qr(X) + o(ζ)*Qo(X) + Qk(X) -func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu, qcpZeta fr.Element, blindedZCanonical []fr.Element, pi2Canonical []fr.Element, pk *ProvingKey) []fr.Element { +func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu fr.Element, qcpZeta, blindedZCanonical []fr.Element, pi2Canonical [][]fr.Element, pk *ProvingKey) []fr.Element { // first part: individual constraints var rl fr.Element @@ -688,8 +697,10 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, t0.Mul(&cqo[i], &oZeta).Add(&t0, &cqk[i]) t.Add(&t, &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) - t0.Mul(&pi2Canonical[i], &qcpZeta) - t.Add(&t, &t0) + for j := range qcpZeta { + t0.Mul(&pi2Canonical[j][i], &qcpZeta[j]) + t.Add(&t, &t0) + } } t0.Mul(&blindedZCanonical[i], &lagrangeZeta) diff --git a/backend/plonk/bls12-377/setup.go b/backend/plonk/bls12-377/setup.go index 15b25e9ad6..464b36c251 100644 --- a/backend/plonk/bls12-377/setup.go +++ b/backend/plonk/bls12-377/setup.go @@ -35,7 +35,8 @@ type Trace struct { // completed by the prover. At those indices i (so from 0 to nb_public_variables), LQl[i]=-1 // so the first nb_public_variables constraints look like this: // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. - Ql, Qr, Qm, Qo, Qk, Qcp *iop.Polynomial + Ql, Qr, Qm, Qo, Qk *iop.Polynomial + Qcp []*iop.Polynomial // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. // The set of interpolation is of size N, so to represent the permutation S we let S acts on the @@ -72,7 +73,8 @@ type VerifyingKey struct { // Commitments to ql, qr, qm, qo, qcp prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk, Qcp kzg.Digest + Ql, Qr, Qm, Qo, Qk kzg.Digest + Qcp []kzg.Digest CommitmentConstraintIndexes []uint64 } @@ -100,7 +102,8 @@ type ProvingKey struct { Vk *VerifyingKey // qr,ql,qm,qo,qcp in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo, Qcp once. - lcQl, lcQr, lcQm, lcQo, lcQcp *iop.Polynomial + lcQl, lcQr, lcQm, lcQo *iop.Polynomial + lcQcp []*iop.Polynomial // LQk qk in Lagrange form -> to be completed by the prover. After being completed, lQk *iop.Polynomial @@ -173,7 +176,10 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro // computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset // basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. func (pk *ProvingKey) computeLagrangeCosetPolys() { - pk.lcQcp = pk.trace.Qcp.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQcp = make([]*iop.Polynomial, len(pk.trace.Qcp)) + for i, qcpI := range pk.trace.Qcp { + pk.lcQcp[i] = qcpI.Clone().ToLagrangeCoset(&pk.Domain[1]) + } pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) @@ -226,7 +232,7 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qm := make([]fr.Element, size) qo := make([]fr.Element, size) qk := make([]fr.Element, size) - qcp := make([]fr.Element, size) + qcp := make([][]fr.Element, len(spr.CommitmentInfo)) for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent ql[i].SetOne().Neg(&ql[i]) @@ -248,12 +254,6 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { j++ } - if len(spr.CommitmentInfo) != 0 { - for _, committed := range spr.CommitmentInfo[0].Committed { - qcp[offset+committed].SetOne() - } - } - lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} pt.Ql = iop.NewPolynomial(&ql, lagReg) @@ -261,11 +261,18 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { pt.Qm = iop.NewPolynomial(&qm, lagReg) pt.Qo = iop.NewPolynomial(&qo, lagReg) pt.Qk = iop.NewPolynomial(&qk, lagReg) - pt.Qcp = iop.NewPolynomial(&qcp, lagReg) + pt.Qcp = make([]*iop.Polynomial, len(qcp)) + for i := range spr.CommitmentInfo { + qcp[i] = make([]fr.Element, size) + for _, committed := range spr.CommitmentInfo[i].Committed { + qcp[i][offset+committed].SetOne() + } + pt.Qcp[i] = iop.NewPolynomial(&qcp[i], lagReg) + } } -// commitTrace commits to every polynomials in the trace, and put +// commitTrace commits to every polynomial in the trace, and put // the commitments int the verifying key. func commitTrace(trace *Trace, pk *ProvingKey) error { @@ -274,12 +281,18 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { trace.Qm.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qo.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qk.ToCanonical(&pk.Domain[0]).ToRegular() // -> qk is not complete - trace.Qcp.ToCanonical(&pk.Domain[0]).ToRegular() trace.S1.ToCanonical(&pk.Domain[0]).ToRegular() trace.S2.ToCanonical(&pk.Domain[0]).ToRegular() trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() var err error + pk.Vk.Qcp = make([]kzg.Digest, len(trace.Qcp)) + for i := range trace.Qcp { + trace.Qcp[i].ToCanonical(&pk.Domain[0]).ToRegular() + if pk.Vk.Qcp[i], err = kzg.Commit(pk.trace.Qcp[i].Coefficients(), pk.Kzg); err != nil { + return err + } + } if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Kzg); err != nil { return err } @@ -295,9 +308,6 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Kzg); err != nil { - return err - } if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Kzg); err != nil { return err } diff --git a/backend/plonk/bls12-377/verify.go b/backend/plonk/bls12-377/verify.go index 964b3768c4..287138eb19 100644 --- a/backend/plonk/bls12-377/verify.go +++ b/backend/plonk/bls12-377/verify.go @@ -112,7 +112,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { for i := range vk.CommitmentConstraintIndexes { var hashRes []fr.Element // TODO: when multi commits are implemented: PI2 -> PI2[i] - if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + if hashRes, err = fr.Hash(proof.PI2[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } @@ -137,14 +137,16 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - claimedQuotient := proof.BatchedProof.ClaimedValues[0] - linearizedPolynomialZeta := proof.BatchedProof.ClaimedValues[1] - l := proof.BatchedProof.ClaimedValues[2] - r := proof.BatchedProof.ClaimedValues[3] - o := proof.BatchedProof.ClaimedValues[4] - s1 := proof.BatchedProof.ClaimedValues[5] - s2 := proof.BatchedProof.ClaimedValues[6] - qC := proof.BatchedProof.ClaimedValues[7] + qC := make([]fr.Element, len(proof.PI2)) + copy(qC, proof.BatchedProof.ClaimedValues) + claimedValues := proof.BatchedProof.ClaimedValues[len(proof.PI2):] + claimedQuotient := claimedValues[0] + linearizedPolynomialZeta := claimedValues[1] + l := claimedValues[2] + r := claimedValues[3] + o := claimedValues[4] + s1 := claimedValues[5] + s2 := claimedValues[6] _s1.Mul(&s1, &beta).Add(&_s1, &l).Add(&_s1, &gamma) // (l(ζ)+β*s1(ζ)+γ) _s2.Mul(&s2, &beta).Add(&_s2, &r).Add(&_s2, &gamma) // (r(ζ)+β*s2(ζ)+γ) @@ -213,21 +215,21 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // note since third part = α²*L₁(ζ)*Z _s2.Mul(&_s2, &alpha).Add(&_s2, &alphaSquareLagrange) // -α*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + α²*L₁(ζ) - points := []curve.G1Affine{ - vk.Ql, vk.Qr, vk.Qm, vk.Qo, vk.Qk, proof.PI2, // first part + points := append(proof.PI2, + vk.Ql, vk.Qr, vk.Qm, vk.Qo, vk.Qk, // first part vk.S[2], proof.Z, // second & third part - } + ) - scalars := []fr.Element{ - l, r, rl, o, one /* TODO Perf @Tabaie Consider just adding Qk instead */, qC, // first part + scalars := append(qC, + l, r, rl, o, one, /* TODO Perf @Tabaie Consider just adding Qk instead */ // first part _s1, _s2, // second & third part - } + ) if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{}); err != nil { return err } // Fold the first proof - foldedProof, foldedDigest, err := kzg.FoldProof([]kzg.Digest{ + foldedProof, foldedDigest, err := kzg.FoldProof(append(vk.Qcp, foldedH, linearizedPolynomialDigest, proof.LRO[0], @@ -235,8 +237,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { proof.LRO[2], vk.S[0], vk.S[1], - vk.Qcp, - }, + ), &proof.BatchedProof, zeta, hFunc, @@ -268,7 +269,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } -func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element, pi2 kzg.Digest) error { +func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element, pi2 []kzg.Digest) error { // permutation if err := fs.Bind(challenge, vk.S[0].Marshal()); err != nil { @@ -306,8 +307,10 @@ func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey } // bsb22 commitment - if err := fs.Bind(challenge, pi2.Marshal()); err != nil { - return err + for i := range pi2 { + if err := fs.Bind(challenge, pi2[i].Marshal()); err != nil { + return err + } } return nil diff --git a/backend/plonk/bls12-381/marshal.go b/backend/plonk/bls12-381/marshal.go index dc52cdedf6..082f63d286 100644 --- a/backend/plonk/bls12-381/marshal.go +++ b/backend/plonk/bls12-381/marshal.go @@ -19,9 +19,11 @@ package plonk import ( curve "github.com/consensys/gnark-crypto/ecc/bls12-381" - "errors" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + + "errors" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/iop" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/kzg" "io" ) @@ -50,7 +52,7 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - &proof.PI2, + proof.PI2, } for _, v := range toEncode { @@ -86,6 +88,10 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { } } + if proof.PI2 == nil { + proof.PI2 = []kzg.Digest{} + } + return dec.BytesRead(), nil } @@ -125,7 +131,7 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { pk.trace.Qm.Coefficients(), pk.trace.Qo.Coefficients(), pk.trace.Qk.Coefficients(), - pk.trace.Qcp.Coefficients(), + coefficients(pk.trace.Qcp), pk.lQk.Coefficients(), pk.trace.S1.Coefficients(), pk.trace.S2.Coefficients(), @@ -166,7 +172,8 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { dec := curve.NewDecoder(r) - var ql, qr, qm, qo, qk, qcp, lqk, s1, s2, s3 []fr.Element + var ql, qr, qm, qo, qk, lqk, s1, s2, s3 []fr.Element + var qcp [][]fr.Element toDecode := []interface{}{ &ql, &qr, @@ -193,11 +200,14 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) - pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + pk.trace.Qcp = make([]*iop.Polynomial, len(qcp)) + for i := range qcp { + pk.trace.Qcp[i] = iop.NewPolynomial(&qcp[i], canReg) + } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} pk.lQk = iop.NewPolynomial(&lqk, lagReg) @@ -234,7 +244,7 @@ func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*curve.Encoder)) (n &vk.Qm, &vk.Qo, &vk.Qk, - &vk.Qcp, + vk.Qcp, vk.CommitmentConstraintIndexes, } diff --git a/backend/plonk/bls12-381/marshal_test.go b/backend/plonk/bls12-381/marshal_test.go index 6c86955b9f..1130a869f5 100644 --- a/backend/plonk/bls12-381/marshal_test.go +++ b/backend/plonk/bls12-381/marshal_test.go @@ -121,7 +121,6 @@ func (pk *ProvingKey) randomize() { qo := randomScalars(n) qk := randomScalars(n) lqk := randomScalars(n) - qcp := randomScalars(n) s1 := randomScalars(n) s2 := randomScalars(n) s3 := randomScalars(n) @@ -132,11 +131,16 @@ func (pk *ProvingKey) randomize() { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) - pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + pk.trace.Qcp = make([]*iop.Polynomial, rand.Intn(4)) + for i := range pk.trace.Qcp { + qcp := randomScalars(rand.Intn(n / 4)) + pk.trace.Qcp[i] = iop.NewPolynomial(&qcp, canReg) + } + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) pk.trace.S[0] = -12 pk.trace.S[len(pk.trace.S)-1] = 8888 @@ -163,7 +167,7 @@ func (vk *VerifyingKey) randomize() { vk.Qm = randomPoint() vk.Qo = randomPoint() vk.Qk = randomPoint() - vk.Qcp = randomPoint() + vk.Qcp = randomPoints(rand.Intn(4)) } func (proof *Proof) randomize() { @@ -178,7 +182,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.PI2 = randomPoint() + proof.PI2 = randomPoints(rand.Intn(4)) } func randomPoint() curve.G1Affine { @@ -187,6 +191,14 @@ func randomPoint() curve.G1Affine { return r } +func randomPoints(n int) []curve.G1Affine { + res := make([]curve.G1Affine, n) + for i := range res { + res[i] = randomPoint() + } + return res +} + func randomScalars(n int) []fr.Element { v := make([]fr.Element, n) one := fr.One() diff --git a/backend/plonk/bls12-381/prove.go b/backend/plonk/bls12-381/prove.go index cd41e8073b..adbd314d43 100644 --- a/backend/plonk/bls12-381/prove.go +++ b/backend/plonk/bls12-381/prove.go @@ -55,7 +55,7 @@ type Proof struct { H [3]kzg.Digest // PI2, the BSB22 commitment - PI2 kzg.Digest + PI2 []kzg.Digest // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2, qCPrime BatchedProof kzg.BatchOpeningProof @@ -64,6 +64,39 @@ type Proof struct { ZShiftedOpening kzg.OpeningProof } +func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, wpi2iop []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { + return func(_ *big.Int, ins, outs []*big.Int) error { + pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + offset := spr.GetNbPublicVariables() + for i := range ins { + pi2[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) + } + var ( + err error + hashRes []fr.Element + ) + /*if _, err = pi2[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + return err + } + if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding + return err + }*/ + pi2iop := iop.NewPolynomial(&pi2, iop.Form{Basis: iop.Lagrange, Layout: iop.Regular}) + wpi2iop[commDepth] = pi2iop.ShallowClone() + wpi2iop[commDepth].ToCanonical(&pk.Domain[0]).ToRegular() + if proof.PI2[commDepth], err = kzg.Commit(wpi2iop[commDepth].Coefficients(), pk.Kzg); err != nil { + return err + } + if hashRes, err = fr.Hash(proof.PI2[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + return err + } + res.Set(&hashRes[0]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses + res.BigInt(outs[0]) + + return nil + } +} + func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", spr.GetNbConstraints()).Str("backend", "plonk").Logger() @@ -82,48 +115,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // result proof := &Proof{} - lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} - var ( - wpi2iop *iop.Polynomial // canonical - commitmentVal fr.Element // TODO @Tabaie get rid of this - ) - if len(spr.CommitmentInfo) != 0 { - opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[0].HintID, func(_ *big.Int, ins, outs []*big.Int) error { - pi2 := make([]fr.Element, pk.Domain[0].Cardinality) - offset := spr.GetNbPublicVariables() - for i := range ins { - pi2[offset+spr.CommitmentInfo[0].Committed[i]].SetBigInt(ins[i]) - } - var ( - err error - hashRes []fr.Element - ) - if _, err = pi2[offset+spr.CommitmentInfo[0].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. - return err - } - if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding - return err - } - pi2iop := iop.NewPolynomial(&pi2, lagReg) - wpi2iop = pi2iop.ShallowClone() - wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() - if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Kzg); err != nil { - return err - } - if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { - return err - } - commitmentVal = hashRes[0] // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses - commitmentVal.BigInt(outs[0]) - return nil - })) - } else { - // TODO Leaving pi2 in for testing. In the future, bypass when no commitment present - pi2 := make([]fr.Element, pk.Domain[0].Cardinality) - pi2iop := iop.NewPolynomial(&pi2, lagReg) - wpi2iop = pi2iop.ShallowClone() - // wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + commitmentVal := make([]fr.Element, len(spr.CommitmentInfo)) // TODO @Tabaie get rid of this + wpi2iop := make([]*iop.Polynomial, len(spr.CommitmentInfo)) + proof.PI2 = make([]kzg.Digest, len(spr.CommitmentInfo)) + for i := range spr.CommitmentInfo { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[i].HintID, + bsb22ComputeCommitmentHint(spr, pk, proof, wpi2iop, &commitmentVal[i], i))) } // query l, r, o in Lagrange basis, not blinded @@ -132,19 +130,17 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } // TODO @gbotrel deal with that conversion lazily - var lcpi2iop *iop.Polynomial - if len(spr.CommitmentInfo) != 0 { - lcpi2iop = wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form - } else { - coeffs := make([]fr.Element, pk.Domain[1].Cardinality) - lcpi2iop = iop.NewPolynomial(&coeffs, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.Regular}) + lcpi2iop := make([]*iop.Polynomial, len(wpi2iop)) + for i := range wpi2iop { + lcpi2iop[i] = wpi2iop[i].Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form } solution := _solution.(*cs.SparseR1CSSolution) evaluationLDomainSmall := []fr.Element(solution.L) evaluationRDomainSmall := []fr.Element(solution.R) evaluationODomainSmall := []fr.Element(solution.O) - // l, r o and blinded versions + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + // l, r, o and blinded versions var ( wliop, wriop, @@ -188,8 +184,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) - if len(spr.CommitmentInfo) != 0 { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[0].CommitmentIndex] = commitmentVal + for i := range spr.CommitmentInfo { + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[i].CommitmentIndex] = commitmentVal[i] } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -285,7 +281,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts }() // Full capture using latest gnark crypto... - fic := func(fql, fqr, fqm, fqo, fqk, fqCPrime, l, r, o, pi2 fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary + fic := func(fql, fqr, fqm, fqo, fqk, l, r, o fr.Element, pi2QcPrime []fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary var ic, tmp fr.Element @@ -296,8 +292,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ic.Add(&ic, &tmp) tmp.Mul(&fqo, &o) ic.Add(&ic, &tmp).Add(&ic, &fqk) - tmp.Mul(&fqCPrime, &pi2) - ic.Add(&ic, &tmp) + nbComms := len(spr.CommitmentInfo) + for i := range spr.CommitmentInfo { + tmp.Mul(&pi2QcPrime[i], &pi2QcPrime[i+nbComms]) + ic.Add(&ic, &tmp) + } return ic } @@ -330,13 +329,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return one } - // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15 , 16 - // l , r , o, id, s1, s2, s3, z, zs, PI2, ql, qr, qm, qo, qk, qCPrime, lone + // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm + // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, PI2 , qCPrime fm := func(x ...fr.Element) fr.Element { - a := fic(x[10], x[11], x[12], x[13], x[14], x[15], x[0], x[1], x[2], x[9]) + a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2], x[15:]) b := fo(x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8]) - c := fone(x[7], x[16]) + c := fone(x[7], x[14]) c.Mul(&c, &alpha).Add(&c, &b).Mul(&c, &alpha).Add(&c, &a) @@ -354,7 +353,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // wait for l, r o lagrange coset conversion wgLRO.Wait() - systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, + toEval := []*iop.Polynomial{ bwliop, bwriop, bwoiop, @@ -364,15 +363,16 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pk.lcS3, bwziop, bwsziop, - lcpi2iop, pk.lcQl, pk.lcQr, pk.lcQm, pk.lcQo, lcqk, - pk.lcQcp, pk.lLoneIOP, - ) + } + toEval = append(toEval, lcpi2iop...) // TODO: Add this at beginning + toEval = append(toEval, pk.lcQcp...) + systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, toEval...) if err != nil { return nil, err } @@ -404,10 +404,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // compute evaluations of (blinded version of) l, r, o, z, qCPrime at zeta - var blzeta, brzeta, bozeta, qcpzeta fr.Element + var blzeta, brzeta, bozeta fr.Element + qcpzeta := make([]fr.Element, len(spr.CommitmentInfo)) var wgEvals sync.WaitGroup - wgEvals.Add(4) + wgEvals.Add(3) evalAtZeta := func(poly *iop.Polynomial, res *fr.Element) { poly.ToCanonical(&pk.Domain[1]).ToRegular() *res = poly.Evaluate(zeta) @@ -416,10 +417,12 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts go evalAtZeta(bwliop, &blzeta) go evalAtZeta(bwriop, &brzeta) go evalAtZeta(bwoiop, &bozeta) - go func() { - qcpzeta = pk.trace.Qcp.Evaluate(zeta) - wgEvals.Done() - }() + evalQcpAtZeta := func(begin, end int) { + for i := begin; i < end; i++ { + qcpzeta[i] = pk.trace.Qcp[i].Evaluate(zeta) + } + } + utils.Parallelize(len(spr.CommitmentInfo), evalQcpAtZeta) var zetaShifted fr.Element zetaShifted.Mul(&zeta, &pk.Vk.Generator) @@ -490,7 +493,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bzuzeta, qcpzeta, bwziop.Coefficients()[:bwziop.BlindedSize()], - wpi2iop.Coefficients(), + coefficients(wpi2iop), pk, ) @@ -506,7 +509,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // Batch open the first list of polynomials proof.BatchedProof, err = kzg.BatchOpenSinglePoint( - [][]fr.Element{ + append(coefficients(pk.trace.Qcp), foldedH, linearizedPolynomialCanonical, bwliop.Coefficients()[:bwliop.BlindedSize()], @@ -514,9 +517,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.Coefficients()[:bwoiop.BlindedSize()], pk.trace.S1.Coefficients(), pk.trace.S2.Coefficients(), - pk.trace.Qcp.Coefficients(), - }, - []kzg.Digest{ + ), + append(pk.Vk.Qcp, foldedHDigest, linearizedPolynomialDigest, proof.LRO[0], @@ -524,8 +526,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.LRO[2], pk.Vk.S[0], pk.Vk.S[1], - pk.Vk.Qcp, - }, + ), zeta, hFunc, pk.Kzg, @@ -541,6 +542,14 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } +func coefficients(p []*iop.Polynomial) [][]fr.Element { + res := make([][]fr.Element, len(p)) + for i, pI := range p { + res[i] = pI.Coefficients() + } + return res +} + // fills proof.LRO with kzg commits of bcl, bcr and bco func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, kzgPk kzg.ProvingKey) error { n := runtime.NumCPU() @@ -605,7 +614,7 @@ func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, kzgPk kzg.ProvingKe // α²*L₁(ζ)*Z(X) // + α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*id1(ζ)+γ)*(r(ζ)+β*id2(ζ)+γ)*(o(ζ)+β*id3(ζ)+γ)) // + l(ζ)*Ql(X) + l(ζ)r(ζ)*Qm(X) + r(ζ)*Qr(X) + o(ζ)*Qo(X) + Qk(X) -func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu, qcpZeta fr.Element, blindedZCanonical []fr.Element, pi2Canonical []fr.Element, pk *ProvingKey) []fr.Element { +func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu fr.Element, qcpZeta, blindedZCanonical []fr.Element, pi2Canonical [][]fr.Element, pk *ProvingKey) []fr.Element { // first part: individual constraints var rl fr.Element @@ -688,8 +697,10 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, t0.Mul(&cqo[i], &oZeta).Add(&t0, &cqk[i]) t.Add(&t, &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) - t0.Mul(&pi2Canonical[i], &qcpZeta) - t.Add(&t, &t0) + for j := range qcpZeta { + t0.Mul(&pi2Canonical[j][i], &qcpZeta[j]) + t.Add(&t, &t0) + } } t0.Mul(&blindedZCanonical[i], &lagrangeZeta) diff --git a/backend/plonk/bls12-381/setup.go b/backend/plonk/bls12-381/setup.go index 7f35b7dfd1..a778d70dec 100644 --- a/backend/plonk/bls12-381/setup.go +++ b/backend/plonk/bls12-381/setup.go @@ -35,7 +35,8 @@ type Trace struct { // completed by the prover. At those indices i (so from 0 to nb_public_variables), LQl[i]=-1 // so the first nb_public_variables constraints look like this: // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. - Ql, Qr, Qm, Qo, Qk, Qcp *iop.Polynomial + Ql, Qr, Qm, Qo, Qk *iop.Polynomial + Qcp []*iop.Polynomial // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. // The set of interpolation is of size N, so to represent the permutation S we let S acts on the @@ -72,7 +73,8 @@ type VerifyingKey struct { // Commitments to ql, qr, qm, qo, qcp prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk, Qcp kzg.Digest + Ql, Qr, Qm, Qo, Qk kzg.Digest + Qcp []kzg.Digest CommitmentConstraintIndexes []uint64 } @@ -100,7 +102,8 @@ type ProvingKey struct { Vk *VerifyingKey // qr,ql,qm,qo,qcp in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo, Qcp once. - lcQl, lcQr, lcQm, lcQo, lcQcp *iop.Polynomial + lcQl, lcQr, lcQm, lcQo *iop.Polynomial + lcQcp []*iop.Polynomial // LQk qk in Lagrange form -> to be completed by the prover. After being completed, lQk *iop.Polynomial @@ -173,7 +176,10 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro // computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset // basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. func (pk *ProvingKey) computeLagrangeCosetPolys() { - pk.lcQcp = pk.trace.Qcp.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQcp = make([]*iop.Polynomial, len(pk.trace.Qcp)) + for i, qcpI := range pk.trace.Qcp { + pk.lcQcp[i] = qcpI.Clone().ToLagrangeCoset(&pk.Domain[1]) + } pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) @@ -226,7 +232,7 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qm := make([]fr.Element, size) qo := make([]fr.Element, size) qk := make([]fr.Element, size) - qcp := make([]fr.Element, size) + qcp := make([][]fr.Element, len(spr.CommitmentInfo)) for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent ql[i].SetOne().Neg(&ql[i]) @@ -248,12 +254,6 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { j++ } - if len(spr.CommitmentInfo) != 0 { - for _, committed := range spr.CommitmentInfo[0].Committed { - qcp[offset+committed].SetOne() - } - } - lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} pt.Ql = iop.NewPolynomial(&ql, lagReg) @@ -261,11 +261,18 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { pt.Qm = iop.NewPolynomial(&qm, lagReg) pt.Qo = iop.NewPolynomial(&qo, lagReg) pt.Qk = iop.NewPolynomial(&qk, lagReg) - pt.Qcp = iop.NewPolynomial(&qcp, lagReg) + pt.Qcp = make([]*iop.Polynomial, len(qcp)) + for i := range spr.CommitmentInfo { + qcp[i] = make([]fr.Element, size) + for _, committed := range spr.CommitmentInfo[i].Committed { + qcp[i][offset+committed].SetOne() + } + pt.Qcp[i] = iop.NewPolynomial(&qcp[i], lagReg) + } } -// commitTrace commits to every polynomials in the trace, and put +// commitTrace commits to every polynomial in the trace, and put // the commitments int the verifying key. func commitTrace(trace *Trace, pk *ProvingKey) error { @@ -274,12 +281,18 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { trace.Qm.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qo.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qk.ToCanonical(&pk.Domain[0]).ToRegular() // -> qk is not complete - trace.Qcp.ToCanonical(&pk.Domain[0]).ToRegular() trace.S1.ToCanonical(&pk.Domain[0]).ToRegular() trace.S2.ToCanonical(&pk.Domain[0]).ToRegular() trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() var err error + pk.Vk.Qcp = make([]kzg.Digest, len(trace.Qcp)) + for i := range trace.Qcp { + trace.Qcp[i].ToCanonical(&pk.Domain[0]).ToRegular() + if pk.Vk.Qcp[i], err = kzg.Commit(pk.trace.Qcp[i].Coefficients(), pk.Kzg); err != nil { + return err + } + } if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Kzg); err != nil { return err } @@ -295,9 +308,6 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Kzg); err != nil { - return err - } if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Kzg); err != nil { return err } diff --git a/backend/plonk/bls12-381/verify.go b/backend/plonk/bls12-381/verify.go index 20d798cc03..288e0826bf 100644 --- a/backend/plonk/bls12-381/verify.go +++ b/backend/plonk/bls12-381/verify.go @@ -112,7 +112,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { for i := range vk.CommitmentConstraintIndexes { var hashRes []fr.Element // TODO: when multi commits are implemented: PI2 -> PI2[i] - if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + if hashRes, err = fr.Hash(proof.PI2[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } @@ -137,14 +137,16 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - claimedQuotient := proof.BatchedProof.ClaimedValues[0] - linearizedPolynomialZeta := proof.BatchedProof.ClaimedValues[1] - l := proof.BatchedProof.ClaimedValues[2] - r := proof.BatchedProof.ClaimedValues[3] - o := proof.BatchedProof.ClaimedValues[4] - s1 := proof.BatchedProof.ClaimedValues[5] - s2 := proof.BatchedProof.ClaimedValues[6] - qC := proof.BatchedProof.ClaimedValues[7] + qC := make([]fr.Element, len(proof.PI2)) + copy(qC, proof.BatchedProof.ClaimedValues) + claimedValues := proof.BatchedProof.ClaimedValues[len(proof.PI2):] + claimedQuotient := claimedValues[0] + linearizedPolynomialZeta := claimedValues[1] + l := claimedValues[2] + r := claimedValues[3] + o := claimedValues[4] + s1 := claimedValues[5] + s2 := claimedValues[6] _s1.Mul(&s1, &beta).Add(&_s1, &l).Add(&_s1, &gamma) // (l(ζ)+β*s1(ζ)+γ) _s2.Mul(&s2, &beta).Add(&_s2, &r).Add(&_s2, &gamma) // (r(ζ)+β*s2(ζ)+γ) @@ -213,21 +215,21 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // note since third part = α²*L₁(ζ)*Z _s2.Mul(&_s2, &alpha).Add(&_s2, &alphaSquareLagrange) // -α*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + α²*L₁(ζ) - points := []curve.G1Affine{ - vk.Ql, vk.Qr, vk.Qm, vk.Qo, vk.Qk, proof.PI2, // first part + points := append(proof.PI2, + vk.Ql, vk.Qr, vk.Qm, vk.Qo, vk.Qk, // first part vk.S[2], proof.Z, // second & third part - } + ) - scalars := []fr.Element{ - l, r, rl, o, one /* TODO Perf @Tabaie Consider just adding Qk instead */, qC, // first part + scalars := append(qC, + l, r, rl, o, one, /* TODO Perf @Tabaie Consider just adding Qk instead */ // first part _s1, _s2, // second & third part - } + ) if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{}); err != nil { return err } // Fold the first proof - foldedProof, foldedDigest, err := kzg.FoldProof([]kzg.Digest{ + foldedProof, foldedDigest, err := kzg.FoldProof(append(vk.Qcp, foldedH, linearizedPolynomialDigest, proof.LRO[0], @@ -235,8 +237,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { proof.LRO[2], vk.S[0], vk.S[1], - vk.Qcp, - }, + ), &proof.BatchedProof, zeta, hFunc, @@ -268,7 +269,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } -func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element, pi2 kzg.Digest) error { +func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element, pi2 []kzg.Digest) error { // permutation if err := fs.Bind(challenge, vk.S[0].Marshal()); err != nil { @@ -306,8 +307,10 @@ func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey } // bsb22 commitment - if err := fs.Bind(challenge, pi2.Marshal()); err != nil { - return err + for i := range pi2 { + if err := fs.Bind(challenge, pi2[i].Marshal()); err != nil { + return err + } } return nil diff --git a/backend/plonk/bls24-315/marshal.go b/backend/plonk/bls24-315/marshal.go index b0b4d40c7d..4ebe5e278c 100644 --- a/backend/plonk/bls24-315/marshal.go +++ b/backend/plonk/bls24-315/marshal.go @@ -19,9 +19,11 @@ package plonk import ( curve "github.com/consensys/gnark-crypto/ecc/bls24-315" - "errors" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" + + "errors" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/iop" + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/kzg" "io" ) @@ -50,7 +52,7 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - &proof.PI2, + proof.PI2, } for _, v := range toEncode { @@ -86,6 +88,10 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { } } + if proof.PI2 == nil { + proof.PI2 = []kzg.Digest{} + } + return dec.BytesRead(), nil } @@ -125,7 +131,7 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { pk.trace.Qm.Coefficients(), pk.trace.Qo.Coefficients(), pk.trace.Qk.Coefficients(), - pk.trace.Qcp.Coefficients(), + coefficients(pk.trace.Qcp), pk.lQk.Coefficients(), pk.trace.S1.Coefficients(), pk.trace.S2.Coefficients(), @@ -166,7 +172,8 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { dec := curve.NewDecoder(r) - var ql, qr, qm, qo, qk, qcp, lqk, s1, s2, s3 []fr.Element + var ql, qr, qm, qo, qk, lqk, s1, s2, s3 []fr.Element + var qcp [][]fr.Element toDecode := []interface{}{ &ql, &qr, @@ -193,11 +200,14 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) - pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + pk.trace.Qcp = make([]*iop.Polynomial, len(qcp)) + for i := range qcp { + pk.trace.Qcp[i] = iop.NewPolynomial(&qcp[i], canReg) + } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} pk.lQk = iop.NewPolynomial(&lqk, lagReg) @@ -234,7 +244,7 @@ func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*curve.Encoder)) (n &vk.Qm, &vk.Qo, &vk.Qk, - &vk.Qcp, + vk.Qcp, vk.CommitmentConstraintIndexes, } diff --git a/backend/plonk/bls24-315/marshal_test.go b/backend/plonk/bls24-315/marshal_test.go index bb4272dbee..be19d2ae58 100644 --- a/backend/plonk/bls24-315/marshal_test.go +++ b/backend/plonk/bls24-315/marshal_test.go @@ -121,7 +121,6 @@ func (pk *ProvingKey) randomize() { qo := randomScalars(n) qk := randomScalars(n) lqk := randomScalars(n) - qcp := randomScalars(n) s1 := randomScalars(n) s2 := randomScalars(n) s3 := randomScalars(n) @@ -132,11 +131,16 @@ func (pk *ProvingKey) randomize() { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) - pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + pk.trace.Qcp = make([]*iop.Polynomial, rand.Intn(4)) + for i := range pk.trace.Qcp { + qcp := randomScalars(rand.Intn(n / 4)) + pk.trace.Qcp[i] = iop.NewPolynomial(&qcp, canReg) + } + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) pk.trace.S[0] = -12 pk.trace.S[len(pk.trace.S)-1] = 8888 @@ -163,7 +167,7 @@ func (vk *VerifyingKey) randomize() { vk.Qm = randomPoint() vk.Qo = randomPoint() vk.Qk = randomPoint() - vk.Qcp = randomPoint() + vk.Qcp = randomPoints(rand.Intn(4)) } func (proof *Proof) randomize() { @@ -178,7 +182,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.PI2 = randomPoint() + proof.PI2 = randomPoints(rand.Intn(4)) } func randomPoint() curve.G1Affine { @@ -187,6 +191,14 @@ func randomPoint() curve.G1Affine { return r } +func randomPoints(n int) []curve.G1Affine { + res := make([]curve.G1Affine, n) + for i := range res { + res[i] = randomPoint() + } + return res +} + func randomScalars(n int) []fr.Element { v := make([]fr.Element, n) one := fr.One() diff --git a/backend/plonk/bls24-315/prove.go b/backend/plonk/bls24-315/prove.go index 406033c82a..0bfa7948c3 100644 --- a/backend/plonk/bls24-315/prove.go +++ b/backend/plonk/bls24-315/prove.go @@ -55,7 +55,7 @@ type Proof struct { H [3]kzg.Digest // PI2, the BSB22 commitment - PI2 kzg.Digest + PI2 []kzg.Digest // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2, qCPrime BatchedProof kzg.BatchOpeningProof @@ -64,6 +64,39 @@ type Proof struct { ZShiftedOpening kzg.OpeningProof } +func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, wpi2iop []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { + return func(_ *big.Int, ins, outs []*big.Int) error { + pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + offset := spr.GetNbPublicVariables() + for i := range ins { + pi2[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) + } + var ( + err error + hashRes []fr.Element + ) + /*if _, err = pi2[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + return err + } + if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding + return err + }*/ + pi2iop := iop.NewPolynomial(&pi2, iop.Form{Basis: iop.Lagrange, Layout: iop.Regular}) + wpi2iop[commDepth] = pi2iop.ShallowClone() + wpi2iop[commDepth].ToCanonical(&pk.Domain[0]).ToRegular() + if proof.PI2[commDepth], err = kzg.Commit(wpi2iop[commDepth].Coefficients(), pk.Kzg); err != nil { + return err + } + if hashRes, err = fr.Hash(proof.PI2[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + return err + } + res.Set(&hashRes[0]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses + res.BigInt(outs[0]) + + return nil + } +} + func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", spr.GetNbConstraints()).Str("backend", "plonk").Logger() @@ -82,48 +115,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // result proof := &Proof{} - lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} - var ( - wpi2iop *iop.Polynomial // canonical - commitmentVal fr.Element // TODO @Tabaie get rid of this - ) - if len(spr.CommitmentInfo) != 0 { - opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[0].HintID, func(_ *big.Int, ins, outs []*big.Int) error { - pi2 := make([]fr.Element, pk.Domain[0].Cardinality) - offset := spr.GetNbPublicVariables() - for i := range ins { - pi2[offset+spr.CommitmentInfo[0].Committed[i]].SetBigInt(ins[i]) - } - var ( - err error - hashRes []fr.Element - ) - if _, err = pi2[offset+spr.CommitmentInfo[0].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. - return err - } - if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding - return err - } - pi2iop := iop.NewPolynomial(&pi2, lagReg) - wpi2iop = pi2iop.ShallowClone() - wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() - if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Kzg); err != nil { - return err - } - if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { - return err - } - commitmentVal = hashRes[0] // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses - commitmentVal.BigInt(outs[0]) - return nil - })) - } else { - // TODO Leaving pi2 in for testing. In the future, bypass when no commitment present - pi2 := make([]fr.Element, pk.Domain[0].Cardinality) - pi2iop := iop.NewPolynomial(&pi2, lagReg) - wpi2iop = pi2iop.ShallowClone() - // wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + commitmentVal := make([]fr.Element, len(spr.CommitmentInfo)) // TODO @Tabaie get rid of this + wpi2iop := make([]*iop.Polynomial, len(spr.CommitmentInfo)) + proof.PI2 = make([]kzg.Digest, len(spr.CommitmentInfo)) + for i := range spr.CommitmentInfo { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[i].HintID, + bsb22ComputeCommitmentHint(spr, pk, proof, wpi2iop, &commitmentVal[i], i))) } // query l, r, o in Lagrange basis, not blinded @@ -132,19 +130,17 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } // TODO @gbotrel deal with that conversion lazily - var lcpi2iop *iop.Polynomial - if len(spr.CommitmentInfo) != 0 { - lcpi2iop = wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form - } else { - coeffs := make([]fr.Element, pk.Domain[1].Cardinality) - lcpi2iop = iop.NewPolynomial(&coeffs, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.Regular}) + lcpi2iop := make([]*iop.Polynomial, len(wpi2iop)) + for i := range wpi2iop { + lcpi2iop[i] = wpi2iop[i].Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form } solution := _solution.(*cs.SparseR1CSSolution) evaluationLDomainSmall := []fr.Element(solution.L) evaluationRDomainSmall := []fr.Element(solution.R) evaluationODomainSmall := []fr.Element(solution.O) - // l, r o and blinded versions + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + // l, r, o and blinded versions var ( wliop, wriop, @@ -188,8 +184,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) - if len(spr.CommitmentInfo) != 0 { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[0].CommitmentIndex] = commitmentVal + for i := range spr.CommitmentInfo { + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[i].CommitmentIndex] = commitmentVal[i] } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -285,7 +281,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts }() // Full capture using latest gnark crypto... - fic := func(fql, fqr, fqm, fqo, fqk, fqCPrime, l, r, o, pi2 fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary + fic := func(fql, fqr, fqm, fqo, fqk, l, r, o fr.Element, pi2QcPrime []fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary var ic, tmp fr.Element @@ -296,8 +292,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ic.Add(&ic, &tmp) tmp.Mul(&fqo, &o) ic.Add(&ic, &tmp).Add(&ic, &fqk) - tmp.Mul(&fqCPrime, &pi2) - ic.Add(&ic, &tmp) + nbComms := len(spr.CommitmentInfo) + for i := range spr.CommitmentInfo { + tmp.Mul(&pi2QcPrime[i], &pi2QcPrime[i+nbComms]) + ic.Add(&ic, &tmp) + } return ic } @@ -330,13 +329,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return one } - // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15 , 16 - // l , r , o, id, s1, s2, s3, z, zs, PI2, ql, qr, qm, qo, qk, qCPrime, lone + // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm + // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, PI2 , qCPrime fm := func(x ...fr.Element) fr.Element { - a := fic(x[10], x[11], x[12], x[13], x[14], x[15], x[0], x[1], x[2], x[9]) + a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2], x[15:]) b := fo(x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8]) - c := fone(x[7], x[16]) + c := fone(x[7], x[14]) c.Mul(&c, &alpha).Add(&c, &b).Mul(&c, &alpha).Add(&c, &a) @@ -354,7 +353,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // wait for l, r o lagrange coset conversion wgLRO.Wait() - systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, + toEval := []*iop.Polynomial{ bwliop, bwriop, bwoiop, @@ -364,15 +363,16 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pk.lcS3, bwziop, bwsziop, - lcpi2iop, pk.lcQl, pk.lcQr, pk.lcQm, pk.lcQo, lcqk, - pk.lcQcp, pk.lLoneIOP, - ) + } + toEval = append(toEval, lcpi2iop...) // TODO: Add this at beginning + toEval = append(toEval, pk.lcQcp...) + systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, toEval...) if err != nil { return nil, err } @@ -404,10 +404,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // compute evaluations of (blinded version of) l, r, o, z, qCPrime at zeta - var blzeta, brzeta, bozeta, qcpzeta fr.Element + var blzeta, brzeta, bozeta fr.Element + qcpzeta := make([]fr.Element, len(spr.CommitmentInfo)) var wgEvals sync.WaitGroup - wgEvals.Add(4) + wgEvals.Add(3) evalAtZeta := func(poly *iop.Polynomial, res *fr.Element) { poly.ToCanonical(&pk.Domain[1]).ToRegular() *res = poly.Evaluate(zeta) @@ -416,10 +417,12 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts go evalAtZeta(bwliop, &blzeta) go evalAtZeta(bwriop, &brzeta) go evalAtZeta(bwoiop, &bozeta) - go func() { - qcpzeta = pk.trace.Qcp.Evaluate(zeta) - wgEvals.Done() - }() + evalQcpAtZeta := func(begin, end int) { + for i := begin; i < end; i++ { + qcpzeta[i] = pk.trace.Qcp[i].Evaluate(zeta) + } + } + utils.Parallelize(len(spr.CommitmentInfo), evalQcpAtZeta) var zetaShifted fr.Element zetaShifted.Mul(&zeta, &pk.Vk.Generator) @@ -490,7 +493,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bzuzeta, qcpzeta, bwziop.Coefficients()[:bwziop.BlindedSize()], - wpi2iop.Coefficients(), + coefficients(wpi2iop), pk, ) @@ -506,7 +509,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // Batch open the first list of polynomials proof.BatchedProof, err = kzg.BatchOpenSinglePoint( - [][]fr.Element{ + append(coefficients(pk.trace.Qcp), foldedH, linearizedPolynomialCanonical, bwliop.Coefficients()[:bwliop.BlindedSize()], @@ -514,9 +517,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.Coefficients()[:bwoiop.BlindedSize()], pk.trace.S1.Coefficients(), pk.trace.S2.Coefficients(), - pk.trace.Qcp.Coefficients(), - }, - []kzg.Digest{ + ), + append(pk.Vk.Qcp, foldedHDigest, linearizedPolynomialDigest, proof.LRO[0], @@ -524,8 +526,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.LRO[2], pk.Vk.S[0], pk.Vk.S[1], - pk.Vk.Qcp, - }, + ), zeta, hFunc, pk.Kzg, @@ -541,6 +542,14 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } +func coefficients(p []*iop.Polynomial) [][]fr.Element { + res := make([][]fr.Element, len(p)) + for i, pI := range p { + res[i] = pI.Coefficients() + } + return res +} + // fills proof.LRO with kzg commits of bcl, bcr and bco func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, kzgPk kzg.ProvingKey) error { n := runtime.NumCPU() @@ -605,7 +614,7 @@ func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, kzgPk kzg.ProvingKe // α²*L₁(ζ)*Z(X) // + α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*id1(ζ)+γ)*(r(ζ)+β*id2(ζ)+γ)*(o(ζ)+β*id3(ζ)+γ)) // + l(ζ)*Ql(X) + l(ζ)r(ζ)*Qm(X) + r(ζ)*Qr(X) + o(ζ)*Qo(X) + Qk(X) -func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu, qcpZeta fr.Element, blindedZCanonical []fr.Element, pi2Canonical []fr.Element, pk *ProvingKey) []fr.Element { +func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu fr.Element, qcpZeta, blindedZCanonical []fr.Element, pi2Canonical [][]fr.Element, pk *ProvingKey) []fr.Element { // first part: individual constraints var rl fr.Element @@ -688,8 +697,10 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, t0.Mul(&cqo[i], &oZeta).Add(&t0, &cqk[i]) t.Add(&t, &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) - t0.Mul(&pi2Canonical[i], &qcpZeta) - t.Add(&t, &t0) + for j := range qcpZeta { + t0.Mul(&pi2Canonical[j][i], &qcpZeta[j]) + t.Add(&t, &t0) + } } t0.Mul(&blindedZCanonical[i], &lagrangeZeta) diff --git a/backend/plonk/bls24-315/setup.go b/backend/plonk/bls24-315/setup.go index f8ad8640c3..27889b05f3 100644 --- a/backend/plonk/bls24-315/setup.go +++ b/backend/plonk/bls24-315/setup.go @@ -35,7 +35,8 @@ type Trace struct { // completed by the prover. At those indices i (so from 0 to nb_public_variables), LQl[i]=-1 // so the first nb_public_variables constraints look like this: // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. - Ql, Qr, Qm, Qo, Qk, Qcp *iop.Polynomial + Ql, Qr, Qm, Qo, Qk *iop.Polynomial + Qcp []*iop.Polynomial // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. // The set of interpolation is of size N, so to represent the permutation S we let S acts on the @@ -72,7 +73,8 @@ type VerifyingKey struct { // Commitments to ql, qr, qm, qo, qcp prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk, Qcp kzg.Digest + Ql, Qr, Qm, Qo, Qk kzg.Digest + Qcp []kzg.Digest CommitmentConstraintIndexes []uint64 } @@ -100,7 +102,8 @@ type ProvingKey struct { Vk *VerifyingKey // qr,ql,qm,qo,qcp in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo, Qcp once. - lcQl, lcQr, lcQm, lcQo, lcQcp *iop.Polynomial + lcQl, lcQr, lcQm, lcQo *iop.Polynomial + lcQcp []*iop.Polynomial // LQk qk in Lagrange form -> to be completed by the prover. After being completed, lQk *iop.Polynomial @@ -173,7 +176,10 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro // computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset // basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. func (pk *ProvingKey) computeLagrangeCosetPolys() { - pk.lcQcp = pk.trace.Qcp.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQcp = make([]*iop.Polynomial, len(pk.trace.Qcp)) + for i, qcpI := range pk.trace.Qcp { + pk.lcQcp[i] = qcpI.Clone().ToLagrangeCoset(&pk.Domain[1]) + } pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) @@ -226,7 +232,7 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qm := make([]fr.Element, size) qo := make([]fr.Element, size) qk := make([]fr.Element, size) - qcp := make([]fr.Element, size) + qcp := make([][]fr.Element, len(spr.CommitmentInfo)) for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent ql[i].SetOne().Neg(&ql[i]) @@ -248,12 +254,6 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { j++ } - if len(spr.CommitmentInfo) != 0 { - for _, committed := range spr.CommitmentInfo[0].Committed { - qcp[offset+committed].SetOne() - } - } - lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} pt.Ql = iop.NewPolynomial(&ql, lagReg) @@ -261,11 +261,18 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { pt.Qm = iop.NewPolynomial(&qm, lagReg) pt.Qo = iop.NewPolynomial(&qo, lagReg) pt.Qk = iop.NewPolynomial(&qk, lagReg) - pt.Qcp = iop.NewPolynomial(&qcp, lagReg) + pt.Qcp = make([]*iop.Polynomial, len(qcp)) + for i := range spr.CommitmentInfo { + qcp[i] = make([]fr.Element, size) + for _, committed := range spr.CommitmentInfo[i].Committed { + qcp[i][offset+committed].SetOne() + } + pt.Qcp[i] = iop.NewPolynomial(&qcp[i], lagReg) + } } -// commitTrace commits to every polynomials in the trace, and put +// commitTrace commits to every polynomial in the trace, and put // the commitments int the verifying key. func commitTrace(trace *Trace, pk *ProvingKey) error { @@ -274,12 +281,18 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { trace.Qm.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qo.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qk.ToCanonical(&pk.Domain[0]).ToRegular() // -> qk is not complete - trace.Qcp.ToCanonical(&pk.Domain[0]).ToRegular() trace.S1.ToCanonical(&pk.Domain[0]).ToRegular() trace.S2.ToCanonical(&pk.Domain[0]).ToRegular() trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() var err error + pk.Vk.Qcp = make([]kzg.Digest, len(trace.Qcp)) + for i := range trace.Qcp { + trace.Qcp[i].ToCanonical(&pk.Domain[0]).ToRegular() + if pk.Vk.Qcp[i], err = kzg.Commit(pk.trace.Qcp[i].Coefficients(), pk.Kzg); err != nil { + return err + } + } if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Kzg); err != nil { return err } @@ -295,9 +308,6 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Kzg); err != nil { - return err - } if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Kzg); err != nil { return err } diff --git a/backend/plonk/bls24-315/verify.go b/backend/plonk/bls24-315/verify.go index 5ebb3d533c..48557038d3 100644 --- a/backend/plonk/bls24-315/verify.go +++ b/backend/plonk/bls24-315/verify.go @@ -112,7 +112,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { for i := range vk.CommitmentConstraintIndexes { var hashRes []fr.Element // TODO: when multi commits are implemented: PI2 -> PI2[i] - if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + if hashRes, err = fr.Hash(proof.PI2[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } @@ -137,14 +137,16 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - claimedQuotient := proof.BatchedProof.ClaimedValues[0] - linearizedPolynomialZeta := proof.BatchedProof.ClaimedValues[1] - l := proof.BatchedProof.ClaimedValues[2] - r := proof.BatchedProof.ClaimedValues[3] - o := proof.BatchedProof.ClaimedValues[4] - s1 := proof.BatchedProof.ClaimedValues[5] - s2 := proof.BatchedProof.ClaimedValues[6] - qC := proof.BatchedProof.ClaimedValues[7] + qC := make([]fr.Element, len(proof.PI2)) + copy(qC, proof.BatchedProof.ClaimedValues) + claimedValues := proof.BatchedProof.ClaimedValues[len(proof.PI2):] + claimedQuotient := claimedValues[0] + linearizedPolynomialZeta := claimedValues[1] + l := claimedValues[2] + r := claimedValues[3] + o := claimedValues[4] + s1 := claimedValues[5] + s2 := claimedValues[6] _s1.Mul(&s1, &beta).Add(&_s1, &l).Add(&_s1, &gamma) // (l(ζ)+β*s1(ζ)+γ) _s2.Mul(&s2, &beta).Add(&_s2, &r).Add(&_s2, &gamma) // (r(ζ)+β*s2(ζ)+γ) @@ -213,21 +215,21 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // note since third part = α²*L₁(ζ)*Z _s2.Mul(&_s2, &alpha).Add(&_s2, &alphaSquareLagrange) // -α*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + α²*L₁(ζ) - points := []curve.G1Affine{ - vk.Ql, vk.Qr, vk.Qm, vk.Qo, vk.Qk, proof.PI2, // first part + points := append(proof.PI2, + vk.Ql, vk.Qr, vk.Qm, vk.Qo, vk.Qk, // first part vk.S[2], proof.Z, // second & third part - } + ) - scalars := []fr.Element{ - l, r, rl, o, one /* TODO Perf @Tabaie Consider just adding Qk instead */, qC, // first part + scalars := append(qC, + l, r, rl, o, one, /* TODO Perf @Tabaie Consider just adding Qk instead */ // first part _s1, _s2, // second & third part - } + ) if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{}); err != nil { return err } // Fold the first proof - foldedProof, foldedDigest, err := kzg.FoldProof([]kzg.Digest{ + foldedProof, foldedDigest, err := kzg.FoldProof(append(vk.Qcp, foldedH, linearizedPolynomialDigest, proof.LRO[0], @@ -235,8 +237,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { proof.LRO[2], vk.S[0], vk.S[1], - vk.Qcp, - }, + ), &proof.BatchedProof, zeta, hFunc, @@ -268,7 +269,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } -func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element, pi2 kzg.Digest) error { +func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element, pi2 []kzg.Digest) error { // permutation if err := fs.Bind(challenge, vk.S[0].Marshal()); err != nil { @@ -306,8 +307,10 @@ func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey } // bsb22 commitment - if err := fs.Bind(challenge, pi2.Marshal()); err != nil { - return err + for i := range pi2 { + if err := fs.Bind(challenge, pi2[i].Marshal()); err != nil { + return err + } } return nil diff --git a/backend/plonk/bls24-317/marshal.go b/backend/plonk/bls24-317/marshal.go index ca62827d78..0dbf089f51 100644 --- a/backend/plonk/bls24-317/marshal.go +++ b/backend/plonk/bls24-317/marshal.go @@ -19,9 +19,11 @@ package plonk import ( curve "github.com/consensys/gnark-crypto/ecc/bls24-317" - "errors" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" + + "errors" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/iop" + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/kzg" "io" ) @@ -50,7 +52,7 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - &proof.PI2, + proof.PI2, } for _, v := range toEncode { @@ -86,6 +88,10 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { } } + if proof.PI2 == nil { + proof.PI2 = []kzg.Digest{} + } + return dec.BytesRead(), nil } @@ -125,7 +131,7 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { pk.trace.Qm.Coefficients(), pk.trace.Qo.Coefficients(), pk.trace.Qk.Coefficients(), - pk.trace.Qcp.Coefficients(), + coefficients(pk.trace.Qcp), pk.lQk.Coefficients(), pk.trace.S1.Coefficients(), pk.trace.S2.Coefficients(), @@ -166,7 +172,8 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { dec := curve.NewDecoder(r) - var ql, qr, qm, qo, qk, qcp, lqk, s1, s2, s3 []fr.Element + var ql, qr, qm, qo, qk, lqk, s1, s2, s3 []fr.Element + var qcp [][]fr.Element toDecode := []interface{}{ &ql, &qr, @@ -193,11 +200,14 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) - pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + pk.trace.Qcp = make([]*iop.Polynomial, len(qcp)) + for i := range qcp { + pk.trace.Qcp[i] = iop.NewPolynomial(&qcp[i], canReg) + } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} pk.lQk = iop.NewPolynomial(&lqk, lagReg) @@ -234,7 +244,7 @@ func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*curve.Encoder)) (n &vk.Qm, &vk.Qo, &vk.Qk, - &vk.Qcp, + vk.Qcp, vk.CommitmentConstraintIndexes, } diff --git a/backend/plonk/bls24-317/marshal_test.go b/backend/plonk/bls24-317/marshal_test.go index 2c40412336..bc4ba341c1 100644 --- a/backend/plonk/bls24-317/marshal_test.go +++ b/backend/plonk/bls24-317/marshal_test.go @@ -121,7 +121,6 @@ func (pk *ProvingKey) randomize() { qo := randomScalars(n) qk := randomScalars(n) lqk := randomScalars(n) - qcp := randomScalars(n) s1 := randomScalars(n) s2 := randomScalars(n) s3 := randomScalars(n) @@ -132,11 +131,16 @@ func (pk *ProvingKey) randomize() { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) - pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + pk.trace.Qcp = make([]*iop.Polynomial, rand.Intn(4)) + for i := range pk.trace.Qcp { + qcp := randomScalars(rand.Intn(n / 4)) + pk.trace.Qcp[i] = iop.NewPolynomial(&qcp, canReg) + } + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) pk.trace.S[0] = -12 pk.trace.S[len(pk.trace.S)-1] = 8888 @@ -163,7 +167,7 @@ func (vk *VerifyingKey) randomize() { vk.Qm = randomPoint() vk.Qo = randomPoint() vk.Qk = randomPoint() - vk.Qcp = randomPoint() + vk.Qcp = randomPoints(rand.Intn(4)) } func (proof *Proof) randomize() { @@ -178,7 +182,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.PI2 = randomPoint() + proof.PI2 = randomPoints(rand.Intn(4)) } func randomPoint() curve.G1Affine { @@ -187,6 +191,14 @@ func randomPoint() curve.G1Affine { return r } +func randomPoints(n int) []curve.G1Affine { + res := make([]curve.G1Affine, n) + for i := range res { + res[i] = randomPoint() + } + return res +} + func randomScalars(n int) []fr.Element { v := make([]fr.Element, n) one := fr.One() diff --git a/backend/plonk/bls24-317/prove.go b/backend/plonk/bls24-317/prove.go index 85f0e7fb31..86b5a00765 100644 --- a/backend/plonk/bls24-317/prove.go +++ b/backend/plonk/bls24-317/prove.go @@ -55,7 +55,7 @@ type Proof struct { H [3]kzg.Digest // PI2, the BSB22 commitment - PI2 kzg.Digest + PI2 []kzg.Digest // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2, qCPrime BatchedProof kzg.BatchOpeningProof @@ -64,6 +64,39 @@ type Proof struct { ZShiftedOpening kzg.OpeningProof } +func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, wpi2iop []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { + return func(_ *big.Int, ins, outs []*big.Int) error { + pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + offset := spr.GetNbPublicVariables() + for i := range ins { + pi2[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) + } + var ( + err error + hashRes []fr.Element + ) + /*if _, err = pi2[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + return err + } + if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding + return err + }*/ + pi2iop := iop.NewPolynomial(&pi2, iop.Form{Basis: iop.Lagrange, Layout: iop.Regular}) + wpi2iop[commDepth] = pi2iop.ShallowClone() + wpi2iop[commDepth].ToCanonical(&pk.Domain[0]).ToRegular() + if proof.PI2[commDepth], err = kzg.Commit(wpi2iop[commDepth].Coefficients(), pk.Kzg); err != nil { + return err + } + if hashRes, err = fr.Hash(proof.PI2[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + return err + } + res.Set(&hashRes[0]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses + res.BigInt(outs[0]) + + return nil + } +} + func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", spr.GetNbConstraints()).Str("backend", "plonk").Logger() @@ -82,48 +115,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // result proof := &Proof{} - lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} - var ( - wpi2iop *iop.Polynomial // canonical - commitmentVal fr.Element // TODO @Tabaie get rid of this - ) - if len(spr.CommitmentInfo) != 0 { - opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[0].HintID, func(_ *big.Int, ins, outs []*big.Int) error { - pi2 := make([]fr.Element, pk.Domain[0].Cardinality) - offset := spr.GetNbPublicVariables() - for i := range ins { - pi2[offset+spr.CommitmentInfo[0].Committed[i]].SetBigInt(ins[i]) - } - var ( - err error - hashRes []fr.Element - ) - if _, err = pi2[offset+spr.CommitmentInfo[0].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. - return err - } - if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding - return err - } - pi2iop := iop.NewPolynomial(&pi2, lagReg) - wpi2iop = pi2iop.ShallowClone() - wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() - if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Kzg); err != nil { - return err - } - if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { - return err - } - commitmentVal = hashRes[0] // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses - commitmentVal.BigInt(outs[0]) - return nil - })) - } else { - // TODO Leaving pi2 in for testing. In the future, bypass when no commitment present - pi2 := make([]fr.Element, pk.Domain[0].Cardinality) - pi2iop := iop.NewPolynomial(&pi2, lagReg) - wpi2iop = pi2iop.ShallowClone() - // wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + commitmentVal := make([]fr.Element, len(spr.CommitmentInfo)) // TODO @Tabaie get rid of this + wpi2iop := make([]*iop.Polynomial, len(spr.CommitmentInfo)) + proof.PI2 = make([]kzg.Digest, len(spr.CommitmentInfo)) + for i := range spr.CommitmentInfo { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[i].HintID, + bsb22ComputeCommitmentHint(spr, pk, proof, wpi2iop, &commitmentVal[i], i))) } // query l, r, o in Lagrange basis, not blinded @@ -132,19 +130,17 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } // TODO @gbotrel deal with that conversion lazily - var lcpi2iop *iop.Polynomial - if len(spr.CommitmentInfo) != 0 { - lcpi2iop = wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form - } else { - coeffs := make([]fr.Element, pk.Domain[1].Cardinality) - lcpi2iop = iop.NewPolynomial(&coeffs, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.Regular}) + lcpi2iop := make([]*iop.Polynomial, len(wpi2iop)) + for i := range wpi2iop { + lcpi2iop[i] = wpi2iop[i].Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form } solution := _solution.(*cs.SparseR1CSSolution) evaluationLDomainSmall := []fr.Element(solution.L) evaluationRDomainSmall := []fr.Element(solution.R) evaluationODomainSmall := []fr.Element(solution.O) - // l, r o and blinded versions + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + // l, r, o and blinded versions var ( wliop, wriop, @@ -188,8 +184,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) - if len(spr.CommitmentInfo) != 0 { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[0].CommitmentIndex] = commitmentVal + for i := range spr.CommitmentInfo { + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[i].CommitmentIndex] = commitmentVal[i] } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -285,7 +281,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts }() // Full capture using latest gnark crypto... - fic := func(fql, fqr, fqm, fqo, fqk, fqCPrime, l, r, o, pi2 fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary + fic := func(fql, fqr, fqm, fqo, fqk, l, r, o fr.Element, pi2QcPrime []fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary var ic, tmp fr.Element @@ -296,8 +292,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ic.Add(&ic, &tmp) tmp.Mul(&fqo, &o) ic.Add(&ic, &tmp).Add(&ic, &fqk) - tmp.Mul(&fqCPrime, &pi2) - ic.Add(&ic, &tmp) + nbComms := len(spr.CommitmentInfo) + for i := range spr.CommitmentInfo { + tmp.Mul(&pi2QcPrime[i], &pi2QcPrime[i+nbComms]) + ic.Add(&ic, &tmp) + } return ic } @@ -330,13 +329,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return one } - // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15 , 16 - // l , r , o, id, s1, s2, s3, z, zs, PI2, ql, qr, qm, qo, qk, qCPrime, lone + // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm + // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, PI2 , qCPrime fm := func(x ...fr.Element) fr.Element { - a := fic(x[10], x[11], x[12], x[13], x[14], x[15], x[0], x[1], x[2], x[9]) + a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2], x[15:]) b := fo(x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8]) - c := fone(x[7], x[16]) + c := fone(x[7], x[14]) c.Mul(&c, &alpha).Add(&c, &b).Mul(&c, &alpha).Add(&c, &a) @@ -354,7 +353,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // wait for l, r o lagrange coset conversion wgLRO.Wait() - systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, + toEval := []*iop.Polynomial{ bwliop, bwriop, bwoiop, @@ -364,15 +363,16 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pk.lcS3, bwziop, bwsziop, - lcpi2iop, pk.lcQl, pk.lcQr, pk.lcQm, pk.lcQo, lcqk, - pk.lcQcp, pk.lLoneIOP, - ) + } + toEval = append(toEval, lcpi2iop...) // TODO: Add this at beginning + toEval = append(toEval, pk.lcQcp...) + systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, toEval...) if err != nil { return nil, err } @@ -404,10 +404,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // compute evaluations of (blinded version of) l, r, o, z, qCPrime at zeta - var blzeta, brzeta, bozeta, qcpzeta fr.Element + var blzeta, brzeta, bozeta fr.Element + qcpzeta := make([]fr.Element, len(spr.CommitmentInfo)) var wgEvals sync.WaitGroup - wgEvals.Add(4) + wgEvals.Add(3) evalAtZeta := func(poly *iop.Polynomial, res *fr.Element) { poly.ToCanonical(&pk.Domain[1]).ToRegular() *res = poly.Evaluate(zeta) @@ -416,10 +417,12 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts go evalAtZeta(bwliop, &blzeta) go evalAtZeta(bwriop, &brzeta) go evalAtZeta(bwoiop, &bozeta) - go func() { - qcpzeta = pk.trace.Qcp.Evaluate(zeta) - wgEvals.Done() - }() + evalQcpAtZeta := func(begin, end int) { + for i := begin; i < end; i++ { + qcpzeta[i] = pk.trace.Qcp[i].Evaluate(zeta) + } + } + utils.Parallelize(len(spr.CommitmentInfo), evalQcpAtZeta) var zetaShifted fr.Element zetaShifted.Mul(&zeta, &pk.Vk.Generator) @@ -490,7 +493,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bzuzeta, qcpzeta, bwziop.Coefficients()[:bwziop.BlindedSize()], - wpi2iop.Coefficients(), + coefficients(wpi2iop), pk, ) @@ -506,7 +509,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // Batch open the first list of polynomials proof.BatchedProof, err = kzg.BatchOpenSinglePoint( - [][]fr.Element{ + append(coefficients(pk.trace.Qcp), foldedH, linearizedPolynomialCanonical, bwliop.Coefficients()[:bwliop.BlindedSize()], @@ -514,9 +517,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.Coefficients()[:bwoiop.BlindedSize()], pk.trace.S1.Coefficients(), pk.trace.S2.Coefficients(), - pk.trace.Qcp.Coefficients(), - }, - []kzg.Digest{ + ), + append(pk.Vk.Qcp, foldedHDigest, linearizedPolynomialDigest, proof.LRO[0], @@ -524,8 +526,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.LRO[2], pk.Vk.S[0], pk.Vk.S[1], - pk.Vk.Qcp, - }, + ), zeta, hFunc, pk.Kzg, @@ -541,6 +542,14 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } +func coefficients(p []*iop.Polynomial) [][]fr.Element { + res := make([][]fr.Element, len(p)) + for i, pI := range p { + res[i] = pI.Coefficients() + } + return res +} + // fills proof.LRO with kzg commits of bcl, bcr and bco func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, kzgPk kzg.ProvingKey) error { n := runtime.NumCPU() @@ -605,7 +614,7 @@ func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, kzgPk kzg.ProvingKe // α²*L₁(ζ)*Z(X) // + α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*id1(ζ)+γ)*(r(ζ)+β*id2(ζ)+γ)*(o(ζ)+β*id3(ζ)+γ)) // + l(ζ)*Ql(X) + l(ζ)r(ζ)*Qm(X) + r(ζ)*Qr(X) + o(ζ)*Qo(X) + Qk(X) -func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu, qcpZeta fr.Element, blindedZCanonical []fr.Element, pi2Canonical []fr.Element, pk *ProvingKey) []fr.Element { +func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu fr.Element, qcpZeta, blindedZCanonical []fr.Element, pi2Canonical [][]fr.Element, pk *ProvingKey) []fr.Element { // first part: individual constraints var rl fr.Element @@ -688,8 +697,10 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, t0.Mul(&cqo[i], &oZeta).Add(&t0, &cqk[i]) t.Add(&t, &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) - t0.Mul(&pi2Canonical[i], &qcpZeta) - t.Add(&t, &t0) + for j := range qcpZeta { + t0.Mul(&pi2Canonical[j][i], &qcpZeta[j]) + t.Add(&t, &t0) + } } t0.Mul(&blindedZCanonical[i], &lagrangeZeta) diff --git a/backend/plonk/bls24-317/setup.go b/backend/plonk/bls24-317/setup.go index d15a30109f..b8407b4596 100644 --- a/backend/plonk/bls24-317/setup.go +++ b/backend/plonk/bls24-317/setup.go @@ -35,7 +35,8 @@ type Trace struct { // completed by the prover. At those indices i (so from 0 to nb_public_variables), LQl[i]=-1 // so the first nb_public_variables constraints look like this: // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. - Ql, Qr, Qm, Qo, Qk, Qcp *iop.Polynomial + Ql, Qr, Qm, Qo, Qk *iop.Polynomial + Qcp []*iop.Polynomial // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. // The set of interpolation is of size N, so to represent the permutation S we let S acts on the @@ -72,7 +73,8 @@ type VerifyingKey struct { // Commitments to ql, qr, qm, qo, qcp prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk, Qcp kzg.Digest + Ql, Qr, Qm, Qo, Qk kzg.Digest + Qcp []kzg.Digest CommitmentConstraintIndexes []uint64 } @@ -100,7 +102,8 @@ type ProvingKey struct { Vk *VerifyingKey // qr,ql,qm,qo,qcp in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo, Qcp once. - lcQl, lcQr, lcQm, lcQo, lcQcp *iop.Polynomial + lcQl, lcQr, lcQm, lcQo *iop.Polynomial + lcQcp []*iop.Polynomial // LQk qk in Lagrange form -> to be completed by the prover. After being completed, lQk *iop.Polynomial @@ -173,7 +176,10 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro // computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset // basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. func (pk *ProvingKey) computeLagrangeCosetPolys() { - pk.lcQcp = pk.trace.Qcp.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQcp = make([]*iop.Polynomial, len(pk.trace.Qcp)) + for i, qcpI := range pk.trace.Qcp { + pk.lcQcp[i] = qcpI.Clone().ToLagrangeCoset(&pk.Domain[1]) + } pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) @@ -226,7 +232,7 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qm := make([]fr.Element, size) qo := make([]fr.Element, size) qk := make([]fr.Element, size) - qcp := make([]fr.Element, size) + qcp := make([][]fr.Element, len(spr.CommitmentInfo)) for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent ql[i].SetOne().Neg(&ql[i]) @@ -248,12 +254,6 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { j++ } - if len(spr.CommitmentInfo) != 0 { - for _, committed := range spr.CommitmentInfo[0].Committed { - qcp[offset+committed].SetOne() - } - } - lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} pt.Ql = iop.NewPolynomial(&ql, lagReg) @@ -261,11 +261,18 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { pt.Qm = iop.NewPolynomial(&qm, lagReg) pt.Qo = iop.NewPolynomial(&qo, lagReg) pt.Qk = iop.NewPolynomial(&qk, lagReg) - pt.Qcp = iop.NewPolynomial(&qcp, lagReg) + pt.Qcp = make([]*iop.Polynomial, len(qcp)) + for i := range spr.CommitmentInfo { + qcp[i] = make([]fr.Element, size) + for _, committed := range spr.CommitmentInfo[i].Committed { + qcp[i][offset+committed].SetOne() + } + pt.Qcp[i] = iop.NewPolynomial(&qcp[i], lagReg) + } } -// commitTrace commits to every polynomials in the trace, and put +// commitTrace commits to every polynomial in the trace, and put // the commitments int the verifying key. func commitTrace(trace *Trace, pk *ProvingKey) error { @@ -274,12 +281,18 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { trace.Qm.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qo.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qk.ToCanonical(&pk.Domain[0]).ToRegular() // -> qk is not complete - trace.Qcp.ToCanonical(&pk.Domain[0]).ToRegular() trace.S1.ToCanonical(&pk.Domain[0]).ToRegular() trace.S2.ToCanonical(&pk.Domain[0]).ToRegular() trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() var err error + pk.Vk.Qcp = make([]kzg.Digest, len(trace.Qcp)) + for i := range trace.Qcp { + trace.Qcp[i].ToCanonical(&pk.Domain[0]).ToRegular() + if pk.Vk.Qcp[i], err = kzg.Commit(pk.trace.Qcp[i].Coefficients(), pk.Kzg); err != nil { + return err + } + } if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Kzg); err != nil { return err } @@ -295,9 +308,6 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Kzg); err != nil { - return err - } if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Kzg); err != nil { return err } diff --git a/backend/plonk/bls24-317/verify.go b/backend/plonk/bls24-317/verify.go index 9e4f8147a3..75bd3dc6a7 100644 --- a/backend/plonk/bls24-317/verify.go +++ b/backend/plonk/bls24-317/verify.go @@ -112,7 +112,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { for i := range vk.CommitmentConstraintIndexes { var hashRes []fr.Element // TODO: when multi commits are implemented: PI2 -> PI2[i] - if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + if hashRes, err = fr.Hash(proof.PI2[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } @@ -137,14 +137,16 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - claimedQuotient := proof.BatchedProof.ClaimedValues[0] - linearizedPolynomialZeta := proof.BatchedProof.ClaimedValues[1] - l := proof.BatchedProof.ClaimedValues[2] - r := proof.BatchedProof.ClaimedValues[3] - o := proof.BatchedProof.ClaimedValues[4] - s1 := proof.BatchedProof.ClaimedValues[5] - s2 := proof.BatchedProof.ClaimedValues[6] - qC := proof.BatchedProof.ClaimedValues[7] + qC := make([]fr.Element, len(proof.PI2)) + copy(qC, proof.BatchedProof.ClaimedValues) + claimedValues := proof.BatchedProof.ClaimedValues[len(proof.PI2):] + claimedQuotient := claimedValues[0] + linearizedPolynomialZeta := claimedValues[1] + l := claimedValues[2] + r := claimedValues[3] + o := claimedValues[4] + s1 := claimedValues[5] + s2 := claimedValues[6] _s1.Mul(&s1, &beta).Add(&_s1, &l).Add(&_s1, &gamma) // (l(ζ)+β*s1(ζ)+γ) _s2.Mul(&s2, &beta).Add(&_s2, &r).Add(&_s2, &gamma) // (r(ζ)+β*s2(ζ)+γ) @@ -213,21 +215,21 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // note since third part = α²*L₁(ζ)*Z _s2.Mul(&_s2, &alpha).Add(&_s2, &alphaSquareLagrange) // -α*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + α²*L₁(ζ) - points := []curve.G1Affine{ - vk.Ql, vk.Qr, vk.Qm, vk.Qo, vk.Qk, proof.PI2, // first part + points := append(proof.PI2, + vk.Ql, vk.Qr, vk.Qm, vk.Qo, vk.Qk, // first part vk.S[2], proof.Z, // second & third part - } + ) - scalars := []fr.Element{ - l, r, rl, o, one /* TODO Perf @Tabaie Consider just adding Qk instead */, qC, // first part + scalars := append(qC, + l, r, rl, o, one, /* TODO Perf @Tabaie Consider just adding Qk instead */ // first part _s1, _s2, // second & third part - } + ) if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{}); err != nil { return err } // Fold the first proof - foldedProof, foldedDigest, err := kzg.FoldProof([]kzg.Digest{ + foldedProof, foldedDigest, err := kzg.FoldProof(append(vk.Qcp, foldedH, linearizedPolynomialDigest, proof.LRO[0], @@ -235,8 +237,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { proof.LRO[2], vk.S[0], vk.S[1], - vk.Qcp, - }, + ), &proof.BatchedProof, zeta, hFunc, @@ -268,7 +269,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } -func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element, pi2 kzg.Digest) error { +func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element, pi2 []kzg.Digest) error { // permutation if err := fs.Bind(challenge, vk.S[0].Marshal()); err != nil { @@ -306,8 +307,10 @@ func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey } // bsb22 commitment - if err := fs.Bind(challenge, pi2.Marshal()); err != nil { - return err + for i := range pi2 { + if err := fs.Bind(challenge, pi2[i].Marshal()); err != nil { + return err + } } return nil diff --git a/backend/plonk/bn254/marshal.go b/backend/plonk/bn254/marshal.go index 38dceb2844..cb55a1f95c 100644 --- a/backend/plonk/bn254/marshal.go +++ b/backend/plonk/bn254/marshal.go @@ -17,13 +17,13 @@ package plonk import ( - "fmt" curve "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark-crypto/ecc/bn254/fr/kzg" - "errors" "github.com/consensys/gnark-crypto/ecc/bn254/fr" + + "errors" "github.com/consensys/gnark-crypto/ecc/bn254/fr/iop" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/kzg" "io" ) @@ -38,11 +38,6 @@ func (proof *Proof) WriteTo(w io.Writer) (int64, error) { } func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64, error) { - pi2 := make([]curve.G1Affine, len(proof.PI2)) - for i := range pi2 { - pi2[i] = proof.PI2[i] - } - enc := curve.NewEncoder(w, options...) toEncode := []interface{}{ @@ -57,7 +52,7 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - pi2, + proof.PI2, } for _, v := range toEncode { @@ -71,11 +66,6 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 // ReadFrom reads binary representation of Proof from r func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { - - var pi2 []curve.G1Affine - - pi2 = make([]curve.G1Affine, 1) // TODO Remove - dec := curve.NewDecoder(r) toDecode := []interface{}{ &proof.LRO[0], @@ -89,19 +79,17 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { &proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - &pi2[0], // TODO Remove index + &proof.PI2, } - for i, v := range toDecode { + for _, v := range toDecode { if err := dec.Decode(v); err != nil { - fmt.Println("error at", i) return dec.BytesRead(), err } } - proof.PI2 = make([]kzg.Digest, len(pi2)) - for i := range pi2 { - proof.PI2[i] = pi2[i] + if proof.PI2 == nil { + proof.PI2 = []kzg.Digest{} } return dec.BytesRead(), nil @@ -220,7 +208,6 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { for i := range qcp { pk.trace.Qcp[i] = iop.NewPolynomial(&qcp[i], canReg) } - lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} pk.lQk = iop.NewPolynomial(&lqk, lagReg) @@ -262,9 +249,6 @@ func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*curve.Encoder)) (n } for _, v := range toEncode { - if v == &vk.Qcp { - fmt.Println("yo") - } if err := enc.Encode(v); err != nil { return enc.BytesWritten(), err } diff --git a/backend/plonk/bn254/marshal_test.go b/backend/plonk/bn254/marshal_test.go index 9f88f1610f..dab23970d6 100644 --- a/backend/plonk/bn254/marshal_test.go +++ b/backend/plonk/bn254/marshal_test.go @@ -140,7 +140,6 @@ func (pk *ProvingKey) randomize() { qcp := randomScalars(rand.Intn(n / 4)) pk.trace.Qcp[i] = iop.NewPolynomial(&qcp, canReg) } - //pk.trace.Qcp = []*iop.Polynomial{} // TODO Remove pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) pk.trace.S[0] = -12 diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index b40013ed2e..7a0f25eac4 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -17,11 +17,7 @@ package plonk import ( - "bytes" "crypto/sha256" - "encoding/base64" - "fmt" - "github.com/google/go-cmp/cmp" "math/big" "runtime" "sync" @@ -97,8 +93,6 @@ func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof res.Set(&hashRes[0]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses res.BigInt(outs[0]) - fmt.Println("computed commitment =", outs[0].Text(16)) - return nil } } @@ -135,22 +129,18 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts if err != nil { return nil, err } - // TODO @gbotrel deal with that conversion lazily lcpi2iop := make([]*iop.Polynomial, len(wpi2iop)) for i := range wpi2iop { lcpi2iop[i] = wpi2iop[i].Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form - fmt.Println("lcp2iop =", fr.Vector(lcpi2iop[i].Coefficients()).String()) } solution := _solution.(*cs.SparseR1CSSolution) evaluationLDomainSmall := []fr.Element(solution.L) evaluationRDomainSmall := []fr.Element(solution.R) evaluationODomainSmall := []fr.Element(solution.O) - printSol(solution) - lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} - // l, r o and blinded versions + // l, r, o and blinded versions var ( wliop, wriop, @@ -165,17 +155,17 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // we keep in lagrange regular form since iop.BuildRatioCopyConstraint prefers it in this form. wliop = iop.NewPolynomial(&evaluationLDomainSmall, lagReg) // we set the underlying slice capacity to domain[1].Cardinality to minimize mem moves. - bwliop = wliop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular() //.Blind(1) + bwliop = wliop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) wgLRO.Done() }() go func() { wriop = iop.NewPolynomial(&evaluationRDomainSmall, lagReg) - bwriop = wriop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular() //.Blind(1) + bwriop = wriop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) wgLRO.Done() }() go func() { woiop = iop.NewPolynomial(&evaluationODomainSmall, lagReg) - bwoiop = woiop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular() //.Blind(1) + bwoiop = woiop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) wgLRO.Done() }() @@ -231,7 +221,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } var beta fr.Element beta.SetBytes(bbeta) - beta.SetZero() // l, r, o are already blinded wgLRO.Add(3) @@ -272,7 +261,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts var alpha fr.Element go func() { bwziop = ziop // iop.NewWrappedPolynomial(&ziop) - //bwziop.Blind(2) + bwziop.Blind(2) proof.Z, err = kzg.Commit(bwziop.Coefficients(), pk.Kzg, runtime.NumCPU()*2) if err != nil { chZ <- err @@ -303,7 +292,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ic.Add(&ic, &tmp) tmp.Mul(&fqo, &o) ic.Add(&ic, &tmp).Add(&ic, &fqk) - nbComms := len(spr.CommitmentInfo) for i := range spr.CommitmentInfo { tmp.Mul(&pi2QcPrime[i], &pi2QcPrime[i+nbComms]) @@ -365,8 +353,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // wait for l, r o lagrange coset conversion wgLRO.Wait() - fmt.Println("lagrange bwliop before batch eval =", fr.Vector(bwliop.Coefficients()).String()) - toEval := []*iop.Polynomial{ bwliop, bwriop, @@ -424,20 +410,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts var wgEvals sync.WaitGroup wgEvals.Add(3) evalAtZeta := func(poly *iop.Polynomial, res *fr.Element) { - if poly == bwliop { - fmt.Println("lagrange bwliop =", fr.Vector(bwliop.Coefficients()).String()) - } poly.ToCanonical(&pk.Domain[1]).ToRegular() - if poly == bwliop { - fmt.Println("canonical bwliop =", fr.Vector(bwliop.Coefficients()).String()) - } *res = poly.Evaluate(zeta) wgEvals.Done() } go evalAtZeta(bwliop, &blzeta) go evalAtZeta(bwriop, &brzeta) go evalAtZeta(bwoiop, &bozeta) - evalQcpAtZeta := func(begin, end int) { for i := begin; i < end; i++ { qcpzeta[i] = pk.trace.Qcp[i].Evaluate(zeta) @@ -497,11 +476,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts errLPoly error ) - fmt.Println("blzeta =", blzeta.Text(16)) - // blinded z evaluated at u*zeta bzuzeta := proof.ZShiftedOpening.ClaimedValue - fmt.Println("bzuzeta =", bzuzeta.Text(16)) + // compute the linearization polynomial r at zeta // (goal: save committing separately to z, ql, qr, qm, qo, k // note: we linearizedPolynomialCanonical reuses bwziop memory @@ -561,26 +538,10 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } - var goodB []byte - if goodB, err = base64.StdEncoding.DecodeString("hJl1Q3FUFttoNHBC1k42rGbUucAJ7eYJr3KDacCqby7H7J7uMGsM3GGuijBTNS7MP5LSoIarvlcuiox2QHoIVJwk464j2CsfiL3IYn3uooZ8yLWOhq6EdfRLoq3WynmOgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHmf0pEcTp/MMXyWlSfiLUi5DpFdl0JQs0b1apQb35IwUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADBCZLn7wU6waYNfji19EaLiHcUED4EXq5AzE1SvSZpXgAAAAgkSzrWKOU4H0o8NEjhIQJF3ibuNltLFGzy6Xgu9AAAAQdW1JVBMTyCInUD2DaU/wthD0kWpBC0dxVCXds7pMM0LYhjh7N9T4U4TaPwirHhwb0uLXEEE5ydUOsoypaE5JADS7B3MMzQLTmhFzN7D+JEKNa+B2gJYrkoeDm85b9eGxtVZ4IB62BkBVdwJGGV8WXyE9G3/nVTZq5SVgsvrLB7E7c9j10b5Dc5tcDJAPsjvp4QZeUOcdfFf6VpuBXWWD4YMic5cJjQGWynnFlri8PvvXlpteSj1nn3OJov66afpzBkTnLhMaApi18PzzEXEob1YXd0GqfvZ/ut+UsX3A2JQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcFEUCi4DHArBKbdB3F8kbGpWFSfTyGDMApxQh+FOhSs"); err != nil { - panic(err) - } - var goodProof Proof - if _, err = goodProof.ReadFrom(bytes.NewReader(goodB)); err != nil { - panic(err) - } - fmt.Println("proof diff =", cmp.Diff(*proof, goodProof)) - return proof, nil } -func printSol(solution *cs.SparseR1CSSolution) { - fmt.Println("Solution L:", solution.L.String()) - fmt.Println("Solution R:", solution.L.String()) - fmt.Println("Solution O:", solution.L.String()) -} - func coefficients(p []*iop.Polynomial) [][]fr.Element { res := make([][]fr.Element, len(p)) for i, pI := range p { @@ -655,17 +616,6 @@ func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, kzgPk kzg.ProvingKe // + l(ζ)*Ql(X) + l(ζ)r(ζ)*Qm(X) + r(ζ)*Qr(X) + o(ζ)*Qo(X) + Qk(X) func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu fr.Element, qcpZeta, blindedZCanonical []fr.Element, pi2Canonical [][]fr.Element, pk *ProvingKey) []fr.Element { - fmt.Println("lZeta =", lZeta.Text(16)) - fmt.Println("rZeta =", rZeta.Text(16)) - fmt.Println("oZeta =", oZeta.Text(16)) - fmt.Println("alpha =", alpha.Text(16)) - fmt.Println("beta =", beta.Text(16)) - fmt.Println("gamma =", gamma.Text(16)) - fmt.Println("zeta =", zeta.Text(16)) - fmt.Println("zu =", zu.Text(16)) - //fmt.Println("qcpZeta =", lZeta.Text(16)) - //fmt.Println("beta =", lZeta.Text(16)) - // first part: individual constraints var rl fr.Element rl.Mul(&rZeta, &lZeta) @@ -755,8 +705,6 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, t0.Mul(&blindedZCanonical[i], &lagrangeZeta) blindedZCanonical[i].Add(&t, &t0) // finish the computation - - fmt.Printf("linPoly[%d] = %s\n", i, blindedZCanonical[i].Text(16)) } }) return blindedZCanonical diff --git a/backend/plonk/bn254/setup.go b/backend/plonk/bn254/setup.go index c44f4a9aa1..680f6c5f46 100644 --- a/backend/plonk/bn254/setup.go +++ b/backend/plonk/bn254/setup.go @@ -308,7 +308,6 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Kzg); err != nil { return err } diff --git a/backend/plonk/bn254/verify.go b/backend/plonk/bn254/verify.go index 351f6b9d7e..d00e03fadc 100644 --- a/backend/plonk/bn254/verify.go +++ b/backend/plonk/bn254/verify.go @@ -19,7 +19,6 @@ package plonk import ( "crypto/sha256" "errors" - "fmt" "io" "math/big" "time" @@ -42,9 +41,6 @@ var ( ) func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { - - kzg.DiffWithGoodClaimed(proof.BatchedProof.ClaimedValues) - log := logger.Logger().With().Str("curve", "bn254").Str("backend", "plonk").Logger() start := time.Now() @@ -138,8 +134,6 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } } - fmt.Println("pi =", pi.Text(16)) - // linearizedpolynomial + pi(ζ) + α*(Z(μζ))*(l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*(o(ζ)+γ) - α²*L₁(ζ) var _s1, _s2, _o, alphaSquareLagrange fr.Element @@ -156,8 +150,6 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { s1 := claimedValues[5] s2 := claimedValues[6] - kzg.DiffWithGoodClaimed(proof.BatchedProof.ClaimedValues) - _s1.Mul(&s1, &beta).Add(&_s1, &l).Add(&_s1, &gamma) // (l(ζ)+β*s1(ζ)+γ) _s2.Mul(&s2, &beta).Add(&_s2, &r).Add(&_s2, &gamma) // (r(ζ)+β*s2(ζ)+γ) _o.Add(&o, &gamma) // (o(ζ)+γ) @@ -180,10 +172,6 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zetaPowerMMinusOne.Sub(&zetaPowerM, &one) linearizedPolynomialZeta.Div(&linearizedPolynomialZeta, &zetaPowerMMinusOne) - fmt.Println("claimed quotient =", claimedQuotient.Text(16)) - fmt.Println("computed quotient =", linearizedPolynomialZeta.Text(16)) - kzg.DiffWithGoodClaimed(proof.BatchedProof.ClaimedValues) - // check that H(ζ) is as claimed if !claimedQuotient.Equal(&linearizedPolynomialZeta) { return errWrongClaimedQuotient @@ -234,7 +222,6 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { vk.S[2], proof.Z, // second & third part ) - kzg.DiffWithGoodClaimed(proof.BatchedProof.ClaimedValues) scalars := append(qC, l, r, rl, o, one, /* TODO Perf @Tabaie Consider just adding Qk instead */ // first part _s1, _s2, // second & third part @@ -242,10 +229,6 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{}); err != nil { return err } - fmt.Println("multiexp") - kzg.DiffWithGoodClaimed(proof.BatchedProof.ClaimedValues) - fmt.Println("linearizedPolynomialDigest =", linearizedPolynomialDigest.String()) - fmt.Println("foldedH =", foldedH.String()) // Fold the first proof foldedProof, foldedDigest, err := kzg.FoldProof(append(vk.Qcp, @@ -268,9 +251,6 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // Batch verify var shiftedZeta fr.Element shiftedZeta.Mul(&zeta, &vk.Generator) - - fmt.Println("foldedDigest =", foldedDigest.String()) - err = kzg.BatchVerifyMultiPoints([]kzg.Digest{ foldedDigest, proof.Z, @@ -355,7 +335,6 @@ func deriveRandomness(fs *fiatshamir.Transcript, challenge string, points ...*cu if err != nil { return r, err } - return r, nil r.SetBytes(b) return r, nil } diff --git a/backend/plonk/bw6-633/marshal.go b/backend/plonk/bw6-633/marshal.go index f4d4f25461..599c3ca398 100644 --- a/backend/plonk/bw6-633/marshal.go +++ b/backend/plonk/bw6-633/marshal.go @@ -19,9 +19,11 @@ package plonk import ( curve "github.com/consensys/gnark-crypto/ecc/bw6-633" - "errors" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" + + "errors" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/iop" + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/kzg" "io" ) @@ -50,7 +52,7 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - &proof.PI2, + proof.PI2, } for _, v := range toEncode { @@ -86,6 +88,10 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { } } + if proof.PI2 == nil { + proof.PI2 = []kzg.Digest{} + } + return dec.BytesRead(), nil } @@ -125,7 +131,7 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { pk.trace.Qm.Coefficients(), pk.trace.Qo.Coefficients(), pk.trace.Qk.Coefficients(), - pk.trace.Qcp.Coefficients(), + coefficients(pk.trace.Qcp), pk.lQk.Coefficients(), pk.trace.S1.Coefficients(), pk.trace.S2.Coefficients(), @@ -166,7 +172,8 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { dec := curve.NewDecoder(r) - var ql, qr, qm, qo, qk, qcp, lqk, s1, s2, s3 []fr.Element + var ql, qr, qm, qo, qk, lqk, s1, s2, s3 []fr.Element + var qcp [][]fr.Element toDecode := []interface{}{ &ql, &qr, @@ -193,11 +200,14 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) - pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + pk.trace.Qcp = make([]*iop.Polynomial, len(qcp)) + for i := range qcp { + pk.trace.Qcp[i] = iop.NewPolynomial(&qcp[i], canReg) + } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} pk.lQk = iop.NewPolynomial(&lqk, lagReg) @@ -234,7 +244,7 @@ func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*curve.Encoder)) (n &vk.Qm, &vk.Qo, &vk.Qk, - &vk.Qcp, + vk.Qcp, vk.CommitmentConstraintIndexes, } diff --git a/backend/plonk/bw6-633/marshal_test.go b/backend/plonk/bw6-633/marshal_test.go index 04f36f8945..4f025edf9c 100644 --- a/backend/plonk/bw6-633/marshal_test.go +++ b/backend/plonk/bw6-633/marshal_test.go @@ -121,7 +121,6 @@ func (pk *ProvingKey) randomize() { qo := randomScalars(n) qk := randomScalars(n) lqk := randomScalars(n) - qcp := randomScalars(n) s1 := randomScalars(n) s2 := randomScalars(n) s3 := randomScalars(n) @@ -132,11 +131,16 @@ func (pk *ProvingKey) randomize() { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) - pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + pk.trace.Qcp = make([]*iop.Polynomial, rand.Intn(4)) + for i := range pk.trace.Qcp { + qcp := randomScalars(rand.Intn(n / 4)) + pk.trace.Qcp[i] = iop.NewPolynomial(&qcp, canReg) + } + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) pk.trace.S[0] = -12 pk.trace.S[len(pk.trace.S)-1] = 8888 @@ -163,7 +167,7 @@ func (vk *VerifyingKey) randomize() { vk.Qm = randomPoint() vk.Qo = randomPoint() vk.Qk = randomPoint() - vk.Qcp = randomPoint() + vk.Qcp = randomPoints(rand.Intn(4)) } func (proof *Proof) randomize() { @@ -178,7 +182,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.PI2 = randomPoint() + proof.PI2 = randomPoints(rand.Intn(4)) } func randomPoint() curve.G1Affine { @@ -187,6 +191,14 @@ func randomPoint() curve.G1Affine { return r } +func randomPoints(n int) []curve.G1Affine { + res := make([]curve.G1Affine, n) + for i := range res { + res[i] = randomPoint() + } + return res +} + func randomScalars(n int) []fr.Element { v := make([]fr.Element, n) one := fr.One() diff --git a/backend/plonk/bw6-633/prove.go b/backend/plonk/bw6-633/prove.go index dd2fea5f3e..6e689fd24c 100644 --- a/backend/plonk/bw6-633/prove.go +++ b/backend/plonk/bw6-633/prove.go @@ -55,7 +55,7 @@ type Proof struct { H [3]kzg.Digest // PI2, the BSB22 commitment - PI2 kzg.Digest + PI2 []kzg.Digest // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2, qCPrime BatchedProof kzg.BatchOpeningProof @@ -64,6 +64,39 @@ type Proof struct { ZShiftedOpening kzg.OpeningProof } +func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, wpi2iop []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { + return func(_ *big.Int, ins, outs []*big.Int) error { + pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + offset := spr.GetNbPublicVariables() + for i := range ins { + pi2[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) + } + var ( + err error + hashRes []fr.Element + ) + /*if _, err = pi2[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + return err + } + if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding + return err + }*/ + pi2iop := iop.NewPolynomial(&pi2, iop.Form{Basis: iop.Lagrange, Layout: iop.Regular}) + wpi2iop[commDepth] = pi2iop.ShallowClone() + wpi2iop[commDepth].ToCanonical(&pk.Domain[0]).ToRegular() + if proof.PI2[commDepth], err = kzg.Commit(wpi2iop[commDepth].Coefficients(), pk.Kzg); err != nil { + return err + } + if hashRes, err = fr.Hash(proof.PI2[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + return err + } + res.Set(&hashRes[0]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses + res.BigInt(outs[0]) + + return nil + } +} + func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", spr.GetNbConstraints()).Str("backend", "plonk").Logger() @@ -82,48 +115,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // result proof := &Proof{} - lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} - var ( - wpi2iop *iop.Polynomial // canonical - commitmentVal fr.Element // TODO @Tabaie get rid of this - ) - if len(spr.CommitmentInfo) != 0 { - opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[0].HintID, func(_ *big.Int, ins, outs []*big.Int) error { - pi2 := make([]fr.Element, pk.Domain[0].Cardinality) - offset := spr.GetNbPublicVariables() - for i := range ins { - pi2[offset+spr.CommitmentInfo[0].Committed[i]].SetBigInt(ins[i]) - } - var ( - err error - hashRes []fr.Element - ) - if _, err = pi2[offset+spr.CommitmentInfo[0].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. - return err - } - if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding - return err - } - pi2iop := iop.NewPolynomial(&pi2, lagReg) - wpi2iop = pi2iop.ShallowClone() - wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() - if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Kzg); err != nil { - return err - } - if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { - return err - } - commitmentVal = hashRes[0] // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses - commitmentVal.BigInt(outs[0]) - return nil - })) - } else { - // TODO Leaving pi2 in for testing. In the future, bypass when no commitment present - pi2 := make([]fr.Element, pk.Domain[0].Cardinality) - pi2iop := iop.NewPolynomial(&pi2, lagReg) - wpi2iop = pi2iop.ShallowClone() - // wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + commitmentVal := make([]fr.Element, len(spr.CommitmentInfo)) // TODO @Tabaie get rid of this + wpi2iop := make([]*iop.Polynomial, len(spr.CommitmentInfo)) + proof.PI2 = make([]kzg.Digest, len(spr.CommitmentInfo)) + for i := range spr.CommitmentInfo { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[i].HintID, + bsb22ComputeCommitmentHint(spr, pk, proof, wpi2iop, &commitmentVal[i], i))) } // query l, r, o in Lagrange basis, not blinded @@ -132,19 +130,17 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } // TODO @gbotrel deal with that conversion lazily - var lcpi2iop *iop.Polynomial - if len(spr.CommitmentInfo) != 0 { - lcpi2iop = wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form - } else { - coeffs := make([]fr.Element, pk.Domain[1].Cardinality) - lcpi2iop = iop.NewPolynomial(&coeffs, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.Regular}) + lcpi2iop := make([]*iop.Polynomial, len(wpi2iop)) + for i := range wpi2iop { + lcpi2iop[i] = wpi2iop[i].Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form } solution := _solution.(*cs.SparseR1CSSolution) evaluationLDomainSmall := []fr.Element(solution.L) evaluationRDomainSmall := []fr.Element(solution.R) evaluationODomainSmall := []fr.Element(solution.O) - // l, r o and blinded versions + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + // l, r, o and blinded versions var ( wliop, wriop, @@ -188,8 +184,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) - if len(spr.CommitmentInfo) != 0 { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[0].CommitmentIndex] = commitmentVal + for i := range spr.CommitmentInfo { + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[i].CommitmentIndex] = commitmentVal[i] } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -285,7 +281,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts }() // Full capture using latest gnark crypto... - fic := func(fql, fqr, fqm, fqo, fqk, fqCPrime, l, r, o, pi2 fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary + fic := func(fql, fqr, fqm, fqo, fqk, l, r, o fr.Element, pi2QcPrime []fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary var ic, tmp fr.Element @@ -296,8 +292,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ic.Add(&ic, &tmp) tmp.Mul(&fqo, &o) ic.Add(&ic, &tmp).Add(&ic, &fqk) - tmp.Mul(&fqCPrime, &pi2) - ic.Add(&ic, &tmp) + nbComms := len(spr.CommitmentInfo) + for i := range spr.CommitmentInfo { + tmp.Mul(&pi2QcPrime[i], &pi2QcPrime[i+nbComms]) + ic.Add(&ic, &tmp) + } return ic } @@ -330,13 +329,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return one } - // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15 , 16 - // l , r , o, id, s1, s2, s3, z, zs, PI2, ql, qr, qm, qo, qk, qCPrime, lone + // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm + // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, PI2 , qCPrime fm := func(x ...fr.Element) fr.Element { - a := fic(x[10], x[11], x[12], x[13], x[14], x[15], x[0], x[1], x[2], x[9]) + a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2], x[15:]) b := fo(x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8]) - c := fone(x[7], x[16]) + c := fone(x[7], x[14]) c.Mul(&c, &alpha).Add(&c, &b).Mul(&c, &alpha).Add(&c, &a) @@ -354,7 +353,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // wait for l, r o lagrange coset conversion wgLRO.Wait() - systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, + toEval := []*iop.Polynomial{ bwliop, bwriop, bwoiop, @@ -364,15 +363,16 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pk.lcS3, bwziop, bwsziop, - lcpi2iop, pk.lcQl, pk.lcQr, pk.lcQm, pk.lcQo, lcqk, - pk.lcQcp, pk.lLoneIOP, - ) + } + toEval = append(toEval, lcpi2iop...) // TODO: Add this at beginning + toEval = append(toEval, pk.lcQcp...) + systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, toEval...) if err != nil { return nil, err } @@ -404,10 +404,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // compute evaluations of (blinded version of) l, r, o, z, qCPrime at zeta - var blzeta, brzeta, bozeta, qcpzeta fr.Element + var blzeta, brzeta, bozeta fr.Element + qcpzeta := make([]fr.Element, len(spr.CommitmentInfo)) var wgEvals sync.WaitGroup - wgEvals.Add(4) + wgEvals.Add(3) evalAtZeta := func(poly *iop.Polynomial, res *fr.Element) { poly.ToCanonical(&pk.Domain[1]).ToRegular() *res = poly.Evaluate(zeta) @@ -416,10 +417,12 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts go evalAtZeta(bwliop, &blzeta) go evalAtZeta(bwriop, &brzeta) go evalAtZeta(bwoiop, &bozeta) - go func() { - qcpzeta = pk.trace.Qcp.Evaluate(zeta) - wgEvals.Done() - }() + evalQcpAtZeta := func(begin, end int) { + for i := begin; i < end; i++ { + qcpzeta[i] = pk.trace.Qcp[i].Evaluate(zeta) + } + } + utils.Parallelize(len(spr.CommitmentInfo), evalQcpAtZeta) var zetaShifted fr.Element zetaShifted.Mul(&zeta, &pk.Vk.Generator) @@ -490,7 +493,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bzuzeta, qcpzeta, bwziop.Coefficients()[:bwziop.BlindedSize()], - wpi2iop.Coefficients(), + coefficients(wpi2iop), pk, ) @@ -506,7 +509,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // Batch open the first list of polynomials proof.BatchedProof, err = kzg.BatchOpenSinglePoint( - [][]fr.Element{ + append(coefficients(pk.trace.Qcp), foldedH, linearizedPolynomialCanonical, bwliop.Coefficients()[:bwliop.BlindedSize()], @@ -514,9 +517,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.Coefficients()[:bwoiop.BlindedSize()], pk.trace.S1.Coefficients(), pk.trace.S2.Coefficients(), - pk.trace.Qcp.Coefficients(), - }, - []kzg.Digest{ + ), + append(pk.Vk.Qcp, foldedHDigest, linearizedPolynomialDigest, proof.LRO[0], @@ -524,8 +526,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.LRO[2], pk.Vk.S[0], pk.Vk.S[1], - pk.Vk.Qcp, - }, + ), zeta, hFunc, pk.Kzg, @@ -541,6 +542,14 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } +func coefficients(p []*iop.Polynomial) [][]fr.Element { + res := make([][]fr.Element, len(p)) + for i, pI := range p { + res[i] = pI.Coefficients() + } + return res +} + // fills proof.LRO with kzg commits of bcl, bcr and bco func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, kzgPk kzg.ProvingKey) error { n := runtime.NumCPU() @@ -605,7 +614,7 @@ func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, kzgPk kzg.ProvingKe // α²*L₁(ζ)*Z(X) // + α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*id1(ζ)+γ)*(r(ζ)+β*id2(ζ)+γ)*(o(ζ)+β*id3(ζ)+γ)) // + l(ζ)*Ql(X) + l(ζ)r(ζ)*Qm(X) + r(ζ)*Qr(X) + o(ζ)*Qo(X) + Qk(X) -func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu, qcpZeta fr.Element, blindedZCanonical []fr.Element, pi2Canonical []fr.Element, pk *ProvingKey) []fr.Element { +func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu fr.Element, qcpZeta, blindedZCanonical []fr.Element, pi2Canonical [][]fr.Element, pk *ProvingKey) []fr.Element { // first part: individual constraints var rl fr.Element @@ -688,8 +697,10 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, t0.Mul(&cqo[i], &oZeta).Add(&t0, &cqk[i]) t.Add(&t, &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) - t0.Mul(&pi2Canonical[i], &qcpZeta) - t.Add(&t, &t0) + for j := range qcpZeta { + t0.Mul(&pi2Canonical[j][i], &qcpZeta[j]) + t.Add(&t, &t0) + } } t0.Mul(&blindedZCanonical[i], &lagrangeZeta) diff --git a/backend/plonk/bw6-633/setup.go b/backend/plonk/bw6-633/setup.go index a84d4d334e..08f14b0c51 100644 --- a/backend/plonk/bw6-633/setup.go +++ b/backend/plonk/bw6-633/setup.go @@ -35,7 +35,8 @@ type Trace struct { // completed by the prover. At those indices i (so from 0 to nb_public_variables), LQl[i]=-1 // so the first nb_public_variables constraints look like this: // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. - Ql, Qr, Qm, Qo, Qk, Qcp *iop.Polynomial + Ql, Qr, Qm, Qo, Qk *iop.Polynomial + Qcp []*iop.Polynomial // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. // The set of interpolation is of size N, so to represent the permutation S we let S acts on the @@ -72,7 +73,8 @@ type VerifyingKey struct { // Commitments to ql, qr, qm, qo, qcp prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk, Qcp kzg.Digest + Ql, Qr, Qm, Qo, Qk kzg.Digest + Qcp []kzg.Digest CommitmentConstraintIndexes []uint64 } @@ -100,7 +102,8 @@ type ProvingKey struct { Vk *VerifyingKey // qr,ql,qm,qo,qcp in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo, Qcp once. - lcQl, lcQr, lcQm, lcQo, lcQcp *iop.Polynomial + lcQl, lcQr, lcQm, lcQo *iop.Polynomial + lcQcp []*iop.Polynomial // LQk qk in Lagrange form -> to be completed by the prover. After being completed, lQk *iop.Polynomial @@ -173,7 +176,10 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro // computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset // basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. func (pk *ProvingKey) computeLagrangeCosetPolys() { - pk.lcQcp = pk.trace.Qcp.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQcp = make([]*iop.Polynomial, len(pk.trace.Qcp)) + for i, qcpI := range pk.trace.Qcp { + pk.lcQcp[i] = qcpI.Clone().ToLagrangeCoset(&pk.Domain[1]) + } pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) @@ -226,7 +232,7 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qm := make([]fr.Element, size) qo := make([]fr.Element, size) qk := make([]fr.Element, size) - qcp := make([]fr.Element, size) + qcp := make([][]fr.Element, len(spr.CommitmentInfo)) for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent ql[i].SetOne().Neg(&ql[i]) @@ -248,12 +254,6 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { j++ } - if len(spr.CommitmentInfo) != 0 { - for _, committed := range spr.CommitmentInfo[0].Committed { - qcp[offset+committed].SetOne() - } - } - lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} pt.Ql = iop.NewPolynomial(&ql, lagReg) @@ -261,11 +261,18 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { pt.Qm = iop.NewPolynomial(&qm, lagReg) pt.Qo = iop.NewPolynomial(&qo, lagReg) pt.Qk = iop.NewPolynomial(&qk, lagReg) - pt.Qcp = iop.NewPolynomial(&qcp, lagReg) + pt.Qcp = make([]*iop.Polynomial, len(qcp)) + for i := range spr.CommitmentInfo { + qcp[i] = make([]fr.Element, size) + for _, committed := range spr.CommitmentInfo[i].Committed { + qcp[i][offset+committed].SetOne() + } + pt.Qcp[i] = iop.NewPolynomial(&qcp[i], lagReg) + } } -// commitTrace commits to every polynomials in the trace, and put +// commitTrace commits to every polynomial in the trace, and put // the commitments int the verifying key. func commitTrace(trace *Trace, pk *ProvingKey) error { @@ -274,12 +281,18 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { trace.Qm.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qo.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qk.ToCanonical(&pk.Domain[0]).ToRegular() // -> qk is not complete - trace.Qcp.ToCanonical(&pk.Domain[0]).ToRegular() trace.S1.ToCanonical(&pk.Domain[0]).ToRegular() trace.S2.ToCanonical(&pk.Domain[0]).ToRegular() trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() var err error + pk.Vk.Qcp = make([]kzg.Digest, len(trace.Qcp)) + for i := range trace.Qcp { + trace.Qcp[i].ToCanonical(&pk.Domain[0]).ToRegular() + if pk.Vk.Qcp[i], err = kzg.Commit(pk.trace.Qcp[i].Coefficients(), pk.Kzg); err != nil { + return err + } + } if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Kzg); err != nil { return err } @@ -295,9 +308,6 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Kzg); err != nil { - return err - } if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Kzg); err != nil { return err } diff --git a/backend/plonk/bw6-633/verify.go b/backend/plonk/bw6-633/verify.go index f17b725bdd..81a2f99b4f 100644 --- a/backend/plonk/bw6-633/verify.go +++ b/backend/plonk/bw6-633/verify.go @@ -112,7 +112,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { for i := range vk.CommitmentConstraintIndexes { var hashRes []fr.Element // TODO: when multi commits are implemented: PI2 -> PI2[i] - if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + if hashRes, err = fr.Hash(proof.PI2[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } @@ -137,14 +137,16 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - claimedQuotient := proof.BatchedProof.ClaimedValues[0] - linearizedPolynomialZeta := proof.BatchedProof.ClaimedValues[1] - l := proof.BatchedProof.ClaimedValues[2] - r := proof.BatchedProof.ClaimedValues[3] - o := proof.BatchedProof.ClaimedValues[4] - s1 := proof.BatchedProof.ClaimedValues[5] - s2 := proof.BatchedProof.ClaimedValues[6] - qC := proof.BatchedProof.ClaimedValues[7] + qC := make([]fr.Element, len(proof.PI2)) + copy(qC, proof.BatchedProof.ClaimedValues) + claimedValues := proof.BatchedProof.ClaimedValues[len(proof.PI2):] + claimedQuotient := claimedValues[0] + linearizedPolynomialZeta := claimedValues[1] + l := claimedValues[2] + r := claimedValues[3] + o := claimedValues[4] + s1 := claimedValues[5] + s2 := claimedValues[6] _s1.Mul(&s1, &beta).Add(&_s1, &l).Add(&_s1, &gamma) // (l(ζ)+β*s1(ζ)+γ) _s2.Mul(&s2, &beta).Add(&_s2, &r).Add(&_s2, &gamma) // (r(ζ)+β*s2(ζ)+γ) @@ -213,21 +215,21 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // note since third part = α²*L₁(ζ)*Z _s2.Mul(&_s2, &alpha).Add(&_s2, &alphaSquareLagrange) // -α*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + α²*L₁(ζ) - points := []curve.G1Affine{ - vk.Ql, vk.Qr, vk.Qm, vk.Qo, vk.Qk, proof.PI2, // first part + points := append(proof.PI2, + vk.Ql, vk.Qr, vk.Qm, vk.Qo, vk.Qk, // first part vk.S[2], proof.Z, // second & third part - } + ) - scalars := []fr.Element{ - l, r, rl, o, one /* TODO Perf @Tabaie Consider just adding Qk instead */, qC, // first part + scalars := append(qC, + l, r, rl, o, one, /* TODO Perf @Tabaie Consider just adding Qk instead */ // first part _s1, _s2, // second & third part - } + ) if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{}); err != nil { return err } // Fold the first proof - foldedProof, foldedDigest, err := kzg.FoldProof([]kzg.Digest{ + foldedProof, foldedDigest, err := kzg.FoldProof(append(vk.Qcp, foldedH, linearizedPolynomialDigest, proof.LRO[0], @@ -235,8 +237,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { proof.LRO[2], vk.S[0], vk.S[1], - vk.Qcp, - }, + ), &proof.BatchedProof, zeta, hFunc, @@ -268,7 +269,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } -func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element, pi2 kzg.Digest) error { +func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element, pi2 []kzg.Digest) error { // permutation if err := fs.Bind(challenge, vk.S[0].Marshal()); err != nil { @@ -306,8 +307,10 @@ func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey } // bsb22 commitment - if err := fs.Bind(challenge, pi2.Marshal()); err != nil { - return err + for i := range pi2 { + if err := fs.Bind(challenge, pi2[i].Marshal()); err != nil { + return err + } } return nil diff --git a/backend/plonk/bw6-761/marshal.go b/backend/plonk/bw6-761/marshal.go index b3559a8077..eb752c7b7f 100644 --- a/backend/plonk/bw6-761/marshal.go +++ b/backend/plonk/bw6-761/marshal.go @@ -19,9 +19,11 @@ package plonk import ( curve "github.com/consensys/gnark-crypto/ecc/bw6-761" - "errors" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" + + "errors" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/iop" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/kzg" "io" ) @@ -50,7 +52,7 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - &proof.PI2, + proof.PI2, } for _, v := range toEncode { @@ -86,6 +88,10 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { } } + if proof.PI2 == nil { + proof.PI2 = []kzg.Digest{} + } + return dec.BytesRead(), nil } @@ -125,7 +131,7 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { pk.trace.Qm.Coefficients(), pk.trace.Qo.Coefficients(), pk.trace.Qk.Coefficients(), - pk.trace.Qcp.Coefficients(), + coefficients(pk.trace.Qcp), pk.lQk.Coefficients(), pk.trace.S1.Coefficients(), pk.trace.S2.Coefficients(), @@ -166,7 +172,8 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { dec := curve.NewDecoder(r) - var ql, qr, qm, qo, qk, qcp, lqk, s1, s2, s3 []fr.Element + var ql, qr, qm, qo, qk, lqk, s1, s2, s3 []fr.Element + var qcp [][]fr.Element toDecode := []interface{}{ &ql, &qr, @@ -193,11 +200,14 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) - pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + pk.trace.Qcp = make([]*iop.Polynomial, len(qcp)) + for i := range qcp { + pk.trace.Qcp[i] = iop.NewPolynomial(&qcp[i], canReg) + } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} pk.lQk = iop.NewPolynomial(&lqk, lagReg) @@ -234,7 +244,7 @@ func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*curve.Encoder)) (n &vk.Qm, &vk.Qo, &vk.Qk, - &vk.Qcp, + vk.Qcp, vk.CommitmentConstraintIndexes, } diff --git a/backend/plonk/bw6-761/marshal_test.go b/backend/plonk/bw6-761/marshal_test.go index 18e553b256..66548853b6 100644 --- a/backend/plonk/bw6-761/marshal_test.go +++ b/backend/plonk/bw6-761/marshal_test.go @@ -121,7 +121,6 @@ func (pk *ProvingKey) randomize() { qo := randomScalars(n) qk := randomScalars(n) lqk := randomScalars(n) - qcp := randomScalars(n) s1 := randomScalars(n) s2 := randomScalars(n) s3 := randomScalars(n) @@ -132,11 +131,16 @@ func (pk *ProvingKey) randomize() { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) - pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + pk.trace.Qcp = make([]*iop.Polynomial, rand.Intn(4)) + for i := range pk.trace.Qcp { + qcp := randomScalars(rand.Intn(n / 4)) + pk.trace.Qcp[i] = iop.NewPolynomial(&qcp, canReg) + } + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) pk.trace.S[0] = -12 pk.trace.S[len(pk.trace.S)-1] = 8888 @@ -163,7 +167,7 @@ func (vk *VerifyingKey) randomize() { vk.Qm = randomPoint() vk.Qo = randomPoint() vk.Qk = randomPoint() - vk.Qcp = randomPoint() + vk.Qcp = randomPoints(rand.Intn(4)) } func (proof *Proof) randomize() { @@ -178,7 +182,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.PI2 = randomPoint() + proof.PI2 = randomPoints(rand.Intn(4)) } func randomPoint() curve.G1Affine { @@ -187,6 +191,14 @@ func randomPoint() curve.G1Affine { return r } +func randomPoints(n int) []curve.G1Affine { + res := make([]curve.G1Affine, n) + for i := range res { + res[i] = randomPoint() + } + return res +} + func randomScalars(n int) []fr.Element { v := make([]fr.Element, n) one := fr.One() diff --git a/backend/plonk/bw6-761/prove.go b/backend/plonk/bw6-761/prove.go index e349bbc222..e917174ad4 100644 --- a/backend/plonk/bw6-761/prove.go +++ b/backend/plonk/bw6-761/prove.go @@ -55,7 +55,7 @@ type Proof struct { H [3]kzg.Digest // PI2, the BSB22 commitment - PI2 kzg.Digest + PI2 []kzg.Digest // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2, qCPrime BatchedProof kzg.BatchOpeningProof @@ -64,6 +64,39 @@ type Proof struct { ZShiftedOpening kzg.OpeningProof } +func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, wpi2iop []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { + return func(_ *big.Int, ins, outs []*big.Int) error { + pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + offset := spr.GetNbPublicVariables() + for i := range ins { + pi2[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) + } + var ( + err error + hashRes []fr.Element + ) + /*if _, err = pi2[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + return err + } + if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding + return err + }*/ + pi2iop := iop.NewPolynomial(&pi2, iop.Form{Basis: iop.Lagrange, Layout: iop.Regular}) + wpi2iop[commDepth] = pi2iop.ShallowClone() + wpi2iop[commDepth].ToCanonical(&pk.Domain[0]).ToRegular() + if proof.PI2[commDepth], err = kzg.Commit(wpi2iop[commDepth].Coefficients(), pk.Kzg); err != nil { + return err + } + if hashRes, err = fr.Hash(proof.PI2[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + return err + } + res.Set(&hashRes[0]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses + res.BigInt(outs[0]) + + return nil + } +} + func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", spr.GetNbConstraints()).Str("backend", "plonk").Logger() @@ -82,48 +115,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // result proof := &Proof{} - lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} - var ( - wpi2iop *iop.Polynomial // canonical - commitmentVal fr.Element // TODO @Tabaie get rid of this - ) - if len(spr.CommitmentInfo) != 0 { - opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[0].HintID, func(_ *big.Int, ins, outs []*big.Int) error { - pi2 := make([]fr.Element, pk.Domain[0].Cardinality) - offset := spr.GetNbPublicVariables() - for i := range ins { - pi2[offset+spr.CommitmentInfo[0].Committed[i]].SetBigInt(ins[i]) - } - var ( - err error - hashRes []fr.Element - ) - if _, err = pi2[offset+spr.CommitmentInfo[0].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. - return err - } - if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding - return err - } - pi2iop := iop.NewPolynomial(&pi2, lagReg) - wpi2iop = pi2iop.ShallowClone() - wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() - if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Kzg); err != nil { - return err - } - if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { - return err - } - commitmentVal = hashRes[0] // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses - commitmentVal.BigInt(outs[0]) - return nil - })) - } else { - // TODO Leaving pi2 in for testing. In the future, bypass when no commitment present - pi2 := make([]fr.Element, pk.Domain[0].Cardinality) - pi2iop := iop.NewPolynomial(&pi2, lagReg) - wpi2iop = pi2iop.ShallowClone() - // wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + commitmentVal := make([]fr.Element, len(spr.CommitmentInfo)) // TODO @Tabaie get rid of this + wpi2iop := make([]*iop.Polynomial, len(spr.CommitmentInfo)) + proof.PI2 = make([]kzg.Digest, len(spr.CommitmentInfo)) + for i := range spr.CommitmentInfo { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[i].HintID, + bsb22ComputeCommitmentHint(spr, pk, proof, wpi2iop, &commitmentVal[i], i))) } // query l, r, o in Lagrange basis, not blinded @@ -132,19 +130,17 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } // TODO @gbotrel deal with that conversion lazily - var lcpi2iop *iop.Polynomial - if len(spr.CommitmentInfo) != 0 { - lcpi2iop = wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form - } else { - coeffs := make([]fr.Element, pk.Domain[1].Cardinality) - lcpi2iop = iop.NewPolynomial(&coeffs, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.Regular}) + lcpi2iop := make([]*iop.Polynomial, len(wpi2iop)) + for i := range wpi2iop { + lcpi2iop[i] = wpi2iop[i].Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form } solution := _solution.(*cs.SparseR1CSSolution) evaluationLDomainSmall := []fr.Element(solution.L) evaluationRDomainSmall := []fr.Element(solution.R) evaluationODomainSmall := []fr.Element(solution.O) - // l, r o and blinded versions + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + // l, r, o and blinded versions var ( wliop, wriop, @@ -188,8 +184,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) - if len(spr.CommitmentInfo) != 0 { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[0].CommitmentIndex] = commitmentVal + for i := range spr.CommitmentInfo { + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[i].CommitmentIndex] = commitmentVal[i] } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -285,7 +281,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts }() // Full capture using latest gnark crypto... - fic := func(fql, fqr, fqm, fqo, fqk, fqCPrime, l, r, o, pi2 fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary + fic := func(fql, fqr, fqm, fqo, fqk, l, r, o fr.Element, pi2QcPrime []fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary var ic, tmp fr.Element @@ -296,8 +292,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ic.Add(&ic, &tmp) tmp.Mul(&fqo, &o) ic.Add(&ic, &tmp).Add(&ic, &fqk) - tmp.Mul(&fqCPrime, &pi2) - ic.Add(&ic, &tmp) + nbComms := len(spr.CommitmentInfo) + for i := range spr.CommitmentInfo { + tmp.Mul(&pi2QcPrime[i], &pi2QcPrime[i+nbComms]) + ic.Add(&ic, &tmp) + } return ic } @@ -330,13 +329,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return one } - // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15 , 16 - // l , r , o, id, s1, s2, s3, z, zs, PI2, ql, qr, qm, qo, qk, qCPrime, lone + // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm + // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, PI2 , qCPrime fm := func(x ...fr.Element) fr.Element { - a := fic(x[10], x[11], x[12], x[13], x[14], x[15], x[0], x[1], x[2], x[9]) + a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2], x[15:]) b := fo(x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8]) - c := fone(x[7], x[16]) + c := fone(x[7], x[14]) c.Mul(&c, &alpha).Add(&c, &b).Mul(&c, &alpha).Add(&c, &a) @@ -354,7 +353,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // wait for l, r o lagrange coset conversion wgLRO.Wait() - systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, + toEval := []*iop.Polynomial{ bwliop, bwriop, bwoiop, @@ -364,15 +363,16 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pk.lcS3, bwziop, bwsziop, - lcpi2iop, pk.lcQl, pk.lcQr, pk.lcQm, pk.lcQo, lcqk, - pk.lcQcp, pk.lLoneIOP, - ) + } + toEval = append(toEval, lcpi2iop...) // TODO: Add this at beginning + toEval = append(toEval, pk.lcQcp...) + systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, toEval...) if err != nil { return nil, err } @@ -404,10 +404,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // compute evaluations of (blinded version of) l, r, o, z, qCPrime at zeta - var blzeta, brzeta, bozeta, qcpzeta fr.Element + var blzeta, brzeta, bozeta fr.Element + qcpzeta := make([]fr.Element, len(spr.CommitmentInfo)) var wgEvals sync.WaitGroup - wgEvals.Add(4) + wgEvals.Add(3) evalAtZeta := func(poly *iop.Polynomial, res *fr.Element) { poly.ToCanonical(&pk.Domain[1]).ToRegular() *res = poly.Evaluate(zeta) @@ -416,10 +417,12 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts go evalAtZeta(bwliop, &blzeta) go evalAtZeta(bwriop, &brzeta) go evalAtZeta(bwoiop, &bozeta) - go func() { - qcpzeta = pk.trace.Qcp.Evaluate(zeta) - wgEvals.Done() - }() + evalQcpAtZeta := func(begin, end int) { + for i := begin; i < end; i++ { + qcpzeta[i] = pk.trace.Qcp[i].Evaluate(zeta) + } + } + utils.Parallelize(len(spr.CommitmentInfo), evalQcpAtZeta) var zetaShifted fr.Element zetaShifted.Mul(&zeta, &pk.Vk.Generator) @@ -490,7 +493,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bzuzeta, qcpzeta, bwziop.Coefficients()[:bwziop.BlindedSize()], - wpi2iop.Coefficients(), + coefficients(wpi2iop), pk, ) @@ -506,7 +509,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // Batch open the first list of polynomials proof.BatchedProof, err = kzg.BatchOpenSinglePoint( - [][]fr.Element{ + append(coefficients(pk.trace.Qcp), foldedH, linearizedPolynomialCanonical, bwliop.Coefficients()[:bwliop.BlindedSize()], @@ -514,9 +517,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.Coefficients()[:bwoiop.BlindedSize()], pk.trace.S1.Coefficients(), pk.trace.S2.Coefficients(), - pk.trace.Qcp.Coefficients(), - }, - []kzg.Digest{ + ), + append(pk.Vk.Qcp, foldedHDigest, linearizedPolynomialDigest, proof.LRO[0], @@ -524,8 +526,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.LRO[2], pk.Vk.S[0], pk.Vk.S[1], - pk.Vk.Qcp, - }, + ), zeta, hFunc, pk.Kzg, @@ -541,6 +542,14 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } +func coefficients(p []*iop.Polynomial) [][]fr.Element { + res := make([][]fr.Element, len(p)) + for i, pI := range p { + res[i] = pI.Coefficients() + } + return res +} + // fills proof.LRO with kzg commits of bcl, bcr and bco func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, kzgPk kzg.ProvingKey) error { n := runtime.NumCPU() @@ -605,7 +614,7 @@ func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, kzgPk kzg.ProvingKe // α²*L₁(ζ)*Z(X) // + α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*id1(ζ)+γ)*(r(ζ)+β*id2(ζ)+γ)*(o(ζ)+β*id3(ζ)+γ)) // + l(ζ)*Ql(X) + l(ζ)r(ζ)*Qm(X) + r(ζ)*Qr(X) + o(ζ)*Qo(X) + Qk(X) -func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu, qcpZeta fr.Element, blindedZCanonical []fr.Element, pi2Canonical []fr.Element, pk *ProvingKey) []fr.Element { +func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu fr.Element, qcpZeta, blindedZCanonical []fr.Element, pi2Canonical [][]fr.Element, pk *ProvingKey) []fr.Element { // first part: individual constraints var rl fr.Element @@ -688,8 +697,10 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, t0.Mul(&cqo[i], &oZeta).Add(&t0, &cqk[i]) t.Add(&t, &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) - t0.Mul(&pi2Canonical[i], &qcpZeta) - t.Add(&t, &t0) + for j := range qcpZeta { + t0.Mul(&pi2Canonical[j][i], &qcpZeta[j]) + t.Add(&t, &t0) + } } t0.Mul(&blindedZCanonical[i], &lagrangeZeta) diff --git a/backend/plonk/bw6-761/setup.go b/backend/plonk/bw6-761/setup.go index a14071de61..6eccbf17f1 100644 --- a/backend/plonk/bw6-761/setup.go +++ b/backend/plonk/bw6-761/setup.go @@ -35,7 +35,8 @@ type Trace struct { // completed by the prover. At those indices i (so from 0 to nb_public_variables), LQl[i]=-1 // so the first nb_public_variables constraints look like this: // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. - Ql, Qr, Qm, Qo, Qk, Qcp *iop.Polynomial + Ql, Qr, Qm, Qo, Qk *iop.Polynomial + Qcp []*iop.Polynomial // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. // The set of interpolation is of size N, so to represent the permutation S we let S acts on the @@ -72,7 +73,8 @@ type VerifyingKey struct { // Commitments to ql, qr, qm, qo, qcp prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk, Qcp kzg.Digest + Ql, Qr, Qm, Qo, Qk kzg.Digest + Qcp []kzg.Digest CommitmentConstraintIndexes []uint64 } @@ -100,7 +102,8 @@ type ProvingKey struct { Vk *VerifyingKey // qr,ql,qm,qo,qcp in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo, Qcp once. - lcQl, lcQr, lcQm, lcQo, lcQcp *iop.Polynomial + lcQl, lcQr, lcQm, lcQo *iop.Polynomial + lcQcp []*iop.Polynomial // LQk qk in Lagrange form -> to be completed by the prover. After being completed, lQk *iop.Polynomial @@ -173,7 +176,10 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro // computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset // basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. func (pk *ProvingKey) computeLagrangeCosetPolys() { - pk.lcQcp = pk.trace.Qcp.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQcp = make([]*iop.Polynomial, len(pk.trace.Qcp)) + for i, qcpI := range pk.trace.Qcp { + pk.lcQcp[i] = qcpI.Clone().ToLagrangeCoset(&pk.Domain[1]) + } pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) @@ -226,7 +232,7 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qm := make([]fr.Element, size) qo := make([]fr.Element, size) qk := make([]fr.Element, size) - qcp := make([]fr.Element, size) + qcp := make([][]fr.Element, len(spr.CommitmentInfo)) for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent ql[i].SetOne().Neg(&ql[i]) @@ -248,12 +254,6 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { j++ } - if len(spr.CommitmentInfo) != 0 { - for _, committed := range spr.CommitmentInfo[0].Committed { - qcp[offset+committed].SetOne() - } - } - lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} pt.Ql = iop.NewPolynomial(&ql, lagReg) @@ -261,11 +261,18 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { pt.Qm = iop.NewPolynomial(&qm, lagReg) pt.Qo = iop.NewPolynomial(&qo, lagReg) pt.Qk = iop.NewPolynomial(&qk, lagReg) - pt.Qcp = iop.NewPolynomial(&qcp, lagReg) + pt.Qcp = make([]*iop.Polynomial, len(qcp)) + for i := range spr.CommitmentInfo { + qcp[i] = make([]fr.Element, size) + for _, committed := range spr.CommitmentInfo[i].Committed { + qcp[i][offset+committed].SetOne() + } + pt.Qcp[i] = iop.NewPolynomial(&qcp[i], lagReg) + } } -// commitTrace commits to every polynomials in the trace, and put +// commitTrace commits to every polynomial in the trace, and put // the commitments int the verifying key. func commitTrace(trace *Trace, pk *ProvingKey) error { @@ -274,12 +281,18 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { trace.Qm.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qo.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qk.ToCanonical(&pk.Domain[0]).ToRegular() // -> qk is not complete - trace.Qcp.ToCanonical(&pk.Domain[0]).ToRegular() trace.S1.ToCanonical(&pk.Domain[0]).ToRegular() trace.S2.ToCanonical(&pk.Domain[0]).ToRegular() trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() var err error + pk.Vk.Qcp = make([]kzg.Digest, len(trace.Qcp)) + for i := range trace.Qcp { + trace.Qcp[i].ToCanonical(&pk.Domain[0]).ToRegular() + if pk.Vk.Qcp[i], err = kzg.Commit(pk.trace.Qcp[i].Coefficients(), pk.Kzg); err != nil { + return err + } + } if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Kzg); err != nil { return err } @@ -295,9 +308,6 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Kzg); err != nil { - return err - } if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Kzg); err != nil { return err } diff --git a/backend/plonk/bw6-761/verify.go b/backend/plonk/bw6-761/verify.go index 19a1a01d08..af30cd65f9 100644 --- a/backend/plonk/bw6-761/verify.go +++ b/backend/plonk/bw6-761/verify.go @@ -112,7 +112,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { for i := range vk.CommitmentConstraintIndexes { var hashRes []fr.Element // TODO: when multi commits are implemented: PI2 -> PI2[i] - if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + if hashRes, err = fr.Hash(proof.PI2[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } @@ -137,14 +137,16 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - claimedQuotient := proof.BatchedProof.ClaimedValues[0] - linearizedPolynomialZeta := proof.BatchedProof.ClaimedValues[1] - l := proof.BatchedProof.ClaimedValues[2] - r := proof.BatchedProof.ClaimedValues[3] - o := proof.BatchedProof.ClaimedValues[4] - s1 := proof.BatchedProof.ClaimedValues[5] - s2 := proof.BatchedProof.ClaimedValues[6] - qC := proof.BatchedProof.ClaimedValues[7] + qC := make([]fr.Element, len(proof.PI2)) + copy(qC, proof.BatchedProof.ClaimedValues) + claimedValues := proof.BatchedProof.ClaimedValues[len(proof.PI2):] + claimedQuotient := claimedValues[0] + linearizedPolynomialZeta := claimedValues[1] + l := claimedValues[2] + r := claimedValues[3] + o := claimedValues[4] + s1 := claimedValues[5] + s2 := claimedValues[6] _s1.Mul(&s1, &beta).Add(&_s1, &l).Add(&_s1, &gamma) // (l(ζ)+β*s1(ζ)+γ) _s2.Mul(&s2, &beta).Add(&_s2, &r).Add(&_s2, &gamma) // (r(ζ)+β*s2(ζ)+γ) @@ -213,21 +215,21 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // note since third part = α²*L₁(ζ)*Z _s2.Mul(&_s2, &alpha).Add(&_s2, &alphaSquareLagrange) // -α*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + α²*L₁(ζ) - points := []curve.G1Affine{ - vk.Ql, vk.Qr, vk.Qm, vk.Qo, vk.Qk, proof.PI2, // first part + points := append(proof.PI2, + vk.Ql, vk.Qr, vk.Qm, vk.Qo, vk.Qk, // first part vk.S[2], proof.Z, // second & third part - } + ) - scalars := []fr.Element{ - l, r, rl, o, one /* TODO Perf @Tabaie Consider just adding Qk instead */, qC, // first part + scalars := append(qC, + l, r, rl, o, one, /* TODO Perf @Tabaie Consider just adding Qk instead */ // first part _s1, _s2, // second & third part - } + ) if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{}); err != nil { return err } // Fold the first proof - foldedProof, foldedDigest, err := kzg.FoldProof([]kzg.Digest{ + foldedProof, foldedDigest, err := kzg.FoldProof(append(vk.Qcp, foldedH, linearizedPolynomialDigest, proof.LRO[0], @@ -235,8 +237,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { proof.LRO[2], vk.S[0], vk.S[1], - vk.Qcp, - }, + ), &proof.BatchedProof, zeta, hFunc, @@ -268,7 +269,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } -func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element, pi2 kzg.Digest) error { +func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element, pi2 []kzg.Digest) error { // permutation if err := fs.Bind(challenge, vk.S[0].Marshal()); err != nil { @@ -306,8 +307,10 @@ func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey } // bsb22 commitment - if err := fs.Bind(challenge, pi2.Marshal()); err != nil { - return err + for i := range pi2 { + if err := fs.Bind(challenge, pi2[i].Marshal()); err != nil { + return err + } } return nil diff --git a/go.mod b/go.mod index dc301ad036..56e1ca848b 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/bits-and-blooms/bitset v1.5.0 github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 - github.com/consensys/gnark-crypto v0.11.1-0.20230505210013-748abeca0330 + github.com/consensys/gnark-crypto v0.11.1-0.20230508024855-0cd4994b7f0b github.com/fxamacker/cbor/v2 v2.4.0 github.com/google/go-cmp v0.5.9 github.com/google/pprof v0.0.0-20230309165930-d61513b1440d @@ -30,5 +30,3 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect rsc.io/tmplfunc v0.0.3 // indirect ) - -replace "github.com/consensys/gnark-crypto" => "/Users/arya/gnark-crypto" \ No newline at end of file diff --git a/go.sum b/go.sum index 45ea69adc2..c622e66d0e 100644 --- a/go.sum +++ b/go.sum @@ -4,12 +4,8 @@ github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.10.1-0.20230426090045-2a781ae21a86 h1:Qvm/R59xXUiB7oM9v53kgN7JRn3yIGeGV9mninTVzWs= -github.com/consensys/gnark-crypto v0.10.1-0.20230426090045-2a781ae21a86/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= -github.com/consensys/gnark-crypto v0.11.1-0.20230504180944-3f61172c800b h1:tj7ZZ8oadsC+Y7u72mW8Q+afaCEDPDR9hN5+y2/peyU= -github.com/consensys/gnark-crypto v0.11.1-0.20230504180944-3f61172c800b/go.mod h1:6C2ytC8zmP8uH2GKVfPOjf0Vw3KwMAaUxlCPK5WQqmw= -github.com/consensys/gnark-crypto v0.11.1-0.20230505210013-748abeca0330 h1:ETzLrW3IXsETVT5zHPfb62V73ytyTEQzYP/T1Sbb5kI= -github.com/consensys/gnark-crypto v0.11.1-0.20230505210013-748abeca0330/go.mod h1:6C2ytC8zmP8uH2GKVfPOjf0Vw3KwMAaUxlCPK5WQqmw= +github.com/consensys/gnark-crypto v0.11.1-0.20230508024855-0cd4994b7f0b h1:owSc8rrE2Tdl7xYxFgdPgx52qlO1fFDujW07aSGrffM= +github.com/consensys/gnark-crypto v0.11.1-0.20230508024855-0cd4994b7f0b/go.mod h1:6C2ytC8zmP8uH2GKVfPOjf0Vw3KwMAaUxlCPK5WQqmw= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -68,6 +64,7 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl index ae5b1e5f75..fd12bd3e3a 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl @@ -1,6 +1,7 @@ import ( {{ template "import_curve" . }} {{ template "import_fr" . }} + {{ template "import_kzg" . }} "github.com/consensys/gnark-crypto/ecc/{{toLower .Curve}}/fr/iop" "io" "errors" @@ -31,7 +32,7 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - &proof.PI2, + proof.PI2, } for _, v := range toEncode { @@ -67,6 +68,10 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { } } + if proof.PI2 == nil { + proof.PI2 = []kzg.Digest{} + } + return dec.BytesRead(), nil } @@ -106,7 +111,7 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { pk.trace.Qm.Coefficients(), pk.trace.Qo.Coefficients(), pk.trace.Qk.Coefficients(), - pk.trace.Qcp.Coefficients(), + coefficients(pk.trace.Qcp), pk.lQk.Coefficients(), pk.trace.S1.Coefficients(), pk.trace.S2.Coefficients(), @@ -147,7 +152,8 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { dec := curve.NewDecoder(r) - var ql, qr, qm, qo, qk, qcp, lqk, s1, s2, s3 []fr.Element + var ql, qr, qm, qo, qk, lqk, s1, s2, s3 []fr.Element + var qcp [][]fr.Element toDecode := []interface{}{ &ql, &qr, @@ -174,11 +180,14 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) - pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + pk.trace.Qcp = make([]*iop.Polynomial, len(qcp)) + for i := range qcp { + pk.trace.Qcp[i] = iop.NewPolynomial(&qcp[i], canReg) + } lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} pk.lQk = iop.NewPolynomial(&lqk, lagReg) @@ -215,7 +224,7 @@ func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*curve.Encoder)) (n &vk.Qm, &vk.Qo, &vk.Qk, - &vk.Qcp, + vk.Qcp, vk.CommitmentConstraintIndexes, } diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl index f3ac55cec8..e2b74379f8 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl @@ -33,7 +33,7 @@ type Proof struct { H [3]kzg.Digest // PI2, the BSB22 commitment - PI2 kzg.Digest + PI2 []kzg.Digest // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2, qCPrime BatchedProof kzg.BatchOpeningProof @@ -42,6 +42,39 @@ type Proof struct { ZShiftedOpening kzg.OpeningProof } +func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, wpi2iop []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { + return func(_ *big.Int, ins, outs []*big.Int) error { + pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + offset := spr.GetNbPublicVariables() + for i := range ins { + pi2[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) + } + var ( + err error + hashRes []fr.Element + ) + /*if _, err = pi2[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + return err + } + if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding + return err + }*/ + pi2iop := iop.NewPolynomial(&pi2, iop.Form{Basis: iop.Lagrange, Layout: iop.Regular}) + wpi2iop[commDepth] = pi2iop.ShallowClone() + wpi2iop[commDepth].ToCanonical(&pk.Domain[0]).ToRegular() + if proof.PI2[commDepth], err = kzg.Commit(wpi2iop[commDepth].Coefficients(), pk.Kzg); err != nil { + return err + } + if hashRes, err = fr.Hash(proof.PI2[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + return err + } + res.Set(&hashRes[0]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses + res.BigInt(outs[0]) + + return nil + } +} + func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { log := logger.Logger().With().Str("curve", spr.CurveID().String()).Int("nbConstraints", spr.GetNbConstraints()).Str("backend", "plonk").Logger() @@ -60,48 +93,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // result proof := &Proof{} - lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} - var ( - wpi2iop *iop.Polynomial // canonical - commitmentVal fr.Element // TODO @Tabaie get rid of this - ) - if len(spr.CommitmentInfo) != 0 { - opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[0].HintID, func(_ *big.Int, ins, outs []*big.Int) error { - pi2 := make([]fr.Element, pk.Domain[0].Cardinality) - offset := spr.GetNbPublicVariables() - for i := range ins { - pi2[offset+spr.CommitmentInfo[0].Committed[i]].SetBigInt(ins[i]) - } - var ( - err error - hashRes []fr.Element - ) - if _, err = pi2[offset+spr.CommitmentInfo[0].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. - return err - } - if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding - return err - } - pi2iop := iop.NewPolynomial(&pi2, lagReg) - wpi2iop = pi2iop.ShallowClone() - wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() - if proof.PI2, err = kzg.Commit(wpi2iop.Coefficients(), pk.Kzg); err != nil { - return err - } - if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { - return err - } - commitmentVal = hashRes[0] // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses - commitmentVal.BigInt(outs[0]) - return nil - })) - } else { - // TODO Leaving pi2 in for testing. In the future, bypass when no commitment present - pi2 := make([]fr.Element, pk.Domain[0].Cardinality) - pi2iop := iop.NewPolynomial(&pi2, lagReg) - wpi2iop = pi2iop.ShallowClone() - // wpi2iop.ToCanonical(&pk.Domain[0]).ToRegular() + commitmentVal := make([]fr.Element, len(spr.CommitmentInfo)) // TODO @Tabaie get rid of this + wpi2iop := make([]*iop.Polynomial, len(spr.CommitmentInfo)) + proof.PI2 = make([]kzg.Digest, len(spr.CommitmentInfo)) + for i := range spr.CommitmentInfo { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[i].HintID, + bsb22ComputeCommitmentHint(spr, pk, proof, wpi2iop, &commitmentVal[i], i))) } // query l, r, o in Lagrange basis, not blinded @@ -110,19 +108,17 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } // TODO @gbotrel deal with that conversion lazily - var lcpi2iop *iop.Polynomial - if len(spr.CommitmentInfo) != 0 { - lcpi2iop = wpi2iop.Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form - } else { - coeffs := make([]fr.Element, pk.Domain[1].Cardinality) - lcpi2iop = iop.NewPolynomial(&coeffs, iop.Form{Basis:iop.LagrangeCoset, Layout: iop.Regular}) + lcpi2iop := make([]*iop.Polynomial, len(wpi2iop)) + for i := range wpi2iop { + lcpi2iop[i] = wpi2iop[i].Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form } solution := _solution.(*cs.SparseR1CSSolution) evaluationLDomainSmall := []fr.Element(solution.L) evaluationRDomainSmall := []fr.Element(solution.R) evaluationODomainSmall := []fr.Element(solution.O) - // l, r o and blinded versions + lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} + // l, r, o and blinded versions var ( wliop, wriop, @@ -168,8 +164,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) - if len(spr.CommitmentInfo) != 0 { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[0].CommitmentIndex] = commitmentVal + for i := range spr.CommitmentInfo { + qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[i].CommitmentIndex] = commitmentVal[i] } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -267,7 +263,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // Full capture using latest gnark crypto... - fic := func(fql, fqr, fqm, fqo, fqk, fqCPrime, l, r, o, pi2 fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary + fic := func(fql, fqr, fqm, fqo, fqk, l, r, o fr.Element, pi2QcPrime []fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary var ic, tmp fr.Element @@ -278,8 +274,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ic.Add(&ic, &tmp) tmp.Mul(&fqo, &o) ic.Add(&ic, &tmp).Add(&ic, &fqk) - tmp.Mul(&fqCPrime, &pi2) - ic.Add(&ic, &tmp) + nbComms := len(spr.CommitmentInfo) + for i := range spr.CommitmentInfo { + tmp.Mul(&pi2QcPrime[i], &pi2QcPrime[i+nbComms]) + ic.Add(&ic, &tmp) + } return ic } @@ -313,13 +312,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return one } - // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15 , 16 - // l , r , o, id, s1, s2, s3, z, zs, PI2, ql, qr, qm, qo, qk, qCPrime, lone + // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm + // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, PI2 , qCPrime fm := func(x ...fr.Element) fr.Element { - a := fic(x[10], x[11], x[12], x[13], x[14], x[15], x[0], x[1], x[2], x[9]) + a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2], x[15:]) b := fo(x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8]) - c := fone(x[7], x[16]) + c := fone(x[7], x[14]) c.Mul(&c, &alpha).Add(&c, &b).Mul(&c, &alpha).Add(&c, &a) @@ -337,7 +336,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // wait for l, r o lagrange coset conversion wgLRO.Wait() - systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, + toEval := []*iop.Polynomial{ bwliop, bwriop, bwoiop, @@ -347,15 +346,17 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pk.lcS3, bwziop, bwsziop, - lcpi2iop, pk.lcQl, pk.lcQr, pk.lcQm, pk.lcQo, lcqk, - pk.lcQcp, pk.lLoneIOP, - ) + + } + toEval = append(toEval, lcpi2iop...) // TODO: Add this at beginning + toEval = append(toEval, pk.lcQcp...) + systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, toEval...) if err != nil { return nil, err } @@ -388,10 +389,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // compute evaluations of (blinded version of) l, r, o, z, qCPrime at zeta - var blzeta, brzeta, bozeta, qcpzeta fr.Element + var blzeta, brzeta, bozeta fr.Element + qcpzeta := make([]fr.Element, len(spr.CommitmentInfo)) var wgEvals sync.WaitGroup - wgEvals.Add(4) + wgEvals.Add(3) evalAtZeta := func(poly *iop.Polynomial, res *fr.Element) { poly.ToCanonical(&pk.Domain[1]).ToRegular() *res = poly.Evaluate(zeta) @@ -400,10 +402,12 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts go evalAtZeta(bwliop, &blzeta) go evalAtZeta(bwriop, &brzeta) go evalAtZeta(bwoiop, &bozeta) - go func() { - qcpzeta = pk.trace.Qcp.Evaluate(zeta) - wgEvals.Done() - }() + evalQcpAtZeta := func(begin, end int) { + for i := begin; i < end; i++ { + qcpzeta[i] = pk.trace.Qcp[i].Evaluate(zeta) + } + } + utils.Parallelize(len(spr.CommitmentInfo), evalQcpAtZeta) var zetaShifted fr.Element zetaShifted.Mul(&zeta, &pk.Vk.Generator) @@ -476,7 +480,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bzuzeta, qcpzeta, bwziop.Coefficients()[:bwziop.BlindedSize()], - wpi2iop.Coefficients(), + coefficients(wpi2iop), pk, ) @@ -493,7 +497,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // Batch open the first list of polynomials proof.BatchedProof, err = kzg.BatchOpenSinglePoint( - [][]fr.Element{ + append(coefficients(pk.trace.Qcp), foldedH, linearizedPolynomialCanonical, bwliop.Coefficients()[:bwliop.BlindedSize()], @@ -501,9 +505,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.Coefficients()[:bwoiop.BlindedSize()], pk.trace.S1.Coefficients(), pk.trace.S2.Coefficients(), - pk.trace.Qcp.Coefficients(), - }, - []kzg.Digest{ + ), + append(pk.Vk.Qcp, foldedHDigest, linearizedPolynomialDigest, proof.LRO[0], @@ -511,8 +514,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof.LRO[2], pk.Vk.S[0], pk.Vk.S[1], - pk.Vk.Qcp, - }, + ), zeta, hFunc, pk.Kzg, @@ -528,6 +530,14 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } +func coefficients(p []*iop.Polynomial) [][]fr.Element { + res := make([][]fr.Element, len(p)) + for i, pI := range p { + res[i] = pI.Coefficients() + } + return res +} + // fills proof.LRO with kzg commits of bcl, bcr and bco func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, kzgPk kzg.ProvingKey) error { n := runtime.NumCPU() @@ -592,7 +602,7 @@ func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, kzgPk kzg.ProvingKe // α²*L₁(ζ)*Z(X) // + α*( (l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*Z(μζ)*s3(X) - Z(X)*(l(ζ)+β*id1(ζ)+γ)*(r(ζ)+β*id2(ζ)+γ)*(o(ζ)+β*id3(ζ)+γ)) // + l(ζ)*Ql(X) + l(ζ)r(ζ)*Qm(X) + r(ζ)*Qr(X) + o(ζ)*Qo(X) + Qk(X) -func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu, qcpZeta fr.Element, blindedZCanonical []fr.Element, pi2Canonical []fr.Element, pk *ProvingKey) []fr.Element { +func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, zu fr.Element, qcpZeta, blindedZCanonical []fr.Element, pi2Canonical [][]fr.Element, pk *ProvingKey) []fr.Element { // first part: individual constraints var rl fr.Element @@ -676,8 +686,10 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, t0.Mul(&cqo[i], &oZeta).Add(&t0, &cqk[i]) t.Add(&t, &t0) // linPol = linPol + o(ζ)*Qo(X) + Qk(X) - t0.Mul(&pi2Canonical[i], &qcpZeta) - t.Add(&t, &t0) + for j := range qcpZeta { + t0.Mul(&pi2Canonical[j][i], &qcpZeta[j]) + t.Add(&t, &t0) + } } t0.Mul(&blindedZCanonical[i], &lagrangeZeta) diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl index f2cc8448bd..b9aa0e7c6d 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl @@ -17,7 +17,8 @@ type Trace struct { // completed by the prover. At those indices i (so from 0 to nb_public_variables), LQl[i]=-1 // so the first nb_public_variables constraints look like this: // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. - Ql, Qr, Qm, Qo, Qk, Qcp *iop.Polynomial + Ql, Qr, Qm, Qo, Qk *iop.Polynomial + Qcp []*iop.Polynomial // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. // The set of interpolation is of size N, so to represent the permutation S we let S acts on the @@ -54,7 +55,8 @@ type VerifyingKey struct { // Commitments to ql, qr, qm, qo, qcp prepended with as many zeroes (ones for l) as there are public inputs. // In particular Qk is not complete. - Ql, Qr, Qm, Qo, Qk, Qcp kzg.Digest + Ql, Qr, Qm, Qo, Qk kzg.Digest + Qcp []kzg.Digest CommitmentConstraintIndexes []uint64 } @@ -82,7 +84,8 @@ type ProvingKey struct { Vk *VerifyingKey // qr,ql,qm,qo,qcp in LagrangeCoset --> these are not serialized, but computed from Ql, Qr, Qm, Qo, Qcp once. - lcQl, lcQr, lcQm, lcQo, lcQcp *iop.Polynomial + lcQl, lcQr, lcQm, lcQo *iop.Polynomial + lcQcp []*iop.Polynomial // LQk qk in Lagrange form -> to be completed by the prover. After being completed, lQk *iop.Polynomial @@ -155,7 +158,10 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro // computeLagrangeCosetPolys computes each polynomial except qk in Lagrange coset // basis. Qk will be evaluated in Lagrange coset basis once it is completed by the prover. func (pk *ProvingKey) computeLagrangeCosetPolys() { - pk.lcQcp = pk.trace.Qcp.Clone().ToLagrangeCoset(&pk.Domain[1]) + pk.lcQcp = make([]*iop.Polynomial, len(pk.trace.Qcp)) + for i, qcpI := range pk.trace.Qcp { + pk.lcQcp[i] = qcpI.Clone().ToLagrangeCoset(&pk.Domain[1]) + } pk.lcQl = pk.trace.Ql.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQr = pk.trace.Qr.Clone().ToLagrangeCoset(&pk.Domain[1]) pk.lcQm = pk.trace.Qm.Clone().ToLagrangeCoset(&pk.Domain[1]) @@ -208,7 +214,7 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { qm := make([]fr.Element, size) qo := make([]fr.Element, size) qk := make([]fr.Element, size) - qcp := make([]fr.Element, size) + qcp := make([][]fr.Element, len(spr.CommitmentInfo)) for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent ql[i].SetOne().Neg(&ql[i]) @@ -232,12 +238,6 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { j++ } - if len(spr.CommitmentInfo) != 0 { - for _, committed := range spr.CommitmentInfo[0].Committed { - qcp[offset+committed].SetOne() - } - } - lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} pt.Ql = iop.NewPolynomial(&ql, lagReg) @@ -245,11 +245,18 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { pt.Qm = iop.NewPolynomial(&qm, lagReg) pt.Qo = iop.NewPolynomial(&qo, lagReg) pt.Qk = iop.NewPolynomial(&qk, lagReg) - pt.Qcp = iop.NewPolynomial(&qcp, lagReg) + pt.Qcp = make([]*iop.Polynomial, len(qcp)) + for i := range spr.CommitmentInfo { + qcp[i] = make([]fr.Element, size) + for _, committed := range spr.CommitmentInfo[i].Committed { + qcp[i][offset+committed].SetOne() + } + pt.Qcp[i] = iop.NewPolynomial(&qcp[i], lagReg) + } } -// commitTrace commits to every polynomials in the trace, and put +// commitTrace commits to every polynomial in the trace, and put // the commitments int the verifying key. func commitTrace(trace *Trace, pk *ProvingKey) error { @@ -258,12 +265,18 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { trace.Qm.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qo.ToCanonical(&pk.Domain[0]).ToRegular() trace.Qk.ToCanonical(&pk.Domain[0]).ToRegular() // -> qk is not complete - trace.Qcp.ToCanonical(&pk.Domain[0]).ToRegular() trace.S1.ToCanonical(&pk.Domain[0]).ToRegular() trace.S2.ToCanonical(&pk.Domain[0]).ToRegular() trace.S3.ToCanonical(&pk.Domain[0]).ToRegular() var err error + pk.Vk.Qcp = make([]kzg.Digest, len(trace.Qcp)) + for i := range trace.Qcp { + trace.Qcp[i].ToCanonical(&pk.Domain[0]).ToRegular() + if pk.Vk.Qcp[i], err = kzg.Commit(pk.trace.Qcp[i].Coefficients(), pk.Kzg); err != nil { + return err + } + } if pk.Vk.Ql, err = kzg.Commit(pk.trace.Ql.Coefficients(), pk.Kzg); err != nil { return err } @@ -279,9 +292,6 @@ func commitTrace(trace *Trace, pk *ProvingKey) error { if pk.Vk.Qk, err = kzg.Commit(pk.trace.Qk.Coefficients(), pk.Kzg); err != nil { return err } - if pk.Vk.Qcp, err = kzg.Commit(pk.trace.Qcp.Coefficients(), pk.Kzg); err != nil { - return err - } if pk.Vk.S[0], err = kzg.Commit(pk.trace.S1.Coefficients(), pk.Kzg); err != nil { return err } diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl index d49bfea5e9..6b4113aabc 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl @@ -93,7 +93,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { for i := range vk.CommitmentConstraintIndexes { var hashRes []fr.Element // TODO: when multi commits are implemented: PI2 -> PI2[i] - if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + if hashRes, err = fr.Hash(proof.PI2[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } @@ -118,14 +118,16 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - claimedQuotient := proof.BatchedProof.ClaimedValues[0] - linearizedPolynomialZeta := proof.BatchedProof.ClaimedValues[1] - l := proof.BatchedProof.ClaimedValues[2] - r := proof.BatchedProof.ClaimedValues[3] - o := proof.BatchedProof.ClaimedValues[4] - s1 := proof.BatchedProof.ClaimedValues[5] - s2 := proof.BatchedProof.ClaimedValues[6] - qC := proof.BatchedProof.ClaimedValues[7] + qC := make([]fr.Element, len(proof.PI2)) + copy(qC, proof.BatchedProof.ClaimedValues) + claimedValues := proof.BatchedProof.ClaimedValues[len(proof.PI2):] + claimedQuotient := claimedValues[0] + linearizedPolynomialZeta := claimedValues[1] + l := claimedValues[2] + r := claimedValues[3] + o := claimedValues[4] + s1 := claimedValues[5] + s2 := claimedValues[6] _s1.Mul(&s1, &beta).Add(&_s1, &l).Add(&_s1, &gamma) // (l(ζ)+β*s1(ζ)+γ) _s2.Mul(&s2, &beta).Add(&_s2, &r).Add(&_s2, &gamma) // (r(ζ)+β*s2(ζ)+γ) @@ -194,21 +196,21 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // note since third part = α²*L₁(ζ)*Z _s2.Mul(&_s2, &alpha).Add(&_s2, &alphaSquareLagrange) // -α*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + α²*L₁(ζ) - points := []curve.G1Affine{ - vk.Ql, vk.Qr, vk.Qm, vk.Qo, vk.Qk, proof.PI2, // first part + points := append(proof.PI2, + vk.Ql, vk.Qr, vk.Qm, vk.Qo, vk.Qk, // first part vk.S[2], proof.Z, // second & third part - } + ) - scalars := []fr.Element{ - l, r, rl, o, one /* TODO Perf @Tabaie Consider just adding Qk instead */, qC, // first part + scalars := append(qC, + l, r, rl, o, one /* TODO Perf @Tabaie Consider just adding Qk instead */, // first part _s1, _s2, // second & third part - } + ) if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{}); err != nil { return err } // Fold the first proof - foldedProof, foldedDigest, err := kzg.FoldProof([]kzg.Digest{ + foldedProof, foldedDigest, err := kzg.FoldProof(append(vk.Qcp, foldedH, linearizedPolynomialDigest, proof.LRO[0], @@ -216,8 +218,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { proof.LRO[2], vk.S[0], vk.S[1], - vk.Qcp, - }, + ), &proof.BatchedProof, zeta, hFunc, @@ -249,7 +250,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } -func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element, pi2 kzg.Digest) error { +func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element, pi2 []kzg.Digest) error { // permutation if err := fs.Bind(challenge, vk.S[0].Marshal()); err != nil { @@ -287,8 +288,10 @@ func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey } // bsb22 commitment - if err := fs.Bind(challenge, pi2.Marshal()); err != nil { - return err + for i := range pi2 { + if err := fs.Bind(challenge, pi2[i].Marshal()); err != nil { + return err + } } return nil diff --git a/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl index 63d96b40f0..3a31b472f4 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl @@ -102,7 +102,6 @@ func (pk *ProvingKey) randomize() { qo := randomScalars(n) qk := randomScalars(n) lqk := randomScalars(n) - qcp := randomScalars(n) s1 := randomScalars(n) s2 := randomScalars(n) s3 := randomScalars(n) @@ -113,11 +112,16 @@ func (pk *ProvingKey) randomize() { pk.trace.Qm = iop.NewPolynomial(&qm, canReg) pk.trace.Qo = iop.NewPolynomial(&qo, canReg) pk.trace.Qk = iop.NewPolynomial(&qk, canReg) - pk.trace.Qcp = iop.NewPolynomial(&qcp, canReg) pk.trace.S1 = iop.NewPolynomial(&s1, canReg) pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) + pk.trace.Qcp = make([]*iop.Polynomial, rand.Intn(4)) + for i := range pk.trace.Qcp { + qcp := randomScalars(rand.Intn(n / 4)) + pk.trace.Qcp[i] = iop.NewPolynomial(&qcp, canReg) + } + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) pk.trace.S[0] = -12 pk.trace.S[len(pk.trace.S)-1] = 8888 @@ -144,7 +148,7 @@ func (vk *VerifyingKey) randomize() { vk.Qm = randomPoint() vk.Qo = randomPoint() vk.Qk = randomPoint() - vk.Qcp = randomPoint() + vk.Qcp = randomPoints(rand.Intn(4)) } func (proof *Proof) randomize() { @@ -159,7 +163,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.PI2 = randomPoint() + proof.PI2 = randomPoints(rand.Intn(4)) } func randomPoint() curve.G1Affine { @@ -168,6 +172,14 @@ func randomPoint() curve.G1Affine { return r } +func randomPoints(n int) []curve.G1Affine { + res := make([]curve.G1Affine, n) + for i := range res { + res[i] = randomPoint() + } + return res +} + func randomScalars(n int) []fr.Element { v := make([]fr.Element, n) one := fr.One() diff --git a/internal/stats/latest.stats b/internal/stats/latest.stats index 2441c9c6dfbbd503e98a0cffeda6fbdafd63d690..0fd0b70df05c10b4e3319b6ea7fce2a9ab4b0f66 100644 GIT binary patch delta 53 zcmew?`dM^?H{)b6uDg>9*dI(j#2PfY0Ek7{S|?9txw|=l;~3*+ZKfQ?$urrmPxfYf JFnK!j9{@`f71jU% delta 59 zcmew?`dM^?H{)b+&Ig;Xu;nl^>P`N@Dn6N?>&aw8mb;Uqn1d#B0Pz~;*2xYW*C%T* PJ=o00dW> Date: Mon, 8 May 2023 16:54:02 -0500 Subject: [PATCH 348/464] revert some debugging conveniences --- internal/utils/parallelize.go | 13 ++++++------- test/commitments_test.go | 3 +-- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/internal/utils/parallelize.go b/internal/utils/parallelize.go index 8d44d909fd..bc377cccec 100644 --- a/internal/utils/parallelize.go +++ b/internal/utils/parallelize.go @@ -1,12 +1,12 @@ package utils -// Parallelize process in parallel the work function - -func Parallelize(nbIterations int, work func(int, int), _ ...int) { - work(0, nbIterations) -} +import ( + "runtime" + "sync" +) -/*func Parallelize(nbIterations int, work func(int, int), maxCpus ...int) { +// Parallelize process in parallel the work function +func Parallelize(nbIterations int, work func(int, int), maxCpus ...int) { nbTasks := runtime.NumCPU() if len(maxCpus) == 1 { @@ -42,4 +42,3 @@ func Parallelize(nbIterations int, work func(int, int), _ ...int) { wg.Wait() } -*/ diff --git a/test/commitments_test.go b/test/commitments_test.go index 5cf9a020a1..4336ef546e 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -76,7 +76,6 @@ func TestNoCommitmentCircuitPlonk(t *testing.T) { var fr = []ecc.ID{ ecc.BN254, - /* TODO: Add back in ecc.BLS12_381, ecc.BLS12_377, ecc.BLS24_315, @@ -84,7 +83,7 @@ var fr = []ecc.ID{ ecc.BLS24_317, ecc.BW6_633, //ecc.BW6_756, TODO: @Tabaie Not autogenerated? - ecc.BW6_761,*/ + ecc.BW6_761, } func plonkTest(t *testing.T, circuit, assignment frontend.Circuit) { From 2f722cfc68f07d8ea6add86c4cbe0edd1a9266c3 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Mon, 8 May 2023 17:03:59 -0500 Subject: [PATCH 349/464] ci: allow weak rng in marshaling tests --- backend/plonk/bls12-377/marshal_test.go | 8 ++++---- backend/plonk/bls12-381/marshal_test.go | 8 ++++---- backend/plonk/bls24-315/marshal_test.go | 8 ++++---- backend/plonk/bls24-317/marshal_test.go | 8 ++++---- backend/plonk/bn254/marshal_test.go | 8 ++++---- backend/plonk/bw6-633/marshal_test.go | 8 ++++---- backend/plonk/bw6-761/marshal_test.go | 8 ++++---- .../template/zkpschemes/plonk/tests/marshal.go.tmpl | 8 ++++---- 8 files changed, 32 insertions(+), 32 deletions(-) diff --git a/backend/plonk/bls12-377/marshal_test.go b/backend/plonk/bls12-377/marshal_test.go index 2dabbd5e27..7bbcfa2390 100644 --- a/backend/plonk/bls12-377/marshal_test.go +++ b/backend/plonk/bls12-377/marshal_test.go @@ -135,9 +135,9 @@ func (pk *ProvingKey) randomize() { pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) - pk.trace.Qcp = make([]*iop.Polynomial, rand.Intn(4)) + pk.trace.Qcp = make([]*iop.Polynomial, rand.Intn(4)) //#nosec G404 weak rng is fine here for i := range pk.trace.Qcp { - qcp := randomScalars(rand.Intn(n / 4)) + qcp := randomScalars(rand.Intn(n / 4)) //#nosec G404 weak rng is fine here pk.trace.Qcp[i] = iop.NewPolynomial(&qcp, canReg) } @@ -167,7 +167,7 @@ func (vk *VerifyingKey) randomize() { vk.Qm = randomPoint() vk.Qo = randomPoint() vk.Qk = randomPoint() - vk.Qcp = randomPoints(rand.Intn(4)) + vk.Qcp = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here } func (proof *Proof) randomize() { @@ -182,7 +182,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.PI2 = randomPoints(rand.Intn(4)) + proof.PI2 = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here } func randomPoint() curve.G1Affine { diff --git a/backend/plonk/bls12-381/marshal_test.go b/backend/plonk/bls12-381/marshal_test.go index 1130a869f5..9d5439f8b9 100644 --- a/backend/plonk/bls12-381/marshal_test.go +++ b/backend/plonk/bls12-381/marshal_test.go @@ -135,9 +135,9 @@ func (pk *ProvingKey) randomize() { pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) - pk.trace.Qcp = make([]*iop.Polynomial, rand.Intn(4)) + pk.trace.Qcp = make([]*iop.Polynomial, rand.Intn(4)) //#nosec G404 weak rng is fine here for i := range pk.trace.Qcp { - qcp := randomScalars(rand.Intn(n / 4)) + qcp := randomScalars(rand.Intn(n / 4)) //#nosec G404 weak rng is fine here pk.trace.Qcp[i] = iop.NewPolynomial(&qcp, canReg) } @@ -167,7 +167,7 @@ func (vk *VerifyingKey) randomize() { vk.Qm = randomPoint() vk.Qo = randomPoint() vk.Qk = randomPoint() - vk.Qcp = randomPoints(rand.Intn(4)) + vk.Qcp = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here } func (proof *Proof) randomize() { @@ -182,7 +182,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.PI2 = randomPoints(rand.Intn(4)) + proof.PI2 = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here } func randomPoint() curve.G1Affine { diff --git a/backend/plonk/bls24-315/marshal_test.go b/backend/plonk/bls24-315/marshal_test.go index be19d2ae58..87fa3fdd9f 100644 --- a/backend/plonk/bls24-315/marshal_test.go +++ b/backend/plonk/bls24-315/marshal_test.go @@ -135,9 +135,9 @@ func (pk *ProvingKey) randomize() { pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) - pk.trace.Qcp = make([]*iop.Polynomial, rand.Intn(4)) + pk.trace.Qcp = make([]*iop.Polynomial, rand.Intn(4)) //#nosec G404 weak rng is fine here for i := range pk.trace.Qcp { - qcp := randomScalars(rand.Intn(n / 4)) + qcp := randomScalars(rand.Intn(n / 4)) //#nosec G404 weak rng is fine here pk.trace.Qcp[i] = iop.NewPolynomial(&qcp, canReg) } @@ -167,7 +167,7 @@ func (vk *VerifyingKey) randomize() { vk.Qm = randomPoint() vk.Qo = randomPoint() vk.Qk = randomPoint() - vk.Qcp = randomPoints(rand.Intn(4)) + vk.Qcp = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here } func (proof *Proof) randomize() { @@ -182,7 +182,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.PI2 = randomPoints(rand.Intn(4)) + proof.PI2 = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here } func randomPoint() curve.G1Affine { diff --git a/backend/plonk/bls24-317/marshal_test.go b/backend/plonk/bls24-317/marshal_test.go index bc4ba341c1..f25c0178c8 100644 --- a/backend/plonk/bls24-317/marshal_test.go +++ b/backend/plonk/bls24-317/marshal_test.go @@ -135,9 +135,9 @@ func (pk *ProvingKey) randomize() { pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) - pk.trace.Qcp = make([]*iop.Polynomial, rand.Intn(4)) + pk.trace.Qcp = make([]*iop.Polynomial, rand.Intn(4)) //#nosec G404 weak rng is fine here for i := range pk.trace.Qcp { - qcp := randomScalars(rand.Intn(n / 4)) + qcp := randomScalars(rand.Intn(n / 4)) //#nosec G404 weak rng is fine here pk.trace.Qcp[i] = iop.NewPolynomial(&qcp, canReg) } @@ -167,7 +167,7 @@ func (vk *VerifyingKey) randomize() { vk.Qm = randomPoint() vk.Qo = randomPoint() vk.Qk = randomPoint() - vk.Qcp = randomPoints(rand.Intn(4)) + vk.Qcp = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here } func (proof *Proof) randomize() { @@ -182,7 +182,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.PI2 = randomPoints(rand.Intn(4)) + proof.PI2 = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here } func randomPoint() curve.G1Affine { diff --git a/backend/plonk/bn254/marshal_test.go b/backend/plonk/bn254/marshal_test.go index dab23970d6..33bfb190e1 100644 --- a/backend/plonk/bn254/marshal_test.go +++ b/backend/plonk/bn254/marshal_test.go @@ -135,9 +135,9 @@ func (pk *ProvingKey) randomize() { pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) - pk.trace.Qcp = make([]*iop.Polynomial, rand.Intn(4)) + pk.trace.Qcp = make([]*iop.Polynomial, rand.Intn(4)) //#nosec G404 weak rng is fine here for i := range pk.trace.Qcp { - qcp := randomScalars(rand.Intn(n / 4)) + qcp := randomScalars(rand.Intn(n / 4)) //#nosec G404 weak rng is fine here pk.trace.Qcp[i] = iop.NewPolynomial(&qcp, canReg) } @@ -167,7 +167,7 @@ func (vk *VerifyingKey) randomize() { vk.Qm = randomPoint() vk.Qo = randomPoint() vk.Qk = randomPoint() - vk.Qcp = randomPoints(rand.Intn(4)) + vk.Qcp = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here } func (proof *Proof) randomize() { @@ -182,7 +182,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.PI2 = randomPoints(rand.Intn(4)) + proof.PI2 = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here } func randomPoint() curve.G1Affine { diff --git a/backend/plonk/bw6-633/marshal_test.go b/backend/plonk/bw6-633/marshal_test.go index 4f025edf9c..7f53e55978 100644 --- a/backend/plonk/bw6-633/marshal_test.go +++ b/backend/plonk/bw6-633/marshal_test.go @@ -135,9 +135,9 @@ func (pk *ProvingKey) randomize() { pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) - pk.trace.Qcp = make([]*iop.Polynomial, rand.Intn(4)) + pk.trace.Qcp = make([]*iop.Polynomial, rand.Intn(4)) //#nosec G404 weak rng is fine here for i := range pk.trace.Qcp { - qcp := randomScalars(rand.Intn(n / 4)) + qcp := randomScalars(rand.Intn(n / 4)) //#nosec G404 weak rng is fine here pk.trace.Qcp[i] = iop.NewPolynomial(&qcp, canReg) } @@ -167,7 +167,7 @@ func (vk *VerifyingKey) randomize() { vk.Qm = randomPoint() vk.Qo = randomPoint() vk.Qk = randomPoint() - vk.Qcp = randomPoints(rand.Intn(4)) + vk.Qcp = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here } func (proof *Proof) randomize() { @@ -182,7 +182,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.PI2 = randomPoints(rand.Intn(4)) + proof.PI2 = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here } func randomPoint() curve.G1Affine { diff --git a/backend/plonk/bw6-761/marshal_test.go b/backend/plonk/bw6-761/marshal_test.go index 66548853b6..5b5fc253db 100644 --- a/backend/plonk/bw6-761/marshal_test.go +++ b/backend/plonk/bw6-761/marshal_test.go @@ -135,9 +135,9 @@ func (pk *ProvingKey) randomize() { pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) - pk.trace.Qcp = make([]*iop.Polynomial, rand.Intn(4)) + pk.trace.Qcp = make([]*iop.Polynomial, rand.Intn(4)) //#nosec G404 weak rng is fine here for i := range pk.trace.Qcp { - qcp := randomScalars(rand.Intn(n / 4)) + qcp := randomScalars(rand.Intn(n / 4)) //#nosec G404 weak rng is fine here pk.trace.Qcp[i] = iop.NewPolynomial(&qcp, canReg) } @@ -167,7 +167,7 @@ func (vk *VerifyingKey) randomize() { vk.Qm = randomPoint() vk.Qo = randomPoint() vk.Qk = randomPoint() - vk.Qcp = randomPoints(rand.Intn(4)) + vk.Qcp = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here } func (proof *Proof) randomize() { @@ -182,7 +182,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.PI2 = randomPoints(rand.Intn(4)) + proof.PI2 = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here } func randomPoint() curve.G1Affine { diff --git a/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl index 3a31b472f4..749ba01da0 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl @@ -116,9 +116,9 @@ func (pk *ProvingKey) randomize() { pk.trace.S2 = iop.NewPolynomial(&s2, canReg) pk.trace.S3 = iop.NewPolynomial(&s3, canReg) - pk.trace.Qcp = make([]*iop.Polynomial, rand.Intn(4)) + pk.trace.Qcp = make([]*iop.Polynomial, rand.Intn(4)) //#nosec G404 weak rng is fine here for i := range pk.trace.Qcp { - qcp := randomScalars(rand.Intn(n / 4)) + qcp := randomScalars(rand.Intn(n / 4)) //#nosec G404 weak rng is fine here pk.trace.Qcp[i] = iop.NewPolynomial(&qcp, canReg) } @@ -148,7 +148,7 @@ func (vk *VerifyingKey) randomize() { vk.Qm = randomPoint() vk.Qo = randomPoint() vk.Qk = randomPoint() - vk.Qcp = randomPoints(rand.Intn(4)) + vk.Qcp = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here } func (proof *Proof) randomize() { @@ -163,7 +163,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.PI2 = randomPoints(rand.Intn(4)) + proof.PI2 = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here } func randomPoint() curve.G1Affine { From 1764232e942f7c6b1bf6a7258d67251ffab7db5b Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Mon, 8 May 2023 17:10:56 -0500 Subject: [PATCH 350/464] revert changes to testing utils --- test/kzg_srs.go | 1 - test/solver_test.go | 16 ++-------------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/test/kzg_srs.go b/test/kzg_srs.go index f34a670d95..c67b89be7f 100644 --- a/test/kzg_srs.go +++ b/test/kzg_srs.go @@ -83,7 +83,6 @@ func newKZGSRS(curve ecc.ID, kzgSize uint64) (kzg.SRS, error) { if err != nil { return nil, err } - alpha.SetUint64(0) switch curve { case ecc.BN254: diff --git a/test/solver_test.go b/test/solver_test.go index f91d6e607a..88e0d39b92 100644 --- a/test/solver_test.go +++ b/test/solver_test.go @@ -2,7 +2,6 @@ package test import ( "fmt" - "github.com/consensys/gnark/internal/backend/circuits" "io" "math/big" "reflect" @@ -18,6 +17,7 @@ import ( "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/consensys/gnark/frontend/cs/scs" "github.com/consensys/gnark/frontend/schema" + "github.com/consensys/gnark/internal/backend/circuits" "github.com/consensys/gnark/internal/kvstore" "github.com/consensys/gnark/internal/tinyfield" "github.com/consensys/gnark/internal/utils" @@ -43,9 +43,7 @@ func TestSolverConsistency(t *testing.T) { // we generate witnesses and compare with the output of big.Int test engine against // R1CS and SparseR1CS solvers - names := map[string]interface{}{"and": nil, "or": nil} - - for name := range names /*circuits.Circuits*/ { + for name := range circuits.Circuits { t.Run(name, func(t *testing.T) { tc := circuits.Circuits[name] t.Parallel() @@ -238,15 +236,6 @@ func copyWitnessFromVector(to frontend.Circuit, from []tinyfield.Element) { }) } -func getCircuitName(circuit frontend.Circuit) string { - for name, c := range circuits.Circuits { - if c.Circuit == circuit { - return name - } - } - panic("not found") -} - // ConsistentSolver solves given circuit with all possible witness combinations using internal/tinyfield // // Since the goal of this method is to flag potential solver issues, it is not exposed as an API for now @@ -264,7 +253,6 @@ func consistentSolver(circuit frontend.Circuit, hintFunctions []solver.Hint) err if err != nil { return err } - p.constraintSystems[i] = ccs if i == 0 { // the -1 is only for r1cs... From 697bec15a4aea81acbe59e55e3d57eef9de03565 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Mon, 8 May 2023 17:14:39 -0500 Subject: [PATCH 351/464] revert adding test files --- backend/plonk/bn254/good.txt | 376 ----------------------------------- 1 file changed, 376 deletions(-) delete mode 100644 backend/plonk/bn254/good.txt diff --git a/backend/plonk/bn254/good.txt b/backend/plonk/bn254/good.txt deleted file mode 100644 index 7684d85212..0000000000 --- a/backend/plonk/bn254/good.txt +++ /dev/null @@ -1,376 +0,0 @@ -package plonk - -import ( - "crypto/sha256" - "fmt" - "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark/logger" - "io" - "math/big" - "time" -) - -// Copyright 2020 ConsenSys Software Inc. -// -// 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. - -// Code generated by gnark DO NOT EDIT - -package plonk - -import ( - "crypto/sha256" - "errors" - "fmt" - "io" - "math/big" - "time" - - "github.com/consensys/gnark-crypto/ecc/bn254/fr" - - "github.com/consensys/gnark-crypto/ecc/bn254/fr/kzg" - - curve "github.com/consensys/gnark-crypto/ecc/bn254" - - "text/template" - - "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/fiat-shamir" - "github.com/consensys/gnark/logger" -) - -var ( - errWrongClaimedQuotient = errors.New("claimed quotient is not as expected") -) - -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { - log := logger.Logger().With().Str("curve", "bn254").Str("backend", "plonk").Logger() - start := time.Now() - - // pick a hash function to derive the challenge (the same as in the prover) - hFunc := sha256.New() - - // transcript to derive the challenge - fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") - - // The first challenge is derived using the public data: the commitments to the permutation, - // the coefficients of the circuit, and the public inputs. - // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *vk, publicWitness, proof.PI2); err != nil { - return err - } - gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) - if err != nil { - return err - } - - // derive beta from Comm(l), Comm(r), Comm(o) - beta, err := deriveRandomness(&fs, "beta") - if err != nil { - return err - } - - // derive alpha from Comm(l), Comm(r), Comm(o), Com(Z) - alpha, err := deriveRandomness(&fs, "alpha", &proof.Z) - if err != nil { - return err - } - - // derive zeta, the point of evaluation - zeta, err := deriveRandomness(&fs, "zeta", &proof.H[0], &proof.H[1], &proof.H[2]) - if err != nil { - return err - } - - // evaluation of Z=Xⁿ⁻¹ at ζ - var zetaPowerM, zzeta fr.Element - var bExpo big.Int - one := fr.One() - bExpo.SetUint64(vk.Size) - zetaPowerM.Exp(zeta, &bExpo) - zzeta.Sub(&zetaPowerM, &one) - - // compute PI = ∑_{i PI2[i] - if hashRes, err = fr.Hash(proof.PI2.Marshal(), []byte("BSB22-Plonk"), 1); err != nil { - return err - } - - // Computing L_{CommitmentIndex} - - wPowI.Exp(vk.Generator, big.NewInt(int64(vk.NbPublicVariables)+int64(vk.CommitmentConstraintIndexes[i]))) - den.Sub(&zeta, &wPowI) // ζ-wⁱ - - lagrange.SetOne(). - Sub(&zeta, &lagrange). // ζ-1 - Mul(&lagrange, &wPowI). // wⁱ(ζ-1) - Div(&lagrange, &den). // wⁱ(ζ-1)/(ζ-wⁱ) - Mul(&lagrange, &lagrangeOne) // wⁱ/n (ζⁿ-1)/(ζ-wⁱ) - - xiLi.Mul(&lagrange, &hashRes[0]) - pi.Add(&pi, &xiLi) - } - } - - fmt.Println("pi =", pi.Text(16)) - - // linearizedpolynomial + pi(ζ) + α*(Z(μζ))*(l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*(o(ζ)+γ) - α²*L₁(ζ) - var _s1, _s2, _o, alphaSquareLagrange fr.Element - - zu := proof.ZShiftedOpening.ClaimedValue - - claimedQuotient := proof.BatchedProof.ClaimedValues[1] - linearizedPolynomialZeta := proof.BatchedProof.ClaimedValues[2] - l := proof.BatchedProof.ClaimedValues[3] - r := proof.BatchedProof.ClaimedValues[4] - o := proof.BatchedProof.ClaimedValues[5] - s1 := proof.BatchedProof.ClaimedValues[6] - s2 := proof.BatchedProof.ClaimedValues[7] - qC := proof.BatchedProof.ClaimedValues[0] - - _s1.Mul(&s1, &beta).Add(&_s1, &l).Add(&_s1, &gamma) // (l(ζ)+β*s1(ζ)+γ) - _s2.Mul(&s2, &beta).Add(&_s2, &r).Add(&_s2, &gamma) // (r(ζ)+β*s2(ζ)+γ) - _o.Add(&o, &gamma) // (o(ζ)+γ) - - _s1.Mul(&_s1, &_s2). - Mul(&_s1, &_o). - Mul(&_s1, &alpha). - Mul(&_s1, &zu) // α*(Z(μζ))*(l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*(o(ζ)+γ) - - alphaSquareLagrange.Mul(&lagrangeOne, &alpha). - Mul(&alphaSquareLagrange, &alpha) // α²*L₁(ζ) - - linearizedPolynomialZeta. - Add(&linearizedPolynomialZeta, &pi). // linearizedpolynomial + pi(zeta) - Add(&linearizedPolynomialZeta, &_s1). // linearizedpolynomial+pi(zeta)+α*(Z(μζ))*(l(ζ)+s1(ζ)+γ)*(r(ζ)+s2(ζ)+γ)*(o(ζ)+γ) - Sub(&linearizedPolynomialZeta, &alphaSquareLagrange) // linearizedpolynomial+pi(zeta)+α*(Z(μζ))*(l(ζ)+s1(ζ)+γ)*(r(ζ)+s2(ζ)+γ)*(o(ζ)+γ)-α²*L₁(ζ) - - // Compute H(ζ) using the previous result: H(ζ) = prev_result/(ζⁿ-1) - var zetaPowerMMinusOne fr.Element - zetaPowerMMinusOne.Sub(&zetaPowerM, &one) - linearizedPolynomialZeta.Div(&linearizedPolynomialZeta, &zetaPowerMMinusOne) - - // check that H(ζ) is as claimed - if !claimedQuotient.Equal(&linearizedPolynomialZeta) { - return errWrongClaimedQuotient - } - - fmt.Println("quotient =", claimedQuotient.Text(16)) - - // compute the folded commitment to H: Comm(h₁) + ζᵐ⁺²*Comm(h₂) + ζ²⁽ᵐ⁺²⁾*Comm(h₃) - mPlusTwo := big.NewInt(int64(vk.Size) + 2) - var zetaMPlusTwo fr.Element - zetaMPlusTwo.Exp(zeta, mPlusTwo) - var zetaMPlusTwoBigInt big.Int - zetaMPlusTwo.BigInt(&zetaMPlusTwoBigInt) - foldedH := proof.H[2] - foldedH.ScalarMultiplication(&foldedH, &zetaMPlusTwoBigInt) - foldedH.Add(&foldedH, &proof.H[1]) - foldedH.ScalarMultiplication(&foldedH, &zetaMPlusTwoBigInt) - foldedH.Add(&foldedH, &proof.H[0]) - - // Compute the commitment to the linearized polynomial - // linearizedPolynomialDigest = - // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+qc*PI2 + - // α*( Z(μζ)(l(ζ)+β*s₁(ζ)+γ)*(r(ζ)+β*s₂(ζ)+γ)*s₃(X)-Z(X)(l(ζ)+β*id_1(ζ)+γ)*(r(ζ)+β*id_2(ζ)+γ)*(o(ζ)+β*id_3(ζ)+γ) ) + - // α²*L₁(ζ)*Z - // first part: individual constraints - var rl fr.Element - rl.Mul(&l, &r) - - var linearizedPolynomialDigest curve.G1Affine - - // second part: α*( Z(μζ)(l(ζ)+β*s₁(ζ)+γ)*(r(ζ)+β*s₂(ζ)+γ)*β*s₃(X)-Z(X)(l(ζ)+β*id_1(ζ)+γ)*(r(ζ)+β*id_2(ζ)+γ)*(o(ζ)+β*id_3(ζ)+γ) ) ) - - var u, v, w, cosetsquare fr.Element - u.Mul(&zu, &beta) - v.Mul(&beta, &s1).Add(&v, &l).Add(&v, &gamma) - w.Mul(&beta, &s2).Add(&w, &r).Add(&w, &gamma) - _s1.Mul(&u, &v).Mul(&_s1, &w).Mul(&_s1, &alpha) // α*Z(μζ)(l(ζ)+β*s₁(ζ)+γ)*(r(ζ)+β*s₂(ζ)+γ)*β - - cosetsquare.Square(&vk.CosetShift) - u.Mul(&beta, &zeta).Add(&u, &l).Add(&u, &gamma) // (l(ζ)+β*ζ+γ) - v.Mul(&beta, &zeta).Mul(&v, &vk.CosetShift).Add(&v, &r).Add(&v, &gamma) // (r(ζ)+β*μ*ζ+γ) - w.Mul(&beta, &zeta).Mul(&w, &cosetsquare).Add(&w, &o).Add(&w, &gamma) // (o(ζ)+β*μ²*ζ+γ) - _s2.Mul(&u, &v).Mul(&_s2, &w).Neg(&_s2) // -(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) - - // note since third part = α²*L₁(ζ)*Z - _s2.Mul(&_s2, &alpha).Add(&_s2, &alphaSquareLagrange) // -α*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + α²*L₁(ζ) - - points := []curve.G1Affine{ - vk.Ql, vk.Qr, vk.Qm, vk.Qo, vk.Qk, proof.PI2, // first part - vk.S[2], proof.Z, // second & third part - } - - scalars := []fr.Element{ - l, r, rl, o, one /* TODO Perf @Tabaie Consider just adding Qk instead */, qC, // first part - _s1, _s2, // second & third part - } - if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{}); err != nil { - return err - } - - fmt.Println("linearizedPolynomialDigest =", linearizedPolynomialDigest.String()) - fmt.Println("foldedH =", foldedH.String()) - - // Fold the first proof - foldedProof, foldedDigest, err := kzg.FoldProof([]kzg.Digest{ - vk.Qcp, - foldedH, - linearizedPolynomialDigest, - proof.LRO[0], - proof.LRO[1], - proof.LRO[2], - vk.S[0], - vk.S[1], - }, - &proof.BatchedProof, - zeta, - hFunc, - ) - if err != nil { - return err - } - - // Batch verify - var shiftedZeta fr.Element - shiftedZeta.Mul(&zeta, &vk.Generator) - - fmt.Println("foldedDigest =", foldedDigest.String()) - - err = kzg.BatchVerifyMultiPoints([]kzg.Digest{ - foldedDigest, - proof.Z, - }, - []kzg.OpeningProof{ - foldedProof, - proof.ZShiftedOpening, - }, - []fr.Element{ - zeta, - shiftedZeta, - }, - vk.Kzg, - ) - - log.Debug().Dur("took", time.Since(start)).Msg("verifier done") - - return err -} - -func bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey, publicInputs []fr.Element, pi2 kzg.Digest) error { - - // permutation - if err := fs.Bind(challenge, vk.S[0].Marshal()); err != nil { - return err - } - if err := fs.Bind(challenge, vk.S[1].Marshal()); err != nil { - return err - } - if err := fs.Bind(challenge, vk.S[2].Marshal()); err != nil { - return err - } - - // coefficients - if err := fs.Bind(challenge, vk.Ql.Marshal()); err != nil { - return err - } - if err := fs.Bind(challenge, vk.Qr.Marshal()); err != nil { - return err - } - if err := fs.Bind(challenge, vk.Qm.Marshal()); err != nil { - return err - } - if err := fs.Bind(challenge, vk.Qo.Marshal()); err != nil { - return err - } - if err := fs.Bind(challenge, vk.Qk.Marshal()); err != nil { - return err - } - - // public inputs - for i := 0; i < len(publicInputs); i++ { - if err := fs.Bind(challenge, publicInputs[i].Marshal()); err != nil { - return err - } - } - - // bsb22 commitment - if err := fs.Bind(challenge, pi2.Marshal()); err != nil { - return err - } - - return nil - -} - -func deriveRandomness(fs *fiatshamir.Transcript, challenge string, points ...*curve.G1Affine) (fr.Element, error) { - - var buf [curve.SizeOfG1AffineUncompressed]byte - var r fr.Element - - for _, p := range points { - buf = p.RawBytes() - if err := fs.Bind(challenge, buf[:]); err != nil { - return r, err - } - } - - b, err := fs.ComputeChallenge(challenge) - if err != nil { - return r, err - } - - return r, nil - - r.SetBytes(b) - return r, nil -} - -// ExportSolidity exports the verifying key to a solidity smart contract. -// -// See https://github.com/ConsenSys/gnark-tests for example usage. -// -// Code has not been audited and is provided as-is, we make no guarantees or warranties to its safety and reliability. -func (vk *VerifyingKey) ExportSolidity(w io.Writer) error { - tmpl, err := template.New("").Parse(solidityTemplate) - if err != nil { - return err - } - return tmpl.Execute(w, vk) -} From 0b4ed1328f8e36750bd950711a8a4e98910c28df Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Mon, 8 May 2023 19:59:33 -0500 Subject: [PATCH 352/464] refactor: r1cs NewNamedHint not taking hint func --- frontend/builder.go | 2 +- frontend/cs/r1cs/builder.go | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/frontend/builder.go b/frontend/builder.go index 3cc17a4a44..672f01f912 100644 --- a/frontend/builder.go +++ b/frontend/builder.go @@ -37,7 +37,7 @@ type Compiler interface { // // If nbOutputs is specified, it must be >= 1 and <= f.NbOutputs NewHint(f solver.Hint, nbOutputs int, inputs ...Variable) ([]Variable, error) - NewNamedHint(f solver.Hint, nameOptions *constraint.HintIds, nbOutputs int, inputs ...Variable) ([]Variable, error) + NewNamedHint(id solver.HintID, nbOutputs int, inputs ...Variable) ([]Variable, error) // ConstantValue returns the big.Int value of v and true if op is a success. // nil and false if failure. This API returns a boolean to allow for future refactoring diff --git a/frontend/cs/r1cs/builder.go b/frontend/cs/r1cs/builder.go index ed3beb9c9c..799f0d1b26 100644 --- a/frontend/cs/r1cs/builder.go +++ b/frontend/cs/r1cs/builder.go @@ -371,10 +371,14 @@ func (builder *builder) toVariables(in ...frontend.Variable) ([]expr.LinearExpre // No new constraints are added to the newly created wire and must be added // manually in the circuit. Failing to do so leads to solver failure. func (builder *builder) NewHint(f solver.Hint, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { - return builder.NewNamedHint(f, nil, nbOutputs, inputs...) + return builder.newHint(f, 0, nbOutputs, inputs) } -func (builder *builder) NewNamedHint(f solver.Hint, nameOptions *constraint.HintIds, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { +func (builder *builder) NewNamedHint(id solver.HintID, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { + return builder.newHint(nil, id, nbOutputs, inputs) +} + +func (builder *builder) newHint(f solver.Hint, id solver.HintID, nbOutputs int, inputs []frontend.Variable) ([]frontend.Variable, error) { hintInputs := make([]constraint.LinearExpression, len(inputs)) // TODO @gbotrel hint input pass @@ -392,10 +396,9 @@ func (builder *builder) NewNamedHint(f solver.Hint, nameOptions *constraint.Hint } var options []constraint.HintIdOption - if nameOptions != nil { + if f == nil { options = []constraint.HintIdOption{ - constraint.WithHintId(nameOptions.UUID), - constraint.WithHintName(nameOptions.Name), + constraint.WithHintId(id), } } From 7320d8940ba8e71659e16ad1ed4f9505afbc8dce Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 9 May 2023 11:23:10 -0500 Subject: [PATCH 353/464] refactor: NewNamedHint not taking hint function input --- constraint/core.go | 27 +++++++++++++++------------ constraint/hint.go | 14 -------------- constraint/solver/hint_registry.go | 4 ++++ constraint/system.go | 3 ++- frontend/cs/r1cs/builder.go | 11 ++--------- frontend/cs/scs/builder.go | 17 ++++++----------- test/engine.go | 9 ++++++--- test/hint_test.go | 10 +--------- 8 files changed, 36 insertions(+), 59 deletions(-) diff --git a/constraint/core.go b/constraint/core.go index 0096ad604d..a62ade95c3 100644 --- a/constraint/core.go +++ b/constraint/core.go @@ -3,6 +3,7 @@ package constraint import ( "fmt" "math/big" + "strconv" "github.com/blang/semver/v4" "github.com/consensys/gnark" @@ -205,25 +206,27 @@ func (system *System) AddSecretVariable(name string) (idx int) { return idx } -func (system *System) AddSolverHint(f solver.Hint, input []LinearExpression, nbOutput int, options ...HintIdOption) (internalVariables []int, err error) { +func (system *System) AddSolverHint(f solver.Hint, id solver.HintID, input []LinearExpression, nbOutput int) (internalVariables []int, err error) { if nbOutput <= 0 { return nil, fmt.Errorf("hint function must return at least one output") } - // register the hint as dependency - ID := HintIds{solver.GetHintID(f), solver.GetHintName(f)} - - for i := range options { - options[i](&ID) + // TODO @Tabaie @gbotrel consider getting rid of hint names entirely + var name string + if id == solver.GetHintID(f) { + name = solver.GetHintName(f) + } else { + name = strconv.Itoa(int(id)) } - if id, ok := system.MHintsDependencies[ID.UUID]; ok { - // hint already registered, let's ensure string id matches - if id != ID.Name { - return nil, fmt.Errorf("hint dependency registration failed; %s previously register with same UUID as %s", ID.Name, id) + // register the hint as dependency + if registeredName, ok := system.MHintsDependencies[id]; ok { + // hint already registered, let's ensure string registeredName matches + if registeredName != name { + return nil, fmt.Errorf("hint dependency registration failed; %s previously register with same UUID as %s", name, registeredName) } } else { - system.MHintsDependencies[ID.UUID] = ID.Name + system.MHintsDependencies[id] = name } // prepare wires @@ -234,7 +237,7 @@ func (system *System) AddSolverHint(f solver.Hint, input []LinearExpression, nbO // associate these wires with the solver hint hm := HintMapping{ - HintID: ID.UUID, + HintID: id, Inputs: input, OutputRange: struct { Start uint32 diff --git a/constraint/hint.go b/constraint/hint.go index e2455a0c48..166f542d3d 100644 --- a/constraint/hint.go +++ b/constraint/hint.go @@ -9,20 +9,6 @@ type HintIds struct { Name string } -type HintIdOption func(*HintIds) - -func WithHintId(id solver.HintID) HintIdOption { - return func(_id *HintIds) { - _id.UUID = id - } -} - -func WithHintName(name string) HintIdOption { - return func(id *HintIds) { - id.Name = name - } -} - // HintMapping mark a list of output variables to be computed using provided hint and inputs. type HintMapping struct { HintID solver.HintID // Hint function id diff --git a/constraint/solver/hint_registry.go b/constraint/solver/hint_registry.go index b5451bc50e..7021de5024 100644 --- a/constraint/solver/hint_registry.go +++ b/constraint/solver/hint_registry.go @@ -33,6 +33,10 @@ func RegisterHint(hintFns ...Hint) { } } +func GetRegisteredHint(key HintID) Hint { + return registry[key] +} + func RegisterNamedHint(hintFn Hint, key HintID) { registryM.Lock() defer registryM.Unlock() diff --git a/constraint/system.go b/constraint/system.go index 7e6ba3eda8..330c26a63d 100644 --- a/constraint/system.go +++ b/constraint/system.go @@ -45,7 +45,8 @@ type ConstraintSystem interface { // AddSolverHint adds a hint to the solver such that the output variables will be computed // using a call to output := f(input...) at solve time. - AddSolverHint(f solver.Hint, input []LinearExpression, nbOutput int, options ...HintIdOption) (internalVariables []int, err error) + // Providing the function f is optional. + AddSolverHint(f solver.Hint, id solver.HintID, input []LinearExpression, nbOutput int) (internalVariables []int, err error) AddCommitment(c Commitment) error diff --git a/frontend/cs/r1cs/builder.go b/frontend/cs/r1cs/builder.go index 799f0d1b26..b517c0562e 100644 --- a/frontend/cs/r1cs/builder.go +++ b/frontend/cs/r1cs/builder.go @@ -371,7 +371,7 @@ func (builder *builder) toVariables(in ...frontend.Variable) ([]expr.LinearExpre // No new constraints are added to the newly created wire and must be added // manually in the circuit. Failing to do so leads to solver failure. func (builder *builder) NewHint(f solver.Hint, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { - return builder.newHint(f, 0, nbOutputs, inputs) + return builder.newHint(f, solver.GetHintID(f), nbOutputs, inputs) } func (builder *builder) NewNamedHint(id solver.HintID, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { @@ -395,14 +395,7 @@ func (builder *builder) newHint(f solver.Hint, id solver.HintID, nbOutputs int, } } - var options []constraint.HintIdOption - if f == nil { - options = []constraint.HintIdOption{ - constraint.WithHintId(id), - } - } - - internalVariables, err := builder.cs.AddSolverHint(f, hintInputs, nbOutputs, options...) + internalVariables, err := builder.cs.AddSolverHint(f, id, hintInputs, nbOutputs) if err != nil { return nil, err } diff --git a/frontend/cs/scs/builder.go b/frontend/cs/scs/builder.go index cd977c1a6f..1ed0f3c8dc 100644 --- a/frontend/cs/scs/builder.go +++ b/frontend/cs/scs/builder.go @@ -342,11 +342,14 @@ func (builder *builder) hintBuffer(size int) []constraint.LinearExpression { // No new constraints are added to the newly created wire and must be added // manually in the circuit. Failing to do so leads to solver failure. func (builder *builder) NewHint(f solver.Hint, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { - return builder.NewNamedHint(f, nil, nbOutputs, inputs...) + return builder.newHint(f, solver.GetHintID(f), nbOutputs, inputs...) } -func (builder *builder) NewNamedHint(f solver.Hint, nameOptions *constraint.HintIds, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { +func (builder *builder) NewNamedHint(id solver.HintID, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { + return builder.newHint(nil, id, nbOutputs, inputs) +} +func (builder *builder) newHint(f solver.Hint, id solver.HintID, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { hintInputs := builder.hintBuffer(len(inputs)) // ensure inputs are set and pack them in a []uint64 @@ -362,15 +365,7 @@ func (builder *builder) NewNamedHint(f solver.Hint, nameOptions *constraint.Hint } } - var options []constraint.HintIdOption - if nameOptions != nil { - options = []constraint.HintIdOption{ - constraint.WithHintId(nameOptions.UUID), - constraint.WithHintName(nameOptions.Name), - } - } - - internalVariables, err := builder.cs.AddSolverHint(f, hintInputs, nbOutputs, options...) + internalVariables, err := builder.cs.AddSolverHint(f, id, hintInputs, nbOutputs) if err != nil { return nil, err } diff --git a/test/engine.go b/test/engine.go index 841a4e238e..f14c1d25e6 100644 --- a/test/engine.go +++ b/test/engine.go @@ -18,7 +18,6 @@ package test import ( "fmt" - "github.com/consensys/gnark/constraint" "math/big" "path/filepath" "reflect" @@ -486,8 +485,12 @@ func (e *engine) NewHint(f solver.Hint, nbOutputs int, inputs ...frontend.Variab return out, nil } -func (e *engine) NewNamedHint(f solver.Hint, _ *constraint.HintIds, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { - return e.NewHint(f, nbOutputs, inputs...) +func (e *engine) NewNamedHint(id solver.HintID, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { + if f := solver.GetRegisteredHint(id); f != nil { + return e.NewHint(f, nbOutputs, inputs...) + } + + return nil, fmt.Errorf("no hint registered with id #%d. Use solver.RegisterHint or solver.RegisterNamedHint", id) } // IsConstant returns true if v is a constant known at compile time diff --git a/test/hint_test.go b/test/hint_test.go index 4a74301944..b445b87692 100644 --- a/test/hint_test.go +++ b/test/hint_test.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/backend/witness" - "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" @@ -13,7 +12,6 @@ import ( "testing" ) -const name = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." const id = solver.HintID(123454321) func identityHint(_ *big.Int, in, out []*big.Int) error { @@ -31,13 +29,7 @@ type customNamedHintCircuit struct { } func (c *customNamedHintCircuit) Define(api frontend.API) error { - y, err := api.Compiler().NewNamedHint(identityHint, - &constraint.HintIds{ - UUID: id, - Name: name, - }, - len(c.X), c.X..., - ) + y, err := api.Compiler().NewNamedHint(id, len(c.X), c.X...) if err != nil { return err From 59d12aa58579ccdc5b6d3cfcc4c2a2192c303e02 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 9 May 2023 11:25:16 -0500 Subject: [PATCH 354/464] refactor: remove HintIds struct --- constraint/hint.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/constraint/hint.go b/constraint/hint.go index 166f542d3d..a79bfea41d 100644 --- a/constraint/hint.go +++ b/constraint/hint.go @@ -4,11 +4,6 @@ import ( "github.com/consensys/gnark/constraint/solver" ) -type HintIds struct { - UUID solver.HintID - Name string -} - // HintMapping mark a list of output variables to be computed using provided hint and inputs. type HintMapping struct { HintID solver.HintID // Hint function id From 1586fa660752b1d3a7f5c31900047a3d8d3bc350 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 9 May 2023 12:07:22 -0500 Subject: [PATCH 355/464] fix: newNamedHint bug --- frontend/cs/scs/builder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/cs/scs/builder.go b/frontend/cs/scs/builder.go index a10c248c3a..24b5bc3d9e 100644 --- a/frontend/cs/scs/builder.go +++ b/frontend/cs/scs/builder.go @@ -346,7 +346,7 @@ func (builder *builder) NewHint(f solver.Hint, nbOutputs int, inputs ...frontend } func (builder *builder) NewNamedHint(id solver.HintID, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { - return builder.newHint(nil, id, nbOutputs, inputs) + return builder.newHint(nil, id, nbOutputs, inputs...) } func (builder *builder) newHint(f solver.Hint, id solver.HintID, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { From 81bc27173045610a54f3270816f6e460eabac6bc Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 9 May 2023 14:57:25 -0500 Subject: [PATCH 356/464] docs: explain the optionality of f in AddSolverHint --- constraint/system.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/constraint/system.go b/constraint/system.go index 5bf2a8a51a..d814e2de2c 100644 --- a/constraint/system.go +++ b/constraint/system.go @@ -46,7 +46,8 @@ type ConstraintSystem interface { // AddSolverHint adds a hint to the solver such that the output variables will be computed // using a call to output := f(input...) at solve time. - // Providing the function f is optional. + // Providing the function f is optional. If it is provided, id will be ignored and one will be derived from f's name. + // Otherwise, the provided id will be used to register the hint with, AddSolverHint(f solver.Hint, id solver.HintID, input []LinearExpression, nbOutput int) (internalVariables []int, err error) AddCommitment(c Commitment) error From d3b97f958393098e2b075aef9efe35bae0493a88 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 9 May 2023 15:33:06 -0500 Subject: [PATCH 357/464] refactor: renaming as per robot overlords --- constraint/core.go | 1 - frontend/builder.go | 2 +- frontend/cs/r1cs/builder.go | 2 +- frontend/cs/scs/builder.go | 2 +- test/engine.go | 2 +- test/hint_test.go | 2 +- 6 files changed, 5 insertions(+), 6 deletions(-) diff --git a/constraint/core.go b/constraint/core.go index b516501e74..3f964ce07c 100644 --- a/constraint/core.go +++ b/constraint/core.go @@ -246,7 +246,6 @@ func (system *System) AddSolverHint(f solver.Hint, id solver.HintID, input []Lin return nil, fmt.Errorf("hint function must return at least one output") } - // TODO @Tabaie @gbotrel consider getting rid of hint names entirely var name string if id == solver.GetHintID(f) { name = solver.GetHintName(f) diff --git a/frontend/builder.go b/frontend/builder.go index 5fe9153aae..680a789b7a 100644 --- a/frontend/builder.go +++ b/frontend/builder.go @@ -39,7 +39,7 @@ type Compiler interface { // // If nbOutputs is specified, it must be >= 1 and <= f.NbOutputs NewHint(f solver.Hint, nbOutputs int, inputs ...Variable) ([]Variable, error) - NewNamedHint(id solver.HintID, nbOutputs int, inputs ...Variable) ([]Variable, error) + NewHintForId(id solver.HintID, nbOutputs int, inputs ...Variable) ([]Variable, error) // ConstantValue returns the big.Int value of v and true if op is a success. // nil and false if failure. This API returns a boolean to allow for future refactoring diff --git a/frontend/cs/r1cs/builder.go b/frontend/cs/r1cs/builder.go index 0b6a4ceeee..1a27261bda 100644 --- a/frontend/cs/r1cs/builder.go +++ b/frontend/cs/r1cs/builder.go @@ -374,7 +374,7 @@ func (builder *builder) NewHint(f solver.Hint, nbOutputs int, inputs ...frontend return builder.newHint(f, solver.GetHintID(f), nbOutputs, inputs) } -func (builder *builder) NewNamedHint(id solver.HintID, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { +func (builder *builder) NewHintForId(id solver.HintID, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { return builder.newHint(nil, id, nbOutputs, inputs) } diff --git a/frontend/cs/scs/builder.go b/frontend/cs/scs/builder.go index 24b5bc3d9e..eee785663a 100644 --- a/frontend/cs/scs/builder.go +++ b/frontend/cs/scs/builder.go @@ -345,7 +345,7 @@ func (builder *builder) NewHint(f solver.Hint, nbOutputs int, inputs ...frontend return builder.newHint(f, solver.GetHintID(f), nbOutputs, inputs...) } -func (builder *builder) NewNamedHint(id solver.HintID, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { +func (builder *builder) NewHintForId(id solver.HintID, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { return builder.newHint(nil, id, nbOutputs, inputs...) } diff --git a/test/engine.go b/test/engine.go index faddd40dba..3a1dd6879e 100644 --- a/test/engine.go +++ b/test/engine.go @@ -489,7 +489,7 @@ func (e *engine) NewHint(f solver.Hint, nbOutputs int, inputs ...frontend.Variab return out, nil } -func (e *engine) NewNamedHint(id solver.HintID, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { +func (e *engine) NewHintForId(id solver.HintID, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { if f := solver.GetRegisteredHint(id); f != nil { return e.NewHint(f, nbOutputs, inputs...) } diff --git a/test/hint_test.go b/test/hint_test.go index b445b87692..b2e862fdd5 100644 --- a/test/hint_test.go +++ b/test/hint_test.go @@ -29,7 +29,7 @@ type customNamedHintCircuit struct { } func (c *customNamedHintCircuit) Define(api frontend.API) error { - y, err := api.Compiler().NewNamedHint(id, len(c.X), c.X...) + y, err := api.Compiler().NewHintForId(id, len(c.X), c.X...) if err != nil { return err From ffdcd611a4f69ead54ebe9816fac65990349e52d Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 9 May 2023 22:07:24 -0500 Subject: [PATCH 358/464] build: merge named hint PR --- frontend/cs/commitment.go | 16 +++++++--------- frontend/cs/r1cs/heap.go | 2 +- frontend/cs/scs/api.go | 6 +++--- test/engine.go | 1 + 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/frontend/cs/commitment.go b/frontend/cs/commitment.go index 21af93792a..f0d555ee2d 100644 --- a/frontend/cs/commitment.go +++ b/frontend/cs/commitment.go @@ -3,7 +3,6 @@ package cs import ( "crypto/sha256" "fmt" - "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/debug" "github.com/consensys/gnark/logger" @@ -35,23 +34,22 @@ func Bsb22CommitmentComputePlaceholder(mod *big.Int, input []*big.Int, output [] } var maxNbCommitments int -var m sync.Mutex // TODO: Remove; this is only used in the frontend which is not required to be thread-safe +var m sync.Mutex -func RegisterBsb22CommitmentComputePlaceholder(index int) (hintName constraint.HintIds, err error) { - hintName = constraint.HintIds{ - Name: "bsb22 commitment #" + strconv.Itoa(index), - } +func RegisterBsb22CommitmentComputePlaceholder(index int) (hintId solver.HintID, err error) { + + hintName := "bsb22 commitment #" + strconv.Itoa(index) // mimic solver.GetHintID hf := fnv.New32a() - if _, err = hf.Write([]byte(hintName.Name)); err != nil { + if _, err = hf.Write([]byte(hintName)); err != nil { return } - hintName.UUID = solver.HintID(hf.Sum32()) + hintId = solver.HintID(hf.Sum32()) m.Lock() if maxNbCommitments == index { maxNbCommitments++ - solver.RegisterNamedHint(Bsb22CommitmentComputePlaceholder, hintName.UUID) + solver.RegisterNamedHint(Bsb22CommitmentComputePlaceholder, hintId) } m.Unlock() diff --git a/frontend/cs/r1cs/heap.go b/frontend/cs/r1cs/heap.go index a0d6035411..07c6bc436e 100644 --- a/frontend/cs/r1cs/heap.go +++ b/frontend/cs/r1cs/heap.go @@ -21,7 +21,7 @@ func (h *minHeap) heapify() { } } -// push pushes the element x onto the heap. +// push the element x onto the heap. // The complexity is O(log n) where n = len(*h). func (h *minHeap) push(x linMeta) { *h = append(*h, x) diff --git a/frontend/cs/scs/api.go b/frontend/cs/scs/api.go index 7482700e45..63c5ec2566 100644 --- a/frontend/cs/scs/api.go +++ b/frontend/cs/scs/api.go @@ -583,13 +583,13 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error builder.addPlonkConstraint(sparseR1C{xa: vINeg.VID, qL: vINeg.Coeff, commitment: constraint.COMMITTED}) } - hintName, err := cs.RegisterBsb22CommitmentComputePlaceholder(builder.cs.GetNbCommitments()) + hintId, err := cs.RegisterBsb22CommitmentComputePlaceholder(builder.cs.GetNbCommitments()) if err != nil { return nil, err } var outs []frontend.Variable - if outs, err = builder.NewNamedHint(cs.Bsb22CommitmentComputePlaceholder, &hintName, 1, v...); err != nil { + if outs, err = builder.NewHintForId(hintId, 1, v...); err != nil { return nil, err } @@ -599,7 +599,7 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error builder.addPlonkConstraint(sparseR1C{xa: commitmentVar.VID, qL: commitmentVar.Coeff, commitment: constraint.COMMITMENT}) // value will be injected later return outs[0], builder.cs.AddCommitment(constraint.Commitment{ - HintID: hintName.UUID, + HintID: hintId, CommitmentIndex: commitmentConstraintIndex, Committed: committed, }) diff --git a/test/engine.go b/test/engine.go index b760648df4..3a7c348f8a 100644 --- a/test/engine.go +++ b/test/engine.go @@ -18,6 +18,7 @@ package test import ( "fmt" + "github.com/consensys/gnark/constraint" "math/big" "path/filepath" "reflect" From 4354d999feaaa5e9785d430351d7bb7c8c3de4d9 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 10 May 2023 13:23:23 -0500 Subject: [PATCH 359/464] fix: failing vk serialization test --- backend/plonk/bn254/marshal.go | 4 ++++ backend/plonk/bn254/marshal_test.go | 35 ++++++++++++++++++----------- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/backend/plonk/bn254/marshal.go b/backend/plonk/bn254/marshal.go index cb55a1f95c..3603786f94 100644 --- a/backend/plonk/bn254/marshal.go +++ b/backend/plonk/bn254/marshal.go @@ -278,6 +278,10 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { &vk.CommitmentConstraintIndexes, } + if vk.Qcp == nil { + vk.Qcp = []kzg.Digest{} + } + for _, v := range toDecode { if err := dec.Decode(v); err != nil { return dec.BytesRead(), err diff --git a/backend/plonk/bn254/marshal_test.go b/backend/plonk/bn254/marshal_test.go index b7e4baec7e..1069a7dad5 100644 --- a/backend/plonk/bn254/marshal_test.go +++ b/backend/plonk/bn254/marshal_test.go @@ -18,6 +18,7 @@ package plonk import ( curve "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/google/go-cmp/cmp" "github.com/consensys/gnark-crypto/ecc/bn254/fr" @@ -41,27 +42,35 @@ func TestProofSerialization(t *testing.T) { } func TestProofSerializationRaw(t *testing.T) { - // create a proof - var proof, reconstructed Proof - proof.randomize() + for i := 0; i < 1000; i++ { + // create a proof + var proof, reconstructed Proof + proof.randomize() - roundTripCheckRaw(t, &proof, &reconstructed) + roundTripCheckRaw(t, &proof, &reconstructed) + } } func TestProvingKeySerialization(t *testing.T) { - // random pk - var pk, reconstructed ProvingKey - pk.randomize() + for i := 0; i < 1000; i++ { + // random pk + var pk, reconstructed ProvingKey + pk.randomize() - roundTripCheck(t, &pk, &reconstructed) + roundTripCheck(t, &pk, &reconstructed) + } } func TestVerifyingKeySerialization(t *testing.T) { - // create a random vk - var vk, reconstructed VerifyingKey - vk.randomize() - roundTripCheck(t, &vk, &reconstructed) + for i := 0; i < 1000; i++ { + // create a random vk + var vk, reconstructed VerifyingKey + vk.randomize() + + roundTripCheck(t, &vk, &reconstructed) + } + } func roundTripCheck(t *testing.T, from io.WriterTo, reconstructed io.ReaderFrom) { @@ -77,7 +86,7 @@ func roundTripCheck(t *testing.T, from io.WriterTo, reconstructed io.ReaderFrom) } if !reflect.DeepEqual(from, reconstructed) { - t.Fatal("reconstructed object don't match original") + t.Fatal("reconstructed object don't match original", cmp.Diff(from, reconstructed)) } if written != read { From 18bfc02c944a59d28a196d0b33bb898a75c2ad6b Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 10 May 2023 13:26:49 -0500 Subject: [PATCH 360/464] build: generify serialization fix --- backend/plonk/bls12-377/marshal.go | 4 +++ backend/plonk/bls12-381/marshal.go | 4 +++ backend/plonk/bls24-315/marshal.go | 4 +++ backend/plonk/bls24-317/marshal.go | 4 +++ backend/plonk/bn254/marshal.go | 8 ++--- backend/plonk/bn254/marshal_test.go | 35 +++++++------------ backend/plonk/bw6-633/marshal.go | 4 +++ backend/plonk/bw6-761/marshal.go | 4 +++ .../zkpschemes/plonk/plonk.marshal.go.tmpl | 4 +++ 9 files changed, 45 insertions(+), 26 deletions(-) diff --git a/backend/plonk/bls12-377/marshal.go b/backend/plonk/bls12-377/marshal.go index b7a0e2b28b..d2cc763a19 100644 --- a/backend/plonk/bls12-377/marshal.go +++ b/backend/plonk/bls12-377/marshal.go @@ -284,5 +284,9 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { } } + if vk.Qcp == nil { + vk.Qcp = []kzg.Digest{} + } + return dec.BytesRead(), nil } diff --git a/backend/plonk/bls12-381/marshal.go b/backend/plonk/bls12-381/marshal.go index 082f63d286..da1ca98e9c 100644 --- a/backend/plonk/bls12-381/marshal.go +++ b/backend/plonk/bls12-381/marshal.go @@ -284,5 +284,9 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { } } + if vk.Qcp == nil { + vk.Qcp = []kzg.Digest{} + } + return dec.BytesRead(), nil } diff --git a/backend/plonk/bls24-315/marshal.go b/backend/plonk/bls24-315/marshal.go index 4ebe5e278c..271e56fba2 100644 --- a/backend/plonk/bls24-315/marshal.go +++ b/backend/plonk/bls24-315/marshal.go @@ -284,5 +284,9 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { } } + if vk.Qcp == nil { + vk.Qcp = []kzg.Digest{} + } + return dec.BytesRead(), nil } diff --git a/backend/plonk/bls24-317/marshal.go b/backend/plonk/bls24-317/marshal.go index 0dbf089f51..dc79e285d8 100644 --- a/backend/plonk/bls24-317/marshal.go +++ b/backend/plonk/bls24-317/marshal.go @@ -284,5 +284,9 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { } } + if vk.Qcp == nil { + vk.Qcp = []kzg.Digest{} + } + return dec.BytesRead(), nil } diff --git a/backend/plonk/bn254/marshal.go b/backend/plonk/bn254/marshal.go index 3603786f94..1826272c36 100644 --- a/backend/plonk/bn254/marshal.go +++ b/backend/plonk/bn254/marshal.go @@ -278,15 +278,15 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { &vk.CommitmentConstraintIndexes, } - if vk.Qcp == nil { - vk.Qcp = []kzg.Digest{} - } - for _, v := range toDecode { if err := dec.Decode(v); err != nil { return dec.BytesRead(), err } } + if vk.Qcp == nil { + vk.Qcp = []kzg.Digest{} + } + return dec.BytesRead(), nil } diff --git a/backend/plonk/bn254/marshal_test.go b/backend/plonk/bn254/marshal_test.go index 1069a7dad5..b7e4baec7e 100644 --- a/backend/plonk/bn254/marshal_test.go +++ b/backend/plonk/bn254/marshal_test.go @@ -18,7 +18,6 @@ package plonk import ( curve "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/google/go-cmp/cmp" "github.com/consensys/gnark-crypto/ecc/bn254/fr" @@ -42,35 +41,27 @@ func TestProofSerialization(t *testing.T) { } func TestProofSerializationRaw(t *testing.T) { - for i := 0; i < 1000; i++ { - // create a proof - var proof, reconstructed Proof - proof.randomize() + // create a proof + var proof, reconstructed Proof + proof.randomize() - roundTripCheckRaw(t, &proof, &reconstructed) - } + roundTripCheckRaw(t, &proof, &reconstructed) } func TestProvingKeySerialization(t *testing.T) { - for i := 0; i < 1000; i++ { - // random pk - var pk, reconstructed ProvingKey - pk.randomize() + // random pk + var pk, reconstructed ProvingKey + pk.randomize() - roundTripCheck(t, &pk, &reconstructed) - } + roundTripCheck(t, &pk, &reconstructed) } func TestVerifyingKeySerialization(t *testing.T) { + // create a random vk + var vk, reconstructed VerifyingKey + vk.randomize() - for i := 0; i < 1000; i++ { - // create a random vk - var vk, reconstructed VerifyingKey - vk.randomize() - - roundTripCheck(t, &vk, &reconstructed) - } - + roundTripCheck(t, &vk, &reconstructed) } func roundTripCheck(t *testing.T, from io.WriterTo, reconstructed io.ReaderFrom) { @@ -86,7 +77,7 @@ func roundTripCheck(t *testing.T, from io.WriterTo, reconstructed io.ReaderFrom) } if !reflect.DeepEqual(from, reconstructed) { - t.Fatal("reconstructed object don't match original", cmp.Diff(from, reconstructed)) + t.Fatal("reconstructed object don't match original") } if written != read { diff --git a/backend/plonk/bw6-633/marshal.go b/backend/plonk/bw6-633/marshal.go index 599c3ca398..5b88f747e8 100644 --- a/backend/plonk/bw6-633/marshal.go +++ b/backend/plonk/bw6-633/marshal.go @@ -284,5 +284,9 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { } } + if vk.Qcp == nil { + vk.Qcp = []kzg.Digest{} + } + return dec.BytesRead(), nil } diff --git a/backend/plonk/bw6-761/marshal.go b/backend/plonk/bw6-761/marshal.go index eb752c7b7f..2e9205a827 100644 --- a/backend/plonk/bw6-761/marshal.go +++ b/backend/plonk/bw6-761/marshal.go @@ -284,5 +284,9 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { } } + if vk.Qcp == nil { + vk.Qcp = []kzg.Digest{} + } + return dec.BytesRead(), nil } diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl index fd12bd3e3a..78a802990c 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl @@ -264,5 +264,9 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { } } + if vk.Qcp == nil { + vk.Qcp = []kzg.Digest{} + } + return dec.BytesRead(), nil } \ No newline at end of file From c6a64481a2ae1427359478af3aa9f8e72a6c3597 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 10 May 2023 14:07:16 -0500 Subject: [PATCH 361/464] refactor: rename PI2 --- backend/plonk/bls12-377/prove.go | 2 +- backend/plonk/bls12-377/verify.go | 4 +-- backend/plonk/bls12-381/prove.go | 2 +- backend/plonk/bls12-381/verify.go | 4 +-- backend/plonk/bls24-315/prove.go | 2 +- backend/plonk/bls24-315/verify.go | 4 +-- backend/plonk/bls24-317/prove.go | 2 +- backend/plonk/bls24-317/verify.go | 4 +-- backend/plonk/bn254/marshal.go | 8 +++--- backend/plonk/bn254/marshal_test.go | 2 +- backend/plonk/bn254/prove.go | 39 ++++++++++++++--------------- backend/plonk/bn254/verify.go | 14 +++++------ backend/plonk/bw6-633/prove.go | 2 +- backend/plonk/bw6-633/verify.go | 4 +-- backend/plonk/bw6-761/prove.go | 2 +- backend/plonk/bw6-761/verify.go | 4 +-- constraint/r1cs_sparse.go | 2 +- 17 files changed, 50 insertions(+), 51 deletions(-) diff --git a/backend/plonk/bls12-377/prove.go b/backend/plonk/bls12-377/prove.go index e534ad200d..3474eb6cdc 100644 --- a/backend/plonk/bls12-377/prove.go +++ b/backend/plonk/bls12-377/prove.go @@ -330,7 +330,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm - // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, PI2 , qCPrime + // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, Bsb22Commitments , qCPrime fm := func(x ...fr.Element) fr.Element { a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2], x[15:]) diff --git a/backend/plonk/bls12-377/verify.go b/backend/plonk/bls12-377/verify.go index 287138eb19..2342a9c4a3 100644 --- a/backend/plonk/bls12-377/verify.go +++ b/backend/plonk/bls12-377/verify.go @@ -111,7 +111,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } for i := range vk.CommitmentConstraintIndexes { - var hashRes []fr.Element // TODO: when multi commits are implemented: PI2 -> PI2[i] + var hashRes []fr.Element // TODO: when multi commits are implemented: Bsb22Commitments -> Bsb22Commitments[i] if hashRes, err = fr.Hash(proof.PI2[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } @@ -189,7 +189,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // Compute the commitment to the linearized polynomial // linearizedPolynomialDigest = - // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+qc*PI2 + + // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+qc*Bsb22Commitments + // α*( Z(μζ)(l(ζ)+β*s₁(ζ)+γ)*(r(ζ)+β*s₂(ζ)+γ)*s₃(X)-Z(X)(l(ζ)+β*id_1(ζ)+γ)*(r(ζ)+β*id_2(ζ)+γ)*(o(ζ)+β*id_3(ζ)+γ) ) + // α²*L₁(ζ)*Z // first part: individual constraints diff --git a/backend/plonk/bls12-381/prove.go b/backend/plonk/bls12-381/prove.go index adbd314d43..e26061da4f 100644 --- a/backend/plonk/bls12-381/prove.go +++ b/backend/plonk/bls12-381/prove.go @@ -330,7 +330,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm - // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, PI2 , qCPrime + // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, Bsb22Commitments , qCPrime fm := func(x ...fr.Element) fr.Element { a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2], x[15:]) diff --git a/backend/plonk/bls12-381/verify.go b/backend/plonk/bls12-381/verify.go index 288e0826bf..3051977f2e 100644 --- a/backend/plonk/bls12-381/verify.go +++ b/backend/plonk/bls12-381/verify.go @@ -111,7 +111,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } for i := range vk.CommitmentConstraintIndexes { - var hashRes []fr.Element // TODO: when multi commits are implemented: PI2 -> PI2[i] + var hashRes []fr.Element // TODO: when multi commits are implemented: Bsb22Commitments -> Bsb22Commitments[i] if hashRes, err = fr.Hash(proof.PI2[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } @@ -189,7 +189,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // Compute the commitment to the linearized polynomial // linearizedPolynomialDigest = - // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+qc*PI2 + + // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+qc*Bsb22Commitments + // α*( Z(μζ)(l(ζ)+β*s₁(ζ)+γ)*(r(ζ)+β*s₂(ζ)+γ)*s₃(X)-Z(X)(l(ζ)+β*id_1(ζ)+γ)*(r(ζ)+β*id_2(ζ)+γ)*(o(ζ)+β*id_3(ζ)+γ) ) + // α²*L₁(ζ)*Z // first part: individual constraints diff --git a/backend/plonk/bls24-315/prove.go b/backend/plonk/bls24-315/prove.go index 0bfa7948c3..d3b7fd485e 100644 --- a/backend/plonk/bls24-315/prove.go +++ b/backend/plonk/bls24-315/prove.go @@ -330,7 +330,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm - // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, PI2 , qCPrime + // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, Bsb22Commitments , qCPrime fm := func(x ...fr.Element) fr.Element { a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2], x[15:]) diff --git a/backend/plonk/bls24-315/verify.go b/backend/plonk/bls24-315/verify.go index 48557038d3..b4c4790ae8 100644 --- a/backend/plonk/bls24-315/verify.go +++ b/backend/plonk/bls24-315/verify.go @@ -111,7 +111,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } for i := range vk.CommitmentConstraintIndexes { - var hashRes []fr.Element // TODO: when multi commits are implemented: PI2 -> PI2[i] + var hashRes []fr.Element // TODO: when multi commits are implemented: Bsb22Commitments -> Bsb22Commitments[i] if hashRes, err = fr.Hash(proof.PI2[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } @@ -189,7 +189,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // Compute the commitment to the linearized polynomial // linearizedPolynomialDigest = - // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+qc*PI2 + + // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+qc*Bsb22Commitments + // α*( Z(μζ)(l(ζ)+β*s₁(ζ)+γ)*(r(ζ)+β*s₂(ζ)+γ)*s₃(X)-Z(X)(l(ζ)+β*id_1(ζ)+γ)*(r(ζ)+β*id_2(ζ)+γ)*(o(ζ)+β*id_3(ζ)+γ) ) + // α²*L₁(ζ)*Z // first part: individual constraints diff --git a/backend/plonk/bls24-317/prove.go b/backend/plonk/bls24-317/prove.go index 86b5a00765..137cbc5f08 100644 --- a/backend/plonk/bls24-317/prove.go +++ b/backend/plonk/bls24-317/prove.go @@ -330,7 +330,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm - // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, PI2 , qCPrime + // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, Bsb22Commitments , qCPrime fm := func(x ...fr.Element) fr.Element { a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2], x[15:]) diff --git a/backend/plonk/bls24-317/verify.go b/backend/plonk/bls24-317/verify.go index 75bd3dc6a7..50ef808ded 100644 --- a/backend/plonk/bls24-317/verify.go +++ b/backend/plonk/bls24-317/verify.go @@ -111,7 +111,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } for i := range vk.CommitmentConstraintIndexes { - var hashRes []fr.Element // TODO: when multi commits are implemented: PI2 -> PI2[i] + var hashRes []fr.Element // TODO: when multi commits are implemented: Bsb22Commitments -> Bsb22Commitments[i] if hashRes, err = fr.Hash(proof.PI2[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } @@ -189,7 +189,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // Compute the commitment to the linearized polynomial // linearizedPolynomialDigest = - // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+qc*PI2 + + // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+qc*Bsb22Commitments + // α*( Z(μζ)(l(ζ)+β*s₁(ζ)+γ)*(r(ζ)+β*s₂(ζ)+γ)*s₃(X)-Z(X)(l(ζ)+β*id_1(ζ)+γ)*(r(ζ)+β*id_2(ζ)+γ)*(o(ζ)+β*id_3(ζ)+γ) ) + // α²*L₁(ζ)*Z // first part: individual constraints diff --git a/backend/plonk/bn254/marshal.go b/backend/plonk/bn254/marshal.go index 1826272c36..8de7d4071e 100644 --- a/backend/plonk/bn254/marshal.go +++ b/backend/plonk/bn254/marshal.go @@ -52,7 +52,7 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - proof.PI2, + proof.Bsb22Commitments, } for _, v := range toEncode { @@ -79,7 +79,7 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { &proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - &proof.PI2, + &proof.Bsb22Commitments, } for _, v := range toDecode { @@ -88,8 +88,8 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { } } - if proof.PI2 == nil { - proof.PI2 = []kzg.Digest{} + if proof.Bsb22Commitments == nil { + proof.Bsb22Commitments = []kzg.Digest{} } return dec.BytesRead(), nil diff --git a/backend/plonk/bn254/marshal_test.go b/backend/plonk/bn254/marshal_test.go index b7e4baec7e..8f62891c76 100644 --- a/backend/plonk/bn254/marshal_test.go +++ b/backend/plonk/bn254/marshal_test.go @@ -182,7 +182,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.PI2 = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here + proof.Bsb22Commitments = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here } func randomPoint() curve.G1Affine { diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index 7a0f25eac4..19eb938736 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -54,8 +54,7 @@ type Proof struct { // Commitments to h1, h2, h3 such that h = h1 + Xh2 + X**2h3 is the quotient polynomial H [3]kzg.Digest - // PI2, the BSB22 commitment - PI2 []kzg.Digest + Bsb22Commitments []kzg.Digest // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2, qCPrime BatchedProof kzg.BatchOpeningProof @@ -66,28 +65,28 @@ type Proof struct { func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, wpi2iop []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { - pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + committedValues := make([]fr.Element, pk.Domain[0].Cardinality) offset := spr.GetNbPublicVariables() for i := range ins { - pi2[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) + committedValues[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - /*if _, err = pi2[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + if _, err = committedValues[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } - if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding + if _, err = committedValues[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding return err - }*/ - pi2iop := iop.NewPolynomial(&pi2, iop.Form{Basis: iop.Lagrange, Layout: iop.Regular}) + } + pi2iop := iop.NewPolynomial(&committedValues, iop.Form{Basis: iop.Lagrange, Layout: iop.Regular}) wpi2iop[commDepth] = pi2iop.ShallowClone() wpi2iop[commDepth].ToCanonical(&pk.Domain[0]).ToRegular() - if proof.PI2[commDepth], err = kzg.Commit(wpi2iop[commDepth].Coefficients(), pk.Kzg); err != nil { + if proof.Bsb22Commitments[commDepth], err = kzg.Commit(wpi2iop[commDepth].Coefficients(), pk.Kzg); err != nil { return err } - if hashRes, err = fr.Hash(proof.PI2[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + if hashRes, err = fr.Hash(proof.Bsb22Commitments[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } res.Set(&hashRes[0]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses @@ -117,11 +116,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof := &Proof{} commitmentVal := make([]fr.Element, len(spr.CommitmentInfo)) // TODO @Tabaie get rid of this - wpi2iop := make([]*iop.Polynomial, len(spr.CommitmentInfo)) - proof.PI2 = make([]kzg.Digest, len(spr.CommitmentInfo)) + commitmentsCanonical := make([]*iop.Polynomial, len(spr.CommitmentInfo)) + proof.Bsb22Commitments = make([]kzg.Digest, len(spr.CommitmentInfo)) for i := range spr.CommitmentInfo { opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[i].HintID, - bsb22ComputeCommitmentHint(spr, pk, proof, wpi2iop, &commitmentVal[i], i))) + bsb22ComputeCommitmentHint(spr, pk, proof, commitmentsCanonical, &commitmentVal[i], i))) } // query l, r, o in Lagrange basis, not blinded @@ -130,9 +129,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } // TODO @gbotrel deal with that conversion lazily - lcpi2iop := make([]*iop.Polynomial, len(wpi2iop)) - for i := range wpi2iop { - lcpi2iop[i] = wpi2iop[i].Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form + lcCommitments := make([]*iop.Polynomial, len(commitmentsCanonical)) + for i := range commitmentsCanonical { + lcCommitments[i] = commitmentsCanonical[i].Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form } solution := _solution.(*cs.SparseR1CSSolution) evaluationLDomainSmall := []fr.Element(solution.L) @@ -199,7 +198,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.PI2); err != nil { + if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.Bsb22Commitments); err != nil { return nil, err } @@ -330,7 +329,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm - // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, PI2 , qCPrime + // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, Bsb22Commitments , qCPrime fm := func(x ...fr.Element) fr.Element { a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2], x[15:]) @@ -370,7 +369,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts lcqk, pk.lLoneIOP, } - toEval = append(toEval, lcpi2iop...) // TODO: Add this at beginning + toEval = append(toEval, lcCommitments...) // TODO: Add this at beginning toEval = append(toEval, pk.lcQcp...) systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, toEval...) if err != nil { @@ -493,7 +492,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bzuzeta, qcpzeta, bwziop.Coefficients()[:bwziop.BlindedSize()], - coefficients(wpi2iop), + coefficients(commitmentsCanonical), pk, ) diff --git a/backend/plonk/bn254/verify.go b/backend/plonk/bn254/verify.go index d00e03fadc..028330de0f 100644 --- a/backend/plonk/bn254/verify.go +++ b/backend/plonk/bn254/verify.go @@ -53,7 +53,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *vk, publicWitness, proof.PI2); err != nil { + if err := bindPublicData(&fs, "gamma", *vk, publicWitness, proof.Bsb22Commitments); err != nil { return err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) @@ -113,8 +113,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } for i := range vk.CommitmentConstraintIndexes { - var hashRes []fr.Element // TODO: when multi commits are implemented: PI2 -> PI2[i] - if hashRes, err = fr.Hash(proof.PI2[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + var hashRes []fr.Element // TODO: when multi commits are implemented: Bsb22Commitments -> Bsb22Commitments[i] + if hashRes, err = fr.Hash(proof.Bsb22Commitments[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } @@ -139,9 +139,9 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - qC := make([]fr.Element, len(proof.PI2)) + qC := make([]fr.Element, len(proof.Bsb22Commitments)) copy(qC, proof.BatchedProof.ClaimedValues) - claimedValues := proof.BatchedProof.ClaimedValues[len(proof.PI2):] + claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] claimedQuotient := claimedValues[0] linearizedPolynomialZeta := claimedValues[1] l := claimedValues[2] @@ -191,7 +191,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // Compute the commitment to the linearized polynomial // linearizedPolynomialDigest = - // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+qc*PI2 + + // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+qc*Bsb22Commitments + // α*( Z(μζ)(l(ζ)+β*s₁(ζ)+γ)*(r(ζ)+β*s₂(ζ)+γ)*s₃(X)-Z(X)(l(ζ)+β*id_1(ζ)+γ)*(r(ζ)+β*id_2(ζ)+γ)*(o(ζ)+β*id_3(ζ)+γ) ) + // α²*L₁(ζ)*Z // first part: individual constraints @@ -217,7 +217,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // note since third part = α²*L₁(ζ)*Z _s2.Mul(&_s2, &alpha).Add(&_s2, &alphaSquareLagrange) // -α*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + α²*L₁(ζ) - points := append(proof.PI2, + points := append(proof.Bsb22Commitments, vk.Ql, vk.Qr, vk.Qm, vk.Qo, vk.Qk, // first part vk.S[2], proof.Z, // second & third part ) diff --git a/backend/plonk/bw6-633/prove.go b/backend/plonk/bw6-633/prove.go index 6e689fd24c..00c47d1cbf 100644 --- a/backend/plonk/bw6-633/prove.go +++ b/backend/plonk/bw6-633/prove.go @@ -330,7 +330,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm - // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, PI2 , qCPrime + // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, Bsb22Commitments , qCPrime fm := func(x ...fr.Element) fr.Element { a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2], x[15:]) diff --git a/backend/plonk/bw6-633/verify.go b/backend/plonk/bw6-633/verify.go index 81a2f99b4f..0c07b83f12 100644 --- a/backend/plonk/bw6-633/verify.go +++ b/backend/plonk/bw6-633/verify.go @@ -111,7 +111,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } for i := range vk.CommitmentConstraintIndexes { - var hashRes []fr.Element // TODO: when multi commits are implemented: PI2 -> PI2[i] + var hashRes []fr.Element // TODO: when multi commits are implemented: Bsb22Commitments -> Bsb22Commitments[i] if hashRes, err = fr.Hash(proof.PI2[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } @@ -189,7 +189,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // Compute the commitment to the linearized polynomial // linearizedPolynomialDigest = - // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+qc*PI2 + + // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+qc*Bsb22Commitments + // α*( Z(μζ)(l(ζ)+β*s₁(ζ)+γ)*(r(ζ)+β*s₂(ζ)+γ)*s₃(X)-Z(X)(l(ζ)+β*id_1(ζ)+γ)*(r(ζ)+β*id_2(ζ)+γ)*(o(ζ)+β*id_3(ζ)+γ) ) + // α²*L₁(ζ)*Z // first part: individual constraints diff --git a/backend/plonk/bw6-761/prove.go b/backend/plonk/bw6-761/prove.go index e917174ad4..845c4adb0d 100644 --- a/backend/plonk/bw6-761/prove.go +++ b/backend/plonk/bw6-761/prove.go @@ -330,7 +330,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts } // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm - // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, PI2 , qCPrime + // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, Bsb22Commitments , qCPrime fm := func(x ...fr.Element) fr.Element { a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2], x[15:]) diff --git a/backend/plonk/bw6-761/verify.go b/backend/plonk/bw6-761/verify.go index af30cd65f9..224ea3b158 100644 --- a/backend/plonk/bw6-761/verify.go +++ b/backend/plonk/bw6-761/verify.go @@ -111,7 +111,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } for i := range vk.CommitmentConstraintIndexes { - var hashRes []fr.Element // TODO: when multi commits are implemented: PI2 -> PI2[i] + var hashRes []fr.Element // TODO: when multi commits are implemented: Bsb22Commitments -> Bsb22Commitments[i] if hashRes, err = fr.Hash(proof.PI2[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } @@ -189,7 +189,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // Compute the commitment to the linearized polynomial // linearizedPolynomialDigest = - // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+qc*PI2 + + // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+qc*Bsb22Commitments + // α*( Z(μζ)(l(ζ)+β*s₁(ζ)+γ)*(r(ζ)+β*s₂(ζ)+γ)*s₃(X)-Z(X)(l(ζ)+β*id_1(ζ)+γ)*(r(ζ)+β*id_2(ζ)+γ)*(o(ζ)+β*id_3(ζ)+γ) ) + // α²*L₁(ζ)*Z // first part: individual constraints diff --git a/constraint/r1cs_sparse.go b/constraint/r1cs_sparse.go index d423d5b844..742521e9d5 100644 --- a/constraint/r1cs_sparse.go +++ b/constraint/r1cs_sparse.go @@ -139,7 +139,7 @@ const ( ) // SparseR1C represent a PlonK-ish constraint -// qL⋅xa + qR⋅xb + qO⋅xc + qM⋅(xaxb) + qC -committed?*PI2-commitment?*commitmentValue == 0 +// qL⋅xa + qR⋅xb + qO⋅xc + qM⋅(xaxb) + qC -committed?*Bsb22Commitments-commitment?*commitmentValue == 0 type SparseR1C struct { XA, XB, XC uint32 QL, QR, QO, QM, QC uint32 From 0434dd5039f0e2cad448665b926b87a26188918a Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 10 May 2023 14:55:12 -0500 Subject: [PATCH 362/464] docs: better names and a link to hackMd --- backend/plonk/bls12-377/prove.go | 48 +++++++++---------- backend/plonk/bls12-377/verify.go | 14 +++--- backend/plonk/bls12-381/prove.go | 48 +++++++++---------- backend/plonk/bls12-381/verify.go | 14 +++--- backend/plonk/bls24-315/prove.go | 48 +++++++++---------- backend/plonk/bls24-315/verify.go | 14 +++--- backend/plonk/bls24-317/prove.go | 48 +++++++++---------- backend/plonk/bls24-317/verify.go | 14 +++--- backend/plonk/bn254/marshal.go | 8 ++-- backend/plonk/bn254/marshal_test.go | 2 +- backend/plonk/bn254/prove.go | 25 +++++----- backend/plonk/bn254/verify.go | 4 +- backend/plonk/bw6-633/prove.go | 48 +++++++++---------- backend/plonk/bw6-633/verify.go | 14 +++--- backend/plonk/bw6-761/prove.go | 48 +++++++++---------- backend/plonk/bw6-761/verify.go | 14 +++--- .../zkpschemes/plonk/plonk.prove.go.tmpl | 48 +++++++++---------- .../zkpschemes/plonk/plonk.verify.go.tmpl | 14 +++--- 18 files changed, 237 insertions(+), 236 deletions(-) diff --git a/backend/plonk/bls12-377/prove.go b/backend/plonk/bls12-377/prove.go index 3474eb6cdc..a6833fe0c9 100644 --- a/backend/plonk/bls12-377/prove.go +++ b/backend/plonk/bls12-377/prove.go @@ -54,8 +54,7 @@ type Proof struct { // Commitments to h1, h2, h3 such that h = h1 + Xh2 + X**2h3 is the quotient polynomial H [3]kzg.Digest - // PI2, the BSB22 commitment - PI2 []kzg.Digest + Bsb22Commitments []kzg.Digest // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2, qCPrime BatchedProof kzg.BatchOpeningProof @@ -64,30 +63,31 @@ type Proof struct { ZShiftedOpening kzg.OpeningProof } -func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, wpi2iop []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { +// Computing and verifying Bsb22 multi-commits explained in https://hackmd.io/x8KsadW3RRyX7YTCFJIkHg +func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, cCommitments []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { - pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + committedValues := make([]fr.Element, pk.Domain[0].Cardinality) offset := spr.GetNbPublicVariables() for i := range ins { - pi2[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) + committedValues[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - /*if _, err = pi2[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + if _, err = committedValues[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } - if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding + if _, err = committedValues[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding return err - }*/ - pi2iop := iop.NewPolynomial(&pi2, iop.Form{Basis: iop.Lagrange, Layout: iop.Regular}) - wpi2iop[commDepth] = pi2iop.ShallowClone() - wpi2iop[commDepth].ToCanonical(&pk.Domain[0]).ToRegular() - if proof.PI2[commDepth], err = kzg.Commit(wpi2iop[commDepth].Coefficients(), pk.Kzg); err != nil { + } + pi2iop := iop.NewPolynomial(&committedValues, iop.Form{Basis: iop.Lagrange, Layout: iop.Regular}) + cCommitments[commDepth] = pi2iop.ShallowClone() + cCommitments[commDepth].ToCanonical(&pk.Domain[0]).ToRegular() + if proof.Bsb22Commitments[commDepth], err = kzg.Commit(cCommitments[commDepth].Coefficients(), pk.Kzg); err != nil { return err } - if hashRes, err = fr.Hash(proof.PI2[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + if hashRes, err = fr.Hash(proof.Bsb22Commitments[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } res.Set(&hashRes[0]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses @@ -117,11 +117,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof := &Proof{} commitmentVal := make([]fr.Element, len(spr.CommitmentInfo)) // TODO @Tabaie get rid of this - wpi2iop := make([]*iop.Polynomial, len(spr.CommitmentInfo)) - proof.PI2 = make([]kzg.Digest, len(spr.CommitmentInfo)) + cCommitments := make([]*iop.Polynomial, len(spr.CommitmentInfo)) + proof.Bsb22Commitments = make([]kzg.Digest, len(spr.CommitmentInfo)) for i := range spr.CommitmentInfo { opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[i].HintID, - bsb22ComputeCommitmentHint(spr, pk, proof, wpi2iop, &commitmentVal[i], i))) + bsb22ComputeCommitmentHint(spr, pk, proof, cCommitments, &commitmentVal[i], i))) } // query l, r, o in Lagrange basis, not blinded @@ -130,9 +130,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } // TODO @gbotrel deal with that conversion lazily - lcpi2iop := make([]*iop.Polynomial, len(wpi2iop)) - for i := range wpi2iop { - lcpi2iop[i] = wpi2iop[i].Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form + lcCommitments := make([]*iop.Polynomial, len(cCommitments)) + for i := range cCommitments { + lcCommitments[i] = cCommitments[i].Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form } solution := _solution.(*cs.SparseR1CSSolution) evaluationLDomainSmall := []fr.Element(solution.L) @@ -199,7 +199,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.PI2); err != nil { + if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.Bsb22Commitments); err != nil { return nil, err } @@ -329,8 +329,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return one } - // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm - // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, Bsb22Commitments , qCPrime + // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm + // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, Bsb22Commitments, qCPrime fm := func(x ...fr.Element) fr.Element { a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2], x[15:]) @@ -370,7 +370,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts lcqk, pk.lLoneIOP, } - toEval = append(toEval, lcpi2iop...) // TODO: Add this at beginning + toEval = append(toEval, lcCommitments...) // TODO: Add this at beginning toEval = append(toEval, pk.lcQcp...) systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, toEval...) if err != nil { @@ -493,7 +493,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bzuzeta, qcpzeta, bwziop.Coefficients()[:bwziop.BlindedSize()], - coefficients(wpi2iop), + coefficients(cCommitments), pk, ) diff --git a/backend/plonk/bls12-377/verify.go b/backend/plonk/bls12-377/verify.go index 2342a9c4a3..af820983d0 100644 --- a/backend/plonk/bls12-377/verify.go +++ b/backend/plonk/bls12-377/verify.go @@ -51,7 +51,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *vk, publicWitness, proof.PI2); err != nil { + if err := bindPublicData(&fs, "gamma", *vk, publicWitness, proof.Bsb22Commitments); err != nil { return err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) @@ -111,8 +111,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } for i := range vk.CommitmentConstraintIndexes { - var hashRes []fr.Element // TODO: when multi commits are implemented: Bsb22Commitments -> Bsb22Commitments[i] - if hashRes, err = fr.Hash(proof.PI2[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + var hashRes []fr.Element + if hashRes, err = fr.Hash(proof.Bsb22Commitments[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } @@ -137,9 +137,9 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - qC := make([]fr.Element, len(proof.PI2)) + qC := make([]fr.Element, len(proof.Bsb22Commitments)) copy(qC, proof.BatchedProof.ClaimedValues) - claimedValues := proof.BatchedProof.ClaimedValues[len(proof.PI2):] + claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] claimedQuotient := claimedValues[0] linearizedPolynomialZeta := claimedValues[1] l := claimedValues[2] @@ -189,7 +189,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // Compute the commitment to the linearized polynomial // linearizedPolynomialDigest = - // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+qc*Bsb22Commitments + + // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+Σᵢqc'ᵢ(ζ)*BsbCommitmentᵢ + // α*( Z(μζ)(l(ζ)+β*s₁(ζ)+γ)*(r(ζ)+β*s₂(ζ)+γ)*s₃(X)-Z(X)(l(ζ)+β*id_1(ζ)+γ)*(r(ζ)+β*id_2(ζ)+γ)*(o(ζ)+β*id_3(ζ)+γ) ) + // α²*L₁(ζ)*Z // first part: individual constraints @@ -215,7 +215,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // note since third part = α²*L₁(ζ)*Z _s2.Mul(&_s2, &alpha).Add(&_s2, &alphaSquareLagrange) // -α*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + α²*L₁(ζ) - points := append(proof.PI2, + points := append(proof.Bsb22Commitments, vk.Ql, vk.Qr, vk.Qm, vk.Qo, vk.Qk, // first part vk.S[2], proof.Z, // second & third part ) diff --git a/backend/plonk/bls12-381/prove.go b/backend/plonk/bls12-381/prove.go index e26061da4f..69bfbeb4a9 100644 --- a/backend/plonk/bls12-381/prove.go +++ b/backend/plonk/bls12-381/prove.go @@ -54,8 +54,7 @@ type Proof struct { // Commitments to h1, h2, h3 such that h = h1 + Xh2 + X**2h3 is the quotient polynomial H [3]kzg.Digest - // PI2, the BSB22 commitment - PI2 []kzg.Digest + Bsb22Commitments []kzg.Digest // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2, qCPrime BatchedProof kzg.BatchOpeningProof @@ -64,30 +63,31 @@ type Proof struct { ZShiftedOpening kzg.OpeningProof } -func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, wpi2iop []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { +// Computing and verifying Bsb22 multi-commits explained in https://hackmd.io/x8KsadW3RRyX7YTCFJIkHg +func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, cCommitments []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { - pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + committedValues := make([]fr.Element, pk.Domain[0].Cardinality) offset := spr.GetNbPublicVariables() for i := range ins { - pi2[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) + committedValues[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - /*if _, err = pi2[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + if _, err = committedValues[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } - if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding + if _, err = committedValues[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding return err - }*/ - pi2iop := iop.NewPolynomial(&pi2, iop.Form{Basis: iop.Lagrange, Layout: iop.Regular}) - wpi2iop[commDepth] = pi2iop.ShallowClone() - wpi2iop[commDepth].ToCanonical(&pk.Domain[0]).ToRegular() - if proof.PI2[commDepth], err = kzg.Commit(wpi2iop[commDepth].Coefficients(), pk.Kzg); err != nil { + } + pi2iop := iop.NewPolynomial(&committedValues, iop.Form{Basis: iop.Lagrange, Layout: iop.Regular}) + cCommitments[commDepth] = pi2iop.ShallowClone() + cCommitments[commDepth].ToCanonical(&pk.Domain[0]).ToRegular() + if proof.Bsb22Commitments[commDepth], err = kzg.Commit(cCommitments[commDepth].Coefficients(), pk.Kzg); err != nil { return err } - if hashRes, err = fr.Hash(proof.PI2[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + if hashRes, err = fr.Hash(proof.Bsb22Commitments[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } res.Set(&hashRes[0]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses @@ -117,11 +117,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof := &Proof{} commitmentVal := make([]fr.Element, len(spr.CommitmentInfo)) // TODO @Tabaie get rid of this - wpi2iop := make([]*iop.Polynomial, len(spr.CommitmentInfo)) - proof.PI2 = make([]kzg.Digest, len(spr.CommitmentInfo)) + cCommitments := make([]*iop.Polynomial, len(spr.CommitmentInfo)) + proof.Bsb22Commitments = make([]kzg.Digest, len(spr.CommitmentInfo)) for i := range spr.CommitmentInfo { opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[i].HintID, - bsb22ComputeCommitmentHint(spr, pk, proof, wpi2iop, &commitmentVal[i], i))) + bsb22ComputeCommitmentHint(spr, pk, proof, cCommitments, &commitmentVal[i], i))) } // query l, r, o in Lagrange basis, not blinded @@ -130,9 +130,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } // TODO @gbotrel deal with that conversion lazily - lcpi2iop := make([]*iop.Polynomial, len(wpi2iop)) - for i := range wpi2iop { - lcpi2iop[i] = wpi2iop[i].Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form + lcCommitments := make([]*iop.Polynomial, len(cCommitments)) + for i := range cCommitments { + lcCommitments[i] = cCommitments[i].Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form } solution := _solution.(*cs.SparseR1CSSolution) evaluationLDomainSmall := []fr.Element(solution.L) @@ -199,7 +199,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.PI2); err != nil { + if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.Bsb22Commitments); err != nil { return nil, err } @@ -329,8 +329,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return one } - // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm - // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, Bsb22Commitments , qCPrime + // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm + // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, Bsb22Commitments, qCPrime fm := func(x ...fr.Element) fr.Element { a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2], x[15:]) @@ -370,7 +370,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts lcqk, pk.lLoneIOP, } - toEval = append(toEval, lcpi2iop...) // TODO: Add this at beginning + toEval = append(toEval, lcCommitments...) // TODO: Add this at beginning toEval = append(toEval, pk.lcQcp...) systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, toEval...) if err != nil { @@ -493,7 +493,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bzuzeta, qcpzeta, bwziop.Coefficients()[:bwziop.BlindedSize()], - coefficients(wpi2iop), + coefficients(cCommitments), pk, ) diff --git a/backend/plonk/bls12-381/verify.go b/backend/plonk/bls12-381/verify.go index 3051977f2e..f22da3bc6e 100644 --- a/backend/plonk/bls12-381/verify.go +++ b/backend/plonk/bls12-381/verify.go @@ -51,7 +51,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *vk, publicWitness, proof.PI2); err != nil { + if err := bindPublicData(&fs, "gamma", *vk, publicWitness, proof.Bsb22Commitments); err != nil { return err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) @@ -111,8 +111,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } for i := range vk.CommitmentConstraintIndexes { - var hashRes []fr.Element // TODO: when multi commits are implemented: Bsb22Commitments -> Bsb22Commitments[i] - if hashRes, err = fr.Hash(proof.PI2[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + var hashRes []fr.Element + if hashRes, err = fr.Hash(proof.Bsb22Commitments[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } @@ -137,9 +137,9 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - qC := make([]fr.Element, len(proof.PI2)) + qC := make([]fr.Element, len(proof.Bsb22Commitments)) copy(qC, proof.BatchedProof.ClaimedValues) - claimedValues := proof.BatchedProof.ClaimedValues[len(proof.PI2):] + claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] claimedQuotient := claimedValues[0] linearizedPolynomialZeta := claimedValues[1] l := claimedValues[2] @@ -189,7 +189,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // Compute the commitment to the linearized polynomial // linearizedPolynomialDigest = - // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+qc*Bsb22Commitments + + // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+Σᵢqc'ᵢ(ζ)*BsbCommitmentᵢ + // α*( Z(μζ)(l(ζ)+β*s₁(ζ)+γ)*(r(ζ)+β*s₂(ζ)+γ)*s₃(X)-Z(X)(l(ζ)+β*id_1(ζ)+γ)*(r(ζ)+β*id_2(ζ)+γ)*(o(ζ)+β*id_3(ζ)+γ) ) + // α²*L₁(ζ)*Z // first part: individual constraints @@ -215,7 +215,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // note since third part = α²*L₁(ζ)*Z _s2.Mul(&_s2, &alpha).Add(&_s2, &alphaSquareLagrange) // -α*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + α²*L₁(ζ) - points := append(proof.PI2, + points := append(proof.Bsb22Commitments, vk.Ql, vk.Qr, vk.Qm, vk.Qo, vk.Qk, // first part vk.S[2], proof.Z, // second & third part ) diff --git a/backend/plonk/bls24-315/prove.go b/backend/plonk/bls24-315/prove.go index d3b7fd485e..69ef7228c1 100644 --- a/backend/plonk/bls24-315/prove.go +++ b/backend/plonk/bls24-315/prove.go @@ -54,8 +54,7 @@ type Proof struct { // Commitments to h1, h2, h3 such that h = h1 + Xh2 + X**2h3 is the quotient polynomial H [3]kzg.Digest - // PI2, the BSB22 commitment - PI2 []kzg.Digest + Bsb22Commitments []kzg.Digest // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2, qCPrime BatchedProof kzg.BatchOpeningProof @@ -64,30 +63,31 @@ type Proof struct { ZShiftedOpening kzg.OpeningProof } -func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, wpi2iop []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { +// Computing and verifying Bsb22 multi-commits explained in https://hackmd.io/x8KsadW3RRyX7YTCFJIkHg +func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, cCommitments []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { - pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + committedValues := make([]fr.Element, pk.Domain[0].Cardinality) offset := spr.GetNbPublicVariables() for i := range ins { - pi2[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) + committedValues[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - /*if _, err = pi2[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + if _, err = committedValues[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } - if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding + if _, err = committedValues[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding return err - }*/ - pi2iop := iop.NewPolynomial(&pi2, iop.Form{Basis: iop.Lagrange, Layout: iop.Regular}) - wpi2iop[commDepth] = pi2iop.ShallowClone() - wpi2iop[commDepth].ToCanonical(&pk.Domain[0]).ToRegular() - if proof.PI2[commDepth], err = kzg.Commit(wpi2iop[commDepth].Coefficients(), pk.Kzg); err != nil { + } + pi2iop := iop.NewPolynomial(&committedValues, iop.Form{Basis: iop.Lagrange, Layout: iop.Regular}) + cCommitments[commDepth] = pi2iop.ShallowClone() + cCommitments[commDepth].ToCanonical(&pk.Domain[0]).ToRegular() + if proof.Bsb22Commitments[commDepth], err = kzg.Commit(cCommitments[commDepth].Coefficients(), pk.Kzg); err != nil { return err } - if hashRes, err = fr.Hash(proof.PI2[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + if hashRes, err = fr.Hash(proof.Bsb22Commitments[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } res.Set(&hashRes[0]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses @@ -117,11 +117,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof := &Proof{} commitmentVal := make([]fr.Element, len(spr.CommitmentInfo)) // TODO @Tabaie get rid of this - wpi2iop := make([]*iop.Polynomial, len(spr.CommitmentInfo)) - proof.PI2 = make([]kzg.Digest, len(spr.CommitmentInfo)) + cCommitments := make([]*iop.Polynomial, len(spr.CommitmentInfo)) + proof.Bsb22Commitments = make([]kzg.Digest, len(spr.CommitmentInfo)) for i := range spr.CommitmentInfo { opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[i].HintID, - bsb22ComputeCommitmentHint(spr, pk, proof, wpi2iop, &commitmentVal[i], i))) + bsb22ComputeCommitmentHint(spr, pk, proof, cCommitments, &commitmentVal[i], i))) } // query l, r, o in Lagrange basis, not blinded @@ -130,9 +130,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } // TODO @gbotrel deal with that conversion lazily - lcpi2iop := make([]*iop.Polynomial, len(wpi2iop)) - for i := range wpi2iop { - lcpi2iop[i] = wpi2iop[i].Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form + lcCommitments := make([]*iop.Polynomial, len(cCommitments)) + for i := range cCommitments { + lcCommitments[i] = cCommitments[i].Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form } solution := _solution.(*cs.SparseR1CSSolution) evaluationLDomainSmall := []fr.Element(solution.L) @@ -199,7 +199,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.PI2); err != nil { + if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.Bsb22Commitments); err != nil { return nil, err } @@ -329,8 +329,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return one } - // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm - // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, Bsb22Commitments , qCPrime + // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm + // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, Bsb22Commitments, qCPrime fm := func(x ...fr.Element) fr.Element { a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2], x[15:]) @@ -370,7 +370,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts lcqk, pk.lLoneIOP, } - toEval = append(toEval, lcpi2iop...) // TODO: Add this at beginning + toEval = append(toEval, lcCommitments...) // TODO: Add this at beginning toEval = append(toEval, pk.lcQcp...) systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, toEval...) if err != nil { @@ -493,7 +493,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bzuzeta, qcpzeta, bwziop.Coefficients()[:bwziop.BlindedSize()], - coefficients(wpi2iop), + coefficients(cCommitments), pk, ) diff --git a/backend/plonk/bls24-315/verify.go b/backend/plonk/bls24-315/verify.go index b4c4790ae8..afa89fa0b6 100644 --- a/backend/plonk/bls24-315/verify.go +++ b/backend/plonk/bls24-315/verify.go @@ -51,7 +51,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *vk, publicWitness, proof.PI2); err != nil { + if err := bindPublicData(&fs, "gamma", *vk, publicWitness, proof.Bsb22Commitments); err != nil { return err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) @@ -111,8 +111,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } for i := range vk.CommitmentConstraintIndexes { - var hashRes []fr.Element // TODO: when multi commits are implemented: Bsb22Commitments -> Bsb22Commitments[i] - if hashRes, err = fr.Hash(proof.PI2[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + var hashRes []fr.Element + if hashRes, err = fr.Hash(proof.Bsb22Commitments[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } @@ -137,9 +137,9 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - qC := make([]fr.Element, len(proof.PI2)) + qC := make([]fr.Element, len(proof.Bsb22Commitments)) copy(qC, proof.BatchedProof.ClaimedValues) - claimedValues := proof.BatchedProof.ClaimedValues[len(proof.PI2):] + claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] claimedQuotient := claimedValues[0] linearizedPolynomialZeta := claimedValues[1] l := claimedValues[2] @@ -189,7 +189,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // Compute the commitment to the linearized polynomial // linearizedPolynomialDigest = - // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+qc*Bsb22Commitments + + // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+Σᵢqc'ᵢ(ζ)*BsbCommitmentᵢ + // α*( Z(μζ)(l(ζ)+β*s₁(ζ)+γ)*(r(ζ)+β*s₂(ζ)+γ)*s₃(X)-Z(X)(l(ζ)+β*id_1(ζ)+γ)*(r(ζ)+β*id_2(ζ)+γ)*(o(ζ)+β*id_3(ζ)+γ) ) + // α²*L₁(ζ)*Z // first part: individual constraints @@ -215,7 +215,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // note since third part = α²*L₁(ζ)*Z _s2.Mul(&_s2, &alpha).Add(&_s2, &alphaSquareLagrange) // -α*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + α²*L₁(ζ) - points := append(proof.PI2, + points := append(proof.Bsb22Commitments, vk.Ql, vk.Qr, vk.Qm, vk.Qo, vk.Qk, // first part vk.S[2], proof.Z, // second & third part ) diff --git a/backend/plonk/bls24-317/prove.go b/backend/plonk/bls24-317/prove.go index 137cbc5f08..753b151b9c 100644 --- a/backend/plonk/bls24-317/prove.go +++ b/backend/plonk/bls24-317/prove.go @@ -54,8 +54,7 @@ type Proof struct { // Commitments to h1, h2, h3 such that h = h1 + Xh2 + X**2h3 is the quotient polynomial H [3]kzg.Digest - // PI2, the BSB22 commitment - PI2 []kzg.Digest + Bsb22Commitments []kzg.Digest // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2, qCPrime BatchedProof kzg.BatchOpeningProof @@ -64,30 +63,31 @@ type Proof struct { ZShiftedOpening kzg.OpeningProof } -func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, wpi2iop []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { +// Computing and verifying Bsb22 multi-commits explained in https://hackmd.io/x8KsadW3RRyX7YTCFJIkHg +func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, cCommitments []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { - pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + committedValues := make([]fr.Element, pk.Domain[0].Cardinality) offset := spr.GetNbPublicVariables() for i := range ins { - pi2[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) + committedValues[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - /*if _, err = pi2[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + if _, err = committedValues[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } - if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding + if _, err = committedValues[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding return err - }*/ - pi2iop := iop.NewPolynomial(&pi2, iop.Form{Basis: iop.Lagrange, Layout: iop.Regular}) - wpi2iop[commDepth] = pi2iop.ShallowClone() - wpi2iop[commDepth].ToCanonical(&pk.Domain[0]).ToRegular() - if proof.PI2[commDepth], err = kzg.Commit(wpi2iop[commDepth].Coefficients(), pk.Kzg); err != nil { + } + pi2iop := iop.NewPolynomial(&committedValues, iop.Form{Basis: iop.Lagrange, Layout: iop.Regular}) + cCommitments[commDepth] = pi2iop.ShallowClone() + cCommitments[commDepth].ToCanonical(&pk.Domain[0]).ToRegular() + if proof.Bsb22Commitments[commDepth], err = kzg.Commit(cCommitments[commDepth].Coefficients(), pk.Kzg); err != nil { return err } - if hashRes, err = fr.Hash(proof.PI2[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + if hashRes, err = fr.Hash(proof.Bsb22Commitments[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } res.Set(&hashRes[0]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses @@ -117,11 +117,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof := &Proof{} commitmentVal := make([]fr.Element, len(spr.CommitmentInfo)) // TODO @Tabaie get rid of this - wpi2iop := make([]*iop.Polynomial, len(spr.CommitmentInfo)) - proof.PI2 = make([]kzg.Digest, len(spr.CommitmentInfo)) + cCommitments := make([]*iop.Polynomial, len(spr.CommitmentInfo)) + proof.Bsb22Commitments = make([]kzg.Digest, len(spr.CommitmentInfo)) for i := range spr.CommitmentInfo { opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[i].HintID, - bsb22ComputeCommitmentHint(spr, pk, proof, wpi2iop, &commitmentVal[i], i))) + bsb22ComputeCommitmentHint(spr, pk, proof, cCommitments, &commitmentVal[i], i))) } // query l, r, o in Lagrange basis, not blinded @@ -130,9 +130,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } // TODO @gbotrel deal with that conversion lazily - lcpi2iop := make([]*iop.Polynomial, len(wpi2iop)) - for i := range wpi2iop { - lcpi2iop[i] = wpi2iop[i].Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form + lcCommitments := make([]*iop.Polynomial, len(cCommitments)) + for i := range cCommitments { + lcCommitments[i] = cCommitments[i].Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form } solution := _solution.(*cs.SparseR1CSSolution) evaluationLDomainSmall := []fr.Element(solution.L) @@ -199,7 +199,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.PI2); err != nil { + if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.Bsb22Commitments); err != nil { return nil, err } @@ -329,8 +329,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return one } - // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm - // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, Bsb22Commitments , qCPrime + // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm + // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, Bsb22Commitments, qCPrime fm := func(x ...fr.Element) fr.Element { a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2], x[15:]) @@ -370,7 +370,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts lcqk, pk.lLoneIOP, } - toEval = append(toEval, lcpi2iop...) // TODO: Add this at beginning + toEval = append(toEval, lcCommitments...) // TODO: Add this at beginning toEval = append(toEval, pk.lcQcp...) systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, toEval...) if err != nil { @@ -493,7 +493,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bzuzeta, qcpzeta, bwziop.Coefficients()[:bwziop.BlindedSize()], - coefficients(wpi2iop), + coefficients(cCommitments), pk, ) diff --git a/backend/plonk/bls24-317/verify.go b/backend/plonk/bls24-317/verify.go index 50ef808ded..3aa9661e80 100644 --- a/backend/plonk/bls24-317/verify.go +++ b/backend/plonk/bls24-317/verify.go @@ -51,7 +51,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *vk, publicWitness, proof.PI2); err != nil { + if err := bindPublicData(&fs, "gamma", *vk, publicWitness, proof.Bsb22Commitments); err != nil { return err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) @@ -111,8 +111,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } for i := range vk.CommitmentConstraintIndexes { - var hashRes []fr.Element // TODO: when multi commits are implemented: Bsb22Commitments -> Bsb22Commitments[i] - if hashRes, err = fr.Hash(proof.PI2[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + var hashRes []fr.Element + if hashRes, err = fr.Hash(proof.Bsb22Commitments[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } @@ -137,9 +137,9 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - qC := make([]fr.Element, len(proof.PI2)) + qC := make([]fr.Element, len(proof.Bsb22Commitments)) copy(qC, proof.BatchedProof.ClaimedValues) - claimedValues := proof.BatchedProof.ClaimedValues[len(proof.PI2):] + claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] claimedQuotient := claimedValues[0] linearizedPolynomialZeta := claimedValues[1] l := claimedValues[2] @@ -189,7 +189,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // Compute the commitment to the linearized polynomial // linearizedPolynomialDigest = - // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+qc*Bsb22Commitments + + // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+Σᵢqc'ᵢ(ζ)*BsbCommitmentᵢ + // α*( Z(μζ)(l(ζ)+β*s₁(ζ)+γ)*(r(ζ)+β*s₂(ζ)+γ)*s₃(X)-Z(X)(l(ζ)+β*id_1(ζ)+γ)*(r(ζ)+β*id_2(ζ)+γ)*(o(ζ)+β*id_3(ζ)+γ) ) + // α²*L₁(ζ)*Z // first part: individual constraints @@ -215,7 +215,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // note since third part = α²*L₁(ζ)*Z _s2.Mul(&_s2, &alpha).Add(&_s2, &alphaSquareLagrange) // -α*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + α²*L₁(ζ) - points := append(proof.PI2, + points := append(proof.Bsb22Commitments, vk.Ql, vk.Qr, vk.Qm, vk.Qo, vk.Qk, // first part vk.S[2], proof.Z, // second & third part ) diff --git a/backend/plonk/bn254/marshal.go b/backend/plonk/bn254/marshal.go index 8de7d4071e..1826272c36 100644 --- a/backend/plonk/bn254/marshal.go +++ b/backend/plonk/bn254/marshal.go @@ -52,7 +52,7 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - proof.Bsb22Commitments, + proof.PI2, } for _, v := range toEncode { @@ -79,7 +79,7 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { &proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - &proof.Bsb22Commitments, + &proof.PI2, } for _, v := range toDecode { @@ -88,8 +88,8 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { } } - if proof.Bsb22Commitments == nil { - proof.Bsb22Commitments = []kzg.Digest{} + if proof.PI2 == nil { + proof.PI2 = []kzg.Digest{} } return dec.BytesRead(), nil diff --git a/backend/plonk/bn254/marshal_test.go b/backend/plonk/bn254/marshal_test.go index 8f62891c76..b7e4baec7e 100644 --- a/backend/plonk/bn254/marshal_test.go +++ b/backend/plonk/bn254/marshal_test.go @@ -182,7 +182,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.Bsb22Commitments = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here + proof.PI2 = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here } func randomPoint() curve.G1Affine { diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index 19eb938736..6cf1ef2dff 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -63,7 +63,8 @@ type Proof struct { ZShiftedOpening kzg.OpeningProof } -func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, wpi2iop []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { +// Computing and verifying Bsb22 multi-commits explained in https://hackmd.io/x8KsadW3RRyX7YTCFJIkHg +func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, cCommitments []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { committedValues := make([]fr.Element, pk.Domain[0].Cardinality) offset := spr.GetNbPublicVariables() @@ -81,9 +82,9 @@ func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof return err } pi2iop := iop.NewPolynomial(&committedValues, iop.Form{Basis: iop.Lagrange, Layout: iop.Regular}) - wpi2iop[commDepth] = pi2iop.ShallowClone() - wpi2iop[commDepth].ToCanonical(&pk.Domain[0]).ToRegular() - if proof.Bsb22Commitments[commDepth], err = kzg.Commit(wpi2iop[commDepth].Coefficients(), pk.Kzg); err != nil { + cCommitments[commDepth] = pi2iop.ShallowClone() + cCommitments[commDepth].ToCanonical(&pk.Domain[0]).ToRegular() + if proof.Bsb22Commitments[commDepth], err = kzg.Commit(cCommitments[commDepth].Coefficients(), pk.Kzg); err != nil { return err } if hashRes, err = fr.Hash(proof.Bsb22Commitments[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { @@ -116,11 +117,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof := &Proof{} commitmentVal := make([]fr.Element, len(spr.CommitmentInfo)) // TODO @Tabaie get rid of this - commitmentsCanonical := make([]*iop.Polynomial, len(spr.CommitmentInfo)) + cCommitments := make([]*iop.Polynomial, len(spr.CommitmentInfo)) proof.Bsb22Commitments = make([]kzg.Digest, len(spr.CommitmentInfo)) for i := range spr.CommitmentInfo { opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[i].HintID, - bsb22ComputeCommitmentHint(spr, pk, proof, commitmentsCanonical, &commitmentVal[i], i))) + bsb22ComputeCommitmentHint(spr, pk, proof, cCommitments, &commitmentVal[i], i))) } // query l, r, o in Lagrange basis, not blinded @@ -129,9 +130,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } // TODO @gbotrel deal with that conversion lazily - lcCommitments := make([]*iop.Polynomial, len(commitmentsCanonical)) - for i := range commitmentsCanonical { - lcCommitments[i] = commitmentsCanonical[i].Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form + lcCommitments := make([]*iop.Polynomial, len(cCommitments)) + for i := range cCommitments { + lcCommitments[i] = cCommitments[i].Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form } solution := _solution.(*cs.SparseR1CSSolution) evaluationLDomainSmall := []fr.Element(solution.L) @@ -328,8 +329,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return one } - // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm - // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, Bsb22Commitments , qCPrime + // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm + // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, Bsb22Commitments, qCPrime fm := func(x ...fr.Element) fr.Element { a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2], x[15:]) @@ -492,7 +493,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bzuzeta, qcpzeta, bwziop.Coefficients()[:bwziop.BlindedSize()], - coefficients(commitmentsCanonical), + coefficients(cCommitments), pk, ) diff --git a/backend/plonk/bn254/verify.go b/backend/plonk/bn254/verify.go index 028330de0f..f370459e8f 100644 --- a/backend/plonk/bn254/verify.go +++ b/backend/plonk/bn254/verify.go @@ -113,7 +113,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } for i := range vk.CommitmentConstraintIndexes { - var hashRes []fr.Element // TODO: when multi commits are implemented: Bsb22Commitments -> Bsb22Commitments[i] + var hashRes []fr.Element if hashRes, err = fr.Hash(proof.Bsb22Commitments[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } @@ -191,7 +191,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // Compute the commitment to the linearized polynomial // linearizedPolynomialDigest = - // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+qc*Bsb22Commitments + + // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+Σᵢqc'ᵢ(ζ)*BsbCommitmentᵢ + // α*( Z(μζ)(l(ζ)+β*s₁(ζ)+γ)*(r(ζ)+β*s₂(ζ)+γ)*s₃(X)-Z(X)(l(ζ)+β*id_1(ζ)+γ)*(r(ζ)+β*id_2(ζ)+γ)*(o(ζ)+β*id_3(ζ)+γ) ) + // α²*L₁(ζ)*Z // first part: individual constraints diff --git a/backend/plonk/bw6-633/prove.go b/backend/plonk/bw6-633/prove.go index 00c47d1cbf..4155f7dc5f 100644 --- a/backend/plonk/bw6-633/prove.go +++ b/backend/plonk/bw6-633/prove.go @@ -54,8 +54,7 @@ type Proof struct { // Commitments to h1, h2, h3 such that h = h1 + Xh2 + X**2h3 is the quotient polynomial H [3]kzg.Digest - // PI2, the BSB22 commitment - PI2 []kzg.Digest + Bsb22Commitments []kzg.Digest // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2, qCPrime BatchedProof kzg.BatchOpeningProof @@ -64,30 +63,31 @@ type Proof struct { ZShiftedOpening kzg.OpeningProof } -func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, wpi2iop []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { +// Computing and verifying Bsb22 multi-commits explained in https://hackmd.io/x8KsadW3RRyX7YTCFJIkHg +func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, cCommitments []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { - pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + committedValues := make([]fr.Element, pk.Domain[0].Cardinality) offset := spr.GetNbPublicVariables() for i := range ins { - pi2[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) + committedValues[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - /*if _, err = pi2[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + if _, err = committedValues[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } - if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding + if _, err = committedValues[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding return err - }*/ - pi2iop := iop.NewPolynomial(&pi2, iop.Form{Basis: iop.Lagrange, Layout: iop.Regular}) - wpi2iop[commDepth] = pi2iop.ShallowClone() - wpi2iop[commDepth].ToCanonical(&pk.Domain[0]).ToRegular() - if proof.PI2[commDepth], err = kzg.Commit(wpi2iop[commDepth].Coefficients(), pk.Kzg); err != nil { + } + pi2iop := iop.NewPolynomial(&committedValues, iop.Form{Basis: iop.Lagrange, Layout: iop.Regular}) + cCommitments[commDepth] = pi2iop.ShallowClone() + cCommitments[commDepth].ToCanonical(&pk.Domain[0]).ToRegular() + if proof.Bsb22Commitments[commDepth], err = kzg.Commit(cCommitments[commDepth].Coefficients(), pk.Kzg); err != nil { return err } - if hashRes, err = fr.Hash(proof.PI2[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + if hashRes, err = fr.Hash(proof.Bsb22Commitments[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } res.Set(&hashRes[0]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses @@ -117,11 +117,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof := &Proof{} commitmentVal := make([]fr.Element, len(spr.CommitmentInfo)) // TODO @Tabaie get rid of this - wpi2iop := make([]*iop.Polynomial, len(spr.CommitmentInfo)) - proof.PI2 = make([]kzg.Digest, len(spr.CommitmentInfo)) + cCommitments := make([]*iop.Polynomial, len(spr.CommitmentInfo)) + proof.Bsb22Commitments = make([]kzg.Digest, len(spr.CommitmentInfo)) for i := range spr.CommitmentInfo { opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[i].HintID, - bsb22ComputeCommitmentHint(spr, pk, proof, wpi2iop, &commitmentVal[i], i))) + bsb22ComputeCommitmentHint(spr, pk, proof, cCommitments, &commitmentVal[i], i))) } // query l, r, o in Lagrange basis, not blinded @@ -130,9 +130,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } // TODO @gbotrel deal with that conversion lazily - lcpi2iop := make([]*iop.Polynomial, len(wpi2iop)) - for i := range wpi2iop { - lcpi2iop[i] = wpi2iop[i].Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form + lcCommitments := make([]*iop.Polynomial, len(cCommitments)) + for i := range cCommitments { + lcCommitments[i] = cCommitments[i].Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form } solution := _solution.(*cs.SparseR1CSSolution) evaluationLDomainSmall := []fr.Element(solution.L) @@ -199,7 +199,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.PI2); err != nil { + if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.Bsb22Commitments); err != nil { return nil, err } @@ -329,8 +329,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return one } - // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm - // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, Bsb22Commitments , qCPrime + // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm + // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, Bsb22Commitments, qCPrime fm := func(x ...fr.Element) fr.Element { a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2], x[15:]) @@ -370,7 +370,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts lcqk, pk.lLoneIOP, } - toEval = append(toEval, lcpi2iop...) // TODO: Add this at beginning + toEval = append(toEval, lcCommitments...) // TODO: Add this at beginning toEval = append(toEval, pk.lcQcp...) systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, toEval...) if err != nil { @@ -493,7 +493,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bzuzeta, qcpzeta, bwziop.Coefficients()[:bwziop.BlindedSize()], - coefficients(wpi2iop), + coefficients(cCommitments), pk, ) diff --git a/backend/plonk/bw6-633/verify.go b/backend/plonk/bw6-633/verify.go index 0c07b83f12..8f9c361479 100644 --- a/backend/plonk/bw6-633/verify.go +++ b/backend/plonk/bw6-633/verify.go @@ -51,7 +51,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *vk, publicWitness, proof.PI2); err != nil { + if err := bindPublicData(&fs, "gamma", *vk, publicWitness, proof.Bsb22Commitments); err != nil { return err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) @@ -111,8 +111,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } for i := range vk.CommitmentConstraintIndexes { - var hashRes []fr.Element // TODO: when multi commits are implemented: Bsb22Commitments -> Bsb22Commitments[i] - if hashRes, err = fr.Hash(proof.PI2[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + var hashRes []fr.Element + if hashRes, err = fr.Hash(proof.Bsb22Commitments[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } @@ -137,9 +137,9 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - qC := make([]fr.Element, len(proof.PI2)) + qC := make([]fr.Element, len(proof.Bsb22Commitments)) copy(qC, proof.BatchedProof.ClaimedValues) - claimedValues := proof.BatchedProof.ClaimedValues[len(proof.PI2):] + claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] claimedQuotient := claimedValues[0] linearizedPolynomialZeta := claimedValues[1] l := claimedValues[2] @@ -189,7 +189,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // Compute the commitment to the linearized polynomial // linearizedPolynomialDigest = - // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+qc*Bsb22Commitments + + // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+Σᵢqc'ᵢ(ζ)*BsbCommitmentᵢ + // α*( Z(μζ)(l(ζ)+β*s₁(ζ)+γ)*(r(ζ)+β*s₂(ζ)+γ)*s₃(X)-Z(X)(l(ζ)+β*id_1(ζ)+γ)*(r(ζ)+β*id_2(ζ)+γ)*(o(ζ)+β*id_3(ζ)+γ) ) + // α²*L₁(ζ)*Z // first part: individual constraints @@ -215,7 +215,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // note since third part = α²*L₁(ζ)*Z _s2.Mul(&_s2, &alpha).Add(&_s2, &alphaSquareLagrange) // -α*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + α²*L₁(ζ) - points := append(proof.PI2, + points := append(proof.Bsb22Commitments, vk.Ql, vk.Qr, vk.Qm, vk.Qo, vk.Qk, // first part vk.S[2], proof.Z, // second & third part ) diff --git a/backend/plonk/bw6-761/prove.go b/backend/plonk/bw6-761/prove.go index 845c4adb0d..d8e147ea0a 100644 --- a/backend/plonk/bw6-761/prove.go +++ b/backend/plonk/bw6-761/prove.go @@ -54,8 +54,7 @@ type Proof struct { // Commitments to h1, h2, h3 such that h = h1 + Xh2 + X**2h3 is the quotient polynomial H [3]kzg.Digest - // PI2, the BSB22 commitment - PI2 []kzg.Digest + Bsb22Commitments []kzg.Digest // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2, qCPrime BatchedProof kzg.BatchOpeningProof @@ -64,30 +63,31 @@ type Proof struct { ZShiftedOpening kzg.OpeningProof } -func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, wpi2iop []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { +// Computing and verifying Bsb22 multi-commits explained in https://hackmd.io/x8KsadW3RRyX7YTCFJIkHg +func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, cCommitments []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { - pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + committedValues := make([]fr.Element, pk.Domain[0].Cardinality) offset := spr.GetNbPublicVariables() for i := range ins { - pi2[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) + committedValues[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - /*if _, err = pi2[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + if _, err = committedValues[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } - if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding + if _, err = committedValues[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding return err - }*/ - pi2iop := iop.NewPolynomial(&pi2, iop.Form{Basis: iop.Lagrange, Layout: iop.Regular}) - wpi2iop[commDepth] = pi2iop.ShallowClone() - wpi2iop[commDepth].ToCanonical(&pk.Domain[0]).ToRegular() - if proof.PI2[commDepth], err = kzg.Commit(wpi2iop[commDepth].Coefficients(), pk.Kzg); err != nil { + } + pi2iop := iop.NewPolynomial(&committedValues, iop.Form{Basis: iop.Lagrange, Layout: iop.Regular}) + cCommitments[commDepth] = pi2iop.ShallowClone() + cCommitments[commDepth].ToCanonical(&pk.Domain[0]).ToRegular() + if proof.Bsb22Commitments[commDepth], err = kzg.Commit(cCommitments[commDepth].Coefficients(), pk.Kzg); err != nil { return err } - if hashRes, err = fr.Hash(proof.PI2[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + if hashRes, err = fr.Hash(proof.Bsb22Commitments[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } res.Set(&hashRes[0]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses @@ -117,11 +117,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof := &Proof{} commitmentVal := make([]fr.Element, len(spr.CommitmentInfo)) // TODO @Tabaie get rid of this - wpi2iop := make([]*iop.Polynomial, len(spr.CommitmentInfo)) - proof.PI2 = make([]kzg.Digest, len(spr.CommitmentInfo)) + cCommitments := make([]*iop.Polynomial, len(spr.CommitmentInfo)) + proof.Bsb22Commitments = make([]kzg.Digest, len(spr.CommitmentInfo)) for i := range spr.CommitmentInfo { opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[i].HintID, - bsb22ComputeCommitmentHint(spr, pk, proof, wpi2iop, &commitmentVal[i], i))) + bsb22ComputeCommitmentHint(spr, pk, proof, cCommitments, &commitmentVal[i], i))) } // query l, r, o in Lagrange basis, not blinded @@ -130,9 +130,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } // TODO @gbotrel deal with that conversion lazily - lcpi2iop := make([]*iop.Polynomial, len(wpi2iop)) - for i := range wpi2iop { - lcpi2iop[i] = wpi2iop[i].Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form + lcCommitments := make([]*iop.Polynomial, len(cCommitments)) + for i := range cCommitments { + lcCommitments[i] = cCommitments[i].Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form } solution := _solution.(*cs.SparseR1CSSolution) evaluationLDomainSmall := []fr.Element(solution.L) @@ -199,7 +199,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.PI2); err != nil { + if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.Bsb22Commitments); err != nil { return nil, err } @@ -329,8 +329,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return one } - // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm - // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, Bsb22Commitments , qCPrime + // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm + // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, Bsb22Commitments, qCPrime fm := func(x ...fr.Element) fr.Element { a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2], x[15:]) @@ -370,7 +370,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts lcqk, pk.lLoneIOP, } - toEval = append(toEval, lcpi2iop...) // TODO: Add this at beginning + toEval = append(toEval, lcCommitments...) // TODO: Add this at beginning toEval = append(toEval, pk.lcQcp...) systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, toEval...) if err != nil { @@ -493,7 +493,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bzuzeta, qcpzeta, bwziop.Coefficients()[:bwziop.BlindedSize()], - coefficients(wpi2iop), + coefficients(cCommitments), pk, ) diff --git a/backend/plonk/bw6-761/verify.go b/backend/plonk/bw6-761/verify.go index 224ea3b158..f9b2dad361 100644 --- a/backend/plonk/bw6-761/verify.go +++ b/backend/plonk/bw6-761/verify.go @@ -51,7 +51,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *vk, publicWitness, proof.PI2); err != nil { + if err := bindPublicData(&fs, "gamma", *vk, publicWitness, proof.Bsb22Commitments); err != nil { return err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) @@ -111,8 +111,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } for i := range vk.CommitmentConstraintIndexes { - var hashRes []fr.Element // TODO: when multi commits are implemented: Bsb22Commitments -> Bsb22Commitments[i] - if hashRes, err = fr.Hash(proof.PI2[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + var hashRes []fr.Element + if hashRes, err = fr.Hash(proof.Bsb22Commitments[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } @@ -137,9 +137,9 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - qC := make([]fr.Element, len(proof.PI2)) + qC := make([]fr.Element, len(proof.Bsb22Commitments)) copy(qC, proof.BatchedProof.ClaimedValues) - claimedValues := proof.BatchedProof.ClaimedValues[len(proof.PI2):] + claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] claimedQuotient := claimedValues[0] linearizedPolynomialZeta := claimedValues[1] l := claimedValues[2] @@ -189,7 +189,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // Compute the commitment to the linearized polynomial // linearizedPolynomialDigest = - // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+qc*Bsb22Commitments + + // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+Σᵢqc'ᵢ(ζ)*BsbCommitmentᵢ + // α*( Z(μζ)(l(ζ)+β*s₁(ζ)+γ)*(r(ζ)+β*s₂(ζ)+γ)*s₃(X)-Z(X)(l(ζ)+β*id_1(ζ)+γ)*(r(ζ)+β*id_2(ζ)+γ)*(o(ζ)+β*id_3(ζ)+γ) ) + // α²*L₁(ζ)*Z // first part: individual constraints @@ -215,7 +215,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // note since third part = α²*L₁(ζ)*Z _s2.Mul(&_s2, &alpha).Add(&_s2, &alphaSquareLagrange) // -α*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + α²*L₁(ζ) - points := append(proof.PI2, + points := append(proof.Bsb22Commitments, vk.Ql, vk.Qr, vk.Qm, vk.Qo, vk.Qk, // first part vk.S[2], proof.Z, // second & third part ) diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl index e2b74379f8..44bf897328 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl @@ -32,8 +32,7 @@ type Proof struct { // Commitments to h1, h2, h3 such that h = h1 + Xh2 + X**2h3 is the quotient polynomial H [3]kzg.Digest - // PI2, the BSB22 commitment - PI2 []kzg.Digest + Bsb22Commitments []kzg.Digest // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2, qCPrime BatchedProof kzg.BatchOpeningProof @@ -42,30 +41,31 @@ type Proof struct { ZShiftedOpening kzg.OpeningProof } -func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, wpi2iop []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { +// Computing and verifying Bsb22 multi-commits explained in https://hackmd.io/x8KsadW3RRyX7YTCFJIkHg +func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, cCommitments []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { - pi2 := make([]fr.Element, pk.Domain[0].Cardinality) + committedValues := make([]fr.Element, pk.Domain[0].Cardinality) offset := spr.GetNbPublicVariables() for i := range ins { - pi2[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) + committedValues[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - /*if _, err = pi2[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + if _, err = committedValues[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } - if _, err = pi2[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding + if _, err = committedValues[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding return err - }*/ - pi2iop := iop.NewPolynomial(&pi2, iop.Form{Basis: iop.Lagrange, Layout: iop.Regular}) - wpi2iop[commDepth] = pi2iop.ShallowClone() - wpi2iop[commDepth].ToCanonical(&pk.Domain[0]).ToRegular() - if proof.PI2[commDepth], err = kzg.Commit(wpi2iop[commDepth].Coefficients(), pk.Kzg); err != nil { + } + pi2iop := iop.NewPolynomial(&committedValues, iop.Form{Basis: iop.Lagrange, Layout: iop.Regular}) + cCommitments[commDepth] = pi2iop.ShallowClone() + cCommitments[commDepth].ToCanonical(&pk.Domain[0]).ToRegular() + if proof.Bsb22Commitments[commDepth], err = kzg.Commit(cCommitments[commDepth].Coefficients(), pk.Kzg); err != nil { return err } - if hashRes, err = fr.Hash(proof.PI2[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + if hashRes, err = fr.Hash(proof.Bsb22Commitments[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } res.Set(&hashRes[0]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses @@ -95,11 +95,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts proof := &Proof{} commitmentVal := make([]fr.Element, len(spr.CommitmentInfo)) // TODO @Tabaie get rid of this - wpi2iop := make([]*iop.Polynomial, len(spr.CommitmentInfo)) - proof.PI2 = make([]kzg.Digest, len(spr.CommitmentInfo)) + cCommitments := make([]*iop.Polynomial, len(spr.CommitmentInfo)) + proof.Bsb22Commitments = make([]kzg.Digest, len(spr.CommitmentInfo)) for i := range spr.CommitmentInfo { opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[i].HintID, - bsb22ComputeCommitmentHint(spr, pk, proof, wpi2iop, &commitmentVal[i], i))) + bsb22ComputeCommitmentHint(spr, pk, proof, cCommitments, &commitmentVal[i], i))) } // query l, r, o in Lagrange basis, not blinded @@ -108,9 +108,9 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } // TODO @gbotrel deal with that conversion lazily - lcpi2iop := make([]*iop.Polynomial, len(wpi2iop)) - for i := range wpi2iop { - lcpi2iop[i] = wpi2iop[i].Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form + lcCommitments := make([]*iop.Polynomial, len(cCommitments)) + for i := range cCommitments { + lcCommitments[i] = cCommitments[i].Clone(int(pk.Domain[1].Cardinality)).ToLagrangeCoset(&pk.Domain[1]) // lagrange coset form } solution := _solution.(*cs.SparseR1CSSolution) evaluationLDomainSmall := []fr.Element(solution.L) @@ -179,7 +179,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.PI2); err != nil { + if err := bindPublicData(&fs, "gamma", *pk.Vk, fw[:len(spr.Public)], proof.Bsb22Commitments); err != nil { return nil, err } @@ -312,8 +312,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return one } - // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm - // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, PI2 , qCPrime + // 0 , 1 , 2, 3 , 4 , 5 , 6 , 7, 8 , 9 , 10, 11, 12, 13, 14, 15:15+nbComm , 15+nbComm:15+2×nbComm + // l , r , o, id, s1, s2, s3, z, zs, ql, qr, qm, qo, qk ,lone, Bsb22Commitments, qCPrime fm := func(x ...fr.Element) fr.Element { a := fic(x[9], x[10], x[11], x[12], x[13], x[0], x[1], x[2], x[15:]) @@ -354,7 +354,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pk.lLoneIOP, } - toEval = append(toEval, lcpi2iop...) // TODO: Add this at beginning + toEval = append(toEval, lcCommitments...) // TODO: Add this at beginning toEval = append(toEval, pk.lcQcp...) systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, toEval...) if err != nil { @@ -480,7 +480,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bzuzeta, qcpzeta, bwziop.Coefficients()[:bwziop.BlindedSize()], - coefficients(wpi2iop), + coefficients(cCommitments), pk, ) diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl index 6b4113aabc..7a2d582ce9 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl @@ -32,7 +32,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) - if err := bindPublicData(&fs, "gamma", *vk, publicWitness, proof.PI2); err != nil { + if err := bindPublicData(&fs, "gamma", *vk, publicWitness, proof.Bsb22Commitments); err != nil { return err } gamma, err := deriveRandomness(&fs, "gamma", &proof.LRO[0], &proof.LRO[1], &proof.LRO[2]) @@ -92,8 +92,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } for i := range vk.CommitmentConstraintIndexes { - var hashRes []fr.Element // TODO: when multi commits are implemented: PI2 -> PI2[i] - if hashRes, err = fr.Hash(proof.PI2[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { + var hashRes []fr.Element + if hashRes, err = fr.Hash(proof.Bsb22Commitments[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { return err } @@ -118,9 +118,9 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - qC := make([]fr.Element, len(proof.PI2)) + qC := make([]fr.Element, len(proof.Bsb22Commitments)) copy(qC, proof.BatchedProof.ClaimedValues) - claimedValues := proof.BatchedProof.ClaimedValues[len(proof.PI2):] + claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] claimedQuotient := claimedValues[0] linearizedPolynomialZeta := claimedValues[1] l := claimedValues[2] @@ -170,7 +170,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // Compute the commitment to the linearized polynomial // linearizedPolynomialDigest = - // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+qc*PI2 + + // l(ζ)*ql+r(ζ)*qr+r(ζ)l(ζ)*qm+o(ζ)*qo+qk+Σᵢqc'ᵢ(ζ)*BsbCommitmentᵢ + // α*( Z(μζ)(l(ζ)+β*s₁(ζ)+γ)*(r(ζ)+β*s₂(ζ)+γ)*s₃(X)-Z(X)(l(ζ)+β*id_1(ζ)+γ)*(r(ζ)+β*id_2(ζ)+γ)*(o(ζ)+β*id_3(ζ)+γ) ) + // α²*L₁(ζ)*Z // first part: individual constraints @@ -196,7 +196,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // note since third part = α²*L₁(ζ)*Z _s2.Mul(&_s2, &alpha).Add(&_s2, &alphaSquareLagrange) // -α*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + α²*L₁(ζ) - points := append(proof.PI2, + points := append(proof.Bsb22Commitments, vk.Ql, vk.Qr, vk.Qm, vk.Qo, vk.Qk, // first part vk.S[2], proof.Z, // second & third part ) From 7f134b99cd2aa05589c5aace7c91ba5c4b348d79 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 10 May 2023 19:08:10 -0500 Subject: [PATCH 363/464] fix: PI2 renaming in marshal --- backend/plonk/bls12-377/marshal.go | 8 ++++---- backend/plonk/bls12-377/marshal_test.go | 2 +- backend/plonk/bls12-381/marshal.go | 8 ++++---- backend/plonk/bls12-381/marshal_test.go | 2 +- backend/plonk/bls24-315/marshal.go | 8 ++++---- backend/plonk/bls24-315/marshal_test.go | 2 +- backend/plonk/bls24-317/marshal.go | 8 ++++---- backend/plonk/bls24-317/marshal_test.go | 2 +- backend/plonk/bn254/marshal.go | 8 ++++---- backend/plonk/bn254/marshal_test.go | 2 +- backend/plonk/bw6-633/marshal.go | 8 ++++---- backend/plonk/bw6-633/marshal_test.go | 2 +- backend/plonk/bw6-761/marshal.go | 8 ++++---- backend/plonk/bw6-761/marshal_test.go | 2 +- .../template/zkpschemes/plonk/plonk.marshal.go.tmpl | 8 ++++---- .../template/zkpschemes/plonk/tests/marshal.go.tmpl | 2 +- 16 files changed, 40 insertions(+), 40 deletions(-) diff --git a/backend/plonk/bls12-377/marshal.go b/backend/plonk/bls12-377/marshal.go index d2cc763a19..fd1986e170 100644 --- a/backend/plonk/bls12-377/marshal.go +++ b/backend/plonk/bls12-377/marshal.go @@ -52,7 +52,7 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - proof.PI2, + proof.Bsb22Commitments, } for _, v := range toEncode { @@ -79,7 +79,7 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { &proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - &proof.PI2, + &proof.Bsb22Commitments, } for _, v := range toDecode { @@ -88,8 +88,8 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { } } - if proof.PI2 == nil { - proof.PI2 = []kzg.Digest{} + if proof.Bsb22Commitments == nil { + proof.Bsb22Commitments = []kzg.Digest{} } return dec.BytesRead(), nil diff --git a/backend/plonk/bls12-377/marshal_test.go b/backend/plonk/bls12-377/marshal_test.go index eea3a0a468..8757e9a3a5 100644 --- a/backend/plonk/bls12-377/marshal_test.go +++ b/backend/plonk/bls12-377/marshal_test.go @@ -182,7 +182,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.PI2 = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here + proof.Bsb22Commitments = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here } func randomPoint() curve.G1Affine { diff --git a/backend/plonk/bls12-381/marshal.go b/backend/plonk/bls12-381/marshal.go index da1ca98e9c..7f9306f2b6 100644 --- a/backend/plonk/bls12-381/marshal.go +++ b/backend/plonk/bls12-381/marshal.go @@ -52,7 +52,7 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - proof.PI2, + proof.Bsb22Commitments, } for _, v := range toEncode { @@ -79,7 +79,7 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { &proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - &proof.PI2, + &proof.Bsb22Commitments, } for _, v := range toDecode { @@ -88,8 +88,8 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { } } - if proof.PI2 == nil { - proof.PI2 = []kzg.Digest{} + if proof.Bsb22Commitments == nil { + proof.Bsb22Commitments = []kzg.Digest{} } return dec.BytesRead(), nil diff --git a/backend/plonk/bls12-381/marshal_test.go b/backend/plonk/bls12-381/marshal_test.go index bb91252717..9beb310d2a 100644 --- a/backend/plonk/bls12-381/marshal_test.go +++ b/backend/plonk/bls12-381/marshal_test.go @@ -182,7 +182,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.PI2 = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here + proof.Bsb22Commitments = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here } func randomPoint() curve.G1Affine { diff --git a/backend/plonk/bls24-315/marshal.go b/backend/plonk/bls24-315/marshal.go index 271e56fba2..c57a9ca828 100644 --- a/backend/plonk/bls24-315/marshal.go +++ b/backend/plonk/bls24-315/marshal.go @@ -52,7 +52,7 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - proof.PI2, + proof.Bsb22Commitments, } for _, v := range toEncode { @@ -79,7 +79,7 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { &proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - &proof.PI2, + &proof.Bsb22Commitments, } for _, v := range toDecode { @@ -88,8 +88,8 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { } } - if proof.PI2 == nil { - proof.PI2 = []kzg.Digest{} + if proof.Bsb22Commitments == nil { + proof.Bsb22Commitments = []kzg.Digest{} } return dec.BytesRead(), nil diff --git a/backend/plonk/bls24-315/marshal_test.go b/backend/plonk/bls24-315/marshal_test.go index 4ba9dea1bf..f61cb1be1d 100644 --- a/backend/plonk/bls24-315/marshal_test.go +++ b/backend/plonk/bls24-315/marshal_test.go @@ -182,7 +182,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.PI2 = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here + proof.Bsb22Commitments = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here } func randomPoint() curve.G1Affine { diff --git a/backend/plonk/bls24-317/marshal.go b/backend/plonk/bls24-317/marshal.go index dc79e285d8..5178acefbd 100644 --- a/backend/plonk/bls24-317/marshal.go +++ b/backend/plonk/bls24-317/marshal.go @@ -52,7 +52,7 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - proof.PI2, + proof.Bsb22Commitments, } for _, v := range toEncode { @@ -79,7 +79,7 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { &proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - &proof.PI2, + &proof.Bsb22Commitments, } for _, v := range toDecode { @@ -88,8 +88,8 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { } } - if proof.PI2 == nil { - proof.PI2 = []kzg.Digest{} + if proof.Bsb22Commitments == nil { + proof.Bsb22Commitments = []kzg.Digest{} } return dec.BytesRead(), nil diff --git a/backend/plonk/bls24-317/marshal_test.go b/backend/plonk/bls24-317/marshal_test.go index a3a664ea84..4e68aa0e9f 100644 --- a/backend/plonk/bls24-317/marshal_test.go +++ b/backend/plonk/bls24-317/marshal_test.go @@ -182,7 +182,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.PI2 = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here + proof.Bsb22Commitments = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here } func randomPoint() curve.G1Affine { diff --git a/backend/plonk/bn254/marshal.go b/backend/plonk/bn254/marshal.go index 1826272c36..8de7d4071e 100644 --- a/backend/plonk/bn254/marshal.go +++ b/backend/plonk/bn254/marshal.go @@ -52,7 +52,7 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - proof.PI2, + proof.Bsb22Commitments, } for _, v := range toEncode { @@ -79,7 +79,7 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { &proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - &proof.PI2, + &proof.Bsb22Commitments, } for _, v := range toDecode { @@ -88,8 +88,8 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { } } - if proof.PI2 == nil { - proof.PI2 = []kzg.Digest{} + if proof.Bsb22Commitments == nil { + proof.Bsb22Commitments = []kzg.Digest{} } return dec.BytesRead(), nil diff --git a/backend/plonk/bn254/marshal_test.go b/backend/plonk/bn254/marshal_test.go index b7e4baec7e..8f62891c76 100644 --- a/backend/plonk/bn254/marshal_test.go +++ b/backend/plonk/bn254/marshal_test.go @@ -182,7 +182,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.PI2 = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here + proof.Bsb22Commitments = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here } func randomPoint() curve.G1Affine { diff --git a/backend/plonk/bw6-633/marshal.go b/backend/plonk/bw6-633/marshal.go index 5b88f747e8..d5fe075d58 100644 --- a/backend/plonk/bw6-633/marshal.go +++ b/backend/plonk/bw6-633/marshal.go @@ -52,7 +52,7 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - proof.PI2, + proof.Bsb22Commitments, } for _, v := range toEncode { @@ -79,7 +79,7 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { &proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - &proof.PI2, + &proof.Bsb22Commitments, } for _, v := range toDecode { @@ -88,8 +88,8 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { } } - if proof.PI2 == nil { - proof.PI2 = []kzg.Digest{} + if proof.Bsb22Commitments == nil { + proof.Bsb22Commitments = []kzg.Digest{} } return dec.BytesRead(), nil diff --git a/backend/plonk/bw6-633/marshal_test.go b/backend/plonk/bw6-633/marshal_test.go index a57b6397fd..039693fbf7 100644 --- a/backend/plonk/bw6-633/marshal_test.go +++ b/backend/plonk/bw6-633/marshal_test.go @@ -182,7 +182,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.PI2 = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here + proof.Bsb22Commitments = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here } func randomPoint() curve.G1Affine { diff --git a/backend/plonk/bw6-761/marshal.go b/backend/plonk/bw6-761/marshal.go index 2e9205a827..b7130a2b8c 100644 --- a/backend/plonk/bw6-761/marshal.go +++ b/backend/plonk/bw6-761/marshal.go @@ -52,7 +52,7 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - proof.PI2, + proof.Bsb22Commitments, } for _, v := range toEncode { @@ -79,7 +79,7 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { &proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - &proof.PI2, + &proof.Bsb22Commitments, } for _, v := range toDecode { @@ -88,8 +88,8 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { } } - if proof.PI2 == nil { - proof.PI2 = []kzg.Digest{} + if proof.Bsb22Commitments == nil { + proof.Bsb22Commitments = []kzg.Digest{} } return dec.BytesRead(), nil diff --git a/backend/plonk/bw6-761/marshal_test.go b/backend/plonk/bw6-761/marshal_test.go index 1e321ce093..e2fdc67ec8 100644 --- a/backend/plonk/bw6-761/marshal_test.go +++ b/backend/plonk/bw6-761/marshal_test.go @@ -182,7 +182,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.PI2 = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here + proof.Bsb22Commitments = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here } func randomPoint() curve.G1Affine { diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl index 78a802990c..3d72c06013 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl @@ -32,7 +32,7 @@ func (proof *Proof) writeTo(w io.Writer, options ...func(*curve.Encoder)) (int64 proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - proof.PI2, + proof.Bsb22Commitments, } for _, v := range toEncode { @@ -59,7 +59,7 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { &proof.BatchedProof.ClaimedValues, &proof.ZShiftedOpening.H, &proof.ZShiftedOpening.ClaimedValue, - &proof.PI2, + &proof.Bsb22Commitments, } for _, v := range toDecode { @@ -68,8 +68,8 @@ func (proof *Proof) ReadFrom(r io.Reader) (int64, error) { } } - if proof.PI2 == nil { - proof.PI2 = []kzg.Digest{} + if proof.Bsb22Commitments == nil { + proof.Bsb22Commitments = []kzg.Digest{} } return dec.BytesRead(), nil diff --git a/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl index 62e3589a00..ccffcfe9bd 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl @@ -163,7 +163,7 @@ func (proof *Proof) randomize() { proof.BatchedProof.ClaimedValues = randomScalars(2) proof.ZShiftedOpening.H = randomPoint() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.PI2 = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here + proof.Bsb22Commitments = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here } func randomPoint() curve.G1Affine { From 7d3c0f5eca9c267f4975dabc9d75652534caa6eb Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Mon, 15 May 2023 15:42:25 +0100 Subject: [PATCH 364/464] Refactor, perf: 2-chains pairing + groth16 API (#664) * refactor: revisit bls12-377 pairing in bw6-761 * refactor: revisit bls24-315 pairing in bw6-633 * refactor(std/groth16): refactor API for bls12 and bls24 * fix: update internal/stats * refactor: FillG1K -> Allocate --------- Co-authored-by: Gautam Botrel --- internal/stats/latest.stats | Bin 2803 -> 2803 bytes internal/stats/snippet.go | 8 +- std/algebra/native/fields_bls12377/e12.go | 2 + .../native/fields_bls12377/e12_pairing.go | 56 +++- std/algebra/native/fields_bls12377/e6.go | 25 ++ .../native/fields_bls24315/e24_pairing.go | 20 ++ std/algebra/native/sw_bls12377/pairing.go | 178 +++++++++--- std/algebra/native/sw_bls24315/pairing.go | 253 ++++++++++++++++-- std/groth16_bls12377/verifier.go | 41 ++- std/groth16_bls12377/verifier_test.go | 165 +++++++----- std/groth16_bls24315/verifier.go | 38 ++- std/groth16_bls24315/verifier_test.go | 165 +++++++----- 12 files changed, 741 insertions(+), 210 deletions(-) diff --git a/internal/stats/latest.stats b/internal/stats/latest.stats index 0fd0b70df05c10b4e3319b6ea7fce2a9ab4b0f66..dcd297d1850cac261218ded2d0419eeb2f924e67 100644 GIT binary patch delta 149 zcmew?`dM^B*5ozJt&_bO?@oTt`gC#>vx-g)?m>_?K~J8<@Z8117KvO= 2 { - // k = 1 - Qacc[1], l1 = DoubleStep(api, &Qacc[1]) + // k = 1, separately to avoid MulBy034 (res × ℓ) + // (res is also a line at this point, so we use Mul034By034 ℓ × ℓ) + Qacc[1], l1 = doubleStep(api, &Qacc[1]) + + // line evaluation at P[1] l1.R0.MulByFp(api, l1.R0, xOverY[1]) l1.R1.MulByFp(api, l1.R1, yInv[1]) - res.Mul034By034(api, l1.R0, l1.R1, res.C1.B0, res.C1.B1) + + // ℓ × res + prodLines = *fields_bls12377.Mul034By034(api, l1.R0, l1.R1, res.C1.B0, res.C1.B1) + res.C0.B0 = prodLines[0] + res.C0.B1 = prodLines[1] + res.C0.B2 = prodLines[2] + res.C1.B0 = prodLines[3] + res.C1.B1 = prodLines[4] + } if n >= 3 { - // k >= 2 - for k := 2; k < n; k++ { - Qacc[k], l1 = DoubleStep(api, &Qacc[k]) + // k = 2, separately to avoid MulBy034 (res × ℓ) + // (res has a zero E2 element, so we use Mul01234By034) + Qacc[2], l1 = doubleStep(api, &Qacc[2]) + + // line evaluation at P[1] + l1.R0.MulByFp(api, l1.R0, xOverY[2]) + l1.R1.MulByFp(api, l1.R1, yInv[2]) + + // ℓ × res + res = *fields_bls12377.Mul01234By034(api, prodLines, l1.R0, l1.R1) + + // k >= 3 + for k := 3; k < n; k++ { + // Qacc[k] ← 2Qacc[k] and l1 the tangent ℓ passing 2Qacc[k] + Qacc[k], l1 = doubleStep(api, &Qacc[k]) + + // line evaluation at P[k] l1.R0.MulByFp(api, l1.R0, xOverY[k]) l1.R1.MulByFp(api, l1.R1, yInv[k]) + + // ℓ × res res.MulBy034(api, l1.R0, l1.R1) } } - for i := len(ateLoopBin) - 3; i >= 0; i-- { + for i := 61; i >= 1; i-- { + // mutualize the square among n Miller loops + // (∏ᵢfᵢ)² res.Square(api, res) - if ateLoopBin[i] == 0 { + if loopCounter[i] == 0 { for k := 0; k < n; k++ { - Qacc[k], l1 = DoubleStep(api, &Qacc[k]) + // Qacc[k] ← 2Qacc[k] and l1 the tangent ℓ passing 2Qacc[k] + Qacc[k], l1 = doubleStep(api, &Qacc[k]) + + // line evaluation at P[k] l1.R0.MulByFp(api, l1.R0, xOverY[k]) l1.R1.MulByFp(api, l1.R1, yInv[k]) + + // ℓ × res res.MulBy034(api, l1.R0, l1.R1) } continue } for k := 0; k < n; k++ { - Qacc[k], l1, l2 = DoubleAndAddStep(api, &Qacc[k], &Q[k]) + // Qacc[k] ← 2Qacc[k]+Q[k], + // l1 the line ℓ passing Qacc[k] and Q[k] + // l2 the line ℓ passing (Qacc[k]+Q[k]) and Qacc[k] + Qacc[k], l1, l2 = doubleAndAddStep(api, &Qacc[k], &Q[k]) + + // lines evaluation at P[k] l1.R0.MulByFp(api, l1.R0, xOverY[k]) l1.R1.MulByFp(api, l1.R1, yInv[k]) - res.MulBy034(api, l1.R0, l1.R1) l2.R0.MulByFp(api, l2.R0, xOverY[k]) l2.R1.MulByFp(api, l2.R1, yInv[k]) - res.MulBy034(api, l2.R0, l2.R1) + + // ℓ × ℓ + prodLines = *fields_bls12377.Mul034By034(api, l1.R0, l1.R1, l2.R0, l2.R1) + // (ℓ × ℓ) × res + res.MulBy01234(api, prodLines) } } + // i = 0 + res.Square(api, res) + for k := 0; k < n; k++ { + // l1 line through Qacc[k] and Q[k] + // l2 line through Qacc[k]+Q[k] and Qacc[k] + l1, l2 = linesCompute(api, &Qacc[k], &Q[k]) + l1.R0.MulByFp(api, l1.R0, xOverY[k]) + l1.R1.MulByFp(api, l1.R1, yInv[k]) + l2.R0.MulByFp(api, l2.R0, xOverY[k]) + l2.R1.MulByFp(api, l2.R1, yInv[k]) + + // ℓ × ℓ + prodLines = *fields_bls12377.Mul034By034(api, l1.R0, l1.R1, l2.R0, l2.R1) + // (ℓ × ℓ) × res + res.MulBy01234(api, prodLines) + } + return res, nil } -// FinalExponentiation computes the final expo x**(p**6-1)(p**2+1)(p**4 - p**2 +1)/r +// FinalExponentiation computes the exponentiation e1ᵈ +// where d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r +// we use instead d=s ⋅ (p⁶-1)(p²+1)(p⁴ - p² +1)/r +// where s is the cofactor 3 (Hayashida et al.) func FinalExponentiation(api frontend.API, e1 GT) GT { - const genT = ateLoop + const genT = 9586122913090633729 result := e1 @@ -122,6 +190,7 @@ func FinalExponentiation(api frontend.API, e1 GT) GT { var t [3]GT // easy part + // (p⁶-1)(p²+1) t[0].Conjugate(api, result) t[0].DivUnchecked(api, t[0], result) result.FrobeniusSquare(api, t[0]). @@ -154,6 +223,9 @@ func FinalExponentiation(api frontend.API, e1 GT) GT { } // Pair calculates the reduced pairing for a set of points +// ∏ᵢ e(Pᵢ, Qᵢ). +// +// This function doesn't check that the inputs are in the correct subgroup. See IsInSubGroup. func Pair(api frontend.API, P []G1Affine, Q []G2Affine) (GT, error) { f, err := MillerLoop(api, P, Q) if err != nil { @@ -162,11 +234,12 @@ func Pair(api frontend.API, P []G1Affine, Q []G2Affine) (GT, error) { return FinalExponentiation(api, f), nil } -// DoubleAndAddStep -func DoubleAndAddStep(api frontend.API, p1, p2 *G2Affine) (G2Affine, LineEvaluation, LineEvaluation) { +// doubleAndAddStep doubles p1 and adds p2 to the result in affine coordinates, and evaluates the line in Miller loop +// https://eprint.iacr.org/2022/1162 (Section 6.1) +func doubleAndAddStep(api frontend.API, p1, p2 *G2Affine) (G2Affine, lineEvaluation, lineEvaluation) { var n, d, l1, l2, x3, x4, y4 fields_bls12377.E2 - var line1, line2 LineEvaluation + var line1, line2 lineEvaluation var p G2Affine // compute lambda1 = (y2-y1)/(x2-x1) @@ -211,11 +284,13 @@ func DoubleAndAddStep(api frontend.API, p1, p2 *G2Affine) (G2Affine, LineEvaluat return p, line1, line2 } -func DoubleStep(api frontend.API, p1 *G2Affine) (G2Affine, LineEvaluation) { +// doubleStep doubles a point in affine coordinates, and evaluates the line in Miller loop +// https://eprint.iacr.org/2022/1162 (Section 6.1) +func doubleStep(api frontend.API, p1 *G2Affine) (G2Affine, lineEvaluation) { var n, d, l, xr, yr fields_bls12377.E2 var p G2Affine - var line LineEvaluation + var line lineEvaluation // lambda = 3*p1.x**2/2*p.y n.Square(api, p1.X).MulByFp(api, n, 3) @@ -241,3 +316,38 @@ func DoubleStep(api frontend.API, p1 *G2Affine) (G2Affine, LineEvaluation) { return p, line } + +// linesCompute computes the lines that goes through p1 and p2, and (p1+p2) and p1 but does not compute 2p1+p2 +func linesCompute(api frontend.API, p1, p2 *G2Affine) (lineEvaluation, lineEvaluation) { + + var n, d, l1, l2, x3 fields_bls12377.E2 + var line1, line2 lineEvaluation + + // compute lambda1 = (y2-y1)/(x2-x1) + n.Sub(api, p1.Y, p2.Y) + d.Sub(api, p1.X, p2.X) + l1.DivUnchecked(api, n, d) + + // x3 =lambda1**2-p1.x-p2.x + x3.Square(api, l1). + Sub(api, x3, p1.X). + Sub(api, x3, p2.X) + + // omit y3 computation + + // compute line1 + line1.R0.Neg(api, l1) + line1.R1.Mul(api, l1, p1.X).Sub(api, line1.R1, p1.Y) + + // compute lambda2 = -lambda1-2*y1/(x3-x1) + n.Double(api, p1.Y) + d.Sub(api, x3, p1.X) + l2.DivUnchecked(api, n, d) + l2.Add(api, l2, l1).Neg(api, l2) + + // compute line2 + line2.R0.Neg(api, l2) + line2.R1.Mul(api, l2, p1.X).Sub(api, line2.R1, p1.Y) + + return line1, line2 +} diff --git a/std/algebra/native/sw_bls24315/pairing.go b/std/algebra/native/sw_bls24315/pairing.go index 57b4b8e928..c796688cb5 100644 --- a/std/algebra/native/sw_bls24315/pairing.go +++ b/std/algebra/native/sw_bls24315/pairing.go @@ -30,12 +30,15 @@ type GT = fields_bls24315.E24 const ateLoop = 3218079743 -// LineEvaluation represents a sparse Fp12 Elmt (result of the line evaluation) -type LineEvaluation struct { +// lineEvaluation represents a sparse Fp12 Elmt (result of the line evaluation) +// line: 1 + R0(x/y) + R1(1/y) = 0 instead of R0'*y + R1'*x + R2' = 0 This +// makes the multiplication by lines (MulBy034) and between lines (Mul034By034) +type lineEvaluation struct { R0, R1 fields_bls24315.E4 } // MillerLoop computes the product of n miller loops (n can be 1) +// ∏ᵢ { fᵢ_{x₀,Q}(P) } func MillerLoop(api frontend.API, P []G1Affine, Q []G2Affine) (GT, error) { // check input size match n := len(P) @@ -48,8 +51,9 @@ func MillerLoop(api frontend.API, P []G1Affine, Q []G2Affine) (GT, error) { var res GT res.SetOne() + var prodLines [5]fields_bls24315.E4 - var l1, l2 LineEvaluation + var l1, l2 lineEvaluation Qacc := make([]G2Affine, n) Qneg := make([]G2Affine, n) yInv := make([]frontend.Variable, n) @@ -57,72 +61,177 @@ func MillerLoop(api frontend.API, P []G1Affine, Q []G2Affine) (GT, error) { for k := 0; k < n; k++ { Qacc[k] = Q[k] Qneg[k].Neg(api, Q[k]) + // TODO: point P=(x,O) should be ruled out yInv[k] = api.DivUnchecked(1, P[k].Y) - xOverY[k] = api.DivUnchecked(P[k].X, P[k].Y) + xOverY[k] = api.Mul(P[k].X, yInv[k]) } - // k = 0 - Qacc[0], l1 = DoubleStep(api, &Qacc[0]) + // Compute ∏ᵢ { fᵢ_{x₀,Q}(P) } + // i = 32, separately to avoid an E24 Square + // (Square(res) = 1² = 1) + + // k = 0, separately to avoid MulBy034 (res × ℓ) + // (assign line to res) + Qacc[0], l1 = doubleStep(api, &Qacc[0]) res.D1.C0.MulByFp(api, l1.R0, xOverY[0]) res.D1.C1.MulByFp(api, l1.R1, yInv[0]) if n >= 2 { - // k = 1 - Qacc[1], l1 = DoubleStep(api, &Qacc[1]) + // k = 1, separately to avoid MulBy034 (res × ℓ) + // (res is also a line at this point, so we use Mul034By034 ℓ × ℓ) + Qacc[1], l1 = doubleStep(api, &Qacc[1]) + + // line evaluation at P[1] l1.R0.MulByFp(api, l1.R0, xOverY[1]) l1.R1.MulByFp(api, l1.R1, yInv[1]) - res.Mul034By034(api, l1.R0, l1.R1, res.D1.C0, res.D1.C1) + + // ℓ × res + prodLines = *fields_bls24315.Mul034By034(api, l1.R0, l1.R1, res.D1.C0, res.D1.C1) + res.D0.C0 = prodLines[0] + res.D0.C1 = prodLines[1] + res.D0.C2 = prodLines[2] + res.D1.C0 = prodLines[3] + res.D1.C1 = prodLines[4] + } if n >= 3 { // k >= 2 for k := 2; k < n; k++ { - Qacc[k], l1 = DoubleStep(api, &Qacc[k]) + // Qacc[k] ← 2Qacc[k] and l1 the tangent ℓ passing 2Qacc[k] + Qacc[k], l1 = doubleStep(api, &Qacc[k]) + + // line evaluation at P[k] l1.R0.MulByFp(api, l1.R0, xOverY[k]) l1.R1.MulByFp(api, l1.R1, yInv[k]) + + // ℓ × res res.MulBy034(api, l1.R0, l1.R1) } } - for i := len(ateLoop2NAF) - 3; i >= 0; i-- { + // i = 30, separately to avoid a doubleStep + // (at this point Qacc = 2Q, so 2Qacc-Q=3Q is equivalent to Qacc+Q=3Q + // this means doubleAndAddStep is equivalent to addStep here) + res.Square(api, res) + for k := 0; k < n; k++ { + // l2 the line passing Qacc[k] and -Q + l2 = lineCompute(api, &Qacc[k], &Qneg[k]) + + // line evaluation at P[k] + l2.R0.MulByFp(api, l2.R0, xOverY[k]) + l2.R1.MulByFp(api, l2.R1, yInv[k]) + + // Qacc[k] ← Qacc[k]+Q[k] and + // l1 the line ℓ passing Qacc[k] and Q[k] + Qacc[k], l1 = addStep(api, &Qacc[k], &Q[k]) + + // line evaluation at P[k] + l1.R0.MulByFp(api, l1.R0, xOverY[k]) + l1.R1.MulByFp(api, l1.R1, yInv[k]) + + // ℓ × res + res.MulBy034(api, l1.R0, l1.R1) + // ℓ × res + res.MulBy034(api, l2.R0, l2.R1) + } + + for i := 29; i >= 1; i-- { + // mutualize the square among n Miller loops + // (∏ᵢfᵢ)² res.Square(api, res) - if ateLoop2NAF[i] == 0 { + switch ateLoop2NAF[i] { + case 0: for k := 0; k < n; k++ { - Qacc[k], l1 = DoubleStep(api, &Qacc[k]) + // Qacc[k] ← 2Qacc[k] and l1 the tangent ℓ passing 2Qacc[k] + Qacc[k], l1 = doubleStep(api, &Qacc[k]) + + // line evaluation at P[k] l1.R0.MulByFp(api, l1.R0, xOverY[k]) l1.R1.MulByFp(api, l1.R1, yInv[k]) + + // ℓ × res res.MulBy034(api, l1.R0, l1.R1) } - } else if ateLoop2NAF[i] == 1 { + case 1: for k := 0; k < n; k++ { - Qacc[k], l1, l2 = DoubleAndAddStep(api, &Qacc[k], &Q[k]) + // Qacc[k] ← 2Qacc[k]+Q[k], + // l1 the line ℓ passing Qacc[k] and Q[k] + // l2 the line ℓ passing (Qacc[k]+Q[k]) and Qacc[k] + Qacc[k], l1, l2 = doubleAndAddStep(api, &Qacc[k], &Q[k]) + + // line evaluation at P[k] l1.R0.MulByFp(api, l1.R0, xOverY[k]) l1.R1.MulByFp(api, l1.R1, yInv[k]) + + // ℓ × res res.MulBy034(api, l1.R0, l1.R1) + + // line evaluation at P[k] l2.R0.MulByFp(api, l2.R0, xOverY[k]) l2.R1.MulByFp(api, l2.R1, yInv[k]) + + // ℓ × res res.MulBy034(api, l2.R0, l2.R1) } - } else { + case -1: for k := 0; k < n; k++ { - Qacc[k], l1, l2 = DoubleAndAddStep(api, &Qacc[k], &Qneg[k]) + // Qacc[k] ← 2Qacc[k]-Q[k], + // l1 the line ℓ passing Qacc[k] and Q[k] + // l2 the line ℓ passing (Qacc[k]-Q[k]) and Qacc[k] + Qacc[k], l1, l2 = doubleAndAddStep(api, &Qacc[k], &Qneg[k]) + + // line evaluation at P[k] l1.R0.MulByFp(api, l1.R0, xOverY[k]) l1.R1.MulByFp(api, l1.R1, yInv[k]) + + // ℓ × res res.MulBy034(api, l1.R0, l1.R1) + + // line evaluation at P[k] l2.R0.MulByFp(api, l2.R0, xOverY[k]) l2.R1.MulByFp(api, l2.R1, yInv[k]) + + // ℓ × res res.MulBy034(api, l2.R0, l2.R1) } + default: + return GT{}, errors.New("invalid loopCounter") } } + // i = 0 + res.Square(api, res) + for k := 0; k < n; k++ { + // l1 the line ℓ passing Qacc[k] and -Q[k] + // l2 the line ℓ passing (Qacc[k]-Q[k]) and Qacc[k] + l1, l2 = linesCompute(api, &Qacc[k], &Qneg[k]) + + // line evaluation at P[k] + l1.R0.MulByFp(api, l1.R0, xOverY[k]) + l1.R1.MulByFp(api, l1.R1, yInv[k]) + + // ℓ × res + res.MulBy034(api, l1.R0, l1.R1) + + // line evaluation at P[k] + l2.R0.MulByFp(api, l2.R0, xOverY[k]) + l2.R1.MulByFp(api, l2.R1, yInv[k]) + + // ℓ × res + res.MulBy034(api, l2.R0, l2.R1) + } + res.Conjugate(api, res) return res, nil } -// FinalExponentiation computes the final expo x**(p**12-1)(p**4+1)(p**8 - p**4 +1)/r +// FinalExponentiation computes the exponentiation e1ᵈ +// where d = (p²⁴-1)/r = (p²⁴-1)/Φ₂₄(p) ⋅ Φ₂₄(p)/r = (p¹²-1)(p⁴+1)(p⁸ - p⁴ +1)/r +// we use instead d=s ⋅ (p¹²-1)(p⁴+1)(p⁸ - p⁴ +1)/r +// where s is the cofactor 3 (Hayashida et al.) func FinalExponentiation(api frontend.API, e1 GT) GT { const genT = ateLoop result := e1 @@ -131,6 +240,7 @@ func FinalExponentiation(api frontend.API, e1 GT) GT { var t [9]GT // easy part + // (p¹²-1)(p⁴+1) t[0].Conjugate(api, result) t[0].DivUnchecked(api, t[0], result) result.FrobeniusQuad(api, t[0]). @@ -140,7 +250,7 @@ func FinalExponentiation(api frontend.API, e1 GT) GT { // Daiki Hayashida and Kenichiro Hayasaka // and Tadanori Teruya // https://eprint.iacr.org/2020/875.pdf - // 3*Phi_24(p)/r = (u-1)² * (u+p) * (u²+p²) * (u⁴+p⁴-1) + 3 + // 3(p⁸ - p⁴ +1)/r = (x₀-1)² * (x₀+p) * (x₀²+p²) * (x₀⁴+p⁴-1) + 3 t[0].CyclotomicSquare(api, result) t[1].Expt(api, result, genT) t[2].Conjugate(api, result) @@ -169,7 +279,10 @@ func FinalExponentiation(api frontend.API, e1 GT) GT { return result } -// Pair calculates the reduced pairing for a set of points +// PairingCheck calculates the reduced pairing for a set of points and returns True if the result is One +// ∏ᵢ e(Pᵢ, Qᵢ) =? 1 +// +// This function doesn't check that the inputs are in the correct subgroup. See IsInSubGroup. func Pair(api frontend.API, P []G1Affine, Q []G2Affine) (GT, error) { f, err := MillerLoop(api, P, Q) if err != nil { @@ -178,11 +291,12 @@ func Pair(api frontend.API, P []G1Affine, Q []G2Affine) (GT, error) { return FinalExponentiation(api, f), nil } -// DoubleAndAddStep -func DoubleAndAddStep(api frontend.API, p1, p2 *G2Affine) (G2Affine, LineEvaluation, LineEvaluation) { +// doubleAndAddStep doubles p1 and adds p2 to the result in affine coordinates, and evaluates the line in Miller loop +// https://eprint.iacr.org/2022/1162 (Section 6.1) +func doubleAndAddStep(api frontend.API, p1, p2 *G2Affine) (G2Affine, lineEvaluation, lineEvaluation) { var n, d, l1, l2, x3, x4, y4 fields_bls24315.E4 - var line1, line2 LineEvaluation + var line1, line2 lineEvaluation var p G2Affine // compute lambda1 = (y2-y1)/(x2-x1) @@ -227,11 +341,13 @@ func DoubleAndAddStep(api frontend.API, p1, p2 *G2Affine) (G2Affine, LineEvaluat return p, line1, line2 } -func DoubleStep(api frontend.API, p1 *G2Affine) (G2Affine, LineEvaluation) { +// doubleStep doubles a point in affine coordinates, and evaluates the line in Miller loop +// https://eprint.iacr.org/2022/1162 (Section 6.1) +func doubleStep(api frontend.API, p1 *G2Affine) (G2Affine, lineEvaluation) { var n, d, l, xr, yr fields_bls24315.E4 var p G2Affine - var line LineEvaluation + var line lineEvaluation // lambda = 3*p1.x**2/2*p.y n.Square(api, p1.X).MulByFp(api, n, 3) @@ -257,3 +373,90 @@ func DoubleStep(api frontend.API, p1 *G2Affine) (G2Affine, LineEvaluation) { return p, line } + +// addStep adds two points in affine coordinates, and evaluates the line in Miller loop +// https://eprint.iacr.org/2022/1162 (Section 6.1) +func addStep(api frontend.API, p1, p2 *G2Affine) (G2Affine, lineEvaluation) { + + var p2ypy, p2xpx, λ, λλ, pxrx, λpxrx, xr, yr fields_bls24315.E4 + // compute λ = (y2-y1)/(x2-x1) + p2ypy.Sub(api, p2.Y, p1.Y) + p2xpx.Sub(api, p2.X, p1.X) + λ.DivUnchecked(api, p2ypy, p2xpx) + + // xr = λ²-x1-x2 + λλ.Square(api, λ) + p2xpx.Add(api, p1.X, p2.X) + xr.Sub(api, λλ, p2xpx) + + // yr = λ(x1-xr) - y1 + pxrx.Sub(api, p1.X, xr) + λpxrx.Mul(api, λ, pxrx) + yr.Sub(api, λpxrx, p1.Y) + + var res G2Affine + res.X = xr + res.Y = yr + + var line lineEvaluation + line.R0.Neg(api, λ) + line.R1.Mul(api, λ, p1.X) + line.R1.Sub(api, line.R1, p1.Y) + + return res, line + +} + +// linesCompute computes the lines that goes through p1 and p2, and (p1+p2) and p1 but does not compute 2p1+p2 +func linesCompute(api frontend.API, p1, p2 *G2Affine) (lineEvaluation, lineEvaluation) { + + var n, d, l1, l2, x3 fields_bls24315.E4 + var line1, line2 lineEvaluation + + // compute lambda1 = (y2-y1)/(x2-x1) + n.Sub(api, p1.Y, p2.Y) + d.Sub(api, p1.X, p2.X) + l1.DivUnchecked(api, n, d) + + // x3 =lambda1**2-p1.x-p2.x + x3.Square(api, l1). + Sub(api, x3, p1.X). + Sub(api, x3, p2.X) + + // omit y3 computation + + // compute line1 + line1.R0.Neg(api, l1) + line1.R1.Mul(api, l1, p1.X).Sub(api, line1.R1, p1.Y) + + // compute lambda2 = -lambda1-2*y1/(x3-x1) + n.Double(api, p1.Y) + d.Sub(api, x3, p1.X) + l2.DivUnchecked(api, n, d) + l2.Add(api, l2, l1).Neg(api, l2) + + // compute line2 + line2.R0.Neg(api, l2) + line2.R1.Mul(api, l2, p1.X).Sub(api, line2.R1, p1.Y) + + return line1, line2 +} + +// lineCompute computes the line that goes through p1 and p2 but does not compute p1+p2 +func lineCompute(api frontend.API, p1, p2 *G2Affine) lineEvaluation { + + var qypy, qxpx, λ fields_bls24315.E4 + + // compute λ = (y2-y1)/(x2-x1) + qypy.Sub(api, p2.Y, p1.Y) + qxpx.Sub(api, p2.X, p1.X) + λ.DivUnchecked(api, qypy, qxpx) + + var line lineEvaluation + line.R0.Neg(api, λ) + line.R1.Mul(api, λ, p1.X) + line.R1.Sub(api, line.R1, p1.Y) + + return line + +} diff --git a/std/groth16_bls12377/verifier.go b/std/groth16_bls12377/verifier.go index 7d6f561dde..e2f7f37338 100644 --- a/std/groth16_bls12377/verifier.go +++ b/std/groth16_bls12377/verifier.go @@ -1,5 +1,5 @@ /* -Copyright © 2020 ConsenSys +Copyright 2020 ConsenSys Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -49,6 +49,7 @@ type VerifyingKey struct { // [Kvk]1 G1 struct { K []sw_bls12377.G1Affine // The indexes correspond to the public wires + } } @@ -57,7 +58,8 @@ type VerifyingKey struct { // publicInputs do NOT contain the ONE_WIRE func Verify(api frontend.API, vk VerifyingKey, proof Proof, publicInputs []frontend.Variable) { if len(vk.G1.K) == 0 { - panic("innver verifying key needs at least one point; VerifyingKey.G1 must be initialized before compiling circuit") + panic("inner verifying key needs at least one point; VerifyingKey.G1 must be initialized before compiling circuit") + } // compute kSum = Σx.[Kvk(t)]1 @@ -71,14 +73,15 @@ func Verify(api frontend.API, vk VerifyingKey, proof Proof, publicInputs []front var ki sw_bls12377.G1Affine ki.ScalarMul(api, vk.G1.K[k+1], v) kSum.AddAssign(api, ki) + } // compute e(Σx.[Kvk(t)]1, -[γ]2) * e(Krs,δ) * e(Ar,Bs) - ml, _ := sw_bls12377.MillerLoop(api, []sw_bls12377.G1Affine{kSum, proof.Krs, proof.Ar}, []sw_bls12377.G2Affine{vk.G2.GammaNeg, vk.G2.DeltaNeg, proof.Bs}) - pairing := sw_bls12377.FinalExponentiation(api, ml) + pairing, _ := sw_bls12377.Pair(api, []sw_bls12377.G1Affine{kSum, proof.Krs, proof.Ar}, []sw_bls12377.G2Affine{vk.G2.GammaNeg, vk.G2.DeltaNeg, proof.Bs}) // vk.E must be equal to pairing vk.E.AssertIsEqual(api, pairing) + } // Assign values to the "in-circuit" VerifyingKey from a "out-of-circuit" VerifyingKey @@ -86,21 +89,51 @@ func (vk *VerifyingKey) Assign(_ovk groth16.VerifyingKey) { ovk, ok := _ovk.(*groth16_bls12377.VerifyingKey) if !ok { panic("expected *groth16_bls12377.VerifyingKey, got " + reflect.TypeOf(_ovk).String()) + } e, err := bls12377.Pair([]bls12377.G1Affine{ovk.G1.Alpha}, []bls12377.G2Affine{ovk.G2.Beta}) if err != nil { panic(err) + } vk.E.Assign(&e) vk.G1.K = make([]sw_bls12377.G1Affine, len(ovk.G1.K)) for i := 0; i < len(ovk.G1.K); i++ { vk.G1.K[i].Assign(&ovk.G1.K[i]) + } var deltaNeg, gammaNeg bls12377.G2Affine deltaNeg.Neg(&ovk.G2.Delta) gammaNeg.Neg(&ovk.G2.Gamma) vk.G2.DeltaNeg.Assign(&deltaNeg) vk.G2.GammaNeg.Assign(&gammaNeg) + +} + +// Allocate memory for the "in-circuit" VerifyingKey +// This is exposed so that the slices in the structure can be allocated +// before calling frontend.Compile(). +func (vk *VerifyingKey) Allocate(_ovk groth16.VerifyingKey) { + ovk, ok := _ovk.(*groth16_bls12377.VerifyingKey) + if !ok { + panic("expected *groth16_bls12377.VerifyingKey, got " + reflect.TypeOf(_ovk).String()) + + } + vk.G1.K = make([]sw_bls12377.G1Affine, len(ovk.G1.K)) + +} + +// Assign the proof values of Groth16 +func (proof *Proof) Assign(_oproof groth16.Proof) { + oproof, ok := _oproof.(*groth16_bls12377.Proof) + if !ok { + panic("expected *groth16_bls12377.Proof, got " + reflect.TypeOf(oproof).String()) + + } + proof.Ar.Assign(&oproof.Ar) + proof.Krs.Assign(&oproof.Krs) + proof.Bs.Assign(&oproof.Bs) + } diff --git a/std/groth16_bls12377/verifier_test.go b/std/groth16_bls12377/verifier_test.go index 40397b507a..282984139e 100644 --- a/std/groth16_bls12377/verifier_test.go +++ b/std/groth16_bls12377/verifier_test.go @@ -1,5 +1,5 @@ /* -Copyright © 2020 ConsenSys +Copyright 2020 ConsenSys Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,12 +22,12 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" - groth16_bls12377 "github.com/consensys/gnark/backend/groth16/bls12-377" + "github.com/consensys/gnark-crypto/hash" + "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/constraint" - cs_bls12377 "github.com/consensys/gnark/constraint/bls12-377" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/std/algebra/native/sw_bls12377" "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/test" ) @@ -46,126 +46,161 @@ func (circuit *mimcCircuit) Define(api frontend.API) error { mimc, err := mimc.NewMiMC(api) if err != nil { return err + } mimc.Write(circuit.PreImage) api.AssertIsEqual(mimc.Sum(), circuit.Hash) return nil + +} + +// Calculate the expected output of MIMC through plain invocation +func preComputeMimc(preImage frontend.Variable) interface{} { + var expectedY fr.Element + expectedY.SetInterface(preImage) + // calc MiMC + goMimc := hash.MIMC_BLS12_377.New() + goMimc.Write(expectedY.Marshal()) + expectedh := goMimc.Sum(nil) + return expectedh + +} + +type verifierCircuit struct { + InnerProof Proof + InnerVk VerifyingKey + Hash frontend.Variable } -// Prepare the data for the inner proof. -// Returns the public inputs string of the inner proof -func generateBls12377InnerProof(t *testing.T, vk *groth16_bls12377.VerifyingKey, proof *groth16_bls12377.Proof) { +func (circuit *verifierCircuit) Define(api frontend.API) error { + // create the verifier cs + Verify(api, circuit.InnerVk, circuit.InnerProof, []frontend.Variable{circuit.Hash}) + + return nil + +} + +func TestVerifier(t *testing.T) { // create a mock cs: knowing the preimage of a hash using mimc - var circuit mimcCircuit - r1cs, err := frontend.Compile(ecc.BLS12_377.ScalarField(), r1cs.NewBuilder, &circuit) + var MimcCircuit mimcCircuit + r1cs, err := frontend.Compile(ecc.BLS12_377.ScalarField(), r1cs.NewBuilder, &MimcCircuit) if err != nil { t.Fatal(err) - } - // build the witness - var assignment mimcCircuit - assignment.PreImage = preImage - assignment.Hash = publicHash + } - witness, err := frontend.NewWitness(&assignment, ecc.BLS12_377.ScalarField()) + var pre_assignment mimcCircuit + pre_assignment.PreImage = preImage + pre_assignment.Hash = publicHash + pre_witness, err := frontend.NewWitness(&pre_assignment, ecc.BLS12_377.ScalarField()) if err != nil { t.Fatal(err) + } - publicWitness, err := witness.Public() + innerPk, innerVk, err := groth16.Setup(r1cs) if err != nil { t.Fatal(err) + } - // generate the data to return for the bls12377 proof - var pk groth16_bls12377.ProvingKey - err = groth16_bls12377.Setup(r1cs.(*cs_bls12377.R1CS), &pk, vk) + proof, err := groth16.Prove(r1cs, innerPk, pre_witness) if err != nil { t.Fatal(err) + } - //_proof, err := groth16_bls12377.Prove(r1cs.(*cs_bls12377.R1CS), &pk, witness.Vector().(fr.Vector), backend.ProverConfig{}) - _proof, err := groth16_bls12377.Prove(r1cs.(*cs_bls12377.R1CS), &pk, witness) + publicWitness, err := pre_witness.Public() if err != nil { t.Fatal(err) + } - proof.Ar = _proof.Ar - proof.Bs = _proof.Bs - proof.Krs = _proof.Krs - // before returning verifies that the proof passes on bls12377 - if err := groth16_bls12377.Verify(proof, vk, publicWitness.Vector().(fr.Vector)); err != nil { + // Check that proof verifies before continuing + if err := groth16.Verify(proof, innerVk, publicWitness); err != nil { t.Fatal(err) + } -} + var circuit verifierCircuit + circuit.InnerVk.Allocate(innerVk) -type verifierCircuit struct { - InnerProof Proof - InnerVk VerifyingKey - Hash frontend.Variable -} + var witness verifierCircuit + witness.InnerProof.Assign(proof) + witness.InnerVk.Assign(innerVk) + witness.Hash = preComputeMimc(preImage) -func (circuit *verifierCircuit) Define(api frontend.API) error { - // create the verifier cs - Verify(api, circuit.InnerVk, circuit.InnerProof, []frontend.Variable{circuit.Hash}) + assert := test.NewAssert(t) + + assert.ProverSucceeded(&circuit, &witness, test.WithCurves(ecc.BW6_761), test.WithBackends(backend.GROTH16)) - return nil } -func TestVerifier(t *testing.T) { +func BenchmarkCompile(b *testing.B) { - // get the data - var innerVk groth16_bls12377.VerifyingKey - var innerProof groth16_bls12377.Proof - generateBls12377InnerProof(t, &innerVk, &innerProof) // get public inputs of the inner proof + // create a mock cs: knowing the preimage of a hash using mimc + var MimcCircuit mimcCircuit + _r1cs, err := frontend.Compile(ecc.BLS12_377.ScalarField(), r1cs.NewBuilder, &MimcCircuit) + if err != nil { + b.Fatal(err) - // create an empty cs - var circuit verifierCircuit - circuit.InnerVk.G1.K = make([]sw_bls12377.G1Affine, len(innerVk.G1.K)) + } - // create assignment, the private part consists of the proof, - // the public part is exactly the public part of the inner proof, - // up to the renaming of the inner ONE_WIRE to not conflict with the one wire of the outer proof. - var witness verifierCircuit - witness.InnerProof.Ar.Assign(&innerProof.Ar) - witness.InnerProof.Krs.Assign(&innerProof.Krs) - witness.InnerProof.Bs.Assign(&innerProof.Bs) + var pre_assignment mimcCircuit + pre_assignment.PreImage = preImage + pre_assignment.Hash = publicHash + pre_witness, err := frontend.NewWitness(&pre_assignment, ecc.BLS12_377.ScalarField()) + if err != nil { + b.Fatal(err) - witness.InnerVk.Assign(&innerVk) - witness.Hash = publicHash + } - // verifies the cs - assert := test.NewAssert(t) + innerPk, innerVk, err := groth16.Setup(_r1cs) + if err != nil { + b.Fatal(err) - assert.SolvingSucceeded(&circuit, &witness, test.WithCurves(ecc.BW6_761)) -} + } -func BenchmarkCompile(b *testing.B) { - // get the data - var innerVk groth16_bls12377.VerifyingKey - var innerProof groth16_bls12377.Proof - generateBls12377InnerProof(nil, &innerVk, &innerProof) // get public inputs of the inner proof + proof, err := groth16.Prove(_r1cs, innerPk, pre_witness) + if err != nil { + b.Fatal(err) + + } + + publicWitness, err := pre_witness.Public() + if err != nil { + b.Fatal(err) + + } + + // Check that proof verifies before continuing + if err := groth16.Verify(proof, innerVk, publicWitness); err != nil { + b.Fatal(err) + + } - // create an empty cs var circuit verifierCircuit - circuit.InnerVk.G1.K = make([]sw_bls12377.G1Affine, len(innerVk.G1.K)) + circuit.InnerVk.Allocate(innerVk) var ccs constraint.ConstraintSystem - var err error b.ResetTimer() for i := 0; i < b.N; i++ { ccs, err = frontend.Compile(ecc.BW6_761.ScalarField(), r1cs.NewBuilder, &circuit) if err != nil { b.Fatal(err) + } + } + b.Log(ccs.GetNbConstraints()) + } var tVariable reflect.Type func init() { tVariable = reflect.ValueOf(struct{ A frontend.Variable }{}).FieldByName("A").Type() + } diff --git a/std/groth16_bls24315/verifier.go b/std/groth16_bls24315/verifier.go index 8da0f6c0b0..8e474a8979 100644 --- a/std/groth16_bls24315/verifier.go +++ b/std/groth16_bls24315/verifier.go @@ -49,6 +49,7 @@ type VerifyingKey struct { // [Kvk]1 G1 struct { K []sw_bls24315.G1Affine // The indexes correspond to the public wires + } } @@ -57,7 +58,8 @@ type VerifyingKey struct { // publicInputs do NOT contain the ONE_WIRE func Verify(api frontend.API, vk VerifyingKey, proof Proof, publicInputs []frontend.Variable) { if len(vk.G1.K) == 0 { - panic("innver verifying key needs at least one point; VerifyingKey.G1 must be initialized before compiling circuit") + panic("inner verifying key needs at least one point; VerifyingKey.G1 must be initialized before compiling circuit") + } // compute kSum = Σx.[Kvk(t)]1 @@ -71,11 +73,11 @@ func Verify(api frontend.API, vk VerifyingKey, proof Proof, publicInputs []front var ki sw_bls24315.G1Affine ki.ScalarMul(api, vk.G1.K[k+1], v) kSum.AddAssign(api, ki) + } // compute e(Σx.[Kvk(t)]1, -[γ]2) * e(Krs,δ) * e(Ar,Bs) - ml, _ := sw_bls24315.MillerLoop(api, []sw_bls24315.G1Affine{kSum, proof.Krs, proof.Ar}, []sw_bls24315.G2Affine{vk.G2.GammaNeg, vk.G2.DeltaNeg, proof.Bs}) - pairing := sw_bls24315.FinalExponentiation(api, ml) + pairing, _ := sw_bls24315.Pair(api, []sw_bls24315.G1Affine{kSum, proof.Krs, proof.Ar}, []sw_bls24315.G2Affine{vk.G2.GammaNeg, vk.G2.DeltaNeg, proof.Bs}) // vk.E must be equal to pairing vk.E.AssertIsEqual(api, pairing) @@ -87,21 +89,51 @@ func (vk *VerifyingKey) Assign(_ovk groth16.VerifyingKey) { ovk, ok := _ovk.(*groth16_bls24315.VerifyingKey) if !ok { panic("expected *groth16_bls24315.VerifyingKey, got " + reflect.TypeOf(_ovk).String()) + } e, err := bls24315.Pair([]bls24315.G1Affine{ovk.G1.Alpha}, []bls24315.G2Affine{ovk.G2.Beta}) if err != nil { panic(err) + } vk.E.Assign(&e) vk.G1.K = make([]sw_bls24315.G1Affine, len(ovk.G1.K)) for i := 0; i < len(ovk.G1.K); i++ { vk.G1.K[i].Assign(&ovk.G1.K[i]) + } var deltaNeg, gammaNeg bls24315.G2Affine deltaNeg.Neg(&ovk.G2.Delta) gammaNeg.Neg(&ovk.G2.Gamma) vk.G2.DeltaNeg.Assign(&deltaNeg) vk.G2.GammaNeg.Assign(&gammaNeg) + +} + +// Allocate memory for the "in-circuit" VerifyingKey +// This is exposed so that the slices in the structure can be allocated +// before calling frontend.Compile(). +func (vk *VerifyingKey) Allocate(_ovk groth16.VerifyingKey) { + ovk, ok := _ovk.(*groth16_bls24315.VerifyingKey) + if !ok { + panic("expected *groth16_bls24315.VerifyingKey, got " + reflect.TypeOf(_ovk).String()) + + } + vk.G1.K = make([]sw_bls24315.G1Affine, len(ovk.G1.K)) + +} + +// Assign the proof values of Groth16 +func (proof *Proof) Assign(_oproof groth16.Proof) { + oproof, ok := _oproof.(*groth16_bls24315.Proof) + if !ok { + panic("expected *groth16_bls24315.Proof, got " + reflect.TypeOf(oproof).String()) + + } + proof.Ar.Assign(&oproof.Ar) + proof.Krs.Assign(&oproof.Krs) + proof.Bs.Assign(&oproof.Bs) + } diff --git a/std/groth16_bls24315/verifier_test.go b/std/groth16_bls24315/verifier_test.go index 9af446d8bf..c3a5a9f3af 100644 --- a/std/groth16_bls24315/verifier_test.go +++ b/std/groth16_bls24315/verifier_test.go @@ -22,19 +22,16 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" - groth16_bls24315 "github.com/consensys/gnark/backend/groth16/bls24-315" + "github.com/consensys/gnark-crypto/hash" + "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/constraint" - cs_bls24315 "github.com/consensys/gnark/constraint/bls24-315" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/std/algebra/native/sw_bls24315" "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/test" ) -//-------------------------------------------------------------------- -// utils - const ( preImage = "4992816046196248432836492760315135318126925090839638585255611512962528270024" publicHash = "4875439939758844840941638351757981379945701574516438614845550995673793857363" @@ -49,121 +46,161 @@ func (circuit *mimcCircuit) Define(api frontend.API) error { mimc, err := mimc.NewMiMC(api) if err != nil { return err + } mimc.Write(circuit.PreImage) api.AssertIsEqual(mimc.Sum(), circuit.Hash) return nil + +} + +// Calculate the expected output of MIMC through plain invocation +func preComputeMimc(preImage frontend.Variable) interface{} { + var expectedY fr.Element + expectedY.SetInterface(preImage) + // calc MiMC + goMimc := hash.MIMC_BLS24_315.New() + goMimc.Write(expectedY.Marshal()) + expectedh := goMimc.Sum(nil) + return expectedh + +} + +type verifierCircuit struct { + InnerProof Proof + InnerVk VerifyingKey + Hash frontend.Variable } -// Prepare the data for the inner proof. -// Returns the public inputs string of the inner proof -func generateBls24315InnerProof(t *testing.T, vk *groth16_bls24315.VerifyingKey, proof *groth16_bls24315.Proof) { +func (circuit *verifierCircuit) Define(api frontend.API) error { + // create the verifier cs + Verify(api, circuit.InnerVk, circuit.InnerProof, []frontend.Variable{circuit.Hash}) + + return nil + +} + +func TestVerifier(t *testing.T) { // create a mock cs: knowing the preimage of a hash using mimc - var circuit, assignment mimcCircuit - r1cs, err := frontend.Compile(ecc.BLS24_315.ScalarField(), r1cs.NewBuilder, &circuit) + var MimcCircuit mimcCircuit + r1cs, err := frontend.Compile(ecc.BLS24_315.ScalarField(), r1cs.NewBuilder, &MimcCircuit) if err != nil { t.Fatal(err) - } - assignment.PreImage = preImage - assignment.Hash = publicHash + } - witness, err := frontend.NewWitness(&assignment, ecc.BLS24_315.ScalarField()) + var pre_assignment mimcCircuit + pre_assignment.PreImage = preImage + pre_assignment.Hash = publicHash + pre_witness, err := frontend.NewWitness(&pre_assignment, ecc.BLS24_315.ScalarField()) if err != nil { t.Fatal(err) + } - publicWitness, err := witness.Public() + innerPk, innerVk, err := groth16.Setup(r1cs) if err != nil { t.Fatal(err) + } - // generate the data to return for the bls24315 proof - var pk groth16_bls24315.ProvingKey - err = groth16_bls24315.Setup(r1cs.(*cs_bls24315.R1CS), &pk, vk) + proof, err := groth16.Prove(r1cs, innerPk, pre_witness) if err != nil { t.Fatal(err) + } - _proof, err := groth16_bls24315.Prove(r1cs.(*cs_bls24315.R1CS), &pk, witness) + publicWitness, err := pre_witness.Public() if err != nil { t.Fatal(err) + } - proof.Ar = _proof.Ar - proof.Bs = _proof.Bs - proof.Krs = _proof.Krs - // before returning verifies that the proof passes on bls24315 - if err := groth16_bls24315.Verify(proof, vk, publicWitness.Vector().(fr.Vector)); err != nil { + // Check that proof verifies before continuing + if err := groth16.Verify(proof, innerVk, publicWitness); err != nil { t.Fatal(err) + } -} -type verifierCircuit struct { - InnerProof Proof - InnerVk VerifyingKey - Hash frontend.Variable -} + var circuit verifierCircuit + circuit.InnerVk.Allocate(innerVk) -func (circuit *verifierCircuit) Define(api frontend.API) error { + var witness verifierCircuit + witness.InnerProof.Assign(proof) + witness.InnerVk.Assign(innerVk) + witness.Hash = preComputeMimc(preImage) - // create the verifier cs - Verify(api, circuit.InnerVk, circuit.InnerProof, []frontend.Variable{circuit.Hash}) + assert := test.NewAssert(t) + + assert.ProverSucceeded(&circuit, &witness, test.WithCurves(ecc.BW6_633), test.WithBackends(backend.GROTH16)) - return nil } -func TestVerifier(t *testing.T) { +func BenchmarkCompile(b *testing.B) { - // get the data - var innerVk groth16_bls24315.VerifyingKey - var innerProof groth16_bls24315.Proof - generateBls24315InnerProof(t, &innerVk, &innerProof) // get public inputs of the inner proof + // create a mock cs: knowing the preimage of a hash using mimc + var MimcCircuit mimcCircuit + _r1cs, err := frontend.Compile(ecc.BLS24_315.ScalarField(), r1cs.NewBuilder, &MimcCircuit) + if err != nil { + b.Fatal(err) - // create an empty cs - var circuit verifierCircuit - circuit.InnerVk.G1.K = make([]sw_bls24315.G1Affine, len(innerVk.G1.K)) + } - // create assignment, the private part consists of the proof, - // the public part is exactly the public part of the inner proof, - // up to the renaming of the inner ONE_WIRE to not conflict with the one wire of the outer proof. - var witness verifierCircuit - witness.InnerProof.Ar.Assign(&innerProof.Ar) - witness.InnerProof.Krs.Assign(&innerProof.Krs) - witness.InnerProof.Bs.Assign(&innerProof.Bs) + var pre_assignment mimcCircuit + pre_assignment.PreImage = preImage + pre_assignment.Hash = publicHash + pre_witness, err := frontend.NewWitness(&pre_assignment, ecc.BLS24_315.ScalarField()) + if err != nil { + b.Fatal(err) + + } - witness.InnerVk.Assign(&innerVk) + innerPk, innerVk, err := groth16.Setup(_r1cs) + if err != nil { + b.Fatal(err) - witness.Hash = publicHash + } - // verifies the cs - assert := test.NewAssert(t) + proof, err := groth16.Prove(_r1cs, innerPk, pre_witness) + if err != nil { + b.Fatal(err) - assert.SolvingSucceeded(&circuit, &witness, test.WithCurves(ecc.BW6_633)) + } -} + publicWitness, err := pre_witness.Public() + if err != nil { + b.Fatal(err) -func BenchmarkCompile(b *testing.B) { - // get the data - var innerVk groth16_bls24315.VerifyingKey - var innerProof groth16_bls24315.Proof - generateBls24315InnerProof(nil, &innerVk, &innerProof) // get public inputs of the inner proof + } + + // Check that proof verifies before continuing + if err := groth16.Verify(proof, innerVk, publicWitness); err != nil { + b.Fatal(err) + + } - // create an empty cs var circuit verifierCircuit - circuit.InnerVk.G1.K = make([]sw_bls24315.G1Affine, len(innerVk.G1.K)) + circuit.InnerVk.Allocate(innerVk) var ccs constraint.ConstraintSystem b.ResetTimer() for i := 0; i < b.N; i++ { - ccs, _ = frontend.Compile(ecc.BW6_633.ScalarField(), r1cs.NewBuilder, &circuit) + ccs, err = frontend.Compile(ecc.BW6_633.ScalarField(), r1cs.NewBuilder, &circuit) + if err != nil { + b.Fatal(err) + + } + } + b.Log(ccs.GetNbConstraints()) + } var tVariable reflect.Type func init() { tVariable = reflect.ValueOf(struct{ A frontend.Variable }{}).FieldByName("A").Type() + } From a2ad4a4f80cb2912a69892599e3e7b4642898671 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Wed, 17 May 2023 12:47:48 +0200 Subject: [PATCH 365/464] feat: modification opening order kzg bn254 --- backend/plonk/bn254/prove.go | 49 +++++++++++++++++++---------------- backend/plonk/bn254/verify.go | 41 +++++++++++++++-------------- 2 files changed, 49 insertions(+), 41 deletions(-) diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index 6cf1ef2dff..5f8e42e3ec 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gnark DO NOT EDIT - package plonk import ( @@ -34,9 +32,9 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" "github.com/consensys/gnark-crypto/ecc/bn254/fr/iop" - "github.com/consensys/gnark/constraint/bn254" + cs "github.com/consensys/gnark/constraint/bn254" - "github.com/consensys/gnark-crypto/fiat-shamir" + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" @@ -508,25 +506,32 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts <-computeFoldedH // Batch open the first list of polynomials + polysQcp := coefficients(pk.trace.Qcp) + polysToOpen := make([][]fr.Element, 7+len(polysQcp)) + copy(polysToOpen[7:], polysQcp) + // offset := len(polysQcp) + polysToOpen[0] = foldedH + polysToOpen[1] = linearizedPolynomialCanonical + polysToOpen[2] = bwliop.Coefficients()[:bwliop.BlindedSize()] + polysToOpen[3] = bwriop.Coefficients()[:bwriop.BlindedSize()] + polysToOpen[4] = bwoiop.Coefficients()[:bwoiop.BlindedSize()] + polysToOpen[5] = pk.trace.S1.Coefficients() + polysToOpen[6] = pk.trace.S2.Coefficients() + + digestsToOpen := make([]curve.G1Affine, len(pk.Vk.Qcp)+7) + copy(digestsToOpen[7:], pk.Vk.Qcp) + // offset = len(pk.Vk.Qcp) + digestsToOpen[0] = foldedHDigest + digestsToOpen[1] = linearizedPolynomialDigest + digestsToOpen[2] = proof.LRO[0] + digestsToOpen[3] = proof.LRO[1] + digestsToOpen[4] = proof.LRO[2] + digestsToOpen[5] = pk.Vk.S[0] + digestsToOpen[6] = pk.Vk.S[1] + proof.BatchedProof, err = kzg.BatchOpenSinglePoint( - append(coefficients(pk.trace.Qcp), - foldedH, - linearizedPolynomialCanonical, - bwliop.Coefficients()[:bwliop.BlindedSize()], - bwriop.Coefficients()[:bwriop.BlindedSize()], - bwoiop.Coefficients()[:bwoiop.BlindedSize()], - pk.trace.S1.Coefficients(), - pk.trace.S2.Coefficients(), - ), - append(pk.Vk.Qcp, - foldedHDigest, - linearizedPolynomialDigest, - proof.LRO[0], - proof.LRO[1], - proof.LRO[2], - pk.Vk.S[0], - pk.Vk.S[1], - ), + polysToOpen, + digestsToOpen, zeta, hFunc, pk.Kzg, diff --git a/backend/plonk/bn254/verify.go b/backend/plonk/bn254/verify.go index f370459e8f..231469dd56 100644 --- a/backend/plonk/bn254/verify.go +++ b/backend/plonk/bn254/verify.go @@ -139,16 +139,13 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - qC := make([]fr.Element, len(proof.Bsb22Commitments)) - copy(qC, proof.BatchedProof.ClaimedValues) - claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] - claimedQuotient := claimedValues[0] - linearizedPolynomialZeta := claimedValues[1] - l := claimedValues[2] - r := claimedValues[3] - o := claimedValues[4] - s1 := claimedValues[5] - s2 := claimedValues[6] + claimedQuotient := proof.BatchedProof.ClaimedValues[0] + linearizedPolynomialZeta := proof.BatchedProof.ClaimedValues[1] + l := proof.BatchedProof.ClaimedValues[2] + r := proof.BatchedProof.ClaimedValues[3] + o := proof.BatchedProof.ClaimedValues[4] + s1 := proof.BatchedProof.ClaimedValues[5] + s2 := proof.BatchedProof.ClaimedValues[6] _s1.Mul(&s1, &beta).Add(&_s1, &l).Add(&_s1, &gamma) // (l(ζ)+β*s1(ζ)+γ) _s2.Mul(&s2, &beta).Add(&_s2, &r).Add(&_s2, &gamma) // (r(ζ)+β*s2(ζ)+γ) @@ -222,6 +219,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { vk.S[2], proof.Z, // second & third part ) + qC := make([]fr.Element, len(proof.Bsb22Commitments)) + copy(qC, proof.BatchedProof.ClaimedValues[7:]) scalars := append(qC, l, r, rl, o, one, /* TODO Perf @Tabaie Consider just adding Qk instead */ // first part _s1, _s2, // second & third part @@ -231,15 +230,18 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } // Fold the first proof - foldedProof, foldedDigest, err := kzg.FoldProof(append(vk.Qcp, - foldedH, - linearizedPolynomialDigest, - proof.LRO[0], - proof.LRO[1], - proof.LRO[2], - vk.S[0], - vk.S[1], - ), + digestsToFold := make([]curve.G1Affine, len(vk.Qcp)+7) + copy(digestsToFold[7:], vk.Qcp) + // offset := len(vk.Qcp) + digestsToFold[0] = foldedH + digestsToFold[1] = linearizedPolynomialDigest + digestsToFold[2] = proof.LRO[0] + digestsToFold[3] = proof.LRO[1] + digestsToFold[4] = proof.LRO[2] + digestsToFold[5] = vk.S[0] + digestsToFold[6] = vk.S[1] + foldedProof, foldedDigest, err := kzg.FoldProof( + digestsToFold, &proof.BatchedProof, zeta, hFunc, @@ -248,6 +250,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } + // Batch verify var shiftedZeta fr.Element shiftedZeta.Mul(&zeta, &vk.Generator) From 2b066fd7e9ae656b8174949a47a90be9eca6f150 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Wed, 17 May 2023 13:06:43 +0200 Subject: [PATCH 366/464] feat: prover template ok --- .../zkpschemes/plonk/plonk.prove.go.tmpl | 66 +++++++++---------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl index 44bf897328..d2034c03ea 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl @@ -133,7 +133,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // we keep in lagrange regular form since iop.BuildRatioCopyConstraint prefers it in this form. wliop = iop.NewPolynomial(&evaluationLDomainSmall, lagReg) // we set the underlying slice capacity to domain[1].Cardinality to minimize mem moves. - bwliop = wliop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) + bwliop = wliop.Clone(int(pk.Domain[1].Cardinality)).ToCanonical(&pk.Domain[0]).ToRegular().Blind(1) wgLRO.Done() }() go func() { @@ -147,13 +147,11 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wgLRO.Done() }() - fw, ok := fullWitness.Vector().(fr.Vector) if !ok { return nil, witness.ErrInvalidWitness } - // start computing lcqk var lcqk *iop.Polynomial chLcqk := make(chan struct{}, 1) @@ -216,7 +214,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwoiop.ToLagrangeCoset(&pk.Domain[1]) wgLRO.Done() }() - // compute the copy constraint's ratio // note that wliop, wriop and woiop are fft'ed (mutated) in the process. @@ -260,7 +257,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts chZ <- nil close(chZ) }() - // Full capture using latest gnark crypto... fic := func(fql, fqr, fqm, fqo, fqk, l, r, o fr.Element, pi2QcPrime []fr.Element) fr.Element { // TODO @Tabaie make use of the fact that qCPrime is a selector: sparse and binary @@ -283,7 +279,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return ic } - fo := func(l, r, o, fid, fs1, fs2, fs3, fz, fzs fr.Element) fr.Element { u := &pk.Domain[0].FrMultiplicativeGen var a, b, tmp fr.Element @@ -352,8 +347,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts pk.lcQo, lcqk, pk.lLoneIOP, - - } + } toEval = append(toEval, lcCommitments...) // TODO: Add this at beginning toEval = append(toEval, pk.lcQcp...) systemEvaluation, err := iop.Evaluate(fm, iop.Form{Basis: iop.LagrangeCoset, Layout: iop.BitReverse}, toEval...) @@ -366,7 +360,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bwziop.ToCanonical(&pk.Domain[1]).ToRegular() close(chbwzIOP) }() - h, err := iop.DivideByXMinusOne(systemEvaluation, [2]*fft.Domain{&pk.Domain[0], &pk.Domain[1]}) // TODO Rename to DivideByXNMinusOne or DivideByVanishingPoly etc if err != nil { @@ -421,7 +414,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts return nil, err } - // start to compute foldedH and foldedHDigest while computeLinearizedPolynomial runs. computeFoldedH := make(chan struct{}, 1) var foldedH []fr.Element @@ -456,7 +448,6 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts wgEvals.Wait() // wait for the evaluations - var ( linearizedPolynomialCanonical []fr.Element linearizedPolynomialDigest curve.G1Affine @@ -486,35 +477,41 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // TODO this commitment is only necessary to derive the challenge, we should // be able to avoid doing it and get the challenge in another way - linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Kzg, runtime.NumCPU() * 2) + linearizedPolynomialDigest, errLPoly = kzg.Commit(linearizedPolynomialCanonical, pk.Kzg, runtime.NumCPU()*2) if errLPoly != nil { return nil, errLPoly } - // wait for foldedH and foldedHDigest <-computeFoldedH // Batch open the first list of polynomials + polysQcp := coefficients(pk.trace.Qcp) + polysToOpen := make([][]fr.Element, 7+len(polysQcp)) + copy(polysToOpen[7:], polysQcp) + // offset := len(polysQcp) + polysToOpen[0] = foldedH + polysToOpen[1] = linearizedPolynomialCanonical + polysToOpen[2] = bwliop.Coefficients()[:bwliop.BlindedSize()] + polysToOpen[3] = bwriop.Coefficients()[:bwriop.BlindedSize()] + polysToOpen[4] = bwoiop.Coefficients()[:bwoiop.BlindedSize()] + polysToOpen[5] = pk.trace.S1.Coefficients() + polysToOpen[6] = pk.trace.S2.Coefficients() + + digestsToOpen := make([]curve.G1Affine, len(pk.Vk.Qcp)+7) + copy(digestsToOpen[7:], pk.Vk.Qcp) + // offset = len(pk.Vk.Qcp) + digestsToOpen[0] = foldedHDigest + digestsToOpen[1] = linearizedPolynomialDigest + digestsToOpen[2] = proof.LRO[0] + digestsToOpen[3] = proof.LRO[1] + digestsToOpen[4] = proof.LRO[2] + digestsToOpen[5] = pk.Vk.S[0] + digestsToOpen[6] = pk.Vk.S[1] + proof.BatchedProof, err = kzg.BatchOpenSinglePoint( - append(coefficients(pk.trace.Qcp), - foldedH, - linearizedPolynomialCanonical, - bwliop.Coefficients()[:bwliop.BlindedSize()], - bwriop.Coefficients()[:bwriop.BlindedSize()], - bwoiop.Coefficients()[:bwoiop.BlindedSize()], - pk.trace.S1.Coefficients(), - pk.trace.S2.Coefficients(), - ), - append(pk.Vk.Qcp, - foldedHDigest, - linearizedPolynomialDigest, - proof.LRO[0], - proof.LRO[1], - proof.LRO[2], - pk.Vk.S[0], - pk.Vk.S[1], - ), + polysToOpen, + digestsToOpen, zeta, hFunc, pk.Kzg, @@ -540,7 +537,7 @@ func coefficients(p []*iop.Polynomial) [][]fr.Element { // fills proof.LRO with kzg commits of bcl, bcr and bco func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, kzgPk kzg.ProvingKey) error { - n := runtime.NumCPU() + n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) @@ -566,7 +563,7 @@ func commitToLRO(bcl, bcr, bco []fr.Element, proof *Proof, kzgPk kzg.ProvingKey) } func commitToQuotient(h1, h2, h3 []fr.Element, proof *Proof, kzgPk kzg.ProvingKey) error { - n := runtime.NumCPU() + n := runtime.NumCPU() var err0, err1, err2 error chCommit0 := make(chan struct{}, 1) chCommit1 := make(chan struct{}, 1) @@ -649,7 +646,6 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, Mul(&lagrangeZeta, &alpha). Mul(&lagrangeZeta, &pk.Domain[0].CardinalityInv) // (1/n)*α²*L₁(ζ) - s3canonical := pk.trace.S3.Coefficients() utils.Parallelize(len(blindedZCanonical), func(start, end int) { @@ -697,4 +693,4 @@ func computeLinearizedPolynomial(lZeta, rZeta, oZeta, alpha, beta, gamma, zeta, } }) return blindedZCanonical -} \ No newline at end of file +} From 243484c2d4abac1a6578a824e3998dadd1c58942 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Wed, 17 May 2023 15:08:54 +0200 Subject: [PATCH 367/464] feat: verifier template ok --- backend/plonk/bls12-377/prove.go | 43 +- backend/plonk/bls12-377/verify.go | 44 +- backend/plonk/bls12-381/prove.go | 43 +- backend/plonk/bls12-381/verify.go | 44 +- backend/plonk/bls24-315/prove.go | 43 +- backend/plonk/bls24-315/verify.go | 44 +- backend/plonk/bls24-317/prove.go | 43 +- backend/plonk/bls24-317/verify.go | 44 +- backend/plonk/bn254/prove.go | 6 +- .../bn254/solidity/abi/PlonkVerifier.abi | 1 + .../bn254/solidity/abi/PlonkVerifier.bin | 1 + .../plonk/bn254/solidity/abi/TestVerifier.abi | 1 + .../plonk/bn254/solidity/abi/TestVerifier.bin | 1 + backend/plonk/bn254/solidity/abi/Utils.abi | 1 + backend/plonk/bn254/solidity/abi/Utils.bin | 1 + backend/plonk/bn254/tips.txt | 1 + backend/plonk/bn254/to_delete.go | 378 ++++++++++++++++++ backend/plonk/bn254/verify.go | 5 +- backend/plonk/bw6-633/prove.go | 43 +- backend/plonk/bw6-633/verify.go | 44 +- backend/plonk/bw6-761/prove.go | 43 +- backend/plonk/bw6-761/verify.go | 44 +- .../zkpschemes/plonk/plonk.verify.go.tmpl | 55 +-- 23 files changed, 716 insertions(+), 257 deletions(-) create mode 100644 backend/plonk/bn254/solidity/abi/PlonkVerifier.abi create mode 100644 backend/plonk/bn254/solidity/abi/PlonkVerifier.bin create mode 100644 backend/plonk/bn254/solidity/abi/TestVerifier.abi create mode 100644 backend/plonk/bn254/solidity/abi/TestVerifier.bin create mode 100644 backend/plonk/bn254/solidity/abi/Utils.abi create mode 100644 backend/plonk/bn254/solidity/abi/Utils.bin create mode 100644 backend/plonk/bn254/tips.txt create mode 100644 backend/plonk/bn254/to_delete.go diff --git a/backend/plonk/bls12-377/prove.go b/backend/plonk/bls12-377/prove.go index a6833fe0c9..b2a9c29b6f 100644 --- a/backend/plonk/bls12-377/prove.go +++ b/backend/plonk/bls12-377/prove.go @@ -508,25 +508,32 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts <-computeFoldedH // Batch open the first list of polynomials + polysQcp := coefficients(pk.trace.Qcp) + polysToOpen := make([][]fr.Element, 7+len(polysQcp)) + copy(polysToOpen[7:], polysQcp) + // offset := len(polysQcp) + polysToOpen[0] = foldedH + polysToOpen[1] = linearizedPolynomialCanonical + polysToOpen[2] = bwliop.Coefficients()[:bwliop.BlindedSize()] + polysToOpen[3] = bwriop.Coefficients()[:bwriop.BlindedSize()] + polysToOpen[4] = bwoiop.Coefficients()[:bwoiop.BlindedSize()] + polysToOpen[5] = pk.trace.S1.Coefficients() + polysToOpen[6] = pk.trace.S2.Coefficients() + + digestsToOpen := make([]curve.G1Affine, len(pk.Vk.Qcp)+7) + copy(digestsToOpen[7:], pk.Vk.Qcp) + // offset = len(pk.Vk.Qcp) + digestsToOpen[0] = foldedHDigest + digestsToOpen[1] = linearizedPolynomialDigest + digestsToOpen[2] = proof.LRO[0] + digestsToOpen[3] = proof.LRO[1] + digestsToOpen[4] = proof.LRO[2] + digestsToOpen[5] = pk.Vk.S[0] + digestsToOpen[6] = pk.Vk.S[1] + proof.BatchedProof, err = kzg.BatchOpenSinglePoint( - append(coefficients(pk.trace.Qcp), - foldedH, - linearizedPolynomialCanonical, - bwliop.Coefficients()[:bwliop.BlindedSize()], - bwriop.Coefficients()[:bwriop.BlindedSize()], - bwoiop.Coefficients()[:bwoiop.BlindedSize()], - pk.trace.S1.Coefficients(), - pk.trace.S2.Coefficients(), - ), - append(pk.Vk.Qcp, - foldedHDigest, - linearizedPolynomialDigest, - proof.LRO[0], - proof.LRO[1], - proof.LRO[2], - pk.Vk.S[0], - pk.Vk.S[1], - ), + polysToOpen, + digestsToOpen, zeta, hFunc, pk.Kzg, diff --git a/backend/plonk/bls12-377/verify.go b/backend/plonk/bls12-377/verify.go index af820983d0..79ff13ad6c 100644 --- a/backend/plonk/bls12-377/verify.go +++ b/backend/plonk/bls12-377/verify.go @@ -39,7 +39,7 @@ var ( ) func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { - log := logger.Logger().With().Str("curve", "bls12_377").Str("backend", "plonk").Logger() + log := logger.Logger().With().Str("curve", "bls12-377").Str("backend", "plonk").Logger() start := time.Now() // pick a hash function to derive the challenge (the same as in the prover) @@ -137,16 +137,16 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - qC := make([]fr.Element, len(proof.Bsb22Commitments)) - copy(qC, proof.BatchedProof.ClaimedValues) - claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] - claimedQuotient := claimedValues[0] - linearizedPolynomialZeta := claimedValues[1] - l := claimedValues[2] - r := claimedValues[3] - o := claimedValues[4] - s1 := claimedValues[5] - s2 := claimedValues[6] + // qC := make([]fr.Element, len(proof.Bsb22Commitments)) + // claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] + // claimedValues := proof.BatchedProof.ClaimedValues[7:] + claimedQuotient := proof.BatchedProof.ClaimedValues[0] + linearizedPolynomialZeta := proof.BatchedProof.ClaimedValues[1] + l := proof.BatchedProof.ClaimedValues[2] + r := proof.BatchedProof.ClaimedValues[3] + o := proof.BatchedProof.ClaimedValues[4] + s1 := proof.BatchedProof.ClaimedValues[5] + s2 := proof.BatchedProof.ClaimedValues[6] _s1.Mul(&s1, &beta).Add(&_s1, &l).Add(&_s1, &gamma) // (l(ζ)+β*s1(ζ)+γ) _s2.Mul(&s2, &beta).Add(&_s2, &r).Add(&_s2, &gamma) // (r(ζ)+β*s2(ζ)+γ) @@ -220,6 +220,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { vk.S[2], proof.Z, // second & third part ) + qC := make([]fr.Element, len(proof.Bsb22Commitments)) + copy(qC, proof.BatchedProof.ClaimedValues[7:]) scalars := append(qC, l, r, rl, o, one, /* TODO Perf @Tabaie Consider just adding Qk instead */ // first part _s1, _s2, // second & third part @@ -229,15 +231,17 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } // Fold the first proof - foldedProof, foldedDigest, err := kzg.FoldProof(append(vk.Qcp, - foldedH, - linearizedPolynomialDigest, - proof.LRO[0], - proof.LRO[1], - proof.LRO[2], - vk.S[0], - vk.S[1], - ), + digestsToFold := make([]curve.G1Affine, len(vk.Qcp)+7) + copy(digestsToFold[7:], vk.Qcp) + digestsToFold[0] = foldedH + digestsToFold[1] = linearizedPolynomialDigest + digestsToFold[2] = proof.LRO[0] + digestsToFold[3] = proof.LRO[1] + digestsToFold[4] = proof.LRO[2] + digestsToFold[5] = vk.S[0] + digestsToFold[6] = vk.S[1] + foldedProof, foldedDigest, err := kzg.FoldProof( + digestsToFold, &proof.BatchedProof, zeta, hFunc, diff --git a/backend/plonk/bls12-381/prove.go b/backend/plonk/bls12-381/prove.go index 69bfbeb4a9..b5972e36d3 100644 --- a/backend/plonk/bls12-381/prove.go +++ b/backend/plonk/bls12-381/prove.go @@ -508,25 +508,32 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts <-computeFoldedH // Batch open the first list of polynomials + polysQcp := coefficients(pk.trace.Qcp) + polysToOpen := make([][]fr.Element, 7+len(polysQcp)) + copy(polysToOpen[7:], polysQcp) + // offset := len(polysQcp) + polysToOpen[0] = foldedH + polysToOpen[1] = linearizedPolynomialCanonical + polysToOpen[2] = bwliop.Coefficients()[:bwliop.BlindedSize()] + polysToOpen[3] = bwriop.Coefficients()[:bwriop.BlindedSize()] + polysToOpen[4] = bwoiop.Coefficients()[:bwoiop.BlindedSize()] + polysToOpen[5] = pk.trace.S1.Coefficients() + polysToOpen[6] = pk.trace.S2.Coefficients() + + digestsToOpen := make([]curve.G1Affine, len(pk.Vk.Qcp)+7) + copy(digestsToOpen[7:], pk.Vk.Qcp) + // offset = len(pk.Vk.Qcp) + digestsToOpen[0] = foldedHDigest + digestsToOpen[1] = linearizedPolynomialDigest + digestsToOpen[2] = proof.LRO[0] + digestsToOpen[3] = proof.LRO[1] + digestsToOpen[4] = proof.LRO[2] + digestsToOpen[5] = pk.Vk.S[0] + digestsToOpen[6] = pk.Vk.S[1] + proof.BatchedProof, err = kzg.BatchOpenSinglePoint( - append(coefficients(pk.trace.Qcp), - foldedH, - linearizedPolynomialCanonical, - bwliop.Coefficients()[:bwliop.BlindedSize()], - bwriop.Coefficients()[:bwriop.BlindedSize()], - bwoiop.Coefficients()[:bwoiop.BlindedSize()], - pk.trace.S1.Coefficients(), - pk.trace.S2.Coefficients(), - ), - append(pk.Vk.Qcp, - foldedHDigest, - linearizedPolynomialDigest, - proof.LRO[0], - proof.LRO[1], - proof.LRO[2], - pk.Vk.S[0], - pk.Vk.S[1], - ), + polysToOpen, + digestsToOpen, zeta, hFunc, pk.Kzg, diff --git a/backend/plonk/bls12-381/verify.go b/backend/plonk/bls12-381/verify.go index f22da3bc6e..823dc36ff6 100644 --- a/backend/plonk/bls12-381/verify.go +++ b/backend/plonk/bls12-381/verify.go @@ -39,7 +39,7 @@ var ( ) func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { - log := logger.Logger().With().Str("curve", "bls12_381").Str("backend", "plonk").Logger() + log := logger.Logger().With().Str("curve", "bls12-381").Str("backend", "plonk").Logger() start := time.Now() // pick a hash function to derive the challenge (the same as in the prover) @@ -137,16 +137,16 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - qC := make([]fr.Element, len(proof.Bsb22Commitments)) - copy(qC, proof.BatchedProof.ClaimedValues) - claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] - claimedQuotient := claimedValues[0] - linearizedPolynomialZeta := claimedValues[1] - l := claimedValues[2] - r := claimedValues[3] - o := claimedValues[4] - s1 := claimedValues[5] - s2 := claimedValues[6] + // qC := make([]fr.Element, len(proof.Bsb22Commitments)) + // claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] + // claimedValues := proof.BatchedProof.ClaimedValues[7:] + claimedQuotient := proof.BatchedProof.ClaimedValues[0] + linearizedPolynomialZeta := proof.BatchedProof.ClaimedValues[1] + l := proof.BatchedProof.ClaimedValues[2] + r := proof.BatchedProof.ClaimedValues[3] + o := proof.BatchedProof.ClaimedValues[4] + s1 := proof.BatchedProof.ClaimedValues[5] + s2 := proof.BatchedProof.ClaimedValues[6] _s1.Mul(&s1, &beta).Add(&_s1, &l).Add(&_s1, &gamma) // (l(ζ)+β*s1(ζ)+γ) _s2.Mul(&s2, &beta).Add(&_s2, &r).Add(&_s2, &gamma) // (r(ζ)+β*s2(ζ)+γ) @@ -220,6 +220,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { vk.S[2], proof.Z, // second & third part ) + qC := make([]fr.Element, len(proof.Bsb22Commitments)) + copy(qC, proof.BatchedProof.ClaimedValues[7:]) scalars := append(qC, l, r, rl, o, one, /* TODO Perf @Tabaie Consider just adding Qk instead */ // first part _s1, _s2, // second & third part @@ -229,15 +231,17 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } // Fold the first proof - foldedProof, foldedDigest, err := kzg.FoldProof(append(vk.Qcp, - foldedH, - linearizedPolynomialDigest, - proof.LRO[0], - proof.LRO[1], - proof.LRO[2], - vk.S[0], - vk.S[1], - ), + digestsToFold := make([]curve.G1Affine, len(vk.Qcp)+7) + copy(digestsToFold[7:], vk.Qcp) + digestsToFold[0] = foldedH + digestsToFold[1] = linearizedPolynomialDigest + digestsToFold[2] = proof.LRO[0] + digestsToFold[3] = proof.LRO[1] + digestsToFold[4] = proof.LRO[2] + digestsToFold[5] = vk.S[0] + digestsToFold[6] = vk.S[1] + foldedProof, foldedDigest, err := kzg.FoldProof( + digestsToFold, &proof.BatchedProof, zeta, hFunc, diff --git a/backend/plonk/bls24-315/prove.go b/backend/plonk/bls24-315/prove.go index 69ef7228c1..39e11185fa 100644 --- a/backend/plonk/bls24-315/prove.go +++ b/backend/plonk/bls24-315/prove.go @@ -508,25 +508,32 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts <-computeFoldedH // Batch open the first list of polynomials + polysQcp := coefficients(pk.trace.Qcp) + polysToOpen := make([][]fr.Element, 7+len(polysQcp)) + copy(polysToOpen[7:], polysQcp) + // offset := len(polysQcp) + polysToOpen[0] = foldedH + polysToOpen[1] = linearizedPolynomialCanonical + polysToOpen[2] = bwliop.Coefficients()[:bwliop.BlindedSize()] + polysToOpen[3] = bwriop.Coefficients()[:bwriop.BlindedSize()] + polysToOpen[4] = bwoiop.Coefficients()[:bwoiop.BlindedSize()] + polysToOpen[5] = pk.trace.S1.Coefficients() + polysToOpen[6] = pk.trace.S2.Coefficients() + + digestsToOpen := make([]curve.G1Affine, len(pk.Vk.Qcp)+7) + copy(digestsToOpen[7:], pk.Vk.Qcp) + // offset = len(pk.Vk.Qcp) + digestsToOpen[0] = foldedHDigest + digestsToOpen[1] = linearizedPolynomialDigest + digestsToOpen[2] = proof.LRO[0] + digestsToOpen[3] = proof.LRO[1] + digestsToOpen[4] = proof.LRO[2] + digestsToOpen[5] = pk.Vk.S[0] + digestsToOpen[6] = pk.Vk.S[1] + proof.BatchedProof, err = kzg.BatchOpenSinglePoint( - append(coefficients(pk.trace.Qcp), - foldedH, - linearizedPolynomialCanonical, - bwliop.Coefficients()[:bwliop.BlindedSize()], - bwriop.Coefficients()[:bwriop.BlindedSize()], - bwoiop.Coefficients()[:bwoiop.BlindedSize()], - pk.trace.S1.Coefficients(), - pk.trace.S2.Coefficients(), - ), - append(pk.Vk.Qcp, - foldedHDigest, - linearizedPolynomialDigest, - proof.LRO[0], - proof.LRO[1], - proof.LRO[2], - pk.Vk.S[0], - pk.Vk.S[1], - ), + polysToOpen, + digestsToOpen, zeta, hFunc, pk.Kzg, diff --git a/backend/plonk/bls24-315/verify.go b/backend/plonk/bls24-315/verify.go index afa89fa0b6..2fdee5191e 100644 --- a/backend/plonk/bls24-315/verify.go +++ b/backend/plonk/bls24-315/verify.go @@ -39,7 +39,7 @@ var ( ) func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { - log := logger.Logger().With().Str("curve", "bls24_315").Str("backend", "plonk").Logger() + log := logger.Logger().With().Str("curve", "bls24-315").Str("backend", "plonk").Logger() start := time.Now() // pick a hash function to derive the challenge (the same as in the prover) @@ -137,16 +137,16 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - qC := make([]fr.Element, len(proof.Bsb22Commitments)) - copy(qC, proof.BatchedProof.ClaimedValues) - claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] - claimedQuotient := claimedValues[0] - linearizedPolynomialZeta := claimedValues[1] - l := claimedValues[2] - r := claimedValues[3] - o := claimedValues[4] - s1 := claimedValues[5] - s2 := claimedValues[6] + // qC := make([]fr.Element, len(proof.Bsb22Commitments)) + // claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] + // claimedValues := proof.BatchedProof.ClaimedValues[7:] + claimedQuotient := proof.BatchedProof.ClaimedValues[0] + linearizedPolynomialZeta := proof.BatchedProof.ClaimedValues[1] + l := proof.BatchedProof.ClaimedValues[2] + r := proof.BatchedProof.ClaimedValues[3] + o := proof.BatchedProof.ClaimedValues[4] + s1 := proof.BatchedProof.ClaimedValues[5] + s2 := proof.BatchedProof.ClaimedValues[6] _s1.Mul(&s1, &beta).Add(&_s1, &l).Add(&_s1, &gamma) // (l(ζ)+β*s1(ζ)+γ) _s2.Mul(&s2, &beta).Add(&_s2, &r).Add(&_s2, &gamma) // (r(ζ)+β*s2(ζ)+γ) @@ -220,6 +220,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { vk.S[2], proof.Z, // second & third part ) + qC := make([]fr.Element, len(proof.Bsb22Commitments)) + copy(qC, proof.BatchedProof.ClaimedValues[7:]) scalars := append(qC, l, r, rl, o, one, /* TODO Perf @Tabaie Consider just adding Qk instead */ // first part _s1, _s2, // second & third part @@ -229,15 +231,17 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } // Fold the first proof - foldedProof, foldedDigest, err := kzg.FoldProof(append(vk.Qcp, - foldedH, - linearizedPolynomialDigest, - proof.LRO[0], - proof.LRO[1], - proof.LRO[2], - vk.S[0], - vk.S[1], - ), + digestsToFold := make([]curve.G1Affine, len(vk.Qcp)+7) + copy(digestsToFold[7:], vk.Qcp) + digestsToFold[0] = foldedH + digestsToFold[1] = linearizedPolynomialDigest + digestsToFold[2] = proof.LRO[0] + digestsToFold[3] = proof.LRO[1] + digestsToFold[4] = proof.LRO[2] + digestsToFold[5] = vk.S[0] + digestsToFold[6] = vk.S[1] + foldedProof, foldedDigest, err := kzg.FoldProof( + digestsToFold, &proof.BatchedProof, zeta, hFunc, diff --git a/backend/plonk/bls24-317/prove.go b/backend/plonk/bls24-317/prove.go index 753b151b9c..5ec3131efc 100644 --- a/backend/plonk/bls24-317/prove.go +++ b/backend/plonk/bls24-317/prove.go @@ -508,25 +508,32 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts <-computeFoldedH // Batch open the first list of polynomials + polysQcp := coefficients(pk.trace.Qcp) + polysToOpen := make([][]fr.Element, 7+len(polysQcp)) + copy(polysToOpen[7:], polysQcp) + // offset := len(polysQcp) + polysToOpen[0] = foldedH + polysToOpen[1] = linearizedPolynomialCanonical + polysToOpen[2] = bwliop.Coefficients()[:bwliop.BlindedSize()] + polysToOpen[3] = bwriop.Coefficients()[:bwriop.BlindedSize()] + polysToOpen[4] = bwoiop.Coefficients()[:bwoiop.BlindedSize()] + polysToOpen[5] = pk.trace.S1.Coefficients() + polysToOpen[6] = pk.trace.S2.Coefficients() + + digestsToOpen := make([]curve.G1Affine, len(pk.Vk.Qcp)+7) + copy(digestsToOpen[7:], pk.Vk.Qcp) + // offset = len(pk.Vk.Qcp) + digestsToOpen[0] = foldedHDigest + digestsToOpen[1] = linearizedPolynomialDigest + digestsToOpen[2] = proof.LRO[0] + digestsToOpen[3] = proof.LRO[1] + digestsToOpen[4] = proof.LRO[2] + digestsToOpen[5] = pk.Vk.S[0] + digestsToOpen[6] = pk.Vk.S[1] + proof.BatchedProof, err = kzg.BatchOpenSinglePoint( - append(coefficients(pk.trace.Qcp), - foldedH, - linearizedPolynomialCanonical, - bwliop.Coefficients()[:bwliop.BlindedSize()], - bwriop.Coefficients()[:bwriop.BlindedSize()], - bwoiop.Coefficients()[:bwoiop.BlindedSize()], - pk.trace.S1.Coefficients(), - pk.trace.S2.Coefficients(), - ), - append(pk.Vk.Qcp, - foldedHDigest, - linearizedPolynomialDigest, - proof.LRO[0], - proof.LRO[1], - proof.LRO[2], - pk.Vk.S[0], - pk.Vk.S[1], - ), + polysToOpen, + digestsToOpen, zeta, hFunc, pk.Kzg, diff --git a/backend/plonk/bls24-317/verify.go b/backend/plonk/bls24-317/verify.go index 3aa9661e80..4092168df5 100644 --- a/backend/plonk/bls24-317/verify.go +++ b/backend/plonk/bls24-317/verify.go @@ -39,7 +39,7 @@ var ( ) func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { - log := logger.Logger().With().Str("curve", "bls24_317").Str("backend", "plonk").Logger() + log := logger.Logger().With().Str("curve", "bls24-317").Str("backend", "plonk").Logger() start := time.Now() // pick a hash function to derive the challenge (the same as in the prover) @@ -137,16 +137,16 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - qC := make([]fr.Element, len(proof.Bsb22Commitments)) - copy(qC, proof.BatchedProof.ClaimedValues) - claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] - claimedQuotient := claimedValues[0] - linearizedPolynomialZeta := claimedValues[1] - l := claimedValues[2] - r := claimedValues[3] - o := claimedValues[4] - s1 := claimedValues[5] - s2 := claimedValues[6] + // qC := make([]fr.Element, len(proof.Bsb22Commitments)) + // claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] + // claimedValues := proof.BatchedProof.ClaimedValues[7:] + claimedQuotient := proof.BatchedProof.ClaimedValues[0] + linearizedPolynomialZeta := proof.BatchedProof.ClaimedValues[1] + l := proof.BatchedProof.ClaimedValues[2] + r := proof.BatchedProof.ClaimedValues[3] + o := proof.BatchedProof.ClaimedValues[4] + s1 := proof.BatchedProof.ClaimedValues[5] + s2 := proof.BatchedProof.ClaimedValues[6] _s1.Mul(&s1, &beta).Add(&_s1, &l).Add(&_s1, &gamma) // (l(ζ)+β*s1(ζ)+γ) _s2.Mul(&s2, &beta).Add(&_s2, &r).Add(&_s2, &gamma) // (r(ζ)+β*s2(ζ)+γ) @@ -220,6 +220,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { vk.S[2], proof.Z, // second & third part ) + qC := make([]fr.Element, len(proof.Bsb22Commitments)) + copy(qC, proof.BatchedProof.ClaimedValues[7:]) scalars := append(qC, l, r, rl, o, one, /* TODO Perf @Tabaie Consider just adding Qk instead */ // first part _s1, _s2, // second & third part @@ -229,15 +231,17 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } // Fold the first proof - foldedProof, foldedDigest, err := kzg.FoldProof(append(vk.Qcp, - foldedH, - linearizedPolynomialDigest, - proof.LRO[0], - proof.LRO[1], - proof.LRO[2], - vk.S[0], - vk.S[1], - ), + digestsToFold := make([]curve.G1Affine, len(vk.Qcp)+7) + copy(digestsToFold[7:], vk.Qcp) + digestsToFold[0] = foldedH + digestsToFold[1] = linearizedPolynomialDigest + digestsToFold[2] = proof.LRO[0] + digestsToFold[3] = proof.LRO[1] + digestsToFold[4] = proof.LRO[2] + digestsToFold[5] = vk.S[0] + digestsToFold[6] = vk.S[1] + foldedProof, foldedDigest, err := kzg.FoldProof( + digestsToFold, &proof.BatchedProof, zeta, hFunc, diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index 5f8e42e3ec..1302571166 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Code generated by gnark DO NOT EDIT + package plonk import ( @@ -32,9 +34,9 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" "github.com/consensys/gnark-crypto/ecc/bn254/fr/iop" - cs "github.com/consensys/gnark/constraint/bn254" + "github.com/consensys/gnark/constraint/bn254" - fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" diff --git a/backend/plonk/bn254/solidity/abi/PlonkVerifier.abi b/backend/plonk/bn254/solidity/abi/PlonkVerifier.abi new file mode 100644 index 0000000000..74799a02a6 --- /dev/null +++ b/backend/plonk/bn254/solidity/abi/PlonkVerifier.abi @@ -0,0 +1 @@ +[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"a","type":"uint256"}],"name":"PrintUint256","type":"event"}] \ No newline at end of file diff --git a/backend/plonk/bn254/solidity/abi/PlonkVerifier.bin b/backend/plonk/bn254/solidity/abi/PlonkVerifier.bin new file mode 100644 index 0000000000..a58baa9f97 --- /dev/null +++ b/backend/plonk/bn254/solidity/abi/PlonkVerifier.bin @@ -0,0 +1 @@ +60566050600b82828239805160001a6073146043577f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212205226b6547ca96d0b3a4de1173ac16d03809a55c3f4d51cfbe714667b28de567564736f6c63430008130033 \ No newline at end of file diff --git a/backend/plonk/bn254/solidity/abi/TestVerifier.abi b/backend/plonk/bn254/solidity/abi/TestVerifier.abi new file mode 100644 index 0000000000..d7446a5382 --- /dev/null +++ b/backend/plonk/bn254/solidity/abi/TestVerifier.abi @@ -0,0 +1 @@ +[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"a","type":"bool"}],"name":"PrintBool","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"a","type":"uint256"}],"name":"PrintUint256","type":"event"},{"inputs":[],"name":"test_verifier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"proof","type":"bytes"},{"internalType":"uint256[]","name":"public_inputs","type":"uint256[]"}],"name":"test_verifier_go","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/backend/plonk/bn254/solidity/abi/TestVerifier.bin b/backend/plonk/bn254/solidity/abi/TestVerifier.bin new file mode 100644 index 0000000000..b2ea814dc5 --- /dev/null +++ b/backend/plonk/bn254/solidity/abi/TestVerifier.bin @@ -0,0 +1 @@ +608060405234801561001057600080fd5b50613ce5806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80638cbba7b71461003b578063c383590a14610045575b600080fd5b610043610061565b005b61005f600480360381019061005a91906134a9565b61016b565b005b6000600367ffffffffffffffff81111561007e5761007d613280565b5b6040519080825280602002602001820160405280156100ac5781602001602082028036833780820191505090505b5090506006816000815181106100c5576100c4613521565b5b6020026020010181815250506007816001815181106100e7576100e6613521565b5b60200260200101818152505060088160028151811061010957610108613521565b5b602002602001018181525050600061011f61017e565b9050600061012d82846107d7565b90507f3e1a1345e360785a18ee3f9d25ba93d69ea5c3b5772b44df827662204209612c8160405161015e919061356b565b60405180910390a1505050565b600061017783836107d7565b9050505050565b6060610188613156565b7f2bfdf48f3358f3e85a081de26fc48b1efaea78b539f40b75371da351434c653c8160000181815250507f260ca2fa81f809e385685f1b0b5a31457d6012230a2b5b41377f20e0a91a05ab8160200181815250507f1a2d48183d3f456fb5b0d973fec425a6f6f5465f6cf2415338d6181c4776d3a08160400181815250507f1480057d0a5ef1b2af09b9a4ebd10dac779d6aaa5654b336297a3e0a2376f9cd8160600181815250507f05bd3d59f4c2346778c6c657e72c214eae17479586c514963673f0e33e1f40ba8160800181815250507f2065ef9df3594d13ff90c6dbbe9452e550e80ac2651dd9c1a9f974932a54c4f88160a00181815250507f2c41ca7bfaf3cc4caeebf0aeb02a385c251f7586328b35402191e8a5038c0da88160c00181815250507f0b6e269d74c93ca056226963d5b22c0d83933c969cef2637cc624c1343ba6df18160e00181815250507f265137a78f4ef26af3b5d31a717ed5686e3c4b8f3f1526cb4b8d7fda7419e75f816101000181815250507f14d04c6f8271552e1dd5afbad2b33f7b55462c7d05203aab1ec8db7fd6b0641e816101200181815250507f06c3865cab1fa4f84d5fcdc576a2ca10dd5b174526f51247958c33bc757ba6e7816101400181815250507f12651f8ab0db434a1aa0fe908ea8dd75a2cdec91773c15e1c9959fd026a785f4816101600181815250507f0693d99a75683fc96a53e8dada884479be55ec150b2cf0c6dd924ee04cfa0184816101800181815250507f2ce56e102172d4b23b5d8d418f514295a887542cea85845c0772b86c442a70f6816101a00181815250507f16ffbbc7a52ba3eb9ac02c4d3a0d0a4ffda6469a88d7b265eb88cbf71d67b1d3816101c00181815250507f02356e4b5a0e900026b55a131d3f279b9dc4977e8cce378c2a6d08570597374c816101e00181815250507f1d7d30b514415c872b0610d3b41a43cb42fb5276a0b9a75c00fa5f5c6dad9a80816102000181815250507f05c64e466e03121fa5d67a8980e418f7d6a3a0e462958b1fe3969008867a9e12816102200181815250507f0a27257bab695b24ebee0a6ec065d88fb04f18f342d554687f38ec894f83f0a9816102400181815250507f104b099b6387a9668601f702d6ce28d4a9a0017b235b87640b55d3c4f020f061816102600181815250507f0218961c70ecb8e1c8b5bdfa2a3238c21e6a1d7017ce0dadb51a16a4bd90baf1816102800181815250507f2b9421b98e344c89af2ea2625344b3d11b2f6b2a731b4ea599e2ba1b548dd447816102a00181815250507f13f2c3df009d71b54a0500f04d36781afd5f9df1e9e8f9418f798ab2b48bda8c816102c00181815250507f2f402d27013130f33b2db0b14bc97f9f99c671ab3f1f3db5c869163c92b8c37d816102e00181815250507f0cecacec73c3e598894de734d1465d30682416170e657fe9c654a627a7142a38816103000181815250507f26f078ad0487efd41675efc58c78aa3f866acb4bb21e275edf615ecc98165bfe816103200181815250506000816103400181815250507f11d16aca7209deba0b3da6df4c4f9dc7e03c3db3a008b42927f3b38e232fb2be816103600181815250507f0e85b9d47c8c5c672b13e49cfb330f1e80632377124fcedf43626f2b63765a67816103800181815250506060816000015182602001518360400151846060015185608001518660a001518760c001518860e001518961010001518a61012001518b61014001518c610160015160405160200161069d9c9b9a999897969594939291906135a7565b604051602081830303815290604052905080826101800151836101a00151846101c001516040516020016106d494939291906136ee565b604051602081830303815290604052905080826101e00151836102000151846102200151856102400151866102600151876102800151886102a00151604051602001610727989796959493929190613738565b604051602081830303815290604052905080826102c00151836102e001518461030001518561032001516040516020016107659594939291906137c6565b60405160208183030381529060405290508082610340015160405160200161078e929190613821565b6040516020818303038152906040529050808261036001518361038001516040516020016107be93929190613849565b6040516020818303038152906040529050809250505090565b60008060008060006107e98787611e4e565b80945081955082965083975050505050600061080688888461235f565b905060008060009050604051856000820152876040820152846060820152866020820152836101c0820152610839610884565b6108428b611996565b61084b8b611921565b6108548b61151b565b61085d8b610fbf565b6108668b610d52565b61086f8b610a33565b61024081015191506102608101519250611e06565b6040516102806040510161089e8160206060850151611da7565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000010382089050806101e08401527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001036060850151086109678360027f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000010383611da7565b90507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000017f2ee12bff4a2813286a8dc388cd754d9a3ef2490635eba50cb9c2e5e750800001820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001828209915060008401517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181840992507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181840992508260c08601525050505050565b60405161028081016003816040810192506102e085015181526103008501516020820152610a678383610320880184611cf7565b6101808401610a7c8484610240890184611cf7565b6101608501610a9084610280890183611d55565b8460408101955060018152600260208201528151604082015260408160608360076107d05a03fa506020810180517f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47038152610aee87838687611c76565b86604088019750610b098860608b01516102e08d0184611cbc565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000017f09c532c6306b93d29678200d47c0b2a99c18d51b838eeb1d3eed4c533bb512d060608b0151097f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018189099750610b8789896103208e0185611cf7565b610b9389838889611c76565b6020870180517f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4703815286518a52602087015160208b01527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c260408b01527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed60608b01527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b60808b01527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa60a08b0152875160c08b0152602088015160e08b01527f21487b7187fea07a8c5035362b098732dbf9c9c3a8b785b5542c595a984a9eb16101008b01527f033b79bd16d5e8a868c369319e7f3fc697a705aef9bd9338dca8f56bcbefd3fc6101208b01527f011b702314a36beb2823cf932d6573734fe6237da634255717bd10a8505d75456101408b01527f1392d6b91b5df791212bc84cb1ce917cd0044df61d989e6010a678e1c18d87d36101608b0152602060006101808c60086107d05a03fa6102408c01518181169050600051811690506000516102608e0152806102408e01525050505050505050505050505050565b6040516102806040510161022082015180604060010261020001808401604085015161018087015260608501516101a08701526102a0870151610160870152610da48184608088016101808a01611cf7565b610db7836102c089016101608901611d55565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018484099250610df0818460c088016101808a01611cf7565b610e03836101a089016101608901611d55565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018484099250610e3f8286018461010088016101808a01611cf7565b610e52836101c089016101608901611d55565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018484099250610e8e8286018461014088016101808a01611cf7565b610ea1836101e089016101608901611d55565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018484099250610edd8286018461018088016101808a01611cf7565b610ef08361020089016101608901611d55565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018484099250610f2c828601846101c088016101808a01611cf7565b610f3f8361022089016101608901611d55565b6103608701610200860160005b6001811015610fb3577f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018787099550610f8d85890187846101808d01611cf7565b610f9c86846101608c01611d55565b602083019250604082019150600181019050610f4c565b50505050505050505050565b604051610280604051016467616d6d6181526060820151602082015260e082015160408201526101008201516060820152610120820151608082015261014082015160a0820152602083015160c0820152604083015160e08201526060830151610100820152608083015161012082015260a083015161014082015260c08301516101608201527f28a65b11eee0b34f6402404d76f1c0c3bc3a01c74c4748c723adf49ae75995556101808201527f1e8175426eb99057633decd6bb26a00b3b003710e702e23b5904e13b7b49a0806101a08201527f22fb19af6150047ef27f32e95e56b9096d60fb9e91738a1de337dd64b46a4a4e6101c08201527f12447dfc10994f0f87af0d14a3588f44c6404d144a4a89f60d0fbe3997ef65d36101e08201526102007f2fc8e621da8773a71ce9c20ecc967a1587e3116566c346f88f9eb6a9cf32243b818301527f044aaed3aa229e3f1906df767f6877b79eb4425c0ac354ab6e1556f1a4082368602082018301526040810190506102a0840151818301526102c0840151602082018301526101a0840151604082018301526101c0840151606082018301526101e08401516080820183015261020084015160a0820183015261022084015160c0820183015260e081018201610360850160005b60018110156111c2578151835260208201915060208301925060018101905061119e565b50601b6003600102601601602081026005019050602061022088018284890160026107d05a03fa507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610220880151066102208801525050505050505050565b604051610280604051017f0e606450dbd88a14565d4e57ee72674787b6860d2139671bcec21ce903174b7e81527f25a3c5619b7c5567df3ab30837006312bb7d3356dc64f83ac36bda1f50cd9e08602082015261128d604082016101a0850151836101208601611cbc565b7f2c975fae7e44ca144b8a2e578e0d21d53e4221b01594af21b96099ae402ecdbe81527f22752d25557cf48a9dde2defb2ba3e16201df82ac4959330b21e465cb700c89760208201526112ee604082016101c0850151836101208601611cf7565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016101c08401516101a0850151097f190b08e03a378a3f870f71f936f0c5621da73c35f749dda2ea343ad5cce0674b82527f03ae9f6bdee25baaf05d98df559a46c0e66b4f2fcee25ce86156c8b262a10e6760208301526113786040830182846101208701611cf7565b7f2c975fae7e44ca144b8a2e578e0d21d53e4221b01594af21b96099ae402ecdbe82527f0def214d8bb4ab9f1a7217c6cec71a4777637266a3dc375c8a0245ba217c34b060208301526113d9604083016101e0860151846101208701611cf7565b7f190b08e03a378a3f870f71f936f0c5621da73c35f749dda2ea343ad5cce0674b82527f2cb5af07024f447ec7f2acd72be7119cb1161b61998f6da4dac9c36475dbeee06020830152611439604083018361012086016101208701611c76565b6103608401602060010261036001850160005b600181101561148e578151855260208201516020860152611477604086018451876101208a01611cf7565b60208301925060408201915060018101905061144c565b507f1dd205b578328dfb97ad3a166d6b7a3479a9581ccbb59b5115307949766c4ad884527f1113e7413b3a28f3893503d7dd743c91574dcd4f9f7e8abda894461b515f577d60208501526114eb6040850188866101208901611cf7565b610240860151845261026086015160208501526115116040850189866101208901611cf7565b5050505050505050565b60405160208101516040820151606083015160008401517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000184610280880151097f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161020088015186097f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016101a0890151820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000185820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161022089015187097f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016101c08a0151820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000186820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018284097f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000182820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000185820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001600580097f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001878a097f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016101a08d0151820895507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000189870895507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016005820994507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016101c08d0151860894507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000189860894507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000182820993507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016101e08d0151850893507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000189850893507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018587097f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018582099050807f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000010390507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000188820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160c08d01518208905061191281858f611222565b50505050505050505050505050565b60405160026020016102806040510161193f81836060860151611da7565b6119528282610160880160e08801611cbc565b61196882610120870160e0870160e08801611c76565b61197a828260e0870160e08801611cbc565b61198f8260e0870160e0870160e08801611c76565b5050505050565b604051610280604051017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160208301516102008501510981527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001604083015182510881527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016101a08401518251088152602081017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160208401516102208601510981527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001604084015182510881527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016101c08501518251088152604082017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160408501516101e08701510881527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001825184510983527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001815184510983527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001600085015184510983527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016102808601518451098352606083017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016101c08601516102c08801510881527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001845182510881527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160c08601517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000010382510881527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016101e08601516102a08801510983528251815114610240860152505050505050565b6040518251855260208301516020860152835160408601526020840151606086015260408260808760066107d05a03fa6102408201518116610240830152505050505050565b604051825185526020830151602086015283604086015260408260608760076107d05a03fa6102408201518116610240830152505050505050565b604051825185526020830151602086015283604086015260408560608760076107d05a03fa825160408701526020830151606087015260408360808860066107d05a03fa811690506102408201518116610240830152505050505050565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001838351097f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181835108825250505050565b600060208452602080850152602060408501528160608501528260808501527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160a085015260208460c08660056107d05a03fa50835190509392505050565b507fc06f90efa9c91dc43be8c00f432325e29d17851ab0f40844b418121428cc043b82604051611e369190613891565b60405180910390a18097505050505050505092915050565b600080600080600080600080604051611e678a8c611f2e565b80519450611e75858c612278565b80519350611e83848c61229f565b80519250611e91838c6122dd565b805191507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001850694507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001840693507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001830692507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000182069150612345565b6040516467616d6d6181527f28a65b11eee0b34f6402404d76f1c0c3bc3a01c74c4748c723adf49ae759955560208201527f1e8175426eb99057633decd6bb26a00b3b003710e702e23b5904e13b7b49a08060408201527f22fb19af6150047ef27f32e95e56b9096d60fb9e91738a1de337dd64b46a4a4e60608201527f12447dfc10994f0f87af0d14a3588f44c6404d144a4a89f60d0fbe3997ef65d360808201527f1dd205b578328dfb97ad3a166d6b7a3479a9581ccbb59b5115307949766c4ad860a08201527f1113e7413b3a28f3893503d7dd743c91574dcd4f9f7e8abda894461b515f577d60c08201527f0e606450dbd88a14565d4e57ee72674787b6860d2139671bcec21ce903174b7e60e08201527f25a3c5619b7c5567df3ab30837006312bb7d3356dc64f83ac36bda1f50cd9e086101008201527f2c975fae7e44ca144b8a2e578e0d21d53e4221b01594af21b96099ae402ecdbe6101208201527f22752d25557cf48a9dde2defb2ba3e16201df82ac4959330b21e465cb700c8976101408201527f190b08e03a378a3f870f71f936f0c5621da73c35f749dda2ea343ad5cce0674b6101608201527f03ae9f6bdee25baaf05d98df559a46c0e66b4f2fcee25ce86156c8b262a10e676101808201527f2c975fae7e44ca144b8a2e578e0d21d53e4221b01594af21b96099ae402ecdbe6101a08201527f0def214d8bb4ab9f1a7217c6cec71a4777637266a3dc375c8a0245ba217c34b06101c08201527f190b08e03a378a3f870f71f936f0c5621da73c35f749dda2ea343ad5cce0674b6101e08201527f2cb5af07024f447ec7f2acd72be7119cb1161b61998f6da4dac9c36475dbeee061020082015260208301610220820160005b85518110156121d257825182526020830192506020820191506001810190506121ae565b50610360840160206001028101905060005b60018110156122125781518352602082015160208401526040830192506040820191506001810190506121e4565b506020850151825260408501516020830152606085015160408301526080850151606083015260a0850151608083015260c085015160a083015260208651026102c50160406001028101905060208582601b880160026107d05a03fa5050505050505050565b604051636265746181528260208201526020816024601c840160026107d05a03fa50505050565b60405164616c7068618152826020820152610240820151604082015261026082015160608201526020816065601b840160026107d05a03fa50505050565b604051637a657461815282602082015260e082015160408201526101008201516060820152610120820151608082015261014082015160a082015261016082015160c082015261018082015160e082015260208160e4601c840160026107d05a03fa50505050565b508383838397509750975097505050505092959194509250565b60008060006123738486516020880161237e565b60405151905061278b565b60405161238c81848661240d565b60008060005b858110156123ff577f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001855185510991507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018284089250602084019350602085019450600181019050612392565b508160405152505050505050565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000010361245e8560208561272c565b087f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000017f2ee12bff4a2813286a8dc388cd754d9a3ef2490635eba50cb9c2e5e7508000018209905060018460005b85811015612552577f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001837f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000103860882527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000017f09c532c6306b93d29678200d47c0b2a99c18d51b838eeb1d3eed4c533bb512d0840992506020820191506001810190506124ab565b5061255e81868861261a565b8590506001915060005b85811015612611577f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001837f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001868551090982526020820191507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000017f09c532c6306b93d29678200d47c0b2a99c18d51b838eeb1d3eed4c533bb512d084099250600181019050612568565b50505050505050565b600183526000805b838110156126705781850151828401517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001818309905060208401935080848801525050600181019050612622565b50602081038201915080840193506126b06020850160027f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000103865161272c565b60005b848110156127245760208603955083517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001875184098086527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001828509935060208603955050506001810190506126b3565b505050505050565b600060208452602080850152602060408501528160608501528260808501527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160a085015260208460c08660056107d05a03fa50835190509392505050565b61279960405160208661272c565b91507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000103830891506000600167ffffffffffffffff81111561280157612800613280565b5b60405190808252806020026020018201604052801561282f5781602001602082028036833780820191505090505b50905061283b816129b5565b60606001600261284b91906138db565b67ffffffffffffffff81111561286457612863613280565b5b6040519080825280602002602001820160405280156128925781602001602082028036833780820191505090505b50905061289f81896129c7565b60005b60018110156129a657600061290f838360026128be91906138db565b815181106128cf576128ce613521565b5b60200260200101518460018560026128e791906138db565b6128f1919061391d565b8151811061290257612901613521565b5b6020026020010151612a1a565b90506000612943898b5187868151811061292c5761292b613521565b5b602002602001015161293e919061391d565b612b9c565b90507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181830990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181870895505050808061299e90613951565b9150506128a2565b50829450505050509392505050565b60208101600381526020810190505050565b60208201610360820160206001028101905060005b6002600102811015612a135781518352602083019250602082019150815183526020830192506020820191506001810190506129dc565b5050505050565b600080612a278484612d9c565b905060005b6020811015612a8b57806008612a4291906138db565b8282602f612a509190613999565b60308110612a6157612a60613521565b5b602002015160ff16901b83612a76919061391d565b92508080612a8390613951565b915050612a2c565b507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000182612ab891906139fc565b9150600080600090505b6010811015612b2157806008612ad891906138db565b8382600f612ae69190613999565b60308110612af757612af6613521565b5b602002015160ff16901b82612b0c919061391d565b91508080612b1990613951565b915050612ac2565b5060007f0e0a77c19a07df2f666ea36f7879462e36fc76959f60cd29ac96341c4ffffffb90507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181830991507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001828508935050505092915050565b600080612c08565b600060405160208152602080820152602060408201528260608201528360808201527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160a08201526020600060c08360056107d05a03fa5060005191505092915050565b612c32837f09c532c6306b93d29678200d47c0b2a99c18d51b838eeb1d3eed4c533bb512d0612ba4565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001817f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000010386089350612c85602086612ba4565b94507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000103860894507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000017f2ee12bff4a2813286a8dc388cd754d9a3ef2490635eba50cb9c2e5e75080000182099050612d4360027f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000010385612ba4565b93507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000184820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018582099150508091505092915050565b612da461322e565b60006040518060400160405280600b81526020017f42534232322d506c6f6e6b00000000000000000000000000000000000000000081525090506060600080603090506000600b905060005b6040811015612e30578484604051602001612e0c929190613a70565b60405160208183030381529060405294508080612e2890613951565b915050612df0565b508388888585878a87604051602001612e50989796959493929190613adf565b60405160208183030381529060405293506000600285604051612e739190613b69565b602060405180830381855afa158015612e90573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190612eb39190613bb6565b90508060018784604051602001612ecd9493929190613c04565b60405160208183030381529060405294506000600286604051612ef09190613b69565b602060405180830381855afa158015612f0d573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190612f309190613bb6565b905060005b6020811015612f8f57818160208110612f5157612f50613521565b5b1a60f81b60f81c898260308110612f6b57612f6a613521565b5b602002019060ff16908160ff16815250508080612f8790613951565b915050612f35565b5080600060208110612fa457612fa3613521565b5b1a60f81b60f81c82600060208110612fbf57612fbe613521565b5b1a60f81b60f81c18604051602001612fd79190613c4e565b60405160208183030381529060405295506000600190505b6020811015613063578682826020811061300c5761300b613521565b5b1a60f81b60f81c84836020811061302657613025613521565b5b1a60f81b60f81c1860405160200161303f929190613a70565b6040516020818303038152906040529650808061305b90613951565b915050612fef565b50856002888560405160200161307c9493929190613c69565b604051602081830303815290604052955060028660405161309d9190613b69565b602060405180830381855afa1580156130ba573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906130dd9190613bb6565b905060005b6010811015613148578181602081106130fe576130fd613521565b5b1a60f81b60f81c89602083613113919061391d565b6030811061312457613123613521565b5b602002019060ff16908160ff1681525050808061314090613951565b9150506130e2565b505050505050505092915050565b604051806103a0016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b604051806106000160405280603090602082028036833780820191505090505090565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6132b88261326f565b810181811067ffffffffffffffff821117156132d7576132d6613280565b5b80604052505050565b60006132ea613251565b90506132f682826132af565b919050565b600067ffffffffffffffff82111561331657613315613280565b5b61331f8261326f565b9050602081019050919050565b82818337600083830152505050565b600061334e613349846132fb565b6132e0565b90508281526020810184848401111561336a5761336961326a565b5b61337584828561332c565b509392505050565b600082601f83011261339257613391613265565b5b81356133a284826020860161333b565b91505092915050565b600067ffffffffffffffff8211156133c6576133c5613280565b5b602082029050602081019050919050565b600080fd5b6000819050919050565b6133ef816133dc565b81146133fa57600080fd5b50565b60008135905061340c816133e6565b92915050565b6000613425613420846133ab565b6132e0565b90508083825260208201905060208402830185811115613448576134476133d7565b5b835b81811015613471578061345d88826133fd565b84526020840193505060208101905061344a565b5050509392505050565b600082601f8301126134905761348f613265565b5b81356134a0848260208601613412565b91505092915050565b600080604083850312156134c0576134bf61325b565b5b600083013567ffffffffffffffff8111156134de576134dd613260565b5b6134ea8582860161337d565b925050602083013567ffffffffffffffff81111561350b5761350a613260565b5b6135178582860161347b565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008115159050919050565b61356581613550565b82525050565b6000602082019050613580600083018461355c565b92915050565b6000819050919050565b6135a161359c826133dc565b613586565b82525050565b60006135b3828f613590565b6020820191506135c3828e613590565b6020820191506135d3828d613590565b6020820191506135e3828c613590565b6020820191506135f3828b613590565b602082019150613603828a613590565b6020820191506136138289613590565b6020820191506136238288613590565b6020820191506136338287613590565b6020820191506136438286613590565b6020820191506136538285613590565b6020820191506136638284613590565b6020820191508190509d9c50505050505050505050505050565b600081519050919050565b600081905092915050565b60005b838110156136b1578082015181840152602081019050613696565b60008484015250505050565b60006136c88261367d565b6136d28185613688565b93506136e2818560208601613693565b80840191505092915050565b60006136fa82876136bd565b91506137068286613590565b6020820191506137168285613590565b6020820191506137268284613590565b60208201915081905095945050505050565b6000613744828b6136bd565b9150613750828a613590565b6020820191506137608289613590565b6020820191506137708288613590565b6020820191506137808287613590565b6020820191506137908286613590565b6020820191506137a08285613590565b6020820191506137b08284613590565b6020820191508190509998505050505050505050565b60006137d282886136bd565b91506137de8287613590565b6020820191506137ee8286613590565b6020820191506137fe8285613590565b60208201915061380e8284613590565b6020820191508190509695505050505050565b600061382d82856136bd565b91506138398284613590565b6020820191508190509392505050565b600061385582866136bd565b91506138618285613590565b6020820191506138718284613590565b602082019150819050949350505050565b61388b816133dc565b82525050565b60006020820190506138a66000830184613882565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006138e6826133dc565b91506138f1836133dc565b92508282026138ff816133dc565b91508282048414831517613916576139156138ac565b5b5092915050565b6000613928826133dc565b9150613933836133dc565b925082820190508082111561394b5761394a6138ac565b5b92915050565b600061395c826133dc565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361398e5761398d6138ac565b5b600182019050919050565b60006139a4826133dc565b91506139af836133dc565b92508282039050818111156139c7576139c66138ac565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000613a07826133dc565b9150613a12836133dc565b925082613a2257613a216139cd565b5b828206905092915050565b600060ff82169050919050565b60008160f81b9050919050565b6000613a5282613a3a565b9050919050565b613a6a613a6582613a2d565b613a47565b82525050565b6000613a7c82856136bd565b9150613a888284613a59565b6001820191508190509392505050565b600081519050919050565b600081905092915050565b6000613ab982613a98565b613ac38185613aa3565b9350613ad3818560208601613693565b80840191505092915050565b6000613aeb828b6136bd565b9150613af7828a613590565b602082019150613b078289613590565b602082019150613b178288613a59565b600182019150613b278287613a59565b600182019150613b378286613a59565b600182019150613b478285613aae565b9150613b538284613a59565b6001820191508190509998505050505050505050565b6000613b7582846136bd565b915081905092915050565b6000819050919050565b613b9381613b80565b8114613b9e57600080fd5b50565b600081519050613bb081613b8a565b92915050565b600060208284031215613bcc57613bcb61325b565b5b6000613bda84828501613ba1565b91505092915050565b6000819050919050565b613bfe613bf982613b80565b613be3565b82525050565b6000613c108287613bed565b602082019150613c208286613a59565b600182019150613c308285613aae565b9150613c3c8284613a59565b60018201915081905095945050505050565b6000613c5a8284613a59565b60018201915081905092915050565b6000613c7582876136bd565b9150613c818286613a59565b600182019150613c918285613aae565b9150613c9d8284613a59565b6001820191508190509594505050505056fea26469706673582212207a0357ed8f715b7512d712b7fb294fbb965ce4b7a0242bb5cb2162a49076238b64736f6c63430008130033 \ No newline at end of file diff --git a/backend/plonk/bn254/solidity/abi/Utils.abi b/backend/plonk/bn254/solidity/abi/Utils.abi new file mode 100644 index 0000000000..b40276e015 --- /dev/null +++ b/backend/plonk/bn254/solidity/abi/Utils.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"name":"expand_msg","outputs":[{"internalType":"uint8[48]","name":"res","type":"uint8[48]"}],"stateMutability":"pure","type":"function"}] \ No newline at end of file diff --git a/backend/plonk/bn254/solidity/abi/Utils.bin b/backend/plonk/bn254/solidity/abi/Utils.bin new file mode 100644 index 0000000000..63de1980ce --- /dev/null +++ b/backend/plonk/bn254/solidity/abi/Utils.bin @@ -0,0 +1 @@ +6109ad610053600b82828239805160001a607314610046577f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100355760003560e01c806361791d3f1461003a575b600080fd5b610054600480360381019061004f9190610482565b61006a565b604051610061919061057a565b60405180910390f35b610072610424565b60006040518060400160405280600b81526020017f42534232322d506c6f6e6b00000000000000000000000000000000000000000081525090506060600080603090506000600b905060005b60408110156100fe5784846040516020016100da92919061063d565b604051602081830303815290604052945080806100f690610694565b9150506100be565b508388888585878a8760405160200161011e989796959493929190610744565b6040516020818303038152906040529350600060028560405161014191906107ce565b602060405180830381855afa15801561015e573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610181919061081b565b9050806001878460405160200161019b9493929190610869565b604051602081830303815290604052945060006002866040516101be91906107ce565b602060405180830381855afa1580156101db573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906101fe919061081b565b905060005b602081101561025d5781816020811061021f5761021e6108b3565b5b1a60f81b60f81c898260308110610239576102386108b3565b5b602002019060ff16908160ff1681525050808061025590610694565b915050610203565b5080600060208110610272576102716108b3565b5b1a60f81b60f81c8260006020811061028d5761028c6108b3565b5b1a60f81b60f81c186040516020016102a591906108e2565b60405160208183030381529060405295506000600190505b602081101561033157868282602081106102da576102d96108b3565b5b1a60f81b60f81c8483602081106102f4576102f36108b3565b5b1a60f81b60f81c1860405160200161030d92919061063d565b6040516020818303038152906040529650808061032990610694565b9150506102bd565b50856002888560405160200161034a94939291906108fd565b604051602081830303815290604052955060028660405161036b91906107ce565b602060405180830381855afa158015610388573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906103ab919061081b565b905060005b6010811015610416578181602081106103cc576103cb6108b3565b5b1a60f81b60f81c896020836103e19190610943565b603081106103f2576103f16108b3565b5b602002019060ff16908160ff1681525050808061040e90610694565b9150506103b0565b505050505050505092915050565b604051806106000160405280603090602082028036833780820191505090505090565b600080fd5b6000819050919050565b61045f8161044c565b811461046a57600080fd5b50565b60008135905061047c81610456565b92915050565b6000806040838503121561049957610498610447565b5b60006104a78582860161046d565b92505060206104b88582860161046d565b9150509250929050565b600060309050919050565b600081905092915050565b6000819050919050565b600060ff82169050919050565b6104f8816104e2565b82525050565b600061050a83836104ef565b60208301905092915050565b6000602082019050919050565b61052c816104c2565b61053681846104cd565b9250610541826104d8565b8060005b8381101561057257815161055987826104fe565b965061056483610516565b925050600181019050610545565b505050505050565b6000610600820190506105906000830184610523565b92915050565b600081519050919050565b600081905092915050565b60005b838110156105ca5780820151818401526020810190506105af565b60008484015250505050565b60006105e182610596565b6105eb81856105a1565b93506105fb8185602086016105ac565b80840191505092915050565b60008160f81b9050919050565b600061061f82610607565b9050919050565b610637610632826104e2565b610614565b82525050565b600061064982856105d6565b91506106558284610626565b6001820191508190509392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061069f8261044c565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036106d1576106d0610665565b5b600182019050919050565b6000819050919050565b6106f76106f28261044c565b6106dc565b82525050565b600081519050919050565b600081905092915050565b600061071e826106fd565b6107288185610708565b93506107388185602086016105ac565b80840191505092915050565b6000610750828b6105d6565b915061075c828a6106e6565b60208201915061076c82896106e6565b60208201915061077c8288610626565b60018201915061078c8287610626565b60018201915061079c8286610626565b6001820191506107ac8285610713565b91506107b88284610626565b6001820191508190509998505050505050505050565b60006107da82846105d6565b915081905092915050565b6000819050919050565b6107f8816107e5565b811461080357600080fd5b50565b600081519050610815816107ef565b92915050565b60006020828403121561083157610830610447565b5b600061083f84828501610806565b91505092915050565b6000819050919050565b61086361085e826107e5565b610848565b82525050565b60006108758287610852565b6020820191506108858286610626565b6001820191506108958285610713565b91506108a18284610626565b60018201915081905095945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006108ee8284610626565b60018201915081905092915050565b600061090982876105d6565b91506109158286610626565b6001820191506109258285610713565b91506109318284610626565b60018201915081905095945050505050565b600061094e8261044c565b91506109598361044c565b925082820190508082111561097157610970610665565b5b9291505056fea2646970667358221220ab9f64a55486844e4be79b30ff50d67695be004f9b72b71161c3207c615115d164736f6c63430008130033 \ No newline at end of file diff --git a/backend/plonk/bn254/tips.txt b/backend/plonk/bn254/tips.txt new file mode 100644 index 0000000000..75e4164e4e --- /dev/null +++ b/backend/plonk/bn254/tips.txt @@ -0,0 +1 @@ +- got rid of arrays for G2 points diff --git a/backend/plonk/bn254/to_delete.go b/backend/plonk/bn254/to_delete.go new file mode 100644 index 0000000000..a167275283 --- /dev/null +++ b/backend/plonk/bn254/to_delete.go @@ -0,0 +1,378 @@ +package plonk + +import ( + "errors" + "hash" + "math/big" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" +) + +var ( + ErrInvalidNbDigests = errors.New("number of digests is not the same as the number of polynomials") + ErrZeroNbDigests = errors.New("number of digests is zero") + ErrInvalidPolynomialSize = errors.New("invalid polynomial size (larger than SRS or == 0)") + ErrVerifyKzgOpeningProof = errors.New("can't verify opening proof") + ErrVerifyKzgBatchOpeningSinglePoint = errors.New("can't verify batch opening proof at single point") + ErrMinSRSSize = errors.New("minimum srs size is 2") +) + +// Digest commitment of a polynomial. +type Digest = bn254.G1Affine + +// KzgProvingKey used to create or open commitments +type KzgProvingKey struct { + G1 []bn254.G1Affine // [G₁ [α]G₁ , [α²]G₁, ... ] +} + +// KzgVerificationKey used to verify opening proofs +type KzgVerificationKey struct { + G2 [2]bn254.G2Affine // [G₂, [α]G₂ ] + G1 bn254.G1Affine +} + +// SRS must be computed through MPC and comprises the KzgProvingKey and the KzgVerificationKey +type SRS struct { + Pk KzgProvingKey + Vk KzgVerificationKey +} + +// TODO @Tabaie get rid of this and use the polynomial package +// eval returns p(point) where p is interpreted as a polynomial +// ∑_{i= 0; i-- { + res.Mul(&res, &point).Add(&res, &p[i]) + } + return res +} + +// NewSRS returns a new SRS using alpha as randomness source +// +// In production, a SRS generated through MPC should be used. +// +// implements io.ReaderFrom and io.WriterTo +func NewSRS(size uint64, bAlpha *big.Int) (*SRS, error) { + + if size < 2 { + return nil, ErrMinSRSSize + } + var srs SRS + srs.Pk.G1 = make([]bn254.G1Affine, size) + + var alpha fr.Element + alpha.SetBigInt(bAlpha) + + _, _, gen1Aff, gen2Aff := bn254.Generators() + srs.Pk.G1[0] = gen1Aff + srs.Vk.G1 = gen1Aff + srs.Vk.G2[0] = gen2Aff + srs.Vk.G2[1].ScalarMultiplication(&gen2Aff, bAlpha) + + alphas := make([]fr.Element, size-1) + alphas[0] = alpha + for i := 1; i < len(alphas); i++ { + alphas[i].Mul(&alphas[i-1], &alpha) + } + g1s := bn254.BatchScalarMultiplicationG1(&gen1Aff, alphas) + copy(srs.Pk.G1[1:], g1s) + + return &srs, nil +} + +// OpeningProof KZG proof for opening at a single point. +// +// implements io.ReaderFrom and io.WriterTo +type OpeningProof struct { + // H quotient polynomial (f - f(z))/(x-z) + H bn254.G1Affine + + // ClaimedValue purported value + ClaimedValue fr.Element +} + +// BatchOpeningProof opening proof for many polynomials at the same point +// +// implements io.ReaderFrom and io.WriterTo +type BatchOpeningProof struct { + // H quotient polynomial Sum_i gamma**i*(f - f(z))/(x-z) + H bn254.G1Affine + + // ClaimedValues purported values + ClaimedValues []fr.Element +} + +// VerifyKzg verifies a KZG opening proof at a single point +func VerifyKzg(commitment *Digest, proof *OpeningProof, point fr.Element, vk KzgVerificationKey) error { + + // [f(a)]G₁ + var claimedValueG1Aff bn254.G1Jac + var claimedValueBigInt big.Int + proof.ClaimedValue.BigInt(&claimedValueBigInt) + claimedValueG1Aff.ScalarMultiplicationAffine(&vk.G1, &claimedValueBigInt) + + // [f(α) - f(a)]G₁ + var fminusfaG1Jac bn254.G1Jac + fminusfaG1Jac.FromAffine(commitment) + fminusfaG1Jac.SubAssign(&claimedValueG1Aff) + + // [-H(α)]G₁ + var negH bn254.G1Affine + negH.Neg(&proof.H) + + // [f(α) - f(a) + a*H(α)]G₁ + var totalG1 bn254.G1Jac + var pointBigInt big.Int + point.BigInt(&pointBigInt) + totalG1.ScalarMultiplicationAffine(&proof.H, &pointBigInt) + totalG1.AddAssign(&fminusfaG1Jac) + var totalG1Aff bn254.G1Affine + totalG1Aff.FromJacobian(&totalG1) + + // e([f(α)-f(a)+aH(α)]G₁], G₂).e([-H(α)]G₁, [α]G₂) == 1 + check, err := bn254.PairingCheck( + []bn254.G1Affine{totalG1Aff, negH}, + []bn254.G2Affine{vk.G2[0], vk.G2[1]}, + ) + if err != nil { + return err + } + if !check { + return ErrVerifyKzgOpeningProof + } + return nil +} + +// FoldProof fold the digests and the proofs in batchOpeningProof using Fiat Shamir +// to obtain an opening proof at a single point. +// +// * digests list of digests on which batchOpeningProof is based +// * batchOpeningProof opening proof of digests +// * returns the folded version of batchOpeningProof, Digest, the folded version of digests +func FoldProof(digests []Digest, batchOpeningProof *BatchOpeningProof, point fr.Element, hf hash.Hash) (OpeningProof, Digest, error) { + + nbDigests := len(digests) + + // check consistency between numbers of claims vs number of digests + if nbDigests != len(batchOpeningProof.ClaimedValues) { + return OpeningProof{}, Digest{}, ErrInvalidNbDigests + } + + // derive the challenge γ, binded to the point and the commitments + gamma, err := deriveGamma(point, digests, batchOpeningProof.ClaimedValues, hf) + if err != nil { + return OpeningProof{}, Digest{}, ErrInvalidNbDigests + } + + // fold the claimed values and digests + // gammai = [1,γ,γ²,..,γⁿ⁻¹] + gammai := make([]fr.Element, nbDigests) + gammai[0].SetOne() + if nbDigests > 1 { + gammai[1] = gamma + } + for i := 2; i < nbDigests; i++ { + gammai[i].Mul(&gammai[i-1], &gamma) + } + + foldedDigests, foldedEvaluations, err := fold(digests, batchOpeningProof.ClaimedValues, gammai) + if err != nil { + return OpeningProof{}, Digest{}, err + } + + // create the folded opening proof + var res OpeningProof + res.ClaimedValue.Set(&foldedEvaluations) + res.H.Set(&batchOpeningProof.H) + + return res, foldedDigests, nil +} + +// BatchVerifyKzgSinglePoint verifies a batched opening proof at a single point of a list of polynomials. +// +// * digests list of digests on which opening proof is done +// * batchOpeningProof proof of correct opening on the digests +func BatchVerifyKzgSinglePoint(digests []Digest, batchOpeningProof *BatchOpeningProof, point fr.Element, hf hash.Hash, vk KzgVerificationKey) error { + + // fold the proof + foldedProof, foldedDigest, err := FoldProof(digests, batchOpeningProof, point, hf) + if err != nil { + return err + } + + // verify the foldedProof against the foldedDigest + err = VerifyKzg(&foldedDigest, &foldedProof, point, vk) + return err + +} + +// BatchVerifyKzgMultiPoints batch verifies a list of opening proofs at different points. +// The purpose of the batching is to have only one pairing for verifying several proofs. +// +// * digests list of committed polynomials +// * proofs list of opening proofs, one for each digest +// * points the list of points at which the opening are done +func BatchVerifyKzgMultiPoints(digests []Digest, proofs []OpeningProof, points []fr.Element, vk KzgVerificationKey) error { + + // check consistency nb proogs vs nb digests + if len(digests) != len(proofs) || len(digests) != len(points) { + return ErrInvalidNbDigests + } + + // len(digests) should be nonzero because of randomNumbers + if len(digests) == 0 { + return ErrZeroNbDigests + } + + // if only one digest, call VerifyKzg + if len(digests) == 1 { + return VerifyKzg(&digests[0], &proofs[0], points[0], vk) + } + + // sample random numbers λᵢ for sampling + randomNumbers := make([]fr.Element, len(digests)) + randomNumbers[0].SetOne() + for i := 1; i < len(randomNumbers); i++ { + // _, err := randomNumbers[i].SetRandom() + // if err != nil { + // return err + // } + randomNumbers[i].SetUint64(3) + } + + // fold the committed quotients compute ∑ᵢλᵢ[Hᵢ(α)]G₁ + var foldedQuotients bn254.G1Affine + quotients := make([]bn254.G1Affine, len(proofs)) + for i := 0; i < len(randomNumbers); i++ { + quotients[i].Set(&proofs[i].H) + } + config := ecc.MultiExpConfig{} + if _, err := foldedQuotients.MultiExp(quotients, randomNumbers, config); err != nil { + return err + } + + // fold digests and evals + // proofs[1].ClaimedValue.SetZero() + evals := make([]fr.Element, len(digests)) + for i := 0; i < len(randomNumbers); i++ { + evals[i].Set(&proofs[i].ClaimedValue) + } + + // fold the digests: ∑ᵢλᵢ[f_i(α)]G₁ + // fold the evals : ∑ᵢλᵢfᵢ(aᵢ) + foldedDigests, foldedEvals, err := fold(digests, evals, randomNumbers) + if err != nil { + return err + } + + // compute commitment to folded Eval [∑ᵢλᵢfᵢ(aᵢ)]G₁ + var foldedEvalsCommit bn254.G1Affine + var foldedEvalsBigInt big.Int + foldedEvals.BigInt(&foldedEvalsBigInt) + foldedEvalsCommit.ScalarMultiplication(&vk.G1, &foldedEvalsBigInt) + + // compute foldedDigests = ∑ᵢλᵢ[fᵢ(α)]G₁ - [∑ᵢλᵢfᵢ(aᵢ)]G₁ + foldedDigests.Sub(&foldedDigests, &foldedEvalsCommit) + + // combien the points and the quotients using γᵢ + // ∑ᵢλᵢ[p_i]([Hᵢ(α)]G₁) + var foldedPointsQuotients bn254.G1Affine + for i := 0; i < len(randomNumbers); i++ { + randomNumbers[i].Mul(&randomNumbers[i], &points[i]) + } + _, err = foldedPointsQuotients.MultiExp(quotients, randomNumbers, config) + if err != nil { + return err + } + + // ∑ᵢλᵢ[f_i(α)]G₁ - [∑ᵢλᵢfᵢ(aᵢ)]G₁ + ∑ᵢλᵢ[p_i]([Hᵢ(α)]G₁) + // = [∑ᵢλᵢf_i(α) - ∑ᵢλᵢfᵢ(aᵢ) + ∑ᵢλᵢpᵢHᵢ(α)]G₁ + foldedDigests.Add(&foldedDigests, &foldedPointsQuotients) + + // -∑ᵢλᵢ[Qᵢ(α)]G₁ + foldedQuotients.Neg(&foldedQuotients) + + // fmt.Println(foldedDigests.String()) + foldedDigests.X.SetString("9580734902255794050927938530373971926002234939716450249429720642097067006115") + foldedDigests.Y.SetString("3278335512197874161585664087513619970054206473530059271941844570397867805823") + + // pairing check + // e([∑ᵢλᵢ(fᵢ(α) - fᵢ(pᵢ) + pᵢHᵢ(α))]G₁, G₂).e([-∑ᵢλᵢ[Hᵢ(α)]G₁), [α]G₂) + check, err := bn254.PairingCheck( + []bn254.G1Affine{foldedDigests, foldedQuotients}, + []bn254.G2Affine{vk.G2[0], vk.G2[1]}, + ) + if err != nil { + return err + } + if !check { + return ErrVerifyKzgOpeningProof + } + return nil + +} + +// fold folds digests and evaluations using the list of factors as random numbers. +// +// * digests list of digests to fold +// * evaluations list of evaluations to fold +// * factors list of multiplicative factors used for the folding (in Montgomery form) +// +// * Returns ∑ᵢcᵢdᵢ, ∑ᵢcᵢf(aᵢ) +func fold(di []Digest, fai []fr.Element, ci []fr.Element) (Digest, fr.Element, error) { + + // length inconsistency between digests and evaluations should have been done before calling this function + nbDigests := len(di) + + // fold the claimed values ∑ᵢcᵢf(aᵢ) + var foldedEvaluations, tmp fr.Element + for i := 0; i < nbDigests; i++ { + tmp.Mul(&fai[i], &ci[i]) + foldedEvaluations.Add(&foldedEvaluations, &tmp) + } + + // fold the digests ∑ᵢ[cᵢ]([fᵢ(α)]G₁) + var foldedDigests Digest + _, err := foldedDigests.MultiExp(di, ci, ecc.MultiExpConfig{}) + if err != nil { + return foldedDigests, foldedEvaluations, err + } + + // folding done + return foldedDigests, foldedEvaluations, nil + +} + +// deriveGamma derives a challenge using Fiat Shamir to fold proofs. +func deriveGamma(point fr.Element, digests []Digest, claimedValues []fr.Element, hf hash.Hash) (fr.Element, error) { + + // derive the challenge gamma, binded to the point and the commitments + fs := fiatshamir.NewTranscript(hf, "gamma") + if err := fs.Bind("gamma", point.Marshal()); err != nil { + return fr.Element{}, err + } + for i := range digests { + if err := fs.Bind("gamma", digests[i].Marshal()); err != nil { + return fr.Element{}, err + } + } + for i := range claimedValues { + if err := fs.Bind("gamma", claimedValues[i].Marshal()); err != nil { + return fr.Element{}, err + } + } + gammaByte, err := fs.ComputeChallenge("gamma") + if err != nil { + return fr.Element{}, err + } + var gamma fr.Element + gamma.SetBytes(gammaByte) + + return gamma, nil +} diff --git a/backend/plonk/bn254/verify.go b/backend/plonk/bn254/verify.go index 231469dd56..c0306b93cf 100644 --- a/backend/plonk/bn254/verify.go +++ b/backend/plonk/bn254/verify.go @@ -139,6 +139,9 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue + // qC := make([]fr.Element, len(proof.Bsb22Commitments)) + // claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] + // claimedValues := proof.BatchedProof.ClaimedValues[7:] claimedQuotient := proof.BatchedProof.ClaimedValues[0] linearizedPolynomialZeta := proof.BatchedProof.ClaimedValues[1] l := proof.BatchedProof.ClaimedValues[2] @@ -232,7 +235,6 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { // Fold the first proof digestsToFold := make([]curve.G1Affine, len(vk.Qcp)+7) copy(digestsToFold[7:], vk.Qcp) - // offset := len(vk.Qcp) digestsToFold[0] = foldedH digestsToFold[1] = linearizedPolynomialDigest digestsToFold[2] = proof.LRO[0] @@ -250,7 +252,6 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } - // Batch verify var shiftedZeta fr.Element shiftedZeta.Mul(&zeta, &vk.Generator) diff --git a/backend/plonk/bw6-633/prove.go b/backend/plonk/bw6-633/prove.go index 4155f7dc5f..ac9cf966e2 100644 --- a/backend/plonk/bw6-633/prove.go +++ b/backend/plonk/bw6-633/prove.go @@ -508,25 +508,32 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts <-computeFoldedH // Batch open the first list of polynomials + polysQcp := coefficients(pk.trace.Qcp) + polysToOpen := make([][]fr.Element, 7+len(polysQcp)) + copy(polysToOpen[7:], polysQcp) + // offset := len(polysQcp) + polysToOpen[0] = foldedH + polysToOpen[1] = linearizedPolynomialCanonical + polysToOpen[2] = bwliop.Coefficients()[:bwliop.BlindedSize()] + polysToOpen[3] = bwriop.Coefficients()[:bwriop.BlindedSize()] + polysToOpen[4] = bwoiop.Coefficients()[:bwoiop.BlindedSize()] + polysToOpen[5] = pk.trace.S1.Coefficients() + polysToOpen[6] = pk.trace.S2.Coefficients() + + digestsToOpen := make([]curve.G1Affine, len(pk.Vk.Qcp)+7) + copy(digestsToOpen[7:], pk.Vk.Qcp) + // offset = len(pk.Vk.Qcp) + digestsToOpen[0] = foldedHDigest + digestsToOpen[1] = linearizedPolynomialDigest + digestsToOpen[2] = proof.LRO[0] + digestsToOpen[3] = proof.LRO[1] + digestsToOpen[4] = proof.LRO[2] + digestsToOpen[5] = pk.Vk.S[0] + digestsToOpen[6] = pk.Vk.S[1] + proof.BatchedProof, err = kzg.BatchOpenSinglePoint( - append(coefficients(pk.trace.Qcp), - foldedH, - linearizedPolynomialCanonical, - bwliop.Coefficients()[:bwliop.BlindedSize()], - bwriop.Coefficients()[:bwriop.BlindedSize()], - bwoiop.Coefficients()[:bwoiop.BlindedSize()], - pk.trace.S1.Coefficients(), - pk.trace.S2.Coefficients(), - ), - append(pk.Vk.Qcp, - foldedHDigest, - linearizedPolynomialDigest, - proof.LRO[0], - proof.LRO[1], - proof.LRO[2], - pk.Vk.S[0], - pk.Vk.S[1], - ), + polysToOpen, + digestsToOpen, zeta, hFunc, pk.Kzg, diff --git a/backend/plonk/bw6-633/verify.go b/backend/plonk/bw6-633/verify.go index 8f9c361479..6cf76e2252 100644 --- a/backend/plonk/bw6-633/verify.go +++ b/backend/plonk/bw6-633/verify.go @@ -39,7 +39,7 @@ var ( ) func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { - log := logger.Logger().With().Str("curve", "bw6_633").Str("backend", "plonk").Logger() + log := logger.Logger().With().Str("curve", "bw6-633").Str("backend", "plonk").Logger() start := time.Now() // pick a hash function to derive the challenge (the same as in the prover) @@ -137,16 +137,16 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - qC := make([]fr.Element, len(proof.Bsb22Commitments)) - copy(qC, proof.BatchedProof.ClaimedValues) - claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] - claimedQuotient := claimedValues[0] - linearizedPolynomialZeta := claimedValues[1] - l := claimedValues[2] - r := claimedValues[3] - o := claimedValues[4] - s1 := claimedValues[5] - s2 := claimedValues[6] + // qC := make([]fr.Element, len(proof.Bsb22Commitments)) + // claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] + // claimedValues := proof.BatchedProof.ClaimedValues[7:] + claimedQuotient := proof.BatchedProof.ClaimedValues[0] + linearizedPolynomialZeta := proof.BatchedProof.ClaimedValues[1] + l := proof.BatchedProof.ClaimedValues[2] + r := proof.BatchedProof.ClaimedValues[3] + o := proof.BatchedProof.ClaimedValues[4] + s1 := proof.BatchedProof.ClaimedValues[5] + s2 := proof.BatchedProof.ClaimedValues[6] _s1.Mul(&s1, &beta).Add(&_s1, &l).Add(&_s1, &gamma) // (l(ζ)+β*s1(ζ)+γ) _s2.Mul(&s2, &beta).Add(&_s2, &r).Add(&_s2, &gamma) // (r(ζ)+β*s2(ζ)+γ) @@ -220,6 +220,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { vk.S[2], proof.Z, // second & third part ) + qC := make([]fr.Element, len(proof.Bsb22Commitments)) + copy(qC, proof.BatchedProof.ClaimedValues[7:]) scalars := append(qC, l, r, rl, o, one, /* TODO Perf @Tabaie Consider just adding Qk instead */ // first part _s1, _s2, // second & third part @@ -229,15 +231,17 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } // Fold the first proof - foldedProof, foldedDigest, err := kzg.FoldProof(append(vk.Qcp, - foldedH, - linearizedPolynomialDigest, - proof.LRO[0], - proof.LRO[1], - proof.LRO[2], - vk.S[0], - vk.S[1], - ), + digestsToFold := make([]curve.G1Affine, len(vk.Qcp)+7) + copy(digestsToFold[7:], vk.Qcp) + digestsToFold[0] = foldedH + digestsToFold[1] = linearizedPolynomialDigest + digestsToFold[2] = proof.LRO[0] + digestsToFold[3] = proof.LRO[1] + digestsToFold[4] = proof.LRO[2] + digestsToFold[5] = vk.S[0] + digestsToFold[6] = vk.S[1] + foldedProof, foldedDigest, err := kzg.FoldProof( + digestsToFold, &proof.BatchedProof, zeta, hFunc, diff --git a/backend/plonk/bw6-761/prove.go b/backend/plonk/bw6-761/prove.go index d8e147ea0a..340a301ea5 100644 --- a/backend/plonk/bw6-761/prove.go +++ b/backend/plonk/bw6-761/prove.go @@ -508,25 +508,32 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts <-computeFoldedH // Batch open the first list of polynomials + polysQcp := coefficients(pk.trace.Qcp) + polysToOpen := make([][]fr.Element, 7+len(polysQcp)) + copy(polysToOpen[7:], polysQcp) + // offset := len(polysQcp) + polysToOpen[0] = foldedH + polysToOpen[1] = linearizedPolynomialCanonical + polysToOpen[2] = bwliop.Coefficients()[:bwliop.BlindedSize()] + polysToOpen[3] = bwriop.Coefficients()[:bwriop.BlindedSize()] + polysToOpen[4] = bwoiop.Coefficients()[:bwoiop.BlindedSize()] + polysToOpen[5] = pk.trace.S1.Coefficients() + polysToOpen[6] = pk.trace.S2.Coefficients() + + digestsToOpen := make([]curve.G1Affine, len(pk.Vk.Qcp)+7) + copy(digestsToOpen[7:], pk.Vk.Qcp) + // offset = len(pk.Vk.Qcp) + digestsToOpen[0] = foldedHDigest + digestsToOpen[1] = linearizedPolynomialDigest + digestsToOpen[2] = proof.LRO[0] + digestsToOpen[3] = proof.LRO[1] + digestsToOpen[4] = proof.LRO[2] + digestsToOpen[5] = pk.Vk.S[0] + digestsToOpen[6] = pk.Vk.S[1] + proof.BatchedProof, err = kzg.BatchOpenSinglePoint( - append(coefficients(pk.trace.Qcp), - foldedH, - linearizedPolynomialCanonical, - bwliop.Coefficients()[:bwliop.BlindedSize()], - bwriop.Coefficients()[:bwriop.BlindedSize()], - bwoiop.Coefficients()[:bwoiop.BlindedSize()], - pk.trace.S1.Coefficients(), - pk.trace.S2.Coefficients(), - ), - append(pk.Vk.Qcp, - foldedHDigest, - linearizedPolynomialDigest, - proof.LRO[0], - proof.LRO[1], - proof.LRO[2], - pk.Vk.S[0], - pk.Vk.S[1], - ), + polysToOpen, + digestsToOpen, zeta, hFunc, pk.Kzg, diff --git a/backend/plonk/bw6-761/verify.go b/backend/plonk/bw6-761/verify.go index f9b2dad361..57e511abf0 100644 --- a/backend/plonk/bw6-761/verify.go +++ b/backend/plonk/bw6-761/verify.go @@ -39,7 +39,7 @@ var ( ) func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { - log := logger.Logger().With().Str("curve", "bw6_761").Str("backend", "plonk").Logger() + log := logger.Logger().With().Str("curve", "bw6-761").Str("backend", "plonk").Logger() start := time.Now() // pick a hash function to derive the challenge (the same as in the prover) @@ -137,16 +137,16 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - qC := make([]fr.Element, len(proof.Bsb22Commitments)) - copy(qC, proof.BatchedProof.ClaimedValues) - claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] - claimedQuotient := claimedValues[0] - linearizedPolynomialZeta := claimedValues[1] - l := claimedValues[2] - r := claimedValues[3] - o := claimedValues[4] - s1 := claimedValues[5] - s2 := claimedValues[6] + // qC := make([]fr.Element, len(proof.Bsb22Commitments)) + // claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] + // claimedValues := proof.BatchedProof.ClaimedValues[7:] + claimedQuotient := proof.BatchedProof.ClaimedValues[0] + linearizedPolynomialZeta := proof.BatchedProof.ClaimedValues[1] + l := proof.BatchedProof.ClaimedValues[2] + r := proof.BatchedProof.ClaimedValues[3] + o := proof.BatchedProof.ClaimedValues[4] + s1 := proof.BatchedProof.ClaimedValues[5] + s2 := proof.BatchedProof.ClaimedValues[6] _s1.Mul(&s1, &beta).Add(&_s1, &l).Add(&_s1, &gamma) // (l(ζ)+β*s1(ζ)+γ) _s2.Mul(&s2, &beta).Add(&_s2, &r).Add(&_s2, &gamma) // (r(ζ)+β*s2(ζ)+γ) @@ -220,6 +220,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { vk.S[2], proof.Z, // second & third part ) + qC := make([]fr.Element, len(proof.Bsb22Commitments)) + copy(qC, proof.BatchedProof.ClaimedValues[7:]) scalars := append(qC, l, r, rl, o, one, /* TODO Perf @Tabaie Consider just adding Qk instead */ // first part _s1, _s2, // second & third part @@ -229,15 +231,17 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } // Fold the first proof - foldedProof, foldedDigest, err := kzg.FoldProof(append(vk.Qcp, - foldedH, - linearizedPolynomialDigest, - proof.LRO[0], - proof.LRO[1], - proof.LRO[2], - vk.S[0], - vk.S[1], - ), + digestsToFold := make([]curve.G1Affine, len(vk.Qcp)+7) + copy(digestsToFold[7:], vk.Qcp) + digestsToFold[0] = foldedH + digestsToFold[1] = linearizedPolynomialDigest + digestsToFold[2] = proof.LRO[0] + digestsToFold[3] = proof.LRO[1] + digestsToFold[4] = proof.LRO[2] + digestsToFold[5] = vk.S[0] + digestsToFold[6] = vk.S[1] + foldedProof, foldedDigest, err := kzg.FoldProof( + digestsToFold, &proof.BatchedProof, zeta, hFunc, diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl index 7a2d582ce9..c0b9d4caf0 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl @@ -20,7 +20,7 @@ var ( ) func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { - log := logger.Logger().With().Str("curve", "{{ toLower .CurveID }}").Str("backend", "plonk").Logger() + log := logger.Logger().With().Str("curve", "{{ toLower .Curve }}").Str("backend", "plonk").Logger() start := time.Now() // pick a hash function to derive the challenge (the same as in the prover) @@ -103,10 +103,10 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { den.Sub(&zeta, &wPowI) // ζ-wⁱ lagrange.SetOne(). - Sub(&zeta, &lagrange). // ζ-1 - Mul(&lagrange, &wPowI). // wⁱ(ζ-1) - Div(&lagrange, &den). // wⁱ(ζ-1)/(ζ-wⁱ) - Mul(&lagrange, &lagrangeOne) // wⁱ/n (ζⁿ-1)/(ζ-wⁱ) + Sub(&zeta, &lagrange). // ζ-1 + Mul(&lagrange, &wPowI). // wⁱ(ζ-1) + Div(&lagrange, &den). // wⁱ(ζ-1)/(ζ-wⁱ) + Mul(&lagrange, &lagrangeOne) // wⁱ/n (ζⁿ-1)/(ζ-wⁱ) xiLi.Mul(&lagrange, &hashRes[0]) pi.Add(&pi, &xiLi) @@ -118,16 +118,16 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - qC := make([]fr.Element, len(proof.Bsb22Commitments)) - copy(qC, proof.BatchedProof.ClaimedValues) - claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] - claimedQuotient := claimedValues[0] - linearizedPolynomialZeta := claimedValues[1] - l := claimedValues[2] - r := claimedValues[3] - o := claimedValues[4] - s1 := claimedValues[5] - s2 := claimedValues[6] + // qC := make([]fr.Element, len(proof.Bsb22Commitments)) + // claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] + // claimedValues := proof.BatchedProof.ClaimedValues[7:] + claimedQuotient := proof.BatchedProof.ClaimedValues[0] + linearizedPolynomialZeta := proof.BatchedProof.ClaimedValues[1] + l := proof.BatchedProof.ClaimedValues[2] + r := proof.BatchedProof.ClaimedValues[3] + o := proof.BatchedProof.ClaimedValues[4] + s1 := proof.BatchedProof.ClaimedValues[5] + s2 := proof.BatchedProof.ClaimedValues[6] _s1.Mul(&s1, &beta).Add(&_s1, &l).Add(&_s1, &gamma) // (l(ζ)+β*s1(ζ)+γ) _s2.Mul(&s2, &beta).Add(&_s2, &r).Add(&_s2, &gamma) // (r(ζ)+β*s2(ζ)+γ) @@ -201,8 +201,10 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { vk.S[2], proof.Z, // second & third part ) + qC := make([]fr.Element, len(proof.Bsb22Commitments)) + copy(qC, proof.BatchedProof.ClaimedValues[7:]) scalars := append(qC, - l, r, rl, o, one /* TODO Perf @Tabaie Consider just adding Qk instead */, // first part + l, r, rl, o, one, /* TODO Perf @Tabaie Consider just adding Qk instead */ // first part _s1, _s2, // second & third part ) if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{}); err != nil { @@ -210,15 +212,17 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } // Fold the first proof - foldedProof, foldedDigest, err := kzg.FoldProof(append(vk.Qcp, - foldedH, - linearizedPolynomialDigest, - proof.LRO[0], - proof.LRO[1], - proof.LRO[2], - vk.S[0], - vk.S[1], - ), + digestsToFold := make([]curve.G1Affine, len(vk.Qcp)+7) + copy(digestsToFold[7:], vk.Qcp) + digestsToFold[0] = foldedH + digestsToFold[1] = linearizedPolynomialDigest + digestsToFold[2] = proof.LRO[0] + digestsToFold[3] = proof.LRO[1] + digestsToFold[4] = proof.LRO[2] + digestsToFold[5] = vk.S[0] + digestsToFold[6] = vk.S[1] + foldedProof, foldedDigest, err := kzg.FoldProof( + digestsToFold, &proof.BatchedProof, zeta, hFunc, @@ -318,6 +322,7 @@ func deriveRandomness(fs *fiatshamir.Transcript, challenge string, points ...*cu return r, nil } + {{if eq .Curve "BN254"}} // ExportSolidity exports the verifying key to a solidity smart contract. // From 274c883477ec050db60e0c86b87dca0402dda439 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 18 May 2023 15:25:17 +0200 Subject: [PATCH 368/464] fix: init elements in arrays and slices if have init hook (#695) * test: implement witness assignment test with init hook * fix: init array and slice elements if initable * test: add new schema with initable elements * fix: init array and slice elements if initable --- backend/witness/witness_test.go | 31 +++++++++++++++++++++++++++++++ frontend/schema/schema.go | 6 +++++- frontend/schema/schema_test.go | 25 +++++++++++++++++++++++++ frontend/schema/walk.go | 19 +++++++++++++++---- 4 files changed, 76 insertions(+), 5 deletions(-) diff --git a/backend/witness/witness_test.go b/backend/witness/witness_test.go index d7feca17a4..40446abe81 100644 --- a/backend/witness/witness_test.go +++ b/backend/witness/witness_test.go @@ -156,3 +156,34 @@ func roundTripMarshalJSON(assert *require.Assertions, assignment circuit, public assert.True(reflect.DeepEqual(rw, w), "witness json round trip serialization") } + +type initableVariable struct { + Val []frontend.Variable +} + +func (iv *initableVariable) GnarkInitHook() { + if iv.Val == nil { + iv.Val = []frontend.Variable{1, 2} // need to init value as are assigning to witness + } +} + +type initableCircuit struct { + X [2]initableVariable + Y []initableVariable + Z initableVariable +} + +func (c *initableCircuit) Define(api frontend.API) error { + panic("not called") +} + +func TestVariableInitHook(t *testing.T) { + assert := require.New(t) + + assignment := &initableCircuit{Y: make([]initableVariable, 2)} + w, err := frontend.NewWitness(assignment, ecc.BN254.ScalarField()) + assert.NoError(err) + fw, ok := w.Vector().(fr.Vector) + assert.True(ok) + assert.Len(fw, 10, "invalid length") +} diff --git a/frontend/schema/schema.go b/frontend/schema/schema.go index 0f41a7ad22..f2903ba65a 100644 --- a/frontend/schema/schema.go +++ b/frontend/schema/schema.go @@ -361,7 +361,11 @@ func parse(r []Field, input interface{}, target reflect.Type, parentFullName, pa val := tValue.Index(j) if val.CanAddr() && val.Addr().CanInterface() { fqn := getFullName(parentFullName, strconv.Itoa(j), "") - subFields, err = parse(subFields, val.Addr().Interface(), target, fqn, fqn, parentTagName, parentVisibility, nbPublic, nbSecret) + ival := val.Addr().Interface() + if ih, hasInitHook := ival.(InitHook); hasInitHook { + ih.GnarkInitHook() + } + subFields, err = parse(subFields, ival, target, fqn, fqn, parentTagName, parentVisibility, nbPublic, nbSecret) if err != nil { return nil, err } diff --git a/frontend/schema/schema_test.go b/frontend/schema/schema_test.go index 929f1cbb51..23a3bfb27e 100644 --- a/frontend/schema/schema_test.go +++ b/frontend/schema/schema_test.go @@ -165,6 +165,31 @@ func TestSchemaInherit(t *testing.T) { } } +type initableVariable struct { + Val []variable +} + +func (iv *initableVariable) GnarkInitHook() { + if iv.Val == nil { + iv.Val = make([]variable, 2) + } +} + +type initableCircuit struct { + X [2]initableVariable + Y []initableVariable + Z initableVariable +} + +func TestVariableInitHook(t *testing.T) { + assert := require.New(t) + + witness := &initableCircuit{Y: make([]initableVariable, 2)} + s, err := New(witness, tVariable) + assert.NoError(err) + assert.Equal(s.NbSecret, 10) // X: 2*2, Y: 2*2, Z: 2 +} + func BenchmarkLargeSchema(b *testing.B) { const n1 = 1 << 12 const n2 = 1 << 12 diff --git a/frontend/schema/walk.go b/frontend/schema/walk.go index 07d56b880a..e62a18db0e 100644 --- a/frontend/schema/walk.go +++ b/frontend/schema/walk.go @@ -91,11 +91,23 @@ func (w *walker) Slice(value reflect.Value) error { return nil } -func (w *walker) SliceElem(index int, _ reflect.Value) error { +func (w *walker) arraySliceElem(index int, v reflect.Value) error { w.path.push(LeafInfo{Visibility: w.visibility(), name: strconv.Itoa(index)}) + if v.CanAddr() && v.Addr().CanInterface() { + // TODO @gbotrel don't like that hook, undesirable side effects + // will be hard to detect; (for example calling Parse multiple times will init multiple times!) + value := v.Addr().Interface() + if ih, hasInitHook := value.(InitHook); hasInitHook { + ih.GnarkInitHook() + } + } return nil } +func (w *walker) SliceElem(index int, v reflect.Value) error { + return w.arraySliceElem(index, v) +} + // Array handles array elements found within complex structures. func (w *walker) Array(value reflect.Value) error { if value.Type() == reflect.ArrayOf(value.Len(), w.target) { @@ -103,9 +115,8 @@ func (w *walker) Array(value reflect.Value) error { } return nil } -func (w *walker) ArrayElem(index int, _ reflect.Value) error { - w.path.push(LeafInfo{Visibility: w.visibility(), name: strconv.Itoa(index)}) - return nil +func (w *walker) ArrayElem(index int, v reflect.Value) error { + return w.arraySliceElem(index, v) } // process an array or slice of leaves; since it's quite common to have large array/slices From 10672c8df3bc8da98e39257c3776fa069a71f75f Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 23 May 2023 15:05:01 -0500 Subject: [PATCH 369/464] refactor: end-to-end commitment tests --- frontend/cs/r1cs/api.go | 4 -- test/commitments_test.go | 107 ++++++++++++++++++++++++++++++--------- 2 files changed, 84 insertions(+), 27 deletions(-) diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index 9e71789321..12f0819843 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -677,10 +677,6 @@ func (builder *builder) Compiler() frontend.Compiler { func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error) { - if builder.cs.GetNbCommitments() != 0 { - return nil, errors.New("multi-commits not available for groth16 - yet") - } - // we want to build a sorted slice of committed variables, without duplicates // this is the same algorithm as builder.add(...); but we expect len(v) to be quite large. diff --git a/test/commitments_test.go b/test/commitments_test.go index 4336ef546e..392b4e5378 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -8,6 +8,8 @@ import ( "github.com/consensys/gnark/frontend/cs/scs" "github.com/stretchr/testify/assert" "math/big" + "reflect" + "strings" "testing" "github.com/consensys/gnark/backend/plonk" @@ -31,33 +33,24 @@ func (c *commitmentCircuit) Define(api frontend.API) error { return err } -func (c *commitmentCircuit) hollow() frontend.Circuit { - return &commitmentCircuit{Public: make([]frontend.Variable, len(c.Public)), X: make([]frontend.Variable, len(c.X))} -} - -func TestSingleCommitmentPlonk(t *testing.T) { - assignment := &commitmentCircuit{X: []frontend.Variable{1}, Public: []frontend.Variable{}} - plonkTest(t, assignment.hollow(), assignment) -} - -func TestSingleCommitmentFuzzer(t *testing.T) { +func TestSingleCommitment(t *testing.T) { assignment := &commitmentCircuit{X: []frontend.Variable{1}, Public: []frontend.Variable{}} - NewAssert(t).ProverSucceeded(assignment.hollow(), assignment, WithCurves(ecc.BN254), WithBackends(backend.GROTH16)) // TODO: Make generic + e2eTest(t, assignment) } -func TestFiveCommitmentsPlonk(t *testing.T) { +func TestFiveCommitments(t *testing.T) { assignment := &commitmentCircuit{X: []frontend.Variable{1, 2, 3, 4, 5}, Public: []frontend.Variable{}} - plonkTest(t, assignment.hollow(), assignment) + e2eTest(t, assignment) } -func TestSingleCommitmentSinglePublicPlonk(t *testing.T) { +func TestSingleCommitmentSinglePublic(t *testing.T) { assignment := &commitmentCircuit{X: []frontend.Variable{0}, Public: []frontend.Variable{1}} - plonkTest(t, assignment.hollow(), assignment) + e2eTest(t, assignment) } -func TestFiveCommitmentsFivePublicPlonk(t *testing.T) { +func TestFiveCommitmentsFivePublic(t *testing.T) { assignment := &commitmentCircuit{X: []frontend.Variable{0, 1, 2, 3, 4}, Public: []frontend.Variable{1, 2, 3, 4, 5}} - plonkTest(t, assignment.hollow(), assignment) + e2eTest(t, assignment) } type noCommitmentCircuit struct { @@ -70,8 +63,8 @@ func (c *noCommitmentCircuit) Define(api frontend.API) error { return nil } -func TestNoCommitmentCircuitPlonk(t *testing.T) { - plonkTest(t, &noCommitmentCircuit{}, &noCommitmentCircuit{1}) +func TestNoCommitmentCircuit(t *testing.T) { + e2eTest(t, &noCommitmentCircuit{1}) } var fr = []ecc.ID{ @@ -131,7 +124,7 @@ func (c *committedConstantCircuit) Define(api frontend.API) error { } func TestCommittedConstant(t *testing.T) { - plonkTest(t, &committedConstantCircuit{}, &committedConstantCircuit{1}) + e2eTest(t, &committedConstantCircuit{1}) } type committedPublicCircuit struct { @@ -148,7 +141,7 @@ func (c *committedPublicCircuit) Define(api frontend.API) error { } func TestCommittedPublic(t *testing.T) { - plonkTest(t, &committedPublicCircuit{}, &committedPublicCircuit{1}) + e2eTest(t, &committedPublicCircuit{1}) } func tryCommit(api frontend.API, x ...frontend.Variable) (frontend.Variable, error) { @@ -177,12 +170,80 @@ func (c *twoCommitCircuit) Define(api frontend.API) error { return nil } -func TestTwoCommitEnginePlonk(t *testing.T) { +func TestTwoCommitEngine(t *testing.T) { assignment := &twoCommitCircuit{X: []frontend.Variable{1, 2}, Y: 3} - NewAssert(t).SolvingSucceeded(&twoCommitCircuit{X: make([]frontend.Variable, len(assignment.X))}, assignment, WithBackends(backend.PLONK)) + NewAssert(t).SolvingSucceeded(&twoCommitCircuit{X: make([]frontend.Variable, len(assignment.X))}, assignment, WithBackends(backend.GROTH16, backend.PLONK)) } func TestTwoCommitPlonk(t *testing.T) { assignment := &twoCommitCircuit{X: []frontend.Variable{1, 2}, Y: 3} plonkTest(t, &twoCommitCircuit{X: make([]frontend.Variable, len(assignment.X))}, assignment) } + +func hollow(c frontend.Circuit) frontend.Circuit { + cV := reflect.ValueOf(c).Elem() + t := reflect.TypeOf(c).Elem() + res := reflect.New(t) + resE := res.Elem() + resC := res.Interface().(frontend.Circuit) + + frontendVar := reflect.TypeOf((*frontend.Variable)(nil)).Elem() + + for i := 0; i < t.NumField(); i++ { + fieldT := t.Field(i).Type + if fieldT.Kind() == reflect.Slice && fieldT.Elem().Implements(frontendVar) { + resE.Field(i).Set(reflect.ValueOf(make([]frontend.Variable, cV.Field(i).Len()))) + } else if fieldT != frontendVar { + resE.Field(i).Set(cV.Field(i)) + } + } + + return resC +} + +func removePackageName(s string) string { + return s[strings.LastIndex(s, ".")+1:] +} + +func TestHollow(t *testing.T) { + + run := func(c, expected frontend.Circuit) func(t *testing.T) { + return func(t *testing.T) { + seen := hollow(c) + assert.Equal(t, expected, seen) + } + } + + assignments := []frontend.Circuit{ + &committedConstantCircuit{1}, + &commitmentCircuit{X: []frontend.Variable{1}, Public: []frontend.Variable{}}, + } + + expected := []frontend.Circuit{ + &committedConstantCircuit{nil}, + &commitmentCircuit{X: []frontend.Variable{nil}, Public: []frontend.Variable{}}, + } + + for i := range assignments { + t.Run(removePackageName(reflect.TypeOf(assignments[i]).String()), run(assignments[i], expected[i])) + } +} + +func e2eTest(t *testing.T, assignment frontend.Circuit) { + t.Parallel() + + t.Run("fuzzer", func(t *testing.T) { + circuit := hollow(assignment).(frontend.Circuit) + NewAssert(t).ProverSucceeded(circuit, assignment, WithBackends(backend.GROTH16, backend.PLONK)) // TODO: Support PlonkFri.Commit + }) + + t.Run("plonk-e2e", func(t *testing.T) { + circuit := hollow(assignment).(frontend.Circuit) + plonkTest(t, circuit, assignment) + }) + + t.Run("groth16-e2e", func(t *testing.T) { + circuit := hollow(assignment).(frontend.Circuit) + groth16Test(t, circuit, assignment) + }) +} From 0e3eb3a83751b98707229f910c83ea0ea13d8a3f Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 23 May 2023 15:12:10 -0500 Subject: [PATCH 370/464] style: subscript group index --- backend/groth16/bls12-377/setup.go | 20 +++++++++---------- backend/groth16/bls12-381/setup.go | 20 +++++++++---------- backend/groth16/bls24-315/setup.go | 20 +++++++++---------- backend/groth16/bls24-317/setup.go | 20 +++++++++---------- backend/groth16/bn254/setup.go | 20 +++++++++---------- backend/groth16/bw6-633/setup.go | 20 +++++++++---------- backend/groth16/bw6-761/setup.go | 20 +++++++++---------- .../zkpschemes/groth16/groth16.setup.go.tmpl | 20 +++++++++---------- 8 files changed, 80 insertions(+), 80 deletions(-) diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index 4e4c782a54..068cc8bfed 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -34,15 +34,15 @@ type ProvingKey struct { // domain Domain fft.Domain - // [α]1, [β]1, [δ]1 - // [A(t)]1, [B(t)]1, [Kpk(t)]1, [Z(t)]1 + // [α]₁, [β]₁, [δ]₁ + // [A(t)]₁, [B(t)]₁, [Kpk(t)]₁, [Z(t)]₁ G1 struct { Alpha, Beta, Delta curve.G1Affine A, B, Z []curve.G1Affine K []curve.G1Affine // the indexes correspond to the private wires } - // [β]2, [δ]2, [B(t)]2 + // [β]₂, [δ]₂, [B(t)]₂ G2 struct { Beta, Delta curve.G2Affine B []curve.G2Affine @@ -58,15 +58,15 @@ type ProvingKey struct { // VerifyingKey is used by a Groth16 verifier to verify the validity of a proof and a statement // Notation follows Figure 4. in DIZK paper https://eprint.iacr.org/2018/691.pdf type VerifyingKey struct { - // [α]1, [Kvk]1 + // [α]₁, [Kvk]₁ G1 struct { Alpha curve.G1Affine Beta, Delta curve.G1Affine // unused, here for compatibility purposes K []curve.G1Affine // The indexes correspond to the public wires } - // [β]2, [δ]2, [γ]2, - // -[δ]2, -[γ]2: see proof.Verify() for more details + // [β]₂, [δ]₂, [γ]₂, + // -[δ]₂, -[γ]₂: see proof.Verify() for more details G2 struct { Beta, Delta, Gamma curve.G2Affine deltaNeg, gammaNeg curve.G2Affine // not serialized @@ -233,7 +233,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { g1PointsAff := curve.BatchScalarMultiplicationG1(&g1, g1Scalars) - // sets pk: [α]1, [β]1, [δ]1 + // sets pk: [α]₁, [β]₁, [δ]₁ pk.G1.Alpha = g1PointsAff[0] pk.G1.Beta = g1PointsAff[1] pk.G1.Delta = g1PointsAff[2] @@ -288,11 +288,11 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pk.G2.B = g2PointsAff[:len(B)] - // sets pk: [β]2, [δ]2 + // sets pk: [β]₂, [δ]₂ pk.G2.Beta = g2PointsAff[len(B)+0] pk.G2.Delta = g2PointsAff[len(B)+1] - // sets vk: [δ]2, [γ]2 + // sets vk: [δ]₂, [γ]₂ vk.G2.Delta = g2PointsAff[len(B)+1] vk.G2.Gamma = g2PointsAff[len(B)+2] @@ -315,7 +315,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return nil } -// Precompute sets e, -[δ]2, -[γ]2 +// Precompute sets e, -[δ]₂, -[γ]₂ // This is meant to be called internally during setup or deserialization. func (vk *VerifyingKey) Precompute() error { var err error diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index 3e870a0084..916fb309f7 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -34,15 +34,15 @@ type ProvingKey struct { // domain Domain fft.Domain - // [α]1, [β]1, [δ]1 - // [A(t)]1, [B(t)]1, [Kpk(t)]1, [Z(t)]1 + // [α]₁, [β]₁, [δ]₁ + // [A(t)]₁, [B(t)]₁, [Kpk(t)]₁, [Z(t)]₁ G1 struct { Alpha, Beta, Delta curve.G1Affine A, B, Z []curve.G1Affine K []curve.G1Affine // the indexes correspond to the private wires } - // [β]2, [δ]2, [B(t)]2 + // [β]₂, [δ]₂, [B(t)]₂ G2 struct { Beta, Delta curve.G2Affine B []curve.G2Affine @@ -58,15 +58,15 @@ type ProvingKey struct { // VerifyingKey is used by a Groth16 verifier to verify the validity of a proof and a statement // Notation follows Figure 4. in DIZK paper https://eprint.iacr.org/2018/691.pdf type VerifyingKey struct { - // [α]1, [Kvk]1 + // [α]₁, [Kvk]₁ G1 struct { Alpha curve.G1Affine Beta, Delta curve.G1Affine // unused, here for compatibility purposes K []curve.G1Affine // The indexes correspond to the public wires } - // [β]2, [δ]2, [γ]2, - // -[δ]2, -[γ]2: see proof.Verify() for more details + // [β]₂, [δ]₂, [γ]₂, + // -[δ]₂, -[γ]₂: see proof.Verify() for more details G2 struct { Beta, Delta, Gamma curve.G2Affine deltaNeg, gammaNeg curve.G2Affine // not serialized @@ -233,7 +233,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { g1PointsAff := curve.BatchScalarMultiplicationG1(&g1, g1Scalars) - // sets pk: [α]1, [β]1, [δ]1 + // sets pk: [α]₁, [β]₁, [δ]₁ pk.G1.Alpha = g1PointsAff[0] pk.G1.Beta = g1PointsAff[1] pk.G1.Delta = g1PointsAff[2] @@ -288,11 +288,11 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pk.G2.B = g2PointsAff[:len(B)] - // sets pk: [β]2, [δ]2 + // sets pk: [β]₂, [δ]₂ pk.G2.Beta = g2PointsAff[len(B)+0] pk.G2.Delta = g2PointsAff[len(B)+1] - // sets vk: [δ]2, [γ]2 + // sets vk: [δ]₂, [γ]₂ vk.G2.Delta = g2PointsAff[len(B)+1] vk.G2.Gamma = g2PointsAff[len(B)+2] @@ -315,7 +315,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return nil } -// Precompute sets e, -[δ]2, -[γ]2 +// Precompute sets e, -[δ]₂, -[γ]₂ // This is meant to be called internally during setup or deserialization. func (vk *VerifyingKey) Precompute() error { var err error diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index 99b87fdc15..6700512c92 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -34,15 +34,15 @@ type ProvingKey struct { // domain Domain fft.Domain - // [α]1, [β]1, [δ]1 - // [A(t)]1, [B(t)]1, [Kpk(t)]1, [Z(t)]1 + // [α]₁, [β]₁, [δ]₁ + // [A(t)]₁, [B(t)]₁, [Kpk(t)]₁, [Z(t)]₁ G1 struct { Alpha, Beta, Delta curve.G1Affine A, B, Z []curve.G1Affine K []curve.G1Affine // the indexes correspond to the private wires } - // [β]2, [δ]2, [B(t)]2 + // [β]₂, [δ]₂, [B(t)]₂ G2 struct { Beta, Delta curve.G2Affine B []curve.G2Affine @@ -58,15 +58,15 @@ type ProvingKey struct { // VerifyingKey is used by a Groth16 verifier to verify the validity of a proof and a statement // Notation follows Figure 4. in DIZK paper https://eprint.iacr.org/2018/691.pdf type VerifyingKey struct { - // [α]1, [Kvk]1 + // [α]₁, [Kvk]₁ G1 struct { Alpha curve.G1Affine Beta, Delta curve.G1Affine // unused, here for compatibility purposes K []curve.G1Affine // The indexes correspond to the public wires } - // [β]2, [δ]2, [γ]2, - // -[δ]2, -[γ]2: see proof.Verify() for more details + // [β]₂, [δ]₂, [γ]₂, + // -[δ]₂, -[γ]₂: see proof.Verify() for more details G2 struct { Beta, Delta, Gamma curve.G2Affine deltaNeg, gammaNeg curve.G2Affine // not serialized @@ -233,7 +233,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { g1PointsAff := curve.BatchScalarMultiplicationG1(&g1, g1Scalars) - // sets pk: [α]1, [β]1, [δ]1 + // sets pk: [α]₁, [β]₁, [δ]₁ pk.G1.Alpha = g1PointsAff[0] pk.G1.Beta = g1PointsAff[1] pk.G1.Delta = g1PointsAff[2] @@ -288,11 +288,11 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pk.G2.B = g2PointsAff[:len(B)] - // sets pk: [β]2, [δ]2 + // sets pk: [β]₂, [δ]₂ pk.G2.Beta = g2PointsAff[len(B)+0] pk.G2.Delta = g2PointsAff[len(B)+1] - // sets vk: [δ]2, [γ]2 + // sets vk: [δ]₂, [γ]₂ vk.G2.Delta = g2PointsAff[len(B)+1] vk.G2.Gamma = g2PointsAff[len(B)+2] @@ -315,7 +315,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return nil } -// Precompute sets e, -[δ]2, -[γ]2 +// Precompute sets e, -[δ]₂, -[γ]₂ // This is meant to be called internally during setup or deserialization. func (vk *VerifyingKey) Precompute() error { var err error diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index 77870e62bb..ec251ada15 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -34,15 +34,15 @@ type ProvingKey struct { // domain Domain fft.Domain - // [α]1, [β]1, [δ]1 - // [A(t)]1, [B(t)]1, [Kpk(t)]1, [Z(t)]1 + // [α]₁, [β]₁, [δ]₁ + // [A(t)]₁, [B(t)]₁, [Kpk(t)]₁, [Z(t)]₁ G1 struct { Alpha, Beta, Delta curve.G1Affine A, B, Z []curve.G1Affine K []curve.G1Affine // the indexes correspond to the private wires } - // [β]2, [δ]2, [B(t)]2 + // [β]₂, [δ]₂, [B(t)]₂ G2 struct { Beta, Delta curve.G2Affine B []curve.G2Affine @@ -58,15 +58,15 @@ type ProvingKey struct { // VerifyingKey is used by a Groth16 verifier to verify the validity of a proof and a statement // Notation follows Figure 4. in DIZK paper https://eprint.iacr.org/2018/691.pdf type VerifyingKey struct { - // [α]1, [Kvk]1 + // [α]₁, [Kvk]₁ G1 struct { Alpha curve.G1Affine Beta, Delta curve.G1Affine // unused, here for compatibility purposes K []curve.G1Affine // The indexes correspond to the public wires } - // [β]2, [δ]2, [γ]2, - // -[δ]2, -[γ]2: see proof.Verify() for more details + // [β]₂, [δ]₂, [γ]₂, + // -[δ]₂, -[γ]₂: see proof.Verify() for more details G2 struct { Beta, Delta, Gamma curve.G2Affine deltaNeg, gammaNeg curve.G2Affine // not serialized @@ -233,7 +233,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { g1PointsAff := curve.BatchScalarMultiplicationG1(&g1, g1Scalars) - // sets pk: [α]1, [β]1, [δ]1 + // sets pk: [α]₁, [β]₁, [δ]₁ pk.G1.Alpha = g1PointsAff[0] pk.G1.Beta = g1PointsAff[1] pk.G1.Delta = g1PointsAff[2] @@ -288,11 +288,11 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pk.G2.B = g2PointsAff[:len(B)] - // sets pk: [β]2, [δ]2 + // sets pk: [β]₂, [δ]₂ pk.G2.Beta = g2PointsAff[len(B)+0] pk.G2.Delta = g2PointsAff[len(B)+1] - // sets vk: [δ]2, [γ]2 + // sets vk: [δ]₂, [γ]₂ vk.G2.Delta = g2PointsAff[len(B)+1] vk.G2.Gamma = g2PointsAff[len(B)+2] @@ -315,7 +315,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return nil } -// Precompute sets e, -[δ]2, -[γ]2 +// Precompute sets e, -[δ]₂, -[γ]₂ // This is meant to be called internally during setup or deserialization. func (vk *VerifyingKey) Precompute() error { var err error diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index e2b6800a98..de34b1f86c 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -34,15 +34,15 @@ type ProvingKey struct { // domain Domain fft.Domain - // [α]1, [β]1, [δ]1 - // [A(t)]1, [B(t)]1, [Kpk(t)]1, [Z(t)]1 + // [α]₁, [β]₁, [δ]₁ + // [A(t)]₁, [B(t)]₁, [Kpk(t)]₁, [Z(t)]₁ G1 struct { Alpha, Beta, Delta curve.G1Affine A, B, Z []curve.G1Affine K []curve.G1Affine // the indexes correspond to the private wires } - // [β]2, [δ]2, [B(t)]2 + // [β]₂, [δ]₂, [B(t)]₂ G2 struct { Beta, Delta curve.G2Affine B []curve.G2Affine @@ -58,15 +58,15 @@ type ProvingKey struct { // VerifyingKey is used by a Groth16 verifier to verify the validity of a proof and a statement // Notation follows Figure 4. in DIZK paper https://eprint.iacr.org/2018/691.pdf type VerifyingKey struct { - // [α]1, [Kvk]1 + // [α]₁, [Kvk]₁ G1 struct { Alpha curve.G1Affine Beta, Delta curve.G1Affine // unused, here for compatibility purposes K []curve.G1Affine // The indexes correspond to the public wires } - // [β]2, [δ]2, [γ]2, - // -[δ]2, -[γ]2: see proof.Verify() for more details + // [β]₂, [δ]₂, [γ]₂, + // -[δ]₂, -[γ]₂: see proof.Verify() for more details G2 struct { Beta, Delta, Gamma curve.G2Affine deltaNeg, gammaNeg curve.G2Affine // not serialized @@ -233,7 +233,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { g1PointsAff := curve.BatchScalarMultiplicationG1(&g1, g1Scalars) - // sets pk: [α]1, [β]1, [δ]1 + // sets pk: [α]₁, [β]₁, [δ]₁ pk.G1.Alpha = g1PointsAff[0] pk.G1.Beta = g1PointsAff[1] pk.G1.Delta = g1PointsAff[2] @@ -288,11 +288,11 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pk.G2.B = g2PointsAff[:len(B)] - // sets pk: [β]2, [δ]2 + // sets pk: [β]₂, [δ]₂ pk.G2.Beta = g2PointsAff[len(B)+0] pk.G2.Delta = g2PointsAff[len(B)+1] - // sets vk: [δ]2, [γ]2 + // sets vk: [δ]₂, [γ]₂ vk.G2.Delta = g2PointsAff[len(B)+1] vk.G2.Gamma = g2PointsAff[len(B)+2] @@ -315,7 +315,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return nil } -// Precompute sets e, -[δ]2, -[γ]2 +// Precompute sets e, -[δ]₂, -[γ]₂ // This is meant to be called internally during setup or deserialization. func (vk *VerifyingKey) Precompute() error { var err error diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index 5b8ba4e712..b2b12b5c07 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -34,15 +34,15 @@ type ProvingKey struct { // domain Domain fft.Domain - // [α]1, [β]1, [δ]1 - // [A(t)]1, [B(t)]1, [Kpk(t)]1, [Z(t)]1 + // [α]₁, [β]₁, [δ]₁ + // [A(t)]₁, [B(t)]₁, [Kpk(t)]₁, [Z(t)]₁ G1 struct { Alpha, Beta, Delta curve.G1Affine A, B, Z []curve.G1Affine K []curve.G1Affine // the indexes correspond to the private wires } - // [β]2, [δ]2, [B(t)]2 + // [β]₂, [δ]₂, [B(t)]₂ G2 struct { Beta, Delta curve.G2Affine B []curve.G2Affine @@ -58,15 +58,15 @@ type ProvingKey struct { // VerifyingKey is used by a Groth16 verifier to verify the validity of a proof and a statement // Notation follows Figure 4. in DIZK paper https://eprint.iacr.org/2018/691.pdf type VerifyingKey struct { - // [α]1, [Kvk]1 + // [α]₁, [Kvk]₁ G1 struct { Alpha curve.G1Affine Beta, Delta curve.G1Affine // unused, here for compatibility purposes K []curve.G1Affine // The indexes correspond to the public wires } - // [β]2, [δ]2, [γ]2, - // -[δ]2, -[γ]2: see proof.Verify() for more details + // [β]₂, [δ]₂, [γ]₂, + // -[δ]₂, -[γ]₂: see proof.Verify() for more details G2 struct { Beta, Delta, Gamma curve.G2Affine deltaNeg, gammaNeg curve.G2Affine // not serialized @@ -233,7 +233,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { g1PointsAff := curve.BatchScalarMultiplicationG1(&g1, g1Scalars) - // sets pk: [α]1, [β]1, [δ]1 + // sets pk: [α]₁, [β]₁, [δ]₁ pk.G1.Alpha = g1PointsAff[0] pk.G1.Beta = g1PointsAff[1] pk.G1.Delta = g1PointsAff[2] @@ -288,11 +288,11 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pk.G2.B = g2PointsAff[:len(B)] - // sets pk: [β]2, [δ]2 + // sets pk: [β]₂, [δ]₂ pk.G2.Beta = g2PointsAff[len(B)+0] pk.G2.Delta = g2PointsAff[len(B)+1] - // sets vk: [δ]2, [γ]2 + // sets vk: [δ]₂, [γ]₂ vk.G2.Delta = g2PointsAff[len(B)+1] vk.G2.Gamma = g2PointsAff[len(B)+2] @@ -315,7 +315,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return nil } -// Precompute sets e, -[δ]2, -[γ]2 +// Precompute sets e, -[δ]₂, -[γ]₂ // This is meant to be called internally during setup or deserialization. func (vk *VerifyingKey) Precompute() error { var err error diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index 26ec2f0d56..636e35ebea 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -34,15 +34,15 @@ type ProvingKey struct { // domain Domain fft.Domain - // [α]1, [β]1, [δ]1 - // [A(t)]1, [B(t)]1, [Kpk(t)]1, [Z(t)]1 + // [α]₁, [β]₁, [δ]₁ + // [A(t)]₁, [B(t)]₁, [Kpk(t)]₁, [Z(t)]₁ G1 struct { Alpha, Beta, Delta curve.G1Affine A, B, Z []curve.G1Affine K []curve.G1Affine // the indexes correspond to the private wires } - // [β]2, [δ]2, [B(t)]2 + // [β]₂, [δ]₂, [B(t)]₂ G2 struct { Beta, Delta curve.G2Affine B []curve.G2Affine @@ -58,15 +58,15 @@ type ProvingKey struct { // VerifyingKey is used by a Groth16 verifier to verify the validity of a proof and a statement // Notation follows Figure 4. in DIZK paper https://eprint.iacr.org/2018/691.pdf type VerifyingKey struct { - // [α]1, [Kvk]1 + // [α]₁, [Kvk]₁ G1 struct { Alpha curve.G1Affine Beta, Delta curve.G1Affine // unused, here for compatibility purposes K []curve.G1Affine // The indexes correspond to the public wires } - // [β]2, [δ]2, [γ]2, - // -[δ]2, -[γ]2: see proof.Verify() for more details + // [β]₂, [δ]₂, [γ]₂, + // -[δ]₂, -[γ]₂: see proof.Verify() for more details G2 struct { Beta, Delta, Gamma curve.G2Affine deltaNeg, gammaNeg curve.G2Affine // not serialized @@ -233,7 +233,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { g1PointsAff := curve.BatchScalarMultiplicationG1(&g1, g1Scalars) - // sets pk: [α]1, [β]1, [δ]1 + // sets pk: [α]₁, [β]₁, [δ]₁ pk.G1.Alpha = g1PointsAff[0] pk.G1.Beta = g1PointsAff[1] pk.G1.Delta = g1PointsAff[2] @@ -288,11 +288,11 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pk.G2.B = g2PointsAff[:len(B)] - // sets pk: [β]2, [δ]2 + // sets pk: [β]₂, [δ]₂ pk.G2.Beta = g2PointsAff[len(B)+0] pk.G2.Delta = g2PointsAff[len(B)+1] - // sets vk: [δ]2, [γ]2 + // sets vk: [δ]₂, [γ]₂ vk.G2.Delta = g2PointsAff[len(B)+1] vk.G2.Gamma = g2PointsAff[len(B)+2] @@ -315,7 +315,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return nil } -// Precompute sets e, -[δ]2, -[γ]2 +// Precompute sets e, -[δ]₂, -[γ]₂ // This is meant to be called internally during setup or deserialization. func (vk *VerifyingKey) Precompute() error { var err error diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl index e83401e5dd..b4e0331295 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl @@ -16,15 +16,15 @@ type ProvingKey struct { // domain Domain fft.Domain - // [α]1, [β]1, [δ]1 - // [A(t)]1, [B(t)]1, [Kpk(t)]1, [Z(t)]1 + // [α]₁, [β]₁, [δ]₁ + // [A(t)]₁, [B(t)]₁, [Kpk(t)]₁, [Z(t)]₁ G1 struct { Alpha, Beta, Delta curve.G1Affine A, B, Z []curve.G1Affine K []curve.G1Affine // the indexes correspond to the private wires } - // [β]2, [δ]2, [B(t)]2 + // [β]₂, [δ]₂, [B(t)]₂ G2 struct { Beta, Delta curve.G2Affine B []curve.G2Affine @@ -40,15 +40,15 @@ type ProvingKey struct { // VerifyingKey is used by a Groth16 verifier to verify the validity of a proof and a statement // Notation follows Figure 4. in DIZK paper https://eprint.iacr.org/2018/691.pdf type VerifyingKey struct { - // [α]1, [Kvk]1 + // [α]₁, [Kvk]₁ G1 struct { Alpha curve.G1Affine Beta, Delta curve.G1Affine // unused, here for compatibility purposes K []curve.G1Affine // The indexes correspond to the public wires } - // [β]2, [δ]2, [γ]2, - // -[δ]2, -[γ]2: see proof.Verify() for more details + // [β]₂, [δ]₂, [γ]₂, + // -[δ]₂, -[γ]₂: see proof.Verify() for more details G2 struct { Beta, Delta, Gamma curve.G2Affine deltaNeg, gammaNeg curve.G2Affine // not serialized @@ -215,7 +215,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { g1PointsAff := curve.BatchScalarMultiplicationG1(&g1, g1Scalars) - // sets pk: [α]1, [β]1, [δ]1 + // sets pk: [α]₁, [β]₁, [δ]₁ pk.G1.Alpha = g1PointsAff[0] pk.G1.Beta = g1PointsAff[1] pk.G1.Delta = g1PointsAff[2] @@ -270,11 +270,11 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pk.G2.B = g2PointsAff[:len(B)] - // sets pk: [β]2, [δ]2 + // sets pk: [β]₂, [δ]₂ pk.G2.Beta = g2PointsAff[len(B)+0] pk.G2.Delta = g2PointsAff[len(B)+1] - // sets vk: [δ]2, [γ]2 + // sets vk: [δ]₂, [γ]₂ vk.G2.Delta = g2PointsAff[len(B)+1] vk.G2.Gamma = g2PointsAff[len(B)+2] @@ -297,7 +297,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return nil } -// Precompute sets e, -[δ]2, -[γ]2 +// Precompute sets e, -[δ]₂, -[γ]₂ // This is meant to be called internally during setup or deserialization. func (vk *VerifyingKey) Precompute() error { var err error From f46e9a1933f014e38ff14892725b1cb2ec5276ce Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Wed, 24 May 2023 10:26:41 +0200 Subject: [PATCH 371/464] fix: fixed kzg serialisation on bn254 --- backend/plonk/bn254/marshal.go | 6 ++++ backend/plonk/bn254/marshal_test.go | 55 +++++++++++++++++------------ 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/backend/plonk/bn254/marshal.go b/backend/plonk/bn254/marshal.go index 8de7d4071e..1290cf2142 100644 --- a/backend/plonk/bn254/marshal.go +++ b/backend/plonk/bn254/marshal.go @@ -245,6 +245,9 @@ func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*curve.Encoder)) (n &vk.Qo, &vk.Qk, vk.Qcp, + &vk.Kzg.G1, + &vk.Kzg.G2[0], + &vk.Kzg.G2[1], vk.CommitmentConstraintIndexes, } @@ -275,6 +278,9 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { &vk.Qo, &vk.Qk, &vk.Qcp, + &vk.Kzg.G1, + &vk.Kzg.G2[0], + &vk.Kzg.G2[1], &vk.CommitmentConstraintIndexes, } diff --git a/backend/plonk/bn254/marshal_test.go b/backend/plonk/bn254/marshal_test.go index 8f62891c76..596cef0903 100644 --- a/backend/plonk/bn254/marshal_test.go +++ b/backend/plonk/bn254/marshal_test.go @@ -159,42 +159,53 @@ func (vk *VerifyingKey) randomize() { vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} //#nosec G404 weak rng is fine here vk.CosetShift.SetRandom() - vk.S[0] = randomPoint() - vk.S[1] = randomPoint() - vk.S[2] = randomPoint() - vk.Ql = randomPoint() - vk.Qr = randomPoint() - vk.Qm = randomPoint() - vk.Qo = randomPoint() - vk.Qk = randomPoint() - vk.Qcp = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here + vk.S[0] = randomG1Point() + vk.S[1] = randomG1Point() + vk.S[2] = randomG1Point() + + vk.Kzg.G1 = randomG1Point() + vk.Kzg.G2[0] = randomG2Point() + vk.Kzg.G2[1] = randomG2Point() + + vk.Ql = randomG1Point() + vk.Qr = randomG1Point() + vk.Qm = randomG1Point() + vk.Qo = randomG1Point() + vk.Qk = randomG1Point() + vk.Qcp = randomG1Points(rand.Intn(4)) //#nosec G404 weak rng is fine here } func (proof *Proof) randomize() { - proof.LRO[0] = randomPoint() - proof.LRO[1] = randomPoint() - proof.LRO[2] = randomPoint() - proof.Z = randomPoint() - proof.H[0] = randomPoint() - proof.H[1] = randomPoint() - proof.H[2] = randomPoint() - proof.BatchedProof.H = randomPoint() + proof.LRO[0] = randomG1Point() + proof.LRO[1] = randomG1Point() + proof.LRO[2] = randomG1Point() + proof.Z = randomG1Point() + proof.H[0] = randomG1Point() + proof.H[1] = randomG1Point() + proof.H[2] = randomG1Point() + proof.BatchedProof.H = randomG1Point() proof.BatchedProof.ClaimedValues = randomScalars(2) - proof.ZShiftedOpening.H = randomPoint() + proof.ZShiftedOpening.H = randomG1Point() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.Bsb22Commitments = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here + proof.Bsb22Commitments = randomG1Points(rand.Intn(4)) //#nosec G404 weak rng is fine here } -func randomPoint() curve.G1Affine { +func randomG2Point() curve.G2Affine{ + _,_,_, r := curve.Generators() + r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) //#nosec G404 weak rng is fine here + return r +} + +func randomG1Point() curve.G1Affine { _, _, r, _ := curve.Generators() r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) //#nosec G404 weak rng is fine here return r } -func randomPoints(n int) []curve.G1Affine { +func randomG1Points(n int) []curve.G1Affine { res := make([]curve.G1Affine, n) for i := range res { - res[i] = randomPoint() + res[i] = randomG1Point() } return res } From 839e41b3e8795f0cd0365795cb36e607b62802b3 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Wed, 24 May 2023 10:40:38 +0200 Subject: [PATCH 372/464] fix: fixes #672 --- backend/plonk/bls12-377/marshal.go | 6 ++ backend/plonk/bls12-377/marshal_test.go | 55 +++++++++++-------- backend/plonk/bls12-381/marshal.go | 6 ++ backend/plonk/bls12-381/marshal_test.go | 55 +++++++++++-------- backend/plonk/bls24-315/marshal.go | 6 ++ backend/plonk/bls24-315/marshal_test.go | 55 +++++++++++-------- backend/plonk/bls24-317/marshal.go | 6 ++ backend/plonk/bls24-317/marshal_test.go | 55 +++++++++++-------- backend/plonk/bn254/marshal_test.go | 4 +- backend/plonk/bw6-633/marshal.go | 6 ++ backend/plonk/bw6-633/marshal_test.go | 55 +++++++++++-------- backend/plonk/bw6-761/marshal.go | 6 ++ backend/plonk/bw6-761/marshal_test.go | 55 +++++++++++-------- .../zkpschemes/plonk/plonk.marshal.go.tmpl | 6 ++ .../zkpschemes/plonk/tests/marshal.go.tmpl | 55 +++++++++++-------- 15 files changed, 275 insertions(+), 156 deletions(-) diff --git a/backend/plonk/bls12-377/marshal.go b/backend/plonk/bls12-377/marshal.go index fd1986e170..4c74a05aa4 100644 --- a/backend/plonk/bls12-377/marshal.go +++ b/backend/plonk/bls12-377/marshal.go @@ -245,6 +245,9 @@ func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*curve.Encoder)) (n &vk.Qo, &vk.Qk, vk.Qcp, + &vk.Kzg.G1, + &vk.Kzg.G2[0], + &vk.Kzg.G2[1], vk.CommitmentConstraintIndexes, } @@ -275,6 +278,9 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { &vk.Qo, &vk.Qk, &vk.Qcp, + &vk.Kzg.G1, + &vk.Kzg.G2[0], + &vk.Kzg.G2[1], &vk.CommitmentConstraintIndexes, } diff --git a/backend/plonk/bls12-377/marshal_test.go b/backend/plonk/bls12-377/marshal_test.go index 8757e9a3a5..da2a447e3c 100644 --- a/backend/plonk/bls12-377/marshal_test.go +++ b/backend/plonk/bls12-377/marshal_test.go @@ -159,42 +159,53 @@ func (vk *VerifyingKey) randomize() { vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} //#nosec G404 weak rng is fine here vk.CosetShift.SetRandom() - vk.S[0] = randomPoint() - vk.S[1] = randomPoint() - vk.S[2] = randomPoint() - vk.Ql = randomPoint() - vk.Qr = randomPoint() - vk.Qm = randomPoint() - vk.Qo = randomPoint() - vk.Qk = randomPoint() - vk.Qcp = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here + vk.S[0] = randomG1Point() + vk.S[1] = randomG1Point() + vk.S[2] = randomG1Point() + + vk.Kzg.G1 = randomG1Point() + vk.Kzg.G2[0] = randomG2Point() + vk.Kzg.G2[1] = randomG2Point() + + vk.Ql = randomG1Point() + vk.Qr = randomG1Point() + vk.Qm = randomG1Point() + vk.Qo = randomG1Point() + vk.Qk = randomG1Point() + vk.Qcp = randomG1Points(rand.Intn(4)) //#nosec G404 weak rng is fine here } func (proof *Proof) randomize() { - proof.LRO[0] = randomPoint() - proof.LRO[1] = randomPoint() - proof.LRO[2] = randomPoint() - proof.Z = randomPoint() - proof.H[0] = randomPoint() - proof.H[1] = randomPoint() - proof.H[2] = randomPoint() - proof.BatchedProof.H = randomPoint() + proof.LRO[0] = randomG1Point() + proof.LRO[1] = randomG1Point() + proof.LRO[2] = randomG1Point() + proof.Z = randomG1Point() + proof.H[0] = randomG1Point() + proof.H[1] = randomG1Point() + proof.H[2] = randomG1Point() + proof.BatchedProof.H = randomG1Point() proof.BatchedProof.ClaimedValues = randomScalars(2) - proof.ZShiftedOpening.H = randomPoint() + proof.ZShiftedOpening.H = randomG1Point() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.Bsb22Commitments = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here + proof.Bsb22Commitments = randomG1Points(rand.Intn(4)) //#nosec G404 weak rng is fine here } -func randomPoint() curve.G1Affine { +func randomG2Point() curve.G2Affine { + _, _, _, r := curve.Generators() + r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) //#nosec G404 weak rng is fine here + return r +} + +func randomG1Point() curve.G1Affine { _, _, r, _ := curve.Generators() r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) //#nosec G404 weak rng is fine here return r } -func randomPoints(n int) []curve.G1Affine { +func randomG1Points(n int) []curve.G1Affine { res := make([]curve.G1Affine, n) for i := range res { - res[i] = randomPoint() + res[i] = randomG1Point() } return res } diff --git a/backend/plonk/bls12-381/marshal.go b/backend/plonk/bls12-381/marshal.go index 7f9306f2b6..6ce9cedd20 100644 --- a/backend/plonk/bls12-381/marshal.go +++ b/backend/plonk/bls12-381/marshal.go @@ -245,6 +245,9 @@ func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*curve.Encoder)) (n &vk.Qo, &vk.Qk, vk.Qcp, + &vk.Kzg.G1, + &vk.Kzg.G2[0], + &vk.Kzg.G2[1], vk.CommitmentConstraintIndexes, } @@ -275,6 +278,9 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { &vk.Qo, &vk.Qk, &vk.Qcp, + &vk.Kzg.G1, + &vk.Kzg.G2[0], + &vk.Kzg.G2[1], &vk.CommitmentConstraintIndexes, } diff --git a/backend/plonk/bls12-381/marshal_test.go b/backend/plonk/bls12-381/marshal_test.go index 9beb310d2a..f67ebb2fe7 100644 --- a/backend/plonk/bls12-381/marshal_test.go +++ b/backend/plonk/bls12-381/marshal_test.go @@ -159,42 +159,53 @@ func (vk *VerifyingKey) randomize() { vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} //#nosec G404 weak rng is fine here vk.CosetShift.SetRandom() - vk.S[0] = randomPoint() - vk.S[1] = randomPoint() - vk.S[2] = randomPoint() - vk.Ql = randomPoint() - vk.Qr = randomPoint() - vk.Qm = randomPoint() - vk.Qo = randomPoint() - vk.Qk = randomPoint() - vk.Qcp = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here + vk.S[0] = randomG1Point() + vk.S[1] = randomG1Point() + vk.S[2] = randomG1Point() + + vk.Kzg.G1 = randomG1Point() + vk.Kzg.G2[0] = randomG2Point() + vk.Kzg.G2[1] = randomG2Point() + + vk.Ql = randomG1Point() + vk.Qr = randomG1Point() + vk.Qm = randomG1Point() + vk.Qo = randomG1Point() + vk.Qk = randomG1Point() + vk.Qcp = randomG1Points(rand.Intn(4)) //#nosec G404 weak rng is fine here } func (proof *Proof) randomize() { - proof.LRO[0] = randomPoint() - proof.LRO[1] = randomPoint() - proof.LRO[2] = randomPoint() - proof.Z = randomPoint() - proof.H[0] = randomPoint() - proof.H[1] = randomPoint() - proof.H[2] = randomPoint() - proof.BatchedProof.H = randomPoint() + proof.LRO[0] = randomG1Point() + proof.LRO[1] = randomG1Point() + proof.LRO[2] = randomG1Point() + proof.Z = randomG1Point() + proof.H[0] = randomG1Point() + proof.H[1] = randomG1Point() + proof.H[2] = randomG1Point() + proof.BatchedProof.H = randomG1Point() proof.BatchedProof.ClaimedValues = randomScalars(2) - proof.ZShiftedOpening.H = randomPoint() + proof.ZShiftedOpening.H = randomG1Point() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.Bsb22Commitments = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here + proof.Bsb22Commitments = randomG1Points(rand.Intn(4)) //#nosec G404 weak rng is fine here } -func randomPoint() curve.G1Affine { +func randomG2Point() curve.G2Affine { + _, _, _, r := curve.Generators() + r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) //#nosec G404 weak rng is fine here + return r +} + +func randomG1Point() curve.G1Affine { _, _, r, _ := curve.Generators() r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) //#nosec G404 weak rng is fine here return r } -func randomPoints(n int) []curve.G1Affine { +func randomG1Points(n int) []curve.G1Affine { res := make([]curve.G1Affine, n) for i := range res { - res[i] = randomPoint() + res[i] = randomG1Point() } return res } diff --git a/backend/plonk/bls24-315/marshal.go b/backend/plonk/bls24-315/marshal.go index c57a9ca828..24cea7ada8 100644 --- a/backend/plonk/bls24-315/marshal.go +++ b/backend/plonk/bls24-315/marshal.go @@ -245,6 +245,9 @@ func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*curve.Encoder)) (n &vk.Qo, &vk.Qk, vk.Qcp, + &vk.Kzg.G1, + &vk.Kzg.G2[0], + &vk.Kzg.G2[1], vk.CommitmentConstraintIndexes, } @@ -275,6 +278,9 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { &vk.Qo, &vk.Qk, &vk.Qcp, + &vk.Kzg.G1, + &vk.Kzg.G2[0], + &vk.Kzg.G2[1], &vk.CommitmentConstraintIndexes, } diff --git a/backend/plonk/bls24-315/marshal_test.go b/backend/plonk/bls24-315/marshal_test.go index f61cb1be1d..1881a62ace 100644 --- a/backend/plonk/bls24-315/marshal_test.go +++ b/backend/plonk/bls24-315/marshal_test.go @@ -159,42 +159,53 @@ func (vk *VerifyingKey) randomize() { vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} //#nosec G404 weak rng is fine here vk.CosetShift.SetRandom() - vk.S[0] = randomPoint() - vk.S[1] = randomPoint() - vk.S[2] = randomPoint() - vk.Ql = randomPoint() - vk.Qr = randomPoint() - vk.Qm = randomPoint() - vk.Qo = randomPoint() - vk.Qk = randomPoint() - vk.Qcp = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here + vk.S[0] = randomG1Point() + vk.S[1] = randomG1Point() + vk.S[2] = randomG1Point() + + vk.Kzg.G1 = randomG1Point() + vk.Kzg.G2[0] = randomG2Point() + vk.Kzg.G2[1] = randomG2Point() + + vk.Ql = randomG1Point() + vk.Qr = randomG1Point() + vk.Qm = randomG1Point() + vk.Qo = randomG1Point() + vk.Qk = randomG1Point() + vk.Qcp = randomG1Points(rand.Intn(4)) //#nosec G404 weak rng is fine here } func (proof *Proof) randomize() { - proof.LRO[0] = randomPoint() - proof.LRO[1] = randomPoint() - proof.LRO[2] = randomPoint() - proof.Z = randomPoint() - proof.H[0] = randomPoint() - proof.H[1] = randomPoint() - proof.H[2] = randomPoint() - proof.BatchedProof.H = randomPoint() + proof.LRO[0] = randomG1Point() + proof.LRO[1] = randomG1Point() + proof.LRO[2] = randomG1Point() + proof.Z = randomG1Point() + proof.H[0] = randomG1Point() + proof.H[1] = randomG1Point() + proof.H[2] = randomG1Point() + proof.BatchedProof.H = randomG1Point() proof.BatchedProof.ClaimedValues = randomScalars(2) - proof.ZShiftedOpening.H = randomPoint() + proof.ZShiftedOpening.H = randomG1Point() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.Bsb22Commitments = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here + proof.Bsb22Commitments = randomG1Points(rand.Intn(4)) //#nosec G404 weak rng is fine here } -func randomPoint() curve.G1Affine { +func randomG2Point() curve.G2Affine { + _, _, _, r := curve.Generators() + r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) //#nosec G404 weak rng is fine here + return r +} + +func randomG1Point() curve.G1Affine { _, _, r, _ := curve.Generators() r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) //#nosec G404 weak rng is fine here return r } -func randomPoints(n int) []curve.G1Affine { +func randomG1Points(n int) []curve.G1Affine { res := make([]curve.G1Affine, n) for i := range res { - res[i] = randomPoint() + res[i] = randomG1Point() } return res } diff --git a/backend/plonk/bls24-317/marshal.go b/backend/plonk/bls24-317/marshal.go index 5178acefbd..5e4ba3a712 100644 --- a/backend/plonk/bls24-317/marshal.go +++ b/backend/plonk/bls24-317/marshal.go @@ -245,6 +245,9 @@ func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*curve.Encoder)) (n &vk.Qo, &vk.Qk, vk.Qcp, + &vk.Kzg.G1, + &vk.Kzg.G2[0], + &vk.Kzg.G2[1], vk.CommitmentConstraintIndexes, } @@ -275,6 +278,9 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { &vk.Qo, &vk.Qk, &vk.Qcp, + &vk.Kzg.G1, + &vk.Kzg.G2[0], + &vk.Kzg.G2[1], &vk.CommitmentConstraintIndexes, } diff --git a/backend/plonk/bls24-317/marshal_test.go b/backend/plonk/bls24-317/marshal_test.go index 4e68aa0e9f..10d26631c5 100644 --- a/backend/plonk/bls24-317/marshal_test.go +++ b/backend/plonk/bls24-317/marshal_test.go @@ -159,42 +159,53 @@ func (vk *VerifyingKey) randomize() { vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} //#nosec G404 weak rng is fine here vk.CosetShift.SetRandom() - vk.S[0] = randomPoint() - vk.S[1] = randomPoint() - vk.S[2] = randomPoint() - vk.Ql = randomPoint() - vk.Qr = randomPoint() - vk.Qm = randomPoint() - vk.Qo = randomPoint() - vk.Qk = randomPoint() - vk.Qcp = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here + vk.S[0] = randomG1Point() + vk.S[1] = randomG1Point() + vk.S[2] = randomG1Point() + + vk.Kzg.G1 = randomG1Point() + vk.Kzg.G2[0] = randomG2Point() + vk.Kzg.G2[1] = randomG2Point() + + vk.Ql = randomG1Point() + vk.Qr = randomG1Point() + vk.Qm = randomG1Point() + vk.Qo = randomG1Point() + vk.Qk = randomG1Point() + vk.Qcp = randomG1Points(rand.Intn(4)) //#nosec G404 weak rng is fine here } func (proof *Proof) randomize() { - proof.LRO[0] = randomPoint() - proof.LRO[1] = randomPoint() - proof.LRO[2] = randomPoint() - proof.Z = randomPoint() - proof.H[0] = randomPoint() - proof.H[1] = randomPoint() - proof.H[2] = randomPoint() - proof.BatchedProof.H = randomPoint() + proof.LRO[0] = randomG1Point() + proof.LRO[1] = randomG1Point() + proof.LRO[2] = randomG1Point() + proof.Z = randomG1Point() + proof.H[0] = randomG1Point() + proof.H[1] = randomG1Point() + proof.H[2] = randomG1Point() + proof.BatchedProof.H = randomG1Point() proof.BatchedProof.ClaimedValues = randomScalars(2) - proof.ZShiftedOpening.H = randomPoint() + proof.ZShiftedOpening.H = randomG1Point() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.Bsb22Commitments = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here + proof.Bsb22Commitments = randomG1Points(rand.Intn(4)) //#nosec G404 weak rng is fine here } -func randomPoint() curve.G1Affine { +func randomG2Point() curve.G2Affine { + _, _, _, r := curve.Generators() + r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) //#nosec G404 weak rng is fine here + return r +} + +func randomG1Point() curve.G1Affine { _, _, r, _ := curve.Generators() r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) //#nosec G404 weak rng is fine here return r } -func randomPoints(n int) []curve.G1Affine { +func randomG1Points(n int) []curve.G1Affine { res := make([]curve.G1Affine, n) for i := range res { - res[i] = randomPoint() + res[i] = randomG1Point() } return res } diff --git a/backend/plonk/bn254/marshal_test.go b/backend/plonk/bn254/marshal_test.go index 596cef0903..74254283a2 100644 --- a/backend/plonk/bn254/marshal_test.go +++ b/backend/plonk/bn254/marshal_test.go @@ -190,8 +190,8 @@ func (proof *Proof) randomize() { proof.Bsb22Commitments = randomG1Points(rand.Intn(4)) //#nosec G404 weak rng is fine here } -func randomG2Point() curve.G2Affine{ - _,_,_, r := curve.Generators() +func randomG2Point() curve.G2Affine { + _, _, _, r := curve.Generators() r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) //#nosec G404 weak rng is fine here return r } diff --git a/backend/plonk/bw6-633/marshal.go b/backend/plonk/bw6-633/marshal.go index d5fe075d58..b78786fbcb 100644 --- a/backend/plonk/bw6-633/marshal.go +++ b/backend/plonk/bw6-633/marshal.go @@ -245,6 +245,9 @@ func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*curve.Encoder)) (n &vk.Qo, &vk.Qk, vk.Qcp, + &vk.Kzg.G1, + &vk.Kzg.G2[0], + &vk.Kzg.G2[1], vk.CommitmentConstraintIndexes, } @@ -275,6 +278,9 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { &vk.Qo, &vk.Qk, &vk.Qcp, + &vk.Kzg.G1, + &vk.Kzg.G2[0], + &vk.Kzg.G2[1], &vk.CommitmentConstraintIndexes, } diff --git a/backend/plonk/bw6-633/marshal_test.go b/backend/plonk/bw6-633/marshal_test.go index 039693fbf7..6e4c9d7667 100644 --- a/backend/plonk/bw6-633/marshal_test.go +++ b/backend/plonk/bw6-633/marshal_test.go @@ -159,42 +159,53 @@ func (vk *VerifyingKey) randomize() { vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} //#nosec G404 weak rng is fine here vk.CosetShift.SetRandom() - vk.S[0] = randomPoint() - vk.S[1] = randomPoint() - vk.S[2] = randomPoint() - vk.Ql = randomPoint() - vk.Qr = randomPoint() - vk.Qm = randomPoint() - vk.Qo = randomPoint() - vk.Qk = randomPoint() - vk.Qcp = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here + vk.S[0] = randomG1Point() + vk.S[1] = randomG1Point() + vk.S[2] = randomG1Point() + + vk.Kzg.G1 = randomG1Point() + vk.Kzg.G2[0] = randomG2Point() + vk.Kzg.G2[1] = randomG2Point() + + vk.Ql = randomG1Point() + vk.Qr = randomG1Point() + vk.Qm = randomG1Point() + vk.Qo = randomG1Point() + vk.Qk = randomG1Point() + vk.Qcp = randomG1Points(rand.Intn(4)) //#nosec G404 weak rng is fine here } func (proof *Proof) randomize() { - proof.LRO[0] = randomPoint() - proof.LRO[1] = randomPoint() - proof.LRO[2] = randomPoint() - proof.Z = randomPoint() - proof.H[0] = randomPoint() - proof.H[1] = randomPoint() - proof.H[2] = randomPoint() - proof.BatchedProof.H = randomPoint() + proof.LRO[0] = randomG1Point() + proof.LRO[1] = randomG1Point() + proof.LRO[2] = randomG1Point() + proof.Z = randomG1Point() + proof.H[0] = randomG1Point() + proof.H[1] = randomG1Point() + proof.H[2] = randomG1Point() + proof.BatchedProof.H = randomG1Point() proof.BatchedProof.ClaimedValues = randomScalars(2) - proof.ZShiftedOpening.H = randomPoint() + proof.ZShiftedOpening.H = randomG1Point() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.Bsb22Commitments = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here + proof.Bsb22Commitments = randomG1Points(rand.Intn(4)) //#nosec G404 weak rng is fine here } -func randomPoint() curve.G1Affine { +func randomG2Point() curve.G2Affine { + _, _, _, r := curve.Generators() + r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) //#nosec G404 weak rng is fine here + return r +} + +func randomG1Point() curve.G1Affine { _, _, r, _ := curve.Generators() r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) //#nosec G404 weak rng is fine here return r } -func randomPoints(n int) []curve.G1Affine { +func randomG1Points(n int) []curve.G1Affine { res := make([]curve.G1Affine, n) for i := range res { - res[i] = randomPoint() + res[i] = randomG1Point() } return res } diff --git a/backend/plonk/bw6-761/marshal.go b/backend/plonk/bw6-761/marshal.go index b7130a2b8c..5c46d00e18 100644 --- a/backend/plonk/bw6-761/marshal.go +++ b/backend/plonk/bw6-761/marshal.go @@ -245,6 +245,9 @@ func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*curve.Encoder)) (n &vk.Qo, &vk.Qk, vk.Qcp, + &vk.Kzg.G1, + &vk.Kzg.G2[0], + &vk.Kzg.G2[1], vk.CommitmentConstraintIndexes, } @@ -275,6 +278,9 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { &vk.Qo, &vk.Qk, &vk.Qcp, + &vk.Kzg.G1, + &vk.Kzg.G2[0], + &vk.Kzg.G2[1], &vk.CommitmentConstraintIndexes, } diff --git a/backend/plonk/bw6-761/marshal_test.go b/backend/plonk/bw6-761/marshal_test.go index e2fdc67ec8..e47c6e815b 100644 --- a/backend/plonk/bw6-761/marshal_test.go +++ b/backend/plonk/bw6-761/marshal_test.go @@ -159,42 +159,53 @@ func (vk *VerifyingKey) randomize() { vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} //#nosec G404 weak rng is fine here vk.CosetShift.SetRandom() - vk.S[0] = randomPoint() - vk.S[1] = randomPoint() - vk.S[2] = randomPoint() - vk.Ql = randomPoint() - vk.Qr = randomPoint() - vk.Qm = randomPoint() - vk.Qo = randomPoint() - vk.Qk = randomPoint() - vk.Qcp = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here + vk.S[0] = randomG1Point() + vk.S[1] = randomG1Point() + vk.S[2] = randomG1Point() + + vk.Kzg.G1 = randomG1Point() + vk.Kzg.G2[0] = randomG2Point() + vk.Kzg.G2[1] = randomG2Point() + + vk.Ql = randomG1Point() + vk.Qr = randomG1Point() + vk.Qm = randomG1Point() + vk.Qo = randomG1Point() + vk.Qk = randomG1Point() + vk.Qcp = randomG1Points(rand.Intn(4)) //#nosec G404 weak rng is fine here } func (proof *Proof) randomize() { - proof.LRO[0] = randomPoint() - proof.LRO[1] = randomPoint() - proof.LRO[2] = randomPoint() - proof.Z = randomPoint() - proof.H[0] = randomPoint() - proof.H[1] = randomPoint() - proof.H[2] = randomPoint() - proof.BatchedProof.H = randomPoint() + proof.LRO[0] = randomG1Point() + proof.LRO[1] = randomG1Point() + proof.LRO[2] = randomG1Point() + proof.Z = randomG1Point() + proof.H[0] = randomG1Point() + proof.H[1] = randomG1Point() + proof.H[2] = randomG1Point() + proof.BatchedProof.H = randomG1Point() proof.BatchedProof.ClaimedValues = randomScalars(2) - proof.ZShiftedOpening.H = randomPoint() + proof.ZShiftedOpening.H = randomG1Point() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.Bsb22Commitments = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here + proof.Bsb22Commitments = randomG1Points(rand.Intn(4)) //#nosec G404 weak rng is fine here } -func randomPoint() curve.G1Affine { +func randomG2Point() curve.G2Affine { + _, _, _, r := curve.Generators() + r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) //#nosec G404 weak rng is fine here + return r +} + +func randomG1Point() curve.G1Affine { _, _, r, _ := curve.Generators() r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) //#nosec G404 weak rng is fine here return r } -func randomPoints(n int) []curve.G1Affine { +func randomG1Points(n int) []curve.G1Affine { res := make([]curve.G1Affine, n) for i := range res { - res[i] = randomPoint() + res[i] = randomG1Point() } return res } diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl index 3d72c06013..b645b9e95f 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl @@ -225,6 +225,9 @@ func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*curve.Encoder)) (n &vk.Qo, &vk.Qk, vk.Qcp, + &vk.Kzg.G1, + &vk.Kzg.G2[0], + &vk.Kzg.G2[1], vk.CommitmentConstraintIndexes, } @@ -255,6 +258,9 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { &vk.Qo, &vk.Qk, &vk.Qcp, + &vk.Kzg.G1, + &vk.Kzg.G2[0], + &vk.Kzg.G2[1], &vk.CommitmentConstraintIndexes, } diff --git a/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl index ccffcfe9bd..cb6acbb018 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl @@ -140,42 +140,53 @@ func (vk *VerifyingKey) randomize() { vk.CommitmentConstraintIndexes = []uint64{rand.Uint64()} //#nosec G404 weak rng is fine here vk.CosetShift.SetRandom() - vk.S[0] = randomPoint() - vk.S[1] = randomPoint() - vk.S[2] = randomPoint() - vk.Ql = randomPoint() - vk.Qr = randomPoint() - vk.Qm = randomPoint() - vk.Qo = randomPoint() - vk.Qk = randomPoint() - vk.Qcp = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here + vk.S[0] = randomG1Point() + vk.S[1] = randomG1Point() + vk.S[2] = randomG1Point() + + vk.Kzg.G1 = randomG1Point() + vk.Kzg.G2[0] = randomG2Point() + vk.Kzg.G2[1] = randomG2Point() + + vk.Ql = randomG1Point() + vk.Qr = randomG1Point() + vk.Qm = randomG1Point() + vk.Qo = randomG1Point() + vk.Qk = randomG1Point() + vk.Qcp = randomG1Points(rand.Intn(4)) //#nosec G404 weak rng is fine here } func (proof *Proof) randomize() { - proof.LRO[0] = randomPoint() - proof.LRO[1] = randomPoint() - proof.LRO[2] = randomPoint() - proof.Z = randomPoint() - proof.H[0] = randomPoint() - proof.H[1] = randomPoint() - proof.H[2] = randomPoint() - proof.BatchedProof.H = randomPoint() + proof.LRO[0] = randomG1Point() + proof.LRO[1] = randomG1Point() + proof.LRO[2] = randomG1Point() + proof.Z = randomG1Point() + proof.H[0] = randomG1Point() + proof.H[1] = randomG1Point() + proof.H[2] = randomG1Point() + proof.BatchedProof.H = randomG1Point() proof.BatchedProof.ClaimedValues = randomScalars(2) - proof.ZShiftedOpening.H = randomPoint() + proof.ZShiftedOpening.H = randomG1Point() proof.ZShiftedOpening.ClaimedValue.SetRandom() - proof.Bsb22Commitments = randomPoints(rand.Intn(4)) //#nosec G404 weak rng is fine here + proof.Bsb22Commitments = randomG1Points(rand.Intn(4)) //#nosec G404 weak rng is fine here } -func randomPoint() curve.G1Affine { +func randomG2Point() curve.G2Affine{ + _,_,_, r := curve.Generators() + r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) //#nosec G404 weak rng is fine here + return r +} + +func randomG1Point() curve.G1Affine { _, _, r, _ := curve.Generators() r.ScalarMultiplication(&r, big.NewInt(int64(rand.Uint64()))) //#nosec G404 weak rng is fine here return r } -func randomPoints(n int) []curve.G1Affine { +func randomG1Points(n int) []curve.G1Affine { res := make([]curve.G1Affine, n) for i := range res { - res[i] = randomPoint() + res[i] = randomG1Point() } return res } From 3422aee800b28d3513196d2f00d072d4314373f0 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Wed, 24 May 2023 10:47:48 +0200 Subject: [PATCH 373/464] fix: removed commented code --- backend/plonk/bls12-377/verify.go | 3 --- backend/plonk/bls12-381/verify.go | 3 --- backend/plonk/bls24-315/verify.go | 3 --- backend/plonk/bls24-317/verify.go | 3 --- backend/plonk/bn254/verify.go | 3 --- backend/plonk/bw6-633/verify.go | 3 --- backend/plonk/bw6-761/verify.go | 3 --- .../backend/template/zkpschemes/plonk/plonk.verify.go.tmpl | 3 --- 8 files changed, 24 deletions(-) diff --git a/backend/plonk/bls12-377/verify.go b/backend/plonk/bls12-377/verify.go index 79ff13ad6c..c28a894d02 100644 --- a/backend/plonk/bls12-377/verify.go +++ b/backend/plonk/bls12-377/verify.go @@ -137,9 +137,6 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - // qC := make([]fr.Element, len(proof.Bsb22Commitments)) - // claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] - // claimedValues := proof.BatchedProof.ClaimedValues[7:] claimedQuotient := proof.BatchedProof.ClaimedValues[0] linearizedPolynomialZeta := proof.BatchedProof.ClaimedValues[1] l := proof.BatchedProof.ClaimedValues[2] diff --git a/backend/plonk/bls12-381/verify.go b/backend/plonk/bls12-381/verify.go index 823dc36ff6..3124e92c5e 100644 --- a/backend/plonk/bls12-381/verify.go +++ b/backend/plonk/bls12-381/verify.go @@ -137,9 +137,6 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - // qC := make([]fr.Element, len(proof.Bsb22Commitments)) - // claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] - // claimedValues := proof.BatchedProof.ClaimedValues[7:] claimedQuotient := proof.BatchedProof.ClaimedValues[0] linearizedPolynomialZeta := proof.BatchedProof.ClaimedValues[1] l := proof.BatchedProof.ClaimedValues[2] diff --git a/backend/plonk/bls24-315/verify.go b/backend/plonk/bls24-315/verify.go index 2fdee5191e..81dc747e0b 100644 --- a/backend/plonk/bls24-315/verify.go +++ b/backend/plonk/bls24-315/verify.go @@ -137,9 +137,6 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - // qC := make([]fr.Element, len(proof.Bsb22Commitments)) - // claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] - // claimedValues := proof.BatchedProof.ClaimedValues[7:] claimedQuotient := proof.BatchedProof.ClaimedValues[0] linearizedPolynomialZeta := proof.BatchedProof.ClaimedValues[1] l := proof.BatchedProof.ClaimedValues[2] diff --git a/backend/plonk/bls24-317/verify.go b/backend/plonk/bls24-317/verify.go index 4092168df5..a6a7479e08 100644 --- a/backend/plonk/bls24-317/verify.go +++ b/backend/plonk/bls24-317/verify.go @@ -137,9 +137,6 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - // qC := make([]fr.Element, len(proof.Bsb22Commitments)) - // claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] - // claimedValues := proof.BatchedProof.ClaimedValues[7:] claimedQuotient := proof.BatchedProof.ClaimedValues[0] linearizedPolynomialZeta := proof.BatchedProof.ClaimedValues[1] l := proof.BatchedProof.ClaimedValues[2] diff --git a/backend/plonk/bn254/verify.go b/backend/plonk/bn254/verify.go index c0306b93cf..4820560fe5 100644 --- a/backend/plonk/bn254/verify.go +++ b/backend/plonk/bn254/verify.go @@ -139,9 +139,6 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - // qC := make([]fr.Element, len(proof.Bsb22Commitments)) - // claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] - // claimedValues := proof.BatchedProof.ClaimedValues[7:] claimedQuotient := proof.BatchedProof.ClaimedValues[0] linearizedPolynomialZeta := proof.BatchedProof.ClaimedValues[1] l := proof.BatchedProof.ClaimedValues[2] diff --git a/backend/plonk/bw6-633/verify.go b/backend/plonk/bw6-633/verify.go index 6cf76e2252..63c4b1dbfb 100644 --- a/backend/plonk/bw6-633/verify.go +++ b/backend/plonk/bw6-633/verify.go @@ -137,9 +137,6 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - // qC := make([]fr.Element, len(proof.Bsb22Commitments)) - // claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] - // claimedValues := proof.BatchedProof.ClaimedValues[7:] claimedQuotient := proof.BatchedProof.ClaimedValues[0] linearizedPolynomialZeta := proof.BatchedProof.ClaimedValues[1] l := proof.BatchedProof.ClaimedValues[2] diff --git a/backend/plonk/bw6-761/verify.go b/backend/plonk/bw6-761/verify.go index 57e511abf0..51c0719b8d 100644 --- a/backend/plonk/bw6-761/verify.go +++ b/backend/plonk/bw6-761/verify.go @@ -137,9 +137,6 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - // qC := make([]fr.Element, len(proof.Bsb22Commitments)) - // claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] - // claimedValues := proof.BatchedProof.ClaimedValues[7:] claimedQuotient := proof.BatchedProof.ClaimedValues[0] linearizedPolynomialZeta := proof.BatchedProof.ClaimedValues[1] l := proof.BatchedProof.ClaimedValues[2] diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl index c0b9d4caf0..3ab826cedd 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl @@ -118,9 +118,6 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { zu := proof.ZShiftedOpening.ClaimedValue - // qC := make([]fr.Element, len(proof.Bsb22Commitments)) - // claimedValues := proof.BatchedProof.ClaimedValues[len(proof.Bsb22Commitments):] - // claimedValues := proof.BatchedProof.ClaimedValues[7:] claimedQuotient := proof.BatchedProof.ClaimedValues[0] linearizedPolynomialZeta := proof.BatchedProof.ClaimedValues[1] l := proof.BatchedProof.ClaimedValues[2] From 31da8a215c9ac1ae3707af7b4a0b23e77584511a Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Wed, 24 May 2023 18:21:35 +0200 Subject: [PATCH 374/464] fix: removed non used code --- backend/plonk/bn254/to_delete.go | 378 ------------------------------- 1 file changed, 378 deletions(-) delete mode 100644 backend/plonk/bn254/to_delete.go diff --git a/backend/plonk/bn254/to_delete.go b/backend/plonk/bn254/to_delete.go deleted file mode 100644 index a167275283..0000000000 --- a/backend/plonk/bn254/to_delete.go +++ /dev/null @@ -1,378 +0,0 @@ -package plonk - -import ( - "errors" - "hash" - "math/big" - - "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark-crypto/ecc/bn254/fr" - fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" -) - -var ( - ErrInvalidNbDigests = errors.New("number of digests is not the same as the number of polynomials") - ErrZeroNbDigests = errors.New("number of digests is zero") - ErrInvalidPolynomialSize = errors.New("invalid polynomial size (larger than SRS or == 0)") - ErrVerifyKzgOpeningProof = errors.New("can't verify opening proof") - ErrVerifyKzgBatchOpeningSinglePoint = errors.New("can't verify batch opening proof at single point") - ErrMinSRSSize = errors.New("minimum srs size is 2") -) - -// Digest commitment of a polynomial. -type Digest = bn254.G1Affine - -// KzgProvingKey used to create or open commitments -type KzgProvingKey struct { - G1 []bn254.G1Affine // [G₁ [α]G₁ , [α²]G₁, ... ] -} - -// KzgVerificationKey used to verify opening proofs -type KzgVerificationKey struct { - G2 [2]bn254.G2Affine // [G₂, [α]G₂ ] - G1 bn254.G1Affine -} - -// SRS must be computed through MPC and comprises the KzgProvingKey and the KzgVerificationKey -type SRS struct { - Pk KzgProvingKey - Vk KzgVerificationKey -} - -// TODO @Tabaie get rid of this and use the polynomial package -// eval returns p(point) where p is interpreted as a polynomial -// ∑_{i= 0; i-- { - res.Mul(&res, &point).Add(&res, &p[i]) - } - return res -} - -// NewSRS returns a new SRS using alpha as randomness source -// -// In production, a SRS generated through MPC should be used. -// -// implements io.ReaderFrom and io.WriterTo -func NewSRS(size uint64, bAlpha *big.Int) (*SRS, error) { - - if size < 2 { - return nil, ErrMinSRSSize - } - var srs SRS - srs.Pk.G1 = make([]bn254.G1Affine, size) - - var alpha fr.Element - alpha.SetBigInt(bAlpha) - - _, _, gen1Aff, gen2Aff := bn254.Generators() - srs.Pk.G1[0] = gen1Aff - srs.Vk.G1 = gen1Aff - srs.Vk.G2[0] = gen2Aff - srs.Vk.G2[1].ScalarMultiplication(&gen2Aff, bAlpha) - - alphas := make([]fr.Element, size-1) - alphas[0] = alpha - for i := 1; i < len(alphas); i++ { - alphas[i].Mul(&alphas[i-1], &alpha) - } - g1s := bn254.BatchScalarMultiplicationG1(&gen1Aff, alphas) - copy(srs.Pk.G1[1:], g1s) - - return &srs, nil -} - -// OpeningProof KZG proof for opening at a single point. -// -// implements io.ReaderFrom and io.WriterTo -type OpeningProof struct { - // H quotient polynomial (f - f(z))/(x-z) - H bn254.G1Affine - - // ClaimedValue purported value - ClaimedValue fr.Element -} - -// BatchOpeningProof opening proof for many polynomials at the same point -// -// implements io.ReaderFrom and io.WriterTo -type BatchOpeningProof struct { - // H quotient polynomial Sum_i gamma**i*(f - f(z))/(x-z) - H bn254.G1Affine - - // ClaimedValues purported values - ClaimedValues []fr.Element -} - -// VerifyKzg verifies a KZG opening proof at a single point -func VerifyKzg(commitment *Digest, proof *OpeningProof, point fr.Element, vk KzgVerificationKey) error { - - // [f(a)]G₁ - var claimedValueG1Aff bn254.G1Jac - var claimedValueBigInt big.Int - proof.ClaimedValue.BigInt(&claimedValueBigInt) - claimedValueG1Aff.ScalarMultiplicationAffine(&vk.G1, &claimedValueBigInt) - - // [f(α) - f(a)]G₁ - var fminusfaG1Jac bn254.G1Jac - fminusfaG1Jac.FromAffine(commitment) - fminusfaG1Jac.SubAssign(&claimedValueG1Aff) - - // [-H(α)]G₁ - var negH bn254.G1Affine - negH.Neg(&proof.H) - - // [f(α) - f(a) + a*H(α)]G₁ - var totalG1 bn254.G1Jac - var pointBigInt big.Int - point.BigInt(&pointBigInt) - totalG1.ScalarMultiplicationAffine(&proof.H, &pointBigInt) - totalG1.AddAssign(&fminusfaG1Jac) - var totalG1Aff bn254.G1Affine - totalG1Aff.FromJacobian(&totalG1) - - // e([f(α)-f(a)+aH(α)]G₁], G₂).e([-H(α)]G₁, [α]G₂) == 1 - check, err := bn254.PairingCheck( - []bn254.G1Affine{totalG1Aff, negH}, - []bn254.G2Affine{vk.G2[0], vk.G2[1]}, - ) - if err != nil { - return err - } - if !check { - return ErrVerifyKzgOpeningProof - } - return nil -} - -// FoldProof fold the digests and the proofs in batchOpeningProof using Fiat Shamir -// to obtain an opening proof at a single point. -// -// * digests list of digests on which batchOpeningProof is based -// * batchOpeningProof opening proof of digests -// * returns the folded version of batchOpeningProof, Digest, the folded version of digests -func FoldProof(digests []Digest, batchOpeningProof *BatchOpeningProof, point fr.Element, hf hash.Hash) (OpeningProof, Digest, error) { - - nbDigests := len(digests) - - // check consistency between numbers of claims vs number of digests - if nbDigests != len(batchOpeningProof.ClaimedValues) { - return OpeningProof{}, Digest{}, ErrInvalidNbDigests - } - - // derive the challenge γ, binded to the point and the commitments - gamma, err := deriveGamma(point, digests, batchOpeningProof.ClaimedValues, hf) - if err != nil { - return OpeningProof{}, Digest{}, ErrInvalidNbDigests - } - - // fold the claimed values and digests - // gammai = [1,γ,γ²,..,γⁿ⁻¹] - gammai := make([]fr.Element, nbDigests) - gammai[0].SetOne() - if nbDigests > 1 { - gammai[1] = gamma - } - for i := 2; i < nbDigests; i++ { - gammai[i].Mul(&gammai[i-1], &gamma) - } - - foldedDigests, foldedEvaluations, err := fold(digests, batchOpeningProof.ClaimedValues, gammai) - if err != nil { - return OpeningProof{}, Digest{}, err - } - - // create the folded opening proof - var res OpeningProof - res.ClaimedValue.Set(&foldedEvaluations) - res.H.Set(&batchOpeningProof.H) - - return res, foldedDigests, nil -} - -// BatchVerifyKzgSinglePoint verifies a batched opening proof at a single point of a list of polynomials. -// -// * digests list of digests on which opening proof is done -// * batchOpeningProof proof of correct opening on the digests -func BatchVerifyKzgSinglePoint(digests []Digest, batchOpeningProof *BatchOpeningProof, point fr.Element, hf hash.Hash, vk KzgVerificationKey) error { - - // fold the proof - foldedProof, foldedDigest, err := FoldProof(digests, batchOpeningProof, point, hf) - if err != nil { - return err - } - - // verify the foldedProof against the foldedDigest - err = VerifyKzg(&foldedDigest, &foldedProof, point, vk) - return err - -} - -// BatchVerifyKzgMultiPoints batch verifies a list of opening proofs at different points. -// The purpose of the batching is to have only one pairing for verifying several proofs. -// -// * digests list of committed polynomials -// * proofs list of opening proofs, one for each digest -// * points the list of points at which the opening are done -func BatchVerifyKzgMultiPoints(digests []Digest, proofs []OpeningProof, points []fr.Element, vk KzgVerificationKey) error { - - // check consistency nb proogs vs nb digests - if len(digests) != len(proofs) || len(digests) != len(points) { - return ErrInvalidNbDigests - } - - // len(digests) should be nonzero because of randomNumbers - if len(digests) == 0 { - return ErrZeroNbDigests - } - - // if only one digest, call VerifyKzg - if len(digests) == 1 { - return VerifyKzg(&digests[0], &proofs[0], points[0], vk) - } - - // sample random numbers λᵢ for sampling - randomNumbers := make([]fr.Element, len(digests)) - randomNumbers[0].SetOne() - for i := 1; i < len(randomNumbers); i++ { - // _, err := randomNumbers[i].SetRandom() - // if err != nil { - // return err - // } - randomNumbers[i].SetUint64(3) - } - - // fold the committed quotients compute ∑ᵢλᵢ[Hᵢ(α)]G₁ - var foldedQuotients bn254.G1Affine - quotients := make([]bn254.G1Affine, len(proofs)) - for i := 0; i < len(randomNumbers); i++ { - quotients[i].Set(&proofs[i].H) - } - config := ecc.MultiExpConfig{} - if _, err := foldedQuotients.MultiExp(quotients, randomNumbers, config); err != nil { - return err - } - - // fold digests and evals - // proofs[1].ClaimedValue.SetZero() - evals := make([]fr.Element, len(digests)) - for i := 0; i < len(randomNumbers); i++ { - evals[i].Set(&proofs[i].ClaimedValue) - } - - // fold the digests: ∑ᵢλᵢ[f_i(α)]G₁ - // fold the evals : ∑ᵢλᵢfᵢ(aᵢ) - foldedDigests, foldedEvals, err := fold(digests, evals, randomNumbers) - if err != nil { - return err - } - - // compute commitment to folded Eval [∑ᵢλᵢfᵢ(aᵢ)]G₁ - var foldedEvalsCommit bn254.G1Affine - var foldedEvalsBigInt big.Int - foldedEvals.BigInt(&foldedEvalsBigInt) - foldedEvalsCommit.ScalarMultiplication(&vk.G1, &foldedEvalsBigInt) - - // compute foldedDigests = ∑ᵢλᵢ[fᵢ(α)]G₁ - [∑ᵢλᵢfᵢ(aᵢ)]G₁ - foldedDigests.Sub(&foldedDigests, &foldedEvalsCommit) - - // combien the points and the quotients using γᵢ - // ∑ᵢλᵢ[p_i]([Hᵢ(α)]G₁) - var foldedPointsQuotients bn254.G1Affine - for i := 0; i < len(randomNumbers); i++ { - randomNumbers[i].Mul(&randomNumbers[i], &points[i]) - } - _, err = foldedPointsQuotients.MultiExp(quotients, randomNumbers, config) - if err != nil { - return err - } - - // ∑ᵢλᵢ[f_i(α)]G₁ - [∑ᵢλᵢfᵢ(aᵢ)]G₁ + ∑ᵢλᵢ[p_i]([Hᵢ(α)]G₁) - // = [∑ᵢλᵢf_i(α) - ∑ᵢλᵢfᵢ(aᵢ) + ∑ᵢλᵢpᵢHᵢ(α)]G₁ - foldedDigests.Add(&foldedDigests, &foldedPointsQuotients) - - // -∑ᵢλᵢ[Qᵢ(α)]G₁ - foldedQuotients.Neg(&foldedQuotients) - - // fmt.Println(foldedDigests.String()) - foldedDigests.X.SetString("9580734902255794050927938530373971926002234939716450249429720642097067006115") - foldedDigests.Y.SetString("3278335512197874161585664087513619970054206473530059271941844570397867805823") - - // pairing check - // e([∑ᵢλᵢ(fᵢ(α) - fᵢ(pᵢ) + pᵢHᵢ(α))]G₁, G₂).e([-∑ᵢλᵢ[Hᵢ(α)]G₁), [α]G₂) - check, err := bn254.PairingCheck( - []bn254.G1Affine{foldedDigests, foldedQuotients}, - []bn254.G2Affine{vk.G2[0], vk.G2[1]}, - ) - if err != nil { - return err - } - if !check { - return ErrVerifyKzgOpeningProof - } - return nil - -} - -// fold folds digests and evaluations using the list of factors as random numbers. -// -// * digests list of digests to fold -// * evaluations list of evaluations to fold -// * factors list of multiplicative factors used for the folding (in Montgomery form) -// -// * Returns ∑ᵢcᵢdᵢ, ∑ᵢcᵢf(aᵢ) -func fold(di []Digest, fai []fr.Element, ci []fr.Element) (Digest, fr.Element, error) { - - // length inconsistency between digests and evaluations should have been done before calling this function - nbDigests := len(di) - - // fold the claimed values ∑ᵢcᵢf(aᵢ) - var foldedEvaluations, tmp fr.Element - for i := 0; i < nbDigests; i++ { - tmp.Mul(&fai[i], &ci[i]) - foldedEvaluations.Add(&foldedEvaluations, &tmp) - } - - // fold the digests ∑ᵢ[cᵢ]([fᵢ(α)]G₁) - var foldedDigests Digest - _, err := foldedDigests.MultiExp(di, ci, ecc.MultiExpConfig{}) - if err != nil { - return foldedDigests, foldedEvaluations, err - } - - // folding done - return foldedDigests, foldedEvaluations, nil - -} - -// deriveGamma derives a challenge using Fiat Shamir to fold proofs. -func deriveGamma(point fr.Element, digests []Digest, claimedValues []fr.Element, hf hash.Hash) (fr.Element, error) { - - // derive the challenge gamma, binded to the point and the commitments - fs := fiatshamir.NewTranscript(hf, "gamma") - if err := fs.Bind("gamma", point.Marshal()); err != nil { - return fr.Element{}, err - } - for i := range digests { - if err := fs.Bind("gamma", digests[i].Marshal()); err != nil { - return fr.Element{}, err - } - } - for i := range claimedValues { - if err := fs.Bind("gamma", claimedValues[i].Marshal()); err != nil { - return fr.Element{}, err - } - } - gammaByte, err := fs.ComputeChallenge("gamma") - if err != nil { - return fr.Element{}, err - } - var gamma fr.Element - gamma.SetBytes(gammaByte) - - return gamma, nil -} From 199cf77f64f3afe6c3f1ebf0c4e3da275f5a5423 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Wed, 24 May 2023 18:29:43 +0200 Subject: [PATCH 375/464] fix: remove dead file --- backend/plonk/bn254/tips.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 backend/plonk/bn254/tips.txt diff --git a/backend/plonk/bn254/tips.txt b/backend/plonk/bn254/tips.txt deleted file mode 100644 index 75e4164e4e..0000000000 --- a/backend/plonk/bn254/tips.txt +++ /dev/null @@ -1 +0,0 @@ -- got rid of arrays for G2 points From a57228393dbca62b662dad03762475fefe18bb2e Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Wed, 24 May 2023 18:33:03 +0200 Subject: [PATCH 376/464] fix: removed solidity folder --- backend/plonk/bn254/solidity.go | 907 ------------------ .../bn254/solidity/abi/PlonkVerifier.abi | 1 - .../bn254/solidity/abi/PlonkVerifier.bin | 1 - .../plonk/bn254/solidity/abi/TestVerifier.abi | 1 - .../plonk/bn254/solidity/abi/TestVerifier.bin | 1 - backend/plonk/bn254/solidity/abi/Utils.abi | 1 - backend/plonk/bn254/solidity/abi/Utils.bin | 1 - 7 files changed, 913 deletions(-) delete mode 100644 backend/plonk/bn254/solidity.go delete mode 100644 backend/plonk/bn254/solidity/abi/PlonkVerifier.abi delete mode 100644 backend/plonk/bn254/solidity/abi/PlonkVerifier.bin delete mode 100644 backend/plonk/bn254/solidity/abi/TestVerifier.abi delete mode 100644 backend/plonk/bn254/solidity/abi/TestVerifier.bin delete mode 100644 backend/plonk/bn254/solidity/abi/Utils.abi delete mode 100644 backend/plonk/bn254/solidity/abi/Utils.bin diff --git a/backend/plonk/bn254/solidity.go b/backend/plonk/bn254/solidity.go deleted file mode 100644 index 7fddbd204f..0000000000 --- a/backend/plonk/bn254/solidity.go +++ /dev/null @@ -1,907 +0,0 @@ -package plonk - -const solidityTemplate = ` -// Warning this code was contributed into gnark here: -// https://github.com/ConsenSys/gnark/pull/358 -// -// It has not been audited and is provided as-is, we make no guarantees or warranties to its safety and reliability. -// -// According to https://eprint.iacr.org/archive/2019/953/1585767119.pdf -pragma solidity ^0.8.0; -pragma experimental ABIEncoderV2; - -library PairingsBn254 { - uint256 constant q_mod = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - uint256 constant r_mod = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - uint256 constant bn254_b_coeff = 3; - - struct G1Point { - uint256 X; - uint256 Y; - } - - struct Fr { - uint256 value; - } - - function new_fr(uint256 fr) internal pure returns (Fr memory) { - require(fr < r_mod); - return Fr({value: fr}); - } - - function copy(Fr memory self) internal pure returns (Fr memory n) { - n.value = self.value; - } - - function assign(Fr memory self, Fr memory other) internal pure { - self.value = other.value; - } - - function inverse(Fr memory fr) internal view returns (Fr memory) { - require(fr.value != 0); - return pow(fr, r_mod-2); - } - - function add_assign(Fr memory self, Fr memory other) internal pure { - self.value = addmod(self.value, other.value, r_mod); - } - - function sub_assign(Fr memory self, Fr memory other) internal pure { - self.value = addmod(self.value, r_mod - other.value, r_mod); - } - - function mul_assign(Fr memory self, Fr memory other) internal pure { - self.value = mulmod(self.value, other.value, r_mod); - } - - function pow(Fr memory self, uint256 power) internal view returns (Fr memory) { - uint256[6] memory input = [32, 32, 32, self.value, power, r_mod]; - uint256[1] memory result; - bool success; - assembly { - success := staticcall(gas(), 0x05, input, 0xc0, result, 0x20) - } - require(success); - return Fr({value: result[0]}); - } - - // Encoding of field elements is: X[0] * z + X[1] - struct G2Point { - uint[2] X; - uint[2] Y; - } - - function P1() internal pure returns (G1Point memory) { - return G1Point(1, 2); - } - - function new_g1(uint256 x, uint256 y) internal pure returns (G1Point memory) { - return G1Point(x, y); - } - - function new_g1_checked(uint256 x, uint256 y) internal pure returns (G1Point memory) { - if (x == 0 && y == 0) { - // point of infinity is (0,0) - return G1Point(x, y); - } - - // check encoding - require(x < q_mod); - require(y < q_mod); - // check on curve - uint256 lhs = mulmod(y, y, q_mod); // y^2 - uint256 rhs = mulmod(x, x, q_mod); // x^2 - rhs = mulmod(rhs, x, q_mod); // x^3 - rhs = addmod(rhs, bn254_b_coeff, q_mod); // x^3 + b - require(lhs == rhs); - - return G1Point(x, y); - } - - function new_g2(uint256[2] memory x, uint256[2] memory y) internal pure returns (G2Point memory) { - return G2Point(x, y); - } - - function copy_g1(G1Point memory self) internal pure returns (G1Point memory result) { - result.X = self.X; - result.Y = self.Y; - } - - function P2() internal pure returns (G2Point memory) { - // for some reason ethereum expects to have c1*v + c0 form - - return G2Point( - [0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2, - 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed], - [0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b, - 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa] - ); - } - - function negate(G1Point memory self) internal pure { - // The prime q in the base field F_q for G1 - if (self.Y == 0) { - require(self.X == 0); - return; - } - - self.Y = q_mod - self.Y; - } - - function point_add(G1Point memory p1, G1Point memory p2) - internal view returns (G1Point memory r) - { - point_add_into_dest(p1, p2, r); - return r; - } - - function point_add_assign(G1Point memory p1, G1Point memory p2) - internal view - { - point_add_into_dest(p1, p2, p1); - } - - function point_add_into_dest(G1Point memory p1, G1Point memory p2, G1Point memory dest) - internal view - { - if (p2.X == 0 && p2.Y == 0) { - // we add zero, nothing happens - dest.X = p1.X; - dest.Y = p1.Y; - return; - } else if (p1.X == 0 && p1.Y == 0) { - // we add into zero, and we add non-zero point - dest.X = p2.X; - dest.Y = p2.Y; - return; - } else { - uint256[4] memory input; - - input[0] = p1.X; - input[1] = p1.Y; - input[2] = p2.X; - input[3] = p2.Y; - - bool success = false; - assembly { - success := staticcall(gas(), 6, input, 0x80, dest, 0x40) - } - require(success); - } - } - - function point_sub_assign(G1Point memory p1, G1Point memory p2) - internal view - { - point_sub_into_dest(p1, p2, p1); - } - - function point_sub_into_dest(G1Point memory p1, G1Point memory p2, G1Point memory dest) - internal view - { - if (p2.X == 0 && p2.Y == 0) { - // we subtracted zero, nothing happens - dest.X = p1.X; - dest.Y = p1.Y; - return; - } else if (p1.X == 0 && p1.Y == 0) { - // we subtract from zero, and we subtract non-zero point - dest.X = p2.X; - dest.Y = q_mod - p2.Y; - return; - } else { - uint256[4] memory input; - - input[0] = p1.X; - input[1] = p1.Y; - input[2] = p2.X; - input[3] = q_mod - p2.Y; - - bool success = false; - assembly { - success := staticcall(gas(), 6, input, 0x80, dest, 0x40) - } - require(success); - } - } - - function point_mul(G1Point memory p, Fr memory s) - internal view returns (G1Point memory r) - { - point_mul_into_dest(p, s, r); - return r; - } - - function point_mul_assign(G1Point memory p, Fr memory s) - internal view - { - point_mul_into_dest(p, s, p); - } - - function point_mul_into_dest(G1Point memory p, Fr memory s, G1Point memory dest) - internal view - { - uint[3] memory input; - input[0] = p.X; - input[1] = p.Y; - input[2] = s.value; - bool success; - assembly { - success := staticcall(gas(), 7, input, 0x60, dest, 0x40) - } - require(success); - } - - function pairing(G1Point[] memory p1, G2Point[] memory p2) - internal view returns (bool) - { - require(p1.length == p2.length); - uint elements = p1.length; - uint inputSize = elements * 6; - uint[] memory input = new uint[](inputSize); - for (uint i = 0; i < elements; i++) - { - input[i * 6 + 0] = p1[i].X; - input[i * 6 + 1] = p1[i].Y; - input[i * 6 + 2] = p2[i].X[0]; - input[i * 6 + 3] = p2[i].X[1]; - input[i * 6 + 4] = p2[i].Y[0]; - input[i * 6 + 5] = p2[i].Y[1]; - } - uint[1] memory out; - bool success; - assembly { - success := staticcall(gas(), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20) - } - require(success); - return out[0] != 0; - } - - /// Convenience method for a pairing check for two pairs. - function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) - internal view returns (bool) - { - G1Point[] memory p1 = new G1Point[](2); - G2Point[] memory p2 = new G2Point[](2); - p1[0] = a1; - p1[1] = b1; - p2[0] = a2; - p2[1] = b2; - return pairing(p1, p2); - } -} - -library TranscriptLibrary { - uint32 constant DST_0 = 0; - uint32 constant DST_1 = 1; - uint32 constant DST_CHALLENGE = 2; - - struct Transcript { - bytes32 previous_randomness; - bytes bindings; - string name; - uint32 challenge_counter; - } - - function new_transcript() internal pure returns (Transcript memory t) { - t.challenge_counter = 0; - } - - function set_challenge_name(Transcript memory self, string memory name) internal pure { - self.name = name; - } - - function update_with_u256(Transcript memory self, uint256 value) internal pure { - self.bindings = abi.encodePacked(self.bindings, value); - } - - function update_with_fr(Transcript memory self, PairingsBn254.Fr memory value) internal pure { - self.bindings = abi.encodePacked(self.bindings, value.value); - } - - function update_with_g1(Transcript memory self, PairingsBn254.G1Point memory p) internal pure { - self.bindings = abi.encodePacked(self.bindings, p.X, p.Y); - } - - function get_encode(Transcript memory self) internal pure returns(bytes memory query) { - if (self.challenge_counter != 0) { - query = abi.encodePacked(self.name, self.previous_randomness, self.bindings); - } else { - query = abi.encodePacked(self.name, self.bindings); - } - return query; - } - function get_challenge(Transcript memory self) internal pure returns(PairingsBn254.Fr memory challenge) { - bytes32 query; - if (self.challenge_counter != 0) { - query = sha256(abi.encodePacked(self.name, self.previous_randomness, self.bindings)); - } else { - query = sha256(abi.encodePacked(self.name, self.bindings)); - } - self.challenge_counter += 1; - self.previous_randomness = query; - challenge = PairingsBn254.Fr({value: uint256(query) % PairingsBn254.r_mod}); - self.bindings = ""; - } -} - -contract PlonkVerifier { - using PairingsBn254 for PairingsBn254.G1Point; - using PairingsBn254 for PairingsBn254.G2Point; - using PairingsBn254 for PairingsBn254.Fr; - - using TranscriptLibrary for TranscriptLibrary.Transcript; - - uint256 constant STATE_WIDTH = 3; - - struct VerificationKey { - uint256 domain_size; - uint256 num_inputs; - PairingsBn254.Fr omega; // w - PairingsBn254.G1Point[STATE_WIDTH+2] selector_commitments; // STATE_WIDTH for witness + multiplication + constant - PairingsBn254.G1Point[STATE_WIDTH] permutation_commitments; // [Sσ1(x)],[Sσ2(x)],[Sσ3(x)] - PairingsBn254.Fr[STATE_WIDTH-1] permutation_non_residues; // k1, k2 - PairingsBn254.G2Point g2_x; - } - - struct Proof { - uint256[] input_values; - PairingsBn254.G1Point[STATE_WIDTH] wire_commitments; // [a(x)]/[b(x)]/[c(x)] - PairingsBn254.G1Point grand_product_commitment; // [z(x)] - PairingsBn254.G1Point[STATE_WIDTH] quotient_poly_commitments; // [t_lo]/[t_mid]/[t_hi] - PairingsBn254.Fr[STATE_WIDTH] wire_values_at_zeta; // a(zeta)/b(zeta)/c(zeta) - PairingsBn254.Fr grand_product_at_zeta_omega; // z(w*zeta) - PairingsBn254.Fr quotient_polynomial_at_zeta; // t(zeta) - PairingsBn254.Fr linearization_polynomial_at_zeta; // r(zeta) - PairingsBn254.Fr[STATE_WIDTH-1] permutation_polynomials_at_zeta; // Sσ1(zeta),Sσ2(zeta) - - PairingsBn254.G1Point opening_at_zeta_proof; // [Wzeta] - PairingsBn254.G1Point opening_at_zeta_omega_proof; // [Wzeta*omega] - } - - struct PartialVerifierState { - PairingsBn254.Fr alpha; - PairingsBn254.Fr beta; - PairingsBn254.Fr gamma; - PairingsBn254.Fr v; - PairingsBn254.Fr u; - PairingsBn254.Fr zeta; - PairingsBn254.Fr[] cached_lagrange_evals; - - PairingsBn254.G1Point cached_fold_quotient_ploy_commitments; - } - - function verify_initial( - PartialVerifierState memory state, - Proof memory proof, - VerificationKey memory vk) internal view returns (bool) { - - require(proof.input_values.length == vk.num_inputs, "not match"); - require(vk.num_inputs >= 1, "inv input"); - - TranscriptLibrary.Transcript memory t = TranscriptLibrary.new_transcript(); - t.set_challenge_name("gamma"); - for (uint256 i = 0; i < vk.permutation_commitments.length; i++) { - t.update_with_g1(vk.permutation_commitments[i]); - } - // this is gnark order: Ql, Qr, Qm, Qo, Qk - // - t.update_with_g1(vk.selector_commitments[0]); - t.update_with_g1(vk.selector_commitments[1]); - t.update_with_g1(vk.selector_commitments[3]); - t.update_with_g1(vk.selector_commitments[2]); - t.update_with_g1(vk.selector_commitments[4]); - - for (uint256 i = 0; i < proof.input_values.length; i++) { - t.update_with_u256(proof.input_values[i]); - } - state.gamma = t.get_challenge(); - - t.set_challenge_name("beta"); - state.beta = t.get_challenge(); - - t.set_challenge_name("alpha"); - t.update_with_g1(proof.grand_product_commitment); - state.alpha = t.get_challenge(); - - t.set_challenge_name("zeta"); - for (uint256 i = 0; i < proof.quotient_poly_commitments.length; i++) { - t.update_with_g1(proof.quotient_poly_commitments[i]); - } - state.zeta = t.get_challenge(); - - uint256[] memory lagrange_poly_numbers = new uint256[](vk.num_inputs); - for (uint256 i = 0; i < lagrange_poly_numbers.length; i++) { - lagrange_poly_numbers[i] = i; - } - state.cached_lagrange_evals = batch_evaluate_lagrange_poly_out_of_domain( - lagrange_poly_numbers, - vk.domain_size, - vk.omega, state.zeta - ); - - bool valid = verify_quotient_poly_eval_at_zeta(state, proof, vk); - return valid; - } - - function verify_commitments( - PartialVerifierState memory state, - Proof memory proof, - VerificationKey memory vk - ) internal view returns (bool) { - PairingsBn254.G1Point memory d = reconstruct_d(state, proof, vk); - - PairingsBn254.G1Point memory tmp_g1 = PairingsBn254.P1(); - - PairingsBn254.Fr memory aggregation_challenge = PairingsBn254.new_fr(1); - - PairingsBn254.G1Point memory commitment_aggregation = PairingsBn254.copy_g1(state.cached_fold_quotient_ploy_commitments); - PairingsBn254.Fr memory tmp_fr = PairingsBn254.new_fr(1); - - aggregation_challenge.mul_assign(state.v); - commitment_aggregation.point_add_assign(d); - - for (uint i = 0; i < proof.wire_commitments.length; i++) { - aggregation_challenge.mul_assign(state.v); - tmp_g1 = proof.wire_commitments[i].point_mul(aggregation_challenge); - commitment_aggregation.point_add_assign(tmp_g1); - } - - for (uint i = 0; i < vk.permutation_commitments.length - 1; i++) { - aggregation_challenge.mul_assign(state.v); - tmp_g1 = vk.permutation_commitments[i].point_mul(aggregation_challenge); - commitment_aggregation.point_add_assign(tmp_g1); - } - - // collect opening values - aggregation_challenge = PairingsBn254.new_fr(1); - - PairingsBn254.Fr memory aggregated_value = PairingsBn254.copy(proof.quotient_polynomial_at_zeta); - - aggregation_challenge.mul_assign(state.v); - - tmp_fr.assign(proof.linearization_polynomial_at_zeta); - tmp_fr.mul_assign(aggregation_challenge); - aggregated_value.add_assign(tmp_fr); - - for (uint i = 0; i < proof.wire_values_at_zeta.length; i++) { - aggregation_challenge.mul_assign(state.v); - - tmp_fr.assign(proof.wire_values_at_zeta[i]); - tmp_fr.mul_assign(aggregation_challenge); - aggregated_value.add_assign(tmp_fr); - } - - for (uint i = 0; i < proof.permutation_polynomials_at_zeta.length; i++) { - aggregation_challenge.mul_assign(state.v); - - tmp_fr.assign(proof.permutation_polynomials_at_zeta[i]); - tmp_fr.mul_assign(aggregation_challenge); - aggregated_value.add_assign(tmp_fr); - } - tmp_fr.assign(proof.grand_product_at_zeta_omega); - tmp_fr.mul_assign(state.u); - aggregated_value.add_assign(tmp_fr); - - commitment_aggregation.point_sub_assign(PairingsBn254.P1().point_mul(aggregated_value)); - - PairingsBn254.G1Point memory pair_with_generator = commitment_aggregation; - pair_with_generator.point_add_assign(proof.opening_at_zeta_proof.point_mul(state.zeta)); - - tmp_fr.assign(state.zeta); - tmp_fr.mul_assign(vk.omega); - tmp_fr.mul_assign(state.u); - pair_with_generator.point_add_assign(proof.opening_at_zeta_omega_proof.point_mul(tmp_fr)); - - PairingsBn254.G1Point memory pair_with_x = proof.opening_at_zeta_omega_proof.point_mul(state.u); - pair_with_x.point_add_assign(proof.opening_at_zeta_proof); - pair_with_x.negate(); - - return PairingsBn254.pairingProd2(pair_with_generator, PairingsBn254.P2(), pair_with_x, vk.g2_x); - } - - function reconstruct_d( - PartialVerifierState memory state, - Proof memory proof, - VerificationKey memory vk - ) internal view returns (PairingsBn254.G1Point memory res) { - res = PairingsBn254.copy_g1(vk.selector_commitments[STATE_WIDTH + 1]); - - PairingsBn254.G1Point memory tmp_g1 = PairingsBn254.P1(); - PairingsBn254.Fr memory tmp_fr = PairingsBn254.new_fr(0); - - // addition gates - for (uint256 i = 0; i < STATE_WIDTH; i++) { - tmp_g1 = vk.selector_commitments[i].point_mul(proof.wire_values_at_zeta[i]); - res.point_add_assign(tmp_g1); - } - - // multiplication gate - tmp_fr.assign(proof.wire_values_at_zeta[0]); - tmp_fr.mul_assign(proof.wire_values_at_zeta[1]); - tmp_g1 = vk.selector_commitments[STATE_WIDTH].point_mul(tmp_fr); - res.point_add_assign(tmp_g1); - - // z * non_res * beta + gamma + a - PairingsBn254.Fr memory grand_product_part_at_z = PairingsBn254.copy(state.zeta); - grand_product_part_at_z.mul_assign(state.beta); - grand_product_part_at_z.add_assign(proof.wire_values_at_zeta[0]); - grand_product_part_at_z.add_assign(state.gamma); - for (uint256 i = 0; i < vk.permutation_non_residues.length; i++) { - tmp_fr.assign(state.zeta); - tmp_fr.mul_assign(vk.permutation_non_residues[i]); - tmp_fr.mul_assign(state.beta); - tmp_fr.add_assign(state.gamma); - tmp_fr.add_assign(proof.wire_values_at_zeta[i+1]); - - grand_product_part_at_z.mul_assign(tmp_fr); - } - - grand_product_part_at_z.mul_assign(state.alpha); - - tmp_fr.assign(state.cached_lagrange_evals[0]); - tmp_fr.mul_assign(state.alpha); - tmp_fr.mul_assign(state.alpha); - // NOTICE - grand_product_part_at_z.sub_assign(tmp_fr); - PairingsBn254.Fr memory last_permutation_part_at_z = PairingsBn254.new_fr(1); - for (uint256 i = 0; i < proof.permutation_polynomials_at_zeta.length; i++) { - tmp_fr.assign(state.beta); - tmp_fr.mul_assign(proof.permutation_polynomials_at_zeta[i]); - tmp_fr.add_assign(state.gamma); - tmp_fr.add_assign(proof.wire_values_at_zeta[i]); - - last_permutation_part_at_z.mul_assign(tmp_fr); - } - - last_permutation_part_at_z.mul_assign(state.beta); - last_permutation_part_at_z.mul_assign(proof.grand_product_at_zeta_omega); - last_permutation_part_at_z.mul_assign(state.alpha); - - // gnark implementation: add third part and sub second second part - // plonk paper implementation: add second part and sub third part - /* - tmp_g1 = proof.grand_product_commitment.point_mul(grand_product_part_at_z); - tmp_g1.point_sub_assign(vk.permutation_commitments[STATE_WIDTH - 1].point_mul(last_permutation_part_at_z)); - */ - // add to the linearization - - tmp_g1 = vk.permutation_commitments[STATE_WIDTH - 1].point_mul(last_permutation_part_at_z); - tmp_g1.point_sub_assign(proof.grand_product_commitment.point_mul(grand_product_part_at_z)); - res.point_add_assign(tmp_g1); - - generate_uv_challenge(state, proof, vk, res); - - res.point_mul_assign(state.v); - res.point_add_assign(proof.grand_product_commitment.point_mul(state.u)); - } - - // gnark v generation process: - // sha256(zeta, proof.quotient_poly_commitments, linearizedPolynomialDigest, proof.wire_commitments, vk.permutation_commitments[0..1], ) - // NOTICE: gnark use "gamma" name for v, it's not reasonable - // NOTICE: gnark use zeta^(n+2) which is a bit different with plonk paper - // generate_v_challenge(); - function generate_uv_challenge( - PartialVerifierState memory state, - Proof memory proof, - VerificationKey memory vk, - PairingsBn254.G1Point memory linearization_point) view internal { - TranscriptLibrary.Transcript memory transcript = TranscriptLibrary.new_transcript(); - transcript.set_challenge_name("gamma"); - transcript.update_with_fr(state.zeta); - PairingsBn254.Fr memory zeta_plus_two = PairingsBn254.copy(state.zeta); - PairingsBn254.Fr memory n_plus_two = PairingsBn254.new_fr(vk.domain_size); - n_plus_two.add_assign(PairingsBn254.new_fr(2)); - zeta_plus_two = zeta_plus_two.pow(n_plus_two.value); - state.cached_fold_quotient_ploy_commitments = PairingsBn254.copy_g1(proof.quotient_poly_commitments[STATE_WIDTH-1]); - for (uint256 i = 0; i < STATE_WIDTH - 1; i++) { - state.cached_fold_quotient_ploy_commitments.point_mul_assign(zeta_plus_two); - state.cached_fold_quotient_ploy_commitments.point_add_assign(proof.quotient_poly_commitments[STATE_WIDTH - 2 - i]); - } - transcript.update_with_g1(state.cached_fold_quotient_ploy_commitments); - transcript.update_with_g1(linearization_point); - - for (uint256 i = 0; i < proof.wire_commitments.length; i++) { - transcript.update_with_g1(proof.wire_commitments[i]); - } - for (uint256 i = 0; i < vk.permutation_commitments.length - 1; i++) { - transcript.update_with_g1(vk.permutation_commitments[i]); - } - state.v = transcript.get_challenge(); - // gnark use local randomness to generate u - // we use opening_at_zeta_proof and opening_at_zeta_omega_proof - transcript.set_challenge_name("u"); - transcript.update_with_g1(proof.opening_at_zeta_proof); - transcript.update_with_g1(proof.opening_at_zeta_omega_proof); - state.u = transcript.get_challenge(); - } - - function batch_evaluate_lagrange_poly_out_of_domain( - uint256[] memory poly_nums, - uint256 domain_size, - PairingsBn254.Fr memory omega, - PairingsBn254.Fr memory at - ) internal view returns (PairingsBn254.Fr[] memory res) { - PairingsBn254.Fr memory one = PairingsBn254.new_fr(1); - PairingsBn254.Fr memory tmp_1 = PairingsBn254.new_fr(0); - PairingsBn254.Fr memory tmp_2 = PairingsBn254.new_fr(domain_size); - PairingsBn254.Fr memory vanishing_at_zeta = at.pow(domain_size); - vanishing_at_zeta.sub_assign(one); - // we can not have random point z be in domain - require(vanishing_at_zeta.value != 0); - PairingsBn254.Fr[] memory nums = new PairingsBn254.Fr[](poly_nums.length); - PairingsBn254.Fr[] memory dens = new PairingsBn254.Fr[](poly_nums.length); - // numerators in a form omega^i * (z^n - 1) - // denoms in a form (z - omega^i) * N - for (uint i = 0; i < poly_nums.length; i++) { - tmp_1 = omega.pow(poly_nums[i]); // power of omega - nums[i].assign(vanishing_at_zeta); - nums[i].mul_assign(tmp_1); - - dens[i].assign(at); // (X - omega^i) * N - dens[i].sub_assign(tmp_1); - dens[i].mul_assign(tmp_2); // mul by domain size - } - - PairingsBn254.Fr[] memory partial_products = new PairingsBn254.Fr[](poly_nums.length); - partial_products[0].assign(PairingsBn254.new_fr(1)); - for (uint i = 1; i < dens.length; i++) { - partial_products[i].assign(dens[i-1]); - partial_products[i].mul_assign(partial_products[i-1]); - } - - tmp_2.assign(partial_products[partial_products.length - 1]); - tmp_2.mul_assign(dens[dens.length - 1]); - tmp_2 = tmp_2.inverse(); // tmp_2 contains a^-1 * b^-1 (with! the last one) - - for (uint i = dens.length; i > 0; i--) { - tmp_1.assign(tmp_2); // all inversed - tmp_1.mul_assign(partial_products[i-1]); // clear lowest terms - tmp_2.mul_assign(dens[i-1]); - dens[i-1].assign(tmp_1); - } - - for (uint i = 0; i < nums.length; i++) { - nums[i].mul_assign(dens[i]); - } - - return nums; - } - - // plonk paper verify process step8: Compute quotient polynomial evaluation - function verify_quotient_poly_eval_at_zeta( - PartialVerifierState memory state, - Proof memory proof, - VerificationKey memory vk - ) internal view returns (bool) { - PairingsBn254.Fr memory lhs = evaluate_vanishing(vk.domain_size, state.zeta); - require(lhs.value != 0); // we can not check a polynomial relationship if point z is in the domain - lhs.mul_assign(proof.quotient_polynomial_at_zeta); - - PairingsBn254.Fr memory quotient_challenge = PairingsBn254.new_fr(1); - PairingsBn254.Fr memory rhs = PairingsBn254.copy(proof.linearization_polynomial_at_zeta); - - // public inputs - PairingsBn254.Fr memory tmp = PairingsBn254.new_fr(0); - for (uint256 i = 0; i < proof.input_values.length; i++) { - tmp.assign(state.cached_lagrange_evals[i]); - tmp.mul_assign(PairingsBn254.new_fr(proof.input_values[i])); - rhs.add_assign(tmp); - } - - quotient_challenge.mul_assign(state.alpha); - - PairingsBn254.Fr memory z_part = PairingsBn254.copy(proof.grand_product_at_zeta_omega); - for (uint256 i = 0; i < proof.permutation_polynomials_at_zeta.length; i++) { - tmp.assign(proof.permutation_polynomials_at_zeta[i]); - tmp.mul_assign(state.beta); - tmp.add_assign(state.gamma); - tmp.add_assign(proof.wire_values_at_zeta[i]); - - z_part.mul_assign(tmp); - } - - tmp.assign(state.gamma); - // we need a wire value of the last polynomial in enumeration - tmp.add_assign(proof.wire_values_at_zeta[STATE_WIDTH - 1]); - - z_part.mul_assign(tmp); - z_part.mul_assign(quotient_challenge); - - // NOTICE: this is different with plonk paper - // plonk paper should be: rhs.sub_assign(z_part); - rhs.add_assign(z_part); - - quotient_challenge.mul_assign(state.alpha); - - tmp.assign(state.cached_lagrange_evals[0]); - tmp.mul_assign(quotient_challenge); - - rhs.sub_assign(tmp); - - return lhs.value == rhs.value; - } - - function evaluate_vanishing( - uint256 domain_size, - PairingsBn254.Fr memory at - ) internal view returns (PairingsBn254.Fr memory res) { - res = at.pow(domain_size); - res.sub_assign(PairingsBn254.new_fr(1)); - } - - // This verifier is for a PLONK with a state width 3 - // and main gate equation - // q_a(X) * a(X) + - // q_b(X) * b(X) + - // q_c(X) * c(X) + - // q_m(X) * a(X) * b(X) + - // q_constants(X)+ - // where q_{}(X) are selectors a, b, c - state (witness) polynomials - - function verify(Proof memory proof, VerificationKey memory vk) internal view returns (bool) { - PartialVerifierState memory state; - - bool valid = verify_initial(state, proof, vk); - - if (valid == false) { - return false; - } - - valid = verify_commitments(state, proof, vk); - - return valid; - } -} - -contract KeyedPlonkVerifier is PlonkVerifier { - uint256 constant SERIALIZED_PROOF_LENGTH = 26; - using PairingsBn254 for PairingsBn254.Fr; - function get_verification_key() internal pure returns(VerificationKey memory vk) { - vk.domain_size = {{.Size}}; - vk.num_inputs = {{.NbPublicVariables}}; - vk.omega = PairingsBn254.new_fr(uint256({{.Generator.String}})); - vk.selector_commitments[0] = PairingsBn254.new_g1( - uint256({{.Ql.X.String}}), - uint256({{.Ql.Y.String}}) - ); - vk.selector_commitments[1] = PairingsBn254.new_g1( - uint256({{.Qr.X.String}}), - uint256({{.Qr.Y.String}}) - ); - vk.selector_commitments[2] = PairingsBn254.new_g1( - uint256({{.Qo.X.String}}), - uint256({{.Qo.Y.String}}) - ); - vk.selector_commitments[3] = PairingsBn254.new_g1( - uint256({{.Qm.X.String}}), - uint256({{.Qm.Y.String}}) - ); - vk.selector_commitments[4] = PairingsBn254.new_g1( - uint256({{.Qk.X.String}}), - uint256({{.Qk.Y.String}}) - ); - - vk.permutation_commitments[0] = PairingsBn254.new_g1( - uint256({{(index .S 0).X.String}}), - uint256({{(index .S 0).Y.String}}) - ); - vk.permutation_commitments[1] = PairingsBn254.new_g1( - uint256({{(index .S 1).X.String}}), - uint256({{(index .S 1).Y.String}}) - ); - vk.permutation_commitments[2] = PairingsBn254.new_g1( - uint256({{(index .S 2).X.String}}), - uint256({{(index .S 2).Y.String}}) - ); - - vk.permutation_non_residues[0] = PairingsBn254.new_fr( - uint256({{.CosetShift.String}}) - ); - vk.permutation_non_residues[1] = PairingsBn254.copy( - vk.permutation_non_residues[0] - ); - vk.permutation_non_residues[1].mul_assign(vk.permutation_non_residues[0]); - - vk.g2_x = PairingsBn254.new_g2( - [uint256({{(index .KZGSRS.G2 1).X.A1.String}}), - uint256({{(index .KZGSRS.G2 1).X.A0.String}})], - [uint256({{(index .KZGSRS.G2 1).Y.A1.String}}), - uint256({{(index .KZGSRS.G2 1).Y.A0.String}})] - ); - } - - - function deserialize_proof( - uint256[] memory public_inputs, - uint256[] memory serialized_proof - ) internal pure returns(Proof memory proof) { - require(serialized_proof.length == SERIALIZED_PROOF_LENGTH); - proof.input_values = new uint256[](public_inputs.length); - for (uint256 i = 0; i < public_inputs.length; i++) { - proof.input_values[i] = public_inputs[i]; - } - - uint256 j = 0; - for (uint256 i = 0; i < STATE_WIDTH; i++) { - proof.wire_commitments[i] = PairingsBn254.new_g1_checked( - serialized_proof[j], - serialized_proof[j+1] - ); - - j += 2; - } - - proof.grand_product_commitment = PairingsBn254.new_g1_checked( - serialized_proof[j], - serialized_proof[j+1] - ); - j += 2; - - for (uint256 i = 0; i < STATE_WIDTH; i++) { - proof.quotient_poly_commitments[i] = PairingsBn254.new_g1_checked( - serialized_proof[j], - serialized_proof[j+1] - ); - - j += 2; - } - - for (uint256 i = 0; i < STATE_WIDTH; i++) { - proof.wire_values_at_zeta[i] = PairingsBn254.new_fr( - serialized_proof[j] - ); - - j += 1; - } - - proof.grand_product_at_zeta_omega = PairingsBn254.new_fr( - serialized_proof[j] - ); - - j += 1; - - proof.quotient_polynomial_at_zeta = PairingsBn254.new_fr( - serialized_proof[j] - ); - - j += 1; - - proof.linearization_polynomial_at_zeta = PairingsBn254.new_fr( - serialized_proof[j] - ); - - j += 1; - - for (uint256 i = 0; i < proof.permutation_polynomials_at_zeta.length; i++) { - proof.permutation_polynomials_at_zeta[i] = PairingsBn254.new_fr( - serialized_proof[j] - ); - - j += 1; - } - - proof.opening_at_zeta_proof = PairingsBn254.new_g1_checked( - serialized_proof[j], - serialized_proof[j+1] - ); - j += 2; - - proof.opening_at_zeta_omega_proof = PairingsBn254.new_g1_checked( - serialized_proof[j], - serialized_proof[j+1] - ); - } - - function verify_serialized_proof( - uint256[] memory public_inputs, - uint256[] memory serialized_proof - ) public view returns (bool) { - VerificationKey memory vk = get_verification_key(); - require(vk.num_inputs == public_inputs.length); - Proof memory proof = deserialize_proof(public_inputs, serialized_proof); - bool valid = verify(proof, vk); - return valid; - } -} -` diff --git a/backend/plonk/bn254/solidity/abi/PlonkVerifier.abi b/backend/plonk/bn254/solidity/abi/PlonkVerifier.abi deleted file mode 100644 index 74799a02a6..0000000000 --- a/backend/plonk/bn254/solidity/abi/PlonkVerifier.abi +++ /dev/null @@ -1 +0,0 @@ -[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"a","type":"uint256"}],"name":"PrintUint256","type":"event"}] \ No newline at end of file diff --git a/backend/plonk/bn254/solidity/abi/PlonkVerifier.bin b/backend/plonk/bn254/solidity/abi/PlonkVerifier.bin deleted file mode 100644 index a58baa9f97..0000000000 --- a/backend/plonk/bn254/solidity/abi/PlonkVerifier.bin +++ /dev/null @@ -1 +0,0 @@ -60566050600b82828239805160001a6073146043577f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212205226b6547ca96d0b3a4de1173ac16d03809a55c3f4d51cfbe714667b28de567564736f6c63430008130033 \ No newline at end of file diff --git a/backend/plonk/bn254/solidity/abi/TestVerifier.abi b/backend/plonk/bn254/solidity/abi/TestVerifier.abi deleted file mode 100644 index d7446a5382..0000000000 --- a/backend/plonk/bn254/solidity/abi/TestVerifier.abi +++ /dev/null @@ -1 +0,0 @@ -[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"a","type":"bool"}],"name":"PrintBool","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"a","type":"uint256"}],"name":"PrintUint256","type":"event"},{"inputs":[],"name":"test_verifier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"proof","type":"bytes"},{"internalType":"uint256[]","name":"public_inputs","type":"uint256[]"}],"name":"test_verifier_go","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/backend/plonk/bn254/solidity/abi/TestVerifier.bin b/backend/plonk/bn254/solidity/abi/TestVerifier.bin deleted file mode 100644 index b2ea814dc5..0000000000 --- a/backend/plonk/bn254/solidity/abi/TestVerifier.bin +++ /dev/null @@ -1 +0,0 @@ -608060405234801561001057600080fd5b50613ce5806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80638cbba7b71461003b578063c383590a14610045575b600080fd5b610043610061565b005b61005f600480360381019061005a91906134a9565b61016b565b005b6000600367ffffffffffffffff81111561007e5761007d613280565b5b6040519080825280602002602001820160405280156100ac5781602001602082028036833780820191505090505b5090506006816000815181106100c5576100c4613521565b5b6020026020010181815250506007816001815181106100e7576100e6613521565b5b60200260200101818152505060088160028151811061010957610108613521565b5b602002602001018181525050600061011f61017e565b9050600061012d82846107d7565b90507f3e1a1345e360785a18ee3f9d25ba93d69ea5c3b5772b44df827662204209612c8160405161015e919061356b565b60405180910390a1505050565b600061017783836107d7565b9050505050565b6060610188613156565b7f2bfdf48f3358f3e85a081de26fc48b1efaea78b539f40b75371da351434c653c8160000181815250507f260ca2fa81f809e385685f1b0b5a31457d6012230a2b5b41377f20e0a91a05ab8160200181815250507f1a2d48183d3f456fb5b0d973fec425a6f6f5465f6cf2415338d6181c4776d3a08160400181815250507f1480057d0a5ef1b2af09b9a4ebd10dac779d6aaa5654b336297a3e0a2376f9cd8160600181815250507f05bd3d59f4c2346778c6c657e72c214eae17479586c514963673f0e33e1f40ba8160800181815250507f2065ef9df3594d13ff90c6dbbe9452e550e80ac2651dd9c1a9f974932a54c4f88160a00181815250507f2c41ca7bfaf3cc4caeebf0aeb02a385c251f7586328b35402191e8a5038c0da88160c00181815250507f0b6e269d74c93ca056226963d5b22c0d83933c969cef2637cc624c1343ba6df18160e00181815250507f265137a78f4ef26af3b5d31a717ed5686e3c4b8f3f1526cb4b8d7fda7419e75f816101000181815250507f14d04c6f8271552e1dd5afbad2b33f7b55462c7d05203aab1ec8db7fd6b0641e816101200181815250507f06c3865cab1fa4f84d5fcdc576a2ca10dd5b174526f51247958c33bc757ba6e7816101400181815250507f12651f8ab0db434a1aa0fe908ea8dd75a2cdec91773c15e1c9959fd026a785f4816101600181815250507f0693d99a75683fc96a53e8dada884479be55ec150b2cf0c6dd924ee04cfa0184816101800181815250507f2ce56e102172d4b23b5d8d418f514295a887542cea85845c0772b86c442a70f6816101a00181815250507f16ffbbc7a52ba3eb9ac02c4d3a0d0a4ffda6469a88d7b265eb88cbf71d67b1d3816101c00181815250507f02356e4b5a0e900026b55a131d3f279b9dc4977e8cce378c2a6d08570597374c816101e00181815250507f1d7d30b514415c872b0610d3b41a43cb42fb5276a0b9a75c00fa5f5c6dad9a80816102000181815250507f05c64e466e03121fa5d67a8980e418f7d6a3a0e462958b1fe3969008867a9e12816102200181815250507f0a27257bab695b24ebee0a6ec065d88fb04f18f342d554687f38ec894f83f0a9816102400181815250507f104b099b6387a9668601f702d6ce28d4a9a0017b235b87640b55d3c4f020f061816102600181815250507f0218961c70ecb8e1c8b5bdfa2a3238c21e6a1d7017ce0dadb51a16a4bd90baf1816102800181815250507f2b9421b98e344c89af2ea2625344b3d11b2f6b2a731b4ea599e2ba1b548dd447816102a00181815250507f13f2c3df009d71b54a0500f04d36781afd5f9df1e9e8f9418f798ab2b48bda8c816102c00181815250507f2f402d27013130f33b2db0b14bc97f9f99c671ab3f1f3db5c869163c92b8c37d816102e00181815250507f0cecacec73c3e598894de734d1465d30682416170e657fe9c654a627a7142a38816103000181815250507f26f078ad0487efd41675efc58c78aa3f866acb4bb21e275edf615ecc98165bfe816103200181815250506000816103400181815250507f11d16aca7209deba0b3da6df4c4f9dc7e03c3db3a008b42927f3b38e232fb2be816103600181815250507f0e85b9d47c8c5c672b13e49cfb330f1e80632377124fcedf43626f2b63765a67816103800181815250506060816000015182602001518360400151846060015185608001518660a001518760c001518860e001518961010001518a61012001518b61014001518c610160015160405160200161069d9c9b9a999897969594939291906135a7565b604051602081830303815290604052905080826101800151836101a00151846101c001516040516020016106d494939291906136ee565b604051602081830303815290604052905080826101e00151836102000151846102200151856102400151866102600151876102800151886102a00151604051602001610727989796959493929190613738565b604051602081830303815290604052905080826102c00151836102e001518461030001518561032001516040516020016107659594939291906137c6565b60405160208183030381529060405290508082610340015160405160200161078e929190613821565b6040516020818303038152906040529050808261036001518361038001516040516020016107be93929190613849565b6040516020818303038152906040529050809250505090565b60008060008060006107e98787611e4e565b80945081955082965083975050505050600061080688888461235f565b905060008060009050604051856000820152876040820152846060820152866020820152836101c0820152610839610884565b6108428b611996565b61084b8b611921565b6108548b61151b565b61085d8b610fbf565b6108668b610d52565b61086f8b610a33565b61024081015191506102608101519250611e06565b6040516102806040510161089e8160206060850151611da7565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000010382089050806101e08401527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001036060850151086109678360027f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000010383611da7565b90507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000017f2ee12bff4a2813286a8dc388cd754d9a3ef2490635eba50cb9c2e5e750800001820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001828209915060008401517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181840992507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181840992508260c08601525050505050565b60405161028081016003816040810192506102e085015181526103008501516020820152610a678383610320880184611cf7565b6101808401610a7c8484610240890184611cf7565b6101608501610a9084610280890183611d55565b8460408101955060018152600260208201528151604082015260408160608360076107d05a03fa506020810180517f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47038152610aee87838687611c76565b86604088019750610b098860608b01516102e08d0184611cbc565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000017f09c532c6306b93d29678200d47c0b2a99c18d51b838eeb1d3eed4c533bb512d060608b0151097f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018189099750610b8789896103208e0185611cf7565b610b9389838889611c76565b6020870180517f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4703815286518a52602087015160208b01527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c260408b01527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed60608b01527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b60808b01527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa60a08b0152875160c08b0152602088015160e08b01527f21487b7187fea07a8c5035362b098732dbf9c9c3a8b785b5542c595a984a9eb16101008b01527f033b79bd16d5e8a868c369319e7f3fc697a705aef9bd9338dca8f56bcbefd3fc6101208b01527f011b702314a36beb2823cf932d6573734fe6237da634255717bd10a8505d75456101408b01527f1392d6b91b5df791212bc84cb1ce917cd0044df61d989e6010a678e1c18d87d36101608b0152602060006101808c60086107d05a03fa6102408c01518181169050600051811690506000516102608e0152806102408e01525050505050505050505050505050565b6040516102806040510161022082015180604060010261020001808401604085015161018087015260608501516101a08701526102a0870151610160870152610da48184608088016101808a01611cf7565b610db7836102c089016101608901611d55565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018484099250610df0818460c088016101808a01611cf7565b610e03836101a089016101608901611d55565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018484099250610e3f8286018461010088016101808a01611cf7565b610e52836101c089016101608901611d55565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018484099250610e8e8286018461014088016101808a01611cf7565b610ea1836101e089016101608901611d55565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018484099250610edd8286018461018088016101808a01611cf7565b610ef08361020089016101608901611d55565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018484099250610f2c828601846101c088016101808a01611cf7565b610f3f8361022089016101608901611d55565b6103608701610200860160005b6001811015610fb3577f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018787099550610f8d85890187846101808d01611cf7565b610f9c86846101608c01611d55565b602083019250604082019150600181019050610f4c565b50505050505050505050565b604051610280604051016467616d6d6181526060820151602082015260e082015160408201526101008201516060820152610120820151608082015261014082015160a0820152602083015160c0820152604083015160e08201526060830151610100820152608083015161012082015260a083015161014082015260c08301516101608201527f28a65b11eee0b34f6402404d76f1c0c3bc3a01c74c4748c723adf49ae75995556101808201527f1e8175426eb99057633decd6bb26a00b3b003710e702e23b5904e13b7b49a0806101a08201527f22fb19af6150047ef27f32e95e56b9096d60fb9e91738a1de337dd64b46a4a4e6101c08201527f12447dfc10994f0f87af0d14a3588f44c6404d144a4a89f60d0fbe3997ef65d36101e08201526102007f2fc8e621da8773a71ce9c20ecc967a1587e3116566c346f88f9eb6a9cf32243b818301527f044aaed3aa229e3f1906df767f6877b79eb4425c0ac354ab6e1556f1a4082368602082018301526040810190506102a0840151818301526102c0840151602082018301526101a0840151604082018301526101c0840151606082018301526101e08401516080820183015261020084015160a0820183015261022084015160c0820183015260e081018201610360850160005b60018110156111c2578151835260208201915060208301925060018101905061119e565b50601b6003600102601601602081026005019050602061022088018284890160026107d05a03fa507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610220880151066102208801525050505050505050565b604051610280604051017f0e606450dbd88a14565d4e57ee72674787b6860d2139671bcec21ce903174b7e81527f25a3c5619b7c5567df3ab30837006312bb7d3356dc64f83ac36bda1f50cd9e08602082015261128d604082016101a0850151836101208601611cbc565b7f2c975fae7e44ca144b8a2e578e0d21d53e4221b01594af21b96099ae402ecdbe81527f22752d25557cf48a9dde2defb2ba3e16201df82ac4959330b21e465cb700c89760208201526112ee604082016101c0850151836101208601611cf7565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016101c08401516101a0850151097f190b08e03a378a3f870f71f936f0c5621da73c35f749dda2ea343ad5cce0674b82527f03ae9f6bdee25baaf05d98df559a46c0e66b4f2fcee25ce86156c8b262a10e6760208301526113786040830182846101208701611cf7565b7f2c975fae7e44ca144b8a2e578e0d21d53e4221b01594af21b96099ae402ecdbe82527f0def214d8bb4ab9f1a7217c6cec71a4777637266a3dc375c8a0245ba217c34b060208301526113d9604083016101e0860151846101208701611cf7565b7f190b08e03a378a3f870f71f936f0c5621da73c35f749dda2ea343ad5cce0674b82527f2cb5af07024f447ec7f2acd72be7119cb1161b61998f6da4dac9c36475dbeee06020830152611439604083018361012086016101208701611c76565b6103608401602060010261036001850160005b600181101561148e578151855260208201516020860152611477604086018451876101208a01611cf7565b60208301925060408201915060018101905061144c565b507f1dd205b578328dfb97ad3a166d6b7a3479a9581ccbb59b5115307949766c4ad884527f1113e7413b3a28f3893503d7dd743c91574dcd4f9f7e8abda894461b515f577d60208501526114eb6040850188866101208901611cf7565b610240860151845261026086015160208501526115116040850189866101208901611cf7565b5050505050505050565b60405160208101516040820151606083015160008401517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000184610280880151097f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161020088015186097f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016101a0890151820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000185820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161022089015187097f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016101c08a0151820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000186820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018284097f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000182820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000185820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001600580097f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001878a097f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016101a08d0151820895507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000189870895507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016005820994507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016101c08d0151860894507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000189860894507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000182820993507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016101e08d0151850893507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000189850893507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018587097f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018582099050807f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000010390507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000188820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160c08d01518208905061191281858f611222565b50505050505050505050505050565b60405160026020016102806040510161193f81836060860151611da7565b6119528282610160880160e08801611cbc565b61196882610120870160e0870160e08801611c76565b61197a828260e0870160e08801611cbc565b61198f8260e0870160e0870160e08801611c76565b5050505050565b604051610280604051017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160208301516102008501510981527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001604083015182510881527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016101a08401518251088152602081017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160208401516102208601510981527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001604084015182510881527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016101c08501518251088152604082017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160408501516101e08701510881527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001825184510983527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001815184510983527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001600085015184510983527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016102808601518451098352606083017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016101c08601516102c08801510881527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001845182510881527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160c08601517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000010382510881527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016101e08601516102a08801510983528251815114610240860152505050505050565b6040518251855260208301516020860152835160408601526020840151606086015260408260808760066107d05a03fa6102408201518116610240830152505050505050565b604051825185526020830151602086015283604086015260408260608760076107d05a03fa6102408201518116610240830152505050505050565b604051825185526020830151602086015283604086015260408560608760076107d05a03fa825160408701526020830151606087015260408360808860066107d05a03fa811690506102408201518116610240830152505050505050565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001838351097f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181835108825250505050565b600060208452602080850152602060408501528160608501528260808501527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160a085015260208460c08660056107d05a03fa50835190509392505050565b507fc06f90efa9c91dc43be8c00f432325e29d17851ab0f40844b418121428cc043b82604051611e369190613891565b60405180910390a18097505050505050505092915050565b600080600080600080600080604051611e678a8c611f2e565b80519450611e75858c612278565b80519350611e83848c61229f565b80519250611e91838c6122dd565b805191507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001850694507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001840693507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001830692507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000182069150612345565b6040516467616d6d6181527f28a65b11eee0b34f6402404d76f1c0c3bc3a01c74c4748c723adf49ae759955560208201527f1e8175426eb99057633decd6bb26a00b3b003710e702e23b5904e13b7b49a08060408201527f22fb19af6150047ef27f32e95e56b9096d60fb9e91738a1de337dd64b46a4a4e60608201527f12447dfc10994f0f87af0d14a3588f44c6404d144a4a89f60d0fbe3997ef65d360808201527f1dd205b578328dfb97ad3a166d6b7a3479a9581ccbb59b5115307949766c4ad860a08201527f1113e7413b3a28f3893503d7dd743c91574dcd4f9f7e8abda894461b515f577d60c08201527f0e606450dbd88a14565d4e57ee72674787b6860d2139671bcec21ce903174b7e60e08201527f25a3c5619b7c5567df3ab30837006312bb7d3356dc64f83ac36bda1f50cd9e086101008201527f2c975fae7e44ca144b8a2e578e0d21d53e4221b01594af21b96099ae402ecdbe6101208201527f22752d25557cf48a9dde2defb2ba3e16201df82ac4959330b21e465cb700c8976101408201527f190b08e03a378a3f870f71f936f0c5621da73c35f749dda2ea343ad5cce0674b6101608201527f03ae9f6bdee25baaf05d98df559a46c0e66b4f2fcee25ce86156c8b262a10e676101808201527f2c975fae7e44ca144b8a2e578e0d21d53e4221b01594af21b96099ae402ecdbe6101a08201527f0def214d8bb4ab9f1a7217c6cec71a4777637266a3dc375c8a0245ba217c34b06101c08201527f190b08e03a378a3f870f71f936f0c5621da73c35f749dda2ea343ad5cce0674b6101e08201527f2cb5af07024f447ec7f2acd72be7119cb1161b61998f6da4dac9c36475dbeee061020082015260208301610220820160005b85518110156121d257825182526020830192506020820191506001810190506121ae565b50610360840160206001028101905060005b60018110156122125781518352602082015160208401526040830192506040820191506001810190506121e4565b506020850151825260408501516020830152606085015160408301526080850151606083015260a0850151608083015260c085015160a083015260208651026102c50160406001028101905060208582601b880160026107d05a03fa5050505050505050565b604051636265746181528260208201526020816024601c840160026107d05a03fa50505050565b60405164616c7068618152826020820152610240820151604082015261026082015160608201526020816065601b840160026107d05a03fa50505050565b604051637a657461815282602082015260e082015160408201526101008201516060820152610120820151608082015261014082015160a082015261016082015160c082015261018082015160e082015260208160e4601c840160026107d05a03fa50505050565b508383838397509750975097505050505092959194509250565b60008060006123738486516020880161237e565b60405151905061278b565b60405161238c81848661240d565b60008060005b858110156123ff577f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001855185510991507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018284089250602084019350602085019450600181019050612392565b508160405152505050505050565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000010361245e8560208561272c565b087f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000017f2ee12bff4a2813286a8dc388cd754d9a3ef2490635eba50cb9c2e5e7508000018209905060018460005b85811015612552577f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001837f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000103860882527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000017f09c532c6306b93d29678200d47c0b2a99c18d51b838eeb1d3eed4c533bb512d0840992506020820191506001810190506124ab565b5061255e81868861261a565b8590506001915060005b85811015612611577f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001837f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001868551090982526020820191507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000017f09c532c6306b93d29678200d47c0b2a99c18d51b838eeb1d3eed4c533bb512d084099250600181019050612568565b50505050505050565b600183526000805b838110156126705781850151828401517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001818309905060208401935080848801525050600181019050612622565b50602081038201915080840193506126b06020850160027f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000103865161272c565b60005b848110156127245760208603955083517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001875184098086527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001828509935060208603955050506001810190506126b3565b505050505050565b600060208452602080850152602060408501528160608501528260808501527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160a085015260208460c08660056107d05a03fa50835190509392505050565b61279960405160208661272c565b91507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000103830891506000600167ffffffffffffffff81111561280157612800613280565b5b60405190808252806020026020018201604052801561282f5781602001602082028036833780820191505090505b50905061283b816129b5565b60606001600261284b91906138db565b67ffffffffffffffff81111561286457612863613280565b5b6040519080825280602002602001820160405280156128925781602001602082028036833780820191505090505b50905061289f81896129c7565b60005b60018110156129a657600061290f838360026128be91906138db565b815181106128cf576128ce613521565b5b60200260200101518460018560026128e791906138db565b6128f1919061391d565b8151811061290257612901613521565b5b6020026020010151612a1a565b90506000612943898b5187868151811061292c5761292b613521565b5b602002602001015161293e919061391d565b612b9c565b90507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181830990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181870895505050808061299e90613951565b9150506128a2565b50829450505050509392505050565b60208101600381526020810190505050565b60208201610360820160206001028101905060005b6002600102811015612a135781518352602083019250602082019150815183526020830192506020820191506001810190506129dc565b5050505050565b600080612a278484612d9c565b905060005b6020811015612a8b57806008612a4291906138db565b8282602f612a509190613999565b60308110612a6157612a60613521565b5b602002015160ff16901b83612a76919061391d565b92508080612a8390613951565b915050612a2c565b507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000182612ab891906139fc565b9150600080600090505b6010811015612b2157806008612ad891906138db565b8382600f612ae69190613999565b60308110612af757612af6613521565b5b602002015160ff16901b82612b0c919061391d565b91508080612b1990613951565b915050612ac2565b5060007f0e0a77c19a07df2f666ea36f7879462e36fc76959f60cd29ac96341c4ffffffb90507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181830991507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001828508935050505092915050565b600080612c08565b600060405160208152602080820152602060408201528260608201528360808201527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160a08201526020600060c08360056107d05a03fa5060005191505092915050565b612c32837f09c532c6306b93d29678200d47c0b2a99c18d51b838eeb1d3eed4c533bb512d0612ba4565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001817f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000010386089350612c85602086612ba4565b94507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000103860894507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000017f2ee12bff4a2813286a8dc388cd754d9a3ef2490635eba50cb9c2e5e75080000182099050612d4360027f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000010385612ba4565b93507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000184820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018582099150508091505092915050565b612da461322e565b60006040518060400160405280600b81526020017f42534232322d506c6f6e6b00000000000000000000000000000000000000000081525090506060600080603090506000600b905060005b6040811015612e30578484604051602001612e0c929190613a70565b60405160208183030381529060405294508080612e2890613951565b915050612df0565b508388888585878a87604051602001612e50989796959493929190613adf565b60405160208183030381529060405293506000600285604051612e739190613b69565b602060405180830381855afa158015612e90573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190612eb39190613bb6565b90508060018784604051602001612ecd9493929190613c04565b60405160208183030381529060405294506000600286604051612ef09190613b69565b602060405180830381855afa158015612f0d573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190612f309190613bb6565b905060005b6020811015612f8f57818160208110612f5157612f50613521565b5b1a60f81b60f81c898260308110612f6b57612f6a613521565b5b602002019060ff16908160ff16815250508080612f8790613951565b915050612f35565b5080600060208110612fa457612fa3613521565b5b1a60f81b60f81c82600060208110612fbf57612fbe613521565b5b1a60f81b60f81c18604051602001612fd79190613c4e565b60405160208183030381529060405295506000600190505b6020811015613063578682826020811061300c5761300b613521565b5b1a60f81b60f81c84836020811061302657613025613521565b5b1a60f81b60f81c1860405160200161303f929190613a70565b6040516020818303038152906040529650808061305b90613951565b915050612fef565b50856002888560405160200161307c9493929190613c69565b604051602081830303815290604052955060028660405161309d9190613b69565b602060405180830381855afa1580156130ba573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906130dd9190613bb6565b905060005b6010811015613148578181602081106130fe576130fd613521565b5b1a60f81b60f81c89602083613113919061391d565b6030811061312457613123613521565b5b602002019060ff16908160ff1681525050808061314090613951565b9150506130e2565b505050505050505092915050565b604051806103a0016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b604051806106000160405280603090602082028036833780820191505090505090565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6132b88261326f565b810181811067ffffffffffffffff821117156132d7576132d6613280565b5b80604052505050565b60006132ea613251565b90506132f682826132af565b919050565b600067ffffffffffffffff82111561331657613315613280565b5b61331f8261326f565b9050602081019050919050565b82818337600083830152505050565b600061334e613349846132fb565b6132e0565b90508281526020810184848401111561336a5761336961326a565b5b61337584828561332c565b509392505050565b600082601f83011261339257613391613265565b5b81356133a284826020860161333b565b91505092915050565b600067ffffffffffffffff8211156133c6576133c5613280565b5b602082029050602081019050919050565b600080fd5b6000819050919050565b6133ef816133dc565b81146133fa57600080fd5b50565b60008135905061340c816133e6565b92915050565b6000613425613420846133ab565b6132e0565b90508083825260208201905060208402830185811115613448576134476133d7565b5b835b81811015613471578061345d88826133fd565b84526020840193505060208101905061344a565b5050509392505050565b600082601f8301126134905761348f613265565b5b81356134a0848260208601613412565b91505092915050565b600080604083850312156134c0576134bf61325b565b5b600083013567ffffffffffffffff8111156134de576134dd613260565b5b6134ea8582860161337d565b925050602083013567ffffffffffffffff81111561350b5761350a613260565b5b6135178582860161347b565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008115159050919050565b61356581613550565b82525050565b6000602082019050613580600083018461355c565b92915050565b6000819050919050565b6135a161359c826133dc565b613586565b82525050565b60006135b3828f613590565b6020820191506135c3828e613590565b6020820191506135d3828d613590565b6020820191506135e3828c613590565b6020820191506135f3828b613590565b602082019150613603828a613590565b6020820191506136138289613590565b6020820191506136238288613590565b6020820191506136338287613590565b6020820191506136438286613590565b6020820191506136538285613590565b6020820191506136638284613590565b6020820191508190509d9c50505050505050505050505050565b600081519050919050565b600081905092915050565b60005b838110156136b1578082015181840152602081019050613696565b60008484015250505050565b60006136c88261367d565b6136d28185613688565b93506136e2818560208601613693565b80840191505092915050565b60006136fa82876136bd565b91506137068286613590565b6020820191506137168285613590565b6020820191506137268284613590565b60208201915081905095945050505050565b6000613744828b6136bd565b9150613750828a613590565b6020820191506137608289613590565b6020820191506137708288613590565b6020820191506137808287613590565b6020820191506137908286613590565b6020820191506137a08285613590565b6020820191506137b08284613590565b6020820191508190509998505050505050505050565b60006137d282886136bd565b91506137de8287613590565b6020820191506137ee8286613590565b6020820191506137fe8285613590565b60208201915061380e8284613590565b6020820191508190509695505050505050565b600061382d82856136bd565b91506138398284613590565b6020820191508190509392505050565b600061385582866136bd565b91506138618285613590565b6020820191506138718284613590565b602082019150819050949350505050565b61388b816133dc565b82525050565b60006020820190506138a66000830184613882565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006138e6826133dc565b91506138f1836133dc565b92508282026138ff816133dc565b91508282048414831517613916576139156138ac565b5b5092915050565b6000613928826133dc565b9150613933836133dc565b925082820190508082111561394b5761394a6138ac565b5b92915050565b600061395c826133dc565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361398e5761398d6138ac565b5b600182019050919050565b60006139a4826133dc565b91506139af836133dc565b92508282039050818111156139c7576139c66138ac565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000613a07826133dc565b9150613a12836133dc565b925082613a2257613a216139cd565b5b828206905092915050565b600060ff82169050919050565b60008160f81b9050919050565b6000613a5282613a3a565b9050919050565b613a6a613a6582613a2d565b613a47565b82525050565b6000613a7c82856136bd565b9150613a888284613a59565b6001820191508190509392505050565b600081519050919050565b600081905092915050565b6000613ab982613a98565b613ac38185613aa3565b9350613ad3818560208601613693565b80840191505092915050565b6000613aeb828b6136bd565b9150613af7828a613590565b602082019150613b078289613590565b602082019150613b178288613a59565b600182019150613b278287613a59565b600182019150613b378286613a59565b600182019150613b478285613aae565b9150613b538284613a59565b6001820191508190509998505050505050505050565b6000613b7582846136bd565b915081905092915050565b6000819050919050565b613b9381613b80565b8114613b9e57600080fd5b50565b600081519050613bb081613b8a565b92915050565b600060208284031215613bcc57613bcb61325b565b5b6000613bda84828501613ba1565b91505092915050565b6000819050919050565b613bfe613bf982613b80565b613be3565b82525050565b6000613c108287613bed565b602082019150613c208286613a59565b600182019150613c308285613aae565b9150613c3c8284613a59565b60018201915081905095945050505050565b6000613c5a8284613a59565b60018201915081905092915050565b6000613c7582876136bd565b9150613c818286613a59565b600182019150613c918285613aae565b9150613c9d8284613a59565b6001820191508190509594505050505056fea26469706673582212207a0357ed8f715b7512d712b7fb294fbb965ce4b7a0242bb5cb2162a49076238b64736f6c63430008130033 \ No newline at end of file diff --git a/backend/plonk/bn254/solidity/abi/Utils.abi b/backend/plonk/bn254/solidity/abi/Utils.abi deleted file mode 100644 index b40276e015..0000000000 --- a/backend/plonk/bn254/solidity/abi/Utils.abi +++ /dev/null @@ -1 +0,0 @@ -[{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"name":"expand_msg","outputs":[{"internalType":"uint8[48]","name":"res","type":"uint8[48]"}],"stateMutability":"pure","type":"function"}] \ No newline at end of file diff --git a/backend/plonk/bn254/solidity/abi/Utils.bin b/backend/plonk/bn254/solidity/abi/Utils.bin deleted file mode 100644 index 63de1980ce..0000000000 --- a/backend/plonk/bn254/solidity/abi/Utils.bin +++ /dev/null @@ -1 +0,0 @@ -6109ad610053600b82828239805160001a607314610046577f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100355760003560e01c806361791d3f1461003a575b600080fd5b610054600480360381019061004f9190610482565b61006a565b604051610061919061057a565b60405180910390f35b610072610424565b60006040518060400160405280600b81526020017f42534232322d506c6f6e6b00000000000000000000000000000000000000000081525090506060600080603090506000600b905060005b60408110156100fe5784846040516020016100da92919061063d565b604051602081830303815290604052945080806100f690610694565b9150506100be565b508388888585878a8760405160200161011e989796959493929190610744565b6040516020818303038152906040529350600060028560405161014191906107ce565b602060405180830381855afa15801561015e573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610181919061081b565b9050806001878460405160200161019b9493929190610869565b604051602081830303815290604052945060006002866040516101be91906107ce565b602060405180830381855afa1580156101db573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906101fe919061081b565b905060005b602081101561025d5781816020811061021f5761021e6108b3565b5b1a60f81b60f81c898260308110610239576102386108b3565b5b602002019060ff16908160ff1681525050808061025590610694565b915050610203565b5080600060208110610272576102716108b3565b5b1a60f81b60f81c8260006020811061028d5761028c6108b3565b5b1a60f81b60f81c186040516020016102a591906108e2565b60405160208183030381529060405295506000600190505b602081101561033157868282602081106102da576102d96108b3565b5b1a60f81b60f81c8483602081106102f4576102f36108b3565b5b1a60f81b60f81c1860405160200161030d92919061063d565b6040516020818303038152906040529650808061032990610694565b9150506102bd565b50856002888560405160200161034a94939291906108fd565b604051602081830303815290604052955060028660405161036b91906107ce565b602060405180830381855afa158015610388573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906103ab919061081b565b905060005b6010811015610416578181602081106103cc576103cb6108b3565b5b1a60f81b60f81c896020836103e19190610943565b603081106103f2576103f16108b3565b5b602002019060ff16908160ff1681525050808061040e90610694565b9150506103b0565b505050505050505092915050565b604051806106000160405280603090602082028036833780820191505090505090565b600080fd5b6000819050919050565b61045f8161044c565b811461046a57600080fd5b50565b60008135905061047c81610456565b92915050565b6000806040838503121561049957610498610447565b5b60006104a78582860161046d565b92505060206104b88582860161046d565b9150509250929050565b600060309050919050565b600081905092915050565b6000819050919050565b600060ff82169050919050565b6104f8816104e2565b82525050565b600061050a83836104ef565b60208301905092915050565b6000602082019050919050565b61052c816104c2565b61053681846104cd565b9250610541826104d8565b8060005b8381101561057257815161055987826104fe565b965061056483610516565b925050600181019050610545565b505050505050565b6000610600820190506105906000830184610523565b92915050565b600081519050919050565b600081905092915050565b60005b838110156105ca5780820151818401526020810190506105af565b60008484015250505050565b60006105e182610596565b6105eb81856105a1565b93506105fb8185602086016105ac565b80840191505092915050565b60008160f81b9050919050565b600061061f82610607565b9050919050565b610637610632826104e2565b610614565b82525050565b600061064982856105d6565b91506106558284610626565b6001820191508190509392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061069f8261044c565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036106d1576106d0610665565b5b600182019050919050565b6000819050919050565b6106f76106f28261044c565b6106dc565b82525050565b600081519050919050565b600081905092915050565b600061071e826106fd565b6107288185610708565b93506107388185602086016105ac565b80840191505092915050565b6000610750828b6105d6565b915061075c828a6106e6565b60208201915061076c82896106e6565b60208201915061077c8288610626565b60018201915061078c8287610626565b60018201915061079c8286610626565b6001820191506107ac8285610713565b91506107b88284610626565b6001820191508190509998505050505050505050565b60006107da82846105d6565b915081905092915050565b6000819050919050565b6107f8816107e5565b811461080357600080fd5b50565b600081519050610815816107ef565b92915050565b60006020828403121561083157610830610447565b5b600061083f84828501610806565b91505092915050565b6000819050919050565b61086361085e826107e5565b610848565b82525050565b60006108758287610852565b6020820191506108858286610626565b6001820191506108958285610713565b91506108a18284610626565b60018201915081905095945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006108ee8284610626565b60018201915081905092915050565b600061090982876105d6565b91506109158286610626565b6001820191506109258285610713565b91506109318284610626565b60018201915081905095945050505050565b600061094e8261044c565b91506109598361044c565b925082820190508082111561097157610970610665565b5b9291505056fea2646970667358221220ab9f64a55486844e4be79b30ff50d67695be004f9b72b71161c3207c615115d164736f6c63430008130033 \ No newline at end of file From 1529c53460740b5619da8b8a15c50a54ea788acb Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Wed, 24 May 2023 19:12:12 +0200 Subject: [PATCH 377/464] fix: re uploading solidity template --- backend/plonk/bn254/solidity.go | 907 ++++++++++++++++++++++++++++++++ 1 file changed, 907 insertions(+) create mode 100644 backend/plonk/bn254/solidity.go diff --git a/backend/plonk/bn254/solidity.go b/backend/plonk/bn254/solidity.go new file mode 100644 index 0000000000..7fddbd204f --- /dev/null +++ b/backend/plonk/bn254/solidity.go @@ -0,0 +1,907 @@ +package plonk + +const solidityTemplate = ` +// Warning this code was contributed into gnark here: +// https://github.com/ConsenSys/gnark/pull/358 +// +// It has not been audited and is provided as-is, we make no guarantees or warranties to its safety and reliability. +// +// According to https://eprint.iacr.org/archive/2019/953/1585767119.pdf +pragma solidity ^0.8.0; +pragma experimental ABIEncoderV2; + +library PairingsBn254 { + uint256 constant q_mod = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + uint256 constant r_mod = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + uint256 constant bn254_b_coeff = 3; + + struct G1Point { + uint256 X; + uint256 Y; + } + + struct Fr { + uint256 value; + } + + function new_fr(uint256 fr) internal pure returns (Fr memory) { + require(fr < r_mod); + return Fr({value: fr}); + } + + function copy(Fr memory self) internal pure returns (Fr memory n) { + n.value = self.value; + } + + function assign(Fr memory self, Fr memory other) internal pure { + self.value = other.value; + } + + function inverse(Fr memory fr) internal view returns (Fr memory) { + require(fr.value != 0); + return pow(fr, r_mod-2); + } + + function add_assign(Fr memory self, Fr memory other) internal pure { + self.value = addmod(self.value, other.value, r_mod); + } + + function sub_assign(Fr memory self, Fr memory other) internal pure { + self.value = addmod(self.value, r_mod - other.value, r_mod); + } + + function mul_assign(Fr memory self, Fr memory other) internal pure { + self.value = mulmod(self.value, other.value, r_mod); + } + + function pow(Fr memory self, uint256 power) internal view returns (Fr memory) { + uint256[6] memory input = [32, 32, 32, self.value, power, r_mod]; + uint256[1] memory result; + bool success; + assembly { + success := staticcall(gas(), 0x05, input, 0xc0, result, 0x20) + } + require(success); + return Fr({value: result[0]}); + } + + // Encoding of field elements is: X[0] * z + X[1] + struct G2Point { + uint[2] X; + uint[2] Y; + } + + function P1() internal pure returns (G1Point memory) { + return G1Point(1, 2); + } + + function new_g1(uint256 x, uint256 y) internal pure returns (G1Point memory) { + return G1Point(x, y); + } + + function new_g1_checked(uint256 x, uint256 y) internal pure returns (G1Point memory) { + if (x == 0 && y == 0) { + // point of infinity is (0,0) + return G1Point(x, y); + } + + // check encoding + require(x < q_mod); + require(y < q_mod); + // check on curve + uint256 lhs = mulmod(y, y, q_mod); // y^2 + uint256 rhs = mulmod(x, x, q_mod); // x^2 + rhs = mulmod(rhs, x, q_mod); // x^3 + rhs = addmod(rhs, bn254_b_coeff, q_mod); // x^3 + b + require(lhs == rhs); + + return G1Point(x, y); + } + + function new_g2(uint256[2] memory x, uint256[2] memory y) internal pure returns (G2Point memory) { + return G2Point(x, y); + } + + function copy_g1(G1Point memory self) internal pure returns (G1Point memory result) { + result.X = self.X; + result.Y = self.Y; + } + + function P2() internal pure returns (G2Point memory) { + // for some reason ethereum expects to have c1*v + c0 form + + return G2Point( + [0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2, + 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed], + [0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b, + 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa] + ); + } + + function negate(G1Point memory self) internal pure { + // The prime q in the base field F_q for G1 + if (self.Y == 0) { + require(self.X == 0); + return; + } + + self.Y = q_mod - self.Y; + } + + function point_add(G1Point memory p1, G1Point memory p2) + internal view returns (G1Point memory r) + { + point_add_into_dest(p1, p2, r); + return r; + } + + function point_add_assign(G1Point memory p1, G1Point memory p2) + internal view + { + point_add_into_dest(p1, p2, p1); + } + + function point_add_into_dest(G1Point memory p1, G1Point memory p2, G1Point memory dest) + internal view + { + if (p2.X == 0 && p2.Y == 0) { + // we add zero, nothing happens + dest.X = p1.X; + dest.Y = p1.Y; + return; + } else if (p1.X == 0 && p1.Y == 0) { + // we add into zero, and we add non-zero point + dest.X = p2.X; + dest.Y = p2.Y; + return; + } else { + uint256[4] memory input; + + input[0] = p1.X; + input[1] = p1.Y; + input[2] = p2.X; + input[3] = p2.Y; + + bool success = false; + assembly { + success := staticcall(gas(), 6, input, 0x80, dest, 0x40) + } + require(success); + } + } + + function point_sub_assign(G1Point memory p1, G1Point memory p2) + internal view + { + point_sub_into_dest(p1, p2, p1); + } + + function point_sub_into_dest(G1Point memory p1, G1Point memory p2, G1Point memory dest) + internal view + { + if (p2.X == 0 && p2.Y == 0) { + // we subtracted zero, nothing happens + dest.X = p1.X; + dest.Y = p1.Y; + return; + } else if (p1.X == 0 && p1.Y == 0) { + // we subtract from zero, and we subtract non-zero point + dest.X = p2.X; + dest.Y = q_mod - p2.Y; + return; + } else { + uint256[4] memory input; + + input[0] = p1.X; + input[1] = p1.Y; + input[2] = p2.X; + input[3] = q_mod - p2.Y; + + bool success = false; + assembly { + success := staticcall(gas(), 6, input, 0x80, dest, 0x40) + } + require(success); + } + } + + function point_mul(G1Point memory p, Fr memory s) + internal view returns (G1Point memory r) + { + point_mul_into_dest(p, s, r); + return r; + } + + function point_mul_assign(G1Point memory p, Fr memory s) + internal view + { + point_mul_into_dest(p, s, p); + } + + function point_mul_into_dest(G1Point memory p, Fr memory s, G1Point memory dest) + internal view + { + uint[3] memory input; + input[0] = p.X; + input[1] = p.Y; + input[2] = s.value; + bool success; + assembly { + success := staticcall(gas(), 7, input, 0x60, dest, 0x40) + } + require(success); + } + + function pairing(G1Point[] memory p1, G2Point[] memory p2) + internal view returns (bool) + { + require(p1.length == p2.length); + uint elements = p1.length; + uint inputSize = elements * 6; + uint[] memory input = new uint[](inputSize); + for (uint i = 0; i < elements; i++) + { + input[i * 6 + 0] = p1[i].X; + input[i * 6 + 1] = p1[i].Y; + input[i * 6 + 2] = p2[i].X[0]; + input[i * 6 + 3] = p2[i].X[1]; + input[i * 6 + 4] = p2[i].Y[0]; + input[i * 6 + 5] = p2[i].Y[1]; + } + uint[1] memory out; + bool success; + assembly { + success := staticcall(gas(), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20) + } + require(success); + return out[0] != 0; + } + + /// Convenience method for a pairing check for two pairs. + function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) + internal view returns (bool) + { + G1Point[] memory p1 = new G1Point[](2); + G2Point[] memory p2 = new G2Point[](2); + p1[0] = a1; + p1[1] = b1; + p2[0] = a2; + p2[1] = b2; + return pairing(p1, p2); + } +} + +library TranscriptLibrary { + uint32 constant DST_0 = 0; + uint32 constant DST_1 = 1; + uint32 constant DST_CHALLENGE = 2; + + struct Transcript { + bytes32 previous_randomness; + bytes bindings; + string name; + uint32 challenge_counter; + } + + function new_transcript() internal pure returns (Transcript memory t) { + t.challenge_counter = 0; + } + + function set_challenge_name(Transcript memory self, string memory name) internal pure { + self.name = name; + } + + function update_with_u256(Transcript memory self, uint256 value) internal pure { + self.bindings = abi.encodePacked(self.bindings, value); + } + + function update_with_fr(Transcript memory self, PairingsBn254.Fr memory value) internal pure { + self.bindings = abi.encodePacked(self.bindings, value.value); + } + + function update_with_g1(Transcript memory self, PairingsBn254.G1Point memory p) internal pure { + self.bindings = abi.encodePacked(self.bindings, p.X, p.Y); + } + + function get_encode(Transcript memory self) internal pure returns(bytes memory query) { + if (self.challenge_counter != 0) { + query = abi.encodePacked(self.name, self.previous_randomness, self.bindings); + } else { + query = abi.encodePacked(self.name, self.bindings); + } + return query; + } + function get_challenge(Transcript memory self) internal pure returns(PairingsBn254.Fr memory challenge) { + bytes32 query; + if (self.challenge_counter != 0) { + query = sha256(abi.encodePacked(self.name, self.previous_randomness, self.bindings)); + } else { + query = sha256(abi.encodePacked(self.name, self.bindings)); + } + self.challenge_counter += 1; + self.previous_randomness = query; + challenge = PairingsBn254.Fr({value: uint256(query) % PairingsBn254.r_mod}); + self.bindings = ""; + } +} + +contract PlonkVerifier { + using PairingsBn254 for PairingsBn254.G1Point; + using PairingsBn254 for PairingsBn254.G2Point; + using PairingsBn254 for PairingsBn254.Fr; + + using TranscriptLibrary for TranscriptLibrary.Transcript; + + uint256 constant STATE_WIDTH = 3; + + struct VerificationKey { + uint256 domain_size; + uint256 num_inputs; + PairingsBn254.Fr omega; // w + PairingsBn254.G1Point[STATE_WIDTH+2] selector_commitments; // STATE_WIDTH for witness + multiplication + constant + PairingsBn254.G1Point[STATE_WIDTH] permutation_commitments; // [Sσ1(x)],[Sσ2(x)],[Sσ3(x)] + PairingsBn254.Fr[STATE_WIDTH-1] permutation_non_residues; // k1, k2 + PairingsBn254.G2Point g2_x; + } + + struct Proof { + uint256[] input_values; + PairingsBn254.G1Point[STATE_WIDTH] wire_commitments; // [a(x)]/[b(x)]/[c(x)] + PairingsBn254.G1Point grand_product_commitment; // [z(x)] + PairingsBn254.G1Point[STATE_WIDTH] quotient_poly_commitments; // [t_lo]/[t_mid]/[t_hi] + PairingsBn254.Fr[STATE_WIDTH] wire_values_at_zeta; // a(zeta)/b(zeta)/c(zeta) + PairingsBn254.Fr grand_product_at_zeta_omega; // z(w*zeta) + PairingsBn254.Fr quotient_polynomial_at_zeta; // t(zeta) + PairingsBn254.Fr linearization_polynomial_at_zeta; // r(zeta) + PairingsBn254.Fr[STATE_WIDTH-1] permutation_polynomials_at_zeta; // Sσ1(zeta),Sσ2(zeta) + + PairingsBn254.G1Point opening_at_zeta_proof; // [Wzeta] + PairingsBn254.G1Point opening_at_zeta_omega_proof; // [Wzeta*omega] + } + + struct PartialVerifierState { + PairingsBn254.Fr alpha; + PairingsBn254.Fr beta; + PairingsBn254.Fr gamma; + PairingsBn254.Fr v; + PairingsBn254.Fr u; + PairingsBn254.Fr zeta; + PairingsBn254.Fr[] cached_lagrange_evals; + + PairingsBn254.G1Point cached_fold_quotient_ploy_commitments; + } + + function verify_initial( + PartialVerifierState memory state, + Proof memory proof, + VerificationKey memory vk) internal view returns (bool) { + + require(proof.input_values.length == vk.num_inputs, "not match"); + require(vk.num_inputs >= 1, "inv input"); + + TranscriptLibrary.Transcript memory t = TranscriptLibrary.new_transcript(); + t.set_challenge_name("gamma"); + for (uint256 i = 0; i < vk.permutation_commitments.length; i++) { + t.update_with_g1(vk.permutation_commitments[i]); + } + // this is gnark order: Ql, Qr, Qm, Qo, Qk + // + t.update_with_g1(vk.selector_commitments[0]); + t.update_with_g1(vk.selector_commitments[1]); + t.update_with_g1(vk.selector_commitments[3]); + t.update_with_g1(vk.selector_commitments[2]); + t.update_with_g1(vk.selector_commitments[4]); + + for (uint256 i = 0; i < proof.input_values.length; i++) { + t.update_with_u256(proof.input_values[i]); + } + state.gamma = t.get_challenge(); + + t.set_challenge_name("beta"); + state.beta = t.get_challenge(); + + t.set_challenge_name("alpha"); + t.update_with_g1(proof.grand_product_commitment); + state.alpha = t.get_challenge(); + + t.set_challenge_name("zeta"); + for (uint256 i = 0; i < proof.quotient_poly_commitments.length; i++) { + t.update_with_g1(proof.quotient_poly_commitments[i]); + } + state.zeta = t.get_challenge(); + + uint256[] memory lagrange_poly_numbers = new uint256[](vk.num_inputs); + for (uint256 i = 0; i < lagrange_poly_numbers.length; i++) { + lagrange_poly_numbers[i] = i; + } + state.cached_lagrange_evals = batch_evaluate_lagrange_poly_out_of_domain( + lagrange_poly_numbers, + vk.domain_size, + vk.omega, state.zeta + ); + + bool valid = verify_quotient_poly_eval_at_zeta(state, proof, vk); + return valid; + } + + function verify_commitments( + PartialVerifierState memory state, + Proof memory proof, + VerificationKey memory vk + ) internal view returns (bool) { + PairingsBn254.G1Point memory d = reconstruct_d(state, proof, vk); + + PairingsBn254.G1Point memory tmp_g1 = PairingsBn254.P1(); + + PairingsBn254.Fr memory aggregation_challenge = PairingsBn254.new_fr(1); + + PairingsBn254.G1Point memory commitment_aggregation = PairingsBn254.copy_g1(state.cached_fold_quotient_ploy_commitments); + PairingsBn254.Fr memory tmp_fr = PairingsBn254.new_fr(1); + + aggregation_challenge.mul_assign(state.v); + commitment_aggregation.point_add_assign(d); + + for (uint i = 0; i < proof.wire_commitments.length; i++) { + aggregation_challenge.mul_assign(state.v); + tmp_g1 = proof.wire_commitments[i].point_mul(aggregation_challenge); + commitment_aggregation.point_add_assign(tmp_g1); + } + + for (uint i = 0; i < vk.permutation_commitments.length - 1; i++) { + aggregation_challenge.mul_assign(state.v); + tmp_g1 = vk.permutation_commitments[i].point_mul(aggregation_challenge); + commitment_aggregation.point_add_assign(tmp_g1); + } + + // collect opening values + aggregation_challenge = PairingsBn254.new_fr(1); + + PairingsBn254.Fr memory aggregated_value = PairingsBn254.copy(proof.quotient_polynomial_at_zeta); + + aggregation_challenge.mul_assign(state.v); + + tmp_fr.assign(proof.linearization_polynomial_at_zeta); + tmp_fr.mul_assign(aggregation_challenge); + aggregated_value.add_assign(tmp_fr); + + for (uint i = 0; i < proof.wire_values_at_zeta.length; i++) { + aggregation_challenge.mul_assign(state.v); + + tmp_fr.assign(proof.wire_values_at_zeta[i]); + tmp_fr.mul_assign(aggregation_challenge); + aggregated_value.add_assign(tmp_fr); + } + + for (uint i = 0; i < proof.permutation_polynomials_at_zeta.length; i++) { + aggregation_challenge.mul_assign(state.v); + + tmp_fr.assign(proof.permutation_polynomials_at_zeta[i]); + tmp_fr.mul_assign(aggregation_challenge); + aggregated_value.add_assign(tmp_fr); + } + tmp_fr.assign(proof.grand_product_at_zeta_omega); + tmp_fr.mul_assign(state.u); + aggregated_value.add_assign(tmp_fr); + + commitment_aggregation.point_sub_assign(PairingsBn254.P1().point_mul(aggregated_value)); + + PairingsBn254.G1Point memory pair_with_generator = commitment_aggregation; + pair_with_generator.point_add_assign(proof.opening_at_zeta_proof.point_mul(state.zeta)); + + tmp_fr.assign(state.zeta); + tmp_fr.mul_assign(vk.omega); + tmp_fr.mul_assign(state.u); + pair_with_generator.point_add_assign(proof.opening_at_zeta_omega_proof.point_mul(tmp_fr)); + + PairingsBn254.G1Point memory pair_with_x = proof.opening_at_zeta_omega_proof.point_mul(state.u); + pair_with_x.point_add_assign(proof.opening_at_zeta_proof); + pair_with_x.negate(); + + return PairingsBn254.pairingProd2(pair_with_generator, PairingsBn254.P2(), pair_with_x, vk.g2_x); + } + + function reconstruct_d( + PartialVerifierState memory state, + Proof memory proof, + VerificationKey memory vk + ) internal view returns (PairingsBn254.G1Point memory res) { + res = PairingsBn254.copy_g1(vk.selector_commitments[STATE_WIDTH + 1]); + + PairingsBn254.G1Point memory tmp_g1 = PairingsBn254.P1(); + PairingsBn254.Fr memory tmp_fr = PairingsBn254.new_fr(0); + + // addition gates + for (uint256 i = 0; i < STATE_WIDTH; i++) { + tmp_g1 = vk.selector_commitments[i].point_mul(proof.wire_values_at_zeta[i]); + res.point_add_assign(tmp_g1); + } + + // multiplication gate + tmp_fr.assign(proof.wire_values_at_zeta[0]); + tmp_fr.mul_assign(proof.wire_values_at_zeta[1]); + tmp_g1 = vk.selector_commitments[STATE_WIDTH].point_mul(tmp_fr); + res.point_add_assign(tmp_g1); + + // z * non_res * beta + gamma + a + PairingsBn254.Fr memory grand_product_part_at_z = PairingsBn254.copy(state.zeta); + grand_product_part_at_z.mul_assign(state.beta); + grand_product_part_at_z.add_assign(proof.wire_values_at_zeta[0]); + grand_product_part_at_z.add_assign(state.gamma); + for (uint256 i = 0; i < vk.permutation_non_residues.length; i++) { + tmp_fr.assign(state.zeta); + tmp_fr.mul_assign(vk.permutation_non_residues[i]); + tmp_fr.mul_assign(state.beta); + tmp_fr.add_assign(state.gamma); + tmp_fr.add_assign(proof.wire_values_at_zeta[i+1]); + + grand_product_part_at_z.mul_assign(tmp_fr); + } + + grand_product_part_at_z.mul_assign(state.alpha); + + tmp_fr.assign(state.cached_lagrange_evals[0]); + tmp_fr.mul_assign(state.alpha); + tmp_fr.mul_assign(state.alpha); + // NOTICE + grand_product_part_at_z.sub_assign(tmp_fr); + PairingsBn254.Fr memory last_permutation_part_at_z = PairingsBn254.new_fr(1); + for (uint256 i = 0; i < proof.permutation_polynomials_at_zeta.length; i++) { + tmp_fr.assign(state.beta); + tmp_fr.mul_assign(proof.permutation_polynomials_at_zeta[i]); + tmp_fr.add_assign(state.gamma); + tmp_fr.add_assign(proof.wire_values_at_zeta[i]); + + last_permutation_part_at_z.mul_assign(tmp_fr); + } + + last_permutation_part_at_z.mul_assign(state.beta); + last_permutation_part_at_z.mul_assign(proof.grand_product_at_zeta_omega); + last_permutation_part_at_z.mul_assign(state.alpha); + + // gnark implementation: add third part and sub second second part + // plonk paper implementation: add second part and sub third part + /* + tmp_g1 = proof.grand_product_commitment.point_mul(grand_product_part_at_z); + tmp_g1.point_sub_assign(vk.permutation_commitments[STATE_WIDTH - 1].point_mul(last_permutation_part_at_z)); + */ + // add to the linearization + + tmp_g1 = vk.permutation_commitments[STATE_WIDTH - 1].point_mul(last_permutation_part_at_z); + tmp_g1.point_sub_assign(proof.grand_product_commitment.point_mul(grand_product_part_at_z)); + res.point_add_assign(tmp_g1); + + generate_uv_challenge(state, proof, vk, res); + + res.point_mul_assign(state.v); + res.point_add_assign(proof.grand_product_commitment.point_mul(state.u)); + } + + // gnark v generation process: + // sha256(zeta, proof.quotient_poly_commitments, linearizedPolynomialDigest, proof.wire_commitments, vk.permutation_commitments[0..1], ) + // NOTICE: gnark use "gamma" name for v, it's not reasonable + // NOTICE: gnark use zeta^(n+2) which is a bit different with plonk paper + // generate_v_challenge(); + function generate_uv_challenge( + PartialVerifierState memory state, + Proof memory proof, + VerificationKey memory vk, + PairingsBn254.G1Point memory linearization_point) view internal { + TranscriptLibrary.Transcript memory transcript = TranscriptLibrary.new_transcript(); + transcript.set_challenge_name("gamma"); + transcript.update_with_fr(state.zeta); + PairingsBn254.Fr memory zeta_plus_two = PairingsBn254.copy(state.zeta); + PairingsBn254.Fr memory n_plus_two = PairingsBn254.new_fr(vk.domain_size); + n_plus_two.add_assign(PairingsBn254.new_fr(2)); + zeta_plus_two = zeta_plus_two.pow(n_plus_two.value); + state.cached_fold_quotient_ploy_commitments = PairingsBn254.copy_g1(proof.quotient_poly_commitments[STATE_WIDTH-1]); + for (uint256 i = 0; i < STATE_WIDTH - 1; i++) { + state.cached_fold_quotient_ploy_commitments.point_mul_assign(zeta_plus_two); + state.cached_fold_quotient_ploy_commitments.point_add_assign(proof.quotient_poly_commitments[STATE_WIDTH - 2 - i]); + } + transcript.update_with_g1(state.cached_fold_quotient_ploy_commitments); + transcript.update_with_g1(linearization_point); + + for (uint256 i = 0; i < proof.wire_commitments.length; i++) { + transcript.update_with_g1(proof.wire_commitments[i]); + } + for (uint256 i = 0; i < vk.permutation_commitments.length - 1; i++) { + transcript.update_with_g1(vk.permutation_commitments[i]); + } + state.v = transcript.get_challenge(); + // gnark use local randomness to generate u + // we use opening_at_zeta_proof and opening_at_zeta_omega_proof + transcript.set_challenge_name("u"); + transcript.update_with_g1(proof.opening_at_zeta_proof); + transcript.update_with_g1(proof.opening_at_zeta_omega_proof); + state.u = transcript.get_challenge(); + } + + function batch_evaluate_lagrange_poly_out_of_domain( + uint256[] memory poly_nums, + uint256 domain_size, + PairingsBn254.Fr memory omega, + PairingsBn254.Fr memory at + ) internal view returns (PairingsBn254.Fr[] memory res) { + PairingsBn254.Fr memory one = PairingsBn254.new_fr(1); + PairingsBn254.Fr memory tmp_1 = PairingsBn254.new_fr(0); + PairingsBn254.Fr memory tmp_2 = PairingsBn254.new_fr(domain_size); + PairingsBn254.Fr memory vanishing_at_zeta = at.pow(domain_size); + vanishing_at_zeta.sub_assign(one); + // we can not have random point z be in domain + require(vanishing_at_zeta.value != 0); + PairingsBn254.Fr[] memory nums = new PairingsBn254.Fr[](poly_nums.length); + PairingsBn254.Fr[] memory dens = new PairingsBn254.Fr[](poly_nums.length); + // numerators in a form omega^i * (z^n - 1) + // denoms in a form (z - omega^i) * N + for (uint i = 0; i < poly_nums.length; i++) { + tmp_1 = omega.pow(poly_nums[i]); // power of omega + nums[i].assign(vanishing_at_zeta); + nums[i].mul_assign(tmp_1); + + dens[i].assign(at); // (X - omega^i) * N + dens[i].sub_assign(tmp_1); + dens[i].mul_assign(tmp_2); // mul by domain size + } + + PairingsBn254.Fr[] memory partial_products = new PairingsBn254.Fr[](poly_nums.length); + partial_products[0].assign(PairingsBn254.new_fr(1)); + for (uint i = 1; i < dens.length; i++) { + partial_products[i].assign(dens[i-1]); + partial_products[i].mul_assign(partial_products[i-1]); + } + + tmp_2.assign(partial_products[partial_products.length - 1]); + tmp_2.mul_assign(dens[dens.length - 1]); + tmp_2 = tmp_2.inverse(); // tmp_2 contains a^-1 * b^-1 (with! the last one) + + for (uint i = dens.length; i > 0; i--) { + tmp_1.assign(tmp_2); // all inversed + tmp_1.mul_assign(partial_products[i-1]); // clear lowest terms + tmp_2.mul_assign(dens[i-1]); + dens[i-1].assign(tmp_1); + } + + for (uint i = 0; i < nums.length; i++) { + nums[i].mul_assign(dens[i]); + } + + return nums; + } + + // plonk paper verify process step8: Compute quotient polynomial evaluation + function verify_quotient_poly_eval_at_zeta( + PartialVerifierState memory state, + Proof memory proof, + VerificationKey memory vk + ) internal view returns (bool) { + PairingsBn254.Fr memory lhs = evaluate_vanishing(vk.domain_size, state.zeta); + require(lhs.value != 0); // we can not check a polynomial relationship if point z is in the domain + lhs.mul_assign(proof.quotient_polynomial_at_zeta); + + PairingsBn254.Fr memory quotient_challenge = PairingsBn254.new_fr(1); + PairingsBn254.Fr memory rhs = PairingsBn254.copy(proof.linearization_polynomial_at_zeta); + + // public inputs + PairingsBn254.Fr memory tmp = PairingsBn254.new_fr(0); + for (uint256 i = 0; i < proof.input_values.length; i++) { + tmp.assign(state.cached_lagrange_evals[i]); + tmp.mul_assign(PairingsBn254.new_fr(proof.input_values[i])); + rhs.add_assign(tmp); + } + + quotient_challenge.mul_assign(state.alpha); + + PairingsBn254.Fr memory z_part = PairingsBn254.copy(proof.grand_product_at_zeta_omega); + for (uint256 i = 0; i < proof.permutation_polynomials_at_zeta.length; i++) { + tmp.assign(proof.permutation_polynomials_at_zeta[i]); + tmp.mul_assign(state.beta); + tmp.add_assign(state.gamma); + tmp.add_assign(proof.wire_values_at_zeta[i]); + + z_part.mul_assign(tmp); + } + + tmp.assign(state.gamma); + // we need a wire value of the last polynomial in enumeration + tmp.add_assign(proof.wire_values_at_zeta[STATE_WIDTH - 1]); + + z_part.mul_assign(tmp); + z_part.mul_assign(quotient_challenge); + + // NOTICE: this is different with plonk paper + // plonk paper should be: rhs.sub_assign(z_part); + rhs.add_assign(z_part); + + quotient_challenge.mul_assign(state.alpha); + + tmp.assign(state.cached_lagrange_evals[0]); + tmp.mul_assign(quotient_challenge); + + rhs.sub_assign(tmp); + + return lhs.value == rhs.value; + } + + function evaluate_vanishing( + uint256 domain_size, + PairingsBn254.Fr memory at + ) internal view returns (PairingsBn254.Fr memory res) { + res = at.pow(domain_size); + res.sub_assign(PairingsBn254.new_fr(1)); + } + + // This verifier is for a PLONK with a state width 3 + // and main gate equation + // q_a(X) * a(X) + + // q_b(X) * b(X) + + // q_c(X) * c(X) + + // q_m(X) * a(X) * b(X) + + // q_constants(X)+ + // where q_{}(X) are selectors a, b, c - state (witness) polynomials + + function verify(Proof memory proof, VerificationKey memory vk) internal view returns (bool) { + PartialVerifierState memory state; + + bool valid = verify_initial(state, proof, vk); + + if (valid == false) { + return false; + } + + valid = verify_commitments(state, proof, vk); + + return valid; + } +} + +contract KeyedPlonkVerifier is PlonkVerifier { + uint256 constant SERIALIZED_PROOF_LENGTH = 26; + using PairingsBn254 for PairingsBn254.Fr; + function get_verification_key() internal pure returns(VerificationKey memory vk) { + vk.domain_size = {{.Size}}; + vk.num_inputs = {{.NbPublicVariables}}; + vk.omega = PairingsBn254.new_fr(uint256({{.Generator.String}})); + vk.selector_commitments[0] = PairingsBn254.new_g1( + uint256({{.Ql.X.String}}), + uint256({{.Ql.Y.String}}) + ); + vk.selector_commitments[1] = PairingsBn254.new_g1( + uint256({{.Qr.X.String}}), + uint256({{.Qr.Y.String}}) + ); + vk.selector_commitments[2] = PairingsBn254.new_g1( + uint256({{.Qo.X.String}}), + uint256({{.Qo.Y.String}}) + ); + vk.selector_commitments[3] = PairingsBn254.new_g1( + uint256({{.Qm.X.String}}), + uint256({{.Qm.Y.String}}) + ); + vk.selector_commitments[4] = PairingsBn254.new_g1( + uint256({{.Qk.X.String}}), + uint256({{.Qk.Y.String}}) + ); + + vk.permutation_commitments[0] = PairingsBn254.new_g1( + uint256({{(index .S 0).X.String}}), + uint256({{(index .S 0).Y.String}}) + ); + vk.permutation_commitments[1] = PairingsBn254.new_g1( + uint256({{(index .S 1).X.String}}), + uint256({{(index .S 1).Y.String}}) + ); + vk.permutation_commitments[2] = PairingsBn254.new_g1( + uint256({{(index .S 2).X.String}}), + uint256({{(index .S 2).Y.String}}) + ); + + vk.permutation_non_residues[0] = PairingsBn254.new_fr( + uint256({{.CosetShift.String}}) + ); + vk.permutation_non_residues[1] = PairingsBn254.copy( + vk.permutation_non_residues[0] + ); + vk.permutation_non_residues[1].mul_assign(vk.permutation_non_residues[0]); + + vk.g2_x = PairingsBn254.new_g2( + [uint256({{(index .KZGSRS.G2 1).X.A1.String}}), + uint256({{(index .KZGSRS.G2 1).X.A0.String}})], + [uint256({{(index .KZGSRS.G2 1).Y.A1.String}}), + uint256({{(index .KZGSRS.G2 1).Y.A0.String}})] + ); + } + + + function deserialize_proof( + uint256[] memory public_inputs, + uint256[] memory serialized_proof + ) internal pure returns(Proof memory proof) { + require(serialized_proof.length == SERIALIZED_PROOF_LENGTH); + proof.input_values = new uint256[](public_inputs.length); + for (uint256 i = 0; i < public_inputs.length; i++) { + proof.input_values[i] = public_inputs[i]; + } + + uint256 j = 0; + for (uint256 i = 0; i < STATE_WIDTH; i++) { + proof.wire_commitments[i] = PairingsBn254.new_g1_checked( + serialized_proof[j], + serialized_proof[j+1] + ); + + j += 2; + } + + proof.grand_product_commitment = PairingsBn254.new_g1_checked( + serialized_proof[j], + serialized_proof[j+1] + ); + j += 2; + + for (uint256 i = 0; i < STATE_WIDTH; i++) { + proof.quotient_poly_commitments[i] = PairingsBn254.new_g1_checked( + serialized_proof[j], + serialized_proof[j+1] + ); + + j += 2; + } + + for (uint256 i = 0; i < STATE_WIDTH; i++) { + proof.wire_values_at_zeta[i] = PairingsBn254.new_fr( + serialized_proof[j] + ); + + j += 1; + } + + proof.grand_product_at_zeta_omega = PairingsBn254.new_fr( + serialized_proof[j] + ); + + j += 1; + + proof.quotient_polynomial_at_zeta = PairingsBn254.new_fr( + serialized_proof[j] + ); + + j += 1; + + proof.linearization_polynomial_at_zeta = PairingsBn254.new_fr( + serialized_proof[j] + ); + + j += 1; + + for (uint256 i = 0; i < proof.permutation_polynomials_at_zeta.length; i++) { + proof.permutation_polynomials_at_zeta[i] = PairingsBn254.new_fr( + serialized_proof[j] + ); + + j += 1; + } + + proof.opening_at_zeta_proof = PairingsBn254.new_g1_checked( + serialized_proof[j], + serialized_proof[j+1] + ); + j += 2; + + proof.opening_at_zeta_omega_proof = PairingsBn254.new_g1_checked( + serialized_proof[j], + serialized_proof[j+1] + ); + } + + function verify_serialized_proof( + uint256[] memory public_inputs, + uint256[] memory serialized_proof + ) public view returns (bool) { + VerificationKey memory vk = get_verification_key(); + require(vk.num_inputs == public_inputs.length); + Proof memory proof = deserialize_proof(public_inputs, serialized_proof); + bool valid = verify(proof, vk); + return valid; + } +} +` From edc63bda364a8f2738e983dda7a8e535af895f91 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 24 May 2023 14:18:49 -0500 Subject: [PATCH 378/464] feat: reflect pedersen changes in bn254 --- backend/groth16/bn254/prove.go | 6 ++++-- backend/groth16/bn254/setup.go | 4 ++-- frontend/cs/r1cs/api.go | 14 ++++++++++++-- go.mod | 2 +- go.sum | 2 ++ 5 files changed, 21 insertions(+), 7 deletions(-) diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index 4dc62f6f3f..4b0d5ab479 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -80,8 +80,10 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var err error - proof.Commitment, proof.CommitmentPok, err = pk.CommitmentKey.Commit(values) - if err != nil { + if proof.Commitment, err = pk.CommitmentKeys[0].Commit(values); err != nil { + return err + } + if proof.CommitmentPok, err = pk.CommitmentKeys[0].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving return err } diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index de34b1f86c..2e63fd711c 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -52,7 +52,7 @@ type ProvingKey struct { InfinityA, InfinityB []bool NbInfinityA, NbInfinityB uint64 - CommitmentKey pedersen.ProvingKey + CommitmentKeys []pedersen.ProvingKey } // VerifyingKey is used by a Groth16 verifier to verify the validity of a proof and a statement @@ -263,7 +263,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { if nbPrivateCommittedWires != 0 { commitmentBasis := g1PointsAff[offset:] - pk.CommitmentKey, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) if err != nil { return err } diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index 12f0819843..95a5ff4c06 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -733,12 +733,22 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error // hint is used at solving time to compute the actual value of the commitment // it is going to be dynamically replaced at solving time. - hintOut, err := builder.NewHint(cs.Bsb22CommitmentComputePlaceholder, 1, builder.getCommittedVariables(&commitment)...) + + var ( + hintOut []frontend.Variable + err error + ) + + commitment.HintID, err = cs.RegisterBsb22CommitmentComputePlaceholder(builder.cs.GetNbCommitments()) if err != nil { return nil, err } + + if hintOut[0], err = builder.NewHintForId(commitment.HintID, 1, v...); err != nil { + return nil, err + } + cVar := hintOut[0] - commitment.HintID = solver.GetHintID(cs.Bsb22CommitmentComputePlaceholder) // TODO @gbotrel probably not needed commitment.CommitmentIndex = (cVar.(expr.LinearExpression))[0].WireID() diff --git a/go.mod b/go.mod index 56e1ca848b..55fe85f336 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/bits-and-blooms/bitset v1.5.0 github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 - github.com/consensys/gnark-crypto v0.11.1-0.20230508024855-0cd4994b7f0b + github.com/consensys/gnark-crypto v0.11.1-0.20230524003106-85db474ed631 github.com/fxamacker/cbor/v2 v2.4.0 github.com/google/go-cmp v0.5.9 github.com/google/pprof v0.0.0-20230309165930-d61513b1440d diff --git a/go.sum b/go.sum index c622e66d0e..403a727abd 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/Yj github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= github.com/consensys/gnark-crypto v0.11.1-0.20230508024855-0cd4994b7f0b h1:owSc8rrE2Tdl7xYxFgdPgx52qlO1fFDujW07aSGrffM= github.com/consensys/gnark-crypto v0.11.1-0.20230508024855-0cd4994b7f0b/go.mod h1:6C2ytC8zmP8uH2GKVfPOjf0Vw3KwMAaUxlCPK5WQqmw= +github.com/consensys/gnark-crypto v0.11.1-0.20230524003106-85db474ed631 h1:6rTz7p7/ph+UNqh9QYSaOv8JdzYnbOO/x4WLB4MZog4= +github.com/consensys/gnark-crypto v0.11.1-0.20230524003106-85db474ed631/go.mod h1:6C2ytC8zmP8uH2GKVfPOjf0Vw3KwMAaUxlCPK5WQqmw= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= From bbc2a4b84a8adc0d6c5cd6b6a2be1f1359074860 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 24 May 2023 16:16:50 -0500 Subject: [PATCH 379/464] fix: gorth16 commit compile bug --- backend/groth16/bls12-377/prove.go | 6 ++++-- backend/groth16/bls12-377/setup.go | 4 ++-- backend/groth16/bls12-381/prove.go | 6 ++++-- backend/groth16/bls12-381/setup.go | 4 ++-- backend/groth16/bls24-315/prove.go | 6 ++++-- backend/groth16/bls24-315/setup.go | 4 ++-- backend/groth16/bls24-317/prove.go | 6 ++++-- backend/groth16/bls24-317/setup.go | 4 ++-- backend/groth16/bn254/commitment.go | 10 ++++++++++ backend/groth16/bn254/commitment_test.go | 2 +- backend/groth16/bn254/verify.go | 4 +++- backend/groth16/bw6-633/prove.go | 6 ++++-- backend/groth16/bw6-633/setup.go | 4 ++-- backend/groth16/bw6-761/prove.go | 6 ++++-- backend/groth16/bw6-761/setup.go | 4 ++-- constraint/bn254/system.go | 6 ++++++ frontend/cs/r1cs/api.go | 2 +- .../template/zkpschemes/groth16/groth16.prove.go.tmpl | 6 ++++-- .../template/zkpschemes/groth16/groth16.setup.go.tmpl | 4 ++-- test/commitments_test.go | 6 +++--- 20 files changed, 66 insertions(+), 34 deletions(-) diff --git a/backend/groth16/bls12-377/prove.go b/backend/groth16/bls12-377/prove.go index df171ff680..d1e5e7a330 100644 --- a/backend/groth16/bls12-377/prove.go +++ b/backend/groth16/bls12-377/prove.go @@ -80,8 +80,10 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var err error - proof.Commitment, proof.CommitmentPok, err = pk.CommitmentKey.Commit(values) - if err != nil { + if proof.Commitment, err = pk.CommitmentKeys[0].Commit(values); err != nil { + return err + } + if proof.CommitmentPok, err = pk.CommitmentKeys[0].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving return err } diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index 068cc8bfed..4305f38ad6 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -52,7 +52,7 @@ type ProvingKey struct { InfinityA, InfinityB []bool NbInfinityA, NbInfinityB uint64 - CommitmentKey pedersen.ProvingKey + CommitmentKeys []pedersen.ProvingKey } // VerifyingKey is used by a Groth16 verifier to verify the validity of a proof and a statement @@ -263,7 +263,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { if nbPrivateCommittedWires != 0 { commitmentBasis := g1PointsAff[offset:] - pk.CommitmentKey, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) if err != nil { return err } diff --git a/backend/groth16/bls12-381/prove.go b/backend/groth16/bls12-381/prove.go index ae0919e89a..1e68abeed5 100644 --- a/backend/groth16/bls12-381/prove.go +++ b/backend/groth16/bls12-381/prove.go @@ -80,8 +80,10 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var err error - proof.Commitment, proof.CommitmentPok, err = pk.CommitmentKey.Commit(values) - if err != nil { + if proof.Commitment, err = pk.CommitmentKeys[0].Commit(values); err != nil { + return err + } + if proof.CommitmentPok, err = pk.CommitmentKeys[0].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving return err } diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index 916fb309f7..d00bd1a012 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -52,7 +52,7 @@ type ProvingKey struct { InfinityA, InfinityB []bool NbInfinityA, NbInfinityB uint64 - CommitmentKey pedersen.ProvingKey + CommitmentKeys []pedersen.ProvingKey } // VerifyingKey is used by a Groth16 verifier to verify the validity of a proof and a statement @@ -263,7 +263,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { if nbPrivateCommittedWires != 0 { commitmentBasis := g1PointsAff[offset:] - pk.CommitmentKey, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) if err != nil { return err } diff --git a/backend/groth16/bls24-315/prove.go b/backend/groth16/bls24-315/prove.go index 210da74522..518bb6cdfa 100644 --- a/backend/groth16/bls24-315/prove.go +++ b/backend/groth16/bls24-315/prove.go @@ -80,8 +80,10 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var err error - proof.Commitment, proof.CommitmentPok, err = pk.CommitmentKey.Commit(values) - if err != nil { + if proof.Commitment, err = pk.CommitmentKeys[0].Commit(values); err != nil { + return err + } + if proof.CommitmentPok, err = pk.CommitmentKeys[0].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving return err } diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index 6700512c92..8b43794587 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -52,7 +52,7 @@ type ProvingKey struct { InfinityA, InfinityB []bool NbInfinityA, NbInfinityB uint64 - CommitmentKey pedersen.ProvingKey + CommitmentKeys []pedersen.ProvingKey } // VerifyingKey is used by a Groth16 verifier to verify the validity of a proof and a statement @@ -263,7 +263,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { if nbPrivateCommittedWires != 0 { commitmentBasis := g1PointsAff[offset:] - pk.CommitmentKey, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) if err != nil { return err } diff --git a/backend/groth16/bls24-317/prove.go b/backend/groth16/bls24-317/prove.go index 44dda05c90..b11eedfc46 100644 --- a/backend/groth16/bls24-317/prove.go +++ b/backend/groth16/bls24-317/prove.go @@ -80,8 +80,10 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var err error - proof.Commitment, proof.CommitmentPok, err = pk.CommitmentKey.Commit(values) - if err != nil { + if proof.Commitment, err = pk.CommitmentKeys[0].Commit(values); err != nil { + return err + } + if proof.CommitmentPok, err = pk.CommitmentKeys[0].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving return err } diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index ec251ada15..94907883ee 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -52,7 +52,7 @@ type ProvingKey struct { InfinityA, InfinityB []bool NbInfinityA, NbInfinityB uint64 - CommitmentKey pedersen.ProvingKey + CommitmentKeys []pedersen.ProvingKey } // VerifyingKey is used by a Groth16 verifier to verify the validity of a proof and a statement @@ -263,7 +263,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { if nbPrivateCommittedWires != 0 { commitmentBasis := g1PointsAff[offset:] - pk.CommitmentKey, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) if err != nil { return err } diff --git a/backend/groth16/bn254/commitment.go b/backend/groth16/bn254/commitment.go index 435a7c058c..0f5cbf6478 100644 --- a/backend/groth16/bn254/commitment.go +++ b/backend/groth16/bn254/commitment.go @@ -17,13 +17,23 @@ package groth16 import ( + "fmt" curve "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark/constraint" "math/big" ) +func printBigInts(x []*big.Int) { + for _, v := range x { + fmt.Println(v.String()) + } +} + func solveCommitmentWire(commitment *curve.G1Affine, publicCommitted []*big.Int) (fr.Element, error) { + fmt.Println("solveCommitmentWire") + fmt.Println(commitment.String()) + printBigInts(publicCommitted) res, err := fr.Hash(constraint.SerializeCommitment(commitment.Marshal(), publicCommitted, (fr.Bits-1)/8+1), []byte(constraint.CommitmentDst), 1) return res[0], err } diff --git a/backend/groth16/bn254/commitment_test.go b/backend/groth16/bn254/commitment_test.go index 759501ebe2..510139780b 100644 --- a/backend/groth16/bn254/commitment_test.go +++ b/backend/groth16/bn254/commitment_test.go @@ -145,6 +145,6 @@ func (c *oneSecretOnePublicCommittedCircuit) Define(api frontend.API) error { func TestOneSecretOnePublicCommitted(t *testing.T) { test(t, &oneSecretOnePublicCommittedCircuit{}, &oneSecretOnePublicCommittedCircuit{ One: 1, - Two: 2, + Two: 2, //public }) } diff --git a/backend/groth16/bn254/verify.go b/backend/groth16/bn254/verify.go index e5310d0624..0cb53f48e6 100644 --- a/backend/groth16/bn254/verify.go +++ b/backend/groth16/bn254/verify.go @@ -76,7 +76,9 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { publicCommitted[i] = &b } - if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err == nil { + if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err != nil { + return err + } else { publicWitness = append(publicWitness, res) } } diff --git a/backend/groth16/bw6-633/prove.go b/backend/groth16/bw6-633/prove.go index 971872aee4..7c06144cbd 100644 --- a/backend/groth16/bw6-633/prove.go +++ b/backend/groth16/bw6-633/prove.go @@ -80,8 +80,10 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var err error - proof.Commitment, proof.CommitmentPok, err = pk.CommitmentKey.Commit(values) - if err != nil { + if proof.Commitment, err = pk.CommitmentKeys[0].Commit(values); err != nil { + return err + } + if proof.CommitmentPok, err = pk.CommitmentKeys[0].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving return err } diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index b2b12b5c07..181cda7542 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -52,7 +52,7 @@ type ProvingKey struct { InfinityA, InfinityB []bool NbInfinityA, NbInfinityB uint64 - CommitmentKey pedersen.ProvingKey + CommitmentKeys []pedersen.ProvingKey } // VerifyingKey is used by a Groth16 verifier to verify the validity of a proof and a statement @@ -263,7 +263,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { if nbPrivateCommittedWires != 0 { commitmentBasis := g1PointsAff[offset:] - pk.CommitmentKey, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) if err != nil { return err } diff --git a/backend/groth16/bw6-761/prove.go b/backend/groth16/bw6-761/prove.go index ef5a998a7e..cce320b277 100644 --- a/backend/groth16/bw6-761/prove.go +++ b/backend/groth16/bw6-761/prove.go @@ -80,8 +80,10 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var err error - proof.Commitment, proof.CommitmentPok, err = pk.CommitmentKey.Commit(values) - if err != nil { + if proof.Commitment, err = pk.CommitmentKeys[0].Commit(values); err != nil { + return err + } + if proof.CommitmentPok, err = pk.CommitmentKeys[0].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving return err } diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index 636e35ebea..c61cdb3c3a 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -52,7 +52,7 @@ type ProvingKey struct { InfinityA, InfinityB []bool NbInfinityA, NbInfinityB uint64 - CommitmentKey pedersen.ProvingKey + CommitmentKeys []pedersen.ProvingKey } // VerifyingKey is used by a Groth16 verifier to verify the validity of a proof and a statement @@ -263,7 +263,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { if nbPrivateCommittedWires != 0 { commitmentBasis := g1PointsAff[offset:] - pk.CommitmentKey, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) if err != nil { return err } diff --git a/constraint/bn254/system.go b/constraint/bn254/system.go index 46786c663f..e44b3686f9 100644 --- a/constraint/bn254/system.go +++ b/constraint/bn254/system.go @@ -17,6 +17,7 @@ package cs import ( + "fmt" "github.com/fxamacker/cbor/v2" "io" "time" @@ -78,6 +79,11 @@ func (cs *system) Solve(witness witness.Witness, opts ...csolver.Option) (any, e // (or sooner, if a constraint is not satisfied) defer solver.printLogs(cs.Logs) + fmt.Println("witness:") + for i := range witness.Vector().(fr.Vector) { + fmt.Println(witness.Vector().(fr.Vector)[i].String()) + } + // run it. if err := solver.run(); err != nil { log.Err(err).Send() diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index 95a5ff4c06..11b3e93388 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -744,7 +744,7 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error return nil, err } - if hintOut[0], err = builder.NewHintForId(commitment.HintID, 1, v...); err != nil { + if hintOut, err = builder.NewHintForId(commitment.HintID, 1, builder.getCommittedVariables(&commitment)...); err != nil { return nil, err } diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl index a9781466a0..864757008e 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl @@ -63,8 +63,10 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var err error - proof.Commitment, proof.CommitmentPok, err = pk.CommitmentKey.Commit(values) - if err != nil { + if proof.Commitment, err = pk.CommitmentKeys[0].Commit(values); err != nil { + return err + } + if proof.CommitmentPok, err = pk.CommitmentKeys[0].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving return err } diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl index b4e0331295..4bdab14afe 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl @@ -34,7 +34,7 @@ type ProvingKey struct { InfinityA, InfinityB []bool NbInfinityA, NbInfinityB uint64 - CommitmentKey pedersen.ProvingKey + CommitmentKeys []pedersen.ProvingKey } // VerifyingKey is used by a Groth16 verifier to verify the validity of a proof and a statement @@ -245,7 +245,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { if nbPrivateCommittedWires != 0 { commitmentBasis := g1PointsAff[offset:] - pk.CommitmentKey, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) if err != nil { return err } diff --git a/test/commitments_test.go b/test/commitments_test.go index 392b4e5378..9c9e2a9d1a 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -233,17 +233,17 @@ func e2eTest(t *testing.T, assignment frontend.Circuit) { t.Parallel() t.Run("fuzzer", func(t *testing.T) { - circuit := hollow(assignment).(frontend.Circuit) + circuit := hollow(assignment) NewAssert(t).ProverSucceeded(circuit, assignment, WithBackends(backend.GROTH16, backend.PLONK)) // TODO: Support PlonkFri.Commit }) t.Run("plonk-e2e", func(t *testing.T) { - circuit := hollow(assignment).(frontend.Circuit) + circuit := hollow(assignment) plonkTest(t, circuit, assignment) }) t.Run("groth16-e2e", func(t *testing.T) { - circuit := hollow(assignment).(frontend.Circuit) + circuit := hollow(assignment) groth16Test(t, circuit, assignment) }) } From 5457111ca14a04691c01b34d25ce9a5d37772e7b Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 24 May 2023 16:19:47 -0500 Subject: [PATCH 380/464] fix: groth16 commit verification error handling --- backend/groth16/bls12-377/verify.go | 4 +++- backend/groth16/bls12-381/verify.go | 4 +++- backend/groth16/bls24-315/verify.go | 4 +++- backend/groth16/bls24-317/verify.go | 4 +++- backend/groth16/bn254/commitment.go | 10 ---------- backend/groth16/bn254/commitment_test.go | 2 +- backend/groth16/bw6-633/verify.go | 4 +++- backend/groth16/bw6-761/verify.go | 4 +++- constraint/bn254/system.go | 6 ------ .../template/zkpschemes/groth16/groth16.verify.go.tmpl | 6 ++++-- 10 files changed, 23 insertions(+), 25 deletions(-) diff --git a/backend/groth16/bls12-377/verify.go b/backend/groth16/bls12-377/verify.go index d1d18caeb7..8d804a3464 100644 --- a/backend/groth16/bls12-377/verify.go +++ b/backend/groth16/bls12-377/verify.go @@ -75,7 +75,9 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { publicCommitted[i] = &b } - if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err == nil { + if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err != nil { + return err + } else { publicWitness = append(publicWitness, res) } } diff --git a/backend/groth16/bls12-381/verify.go b/backend/groth16/bls12-381/verify.go index 4bdb023b5a..81b1ebf3ea 100644 --- a/backend/groth16/bls12-381/verify.go +++ b/backend/groth16/bls12-381/verify.go @@ -75,7 +75,9 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { publicCommitted[i] = &b } - if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err == nil { + if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err != nil { + return err + } else { publicWitness = append(publicWitness, res) } } diff --git a/backend/groth16/bls24-315/verify.go b/backend/groth16/bls24-315/verify.go index c44e9eab72..42151e800b 100644 --- a/backend/groth16/bls24-315/verify.go +++ b/backend/groth16/bls24-315/verify.go @@ -75,7 +75,9 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { publicCommitted[i] = &b } - if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err == nil { + if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err != nil { + return err + } else { publicWitness = append(publicWitness, res) } } diff --git a/backend/groth16/bls24-317/verify.go b/backend/groth16/bls24-317/verify.go index 09affc8070..86ce12f362 100644 --- a/backend/groth16/bls24-317/verify.go +++ b/backend/groth16/bls24-317/verify.go @@ -75,7 +75,9 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { publicCommitted[i] = &b } - if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err == nil { + if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err != nil { + return err + } else { publicWitness = append(publicWitness, res) } } diff --git a/backend/groth16/bn254/commitment.go b/backend/groth16/bn254/commitment.go index 0f5cbf6478..435a7c058c 100644 --- a/backend/groth16/bn254/commitment.go +++ b/backend/groth16/bn254/commitment.go @@ -17,23 +17,13 @@ package groth16 import ( - "fmt" curve "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark/constraint" "math/big" ) -func printBigInts(x []*big.Int) { - for _, v := range x { - fmt.Println(v.String()) - } -} - func solveCommitmentWire(commitment *curve.G1Affine, publicCommitted []*big.Int) (fr.Element, error) { - fmt.Println("solveCommitmentWire") - fmt.Println(commitment.String()) - printBigInts(publicCommitted) res, err := fr.Hash(constraint.SerializeCommitment(commitment.Marshal(), publicCommitted, (fr.Bits-1)/8+1), []byte(constraint.CommitmentDst), 1) return res[0], err } diff --git a/backend/groth16/bn254/commitment_test.go b/backend/groth16/bn254/commitment_test.go index 510139780b..759501ebe2 100644 --- a/backend/groth16/bn254/commitment_test.go +++ b/backend/groth16/bn254/commitment_test.go @@ -145,6 +145,6 @@ func (c *oneSecretOnePublicCommittedCircuit) Define(api frontend.API) error { func TestOneSecretOnePublicCommitted(t *testing.T) { test(t, &oneSecretOnePublicCommittedCircuit{}, &oneSecretOnePublicCommittedCircuit{ One: 1, - Two: 2, //public + Two: 2, }) } diff --git a/backend/groth16/bw6-633/verify.go b/backend/groth16/bw6-633/verify.go index 7bed98172f..2769307995 100644 --- a/backend/groth16/bw6-633/verify.go +++ b/backend/groth16/bw6-633/verify.go @@ -75,7 +75,9 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { publicCommitted[i] = &b } - if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err == nil { + if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err != nil { + return err + } else { publicWitness = append(publicWitness, res) } } diff --git a/backend/groth16/bw6-761/verify.go b/backend/groth16/bw6-761/verify.go index b30724bef0..66aaf4c861 100644 --- a/backend/groth16/bw6-761/verify.go +++ b/backend/groth16/bw6-761/verify.go @@ -75,7 +75,9 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { publicCommitted[i] = &b } - if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err == nil { + if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err != nil { + return err + } else { publicWitness = append(publicWitness, res) } } diff --git a/constraint/bn254/system.go b/constraint/bn254/system.go index e44b3686f9..46786c663f 100644 --- a/constraint/bn254/system.go +++ b/constraint/bn254/system.go @@ -17,7 +17,6 @@ package cs import ( - "fmt" "github.com/fxamacker/cbor/v2" "io" "time" @@ -79,11 +78,6 @@ func (cs *system) Solve(witness witness.Witness, opts ...csolver.Option) (any, e // (or sooner, if a constraint is not satisfied) defer solver.printLogs(cs.Logs) - fmt.Println("witness:") - for i := range witness.Vector().(fr.Vector) { - fmt.Println(witness.Vector().(fr.Vector)[i].String()) - } - // run it. if err := solver.run(); err != nil { log.Err(err).Send() diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl index 307b82f0bf..d40af97e21 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl @@ -59,8 +59,10 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { publicWitness[vk.PublicCommitted[i]-1].BigInt(&b) publicCommitted[i] = &b } - - if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err == nil { + + if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err != nil { + return err + } else { publicWitness = append(publicWitness, res) } } From f6ba8f4b01b199036f5971413197faa15991d12c Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 24 May 2023 16:40:04 -0500 Subject: [PATCH 381/464] fix: no private committed bug --- backend/groth16/bls12-377/setup.go | 12 ++++++------ backend/groth16/bls12-381/setup.go | 12 ++++++------ backend/groth16/bls24-315/setup.go | 12 ++++++------ backend/groth16/bls24-317/setup.go | 12 ++++++------ backend/groth16/bn254/setup.go | 12 ++++++------ backend/groth16/bw6-633/setup.go | 12 ++++++------ backend/groth16/bw6-761/setup.go | 12 ++++++------ .../zkpschemes/groth16/groth16.setup.go.tmpl | 12 ++++++------ 8 files changed, 48 insertions(+), 48 deletions(-) diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index 4305f38ad6..676f7abadb 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -260,14 +260,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // --------------------------------------------------------------------------------------------- // Commitment setup - if nbPrivateCommittedWires != 0 { - commitmentBasis := g1PointsAff[offset:] + //if nbPrivateCommittedWires != 0 { + commitmentBasis := g1PointsAff[offset:] - pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) - if err != nil { - return err - } + pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + if err != nil { + return err } + //} if vk.HasCommitment = r1cs.GetNbCommitments() != 0; vk.HasCommitment { vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index d00bd1a012..cc2371c98d 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -260,14 +260,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // --------------------------------------------------------------------------------------------- // Commitment setup - if nbPrivateCommittedWires != 0 { - commitmentBasis := g1PointsAff[offset:] + //if nbPrivateCommittedWires != 0 { + commitmentBasis := g1PointsAff[offset:] - pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) - if err != nil { - return err - } + pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + if err != nil { + return err } + //} if vk.HasCommitment = r1cs.GetNbCommitments() != 0; vk.HasCommitment { vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index 8b43794587..628b1f1341 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -260,14 +260,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // --------------------------------------------------------------------------------------------- // Commitment setup - if nbPrivateCommittedWires != 0 { - commitmentBasis := g1PointsAff[offset:] + //if nbPrivateCommittedWires != 0 { + commitmentBasis := g1PointsAff[offset:] - pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) - if err != nil { - return err - } + pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + if err != nil { + return err } + //} if vk.HasCommitment = r1cs.GetNbCommitments() != 0; vk.HasCommitment { vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index 94907883ee..b47ccc951f 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -260,14 +260,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // --------------------------------------------------------------------------------------------- // Commitment setup - if nbPrivateCommittedWires != 0 { - commitmentBasis := g1PointsAff[offset:] + //if nbPrivateCommittedWires != 0 { + commitmentBasis := g1PointsAff[offset:] - pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) - if err != nil { - return err - } + pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + if err != nil { + return err } + //} if vk.HasCommitment = r1cs.GetNbCommitments() != 0; vk.HasCommitment { vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index 2e63fd711c..bd7f98817f 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -260,14 +260,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // --------------------------------------------------------------------------------------------- // Commitment setup - if nbPrivateCommittedWires != 0 { - commitmentBasis := g1PointsAff[offset:] + //if nbPrivateCommittedWires != 0 { + commitmentBasis := g1PointsAff[offset:] - pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) - if err != nil { - return err - } + pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + if err != nil { + return err } + //} if vk.HasCommitment = r1cs.GetNbCommitments() != 0; vk.HasCommitment { vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index 181cda7542..e9d7b115b6 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -260,14 +260,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // --------------------------------------------------------------------------------------------- // Commitment setup - if nbPrivateCommittedWires != 0 { - commitmentBasis := g1PointsAff[offset:] + //if nbPrivateCommittedWires != 0 { + commitmentBasis := g1PointsAff[offset:] - pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) - if err != nil { - return err - } + pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + if err != nil { + return err } + //} if vk.HasCommitment = r1cs.GetNbCommitments() != 0; vk.HasCommitment { vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index c61cdb3c3a..a0588ccf7b 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -260,14 +260,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // --------------------------------------------------------------------------------------------- // Commitment setup - if nbPrivateCommittedWires != 0 { - commitmentBasis := g1PointsAff[offset:] + //if nbPrivateCommittedWires != 0 { + commitmentBasis := g1PointsAff[offset:] - pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) - if err != nil { - return err - } + pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + if err != nil { + return err } + //} if vk.HasCommitment = r1cs.GetNbCommitments() != 0; vk.HasCommitment { vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl index 4bdab14afe..4b2f820145 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl @@ -242,14 +242,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // --------------------------------------------------------------------------------------------- // Commitment setup - if nbPrivateCommittedWires != 0 { - commitmentBasis := g1PointsAff[offset:] + //if nbPrivateCommittedWires != 0 { + commitmentBasis := g1PointsAff[offset:] - pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) - if err != nil { - return err - } + pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + if err != nil { + return err } + //} if vk.HasCommitment = r1cs.GetNbCommitments() != 0; vk.HasCommitment { vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() From 7f67e1e3c786bbfa5149616d3b87fcdff8e3c1fa Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 24 May 2023 16:48:01 -0500 Subject: [PATCH 382/464] feat: prover with no commitment act like vanilla groth16 --- backend/groth16/bls12-377/prove.go | 18 +++++++++--------- backend/groth16/bls12-381/prove.go | 18 +++++++++--------- backend/groth16/bls24-315/prove.go | 18 +++++++++--------- backend/groth16/bls24-317/prove.go | 18 +++++++++--------- backend/groth16/bn254/prove.go | 18 +++++++++--------- backend/groth16/bw6-633/prove.go | 18 +++++++++--------- backend/groth16/bw6-761/prove.go | 18 +++++++++--------- .../zkpschemes/groth16/groth16.prove.go.tmpl | 18 +++++++++--------- 8 files changed, 72 insertions(+), 72 deletions(-) diff --git a/backend/groth16/bls12-377/prove.go b/backend/groth16/bls12-377/prove.go index d1e5e7a330..c22d87b773 100644 --- a/backend/groth16/bls12-377/prove.go +++ b/backend/groth16/bls12-377/prove.go @@ -65,14 +65,14 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.GetNbCommitments() != 0 { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { + for i := range r1cs.CommitmentInfo { + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function - if len(in) != r1cs.CommitmentInfo[0].NbCommitted() { // TODO: Remove + if len(in) != r1cs.CommitmentInfo[i].NbCommitted() { // TODO: Remove return fmt.Errorf("unexpected number of committed variables") } - values := make([]fr.Element, r1cs.CommitmentInfo[0].NbPrivateCommitted) + values := make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) nbPublicCommitted := len(in) - len(values) inPrivate := in[nbPublicCommitted:] for i, inI := range inPrivate { @@ -80,15 +80,15 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var err error - if proof.Commitment, err = pk.CommitmentKeys[0].Commit(values); err != nil { + if proof.Commitment, err = pk.CommitmentKeys[i].Commit(values); err != nil { return err } - if proof.CommitmentPok, err = pk.CommitmentKeys[0].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving + if proof.CommitmentPok, err = pk.CommitmentKeys[i].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving return err } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[0].NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) res.BigInt(out[0]) return err })) @@ -206,8 +206,8 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed _wireValues := wireValues - if r1cs.GetNbCommitments() != 0 { - _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) + for i := range r1cs.CommitmentInfo { + _wireValues = filter(_wireValues, r1cs.CommitmentInfo[i].PrivateToPublicGroth16()) } if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { diff --git a/backend/groth16/bls12-381/prove.go b/backend/groth16/bls12-381/prove.go index 1e68abeed5..246c908d35 100644 --- a/backend/groth16/bls12-381/prove.go +++ b/backend/groth16/bls12-381/prove.go @@ -65,14 +65,14 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.GetNbCommitments() != 0 { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { + for i := range r1cs.CommitmentInfo { + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function - if len(in) != r1cs.CommitmentInfo[0].NbCommitted() { // TODO: Remove + if len(in) != r1cs.CommitmentInfo[i].NbCommitted() { // TODO: Remove return fmt.Errorf("unexpected number of committed variables") } - values := make([]fr.Element, r1cs.CommitmentInfo[0].NbPrivateCommitted) + values := make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) nbPublicCommitted := len(in) - len(values) inPrivate := in[nbPublicCommitted:] for i, inI := range inPrivate { @@ -80,15 +80,15 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var err error - if proof.Commitment, err = pk.CommitmentKeys[0].Commit(values); err != nil { + if proof.Commitment, err = pk.CommitmentKeys[i].Commit(values); err != nil { return err } - if proof.CommitmentPok, err = pk.CommitmentKeys[0].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving + if proof.CommitmentPok, err = pk.CommitmentKeys[i].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving return err } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[0].NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) res.BigInt(out[0]) return err })) @@ -206,8 +206,8 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed _wireValues := wireValues - if r1cs.GetNbCommitments() != 0 { - _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) + for i := range r1cs.CommitmentInfo { + _wireValues = filter(_wireValues, r1cs.CommitmentInfo[i].PrivateToPublicGroth16()) } if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { diff --git a/backend/groth16/bls24-315/prove.go b/backend/groth16/bls24-315/prove.go index 518bb6cdfa..a5662ab206 100644 --- a/backend/groth16/bls24-315/prove.go +++ b/backend/groth16/bls24-315/prove.go @@ -65,14 +65,14 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.GetNbCommitments() != 0 { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { + for i := range r1cs.CommitmentInfo { + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function - if len(in) != r1cs.CommitmentInfo[0].NbCommitted() { // TODO: Remove + if len(in) != r1cs.CommitmentInfo[i].NbCommitted() { // TODO: Remove return fmt.Errorf("unexpected number of committed variables") } - values := make([]fr.Element, r1cs.CommitmentInfo[0].NbPrivateCommitted) + values := make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) nbPublicCommitted := len(in) - len(values) inPrivate := in[nbPublicCommitted:] for i, inI := range inPrivate { @@ -80,15 +80,15 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var err error - if proof.Commitment, err = pk.CommitmentKeys[0].Commit(values); err != nil { + if proof.Commitment, err = pk.CommitmentKeys[i].Commit(values); err != nil { return err } - if proof.CommitmentPok, err = pk.CommitmentKeys[0].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving + if proof.CommitmentPok, err = pk.CommitmentKeys[i].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving return err } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[0].NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) res.BigInt(out[0]) return err })) @@ -206,8 +206,8 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed _wireValues := wireValues - if r1cs.GetNbCommitments() != 0 { - _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) + for i := range r1cs.CommitmentInfo { + _wireValues = filter(_wireValues, r1cs.CommitmentInfo[i].PrivateToPublicGroth16()) } if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { diff --git a/backend/groth16/bls24-317/prove.go b/backend/groth16/bls24-317/prove.go index b11eedfc46..04538e7f5c 100644 --- a/backend/groth16/bls24-317/prove.go +++ b/backend/groth16/bls24-317/prove.go @@ -65,14 +65,14 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.GetNbCommitments() != 0 { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { + for i := range r1cs.CommitmentInfo { + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function - if len(in) != r1cs.CommitmentInfo[0].NbCommitted() { // TODO: Remove + if len(in) != r1cs.CommitmentInfo[i].NbCommitted() { // TODO: Remove return fmt.Errorf("unexpected number of committed variables") } - values := make([]fr.Element, r1cs.CommitmentInfo[0].NbPrivateCommitted) + values := make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) nbPublicCommitted := len(in) - len(values) inPrivate := in[nbPublicCommitted:] for i, inI := range inPrivate { @@ -80,15 +80,15 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var err error - if proof.Commitment, err = pk.CommitmentKeys[0].Commit(values); err != nil { + if proof.Commitment, err = pk.CommitmentKeys[i].Commit(values); err != nil { return err } - if proof.CommitmentPok, err = pk.CommitmentKeys[0].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving + if proof.CommitmentPok, err = pk.CommitmentKeys[i].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving return err } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[0].NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) res.BigInt(out[0]) return err })) @@ -206,8 +206,8 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed _wireValues := wireValues - if r1cs.GetNbCommitments() != 0 { - _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) + for i := range r1cs.CommitmentInfo { + _wireValues = filter(_wireValues, r1cs.CommitmentInfo[i].PrivateToPublicGroth16()) } if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index 4b0d5ab479..10d5c1150c 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -65,14 +65,14 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.GetNbCommitments() != 0 { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { + for i := range r1cs.CommitmentInfo { + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function - if len(in) != r1cs.CommitmentInfo[0].NbCommitted() { // TODO: Remove + if len(in) != r1cs.CommitmentInfo[i].NbCommitted() { // TODO: Remove return fmt.Errorf("unexpected number of committed variables") } - values := make([]fr.Element, r1cs.CommitmentInfo[0].NbPrivateCommitted) + values := make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) nbPublicCommitted := len(in) - len(values) inPrivate := in[nbPublicCommitted:] for i, inI := range inPrivate { @@ -80,15 +80,15 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var err error - if proof.Commitment, err = pk.CommitmentKeys[0].Commit(values); err != nil { + if proof.Commitment, err = pk.CommitmentKeys[i].Commit(values); err != nil { return err } - if proof.CommitmentPok, err = pk.CommitmentKeys[0].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving + if proof.CommitmentPok, err = pk.CommitmentKeys[i].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving return err } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[0].NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) res.BigInt(out[0]) return err })) @@ -206,8 +206,8 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed _wireValues := wireValues - if r1cs.GetNbCommitments() != 0 { - _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) + for i := range r1cs.CommitmentInfo { + _wireValues = filter(_wireValues, r1cs.CommitmentInfo[i].PrivateToPublicGroth16()) } if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { diff --git a/backend/groth16/bw6-633/prove.go b/backend/groth16/bw6-633/prove.go index 7c06144cbd..927d6d4504 100644 --- a/backend/groth16/bw6-633/prove.go +++ b/backend/groth16/bw6-633/prove.go @@ -65,14 +65,14 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.GetNbCommitments() != 0 { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { + for i := range r1cs.CommitmentInfo { + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function - if len(in) != r1cs.CommitmentInfo[0].NbCommitted() { // TODO: Remove + if len(in) != r1cs.CommitmentInfo[i].NbCommitted() { // TODO: Remove return fmt.Errorf("unexpected number of committed variables") } - values := make([]fr.Element, r1cs.CommitmentInfo[0].NbPrivateCommitted) + values := make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) nbPublicCommitted := len(in) - len(values) inPrivate := in[nbPublicCommitted:] for i, inI := range inPrivate { @@ -80,15 +80,15 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var err error - if proof.Commitment, err = pk.CommitmentKeys[0].Commit(values); err != nil { + if proof.Commitment, err = pk.CommitmentKeys[i].Commit(values); err != nil { return err } - if proof.CommitmentPok, err = pk.CommitmentKeys[0].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving + if proof.CommitmentPok, err = pk.CommitmentKeys[i].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving return err } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[0].NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) res.BigInt(out[0]) return err })) @@ -206,8 +206,8 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed _wireValues := wireValues - if r1cs.GetNbCommitments() != 0 { - _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) + for i := range r1cs.CommitmentInfo { + _wireValues = filter(_wireValues, r1cs.CommitmentInfo[i].PrivateToPublicGroth16()) } if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { diff --git a/backend/groth16/bw6-761/prove.go b/backend/groth16/bw6-761/prove.go index cce320b277..b4b4d74853 100644 --- a/backend/groth16/bw6-761/prove.go +++ b/backend/groth16/bw6-761/prove.go @@ -65,14 +65,14 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.GetNbCommitments() != 0 { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { + for i := range r1cs.CommitmentInfo { + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function - if len(in) != r1cs.CommitmentInfo[0].NbCommitted() { // TODO: Remove + if len(in) != r1cs.CommitmentInfo[i].NbCommitted() { // TODO: Remove return fmt.Errorf("unexpected number of committed variables") } - values := make([]fr.Element, r1cs.CommitmentInfo[0].NbPrivateCommitted) + values := make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) nbPublicCommitted := len(in) - len(values) inPrivate := in[nbPublicCommitted:] for i, inI := range inPrivate { @@ -80,15 +80,15 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var err error - if proof.Commitment, err = pk.CommitmentKeys[0].Commit(values); err != nil { + if proof.Commitment, err = pk.CommitmentKeys[i].Commit(values); err != nil { return err } - if proof.CommitmentPok, err = pk.CommitmentKeys[0].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving + if proof.CommitmentPok, err = pk.CommitmentKeys[i].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving return err } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[0].NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) res.BigInt(out[0]) return err })) @@ -206,8 +206,8 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed _wireValues := wireValues - if r1cs.GetNbCommitments() != 0 { - _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) + for i := range r1cs.CommitmentInfo { + _wireValues = filter(_wireValues, r1cs.CommitmentInfo[i].PrivateToPublicGroth16()) } if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl index 864757008e..c4bb8425c3 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl @@ -48,14 +48,14 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - if r1cs.GetNbCommitments() != 0 { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[0].HintID,func(_ *big.Int, in []*big.Int, out []*big.Int) error { + for i := range r1cs.CommitmentInfo { + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID,func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. // If that is the case, figure out a way to feed the solution vector into this function - if len(in) != r1cs.CommitmentInfo[0].NbCommitted() { // TODO: Remove + if len(in) != r1cs.CommitmentInfo[i].NbCommitted() { // TODO: Remove return fmt.Errorf("unexpected number of committed variables") } - values := make([]fr.Element, r1cs.CommitmentInfo[0].NbPrivateCommitted) + values := make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) nbPublicCommitted := len(in) - len(values) inPrivate := in[nbPublicCommitted:] for i, inI := range inPrivate { @@ -63,15 +63,15 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var err error - if proof.Commitment, err = pk.CommitmentKeys[0].Commit(values); err != nil { + if proof.Commitment, err = pk.CommitmentKeys[i].Commit(values); err != nil { return err } - if proof.CommitmentPok, err = pk.CommitmentKeys[0].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving + if proof.CommitmentPok, err = pk.CommitmentKeys[i].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving return err } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[0].NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) res.BigInt(out[0]) return err } )) @@ -189,8 +189,8 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed _wireValues := wireValues - if r1cs.GetNbCommitments() != 0 { - _wireValues = filter(wireValues, r1cs.CommitmentInfo[0].PrivateToPublicGroth16()) + for i := range r1cs.CommitmentInfo { + _wireValues = filter(_wireValues, r1cs.CommitmentInfo[i].PrivateToPublicGroth16()) } if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { From 4f5f5802fdd20aae8574f0e45809192869a264e4 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 24 May 2023 17:17:35 -0500 Subject: [PATCH 383/464] feat: no commitments -> vanilla groth16 --- backend/groth16/bls12-377/prove.go | 15 +- backend/groth16/bls12-377/setup.go | 8 +- backend/groth16/bls12-377/verify.go | 24 +- backend/groth16/bls12-381/prove.go | 15 +- backend/groth16/bls12-381/setup.go | 8 +- backend/groth16/bls12-381/verify.go | 24 +- backend/groth16/bls24-315/prove.go | 15 +- backend/groth16/bls24-315/setup.go | 8 +- backend/groth16/bls24-315/verify.go | 24 +- backend/groth16/bls24-317/prove.go | 15 +- backend/groth16/bls24-317/setup.go | 8 +- backend/groth16/bls24-317/verify.go | 24 +- backend/groth16/bn254/prove.go | 17 +- backend/groth16/bn254/setup.go | 8 +- backend/groth16/bn254/verify.go | 24 +- backend/groth16/bw6-633/prove.go | 15 +- backend/groth16/bw6-633/setup.go | 8 +- backend/groth16/bw6-633/verify.go | 24 +- backend/groth16/bw6-761/prove.go | 15 +- backend/groth16/bw6-761/setup.go | 8 +- backend/groth16/bw6-761/verify.go | 24 +- .../zkpschemes/groth16/groth16.prove.go.tmpl | 11 +- .../zkpschemes/groth16/groth16.setup.go.tmpl | 8 +- .../zkpschemes/groth16/groth16.verify.go.tmpl | 24 +- test/commitments_test.gop | 249 ++++++++++++++++++ 25 files changed, 432 insertions(+), 191 deletions(-) create mode 100644 test/commitments_test.gop diff --git a/backend/groth16/bls12-377/prove.go b/backend/groth16/bls12-377/prove.go index c22d87b773..95fda0d9fc 100644 --- a/backend/groth16/bls12-377/prove.go +++ b/backend/groth16/bls12-377/prove.go @@ -37,9 +37,10 @@ import ( // with a valid statement and a VerifyingKey // Notation follows Figure 4. in DIZK paper https://eprint.iacr.org/2018/691.pdf type Proof struct { - Ar, Krs curve.G1Affine - Bs curve.G2Affine - Commitment, CommitmentPok curve.G1Affine + Ar, Krs curve.G1Affine + Bs curve.G2Affine + CommitmentPok curve.G1Affine + Commitments []curve.G1Affine } // isValid ensures proof elements are in the correct subgroup @@ -75,12 +76,12 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b values := make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) nbPublicCommitted := len(in) - len(values) inPrivate := in[nbPublicCommitted:] - for i, inI := range inPrivate { - values[i].SetBigInt(inI) + for j, inJ := range inPrivate { + values[j].SetBigInt(inJ) } var err error - if proof.Commitment, err = pk.CommitmentKeys[i].Commit(values); err != nil { + if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(values); err != nil { return err } if proof.CommitmentPok, err = pk.CommitmentKeys[i].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving @@ -88,7 +89,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitments[i], in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) res.BigInt(out[0]) return err })) diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index 676f7abadb..3c1f436351 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -76,8 +76,7 @@ type VerifyingKey struct { e curve.GT // not serialized CommitmentKey pedersen.VerifyingKey - HasCommitment bool // TODO: Make CommitmentKey nullable instead - PublicCommitted []int // indexes of public committed variables + PublicCommitted [][]int // indexes of public committed variables } // Setup constructs the SRS @@ -269,8 +268,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } //} - if vk.HasCommitment = r1cs.GetNbCommitments() != 0; vk.HasCommitment { - vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() + vk.PublicCommitted = make([][]int, len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + vk.PublicCommitted[i] = r1cs.CommitmentInfo[i].PublicCommitted() } // --------------------------------------------------------------------------------------------- diff --git a/backend/groth16/bls12-377/verify.go b/backend/groth16/bls12-377/verify.go index 8d804a3464..4a2c1a0a8d 100644 --- a/backend/groth16/bls12-377/verify.go +++ b/backend/groth16/bls12-377/verify.go @@ -36,10 +36,8 @@ var ( // Verify verifies a proof with given VerifyingKey and publicWitness func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { - nbPublicVars := len(vk.G1.K) - if vk.HasCommitment { - nbPublicVars-- - } + nbPublicVars := len(vk.G1.K) - len(vk.PublicCommitted) + if len(publicWitness) != nbPublicVars-1 { return fmt.Errorf("invalid witness size, got %d, expected %d (public - ONE_WIRE)", len(publicWitness), len(vk.G1.K)-1) } @@ -62,20 +60,20 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() - if vk.HasCommitment { + for i := range vk.PublicCommitted { - if err := vk.CommitmentKey.Verify(proof.Commitment, proof.CommitmentPok); err != nil { + if err := vk.CommitmentKey.Verify(proof.Commitments[i], proof.CommitmentPok); err != nil { return err } - publicCommitted := make([]*big.Int, len(vk.PublicCommitted)) - for i := range publicCommitted { + publicCommitted := make([]*big.Int, len(vk.PublicCommitted[i])) + for j := range publicCommitted { var b big.Int - publicWitness[vk.PublicCommitted[i]-1].BigInt(&b) - publicCommitted[i] = &b + publicWitness[vk.PublicCommitted[i][j]-1].BigInt(&b) + publicCommitted[j] = &b } - if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err != nil { + if res, err := solveCommitmentWire(&proof.Commitments[i], publicCommitted); err != nil { return err } else { publicWitness = append(publicWitness, res) @@ -89,8 +87,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } kSum.AddMixed(&vk.G1.K[0]) - if vk.HasCommitment { - kSum.AddMixed(&proof.Commitment) + for i := range proof.Commitments { + kSum.AddMixed(&proof.Commitments[i]) } var kSumAff curve.G1Affine diff --git a/backend/groth16/bls12-381/prove.go b/backend/groth16/bls12-381/prove.go index 246c908d35..aefb066ef0 100644 --- a/backend/groth16/bls12-381/prove.go +++ b/backend/groth16/bls12-381/prove.go @@ -37,9 +37,10 @@ import ( // with a valid statement and a VerifyingKey // Notation follows Figure 4. in DIZK paper https://eprint.iacr.org/2018/691.pdf type Proof struct { - Ar, Krs curve.G1Affine - Bs curve.G2Affine - Commitment, CommitmentPok curve.G1Affine + Ar, Krs curve.G1Affine + Bs curve.G2Affine + CommitmentPok curve.G1Affine + Commitments []curve.G1Affine } // isValid ensures proof elements are in the correct subgroup @@ -75,12 +76,12 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b values := make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) nbPublicCommitted := len(in) - len(values) inPrivate := in[nbPublicCommitted:] - for i, inI := range inPrivate { - values[i].SetBigInt(inI) + for j, inJ := range inPrivate { + values[j].SetBigInt(inJ) } var err error - if proof.Commitment, err = pk.CommitmentKeys[i].Commit(values); err != nil { + if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(values); err != nil { return err } if proof.CommitmentPok, err = pk.CommitmentKeys[i].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving @@ -88,7 +89,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitments[i], in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) res.BigInt(out[0]) return err })) diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index cc2371c98d..32d7645a8b 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -76,8 +76,7 @@ type VerifyingKey struct { e curve.GT // not serialized CommitmentKey pedersen.VerifyingKey - HasCommitment bool // TODO: Make CommitmentKey nullable instead - PublicCommitted []int // indexes of public committed variables + PublicCommitted [][]int // indexes of public committed variables } // Setup constructs the SRS @@ -269,8 +268,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } //} - if vk.HasCommitment = r1cs.GetNbCommitments() != 0; vk.HasCommitment { - vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() + vk.PublicCommitted = make([][]int, len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + vk.PublicCommitted[i] = r1cs.CommitmentInfo[i].PublicCommitted() } // --------------------------------------------------------------------------------------------- diff --git a/backend/groth16/bls12-381/verify.go b/backend/groth16/bls12-381/verify.go index 81b1ebf3ea..fefaeb1dfa 100644 --- a/backend/groth16/bls12-381/verify.go +++ b/backend/groth16/bls12-381/verify.go @@ -36,10 +36,8 @@ var ( // Verify verifies a proof with given VerifyingKey and publicWitness func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { - nbPublicVars := len(vk.G1.K) - if vk.HasCommitment { - nbPublicVars-- - } + nbPublicVars := len(vk.G1.K) - len(vk.PublicCommitted) + if len(publicWitness) != nbPublicVars-1 { return fmt.Errorf("invalid witness size, got %d, expected %d (public - ONE_WIRE)", len(publicWitness), len(vk.G1.K)-1) } @@ -62,20 +60,20 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() - if vk.HasCommitment { + for i := range vk.PublicCommitted { - if err := vk.CommitmentKey.Verify(proof.Commitment, proof.CommitmentPok); err != nil { + if err := vk.CommitmentKey.Verify(proof.Commitments[i], proof.CommitmentPok); err != nil { return err } - publicCommitted := make([]*big.Int, len(vk.PublicCommitted)) - for i := range publicCommitted { + publicCommitted := make([]*big.Int, len(vk.PublicCommitted[i])) + for j := range publicCommitted { var b big.Int - publicWitness[vk.PublicCommitted[i]-1].BigInt(&b) - publicCommitted[i] = &b + publicWitness[vk.PublicCommitted[i][j]-1].BigInt(&b) + publicCommitted[j] = &b } - if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err != nil { + if res, err := solveCommitmentWire(&proof.Commitments[i], publicCommitted); err != nil { return err } else { publicWitness = append(publicWitness, res) @@ -89,8 +87,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } kSum.AddMixed(&vk.G1.K[0]) - if vk.HasCommitment { - kSum.AddMixed(&proof.Commitment) + for i := range proof.Commitments { + kSum.AddMixed(&proof.Commitments[i]) } var kSumAff curve.G1Affine diff --git a/backend/groth16/bls24-315/prove.go b/backend/groth16/bls24-315/prove.go index a5662ab206..cc7bed7b5c 100644 --- a/backend/groth16/bls24-315/prove.go +++ b/backend/groth16/bls24-315/prove.go @@ -37,9 +37,10 @@ import ( // with a valid statement and a VerifyingKey // Notation follows Figure 4. in DIZK paper https://eprint.iacr.org/2018/691.pdf type Proof struct { - Ar, Krs curve.G1Affine - Bs curve.G2Affine - Commitment, CommitmentPok curve.G1Affine + Ar, Krs curve.G1Affine + Bs curve.G2Affine + CommitmentPok curve.G1Affine + Commitments []curve.G1Affine } // isValid ensures proof elements are in the correct subgroup @@ -75,12 +76,12 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b values := make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) nbPublicCommitted := len(in) - len(values) inPrivate := in[nbPublicCommitted:] - for i, inI := range inPrivate { - values[i].SetBigInt(inI) + for j, inJ := range inPrivate { + values[j].SetBigInt(inJ) } var err error - if proof.Commitment, err = pk.CommitmentKeys[i].Commit(values); err != nil { + if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(values); err != nil { return err } if proof.CommitmentPok, err = pk.CommitmentKeys[i].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving @@ -88,7 +89,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitments[i], in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) res.BigInt(out[0]) return err })) diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index 628b1f1341..1bc849c204 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -76,8 +76,7 @@ type VerifyingKey struct { e curve.GT // not serialized CommitmentKey pedersen.VerifyingKey - HasCommitment bool // TODO: Make CommitmentKey nullable instead - PublicCommitted []int // indexes of public committed variables + PublicCommitted [][]int // indexes of public committed variables } // Setup constructs the SRS @@ -269,8 +268,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } //} - if vk.HasCommitment = r1cs.GetNbCommitments() != 0; vk.HasCommitment { - vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() + vk.PublicCommitted = make([][]int, len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + vk.PublicCommitted[i] = r1cs.CommitmentInfo[i].PublicCommitted() } // --------------------------------------------------------------------------------------------- diff --git a/backend/groth16/bls24-315/verify.go b/backend/groth16/bls24-315/verify.go index 42151e800b..d9bf187e03 100644 --- a/backend/groth16/bls24-315/verify.go +++ b/backend/groth16/bls24-315/verify.go @@ -36,10 +36,8 @@ var ( // Verify verifies a proof with given VerifyingKey and publicWitness func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { - nbPublicVars := len(vk.G1.K) - if vk.HasCommitment { - nbPublicVars-- - } + nbPublicVars := len(vk.G1.K) - len(vk.PublicCommitted) + if len(publicWitness) != nbPublicVars-1 { return fmt.Errorf("invalid witness size, got %d, expected %d (public - ONE_WIRE)", len(publicWitness), len(vk.G1.K)-1) } @@ -62,20 +60,20 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() - if vk.HasCommitment { + for i := range vk.PublicCommitted { - if err := vk.CommitmentKey.Verify(proof.Commitment, proof.CommitmentPok); err != nil { + if err := vk.CommitmentKey.Verify(proof.Commitments[i], proof.CommitmentPok); err != nil { return err } - publicCommitted := make([]*big.Int, len(vk.PublicCommitted)) - for i := range publicCommitted { + publicCommitted := make([]*big.Int, len(vk.PublicCommitted[i])) + for j := range publicCommitted { var b big.Int - publicWitness[vk.PublicCommitted[i]-1].BigInt(&b) - publicCommitted[i] = &b + publicWitness[vk.PublicCommitted[i][j]-1].BigInt(&b) + publicCommitted[j] = &b } - if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err != nil { + if res, err := solveCommitmentWire(&proof.Commitments[i], publicCommitted); err != nil { return err } else { publicWitness = append(publicWitness, res) @@ -89,8 +87,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } kSum.AddMixed(&vk.G1.K[0]) - if vk.HasCommitment { - kSum.AddMixed(&proof.Commitment) + for i := range proof.Commitments { + kSum.AddMixed(&proof.Commitments[i]) } var kSumAff curve.G1Affine diff --git a/backend/groth16/bls24-317/prove.go b/backend/groth16/bls24-317/prove.go index 04538e7f5c..2f52346d35 100644 --- a/backend/groth16/bls24-317/prove.go +++ b/backend/groth16/bls24-317/prove.go @@ -37,9 +37,10 @@ import ( // with a valid statement and a VerifyingKey // Notation follows Figure 4. in DIZK paper https://eprint.iacr.org/2018/691.pdf type Proof struct { - Ar, Krs curve.G1Affine - Bs curve.G2Affine - Commitment, CommitmentPok curve.G1Affine + Ar, Krs curve.G1Affine + Bs curve.G2Affine + CommitmentPok curve.G1Affine + Commitments []curve.G1Affine } // isValid ensures proof elements are in the correct subgroup @@ -75,12 +76,12 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b values := make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) nbPublicCommitted := len(in) - len(values) inPrivate := in[nbPublicCommitted:] - for i, inI := range inPrivate { - values[i].SetBigInt(inI) + for j, inJ := range inPrivate { + values[j].SetBigInt(inJ) } var err error - if proof.Commitment, err = pk.CommitmentKeys[i].Commit(values); err != nil { + if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(values); err != nil { return err } if proof.CommitmentPok, err = pk.CommitmentKeys[i].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving @@ -88,7 +89,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitments[i], in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) res.BigInt(out[0]) return err })) diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index b47ccc951f..77dc2f1618 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -76,8 +76,7 @@ type VerifyingKey struct { e curve.GT // not serialized CommitmentKey pedersen.VerifyingKey - HasCommitment bool // TODO: Make CommitmentKey nullable instead - PublicCommitted []int // indexes of public committed variables + PublicCommitted [][]int // indexes of public committed variables } // Setup constructs the SRS @@ -269,8 +268,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } //} - if vk.HasCommitment = r1cs.GetNbCommitments() != 0; vk.HasCommitment { - vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() + vk.PublicCommitted = make([][]int, len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + vk.PublicCommitted[i] = r1cs.CommitmentInfo[i].PublicCommitted() } // --------------------------------------------------------------------------------------------- diff --git a/backend/groth16/bls24-317/verify.go b/backend/groth16/bls24-317/verify.go index 86ce12f362..0b5f449cb6 100644 --- a/backend/groth16/bls24-317/verify.go +++ b/backend/groth16/bls24-317/verify.go @@ -36,10 +36,8 @@ var ( // Verify verifies a proof with given VerifyingKey and publicWitness func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { - nbPublicVars := len(vk.G1.K) - if vk.HasCommitment { - nbPublicVars-- - } + nbPublicVars := len(vk.G1.K) - len(vk.PublicCommitted) + if len(publicWitness) != nbPublicVars-1 { return fmt.Errorf("invalid witness size, got %d, expected %d (public - ONE_WIRE)", len(publicWitness), len(vk.G1.K)-1) } @@ -62,20 +60,20 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() - if vk.HasCommitment { + for i := range vk.PublicCommitted { - if err := vk.CommitmentKey.Verify(proof.Commitment, proof.CommitmentPok); err != nil { + if err := vk.CommitmentKey.Verify(proof.Commitments[i], proof.CommitmentPok); err != nil { return err } - publicCommitted := make([]*big.Int, len(vk.PublicCommitted)) - for i := range publicCommitted { + publicCommitted := make([]*big.Int, len(vk.PublicCommitted[i])) + for j := range publicCommitted { var b big.Int - publicWitness[vk.PublicCommitted[i]-1].BigInt(&b) - publicCommitted[i] = &b + publicWitness[vk.PublicCommitted[i][j]-1].BigInt(&b) + publicCommitted[j] = &b } - if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err != nil { + if res, err := solveCommitmentWire(&proof.Commitments[i], publicCommitted); err != nil { return err } else { publicWitness = append(publicWitness, res) @@ -89,8 +87,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } kSum.AddMixed(&vk.G1.K[0]) - if vk.HasCommitment { - kSum.AddMixed(&proof.Commitment) + for i := range proof.Commitments { + kSum.AddMixed(&proof.Commitments[i]) } var kSumAff curve.G1Affine diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index 10d5c1150c..45722c553e 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -37,9 +37,10 @@ import ( // with a valid statement and a VerifyingKey // Notation follows Figure 4. in DIZK paper https://eprint.iacr.org/2018/691.pdf type Proof struct { - Ar, Krs curve.G1Affine - Bs curve.G2Affine - Commitment, CommitmentPok curve.G1Affine + Ar, Krs curve.G1Affine + Bs curve.G2Affine + CommitmentPok curve.G1Affine + Commitments []curve.G1Affine } // isValid ensures proof elements are in the correct subgroup @@ -61,7 +62,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - proof := &Proof{} + proof := &Proof{Commitments: make([]curve.G1Affine, len(r1cs.CommitmentInfo))} solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] @@ -75,12 +76,12 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b values := make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) nbPublicCommitted := len(in) - len(values) inPrivate := in[nbPublicCommitted:] - for i, inI := range inPrivate { - values[i].SetBigInt(inI) + for j, inJ := range inPrivate { + values[j].SetBigInt(inJ) } var err error - if proof.Commitment, err = pk.CommitmentKeys[i].Commit(values); err != nil { + if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(values); err != nil { return err } if proof.CommitmentPok, err = pk.CommitmentKeys[i].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving @@ -88,7 +89,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitments[i], in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) res.BigInt(out[0]) return err })) diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index bd7f98817f..921b979c9d 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -76,8 +76,7 @@ type VerifyingKey struct { e curve.GT // not serialized CommitmentKey pedersen.VerifyingKey - HasCommitment bool // TODO: Make CommitmentKey nullable instead - PublicCommitted []int // indexes of public committed variables + PublicCommitted [][]int // indexes of public committed variables } // Setup constructs the SRS @@ -269,8 +268,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } //} - if vk.HasCommitment = r1cs.GetNbCommitments() != 0; vk.HasCommitment { - vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() + vk.PublicCommitted = make([][]int, len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + vk.PublicCommitted[i] = r1cs.CommitmentInfo[i].PublicCommitted() } // --------------------------------------------------------------------------------------------- diff --git a/backend/groth16/bn254/verify.go b/backend/groth16/bn254/verify.go index 0cb53f48e6..630b751ca2 100644 --- a/backend/groth16/bn254/verify.go +++ b/backend/groth16/bn254/verify.go @@ -37,10 +37,8 @@ var ( // Verify verifies a proof with given VerifyingKey and publicWitness func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { - nbPublicVars := len(vk.G1.K) - if vk.HasCommitment { - nbPublicVars-- - } + nbPublicVars := len(vk.G1.K) - len(vk.PublicCommitted) + if len(publicWitness) != nbPublicVars-1 { return fmt.Errorf("invalid witness size, got %d, expected %d (public - ONE_WIRE)", len(publicWitness), len(vk.G1.K)-1) } @@ -63,20 +61,20 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() - if vk.HasCommitment { + for i := range vk.PublicCommitted { - if err := vk.CommitmentKey.Verify(proof.Commitment, proof.CommitmentPok); err != nil { + if err := vk.CommitmentKey.Verify(proof.Commitments[i], proof.CommitmentPok); err != nil { return err } - publicCommitted := make([]*big.Int, len(vk.PublicCommitted)) - for i := range publicCommitted { + publicCommitted := make([]*big.Int, len(vk.PublicCommitted[i])) + for j := range publicCommitted { var b big.Int - publicWitness[vk.PublicCommitted[i]-1].BigInt(&b) - publicCommitted[i] = &b + publicWitness[vk.PublicCommitted[i][j]-1].BigInt(&b) + publicCommitted[j] = &b } - if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err != nil { + if res, err := solveCommitmentWire(&proof.Commitments[i], publicCommitted); err != nil { return err } else { publicWitness = append(publicWitness, res) @@ -90,8 +88,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } kSum.AddMixed(&vk.G1.K[0]) - if vk.HasCommitment { - kSum.AddMixed(&proof.Commitment) + for i := range proof.Commitments { + kSum.AddMixed(&proof.Commitments[i]) } var kSumAff curve.G1Affine diff --git a/backend/groth16/bw6-633/prove.go b/backend/groth16/bw6-633/prove.go index 927d6d4504..7b8e607410 100644 --- a/backend/groth16/bw6-633/prove.go +++ b/backend/groth16/bw6-633/prove.go @@ -37,9 +37,10 @@ import ( // with a valid statement and a VerifyingKey // Notation follows Figure 4. in DIZK paper https://eprint.iacr.org/2018/691.pdf type Proof struct { - Ar, Krs curve.G1Affine - Bs curve.G2Affine - Commitment, CommitmentPok curve.G1Affine + Ar, Krs curve.G1Affine + Bs curve.G2Affine + CommitmentPok curve.G1Affine + Commitments []curve.G1Affine } // isValid ensures proof elements are in the correct subgroup @@ -75,12 +76,12 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b values := make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) nbPublicCommitted := len(in) - len(values) inPrivate := in[nbPublicCommitted:] - for i, inI := range inPrivate { - values[i].SetBigInt(inI) + for j, inJ := range inPrivate { + values[j].SetBigInt(inJ) } var err error - if proof.Commitment, err = pk.CommitmentKeys[i].Commit(values); err != nil { + if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(values); err != nil { return err } if proof.CommitmentPok, err = pk.CommitmentKeys[i].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving @@ -88,7 +89,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitments[i], in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) res.BigInt(out[0]) return err })) diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index e9d7b115b6..4c72fa30fe 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -76,8 +76,7 @@ type VerifyingKey struct { e curve.GT // not serialized CommitmentKey pedersen.VerifyingKey - HasCommitment bool // TODO: Make CommitmentKey nullable instead - PublicCommitted []int // indexes of public committed variables + PublicCommitted [][]int // indexes of public committed variables } // Setup constructs the SRS @@ -269,8 +268,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } //} - if vk.HasCommitment = r1cs.GetNbCommitments() != 0; vk.HasCommitment { - vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() + vk.PublicCommitted = make([][]int, len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + vk.PublicCommitted[i] = r1cs.CommitmentInfo[i].PublicCommitted() } // --------------------------------------------------------------------------------------------- diff --git a/backend/groth16/bw6-633/verify.go b/backend/groth16/bw6-633/verify.go index 2769307995..f96b24e697 100644 --- a/backend/groth16/bw6-633/verify.go +++ b/backend/groth16/bw6-633/verify.go @@ -36,10 +36,8 @@ var ( // Verify verifies a proof with given VerifyingKey and publicWitness func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { - nbPublicVars := len(vk.G1.K) - if vk.HasCommitment { - nbPublicVars-- - } + nbPublicVars := len(vk.G1.K) - len(vk.PublicCommitted) + if len(publicWitness) != nbPublicVars-1 { return fmt.Errorf("invalid witness size, got %d, expected %d (public - ONE_WIRE)", len(publicWitness), len(vk.G1.K)-1) } @@ -62,20 +60,20 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() - if vk.HasCommitment { + for i := range vk.PublicCommitted { - if err := vk.CommitmentKey.Verify(proof.Commitment, proof.CommitmentPok); err != nil { + if err := vk.CommitmentKey.Verify(proof.Commitments[i], proof.CommitmentPok); err != nil { return err } - publicCommitted := make([]*big.Int, len(vk.PublicCommitted)) - for i := range publicCommitted { + publicCommitted := make([]*big.Int, len(vk.PublicCommitted[i])) + for j := range publicCommitted { var b big.Int - publicWitness[vk.PublicCommitted[i]-1].BigInt(&b) - publicCommitted[i] = &b + publicWitness[vk.PublicCommitted[i][j]-1].BigInt(&b) + publicCommitted[j] = &b } - if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err != nil { + if res, err := solveCommitmentWire(&proof.Commitments[i], publicCommitted); err != nil { return err } else { publicWitness = append(publicWitness, res) @@ -89,8 +87,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } kSum.AddMixed(&vk.G1.K[0]) - if vk.HasCommitment { - kSum.AddMixed(&proof.Commitment) + for i := range proof.Commitments { + kSum.AddMixed(&proof.Commitments[i]) } var kSumAff curve.G1Affine diff --git a/backend/groth16/bw6-761/prove.go b/backend/groth16/bw6-761/prove.go index b4b4d74853..b461ccacf0 100644 --- a/backend/groth16/bw6-761/prove.go +++ b/backend/groth16/bw6-761/prove.go @@ -37,9 +37,10 @@ import ( // with a valid statement and a VerifyingKey // Notation follows Figure 4. in DIZK paper https://eprint.iacr.org/2018/691.pdf type Proof struct { - Ar, Krs curve.G1Affine - Bs curve.G2Affine - Commitment, CommitmentPok curve.G1Affine + Ar, Krs curve.G1Affine + Bs curve.G2Affine + CommitmentPok curve.G1Affine + Commitments []curve.G1Affine } // isValid ensures proof elements are in the correct subgroup @@ -75,12 +76,12 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b values := make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) nbPublicCommitted := len(in) - len(values) inPrivate := in[nbPublicCommitted:] - for i, inI := range inPrivate { - values[i].SetBigInt(inI) + for j, inJ := range inPrivate { + values[j].SetBigInt(inJ) } var err error - if proof.Commitment, err = pk.CommitmentKeys[i].Commit(values); err != nil { + if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(values); err != nil { return err } if proof.CommitmentPok, err = pk.CommitmentKeys[i].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving @@ -88,7 +89,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitments[i], in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) res.BigInt(out[0]) return err })) diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index a0588ccf7b..cc9f81df68 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -76,8 +76,7 @@ type VerifyingKey struct { e curve.GT // not serialized CommitmentKey pedersen.VerifyingKey - HasCommitment bool // TODO: Make CommitmentKey nullable instead - PublicCommitted []int // indexes of public committed variables + PublicCommitted [][]int // indexes of public committed variables } // Setup constructs the SRS @@ -269,8 +268,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } //} - if vk.HasCommitment = r1cs.GetNbCommitments() != 0; vk.HasCommitment { - vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() + vk.PublicCommitted = make([][]int, len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + vk.PublicCommitted[i] = r1cs.CommitmentInfo[i].PublicCommitted() } // --------------------------------------------------------------------------------------------- diff --git a/backend/groth16/bw6-761/verify.go b/backend/groth16/bw6-761/verify.go index 66aaf4c861..22f1d42d7a 100644 --- a/backend/groth16/bw6-761/verify.go +++ b/backend/groth16/bw6-761/verify.go @@ -36,10 +36,8 @@ var ( // Verify verifies a proof with given VerifyingKey and publicWitness func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { - nbPublicVars := len(vk.G1.K) - if vk.HasCommitment { - nbPublicVars-- - } + nbPublicVars := len(vk.G1.K) - len(vk.PublicCommitted) + if len(publicWitness) != nbPublicVars-1 { return fmt.Errorf("invalid witness size, got %d, expected %d (public - ONE_WIRE)", len(publicWitness), len(vk.G1.K)-1) } @@ -62,20 +60,20 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() - if vk.HasCommitment { + for i := range vk.PublicCommitted { - if err := vk.CommitmentKey.Verify(proof.Commitment, proof.CommitmentPok); err != nil { + if err := vk.CommitmentKey.Verify(proof.Commitments[i], proof.CommitmentPok); err != nil { return err } - publicCommitted := make([]*big.Int, len(vk.PublicCommitted)) - for i := range publicCommitted { + publicCommitted := make([]*big.Int, len(vk.PublicCommitted[i])) + for j := range publicCommitted { var b big.Int - publicWitness[vk.PublicCommitted[i]-1].BigInt(&b) - publicCommitted[i] = &b + publicWitness[vk.PublicCommitted[i][j]-1].BigInt(&b) + publicCommitted[j] = &b } - if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err != nil { + if res, err := solveCommitmentWire(&proof.Commitments[i], publicCommitted); err != nil { return err } else { publicWitness = append(publicWitness, res) @@ -89,8 +87,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } kSum.AddMixed(&vk.G1.K[0]) - if vk.HasCommitment { - kSum.AddMixed(&proof.Commitment) + for i := range proof.Commitments { + kSum.AddMixed(&proof.Commitments[i]) } var kSumAff curve.G1Affine diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl index c4bb8425c3..598c904cd0 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl @@ -22,7 +22,8 @@ import ( type Proof struct { Ar, Krs curve.G1Affine Bs curve.G2Affine - Commitment, CommitmentPok curve.G1Affine + CommitmentPok curve.G1Affine + Commitments []curve.G1Affine } // isValid ensures proof elements are in the correct subgroup @@ -58,12 +59,12 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b values := make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) nbPublicCommitted := len(in) - len(values) inPrivate := in[nbPublicCommitted:] - for i, inI := range inPrivate { - values[i].SetBigInt(inI) + for j, inJ := range inPrivate { + values[j].SetBigInt(inJ) } var err error - if proof.Commitment, err = pk.CommitmentKeys[i].Commit(values); err != nil { + if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(values); err != nil { return err } if proof.CommitmentPok, err = pk.CommitmentKeys[i].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving @@ -71,7 +72,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitment, in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) + res, err = solveCommitmentWire(&proof.Commitments[i], in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) res.BigInt(out[0]) return err } )) diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl index 4b2f820145..79656a3416 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl @@ -58,8 +58,7 @@ type VerifyingKey struct { e curve.GT // not serialized CommitmentKey pedersen.VerifyingKey - HasCommitment bool // TODO: Make CommitmentKey nullable instead - PublicCommitted []int // indexes of public committed variables + PublicCommitted [][]int // indexes of public committed variables } // Setup constructs the SRS @@ -251,8 +250,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } //} - if vk.HasCommitment = r1cs.GetNbCommitments() != 0; vk.HasCommitment { - vk.PublicCommitted = r1cs.CommitmentInfo[0].PublicCommitted() + vk.PublicCommitted = make([][]int, len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + vk.PublicCommitted[i] = r1cs.CommitmentInfo[i].PublicCommitted() } // --------------------------------------------------------------------------------------------- diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl index d40af97e21..d41a9e107f 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl @@ -21,10 +21,8 @@ var ( // Verify verifies a proof with given VerifyingKey and publicWitness func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { - nbPublicVars := len(vk.G1.K) - if vk.HasCommitment { - nbPublicVars-- - } + nbPublicVars := len(vk.G1.K) - len(vk.PublicCommitted) + if len(publicWitness) != nbPublicVars-1 { return fmt.Errorf("invalid witness size, got %d, expected %d (public - ONE_WIRE)", len(publicWitness), len(vk.G1.K) - 1) } @@ -47,20 +45,20 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() - if vk.HasCommitment { + for i := range vk.PublicCommitted { - if err := vk.CommitmentKey.Verify(proof.Commitment, proof.CommitmentPok); err != nil { + if err := vk.CommitmentKey.Verify(proof.Commitments[i], proof.CommitmentPok); err != nil { return err } - publicCommitted := make([]*big.Int, len(vk.PublicCommitted)) - for i := range publicCommitted { + publicCommitted := make([]*big.Int, len(vk.PublicCommitted[i])) + for j := range publicCommitted { var b big.Int - publicWitness[vk.PublicCommitted[i]-1].BigInt(&b) - publicCommitted[i] = &b + publicWitness[vk.PublicCommitted[i][j]-1].BigInt(&b) + publicCommitted[j] = &b } - if res, err := solveCommitmentWire(&proof.Commitment, publicCommitted); err != nil { + if res, err := solveCommitmentWire(&proof.Commitments[i], publicCommitted); err != nil { return err } else { publicWitness = append(publicWitness, res) @@ -74,8 +72,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } kSum.AddMixed(&vk.G1.K[0]) - if vk.HasCommitment { - kSum.AddMixed(&proof.Commitment) + for i := range proof.Commitments { + kSum.AddMixed(&proof.Commitments[i]) } var kSumAff curve.G1Affine diff --git a/test/commitments_test.gop b/test/commitments_test.gop new file mode 100644 index 0000000000..a08ca0055a --- /dev/null +++ b/test/commitments_test.gop @@ -0,0 +1,249 @@ +package test + +import ( + "fmt" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/scs" + "github.com/stretchr/testify/assert" + "math/big" + "reflect" + "strings" + "testing" + + "github.com/consensys/gnark/backend/plonk" +) + +type commitmentCircuit struct { + Public []frontend.Variable `gnark:",public"` + X []frontend.Variable +} + +func (c *commitmentCircuit) Define(api frontend.API) error { + + commitment, err := tryCommit(api, c.X...) + if err != nil { + return err + } + api.AssertIsDifferent(commitment, c.X[0]) + for _, p := range c.Public { + api.AssertIsDifferent(p, 0) + } + return err +} + +func TestSingleCommitment(t *testing.T) { + assignment := &commitmentCircuit{X: []frontend.Variable{1}, Public: []frontend.Variable{}} + e2eTest(t, assignment) +} + +func TestFiveCommitments(t *testing.T) { + assignment := &commitmentCircuit{X: []frontend.Variable{1, 2, 3, 4, 5}, Public: []frontend.Variable{}} + e2eTest(t, assignment) +} + +func TestSingleCommitmentSinglePublic(t *testing.T) { + assignment := &commitmentCircuit{X: []frontend.Variable{0}, Public: []frontend.Variable{1}} + e2eTest(t, assignment) +} + +func TestFiveCommitmentsFivePublic(t *testing.T) { + assignment := &commitmentCircuit{X: []frontend.Variable{0, 1, 2, 3, 4}, Public: []frontend.Variable{1, 2, 3, 4, 5}} + e2eTest(t, assignment) +} + +type noCommitmentCircuit struct { + X frontend.Variable +} + +func (c *noCommitmentCircuit) Define(api frontend.API) error { + api.AssertIsEqual(c.X, 1) + api.AssertIsEqual(c.X, 1) + return nil +} + +func TestNoCommitmentCircuit(t *testing.T) { + e2eTest(t, &noCommitmentCircuit{1}) +} + +var fr = []ecc.ID{ + ecc.BN254, + ecc.BLS12_381, + ecc.BLS12_377, + ecc.BLS24_315, + //ecc.BLS12_378, TODO: @Tabaie Not autogenerated? + ecc.BLS24_317, + ecc.BW6_633, + //ecc.BW6_756, TODO: @Tabaie Not autogenerated? + ecc.BW6_761, +} + +func plonkTest(t *testing.T, circuit, assignment frontend.Circuit) { + + run := func(mod *big.Int) func(t *testing.T) { + return func(t *testing.T) { + ccs, err := frontend.Compile(mod, scs.NewBuilder, circuit) + assert.NoError(t, err) + + witnessFull, err := frontend.NewWitness(assignment, mod) + assert.NoError(t, err) + witnessPublic, err := witnessFull.Public() + assert.NoError(t, err) + + srs, err := NewKZGSRS(ccs) + assert.NoError(t, err) + + pk, vk, err := plonk.Setup(ccs, srs) + assert.NoError(t, err) + + proof, err := plonk.Prove(ccs, pk, witnessFull) + assert.NoError(t, err) + + err = plonk.Verify(proof, vk, witnessPublic) + assert.NoError(t, err) + } + } + + for _, id := range fr { + t.Run(id.String(), run(id.ScalarField())) + } +} + +type committedConstantCircuit struct { + X frontend.Variable +} + +func (c *committedConstantCircuit) Define(api frontend.API) error { + commitment, err := tryCommit(api, 1, c.X) + if err != nil { + return err + } + api.AssertIsDifferent(commitment, c.X) + return nil +} + +func TestCommittedConstant(t *testing.T) { + e2eTest(t, &committedConstantCircuit{1}) +} + +type committedPublicCircuit struct { + X frontend.Variable `gnark:",public"` +} + +func (c *committedPublicCircuit) Define(api frontend.API) error { + commitment, err := tryCommit(api, c.X) + if err != nil { + return err + } + api.AssertIsDifferent(commitment, c.X) + return nil +} + +func TestCommittedPublic(t *testing.T) { + e2eTest(t, &committedPublicCircuit{1}) +} + +func tryCommit(api frontend.API, x ...frontend.Variable) (frontend.Variable, error) { + committer, ok := api.(frontend.Committer) + if !ok { + return nil, fmt.Errorf("type %T doesn't impl the Committer interface", api) + } + return committer.Commit(x...) +} + +type twoCommitCircuit struct { + X []frontend.Variable + Y frontend.Variable +} + +func (c *twoCommitCircuit) Define(api frontend.API) error { + c0, err := api.(frontend.Committer).Commit(c.X...) + if err != nil { + return err + } + var c1 frontend.Variable + if c1, err = api.(frontend.Committer).Commit(c0, c.Y); err != nil { + return err + } + api.AssertIsDifferent(c1, c.Y) + return nil +} + +func TestTwoCommitEngine(t *testing.T) { + assignment := &twoCommitCircuit{X: []frontend.Variable{1, 2}, Y: 3} + NewAssert(t).SolvingSucceeded(&twoCommitCircuit{X: make([]frontend.Variable, len(assignment.X))}, assignment, WithBackends(backend.GROTH16, backend.PLONK)) +} + +func TestTwoCommitPlonk(t *testing.T) { + assignment := &twoCommitCircuit{X: []frontend.Variable{1, 2}, Y: 3} + plonkTest(t, &twoCommitCircuit{X: make([]frontend.Variable, len(assignment.X))}, assignment) +} + +func hollow(c frontend.Circuit) frontend.Circuit { + cV := reflect.ValueOf(c).Elem() + t := reflect.TypeOf(c).Elem() + res := reflect.New(t) + resE := res.Elem() + resC := res.Interface().(frontend.Circuit) + + frontendVar := reflect.TypeOf((*frontend.Variable)(nil)).Elem() + + for i := 0; i < t.NumField(); i++ { + fieldT := t.Field(i).Type + if fieldT.Kind() == reflect.Slice && fieldT.Elem().Implements(frontendVar) { + resE.Field(i).Set(reflect.ValueOf(make([]frontend.Variable, cV.Field(i).Len()))) + } else if fieldT != frontendVar { + resE.Field(i).Set(cV.Field(i)) + } + } + + return resC +} + +func removePackageName(s string) string { + return s[strings.LastIndex(s, ".")+1:] +} + +func TestHollow(t *testing.T) { + + run := func(c, expected frontend.Circuit) func(t *testing.T) { + return func(t *testing.T) { + seen := hollow(c) + assert.Equal(t, expected, seen) + } + } + + assignments := []frontend.Circuit{ + &committedConstantCircuit{1}, + &commitmentCircuit{X: []frontend.Variable{1}, Public: []frontend.Variable{}}, + } + + expected := []frontend.Circuit{ + &committedConstantCircuit{nil}, + &commitmentCircuit{X: []frontend.Variable{nil}, Public: []frontend.Variable{}}, + } + + for i := range assignments { + t.Run(removePackageName(reflect.TypeOf(assignments[i]).String()), run(assignments[i], expected[i])) + } +} + +func e2eTest(t *testing.T, assignment frontend.Circuit) { + t.Parallel() + + t.Run("fuzzer", func(t *testing.T) { + circuit := hollow(assignment) + NewAssert(t).ProverSucceeded(circuit, assignment, WithBackends(backend.GROTH16 /*, backend.PLONK*/), WithCurves(ecc.BN254)) // TODO: Support PlonkFri.Commit + }) + /* + t.Run("plonk-e2e", func(t *testing.T) { + circuit := hollow(assignment) + plonkTest(t, circuit, assignment) + }) + + t.Run("groth16-e2e", func(t *testing.T) { + circuit := hollow(assignment) + groth16Test(t, circuit, assignment) + })*/ +} From 2e10a8b8df229c9fab3d84848e03a47002d29932 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 24 May 2023 17:18:48 -0500 Subject: [PATCH 384/464] fix: empty commitments vector --- backend/groth16/bls12-377/prove.go | 2 +- backend/groth16/bls12-381/prove.go | 2 +- backend/groth16/bls24-315/prove.go | 2 +- backend/groth16/bls24-317/prove.go | 2 +- backend/groth16/bw6-633/prove.go | 2 +- backend/groth16/bw6-761/prove.go | 2 +- .../backend/template/zkpschemes/groth16/groth16.prove.go.tmpl | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/backend/groth16/bls12-377/prove.go b/backend/groth16/bls12-377/prove.go index 95fda0d9fc..e28ca68d54 100644 --- a/backend/groth16/bls12-377/prove.go +++ b/backend/groth16/bls12-377/prove.go @@ -62,7 +62,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - proof := &Proof{} + proof := &Proof{Commitments: make([]curve.G1Affine, len(r1cs.CommitmentInfo))} solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] diff --git a/backend/groth16/bls12-381/prove.go b/backend/groth16/bls12-381/prove.go index aefb066ef0..6b2ed4113f 100644 --- a/backend/groth16/bls12-381/prove.go +++ b/backend/groth16/bls12-381/prove.go @@ -62,7 +62,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - proof := &Proof{} + proof := &Proof{Commitments: make([]curve.G1Affine, len(r1cs.CommitmentInfo))} solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] diff --git a/backend/groth16/bls24-315/prove.go b/backend/groth16/bls24-315/prove.go index cc7bed7b5c..e9a6569bfd 100644 --- a/backend/groth16/bls24-315/prove.go +++ b/backend/groth16/bls24-315/prove.go @@ -62,7 +62,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - proof := &Proof{} + proof := &Proof{Commitments: make([]curve.G1Affine, len(r1cs.CommitmentInfo))} solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] diff --git a/backend/groth16/bls24-317/prove.go b/backend/groth16/bls24-317/prove.go index 2f52346d35..053b3fc92c 100644 --- a/backend/groth16/bls24-317/prove.go +++ b/backend/groth16/bls24-317/prove.go @@ -62,7 +62,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - proof := &Proof{} + proof := &Proof{Commitments: make([]curve.G1Affine, len(r1cs.CommitmentInfo))} solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] diff --git a/backend/groth16/bw6-633/prove.go b/backend/groth16/bw6-633/prove.go index 7b8e607410..735f9e8cc1 100644 --- a/backend/groth16/bw6-633/prove.go +++ b/backend/groth16/bw6-633/prove.go @@ -62,7 +62,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - proof := &Proof{} + proof := &Proof{Commitments: make([]curve.G1Affine, len(r1cs.CommitmentInfo))} solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] diff --git a/backend/groth16/bw6-761/prove.go b/backend/groth16/bw6-761/prove.go index b461ccacf0..344d4dea3f 100644 --- a/backend/groth16/bw6-761/prove.go +++ b/backend/groth16/bw6-761/prove.go @@ -62,7 +62,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - proof := &Proof{} + proof := &Proof{Commitments: make([]curve.G1Affine, len(r1cs.CommitmentInfo))} solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl index 598c904cd0..6976f4d351 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl @@ -45,7 +45,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - proof := &Proof{} + proof := &Proof{Commitments: make([]curve.G1Affine, len(r1cs.CommitmentInfo))} solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] From cb0c4d224eabb2160f9c41dcea7c785a795c4c21 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 25 May 2023 13:03:50 +0200 Subject: [PATCH 385/464] feat: differentiate ecrecover with strict and lax check for s (#656) * feat: handle both strict and lax s range in ecrecover * test: check strict and lax ranges --- std/evmprecompiles/01-ecrecover.go | 13 +++++- std/evmprecompiles/01-ecrecover_test.go | 59 +++++++++++++++++++++---- 2 files changed, 61 insertions(+), 11 deletions(-) diff --git a/std/evmprecompiles/01-ecrecover.go b/std/evmprecompiles/01-ecrecover.go index 1748a24295..2e7dea01f3 100644 --- a/std/evmprecompiles/01-ecrecover.go +++ b/std/evmprecompiles/01-ecrecover.go @@ -2,6 +2,7 @@ package evmprecompiles import ( "fmt" + "math/big" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/algebra/emulated/sw_emulated" @@ -13,7 +14,8 @@ import ( // // [ECRECOVER]: https://ethereum.github.io/execution-specs/autoapi/ethereum/paris/vm/precompiled_contracts/ecrecover/index.html func ECRecover(api frontend.API, msg emulated.Element[emulated.Secp256k1Fr], - v frontend.Variable, r, s emulated.Element[emulated.Secp256k1Fr]) *sw_emulated.AffinePoint[emulated.Secp256k1Fp] { + v frontend.Variable, r, s emulated.Element[emulated.Secp256k1Fr], + strictRange frontend.Variable) *sw_emulated.AffinePoint[emulated.Secp256k1Fp] { // EVM uses v \in {27, 28}, but everyone else v >= 0. Convert back v = api.Sub(v, 27) var emfp emulated.Secp256k1Fp @@ -28,7 +30,14 @@ func ECRecover(api frontend.API, msg emulated.Element[emulated.Secp256k1Fr], } // with the encoding we may have that r,s < 2*Fr (i.e. not r,s < Fr). Apply more thorough checks. frField.AssertIsLessOrEqual(&r, frField.Modulus()) - frField.AssertIsLessOrEqual(&s, frField.Modulus()) + // Ethereum Yellow Paper defines that the check for s should be more strict + // when checking transaction signatures (Appendix F). There we should check + // that s <= (Fr-1)/2 + halfFr := new(big.Int).Sub(emfr.Modulus(), big.NewInt(1)) + halfFr.Div(halfFr, big.NewInt(2)) + bound := frField.Select(strictRange, frField.NewElement(halfFr), frField.Modulus()) + frField.AssertIsLessOrEqual(&s, bound) + curve, err := sw_emulated.New[emulated.Secp256k1Fp, emulated.Secp256k1Fr](api, sw_emulated.GetSecp256k1Params()) if err != nil { panic(fmt.Sprintf("new curve: %v", err)) diff --git a/std/evmprecompiles/01-ecrecover_test.go b/std/evmprecompiles/01-ecrecover_test.go index b9193dd372..577a45b75b 100644 --- a/std/evmprecompiles/01-ecrecover_test.go +++ b/std/evmprecompiles/01-ecrecover_test.go @@ -3,6 +3,7 @@ package evmprecompiles import ( "crypto/rand" "fmt" + "math/big" "testing" "github.com/consensys/gnark-crypto/ecc" @@ -44,6 +45,7 @@ type ecrecoverCircuit struct { V frontend.Variable R emulated.Element[emulated.Secp256k1Fr] S emulated.Element[emulated.Secp256k1Fr] + Strict frontend.Variable Expected sw_emulated.AffinePoint[emulated.Secp256k1Fp] } @@ -52,21 +54,35 @@ func (c *ecrecoverCircuit) Define(api frontend.API) error { if err != nil { return fmt.Errorf("new curve: %w", err) } - res := ECRecover(api, c.Message, c.V, c.R, c.S) + res := ECRecover(api, c.Message, c.V, c.R, c.S, c.Strict) curve.AssertIsEqual(&c.Expected, res) return nil } -func testRoutineECRecover(t *testing.T) (circ, wit frontend.Circuit) { +func testRoutineECRecover(t *testing.T, wantStrict bool) (circ, wit *ecrecoverCircuit, largeS bool) { + halfFr := new(big.Int).Sub(fr.Modulus(), big.NewInt(1)) + halfFr.Div(halfFr, big.NewInt(2)) + sk, err := ecdsa.GenerateKey(rand.Reader) if err != nil { t.Fatal("generate", err) } pk := sk.PublicKey msg := []byte("test") - v, r, s, err := sk.SignForRecover(msg, nil) - if err != nil { - t.Fatal("sign", err) + var r, s *big.Int + var v uint + for { + v, r, s, err = sk.SignForRecover(msg, nil) + if err != nil { + t.Fatal("sign", err) + } + if !wantStrict || halfFr.Cmp(s) > 0 { + break + } + } + strict := 0 + if wantStrict { + strict = 1 } circuit := ecrecoverCircuit{} witness := ecrecoverCircuit{ @@ -74,25 +90,50 @@ func testRoutineECRecover(t *testing.T) (circ, wit frontend.Circuit) { V: v + 27, // EVM constant R: emulated.ValueOf[emulated.Secp256k1Fr](r), S: emulated.ValueOf[emulated.Secp256k1Fr](s), + Strict: strict, Expected: sw_emulated.AffinePoint[emulated.Secp256k1Fp]{ X: emulated.ValueOf[emulated.Secp256k1Fp](pk.A.X), Y: emulated.ValueOf[emulated.Secp256k1Fp](pk.A.Y), }, } - return &circuit, &witness + return &circuit, &witness, halfFr.Cmp(s) <= 0 +} + +func TestECRecoverCircuitShortStrict(t *testing.T) { + assert := test.NewAssert(t) + circuit, witness, _ := testRoutineECRecover(t, true) + err := test.IsSolved(circuit, witness, ecc.BN254.ScalarField()) + assert.NoError(err) } -func TestECRecoverCircuitShort(t *testing.T) { +func TestECRecoverCircuitShortLax(t *testing.T) { assert := test.NewAssert(t) - circuit, witness := testRoutineECRecover(t) + circuit, witness, _ := testRoutineECRecover(t, false) err := test.IsSolved(circuit, witness, ecc.BN254.ScalarField()) assert.NoError(err) } +func TestECRecoverCircuitShortMismatch(t *testing.T) { + assert := test.NewAssert(t) + halfFr := new(big.Int).Sub(fr.Modulus(), big.NewInt(1)) + halfFr.Div(halfFr, big.NewInt(2)) + var circuit, witness *ecrecoverCircuit + var largeS bool + for { + circuit, witness, largeS = testRoutineECRecover(t, false) + if largeS { + witness.Strict = 1 + break + } + } + err := test.IsSolved(circuit, witness, ecc.BN254.ScalarField()) + assert.Error(err) +} + func TestECRecoverCircuitFull(t *testing.T) { t.Skip("skipping very long test") assert := test.NewAssert(t) - circuit, witness := testRoutineECRecover(t) + circuit, witness, _ := testRoutineECRecover(t, false) assert.ProverSucceeded(circuit, witness, test.NoFuzzing(), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK), test.WithCurves(ecc.BN254), From c1bddbf0e05affb04a726cdd33030eed1ab8d286 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 25 May 2023 13:15:14 +0200 Subject: [PATCH 386/464] refactor: emulation parameters (#696) * refactor: use goldilocks modulus from gnark-crypto * refactor: use secp256k1 moduli from gnark-crypto * refactor: move emulation parameters to separate package * chore: godoc compatible emulation parms docs * docs: add package documentation for emulation params * refactor: use type embedding for common params * docs: expand FieldParams doc * feat: add P384 emulation params * feat: add P256 field emulation params * refactor: rename to emparams * feat: include all params from emparams --- std/math/emulated/emparams/emparams.go | 201 +++++++++++++++++++++++++ std/math/emulated/params.go | 120 +++------------ 2 files changed, 226 insertions(+), 95 deletions(-) create mode 100644 std/math/emulated/emparams/emparams.go diff --git a/std/math/emulated/emparams/emparams.go b/std/math/emulated/emparams/emparams.go new file mode 100644 index 0000000000..9b888d6a4d --- /dev/null +++ b/std/math/emulated/emparams/emparams.go @@ -0,0 +1,201 @@ +// Package emparams contains emulation parameters for well known fields. +// +// We define some well-known parameters in this package for compatibility and +// ease of use. When needing to use parameters not defined in this package it is +// sufficient to define a new type implementing [FieldParams]. For example, as: +// +// type SmallField struct {} +// func (SmallField) NbLimbs() uint { return 1 } +// func (SmallField) BitsPerLimb() uint { return 11 } +// func (SmallField) IsPrime() bool { return true } +// func (SmallField) Modulus() *big.Int { return big.NewInt(1032) } +package emparams + +import ( + "crypto/elliptic" + "math/big" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/field/goldilocks" +) + +type fourLimbPrimeField struct{} + +func (fourLimbPrimeField) NbLimbs() uint { return 4 } +func (fourLimbPrimeField) BitsPerLimb() uint { return 64 } +func (fourLimbPrimeField) IsPrime() bool { return true } + +type sixLimbPrimeField struct{} + +func (sixLimbPrimeField) NbLimbs() uint { return 6 } +func (sixLimbPrimeField) BitsPerLimb() uint { return 64 } +func (sixLimbPrimeField) IsPrime() bool { return true } + +// Goldilocks provides type parametrization for field emulation: +// - limbs: 1 +// - limb width: 64 bits +// +// The prime modulus for type parametrisation is: +// +// 0xffffffff00000001 (base 16) +// 18446744069414584321 (base 10) +type Goldilocks struct{} + +func (fp Goldilocks) NbLimbs() uint { return 1 } +func (fp Goldilocks) BitsPerLimb() uint { return 64 } +func (fp Goldilocks) IsPrime() bool { return true } +func (fp Goldilocks) Modulus() *big.Int { return goldilocks.Modulus() } + +// Secp256k1Fp provides type parametrization for field emulation: +// - limbs: 4 +// - limb width: 64 bits +// +// The prime modulus for type parametrisation is: +// +// 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f (base 16) +// 115792089237316195423570985008687907853269984665640564039457584007908834671663 (base 10) +// +// This is the base field of the SECP256k1 curve. +type Secp256k1Fp struct{ fourLimbPrimeField } + +func (fp Secp256k1Fp) Modulus() *big.Int { return ecc.SECP256K1.BaseField() } + +// Secp256k1Fr provides type parametrization for field emulation: +// - limbs: 4 +// - limb width: 64 bits +// +// The prime modulus for type parametrisation is: +// +// 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 (base 16) +// 115792089237316195423570985008687907852837564279074904382605163141518161494337 (base 10) +// +// This is the scalar field of the SECP256k1 curve. +type Secp256k1Fr struct{ fourLimbPrimeField } + +func (fp Secp256k1Fr) Modulus() *big.Int { return ecc.SECP256K1.ScalarField() } + +// BN254Fp provides type parametrization for field emulation: +// - limbs: 4 +// - limb width: 64 bits +// +// The prime modulus for type parametrisation is: +// +// 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 (base 16) +// 21888242871839275222246405745257275088696311157297823662689037894645226208583 (base 10) +// +// This is the base field of the BN254 curve. +type BN254Fp struct{ fourLimbPrimeField } + +func (fp BN254Fp) Modulus() *big.Int { return ecc.BN254.BaseField() } + +// BN254Fr provides type parametrization for field emulation: +// - limbs: 4 +// - limb width: 64 bits +// +// The prime modulus for type parametrisation is: +// +// 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 (base 16) +// 21888242871839275222246405745257275088548364400416034343698204186575808495617 (base 10) +// +// This is the scalar field of the BN254 curve. +type BN254Fr struct{ fourLimbPrimeField } + +func (fp BN254Fr) Modulus() *big.Int { return ecc.BN254.ScalarField() } + +// BLS12377Fp provides type parametrization for field emulation: +// - limbs: 6 +// - limb width: 64 bits +// +// The prime modulus for type parametrisation is: +// +// 0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d44300000008508c00000000001 (base 16) +// 258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458177 (base 10) +// +// This is the base field of the BLS12-377 curve. +type BLS12377Fp struct{ sixLimbPrimeField } + +func (fp BLS12377Fp) Modulus() *big.Int { return ecc.BLS12_377.BaseField() } + +// BLS12381Fp provides type parametrization for field emulation: +// - limbs: 6 +// - limb width: 64 bits +// +// The prime modulus for type parametrisation is: +// +// 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab (base 16) +// 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787 (base 10) +// +// This is the base field of the BLS12-381 curve. +type BLS12381Fp struct{ sixLimbPrimeField } + +func (fp BLS12381Fp) Modulus() *big.Int { return ecc.BLS12_381.BaseField() } + +// BLS12381Fr provides type parametrization for field emulation: +// - limbs: 4 +// - limb width: 64 bits +// +// The prime modulus for type parametrisation is: +// +// 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001 (base 16) +// 52435875175126190479447740508185965837690552500527637822603658699938581184513 (base 10) +// +// This is the scalar field of the BLS12-381 curve. +type BLS12381Fr struct{ fourLimbPrimeField } + +func (fp BLS12381Fr) Modulus() *big.Int { return ecc.BLS12_381.ScalarField() } + +// P256Fp provides type parametrization for field emulation: +// - limbs: 4 +// - limb width: 64 bits +// +// The prime modulus for type parametrisation is: +// +// 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff (base 16) +// 115792089210356248762697446949407573530086143415290314195533631308867097853951 (base 10) +// +// This is the base field of the P-256 (also SECP256r1) curve. +type P256Fp struct{ fourLimbPrimeField } + +func (P256Fp) Modulus() *big.Int { return elliptic.P256().Params().P } + +// P256Fr provides type parametrization for field emulation: +// - limbs: 4 +// - limb width: 64 bits +// +// The prime modulus for type parametrisation is: +// +// 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551 (base 16) +// 115792089210356248762697446949407573529996955224135760342422259061068512044369 (base 10) +// +// This is the base field of the P-256 (also SECP256r1) curve. +type P256Fr struct{ fourLimbPrimeField } + +func (P256Fr) Modulus() *big.Int { return elliptic.P256().Params().N } + +// P384Fp provides type parametrization for field emulation: +// - limbs: 6 +// - limb width: 64 bits +// +// The prime modulus for type parametrisation is: +// +// 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff (base 16) +// 39402006196394479212279040100143613805079739270465446667948293404245721771496870329047266088258938001861606973112319 (base 10) +// +// This is the base field of the P-384 (also SECP384r1) curve. +type P384Fp struct{ sixLimbPrimeField } + +func (P384Fp) Modulus() *big.Int { return elliptic.P384().Params().P } + +// P384Fr provides type parametrization for field emulation: +// - limbs: 6 +// - limb width: 64 bits +// +// The prime modulus for type parametrisation is: +// +// 0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973 (base 16) +// 39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942643 (base 10) +// +// This is the scalar field of the P-384 (also SECP384r1) curve. +type P384Fr struct{ sixLimbPrimeField } + +func (P384Fr) Modulus() *big.Int { return elliptic.P384().Params().N } diff --git a/std/math/emulated/params.go b/std/math/emulated/params.go index b40b2f2493..fc3d8abfc1 100644 --- a/std/math/emulated/params.go +++ b/std/math/emulated/params.go @@ -3,10 +3,20 @@ package emulated import ( "math/big" - "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/std/math/emulated/emparams" ) -// FieldParams describes the emulated field characteristics +// FieldParams describes the emulated field characteristics. For a list of +// included built-in emulation params refer to the [emparams] package. +// For backwards compatibility, the current package contains the following +// parameters: +// - [Goldilocks] +// - [Secp256k1Fp] and [Secp256k1Fr] +// - [BN254Fp] and [BN254Fr] +// - [BLS12377Fp] +// - [BLS12381Fp] and [BLS12381Fr] +// - [P256Fp] and [P256Fr] +// - [P384Fp] and [P384Fr] type FieldParams interface { NbLimbs() uint // number of limbs to represent field element BitsPerLimb() uint // number of bits per limb. Top limb may contain less than limbSize bits. @@ -14,97 +24,17 @@ type FieldParams interface { Modulus() *big.Int // returns modulus. Do not modify. } -var ( - qSecp256k1, rSecp256k1 *big.Int - qGoldilocks *big.Int +type ( + Goldilocks = emparams.Goldilocks + Secp256k1Fp = emparams.Secp256k1Fp + Secp256k1Fr = emparams.Secp256k1Fr + BN254Fp = emparams.BN254Fp + BN254Fr = emparams.BN254Fr + BLS12377Fp = emparams.BLS12377Fp + BLS12381Fp = emparams.BLS12381Fp + BLS12381Fr = emparams.BLS12381Fr + P256Fp = emparams.P256Fp + P256Fr = emparams.P256Fr + P384Fp = emparams.P384Fp + P384Fr = emparams.P384Fr ) - -func init() { - qSecp256k1, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", 16) - rSecp256k1, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16) - qGoldilocks, _ = new(big.Int).SetString("ffffffff00000001", 16) -} - -// Goldilocks provide type parametrization for emulated field on 1 limb of width 64bits -// for modulus 0xffffffff00000001 -type Goldilocks struct{} - -func (fp Goldilocks) NbLimbs() uint { return 1 } -func (fp Goldilocks) BitsPerLimb() uint { return 64 } -func (fp Goldilocks) IsPrime() bool { return true } -func (fp Goldilocks) Modulus() *big.Int { return qGoldilocks } - -// Secp256k1Fp provide type parametrization for emulated field on 4 limb of width 64bits -// for modulus 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f. -// This is the base field of secp256k1 curve -type Secp256k1Fp struct{} - -func (fp Secp256k1Fp) NbLimbs() uint { return 4 } -func (fp Secp256k1Fp) BitsPerLimb() uint { return 64 } -func (fp Secp256k1Fp) IsPrime() bool { return true } -func (fp Secp256k1Fp) Modulus() *big.Int { return qSecp256k1 } - -// Secp256k1Fr provides type parametrization for emulated field on 4 limbs of width 64bits -// for modulus 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141. -// This is the scalar field of secp256k1 curve. -type Secp256k1Fr struct{} - -func (fp Secp256k1Fr) NbLimbs() uint { return 4 } -func (fp Secp256k1Fr) BitsPerLimb() uint { return 64 } -func (fp Secp256k1Fr) IsPrime() bool { return true } -func (fp Secp256k1Fr) Modulus() *big.Int { return rSecp256k1 } - -// BN254Fp provide type parametrization for emulated field on 4 limb of width -// 64bits for modulus -// 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47. This is -// the base field of the BN254 curve. -type BN254Fp struct{} - -func (fp BN254Fp) NbLimbs() uint { return 4 } -func (fp BN254Fp) BitsPerLimb() uint { return 64 } -func (fp BN254Fp) IsPrime() bool { return true } -func (fp BN254Fp) Modulus() *big.Int { return ecc.BN254.BaseField() } - -// BN254Fr provides type parametrisation for emulated field on 4 limbs of width -// 64bits for modulus -// 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001. This is -// the scalar field of the BN254 curve. -type BN254Fr struct{} - -func (fp BN254Fr) NbLimbs() uint { return 4 } -func (fp BN254Fr) BitsPerLimb() uint { return 64 } -func (fp BN254Fr) IsPrime() bool { return true } -func (fp BN254Fr) Modulus() *big.Int { return ecc.BN254.ScalarField() } - -// BLS12377Fp provide type parametrization for emulated field on 6 limb of width -// 64bits for modulus -// 0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d44300000008508c00000000001. -// This is the base field of the BLS12-377 curve. -type BLS12377Fp struct{} - -func (fp BLS12377Fp) NbLimbs() uint { return 6 } -func (fp BLS12377Fp) BitsPerLimb() uint { return 64 } -func (fp BLS12377Fp) IsPrime() bool { return true } -func (fp BLS12377Fp) Modulus() *big.Int { return ecc.BLS12_377.BaseField() } - -// BLS12381Fp provide type parametrization for emulated field on 6 limb of width -// 64bits for modulus -// 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab. -// This is the base field of the BLS12-381 curve. -type BLS12381Fp struct{} - -func (fp BLS12381Fp) NbLimbs() uint { return 6 } -func (fp BLS12381Fp) BitsPerLimb() uint { return 64 } -func (fp BLS12381Fp) IsPrime() bool { return true } -func (fp BLS12381Fp) Modulus() *big.Int { return ecc.BLS12_381.BaseField() } - -// BLS12381Fr provide type parametrization for emulated field on 4 limb of width -// 64bits for modulus -// 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001. -// This is the scalar field of the BLS12-381 curve. -type BLS12381Fr struct{} - -func (fp BLS12381Fr) NbLimbs() uint { return 4 } -func (fp BLS12381Fr) BitsPerLimb() uint { return 64 } -func (fp BLS12381Fr) IsPrime() bool { return true } -func (fp BLS12381Fr) Modulus() *big.Int { return ecc.BLS12_381.ScalarField() } From c617c9fa7c64bae4b266c00d3f68c7180b85ba1b Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 25 May 2023 13:53:57 +0200 Subject: [PATCH 387/464] feat: implement NIST P-256 and P-384 curves (#697) * refactor: use goldilocks modulus from gnark-crypto * refactor: use secp256k1 moduli from gnark-crypto * refactor: move emulation parameters to separate package * chore: godoc compatible emulation parms docs * docs: add package documentation for emulation params * refactor: use type embedding for common params * docs: expand FieldParams doc * feat: add P384 emulation params * feat: add P256 field emulation params * refactor: rename to emparams * feat: add P256 and P384 curves * chore: refer to moduli in curve parameter getter * fix: wrong precomputation * feat: merge contribution commit cbf25b5a16fdb61c04f2007e3be798bf02ed5612 Author: SherLzp Date: Thu Mar 30 13:57:51 2023 +0800 secp256r1: ecdsa * refactor: use type alias --- std/algebra/emulated/sw_emulated/params.go | 51 +++++++- .../emulated/sw_emulated/params_compute.go | 45 +++++++ .../emulated/sw_emulated/point_test.go | 48 ++++++++ std/signature/ecdsa/ecdsa_secpr_test.go | 111 ++++++++++++++++++ 4 files changed, 250 insertions(+), 5 deletions(-) create mode 100644 std/signature/ecdsa/ecdsa_secpr_test.go diff --git a/std/algebra/emulated/sw_emulated/params.go b/std/algebra/emulated/sw_emulated/params.go index bb513b6e41..efce7a1566 100644 --- a/std/algebra/emulated/sw_emulated/params.go +++ b/std/algebra/emulated/sw_emulated/params.go @@ -1,6 +1,7 @@ package sw_emulated import ( + "crypto/elliptic" "math/big" bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" @@ -65,16 +66,52 @@ func GetBLS12381Params() CurveParams { } } -// GetCurveParams returns suitable curve parameters given the parametric type Base as base field. +// GetP256Params returns the curve parameters for the curve P-256 (also +// SECP256r1). When initialising new curve, use the base field +// [emulated.P256Fp] and scalar field [emulated.P256Fr]. +func GetP256Params() CurveParams { + pr := elliptic.P256().Params() + a := new(big.Int).Sub(pr.P, big.NewInt(3)) + return CurveParams{ + A: a, + B: pr.B, + Gx: pr.Gx, + Gy: pr.Gy, + Gm: computeP256Table(), + } +} + +// GetP384Params returns the curve parameters for the curve P-384 (also +// SECP384r1). When initialising new curve, use the base field +// [emulated.P384Fp] and scalar field [emulated.P384Fr]. +func GetP384Params() CurveParams { + pr := elliptic.P384().Params() + a := new(big.Int).Sub(pr.P, big.NewInt(3)) + return CurveParams{ + A: a, + B: pr.B, + Gx: pr.Gx, + Gy: pr.Gy, + Gm: computeP384Table(), + } +} + +// GetCurveParams returns suitable curve parameters given the parametric type +// Base as base field. It caches the parameters and modifying the values in the +// parameters struct leads to undefined behaviour. func GetCurveParams[Base emulated.FieldParams]() CurveParams { var t Base - switch t.Modulus().Text(16) { - case "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f": + switch t.Modulus().String() { + case emulated.Secp256k1Fp{}.Modulus().String(): return secp256k1Params - case "30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47": + case emulated.BN254Fp{}.Modulus().String(): return bn254Params - case "1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab": + case emulated.BLS12381Fp{}.Modulus().String(): return bls12381Params + case emulated.P256Fp{}.Modulus().String(): + return p256Params + case emulated.P384Fp{}.Modulus().String(): + return p384Params default: panic("no stored parameters") } @@ -84,10 +121,14 @@ var ( secp256k1Params CurveParams bn254Params CurveParams bls12381Params CurveParams + p256Params CurveParams + p384Params CurveParams ) func init() { secp256k1Params = GetSecp256k1Params() bn254Params = GetBN254Params() bls12381Params = GetBLS12381Params() + p256Params = GetP256Params() + p384Params = GetP384Params() } diff --git a/std/algebra/emulated/sw_emulated/params_compute.go b/std/algebra/emulated/sw_emulated/params_compute.go index 58d3e26df8..5eaf21e87b 100644 --- a/std/algebra/emulated/sw_emulated/params_compute.go +++ b/std/algebra/emulated/sw_emulated/params_compute.go @@ -1,6 +1,7 @@ package sw_emulated import ( + "crypto/elliptic" "math/big" bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" @@ -85,3 +86,47 @@ func computeBLS12381Table() [][2]*big.Int { } return table } + +func computeP256Table() [][2]*big.Int { + table := make([][2]*big.Int, 256) + p256 := elliptic.P256() + gx, gy := p256.Params().Gx, p256.Params().Gy + tmpx, tmpy := new(big.Int).Set(gx), new(big.Int).Set(gy) + for i := 1; i < 256; i++ { + tmpx, tmpy = p256.Double(tmpx, tmpy) + switch i { + case 1, 2: + xx, yy := p256.Add(tmpx, tmpy, gx, gy) + table[i-1] = [2]*big.Int{xx, yy} + case 3: + xx, yy := p256.Add(tmpx, tmpy, gx, new(big.Int).Sub(p256.Params().P, gy)) + table[i-1] = [2]*big.Int{xx, yy} + fallthrough + default: + table[i] = [2]*big.Int{tmpx, tmpy} + } + } + return table +} + +func computeP384Table() [][2]*big.Int { + table := make([][2]*big.Int, 384) + p384 := elliptic.P384() + gx, gy := p384.Params().Gx, p384.Params().Gy + tmpx, tmpy := new(big.Int).Set(gx), new(big.Int).Set(gy) + for i := 1; i < 384; i++ { + tmpx, tmpy = p384.Double(tmpx, tmpy) + switch i { + case 1, 2: + xx, yy := p384.Add(tmpx, tmpy, gx, gy) + table[i-1] = [2]*big.Int{xx, yy} + case 3: + xx, yy := p384.Add(tmpx, tmpy, gx, new(big.Int).Sub(p384.Params().P, gy)) + table[i-1] = [2]*big.Int{xx, yy} + fallthrough + default: + table[i] = [2]*big.Int{tmpx, tmpy} + } + } + return table +} diff --git a/std/algebra/emulated/sw_emulated/point_test.go b/std/algebra/emulated/sw_emulated/point_test.go index 0543c8bb91..e006a8d7f2 100644 --- a/std/algebra/emulated/sw_emulated/point_test.go +++ b/std/algebra/emulated/sw_emulated/point_test.go @@ -1,6 +1,8 @@ package sw_emulated import ( + "crypto/elliptic" + "crypto/rand" "math/big" "testing" @@ -569,6 +571,52 @@ func TestScalarMul3(t *testing.T) { assert.NoError(err) } +func TestScalarMul4(t *testing.T) { + assert := test.NewAssert(t) + p256 := elliptic.P256() + s, err := rand.Int(rand.Reader, p256.Params().N) + assert.NoError(err) + px, py := p256.ScalarBaseMult(s.Bytes()) + + circuit := ScalarMulTest[emulated.P256Fp, emulated.P256Fr]{} + witness := ScalarMulTest[emulated.P256Fp, emulated.P256Fr]{ + S: emulated.ValueOf[emulated.P256Fr](s), + P: AffinePoint[emulated.P256Fp]{ + X: emulated.ValueOf[emulated.P256Fp](p256.Params().Gx), + Y: emulated.ValueOf[emulated.P256Fp](p256.Params().Gy), + }, + Q: AffinePoint[emulated.P256Fp]{ + X: emulated.ValueOf[emulated.P256Fp](px), + Y: emulated.ValueOf[emulated.P256Fp](py), + }, + } + err = test.IsSolved(&circuit, &witness, testCurve.ScalarField()) + assert.NoError(err) +} + +func TestScalarMul5(t *testing.T) { + assert := test.NewAssert(t) + p384 := elliptic.P384() + s, err := rand.Int(rand.Reader, p384.Params().N) + assert.NoError(err) + px, py := p384.ScalarBaseMult(s.Bytes()) + + circuit := ScalarMulTest[emulated.P384Fp, emulated.P384Fr]{} + witness := ScalarMulTest[emulated.P384Fp, emulated.P384Fr]{ + S: emulated.ValueOf[emulated.P384Fr](s), + P: AffinePoint[emulated.P384Fp]{ + X: emulated.ValueOf[emulated.P384Fp](p384.Params().Gx), + Y: emulated.ValueOf[emulated.P384Fp](p384.Params().Gy), + }, + Q: AffinePoint[emulated.P384Fp]{ + X: emulated.ValueOf[emulated.P384Fp](px), + Y: emulated.ValueOf[emulated.P384Fp](py), + }, + } + err = test.IsSolved(&circuit, &witness, testCurve.ScalarField()) + assert.NoError(err) +} + type IsOnCurveTest[T, S emulated.FieldParams] struct { Q AffinePoint[T] } diff --git a/std/signature/ecdsa/ecdsa_secpr_test.go b/std/signature/ecdsa/ecdsa_secpr_test.go new file mode 100644 index 0000000000..139865e48b --- /dev/null +++ b/std/signature/ecdsa/ecdsa_secpr_test.go @@ -0,0 +1,111 @@ +package ecdsa + +import ( + cryptoecdsa "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/sha256" + "crypto/sha512" + "math/big" + "testing" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/std/math/emulated" + "github.com/consensys/gnark/test" + "golang.org/x/crypto/cryptobyte" + "golang.org/x/crypto/cryptobyte/asn1" +) + +func TestEcdsaP256PreHashed(t *testing.T) { + + // generate parameters + privKey, _ := cryptoecdsa.GenerateKey(elliptic.P256(), rand.Reader) + publicKey := privKey.PublicKey + + // sign + msg := []byte("testing ECDSA (pre-hashed)") + msgHash := sha256.Sum256(msg) + sigBin, _ := privKey.Sign(rand.Reader, msgHash[:], nil) + + // check that the signature is correct + var ( + r, s = &big.Int{}, &big.Int{} + inner cryptobyte.String + ) + input := cryptobyte.String(sigBin) + if !input.ReadASN1(&inner, asn1.SEQUENCE) || + !input.Empty() || + !inner.ReadASN1Integer(r) || + !inner.ReadASN1Integer(s) || + !inner.Empty() { + panic("invalid sig") + } + flag := cryptoecdsa.Verify(&publicKey, msgHash[:], r, s) + if !flag { + t.Errorf("can't verify signature") + } + + circuit := EcdsaCircuit[emulated.P256Fp, emulated.P256Fr]{} + witness := EcdsaCircuit[emulated.P256Fp, emulated.P256Fr]{ + Sig: Signature[emulated.P256Fr]{ + R: emulated.ValueOf[emulated.P256Fr](r), + S: emulated.ValueOf[emulated.P256Fr](s), + }, + Msg: emulated.ValueOf[emulated.P256Fr](msgHash[:]), + Pub: PublicKey[emulated.P256Fp, emulated.P256Fr]{ + X: emulated.ValueOf[emulated.P256Fp](privKey.PublicKey.X), + Y: emulated.ValueOf[emulated.P256Fp](privKey.PublicKey.Y), + }, + } + assert := test.NewAssert(t) + err := test.IsSolved(&circuit, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} + +func TestEcdsaP384PreHashed(t *testing.T) { + + // generate parameters + privKey, _ := cryptoecdsa.GenerateKey(elliptic.P384(), rand.Reader) + publicKey := privKey.PublicKey + + // sign + msg := []byte("testing ECDSA (pre-hashed)") + msgHash := sha512.Sum384(msg) + sigBin, _ := privKey.Sign(rand.Reader, msgHash[:], nil) + + // check that the signature is correct + var ( + r, s = &big.Int{}, &big.Int{} + inner cryptobyte.String + ) + input := cryptobyte.String(sigBin) + if !input.ReadASN1(&inner, asn1.SEQUENCE) || + !input.Empty() || + !inner.ReadASN1Integer(r) || + !inner.ReadASN1Integer(s) || + !inner.Empty() { + panic("invalid sig") + } + flag := cryptoecdsa.Verify(&publicKey, msgHash[:], r, s) + if !flag { + t.Errorf("can't verify signature") + } + + circuit := EcdsaCircuit[emulated.P384Fp, emulated.P384Fr]{} + witness := EcdsaCircuit[emulated.P384Fp, emulated.P384Fr]{ + Sig: Signature[emulated.P384Fr]{ + R: emulated.ValueOf[emulated.P384Fr](r), + S: emulated.ValueOf[emulated.P384Fr](s), + }, + Msg: emulated.ValueOf[emulated.P384Fr](msgHash[:]), + Pub: PublicKey[emulated.P384Fp, emulated.P384Fr]{ + X: emulated.ValueOf[emulated.P384Fp](privKey.PublicKey.X), + Y: emulated.ValueOf[emulated.P384Fp](privKey.PublicKey.Y), + }, + } + assert := test.NewAssert(t) + err := test.IsSolved(&circuit, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) + +} From e9685e86c3bbb453477506b2935b02155bc227c3 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 25 May 2023 12:57:23 -0500 Subject: [PATCH 388/464] feat: batch pedersen poks --- backend/groth16/bn254/prove.go | 17 ++++++++++------- backend/groth16/bn254/verify.go | 9 +++++++++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index 45722c553e..ee6ebc800f 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -22,6 +22,7 @@ import ( curve "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/pedersen" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint/bn254" @@ -66,6 +67,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] + privateCommitted := make([][]fr.Element, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. @@ -73,18 +75,15 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b if len(in) != r1cs.CommitmentInfo[i].NbCommitted() { // TODO: Remove return fmt.Errorf("unexpected number of committed variables") } - values := make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) - nbPublicCommitted := len(in) - len(values) + privateCommitted[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) + nbPublicCommitted := len(in) - len(privateCommitted[i]) inPrivate := in[nbPublicCommitted:] for j, inJ := range inPrivate { - values[j].SetBigInt(inJ) + privateCommitted[i][j].SetBigInt(inJ) } var err error - if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(values); err != nil { - return err - } - if proof.CommitmentPok, err = pk.CommitmentKeys[i].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving + if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(privateCommitted[i]); err != nil { return err } @@ -100,6 +99,10 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return nil, err } + if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, []byte("TODO PUT COMMITMENTS HERE")); err != nil { + return nil, err + } + solution := _solution.(*cs.R1CSSolution) wireValues := []fr.Element(solution.W) diff --git a/backend/groth16/bn254/verify.go b/backend/groth16/bn254/verify.go index 630b751ca2..a7f2aeac7e 100644 --- a/backend/groth16/bn254/verify.go +++ b/backend/groth16/bn254/verify.go @@ -22,6 +22,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/pedersen" "github.com/consensys/gnark/logger" "io" "math/big" @@ -61,6 +62,14 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() + if folded, err := pedersen.FoldCommitments(proof.Commitments, []byte("TODO PUT COMMITMENTS HERE")); err != nil { + return err + } else { + if err = vk.CommitmentKey.Verify(folded, proof.CommitmentPok); err != nil { + return err + } + } + for i := range vk.PublicCommitted { if err := vk.CommitmentKey.Verify(proof.Commitments[i], proof.CommitmentPok); err != nil { From bba21d10d80651b953c1a1cde171173df11c4914 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 25 May 2023 13:12:44 -0500 Subject: [PATCH 389/464] build: generify batch verification --- backend/groth16/bls12-377/prove.go | 19 ++++++++++--------- backend/groth16/bls12-377/verify.go | 9 +++++++++ backend/groth16/bls12-381/prove.go | 19 ++++++++++--------- backend/groth16/bls12-381/verify.go | 9 +++++++++ backend/groth16/bls24-315/prove.go | 19 ++++++++++--------- backend/groth16/bls24-315/verify.go | 9 +++++++++ backend/groth16/bls24-317/prove.go | 19 ++++++++++--------- backend/groth16/bls24-317/verify.go | 9 +++++++++ backend/groth16/bn254/prove.go | 12 +++++------- backend/groth16/bw6-633/prove.go | 19 ++++++++++--------- backend/groth16/bw6-633/verify.go | 9 +++++++++ backend/groth16/bw6-761/prove.go | 19 ++++++++++--------- backend/groth16/bw6-761/verify.go | 9 +++++++++ .../zkpschemes/groth16/groth16.prove.go.tmpl | 19 ++++++++++--------- .../zkpschemes/groth16/groth16.verify.go.tmpl | 9 +++++++++ 15 files changed, 138 insertions(+), 70 deletions(-) diff --git a/backend/groth16/bls12-377/prove.go b/backend/groth16/bls12-377/prove.go index e28ca68d54..bda95ca87b 100644 --- a/backend/groth16/bls12-377/prove.go +++ b/backend/groth16/bls12-377/prove.go @@ -22,6 +22,7 @@ import ( curve "github.com/consensys/gnark-crypto/ecc/bls12-377" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/pedersen" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint/bls12-377" @@ -66,25 +67,21 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] + privateCommitted := make([][]fr.Element, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { - // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. - // If that is the case, figure out a way to feed the solution vector into this function if len(in) != r1cs.CommitmentInfo[i].NbCommitted() { // TODO: Remove return fmt.Errorf("unexpected number of committed variables") } - values := make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) - nbPublicCommitted := len(in) - len(values) + privateCommitted[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) + nbPublicCommitted := len(in) - len(privateCommitted[i]) inPrivate := in[nbPublicCommitted:] for j, inJ := range inPrivate { - values[j].SetBigInt(inJ) + privateCommitted[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead } var err error - if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(values); err != nil { - return err - } - if proof.CommitmentPok, err = pk.CommitmentKeys[i].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving + if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(privateCommitted[i]); err != nil { return err } @@ -105,6 +102,10 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b start := time.Now() + if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, []byte("TODO PUT COMMITMENTS HERE")); err != nil { + return nil, err + } + // H (witness reduction / FFT part) var h []fr.Element chHDone := make(chan struct{}, 1) diff --git a/backend/groth16/bls12-377/verify.go b/backend/groth16/bls12-377/verify.go index 4a2c1a0a8d..cf7fcda04d 100644 --- a/backend/groth16/bls12-377/verify.go +++ b/backend/groth16/bls12-377/verify.go @@ -22,6 +22,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bls12-377" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/pedersen" "github.com/consensys/gnark/logger" "io" "math/big" @@ -60,6 +61,14 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() + if folded, err := pedersen.FoldCommitments(proof.Commitments, []byte("TODO PUT COMMITMENTS HERE")); err != nil { + return err + } else { + if err = vk.CommitmentKey.Verify(folded, proof.CommitmentPok); err != nil { + return err + } + } + for i := range vk.PublicCommitted { if err := vk.CommitmentKey.Verify(proof.Commitments[i], proof.CommitmentPok); err != nil { diff --git a/backend/groth16/bls12-381/prove.go b/backend/groth16/bls12-381/prove.go index 6b2ed4113f..f61ff4da9f 100644 --- a/backend/groth16/bls12-381/prove.go +++ b/backend/groth16/bls12-381/prove.go @@ -22,6 +22,7 @@ import ( curve "github.com/consensys/gnark-crypto/ecc/bls12-381" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/fft" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/pedersen" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint/bls12-381" @@ -66,25 +67,21 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] + privateCommitted := make([][]fr.Element, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { - // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. - // If that is the case, figure out a way to feed the solution vector into this function if len(in) != r1cs.CommitmentInfo[i].NbCommitted() { // TODO: Remove return fmt.Errorf("unexpected number of committed variables") } - values := make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) - nbPublicCommitted := len(in) - len(values) + privateCommitted[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) + nbPublicCommitted := len(in) - len(privateCommitted[i]) inPrivate := in[nbPublicCommitted:] for j, inJ := range inPrivate { - values[j].SetBigInt(inJ) + privateCommitted[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead } var err error - if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(values); err != nil { - return err - } - if proof.CommitmentPok, err = pk.CommitmentKeys[i].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving + if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(privateCommitted[i]); err != nil { return err } @@ -105,6 +102,10 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b start := time.Now() + if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, []byte("TODO PUT COMMITMENTS HERE")); err != nil { + return nil, err + } + // H (witness reduction / FFT part) var h []fr.Element chHDone := make(chan struct{}, 1) diff --git a/backend/groth16/bls12-381/verify.go b/backend/groth16/bls12-381/verify.go index fefaeb1dfa..c21bfdf14f 100644 --- a/backend/groth16/bls12-381/verify.go +++ b/backend/groth16/bls12-381/verify.go @@ -22,6 +22,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bls12-381" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/pedersen" "github.com/consensys/gnark/logger" "io" "math/big" @@ -60,6 +61,14 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() + if folded, err := pedersen.FoldCommitments(proof.Commitments, []byte("TODO PUT COMMITMENTS HERE")); err != nil { + return err + } else { + if err = vk.CommitmentKey.Verify(folded, proof.CommitmentPok); err != nil { + return err + } + } + for i := range vk.PublicCommitted { if err := vk.CommitmentKey.Verify(proof.Commitments[i], proof.CommitmentPok); err != nil { diff --git a/backend/groth16/bls24-315/prove.go b/backend/groth16/bls24-315/prove.go index e9a6569bfd..db58646a64 100644 --- a/backend/groth16/bls24-315/prove.go +++ b/backend/groth16/bls24-315/prove.go @@ -22,6 +22,7 @@ import ( curve "github.com/consensys/gnark-crypto/ecc/bls24-315" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/fft" + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/pedersen" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint/bls24-315" @@ -66,25 +67,21 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] + privateCommitted := make([][]fr.Element, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { - // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. - // If that is the case, figure out a way to feed the solution vector into this function if len(in) != r1cs.CommitmentInfo[i].NbCommitted() { // TODO: Remove return fmt.Errorf("unexpected number of committed variables") } - values := make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) - nbPublicCommitted := len(in) - len(values) + privateCommitted[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) + nbPublicCommitted := len(in) - len(privateCommitted[i]) inPrivate := in[nbPublicCommitted:] for j, inJ := range inPrivate { - values[j].SetBigInt(inJ) + privateCommitted[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead } var err error - if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(values); err != nil { - return err - } - if proof.CommitmentPok, err = pk.CommitmentKeys[i].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving + if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(privateCommitted[i]); err != nil { return err } @@ -105,6 +102,10 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b start := time.Now() + if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, []byte("TODO PUT COMMITMENTS HERE")); err != nil { + return nil, err + } + // H (witness reduction / FFT part) var h []fr.Element chHDone := make(chan struct{}, 1) diff --git a/backend/groth16/bls24-315/verify.go b/backend/groth16/bls24-315/verify.go index d9bf187e03..a20d95be23 100644 --- a/backend/groth16/bls24-315/verify.go +++ b/backend/groth16/bls24-315/verify.go @@ -22,6 +22,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bls24-315" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/pedersen" "github.com/consensys/gnark/logger" "io" "math/big" @@ -60,6 +61,14 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() + if folded, err := pedersen.FoldCommitments(proof.Commitments, []byte("TODO PUT COMMITMENTS HERE")); err != nil { + return err + } else { + if err = vk.CommitmentKey.Verify(folded, proof.CommitmentPok); err != nil { + return err + } + } + for i := range vk.PublicCommitted { if err := vk.CommitmentKey.Verify(proof.Commitments[i], proof.CommitmentPok); err != nil { diff --git a/backend/groth16/bls24-317/prove.go b/backend/groth16/bls24-317/prove.go index 053b3fc92c..d940db69d8 100644 --- a/backend/groth16/bls24-317/prove.go +++ b/backend/groth16/bls24-317/prove.go @@ -22,6 +22,7 @@ import ( curve "github.com/consensys/gnark-crypto/ecc/bls24-317" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/fft" + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/pedersen" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint/bls24-317" @@ -66,25 +67,21 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] + privateCommitted := make([][]fr.Element, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { - // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. - // If that is the case, figure out a way to feed the solution vector into this function if len(in) != r1cs.CommitmentInfo[i].NbCommitted() { // TODO: Remove return fmt.Errorf("unexpected number of committed variables") } - values := make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) - nbPublicCommitted := len(in) - len(values) + privateCommitted[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) + nbPublicCommitted := len(in) - len(privateCommitted[i]) inPrivate := in[nbPublicCommitted:] for j, inJ := range inPrivate { - values[j].SetBigInt(inJ) + privateCommitted[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead } var err error - if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(values); err != nil { - return err - } - if proof.CommitmentPok, err = pk.CommitmentKeys[i].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving + if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(privateCommitted[i]); err != nil { return err } @@ -105,6 +102,10 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b start := time.Now() + if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, []byte("TODO PUT COMMITMENTS HERE")); err != nil { + return nil, err + } + // H (witness reduction / FFT part) var h []fr.Element chHDone := make(chan struct{}, 1) diff --git a/backend/groth16/bls24-317/verify.go b/backend/groth16/bls24-317/verify.go index 0b5f449cb6..aa6c3df6e6 100644 --- a/backend/groth16/bls24-317/verify.go +++ b/backend/groth16/bls24-317/verify.go @@ -22,6 +22,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bls24-317" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/pedersen" "github.com/consensys/gnark/logger" "io" "math/big" @@ -60,6 +61,14 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() + if folded, err := pedersen.FoldCommitments(proof.Commitments, []byte("TODO PUT COMMITMENTS HERE")); err != nil { + return err + } else { + if err = vk.CommitmentKey.Verify(folded, proof.CommitmentPok); err != nil { + return err + } + } + for i := range vk.PublicCommitted { if err := vk.CommitmentKey.Verify(proof.Commitments[i], proof.CommitmentPok); err != nil { diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index ee6ebc800f..cd71cf5747 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -70,8 +70,6 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b privateCommitted := make([][]fr.Element, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { - // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. - // If that is the case, figure out a way to feed the solution vector into this function if len(in) != r1cs.CommitmentInfo[i].NbCommitted() { // TODO: Remove return fmt.Errorf("unexpected number of committed variables") } @@ -79,7 +77,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b nbPublicCommitted := len(in) - len(privateCommitted[i]) inPrivate := in[nbPublicCommitted:] for j, inJ := range inPrivate { - privateCommitted[i][j].SetBigInt(inJ) + privateCommitted[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead } var err error @@ -99,15 +97,15 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return nil, err } - if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, []byte("TODO PUT COMMITMENTS HERE")); err != nil { - return nil, err - } - solution := _solution.(*cs.R1CSSolution) wireValues := []fr.Element(solution.W) start := time.Now() + if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, []byte("TODO PUT COMMITMENTS HERE")); err != nil { + return nil, err + } + // H (witness reduction / FFT part) var h []fr.Element chHDone := make(chan struct{}, 1) diff --git a/backend/groth16/bw6-633/prove.go b/backend/groth16/bw6-633/prove.go index 735f9e8cc1..aded423cd0 100644 --- a/backend/groth16/bw6-633/prove.go +++ b/backend/groth16/bw6-633/prove.go @@ -22,6 +22,7 @@ import ( curve "github.com/consensys/gnark-crypto/ecc/bw6-633" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/fft" + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/pedersen" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint/bw6-633" @@ -66,25 +67,21 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] + privateCommitted := make([][]fr.Element, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { - // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. - // If that is the case, figure out a way to feed the solution vector into this function if len(in) != r1cs.CommitmentInfo[i].NbCommitted() { // TODO: Remove return fmt.Errorf("unexpected number of committed variables") } - values := make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) - nbPublicCommitted := len(in) - len(values) + privateCommitted[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) + nbPublicCommitted := len(in) - len(privateCommitted[i]) inPrivate := in[nbPublicCommitted:] for j, inJ := range inPrivate { - values[j].SetBigInt(inJ) + privateCommitted[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead } var err error - if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(values); err != nil { - return err - } - if proof.CommitmentPok, err = pk.CommitmentKeys[i].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving + if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(privateCommitted[i]); err != nil { return err } @@ -105,6 +102,10 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b start := time.Now() + if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, []byte("TODO PUT COMMITMENTS HERE")); err != nil { + return nil, err + } + // H (witness reduction / FFT part) var h []fr.Element chHDone := make(chan struct{}, 1) diff --git a/backend/groth16/bw6-633/verify.go b/backend/groth16/bw6-633/verify.go index f96b24e697..9bf8e8c95a 100644 --- a/backend/groth16/bw6-633/verify.go +++ b/backend/groth16/bw6-633/verify.go @@ -22,6 +22,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bw6-633" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/pedersen" "github.com/consensys/gnark/logger" "io" "math/big" @@ -60,6 +61,14 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() + if folded, err := pedersen.FoldCommitments(proof.Commitments, []byte("TODO PUT COMMITMENTS HERE")); err != nil { + return err + } else { + if err = vk.CommitmentKey.Verify(folded, proof.CommitmentPok); err != nil { + return err + } + } + for i := range vk.PublicCommitted { if err := vk.CommitmentKey.Verify(proof.Commitments[i], proof.CommitmentPok); err != nil { diff --git a/backend/groth16/bw6-761/prove.go b/backend/groth16/bw6-761/prove.go index 344d4dea3f..11d40d88b1 100644 --- a/backend/groth16/bw6-761/prove.go +++ b/backend/groth16/bw6-761/prove.go @@ -22,6 +22,7 @@ import ( curve "github.com/consensys/gnark-crypto/ecc/bw6-761" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/fft" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/pedersen" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint/bw6-761" @@ -66,25 +67,21 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] + privateCommitted := make([][]fr.Element, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { - // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. - // If that is the case, figure out a way to feed the solution vector into this function if len(in) != r1cs.CommitmentInfo[i].NbCommitted() { // TODO: Remove return fmt.Errorf("unexpected number of committed variables") } - values := make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) - nbPublicCommitted := len(in) - len(values) + privateCommitted[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) + nbPublicCommitted := len(in) - len(privateCommitted[i]) inPrivate := in[nbPublicCommitted:] for j, inJ := range inPrivate { - values[j].SetBigInt(inJ) + privateCommitted[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead } var err error - if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(values); err != nil { - return err - } - if proof.CommitmentPok, err = pk.CommitmentKeys[i].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving + if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(privateCommitted[i]); err != nil { return err } @@ -105,6 +102,10 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b start := time.Now() + if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, []byte("TODO PUT COMMITMENTS HERE")); err != nil { + return nil, err + } + // H (witness reduction / FFT part) var h []fr.Element chHDone := make(chan struct{}, 1) diff --git a/backend/groth16/bw6-761/verify.go b/backend/groth16/bw6-761/verify.go index 22f1d42d7a..424c075014 100644 --- a/backend/groth16/bw6-761/verify.go +++ b/backend/groth16/bw6-761/verify.go @@ -22,6 +22,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bw6-761" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/pedersen" "github.com/consensys/gnark/logger" "io" "math/big" @@ -60,6 +61,14 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() + if folded, err := pedersen.FoldCommitments(proof.Commitments, []byte("TODO PUT COMMITMENTS HERE")); err != nil { + return err + } else { + if err = vk.CommitmentKey.Verify(folded, proof.CommitmentPok); err != nil { + return err + } + } + for i := range vk.PublicCommitted { if err := vk.CommitmentKey.Verify(proof.Commitments[i], proof.CommitmentPok); err != nil { diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl index 6976f4d351..b9fe53f13d 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl @@ -4,6 +4,7 @@ import ( {{- template "import_curve" . }} {{- template "import_backend_cs" . }} {{- template "import_fft" . }} + {{- template "import_pedersen" .}} "runtime" "math/big" "time" @@ -49,25 +50,21 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] + privateCommitted := make([][]fr.Element, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID,func(_ *big.Int, in []*big.Int, out []*big.Int) error { - // Perf-TODO: Converting these values to big.Int and back may be a performance bottleneck. - // If that is the case, figure out a way to feed the solution vector into this function if len(in) != r1cs.CommitmentInfo[i].NbCommitted() { // TODO: Remove return fmt.Errorf("unexpected number of committed variables") } - values := make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) - nbPublicCommitted := len(in) - len(values) + privateCommitted[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) + nbPublicCommitted := len(in) - len(privateCommitted[i]) inPrivate := in[nbPublicCommitted:] for j, inJ := range inPrivate { - values[j].SetBigInt(inJ) + privateCommitted[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead } var err error - if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(values); err != nil { - return err - } - if proof.CommitmentPok, err = pk.CommitmentKeys[i].ProveKnowledge(values); err != nil { // TODO: Will have to send proofs of knowledge to after solving + if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(privateCommitted[i]); err != nil { return err } @@ -88,6 +85,10 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b start := time.Now() + if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, []byte("TODO PUT COMMITMENTS HERE")); err != nil { + return nil, err + } + // H (witness reduction / FFT part) var h []fr.Element chHDone := make(chan struct{}, 1) diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl index d41a9e107f..b4229d6541 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl @@ -10,6 +10,7 @@ import ( {{- if eq .Curve "BN254"}} "text/template" {{- end}} + {{- template "import_pedersen" .}} "github.com/consensys/gnark/logger" ) @@ -45,6 +46,14 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() + if folded, err := pedersen.FoldCommitments(proof.Commitments, []byte("TODO PUT COMMITMENTS HERE")); err != nil { + return err + } else { + if err = vk.CommitmentKey.Verify(folded, proof.CommitmentPok); err != nil { + return err + } + } + for i := range vk.PublicCommitted { if err := vk.CommitmentKey.Verify(proof.Commitments[i], proof.CommitmentPok); err != nil { From 11b2a6d9b0d3a95a7f5dc236201f1e6ffa1a12aa Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 25 May 2023 13:34:38 -0500 Subject: [PATCH 390/464] fix: no commitments case for bn254 --- backend/groth16/bn254/setup.go | 15 +++++++++++---- go.mod | 2 +- go.sum | 2 ++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index 921b979c9d..c6317a0682 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -17,6 +17,7 @@ package groth16 import ( + "errors" "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr" @@ -259,14 +260,20 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // --------------------------------------------------------------------------------------------- // Commitment setup - //if nbPrivateCommittedWires != 0 { - commitmentBasis := g1PointsAff[offset:] + commitmentBases := make([][]curve.G1Affine, len(r1cs.CommitmentInfo)) + for i := range commitmentBases { + size := r1cs.CommitmentInfo[i].NbPrivateCommitted + commitmentBases[i] = g1PointsAff[offset : offset+size] + offset += size + } + if offset != len(g1PointsAff) { + return errors.New("didn't consume all G1 points") // TODO @Tabaie Remove this + } - pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBases...) if err != nil { return err } - //} vk.PublicCommitted = make([][]int, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { diff --git a/go.mod b/go.mod index 55fe85f336..b5c291b943 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/bits-and-blooms/bitset v1.5.0 github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 - github.com/consensys/gnark-crypto v0.11.1-0.20230524003106-85db474ed631 + github.com/consensys/gnark-crypto v0.11.1-0.20230525183059-684135cb6410 github.com/fxamacker/cbor/v2 v2.4.0 github.com/google/go-cmp v0.5.9 github.com/google/pprof v0.0.0-20230309165930-d61513b1440d diff --git a/go.sum b/go.sum index 403a727abd..8854233e5e 100644 --- a/go.sum +++ b/go.sum @@ -8,6 +8,8 @@ github.com/consensys/gnark-crypto v0.11.1-0.20230508024855-0cd4994b7f0b h1:owSc8 github.com/consensys/gnark-crypto v0.11.1-0.20230508024855-0cd4994b7f0b/go.mod h1:6C2ytC8zmP8uH2GKVfPOjf0Vw3KwMAaUxlCPK5WQqmw= github.com/consensys/gnark-crypto v0.11.1-0.20230524003106-85db474ed631 h1:6rTz7p7/ph+UNqh9QYSaOv8JdzYnbOO/x4WLB4MZog4= github.com/consensys/gnark-crypto v0.11.1-0.20230524003106-85db474ed631/go.mod h1:6C2ytC8zmP8uH2GKVfPOjf0Vw3KwMAaUxlCPK5WQqmw= +github.com/consensys/gnark-crypto v0.11.1-0.20230525183059-684135cb6410 h1:MWbTUH7IV4pOu0O1fG2G6h3GuKI9Bu3tAffskwOW2+I= +github.com/consensys/gnark-crypto v0.11.1-0.20230525183059-684135cb6410/go.mod h1:6C2ytC8zmP8uH2GKVfPOjf0Vw3KwMAaUxlCPK5WQqmw= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= From 85dfd17dce097e2d94e53a3effdc4876917b7d86 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 25 May 2023 13:38:22 -0500 Subject: [PATCH 391/464] build generify bn254 no commitments fix --- backend/groth16/bls12-377/setup.go | 15 +++++++++++---- backend/groth16/bls12-381/setup.go | 15 +++++++++++---- backend/groth16/bls24-315/setup.go | 15 +++++++++++---- backend/groth16/bls24-317/setup.go | 15 +++++++++++---- backend/groth16/bw6-633/setup.go | 15 +++++++++++---- backend/groth16/bw6-761/setup.go | 15 +++++++++++---- .../zkpschemes/groth16/groth16.setup.go.tmpl | 15 +++++++++++---- 7 files changed, 77 insertions(+), 28 deletions(-) diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index 3c1f436351..f77d3bb082 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -17,6 +17,7 @@ package groth16 import ( + "errors" "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bls12-377" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" @@ -259,14 +260,20 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // --------------------------------------------------------------------------------------------- // Commitment setup - //if nbPrivateCommittedWires != 0 { - commitmentBasis := g1PointsAff[offset:] + commitmentBases := make([][]curve.G1Affine, len(r1cs.CommitmentInfo)) + for i := range commitmentBases { + size := r1cs.CommitmentInfo[i].NbPrivateCommitted + commitmentBases[i] = g1PointsAff[offset : offset+size] + offset += size + } + if offset != len(g1PointsAff) { + return errors.New("didn't consume all G1 points") // TODO @Tabaie Remove this + } - pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBases...) if err != nil { return err } - //} vk.PublicCommitted = make([][]int, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index 32d7645a8b..fae43e2f78 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -17,6 +17,7 @@ package groth16 import ( + "errors" "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bls12-381" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" @@ -259,14 +260,20 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // --------------------------------------------------------------------------------------------- // Commitment setup - //if nbPrivateCommittedWires != 0 { - commitmentBasis := g1PointsAff[offset:] + commitmentBases := make([][]curve.G1Affine, len(r1cs.CommitmentInfo)) + for i := range commitmentBases { + size := r1cs.CommitmentInfo[i].NbPrivateCommitted + commitmentBases[i] = g1PointsAff[offset : offset+size] + offset += size + } + if offset != len(g1PointsAff) { + return errors.New("didn't consume all G1 points") // TODO @Tabaie Remove this + } - pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBases...) if err != nil { return err } - //} vk.PublicCommitted = make([][]int, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index 1bc849c204..55cfd6ff08 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -17,6 +17,7 @@ package groth16 import ( + "errors" "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bls24-315" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" @@ -259,14 +260,20 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // --------------------------------------------------------------------------------------------- // Commitment setup - //if nbPrivateCommittedWires != 0 { - commitmentBasis := g1PointsAff[offset:] + commitmentBases := make([][]curve.G1Affine, len(r1cs.CommitmentInfo)) + for i := range commitmentBases { + size := r1cs.CommitmentInfo[i].NbPrivateCommitted + commitmentBases[i] = g1PointsAff[offset : offset+size] + offset += size + } + if offset != len(g1PointsAff) { + return errors.New("didn't consume all G1 points") // TODO @Tabaie Remove this + } - pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBases...) if err != nil { return err } - //} vk.PublicCommitted = make([][]int, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index 77dc2f1618..96e9f00ee6 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -17,6 +17,7 @@ package groth16 import ( + "errors" "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bls24-317" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" @@ -259,14 +260,20 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // --------------------------------------------------------------------------------------------- // Commitment setup - //if nbPrivateCommittedWires != 0 { - commitmentBasis := g1PointsAff[offset:] + commitmentBases := make([][]curve.G1Affine, len(r1cs.CommitmentInfo)) + for i := range commitmentBases { + size := r1cs.CommitmentInfo[i].NbPrivateCommitted + commitmentBases[i] = g1PointsAff[offset : offset+size] + offset += size + } + if offset != len(g1PointsAff) { + return errors.New("didn't consume all G1 points") // TODO @Tabaie Remove this + } - pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBases...) if err != nil { return err } - //} vk.PublicCommitted = make([][]int, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index 4c72fa30fe..c84b07d63e 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -17,6 +17,7 @@ package groth16 import ( + "errors" "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bw6-633" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" @@ -259,14 +260,20 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // --------------------------------------------------------------------------------------------- // Commitment setup - //if nbPrivateCommittedWires != 0 { - commitmentBasis := g1PointsAff[offset:] + commitmentBases := make([][]curve.G1Affine, len(r1cs.CommitmentInfo)) + for i := range commitmentBases { + size := r1cs.CommitmentInfo[i].NbPrivateCommitted + commitmentBases[i] = g1PointsAff[offset : offset+size] + offset += size + } + if offset != len(g1PointsAff) { + return errors.New("didn't consume all G1 points") // TODO @Tabaie Remove this + } - pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBases...) if err != nil { return err } - //} vk.PublicCommitted = make([][]int, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index cc9f81df68..35704ae370 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -17,6 +17,7 @@ package groth16 import ( + "errors" "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bw6-761" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" @@ -259,14 +260,20 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // --------------------------------------------------------------------------------------------- // Commitment setup - //if nbPrivateCommittedWires != 0 { - commitmentBasis := g1PointsAff[offset:] + commitmentBases := make([][]curve.G1Affine, len(r1cs.CommitmentInfo)) + for i := range commitmentBases { + size := r1cs.CommitmentInfo[i].NbPrivateCommitted + commitmentBases[i] = g1PointsAff[offset : offset+size] + offset += size + } + if offset != len(g1PointsAff) { + return errors.New("didn't consume all G1 points") // TODO @Tabaie Remove this + } - pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBases...) if err != nil { return err } - //} vk.PublicCommitted = make([][]int, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl index 79656a3416..84fa6d9fd0 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl @@ -1,4 +1,5 @@ import ( + "errors" {{- template "import_fr" . }} {{- template "import_curve" . }} {{- template "import_backend_cs" . }} @@ -241,14 +242,20 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // --------------------------------------------------------------------------------------------- // Commitment setup - //if nbPrivateCommittedWires != 0 { - commitmentBasis := g1PointsAff[offset:] + commitmentBases := make([][]curve.G1Affine, len(r1cs.CommitmentInfo)) + for i := range commitmentBases { + size := r1cs.CommitmentInfo[i].NbPrivateCommitted + commitmentBases[i] = g1PointsAff[offset : offset+size] + offset += size + } + if offset != len(g1PointsAff) { + return errors.New("didn't consume all G1 points") // TODO @Tabaie Remove this + } - pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBasis) + pk.CommitmentKeys, vk.CommitmentKey, err = pedersen.Setup(commitmentBases...) if err != nil { return err } - //} vk.PublicCommitted = make([][]int, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { From 51c8c8bc2870ea47b88c20417e166bca6a0d9d68 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 25 May 2023 14:53:08 -0500 Subject: [PATCH 392/464] feat bn254 hash commitment values for folding --- backend/groth16/bn254/prove.go | 7 ++++++- backend/groth16/bn254/verify.go | 23 ++++++++++------------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index cd71cf5747..665cb03bcd 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -102,7 +102,12 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b start := time.Now() - if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, []byte("TODO PUT COMMITMENTS HERE")); err != nil { + commitmentsSerialized := make([]byte, fr.Bytes*len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + copy(commitmentsSerialized[fr.Bytes*i:], wireValues[r1cs.CommitmentInfo[i].CommitmentIndex].Marshal()) + } + + if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, commitmentsSerialized); err != nil { return nil, err } diff --git a/backend/groth16/bn254/verify.go b/backend/groth16/bn254/verify.go index a7f2aeac7e..de7b3f9aac 100644 --- a/backend/groth16/bn254/verify.go +++ b/backend/groth16/bn254/verify.go @@ -62,20 +62,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() - if folded, err := pedersen.FoldCommitments(proof.Commitments, []byte("TODO PUT COMMITMENTS HERE")); err != nil { - return err - } else { - if err = vk.CommitmentKey.Verify(folded, proof.CommitmentPok); err != nil { - return err - } - } - + commitmentsSerialized := make([]byte, len(vk.PublicCommitted)*fr.Bytes) for i := range vk.PublicCommitted { - - if err := vk.CommitmentKey.Verify(proof.Commitments[i], proof.CommitmentPok); err != nil { - return err - } - publicCommitted := make([]*big.Int, len(vk.PublicCommitted[i])) for j := range publicCommitted { var b big.Int @@ -87,6 +75,15 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } else { publicWitness = append(publicWitness, res) + copy(commitmentsSerialized[i*fr.Bytes:], res.Marshal()) + } + } + + if folded, err := pedersen.FoldCommitments(proof.Commitments, commitmentsSerialized); err != nil { + return err + } else { + if err = vk.CommitmentKey.Verify(folded, proof.CommitmentPok); err != nil { + return err } } From d86365b828bd9fe5eff7b53e345dbb992e6bc61b Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 25 May 2023 14:57:31 -0500 Subject: [PATCH 393/464] build: generify commitment hashing --- backend/groth16/bls12-377/prove.go | 7 +++++- backend/groth16/bls12-377/verify.go | 23 ++++++++----------- backend/groth16/bls12-381/prove.go | 7 +++++- backend/groth16/bls12-381/verify.go | 23 ++++++++----------- backend/groth16/bls24-315/prove.go | 7 +++++- backend/groth16/bls24-315/verify.go | 23 ++++++++----------- backend/groth16/bls24-317/prove.go | 7 +++++- backend/groth16/bls24-317/verify.go | 23 ++++++++----------- backend/groth16/bw6-633/prove.go | 7 +++++- backend/groth16/bw6-633/verify.go | 23 ++++++++----------- backend/groth16/bw6-761/prove.go | 7 +++++- backend/groth16/bw6-761/verify.go | 23 ++++++++----------- .../zkpschemes/groth16/groth16.prove.go.tmpl | 7 +++++- .../zkpschemes/groth16/groth16.verify.go.tmpl | 23 ++++++++----------- 14 files changed, 112 insertions(+), 98 deletions(-) diff --git a/backend/groth16/bls12-377/prove.go b/backend/groth16/bls12-377/prove.go index bda95ca87b..2f6bab5e75 100644 --- a/backend/groth16/bls12-377/prove.go +++ b/backend/groth16/bls12-377/prove.go @@ -102,7 +102,12 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b start := time.Now() - if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, []byte("TODO PUT COMMITMENTS HERE")); err != nil { + commitmentsSerialized := make([]byte, fr.Bytes*len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + copy(commitmentsSerialized[fr.Bytes*i:], wireValues[r1cs.CommitmentInfo[i].CommitmentIndex].Marshal()) + } + + if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, commitmentsSerialized); err != nil { return nil, err } diff --git a/backend/groth16/bls12-377/verify.go b/backend/groth16/bls12-377/verify.go index cf7fcda04d..8982fcb132 100644 --- a/backend/groth16/bls12-377/verify.go +++ b/backend/groth16/bls12-377/verify.go @@ -61,20 +61,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() - if folded, err := pedersen.FoldCommitments(proof.Commitments, []byte("TODO PUT COMMITMENTS HERE")); err != nil { - return err - } else { - if err = vk.CommitmentKey.Verify(folded, proof.CommitmentPok); err != nil { - return err - } - } - + commitmentsSerialized := make([]byte, len(vk.PublicCommitted)*fr.Bytes) for i := range vk.PublicCommitted { - - if err := vk.CommitmentKey.Verify(proof.Commitments[i], proof.CommitmentPok); err != nil { - return err - } - publicCommitted := make([]*big.Int, len(vk.PublicCommitted[i])) for j := range publicCommitted { var b big.Int @@ -86,6 +74,15 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } else { publicWitness = append(publicWitness, res) + copy(commitmentsSerialized[i*fr.Bytes:], res.Marshal()) + } + } + + if folded, err := pedersen.FoldCommitments(proof.Commitments, commitmentsSerialized); err != nil { + return err + } else { + if err = vk.CommitmentKey.Verify(folded, proof.CommitmentPok); err != nil { + return err } } diff --git a/backend/groth16/bls12-381/prove.go b/backend/groth16/bls12-381/prove.go index f61ff4da9f..86dca47271 100644 --- a/backend/groth16/bls12-381/prove.go +++ b/backend/groth16/bls12-381/prove.go @@ -102,7 +102,12 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b start := time.Now() - if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, []byte("TODO PUT COMMITMENTS HERE")); err != nil { + commitmentsSerialized := make([]byte, fr.Bytes*len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + copy(commitmentsSerialized[fr.Bytes*i:], wireValues[r1cs.CommitmentInfo[i].CommitmentIndex].Marshal()) + } + + if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, commitmentsSerialized); err != nil { return nil, err } diff --git a/backend/groth16/bls12-381/verify.go b/backend/groth16/bls12-381/verify.go index c21bfdf14f..893e6be13d 100644 --- a/backend/groth16/bls12-381/verify.go +++ b/backend/groth16/bls12-381/verify.go @@ -61,20 +61,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() - if folded, err := pedersen.FoldCommitments(proof.Commitments, []byte("TODO PUT COMMITMENTS HERE")); err != nil { - return err - } else { - if err = vk.CommitmentKey.Verify(folded, proof.CommitmentPok); err != nil { - return err - } - } - + commitmentsSerialized := make([]byte, len(vk.PublicCommitted)*fr.Bytes) for i := range vk.PublicCommitted { - - if err := vk.CommitmentKey.Verify(proof.Commitments[i], proof.CommitmentPok); err != nil { - return err - } - publicCommitted := make([]*big.Int, len(vk.PublicCommitted[i])) for j := range publicCommitted { var b big.Int @@ -86,6 +74,15 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } else { publicWitness = append(publicWitness, res) + copy(commitmentsSerialized[i*fr.Bytes:], res.Marshal()) + } + } + + if folded, err := pedersen.FoldCommitments(proof.Commitments, commitmentsSerialized); err != nil { + return err + } else { + if err = vk.CommitmentKey.Verify(folded, proof.CommitmentPok); err != nil { + return err } } diff --git a/backend/groth16/bls24-315/prove.go b/backend/groth16/bls24-315/prove.go index db58646a64..a0f5389fec 100644 --- a/backend/groth16/bls24-315/prove.go +++ b/backend/groth16/bls24-315/prove.go @@ -102,7 +102,12 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b start := time.Now() - if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, []byte("TODO PUT COMMITMENTS HERE")); err != nil { + commitmentsSerialized := make([]byte, fr.Bytes*len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + copy(commitmentsSerialized[fr.Bytes*i:], wireValues[r1cs.CommitmentInfo[i].CommitmentIndex].Marshal()) + } + + if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, commitmentsSerialized); err != nil { return nil, err } diff --git a/backend/groth16/bls24-315/verify.go b/backend/groth16/bls24-315/verify.go index a20d95be23..4c774f909b 100644 --- a/backend/groth16/bls24-315/verify.go +++ b/backend/groth16/bls24-315/verify.go @@ -61,20 +61,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() - if folded, err := pedersen.FoldCommitments(proof.Commitments, []byte("TODO PUT COMMITMENTS HERE")); err != nil { - return err - } else { - if err = vk.CommitmentKey.Verify(folded, proof.CommitmentPok); err != nil { - return err - } - } - + commitmentsSerialized := make([]byte, len(vk.PublicCommitted)*fr.Bytes) for i := range vk.PublicCommitted { - - if err := vk.CommitmentKey.Verify(proof.Commitments[i], proof.CommitmentPok); err != nil { - return err - } - publicCommitted := make([]*big.Int, len(vk.PublicCommitted[i])) for j := range publicCommitted { var b big.Int @@ -86,6 +74,15 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } else { publicWitness = append(publicWitness, res) + copy(commitmentsSerialized[i*fr.Bytes:], res.Marshal()) + } + } + + if folded, err := pedersen.FoldCommitments(proof.Commitments, commitmentsSerialized); err != nil { + return err + } else { + if err = vk.CommitmentKey.Verify(folded, proof.CommitmentPok); err != nil { + return err } } diff --git a/backend/groth16/bls24-317/prove.go b/backend/groth16/bls24-317/prove.go index d940db69d8..085f8d179b 100644 --- a/backend/groth16/bls24-317/prove.go +++ b/backend/groth16/bls24-317/prove.go @@ -102,7 +102,12 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b start := time.Now() - if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, []byte("TODO PUT COMMITMENTS HERE")); err != nil { + commitmentsSerialized := make([]byte, fr.Bytes*len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + copy(commitmentsSerialized[fr.Bytes*i:], wireValues[r1cs.CommitmentInfo[i].CommitmentIndex].Marshal()) + } + + if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, commitmentsSerialized); err != nil { return nil, err } diff --git a/backend/groth16/bls24-317/verify.go b/backend/groth16/bls24-317/verify.go index aa6c3df6e6..8854213e89 100644 --- a/backend/groth16/bls24-317/verify.go +++ b/backend/groth16/bls24-317/verify.go @@ -61,20 +61,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() - if folded, err := pedersen.FoldCommitments(proof.Commitments, []byte("TODO PUT COMMITMENTS HERE")); err != nil { - return err - } else { - if err = vk.CommitmentKey.Verify(folded, proof.CommitmentPok); err != nil { - return err - } - } - + commitmentsSerialized := make([]byte, len(vk.PublicCommitted)*fr.Bytes) for i := range vk.PublicCommitted { - - if err := vk.CommitmentKey.Verify(proof.Commitments[i], proof.CommitmentPok); err != nil { - return err - } - publicCommitted := make([]*big.Int, len(vk.PublicCommitted[i])) for j := range publicCommitted { var b big.Int @@ -86,6 +74,15 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } else { publicWitness = append(publicWitness, res) + copy(commitmentsSerialized[i*fr.Bytes:], res.Marshal()) + } + } + + if folded, err := pedersen.FoldCommitments(proof.Commitments, commitmentsSerialized); err != nil { + return err + } else { + if err = vk.CommitmentKey.Verify(folded, proof.CommitmentPok); err != nil { + return err } } diff --git a/backend/groth16/bw6-633/prove.go b/backend/groth16/bw6-633/prove.go index aded423cd0..61c5a20509 100644 --- a/backend/groth16/bw6-633/prove.go +++ b/backend/groth16/bw6-633/prove.go @@ -102,7 +102,12 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b start := time.Now() - if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, []byte("TODO PUT COMMITMENTS HERE")); err != nil { + commitmentsSerialized := make([]byte, fr.Bytes*len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + copy(commitmentsSerialized[fr.Bytes*i:], wireValues[r1cs.CommitmentInfo[i].CommitmentIndex].Marshal()) + } + + if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, commitmentsSerialized); err != nil { return nil, err } diff --git a/backend/groth16/bw6-633/verify.go b/backend/groth16/bw6-633/verify.go index 9bf8e8c95a..eb81eb6f35 100644 --- a/backend/groth16/bw6-633/verify.go +++ b/backend/groth16/bw6-633/verify.go @@ -61,20 +61,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() - if folded, err := pedersen.FoldCommitments(proof.Commitments, []byte("TODO PUT COMMITMENTS HERE")); err != nil { - return err - } else { - if err = vk.CommitmentKey.Verify(folded, proof.CommitmentPok); err != nil { - return err - } - } - + commitmentsSerialized := make([]byte, len(vk.PublicCommitted)*fr.Bytes) for i := range vk.PublicCommitted { - - if err := vk.CommitmentKey.Verify(proof.Commitments[i], proof.CommitmentPok); err != nil { - return err - } - publicCommitted := make([]*big.Int, len(vk.PublicCommitted[i])) for j := range publicCommitted { var b big.Int @@ -86,6 +74,15 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } else { publicWitness = append(publicWitness, res) + copy(commitmentsSerialized[i*fr.Bytes:], res.Marshal()) + } + } + + if folded, err := pedersen.FoldCommitments(proof.Commitments, commitmentsSerialized); err != nil { + return err + } else { + if err = vk.CommitmentKey.Verify(folded, proof.CommitmentPok); err != nil { + return err } } diff --git a/backend/groth16/bw6-761/prove.go b/backend/groth16/bw6-761/prove.go index 11d40d88b1..237c74de72 100644 --- a/backend/groth16/bw6-761/prove.go +++ b/backend/groth16/bw6-761/prove.go @@ -102,7 +102,12 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b start := time.Now() - if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, []byte("TODO PUT COMMITMENTS HERE")); err != nil { + commitmentsSerialized := make([]byte, fr.Bytes*len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + copy(commitmentsSerialized[fr.Bytes*i:], wireValues[r1cs.CommitmentInfo[i].CommitmentIndex].Marshal()) + } + + if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, commitmentsSerialized); err != nil { return nil, err } diff --git a/backend/groth16/bw6-761/verify.go b/backend/groth16/bw6-761/verify.go index 424c075014..c610cae314 100644 --- a/backend/groth16/bw6-761/verify.go +++ b/backend/groth16/bw6-761/verify.go @@ -61,20 +61,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() - if folded, err := pedersen.FoldCommitments(proof.Commitments, []byte("TODO PUT COMMITMENTS HERE")); err != nil { - return err - } else { - if err = vk.CommitmentKey.Verify(folded, proof.CommitmentPok); err != nil { - return err - } - } - + commitmentsSerialized := make([]byte, len(vk.PublicCommitted)*fr.Bytes) for i := range vk.PublicCommitted { - - if err := vk.CommitmentKey.Verify(proof.Commitments[i], proof.CommitmentPok); err != nil { - return err - } - publicCommitted := make([]*big.Int, len(vk.PublicCommitted[i])) for j := range publicCommitted { var b big.Int @@ -86,6 +74,15 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } else { publicWitness = append(publicWitness, res) + copy(commitmentsSerialized[i*fr.Bytes:], res.Marshal()) + } + } + + if folded, err := pedersen.FoldCommitments(proof.Commitments, commitmentsSerialized); err != nil { + return err + } else { + if err = vk.CommitmentKey.Verify(folded, proof.CommitmentPok); err != nil { + return err } } diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl index b9fe53f13d..4c24d0a451 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl @@ -85,7 +85,12 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b start := time.Now() - if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, []byte("TODO PUT COMMITMENTS HERE")); err != nil { + commitmentsSerialized := make([]byte, fr.Bytes*len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + copy(commitmentsSerialized[fr.Bytes*i:], wireValues[r1cs.CommitmentInfo[i].CommitmentIndex].Marshal()) + } + + if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, commitmentsSerialized); err != nil { return nil, err } diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl index b4229d6541..566e7813e9 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl @@ -46,20 +46,8 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() - if folded, err := pedersen.FoldCommitments(proof.Commitments, []byte("TODO PUT COMMITMENTS HERE")); err != nil { - return err - } else { - if err = vk.CommitmentKey.Verify(folded, proof.CommitmentPok); err != nil { - return err - } - } - + commitmentsSerialized := make([]byte, len(vk.PublicCommitted)*fr.Bytes) for i := range vk.PublicCommitted { - - if err := vk.CommitmentKey.Verify(proof.Commitments[i], proof.CommitmentPok); err != nil { - return err - } - publicCommitted := make([]*big.Int, len(vk.PublicCommitted[i])) for j := range publicCommitted { var b big.Int @@ -71,6 +59,15 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } else { publicWitness = append(publicWitness, res) + copy(commitmentsSerialized[i*fr.Bytes:], res.Marshal()) + } + } + + if folded, err := pedersen.FoldCommitments(proof.Commitments, commitmentsSerialized); err != nil { + return err + } else { + if err = vk.CommitmentKey.Verify(folded, proof.CommitmentPok); err != nil { + return err } } From 12aaf0c3837de7fddca9a21534dc8d5fbeaf983f Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 25 May 2023 15:00:52 -0500 Subject: [PATCH 394/464] refactor: test utils to another file --- test/commitments_test.go | 109 +++---------------------------- test/end_to_end.go | 136 +++++++++++++++++++++++++++++++++++++++ test/hint_test.go | 40 +----------- 3 files changed, 146 insertions(+), 139 deletions(-) create mode 100644 test/end_to_end.go diff --git a/test/commitments_test.go b/test/commitments_test.go index 9c9e2a9d1a..2d89a8af93 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -2,17 +2,11 @@ package test import ( "fmt" - "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/frontend/cs/scs" "github.com/stretchr/testify/assert" - "math/big" "reflect" - "strings" "testing" - - "github.com/consensys/gnark/backend/plonk" ) type commitmentCircuit struct { @@ -35,22 +29,22 @@ func (c *commitmentCircuit) Define(api frontend.API) error { func TestSingleCommitment(t *testing.T) { assignment := &commitmentCircuit{X: []frontend.Variable{1}, Public: []frontend.Variable{}} - e2eTest(t, assignment) + testAll(t, assignment) } func TestFiveCommitments(t *testing.T) { assignment := &commitmentCircuit{X: []frontend.Variable{1, 2, 3, 4, 5}, Public: []frontend.Variable{}} - e2eTest(t, assignment) + testAll(t, assignment) } func TestSingleCommitmentSinglePublic(t *testing.T) { assignment := &commitmentCircuit{X: []frontend.Variable{0}, Public: []frontend.Variable{1}} - e2eTest(t, assignment) + testAll(t, assignment) } func TestFiveCommitmentsFivePublic(t *testing.T) { assignment := &commitmentCircuit{X: []frontend.Variable{0, 1, 2, 3, 4}, Public: []frontend.Variable{1, 2, 3, 4, 5}} - e2eTest(t, assignment) + testAll(t, assignment) } type noCommitmentCircuit struct { @@ -64,50 +58,7 @@ func (c *noCommitmentCircuit) Define(api frontend.API) error { } func TestNoCommitmentCircuit(t *testing.T) { - e2eTest(t, &noCommitmentCircuit{1}) -} - -var fr = []ecc.ID{ - ecc.BN254, - ecc.BLS12_381, - ecc.BLS12_377, - ecc.BLS24_315, - //ecc.BLS12_378, TODO: @Tabaie Not autogenerated? - ecc.BLS24_317, - ecc.BW6_633, - //ecc.BW6_756, TODO: @Tabaie Not autogenerated? - ecc.BW6_761, -} - -func plonkTest(t *testing.T, circuit, assignment frontend.Circuit) { - - run := func(mod *big.Int) func(t *testing.T) { - return func(t *testing.T) { - ccs, err := frontend.Compile(mod, scs.NewBuilder, circuit) - assert.NoError(t, err) - - witnessFull, err := frontend.NewWitness(assignment, mod) - assert.NoError(t, err) - witnessPublic, err := witnessFull.Public() - assert.NoError(t, err) - - srs, err := NewKZGSRS(ccs) - assert.NoError(t, err) - - pk, vk, err := plonk.Setup(ccs, srs) - assert.NoError(t, err) - - proof, err := plonk.Prove(ccs, pk, witnessFull) - assert.NoError(t, err) - - err = plonk.Verify(proof, vk, witnessPublic) - assert.NoError(t, err) - } - } - - for _, id := range fr { - t.Run(id.String(), run(id.ScalarField())) - } + testAll(t, &noCommitmentCircuit{1}) } type committedConstantCircuit struct { @@ -124,7 +75,7 @@ func (c *committedConstantCircuit) Define(api frontend.API) error { } func TestCommittedConstant(t *testing.T) { - e2eTest(t, &committedConstantCircuit{1}) + testAll(t, &committedConstantCircuit{1}) } type committedPublicCircuit struct { @@ -141,7 +92,7 @@ func (c *committedPublicCircuit) Define(api frontend.API) error { } func TestCommittedPublic(t *testing.T) { - e2eTest(t, &committedPublicCircuit{1}) + testAll(t, &committedPublicCircuit{1}) } func tryCommit(api frontend.API, x ...frontend.Variable) (frontend.Variable, error) { @@ -177,32 +128,7 @@ func TestTwoCommitEngine(t *testing.T) { func TestTwoCommitPlonk(t *testing.T) { assignment := &twoCommitCircuit{X: []frontend.Variable{1, 2}, Y: 3} - plonkTest(t, &twoCommitCircuit{X: make([]frontend.Variable, len(assignment.X))}, assignment) -} - -func hollow(c frontend.Circuit) frontend.Circuit { - cV := reflect.ValueOf(c).Elem() - t := reflect.TypeOf(c).Elem() - res := reflect.New(t) - resE := res.Elem() - resC := res.Interface().(frontend.Circuit) - - frontendVar := reflect.TypeOf((*frontend.Variable)(nil)).Elem() - - for i := 0; i < t.NumField(); i++ { - fieldT := t.Field(i).Type - if fieldT.Kind() == reflect.Slice && fieldT.Elem().Implements(frontendVar) { - resE.Field(i).Set(reflect.ValueOf(make([]frontend.Variable, cV.Field(i).Len()))) - } else if fieldT != frontendVar { - resE.Field(i).Set(cV.Field(i)) - } - } - - return resC -} - -func removePackageName(s string) string { - return s[strings.LastIndex(s, ".")+1:] + testPlonk(t, &twoCommitCircuit{X: make([]frontend.Variable, len(assignment.X))}, assignment) } func TestHollow(t *testing.T) { @@ -228,22 +154,3 @@ func TestHollow(t *testing.T) { t.Run(removePackageName(reflect.TypeOf(assignments[i]).String()), run(assignments[i], expected[i])) } } - -func e2eTest(t *testing.T, assignment frontend.Circuit) { - t.Parallel() - - t.Run("fuzzer", func(t *testing.T) { - circuit := hollow(assignment) - NewAssert(t).ProverSucceeded(circuit, assignment, WithBackends(backend.GROTH16, backend.PLONK)) // TODO: Support PlonkFri.Commit - }) - - t.Run("plonk-e2e", func(t *testing.T) { - circuit := hollow(assignment) - plonkTest(t, circuit, assignment) - }) - - t.Run("groth16-e2e", func(t *testing.T) { - circuit := hollow(assignment) - groth16Test(t, circuit, assignment) - }) -} diff --git a/test/end_to_end.go b/test/end_to_end.go new file mode 100644 index 0000000000..848eed0f49 --- /dev/null +++ b/test/end_to_end.go @@ -0,0 +1,136 @@ +package test + +import ( + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/groth16" + "github.com/consensys/gnark/backend/plonk" + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/frontend/cs/scs" + "github.com/stretchr/testify/assert" + "math/big" + "reflect" + "strings" + "testing" +) + +var fr = []ecc.ID{ + ecc.BN254, + ecc.BLS12_381, + ecc.BLS12_377, + ecc.BLS24_315, + //ecc.BLS12_378, TODO: @Tabaie Not autogenerated? + ecc.BLS24_317, + ecc.BW6_633, + //ecc.BW6_756, TODO: @Tabaie Not autogenerated? + ecc.BW6_761, +} + +func testPlonk(t *testing.T, circuit, assignment frontend.Circuit) { + + run := func(mod *big.Int) func(t *testing.T) { + return func(t *testing.T) { + ccs, err := frontend.Compile(mod, scs.NewBuilder, circuit) + assert.NoError(t, err) + + witnessFull, err := frontend.NewWitness(assignment, mod) + assert.NoError(t, err) + witnessPublic, err := witnessFull.Public() + assert.NoError(t, err) + + srs, err := NewKZGSRS(ccs) + assert.NoError(t, err) + + pk, vk, err := plonk.Setup(ccs, srs) + assert.NoError(t, err) + + proof, err := plonk.Prove(ccs, pk, witnessFull) + assert.NoError(t, err) + + err = plonk.Verify(proof, vk, witnessPublic) + assert.NoError(t, err) + } + } + + for _, id := range fr { + t.Run(id.String(), run(id.ScalarField())) + } +} + +func testGroth16(t *testing.T, circuit, assignment frontend.Circuit) { + run := func(mod *big.Int) func(*testing.T) { + return func(t *testing.T) { + cs, err := frontend.Compile(mod, r1cs.NewBuilder, circuit) + assert.NoError(t, err) + var ( + pk groth16.ProvingKey + vk groth16.VerifyingKey + w, pw witness.Witness + proof groth16.Proof + ) + pk, vk, err = groth16.Setup(cs) + assert.NoError(t, err) + + w, err = frontend.NewWitness(assignment, mod) + assert.NoError(t, err) + + proof, err = groth16.Prove(cs, pk, w) + assert.NoError(t, err) + + pw, err = w.Public() + assert.NoError(t, err) + + assert.NoError(t, groth16.Verify(proof, vk, pw)) + } + } + + for _, id := range fr { + t.Run(id.String(), run(id.ScalarField())) + } +} + +func testAll(t *testing.T, assignment frontend.Circuit) { + t.Parallel() + + t.Run("fuzzer", func(t *testing.T) { + circuit := hollow(assignment) + NewAssert(t).ProverSucceeded(circuit, assignment, WithBackends(backend.GROTH16, backend.PLONK)) // TODO: Support PlonkFri.Commit + }) + + t.Run("plonk-e2e", func(t *testing.T) { + circuit := hollow(assignment) + testPlonk(t, circuit, assignment) + }) + + t.Run("groth16-e2e", func(t *testing.T) { + circuit := hollow(assignment) + testGroth16(t, circuit, assignment) + }) +} + +func hollow(c frontend.Circuit) frontend.Circuit { + cV := reflect.ValueOf(c).Elem() + t := reflect.TypeOf(c).Elem() + res := reflect.New(t) + resE := res.Elem() + resC := res.Interface().(frontend.Circuit) + + frontendVar := reflect.TypeOf((*frontend.Variable)(nil)).Elem() + + for i := 0; i < t.NumField(); i++ { + fieldT := t.Field(i).Type + if fieldT.Kind() == reflect.Slice && fieldT.Elem().Implements(frontendVar) { + resE.Field(i).Set(reflect.ValueOf(make([]frontend.Variable, cV.Field(i).Len()))) + } else if fieldT != frontendVar { + resE.Field(i).Set(cV.Field(i)) + } + } + + return resC +} + +func removePackageName(s string) string { + return s[strings.LastIndex(s, ".")+1:] +} diff --git a/test/hint_test.go b/test/hint_test.go index b2e862fdd5..dd8ad7d9ed 100644 --- a/test/hint_test.go +++ b/test/hint_test.go @@ -2,12 +2,8 @@ package test import ( "fmt" - "github.com/consensys/gnark/backend/groth16" - "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/stretchr/testify/assert" "math/big" "testing" ) @@ -50,45 +46,13 @@ func init() { } func TestHintWithCustomNamePlonk(t *testing.T) { - plonkTest(t, &circuit, &assignment) + testPlonk(t, &circuit, &assignment) } func TestHintWithCustomNameGroth16(t *testing.T) { - groth16Test(t, &circuit, &assignment) + testGroth16(t, &circuit, &assignment) } func TestHintWithCustomNameEngine(t *testing.T) { NewAssert(t).SolvingSucceeded(&circuit, &assignment) } - -func groth16Test(t *testing.T, circuit, assignment frontend.Circuit) { - run := func(mod *big.Int) func(*testing.T) { - return func(t *testing.T) { - cs, err := frontend.Compile(mod, r1cs.NewBuilder, circuit) - assert.NoError(t, err) - var ( - pk groth16.ProvingKey - vk groth16.VerifyingKey - w, pw witness.Witness - proof groth16.Proof - ) - pk, vk, err = groth16.Setup(cs) - assert.NoError(t, err) - - w, err = frontend.NewWitness(assignment, mod) - assert.NoError(t, err) - - proof, err = groth16.Prove(cs, pk, w) - assert.NoError(t, err) - - pw, err = w.Public() - assert.NoError(t, err) - - assert.NoError(t, groth16.Verify(proof, vk, pw)) - } - } - - for _, id := range fr { - t.Run(id.String(), run(id.ScalarField())) - } -} From 7b98f4a8f340b07721a08703528f76bcabfaaa2e Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 25 May 2023 15:09:06 -0500 Subject: [PATCH 395/464] refactor: groth16 and plonk tests to hollow circuits themselves --- test/commitments_test.go | 23 +++++++++++++++++++++-- test/end_to_end.go | 12 ++++++------ test/hint_test.go | 10 +++++----- 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/test/commitments_test.go b/test/commitments_test.go index 2d89a8af93..8cac007354 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -127,8 +127,27 @@ func TestTwoCommitEngine(t *testing.T) { } func TestTwoCommitPlonk(t *testing.T) { - assignment := &twoCommitCircuit{X: []frontend.Variable{1, 2}, Y: 3} - testPlonk(t, &twoCommitCircuit{X: make([]frontend.Variable, len(assignment.X))}, assignment) + testPlonk(t, &twoCommitCircuit{X: []frontend.Variable{1, 2}, Y: 3}) +} + +type independentCommitsCircuit struct { + X []frontend.Variable +} + +func (c *independentCommitsCircuit) Define(api frontend.API) error { + committer := api.(frontend.Committer) + for i := range c.X { + if ch, err := committer.Commit(c.X[i]); err != nil { + return err + } else { + api.AssertIsDifferent(ch, 0) + } + } + return nil +} + +func TestTwoIndependentCommitsGroth16(t *testing.T) { + testGroth16(t, &independentCommitsCircuit{X: []frontend.Variable{1, 2}}) } func TestHollow(t *testing.T) { diff --git a/test/end_to_end.go b/test/end_to_end.go index 848eed0f49..007220a550 100644 --- a/test/end_to_end.go +++ b/test/end_to_end.go @@ -28,7 +28,8 @@ var fr = []ecc.ID{ ecc.BW6_761, } -func testPlonk(t *testing.T, circuit, assignment frontend.Circuit) { +func testPlonk(t *testing.T, assignment frontend.Circuit) { + circuit := hollow(assignment) run := func(mod *big.Int) func(t *testing.T) { return func(t *testing.T) { @@ -59,7 +60,8 @@ func testPlonk(t *testing.T, circuit, assignment frontend.Circuit) { } } -func testGroth16(t *testing.T, circuit, assignment frontend.Circuit) { +func testGroth16(t *testing.T, assignment frontend.Circuit) { + circuit := hollow(assignment) run := func(mod *big.Int) func(*testing.T) { return func(t *testing.T) { cs, err := frontend.Compile(mod, r1cs.NewBuilder, circuit) @@ -100,13 +102,11 @@ func testAll(t *testing.T, assignment frontend.Circuit) { }) t.Run("plonk-e2e", func(t *testing.T) { - circuit := hollow(assignment) - testPlonk(t, circuit, assignment) + testPlonk(t, assignment) }) t.Run("groth16-e2e", func(t *testing.T) { - circuit := hollow(assignment) - testGroth16(t, circuit, assignment) + testGroth16(t, assignment) }) } diff --git a/test/hint_test.go b/test/hint_test.go index dd8ad7d9ed..d2c6650f7f 100644 --- a/test/hint_test.go +++ b/test/hint_test.go @@ -37,22 +37,22 @@ func (c *customNamedHintCircuit) Define(api frontend.API) error { return nil } -var assignment, circuit customNamedHintCircuit +var assignment customNamedHintCircuit func init() { solver.RegisterNamedHint(identityHint, id) assignment = customNamedHintCircuit{X: []frontend.Variable{1, 2, 3, 4, 5}} - circuit = customNamedHintCircuit{X: make([]frontend.Variable, len(assignment.X))} } func TestHintWithCustomNamePlonk(t *testing.T) { - testPlonk(t, &circuit, &assignment) + testPlonk(t, &assignment) } func TestHintWithCustomNameGroth16(t *testing.T) { - testGroth16(t, &circuit, &assignment) + testGroth16(t, &assignment) } func TestHintWithCustomNameEngine(t *testing.T) { - NewAssert(t).SolvingSucceeded(&circuit, &assignment) + circuit := hollow(&assignment) + NewAssert(t).SolvingSucceeded(circuit, &assignment) } From 34cb89bbdc3dc1b6c0562050f21dee7645b55b2e Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 25 May 2023 18:32:31 -0500 Subject: [PATCH 396/464] feat: groth16 multicommit setup bn254, hopefully --- backend/groth16/bn254/setup.go | 105 +++++++++++++++++++++++++-------- constraint/core.go | 4 +- constraint/system.go | 2 +- frontend/cs/r1cs/api.go | 19 +++++- internal/utils/heap.go | 84 ++++++++++++++++++++++++++ internal/utils/search.go | 18 ++++++ 6 files changed, 205 insertions(+), 27 deletions(-) create mode 100644 internal/utils/heap.go create mode 100644 internal/utils/search.go diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index c6317a0682..4ef65d7139 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -25,6 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr/pedersen" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bn254" + "github.com/consensys/gnark/internal/utils" "math/big" "math/bits" ) @@ -95,16 +96,28 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbPrivateCommittedWires := 0 - if r1cs.GetNbCommitments() != 0 { - nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted + commitmentWires := make([]int, len(r1cs.CommitmentInfo)) + privateCommitted := make([][]int, len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + nbPrivateCommittedWires += r1cs.CommitmentInfo[i].NbPrivateCommitted + privateCommitted[i] = r1cs.CommitmentInfo[i].PrivateCommitted() + commitmentWires[i] = r1cs.CommitmentInfo[i].CommitmentIndex } - nbPublicWires := r1cs.GetNbPublicVariables() - nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.GetNbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private - nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 - nbPrivateWires-- // level it must be considered public + // a commitment is itself defined by a hint so the prover considers it private + // but the verifier will need to inject the value itself so on the groth16 + // level it must be considered public + nbPublicWires := r1cs.GetNbPublicVariables() + len(r1cs.CommitmentInfo) + nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(r1cs.CommitmentInfo) + + // we will need to iterate through the private-to-public wires in order + /*privToPub := make([], nbPrivateCommittedWires+len(r1cs.CommitmentInfo)) + offset := 0 + for i := range r1cs.CommitmentInfo { + copy(privToPub[offset:], r1cs.CommitmentInfo[i].PrivateCommitted()) // TODO Take out commitments + offset += r1cs.CommitmentInfo[i].NbPrivateCommitted } + privToPub.Heapify()*/ // Setting group for fft domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) @@ -141,7 +154,19 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // compute scalars for pkK, vkK and ckK pkK := make([]fr.Element, nbPrivateWires) vkK := make([]fr.Element, nbPublicWires) - ckK := make([]fr.Element, nbPrivateCommittedWires) + ckK := make([][]fr.Element, len(r1cs.CommitmentInfo)) + + // see if i commits to j + for i := range r1cs.CommitmentInfo { + commitmentCommitments := 0 + + for j := 0; j < i; j++ { + if found, _ := utils.BinarySearch(privateCommitted[i], r1cs.CommitmentInfo[j].CommitmentIndex); found { + commitmentCommitments++ + } + } + ckK[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-commitmentCommitments) + } var t0, t1 fr.Element @@ -153,30 +178,62 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Mul(&t1, coeff) } - vI, cI := 0, 0 - var privateCommitted []int - if r1cs.GetNbCommitments() != 0 { - privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() + vI := 0 + cI := make([]int, len(r1cs.CommitmentInfo)) + nbCommitToCommit := make([]int, len(r1cs.CommitmentInfo)) + nbPrivateCommittedSeen := 0 + nbCommitmentsSeen := 0 + + /*for j := range r1cs.CommitmentInfo { // skip commitments to commitments + k := 0 + l := 0 + for ; k < len(privateCommitted[j]); k++ { + for ; l < len(commitmentWires) && commitmentWires[l] < privateCommitted[j][k]; l++ {} + if k != l { + break + } + } + cI[j] = k } + copy(nbCommitToCommit, cI)*/ for i := range A { - isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.GetNbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex - isPublic := i < r1cs.GetNbPublicVariables() + var isCommitment, isPublic bool + if isPublic = i < r1cs.GetNbPublicVariables(); !isPublic { + if nbCommitmentsSeen < len(commitmentWires) && commitmentWires[nbCommitmentsSeen] == i { + isCommitment = true + nbCommitmentsSeen++ + } + } + commitment := -1 // index of the commitment that commits to this variable as a private or commitment value + + if !isPublic { + for j := range r1cs.CommitmentInfo { + if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { + commitment = j + cI[j]-- + if isCommitment { + nbCommitToCommit[j]++ + } else { + break + } + } + } + } - if isPublic || isCommittedPrivate || isCommitment { + if isPublic || commitment != -1 || isCommitment { computeK(i, &toxicWaste.gammaInv) - if isCommittedPrivate { - ckK[cI] = t1 - cI++ - } else { + if isPublic || isCommitment { vkK[vI] = t1 vI++ + } else { // committed and private + ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]-1] = t1 + nbPrivateCommittedSeen++ } } else { computeK(i, &toxicWaste.deltaInv) - pkK[i-vI-cI] = t1 + pkK[i-vI-nbPrivateCommittedSeen] = t1 // vI = nbPublicSeen + nbCommitmentsSeen } } @@ -229,7 +286,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { g1Scalars = append(g1Scalars, Z...) g1Scalars = append(g1Scalars, vkK...) g1Scalars = append(g1Scalars, pkK...) - g1Scalars = append(g1Scalars, ckK...) + for i := range ckK { + g1Scalars = append(g1Scalars, ckK[i]...) + } g1PointsAff := curve.BatchScalarMultiplicationG1(&g1, g1Scalars) @@ -262,7 +321,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { commitmentBases := make([][]curve.G1Affine, len(r1cs.CommitmentInfo)) for i := range commitmentBases { - size := r1cs.CommitmentInfo[i].NbPrivateCommitted + size := len(ckK[i]) commitmentBases[i] = g1PointsAff[offset : offset+size] offset += size } diff --git a/constraint/core.go b/constraint/core.go index 68b956d6e2..7efb6192f2 100644 --- a/constraint/core.go +++ b/constraint/core.go @@ -418,8 +418,8 @@ func (cs *System) GetSparseR1CIterator() SparseR1CIterator { return SparseR1CIterator{cs: cs} } -func (cs *System) GetNbCommitments() int { - return len(cs.CommitmentInfo) +func (cs *System) GetCommitments() []Commitment { + return cs.CommitmentInfo } // bufPool is a pool of buffers used by getBuffer and putBuffer. diff --git a/constraint/system.go b/constraint/system.go index 86d561584c..e733b8f12c 100644 --- a/constraint/system.go +++ b/constraint/system.go @@ -51,7 +51,7 @@ type ConstraintSystem interface { AddSolverHint(f solver.Hint, id solver.HintID, input []LinearExpression, nbOutput int) (internalVariables []int, err error) AddCommitment(c Commitment) error - GetNbCommitments() int // TODO: Erase once multi-commits are implemented in Groth16 + GetCommitments() []Commitment AddLog(l LogEntry) diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index 11b3e93388..4b44531717 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -19,6 +19,7 @@ package r1cs import ( "errors" "fmt" + "github.com/consensys/gnark/internal/utils" "path/filepath" "reflect" "runtime" @@ -719,6 +720,22 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error committed = append(committed, t.VID) if t.VID < builder.cs.GetNbPublicVariables() { nbPublicCommitted++ + } else { + // Cannot commit to a secret variable that has already been committed to + // instead we commit to its commitment + commitments := builder.cs.GetCommitments() + for i := range commitments { + if alreadyCommitted, _ := utils.BinarySearch(commitments[i].Committed, t.VID); alreadyCommitted { + toCommit := commitments[i].CommitmentIndex + if alreadyCommitted, toInsert := utils.BinarySearch(committed, toCommit); alreadyCommitted { + committed = committed[:len(committed)-1] // variable already represented + } else { + copy(committed[toInsert+1:], committed[toInsert:]) + committed[toInsert] = toCommit + } + break + } + } } curr++ } @@ -739,7 +756,7 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error err error ) - commitment.HintID, err = cs.RegisterBsb22CommitmentComputePlaceholder(builder.cs.GetNbCommitments()) + commitment.HintID, err = cs.RegisterBsb22CommitmentComputePlaceholder(len(builder.cs.GetCommitments())) if err != nil { return nil, err } diff --git a/internal/utils/heap.go b/internal/utils/heap.go new file mode 100644 index 0000000000..09bfd820dd --- /dev/null +++ b/internal/utils/heap.go @@ -0,0 +1,84 @@ +package utils + +// An IntHeap is a min-heap of linear expressions. It facilitates merging k-linear expressions. +// +// The code is identical to https://pkg.go.dev/container/heap but replaces interfaces with concrete +// type to avoid memory overhead. +type IntHeap []int + +func (h *IntHeap) less(i, j int) bool { return (*h)[i] < (*h)[j] } +func (h *IntHeap) swap(i, j int) { (*h)[i], (*h)[j] = (*h)[j], (*h)[i] } + +// Heapify establishes the heap invariants required by the other routines in this package. +// Heapify is idempotent with respect to the heap invariants +// and may be called whenever the heap invariants may have been invalidated. +// The complexity is O(n) where n = len(*h). +func (h *IntHeap) Heapify() { + // heapify + n := len(*h) + for i := n/2 - 1; i >= 0; i-- { + h.down(i, n) + } +} + +// Pop removes and returns the minimum element (according to Less) from the heap. +// The complexity is O(log n) where n = len(*h). +// Pop is equivalent to Remove(h, 0). +func (h *IntHeap) Pop() { + n := len(*h) - 1 + h.swap(0, n) + h.down(0, n) + *h = (*h)[0:n] +} + +func (h *IntHeap) up(j int) { + for { + i := (j - 1) / 2 // parent + if i == j || !h.less(j, i) { + break + } + h.swap(i, j) + j = i + } +} + +func (h *IntHeap) down(i0, n int) bool { + i := i0 + for { + j1 := 2*i + 1 + if j1 >= n || j1 < 0 { // j1 < 0 after int overflow + break + } + j := j1 // left child + if j2 := j1 + 1; j2 < n && h.less(j2, j1) { + j = j2 // = 2*i + 2 // right child + } + if !h.less(j, i) { + break + } + h.swap(i, j) + i = j + } + return i > i0 +} + +// Copied from go codebase but not needed (yet) +/* + +// Fix re-establishes the heap ordering after the element at index i has changed its value. +// Changing the value of the element at index i and then calling fix is equivalent to, +// but less expensive than, calling Remove(h, i) followed by a Push of the new value. +// The complexity is O(log n) where n = len(*h). +func (h *IntHeap) Fix(i int) { + if !h.down(i, len(*h)) { + h.up(i) + } +} + +// Push the element x onto the heap. +// The complexity is O(log n) where n = len(*h). +func (h *IntHeap) Push(x int) { + *h = append(*h, x) + h.up(len(*h) - 1) +} +*/ diff --git a/internal/utils/search.go b/internal/utils/search.go new file mode 100644 index 0000000000..c8e8ae05cd --- /dev/null +++ b/internal/utils/search.go @@ -0,0 +1,18 @@ +package utils + +// BinarySearch attempts to find the target in x. If not found, returns false and the index where the target would be inserted. +func BinarySearch(x []int, target int) (bool, int) { + i := 0 + for j := len(x); i != j; { + m := (i + j) / 2 + if x[m] < target { + i = m + 1 + } else { + j = m + } + } + if i < len(x) && x[i] == target { + return true, i + } + return false, i +} From 015d4025c5bae6f661dbe5ad0926987a26d90a46 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 26 May 2023 12:23:23 -0500 Subject: [PATCH 397/464] refactor test bn254 groth16 only --- test/commitments_test.go | 44 +++---- test/commitments_test.gop | 249 -------------------------------------- test/end_to_end.go | 22 ++-- 3 files changed, 36 insertions(+), 279 deletions(-) delete mode 100644 test/commitments_test.gop diff --git a/test/commitments_test.go b/test/commitments_test.go index 8cac007354..0393696331 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -9,6 +9,20 @@ import ( "testing" ) +type noCommitmentCircuit struct { + X frontend.Variable +} + +func (c *noCommitmentCircuit) Define(api frontend.API) error { + api.AssertIsEqual(c.X, 1) + api.AssertIsEqual(c.X, 1) + return nil +} + +func TestNoCommitmentCircuit(t *testing.T) { + testAll(t, &noCommitmentCircuit{1}) +} + type commitmentCircuit struct { Public []frontend.Variable `gnark:",public"` X []frontend.Variable @@ -47,20 +61,6 @@ func TestFiveCommitmentsFivePublic(t *testing.T) { testAll(t, assignment) } -type noCommitmentCircuit struct { - X frontend.Variable -} - -func (c *noCommitmentCircuit) Define(api frontend.API) error { - api.AssertIsEqual(c.X, 1) - api.AssertIsEqual(c.X, 1) - return nil -} - -func TestNoCommitmentCircuit(t *testing.T) { - testAll(t, &noCommitmentCircuit{1}) -} - type committedConstantCircuit struct { X frontend.Variable } @@ -95,14 +95,6 @@ func TestCommittedPublic(t *testing.T) { testAll(t, &committedPublicCircuit{1}) } -func tryCommit(api frontend.API, x ...frontend.Variable) (frontend.Variable, error) { - committer, ok := api.(frontend.Committer) - if !ok { - return nil, fmt.Errorf("type %T doesn't impl the Committer interface", api) - } - return committer.Commit(x...) -} - type twoCommitCircuit struct { X []frontend.Variable Y frontend.Variable @@ -173,3 +165,11 @@ func TestHollow(t *testing.T) { t.Run(removePackageName(reflect.TypeOf(assignments[i]).String()), run(assignments[i], expected[i])) } } + +func tryCommit(api frontend.API, x ...frontend.Variable) (frontend.Variable, error) { + committer, ok := api.(frontend.Committer) + if !ok { + return nil, fmt.Errorf("type %T doesn't impl the Committer interface", api) + } + return committer.Commit(x...) +} diff --git a/test/commitments_test.gop b/test/commitments_test.gop deleted file mode 100644 index a08ca0055a..0000000000 --- a/test/commitments_test.gop +++ /dev/null @@ -1,249 +0,0 @@ -package test - -import ( - "fmt" - "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark/backend" - "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/frontend/cs/scs" - "github.com/stretchr/testify/assert" - "math/big" - "reflect" - "strings" - "testing" - - "github.com/consensys/gnark/backend/plonk" -) - -type commitmentCircuit struct { - Public []frontend.Variable `gnark:",public"` - X []frontend.Variable -} - -func (c *commitmentCircuit) Define(api frontend.API) error { - - commitment, err := tryCommit(api, c.X...) - if err != nil { - return err - } - api.AssertIsDifferent(commitment, c.X[0]) - for _, p := range c.Public { - api.AssertIsDifferent(p, 0) - } - return err -} - -func TestSingleCommitment(t *testing.T) { - assignment := &commitmentCircuit{X: []frontend.Variable{1}, Public: []frontend.Variable{}} - e2eTest(t, assignment) -} - -func TestFiveCommitments(t *testing.T) { - assignment := &commitmentCircuit{X: []frontend.Variable{1, 2, 3, 4, 5}, Public: []frontend.Variable{}} - e2eTest(t, assignment) -} - -func TestSingleCommitmentSinglePublic(t *testing.T) { - assignment := &commitmentCircuit{X: []frontend.Variable{0}, Public: []frontend.Variable{1}} - e2eTest(t, assignment) -} - -func TestFiveCommitmentsFivePublic(t *testing.T) { - assignment := &commitmentCircuit{X: []frontend.Variable{0, 1, 2, 3, 4}, Public: []frontend.Variable{1, 2, 3, 4, 5}} - e2eTest(t, assignment) -} - -type noCommitmentCircuit struct { - X frontend.Variable -} - -func (c *noCommitmentCircuit) Define(api frontend.API) error { - api.AssertIsEqual(c.X, 1) - api.AssertIsEqual(c.X, 1) - return nil -} - -func TestNoCommitmentCircuit(t *testing.T) { - e2eTest(t, &noCommitmentCircuit{1}) -} - -var fr = []ecc.ID{ - ecc.BN254, - ecc.BLS12_381, - ecc.BLS12_377, - ecc.BLS24_315, - //ecc.BLS12_378, TODO: @Tabaie Not autogenerated? - ecc.BLS24_317, - ecc.BW6_633, - //ecc.BW6_756, TODO: @Tabaie Not autogenerated? - ecc.BW6_761, -} - -func plonkTest(t *testing.T, circuit, assignment frontend.Circuit) { - - run := func(mod *big.Int) func(t *testing.T) { - return func(t *testing.T) { - ccs, err := frontend.Compile(mod, scs.NewBuilder, circuit) - assert.NoError(t, err) - - witnessFull, err := frontend.NewWitness(assignment, mod) - assert.NoError(t, err) - witnessPublic, err := witnessFull.Public() - assert.NoError(t, err) - - srs, err := NewKZGSRS(ccs) - assert.NoError(t, err) - - pk, vk, err := plonk.Setup(ccs, srs) - assert.NoError(t, err) - - proof, err := plonk.Prove(ccs, pk, witnessFull) - assert.NoError(t, err) - - err = plonk.Verify(proof, vk, witnessPublic) - assert.NoError(t, err) - } - } - - for _, id := range fr { - t.Run(id.String(), run(id.ScalarField())) - } -} - -type committedConstantCircuit struct { - X frontend.Variable -} - -func (c *committedConstantCircuit) Define(api frontend.API) error { - commitment, err := tryCommit(api, 1, c.X) - if err != nil { - return err - } - api.AssertIsDifferent(commitment, c.X) - return nil -} - -func TestCommittedConstant(t *testing.T) { - e2eTest(t, &committedConstantCircuit{1}) -} - -type committedPublicCircuit struct { - X frontend.Variable `gnark:",public"` -} - -func (c *committedPublicCircuit) Define(api frontend.API) error { - commitment, err := tryCommit(api, c.X) - if err != nil { - return err - } - api.AssertIsDifferent(commitment, c.X) - return nil -} - -func TestCommittedPublic(t *testing.T) { - e2eTest(t, &committedPublicCircuit{1}) -} - -func tryCommit(api frontend.API, x ...frontend.Variable) (frontend.Variable, error) { - committer, ok := api.(frontend.Committer) - if !ok { - return nil, fmt.Errorf("type %T doesn't impl the Committer interface", api) - } - return committer.Commit(x...) -} - -type twoCommitCircuit struct { - X []frontend.Variable - Y frontend.Variable -} - -func (c *twoCommitCircuit) Define(api frontend.API) error { - c0, err := api.(frontend.Committer).Commit(c.X...) - if err != nil { - return err - } - var c1 frontend.Variable - if c1, err = api.(frontend.Committer).Commit(c0, c.Y); err != nil { - return err - } - api.AssertIsDifferent(c1, c.Y) - return nil -} - -func TestTwoCommitEngine(t *testing.T) { - assignment := &twoCommitCircuit{X: []frontend.Variable{1, 2}, Y: 3} - NewAssert(t).SolvingSucceeded(&twoCommitCircuit{X: make([]frontend.Variable, len(assignment.X))}, assignment, WithBackends(backend.GROTH16, backend.PLONK)) -} - -func TestTwoCommitPlonk(t *testing.T) { - assignment := &twoCommitCircuit{X: []frontend.Variable{1, 2}, Y: 3} - plonkTest(t, &twoCommitCircuit{X: make([]frontend.Variable, len(assignment.X))}, assignment) -} - -func hollow(c frontend.Circuit) frontend.Circuit { - cV := reflect.ValueOf(c).Elem() - t := reflect.TypeOf(c).Elem() - res := reflect.New(t) - resE := res.Elem() - resC := res.Interface().(frontend.Circuit) - - frontendVar := reflect.TypeOf((*frontend.Variable)(nil)).Elem() - - for i := 0; i < t.NumField(); i++ { - fieldT := t.Field(i).Type - if fieldT.Kind() == reflect.Slice && fieldT.Elem().Implements(frontendVar) { - resE.Field(i).Set(reflect.ValueOf(make([]frontend.Variable, cV.Field(i).Len()))) - } else if fieldT != frontendVar { - resE.Field(i).Set(cV.Field(i)) - } - } - - return resC -} - -func removePackageName(s string) string { - return s[strings.LastIndex(s, ".")+1:] -} - -func TestHollow(t *testing.T) { - - run := func(c, expected frontend.Circuit) func(t *testing.T) { - return func(t *testing.T) { - seen := hollow(c) - assert.Equal(t, expected, seen) - } - } - - assignments := []frontend.Circuit{ - &committedConstantCircuit{1}, - &commitmentCircuit{X: []frontend.Variable{1}, Public: []frontend.Variable{}}, - } - - expected := []frontend.Circuit{ - &committedConstantCircuit{nil}, - &commitmentCircuit{X: []frontend.Variable{nil}, Public: []frontend.Variable{}}, - } - - for i := range assignments { - t.Run(removePackageName(reflect.TypeOf(assignments[i]).String()), run(assignments[i], expected[i])) - } -} - -func e2eTest(t *testing.T, assignment frontend.Circuit) { - t.Parallel() - - t.Run("fuzzer", func(t *testing.T) { - circuit := hollow(assignment) - NewAssert(t).ProverSucceeded(circuit, assignment, WithBackends(backend.GROTH16 /*, backend.PLONK*/), WithCurves(ecc.BN254)) // TODO: Support PlonkFri.Commit - }) - /* - t.Run("plonk-e2e", func(t *testing.T) { - circuit := hollow(assignment) - plonkTest(t, circuit, assignment) - }) - - t.Run("groth16-e2e", func(t *testing.T) { - circuit := hollow(assignment) - groth16Test(t, circuit, assignment) - })*/ -} diff --git a/test/end_to_end.go b/test/end_to_end.go index 007220a550..96c042d3b3 100644 --- a/test/end_to_end.go +++ b/test/end_to_end.go @@ -16,6 +16,8 @@ import ( "testing" ) +const onlyGroth16Bn254 = true // TODO remove + var fr = []ecc.ID{ ecc.BN254, ecc.BLS12_381, @@ -96,14 +98,18 @@ func testGroth16(t *testing.T, assignment frontend.Circuit) { func testAll(t *testing.T, assignment frontend.Circuit) { t.Parallel() - t.Run("fuzzer", func(t *testing.T) { - circuit := hollow(assignment) - NewAssert(t).ProverSucceeded(circuit, assignment, WithBackends(backend.GROTH16, backend.PLONK)) // TODO: Support PlonkFri.Commit - }) - - t.Run("plonk-e2e", func(t *testing.T) { - testPlonk(t, assignment) - }) + if !onlyGroth16Bn254 { // TODO remove + t.Run("fuzzer", func(t *testing.T) { + circuit := hollow(assignment) + NewAssert(t).ProverSucceeded(circuit, assignment, WithBackends(backend.GROTH16, backend.PLONK)) // TODO: Support PlonkFri.Commit + }) + + t.Run("plonk-e2e", func(t *testing.T) { + testPlonk(t, assignment) + }) + } else { + fr = []ecc.ID{ecc.BN254} + } t.Run("groth16-e2e", func(t *testing.T) { testGroth16(t, assignment) From aef2c64f05a2d6f8bc399b4e39f68e6dc74cfe59 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 26 May 2023 13:32:05 -0500 Subject: [PATCH 398/464] build generify bn254 changes --- backend/groth16/bls12-377/setup.go | 107 ++++++++++++++---- backend/groth16/bls12-381/setup.go | 107 ++++++++++++++---- backend/groth16/bls24-315/setup.go | 107 ++++++++++++++---- backend/groth16/bls24-317/setup.go | 107 ++++++++++++++---- backend/groth16/bn254/setup.go | 6 +- backend/groth16/bw6-633/setup.go | 107 ++++++++++++++---- backend/groth16/bw6-761/setup.go | 107 ++++++++++++++---- .../zkpschemes/groth16/groth16.setup.go.tmpl | 107 ++++++++++++++---- 8 files changed, 584 insertions(+), 171 deletions(-) diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index f77d3bb082..8e6f145829 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -25,6 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/pedersen" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls12-377" + "github.com/consensys/gnark/internal/utils" "math/big" "math/bits" ) @@ -95,16 +96,29 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbPrivateCommittedWires := 0 - if r1cs.GetNbCommitments() != 0 { - nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted + commitmentWires := make([]int, len(r1cs.CommitmentInfo)) + privateCommitted := make([][]int, len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + nbPrivateCommittedWires += r1cs.CommitmentInfo[i].NbPrivateCommitted + privateCommitted[i] = r1cs.CommitmentInfo[i].PrivateCommitted() + commitmentWires[i] = r1cs.CommitmentInfo[i].CommitmentIndex } - nbPublicWires := r1cs.GetNbPublicVariables() - nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.GetNbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private - nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 - nbPrivateWires-- // level it must be considered public + // a commitment is itself defined by a hint so the prover considers it private + // but the verifier will need to inject the value itself so on the groth16 + // level it must be considered public + nbPublicWires := r1cs.GetNbPublicVariables() + len(r1cs.CommitmentInfo) + nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(r1cs.CommitmentInfo) + + // we will need to iterate through the private-to-public wires in order + /*privToPub := make([], nbPrivateCommittedWires+len(r1cs.CommitmentInfo)) + offset := 0 + for i := range r1cs.CommitmentInfo { + copy(privToPub[offset:], r1cs.CommitmentInfo[i].PrivateCommitted()) // TODO Take out commitments + offset += r1cs.CommitmentInfo[i].NbPrivateCommitted } + privToPub.Heapify() + */ // Setting group for fft domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) @@ -141,7 +155,19 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // compute scalars for pkK, vkK and ckK pkK := make([]fr.Element, nbPrivateWires) vkK := make([]fr.Element, nbPublicWires) - ckK := make([]fr.Element, nbPrivateCommittedWires) + ckK := make([][]fr.Element, len(r1cs.CommitmentInfo)) + + // see if i commits to j + for i := range r1cs.CommitmentInfo { + commitmentCommitments := 0 + + for j := 0; j < i; j++ { + if found, _ := utils.BinarySearch(privateCommitted[i], r1cs.CommitmentInfo[j].CommitmentIndex); found { + commitmentCommitments++ + } + } + ckK[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-commitmentCommitments) + } var t0, t1 fr.Element @@ -152,31 +178,62 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Add(&t1, &C[i]). Mul(&t1, coeff) } - - vI, cI := 0, 0 - var privateCommitted []int - if r1cs.GetNbCommitments() != 0 { - privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() + vI := 0 + cI := make([]int, len(r1cs.CommitmentInfo)) + nbCommitToCommit := make([]int, len(r1cs.CommitmentInfo)) + nbPrivateCommittedSeen := 0 + nbCommitmentsSeen := 0 + + /* for j := range r1cs.CommitmentInfo { // skip commitments to commitments + k := 0 + l := 0 + for ; k < len(privateCommitted[j]); k++ { + for ; l < len(commitmentWires) && commitmentWires[l] < privateCommitted[j][k]; l++ {} + if k != l { + break + } + } + cI[j] = k } + copy(nbCommitToCommit, cI)*/ for i := range A { - isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.GetNbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex - isPublic := i < r1cs.GetNbPublicVariables() + var isCommitment, isPublic bool + if isPublic = i < r1cs.GetNbPublicVariables(); !isPublic { + if nbCommitmentsSeen < len(commitmentWires) && commitmentWires[nbCommitmentsSeen] == i { + isCommitment = true + nbCommitmentsSeen++ + } + } + commitment := -1 // index of the commitment that commits to this variable as a private or commitment value + + if !isPublic { + for j := range r1cs.CommitmentInfo { + if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { + commitment = j + cI[j]-- + if isCommitment { + nbCommitToCommit[j]++ + } else { + break + } + } + } + } - if isPublic || isCommittedPrivate || isCommitment { + if isPublic || commitment != -1 || isCommitment { computeK(i, &toxicWaste.gammaInv) - if isCommittedPrivate { - ckK[cI] = t1 - cI++ - } else { + if isPublic || isCommitment { vkK[vI] = t1 vI++ + } else { // committed and private + ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]-1] = t1 + nbPrivateCommittedSeen++ } } else { computeK(i, &toxicWaste.deltaInv) - pkK[i-vI-cI] = t1 + pkK[i-vI-nbPrivateCommittedSeen] = t1 // vI = nbPublicSeen + nbCommitmentsSeen } } @@ -229,7 +286,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { g1Scalars = append(g1Scalars, Z...) g1Scalars = append(g1Scalars, vkK...) g1Scalars = append(g1Scalars, pkK...) - g1Scalars = append(g1Scalars, ckK...) + for i := range ckK { + g1Scalars = append(g1Scalars, ckK[i]...) + } g1PointsAff := curve.BatchScalarMultiplicationG1(&g1, g1Scalars) @@ -262,7 +321,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { commitmentBases := make([][]curve.G1Affine, len(r1cs.CommitmentInfo)) for i := range commitmentBases { - size := r1cs.CommitmentInfo[i].NbPrivateCommitted + size := len(ckK[i]) commitmentBases[i] = g1PointsAff[offset : offset+size] offset += size } diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index fae43e2f78..1dd7874fb7 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -25,6 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/pedersen" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls12-381" + "github.com/consensys/gnark/internal/utils" "math/big" "math/bits" ) @@ -95,16 +96,29 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbPrivateCommittedWires := 0 - if r1cs.GetNbCommitments() != 0 { - nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted + commitmentWires := make([]int, len(r1cs.CommitmentInfo)) + privateCommitted := make([][]int, len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + nbPrivateCommittedWires += r1cs.CommitmentInfo[i].NbPrivateCommitted + privateCommitted[i] = r1cs.CommitmentInfo[i].PrivateCommitted() + commitmentWires[i] = r1cs.CommitmentInfo[i].CommitmentIndex } - nbPublicWires := r1cs.GetNbPublicVariables() - nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.GetNbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private - nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 - nbPrivateWires-- // level it must be considered public + // a commitment is itself defined by a hint so the prover considers it private + // but the verifier will need to inject the value itself so on the groth16 + // level it must be considered public + nbPublicWires := r1cs.GetNbPublicVariables() + len(r1cs.CommitmentInfo) + nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(r1cs.CommitmentInfo) + + // we will need to iterate through the private-to-public wires in order + /*privToPub := make([], nbPrivateCommittedWires+len(r1cs.CommitmentInfo)) + offset := 0 + for i := range r1cs.CommitmentInfo { + copy(privToPub[offset:], r1cs.CommitmentInfo[i].PrivateCommitted()) // TODO Take out commitments + offset += r1cs.CommitmentInfo[i].NbPrivateCommitted } + privToPub.Heapify() + */ // Setting group for fft domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) @@ -141,7 +155,19 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // compute scalars for pkK, vkK and ckK pkK := make([]fr.Element, nbPrivateWires) vkK := make([]fr.Element, nbPublicWires) - ckK := make([]fr.Element, nbPrivateCommittedWires) + ckK := make([][]fr.Element, len(r1cs.CommitmentInfo)) + + // see if i commits to j + for i := range r1cs.CommitmentInfo { + commitmentCommitments := 0 + + for j := 0; j < i; j++ { + if found, _ := utils.BinarySearch(privateCommitted[i], r1cs.CommitmentInfo[j].CommitmentIndex); found { + commitmentCommitments++ + } + } + ckK[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-commitmentCommitments) + } var t0, t1 fr.Element @@ -152,31 +178,62 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Add(&t1, &C[i]). Mul(&t1, coeff) } - - vI, cI := 0, 0 - var privateCommitted []int - if r1cs.GetNbCommitments() != 0 { - privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() + vI := 0 + cI := make([]int, len(r1cs.CommitmentInfo)) + nbCommitToCommit := make([]int, len(r1cs.CommitmentInfo)) + nbPrivateCommittedSeen := 0 + nbCommitmentsSeen := 0 + + /* for j := range r1cs.CommitmentInfo { // skip commitments to commitments + k := 0 + l := 0 + for ; k < len(privateCommitted[j]); k++ { + for ; l < len(commitmentWires) && commitmentWires[l] < privateCommitted[j][k]; l++ {} + if k != l { + break + } + } + cI[j] = k } + copy(nbCommitToCommit, cI)*/ for i := range A { - isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.GetNbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex - isPublic := i < r1cs.GetNbPublicVariables() + var isCommitment, isPublic bool + if isPublic = i < r1cs.GetNbPublicVariables(); !isPublic { + if nbCommitmentsSeen < len(commitmentWires) && commitmentWires[nbCommitmentsSeen] == i { + isCommitment = true + nbCommitmentsSeen++ + } + } + commitment := -1 // index of the commitment that commits to this variable as a private or commitment value + + if !isPublic { + for j := range r1cs.CommitmentInfo { + if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { + commitment = j + cI[j]-- + if isCommitment { + nbCommitToCommit[j]++ + } else { + break + } + } + } + } - if isPublic || isCommittedPrivate || isCommitment { + if isPublic || commitment != -1 || isCommitment { computeK(i, &toxicWaste.gammaInv) - if isCommittedPrivate { - ckK[cI] = t1 - cI++ - } else { + if isPublic || isCommitment { vkK[vI] = t1 vI++ + } else { // committed and private + ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]-1] = t1 + nbPrivateCommittedSeen++ } } else { computeK(i, &toxicWaste.deltaInv) - pkK[i-vI-cI] = t1 + pkK[i-vI-nbPrivateCommittedSeen] = t1 // vI = nbPublicSeen + nbCommitmentsSeen } } @@ -229,7 +286,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { g1Scalars = append(g1Scalars, Z...) g1Scalars = append(g1Scalars, vkK...) g1Scalars = append(g1Scalars, pkK...) - g1Scalars = append(g1Scalars, ckK...) + for i := range ckK { + g1Scalars = append(g1Scalars, ckK[i]...) + } g1PointsAff := curve.BatchScalarMultiplicationG1(&g1, g1Scalars) @@ -262,7 +321,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { commitmentBases := make([][]curve.G1Affine, len(r1cs.CommitmentInfo)) for i := range commitmentBases { - size := r1cs.CommitmentInfo[i].NbPrivateCommitted + size := len(ckK[i]) commitmentBases[i] = g1PointsAff[offset : offset+size] offset += size } diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index 55cfd6ff08..ebee0f0ff1 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -25,6 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/pedersen" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls24-315" + "github.com/consensys/gnark/internal/utils" "math/big" "math/bits" ) @@ -95,16 +96,29 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbPrivateCommittedWires := 0 - if r1cs.GetNbCommitments() != 0 { - nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted + commitmentWires := make([]int, len(r1cs.CommitmentInfo)) + privateCommitted := make([][]int, len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + nbPrivateCommittedWires += r1cs.CommitmentInfo[i].NbPrivateCommitted + privateCommitted[i] = r1cs.CommitmentInfo[i].PrivateCommitted() + commitmentWires[i] = r1cs.CommitmentInfo[i].CommitmentIndex } - nbPublicWires := r1cs.GetNbPublicVariables() - nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.GetNbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private - nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 - nbPrivateWires-- // level it must be considered public + // a commitment is itself defined by a hint so the prover considers it private + // but the verifier will need to inject the value itself so on the groth16 + // level it must be considered public + nbPublicWires := r1cs.GetNbPublicVariables() + len(r1cs.CommitmentInfo) + nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(r1cs.CommitmentInfo) + + // we will need to iterate through the private-to-public wires in order + /*privToPub := make([], nbPrivateCommittedWires+len(r1cs.CommitmentInfo)) + offset := 0 + for i := range r1cs.CommitmentInfo { + copy(privToPub[offset:], r1cs.CommitmentInfo[i].PrivateCommitted()) // TODO Take out commitments + offset += r1cs.CommitmentInfo[i].NbPrivateCommitted } + privToPub.Heapify() + */ // Setting group for fft domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) @@ -141,7 +155,19 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // compute scalars for pkK, vkK and ckK pkK := make([]fr.Element, nbPrivateWires) vkK := make([]fr.Element, nbPublicWires) - ckK := make([]fr.Element, nbPrivateCommittedWires) + ckK := make([][]fr.Element, len(r1cs.CommitmentInfo)) + + // see if i commits to j + for i := range r1cs.CommitmentInfo { + commitmentCommitments := 0 + + for j := 0; j < i; j++ { + if found, _ := utils.BinarySearch(privateCommitted[i], r1cs.CommitmentInfo[j].CommitmentIndex); found { + commitmentCommitments++ + } + } + ckK[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-commitmentCommitments) + } var t0, t1 fr.Element @@ -152,31 +178,62 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Add(&t1, &C[i]). Mul(&t1, coeff) } - - vI, cI := 0, 0 - var privateCommitted []int - if r1cs.GetNbCommitments() != 0 { - privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() + vI := 0 + cI := make([]int, len(r1cs.CommitmentInfo)) + nbCommitToCommit := make([]int, len(r1cs.CommitmentInfo)) + nbPrivateCommittedSeen := 0 + nbCommitmentsSeen := 0 + + /* for j := range r1cs.CommitmentInfo { // skip commitments to commitments + k := 0 + l := 0 + for ; k < len(privateCommitted[j]); k++ { + for ; l < len(commitmentWires) && commitmentWires[l] < privateCommitted[j][k]; l++ {} + if k != l { + break + } + } + cI[j] = k } + copy(nbCommitToCommit, cI)*/ for i := range A { - isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.GetNbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex - isPublic := i < r1cs.GetNbPublicVariables() + var isCommitment, isPublic bool + if isPublic = i < r1cs.GetNbPublicVariables(); !isPublic { + if nbCommitmentsSeen < len(commitmentWires) && commitmentWires[nbCommitmentsSeen] == i { + isCommitment = true + nbCommitmentsSeen++ + } + } + commitment := -1 // index of the commitment that commits to this variable as a private or commitment value + + if !isPublic { + for j := range r1cs.CommitmentInfo { + if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { + commitment = j + cI[j]-- + if isCommitment { + nbCommitToCommit[j]++ + } else { + break + } + } + } + } - if isPublic || isCommittedPrivate || isCommitment { + if isPublic || commitment != -1 || isCommitment { computeK(i, &toxicWaste.gammaInv) - if isCommittedPrivate { - ckK[cI] = t1 - cI++ - } else { + if isPublic || isCommitment { vkK[vI] = t1 vI++ + } else { // committed and private + ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]-1] = t1 + nbPrivateCommittedSeen++ } } else { computeK(i, &toxicWaste.deltaInv) - pkK[i-vI-cI] = t1 + pkK[i-vI-nbPrivateCommittedSeen] = t1 // vI = nbPublicSeen + nbCommitmentsSeen } } @@ -229,7 +286,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { g1Scalars = append(g1Scalars, Z...) g1Scalars = append(g1Scalars, vkK...) g1Scalars = append(g1Scalars, pkK...) - g1Scalars = append(g1Scalars, ckK...) + for i := range ckK { + g1Scalars = append(g1Scalars, ckK[i]...) + } g1PointsAff := curve.BatchScalarMultiplicationG1(&g1, g1Scalars) @@ -262,7 +321,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { commitmentBases := make([][]curve.G1Affine, len(r1cs.CommitmentInfo)) for i := range commitmentBases { - size := r1cs.CommitmentInfo[i].NbPrivateCommitted + size := len(ckK[i]) commitmentBases[i] = g1PointsAff[offset : offset+size] offset += size } diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index 96e9f00ee6..60c4550c6a 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -25,6 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/pedersen" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls24-317" + "github.com/consensys/gnark/internal/utils" "math/big" "math/bits" ) @@ -95,16 +96,29 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbPrivateCommittedWires := 0 - if r1cs.GetNbCommitments() != 0 { - nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted + commitmentWires := make([]int, len(r1cs.CommitmentInfo)) + privateCommitted := make([][]int, len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + nbPrivateCommittedWires += r1cs.CommitmentInfo[i].NbPrivateCommitted + privateCommitted[i] = r1cs.CommitmentInfo[i].PrivateCommitted() + commitmentWires[i] = r1cs.CommitmentInfo[i].CommitmentIndex } - nbPublicWires := r1cs.GetNbPublicVariables() - nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.GetNbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private - nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 - nbPrivateWires-- // level it must be considered public + // a commitment is itself defined by a hint so the prover considers it private + // but the verifier will need to inject the value itself so on the groth16 + // level it must be considered public + nbPublicWires := r1cs.GetNbPublicVariables() + len(r1cs.CommitmentInfo) + nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(r1cs.CommitmentInfo) + + // we will need to iterate through the private-to-public wires in order + /*privToPub := make([], nbPrivateCommittedWires+len(r1cs.CommitmentInfo)) + offset := 0 + for i := range r1cs.CommitmentInfo { + copy(privToPub[offset:], r1cs.CommitmentInfo[i].PrivateCommitted()) // TODO Take out commitments + offset += r1cs.CommitmentInfo[i].NbPrivateCommitted } + privToPub.Heapify() + */ // Setting group for fft domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) @@ -141,7 +155,19 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // compute scalars for pkK, vkK and ckK pkK := make([]fr.Element, nbPrivateWires) vkK := make([]fr.Element, nbPublicWires) - ckK := make([]fr.Element, nbPrivateCommittedWires) + ckK := make([][]fr.Element, len(r1cs.CommitmentInfo)) + + // see if i commits to j + for i := range r1cs.CommitmentInfo { + commitmentCommitments := 0 + + for j := 0; j < i; j++ { + if found, _ := utils.BinarySearch(privateCommitted[i], r1cs.CommitmentInfo[j].CommitmentIndex); found { + commitmentCommitments++ + } + } + ckK[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-commitmentCommitments) + } var t0, t1 fr.Element @@ -152,31 +178,62 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Add(&t1, &C[i]). Mul(&t1, coeff) } - - vI, cI := 0, 0 - var privateCommitted []int - if r1cs.GetNbCommitments() != 0 { - privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() + vI := 0 + cI := make([]int, len(r1cs.CommitmentInfo)) + nbCommitToCommit := make([]int, len(r1cs.CommitmentInfo)) + nbPrivateCommittedSeen := 0 + nbCommitmentsSeen := 0 + + /* for j := range r1cs.CommitmentInfo { // skip commitments to commitments + k := 0 + l := 0 + for ; k < len(privateCommitted[j]); k++ { + for ; l < len(commitmentWires) && commitmentWires[l] < privateCommitted[j][k]; l++ {} + if k != l { + break + } + } + cI[j] = k } + copy(nbCommitToCommit, cI)*/ for i := range A { - isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.GetNbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex - isPublic := i < r1cs.GetNbPublicVariables() + var isCommitment, isPublic bool + if isPublic = i < r1cs.GetNbPublicVariables(); !isPublic { + if nbCommitmentsSeen < len(commitmentWires) && commitmentWires[nbCommitmentsSeen] == i { + isCommitment = true + nbCommitmentsSeen++ + } + } + commitment := -1 // index of the commitment that commits to this variable as a private or commitment value + + if !isPublic { + for j := range r1cs.CommitmentInfo { + if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { + commitment = j + cI[j]-- + if isCommitment { + nbCommitToCommit[j]++ + } else { + break + } + } + } + } - if isPublic || isCommittedPrivate || isCommitment { + if isPublic || commitment != -1 || isCommitment { computeK(i, &toxicWaste.gammaInv) - if isCommittedPrivate { - ckK[cI] = t1 - cI++ - } else { + if isPublic || isCommitment { vkK[vI] = t1 vI++ + } else { // committed and private + ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]-1] = t1 + nbPrivateCommittedSeen++ } } else { computeK(i, &toxicWaste.deltaInv) - pkK[i-vI-cI] = t1 + pkK[i-vI-nbPrivateCommittedSeen] = t1 // vI = nbPublicSeen + nbCommitmentsSeen } } @@ -229,7 +286,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { g1Scalars = append(g1Scalars, Z...) g1Scalars = append(g1Scalars, vkK...) g1Scalars = append(g1Scalars, pkK...) - g1Scalars = append(g1Scalars, ckK...) + for i := range ckK { + g1Scalars = append(g1Scalars, ckK[i]...) + } g1PointsAff := curve.BatchScalarMultiplicationG1(&g1, g1Scalars) @@ -262,7 +321,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { commitmentBases := make([][]curve.G1Affine, len(r1cs.CommitmentInfo)) for i := range commitmentBases { - size := r1cs.CommitmentInfo[i].NbPrivateCommitted + size := len(ckK[i]) commitmentBases[i] = g1PointsAff[offset : offset+size] offset += size } diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index 4ef65d7139..3896db0424 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -117,7 +117,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { copy(privToPub[offset:], r1cs.CommitmentInfo[i].PrivateCommitted()) // TODO Take out commitments offset += r1cs.CommitmentInfo[i].NbPrivateCommitted } - privToPub.Heapify()*/ + privToPub.Heapify() + */ // Setting group for fft domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) @@ -177,14 +178,13 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Add(&t1, &C[i]). Mul(&t1, coeff) } - vI := 0 cI := make([]int, len(r1cs.CommitmentInfo)) nbCommitToCommit := make([]int, len(r1cs.CommitmentInfo)) nbPrivateCommittedSeen := 0 nbCommitmentsSeen := 0 - /*for j := range r1cs.CommitmentInfo { // skip commitments to commitments + /* for j := range r1cs.CommitmentInfo { // skip commitments to commitments k := 0 l := 0 for ; k < len(privateCommitted[j]); k++ { diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index c84b07d63e..530909ff48 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -25,6 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/pedersen" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bw6-633" + "github.com/consensys/gnark/internal/utils" "math/big" "math/bits" ) @@ -95,16 +96,29 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbPrivateCommittedWires := 0 - if r1cs.GetNbCommitments() != 0 { - nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted + commitmentWires := make([]int, len(r1cs.CommitmentInfo)) + privateCommitted := make([][]int, len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + nbPrivateCommittedWires += r1cs.CommitmentInfo[i].NbPrivateCommitted + privateCommitted[i] = r1cs.CommitmentInfo[i].PrivateCommitted() + commitmentWires[i] = r1cs.CommitmentInfo[i].CommitmentIndex } - nbPublicWires := r1cs.GetNbPublicVariables() - nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.GetNbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private - nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 - nbPrivateWires-- // level it must be considered public + // a commitment is itself defined by a hint so the prover considers it private + // but the verifier will need to inject the value itself so on the groth16 + // level it must be considered public + nbPublicWires := r1cs.GetNbPublicVariables() + len(r1cs.CommitmentInfo) + nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(r1cs.CommitmentInfo) + + // we will need to iterate through the private-to-public wires in order + /*privToPub := make([], nbPrivateCommittedWires+len(r1cs.CommitmentInfo)) + offset := 0 + for i := range r1cs.CommitmentInfo { + copy(privToPub[offset:], r1cs.CommitmentInfo[i].PrivateCommitted()) // TODO Take out commitments + offset += r1cs.CommitmentInfo[i].NbPrivateCommitted } + privToPub.Heapify() + */ // Setting group for fft domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) @@ -141,7 +155,19 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // compute scalars for pkK, vkK and ckK pkK := make([]fr.Element, nbPrivateWires) vkK := make([]fr.Element, nbPublicWires) - ckK := make([]fr.Element, nbPrivateCommittedWires) + ckK := make([][]fr.Element, len(r1cs.CommitmentInfo)) + + // see if i commits to j + for i := range r1cs.CommitmentInfo { + commitmentCommitments := 0 + + for j := 0; j < i; j++ { + if found, _ := utils.BinarySearch(privateCommitted[i], r1cs.CommitmentInfo[j].CommitmentIndex); found { + commitmentCommitments++ + } + } + ckK[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-commitmentCommitments) + } var t0, t1 fr.Element @@ -152,31 +178,62 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Add(&t1, &C[i]). Mul(&t1, coeff) } - - vI, cI := 0, 0 - var privateCommitted []int - if r1cs.GetNbCommitments() != 0 { - privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() + vI := 0 + cI := make([]int, len(r1cs.CommitmentInfo)) + nbCommitToCommit := make([]int, len(r1cs.CommitmentInfo)) + nbPrivateCommittedSeen := 0 + nbCommitmentsSeen := 0 + + /* for j := range r1cs.CommitmentInfo { // skip commitments to commitments + k := 0 + l := 0 + for ; k < len(privateCommitted[j]); k++ { + for ; l < len(commitmentWires) && commitmentWires[l] < privateCommitted[j][k]; l++ {} + if k != l { + break + } + } + cI[j] = k } + copy(nbCommitToCommit, cI)*/ for i := range A { - isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.GetNbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex - isPublic := i < r1cs.GetNbPublicVariables() + var isCommitment, isPublic bool + if isPublic = i < r1cs.GetNbPublicVariables(); !isPublic { + if nbCommitmentsSeen < len(commitmentWires) && commitmentWires[nbCommitmentsSeen] == i { + isCommitment = true + nbCommitmentsSeen++ + } + } + commitment := -1 // index of the commitment that commits to this variable as a private or commitment value + + if !isPublic { + for j := range r1cs.CommitmentInfo { + if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { + commitment = j + cI[j]-- + if isCommitment { + nbCommitToCommit[j]++ + } else { + break + } + } + } + } - if isPublic || isCommittedPrivate || isCommitment { + if isPublic || commitment != -1 || isCommitment { computeK(i, &toxicWaste.gammaInv) - if isCommittedPrivate { - ckK[cI] = t1 - cI++ - } else { + if isPublic || isCommitment { vkK[vI] = t1 vI++ + } else { // committed and private + ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]-1] = t1 + nbPrivateCommittedSeen++ } } else { computeK(i, &toxicWaste.deltaInv) - pkK[i-vI-cI] = t1 + pkK[i-vI-nbPrivateCommittedSeen] = t1 // vI = nbPublicSeen + nbCommitmentsSeen } } @@ -229,7 +286,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { g1Scalars = append(g1Scalars, Z...) g1Scalars = append(g1Scalars, vkK...) g1Scalars = append(g1Scalars, pkK...) - g1Scalars = append(g1Scalars, ckK...) + for i := range ckK { + g1Scalars = append(g1Scalars, ckK[i]...) + } g1PointsAff := curve.BatchScalarMultiplicationG1(&g1, g1Scalars) @@ -262,7 +321,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { commitmentBases := make([][]curve.G1Affine, len(r1cs.CommitmentInfo)) for i := range commitmentBases { - size := r1cs.CommitmentInfo[i].NbPrivateCommitted + size := len(ckK[i]) commitmentBases[i] = g1PointsAff[offset : offset+size] offset += size } diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index 35704ae370..8b2fa2e5ba 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -25,6 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/pedersen" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bw6-761" + "github.com/consensys/gnark/internal/utils" "math/big" "math/bits" ) @@ -95,16 +96,29 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbPrivateCommittedWires := 0 - if r1cs.GetNbCommitments() != 0 { - nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted + commitmentWires := make([]int, len(r1cs.CommitmentInfo)) + privateCommitted := make([][]int, len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + nbPrivateCommittedWires += r1cs.CommitmentInfo[i].NbPrivateCommitted + privateCommitted[i] = r1cs.CommitmentInfo[i].PrivateCommitted() + commitmentWires[i] = r1cs.CommitmentInfo[i].CommitmentIndex } - nbPublicWires := r1cs.GetNbPublicVariables() - nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.GetNbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private - nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 - nbPrivateWires-- // level it must be considered public + // a commitment is itself defined by a hint so the prover considers it private + // but the verifier will need to inject the value itself so on the groth16 + // level it must be considered public + nbPublicWires := r1cs.GetNbPublicVariables() + len(r1cs.CommitmentInfo) + nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(r1cs.CommitmentInfo) + + // we will need to iterate through the private-to-public wires in order + /*privToPub := make([], nbPrivateCommittedWires+len(r1cs.CommitmentInfo)) + offset := 0 + for i := range r1cs.CommitmentInfo { + copy(privToPub[offset:], r1cs.CommitmentInfo[i].PrivateCommitted()) // TODO Take out commitments + offset += r1cs.CommitmentInfo[i].NbPrivateCommitted } + privToPub.Heapify() + */ // Setting group for fft domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) @@ -141,7 +155,19 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // compute scalars for pkK, vkK and ckK pkK := make([]fr.Element, nbPrivateWires) vkK := make([]fr.Element, nbPublicWires) - ckK := make([]fr.Element, nbPrivateCommittedWires) + ckK := make([][]fr.Element, len(r1cs.CommitmentInfo)) + + // see if i commits to j + for i := range r1cs.CommitmentInfo { + commitmentCommitments := 0 + + for j := 0; j < i; j++ { + if found, _ := utils.BinarySearch(privateCommitted[i], r1cs.CommitmentInfo[j].CommitmentIndex); found { + commitmentCommitments++ + } + } + ckK[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-commitmentCommitments) + } var t0, t1 fr.Element @@ -152,31 +178,62 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Add(&t1, &C[i]). Mul(&t1, coeff) } - - vI, cI := 0, 0 - var privateCommitted []int - if r1cs.GetNbCommitments() != 0 { - privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() + vI := 0 + cI := make([]int, len(r1cs.CommitmentInfo)) + nbCommitToCommit := make([]int, len(r1cs.CommitmentInfo)) + nbPrivateCommittedSeen := 0 + nbCommitmentsSeen := 0 + + /* for j := range r1cs.CommitmentInfo { // skip commitments to commitments + k := 0 + l := 0 + for ; k < len(privateCommitted[j]); k++ { + for ; l < len(commitmentWires) && commitmentWires[l] < privateCommitted[j][k]; l++ {} + if k != l { + break + } + } + cI[j] = k } + copy(nbCommitToCommit, cI)*/ for i := range A { - isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.GetNbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex - isPublic := i < r1cs.GetNbPublicVariables() + var isCommitment, isPublic bool + if isPublic = i < r1cs.GetNbPublicVariables(); !isPublic { + if nbCommitmentsSeen < len(commitmentWires) && commitmentWires[nbCommitmentsSeen] == i { + isCommitment = true + nbCommitmentsSeen++ + } + } + commitment := -1 // index of the commitment that commits to this variable as a private or commitment value + + if !isPublic { + for j := range r1cs.CommitmentInfo { + if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { + commitment = j + cI[j]-- + if isCommitment { + nbCommitToCommit[j]++ + } else { + break + } + } + } + } - if isPublic || isCommittedPrivate || isCommitment { + if isPublic || commitment != -1 || isCommitment { computeK(i, &toxicWaste.gammaInv) - if isCommittedPrivate { - ckK[cI] = t1 - cI++ - } else { + if isPublic || isCommitment { vkK[vI] = t1 vI++ + } else { // committed and private + ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]-1] = t1 + nbPrivateCommittedSeen++ } } else { computeK(i, &toxicWaste.deltaInv) - pkK[i-vI-cI] = t1 + pkK[i-vI-nbPrivateCommittedSeen] = t1 // vI = nbPublicSeen + nbCommitmentsSeen } } @@ -229,7 +286,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { g1Scalars = append(g1Scalars, Z...) g1Scalars = append(g1Scalars, vkK...) g1Scalars = append(g1Scalars, pkK...) - g1Scalars = append(g1Scalars, ckK...) + for i := range ckK { + g1Scalars = append(g1Scalars, ckK[i]...) + } g1PointsAff := curve.BatchScalarMultiplicationG1(&g1, g1Scalars) @@ -262,7 +321,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { commitmentBases := make([][]curve.G1Affine, len(r1cs.CommitmentInfo)) for i := range commitmentBases { - size := r1cs.CommitmentInfo[i].NbPrivateCommitted + size := len(ckK[i]) commitmentBases[i] = g1PointsAff[offset : offset+size] offset += size } diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl index 84fa6d9fd0..a4ca0cf971 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl @@ -7,6 +7,7 @@ import ( {{- template "import_pedersen" .}} "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/internal/utils" "math/big" "math/bits" ) @@ -77,16 +78,29 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbPrivateCommittedWires := 0 - if r1cs.GetNbCommitments() != 0 { - nbPrivateCommittedWires = r1cs.CommitmentInfo[0].NbPrivateCommitted + commitmentWires := make([]int, len(r1cs.CommitmentInfo)) + privateCommitted := make([][]int, len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + nbPrivateCommittedWires += r1cs.CommitmentInfo[i].NbPrivateCommitted + privateCommitted[i] = r1cs.CommitmentInfo[i].PrivateCommitted() + commitmentWires[i] = r1cs.CommitmentInfo[i].CommitmentIndex } - nbPublicWires := r1cs.GetNbPublicVariables() - nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - if r1cs.GetNbCommitments() != 0 { // the commitment itself is defined by a hint so the prover considers it private - nbPublicWires++ // but the verifier will need to inject the value itself so on the groth16 - nbPrivateWires-- // level it must be considered public + // a commitment is itself defined by a hint so the prover considers it private + // but the verifier will need to inject the value itself so on the groth16 + // level it must be considered public + nbPublicWires := r1cs.GetNbPublicVariables() + len(r1cs.CommitmentInfo) + nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(r1cs.CommitmentInfo) + + // we will need to iterate through the private-to-public wires in order + /*privToPub := make([], nbPrivateCommittedWires+len(r1cs.CommitmentInfo)) + offset := 0 + for i := range r1cs.CommitmentInfo { + copy(privToPub[offset:], r1cs.CommitmentInfo[i].PrivateCommitted()) // TODO Take out commitments + offset += r1cs.CommitmentInfo[i].NbPrivateCommitted } + privToPub.Heapify() + */ // Setting group for fft domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) @@ -123,7 +137,19 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // compute scalars for pkK, vkK and ckK pkK := make([]fr.Element, nbPrivateWires) vkK := make([]fr.Element, nbPublicWires) - ckK := make([]fr.Element, nbPrivateCommittedWires) + ckK := make([][]fr.Element, len(r1cs.CommitmentInfo)) + + // see if i commits to j + for i := range r1cs.CommitmentInfo { + commitmentCommitments := 0 + + for j := 0; j < i; j++ { + if found, _ := utils.BinarySearch(privateCommitted[i], r1cs.CommitmentInfo[j].CommitmentIndex); found { + commitmentCommitments++ + } + } + ckK[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-commitmentCommitments) + } var t0, t1 fr.Element @@ -134,31 +160,62 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Add(&t1, &C[i]). Mul(&t1, coeff) } - - vI, cI := 0, 0 - var privateCommitted []int - if r1cs.GetNbCommitments() != 0 { - privateCommitted = r1cs.CommitmentInfo[0].PrivateCommitted() + vI := 0 + cI := make([]int, len(r1cs.CommitmentInfo)) + nbCommitToCommit := make([]int, len(r1cs.CommitmentInfo)) + nbPrivateCommittedSeen := 0 + nbCommitmentsSeen := 0 + + /* for j := range r1cs.CommitmentInfo { // skip commitments to commitments + k := 0 + l := 0 + for ; k < len(privateCommitted[j]); k++ { + for ; l < len(commitmentWires) && commitmentWires[l] < privateCommitted[j][k]; l++ {} + if k != l { + break + } + } + cI[j] = k } + copy(nbCommitToCommit, cI)*/ for i := range A { - isCommittedPrivate := cI < len(privateCommitted) && i == privateCommitted[cI] - isCommitment := r1cs.GetNbCommitments() != 0 && i == r1cs.CommitmentInfo[0].CommitmentIndex - isPublic := i < r1cs.GetNbPublicVariables() + var isCommitment, isPublic bool + if isPublic = i < r1cs.GetNbPublicVariables(); !isPublic { + if nbCommitmentsSeen < len(commitmentWires) && commitmentWires[nbCommitmentsSeen] == i { + isCommitment = true + nbCommitmentsSeen++ + } + } + commitment := -1 // index of the commitment that commits to this variable as a private or commitment value + + if !isPublic { + for j := range r1cs.CommitmentInfo { + if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { + commitment = j + cI[j]-- + if isCommitment { + nbCommitToCommit[j]++ + } else { + break + } + } + } + } - if isPublic || isCommittedPrivate || isCommitment { + if isPublic || commitment != -1 || isCommitment { computeK(i, &toxicWaste.gammaInv) - if isCommittedPrivate { - ckK[cI] = t1 - cI++ - } else { + if isPublic || isCommitment { vkK[vI] = t1 vI++ + } else { // committed and private + ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]-1] = t1 + nbPrivateCommittedSeen++ } } else { computeK(i, &toxicWaste.deltaInv) - pkK[i-vI-cI] = t1 + pkK[i-vI-nbPrivateCommittedSeen] = t1 // vI = nbPublicSeen + nbCommitmentsSeen } } @@ -211,7 +268,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { g1Scalars = append(g1Scalars, Z...) g1Scalars = append(g1Scalars, vkK...) g1Scalars = append(g1Scalars, pkK...) - g1Scalars = append(g1Scalars, ckK...) + for i := range ckK { + g1Scalars = append(g1Scalars, ckK[i]...) + } g1PointsAff := curve.BatchScalarMultiplicationG1(&g1, g1Scalars) @@ -244,7 +303,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { commitmentBases := make([][]curve.G1Affine, len(r1cs.CommitmentInfo)) for i := range commitmentBases { - size := r1cs.CommitmentInfo[i].NbPrivateCommitted + size := len(ckK[i]) commitmentBases[i] = g1PointsAff[offset : offset+size] offset += size } From f0dfa30cf7360ef8e4131dfe0409d0cce8ea4253 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 26 May 2023 13:43:40 -0500 Subject: [PATCH 399/464] refactor: eliminate GetNbCommitments --- backend/groth16/bls12-377/setup.go | 4 +--- backend/groth16/bls12-381/setup.go | 4 +--- backend/groth16/bls24-315/setup.go | 4 +--- backend/groth16/bls24-317/setup.go | 4 +--- backend/groth16/bn254/setup.go | 4 +--- backend/groth16/bw6-633/setup.go | 4 +--- backend/groth16/bw6-761/setup.go | 4 +--- frontend/cs/scs/api.go | 2 +- .../backend/template/zkpschemes/groth16/groth16.setup.go.tmpl | 4 +--- 9 files changed, 9 insertions(+), 25 deletions(-) diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index 8e6f145829..058b63b0f6 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -198,16 +198,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { copy(nbCommitToCommit, cI)*/ for i := range A { + commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool if isPublic = i < r1cs.GetNbPublicVariables(); !isPublic { if nbCommitmentsSeen < len(commitmentWires) && commitmentWires[nbCommitmentsSeen] == i { isCommitment = true nbCommitmentsSeen++ } - } - commitment := -1 // index of the commitment that commits to this variable as a private or commitment value - if !isPublic { for j := range r1cs.CommitmentInfo { if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index 1dd7874fb7..63743698c5 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -198,16 +198,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { copy(nbCommitToCommit, cI)*/ for i := range A { + commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool if isPublic = i < r1cs.GetNbPublicVariables(); !isPublic { if nbCommitmentsSeen < len(commitmentWires) && commitmentWires[nbCommitmentsSeen] == i { isCommitment = true nbCommitmentsSeen++ } - } - commitment := -1 // index of the commitment that commits to this variable as a private or commitment value - if !isPublic { for j := range r1cs.CommitmentInfo { if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index ebee0f0ff1..e7f5c5bfb6 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -198,16 +198,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { copy(nbCommitToCommit, cI)*/ for i := range A { + commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool if isPublic = i < r1cs.GetNbPublicVariables(); !isPublic { if nbCommitmentsSeen < len(commitmentWires) && commitmentWires[nbCommitmentsSeen] == i { isCommitment = true nbCommitmentsSeen++ } - } - commitment := -1 // index of the commitment that commits to this variable as a private or commitment value - if !isPublic { for j := range r1cs.CommitmentInfo { if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index 60c4550c6a..4631fc468d 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -198,16 +198,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { copy(nbCommitToCommit, cI)*/ for i := range A { + commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool if isPublic = i < r1cs.GetNbPublicVariables(); !isPublic { if nbCommitmentsSeen < len(commitmentWires) && commitmentWires[nbCommitmentsSeen] == i { isCommitment = true nbCommitmentsSeen++ } - } - commitment := -1 // index of the commitment that commits to this variable as a private or commitment value - if !isPublic { for j := range r1cs.CommitmentInfo { if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index 3896db0424..2ad7c294fd 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -198,16 +198,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { copy(nbCommitToCommit, cI)*/ for i := range A { + commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool if isPublic = i < r1cs.GetNbPublicVariables(); !isPublic { if nbCommitmentsSeen < len(commitmentWires) && commitmentWires[nbCommitmentsSeen] == i { isCommitment = true nbCommitmentsSeen++ } - } - commitment := -1 // index of the commitment that commits to this variable as a private or commitment value - if !isPublic { for j := range r1cs.CommitmentInfo { if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index 530909ff48..d886c30023 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -198,16 +198,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { copy(nbCommitToCommit, cI)*/ for i := range A { + commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool if isPublic = i < r1cs.GetNbPublicVariables(); !isPublic { if nbCommitmentsSeen < len(commitmentWires) && commitmentWires[nbCommitmentsSeen] == i { isCommitment = true nbCommitmentsSeen++ } - } - commitment := -1 // index of the commitment that commits to this variable as a private or commitment value - if !isPublic { for j := range r1cs.CommitmentInfo { if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index 8b2fa2e5ba..8732589a92 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -198,16 +198,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { copy(nbCommitToCommit, cI)*/ for i := range A { + commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool if isPublic = i < r1cs.GetNbPublicVariables(); !isPublic { if nbCommitmentsSeen < len(commitmentWires) && commitmentWires[nbCommitmentsSeen] == i { isCommitment = true nbCommitmentsSeen++ } - } - commitment := -1 // index of the commitment that commits to this variable as a private or commitment value - if !isPublic { for j := range r1cs.CommitmentInfo { if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j diff --git a/frontend/cs/scs/api.go b/frontend/cs/scs/api.go index 63c5ec2566..20d5740c94 100644 --- a/frontend/cs/scs/api.go +++ b/frontend/cs/scs/api.go @@ -583,7 +583,7 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error builder.addPlonkConstraint(sparseR1C{xa: vINeg.VID, qL: vINeg.Coeff, commitment: constraint.COMMITTED}) } - hintId, err := cs.RegisterBsb22CommitmentComputePlaceholder(builder.cs.GetNbCommitments()) + hintId, err := cs.RegisterBsb22CommitmentComputePlaceholder(len(builder.cs.GetCommitments())) if err != nil { return nil, err } diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl index a4ca0cf971..24eac42d33 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl @@ -180,16 +180,14 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { copy(nbCommitToCommit, cI)*/ for i := range A { + commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool if isPublic = i < r1cs.GetNbPublicVariables(); !isPublic { if nbCommitmentsSeen < len(commitmentWires) && commitmentWires[nbCommitmentsSeen] == i { isCommitment = true nbCommitmentsSeen++ } - } - commitment := -1 // index of the commitment that commits to this variable as a private or commitment value - if !isPublic { for j := range r1cs.CommitmentInfo { if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j From a5ea0bf9568dddc6578d5e97accc4b5309eabe32 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 26 May 2023 13:51:46 -0500 Subject: [PATCH 400/464] fix: single commits work for bn254 --- backend/groth16/bls12-377/setup.go | 4 ++-- backend/groth16/bls12-381/setup.go | 4 ++-- backend/groth16/bls24-315/setup.go | 4 ++-- backend/groth16/bls24-317/setup.go | 4 ++-- backend/groth16/bn254/setup.go | 4 ++-- backend/groth16/bw6-633/setup.go | 4 ++-- backend/groth16/bw6-761/setup.go | 4 ++-- .../template/zkpschemes/groth16/groth16.setup.go.tmpl | 4 ++-- test/commitments_test.go | 9 +++++---- test/end_to_end.go | 2 +- 10 files changed, 22 insertions(+), 21 deletions(-) diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index 058b63b0f6..d57dd8ce0f 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -209,7 +209,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { for j := range r1cs.CommitmentInfo { if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j - cI[j]-- if isCommitment { nbCommitToCommit[j]++ } else { @@ -226,7 +225,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vkK[vI] = t1 vI++ } else { // committed and private - ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]-1] = t1 + ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]] = t1 + cI[commitment]++ nbPrivateCommittedSeen++ } } else { diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index 63743698c5..27dc11fc1c 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -209,7 +209,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { for j := range r1cs.CommitmentInfo { if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j - cI[j]-- if isCommitment { nbCommitToCommit[j]++ } else { @@ -226,7 +225,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vkK[vI] = t1 vI++ } else { // committed and private - ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]-1] = t1 + ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]] = t1 + cI[commitment]++ nbPrivateCommittedSeen++ } } else { diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index e7f5c5bfb6..b42f52943d 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -209,7 +209,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { for j := range r1cs.CommitmentInfo { if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j - cI[j]-- if isCommitment { nbCommitToCommit[j]++ } else { @@ -226,7 +225,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vkK[vI] = t1 vI++ } else { // committed and private - ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]-1] = t1 + ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]] = t1 + cI[commitment]++ nbPrivateCommittedSeen++ } } else { diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index 4631fc468d..174a768b1e 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -209,7 +209,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { for j := range r1cs.CommitmentInfo { if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j - cI[j]-- if isCommitment { nbCommitToCommit[j]++ } else { @@ -226,7 +225,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vkK[vI] = t1 vI++ } else { // committed and private - ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]-1] = t1 + ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]] = t1 + cI[commitment]++ nbPrivateCommittedSeen++ } } else { diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index 2ad7c294fd..6797de36cd 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -209,7 +209,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { for j := range r1cs.CommitmentInfo { if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j - cI[j]-- if isCommitment { nbCommitToCommit[j]++ } else { @@ -226,7 +225,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vkK[vI] = t1 vI++ } else { // committed and private - ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]-1] = t1 + ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]] = t1 + cI[commitment]++ nbPrivateCommittedSeen++ } } else { diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index d886c30023..e2cffe1329 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -209,7 +209,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { for j := range r1cs.CommitmentInfo { if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j - cI[j]-- if isCommitment { nbCommitToCommit[j]++ } else { @@ -226,7 +225,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vkK[vI] = t1 vI++ } else { // committed and private - ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]-1] = t1 + ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]] = t1 + cI[commitment]++ nbPrivateCommittedSeen++ } } else { diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index 8732589a92..93c7c13df9 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -209,7 +209,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { for j := range r1cs.CommitmentInfo { if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j - cI[j]-- if isCommitment { nbCommitToCommit[j]++ } else { @@ -226,7 +225,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vkK[vI] = t1 vI++ } else { // committed and private - ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]-1] = t1 + ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]] = t1 + cI[commitment]++ nbPrivateCommittedSeen++ } } else { diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl index 24eac42d33..eeafdeda6e 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl @@ -191,7 +191,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { for j := range r1cs.CommitmentInfo { if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j - cI[j]-- if isCommitment { nbCommitToCommit[j]++ } else { @@ -208,7 +207,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vkK[vI] = t1 vI++ } else { // committed and private - ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]-1] = t1 + ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]] = t1 + cI[commitment]++ nbPrivateCommittedSeen++ } } else { diff --git a/test/commitments_test.go b/test/commitments_test.go index 0393696331..a8f65cd843 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -138,10 +138,11 @@ func (c *independentCommitsCircuit) Define(api frontend.API) error { return nil } -func TestTwoIndependentCommitsGroth16(t *testing.T) { - testGroth16(t, &independentCommitsCircuit{X: []frontend.Variable{1, 2}}) -} - +/* + func TestTwoIndependentCommitsGroth16(t *testing.T) { + testGroth16(t, &independentCommitsCircuit{X: []frontend.Variable{1, 2}}) + } +*/ func TestHollow(t *testing.T) { run := func(c, expected frontend.Circuit) func(t *testing.T) { diff --git a/test/end_to_end.go b/test/end_to_end.go index 96c042d3b3..794b2debc8 100644 --- a/test/end_to_end.go +++ b/test/end_to_end.go @@ -16,7 +16,7 @@ import ( "testing" ) -const onlyGroth16Bn254 = true // TODO remove +const onlyGroth16Bn254 = false // TODO remove var fr = []ecc.ID{ ecc.BN254, From 15e784db3486d879ceaab1a41fea8877e517e4de Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 26 May 2023 15:55:26 -0500 Subject: [PATCH 401/464] fix: using loop counter in lambda --- backend/groth16/bn254/commitment.go | 2 ++ backend/groth16/bn254/prove.go | 24 ++++++++++++++---------- backend/groth16/bn254/utils_test.go | 9 ++++++++- test/commitments_test.go | 28 ++++++++++++++++++++-------- test/end_to_end.go | 2 +- 5 files changed, 45 insertions(+), 20 deletions(-) diff --git a/backend/groth16/bn254/commitment.go b/backend/groth16/bn254/commitment.go index 435a7c058c..4a6048f6f1 100644 --- a/backend/groth16/bn254/commitment.go +++ b/backend/groth16/bn254/commitment.go @@ -17,6 +17,7 @@ package groth16 import ( + "fmt" curve "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark/constraint" @@ -25,5 +26,6 @@ import ( func solveCommitmentWire(commitment *curve.G1Affine, publicCommitted []*big.Int) (fr.Element, error) { res, err := fr.Hash(constraint.SerializeCommitment(commitment.Marshal(), publicCommitted, (fr.Bits-1)/8+1), []byte(constraint.CommitmentDst), 1) + fmt.Println("commitment", res[0].Text(16)) return res[0], err } diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index 665cb03bcd..cace9e09e4 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -17,7 +17,6 @@ package groth16 import ( - "fmt" "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr" @@ -69,24 +68,26 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b privateCommitted := make([][]fr.Element, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { + commitmentInfo := &r1cs.CommitmentInfo[i] + privateCommitted[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) + privateCommittedI := privateCommitted[i] + commitmentOut := &proof.Commitments[i] + commitmentKey := pk.CommitmentKeys[i] + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { - if len(in) != r1cs.CommitmentInfo[i].NbCommitted() { // TODO: Remove - return fmt.Errorf("unexpected number of committed variables") - } - privateCommitted[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) - nbPublicCommitted := len(in) - len(privateCommitted[i]) + nbPublicCommitted := len(in) - len(privateCommittedI) inPrivate := in[nbPublicCommitted:] for j, inJ := range inPrivate { - privateCommitted[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead + privateCommittedI[j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead } var err error - if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(privateCommitted[i]); err != nil { + if *commitmentOut, err = commitmentKey.Commit(privateCommittedI); err != nil { return err } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitments[i], in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) + res, err = solveCommitmentWire(commitmentOut, in[:commitmentInfo.NbPublicCommitted()]) res.BigInt(out[0]) return err })) @@ -213,6 +214,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed _wireValues := wireValues + for i := range r1cs.CommitmentInfo { _wireValues = filter(_wireValues, r1cs.CommitmentInfo[i].PrivateToPublicGroth16()) } @@ -311,7 +313,9 @@ func filter(slice []fr.Element, toRemove []int) (r []fr.Element) { // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) for i := 0; i < len(slice); i++ { if j < len(toRemove) && i == toRemove[j] { - j++ + for j < len(toRemove) && i == toRemove[j] { + j++ + } continue } r = append(r, slice[i]) diff --git a/backend/groth16/bn254/utils_test.go b/backend/groth16/bn254/utils_test.go index 4552aa5e37..e3f547c16c 100644 --- a/backend/groth16/bn254/utils_test.go +++ b/backend/groth16/bn254/utils_test.go @@ -14,9 +14,16 @@ func assertSliceEquals[T any](t *testing.T, expected []T, seen []T) { } } -func TestRemoveIndex(t *testing.T) { +func TestFilter(t *testing.T) { elems := []fr.Element{{0}, {1}, {2}, {3}} r := filter(elems, []int{1, 2}) expected := []fr.Element{{0}, {3}} assertSliceEquals(t, expected, r) } + +func TestFilterRepeated(t *testing.T) { + elems := []fr.Element{{0}, {1}, {2}, {3}} + r := filter(elems, []int{1, 1, 2}) + expected := []fr.Element{{0}, {3}} + assertSliceEquals(t, expected, r) +} diff --git a/test/commitments_test.go b/test/commitments_test.go index a8f65cd843..a50b9e9dd0 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -34,10 +34,14 @@ func (c *commitmentCircuit) Define(api frontend.API) error { if err != nil { return err } - api.AssertIsDifferent(commitment, c.X[0]) + sum := frontend.Variable(0) + for i, x := range c.X { + sum = api.Add(sum, api.Mul(x, i+1)) + } for _, p := range c.Public { - api.AssertIsDifferent(p, 0) + sum = api.Add(sum, p) } + api.AssertIsDifferent(commitment, sum) return err } @@ -46,6 +50,11 @@ func TestSingleCommitment(t *testing.T) { testAll(t, assignment) } +func TestTwoCommitments(t *testing.T) { + assignment := &commitmentCircuit{X: []frontend.Variable{1, 2}, Public: []frontend.Variable{}} + testAll(t, assignment) +} + func TestFiveCommitments(t *testing.T) { assignment := &commitmentCircuit{X: []frontend.Variable{1, 2, 3, 4, 5}, Public: []frontend.Variable{}} testAll(t, assignment) @@ -128,21 +137,24 @@ type independentCommitsCircuit struct { func (c *independentCommitsCircuit) Define(api frontend.API) error { committer := api.(frontend.Committer) + /*var ( + ch []frontend.Variable + err error + )*/ for i := range c.X { if ch, err := committer.Commit(c.X[i]); err != nil { return err } else { - api.AssertIsDifferent(ch, 0) + api.AssertIsDifferent(ch, c.X[i]) } } return nil } -/* - func TestTwoIndependentCommitsGroth16(t *testing.T) { - testGroth16(t, &independentCommitsCircuit{X: []frontend.Variable{1, 2}}) - } -*/ +func TestTwoIndependentCommitsGroth16(t *testing.T) { + testGroth16(t, &independentCommitsCircuit{X: []frontend.Variable{1, 1}}) +} + func TestHollow(t *testing.T) { run := func(c, expected frontend.Circuit) func(t *testing.T) { diff --git a/test/end_to_end.go b/test/end_to_end.go index 794b2debc8..96c042d3b3 100644 --- a/test/end_to_end.go +++ b/test/end_to_end.go @@ -16,7 +16,7 @@ import ( "testing" ) -const onlyGroth16Bn254 = false // TODO remove +const onlyGroth16Bn254 = true // TODO remove var fr = []ecc.ID{ ecc.BN254, From 590196cd35f3639a340dcc8bfea32278d3576146 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Mon, 29 May 2023 14:16:48 +0100 Subject: [PATCH 402/464] perf(2-chain/varScalarMul): use DoubleAndAdd to reduce #constraints --- std/algebra/native/sw_bls12377/g1.go | 6 ++---- std/algebra/native/sw_bls12377/g2.go | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/std/algebra/native/sw_bls12377/g1.go b/std/algebra/native/sw_bls12377/g1.go index f3a7de0a85..546fd19857 100644 --- a/std/algebra/native/sw_bls12377/g1.go +++ b/std/algebra/native/sw_bls12377/g1.go @@ -300,20 +300,18 @@ func (P *G1Affine) varScalarMul(api frontend.API, Q G1Affine, s frontend.Variabl // step value from [2] Acc (instead of conditionally adding step value to // Acc): // Acc = [2] (Q + Φ(Q)) ± Q ± Φ(Q) - Acc.Double(api, Acc) // only y coordinate differs for negation, select on that instead. B.X = tableQ[0].X B.Y = api.Select(s1bits[nbits-1], tableQ[1].Y, tableQ[0].Y) - Acc.AddAssign(api, B) + Acc.DoubleAndAdd(api, &Acc, &B) B.X = tablePhiQ[0].X B.Y = api.Select(s2bits[nbits-1], tablePhiQ[1].Y, tablePhiQ[0].Y) Acc.AddAssign(api, B) // second bit - Acc.Double(api, Acc) B.X = tableQ[0].X B.Y = api.Select(s1bits[nbits-2], tableQ[1].Y, tableQ[0].Y) - Acc.AddAssign(api, B) + Acc.DoubleAndAdd(api, &Acc, &B) B.X = tablePhiQ[0].X B.Y = api.Select(s2bits[nbits-2], tablePhiQ[1].Y, tablePhiQ[0].Y) Acc.AddAssign(api, B) diff --git a/std/algebra/native/sw_bls12377/g2.go b/std/algebra/native/sw_bls12377/g2.go index 7d0152f753..64fdf9e87f 100644 --- a/std/algebra/native/sw_bls12377/g2.go +++ b/std/algebra/native/sw_bls12377/g2.go @@ -315,20 +315,18 @@ func (P *G2Affine) varScalarMul(api frontend.API, Q G2Affine, s frontend.Variabl // step value from [2] Acc (instead of conditionally adding step value to // Acc): // Acc = [2] (Q + Φ(Q)) ± Q ± Φ(Q) - Acc.Double(api, Acc) // only y coordinate differs for negation, select on that instead. B.X = tableQ[0].X B.Y.Select(api, s1bits[nbits-1], tableQ[1].Y, tableQ[0].Y) - Acc.AddAssign(api, B) + Acc.DoubleAndAdd(api, &Acc, &B) B.X = tablePhiQ[0].X B.Y.Select(api, s2bits[nbits-1], tablePhiQ[1].Y, tablePhiQ[0].Y) Acc.AddAssign(api, B) // second bit - Acc.Double(api, Acc) B.X = tableQ[0].X B.Y.Select(api, s1bits[nbits-2], tableQ[1].Y, tableQ[0].Y) - Acc.AddAssign(api, B) + Acc.DoubleAndAdd(api, &Acc, &B) B.X = tablePhiQ[0].X B.Y.Select(api, s2bits[nbits-2], tablePhiQ[1].Y, tablePhiQ[0].Y) Acc.AddAssign(api, B) From 043fc45cf6c2a0c2c78df6b849c6c7c7153ae6a2 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Mon, 29 May 2023 16:59:52 +0100 Subject: [PATCH 403/464] perf(2-chain/varScalarMul): DoubleAndAdd to reduce #constraints BLS24 --- std/algebra/native/sw_bls24315/g1.go | 6 ++---- std/algebra/native/sw_bls24315/g2.go | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/std/algebra/native/sw_bls24315/g1.go b/std/algebra/native/sw_bls24315/g1.go index 418f4f9352..61cda042ff 100644 --- a/std/algebra/native/sw_bls24315/g1.go +++ b/std/algebra/native/sw_bls24315/g1.go @@ -299,20 +299,18 @@ func (P *G1Affine) varScalarMul(api frontend.API, Q G1Affine, s frontend.Variabl // step value from [2] Acc (instead of conditionally adding step value to // Acc): // Acc = [2] (Q + Φ(Q)) ± Q ± Φ(Q) - Acc.Double(api, Acc) // only y coordinate differs for negation, select on that instead. B.X = tableQ[0].X B.Y = api.Select(s1bits[nbits-1], tableQ[1].Y, tableQ[0].Y) - Acc.AddAssign(api, B) + Acc.DoubleAndAdd(api, &Acc, &B) B.X = tablePhiQ[0].X B.Y = api.Select(s2bits[nbits-1], tablePhiQ[1].Y, tablePhiQ[0].Y) Acc.AddAssign(api, B) // second bit - Acc.Double(api, Acc) B.X = tableQ[0].X B.Y = api.Select(s1bits[nbits-2], tableQ[1].Y, tableQ[0].Y) - Acc.AddAssign(api, B) + Acc.DoubleAndAdd(api, &Acc, &B) B.X = tablePhiQ[0].X B.Y = api.Select(s2bits[nbits-2], tablePhiQ[1].Y, tablePhiQ[0].Y) Acc.AddAssign(api, B) diff --git a/std/algebra/native/sw_bls24315/g2.go b/std/algebra/native/sw_bls24315/g2.go index 7997060144..cd5dc9d064 100644 --- a/std/algebra/native/sw_bls24315/g2.go +++ b/std/algebra/native/sw_bls24315/g2.go @@ -314,20 +314,18 @@ func (P *G2Affine) varScalarMul(api frontend.API, Q G2Affine, s frontend.Variabl // step value from [2] Acc (instead of conditionally adding step value to // Acc): // Acc = [2] (Q + Φ(Q)) ± Q ± Φ(Q) - Acc.Double(api, Acc) // only y coordinate differs for negation, select on that instead. B.X = tableQ[0].X B.Y.Select(api, s1bits[nbits-1], tableQ[1].Y, tableQ[0].Y) - Acc.AddAssign(api, B) + Acc.DoubleAndAdd(api, &Acc, &B) B.X = tablePhiQ[0].X B.Y.Select(api, s2bits[nbits-1], tablePhiQ[1].Y, tablePhiQ[0].Y) Acc.AddAssign(api, B) // second bit - Acc.Double(api, Acc) B.X = tableQ[0].X B.Y.Select(api, s1bits[nbits-2], tableQ[1].Y, tableQ[0].Y) - Acc.AddAssign(api, B) + Acc.DoubleAndAdd(api, &Acc, &B) B.X = tablePhiQ[0].X B.Y.Select(api, s2bits[nbits-2], tablePhiQ[1].Y, tablePhiQ[0].Y) Acc.AddAssign(api, B) From 10ff3894aa944d76e00b89989b82a1a9a4096c6d Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 30 May 2023 15:11:16 -0500 Subject: [PATCH 404/464] feat: filterHeap for unsorted lists --- backend/groth16/bn254/prove.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index cace9e09e4..056fbac3fc 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -324,6 +324,35 @@ func filter(slice []fr.Element, toRemove []int) (r []fr.Element) { return r } +// if len(toRemove) == 0, returns slice +// else, returns a new slice without the indexes in toRemove +// this assumes toRemove indexes are sorted and len(slice) > len(toRemove) +// filterHeap modifies toRemove +func filterHeap(slice []fr.Element, toRemove []int) (r []fr.Element) { + + if len(toRemove) == 0 { + return slice + } + + heap := utils.IntHeap(toRemove) + heap.Heapify() + + r = make([]fr.Element, 0, len(slice)-len(toRemove)) + + // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) + for i := 0; i < len(slice); i++ { + if len(heap) > 0 && i == heap[0] { + for len(heap) > 0 && i == heap[0] { + heap.Pop() + } + continue + } + r = append(r, slice[i]) + } + + return +} + func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { // H part of Krs // Compute H (hz=ab-c, where z=-2 on ker X^n+1 (z(x)=x^n-1)) From 1049da48535f78c21b13a6c2a0e3bf54998fd4e6 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 30 May 2023 16:31:20 -0500 Subject: [PATCH 405/464] fix: two indep commitments work for bn254 --- backend/groth16/bn254/prove.go | 8 ++------ constraint/commitment.go | 18 ++++++++++++++++++ constraint/core.go | 2 +- test/end_to_end.go | 5 +++++ 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index 056fbac3fc..a16ec8f492 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -213,11 +213,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed - _wireValues := wireValues - - for i := range r1cs.CommitmentInfo { - _wireValues = filter(_wireValues, r1cs.CommitmentInfo[i].PrivateToPublicGroth16()) - } + _wireValues := filterHeap(wireValues, r1cs.CommitmentInfo.CommitmentsAndPrivateCommittedIndexes()) if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err @@ -337,7 +333,7 @@ func filterHeap(slice []fr.Element, toRemove []int) (r []fr.Element) { heap := utils.IntHeap(toRemove) heap.Heapify() - r = make([]fr.Element, 0, len(slice)-len(toRemove)) + r = make([]fr.Element, 0, len(slice)) // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) for i := 0; i < len(slice); i++ { diff --git a/constraint/commitment.go b/constraint/commitment.go index 4291869541..add98504b1 100644 --- a/constraint/commitment.go +++ b/constraint/commitment.go @@ -15,6 +15,8 @@ type Commitment struct { CommitmentIndex int // in groth16, CommitmentIndex is the wire index. in plonk, it's the constraint defining it } +type Commitments []Commitment + func (i *Commitment) NbPublicCommitted() int { return i.NbCommitted() - i.NbPrivateCommitted } @@ -71,3 +73,19 @@ func CommitmentIndexes(commitments []Commitment) []uint64 { } return res } + +func (c Commitments) CommitmentsAndPrivateCommittedIndexes() []int { + nbCommitmentAndPrivCommitted := len(c) // an upper bound + for i := range c { + nbCommitmentAndPrivCommitted += c[i].NbPrivateCommitted + } + res := make([]int, nbCommitmentAndPrivCommitted) + offset := 0 + for i := range c { + copy(res[offset:], c[i].PrivateCommitted()) + offset += c[i].NbPrivateCommitted + res[offset] = c[i].CommitmentIndex + offset++ + } + return res +} diff --git a/constraint/core.go b/constraint/core.go index 7efb6192f2..c3291f6404 100644 --- a/constraint/core.go +++ b/constraint/core.go @@ -124,7 +124,7 @@ type System struct { lbWireLevel []int `cbor:"-"` // at which level we solve a wire. init at -1. lbOutputs []uint32 `cbor:"-"` // wire outputs for current constraint. - CommitmentInfo []Commitment + CommitmentInfo Commitments genericHint BlueprintID } diff --git a/test/end_to_end.go b/test/end_to_end.go index 96c042d3b3..c66895a39d 100644 --- a/test/end_to_end.go +++ b/test/end_to_end.go @@ -63,6 +63,11 @@ func testPlonk(t *testing.T, assignment frontend.Circuit) { } func testGroth16(t *testing.T, assignment frontend.Circuit) { + + if onlyGroth16Bn254 { + fr = []ecc.ID{ecc.BN254} + } + circuit := hollow(assignment) run := func(mod *big.Int) func(*testing.T) { return func(t *testing.T) { From 319daca189c9286d741b283aa7a87cb0badf3e83 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 30 May 2023 18:32:14 -0500 Subject: [PATCH 406/464] fix: attempt at commitment hint input filtering --- backend/groth16/bn254/commitment.go | 1 + backend/groth16/bn254/prove.go | 51 +++++++++++++++-------------- backend/groth16/bn254/setup.go | 29 ++++++---------- backend/groth16/bn254/utils_test.go | 6 ++-- backend/groth16/internal/utils.go | 23 +++++++++++++ constraint/commitment.go | 47 +++++++++++++++++++++++--- test/commitments_test.go | 16 +++------ test/end_to_end.go | 5 --- 8 files changed, 110 insertions(+), 68 deletions(-) create mode 100644 backend/groth16/internal/utils.go diff --git a/backend/groth16/bn254/commitment.go b/backend/groth16/bn254/commitment.go index 4a6048f6f1..df390bc38c 100644 --- a/backend/groth16/bn254/commitment.go +++ b/backend/groth16/bn254/commitment.go @@ -25,6 +25,7 @@ import ( ) func solveCommitmentWire(commitment *curve.G1Affine, publicCommitted []*big.Int) (fr.Element, error) { + fmt.Println("len(pubCom)=", len(publicCommitted)) res, err := fr.Hash(constraint.SerializeCommitment(commitment.Marshal(), publicCommitted, (fr.Bits-1)/8+1), []byte(constraint.CommitmentDst), 1) fmt.Println("commitment", res[0].Text(16)) return res[0], err diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index a16ec8f492..366e0d7d62 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -23,6 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" "github.com/consensys/gnark-crypto/ecc/bn254/fr/pedersen" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint/bn254" "github.com/consensys/gnark/constraint/solver" @@ -66,28 +67,29 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - privateCommitted := make([][]fr.Element, len(r1cs.CommitmentInfo)) + commitmentSubIndexes := r1cs.CommitmentInfo.CommitmentIndexesInCommittedLists() + privateCommittedValues := make([][]fr.Element, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { - commitmentInfo := &r1cs.CommitmentInfo[i] - privateCommitted[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) - privateCommittedI := privateCommitted[i] + nbPublicI := r1cs.CommitmentInfo[i].NbPublicCommitted() + commitmentSubIndexesI := commitmentSubIndexes[i] + privateCommittedValues[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-len(commitmentSubIndexesI)) + privateCommittedValuesI := privateCommittedValues[i] commitmentOut := &proof.Commitments[i] commitmentKey := pk.CommitmentKeys[i] solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { - nbPublicCommitted := len(in) - len(privateCommittedI) - inPrivate := in[nbPublicCommitted:] - for j, inJ := range inPrivate { - privateCommittedI[j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead + committed, hashed := internal.DivideByThresholdOrList(nbPublicI, commitmentSubIndexesI, in) + for j, inJ := range committed { + privateCommittedValuesI[j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead } var err error - if *commitmentOut, err = commitmentKey.Commit(privateCommittedI); err != nil { + if *commitmentOut, err = commitmentKey.Commit(privateCommittedValuesI); err != nil { return err } var res fr.Element - res, err = solveCommitmentWire(commitmentOut, in[:commitmentInfo.NbPublicCommitted()]) + res, err = solveCommitmentWire(commitmentOut, hashed) res.BigInt(out[0]) return err })) @@ -108,7 +110,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b copy(commitmentsSerialized[fr.Bytes*i:], wireValues[r1cs.CommitmentInfo[i].CommitmentIndex].Marshal()) } - if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, commitmentsSerialized); err != nil { + if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommittedValues, commitmentsSerialized); err != nil { return nil, err } @@ -295,29 +297,28 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return proof, nil } -// if len(toRemove) == 0, returns slice -// else, returns a new slice without the indexes in toRemove -// this assumes toRemove indexes are sorted and len(slice) > len(toRemove) -func filter(slice []fr.Element, toRemove []int) (r []fr.Element) { +// if len(indexes) == 0, returns slice, nil +// else, returns a slice with the indexes and another without +// this assumes the indexes are sorted, without repetition and that len(slice) > len(indexes) +func split(slice []*big.Int, indexes []int) (with, without []*big.Int) { - if len(toRemove) == 0 { - return slice + if len(indexes) == 0 { + return slice, nil } - r = make([]fr.Element, 0, len(slice)-len(toRemove)) + with = make([]*big.Int, 0, len(slice)-len(indexes)) + without = make([]*big.Int, 0, len(indexes)) j := 0 // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) for i := 0; i < len(slice); i++ { - if j < len(toRemove) && i == toRemove[j] { - for j < len(toRemove) && i == toRemove[j] { - j++ - } + if j < len(indexes) && i == indexes[j] { + without = append(without, slice[i]) + j++ continue } - r = append(r, slice[i]) + with = append(with, slice[i]) } - - return r + return } // if len(toRemove) == 0, returns slice diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index 6797de36cd..2450d5ef00 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -25,7 +25,6 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr/pedersen" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bn254" - "github.com/consensys/gnark/internal/utils" "math/big" "math/bits" ) @@ -95,14 +94,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbPrivateCommittedWires := 0 - commitmentWires := make([]int, len(r1cs.CommitmentInfo)) - privateCommitted := make([][]int, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - nbPrivateCommittedWires += r1cs.CommitmentInfo[i].NbPrivateCommitted - privateCommitted[i] = r1cs.CommitmentInfo[i].PrivateCommitted() - commitmentWires[i] = r1cs.CommitmentInfo[i].CommitmentIndex - } + nbPrivateCommittedWires, commitmentWires, privateCommitted := r1cs.CommitmentInfo.Interleave() // a commitment is itself defined by a hint so the prover considers it private // but the verifier will need to inject the value itself so on the groth16 @@ -156,9 +148,12 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pkK := make([]fr.Element, nbPrivateWires) vkK := make([]fr.Element, nbPublicWires) ckK := make([][]fr.Element, len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + ckK[i] = make([]fr.Element, len(privateCommitted[i])) + } // see if i commits to j - for i := range r1cs.CommitmentInfo { + /*for i := range r1cs.CommitmentInfo { commitmentCommitments := 0 for j := 0; j < i; j++ { @@ -167,7 +162,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } ckK[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-commitmentCommitments) - } + }*/ var t0, t1 fr.Element @@ -180,8 +175,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } vI := 0 cI := make([]int, len(r1cs.CommitmentInfo)) - nbCommitToCommit := make([]int, len(r1cs.CommitmentInfo)) - nbPrivateCommittedSeen := 0 + //nbCommitToCommit := make([]int, len(r1cs.CommitmentInfo)) + nbPrivateCommittedSeen := 0 // = \sum_i cI[i] nbCommitmentsSeen := 0 /* for j := range r1cs.CommitmentInfo { // skip commitments to commitments @@ -209,11 +204,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { for j := range r1cs.CommitmentInfo { if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j - if isCommitment { - nbCommitToCommit[j]++ - } else { - break - } + break // frontend guarantees that no private variable is committed to more than once } } } @@ -225,7 +216,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vkK[vI] = t1 vI++ } else { // committed and private - ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]] = t1 + ckK[commitment][cI[commitment]] = t1 cI[commitment]++ nbPrivateCommittedSeen++ } diff --git a/backend/groth16/bn254/utils_test.go b/backend/groth16/bn254/utils_test.go index e3f547c16c..65d22f6b2d 100644 --- a/backend/groth16/bn254/utils_test.go +++ b/backend/groth16/bn254/utils_test.go @@ -14,16 +14,16 @@ func assertSliceEquals[T any](t *testing.T, expected []T, seen []T) { } } -func TestFilter(t *testing.T) { +func TestFilterHeap(t *testing.T) { elems := []fr.Element{{0}, {1}, {2}, {3}} - r := filter(elems, []int{1, 2}) + r := filterHeap(elems, []int{1, 2}) expected := []fr.Element{{0}, {3}} assertSliceEquals(t, expected, r) } func TestFilterRepeated(t *testing.T) { elems := []fr.Element{{0}, {1}, {2}, {3}} - r := filter(elems, []int{1, 1, 2}) + r := filterHeap(elems, []int{1, 1, 2}) expected := []fr.Element{{0}, {3}} assertSliceEquals(t, expected, r) } diff --git a/backend/groth16/internal/utils.go b/backend/groth16/internal/utils.go new file mode 100644 index 0000000000..f948f699af --- /dev/null +++ b/backend/groth16/internal/utils.go @@ -0,0 +1,23 @@ +package internal + +import "math/big" + +// DivideByThresholdOrList divides x into two sub-lists. list must be sorted, non-repeating and contain no value less than indexThreshold +func DivideByThresholdOrList(indexThreshold int, list []int, x []*big.Int) (ltOrInList, gtAndNotInList []*big.Int) { + ltOrInList = make([]*big.Int, indexThreshold+len(list)) + gtAndNotInList = make([]*big.Int, len(x)-len(ltOrInList)) + + copy(ltOrInList, x[:indexThreshold]) + + j := 0 + for i := indexThreshold; i < len(x); i++ { + if j < len(list) && i == list[j] { + ltOrInList[indexThreshold+j] = x[i] + j++ + } else { + gtAndNotInList[i-indexThreshold-j] = x[i] + } + } + + return +} diff --git a/constraint/commitment.go b/constraint/commitment.go index add98504b1..441adfda6a 100644 --- a/constraint/commitment.go +++ b/constraint/commitment.go @@ -1,6 +1,7 @@ package constraint import ( + "github.com/consensys/gnark/internal/utils" "math/big" "github.com/consensys/gnark/constraint/solver" @@ -66,12 +67,12 @@ func (i *Commitment) PublicCommitted() []int { return i.Committed[:i.NbPublicCommitted()] } -func CommitmentIndexes(commitments []Commitment) []uint64 { - res := make([]uint64, len(commitments)) - for i := range res { - res[i] = uint64(commitments[i].CommitmentIndex) +func (c Commitments) CommitmentWireIndexes() []int { + commitmentWires := make([]int, len(c)) + for i := range c { + commitmentWires[i] = c[i].CommitmentIndex } - return res + return commitmentWires } func (c Commitments) CommitmentsAndPrivateCommittedIndexes() []int { @@ -89,3 +90,39 @@ func (c Commitments) CommitmentsAndPrivateCommittedIndexes() []int { } return res } + +// Interleave returns combined information about the commitments +// nbPrivateCommittedWires doesn't double count because the frontend guarantees that no private wire is committed to more than once +func (c Commitments) Interleave() (nbPrivateCommittedWires int, commitmentWires []int, privateCommitted [][]int) { + commitmentWires = c.CommitmentWireIndexes() + + privateCommitted = make([][]int, len(c)) + for i := range c { + nonPublicCommitted := c[i].PrivateCommitted() + privateCommitted[i] = make([]int, 0, len(nonPublicCommitted)) + + for _, j := range nonPublicCommitted { + if found, _ := utils.BinarySearch(commitmentWires, j); !found { + privateCommitted[i] = append(privateCommitted[i], j) + } + } + + nbPrivateCommittedWires += len(privateCommitted[i]) + } + return +} + +// CommitmentIndexesInCommittedLists returns the indexes of the commitments in the list of committed wires +// note that these are not absolute indexes +func (c Commitments) CommitmentIndexesInCommittedLists() [][]int { + res := make([][]int, len(c)) + for i := range c { + res[i] = make([]int, i) + for j := 0; j < i; j++ { + if found, k := utils.BinarySearch(c[i].PrivateCommitted(), c[j].CommitmentIndex); found { + res[i][j] = k + c[i].NbPublicCommitted() + } + } + } + return res +} diff --git a/test/commitments_test.go b/test/commitments_test.go index a50b9e9dd0..59a4798227 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -2,7 +2,6 @@ package test import ( "fmt" - "github.com/consensys/gnark/backend" "github.com/consensys/gnark/frontend" "github.com/stretchr/testify/assert" "reflect" @@ -42,7 +41,7 @@ func (c *commitmentCircuit) Define(api frontend.API) error { sum = api.Add(sum, p) } api.AssertIsDifferent(commitment, sum) - return err + return nil } func TestSingleCommitment(t *testing.T) { @@ -122,13 +121,8 @@ func (c *twoCommitCircuit) Define(api frontend.API) error { return nil } -func TestTwoCommitEngine(t *testing.T) { - assignment := &twoCommitCircuit{X: []frontend.Variable{1, 2}, Y: 3} - NewAssert(t).SolvingSucceeded(&twoCommitCircuit{X: make([]frontend.Variable, len(assignment.X))}, assignment, WithBackends(backend.GROTH16, backend.PLONK)) -} - -func TestTwoCommitPlonk(t *testing.T) { - testPlonk(t, &twoCommitCircuit{X: []frontend.Variable{1, 2}, Y: 3}) +func TestTwoCommit(t *testing.T) { + testAll(t, &twoCommitCircuit{X: []frontend.Variable{1, 2}, Y: 3}) } type independentCommitsCircuit struct { @@ -151,8 +145,8 @@ func (c *independentCommitsCircuit) Define(api frontend.API) error { return nil } -func TestTwoIndependentCommitsGroth16(t *testing.T) { - testGroth16(t, &independentCommitsCircuit{X: []frontend.Variable{1, 1}}) +func TestTwoIndependentCommits(t *testing.T) { + testAll(t, &independentCommitsCircuit{X: []frontend.Variable{1, 1}}) } func TestHollow(t *testing.T) { diff --git a/test/end_to_end.go b/test/end_to_end.go index c66895a39d..96c042d3b3 100644 --- a/test/end_to_end.go +++ b/test/end_to_end.go @@ -63,11 +63,6 @@ func testPlonk(t *testing.T, assignment frontend.Circuit) { } func testGroth16(t *testing.T, assignment frontend.Circuit) { - - if onlyGroth16Bn254 { - fr = []ecc.ID{ecc.BN254} - } - circuit := hollow(assignment) run := func(mod *big.Int) func(*testing.T) { return func(t *testing.T) { From d5912b25fb90cf38520fb82067f15a025c31d7e1 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 30 May 2023 18:36:32 -0500 Subject: [PATCH 407/464] refactor: use c.CommitmentWireIndexes in Plonk backend --- backend/plonk/bls24-315/setup.go | 4 ++-- backend/plonk/internal/utils.go | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 backend/plonk/internal/utils.go diff --git a/backend/plonk/bls24-315/setup.go b/backend/plonk/bls24-315/setup.go index 27889b05f3..90c521ac37 100644 --- a/backend/plonk/bls24-315/setup.go +++ b/backend/plonk/bls24-315/setup.go @@ -23,7 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/iop" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/kzg" - "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/backend/plonk/internal" "github.com/consensys/gnark/constraint/bls24-315" ) @@ -125,7 +125,7 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - vk.CommitmentConstraintIndexes = constraint.CommitmentIndexes(spr.CommitmentInfo) + vk.CommitmentConstraintIndexes = internal.IntSliceToUint64Slice(spr.CommitmentInfo.CommitmentWireIndexes()) // nbConstraints := len(spr.Constraints) // step 0: set the fft domains diff --git a/backend/plonk/internal/utils.go b/backend/plonk/internal/utils.go new file mode 100644 index 0000000000..9f92e7ccf6 --- /dev/null +++ b/backend/plonk/internal/utils.go @@ -0,0 +1,9 @@ +package internal + +func IntSliceToUint64Slice(in []int) []uint64 { + res := make([]uint64, len(in)) + for i := range in { + res[i] = uint64(in[i]) + } + return res +} From c438c44ffabc6d5769e0a1283c3e53df2ffe007c Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 30 May 2023 18:38:02 -0500 Subject: [PATCH 408/464] build: generify plonk refactor --- backend/plonk/bls12-377/setup.go | 4 ++-- backend/plonk/bls12-381/setup.go | 4 ++-- backend/plonk/bls24-317/setup.go | 4 ++-- backend/plonk/bn254/setup.go | 4 ++-- backend/plonk/bw6-633/setup.go | 4 ++-- backend/plonk/bw6-761/setup.go | 4 ++-- .../backend/template/zkpschemes/plonk/plonk.setup.go.tmpl | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/backend/plonk/bls12-377/setup.go b/backend/plonk/bls12-377/setup.go index 464b36c251..216b147d59 100644 --- a/backend/plonk/bls12-377/setup.go +++ b/backend/plonk/bls12-377/setup.go @@ -23,7 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/iop" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/kzg" - "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/backend/plonk/internal" "github.com/consensys/gnark/constraint/bls12-377" ) @@ -125,7 +125,7 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - vk.CommitmentConstraintIndexes = constraint.CommitmentIndexes(spr.CommitmentInfo) + vk.CommitmentConstraintIndexes = internal.IntSliceToUint64Slice(spr.CommitmentInfo.CommitmentWireIndexes()) // nbConstraints := len(spr.Constraints) // step 0: set the fft domains diff --git a/backend/plonk/bls12-381/setup.go b/backend/plonk/bls12-381/setup.go index a778d70dec..ed653a9aa9 100644 --- a/backend/plonk/bls12-381/setup.go +++ b/backend/plonk/bls12-381/setup.go @@ -23,7 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/iop" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/kzg" - "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/backend/plonk/internal" "github.com/consensys/gnark/constraint/bls12-381" ) @@ -125,7 +125,7 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - vk.CommitmentConstraintIndexes = constraint.CommitmentIndexes(spr.CommitmentInfo) + vk.CommitmentConstraintIndexes = internal.IntSliceToUint64Slice(spr.CommitmentInfo.CommitmentWireIndexes()) // nbConstraints := len(spr.Constraints) // step 0: set the fft domains diff --git a/backend/plonk/bls24-317/setup.go b/backend/plonk/bls24-317/setup.go index b8407b4596..0f7cd1a6c0 100644 --- a/backend/plonk/bls24-317/setup.go +++ b/backend/plonk/bls24-317/setup.go @@ -23,7 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/iop" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/kzg" - "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/backend/plonk/internal" "github.com/consensys/gnark/constraint/bls24-317" ) @@ -125,7 +125,7 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - vk.CommitmentConstraintIndexes = constraint.CommitmentIndexes(spr.CommitmentInfo) + vk.CommitmentConstraintIndexes = internal.IntSliceToUint64Slice(spr.CommitmentInfo.CommitmentWireIndexes()) // nbConstraints := len(spr.Constraints) // step 0: set the fft domains diff --git a/backend/plonk/bn254/setup.go b/backend/plonk/bn254/setup.go index 680f6c5f46..e4db1924a6 100644 --- a/backend/plonk/bn254/setup.go +++ b/backend/plonk/bn254/setup.go @@ -23,7 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" "github.com/consensys/gnark-crypto/ecc/bn254/fr/iop" "github.com/consensys/gnark-crypto/ecc/bn254/fr/kzg" - "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/backend/plonk/internal" "github.com/consensys/gnark/constraint/bn254" ) @@ -125,7 +125,7 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - vk.CommitmentConstraintIndexes = constraint.CommitmentIndexes(spr.CommitmentInfo) + vk.CommitmentConstraintIndexes = internal.IntSliceToUint64Slice(spr.CommitmentInfo.CommitmentWireIndexes()) // nbConstraints := len(spr.Constraints) // step 0: set the fft domains diff --git a/backend/plonk/bw6-633/setup.go b/backend/plonk/bw6-633/setup.go index 08f14b0c51..db87a4f4a0 100644 --- a/backend/plonk/bw6-633/setup.go +++ b/backend/plonk/bw6-633/setup.go @@ -23,7 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/fft" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/iop" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/kzg" - "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/backend/plonk/internal" "github.com/consensys/gnark/constraint/bw6-633" ) @@ -125,7 +125,7 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - vk.CommitmentConstraintIndexes = constraint.CommitmentIndexes(spr.CommitmentInfo) + vk.CommitmentConstraintIndexes = internal.IntSliceToUint64Slice(spr.CommitmentInfo.CommitmentWireIndexes()) // nbConstraints := len(spr.Constraints) // step 0: set the fft domains diff --git a/backend/plonk/bw6-761/setup.go b/backend/plonk/bw6-761/setup.go index 6eccbf17f1..086e6b78db 100644 --- a/backend/plonk/bw6-761/setup.go +++ b/backend/plonk/bw6-761/setup.go @@ -23,7 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/fft" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/iop" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/kzg" - "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/backend/plonk/internal" "github.com/consensys/gnark/constraint/bw6-761" ) @@ -125,7 +125,7 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - vk.CommitmentConstraintIndexes = constraint.CommitmentIndexes(spr.CommitmentInfo) + vk.CommitmentConstraintIndexes = internal.IntSliceToUint64Slice(spr.CommitmentInfo.CommitmentWireIndexes()) // nbConstraints := len(spr.Constraints) // step 0: set the fft domains diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl index b9aa0e7c6d..33e4787d3c 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl @@ -6,7 +6,7 @@ import ( {{- template "import_backend_cs" . }} "github.com/consensys/gnark-crypto/ecc/{{toLower .Curve}}/fr/iop" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/backend/plonk/internal" ) // Trace stores a plonk trace as columns @@ -107,7 +107,7 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - vk.CommitmentConstraintIndexes = constraint.CommitmentIndexes(spr.CommitmentInfo) + vk.CommitmentConstraintIndexes = internal.IntSliceToUint64Slice(spr.CommitmentInfo.CommitmentWireIndexes()) // nbConstraints := len(spr.Constraints) // step 0: set the fft domains From cb241c3fb077821d7dfd7bde63490ba7c8b77824 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 30 May 2023 18:45:15 -0500 Subject: [PATCH 409/464] fix: single commitments work again --- backend/groth16/bn254/prove.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index 366e0d7d62..774bb6637b 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -78,7 +78,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b commitmentKey := pk.CommitmentKeys[i] solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { - committed, hashed := internal.DivideByThresholdOrList(nbPublicI, commitmentSubIndexesI, in) + hashed, committed := internal.DivideByThresholdOrList(nbPublicI, commitmentSubIndexesI, in) for j, inJ := range committed { privateCommittedValuesI[j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead } From 6aece8fd59326bfee38c250d93b2cec69a569e6f Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 30 May 2023 20:17:47 -0500 Subject: [PATCH 410/464] fix: commitment to commitment works --- backend/groth16/bn254/prove.go | 42 ++++++++++++++++---------------- backend/groth16/bn254/setup.go | 8 +++---- constraint/commitment.go | 15 ++++++++---- test/commitments_test.go | 44 +++++++++++++++++----------------- 4 files changed, 57 insertions(+), 52 deletions(-) diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index 774bb6637b..b45775be12 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -17,6 +17,7 @@ package groth16 import ( + "fmt" "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr" @@ -70,29 +71,30 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b commitmentSubIndexes := r1cs.CommitmentInfo.CommitmentIndexesInCommittedLists() privateCommittedValues := make([][]fr.Element, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { - nbPublicI := r1cs.CommitmentInfo[i].NbPublicCommitted() - commitmentSubIndexesI := commitmentSubIndexes[i] - privateCommittedValues[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-len(commitmentSubIndexesI)) - privateCommittedValuesI := privateCommittedValues[i] - commitmentOut := &proof.Commitments[i] - commitmentKey := pk.CommitmentKeys[i] - - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { - hashed, committed := internal.DivideByThresholdOrList(nbPublicI, commitmentSubIndexesI, in) - for j, inJ := range committed { - privateCommittedValuesI[j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead - } + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(i int) solver.Hint { + fmt.Println("defining, i=", i) + return func(_ *big.Int, in []*big.Int, out []*big.Int) error { + fmt.Println("executing, i=", i) + if i == 1 { + print("yo") + } + privateCommittedValues[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-len(commitmentSubIndexes[i])) + hashed, committed := internal.DivideByThresholdOrList(r1cs.CommitmentInfo[i].NbPublicCommitted(), commitmentSubIndexes[i], in) + for j, inJ := range committed { + privateCommittedValues[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead + } - var err error - if *commitmentOut, err = commitmentKey.Commit(privateCommittedValuesI); err != nil { + var err error + if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(privateCommittedValues[i]); err != nil { + return err + } + + var res fr.Element + res, err = solveCommitmentWire(&proof.Commitments[i], hashed) + res.BigInt(out[0]) return err } - - var res fr.Element - res, err = solveCommitmentWire(commitmentOut, hashed) - res.BigInt(out[0]) - return err - })) + }(i))) } _solution, err := r1cs.Solve(fullWitness, solverOpts...) diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index 2450d5ef00..6929d7c975 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -94,7 +94,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbPrivateCommittedWires, commitmentWires, privateCommitted := r1cs.CommitmentInfo.Interleave() + nbPrivateCommittedWires, commitmentWires, privateCommitted, publicAndCommitmentCommitted := + r1cs.CommitmentInfo.Interleave(r1cs.GetNbPublicVariables()) // a commitment is itself defined by a hint so the prover considers it private // but the verifier will need to inject the value itself so on the groth16 @@ -323,10 +324,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = make([][]int, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - vk.PublicCommitted[i] = r1cs.CommitmentInfo[i].PublicCommitted() - } + vk.PublicCommitted = publicAndCommitmentCommitted // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/constraint/commitment.go b/constraint/commitment.go index 441adfda6a..ffe013e56e 100644 --- a/constraint/commitment.go +++ b/constraint/commitment.go @@ -93,16 +93,21 @@ func (c Commitments) CommitmentsAndPrivateCommittedIndexes() []int { // Interleave returns combined information about the commitments // nbPrivateCommittedWires doesn't double count because the frontend guarantees that no private wire is committed to more than once -func (c Commitments) Interleave() (nbPrivateCommittedWires int, commitmentWires []int, privateCommitted [][]int) { +// publicAndCommitmentCommitted returns the index of committed wires that would be hashed, and are indexed from the verifier's point of view +func (c Commitments) Interleave(nbPublicVars int) (nbPrivateCommittedWires int, commitmentWires []int, privateCommitted [][]int, publicAndCommitmentCommitted [][]int) { commitmentWires = c.CommitmentWireIndexes() privateCommitted = make([][]int, len(c)) + publicAndCommitmentCommitted = make([][]int, len(c)) for i := range c { nonPublicCommitted := c[i].PrivateCommitted() privateCommitted[i] = make([]int, 0, len(nonPublicCommitted)) - + publicAndCommitmentCommitted[i] = make([]int, c[i].NbPublicCommitted(), len(c[i].Committed)) + copy(publicAndCommitmentCommitted[i], c[i].PublicCommitted()) for _, j := range nonPublicCommitted { - if found, _ := utils.BinarySearch(commitmentWires, j); !found { + if found, k := utils.BinarySearch(commitmentWires, j); found { // if j is a commitment wire + publicAndCommitmentCommitted[i] = append(publicAndCommitmentCommitted[i], k+nbPublicVars) + } else { privateCommitted[i] = append(privateCommitted[i], j) } } @@ -117,10 +122,10 @@ func (c Commitments) Interleave() (nbPrivateCommittedWires int, commitmentWires func (c Commitments) CommitmentIndexesInCommittedLists() [][]int { res := make([][]int, len(c)) for i := range c { - res[i] = make([]int, i) + res[i] = make([]int, 0, i) for j := 0; j < i; j++ { if found, k := utils.BinarySearch(c[i].PrivateCommitted(), c[j].CommitmentIndex); found { - res[i][j] = k + c[i].NbPublicCommitted() + res[i] = append(res[i], k+c[i].NbPublicCommitted()) } } } diff --git a/test/commitments_test.go b/test/commitments_test.go index 59a4798227..f233ec3d65 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -103,28 +103,6 @@ func TestCommittedPublic(t *testing.T) { testAll(t, &committedPublicCircuit{1}) } -type twoCommitCircuit struct { - X []frontend.Variable - Y frontend.Variable -} - -func (c *twoCommitCircuit) Define(api frontend.API) error { - c0, err := api.(frontend.Committer).Commit(c.X...) - if err != nil { - return err - } - var c1 frontend.Variable - if c1, err = api.(frontend.Committer).Commit(c0, c.Y); err != nil { - return err - } - api.AssertIsDifferent(c1, c.Y) - return nil -} - -func TestTwoCommit(t *testing.T) { - testAll(t, &twoCommitCircuit{X: []frontend.Variable{1, 2}, Y: 3}) -} - type independentCommitsCircuit struct { X []frontend.Variable } @@ -149,6 +127,28 @@ func TestTwoIndependentCommits(t *testing.T) { testAll(t, &independentCommitsCircuit{X: []frontend.Variable{1, 1}}) } +type twoCommitCircuit struct { + X []frontend.Variable + Y frontend.Variable +} + +func (c *twoCommitCircuit) Define(api frontend.API) error { + c0, err := api.(frontend.Committer).Commit(c.X...) + if err != nil { + return err + } + var c1 frontend.Variable + if c1, err = api.(frontend.Committer).Commit(c0, c.Y); err != nil { + return err + } + api.AssertIsDifferent(c1, c.Y) + return nil +} + +func TestTwoCommit(t *testing.T) { + testAll(t, &twoCommitCircuit{X: []frontend.Variable{1, 2}, Y: 3}) +} + func TestHollow(t *testing.T) { run := func(c, expected frontend.Circuit) func(t *testing.T) { From 348b0f6e0754beeac4d5bb726677725b5cc489a6 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 30 May 2023 22:06:26 -0500 Subject: [PATCH 411/464] build: some generification and remove commented code --- backend/groth16/bls12-377/prove.go | 92 +++++++++++++------ backend/groth16/bls12-377/setup.go | 13 +-- backend/groth16/bls12-381/prove.go | 92 +++++++++++++------ backend/groth16/bls12-381/setup.go | 13 +-- backend/groth16/bls24-315/prove.go | 92 +++++++++++++------ backend/groth16/bls24-315/setup.go | 13 +-- backend/groth16/bls24-317/prove.go | 92 +++++++++++++------ backend/groth16/bls24-317/setup.go | 13 +-- backend/groth16/bn254/commitment.go | 3 - backend/groth16/bn254/setup.go | 28 +----- backend/groth16/bw6-633/prove.go | 92 +++++++++++++------ backend/groth16/bw6-633/setup.go | 13 +-- backend/groth16/bw6-761/prove.go | 92 +++++++++++++------ backend/groth16/bw6-761/setup.go | 13 +-- .../zkpschemes/groth16/groth16.prove.go.tmpl | 92 +++++++++++++------ .../zkpschemes/groth16/groth16.setup.go.tmpl | 13 +-- 16 files changed, 470 insertions(+), 296 deletions(-) diff --git a/backend/groth16/bls12-377/prove.go b/backend/groth16/bls12-377/prove.go index 2f6bab5e75..1fcb1ce516 100644 --- a/backend/groth16/bls12-377/prove.go +++ b/backend/groth16/bls12-377/prove.go @@ -24,6 +24,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/pedersen" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint/bls12-377" "github.com/consensys/gnark/constraint/solver" @@ -67,29 +68,33 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - privateCommitted := make([][]fr.Element, len(r1cs.CommitmentInfo)) + commitmentSubIndexes := r1cs.CommitmentInfo.CommitmentIndexesInCommittedLists() + privateCommittedValues := make([][]fr.Element, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { - if len(in) != r1cs.CommitmentInfo[i].NbCommitted() { // TODO: Remove - return fmt.Errorf("unexpected number of committed variables") - } - privateCommitted[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) - nbPublicCommitted := len(in) - len(privateCommitted[i]) - inPrivate := in[nbPublicCommitted:] - for j, inJ := range inPrivate { - privateCommitted[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead - } + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(i int) solver.Hint { + fmt.Println("defining, i=", i) + return func(_ *big.Int, in []*big.Int, out []*big.Int) error { + fmt.Println("executing, i=", i) + if i == 1 { + print("yo") + } + privateCommittedValues[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-len(commitmentSubIndexes[i])) + hashed, committed := internal.DivideByThresholdOrList(r1cs.CommitmentInfo[i].NbPublicCommitted(), commitmentSubIndexes[i], in) + for j, inJ := range committed { + privateCommittedValues[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead + } - var err error - if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(privateCommitted[i]); err != nil { + var err error + if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(privateCommittedValues[i]); err != nil { + return err + } + + var res fr.Element + res, err = solveCommitmentWire(&proof.Commitments[i], hashed) + res.BigInt(out[0]) return err } - - var res fr.Element - res, err = solveCommitmentWire(&proof.Commitments[i], in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) - res.BigInt(out[0]) - return err - })) + }(i))) } _solution, err := r1cs.Solve(fullWitness, solverOpts...) @@ -107,7 +112,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b copy(commitmentsSerialized[fr.Bytes*i:], wireValues[r1cs.CommitmentInfo[i].CommitmentIndex].Marshal()) } - if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, commitmentsSerialized); err != nil { + if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommittedValues, commitmentsSerialized); err != nil { return nil, err } @@ -212,10 +217,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed - _wireValues := wireValues - for i := range r1cs.CommitmentInfo { - _wireValues = filter(_wireValues, r1cs.CommitmentInfo[i].PrivateToPublicGroth16()) - } + _wireValues := filterHeap(wireValues, r1cs.CommitmentInfo.CommitmentsAndPrivateCommittedIndexes()) if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err @@ -297,27 +299,57 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return proof, nil } +// if len(indexes) == 0, returns slice, nil +// else, returns a slice with the indexes and another without +// this assumes the indexes are sorted, without repetition and that len(slice) > len(indexes) +func split(slice []*big.Int, indexes []int) (with, without []*big.Int) { + + if len(indexes) == 0 { + return slice, nil + } + with = make([]*big.Int, 0, len(slice)-len(indexes)) + without = make([]*big.Int, 0, len(indexes)) + + j := 0 + // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) + for i := 0; i < len(slice); i++ { + if j < len(indexes) && i == indexes[j] { + without = append(without, slice[i]) + j++ + continue + } + with = append(with, slice[i]) + } + return +} + // if len(toRemove) == 0, returns slice // else, returns a new slice without the indexes in toRemove // this assumes toRemove indexes are sorted and len(slice) > len(toRemove) -func filter(slice []fr.Element, toRemove []int) (r []fr.Element) { +// filterHeap modifies toRemove +func filterHeap(slice []fr.Element, toRemove []int) (r []fr.Element) { if len(toRemove) == 0 { return slice } - r = make([]fr.Element, 0, len(slice)-len(toRemove)) - j := 0 + heap := utils.IntHeap(toRemove) + heap.Heapify() + + r = make([]fr.Element, 0, len(slice)) + // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) for i := 0; i < len(slice); i++ { - if j < len(toRemove) && i == toRemove[j] { - j++ + if len(heap) > 0 && i == heap[0] { + for len(heap) > 0 && i == heap[0] { + heap.Pop() + } continue } r = append(r, slice[i]) } - return r + return } func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index d57dd8ce0f..713bc6fa56 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -95,14 +95,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbPrivateCommittedWires := 0 - commitmentWires := make([]int, len(r1cs.CommitmentInfo)) - privateCommitted := make([][]int, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - nbPrivateCommittedWires += r1cs.CommitmentInfo[i].NbPrivateCommitted - privateCommitted[i] = r1cs.CommitmentInfo[i].PrivateCommitted() - commitmentWires[i] = r1cs.CommitmentInfo[i].CommitmentIndex - } + nbPrivateCommittedWires, commitmentWires, privateCommitted, publicAndCommitmentCommitted := + r1cs.CommitmentInfo.Interleave(r1cs.GetNbPublicVariables()) // a commitment is itself defined by a hint so the prover considers it private // but the verifier will need to inject the value itself so on the groth16 @@ -156,6 +150,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pkK := make([]fr.Element, nbPrivateWires) vkK := make([]fr.Element, nbPublicWires) ckK := make([][]fr.Element, len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + ckK[i] = make([]fr.Element, len(privateCommitted[i])) + } // see if i commits to j for i := range r1cs.CommitmentInfo { diff --git a/backend/groth16/bls12-381/prove.go b/backend/groth16/bls12-381/prove.go index 86dca47271..7b9c562afc 100644 --- a/backend/groth16/bls12-381/prove.go +++ b/backend/groth16/bls12-381/prove.go @@ -24,6 +24,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/pedersen" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint/bls12-381" "github.com/consensys/gnark/constraint/solver" @@ -67,29 +68,33 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - privateCommitted := make([][]fr.Element, len(r1cs.CommitmentInfo)) + commitmentSubIndexes := r1cs.CommitmentInfo.CommitmentIndexesInCommittedLists() + privateCommittedValues := make([][]fr.Element, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { - if len(in) != r1cs.CommitmentInfo[i].NbCommitted() { // TODO: Remove - return fmt.Errorf("unexpected number of committed variables") - } - privateCommitted[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) - nbPublicCommitted := len(in) - len(privateCommitted[i]) - inPrivate := in[nbPublicCommitted:] - for j, inJ := range inPrivate { - privateCommitted[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead - } + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(i int) solver.Hint { + fmt.Println("defining, i=", i) + return func(_ *big.Int, in []*big.Int, out []*big.Int) error { + fmt.Println("executing, i=", i) + if i == 1 { + print("yo") + } + privateCommittedValues[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-len(commitmentSubIndexes[i])) + hashed, committed := internal.DivideByThresholdOrList(r1cs.CommitmentInfo[i].NbPublicCommitted(), commitmentSubIndexes[i], in) + for j, inJ := range committed { + privateCommittedValues[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead + } - var err error - if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(privateCommitted[i]); err != nil { + var err error + if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(privateCommittedValues[i]); err != nil { + return err + } + + var res fr.Element + res, err = solveCommitmentWire(&proof.Commitments[i], hashed) + res.BigInt(out[0]) return err } - - var res fr.Element - res, err = solveCommitmentWire(&proof.Commitments[i], in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) - res.BigInt(out[0]) - return err - })) + }(i))) } _solution, err := r1cs.Solve(fullWitness, solverOpts...) @@ -107,7 +112,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b copy(commitmentsSerialized[fr.Bytes*i:], wireValues[r1cs.CommitmentInfo[i].CommitmentIndex].Marshal()) } - if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, commitmentsSerialized); err != nil { + if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommittedValues, commitmentsSerialized); err != nil { return nil, err } @@ -212,10 +217,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed - _wireValues := wireValues - for i := range r1cs.CommitmentInfo { - _wireValues = filter(_wireValues, r1cs.CommitmentInfo[i].PrivateToPublicGroth16()) - } + _wireValues := filterHeap(wireValues, r1cs.CommitmentInfo.CommitmentsAndPrivateCommittedIndexes()) if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err @@ -297,27 +299,57 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return proof, nil } +// if len(indexes) == 0, returns slice, nil +// else, returns a slice with the indexes and another without +// this assumes the indexes are sorted, without repetition and that len(slice) > len(indexes) +func split(slice []*big.Int, indexes []int) (with, without []*big.Int) { + + if len(indexes) == 0 { + return slice, nil + } + with = make([]*big.Int, 0, len(slice)-len(indexes)) + without = make([]*big.Int, 0, len(indexes)) + + j := 0 + // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) + for i := 0; i < len(slice); i++ { + if j < len(indexes) && i == indexes[j] { + without = append(without, slice[i]) + j++ + continue + } + with = append(with, slice[i]) + } + return +} + // if len(toRemove) == 0, returns slice // else, returns a new slice without the indexes in toRemove // this assumes toRemove indexes are sorted and len(slice) > len(toRemove) -func filter(slice []fr.Element, toRemove []int) (r []fr.Element) { +// filterHeap modifies toRemove +func filterHeap(slice []fr.Element, toRemove []int) (r []fr.Element) { if len(toRemove) == 0 { return slice } - r = make([]fr.Element, 0, len(slice)-len(toRemove)) - j := 0 + heap := utils.IntHeap(toRemove) + heap.Heapify() + + r = make([]fr.Element, 0, len(slice)) + // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) for i := 0; i < len(slice); i++ { - if j < len(toRemove) && i == toRemove[j] { - j++ + if len(heap) > 0 && i == heap[0] { + for len(heap) > 0 && i == heap[0] { + heap.Pop() + } continue } r = append(r, slice[i]) } - return r + return } func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index 27dc11fc1c..222ea6b123 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -95,14 +95,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbPrivateCommittedWires := 0 - commitmentWires := make([]int, len(r1cs.CommitmentInfo)) - privateCommitted := make([][]int, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - nbPrivateCommittedWires += r1cs.CommitmentInfo[i].NbPrivateCommitted - privateCommitted[i] = r1cs.CommitmentInfo[i].PrivateCommitted() - commitmentWires[i] = r1cs.CommitmentInfo[i].CommitmentIndex - } + nbPrivateCommittedWires, commitmentWires, privateCommitted, publicAndCommitmentCommitted := + r1cs.CommitmentInfo.Interleave(r1cs.GetNbPublicVariables()) // a commitment is itself defined by a hint so the prover considers it private // but the verifier will need to inject the value itself so on the groth16 @@ -156,6 +150,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pkK := make([]fr.Element, nbPrivateWires) vkK := make([]fr.Element, nbPublicWires) ckK := make([][]fr.Element, len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + ckK[i] = make([]fr.Element, len(privateCommitted[i])) + } // see if i commits to j for i := range r1cs.CommitmentInfo { diff --git a/backend/groth16/bls24-315/prove.go b/backend/groth16/bls24-315/prove.go index a0f5389fec..c3ed14c11d 100644 --- a/backend/groth16/bls24-315/prove.go +++ b/backend/groth16/bls24-315/prove.go @@ -24,6 +24,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/pedersen" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint/bls24-315" "github.com/consensys/gnark/constraint/solver" @@ -67,29 +68,33 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - privateCommitted := make([][]fr.Element, len(r1cs.CommitmentInfo)) + commitmentSubIndexes := r1cs.CommitmentInfo.CommitmentIndexesInCommittedLists() + privateCommittedValues := make([][]fr.Element, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { - if len(in) != r1cs.CommitmentInfo[i].NbCommitted() { // TODO: Remove - return fmt.Errorf("unexpected number of committed variables") - } - privateCommitted[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) - nbPublicCommitted := len(in) - len(privateCommitted[i]) - inPrivate := in[nbPublicCommitted:] - for j, inJ := range inPrivate { - privateCommitted[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead - } + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(i int) solver.Hint { + fmt.Println("defining, i=", i) + return func(_ *big.Int, in []*big.Int, out []*big.Int) error { + fmt.Println("executing, i=", i) + if i == 1 { + print("yo") + } + privateCommittedValues[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-len(commitmentSubIndexes[i])) + hashed, committed := internal.DivideByThresholdOrList(r1cs.CommitmentInfo[i].NbPublicCommitted(), commitmentSubIndexes[i], in) + for j, inJ := range committed { + privateCommittedValues[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead + } - var err error - if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(privateCommitted[i]); err != nil { + var err error + if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(privateCommittedValues[i]); err != nil { + return err + } + + var res fr.Element + res, err = solveCommitmentWire(&proof.Commitments[i], hashed) + res.BigInt(out[0]) return err } - - var res fr.Element - res, err = solveCommitmentWire(&proof.Commitments[i], in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) - res.BigInt(out[0]) - return err - })) + }(i))) } _solution, err := r1cs.Solve(fullWitness, solverOpts...) @@ -107,7 +112,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b copy(commitmentsSerialized[fr.Bytes*i:], wireValues[r1cs.CommitmentInfo[i].CommitmentIndex].Marshal()) } - if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, commitmentsSerialized); err != nil { + if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommittedValues, commitmentsSerialized); err != nil { return nil, err } @@ -212,10 +217,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed - _wireValues := wireValues - for i := range r1cs.CommitmentInfo { - _wireValues = filter(_wireValues, r1cs.CommitmentInfo[i].PrivateToPublicGroth16()) - } + _wireValues := filterHeap(wireValues, r1cs.CommitmentInfo.CommitmentsAndPrivateCommittedIndexes()) if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err @@ -297,27 +299,57 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return proof, nil } +// if len(indexes) == 0, returns slice, nil +// else, returns a slice with the indexes and another without +// this assumes the indexes are sorted, without repetition and that len(slice) > len(indexes) +func split(slice []*big.Int, indexes []int) (with, without []*big.Int) { + + if len(indexes) == 0 { + return slice, nil + } + with = make([]*big.Int, 0, len(slice)-len(indexes)) + without = make([]*big.Int, 0, len(indexes)) + + j := 0 + // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) + for i := 0; i < len(slice); i++ { + if j < len(indexes) && i == indexes[j] { + without = append(without, slice[i]) + j++ + continue + } + with = append(with, slice[i]) + } + return +} + // if len(toRemove) == 0, returns slice // else, returns a new slice without the indexes in toRemove // this assumes toRemove indexes are sorted and len(slice) > len(toRemove) -func filter(slice []fr.Element, toRemove []int) (r []fr.Element) { +// filterHeap modifies toRemove +func filterHeap(slice []fr.Element, toRemove []int) (r []fr.Element) { if len(toRemove) == 0 { return slice } - r = make([]fr.Element, 0, len(slice)-len(toRemove)) - j := 0 + heap := utils.IntHeap(toRemove) + heap.Heapify() + + r = make([]fr.Element, 0, len(slice)) + // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) for i := 0; i < len(slice); i++ { - if j < len(toRemove) && i == toRemove[j] { - j++ + if len(heap) > 0 && i == heap[0] { + for len(heap) > 0 && i == heap[0] { + heap.Pop() + } continue } r = append(r, slice[i]) } - return r + return } func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index b42f52943d..1241da99ed 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -95,14 +95,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbPrivateCommittedWires := 0 - commitmentWires := make([]int, len(r1cs.CommitmentInfo)) - privateCommitted := make([][]int, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - nbPrivateCommittedWires += r1cs.CommitmentInfo[i].NbPrivateCommitted - privateCommitted[i] = r1cs.CommitmentInfo[i].PrivateCommitted() - commitmentWires[i] = r1cs.CommitmentInfo[i].CommitmentIndex - } + nbPrivateCommittedWires, commitmentWires, privateCommitted, publicAndCommitmentCommitted := + r1cs.CommitmentInfo.Interleave(r1cs.GetNbPublicVariables()) // a commitment is itself defined by a hint so the prover considers it private // but the verifier will need to inject the value itself so on the groth16 @@ -156,6 +150,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pkK := make([]fr.Element, nbPrivateWires) vkK := make([]fr.Element, nbPublicWires) ckK := make([][]fr.Element, len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + ckK[i] = make([]fr.Element, len(privateCommitted[i])) + } // see if i commits to j for i := range r1cs.CommitmentInfo { diff --git a/backend/groth16/bls24-317/prove.go b/backend/groth16/bls24-317/prove.go index 085f8d179b..c1a98b9686 100644 --- a/backend/groth16/bls24-317/prove.go +++ b/backend/groth16/bls24-317/prove.go @@ -24,6 +24,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/pedersen" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint/bls24-317" "github.com/consensys/gnark/constraint/solver" @@ -67,29 +68,33 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - privateCommitted := make([][]fr.Element, len(r1cs.CommitmentInfo)) + commitmentSubIndexes := r1cs.CommitmentInfo.CommitmentIndexesInCommittedLists() + privateCommittedValues := make([][]fr.Element, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { - if len(in) != r1cs.CommitmentInfo[i].NbCommitted() { // TODO: Remove - return fmt.Errorf("unexpected number of committed variables") - } - privateCommitted[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) - nbPublicCommitted := len(in) - len(privateCommitted[i]) - inPrivate := in[nbPublicCommitted:] - for j, inJ := range inPrivate { - privateCommitted[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead - } + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(i int) solver.Hint { + fmt.Println("defining, i=", i) + return func(_ *big.Int, in []*big.Int, out []*big.Int) error { + fmt.Println("executing, i=", i) + if i == 1 { + print("yo") + } + privateCommittedValues[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-len(commitmentSubIndexes[i])) + hashed, committed := internal.DivideByThresholdOrList(r1cs.CommitmentInfo[i].NbPublicCommitted(), commitmentSubIndexes[i], in) + for j, inJ := range committed { + privateCommittedValues[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead + } - var err error - if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(privateCommitted[i]); err != nil { + var err error + if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(privateCommittedValues[i]); err != nil { + return err + } + + var res fr.Element + res, err = solveCommitmentWire(&proof.Commitments[i], hashed) + res.BigInt(out[0]) return err } - - var res fr.Element - res, err = solveCommitmentWire(&proof.Commitments[i], in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) - res.BigInt(out[0]) - return err - })) + }(i))) } _solution, err := r1cs.Solve(fullWitness, solverOpts...) @@ -107,7 +112,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b copy(commitmentsSerialized[fr.Bytes*i:], wireValues[r1cs.CommitmentInfo[i].CommitmentIndex].Marshal()) } - if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, commitmentsSerialized); err != nil { + if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommittedValues, commitmentsSerialized); err != nil { return nil, err } @@ -212,10 +217,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed - _wireValues := wireValues - for i := range r1cs.CommitmentInfo { - _wireValues = filter(_wireValues, r1cs.CommitmentInfo[i].PrivateToPublicGroth16()) - } + _wireValues := filterHeap(wireValues, r1cs.CommitmentInfo.CommitmentsAndPrivateCommittedIndexes()) if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err @@ -297,27 +299,57 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return proof, nil } +// if len(indexes) == 0, returns slice, nil +// else, returns a slice with the indexes and another without +// this assumes the indexes are sorted, without repetition and that len(slice) > len(indexes) +func split(slice []*big.Int, indexes []int) (with, without []*big.Int) { + + if len(indexes) == 0 { + return slice, nil + } + with = make([]*big.Int, 0, len(slice)-len(indexes)) + without = make([]*big.Int, 0, len(indexes)) + + j := 0 + // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) + for i := 0; i < len(slice); i++ { + if j < len(indexes) && i == indexes[j] { + without = append(without, slice[i]) + j++ + continue + } + with = append(with, slice[i]) + } + return +} + // if len(toRemove) == 0, returns slice // else, returns a new slice without the indexes in toRemove // this assumes toRemove indexes are sorted and len(slice) > len(toRemove) -func filter(slice []fr.Element, toRemove []int) (r []fr.Element) { +// filterHeap modifies toRemove +func filterHeap(slice []fr.Element, toRemove []int) (r []fr.Element) { if len(toRemove) == 0 { return slice } - r = make([]fr.Element, 0, len(slice)-len(toRemove)) - j := 0 + heap := utils.IntHeap(toRemove) + heap.Heapify() + + r = make([]fr.Element, 0, len(slice)) + // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) for i := 0; i < len(slice); i++ { - if j < len(toRemove) && i == toRemove[j] { - j++ + if len(heap) > 0 && i == heap[0] { + for len(heap) > 0 && i == heap[0] { + heap.Pop() + } continue } r = append(r, slice[i]) } - return r + return } func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index 174a768b1e..489bf21264 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -95,14 +95,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbPrivateCommittedWires := 0 - commitmentWires := make([]int, len(r1cs.CommitmentInfo)) - privateCommitted := make([][]int, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - nbPrivateCommittedWires += r1cs.CommitmentInfo[i].NbPrivateCommitted - privateCommitted[i] = r1cs.CommitmentInfo[i].PrivateCommitted() - commitmentWires[i] = r1cs.CommitmentInfo[i].CommitmentIndex - } + nbPrivateCommittedWires, commitmentWires, privateCommitted, publicAndCommitmentCommitted := + r1cs.CommitmentInfo.Interleave(r1cs.GetNbPublicVariables()) // a commitment is itself defined by a hint so the prover considers it private // but the verifier will need to inject the value itself so on the groth16 @@ -156,6 +150,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pkK := make([]fr.Element, nbPrivateWires) vkK := make([]fr.Element, nbPublicWires) ckK := make([][]fr.Element, len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + ckK[i] = make([]fr.Element, len(privateCommitted[i])) + } // see if i commits to j for i := range r1cs.CommitmentInfo { diff --git a/backend/groth16/bn254/commitment.go b/backend/groth16/bn254/commitment.go index df390bc38c..435a7c058c 100644 --- a/backend/groth16/bn254/commitment.go +++ b/backend/groth16/bn254/commitment.go @@ -17,7 +17,6 @@ package groth16 import ( - "fmt" curve "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark/constraint" @@ -25,8 +24,6 @@ import ( ) func solveCommitmentWire(commitment *curve.G1Affine, publicCommitted []*big.Int) (fr.Element, error) { - fmt.Println("len(pubCom)=", len(publicCommitted)) res, err := fr.Hash(constraint.SerializeCommitment(commitment.Marshal(), publicCommitted, (fr.Bits-1)/8+1), []byte(constraint.CommitmentDst), 1) - fmt.Println("commitment", res[0].Text(16)) return res[0], err } diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index 6929d7c975..112c07446f 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -153,18 +153,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { ckK[i] = make([]fr.Element, len(privateCommitted[i])) } - // see if i commits to j - /*for i := range r1cs.CommitmentInfo { - commitmentCommitments := 0 - - for j := 0; j < i; j++ { - if found, _ := utils.BinarySearch(privateCommitted[i], r1cs.CommitmentInfo[j].CommitmentIndex); found { - commitmentCommitments++ - } - } - ckK[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-commitmentCommitments) - }*/ - var t0, t1 fr.Element computeK := func(i int, coeff *fr.Element) { // TODO: Inline again @@ -176,23 +164,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } vI := 0 cI := make([]int, len(r1cs.CommitmentInfo)) - //nbCommitToCommit := make([]int, len(r1cs.CommitmentInfo)) - nbPrivateCommittedSeen := 0 // = \sum_i cI[i] + nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 - /* for j := range r1cs.CommitmentInfo { // skip commitments to commitments - k := 0 - l := 0 - for ; k < len(privateCommitted[j]); k++ { - for ; l < len(commitmentWires) && commitmentWires[l] < privateCommitted[j][k]; l++ {} - if k != l { - break - } - } - cI[j] = k - } - copy(nbCommitToCommit, cI)*/ - for i := range A { commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool diff --git a/backend/groth16/bw6-633/prove.go b/backend/groth16/bw6-633/prove.go index 61c5a20509..be293f56f7 100644 --- a/backend/groth16/bw6-633/prove.go +++ b/backend/groth16/bw6-633/prove.go @@ -24,6 +24,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/fft" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/pedersen" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint/bw6-633" "github.com/consensys/gnark/constraint/solver" @@ -67,29 +68,33 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - privateCommitted := make([][]fr.Element, len(r1cs.CommitmentInfo)) + commitmentSubIndexes := r1cs.CommitmentInfo.CommitmentIndexesInCommittedLists() + privateCommittedValues := make([][]fr.Element, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { - if len(in) != r1cs.CommitmentInfo[i].NbCommitted() { // TODO: Remove - return fmt.Errorf("unexpected number of committed variables") - } - privateCommitted[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) - nbPublicCommitted := len(in) - len(privateCommitted[i]) - inPrivate := in[nbPublicCommitted:] - for j, inJ := range inPrivate { - privateCommitted[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead - } + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(i int) solver.Hint { + fmt.Println("defining, i=", i) + return func(_ *big.Int, in []*big.Int, out []*big.Int) error { + fmt.Println("executing, i=", i) + if i == 1 { + print("yo") + } + privateCommittedValues[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-len(commitmentSubIndexes[i])) + hashed, committed := internal.DivideByThresholdOrList(r1cs.CommitmentInfo[i].NbPublicCommitted(), commitmentSubIndexes[i], in) + for j, inJ := range committed { + privateCommittedValues[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead + } - var err error - if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(privateCommitted[i]); err != nil { + var err error + if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(privateCommittedValues[i]); err != nil { + return err + } + + var res fr.Element + res, err = solveCommitmentWire(&proof.Commitments[i], hashed) + res.BigInt(out[0]) return err } - - var res fr.Element - res, err = solveCommitmentWire(&proof.Commitments[i], in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) - res.BigInt(out[0]) - return err - })) + }(i))) } _solution, err := r1cs.Solve(fullWitness, solverOpts...) @@ -107,7 +112,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b copy(commitmentsSerialized[fr.Bytes*i:], wireValues[r1cs.CommitmentInfo[i].CommitmentIndex].Marshal()) } - if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, commitmentsSerialized); err != nil { + if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommittedValues, commitmentsSerialized); err != nil { return nil, err } @@ -212,10 +217,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed - _wireValues := wireValues - for i := range r1cs.CommitmentInfo { - _wireValues = filter(_wireValues, r1cs.CommitmentInfo[i].PrivateToPublicGroth16()) - } + _wireValues := filterHeap(wireValues, r1cs.CommitmentInfo.CommitmentsAndPrivateCommittedIndexes()) if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err @@ -297,27 +299,57 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return proof, nil } +// if len(indexes) == 0, returns slice, nil +// else, returns a slice with the indexes and another without +// this assumes the indexes are sorted, without repetition and that len(slice) > len(indexes) +func split(slice []*big.Int, indexes []int) (with, without []*big.Int) { + + if len(indexes) == 0 { + return slice, nil + } + with = make([]*big.Int, 0, len(slice)-len(indexes)) + without = make([]*big.Int, 0, len(indexes)) + + j := 0 + // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) + for i := 0; i < len(slice); i++ { + if j < len(indexes) && i == indexes[j] { + without = append(without, slice[i]) + j++ + continue + } + with = append(with, slice[i]) + } + return +} + // if len(toRemove) == 0, returns slice // else, returns a new slice without the indexes in toRemove // this assumes toRemove indexes are sorted and len(slice) > len(toRemove) -func filter(slice []fr.Element, toRemove []int) (r []fr.Element) { +// filterHeap modifies toRemove +func filterHeap(slice []fr.Element, toRemove []int) (r []fr.Element) { if len(toRemove) == 0 { return slice } - r = make([]fr.Element, 0, len(slice)-len(toRemove)) - j := 0 + heap := utils.IntHeap(toRemove) + heap.Heapify() + + r = make([]fr.Element, 0, len(slice)) + // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) for i := 0; i < len(slice); i++ { - if j < len(toRemove) && i == toRemove[j] { - j++ + if len(heap) > 0 && i == heap[0] { + for len(heap) > 0 && i == heap[0] { + heap.Pop() + } continue } r = append(r, slice[i]) } - return r + return } func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index e2cffe1329..080d59d516 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -95,14 +95,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbPrivateCommittedWires := 0 - commitmentWires := make([]int, len(r1cs.CommitmentInfo)) - privateCommitted := make([][]int, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - nbPrivateCommittedWires += r1cs.CommitmentInfo[i].NbPrivateCommitted - privateCommitted[i] = r1cs.CommitmentInfo[i].PrivateCommitted() - commitmentWires[i] = r1cs.CommitmentInfo[i].CommitmentIndex - } + nbPrivateCommittedWires, commitmentWires, privateCommitted, publicAndCommitmentCommitted := + r1cs.CommitmentInfo.Interleave(r1cs.GetNbPublicVariables()) // a commitment is itself defined by a hint so the prover considers it private // but the verifier will need to inject the value itself so on the groth16 @@ -156,6 +150,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pkK := make([]fr.Element, nbPrivateWires) vkK := make([]fr.Element, nbPublicWires) ckK := make([][]fr.Element, len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + ckK[i] = make([]fr.Element, len(privateCommitted[i])) + } // see if i commits to j for i := range r1cs.CommitmentInfo { diff --git a/backend/groth16/bw6-761/prove.go b/backend/groth16/bw6-761/prove.go index 237c74de72..c11ef9c11b 100644 --- a/backend/groth16/bw6-761/prove.go +++ b/backend/groth16/bw6-761/prove.go @@ -24,6 +24,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/fft" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/pedersen" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint/bw6-761" "github.com/consensys/gnark/constraint/solver" @@ -67,29 +68,33 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - privateCommitted := make([][]fr.Element, len(r1cs.CommitmentInfo)) + commitmentSubIndexes := r1cs.CommitmentInfo.CommitmentIndexesInCommittedLists() + privateCommittedValues := make([][]fr.Element, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(_ *big.Int, in []*big.Int, out []*big.Int) error { - if len(in) != r1cs.CommitmentInfo[i].NbCommitted() { // TODO: Remove - return fmt.Errorf("unexpected number of committed variables") - } - privateCommitted[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) - nbPublicCommitted := len(in) - len(privateCommitted[i]) - inPrivate := in[nbPublicCommitted:] - for j, inJ := range inPrivate { - privateCommitted[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead - } + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(i int) solver.Hint { + fmt.Println("defining, i=", i) + return func(_ *big.Int, in []*big.Int, out []*big.Int) error { + fmt.Println("executing, i=", i) + if i == 1 { + print("yo") + } + privateCommittedValues[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-len(commitmentSubIndexes[i])) + hashed, committed := internal.DivideByThresholdOrList(r1cs.CommitmentInfo[i].NbPublicCommitted(), commitmentSubIndexes[i], in) + for j, inJ := range committed { + privateCommittedValues[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead + } - var err error - if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(privateCommitted[i]); err != nil { + var err error + if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(privateCommittedValues[i]); err != nil { + return err + } + + var res fr.Element + res, err = solveCommitmentWire(&proof.Commitments[i], hashed) + res.BigInt(out[0]) return err } - - var res fr.Element - res, err = solveCommitmentWire(&proof.Commitments[i], in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) - res.BigInt(out[0]) - return err - })) + }(i))) } _solution, err := r1cs.Solve(fullWitness, solverOpts...) @@ -107,7 +112,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b copy(commitmentsSerialized[fr.Bytes*i:], wireValues[r1cs.CommitmentInfo[i].CommitmentIndex].Marshal()) } - if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, commitmentsSerialized); err != nil { + if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommittedValues, commitmentsSerialized); err != nil { return nil, err } @@ -212,10 +217,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed - _wireValues := wireValues - for i := range r1cs.CommitmentInfo { - _wireValues = filter(_wireValues, r1cs.CommitmentInfo[i].PrivateToPublicGroth16()) - } + _wireValues := filterHeap(wireValues, r1cs.CommitmentInfo.CommitmentsAndPrivateCommittedIndexes()) if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err @@ -297,27 +299,57 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return proof, nil } +// if len(indexes) == 0, returns slice, nil +// else, returns a slice with the indexes and another without +// this assumes the indexes are sorted, without repetition and that len(slice) > len(indexes) +func split(slice []*big.Int, indexes []int) (with, without []*big.Int) { + + if len(indexes) == 0 { + return slice, nil + } + with = make([]*big.Int, 0, len(slice)-len(indexes)) + without = make([]*big.Int, 0, len(indexes)) + + j := 0 + // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) + for i := 0; i < len(slice); i++ { + if j < len(indexes) && i == indexes[j] { + without = append(without, slice[i]) + j++ + continue + } + with = append(with, slice[i]) + } + return +} + // if len(toRemove) == 0, returns slice // else, returns a new slice without the indexes in toRemove // this assumes toRemove indexes are sorted and len(slice) > len(toRemove) -func filter(slice []fr.Element, toRemove []int) (r []fr.Element) { +// filterHeap modifies toRemove +func filterHeap(slice []fr.Element, toRemove []int) (r []fr.Element) { if len(toRemove) == 0 { return slice } - r = make([]fr.Element, 0, len(slice)-len(toRemove)) - j := 0 + heap := utils.IntHeap(toRemove) + heap.Heapify() + + r = make([]fr.Element, 0, len(slice)) + // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) for i := 0; i < len(slice); i++ { - if j < len(toRemove) && i == toRemove[j] { - j++ + if len(heap) > 0 && i == heap[0] { + for len(heap) > 0 && i == heap[0] { + heap.Pop() + } continue } r = append(r, slice[i]) } - return r + return } func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index 93c7c13df9..fa838bc8b1 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -95,14 +95,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbPrivateCommittedWires := 0 - commitmentWires := make([]int, len(r1cs.CommitmentInfo)) - privateCommitted := make([][]int, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - nbPrivateCommittedWires += r1cs.CommitmentInfo[i].NbPrivateCommitted - privateCommitted[i] = r1cs.CommitmentInfo[i].PrivateCommitted() - commitmentWires[i] = r1cs.CommitmentInfo[i].CommitmentIndex - } + nbPrivateCommittedWires, commitmentWires, privateCommitted, publicAndCommitmentCommitted := + r1cs.CommitmentInfo.Interleave(r1cs.GetNbPublicVariables()) // a commitment is itself defined by a hint so the prover considers it private // but the verifier will need to inject the value itself so on the groth16 @@ -156,6 +150,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pkK := make([]fr.Element, nbPrivateWires) vkK := make([]fr.Element, nbPublicWires) ckK := make([][]fr.Element, len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + ckK[i] = make([]fr.Element, len(privateCommitted[i])) + } // see if i commits to j for i := range r1cs.CommitmentInfo { diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl index 4c24d0a451..3459ae38bf 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl @@ -11,6 +11,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/logger" @@ -50,29 +51,33 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - privateCommitted := make([][]fr.Element, len(r1cs.CommitmentInfo)) + commitmentSubIndexes := r1cs.CommitmentInfo.CommitmentIndexesInCommittedLists() + privateCommittedValues := make([][]fr.Element, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID,func(_ *big.Int, in []*big.Int, out []*big.Int) error { - if len(in) != r1cs.CommitmentInfo[i].NbCommitted() { // TODO: Remove - return fmt.Errorf("unexpected number of committed variables") - } - privateCommitted[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted) - nbPublicCommitted := len(in) - len(privateCommitted[i]) - inPrivate := in[nbPublicCommitted:] - for j, inJ := range inPrivate { - privateCommitted[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead - } + solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(i int) solver.Hint { + fmt.Println("defining, i=", i) + return func(_ *big.Int, in []*big.Int, out []*big.Int) error { + fmt.Println("executing, i=", i) + if i == 1 { + print("yo") + } + privateCommittedValues[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-len(commitmentSubIndexes[i])) + hashed, committed := internal.DivideByThresholdOrList(r1cs.CommitmentInfo[i].NbPublicCommitted(), commitmentSubIndexes[i], in) + for j, inJ := range committed { + privateCommittedValues[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead + } + + var err error + if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(privateCommittedValues[i]); err != nil { + return err + } - var err error - if proof.Commitments[i], err = pk.CommitmentKeys[i].Commit(privateCommitted[i]); err != nil { + var res fr.Element + res, err = solveCommitmentWire(&proof.Commitments[i], hashed) + res.BigInt(out[0]) return err } - - var res fr.Element - res, err = solveCommitmentWire(&proof.Commitments[i], in[:r1cs.CommitmentInfo[i].NbPublicCommitted()]) - res.BigInt(out[0]) - return err - } )) + }(i))) } _solution, err := r1cs.Solve(fullWitness, solverOpts...) @@ -90,7 +95,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b copy(commitmentsSerialized[fr.Bytes*i:], wireValues[r1cs.CommitmentInfo[i].CommitmentIndex].Marshal()) } - if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommitted, commitmentsSerialized); err != nil { + if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommittedValues, commitmentsSerialized); err != nil { return nil, err } @@ -195,10 +200,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed - _wireValues := wireValues - for i := range r1cs.CommitmentInfo { - _wireValues = filter(_wireValues, r1cs.CommitmentInfo[i].PrivateToPublicGroth16()) - } + _wireValues := filterHeap(wireValues, r1cs.CommitmentInfo.CommitmentsAndPrivateCommittedIndexes()) if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err @@ -280,27 +282,57 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return proof, nil } +// if len(indexes) == 0, returns slice, nil +// else, returns a slice with the indexes and another without +// this assumes the indexes are sorted, without repetition and that len(slice) > len(indexes) +func split(slice []*big.Int, indexes []int) (with, without []*big.Int) { + + if len(indexes) == 0 { + return slice, nil + } + with = make([]*big.Int, 0, len(slice)-len(indexes)) + without = make([]*big.Int, 0, len(indexes)) + + j := 0 + // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) + for i := 0; i < len(slice); i++ { + if j < len(indexes) && i == indexes[j] { + without = append(without, slice[i]) + j++ + continue + } + with = append(with, slice[i]) + } + return +} + // if len(toRemove) == 0, returns slice // else, returns a new slice without the indexes in toRemove // this assumes toRemove indexes are sorted and len(slice) > len(toRemove) -func filter(slice []fr.Element, toRemove []int) (r []fr.Element) { +// filterHeap modifies toRemove +func filterHeap(slice []fr.Element, toRemove []int) (r []fr.Element) { if len(toRemove) == 0 { return slice } - r = make([]fr.Element, 0, len(slice)-len(toRemove)) + + heap := utils.IntHeap(toRemove) + heap.Heapify() + + r = make([]fr.Element, 0, len(slice)) - j := 0 // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) for i:=0; i < len(slice);i++ { - if j < len(toRemove) && i == toRemove[j] { - j++ + if len(heap) > 0 && i == heap[0] { + for len(heap) > 0 && i == heap[0] { + heap.Pop() + } continue } r = append(r, slice[i]) } - return r + return } func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl index eeafdeda6e..549988cb09 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl @@ -77,14 +77,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbPrivateCommittedWires := 0 - commitmentWires := make([]int, len(r1cs.CommitmentInfo)) - privateCommitted := make([][]int, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - nbPrivateCommittedWires += r1cs.CommitmentInfo[i].NbPrivateCommitted - privateCommitted[i] = r1cs.CommitmentInfo[i].PrivateCommitted() - commitmentWires[i] = r1cs.CommitmentInfo[i].CommitmentIndex - } + nbPrivateCommittedWires, commitmentWires, privateCommitted, publicAndCommitmentCommitted := + r1cs.CommitmentInfo.Interleave(r1cs.GetNbPublicVariables()) // a commitment is itself defined by a hint so the prover considers it private // but the verifier will need to inject the value itself so on the groth16 @@ -138,6 +132,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { pkK := make([]fr.Element, nbPrivateWires) vkK := make([]fr.Element, nbPublicWires) ckK := make([][]fr.Element, len(r1cs.CommitmentInfo)) + for i := range r1cs.CommitmentInfo { + ckK[i] = make([]fr.Element, len(privateCommitted[i])) + } // see if i commits to j for i := range r1cs.CommitmentInfo { From a39ea6bd5177148fbb2a0b2cc27e664198a43cef Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 30 May 2023 22:10:25 -0500 Subject: [PATCH 412/464] build generify bn254 fixes --- backend/groth16/bls12-377/setup.go | 42 ++----------------- backend/groth16/bls12-381/setup.go | 42 ++----------------- backend/groth16/bls24-315/setup.go | 42 ++----------------- backend/groth16/bls24-317/setup.go | 42 ++----------------- backend/groth16/bw6-633/setup.go | 42 ++----------------- backend/groth16/bw6-761/setup.go | 42 ++----------------- .../zkpschemes/groth16/groth16.setup.go.tmpl | 42 ++----------------- 7 files changed, 28 insertions(+), 266 deletions(-) diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index 713bc6fa56..eb53d87d90 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -25,7 +25,6 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/pedersen" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls12-377" - "github.com/consensys/gnark/internal/utils" "math/big" "math/bits" ) @@ -154,18 +153,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { ckK[i] = make([]fr.Element, len(privateCommitted[i])) } - // see if i commits to j - for i := range r1cs.CommitmentInfo { - commitmentCommitments := 0 - - for j := 0; j < i; j++ { - if found, _ := utils.BinarySearch(privateCommitted[i], r1cs.CommitmentInfo[j].CommitmentIndex); found { - commitmentCommitments++ - } - } - ckK[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-commitmentCommitments) - } - var t0, t1 fr.Element computeK := func(i int, coeff *fr.Element) { // TODO: Inline again @@ -177,23 +164,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } vI := 0 cI := make([]int, len(r1cs.CommitmentInfo)) - nbCommitToCommit := make([]int, len(r1cs.CommitmentInfo)) - nbPrivateCommittedSeen := 0 + nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 - /* for j := range r1cs.CommitmentInfo { // skip commitments to commitments - k := 0 - l := 0 - for ; k < len(privateCommitted[j]); k++ { - for ; l < len(commitmentWires) && commitmentWires[l] < privateCommitted[j][k]; l++ {} - if k != l { - break - } - } - cI[j] = k - } - copy(nbCommitToCommit, cI)*/ - for i := range A { commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool @@ -206,11 +179,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { for j := range r1cs.CommitmentInfo { if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j - if isCommitment { - nbCommitToCommit[j]++ - } else { - break - } + break // frontend guarantees that no private variable is committed to more than once } } } @@ -222,7 +191,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vkK[vI] = t1 vI++ } else { // committed and private - ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]] = t1 + ckK[commitment][cI[commitment]] = t1 cI[commitment]++ nbPrivateCommittedSeen++ } @@ -329,10 +298,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = make([][]int, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - vk.PublicCommitted[i] = r1cs.CommitmentInfo[i].PublicCommitted() - } + vk.PublicCommitted = publicAndCommitmentCommitted // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index 222ea6b123..4955be930e 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -25,7 +25,6 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/pedersen" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls12-381" - "github.com/consensys/gnark/internal/utils" "math/big" "math/bits" ) @@ -154,18 +153,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { ckK[i] = make([]fr.Element, len(privateCommitted[i])) } - // see if i commits to j - for i := range r1cs.CommitmentInfo { - commitmentCommitments := 0 - - for j := 0; j < i; j++ { - if found, _ := utils.BinarySearch(privateCommitted[i], r1cs.CommitmentInfo[j].CommitmentIndex); found { - commitmentCommitments++ - } - } - ckK[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-commitmentCommitments) - } - var t0, t1 fr.Element computeK := func(i int, coeff *fr.Element) { // TODO: Inline again @@ -177,23 +164,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } vI := 0 cI := make([]int, len(r1cs.CommitmentInfo)) - nbCommitToCommit := make([]int, len(r1cs.CommitmentInfo)) - nbPrivateCommittedSeen := 0 + nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 - /* for j := range r1cs.CommitmentInfo { // skip commitments to commitments - k := 0 - l := 0 - for ; k < len(privateCommitted[j]); k++ { - for ; l < len(commitmentWires) && commitmentWires[l] < privateCommitted[j][k]; l++ {} - if k != l { - break - } - } - cI[j] = k - } - copy(nbCommitToCommit, cI)*/ - for i := range A { commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool @@ -206,11 +179,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { for j := range r1cs.CommitmentInfo { if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j - if isCommitment { - nbCommitToCommit[j]++ - } else { - break - } + break // frontend guarantees that no private variable is committed to more than once } } } @@ -222,7 +191,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vkK[vI] = t1 vI++ } else { // committed and private - ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]] = t1 + ckK[commitment][cI[commitment]] = t1 cI[commitment]++ nbPrivateCommittedSeen++ } @@ -329,10 +298,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = make([][]int, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - vk.PublicCommitted[i] = r1cs.CommitmentInfo[i].PublicCommitted() - } + vk.PublicCommitted = publicAndCommitmentCommitted // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index 1241da99ed..059c6db114 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -25,7 +25,6 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/pedersen" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls24-315" - "github.com/consensys/gnark/internal/utils" "math/big" "math/bits" ) @@ -154,18 +153,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { ckK[i] = make([]fr.Element, len(privateCommitted[i])) } - // see if i commits to j - for i := range r1cs.CommitmentInfo { - commitmentCommitments := 0 - - for j := 0; j < i; j++ { - if found, _ := utils.BinarySearch(privateCommitted[i], r1cs.CommitmentInfo[j].CommitmentIndex); found { - commitmentCommitments++ - } - } - ckK[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-commitmentCommitments) - } - var t0, t1 fr.Element computeK := func(i int, coeff *fr.Element) { // TODO: Inline again @@ -177,23 +164,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } vI := 0 cI := make([]int, len(r1cs.CommitmentInfo)) - nbCommitToCommit := make([]int, len(r1cs.CommitmentInfo)) - nbPrivateCommittedSeen := 0 + nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 - /* for j := range r1cs.CommitmentInfo { // skip commitments to commitments - k := 0 - l := 0 - for ; k < len(privateCommitted[j]); k++ { - for ; l < len(commitmentWires) && commitmentWires[l] < privateCommitted[j][k]; l++ {} - if k != l { - break - } - } - cI[j] = k - } - copy(nbCommitToCommit, cI)*/ - for i := range A { commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool @@ -206,11 +179,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { for j := range r1cs.CommitmentInfo { if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j - if isCommitment { - nbCommitToCommit[j]++ - } else { - break - } + break // frontend guarantees that no private variable is committed to more than once } } } @@ -222,7 +191,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vkK[vI] = t1 vI++ } else { // committed and private - ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]] = t1 + ckK[commitment][cI[commitment]] = t1 cI[commitment]++ nbPrivateCommittedSeen++ } @@ -329,10 +298,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = make([][]int, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - vk.PublicCommitted[i] = r1cs.CommitmentInfo[i].PublicCommitted() - } + vk.PublicCommitted = publicAndCommitmentCommitted // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index 489bf21264..c14b6be423 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -25,7 +25,6 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/pedersen" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls24-317" - "github.com/consensys/gnark/internal/utils" "math/big" "math/bits" ) @@ -154,18 +153,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { ckK[i] = make([]fr.Element, len(privateCommitted[i])) } - // see if i commits to j - for i := range r1cs.CommitmentInfo { - commitmentCommitments := 0 - - for j := 0; j < i; j++ { - if found, _ := utils.BinarySearch(privateCommitted[i], r1cs.CommitmentInfo[j].CommitmentIndex); found { - commitmentCommitments++ - } - } - ckK[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-commitmentCommitments) - } - var t0, t1 fr.Element computeK := func(i int, coeff *fr.Element) { // TODO: Inline again @@ -177,23 +164,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } vI := 0 cI := make([]int, len(r1cs.CommitmentInfo)) - nbCommitToCommit := make([]int, len(r1cs.CommitmentInfo)) - nbPrivateCommittedSeen := 0 + nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 - /* for j := range r1cs.CommitmentInfo { // skip commitments to commitments - k := 0 - l := 0 - for ; k < len(privateCommitted[j]); k++ { - for ; l < len(commitmentWires) && commitmentWires[l] < privateCommitted[j][k]; l++ {} - if k != l { - break - } - } - cI[j] = k - } - copy(nbCommitToCommit, cI)*/ - for i := range A { commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool @@ -206,11 +179,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { for j := range r1cs.CommitmentInfo { if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j - if isCommitment { - nbCommitToCommit[j]++ - } else { - break - } + break // frontend guarantees that no private variable is committed to more than once } } } @@ -222,7 +191,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vkK[vI] = t1 vI++ } else { // committed and private - ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]] = t1 + ckK[commitment][cI[commitment]] = t1 cI[commitment]++ nbPrivateCommittedSeen++ } @@ -329,10 +298,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = make([][]int, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - vk.PublicCommitted[i] = r1cs.CommitmentInfo[i].PublicCommitted() - } + vk.PublicCommitted = publicAndCommitmentCommitted // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index 080d59d516..e10a5240ba 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -25,7 +25,6 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/pedersen" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bw6-633" - "github.com/consensys/gnark/internal/utils" "math/big" "math/bits" ) @@ -154,18 +153,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { ckK[i] = make([]fr.Element, len(privateCommitted[i])) } - // see if i commits to j - for i := range r1cs.CommitmentInfo { - commitmentCommitments := 0 - - for j := 0; j < i; j++ { - if found, _ := utils.BinarySearch(privateCommitted[i], r1cs.CommitmentInfo[j].CommitmentIndex); found { - commitmentCommitments++ - } - } - ckK[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-commitmentCommitments) - } - var t0, t1 fr.Element computeK := func(i int, coeff *fr.Element) { // TODO: Inline again @@ -177,23 +164,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } vI := 0 cI := make([]int, len(r1cs.CommitmentInfo)) - nbCommitToCommit := make([]int, len(r1cs.CommitmentInfo)) - nbPrivateCommittedSeen := 0 + nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 - /* for j := range r1cs.CommitmentInfo { // skip commitments to commitments - k := 0 - l := 0 - for ; k < len(privateCommitted[j]); k++ { - for ; l < len(commitmentWires) && commitmentWires[l] < privateCommitted[j][k]; l++ {} - if k != l { - break - } - } - cI[j] = k - } - copy(nbCommitToCommit, cI)*/ - for i := range A { commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool @@ -206,11 +179,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { for j := range r1cs.CommitmentInfo { if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j - if isCommitment { - nbCommitToCommit[j]++ - } else { - break - } + break // frontend guarantees that no private variable is committed to more than once } } } @@ -222,7 +191,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vkK[vI] = t1 vI++ } else { // committed and private - ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]] = t1 + ckK[commitment][cI[commitment]] = t1 cI[commitment]++ nbPrivateCommittedSeen++ } @@ -329,10 +298,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = make([][]int, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - vk.PublicCommitted[i] = r1cs.CommitmentInfo[i].PublicCommitted() - } + vk.PublicCommitted = publicAndCommitmentCommitted // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index fa838bc8b1..ca7135a535 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -25,7 +25,6 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/pedersen" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bw6-761" - "github.com/consensys/gnark/internal/utils" "math/big" "math/bits" ) @@ -154,18 +153,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { ckK[i] = make([]fr.Element, len(privateCommitted[i])) } - // see if i commits to j - for i := range r1cs.CommitmentInfo { - commitmentCommitments := 0 - - for j := 0; j < i; j++ { - if found, _ := utils.BinarySearch(privateCommitted[i], r1cs.CommitmentInfo[j].CommitmentIndex); found { - commitmentCommitments++ - } - } - ckK[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-commitmentCommitments) - } - var t0, t1 fr.Element computeK := func(i int, coeff *fr.Element) { // TODO: Inline again @@ -177,23 +164,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } vI := 0 cI := make([]int, len(r1cs.CommitmentInfo)) - nbCommitToCommit := make([]int, len(r1cs.CommitmentInfo)) - nbPrivateCommittedSeen := 0 + nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 - /* for j := range r1cs.CommitmentInfo { // skip commitments to commitments - k := 0 - l := 0 - for ; k < len(privateCommitted[j]); k++ { - for ; l < len(commitmentWires) && commitmentWires[l] < privateCommitted[j][k]; l++ {} - if k != l { - break - } - } - cI[j] = k - } - copy(nbCommitToCommit, cI)*/ - for i := range A { commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool @@ -206,11 +179,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { for j := range r1cs.CommitmentInfo { if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j - if isCommitment { - nbCommitToCommit[j]++ - } else { - break - } + break // frontend guarantees that no private variable is committed to more than once } } } @@ -222,7 +191,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vkK[vI] = t1 vI++ } else { // committed and private - ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]] = t1 + ckK[commitment][cI[commitment]] = t1 cI[commitment]++ nbPrivateCommittedSeen++ } @@ -329,10 +298,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = make([][]int, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - vk.PublicCommitted[i] = r1cs.CommitmentInfo[i].PublicCommitted() - } + vk.PublicCommitted = publicAndCommitmentCommitted // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl index 549988cb09..406cc90d2d 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl @@ -7,7 +7,6 @@ import ( {{- template "import_pedersen" .}} "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/internal/utils" "math/big" "math/bits" ) @@ -136,18 +135,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { ckK[i] = make([]fr.Element, len(privateCommitted[i])) } - // see if i commits to j - for i := range r1cs.CommitmentInfo { - commitmentCommitments := 0 - - for j := 0; j < i; j++ { - if found, _ := utils.BinarySearch(privateCommitted[i], r1cs.CommitmentInfo[j].CommitmentIndex); found { - commitmentCommitments++ - } - } - ckK[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-commitmentCommitments) - } - var t0, t1 fr.Element computeK := func(i int, coeff *fr.Element) { // TODO: Inline again @@ -159,23 +146,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } vI := 0 cI := make([]int, len(r1cs.CommitmentInfo)) - nbCommitToCommit := make([]int, len(r1cs.CommitmentInfo)) - nbPrivateCommittedSeen := 0 + nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 - /* for j := range r1cs.CommitmentInfo { // skip commitments to commitments - k := 0 - l := 0 - for ; k < len(privateCommitted[j]); k++ { - for ; l < len(commitmentWires) && commitmentWires[l] < privateCommitted[j][k]; l++ {} - if k != l { - break - } - } - cI[j] = k - } - copy(nbCommitToCommit, cI)*/ - for i := range A { commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool @@ -188,11 +161,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { for j := range r1cs.CommitmentInfo { if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j - if isCommitment { - nbCommitToCommit[j]++ - } else { - break - } + break // frontend guarantees that no private variable is committed to more than once } } } @@ -204,7 +173,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { vkK[vI] = t1 vI++ } else { // committed and private - ckK[commitment][cI[commitment]-nbCommitToCommit[commitment]] = t1 + ckK[commitment][cI[commitment]] = t1 cI[commitment]++ nbPrivateCommittedSeen++ } @@ -311,10 +280,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = make([][]int, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - vk.PublicCommitted[i] = r1cs.CommitmentInfo[i].PublicCommitted() - } + vk.PublicCommitted = publicAndCommitmentCommitted // --------------------------------------------------------------------------------------------- // G2 scalars From 4d71f190c757181e8ff7c091743c7e8a4e6b9c97 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 30 May 2023 22:12:24 -0500 Subject: [PATCH 413/464] chore: clean up tests --- test/commitments_test.go | 4 ---- test/end_to_end.go | 22 ++++++++-------------- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/test/commitments_test.go b/test/commitments_test.go index f233ec3d65..8134960f61 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -109,10 +109,6 @@ type independentCommitsCircuit struct { func (c *independentCommitsCircuit) Define(api frontend.API) error { committer := api.(frontend.Committer) - /*var ( - ch []frontend.Variable - err error - )*/ for i := range c.X { if ch, err := committer.Commit(c.X[i]); err != nil { return err diff --git a/test/end_to_end.go b/test/end_to_end.go index 96c042d3b3..007220a550 100644 --- a/test/end_to_end.go +++ b/test/end_to_end.go @@ -16,8 +16,6 @@ import ( "testing" ) -const onlyGroth16Bn254 = true // TODO remove - var fr = []ecc.ID{ ecc.BN254, ecc.BLS12_381, @@ -98,18 +96,14 @@ func testGroth16(t *testing.T, assignment frontend.Circuit) { func testAll(t *testing.T, assignment frontend.Circuit) { t.Parallel() - if !onlyGroth16Bn254 { // TODO remove - t.Run("fuzzer", func(t *testing.T) { - circuit := hollow(assignment) - NewAssert(t).ProverSucceeded(circuit, assignment, WithBackends(backend.GROTH16, backend.PLONK)) // TODO: Support PlonkFri.Commit - }) - - t.Run("plonk-e2e", func(t *testing.T) { - testPlonk(t, assignment) - }) - } else { - fr = []ecc.ID{ecc.BN254} - } + t.Run("fuzzer", func(t *testing.T) { + circuit := hollow(assignment) + NewAssert(t).ProverSucceeded(circuit, assignment, WithBackends(backend.GROTH16, backend.PLONK)) // TODO: Support PlonkFri.Commit + }) + + t.Run("plonk-e2e", func(t *testing.T) { + testPlonk(t, assignment) + }) t.Run("groth16-e2e", func(t *testing.T) { testGroth16(t, assignment) From 4a72cab7509930780fea92f71a96e2be09379c88 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 30 May 2023 22:14:42 -0500 Subject: [PATCH 414/464] chore remove prints --- backend/groth16/bls12-377/prove.go | 5 ----- backend/groth16/bls12-381/prove.go | 5 ----- backend/groth16/bls24-315/prove.go | 5 ----- backend/groth16/bls24-317/prove.go | 5 ----- backend/groth16/bn254/prove.go | 5 ----- backend/groth16/bw6-633/prove.go | 5 ----- backend/groth16/bw6-761/prove.go | 5 ----- .../template/zkpschemes/groth16/groth16.prove.go.tmpl | 5 ----- 8 files changed, 40 deletions(-) diff --git a/backend/groth16/bls12-377/prove.go b/backend/groth16/bls12-377/prove.go index 1fcb1ce516..6a34d5783f 100644 --- a/backend/groth16/bls12-377/prove.go +++ b/backend/groth16/bls12-377/prove.go @@ -72,12 +72,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b privateCommittedValues := make([][]fr.Element, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(i int) solver.Hint { - fmt.Println("defining, i=", i) return func(_ *big.Int, in []*big.Int, out []*big.Int) error { - fmt.Println("executing, i=", i) - if i == 1 { - print("yo") - } privateCommittedValues[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-len(commitmentSubIndexes[i])) hashed, committed := internal.DivideByThresholdOrList(r1cs.CommitmentInfo[i].NbPublicCommitted(), commitmentSubIndexes[i], in) for j, inJ := range committed { diff --git a/backend/groth16/bls12-381/prove.go b/backend/groth16/bls12-381/prove.go index 7b9c562afc..a3b95a527d 100644 --- a/backend/groth16/bls12-381/prove.go +++ b/backend/groth16/bls12-381/prove.go @@ -72,12 +72,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b privateCommittedValues := make([][]fr.Element, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(i int) solver.Hint { - fmt.Println("defining, i=", i) return func(_ *big.Int, in []*big.Int, out []*big.Int) error { - fmt.Println("executing, i=", i) - if i == 1 { - print("yo") - } privateCommittedValues[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-len(commitmentSubIndexes[i])) hashed, committed := internal.DivideByThresholdOrList(r1cs.CommitmentInfo[i].NbPublicCommitted(), commitmentSubIndexes[i], in) for j, inJ := range committed { diff --git a/backend/groth16/bls24-315/prove.go b/backend/groth16/bls24-315/prove.go index c3ed14c11d..51910d84e6 100644 --- a/backend/groth16/bls24-315/prove.go +++ b/backend/groth16/bls24-315/prove.go @@ -72,12 +72,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b privateCommittedValues := make([][]fr.Element, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(i int) solver.Hint { - fmt.Println("defining, i=", i) return func(_ *big.Int, in []*big.Int, out []*big.Int) error { - fmt.Println("executing, i=", i) - if i == 1 { - print("yo") - } privateCommittedValues[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-len(commitmentSubIndexes[i])) hashed, committed := internal.DivideByThresholdOrList(r1cs.CommitmentInfo[i].NbPublicCommitted(), commitmentSubIndexes[i], in) for j, inJ := range committed { diff --git a/backend/groth16/bls24-317/prove.go b/backend/groth16/bls24-317/prove.go index c1a98b9686..11afdcebda 100644 --- a/backend/groth16/bls24-317/prove.go +++ b/backend/groth16/bls24-317/prove.go @@ -72,12 +72,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b privateCommittedValues := make([][]fr.Element, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(i int) solver.Hint { - fmt.Println("defining, i=", i) return func(_ *big.Int, in []*big.Int, out []*big.Int) error { - fmt.Println("executing, i=", i) - if i == 1 { - print("yo") - } privateCommittedValues[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-len(commitmentSubIndexes[i])) hashed, committed := internal.DivideByThresholdOrList(r1cs.CommitmentInfo[i].NbPublicCommitted(), commitmentSubIndexes[i], in) for j, inJ := range committed { diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index b45775be12..39742b40d0 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -72,12 +72,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b privateCommittedValues := make([][]fr.Element, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(i int) solver.Hint { - fmt.Println("defining, i=", i) return func(_ *big.Int, in []*big.Int, out []*big.Int) error { - fmt.Println("executing, i=", i) - if i == 1 { - print("yo") - } privateCommittedValues[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-len(commitmentSubIndexes[i])) hashed, committed := internal.DivideByThresholdOrList(r1cs.CommitmentInfo[i].NbPublicCommitted(), commitmentSubIndexes[i], in) for j, inJ := range committed { diff --git a/backend/groth16/bw6-633/prove.go b/backend/groth16/bw6-633/prove.go index be293f56f7..b5c7b6a331 100644 --- a/backend/groth16/bw6-633/prove.go +++ b/backend/groth16/bw6-633/prove.go @@ -72,12 +72,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b privateCommittedValues := make([][]fr.Element, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(i int) solver.Hint { - fmt.Println("defining, i=", i) return func(_ *big.Int, in []*big.Int, out []*big.Int) error { - fmt.Println("executing, i=", i) - if i == 1 { - print("yo") - } privateCommittedValues[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-len(commitmentSubIndexes[i])) hashed, committed := internal.DivideByThresholdOrList(r1cs.CommitmentInfo[i].NbPublicCommitted(), commitmentSubIndexes[i], in) for j, inJ := range committed { diff --git a/backend/groth16/bw6-761/prove.go b/backend/groth16/bw6-761/prove.go index c11ef9c11b..c0fdd0501d 100644 --- a/backend/groth16/bw6-761/prove.go +++ b/backend/groth16/bw6-761/prove.go @@ -72,12 +72,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b privateCommittedValues := make([][]fr.Element, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(i int) solver.Hint { - fmt.Println("defining, i=", i) return func(_ *big.Int, in []*big.Int, out []*big.Int) error { - fmt.Println("executing, i=", i) - if i == 1 { - print("yo") - } privateCommittedValues[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-len(commitmentSubIndexes[i])) hashed, committed := internal.DivideByThresholdOrList(r1cs.CommitmentInfo[i].NbPublicCommitted(), commitmentSubIndexes[i], in) for j, inJ := range committed { diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl index 3459ae38bf..e89cc7c609 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl @@ -55,12 +55,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b privateCommittedValues := make([][]fr.Element, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(i int) solver.Hint { - fmt.Println("defining, i=", i) return func(_ *big.Int, in []*big.Int, out []*big.Int) error { - fmt.Println("executing, i=", i) - if i == 1 { - print("yo") - } privateCommittedValues[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-len(commitmentSubIndexes[i])) hashed, committed := internal.DivideByThresholdOrList(r1cs.CommitmentInfo[i].NbPublicCommitted(), commitmentSubIndexes[i], in) for j, inJ := range committed { From 56be842ef76f061dcc1ee9e4ff177a976e11ad25 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 31 May 2023 15:39:59 -0500 Subject: [PATCH 415/464] fix: remove unnecessary import --- backend/groth16/bls12-377/prove.go | 1 - backend/groth16/bls12-381/prove.go | 1 - backend/groth16/bls24-315/prove.go | 1 - backend/groth16/bls24-317/prove.go | 1 - backend/groth16/bn254/prove.go | 1 - backend/groth16/bw6-633/prove.go | 1 - backend/groth16/bw6-761/prove.go | 1 - .../backend/template/zkpschemes/groth16/groth16.prove.go.tmpl | 1 - 8 files changed, 8 deletions(-) diff --git a/backend/groth16/bls12-377/prove.go b/backend/groth16/bls12-377/prove.go index 6a34d5783f..c8edd2e3f2 100644 --- a/backend/groth16/bls12-377/prove.go +++ b/backend/groth16/bls12-377/prove.go @@ -17,7 +17,6 @@ package groth16 import ( - "fmt" "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bls12-377" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" diff --git a/backend/groth16/bls12-381/prove.go b/backend/groth16/bls12-381/prove.go index a3b95a527d..50c3711363 100644 --- a/backend/groth16/bls12-381/prove.go +++ b/backend/groth16/bls12-381/prove.go @@ -17,7 +17,6 @@ package groth16 import ( - "fmt" "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bls12-381" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" diff --git a/backend/groth16/bls24-315/prove.go b/backend/groth16/bls24-315/prove.go index 51910d84e6..415ab11df0 100644 --- a/backend/groth16/bls24-315/prove.go +++ b/backend/groth16/bls24-315/prove.go @@ -17,7 +17,6 @@ package groth16 import ( - "fmt" "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bls24-315" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" diff --git a/backend/groth16/bls24-317/prove.go b/backend/groth16/bls24-317/prove.go index 11afdcebda..dd8ce912ba 100644 --- a/backend/groth16/bls24-317/prove.go +++ b/backend/groth16/bls24-317/prove.go @@ -17,7 +17,6 @@ package groth16 import ( - "fmt" "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bls24-317" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index 39742b40d0..a3a5e1ec6d 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -17,7 +17,6 @@ package groth16 import ( - "fmt" "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr" diff --git a/backend/groth16/bw6-633/prove.go b/backend/groth16/bw6-633/prove.go index b5c7b6a331..719696b93b 100644 --- a/backend/groth16/bw6-633/prove.go +++ b/backend/groth16/bw6-633/prove.go @@ -17,7 +17,6 @@ package groth16 import ( - "fmt" "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bw6-633" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" diff --git a/backend/groth16/bw6-761/prove.go b/backend/groth16/bw6-761/prove.go index c0fdd0501d..da3d48d925 100644 --- a/backend/groth16/bw6-761/prove.go +++ b/backend/groth16/bw6-761/prove.go @@ -17,7 +17,6 @@ package groth16 import ( - "fmt" "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bw6-761" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl index e89cc7c609..6934847941 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl @@ -1,5 +1,4 @@ import ( - "fmt" {{- template "import_fr" . }} {{- template "import_curve" . }} {{- template "import_backend_cs" . }} From 09e9a1e8f012eb9e9fe6efdf0cd5a4ebf8cae448 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 31 May 2023 17:28:49 -0500 Subject: [PATCH 416/464] fix: groth16 works. plonk fuzzer fails --- frontend/cs/r1cs/api.go | 20 +++++++++---------- test/commitments_test.go | 42 ++++++++++++++++++++++++++++------------ test/end_to_end.go | 3 +-- 3 files changed, 41 insertions(+), 24 deletions(-) diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index 4b44531717..9ba52e44af 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -686,7 +686,7 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error // initialize the min-heap // this is the same algorithm as api.add --> we want to merge k sorted linear expression for lID, v := range vars { - builder.heap = append(builder.heap, linMeta{val: v[0].VID, lID: lID}) + builder.heap = append(builder.heap, linMeta{val: v[0].VID, lID: lID}) // TODO: Use int heap } builder.heap.heapify() @@ -716,27 +716,27 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error // it's the same variable ID, do nothing continue } else { - // append, it's a new variable ID - committed = append(committed, t.VID) if t.VID < builder.cs.GetNbPublicVariables() { nbPublicCommitted++ } else { // Cannot commit to a secret variable that has already been committed to // instead we commit to its commitment commitments := builder.cs.GetCommitments() + var alreadyCommitted bool for i := range commitments { - if alreadyCommitted, _ := utils.BinarySearch(commitments[i].Committed, t.VID); alreadyCommitted { + if alreadyCommitted, _ = utils.BinarySearch(commitments[i].Committed, t.VID); alreadyCommitted { toCommit := commitments[i].CommitmentIndex - if alreadyCommitted, toInsert := utils.BinarySearch(committed, toCommit); alreadyCommitted { - committed = committed[:len(committed)-1] // variable already represented - } else { - copy(committed[toInsert+1:], committed[toInsert:]) - committed[toInsert] = toCommit - } + vars = append(vars, expr.LinearExpression{{Coeff: constraint.Element{1}, VID: toCommit}}) // TODO Replace with mont 1 + builder.heap.push(linMeta{lID: len(vars) - 1, tID: 0, val: toCommit}) break } } + if alreadyCommitted { + continue + } } + // append, it's a new variable ID + committed = append(committed, t.VID) // if public or not already committed curr++ } } diff --git a/test/commitments_test.go b/test/commitments_test.go index 8134960f61..ccc3c4728c 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -1,7 +1,8 @@ package test import ( - "fmt" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/backend" "github.com/consensys/gnark/frontend" "github.com/stretchr/testify/assert" "reflect" @@ -29,7 +30,7 @@ type commitmentCircuit struct { func (c *commitmentCircuit) Define(api frontend.API) error { - commitment, err := tryCommit(api, c.X...) + commitment, err := api.(frontend.Committer).Commit(c.X...) if err != nil { return err } @@ -74,7 +75,7 @@ type committedConstantCircuit struct { } func (c *committedConstantCircuit) Define(api frontend.API) error { - commitment, err := tryCommit(api, 1, c.X) + commitment, err := api.(frontend.Committer).Commit(1, c.X) if err != nil { return err } @@ -91,7 +92,7 @@ type committedPublicCircuit struct { } func (c *committedPublicCircuit) Define(api frontend.API) error { - commitment, err := tryCommit(api, c.X) + commitment, err := api.(frontend.Committer).Commit(c.X) if err != nil { return err } @@ -145,6 +146,31 @@ func TestTwoCommit(t *testing.T) { testAll(t, &twoCommitCircuit{X: []frontend.Variable{1, 2}, Y: 3}) } +type doubleCommitCircuit struct { + X, Y frontend.Variable +} + +func (c *doubleCommitCircuit) Define(api frontend.API) error { + var c0, c1 frontend.Variable + var err error + if c0, err = api.(frontend.Committer).Commit(c.X); err != nil { + return err + } + if c1, err = api.(frontend.Committer).Commit(c.X, c.Y); err != nil { + return err + } + api.AssertIsDifferent(c0, c1) + return nil +} + +func TestDoubleCommit(t *testing.T) { + testAll(t, &doubleCommitCircuit{X: 1, Y: 2}) +} + +func TestDoubleCommitFail(t *testing.T) { + NewAssert(t).ProverSucceeded(&doubleCommitCircuit{}, &doubleCommitCircuit{X: 1, Y: 1}, WithBackends(backend.PLONK), WithCurves(ecc.BN254)) +} + func TestHollow(t *testing.T) { run := func(c, expected frontend.Circuit) func(t *testing.T) { @@ -168,11 +194,3 @@ func TestHollow(t *testing.T) { t.Run(removePackageName(reflect.TypeOf(assignments[i]).String()), run(assignments[i], expected[i])) } } - -func tryCommit(api frontend.API, x ...frontend.Variable) (frontend.Variable, error) { - committer, ok := api.(frontend.Committer) - if !ok { - return nil, fmt.Errorf("type %T doesn't impl the Committer interface", api) - } - return committer.Commit(x...) -} diff --git a/test/end_to_end.go b/test/end_to_end.go index 007220a550..1924d7b199 100644 --- a/test/end_to_end.go +++ b/test/end_to_end.go @@ -97,8 +97,7 @@ func testAll(t *testing.T, assignment frontend.Circuit) { t.Parallel() t.Run("fuzzer", func(t *testing.T) { - circuit := hollow(assignment) - NewAssert(t).ProverSucceeded(circuit, assignment, WithBackends(backend.GROTH16, backend.PLONK)) // TODO: Support PlonkFri.Commit + NewAssert(t).ProverSucceeded(hollow(assignment), assignment, WithCurves(ecc.BN254), WithBackends(backend.GROTH16, backend.PLONK)) // TODO: Support PlonkFri.Commit }) t.Run("plonk-e2e", func(t *testing.T) { From 2457d31d4b2e3cccbc3fb4f1e057808dc083e237 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Thu, 1 Jun 2023 13:36:31 -0500 Subject: [PATCH 417/464] refactor failing test --- test/commitments_test.go | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/test/commitments_test.go b/test/commitments_test.go index ccc3c4728c..9c0fe9df78 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -1,12 +1,15 @@ package test import ( + "reflect" + "testing" + "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark/backend" "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/frontend/cs/scs" "github.com/stretchr/testify/assert" - "reflect" - "testing" + "github.com/stretchr/testify/require" ) type noCommitmentCircuit struct { @@ -168,7 +171,34 @@ func TestDoubleCommit(t *testing.T) { } func TestDoubleCommitFail(t *testing.T) { - NewAssert(t).ProverSucceeded(&doubleCommitCircuit{}, &doubleCommitCircuit{X: 1, Y: 1}, WithBackends(backend.PLONK), WithCurves(ecc.BN254)) + assert := require.New(t) + + var assignment doubleCommitCircuit + assignment.X = 0 + assignment.Y = 0 + + w, err := frontend.NewWitness(&assignment, ecc.BN254.ScalarField()) + assert.NoError(err) + + // Solve with test engine: OK + err = IsSolved(&doubleCommitCircuit{}, &assignment, ecc.BN254.ScalarField()) + assert.NoError(err) + + // Solve with R1CS: OK + ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &doubleCommitCircuit{}) + assert.NoError(err) + + _, err = ccs.Solve(w) + assert.NoError(err) + + // Solve with SCS: NOK + ccs, err = frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, &doubleCommitCircuit{}) + assert.NoError(err) + + _, err = ccs.Solve(w) + assert.NoError(err) + + // NewAssert(t).ProverSucceeded(&doubleCommitCircuit{}, &doubleCommitCircuit{X: 1, Y: 1}, WithBackends(backend.PLONK), WithCurves(ecc.BN254)) } func TestHollow(t *testing.T) { From bb53099ae1a9319120f19e20e2849340694e3385 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 1 Jun 2023 14:46:23 -0500 Subject: [PATCH 418/464] fix: randomize fake commitments --- frontend/cs/commitment.go | 13 +++++++++---- test/commitments_test.go | 31 +++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/frontend/cs/commitment.go b/frontend/cs/commitment.go index f0d555ee2d..a37464ee63 100644 --- a/frontend/cs/commitment.go +++ b/frontend/cs/commitment.go @@ -1,6 +1,7 @@ package cs import ( + "crypto/rand" "crypto/sha256" "fmt" "github.com/consensys/gnark/constraint/solver" @@ -18,11 +19,15 @@ func Bsb22CommitmentComputePlaceholder(mod *big.Int, input []*big.Int, output [] if (len(os.Args) > 0 && (strings.HasSuffix(os.Args[0], ".test") || strings.HasSuffix(os.Args[0], ".test.exe"))) || debug.Debug { // usually we only run solver without prover during testing log := logger.Logger() - log.Error().Msg("Augmented groth16 commitment hint not replaced. Proof will not be sound and verification will fail!") - toHash := make([]byte, 0, (1+mod.BitLen()/8)*len(input)) - for _, in := range input { + log.Error().Msg("Augmented commitment hint not replaced. Proof will not be sound and verification will fail!") + byteLen := 1 + mod.BitLen()/8 + toHash := make([]byte, byteLen*len(input)+32) + for i, in := range input { inBytes := in.Bytes() - toHash = append(toHash, inBytes[:]...) + copy(toHash[(i+1)*byteLen-len(inBytes):], inBytes) + } + if n, err := rand.Read(toHash[len(toHash)-32:]); err != nil || n != 32 { + return fmt.Errorf("generated %d random bytes: %v", n, err) } hsh := sha256.New().Sum(toHash) output[0].SetBytes(hsh) diff --git a/test/commitments_test.go b/test/commitments_test.go index 4336ef546e..b0bc6c2bb1 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -186,3 +186,34 @@ func TestTwoCommitPlonk(t *testing.T) { assignment := &twoCommitCircuit{X: []frontend.Variable{1, 2}, Y: 3} plonkTest(t, &twoCommitCircuit{X: make([]frontend.Variable, len(assignment.X))}, assignment) } + +type commitUniquenessCircuit struct { + X []frontend.Variable +} + +func (c *commitUniquenessCircuit) Define(api frontend.API) error { + var err error + + ch := make([]frontend.Variable, len(c.X)) + for i := range c.X { + if ch[i], err = api.(frontend.Committer).Commit(c.X[i]); err != nil { + return err + } + for j := 0; j < i; j++ { + api.AssertIsDifferent(ch[i], ch[j]) + } + } + return nil +} + +func TestCommitUniquenessZerosScs(t *testing.T) { + + w, err := frontend.NewWitness(&commitUniquenessCircuit{[]frontend.Variable{0, 0}}, ecc.BN254.ScalarField()) + assert.NoError(t, err) + + ccs, err := frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, &commitUniquenessCircuit{[]frontend.Variable{nil, nil}}) + assert.NoError(t, err) + + _, err = ccs.Solve(w) + assert.NoError(t, err) +} From bcb3764d3b31b3c79264e1e387890d0fe2d90aca Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 1 Jun 2023 14:53:38 -0500 Subject: [PATCH 419/464] feat: commitment placeholder -> randomness --- frontend/cs/commitment.go | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/frontend/cs/commitment.go b/frontend/cs/commitment.go index a37464ee63..d08b987fb4 100644 --- a/frontend/cs/commitment.go +++ b/frontend/cs/commitment.go @@ -2,7 +2,6 @@ package cs import ( "crypto/rand" - "crypto/sha256" "fmt" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/debug" @@ -15,25 +14,13 @@ import ( "sync" ) -func Bsb22CommitmentComputePlaceholder(mod *big.Int, input []*big.Int, output []*big.Int) error { +func Bsb22CommitmentComputePlaceholder(mod *big.Int, input []*big.Int, output []*big.Int) (err error) { if (len(os.Args) > 0 && (strings.HasSuffix(os.Args[0], ".test") || strings.HasSuffix(os.Args[0], ".test.exe"))) || debug.Debug { // usually we only run solver without prover during testing log := logger.Logger() log.Error().Msg("Augmented commitment hint not replaced. Proof will not be sound and verification will fail!") - byteLen := 1 + mod.BitLen()/8 - toHash := make([]byte, byteLen*len(input)+32) - for i, in := range input { - inBytes := in.Bytes() - copy(toHash[(i+1)*byteLen-len(inBytes):], inBytes) - } - if n, err := rand.Read(toHash[len(toHash)-32:]); err != nil || n != 32 { - return fmt.Errorf("generated %d random bytes: %v", n, err) - } - hsh := sha256.New().Sum(toHash) - output[0].SetBytes(hsh) - output[0].Mod(output[0], mod) - - return nil + output[0], err = rand.Int(rand.Reader, mod) + return } return fmt.Errorf("placeholder function: to be replaced by commitment computation") } From 331a1800e42dd13bec4654af9f9f2858d56bbcc0 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 1 Jun 2023 14:55:26 -0500 Subject: [PATCH 420/464] style: unused input -> _ --- frontend/cs/commitment.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/cs/commitment.go b/frontend/cs/commitment.go index d08b987fb4..e8b92478f9 100644 --- a/frontend/cs/commitment.go +++ b/frontend/cs/commitment.go @@ -14,7 +14,7 @@ import ( "sync" ) -func Bsb22CommitmentComputePlaceholder(mod *big.Int, input []*big.Int, output []*big.Int) (err error) { +func Bsb22CommitmentComputePlaceholder(mod *big.Int, _ []*big.Int, output []*big.Int) (err error) { if (len(os.Args) > 0 && (strings.HasSuffix(os.Args[0], ".test") || strings.HasSuffix(os.Args[0], ".test.exe"))) || debug.Debug { // usually we only run solver without prover during testing log := logger.Logger() From 9f689a97bc4309aeb51337b97f0f1635b2577aff Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 1 Jun 2023 17:48:52 -0500 Subject: [PATCH 421/464] test all curves --- test/commitments_test.go | 2 +- test/end_to_end.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/commitments_test.go b/test/commitments_test.go index 6b2ea0971b..5e137c04f3 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -244,7 +244,7 @@ func (c *commitUniquenessCircuit) Define(api frontend.API) error { return nil } -func TestCommitUniquenessZerosScs(t *testing.T) { +func TestCommitUniquenessZerosScs(t *testing.T) { // TODO @Tabaie Randomize Groth16 commitments for real w, err := frontend.NewWitness(&commitUniquenessCircuit{[]frontend.Variable{0, 0}}, ecc.BN254.ScalarField()) assert.NoError(t, err) diff --git a/test/end_to_end.go b/test/end_to_end.go index 1924d7b199..9c9eea12c4 100644 --- a/test/end_to_end.go +++ b/test/end_to_end.go @@ -97,7 +97,7 @@ func testAll(t *testing.T, assignment frontend.Circuit) { t.Parallel() t.Run("fuzzer", func(t *testing.T) { - NewAssert(t).ProverSucceeded(hollow(assignment), assignment, WithCurves(ecc.BN254), WithBackends(backend.GROTH16, backend.PLONK)) // TODO: Support PlonkFri.Commit + NewAssert(t).ProverSucceeded(hollow(assignment), assignment, WithBackends(backend.GROTH16, backend.PLONK)) // TODO: Support PlonkFri.Commit }) t.Run("plonk-e2e", func(t *testing.T) { From 5711c4ae475535ce2a0febdeade86ff98914a378 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 2 Jun 2023 14:06:51 -0500 Subject: [PATCH 422/464] feat: commitment info in groth16.vk[bn254] serialization --- backend/groth16/bn254/marshal.go | 44 +++++++++++++++++-- backend/groth16/bn254/marshal_test.go | 43 +++++++++++++++--- .../groth16/internal/test_utils/test_utils.go | 14 ++++++ go.mod | 2 +- go.sum | 8 +--- internal/utils/convert.go | 31 ++++++++++++- test/commitments_test.go | 33 -------------- 7 files changed, 123 insertions(+), 52 deletions(-) create mode 100644 backend/groth16/internal/test_utils/test_utils.go diff --git a/backend/groth16/bn254/marshal.go b/backend/groth16/bn254/marshal.go index f906599f75..ea95c71a4c 100644 --- a/backend/groth16/bn254/marshal.go +++ b/backend/groth16/bn254/marshal.go @@ -18,6 +18,7 @@ package groth16 import ( curve "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark/internal/utils" "io" ) @@ -78,14 +79,24 @@ func (proof *Proof) ReadFrom(r io.Reader) (n int64, err error) { // points are compressed // use WriteRawTo(...) to encode the key without point compression func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { - return vk.writeTo(w, false) + if n, err = vk.writeTo(w, false); err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.WriteTo(w) + return m + n, err } // WriteRawTo writes binary encoding of the key elements to writer // points are not compressed // use WriteTo(...) to encode the key with point compression func (vk *VerifyingKey) WriteRawTo(w io.Writer) (n int64, err error) { - return vk.writeTo(w, true) + if n, err = vk.writeTo(w, true); err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.WriteRawTo(w) + return m + n, err } // writeTo serialization format: @@ -124,6 +135,14 @@ func (vk *VerifyingKey) writeTo(w io.Writer, raw bool) (int64, error) { if err := enc.Encode(vk.G1.K); err != nil { return enc.BytesWritten(), err } + + if vk.PublicCommitted == nil { + vk.PublicCommitted = [][]int{} // only matters in tests + } + if err := enc.Encode(utils.IntSliceSliceToUint64SliceSlice(vk.PublicCommitted)); err != nil { + return enc.BytesWritten(), err + } + return enc.BytesWritten(), nil } @@ -133,13 +152,25 @@ func (vk *VerifyingKey) writeTo(w io.Writer, raw bool) (int64, error) { // https://github.com/zkcrypto/bellman/blob/fa9be45588227a8c6ec34957de3f68705f07bd92/src/groth16/mod.rs#L143 // [α]1,[β]1,[β]2,[γ]2,[δ]1,[δ]2,uint32(len(Kvk)),[Kvk]1 func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { - return vk.readFrom(r) + n, err := vk.readFrom(r) + if err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.ReadFrom(r) + return m + n, err } // UnsafeReadFrom has the same behavior as ReadFrom, except that it will not check that decode points // are on the curve and in the correct subgroup. func (vk *VerifyingKey) UnsafeReadFrom(r io.Reader) (int64, error) { - return vk.readFrom(r, curve.NoSubgroupChecks()) + n, err := vk.readFrom(r, curve.NoSubgroupChecks()) + if err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.UnsafeReadFrom(r) + return m + n, err } func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) (int64, error) { @@ -169,6 +200,11 @@ func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder) if err := dec.Decode(&vk.G1.K); err != nil { return dec.BytesRead(), err } + var publicCommitted [][]uint64 + if err := dec.Decode(&publicCommitted); err != nil { + return dec.BytesRead(), err + } + vk.PublicCommitted = utils.Uint64SliceSliceToIntSliceSlice(publicCommitted) // recompute vk.e (e(α, β)) and -[δ]2, -[γ]2 if err := vk.Precompute(); err != nil { diff --git a/backend/groth16/bn254/marshal_test.go b/backend/groth16/bn254/marshal_test.go index 2db9e45415..ee85c8ec93 100644 --- a/backend/groth16/bn254/marshal_test.go +++ b/backend/groth16/bn254/marshal_test.go @@ -18,6 +18,9 @@ package groth16 import ( curve "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/pedersen" + "github.com/consensys/gnark/backend/groth16/internal/test_utils" + "github.com/stretchr/testify/assert" "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" @@ -87,13 +90,9 @@ func TestProofSerialization(t *testing.T) { } func TestVerifyingKeySerialization(t *testing.T) { - parameters := gopter.DefaultTestParameters() - parameters.MinSuccessfulTests = 10 - - properties := gopter.NewProperties(parameters) - properties.Property("VerifyingKey -> writer -> reader -> VerifyingKey should stay constant", prop.ForAll( - func(p1 curve.G1Affine, p2 curve.G2Affine) bool { + roundTrip := func(withCommitment bool) func(curve.G1Affine, curve.G2Affine) bool { + return func(p1 curve.G1Affine, p2 curve.G2Affine) bool { var vk, vkCompressed, vkRaw VerifyingKey // create a random vk @@ -121,6 +120,21 @@ func TestVerifyingKeySerialization(t *testing.T) { vk.G1.K[i] = p1 } + if withCommitment { + vk.PublicCommitted = test_utils.Random2DIntSlice(5, 10) // TODO: Use gopter randomization + bases := make([][]curve.G1Affine, len(vk.PublicCommitted)) + elem := p1 + for i := 0; i < len(vk.PublicCommitted); i++ { + bases[i] = make([]curve.G1Affine, len(vk.PublicCommitted[i])) + for j := range bases[i] { + bases[i][j] = elem + elem.Add(&elem, &p1) + } + } + _, vk.CommitmentKey, err = pedersen.Setup(bases...) + assert.NoError(t, err) + } + var bufCompressed bytes.Buffer written, err := vk.WriteTo(&bufCompressed) if err != nil { @@ -158,7 +172,22 @@ func TestVerifyingKeySerialization(t *testing.T) { } return reflect.DeepEqual(&vk, &vkCompressed) && reflect.DeepEqual(&vk, &vkRaw) - }, + } + } + + parameters := gopter.DefaultTestParameters() + parameters.MinSuccessfulTests = 10 + + properties := gopter.NewProperties(parameters) + + properties.Property("VerifyingKey -> writer -> reader -> VerifyingKey should stay constant", prop.ForAll( + roundTrip(false), + GenG1(), + GenG2(), + )) + + properties.Property("VerifyingKey (with commitments) -> writer -> reader -> VerifyingKey should stay constant", prop.ForAll( + roundTrip(true), GenG1(), GenG2(), )) diff --git a/backend/groth16/internal/test_utils/test_utils.go b/backend/groth16/internal/test_utils/test_utils.go new file mode 100644 index 0000000000..75cb44a08c --- /dev/null +++ b/backend/groth16/internal/test_utils/test_utils.go @@ -0,0 +1,14 @@ +package test_utils + +import "math/rand" + +func Random2DIntSlice(maxN, maxM int) [][]int { + res := make([][]int, rand.Intn(maxN)) + for i := range res { + res[i] = make([]int, rand.Intn(maxM)) + for j := range res[i] { + res[i][j] = rand.Int() + } + } + return res +} diff --git a/go.mod b/go.mod index b5c291b943..c7537d1765 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/bits-and-blooms/bitset v1.5.0 github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 - github.com/consensys/gnark-crypto v0.11.1-0.20230525183059-684135cb6410 + github.com/consensys/gnark-crypto v0.11.1-0.20230602185655-ff9bcec080c7 github.com/fxamacker/cbor/v2 v2.4.0 github.com/google/go-cmp v0.5.9 github.com/google/pprof v0.0.0-20230309165930-d61513b1440d diff --git a/go.sum b/go.sum index 8854233e5e..298ce09a43 100644 --- a/go.sum +++ b/go.sum @@ -4,12 +4,8 @@ github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.11.1-0.20230508024855-0cd4994b7f0b h1:owSc8rrE2Tdl7xYxFgdPgx52qlO1fFDujW07aSGrffM= -github.com/consensys/gnark-crypto v0.11.1-0.20230508024855-0cd4994b7f0b/go.mod h1:6C2ytC8zmP8uH2GKVfPOjf0Vw3KwMAaUxlCPK5WQqmw= -github.com/consensys/gnark-crypto v0.11.1-0.20230524003106-85db474ed631 h1:6rTz7p7/ph+UNqh9QYSaOv8JdzYnbOO/x4WLB4MZog4= -github.com/consensys/gnark-crypto v0.11.1-0.20230524003106-85db474ed631/go.mod h1:6C2ytC8zmP8uH2GKVfPOjf0Vw3KwMAaUxlCPK5WQqmw= -github.com/consensys/gnark-crypto v0.11.1-0.20230525183059-684135cb6410 h1:MWbTUH7IV4pOu0O1fG2G6h3GuKI9Bu3tAffskwOW2+I= -github.com/consensys/gnark-crypto v0.11.1-0.20230525183059-684135cb6410/go.mod h1:6C2ytC8zmP8uH2GKVfPOjf0Vw3KwMAaUxlCPK5WQqmw= +github.com/consensys/gnark-crypto v0.11.1-0.20230602185655-ff9bcec080c7 h1:Pi5ONVS8L+U35O7f00faO0h56EZNztHLvHwnGkACIYU= +github.com/consensys/gnark-crypto v0.11.1-0.20230602185655-ff9bcec080c7/go.mod h1:6C2ytC8zmP8uH2GKVfPOjf0Vw3KwMAaUxlCPK5WQqmw= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/internal/utils/convert.go b/internal/utils/convert.go index 7ca9ba1674..3bc19c6758 100644 --- a/internal/utils/convert.go +++ b/internal/utils/convert.go @@ -15,6 +15,7 @@ package utils import ( + "math" "math/big" "reflect" ) @@ -60,7 +61,7 @@ func FromInterface(input interface{}) big.Int { case int32: r.SetInt64(int64(v)) case int64: - r.SetInt64(int64(v)) + r.SetInt64(v) case int: r.SetInt64(int64(v)) case string: @@ -87,3 +88,31 @@ func FromInterface(input interface{}) big.Int { return r } + +func IntSliceSliceToUint64SliceSlice(in [][]int) [][]uint64 { + res := make([][]uint64, len(in)) + for i := range in { + res[i] = make([]uint64, len(in[i])) + for j := range in[i] { + if in[i][j] < 0 { + panic("negative value in int slice") + } + res[i][j] = uint64(in[i][j]) + } + } + return res +} + +func Uint64SliceSliceToIntSliceSlice(in [][]uint64) [][]int { + res := make([][]int, len(in)) + for i := range in { + res[i] = make([]int, len(in[i])) + for j := range in[i] { + if in[i][j] >= math.MaxInt { + panic("too large") + } + res[i][j] = int(in[i][j]) + } + } + return res +} diff --git a/test/commitments_test.go b/test/commitments_test.go index 5e137c04f3..d0a1988862 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -6,10 +6,8 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/consensys/gnark/frontend/cs/scs" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) type noCommitmentCircuit struct { @@ -170,37 +168,6 @@ func TestDoubleCommit(t *testing.T) { testAll(t, &doubleCommitCircuit{X: 1, Y: 2}) } -func TestDoubleCommitFail(t *testing.T) { - assert := require.New(t) - - var assignment doubleCommitCircuit - assignment.X = 0 - assignment.Y = 0 - - w, err := frontend.NewWitness(&assignment, ecc.BN254.ScalarField()) - assert.NoError(err) - - // Solve with test engine: OK - err = IsSolved(&doubleCommitCircuit{}, &assignment, ecc.BN254.ScalarField()) - assert.NoError(err) - - // Solve with R1CS: OK - ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &doubleCommitCircuit{}) - assert.NoError(err) - - _, err = ccs.Solve(w) - assert.NoError(err) - - // Solve with SCS: NOK - ccs, err = frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, &doubleCommitCircuit{}) - assert.NoError(err) - - _, err = ccs.Solve(w) - assert.NoError(err) - - // NewAssert(t).ProverSucceeded(&doubleCommitCircuit{}, &doubleCommitCircuit{X: 1, Y: 1}, WithBackends(backend.PLONK), WithCurves(ecc.BN254)) -} - func TestHollow(t *testing.T) { run := func(c, expected frontend.Circuit) func(t *testing.T) { From b2d64b0b9d34e340b021993a1a6e19fef72c160a Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 2 Jun 2023 14:19:03 -0500 Subject: [PATCH 423/464] build: generify --- backend/groth16/bls12-377/marshal.go | 44 +++++++++++++++++-- backend/groth16/bls12-377/marshal_test.go | 44 ++++++++++++++++--- backend/groth16/bls12-381/marshal.go | 44 +++++++++++++++++-- backend/groth16/bls12-381/marshal_test.go | 44 ++++++++++++++++--- backend/groth16/bls24-315/marshal.go | 44 +++++++++++++++++-- backend/groth16/bls24-315/marshal_test.go | 44 ++++++++++++++++--- backend/groth16/bls24-317/marshal.go | 44 +++++++++++++++++-- backend/groth16/bls24-317/marshal_test.go | 44 ++++++++++++++++--- backend/groth16/bn254/marshal_test.go | 5 ++- backend/groth16/bw6-633/marshal.go | 44 +++++++++++++++++-- backend/groth16/bw6-633/marshal_test.go | 44 ++++++++++++++++--- backend/groth16/bw6-761/marshal.go | 44 +++++++++++++++++-- backend/groth16/bw6-761/marshal_test.go | 44 ++++++++++++++++--- .../groth16/groth16.marshal.go.tmpl | 44 +++++++++++++++++-- .../groth16/tests/groth16.marshal.go.tmpl | 43 ++++++++++++++---- 15 files changed, 540 insertions(+), 80 deletions(-) diff --git a/backend/groth16/bls12-377/marshal.go b/backend/groth16/bls12-377/marshal.go index e4fdff1a48..34c0828f09 100644 --- a/backend/groth16/bls12-377/marshal.go +++ b/backend/groth16/bls12-377/marshal.go @@ -18,6 +18,7 @@ package groth16 import ( curve "github.com/consensys/gnark-crypto/ecc/bls12-377" + "github.com/consensys/gnark/internal/utils" "io" ) @@ -78,14 +79,24 @@ func (proof *Proof) ReadFrom(r io.Reader) (n int64, err error) { // points are compressed // use WriteRawTo(...) to encode the key without point compression func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { - return vk.writeTo(w, false) + if n, err = vk.writeTo(w, false); err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.WriteTo(w) + return m + n, err } // WriteRawTo writes binary encoding of the key elements to writer // points are not compressed // use WriteTo(...) to encode the key with point compression func (vk *VerifyingKey) WriteRawTo(w io.Writer) (n int64, err error) { - return vk.writeTo(w, true) + if n, err = vk.writeTo(w, true); err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.WriteRawTo(w) + return m + n, err } // writeTo serialization format: @@ -124,6 +135,14 @@ func (vk *VerifyingKey) writeTo(w io.Writer, raw bool) (int64, error) { if err := enc.Encode(vk.G1.K); err != nil { return enc.BytesWritten(), err } + + if vk.PublicCommitted == nil { + vk.PublicCommitted = [][]int{} // only matters in tests + } + if err := enc.Encode(utils.IntSliceSliceToUint64SliceSlice(vk.PublicCommitted)); err != nil { + return enc.BytesWritten(), err + } + return enc.BytesWritten(), nil } @@ -133,13 +152,25 @@ func (vk *VerifyingKey) writeTo(w io.Writer, raw bool) (int64, error) { // https://github.com/zkcrypto/bellman/blob/fa9be45588227a8c6ec34957de3f68705f07bd92/src/groth16/mod.rs#L143 // [α]1,[β]1,[β]2,[γ]2,[δ]1,[δ]2,uint32(len(Kvk)),[Kvk]1 func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { - return vk.readFrom(r) + n, err := vk.readFrom(r) + if err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.ReadFrom(r) + return m + n, err } // UnsafeReadFrom has the same behavior as ReadFrom, except that it will not check that decode points // are on the curve and in the correct subgroup. func (vk *VerifyingKey) UnsafeReadFrom(r io.Reader) (int64, error) { - return vk.readFrom(r, curve.NoSubgroupChecks()) + n, err := vk.readFrom(r, curve.NoSubgroupChecks()) + if err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.UnsafeReadFrom(r) + return m + n, err } func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) (int64, error) { @@ -169,6 +200,11 @@ func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder) if err := dec.Decode(&vk.G1.K); err != nil { return dec.BytesRead(), err } + var publicCommitted [][]uint64 + if err := dec.Decode(&publicCommitted); err != nil { + return dec.BytesRead(), err + } + vk.PublicCommitted = utils.Uint64SliceSliceToIntSliceSlice(publicCommitted) // recompute vk.e (e(α, β)) and -[δ]2, -[γ]2 if err := vk.Precompute(); err != nil { diff --git a/backend/groth16/bls12-377/marshal_test.go b/backend/groth16/bls12-377/marshal_test.go index 901d6f885f..5a572e147d 100644 --- a/backend/groth16/bls12-377/marshal_test.go +++ b/backend/groth16/bls12-377/marshal_test.go @@ -21,6 +21,10 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/pedersen" + "github.com/consensys/gnark/backend/groth16/internal/test_utils" + "github.com/stretchr/testify/assert" + "bytes" "math/big" "reflect" @@ -87,13 +91,9 @@ func TestProofSerialization(t *testing.T) { } func TestVerifyingKeySerialization(t *testing.T) { - parameters := gopter.DefaultTestParameters() - parameters.MinSuccessfulTests = 10 - properties := gopter.NewProperties(parameters) - - properties.Property("VerifyingKey -> writer -> reader -> VerifyingKey should stay constant", prop.ForAll( - func(p1 curve.G1Affine, p2 curve.G2Affine) bool { + roundTrip := func(withCommitment bool) func(curve.G1Affine, curve.G2Affine) bool { + return func(p1 curve.G1Affine, p2 curve.G2Affine) bool { var vk, vkCompressed, vkRaw VerifyingKey // create a random vk @@ -121,6 +121,21 @@ func TestVerifyingKeySerialization(t *testing.T) { vk.G1.K[i] = p1 } + if withCommitment { + vk.PublicCommitted = test_utils.Random2DIntSlice(5, 10) // TODO: Use gopter randomization + bases := make([][]curve.G1Affine, len(vk.PublicCommitted)) + elem := p1 + for i := 0; i < len(vk.PublicCommitted); i++ { + bases[i] = make([]curve.G1Affine, len(vk.PublicCommitted[i])) + for j := range bases[i] { + bases[i][j] = elem + elem.Add(&elem, &p1) + } + } + _, vk.CommitmentKey, err = pedersen.Setup(bases...) + assert.NoError(t, err) + } + var bufCompressed bytes.Buffer written, err := vk.WriteTo(&bufCompressed) if err != nil { @@ -158,7 +173,22 @@ func TestVerifyingKeySerialization(t *testing.T) { } return reflect.DeepEqual(&vk, &vkCompressed) && reflect.DeepEqual(&vk, &vkRaw) - }, + } + } + + parameters := gopter.DefaultTestParameters() + parameters.MinSuccessfulTests = 10 + + properties := gopter.NewProperties(parameters) + + properties.Property("VerifyingKey -> writer -> reader -> VerifyingKey should stay constant", prop.ForAll( + roundTrip(false), + GenG1(), + GenG2(), + )) + + properties.Property("VerifyingKey (with commitments) -> writer -> reader -> VerifyingKey should stay constant", prop.ForAll( + roundTrip(true), GenG1(), GenG2(), )) diff --git a/backend/groth16/bls12-381/marshal.go b/backend/groth16/bls12-381/marshal.go index bb544afd21..93a77a6733 100644 --- a/backend/groth16/bls12-381/marshal.go +++ b/backend/groth16/bls12-381/marshal.go @@ -18,6 +18,7 @@ package groth16 import ( curve "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark/internal/utils" "io" ) @@ -78,14 +79,24 @@ func (proof *Proof) ReadFrom(r io.Reader) (n int64, err error) { // points are compressed // use WriteRawTo(...) to encode the key without point compression func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { - return vk.writeTo(w, false) + if n, err = vk.writeTo(w, false); err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.WriteTo(w) + return m + n, err } // WriteRawTo writes binary encoding of the key elements to writer // points are not compressed // use WriteTo(...) to encode the key with point compression func (vk *VerifyingKey) WriteRawTo(w io.Writer) (n int64, err error) { - return vk.writeTo(w, true) + if n, err = vk.writeTo(w, true); err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.WriteRawTo(w) + return m + n, err } // writeTo serialization format: @@ -124,6 +135,14 @@ func (vk *VerifyingKey) writeTo(w io.Writer, raw bool) (int64, error) { if err := enc.Encode(vk.G1.K); err != nil { return enc.BytesWritten(), err } + + if vk.PublicCommitted == nil { + vk.PublicCommitted = [][]int{} // only matters in tests + } + if err := enc.Encode(utils.IntSliceSliceToUint64SliceSlice(vk.PublicCommitted)); err != nil { + return enc.BytesWritten(), err + } + return enc.BytesWritten(), nil } @@ -133,13 +152,25 @@ func (vk *VerifyingKey) writeTo(w io.Writer, raw bool) (int64, error) { // https://github.com/zkcrypto/bellman/blob/fa9be45588227a8c6ec34957de3f68705f07bd92/src/groth16/mod.rs#L143 // [α]1,[β]1,[β]2,[γ]2,[δ]1,[δ]2,uint32(len(Kvk)),[Kvk]1 func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { - return vk.readFrom(r) + n, err := vk.readFrom(r) + if err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.ReadFrom(r) + return m + n, err } // UnsafeReadFrom has the same behavior as ReadFrom, except that it will not check that decode points // are on the curve and in the correct subgroup. func (vk *VerifyingKey) UnsafeReadFrom(r io.Reader) (int64, error) { - return vk.readFrom(r, curve.NoSubgroupChecks()) + n, err := vk.readFrom(r, curve.NoSubgroupChecks()) + if err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.UnsafeReadFrom(r) + return m + n, err } func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) (int64, error) { @@ -169,6 +200,11 @@ func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder) if err := dec.Decode(&vk.G1.K); err != nil { return dec.BytesRead(), err } + var publicCommitted [][]uint64 + if err := dec.Decode(&publicCommitted); err != nil { + return dec.BytesRead(), err + } + vk.PublicCommitted = utils.Uint64SliceSliceToIntSliceSlice(publicCommitted) // recompute vk.e (e(α, β)) and -[δ]2, -[γ]2 if err := vk.Precompute(); err != nil { diff --git a/backend/groth16/bls12-381/marshal_test.go b/backend/groth16/bls12-381/marshal_test.go index 990e3ee6b1..157520b5cd 100644 --- a/backend/groth16/bls12-381/marshal_test.go +++ b/backend/groth16/bls12-381/marshal_test.go @@ -21,6 +21,10 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/fft" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/pedersen" + "github.com/consensys/gnark/backend/groth16/internal/test_utils" + "github.com/stretchr/testify/assert" + "bytes" "math/big" "reflect" @@ -87,13 +91,9 @@ func TestProofSerialization(t *testing.T) { } func TestVerifyingKeySerialization(t *testing.T) { - parameters := gopter.DefaultTestParameters() - parameters.MinSuccessfulTests = 10 - properties := gopter.NewProperties(parameters) - - properties.Property("VerifyingKey -> writer -> reader -> VerifyingKey should stay constant", prop.ForAll( - func(p1 curve.G1Affine, p2 curve.G2Affine) bool { + roundTrip := func(withCommitment bool) func(curve.G1Affine, curve.G2Affine) bool { + return func(p1 curve.G1Affine, p2 curve.G2Affine) bool { var vk, vkCompressed, vkRaw VerifyingKey // create a random vk @@ -121,6 +121,21 @@ func TestVerifyingKeySerialization(t *testing.T) { vk.G1.K[i] = p1 } + if withCommitment { + vk.PublicCommitted = test_utils.Random2DIntSlice(5, 10) // TODO: Use gopter randomization + bases := make([][]curve.G1Affine, len(vk.PublicCommitted)) + elem := p1 + for i := 0; i < len(vk.PublicCommitted); i++ { + bases[i] = make([]curve.G1Affine, len(vk.PublicCommitted[i])) + for j := range bases[i] { + bases[i][j] = elem + elem.Add(&elem, &p1) + } + } + _, vk.CommitmentKey, err = pedersen.Setup(bases...) + assert.NoError(t, err) + } + var bufCompressed bytes.Buffer written, err := vk.WriteTo(&bufCompressed) if err != nil { @@ -158,7 +173,22 @@ func TestVerifyingKeySerialization(t *testing.T) { } return reflect.DeepEqual(&vk, &vkCompressed) && reflect.DeepEqual(&vk, &vkRaw) - }, + } + } + + parameters := gopter.DefaultTestParameters() + parameters.MinSuccessfulTests = 10 + + properties := gopter.NewProperties(parameters) + + properties.Property("VerifyingKey -> writer -> reader -> VerifyingKey should stay constant", prop.ForAll( + roundTrip(false), + GenG1(), + GenG2(), + )) + + properties.Property("VerifyingKey (with commitments) -> writer -> reader -> VerifyingKey should stay constant", prop.ForAll( + roundTrip(true), GenG1(), GenG2(), )) diff --git a/backend/groth16/bls24-315/marshal.go b/backend/groth16/bls24-315/marshal.go index 6a53616cd7..b4e3c6037b 100644 --- a/backend/groth16/bls24-315/marshal.go +++ b/backend/groth16/bls24-315/marshal.go @@ -18,6 +18,7 @@ package groth16 import ( curve "github.com/consensys/gnark-crypto/ecc/bls24-315" + "github.com/consensys/gnark/internal/utils" "io" ) @@ -78,14 +79,24 @@ func (proof *Proof) ReadFrom(r io.Reader) (n int64, err error) { // points are compressed // use WriteRawTo(...) to encode the key without point compression func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { - return vk.writeTo(w, false) + if n, err = vk.writeTo(w, false); err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.WriteTo(w) + return m + n, err } // WriteRawTo writes binary encoding of the key elements to writer // points are not compressed // use WriteTo(...) to encode the key with point compression func (vk *VerifyingKey) WriteRawTo(w io.Writer) (n int64, err error) { - return vk.writeTo(w, true) + if n, err = vk.writeTo(w, true); err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.WriteRawTo(w) + return m + n, err } // writeTo serialization format: @@ -124,6 +135,14 @@ func (vk *VerifyingKey) writeTo(w io.Writer, raw bool) (int64, error) { if err := enc.Encode(vk.G1.K); err != nil { return enc.BytesWritten(), err } + + if vk.PublicCommitted == nil { + vk.PublicCommitted = [][]int{} // only matters in tests + } + if err := enc.Encode(utils.IntSliceSliceToUint64SliceSlice(vk.PublicCommitted)); err != nil { + return enc.BytesWritten(), err + } + return enc.BytesWritten(), nil } @@ -133,13 +152,25 @@ func (vk *VerifyingKey) writeTo(w io.Writer, raw bool) (int64, error) { // https://github.com/zkcrypto/bellman/blob/fa9be45588227a8c6ec34957de3f68705f07bd92/src/groth16/mod.rs#L143 // [α]1,[β]1,[β]2,[γ]2,[δ]1,[δ]2,uint32(len(Kvk)),[Kvk]1 func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { - return vk.readFrom(r) + n, err := vk.readFrom(r) + if err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.ReadFrom(r) + return m + n, err } // UnsafeReadFrom has the same behavior as ReadFrom, except that it will not check that decode points // are on the curve and in the correct subgroup. func (vk *VerifyingKey) UnsafeReadFrom(r io.Reader) (int64, error) { - return vk.readFrom(r, curve.NoSubgroupChecks()) + n, err := vk.readFrom(r, curve.NoSubgroupChecks()) + if err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.UnsafeReadFrom(r) + return m + n, err } func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) (int64, error) { @@ -169,6 +200,11 @@ func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder) if err := dec.Decode(&vk.G1.K); err != nil { return dec.BytesRead(), err } + var publicCommitted [][]uint64 + if err := dec.Decode(&publicCommitted); err != nil { + return dec.BytesRead(), err + } + vk.PublicCommitted = utils.Uint64SliceSliceToIntSliceSlice(publicCommitted) // recompute vk.e (e(α, β)) and -[δ]2, -[γ]2 if err := vk.Precompute(); err != nil { diff --git a/backend/groth16/bls24-315/marshal_test.go b/backend/groth16/bls24-315/marshal_test.go index 06bf1ec9de..b6bea935af 100644 --- a/backend/groth16/bls24-315/marshal_test.go +++ b/backend/groth16/bls24-315/marshal_test.go @@ -21,6 +21,10 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/fft" + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/pedersen" + "github.com/consensys/gnark/backend/groth16/internal/test_utils" + "github.com/stretchr/testify/assert" + "bytes" "math/big" "reflect" @@ -87,13 +91,9 @@ func TestProofSerialization(t *testing.T) { } func TestVerifyingKeySerialization(t *testing.T) { - parameters := gopter.DefaultTestParameters() - parameters.MinSuccessfulTests = 10 - properties := gopter.NewProperties(parameters) - - properties.Property("VerifyingKey -> writer -> reader -> VerifyingKey should stay constant", prop.ForAll( - func(p1 curve.G1Affine, p2 curve.G2Affine) bool { + roundTrip := func(withCommitment bool) func(curve.G1Affine, curve.G2Affine) bool { + return func(p1 curve.G1Affine, p2 curve.G2Affine) bool { var vk, vkCompressed, vkRaw VerifyingKey // create a random vk @@ -121,6 +121,21 @@ func TestVerifyingKeySerialization(t *testing.T) { vk.G1.K[i] = p1 } + if withCommitment { + vk.PublicCommitted = test_utils.Random2DIntSlice(5, 10) // TODO: Use gopter randomization + bases := make([][]curve.G1Affine, len(vk.PublicCommitted)) + elem := p1 + for i := 0; i < len(vk.PublicCommitted); i++ { + bases[i] = make([]curve.G1Affine, len(vk.PublicCommitted[i])) + for j := range bases[i] { + bases[i][j] = elem + elem.Add(&elem, &p1) + } + } + _, vk.CommitmentKey, err = pedersen.Setup(bases...) + assert.NoError(t, err) + } + var bufCompressed bytes.Buffer written, err := vk.WriteTo(&bufCompressed) if err != nil { @@ -158,7 +173,22 @@ func TestVerifyingKeySerialization(t *testing.T) { } return reflect.DeepEqual(&vk, &vkCompressed) && reflect.DeepEqual(&vk, &vkRaw) - }, + } + } + + parameters := gopter.DefaultTestParameters() + parameters.MinSuccessfulTests = 10 + + properties := gopter.NewProperties(parameters) + + properties.Property("VerifyingKey -> writer -> reader -> VerifyingKey should stay constant", prop.ForAll( + roundTrip(false), + GenG1(), + GenG2(), + )) + + properties.Property("VerifyingKey (with commitments) -> writer -> reader -> VerifyingKey should stay constant", prop.ForAll( + roundTrip(true), GenG1(), GenG2(), )) diff --git a/backend/groth16/bls24-317/marshal.go b/backend/groth16/bls24-317/marshal.go index 6aeab91292..c6f6b24261 100644 --- a/backend/groth16/bls24-317/marshal.go +++ b/backend/groth16/bls24-317/marshal.go @@ -18,6 +18,7 @@ package groth16 import ( curve "github.com/consensys/gnark-crypto/ecc/bls24-317" + "github.com/consensys/gnark/internal/utils" "io" ) @@ -78,14 +79,24 @@ func (proof *Proof) ReadFrom(r io.Reader) (n int64, err error) { // points are compressed // use WriteRawTo(...) to encode the key without point compression func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { - return vk.writeTo(w, false) + if n, err = vk.writeTo(w, false); err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.WriteTo(w) + return m + n, err } // WriteRawTo writes binary encoding of the key elements to writer // points are not compressed // use WriteTo(...) to encode the key with point compression func (vk *VerifyingKey) WriteRawTo(w io.Writer) (n int64, err error) { - return vk.writeTo(w, true) + if n, err = vk.writeTo(w, true); err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.WriteRawTo(w) + return m + n, err } // writeTo serialization format: @@ -124,6 +135,14 @@ func (vk *VerifyingKey) writeTo(w io.Writer, raw bool) (int64, error) { if err := enc.Encode(vk.G1.K); err != nil { return enc.BytesWritten(), err } + + if vk.PublicCommitted == nil { + vk.PublicCommitted = [][]int{} // only matters in tests + } + if err := enc.Encode(utils.IntSliceSliceToUint64SliceSlice(vk.PublicCommitted)); err != nil { + return enc.BytesWritten(), err + } + return enc.BytesWritten(), nil } @@ -133,13 +152,25 @@ func (vk *VerifyingKey) writeTo(w io.Writer, raw bool) (int64, error) { // https://github.com/zkcrypto/bellman/blob/fa9be45588227a8c6ec34957de3f68705f07bd92/src/groth16/mod.rs#L143 // [α]1,[β]1,[β]2,[γ]2,[δ]1,[δ]2,uint32(len(Kvk)),[Kvk]1 func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { - return vk.readFrom(r) + n, err := vk.readFrom(r) + if err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.ReadFrom(r) + return m + n, err } // UnsafeReadFrom has the same behavior as ReadFrom, except that it will not check that decode points // are on the curve and in the correct subgroup. func (vk *VerifyingKey) UnsafeReadFrom(r io.Reader) (int64, error) { - return vk.readFrom(r, curve.NoSubgroupChecks()) + n, err := vk.readFrom(r, curve.NoSubgroupChecks()) + if err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.UnsafeReadFrom(r) + return m + n, err } func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) (int64, error) { @@ -169,6 +200,11 @@ func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder) if err := dec.Decode(&vk.G1.K); err != nil { return dec.BytesRead(), err } + var publicCommitted [][]uint64 + if err := dec.Decode(&publicCommitted); err != nil { + return dec.BytesRead(), err + } + vk.PublicCommitted = utils.Uint64SliceSliceToIntSliceSlice(publicCommitted) // recompute vk.e (e(α, β)) and -[δ]2, -[γ]2 if err := vk.Precompute(); err != nil { diff --git a/backend/groth16/bls24-317/marshal_test.go b/backend/groth16/bls24-317/marshal_test.go index aa75c1d456..4e37fe2b88 100644 --- a/backend/groth16/bls24-317/marshal_test.go +++ b/backend/groth16/bls24-317/marshal_test.go @@ -21,6 +21,10 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/fft" + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/pedersen" + "github.com/consensys/gnark/backend/groth16/internal/test_utils" + "github.com/stretchr/testify/assert" + "bytes" "math/big" "reflect" @@ -87,13 +91,9 @@ func TestProofSerialization(t *testing.T) { } func TestVerifyingKeySerialization(t *testing.T) { - parameters := gopter.DefaultTestParameters() - parameters.MinSuccessfulTests = 10 - properties := gopter.NewProperties(parameters) - - properties.Property("VerifyingKey -> writer -> reader -> VerifyingKey should stay constant", prop.ForAll( - func(p1 curve.G1Affine, p2 curve.G2Affine) bool { + roundTrip := func(withCommitment bool) func(curve.G1Affine, curve.G2Affine) bool { + return func(p1 curve.G1Affine, p2 curve.G2Affine) bool { var vk, vkCompressed, vkRaw VerifyingKey // create a random vk @@ -121,6 +121,21 @@ func TestVerifyingKeySerialization(t *testing.T) { vk.G1.K[i] = p1 } + if withCommitment { + vk.PublicCommitted = test_utils.Random2DIntSlice(5, 10) // TODO: Use gopter randomization + bases := make([][]curve.G1Affine, len(vk.PublicCommitted)) + elem := p1 + for i := 0; i < len(vk.PublicCommitted); i++ { + bases[i] = make([]curve.G1Affine, len(vk.PublicCommitted[i])) + for j := range bases[i] { + bases[i][j] = elem + elem.Add(&elem, &p1) + } + } + _, vk.CommitmentKey, err = pedersen.Setup(bases...) + assert.NoError(t, err) + } + var bufCompressed bytes.Buffer written, err := vk.WriteTo(&bufCompressed) if err != nil { @@ -158,7 +173,22 @@ func TestVerifyingKeySerialization(t *testing.T) { } return reflect.DeepEqual(&vk, &vkCompressed) && reflect.DeepEqual(&vk, &vkRaw) - }, + } + } + + parameters := gopter.DefaultTestParameters() + parameters.MinSuccessfulTests = 10 + + properties := gopter.NewProperties(parameters) + + properties.Property("VerifyingKey -> writer -> reader -> VerifyingKey should stay constant", prop.ForAll( + roundTrip(false), + GenG1(), + GenG2(), + )) + + properties.Property("VerifyingKey (with commitments) -> writer -> reader -> VerifyingKey should stay constant", prop.ForAll( + roundTrip(true), GenG1(), GenG2(), )) diff --git a/backend/groth16/bn254/marshal_test.go b/backend/groth16/bn254/marshal_test.go index ee85c8ec93..5a90e4b36f 100644 --- a/backend/groth16/bn254/marshal_test.go +++ b/backend/groth16/bn254/marshal_test.go @@ -18,12 +18,13 @@ package groth16 import ( curve "github.com/consensys/gnark-crypto/ecc/bn254" + + "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/pedersen" "github.com/consensys/gnark/backend/groth16/internal/test_utils" "github.com/stretchr/testify/assert" - "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" - "bytes" "math/big" "reflect" diff --git a/backend/groth16/bw6-633/marshal.go b/backend/groth16/bw6-633/marshal.go index cb7e234fc5..c44d794d14 100644 --- a/backend/groth16/bw6-633/marshal.go +++ b/backend/groth16/bw6-633/marshal.go @@ -18,6 +18,7 @@ package groth16 import ( curve "github.com/consensys/gnark-crypto/ecc/bw6-633" + "github.com/consensys/gnark/internal/utils" "io" ) @@ -78,14 +79,24 @@ func (proof *Proof) ReadFrom(r io.Reader) (n int64, err error) { // points are compressed // use WriteRawTo(...) to encode the key without point compression func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { - return vk.writeTo(w, false) + if n, err = vk.writeTo(w, false); err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.WriteTo(w) + return m + n, err } // WriteRawTo writes binary encoding of the key elements to writer // points are not compressed // use WriteTo(...) to encode the key with point compression func (vk *VerifyingKey) WriteRawTo(w io.Writer) (n int64, err error) { - return vk.writeTo(w, true) + if n, err = vk.writeTo(w, true); err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.WriteRawTo(w) + return m + n, err } // writeTo serialization format: @@ -124,6 +135,14 @@ func (vk *VerifyingKey) writeTo(w io.Writer, raw bool) (int64, error) { if err := enc.Encode(vk.G1.K); err != nil { return enc.BytesWritten(), err } + + if vk.PublicCommitted == nil { + vk.PublicCommitted = [][]int{} // only matters in tests + } + if err := enc.Encode(utils.IntSliceSliceToUint64SliceSlice(vk.PublicCommitted)); err != nil { + return enc.BytesWritten(), err + } + return enc.BytesWritten(), nil } @@ -133,13 +152,25 @@ func (vk *VerifyingKey) writeTo(w io.Writer, raw bool) (int64, error) { // https://github.com/zkcrypto/bellman/blob/fa9be45588227a8c6ec34957de3f68705f07bd92/src/groth16/mod.rs#L143 // [α]1,[β]1,[β]2,[γ]2,[δ]1,[δ]2,uint32(len(Kvk)),[Kvk]1 func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { - return vk.readFrom(r) + n, err := vk.readFrom(r) + if err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.ReadFrom(r) + return m + n, err } // UnsafeReadFrom has the same behavior as ReadFrom, except that it will not check that decode points // are on the curve and in the correct subgroup. func (vk *VerifyingKey) UnsafeReadFrom(r io.Reader) (int64, error) { - return vk.readFrom(r, curve.NoSubgroupChecks()) + n, err := vk.readFrom(r, curve.NoSubgroupChecks()) + if err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.UnsafeReadFrom(r) + return m + n, err } func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) (int64, error) { @@ -169,6 +200,11 @@ func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder) if err := dec.Decode(&vk.G1.K); err != nil { return dec.BytesRead(), err } + var publicCommitted [][]uint64 + if err := dec.Decode(&publicCommitted); err != nil { + return dec.BytesRead(), err + } + vk.PublicCommitted = utils.Uint64SliceSliceToIntSliceSlice(publicCommitted) // recompute vk.e (e(α, β)) and -[δ]2, -[γ]2 if err := vk.Precompute(); err != nil { diff --git a/backend/groth16/bw6-633/marshal_test.go b/backend/groth16/bw6-633/marshal_test.go index b2a3a63d4b..b1630b93fe 100644 --- a/backend/groth16/bw6-633/marshal_test.go +++ b/backend/groth16/bw6-633/marshal_test.go @@ -21,6 +21,10 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/fft" + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/pedersen" + "github.com/consensys/gnark/backend/groth16/internal/test_utils" + "github.com/stretchr/testify/assert" + "bytes" "math/big" "reflect" @@ -87,13 +91,9 @@ func TestProofSerialization(t *testing.T) { } func TestVerifyingKeySerialization(t *testing.T) { - parameters := gopter.DefaultTestParameters() - parameters.MinSuccessfulTests = 10 - properties := gopter.NewProperties(parameters) - - properties.Property("VerifyingKey -> writer -> reader -> VerifyingKey should stay constant", prop.ForAll( - func(p1 curve.G1Affine, p2 curve.G2Affine) bool { + roundTrip := func(withCommitment bool) func(curve.G1Affine, curve.G2Affine) bool { + return func(p1 curve.G1Affine, p2 curve.G2Affine) bool { var vk, vkCompressed, vkRaw VerifyingKey // create a random vk @@ -121,6 +121,21 @@ func TestVerifyingKeySerialization(t *testing.T) { vk.G1.K[i] = p1 } + if withCommitment { + vk.PublicCommitted = test_utils.Random2DIntSlice(5, 10) // TODO: Use gopter randomization + bases := make([][]curve.G1Affine, len(vk.PublicCommitted)) + elem := p1 + for i := 0; i < len(vk.PublicCommitted); i++ { + bases[i] = make([]curve.G1Affine, len(vk.PublicCommitted[i])) + for j := range bases[i] { + bases[i][j] = elem + elem.Add(&elem, &p1) + } + } + _, vk.CommitmentKey, err = pedersen.Setup(bases...) + assert.NoError(t, err) + } + var bufCompressed bytes.Buffer written, err := vk.WriteTo(&bufCompressed) if err != nil { @@ -158,7 +173,22 @@ func TestVerifyingKeySerialization(t *testing.T) { } return reflect.DeepEqual(&vk, &vkCompressed) && reflect.DeepEqual(&vk, &vkRaw) - }, + } + } + + parameters := gopter.DefaultTestParameters() + parameters.MinSuccessfulTests = 10 + + properties := gopter.NewProperties(parameters) + + properties.Property("VerifyingKey -> writer -> reader -> VerifyingKey should stay constant", prop.ForAll( + roundTrip(false), + GenG1(), + GenG2(), + )) + + properties.Property("VerifyingKey (with commitments) -> writer -> reader -> VerifyingKey should stay constant", prop.ForAll( + roundTrip(true), GenG1(), GenG2(), )) diff --git a/backend/groth16/bw6-761/marshal.go b/backend/groth16/bw6-761/marshal.go index 662ece22be..568e050a9e 100644 --- a/backend/groth16/bw6-761/marshal.go +++ b/backend/groth16/bw6-761/marshal.go @@ -18,6 +18,7 @@ package groth16 import ( curve "github.com/consensys/gnark-crypto/ecc/bw6-761" + "github.com/consensys/gnark/internal/utils" "io" ) @@ -78,14 +79,24 @@ func (proof *Proof) ReadFrom(r io.Reader) (n int64, err error) { // points are compressed // use WriteRawTo(...) to encode the key without point compression func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { - return vk.writeTo(w, false) + if n, err = vk.writeTo(w, false); err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.WriteTo(w) + return m + n, err } // WriteRawTo writes binary encoding of the key elements to writer // points are not compressed // use WriteTo(...) to encode the key with point compression func (vk *VerifyingKey) WriteRawTo(w io.Writer) (n int64, err error) { - return vk.writeTo(w, true) + if n, err = vk.writeTo(w, true); err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.WriteRawTo(w) + return m + n, err } // writeTo serialization format: @@ -124,6 +135,14 @@ func (vk *VerifyingKey) writeTo(w io.Writer, raw bool) (int64, error) { if err := enc.Encode(vk.G1.K); err != nil { return enc.BytesWritten(), err } + + if vk.PublicCommitted == nil { + vk.PublicCommitted = [][]int{} // only matters in tests + } + if err := enc.Encode(utils.IntSliceSliceToUint64SliceSlice(vk.PublicCommitted)); err != nil { + return enc.BytesWritten(), err + } + return enc.BytesWritten(), nil } @@ -133,13 +152,25 @@ func (vk *VerifyingKey) writeTo(w io.Writer, raw bool) (int64, error) { // https://github.com/zkcrypto/bellman/blob/fa9be45588227a8c6ec34957de3f68705f07bd92/src/groth16/mod.rs#L143 // [α]1,[β]1,[β]2,[γ]2,[δ]1,[δ]2,uint32(len(Kvk)),[Kvk]1 func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { - return vk.readFrom(r) + n, err := vk.readFrom(r) + if err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.ReadFrom(r) + return m + n, err } // UnsafeReadFrom has the same behavior as ReadFrom, except that it will not check that decode points // are on the curve and in the correct subgroup. func (vk *VerifyingKey) UnsafeReadFrom(r io.Reader) (int64, error) { - return vk.readFrom(r, curve.NoSubgroupChecks()) + n, err := vk.readFrom(r, curve.NoSubgroupChecks()) + if err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.UnsafeReadFrom(r) + return m + n, err } func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) (int64, error) { @@ -169,6 +200,11 @@ func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder) if err := dec.Decode(&vk.G1.K); err != nil { return dec.BytesRead(), err } + var publicCommitted [][]uint64 + if err := dec.Decode(&publicCommitted); err != nil { + return dec.BytesRead(), err + } + vk.PublicCommitted = utils.Uint64SliceSliceToIntSliceSlice(publicCommitted) // recompute vk.e (e(α, β)) and -[δ]2, -[γ]2 if err := vk.Precompute(); err != nil { diff --git a/backend/groth16/bw6-761/marshal_test.go b/backend/groth16/bw6-761/marshal_test.go index bccf077d51..158be28ba8 100644 --- a/backend/groth16/bw6-761/marshal_test.go +++ b/backend/groth16/bw6-761/marshal_test.go @@ -21,6 +21,10 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/fft" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/pedersen" + "github.com/consensys/gnark/backend/groth16/internal/test_utils" + "github.com/stretchr/testify/assert" + "bytes" "math/big" "reflect" @@ -87,13 +91,9 @@ func TestProofSerialization(t *testing.T) { } func TestVerifyingKeySerialization(t *testing.T) { - parameters := gopter.DefaultTestParameters() - parameters.MinSuccessfulTests = 10 - properties := gopter.NewProperties(parameters) - - properties.Property("VerifyingKey -> writer -> reader -> VerifyingKey should stay constant", prop.ForAll( - func(p1 curve.G1Affine, p2 curve.G2Affine) bool { + roundTrip := func(withCommitment bool) func(curve.G1Affine, curve.G2Affine) bool { + return func(p1 curve.G1Affine, p2 curve.G2Affine) bool { var vk, vkCompressed, vkRaw VerifyingKey // create a random vk @@ -121,6 +121,21 @@ func TestVerifyingKeySerialization(t *testing.T) { vk.G1.K[i] = p1 } + if withCommitment { + vk.PublicCommitted = test_utils.Random2DIntSlice(5, 10) // TODO: Use gopter randomization + bases := make([][]curve.G1Affine, len(vk.PublicCommitted)) + elem := p1 + for i := 0; i < len(vk.PublicCommitted); i++ { + bases[i] = make([]curve.G1Affine, len(vk.PublicCommitted[i])) + for j := range bases[i] { + bases[i][j] = elem + elem.Add(&elem, &p1) + } + } + _, vk.CommitmentKey, err = pedersen.Setup(bases...) + assert.NoError(t, err) + } + var bufCompressed bytes.Buffer written, err := vk.WriteTo(&bufCompressed) if err != nil { @@ -158,7 +173,22 @@ func TestVerifyingKeySerialization(t *testing.T) { } return reflect.DeepEqual(&vk, &vkCompressed) && reflect.DeepEqual(&vk, &vkRaw) - }, + } + } + + parameters := gopter.DefaultTestParameters() + parameters.MinSuccessfulTests = 10 + + properties := gopter.NewProperties(parameters) + + properties.Property("VerifyingKey -> writer -> reader -> VerifyingKey should stay constant", prop.ForAll( + roundTrip(false), + GenG1(), + GenG2(), + )) + + properties.Property("VerifyingKey (with commitments) -> writer -> reader -> VerifyingKey should stay constant", prop.ForAll( + roundTrip(true), GenG1(), GenG2(), )) diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl index e29c0f451e..8f021dbf7a 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl @@ -1,5 +1,6 @@ import ( {{ template "import_curve" . }} + "github.com/consensys/gnark/internal/utils" "io" ) @@ -61,14 +62,24 @@ func (proof *Proof) ReadFrom(r io.Reader) (n int64, err error) { // points are compressed // use WriteRawTo(...) to encode the key without point compression func (vk *VerifyingKey) WriteTo(w io.Writer) (n int64, err error) { - return vk.writeTo(w, false) + if n, err = vk.writeTo(w, false); err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.WriteTo(w) + return m + n, err } // WriteRawTo writes binary encoding of the key elements to writer // points are not compressed // use WriteTo(...) to encode the key with point compression func (vk *VerifyingKey) WriteRawTo(w io.Writer) (n int64, err error) { - return vk.writeTo(w, true) + if n, err = vk.writeTo(w, true); err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.WriteRawTo(w) + return m + n, err } // writeTo serialization format: @@ -108,6 +119,14 @@ func (vk *VerifyingKey) writeTo(w io.Writer, raw bool) (int64, error) { if err := enc.Encode(vk.G1.K); err != nil { return enc.BytesWritten(), err } + + if vk.PublicCommitted == nil { + vk.PublicCommitted = [][]int{} // only matters in tests + } + if err := enc.Encode(utils.IntSliceSliceToUint64SliceSlice(vk.PublicCommitted)); err != nil { + return enc.BytesWritten(), err + } + return enc.BytesWritten(), nil } @@ -117,13 +136,25 @@ func (vk *VerifyingKey) writeTo(w io.Writer, raw bool) (int64, error) { // https://github.com/zkcrypto/bellman/blob/fa9be45588227a8c6ec34957de3f68705f07bd92/src/groth16/mod.rs#L143 // [α]1,[β]1,[β]2,[γ]2,[δ]1,[δ]2,uint32(len(Kvk)),[Kvk]1 func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { - return vk.readFrom(r) + n, err := vk.readFrom(r) + if err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.ReadFrom(r) + return m + n, err } // UnsafeReadFrom has the same behavior as ReadFrom, except that it will not check that decode points // are on the curve and in the correct subgroup. func (vk *VerifyingKey) UnsafeReadFrom(r io.Reader) (int64, error) { - return vk.readFrom(r, curve.NoSubgroupChecks()) + n, err := vk.readFrom(r, curve.NoSubgroupChecks()) + if err != nil { + return n, err + } + var m int64 + m, err = vk.CommitmentKey.UnsafeReadFrom(r) + return m + n, err } func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) (int64, error) { @@ -153,6 +184,11 @@ func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder) if err := dec.Decode(&vk.G1.K); err != nil { return dec.BytesRead(), err } + var publicCommitted [][]uint64 + if err := dec.Decode(&publicCommitted); err != nil { + return dec.BytesRead(), err + } + vk.PublicCommitted = utils.Uint64SliceSliceToIntSliceSlice(publicCommitted) // recompute vk.e (e(α, β)) and -[δ]2, -[γ]2 if err := vk.Precompute(); err != nil { diff --git a/internal/generator/backend/template/zkpschemes/groth16/tests/groth16.marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/tests/groth16.marshal.go.tmpl index e5ad79d370..f84d183473 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/tests/groth16.marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/tests/groth16.marshal.go.tmpl @@ -2,7 +2,9 @@ import ( {{ template "import_curve" . }} {{ template "import_fft" . }} - + {{ template "import_pedersen" . }} + "github.com/consensys/gnark/backend/groth16/internal/test_utils" + "github.com/stretchr/testify/assert" "bytes" "math/big" @@ -73,13 +75,9 @@ func TestProofSerialization(t *testing.T) { func TestVerifyingKeySerialization(t *testing.T) { - parameters := gopter.DefaultTestParameters() - parameters.MinSuccessfulTests = 10 - - properties := gopter.NewProperties(parameters) - properties.Property("VerifyingKey -> writer -> reader -> VerifyingKey should stay constant", prop.ForAll( - func(p1 curve.G1Affine, p2 curve.G2Affine) bool { + roundTrip := func(withCommitment bool) func(curve.G1Affine, curve.G2Affine) bool { + return func(p1 curve.G1Affine, p2 curve.G2Affine) bool { var vk, vkCompressed, vkRaw VerifyingKey // create a random vk @@ -107,6 +105,20 @@ func TestVerifyingKeySerialization(t *testing.T) { vk.G1.K[i] = p1 } + if withCommitment { + vk.PublicCommitted = test_utils.Random2DIntSlice(5, 10) // TODO: Use gopter randomization + bases := make([][]curve.G1Affine, len(vk.PublicCommitted)) + elem := p1 + for i := 0; i < len(vk.PublicCommitted); i++ { + bases[i] = make([]curve.G1Affine, len(vk.PublicCommitted[i])) + for j := range bases[i] { + bases[i][j] = elem + elem.Add(&elem, &p1) + } + } + _, vk.CommitmentKey, err = pedersen.Setup(bases...) + assert.NoError(t, err) + } var bufCompressed bytes.Buffer written, err := vk.WriteTo(&bufCompressed) @@ -145,7 +157,22 @@ func TestVerifyingKeySerialization(t *testing.T) { } return reflect.DeepEqual(&vk, &vkCompressed) && reflect.DeepEqual(&vk, &vkRaw) - }, + } + } + + parameters := gopter.DefaultTestParameters() + parameters.MinSuccessfulTests = 10 + + properties := gopter.NewProperties(parameters) + + properties.Property("VerifyingKey -> writer -> reader -> VerifyingKey should stay constant", prop.ForAll( + roundTrip(false), + GenG1(), + GenG2(), + )) + + properties.Property("VerifyingKey (with commitments) -> writer -> reader -> VerifyingKey should stay constant", prop.ForAll( + roundTrip(true), GenG1(), GenG2(), )) From 7526a9964c55b243b83a87544a93bfcfd868fa33 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Fri, 2 Jun 2023 14:58:53 -0500 Subject: [PATCH 424/464] fix: make linter happy --- backend/groth16/internal/test_utils/test_utils.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/groth16/internal/test_utils/test_utils.go b/backend/groth16/internal/test_utils/test_utils.go index 75cb44a08c..4a76414298 100644 --- a/backend/groth16/internal/test_utils/test_utils.go +++ b/backend/groth16/internal/test_utils/test_utils.go @@ -3,11 +3,11 @@ package test_utils import "math/rand" func Random2DIntSlice(maxN, maxM int) [][]int { - res := make([][]int, rand.Intn(maxN)) + res := make([][]int, rand.Intn(maxN)) //#nosec G404 weak rng OK for test for i := range res { - res[i] = make([]int, rand.Intn(maxM)) + res[i] = make([]int, rand.Intn(maxM)) //#nosec G404 weak rng OK for test for j := range res[i] { - res[i][j] = rand.Int() + res[i][j] = rand.Int() //#nosec G404 weak rng OK for test } } return res From 9469995a800a8bbd94626df133d4895a63cdf7fd Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 2 Jun 2023 15:33:23 -0500 Subject: [PATCH 425/464] fix: bellman test vk --- backend/groth16/bellman_test.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/backend/groth16/bellman_test.go b/backend/groth16/bellman_test.go index af74b4e47d..eb4649d34b 100644 --- a/backend/groth16/bellman_test.go +++ b/backend/groth16/bellman_test.go @@ -23,62 +23,62 @@ func TestVerifyBellmanProof(t *testing.T) { ok bool }{ { - "hwk883gUlTKCyXYA6XWZa8H9/xKIYZaJ0xEs0M5hQOMxiGpxocuX/8maSDmeCk3bhwk883gUlTKCyXYA6XWZa8H9/xKIYZaJ0xEs0M5hQOMxiGpxocuX/8maSDmeCk3bo5ViaDBdO7ZBxAhLSe5k/5TFQyF5Lv7KN2tLKnwgoWMqB16OL8WdbePIwTCuPtJNAFKoTZylLDbSf02kckMcZQDPF9iGh+JC99Pio74vDpwTEjUx5tQ99gNQwxULtztsqDRsPnEvKvLmsxHt8LQVBkEBm2PBJFY+OXf1MNW021viDBpR10mX4WQ6zrsGL5L0GY4cwf4tlbh+Obit+LnN/SQTnREf8fPpdKZ1sa/ui3pGi8lMT6io4D7Ujlwx2RdChwk883gUlTKCyXYA6XWZa8H9/xKIYZaJ0xEs0M5hQOMxiGpxocuX/8maSDmeCk3bkBF+isfMf77HCEGsZANw0hSrO2FGg14Sl26xLAIohdaW8O7gEaag8JdVAZ3OVLd5Df1NkZBEr753Xb8WwaXsJjE7qxwINL1KdqA4+EiYW4edb7+a9bbBeOPtb67ZxmFqAAAAAoMkzUv+KG8WoXszZI5NNMrbMLBDYP/xHunVgSWcix/kBrGlNozv1uFr0cmYZiij3YqToYs+EZa3dl2ILHx7H1n+b+Bjky/td2QduHVtf5t/Z9sKCfr+vOn12zVvOVz/6w==", + "hwk883gUlTKCyXYA6XWZa8H9/xKIYZaJ0xEs0M5hQOMxiGpxocuX/8maSDmeCk3bhwk883gUlTKCyXYA6XWZa8H9/xKIYZaJ0xEs0M5hQOMxiGpxocuX/8maSDmeCk3bo5ViaDBdO7ZBxAhLSe5k/5TFQyF5Lv7KN2tLKnwgoWMqB16OL8WdbePIwTCuPtJNAFKoTZylLDbSf02kckMcZQDPF9iGh+JC99Pio74vDpwTEjUx5tQ99gNQwxULtztsqDRsPnEvKvLmsxHt8LQVBkEBm2PBJFY+OXf1MNW021viDBpR10mX4WQ6zrsGL5L0GY4cwf4tlbh+Obit+LnN/SQTnREf8fPpdKZ1sa/ui3pGi8lMT6io4D7Ujlwx2RdChwk883gUlTKCyXYA6XWZa8H9/xKIYZaJ0xEs0M5hQOMxiGpxocuX/8maSDmeCk3bkBF+isfMf77HCEGsZANw0hSrO2FGg14Sl26xLAIohdaW8O7gEaag8JdVAZ3OVLd5Df1NkZBEr753Xb8WwaXsJjE7qxwINL1KdqA4+EiYW4edb7+a9bbBeOPtb67ZxmFqAAAAAoMkzUv+KG8WoXszZI5NNMrbMLBDYP/xHunVgSWcix/kBrGlNozv1uFr0cmYZiij3YqToYs+EZa3dl2ILHx7H1n+b+Bjky/td2QduHVtf5t/Z9sKCfr+vOn12zVvOVz/6wAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "lvQLU/KqgFhsLkt/5C/scqs7nWR+eYtyPdWiLVBux9GblT4AhHYMdCgwQfSJcudvsgV6fXoK+DUSRgJ++Nqt+Wvb7GlYlHpxCysQhz26TTu8Nyo7zpmVPH92+UYmbvbQCSvX2BhWtvkfHmqDVjmSIQ4RUMfeveA1KZbSf999NE4qKK8Do+8oXcmTM4LZVmh1rlyqznIdFXPN7x3pD4E0gb6/y69xtWMChv9654FMg05bAdueKt9uA4BEcAbpkdHF", "LcMT3OOlkHLzJBKCKjjzzVMg+r+FVgd52LlhZPB4RFg=", true, }, { - "hwk883gUlTKCyXYA6XWZa8H9/xKIYZaJ0xEs0M5hQOMxiGpxocuX/8maSDmeCk3bhwk883gUlTKCyXYA6XWZa8H9/xKIYZaJ0xEs0M5hQOMxiGpxocuX/8maSDmeCk3bo5ViaDBdO7ZBxAhLSe5k/5TFQyF5Lv7KN2tLKnwgoWMqB16OL8WdbePIwTCuPtJNAFKoTZylLDbSf02kckMcZQDPF9iGh+JC99Pio74vDpwTEjUx5tQ99gNQwxULtztsqDRsPnEvKvLmsxHt8LQVBkEBm2PBJFY+OXf1MNW021viDBpR10mX4WQ6zrsGL5L0GY4cwf4tlbh+Obit+LnN/SQTnREf8fPpdKZ1sa/ui3pGi8lMT6io4D7Ujlwx2RdChwk883gUlTKCyXYA6XWZa8H9/xKIYZaJ0xEs0M5hQOMxiGpxocuX/8maSDmeCk3bkBF+isfMf77HCEGsZANw0hSrO2FGg14Sl26xLAIohdaW8O7gEaag8JdVAZ3OVLd5Df1NkZBEr753Xb8WwaXsJjE7qxwINL1KdqA4+EiYW4edb7+a9bbBeOPtb67ZxmFqAAAAAoMkzUv+KG8WoXszZI5NNMrbMLBDYP/xHunVgSWcix/kBrGlNozv1uFr0cmYZiij3YqToYs+EZa3dl2ILHx7H1n+b+Bjky/td2QduHVtf5t/Z9sKCfr+vOn12zVvOVz/6w==", + "hwk883gUlTKCyXYA6XWZa8H9/xKIYZaJ0xEs0M5hQOMxiGpxocuX/8maSDmeCk3bhwk883gUlTKCyXYA6XWZa8H9/xKIYZaJ0xEs0M5hQOMxiGpxocuX/8maSDmeCk3bo5ViaDBdO7ZBxAhLSe5k/5TFQyF5Lv7KN2tLKnwgoWMqB16OL8WdbePIwTCuPtJNAFKoTZylLDbSf02kckMcZQDPF9iGh+JC99Pio74vDpwTEjUx5tQ99gNQwxULtztsqDRsPnEvKvLmsxHt8LQVBkEBm2PBJFY+OXf1MNW021viDBpR10mX4WQ6zrsGL5L0GY4cwf4tlbh+Obit+LnN/SQTnREf8fPpdKZ1sa/ui3pGi8lMT6io4D7Ujlwx2RdChwk883gUlTKCyXYA6XWZa8H9/xKIYZaJ0xEs0M5hQOMxiGpxocuX/8maSDmeCk3bkBF+isfMf77HCEGsZANw0hSrO2FGg14Sl26xLAIohdaW8O7gEaag8JdVAZ3OVLd5Df1NkZBEr753Xb8WwaXsJjE7qxwINL1KdqA4+EiYW4edb7+a9bbBeOPtb67ZxmFqAAAAAoMkzUv+KG8WoXszZI5NNMrbMLBDYP/xHunVgSWcix/kBrGlNozv1uFr0cmYZiij3YqToYs+EZa3dl2ILHx7H1n+b+Bjky/td2QduHVtf5t/Z9sKCfr+vOn12zVvOVz/6wAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "lvQLU/KqgFhsLkt/5C/scqs7nWR+eYtyPdWiLVBux9GblT4AhHYMdCgwQfSJcudvsgV6fXoK+DUSRgJ++Nqt+Wvb7GlYlHpxCysQhz26TTu8Nyo7zpmVPH92+UYmbvbQCSvX2BhWtvkfHmqDVjmSIQ4RUMfeveA1KZbSf999NE4qKK8Do+8oXcmTM4LZVmh1rlyqznIdFXPN7x3pD4E0gb6/y69xtWMChv9654FMg05bAdueKt9uA4BEcAbpkdHF", "cmzVCcRVnckw3QUPhmG4Bkppeg4K50oDQwQ9EH+Fq1s=", false, }, { - "hwk883gUlTKCyXYA6XWZa8H9/xKIYZaJ0xEs0M5hQOMxiGpxocuX/8maSDmeCk3bhwk883gUlTKCyXYA6XWZa8H9/xKIYZaJ0xEs0M5hQOMxiGpxocuX/8maSDmeCk3bo5ViaDBdO7ZBxAhLSe5k/5TFQyF5Lv7KN2tLKnwgoWMqB16OL8WdbePIwTCuPtJNAFKoTZylLDbSf02kckMcZQDPF9iGh+JC99Pio74vDpwTEjUx5tQ99gNQwxULtztsqDRsPnEvKvLmsxHt8LQVBkEBm2PBJFY+OXf1MNW021viDBpR10mX4WQ6zrsGL5L0GY4cwf4tlbh+Obit+LnN/SQTnREf8fPpdKZ1sa/ui3pGi8lMT6io4D7Ujlwx2RdChwk883gUlTKCyXYA6XWZa8H9/xKIYZaJ0xEs0M5hQOMxiGpxocuX/8maSDmeCk3bkBF+isfMf77HCEGsZANw0hSrO2FGg14Sl26xLAIohdaW8O7gEaag8JdVAZ3OVLd5Df1NkZBEr753Xb8WwaXsJjE7qxwINL1KdqA4+EiYW4edb7+a9bbBeOPtb67ZxmFqAAAAAoMkzUv+KG8WoXszZI5NNMrbMLBDYP/xHunVgSWcix/kBrGlNozv1uFr0cmYZiij3YqToYs+EZa3dl2ILHx7H1n+b+Bjky/td2QduHVtf5t/Z9sKCfr+vOn12zVvOVz/6w==", + "hwk883gUlTKCyXYA6XWZa8H9/xKIYZaJ0xEs0M5hQOMxiGpxocuX/8maSDmeCk3bhwk883gUlTKCyXYA6XWZa8H9/xKIYZaJ0xEs0M5hQOMxiGpxocuX/8maSDmeCk3bo5ViaDBdO7ZBxAhLSe5k/5TFQyF5Lv7KN2tLKnwgoWMqB16OL8WdbePIwTCuPtJNAFKoTZylLDbSf02kckMcZQDPF9iGh+JC99Pio74vDpwTEjUx5tQ99gNQwxULtztsqDRsPnEvKvLmsxHt8LQVBkEBm2PBJFY+OXf1MNW021viDBpR10mX4WQ6zrsGL5L0GY4cwf4tlbh+Obit+LnN/SQTnREf8fPpdKZ1sa/ui3pGi8lMT6io4D7Ujlwx2RdChwk883gUlTKCyXYA6XWZa8H9/xKIYZaJ0xEs0M5hQOMxiGpxocuX/8maSDmeCk3bkBF+isfMf77HCEGsZANw0hSrO2FGg14Sl26xLAIohdaW8O7gEaag8JdVAZ3OVLd5Df1NkZBEr753Xb8WwaXsJjE7qxwINL1KdqA4+EiYW4edb7+a9bbBeOPtb67ZxmFqAAAAAoMkzUv+KG8WoXszZI5NNMrbMLBDYP/xHunVgSWcix/kBrGlNozv1uFr0cmYZiij3YqToYs+EZa3dl2ILHx7H1n+b+Bjky/td2QduHVtf5t/Z9sKCfr+vOn12zVvOVz/6wAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "lvQLU/KqgFhsLkt/5C/scqs7nWR+eYtyPdWiLVBux9GblT4AhHYMdCgwQfSJcudvsgV6fXoK+DUSRgJ++Nqt+Wvb7GlYlHpxCysQhz26TTu8Nyo7zpmVPH92+UYmbvbQCSvX2BhWtvkfHmqDVjmSIQ4RUMfeveA1KZbSf999NE4qKK8Do+8oXcmTM4LZVmh1rlyqznIdFXPN7x3pD4E0gb6/y69xtWMChv9654FMg05bAdueKt9uA4BEcAbpkdHF", "cmzVCcRVnckw3QUPhmG4Bkppeg4K50oDQwQ9EH+Fq1s=", false, }, { - "kYYCAS8vM2T99GeCr4toQ+iQzvl5fI89mPrncYqx3C1d75BQbFk8LMtcnLWwntd6kYYCAS8vM2T99GeCr4toQ+iQzvl5fI89mPrncYqx3C1d75BQbFk8LMtcnLWwntd6knkzSwcsialcheg69eZYPK8EzKRVI5FrRHKi8rgB+R5jyPV70ejmYEx1neTmfYKODRmARr/ld6pZTzBWYDfrCkiS1QB+3q3M08OQgYcLzs/vjW4epetDCmk0K1CEGcWdh7yLzdqr7HHQNOpZI8mdj/7lR0IBqB9zvRfyTr+guUG22kZo4y2KINDp272xGglKEeTglTxyDUriZJNF/+T6F8w70MR/rV+flvuo6EJ0+HA+A2ZnBbTjOIl9wjisBV+0kYYCAS8vM2T99GeCr4toQ+iQzvl5fI89mPrncYqx3C1d75BQbFk8LMtcnLWwntd6jgld4oAppAOzvQ7eoIx2tbuuKVSdbJm65KDxl/T+boaYnjRm3omdETYnYRk3HAhrAeWpefX+dM/k7PrcheInnxHUyjzSzqlN03xYjg28kdda9FZJaVsQKqdEJ/St9ivXAAAAAZae/nTwyDn5u+4WkhZ76991cGB/ymyGpXziT0bwS86pRw/AcbpzXmzK+hq+kvrvpw==", + "kYYCAS8vM2T99GeCr4toQ+iQzvl5fI89mPrncYqx3C1d75BQbFk8LMtcnLWwntd6kYYCAS8vM2T99GeCr4toQ+iQzvl5fI89mPrncYqx3C1d75BQbFk8LMtcnLWwntd6knkzSwcsialcheg69eZYPK8EzKRVI5FrRHKi8rgB+R5jyPV70ejmYEx1neTmfYKODRmARr/ld6pZTzBWYDfrCkiS1QB+3q3M08OQgYcLzs/vjW4epetDCmk0K1CEGcWdh7yLzdqr7HHQNOpZI8mdj/7lR0IBqB9zvRfyTr+guUG22kZo4y2KINDp272xGglKEeTglTxyDUriZJNF/+T6F8w70MR/rV+flvuo6EJ0+HA+A2ZnBbTjOIl9wjisBV+0kYYCAS8vM2T99GeCr4toQ+iQzvl5fI89mPrncYqx3C1d75BQbFk8LMtcnLWwntd6jgld4oAppAOzvQ7eoIx2tbuuKVSdbJm65KDxl/T+boaYnjRm3omdETYnYRk3HAhrAeWpefX+dM/k7PrcheInnxHUyjzSzqlN03xYjg28kdda9FZJaVsQKqdEJ/St9ivXAAAAAZae/nTwyDn5u+4WkhZ76991cGB/ymyGpXziT0bwS86pRw/AcbpzXmzK+hq+kvrvpwAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "sStVLdyxqInmv76iaNnRFB464lGq48iVeqYWSi2linE9DST0fTNhxSnvSXAoPpt8tFsanj5vPafC+ij/Fh98dOUlMbO42bf280pOZ4lm+zr63AWUpOOIugST+S6pq9zeB0OHp2NY8XFmriOEKhxeabhuV89ljqCDjlhXBeNZwM5zti4zg89Hd8TbKcw46jAsjIJe2Siw3Th7ELQQKR5ucX50f0GISmnOSceePPdvjbGJ8fSFOnSmSp8dK7uyehrU", "", true, }, { - "mY//hEITCBCZUJUN/wsOlw1iUSSOESL6PFSbN1abGK80t5jPNICNlPuSorio4mmWmY//hEITCBCZUJUN/wsOlw1iUSSOESL6PFSbN1abGK80t5jPNICNlPuSorio4mmWpf+4uOyv3gPZe54SYGM4pfhteqJpwFQxdlpwXWyYxMTNaSLDj8VtSn/EJaSu+P6nFmWsda3mTYUPYMZzWE4hMqpDgFPcJhw3prArMThDPbR3Hx7E6NRAAR0LqcrdtsbDqu2T0tto1rpnFILdvHL4PqEUfTmF2mkM+DKj7lKwvvZUbukqBwLrnnbdfyqZJryzGAMIa2JvMEMYszGsYyiPXZvYx6Luk54oWOlOrwEKrCY4NMPwch6DbFq6KpnNSQwOmY//hEITCBCZUJUN/wsOlw1iUSSOESL6PFSbN1abGK80t5jPNICNlPuSorio4mmWpgRYCz7wpjk57X+NGJmo85tYKc+TNa1rT4/DxG9v6SHkpXmmPeHhzIIW8MOdkFjxB5o6Qn8Fa0c6Tt6br2gzkrGr1eK5/+RiIgEzVhcRrqdY/p7PLmKXqawrEvIv9QZ3AAAAAoo8rTzcIp5QvF3USzv2Lz99z43CPVkjHB1ejzj/SjzKNa54GiDzHoCoAL0xKLjRSqeL98AF0V1+cRI8FwJjOcMgf0gDmjzwiv3ppbPZKqJR7Go+57k02670lfG6s1MM0A==", + "mY//hEITCBCZUJUN/wsOlw1iUSSOESL6PFSbN1abGK80t5jPNICNlPuSorio4mmWmY//hEITCBCZUJUN/wsOlw1iUSSOESL6PFSbN1abGK80t5jPNICNlPuSorio4mmWpf+4uOyv3gPZe54SYGM4pfhteqJpwFQxdlpwXWyYxMTNaSLDj8VtSn/EJaSu+P6nFmWsda3mTYUPYMZzWE4hMqpDgFPcJhw3prArMThDPbR3Hx7E6NRAAR0LqcrdtsbDqu2T0tto1rpnFILdvHL4PqEUfTmF2mkM+DKj7lKwvvZUbukqBwLrnnbdfyqZJryzGAMIa2JvMEMYszGsYyiPXZvYx6Luk54oWOlOrwEKrCY4NMPwch6DbFq6KpnNSQwOmY//hEITCBCZUJUN/wsOlw1iUSSOESL6PFSbN1abGK80t5jPNICNlPuSorio4mmWpgRYCz7wpjk57X+NGJmo85tYKc+TNa1rT4/DxG9v6SHkpXmmPeHhzIIW8MOdkFjxB5o6Qn8Fa0c6Tt6br2gzkrGr1eK5/+RiIgEzVhcRrqdY/p7PLmKXqawrEvIv9QZ3AAAAAoo8rTzcIp5QvF3USzv2Lz99z43CPVkjHB1ejzj/SjzKNa54GiDzHoCoAL0xKLjRSqeL98AF0V1+cRI8FwJjOcMgf0gDmjzwiv3ppbPZKqJR7Go+57k02670lfG6s1MM0AAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "g53N8ecorvG2sDgNv8D7quVhKMIIpdP9Bqk/8gmV5cJ5Rhk9gKvb4F0ll8J/ZZJVqa27OyciJwx6lym6QpVK9q1ASrqio7rD5POMDGm64Iay/ixXXn+//F+uKgDXADj9AySri2J1j3qEkqqe3kxKthw94DzAfUBPncHfTPazVtE48AfzB1KWZA7Vf/x/3phYs4ckcP7ZrdVViJVLbUgFy543dpKfEH2MD30ZLLYRhw8SatRCyIJuTZcMlluEKG+d", "aZ8tqrOeEJKt4AMqiRF/WJhIKTDC0HeDTgiJVLZ8OEs=", true, }, { - "tRpqHB4HADuHAUvHTcrzxmq1awdwEBA0GOJfebYTODyUqXBQ7FkYrz1oDvPyx5Z3tRpqHB4HADuHAUvHTcrzxmq1awdwEBA0GOJfebYTODyUqXBQ7FkYrz1oDvPyx5Z3sUmODSJXAQmAFBVnS2t+Xzf5ZCr1gCtMiJVjQ48/nob/SkrS4cTHHjbKIVS9cdD/BG/VDrZvBt/dPqXmdUFyFuTTMrViagR57YRrDmm1qm5LQ/A8VwUBdiArwgRQXH9jsYhgVmfcRAjJytrbYeR6ck4ZfmGr6x6akKiBLY4B1l9LaHTyz/6KSM5t8atpuR3HBJZfbBm2/K8nnYTl+mAU/EnIN3YQdUd65Hsd4Gtf6VT2qfz6hcrSgHutxR1usIL2tRpqHB4HADuHAUvHTcrzxmq1awdwEBA0GOJfebYTODyUqXBQ7FkYrz1oDvPyx5Z3kyU9X4Kqjx6I6zYwVbn7PWbiy3OtY277z4ggIqW6AuDgzUeIyG9a4stMeQ07mOV/Ef4faj+eh4GJRKjJm7aUTYJCSAGY6klOXNoEzB54XF4EY5pkMPfW73SmxJi9B0aHAAAAEJGVg8trc1JcL8WfwX7A5FGZ7epiPqnQzrUxuiRSLUkGaLWBgwZusz3M8KN2QBqa/IIm0xOg40+xhjQxJduo4ACd2gHQa3+2G9L1hGIsziSuEjv1HfuP1sVw28u8W8JRWJIBLWGzDuj16M4Uag4qLSdAn3UhMTRwPQN+5kf26TTisoQK38r0gSCZ1EIDsOcDAavhjj+Z+/BPfWua2OBVxlJjNyxnafwr5BiE2H9OElh5GQBLnmB/emLOY6x5SGUANpPY9NiYvki/NgyRR/Cw4e+34Ifc4dMAIwgKmO/6+9uN+EQwPe23xGSWr0ZgBDbIH5bElW/Hfa0DAaVpd15G/JjZVDkn/iwF3l2EEeNmeMrlI8AFL5P//oprobFhfGQjJKW/cEP+nK1R+BORN3+iH/zLfw3Hp1pTzbb7tgiRWrXPKt9WknZ1oTDfFOuUl9wwaLg3PBFwxXebcMuFVjEuZYWOlW1P5UvE/KMoa/jSKbLbClJkodBDNaxslIdjzYCGM6Hgc5x1moKdljt5yGzWCHFxETgU/EKagOA6s8b+uuY8Goxl5gGsEb3Wasy6rwpHro3pKZWWKFdGlxJ2BDiL3xe3eMWst6pMdjbKaKDOB3maYh5JyFpFFYRlSQcwQy4ywY4hgSvkxh3x/DmnXsYXXrexMciFom0pmplkL332ZMpd1pzKFW00N5TpLODHGt7FOYadYjHqXbtKyqAYdDV3MPRfYZIoIAyJETSDatq5b1MqT4kpqfFPLQ0jHhtGFUqLxZQOA7IwcJ7SR+OTYDW2P0W7v4X3u0LJE5AYk6NgPpJmEh++VL39lAF8AQE9T6BNLKrWJ3Rdim7YZehspVd4/TSCrSMx3fxsJXhMbjOypSNR9tj+/G6+c5ofA+1dWhXMT6X7UIY3IeGm17sRD+GoYHzZrYXYaEr0MpC4Y25hvQa78Jsmg0Xf7Bwk3kl5i6iMm63erQPGSyatgy8yiRDpZnzPWiIoS3vxS53X500pDStnreKPLzN2IwJoDp6wKOySKQ==", + "tRpqHB4HADuHAUvHTcrzxmq1awdwEBA0GOJfebYTODyUqXBQ7FkYrz1oDvPyx5Z3tRpqHB4HADuHAUvHTcrzxmq1awdwEBA0GOJfebYTODyUqXBQ7FkYrz1oDvPyx5Z3sUmODSJXAQmAFBVnS2t+Xzf5ZCr1gCtMiJVjQ48/nob/SkrS4cTHHjbKIVS9cdD/BG/VDrZvBt/dPqXmdUFyFuTTMrViagR57YRrDmm1qm5LQ/A8VwUBdiArwgRQXH9jsYhgVmfcRAjJytrbYeR6ck4ZfmGr6x6akKiBLY4B1l9LaHTyz/6KSM5t8atpuR3HBJZfbBm2/K8nnYTl+mAU/EnIN3YQdUd65Hsd4Gtf6VT2qfz6hcrSgHutxR1usIL2tRpqHB4HADuHAUvHTcrzxmq1awdwEBA0GOJfebYTODyUqXBQ7FkYrz1oDvPyx5Z3kyU9X4Kqjx6I6zYwVbn7PWbiy3OtY277z4ggIqW6AuDgzUeIyG9a4stMeQ07mOV/Ef4faj+eh4GJRKjJm7aUTYJCSAGY6klOXNoEzB54XF4EY5pkMPfW73SmxJi9B0aHAAAAEJGVg8trc1JcL8WfwX7A5FGZ7epiPqnQzrUxuiRSLUkGaLWBgwZusz3M8KN2QBqa/IIm0xOg40+xhjQxJduo4ACd2gHQa3+2G9L1hGIsziSuEjv1HfuP1sVw28u8W8JRWJIBLWGzDuj16M4Uag4qLSdAn3UhMTRwPQN+5kf26TTisoQK38r0gSCZ1EIDsOcDAavhjj+Z+/BPfWua2OBVxlJjNyxnafwr5BiE2H9OElh5GQBLnmB/emLOY6x5SGUANpPY9NiYvki/NgyRR/Cw4e+34Ifc4dMAIwgKmO/6+9uN+EQwPe23xGSWr0ZgBDbIH5bElW/Hfa0DAaVpd15G/JjZVDkn/iwF3l2EEeNmeMrlI8AFL5P//oprobFhfGQjJKW/cEP+nK1R+BORN3+iH/zLfw3Hp1pTzbb7tgiRWrXPKt9WknZ1oTDfFOuUl9wwaLg3PBFwxXebcMuFVjEuZYWOlW1P5UvE/KMoa/jSKbLbClJkodBDNaxslIdjzYCGM6Hgc5x1moKdljt5yGzWCHFxETgU/EKagOA6s8b+uuY8Goxl5gGsEb3Wasy6rwpHro3pKZWWKFdGlxJ2BDiL3xe3eMWst6pMdjbKaKDOB3maYh5JyFpFFYRlSQcwQy4ywY4hgSvkxh3x/DmnXsYXXrexMciFom0pmplkL332ZMpd1pzKFW00N5TpLODHGt7FOYadYjHqXbtKyqAYdDV3MPRfYZIoIAyJETSDatq5b1MqT4kpqfFPLQ0jHhtGFUqLxZQOA7IwcJ7SR+OTYDW2P0W7v4X3u0LJE5AYk6NgPpJmEh++VL39lAF8AQE9T6BNLKrWJ3Rdim7YZehspVd4/TSCrSMx3fxsJXhMbjOypSNR9tj+/G6+c5ofA+1dWhXMT6X7UIY3IeGm17sRD+GoYHzZrYXYaEr0MpC4Y25hvQa78Jsmg0Xf7Bwk3kl5i6iMm63erQPGSyatgy8yiRDpZnzPWiIoS3vxS53X500pDStnreKPLzN2IwJoDp6wKOySKQAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "lgFU4Jyo9GdHL7w31u3zXc8RQRnHVarZWNfd0lD45GvvQtwrZ1Y1OKB4T29a79UagPHOdk1S0k0hYAYQyyNAfRUzde1HP8R+2dms75gGZEnx2tXexEN+BVjRJfC8PR1lFJa6xvsEx5uSrOZzKmoMfCwcA55SMT5jFo4+KyWg2wP5OnFPx7XTdEKvf5YhpY0krQKiq3OUu79EwjNF1xV1+iLxx2KEIyK7RSYxO1BHrKOGOEzxSUK00MA+YVHe+DvW", "aZ8tqrOeEJKt4AMqiRF/WJhIKTDC0HeDTgiJVLZ8OEtiLNj7hflFeVnNXPguxyoqkI/V7pGJtXBpH5N+RswQNA0b23aM33aH0HKHOWoGY/T/L7TQzYFGJ3vTLiXDFZg1OVqkGOMvqAgonOrHGi6IgcALyUMyCKlL5BQY23SeILJpYKolybJNwJfbjxpg0Oz+D2fr7r9XL1GMvgblu52bVQT1fR8uCRJfSsgA2OGw6k/MpKDCfMcjbR8jnZa8ROEvF4cohm7iV1788Vp2/2bdcEZRQSoaGV8pOmA9EkqzJVRABjkDso40fnQcm2IzjBUOsX+uFExVan56/vl9VZVwB0wnee3Uxiredn0kOayiPB16yimxXCDet+M+0UKjmIlmXYpkrCDrH0dn53w+U3OHqMQxPDnUpYBxadM1eI8xWFFxzaLkvega0q0DmEquyY02yiTqo+7Q4qaJVTLgu6/8ekzPxGKRi845NL8gRgaTtM3kidDzIQpyODZD0yeEZDY1M+3sUKHcVkhoxTQBTMyKJPc+M5DeBL3uaWMrvxuL6q8+X0xeBt+9kguPUNtIYqUgPAaXvM2i041bWHTJ0dZLyDJVOyzGaXRaF4mNkAuh4Et6Zw5PuOpMM2mI1oFKEZj7", true, }, { - "kY4NWaOoYItWtLKVQnxDh+XTsa0Yev5Ae3Q9vlQSKp6+IUtwS7GH5ZrZefmBEwWEkY4NWaOoYItWtLKVQnxDh+XTsa0Yev5Ae3Q9vlQSKp6+IUtwS7GH5ZrZefmBEwWEqvAtYaSs5qW3riOiiRFoLp7MThW4vCEhK0j8BZY5ZM/tnjB7mrLB59kGvzpW8PM/AoQRIWzyvO3Dxxfyj/UQcQRw+KakVRvrFca3Vy2K5cFwxYHwl6PFDM+OmGrlgOCoqZtY1SLOd+ovmFOODKiHBZzDZhC/lRfjKVy4LzI7AXDuFn4tlWoT7IsJyy6lYNaWFfLjYZPAsrv1gXJ1NYat5B6E0Pnz5C67u2Uigmlol2D91re3oAqIo+r8kiyFKOSBkY4NWaOoYItWtLKVQnxDh+XTsa0Yev5Ae3Q9vlQSKp6+IUtwS7GH5ZrZefmBEwWEooG0cMN47zQor6qj0owuxJjn5Ymrcd/FCQ1ud4cKoUlNaGWIekSjxJEB87elMy5oEUlUzVI9ObMm+2SE3Udgws7pkMM8fgQUQUqUVyc7sNCE9m/hQzlwtbXrNSS5Pb+6AAAAEaMO2hzDmr41cml4ktH+m9acCaUtck/ivOVANQi6qsQmhMOfvFgIzMwTqypsQVKWAKSOBQQCGv0o3lP8GJ5Y1FDEzH5wXwkPDEtNYRUkGUqD8dXaPGcZ+WNzT4KWqJlw36clSvUNFNDZKkKj7JPk/gK6MUBsavX/xzl+SOWYmxdu3Wd9rQm0yqNthoLKarQL9or9Oj7m8kmOZUSBGJQo6+Y/AIZfYBbzfttnCIdYhorsAcoT4xg4D+Ye/MWVwgaCXpBGD3CNgtC7QXIeaWQvyaUtZBfZQS53aHYSJbrRK95pCqIUfg/3MzfxU3cVNm/NkKn2Th3Puq79m4hF8vAHaADMpI9XbCMO/3eTPF3ID4lMzZKOB+qdNkbdkdNTDmG6E6IGkB/JclOqPHPojkURhKGQ06uIbQvkGuwF06Hb0pht9yK8CVRjigzLb1iNVWHYVrN9kgdFtXfgaxW9DmwRrM/lJ+z/lfKnqwjKrvdOgZG43VprCmykARQvP2A03UovdqyKtSElEFp/PAIFv6vruij8cm1ORGYGwPhGcAgwejMgTYR3KwL1RXl/pI9UWNRsdZMwhN5XbE9+7Am2shbcjDGy+oA0AqE2nSV/44bPcIKdHWbo8DpNFnn4YMtQVB15f6vtp1wCj7yppYulqO/6WK/6tdxnLI+2e1kilZ+BZuF35CQ+tquqWgsTudQZSUBHJ6TTyku/s44ZkJU0YhK8g/L3uykM5NtHm+E4CDEdYSOaZ0Joxnk+esWckqdpw52A7KrJ1webkGPJcn+iGAvzx8xG960sfdZNGRLucOSDK1SvKLTc2R61LjNGj3SJqS0CeKhIL5nszkaXFAquEkafWxpd/8s1xObVmYJ90OpF8oxTIbvn6E2MtTVfhyWySNZ2DI3k693/kcUqYSGFsjGe7A90YA80ZOYkKg9SfvK3TiGZYjm365lmq6PwQcTb3dXzwJRRD4g3oAXA2lVh0tgNRTyAvXfg1NOb4s6wX5YurLvawr0gTVZ6A0gRds3lPtjY14+8nB2MQrmYJfHQbvBWY745Q1GQqn3atz7M0HqNl+ebawyRB3lVmkaCHIIhtoX0zQ==", + "kY4NWaOoYItWtLKVQnxDh+XTsa0Yev5Ae3Q9vlQSKp6+IUtwS7GH5ZrZefmBEwWEkY4NWaOoYItWtLKVQnxDh+XTsa0Yev5Ae3Q9vlQSKp6+IUtwS7GH5ZrZefmBEwWEqvAtYaSs5qW3riOiiRFoLp7MThW4vCEhK0j8BZY5ZM/tnjB7mrLB59kGvzpW8PM/AoQRIWzyvO3Dxxfyj/UQcQRw+KakVRvrFca3Vy2K5cFwxYHwl6PFDM+OmGrlgOCoqZtY1SLOd+ovmFOODKiHBZzDZhC/lRfjKVy4LzI7AXDuFn4tlWoT7IsJyy6lYNaWFfLjYZPAsrv1gXJ1NYat5B6E0Pnz5C67u2Uigmlol2D91re3oAqIo+r8kiyFKOSBkY4NWaOoYItWtLKVQnxDh+XTsa0Yev5Ae3Q9vlQSKp6+IUtwS7GH5ZrZefmBEwWEooG0cMN47zQor6qj0owuxJjn5Ymrcd/FCQ1ud4cKoUlNaGWIekSjxJEB87elMy5oEUlUzVI9ObMm+2SE3Udgws7pkMM8fgQUQUqUVyc7sNCE9m/hQzlwtbXrNSS5Pb+6AAAAEaMO2hzDmr41cml4ktH+m9acCaUtck/ivOVANQi6qsQmhMOfvFgIzMwTqypsQVKWAKSOBQQCGv0o3lP8GJ5Y1FDEzH5wXwkPDEtNYRUkGUqD8dXaPGcZ+WNzT4KWqJlw36clSvUNFNDZKkKj7JPk/gK6MUBsavX/xzl+SOWYmxdu3Wd9rQm0yqNthoLKarQL9or9Oj7m8kmOZUSBGJQo6+Y/AIZfYBbzfttnCIdYhorsAcoT4xg4D+Ye/MWVwgaCXpBGD3CNgtC7QXIeaWQvyaUtZBfZQS53aHYSJbrRK95pCqIUfg/3MzfxU3cVNm/NkKn2Th3Puq79m4hF8vAHaADMpI9XbCMO/3eTPF3ID4lMzZKOB+qdNkbdkdNTDmG6E6IGkB/JclOqPHPojkURhKGQ06uIbQvkGuwF06Hb0pht9yK8CVRjigzLb1iNVWHYVrN9kgdFtXfgaxW9DmwRrM/lJ+z/lfKnqwjKrvdOgZG43VprCmykARQvP2A03UovdqyKtSElEFp/PAIFv6vruij8cm1ORGYGwPhGcAgwejMgTYR3KwL1RXl/pI9UWNRsdZMwhN5XbE9+7Am2shbcjDGy+oA0AqE2nSV/44bPcIKdHWbo8DpNFnn4YMtQVB15f6vtp1wCj7yppYulqO/6WK/6tdxnLI+2e1kilZ+BZuF35CQ+tquqWgsTudQZSUBHJ6TTyku/s44ZkJU0YhK8g/L3uykM5NtHm+E4CDEdYSOaZ0Joxnk+esWckqdpw52A7KrJ1webkGPJcn+iGAvzx8xG960sfdZNGRLucOSDK1SvKLTc2R61LjNGj3SJqS0CeKhIL5nszkaXFAquEkafWxpd/8s1xObVmYJ90OpF8oxTIbvn6E2MtTVfhyWySNZ2DI3k693/kcUqYSGFsjGe7A90YA80ZOYkKg9SfvK3TiGZYjm365lmq6PwQcTb3dXzwJRRD4g3oAXA2lVh0tgNRTyAvXfg1NOb4s6wX5YurLvawr0gTVZ6A0gRds3lPtjY14+8nB2MQrmYJfHQbvBWY745Q1GQqn3atz7M0HqNl+ebawyRB3lVmkaCHIIhtoX0zQAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "jqPSA/XKqZDJnRSmM0sJxbrFv7GUcA45QMysIx1xTsI3+2iysF5Tr68565ZuO65qjo2lklZpQo+wtyKSA/56EaKOJZCZhSvDdBEdvVYJCjmWusuK5qav7xZO0w5W1qRiEgIdcGUz5V7JHqfRf4xI6/uUD846alyzzNjxQtKErqJbRw6yyBO6j6box363pinjiMTzU4w/qltzFuOEpKxy/H3vyH8RcsF24Ou/Rb6vfR7cSLtLwCsf/BMtPcsQfdRK", "aZ8tqrOeEJKt4AMqiRF/WJhIKTDC0HeDTgiJVLZ8OEtiLNj7hflFeVnNXPguxyoqkI/V7pGJtXBpH5N+RswQNA0b23aM33aH0HKHOWoGY/T/L7TQzYFGJ3vTLiXDFZg1OVqkGOMvqAgonOrHGi6IgcALyUMyCKlL5BQY23SeILJpYKolybJNwJfbjxpg0Oz+D2fr7r9XL1GMvgblu52bVQT1fR8uCRJfSsgA2OGw6k/MpKDCfMcjbR8jnZa8ROEvF4cohm7iV1788Vp2/2bdcEZRQSoaGV8pOmA9EkqzJVRABjkDso40fnQcm2IzjBUOsX+uFExVan56/vl9VZVwB0wnee3Uxiredn0kOayiPB16yimxXCDet+M+0UKjmIlmXYpkrCDrH0dn53w+U3OHqMQxPDnUpYBxadM1eI8xWFFxzaLkvega0q0DmEquyY02yiTqo+7Q4qaJVTLgu6/8ekzPxGKRi845NL8gRgaTtM3kidDzIQpyODZD0yeEZDY1M+3sUKHcVkhoxTQBTMyKJPc+M5DeBL3uaWMrvxuL6q8+X0xeBt+9kguPUNtIYqUgPAaXvM2i041bWHTJ0dZLyDJVOyzGaXRaF4mNkAuh4Et6Zw5PuOpMM2mI1oFKEZj7Xqf/yAmy/Le3GfJnMg5vNgE7QxmVsjuKUP28iN8rdi4=", true, }, { - "pQUlLSBu9HmVa9hB0rEu1weeBv2RKQQ8yCHpwXTHeSkcQqmSOuzednF8o0+MdyNupQUlLSBu9HmVa9hB0rEu1weeBv2RKQQ8yCHpwXTHeSkcQqmSOuzednF8o0+MdyNuhKgxmPN2c94UBtlYc0kZS6CwyMEEV/nVGSjajEZPdnpbK7fEcPd0hWNcOxKWq8qBBPfT69Ore74buf8C26ZTyKnjgMsGCvoDAMOsA07DjjQ1nIkkwIGFFUT3iMO83TdEpWgV/2z7WT9axNH/QFPOjXvwQJFnC7hLxHnX6pgKOdAaioKdi6FX3Y2SwWEO3UuxFd3KwsrZ2+mma/W3KP/cPpSzqyHa5VaJwOCw6vSM4wHSGKmDF4TSrrnMxzIYiTbTpQUlLSBu9HmVa9hB0rEu1weeBv2RKQQ8yCHpwXTHeSkcQqmSOuzednF8o0+MdyNulrwLi5GjMxD6BKzMMN9+7xFuO7txLCEIhGrIMFIvqTw1QFAO4rmAgyG+ljlYTfWHAkzqvImL1o8dMHhGOTsMLLMg39KsZVqalZwwL3ckpdAf81OJJeWCpCuaSgSXnWhJAAAAEph8ULgPc1Ia5pUdcBzvXnoB4f6dNaLD9MVNN62NaBqJzmdvGnGBujEjn2QZCk/jaKjnBFrS+EQj+rewVlx4CFJpYQhI/6cDVcfdlXN2cxPMzId1NfeiAh800mc9KzMCZJk9JdZu0HbwaalHqgscl4GPumn6rHQHRo2XrlDjwdkQ2ptwpto9meVcoL3SASNdqpSKBAYZ64QscekzfssIpXyNmgY807Z9KwnuyAPbGLXGJ910qKFO0wTQd/TvHGxoJ5hmEMoMQbEPxJo9igwqkOANTEZ0nt6urUIY06Kg4x0VxCs5VpGv+PoVjZyaYnKvy5k948Qh/f8q3vKhVF8vh6tsnIrY7966IMPocl5St6SKEJg7JCZ6gZN4cYrI90EK0Ir9Oj7m8kmOZUSBGJQo6+Y/AIZfYBbzfttnCIdYhorsAcoT4xg4D+Ye/MWVwgaCXpBGD3CNgtC7QXIeaWQvyaUtZBfZQS53aHYSJbrRK95pCqIUfg/3MzfxU3cVNm/NkKn2Th3Puq79m4hF8vAHaADMpI9XbCMO/3eTPF3ID4lMzZKOB+qdNkbdkdNTDmG6E6IGkB/JclOqPHPojkURhKGQ06uIbQvkGuwF06Hb0pht9yK8CVRjigzLb1iNVWHYVrN9kgdFtXfgaxW9DmwRrM/lJ+z/lfKnqwjKrvdOgZG43VprCmykARQvP2A03UovdqyKtSElEFp/PAIFv6vruij8cm1ORGYGwPhGcAgwejMgTYR3KwL1RXl/pI9UWNRsdZMwhN5XbE9+7Am2shbcjDGy+oA0AqE2nSV/44bPcIKdHWbo8DpNFnn4YMtQVB15f6vtp1wCj7yppYulqO/6WK/6tdxnLI+2e1kilZ+BZuF35CQ+tquqWgsTudQZSUBHJ6TTyku/s44ZkJU0YhK8g/L3uykM5NtHm+E4CDEdYSOaZ0Joxnk+esWckqdpw52A7KrJ1webkGPJcn+iGAvzx8xG960sfdZNGRLucOSDK1SvKLTc2R61LjNGj3SJqS0CeKhIL5nszkaXFAquEkafWxpd/8s1xObVmYJ90OpF8oxTIbvn6E2MtTVfhyWySNZ2DI3k693/kcUqYSGFsjGe7A90YA80ZOYkKg9SfvK3TiGZYjm365lmq6PwQcTb3dXzwA==", + "pQUlLSBu9HmVa9hB0rEu1weeBv2RKQQ8yCHpwXTHeSkcQqmSOuzednF8o0+MdyNupQUlLSBu9HmVa9hB0rEu1weeBv2RKQQ8yCHpwXTHeSkcQqmSOuzednF8o0+MdyNuhKgxmPN2c94UBtlYc0kZS6CwyMEEV/nVGSjajEZPdnpbK7fEcPd0hWNcOxKWq8qBBPfT69Ore74buf8C26ZTyKnjgMsGCvoDAMOsA07DjjQ1nIkkwIGFFUT3iMO83TdEpWgV/2z7WT9axNH/QFPOjXvwQJFnC7hLxHnX6pgKOdAaioKdi6FX3Y2SwWEO3UuxFd3KwsrZ2+mma/W3KP/cPpSzqyHa5VaJwOCw6vSM4wHSGKmDF4TSrrnMxzIYiTbTpQUlLSBu9HmVa9hB0rEu1weeBv2RKQQ8yCHpwXTHeSkcQqmSOuzednF8o0+MdyNulrwLi5GjMxD6BKzMMN9+7xFuO7txLCEIhGrIMFIvqTw1QFAO4rmAgyG+ljlYTfWHAkzqvImL1o8dMHhGOTsMLLMg39KsZVqalZwwL3ckpdAf81OJJeWCpCuaSgSXnWhJAAAAEph8ULgPc1Ia5pUdcBzvXnoB4f6dNaLD9MVNN62NaBqJzmdvGnGBujEjn2QZCk/jaKjnBFrS+EQj+rewVlx4CFJpYQhI/6cDVcfdlXN2cxPMzId1NfeiAh800mc9KzMCZJk9JdZu0HbwaalHqgscl4GPumn6rHQHRo2XrlDjwdkQ2ptwpto9meVcoL3SASNdqpSKBAYZ64QscekzfssIpXyNmgY807Z9KwnuyAPbGLXGJ910qKFO0wTQd/TvHGxoJ5hmEMoMQbEPxJo9igwqkOANTEZ0nt6urUIY06Kg4x0VxCs5VpGv+PoVjZyaYnKvy5k948Qh/f8q3vKhVF8vh6tsnIrY7966IMPocl5St6SKEJg7JCZ6gZN4cYrI90EK0Ir9Oj7m8kmOZUSBGJQo6+Y/AIZfYBbzfttnCIdYhorsAcoT4xg4D+Ye/MWVwgaCXpBGD3CNgtC7QXIeaWQvyaUtZBfZQS53aHYSJbrRK95pCqIUfg/3MzfxU3cVNm/NkKn2Th3Puq79m4hF8vAHaADMpI9XbCMO/3eTPF3ID4lMzZKOB+qdNkbdkdNTDmG6E6IGkB/JclOqPHPojkURhKGQ06uIbQvkGuwF06Hb0pht9yK8CVRjigzLb1iNVWHYVrN9kgdFtXfgaxW9DmwRrM/lJ+z/lfKnqwjKrvdOgZG43VprCmykARQvP2A03UovdqyKtSElEFp/PAIFv6vruij8cm1ORGYGwPhGcAgwejMgTYR3KwL1RXl/pI9UWNRsdZMwhN5XbE9+7Am2shbcjDGy+oA0AqE2nSV/44bPcIKdHWbo8DpNFnn4YMtQVB15f6vtp1wCj7yppYulqO/6WK/6tdxnLI+2e1kilZ+BZuF35CQ+tquqWgsTudQZSUBHJ6TTyku/s44ZkJU0YhK8g/L3uykM5NtHm+E4CDEdYSOaZ0Joxnk+esWckqdpw52A7KrJ1webkGPJcn+iGAvzx8xG960sfdZNGRLucOSDK1SvKLTc2R61LjNGj3SJqS0CeKhIL5nszkaXFAquEkafWxpd/8s1xObVmYJ90OpF8oxTIbvn6E2MtTVfhyWySNZ2DI3k693/kcUqYSGFsjGe7A90YA80ZOYkKg9SfvK3TiGZYjm365lmq6PwQcTb3dXzwAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "qV2FNaBFqWeL6n9q9OUbCSTcIQvwO0vfaA/f/SxEtLSIaOGIOx8r+WVGFdxmC6i3oOaoEkJWvML7PpKBDtqiK7pKDIaMV5PkV/kQl6UgxZv9OInTwpVPtYcgeeTokG/eBi1qKzJwDoEHVqKeLqrLXJHXhBVQLdoIUOeKj8YMkagVniO9EtK0fW0/9QnRIxXoilxSj5HBEpYwFBitJXRk1ftFGWZFxJXU5PXdRmC+pomyo5Scx+UJQ2NLRWHjKlV0", "aZ8tqrOeEJKt4AMqiRF/WJhIKTDC0HeDTgiJVLZ8OEtiLNj7hflFeVnNXPguxyoqkI/V7pGJtXBpH5N+RswQNA0b23aM33aH0HKHOWoGY/T/L7TQzYFGJ3vTLiXDFZg1OVqkGOMvqAgonOrHGi6IgcALyUMyCKlL5BQY23SeILJpYKolybJNwJfbjxpg0Oz+D2fr7r9XL1GMvgblu52bVQT1fR8uCRJfSsgA2OGw6k/MpKDCfMcjbR8jnZa8ROEvF4cohm7iV1788Vp2/2bdcEZRQSoaGV8pOmA9EkqzJVRABjkDso40fnQcm2IzjBUOsX+uFExVan56/vl9VZVwB0wnee3Uxiredn0kOayiPB16yimxXCDet+M+0UKjmIlmXYpkrCDrH0dn53w+U3OHqMQxPDnUpYBxadM1eI8xWFFxzaLkvega0q0DmEquyY02yiTqo+7Q4qaJVTLgu6/8ekzPxGKRi845NL8gRgaTtM3kidDzIQpyODZD0yeEZDY1M+3sUKHcVkhoxTQBTMyKJPc+M5DeBL3uaWMrvxuL6q8+X0xeBt+9kguPUNtIYqUgPAaXvM2i041bWHTJ0dZLyDJVOyzGaXRaF4mNkAuh4Et6Zw5PuOpMM2mI1oFKEZj7Xqf/yAmy/Le3GfJnMg5vNgE7QxmVsjuKUP28iN8rdi4bUp7c0KJpqLXE6evfRrdZBDRYp+rmOLLDg55ggNuwog==", true, }, { - "lp7+dPDIOfm77haSFnvr33VwYH/KbIalfOJPRvBLzqlHD8BxunNebMr6Gr6S+u+nlp7+dPDIOfm77haSFnvr33VwYH/KbIalfOJPRvBLzqlHD8BxunNebMr6Gr6S+u+nh7yLzdqr7HHQNOpZI8mdj/7lR0IBqB9zvRfyTr+guUG22kZo4y2KINDp272xGglKEeTglTxyDUriZJNF/+T6F8w70MR/rV+flvuo6EJ0+HA+A2ZnBbTjOIl9wjisBV+0iISo2JdNY1vPXlpwhlL2fVpW/WlREkF0bKlBadDIbNJBgM4niJGuEZDru3wqrGueETKHPv7hQ8em+p6vQolp7c0iknjXrGnvlpf4QtUtpg3z/D+snWjRPbVqRgKXWtihlp7+dPDIOfm77haSFnvr33VwYH/KbIalfOJPRvBLzqlHD8BxunNebMr6Gr6S+u+nuIvPFaM6dt7HZEbkeMnXWwSINeYC/j3lqYnce8Jq+XkuF42stVNiooI+TuXECnFdFi9Ib25b9wtyz3H/oKg48He1ftntj5uIRCOBvzkFHGUF6Ty214v3JYvXJjdS4uS2AAAAAY3pKZWWKFdGlxJ2BDiL3xe3eMWst6pMdjbKaKDOB3maYh5JyFpFFYRlSQcwQy4ywQ==", + "lp7+dPDIOfm77haSFnvr33VwYH/KbIalfOJPRvBLzqlHD8BxunNebMr6Gr6S+u+nlp7+dPDIOfm77haSFnvr33VwYH/KbIalfOJPRvBLzqlHD8BxunNebMr6Gr6S+u+nh7yLzdqr7HHQNOpZI8mdj/7lR0IBqB9zvRfyTr+guUG22kZo4y2KINDp272xGglKEeTglTxyDUriZJNF/+T6F8w70MR/rV+flvuo6EJ0+HA+A2ZnBbTjOIl9wjisBV+0iISo2JdNY1vPXlpwhlL2fVpW/WlREkF0bKlBadDIbNJBgM4niJGuEZDru3wqrGueETKHPv7hQ8em+p6vQolp7c0iknjXrGnvlpf4QtUtpg3z/D+snWjRPbVqRgKXWtihlp7+dPDIOfm77haSFnvr33VwYH/KbIalfOJPRvBLzqlHD8BxunNebMr6Gr6S+u+nuIvPFaM6dt7HZEbkeMnXWwSINeYC/j3lqYnce8Jq+XkuF42stVNiooI+TuXECnFdFi9Ib25b9wtyz3H/oKg48He1ftntj5uIRCOBvzkFHGUF6Ty214v3JYvXJjdS4uS2AAAAAY3pKZWWKFdGlxJ2BDiL3xe3eMWst6pMdjbKaKDOB3maYh5JyFpFFYRlSQcwQy4ywQAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "jiGBK+TGHfH8Oadexhdet7ExyIWibSmamWQvffZkyl3WnMoVbTQ3lOks4Mca3sU5qgcaLyQQ1FjFW4g6vtoMapZ43hTGKaWO7bQHsOCvdwHCdwJDulVH16cMTyS9F0BfBJxa88F+JKZc4qMTJjQhspmq755SrKhN9Jf+7uPUhgB4hJTSrmlOkTatgW+/HAf5kZKhv2oRK5p5kS4sU48oqlG1azhMtcHEXDQdcwf9ANel4Z9cb+MQyp2RzI/3hlIx", "", false, }, { - "lp7+dPDIOfm77haSFnvr33VwYH/KbIalfOJPRvBLzqlHD8BxunNebMr6Gr6S+u+nlp7+dPDIOfm77haSFnvr33VwYH/KbIalfOJPRvBLzqlHD8BxunNebMr6Gr6S+u+nh7yLzdqr7HHQNOpZI8mdj/7lR0IBqB9zvRfyTr+guUG22kZo4y2KINDp272xGglKEeTglTxyDUriZJNF/+T6F8w70MR/rV+flvuo6EJ0+HA+A2ZnBbTjOIl9wjisBV+0iISo2JdNY1vPXlpwhlL2fVpW/WlREkF0bKlBadDIbNJBgM4niJGuEZDru3wqrGueETKHPv7hQ8em+p6vQolp7c0iknjXrGnvlpf4QtUtpg3z/D+snWjRPbVqRgKXWtihlp7+dPDIOfm77haSFnvr33VwYH/KbIalfOJPRvBLzqlHD8BxunNebMr6Gr6S+u+nuIvPFaM6dt7HZEbkeMnXWwSINeYC/j3lqYnce8Jq+XkuF42stVNiooI+TuXECnFdFi9Ib25b9wtyz3H/oKg48He1ftntj5uIRCOBvzkFHGUF6Ty214v3JYvXJjdS4uS2AAAAAo3pKZWWKFdGlxJ2BDiL3xe3eMWst6pMdjbKaKDOB3maYh5JyFpFFYRlSQcwQy4ywY4hgSvkxh3x/DmnXsYXXrexMciFom0pmplkL332ZMpd1pzKFW00N5TpLODHGt7FOQ==", + "lp7+dPDIOfm77haSFnvr33VwYH/KbIalfOJPRvBLzqlHD8BxunNebMr6Gr6S+u+nlp7+dPDIOfm77haSFnvr33VwYH/KbIalfOJPRvBLzqlHD8BxunNebMr6Gr6S+u+nh7yLzdqr7HHQNOpZI8mdj/7lR0IBqB9zvRfyTr+guUG22kZo4y2KINDp272xGglKEeTglTxyDUriZJNF/+T6F8w70MR/rV+flvuo6EJ0+HA+A2ZnBbTjOIl9wjisBV+0iISo2JdNY1vPXlpwhlL2fVpW/WlREkF0bKlBadDIbNJBgM4niJGuEZDru3wqrGueETKHPv7hQ8em+p6vQolp7c0iknjXrGnvlpf4QtUtpg3z/D+snWjRPbVqRgKXWtihlp7+dPDIOfm77haSFnvr33VwYH/KbIalfOJPRvBLzqlHD8BxunNebMr6Gr6S+u+nuIvPFaM6dt7HZEbkeMnXWwSINeYC/j3lqYnce8Jq+XkuF42stVNiooI+TuXECnFdFi9Ib25b9wtyz3H/oKg48He1ftntj5uIRCOBvzkFHGUF6Ty214v3JYvXJjdS4uS2AAAAAo3pKZWWKFdGlxJ2BDiL3xe3eMWst6pMdjbKaKDOB3maYh5JyFpFFYRlSQcwQy4ywY4hgSvkxh3x/DmnXsYXXrexMciFom0pmplkL332ZMpd1pzKFW00N5TpLODHGt7FOQAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "hp1iMepdu0rKoBh0NXcw9F9hkiggDIkRNINq2rlvUypPiSmp8U8tDSMeG0YVSovFteecr3THhBJj0qNeEe9jA2Ci64fKG9WT1heMYzEAQKebOErYXYCm9d72n97mYn1XBq+g1Y730XEDv4BIDI1hBDntJcgcj/cSvcILB1+60axJvtyMyuizxUr1JUBUq9njtmJ9m8zK6QZLNqMiKh0f2jokQb5mVhu6v5guW3KIjwQc/oFK/l5ehKAOPKUUggNh", "c9BSUPtO0xjPxWVNkEMfXe7O4UZKpaH/nLIyQJj7iA4=", false, }, { - "lp7+dPDIOfm77haSFnvr33VwYH/KbIalfOJPRvBLzqlHD8BxunNebMr6Gr6S+u+nlp7+dPDIOfm77haSFnvr33VwYH/KbIalfOJPRvBLzqlHD8BxunNebMr6Gr6S+u+nh7yLzdqr7HHQNOpZI8mdj/7lR0IBqB9zvRfyTr+guUG22kZo4y2KINDp272xGglKEeTglTxyDUriZJNF/+T6F8w70MR/rV+flvuo6EJ0+HA+A2ZnBbTjOIl9wjisBV+0iISo2JdNY1vPXlpwhlL2fVpW/WlREkF0bKlBadDIbNJBgM4niJGuEZDru3wqrGueETKHPv7hQ8em+p6vQolp7c0iknjXrGnvlpf4QtUtpg3z/D+snWjRPbVqRgKXWtihlp7+dPDIOfm77haSFnvr33VwYH/KbIalfOJPRvBLzqlHD8BxunNebMr6Gr6S+u+nuIvPFaM6dt7HZEbkeMnXWwSINeYC/j3lqYnce8Jq+XkuF42stVNiooI+TuXECnFdFi9Ib25b9wtyz3H/oKg48He1ftntj5uIRCOBvzkFHGUF6Ty214v3JYvXJjdS4uS2AAAAEI3pKZWWKFdGlxJ2BDiL3xe3eMWst6pMdjbKaKDOB3maYh5JyFpFFYRlSQcwQy4ywY4hgSvkxh3x/DmnXsYXXrexMciFom0pmplkL332ZMpd1pzKFW00N5TpLODHGt7FOYadYjHqXbtKyqAYdDV3MPRfYZIoIAyJETSDatq5b1MqT4kpqfFPLQ0jHhtGFUqLxZQOA7IwcJ7SR+OTYDW2P0W7v4X3u0LJE5AYk6NgPpJmEh++VL39lAF8AQE9T6BNLKrWJ3Rdim7YZehspVd4/TSCrSMx3fxsJXhMbjOypSNR9tj+/G6+c5ofA+1dWhXMT6X7UIY3IeGm17sRD+GoYHzZrYXYaEr0MpC4Y25hvQa78Jsmg0Xf7Bwk3kl5i6iMm63erQPGSyatgy8yiRDpZnzPWiIoS3vxS53X500pDStnreKPLzN2IwJoDp6wKOySKZdGaLefTVIk3ceY9uyFfvLIkVkUc/VN77b8+NtaoDxOZJ+mKyUlZ2CgqFngdxTX6YdVfjIfPeKN0i3Y/Z+6IH5R/7H14rGI+b5XkjZXSYv+u0yjOAYCNWmhnV7k7Xh6irYuuq10PvWvXfkpsCoJ0VKY1btbZK1mQkhW1broGWBGfQWY4VQkmOt+sAbhuihb+7AyoomdL10aqVI1AjhTH5ExvZyXaDrWrY5YgHn+/g0197VE5dZlXTXM5gJxIHomSat5jCsXGyonDl0LHKlPyYHdfmNm7MkLAyIMDf5Nt8u4wLmhISD5THi8y/OCZJeTfLGwCId+al2c+7XrMmHbfBbiV+hgruqlyjhbPGhZ/EVdsfQWvM+YhwQsEu0DgpmZ2pMsFPy29pBRGqrANivFv92Q8NrVuZjUKi5R/zEaBqeEjC7OmtAijtj4dOd9qHj6Q5YEKBdZF/acn/VAUGjSH65FwxkBkv69sui2U3T4r2LOpfa+gEVMYrEUc6m3vFr8VaD2ib6/F4P3akFs9pWILQnYhlm47zVIQ2KSnc0fvL/CEXq2JR+i/EaaQ0YYgs0E1A==", + "lp7+dPDIOfm77haSFnvr33VwYH/KbIalfOJPRvBLzqlHD8BxunNebMr6Gr6S+u+nlp7+dPDIOfm77haSFnvr33VwYH/KbIalfOJPRvBLzqlHD8BxunNebMr6Gr6S+u+nh7yLzdqr7HHQNOpZI8mdj/7lR0IBqB9zvRfyTr+guUG22kZo4y2KINDp272xGglKEeTglTxyDUriZJNF/+T6F8w70MR/rV+flvuo6EJ0+HA+A2ZnBbTjOIl9wjisBV+0iISo2JdNY1vPXlpwhlL2fVpW/WlREkF0bKlBadDIbNJBgM4niJGuEZDru3wqrGueETKHPv7hQ8em+p6vQolp7c0iknjXrGnvlpf4QtUtpg3z/D+snWjRPbVqRgKXWtihlp7+dPDIOfm77haSFnvr33VwYH/KbIalfOJPRvBLzqlHD8BxunNebMr6Gr6S+u+nuIvPFaM6dt7HZEbkeMnXWwSINeYC/j3lqYnce8Jq+XkuF42stVNiooI+TuXECnFdFi9Ib25b9wtyz3H/oKg48He1ftntj5uIRCOBvzkFHGUF6Ty214v3JYvXJjdS4uS2AAAAEI3pKZWWKFdGlxJ2BDiL3xe3eMWst6pMdjbKaKDOB3maYh5JyFpFFYRlSQcwQy4ywY4hgSvkxh3x/DmnXsYXXrexMciFom0pmplkL332ZMpd1pzKFW00N5TpLODHGt7FOYadYjHqXbtKyqAYdDV3MPRfYZIoIAyJETSDatq5b1MqT4kpqfFPLQ0jHhtGFUqLxZQOA7IwcJ7SR+OTYDW2P0W7v4X3u0LJE5AYk6NgPpJmEh++VL39lAF8AQE9T6BNLKrWJ3Rdim7YZehspVd4/TSCrSMx3fxsJXhMbjOypSNR9tj+/G6+c5ofA+1dWhXMT6X7UIY3IeGm17sRD+GoYHzZrYXYaEr0MpC4Y25hvQa78Jsmg0Xf7Bwk3kl5i6iMm63erQPGSyatgy8yiRDpZnzPWiIoS3vxS53X500pDStnreKPLzN2IwJoDp6wKOySKZdGaLefTVIk3ceY9uyFfvLIkVkUc/VN77b8+NtaoDxOZJ+mKyUlZ2CgqFngdxTX6YdVfjIfPeKN0i3Y/Z+6IH5R/7H14rGI+b5XkjZXSYv+u0yjOAYCNWmhnV7k7Xh6irYuuq10PvWvXfkpsCoJ0VKY1btbZK1mQkhW1broGWBGfQWY4VQkmOt+sAbhuihb+7AyoomdL10aqVI1AjhTH5ExvZyXaDrWrY5YgHn+/g0197VE5dZlXTXM5gJxIHomSat5jCsXGyonDl0LHKlPyYHdfmNm7MkLAyIMDf5Nt8u4wLmhISD5THi8y/OCZJeTfLGwCId+al2c+7XrMmHbfBbiV+hgruqlyjhbPGhZ/EVdsfQWvM+YhwQsEu0DgpmZ2pMsFPy29pBRGqrANivFv92Q8NrVuZjUKi5R/zEaBqeEjC7OmtAijtj4dOd9qHj6Q5YEKBdZF/acn/VAUGjSH65FwxkBkv69sui2U3T4r2LOpfa+gEVMYrEUc6m3vFr8VaD2ib6/F4P3akFs9pWILQnYhlm47zVIQ2KSnc0fvL/CEXq2JR+i/EaaQ0YYgs0E1AAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "pNeWbxzzJPMsPpuXBXWZgtLic1s0KL8UeLDGBhEjygrv8m1eMM12pzd+r/scvBEHrnEoQHanlNTlWPywaXaFtB5Hd5RMrnbfLbpe16tvtlH2SRbJbGXSpib5uiuSa6z1ExLtXs9nNWiu10eupG6Pq4SNOacCEVvUgSzCzhyLIlz62gq4DlBBWKmEFI7KiFs7kr2EPBjj2m83dbA/GGVgoYYjgBmFX6/srvLADxerZTKG2moOQrmAx9GJ99nwhRbW", "I8C5RcBDPi2n4omt9oOV2rZk9T9xlSV8PQvLeVHjGb00fCVz7AHOIjLJ03ZCTLQwEKkAk9tQWJ6gFTBnG2+0DDHlXcVkwpMafcpS2diKFe0T4fRb0t9mxNzOFiRVcJoeMU1zb/rE4dIMm9rbEPSDnVSOd8tHNnJDkT+/NcNsQ2w0UEVJJRAEnC7G0Y3522RlDLxpTZ6w0U/9V0pLNkFgDCkFBKvpaEfPDJjoEVyCUWDC1ts9LIR43xh3ZZBdcO/HATHoLzxM3Ef11qF+riV7WDPEJfK11u8WGazzCAFhsx0aKkkbnKl7LnypBzwRvrG2JxdLI/oXL0eoIw9woVjqrg6elHudnHDXezDVXjRWMPaU+L3tOW9aqN+OdP4AhtpgT2CoRCjrOIU3MCFqsrCK9bh33PW1gtNeHC78mIetQM5LWZHtw4KNwafTrQ+GCKPelJhiC2x7ygBtat5rtBsJAVF5wjssLPZx/7fqNqifXB7WyMV7J1M8LBQVXj5kLoS9bpmNHlERRSadC0DEUbY9xhIG2xo7R88R0sq04a299MFv8XJNd+IdueYiMiGF5broHD4UUhPxRBlBO3lOfDTPnRSUGS3Sr6GxwCjKO3MObz/6RNxCk9SnQ4NccD17hS/m", false, }, { - "lp7+dPDIOfm77haSFnvr33VwYH/KbIalfOJPRvBLzqlHD8BxunNebMr6Gr6S+u+nlp7+dPDIOfm77haSFnvr33VwYH/KbIalfOJPRvBLzqlHD8BxunNebMr6Gr6S+u+nh7yLzdqr7HHQNOpZI8mdj/7lR0IBqB9zvRfyTr+guUG22kZo4y2KINDp272xGglKEeTglTxyDUriZJNF/+T6F8w70MR/rV+flvuo6EJ0+HA+A2ZnBbTjOIl9wjisBV+0iISo2JdNY1vPXlpwhlL2fVpW/WlREkF0bKlBadDIbNJBgM4niJGuEZDru3wqrGueETKHPv7hQ8em+p6vQolp7c0iknjXrGnvlpf4QtUtpg3z/D+snWjRPbVqRgKXWtihlp7+dPDIOfm77haSFnvr33VwYH/KbIalfOJPRvBLzqlHD8BxunNebMr6Gr6S+u+nuIvPFaM6dt7HZEbkeMnXWwSINeYC/j3lqYnce8Jq+XkuF42stVNiooI+TuXECnFdFi9Ib25b9wtyz3H/oKg48He1ftntj5uIRCOBvzkFHGUF6Ty214v3JYvXJjdS4uS2AAAAEY3pKZWWKFdGlxJ2BDiL3xe3eMWst6pMdjbKaKDOB3maYh5JyFpFFYRlSQcwQy4ywY4hgSvkxh3x/DmnXsYXXrexMciFom0pmplkL332ZMpd1pzKFW00N5TpLODHGt7FOYadYjHqXbtKyqAYdDV3MPRfYZIoIAyJETSDatq5b1MqT4kpqfFPLQ0jHhtGFUqLxZQOA7IwcJ7SR+OTYDW2P0W7v4X3u0LJE5AYk6NgPpJmEh++VL39lAF8AQE9T6BNLKrWJ3Rdim7YZehspVd4/TSCrSMx3fxsJXhMbjOypSNR9tj+/G6+c5ofA+1dWhXMT6X7UIY3IeGm17sRD+GoYHzZrYXYaEr0MpC4Y25hvQa78Jsmg0Xf7Bwk3kl5i6iMm63erQPGSyatgy8yiRDpZnzPWiIoS3vxS53X500pDStnreKPLzN2IwJoDp6wKOySKZdGaLefTVIk3ceY9uyFfvLIkVkUc/VN77b8+NtaoDxOZJ+mKyUlZ2CgqFngdxTX6YdVfjIfPeKN0i3Y/Z+6IH5R/7H14rGI+b5XkjZXSYv+u0yjOAYCNWmhnV7k7Xh6irYuuq10PvWvXfkpsCoJ0VKY1btbZK1mQkhW1broGWBGfQWY4VQkmOt+sAbhuihb+7AyoomdL10aqVI1AjhTH5ExvZyXaDrWrY5YgHn+/g0197VE5dZlXTXM5gJxIHomSat5jCsXGyonDl0LHKlPyYHdfmNm7MkLAyIMDf5Nt8u4wLmhISD5THi8y/OCZJeTfLGwCId+al2c+7XrMmHbfBbiV+hgruqlyjhbPGhZ/EVdsfQWvM+YhwQsEu0DgpmZ2pMsFPy29pBRGqrANivFv92Q8NrVuZjUKi5R/zEaBqeEjC7OmtAijtj4dOd9qHj6Q5YEKBdZF/acn/VAUGjSH65FwxkBkv69sui2U3T4r2LOpfa+gEVMYrEUc6m3vFr8VaD2ib6/F4P3akFs9pWILQnYhlm47zVIQ2KSnc0fvL/CEXq2JR+i/EaaQ0YYgs0E1KTXlm8c8yTzLD6blwV1mYLS4nNbNCi/FHiwxgYRI8oK7/JtXjDNdqc3fq/7HLwRBw==", + "lp7+dPDIOfm77haSFnvr33VwYH/KbIalfOJPRvBLzqlHD8BxunNebMr6Gr6S+u+nlp7+dPDIOfm77haSFnvr33VwYH/KbIalfOJPRvBLzqlHD8BxunNebMr6Gr6S+u+nh7yLzdqr7HHQNOpZI8mdj/7lR0IBqB9zvRfyTr+guUG22kZo4y2KINDp272xGglKEeTglTxyDUriZJNF/+T6F8w70MR/rV+flvuo6EJ0+HA+A2ZnBbTjOIl9wjisBV+0iISo2JdNY1vPXlpwhlL2fVpW/WlREkF0bKlBadDIbNJBgM4niJGuEZDru3wqrGueETKHPv7hQ8em+p6vQolp7c0iknjXrGnvlpf4QtUtpg3z/D+snWjRPbVqRgKXWtihlp7+dPDIOfm77haSFnvr33VwYH/KbIalfOJPRvBLzqlHD8BxunNebMr6Gr6S+u+nuIvPFaM6dt7HZEbkeMnXWwSINeYC/j3lqYnce8Jq+XkuF42stVNiooI+TuXECnFdFi9Ib25b9wtyz3H/oKg48He1ftntj5uIRCOBvzkFHGUF6Ty214v3JYvXJjdS4uS2AAAAEY3pKZWWKFdGlxJ2BDiL3xe3eMWst6pMdjbKaKDOB3maYh5JyFpFFYRlSQcwQy4ywY4hgSvkxh3x/DmnXsYXXrexMciFom0pmplkL332ZMpd1pzKFW00N5TpLODHGt7FOYadYjHqXbtKyqAYdDV3MPRfYZIoIAyJETSDatq5b1MqT4kpqfFPLQ0jHhtGFUqLxZQOA7IwcJ7SR+OTYDW2P0W7v4X3u0LJE5AYk6NgPpJmEh++VL39lAF8AQE9T6BNLKrWJ3Rdim7YZehspVd4/TSCrSMx3fxsJXhMbjOypSNR9tj+/G6+c5ofA+1dWhXMT6X7UIY3IeGm17sRD+GoYHzZrYXYaEr0MpC4Y25hvQa78Jsmg0Xf7Bwk3kl5i6iMm63erQPGSyatgy8yiRDpZnzPWiIoS3vxS53X500pDStnreKPLzN2IwJoDp6wKOySKZdGaLefTVIk3ceY9uyFfvLIkVkUc/VN77b8+NtaoDxOZJ+mKyUlZ2CgqFngdxTX6YdVfjIfPeKN0i3Y/Z+6IH5R/7H14rGI+b5XkjZXSYv+u0yjOAYCNWmhnV7k7Xh6irYuuq10PvWvXfkpsCoJ0VKY1btbZK1mQkhW1broGWBGfQWY4VQkmOt+sAbhuihb+7AyoomdL10aqVI1AjhTH5ExvZyXaDrWrY5YgHn+/g0197VE5dZlXTXM5gJxIHomSat5jCsXGyonDl0LHKlPyYHdfmNm7MkLAyIMDf5Nt8u4wLmhISD5THi8y/OCZJeTfLGwCId+al2c+7XrMmHbfBbiV+hgruqlyjhbPGhZ/EVdsfQWvM+YhwQsEu0DgpmZ2pMsFPy29pBRGqrANivFv92Q8NrVuZjUKi5R/zEaBqeEjC7OmtAijtj4dOd9qHj6Q5YEKBdZF/acn/VAUGjSH65FwxkBkv69sui2U3T4r2LOpfa+gEVMYrEUc6m3vFr8VaD2ib6/F4P3akFs9pWILQnYhlm47zVIQ2KSnc0fvL/CEXq2JR+i/EaaQ0YYgs0E1KTXlm8c8yTzLD6blwV1mYLS4nNbNCi/FHiwxgYRI8oK7/JtXjDNdqc3fq/7HLwRBwAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "iw5yhCCarVRq/h0Klq4tHNdF1j7PxaDn0AfHTxc2hb//Acav53QStwQShQ0BpQJ7sdchkTTJLkhM13+JpPY/I2WIc6DMZdRzw3pRjLSdMUmce7LYbBJOI+/IyuLZH5IXA7sX4r+xrPssIaMiKR3twmmReN9NrSoovLepDsNmzDVraO71B4rkx7uPXvkqvt3Zkr2EPBjj2m83dbA/GGVgoYYjgBmFX6/srvLADxerZTKG2moOQrmAx9GJ99nwhRbW", "I8C5RcBDPi2n4omt9oOV2rZk9T9xlSV8PQvLeVHjGb00fCVz7AHOIjLJ03ZCTLQwEKkAk9tQWJ6gFTBnG2+0DDHlXcVkwpMafcpS2diKFe0T4fRb0t9mxNzOFiRVcJoeMU1zb/rE4dIMm9rbEPSDnVSOd8tHNnJDkT+/NcNsQ2w0UEVJJRAEnC7G0Y3522RlDLxpTZ6w0U/9V0pLNkFgDCkFBKvpaEfPDJjoEVyCUWDC1ts9LIR43xh3ZZBdcO/HATHoLzxM3Ef11qF+riV7WDPEJfK11u8WGazzCAFhsx0aKkkbnKl7LnypBzwRvrG2JxdLI/oXL0eoIw9woVjqrg6elHudnHDXezDVXjRWMPaU+L3tOW9aqN+OdP4AhtpgT2CoRCjrOIU3MCFqsrCK9bh33PW1gtNeHC78mIetQM5LWZHtw4KNwafTrQ+GCKPelJhiC2x7ygBtat5rtBsJAVF5wjssLPZx/7fqNqifXB7WyMV7J1M8LBQVXj5kLoS9bpmNHlERRSadC0DEUbY9xhIG2xo7R88R0sq04a299MFv8XJNd+IdueYiMiGF5broHD4UUhPxRBlBO3lOfDTPnRSUGS3Sr6GxwCjKO3MObz/6RNxCk9SnQ4NccD17hS/mEFt8d4ERZOfmuvD3A0RCPCnx3Fr6rHdm6j+cfn/NM6o=", false, }, From 88eae36183b2b9a044d9a15c825c0e70f1e8bef4 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 2 Jun 2023 16:59:41 -0500 Subject: [PATCH 426/464] chore: document hollow, remove in-house search --- constraint/commitment.go | 4 ++-- frontend/cs/r1cs/api.go | 2 +- internal/utils/search.go | 23 ++++++++--------------- test/end_to_end.go | 9 ++++++--- 4 files changed, 17 insertions(+), 21 deletions(-) diff --git a/constraint/commitment.go b/constraint/commitment.go index ffe013e56e..a64cc8d280 100644 --- a/constraint/commitment.go +++ b/constraint/commitment.go @@ -105,7 +105,7 @@ func (c Commitments) Interleave(nbPublicVars int) (nbPrivateCommittedWires int, publicAndCommitmentCommitted[i] = make([]int, c[i].NbPublicCommitted(), len(c[i].Committed)) copy(publicAndCommitmentCommitted[i], c[i].PublicCommitted()) for _, j := range nonPublicCommitted { - if found, k := utils.BinarySearch(commitmentWires, j); found { // if j is a commitment wire + if k, found := utils.FindInSlice(commitmentWires, j); found { // if j is a commitment wire publicAndCommitmentCommitted[i] = append(publicAndCommitmentCommitted[i], k+nbPublicVars) } else { privateCommitted[i] = append(privateCommitted[i], j) @@ -124,7 +124,7 @@ func (c Commitments) CommitmentIndexesInCommittedLists() [][]int { for i := range c { res[i] = make([]int, 0, i) for j := 0; j < i; j++ { - if found, k := utils.BinarySearch(c[i].PrivateCommitted(), c[j].CommitmentIndex); found { + if k, found := utils.FindInSlice(c[i].PrivateCommitted(), c[j].CommitmentIndex); found { res[i] = append(res[i], k+c[i].NbPublicCommitted()) } } diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index 9ba52e44af..4a864c65d5 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -724,7 +724,7 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error commitments := builder.cs.GetCommitments() var alreadyCommitted bool for i := range commitments { - if alreadyCommitted, _ = utils.BinarySearch(commitments[i].Committed, t.VID); alreadyCommitted { + if alreadyCommitted, _ = utils.FindInSlice(commitments[i].Committed, t.VID); alreadyCommitted { toCommit := commitments[i].CommitmentIndex vars = append(vars, expr.LinearExpression{{Coeff: constraint.Element{1}, VID: toCommit}}) // TODO Replace with mont 1 builder.heap.push(linMeta{lID: len(vars) - 1, tID: 0, val: toCommit}) diff --git a/internal/utils/search.go b/internal/utils/search.go index c8e8ae05cd..7a8d00e6ab 100644 --- a/internal/utils/search.go +++ b/internal/utils/search.go @@ -1,18 +1,11 @@ package utils -// BinarySearch attempts to find the target in x. If not found, returns false and the index where the target would be inserted. -func BinarySearch(x []int, target int) (bool, int) { - i := 0 - for j := len(x); i != j; { - m := (i + j) / 2 - if x[m] < target { - i = m + 1 - } else { - j = m - } - } - if i < len(x) && x[i] == target { - return true, i - } - return false, i +import "sort" + +// FindInSlice attempts to find the target in increasing slice x. +// If not found, returns false and the index where the target would be inserted. +func FindInSlice(x []int, target int) (int, bool) { + return sort.Find(len(x), func(i int) int { + return target - x[i] + }) } diff --git a/test/end_to_end.go b/test/end_to_end.go index 9c9eea12c4..d5e581de57 100644 --- a/test/end_to_end.go +++ b/test/end_to_end.go @@ -109,10 +109,13 @@ func testAll(t *testing.T, assignment frontend.Circuit) { }) } +// hollow takes a gnark circuit and removes all the witness data. The resulting circuit can be used for compilation purposes +// Its purpose is to make testing more convenient. For example, as opposed to SolvingSucceeded(circuit, assignment), +// one can write SolvingSucceeded(hollow(assignment), assignment), obviating the creation of a separate circuit object. func hollow(c frontend.Circuit) frontend.Circuit { cV := reflect.ValueOf(c).Elem() t := reflect.TypeOf(c).Elem() - res := reflect.New(t) + res := reflect.New(t) // a new object of the same type as c resE := res.Elem() resC := res.Interface().(frontend.Circuit) @@ -120,9 +123,9 @@ func hollow(c frontend.Circuit) frontend.Circuit { for i := 0; i < t.NumField(); i++ { fieldT := t.Field(i).Type - if fieldT.Kind() == reflect.Slice && fieldT.Elem().Implements(frontendVar) { + if fieldT.Kind() == reflect.Slice && fieldT.Elem().Implements(frontendVar) { // create empty slices for witness slices resE.Field(i).Set(reflect.ValueOf(make([]frontend.Variable, cV.Field(i).Len()))) - } else if fieldT != frontendVar { + } else if fieldT != frontendVar { // copy non-witness variables resE.Field(i).Set(cV.Field(i)) } } From 6ec0af711b068ee37d974fa9a7615aaa256b5b64 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Mon, 5 Jun 2023 16:37:45 +0200 Subject: [PATCH 427/464] feat: add sha2 primitive (#689) * feat: add variable partition into two * refactor: collect bits hints * refactor: make hints private * fix: use anon hints for some tests * feat: add BinaryHasher interface * feat: add logderivprecomp package for precomputed functions * fixup! feat: add BinaryHasher interface * feat: add uints package * refactor: use uints in keccak permutation * feat: add sha256 permutation * feat: implement sha2 hash * fix: ignore test lint error * chore: remove old uint64api implementation --- internal/backend/circuits/hint.go | 2 +- std/accumulator/merkle/verify.go | 6 +- std/commitments/fri/fri.go | 4 +- std/fiat-shamir/settings.go | 4 +- std/fiat-shamir/transcript.go | 4 +- std/gkr/gkr_test.go | 10 +- std/hash/hash.go | 41 ++- std/hash/sha2/sha2.go | 89 +++++ std/hash/sha2/sha2_test.go | 50 +++ std/hints.go | 7 +- .../logderivprecomp/logderivprecomp.go | 127 +++++++ .../logderivprecomp/logderivprecomp_test.go | 55 +++ std/math/bits/conversion_binary.go | 33 +- std/math/bits/conversion_ternary.go | 27 +- std/math/bits/hints.go | 114 ++++++ std/math/bits/naf.go | 61 +--- std/math/bitslice/hints.go | 34 ++ std/math/bitslice/opts.go | 37 ++ std/math/bitslice/partition.go | 69 ++++ std/math/bitslice/partition_test.go | 30 ++ std/math/uints/hints.go | 53 +++ std/math/uints/uint8.go | 342 ++++++++++++++++++ std/math/uints/uint8_test.go | 81 +++++ std/permutation/keccakf/keccak_test.go | 21 +- std/permutation/keccakf/keccakf.go | 83 +++-- std/permutation/keccakf/uint64api.go | 101 ------ std/permutation/keccakf/uint64api_test.go | 30 -- std/permutation/sha2/sha2block.go | 90 +++++ std/permutation/sha2/sha2block_test.go | 116 ++++++ std/signature/eddsa/eddsa.go | 2 +- test/engine_test.go | 4 +- 31 files changed, 1407 insertions(+), 320 deletions(-) create mode 100644 std/hash/sha2/sha2.go create mode 100644 std/hash/sha2/sha2_test.go create mode 100644 std/internal/logderivprecomp/logderivprecomp.go create mode 100644 std/internal/logderivprecomp/logderivprecomp_test.go create mode 100644 std/math/bits/hints.go create mode 100644 std/math/bitslice/hints.go create mode 100644 std/math/bitslice/opts.go create mode 100644 std/math/bitslice/partition.go create mode 100644 std/math/bitslice/partition_test.go create mode 100644 std/math/uints/hints.go create mode 100644 std/math/uints/uint8.go create mode 100644 std/math/uints/uint8_test.go delete mode 100644 std/permutation/keccakf/uint64api.go delete mode 100644 std/permutation/keccakf/uint64api_test.go create mode 100644 std/permutation/sha2/sha2block.go create mode 100644 std/permutation/sha2/sha2block_test.go diff --git a/internal/backend/circuits/hint.go b/internal/backend/circuits/hint.go index 5ed7a009de..1542438d5f 100644 --- a/internal/backend/circuits/hint.go +++ b/internal/backend/circuits/hint.go @@ -91,7 +91,7 @@ func init() { }, } - addNewEntry("recursive_hint", &recursiveHint{}, good, bad, gnark.Curves(), make3, bits.NBits) + addNewEntry("recursive_hint", &recursiveHint{}, good, bad, gnark.Curves(), make3, bits.GetHints()[1]) } { diff --git a/std/accumulator/merkle/verify.go b/std/accumulator/merkle/verify.go index 35caff2ce8..3ec92412d6 100644 --- a/std/accumulator/merkle/verify.go +++ b/std/accumulator/merkle/verify.go @@ -62,7 +62,7 @@ type MerkleProof struct { // leafSum returns the hash created from data inserted to form a leaf. // Without domain separation. -func leafSum(api frontend.API, h hash.Hash, data frontend.Variable) frontend.Variable { +func leafSum(api frontend.API, h hash.FieldHasher, data frontend.Variable) frontend.Variable { h.Reset() h.Write(data) @@ -73,7 +73,7 @@ func leafSum(api frontend.API, h hash.Hash, data frontend.Variable) frontend.Var // nodeSum returns the hash created from data inserted to form a leaf. // Without domain separation. -func nodeSum(api frontend.API, h hash.Hash, a, b frontend.Variable) frontend.Variable { +func nodeSum(api frontend.API, h hash.FieldHasher, a, b frontend.Variable) frontend.Variable { h.Reset() h.Write(a, b) @@ -86,7 +86,7 @@ func nodeSum(api frontend.API, h hash.Hash, a, b frontend.Variable) frontend.Var // true if the first element of the proof set is a leaf of data in the Merkle // root. False is returned if the proof set or Merkle root is nil, and if // 'numLeaves' equals 0. -func (mp *MerkleProof) VerifyProof(api frontend.API, h hash.Hash, leaf frontend.Variable) { +func (mp *MerkleProof) VerifyProof(api frontend.API, h hash.FieldHasher, leaf frontend.Variable) { depth := len(mp.Path) - 1 sum := leafSum(api, h, mp.Path[0]) diff --git a/std/commitments/fri/fri.go b/std/commitments/fri/fri.go index 96b8ac2c3d..93dd0b301f 100644 --- a/std/commitments/fri/fri.go +++ b/std/commitments/fri/fri.go @@ -50,7 +50,7 @@ type RadixTwoFri struct { // hash function that is used for Fiat Shamir and for committing to // the oracles. - h hash.Hash + h hash.FieldHasher // nbSteps number of interactions between the prover and the verifier nbSteps int @@ -66,7 +66,7 @@ type RadixTwoFri struct { // NewRadixTwoFri creates an FFT-like oracle proof of proximity. // * h is the hash function that is used for the Merkle proofs // * gen is the generator of the cyclic group of unity of size \rho * size -func NewRadixTwoFri(size uint64, h hash.Hash, gen big.Int) RadixTwoFri { +func NewRadixTwoFri(size uint64, h hash.FieldHasher, gen big.Int) RadixTwoFri { var res RadixTwoFri diff --git a/std/fiat-shamir/settings.go b/std/fiat-shamir/settings.go index 7b1f2a31a7..146a64355e 100644 --- a/std/fiat-shamir/settings.go +++ b/std/fiat-shamir/settings.go @@ -9,7 +9,7 @@ type Settings struct { Transcript *Transcript Prefix string BaseChallenges []frontend.Variable - Hash hash.Hash + Hash hash.FieldHasher } func WithTranscript(transcript *Transcript, prefix string, baseChallenges ...frontend.Variable) Settings { @@ -20,7 +20,7 @@ func WithTranscript(transcript *Transcript, prefix string, baseChallenges ...fro } } -func WithHash(hash hash.Hash, baseChallenges ...frontend.Variable) Settings { +func WithHash(hash hash.FieldHasher, baseChallenges ...frontend.Variable) Settings { return Settings{ BaseChallenges: baseChallenges, Hash: hash, diff --git a/std/fiat-shamir/transcript.go b/std/fiat-shamir/transcript.go index 3ce9af5d98..a8d82547d0 100644 --- a/std/fiat-shamir/transcript.go +++ b/std/fiat-shamir/transcript.go @@ -33,7 +33,7 @@ var ( // Transcript handles the creation of challenges for Fiat Shamir. type Transcript struct { // hash function that is used. - h hash.Hash + h hash.FieldHasher challenges map[string]challenge previous *challenge @@ -52,7 +52,7 @@ type challenge struct { // NewTranscript returns a new transcript. // h is the hash function that is used to compute the challenges. // challenges are the name of the challenges. The order is important. -func NewTranscript(api frontend.API, h hash.Hash, challengesID ...string) Transcript { +func NewTranscript(api frontend.API, h hash.FieldHasher, challengesID ...string) Transcript { n := len(challengesID) t := Transcript{ challenges: make(map[string]challenge, n), diff --git a/std/gkr/gkr_test.go b/std/gkr/gkr_test.go index 29060c59b6..96b6078b57 100644 --- a/std/gkr/gkr_test.go +++ b/std/gkr/gkr_test.go @@ -110,7 +110,7 @@ func (c *GkrVerifierCircuit) Define(api frontend.API) error { } assignment := makeInOutAssignment(testCase.Circuit, c.Input, c.Output) - var hsh hash.Hash + var hsh hash.FieldHasher if c.ToFail { hsh = NewMessageCounter(api, 1, 1) } else { @@ -414,7 +414,7 @@ func SliceEqual[T comparable](expected, seen []T) bool { type HashDescription map[string]interface{} -func HashFromDescription(api frontend.API, d HashDescription) (hash.Hash, error) { +func HashFromDescription(api frontend.API, d HashDescription) (hash.FieldHasher, error) { if _type, ok := d["type"]; ok { switch _type { case "const": @@ -456,13 +456,13 @@ func (m *MessageCounter) Reset() { m.state = m.startState } -func NewMessageCounter(api frontend.API, startState, step int) hash.Hash { +func NewMessageCounter(api frontend.API, startState, step int) hash.FieldHasher { transcript := &MessageCounter{startState: int64(startState), state: int64(startState), step: int64(step), api: api} return transcript } -func NewMessageCounterGenerator(startState, step int) func(frontend.API) hash.Hash { - return func(api frontend.API) hash.Hash { +func NewMessageCounterGenerator(startState, step int) func(frontend.API) hash.FieldHasher { + return func(api frontend.API) hash.FieldHasher { return NewMessageCounter(api, startState, step) } } diff --git a/std/hash/hash.go b/std/hash/hash.go index 55e8791084..b63f9835ec 100644 --- a/std/hash/hash.go +++ b/std/hash/hash.go @@ -17,16 +17,47 @@ limitations under the License. // Package hash provides an interface that hash functions (as gadget) should implement. package hash -import "github.com/consensys/gnark/frontend" - -type Hash interface { - +import ( + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/math/uints" +) + +// FieldHasher hashes inputs into a short digest. This interface mocks +// [BinaryHasher], but is more suitable in-circuit by assuming the inputs are +// scalar field elements and outputs digest as a field element. Such hash +// functions are for examle Poseidon, MiMC etc. +type FieldHasher interface { // Sum computes the hash of the internal state of the hash function. Sum() frontend.Variable - // Write populate the internal state of the hash function with data. + // Write populate the internal state of the hash function with data. The inputs are native field elements. Write(data ...frontend.Variable) // Reset empty the internal state and put the intermediate state to zero. Reset() } + +// BinaryHasher hashes inputs into a short digest. It takes as inputs bytes and +// outputs byte array whose length depends on the underlying hash function. For +// SNARK-native hash functions use [FieldHasher]. +type BinaryHasher interface { + // Sum finalises the current hash and returns the digest. + Sum() []uints.U8 + + // Write writes more bytes into the current hash state. + Write([]uints.U8) + + // Size returns the number of bytes this hash function returns in a call to + // [BinaryHasher.Sum]. + Size() int +} + +// BinaryFixedLengthHasher is like [BinaryHasher], but assumes the length of the +// input is not full length as defined during compile time. This allows to +// compute digest of variable-length input, unlike [BinaryHasher] which assumes +// the length of the input is the total number of bytes written. +type BinaryFixedLengthHasher interface { + BinaryHasher + // FixedLengthSum returns digest of the first length bytes. + FixedLengthSum(length frontend.Variable) []uints.U8 +} diff --git a/std/hash/sha2/sha2.go b/std/hash/sha2/sha2.go new file mode 100644 index 0000000000..edb261e621 --- /dev/null +++ b/std/hash/sha2/sha2.go @@ -0,0 +1,89 @@ +// Package sha2 implements SHA2 hash computation. +// +// This package extends the SHA2 permutation function [sha2] into a full SHA2 +// hash. +package sha2 + +import ( + "encoding/binary" + + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/hash" + "github.com/consensys/gnark/std/math/uints" + "github.com/consensys/gnark/std/permutation/sha2" +) + +var _seed = uints.NewU32Array([]uint32{ + 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19, +}) + +type digest struct { + uapi *uints.BinaryField[uints.U32] + in []uints.U8 +} + +func New(api frontend.API) (hash.BinaryHasher, error) { + uapi, err := uints.New[uints.U32](api) + if err != nil { + return nil, err + } + return &digest{uapi: uapi}, nil +} + +func (d *digest) Write(data []uints.U8) { + d.in = append(d.in, data...) +} + +func (d *digest) padded(bytesLen int) []uints.U8 { + zeroPadLen := 55 - bytesLen%64 + if zeroPadLen < 0 { + zeroPadLen += 64 + } + if cap(d.in) < len(d.in)+9+zeroPadLen { + // in case this is the first time this method is called increase the + // capacity of the slice to fit the padding. + d.in = append(d.in, make([]uints.U8, 9+zeroPadLen)...) + d.in = d.in[:len(d.in)-9-zeroPadLen] + } + buf := d.in + buf = append(buf, uints.NewU8(0x80)) + buf = append(buf, uints.NewU8Array(make([]uint8, zeroPadLen))...) + lenbuf := make([]uint8, 8) + binary.BigEndian.PutUint64(lenbuf, uint64(8*bytesLen)) + buf = append(buf, uints.NewU8Array(lenbuf)...) + return buf +} + +func (d *digest) Sum() []uints.U8 { + var runningDigest [8]uints.U32 + var buf [64]uints.U8 + copy(runningDigest[:], _seed) + padded := d.padded(len(d.in)) + for i := 0; i < len(padded)/64; i++ { + copy(buf[:], padded[i*64:(i+1)*64]) + runningDigest = sha2.Permute(d.uapi, runningDigest, buf) + } + var ret []uints.U8 + for i := range runningDigest { + ret = append(ret, d.uapi.UnpackMSB(runningDigest[i])...) + } + return ret +} + +func (d *digest) FixedLengthSum(length frontend.Variable) []uints.U8 { + panic("TODO") + // we need to do two things here -- first the padding has to be put to the + // right place. For that we need to know how many blocks we have used. We + // need to fit at least 9 more bytes (padding byte and 8 bytes for input + // length). Knowing the block, we have to keep running track if the current + // block is the expected one. + // + // idea - have a mask for blocks where 1 is only for the block we want to + // use. +} + +func (d *digest) Reset() { + d.in = nil +} + +func (d *digest) Size() int { return 32 } diff --git a/std/hash/sha2/sha2_test.go b/std/hash/sha2/sha2_test.go new file mode 100644 index 0000000000..d4acf5baf3 --- /dev/null +++ b/std/hash/sha2/sha2_test.go @@ -0,0 +1,50 @@ +package sha2 + +import ( + "crypto/sha256" + "fmt" + "testing" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/math/uints" + "github.com/consensys/gnark/test" +) + +type sha2Circuit struct { + In []uints.U8 + Expected [32]uints.U8 +} + +func (c *sha2Circuit) Define(api frontend.API) error { + h, err := New(api) + if err != nil { + return err + } + uapi, err := uints.New[uints.U32](api) + if err != nil { + return err + } + h.Write(c.In) + res := h.Sum() + if len(res) != 32 { + return fmt.Errorf("not 32 bytes") + } + for i := range c.Expected { + uapi.ByteAssertEq(c.Expected[i], res[i]) + } + return nil +} + +func TestSHA2(t *testing.T) { + bts := make([]byte, 310) + dgst := sha256.Sum256(bts) + witness := sha2Circuit{ + In: uints.NewU8Array(bts), + } + copy(witness.Expected[:], uints.NewU8Array(dgst[:])) + err := test.IsSolved(&sha2Circuit{In: make([]uints.U8, len(bts))}, &witness, ecc.BN254.ScalarField()) + if err != nil { + t.Fatal(err) + } +} diff --git a/std/hints.go b/std/hints.go index fae0ee91e3..d807b1f024 100644 --- a/std/hints.go +++ b/std/hints.go @@ -9,6 +9,7 @@ import ( "github.com/consensys/gnark/std/evmprecompiles" "github.com/consensys/gnark/std/internal/logderivarg" "github.com/consensys/gnark/std/math/bits" + "github.com/consensys/gnark/std/math/bitslice" "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/std/rangecheck" "github.com/consensys/gnark/std/selector" @@ -30,13 +31,11 @@ func registerHints() { solver.RegisterHint(sw_bls12377.DecomposeScalarG1) solver.RegisterHint(sw_bls24315.DecomposeScalarG2) solver.RegisterHint(sw_bls12377.DecomposeScalarG2) - solver.RegisterHint(bits.NTrits) - solver.RegisterHint(bits.NNAF) - solver.RegisterHint(bits.IthBit) - solver.RegisterHint(bits.NBits) + solver.RegisterHint(bits.GetHints()...) solver.RegisterHint(selector.GetHints()...) solver.RegisterHint(emulated.GetHints()...) solver.RegisterHint(rangecheck.GetHints()...) solver.RegisterHint(evmprecompiles.GetHints()...) solver.RegisterHint(logderivarg.GetHints()...) + solver.RegisterHint(bitslice.GetHints()...) } diff --git a/std/internal/logderivprecomp/logderivprecomp.go b/std/internal/logderivprecomp/logderivprecomp.go new file mode 100644 index 0000000000..d768c10a32 --- /dev/null +++ b/std/internal/logderivprecomp/logderivprecomp.go @@ -0,0 +1,127 @@ +// Package logderivprecomp allows computing functions using precomputation. +// +// Instead of computing binary functions and checking that the result is +// correctly constrained, we instead can precompute all valid values of a +// function and then perform lookup to obtain the result. For example, for the +// XOR function we would naively otherwise have to split the inputs into bits, +// XOR one-by-one and recombine. +// +// With this package, we can instead compute all results for two inputs of +// length 8 bit and then just perform a lookup on the inputs. +// +// We use the [logderivarg] package for the actual log-derivative argument. +package logderivprecomp + +import ( + "fmt" + "math/big" + "reflect" + + "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/internal/kvstore" + "github.com/consensys/gnark/std/internal/logderivarg" +) + +type ctxPrecomputedKey struct{ fn uintptr } + +// Precomputed holds all precomputed function values and queries. +type Precomputed struct { + api frontend.API + compute solver.Hint + queries []frontend.Variable + rets []uint +} + +// New returns a new [Precomputed]. It defers the log-derivative argument. +func New(api frontend.API, fn solver.Hint, rets []uint) (*Precomputed, error) { + kv, ok := api.Compiler().(kvstore.Store) + if !ok { + panic("builder should implement key-value store") + } + ch := kv.GetKeyValue(ctxPrecomputedKey{fn: reflect.ValueOf(fn).Pointer()}) + if ch != nil { + if prt, ok := ch.(*Precomputed); ok { + return prt, nil + } else { + panic("stored rangechecker is not valid") + } + } + // check that the output lengths fit into a single element + var s uint = 16 + for _, v := range rets { + s += v + } + if s >= uint(api.Compiler().FieldBitLen()) { + return nil, fmt.Errorf("result doesn't fit into field element") + } + t := &Precomputed{ + api: api, + compute: fn, + queries: nil, + rets: rets, + } + kv.SetKeyValue(ctxPrecomputedKey{fn: reflect.ValueOf(fn).Pointer()}, t) + api.Compiler().Defer(t.build) + return t, nil +} + +func (t *Precomputed) pack(x, y frontend.Variable, rets []frontend.Variable) frontend.Variable { + shift := big.NewInt(1 << 8) + packed := t.api.Add(x, t.api.Mul(y, shift)) + for i := range t.rets { + shift.Lsh(shift, t.rets[i]) + packed = t.api.Add(packed, t.api.Mul(rets[i], shift)) + } + return packed +} + +// Query +func (t *Precomputed) Query(x, y frontend.Variable) []frontend.Variable { + // we don't have to check here. We assume the inputs are range checked and + // range check the output. + rets, err := t.api.Compiler().NewHint(t.compute, len(t.rets), x, y) + if err != nil { + panic(err) + } + packed := t.pack(x, y, rets) + t.queries = append(t.queries, packed) + return rets +} + +func (t *Precomputed) buildTable() []frontend.Variable { + tmp := new(big.Int) + shift := new(big.Int) + tbl := make([]frontend.Variable, 65536) + inputs := []*big.Int{big.NewInt(0), big.NewInt(0)} + outputs := make([]*big.Int, len(t.rets)) + for i := range outputs { + outputs[i] = new(big.Int) + } + for x := int64(0); x < 256; x++ { + inputs[0].SetInt64(x) + for y := int64(0); y < 256; y++ { + shift.SetInt64(1 << 8) + i := x | (y << 8) + inputs[1].SetInt64(y) + if err := t.compute(t.api.Compiler().Field(), inputs, outputs); err != nil { + panic(err) + } + tblval := new(big.Int).SetInt64(i) + for j := range t.rets { + shift.Lsh(shift, t.rets[j]) + tblval.Add(tblval, tmp.Mul(outputs[j], shift)) + } + tbl[i] = tblval + } + } + return tbl +} + +func (t *Precomputed) build(api frontend.API) error { + if len(t.queries) == 0 { + return nil + } + table := t.buildTable() + return logderivarg.Build(t.api, logderivarg.AsTable(table), logderivarg.AsTable(t.queries)) +} diff --git a/std/internal/logderivprecomp/logderivprecomp_test.go b/std/internal/logderivprecomp/logderivprecomp_test.go new file mode 100644 index 0000000000..8de2755f1a --- /dev/null +++ b/std/internal/logderivprecomp/logderivprecomp_test.go @@ -0,0 +1,55 @@ +package logderivprecomp + +import ( + "crypto/rand" + "math/big" + "testing" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/constraint/solver" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/test" +) + +type TestXORCircuit struct { + X, Y [100]frontend.Variable + Res [100]frontend.Variable +} + +func (c *TestXORCircuit) Define(api frontend.API) error { + tbl, err := New(api, xorHint, []uint{8}) + if err != nil { + return err + } + for i := range c.X { + res := tbl.Query(c.X[i], c.Y[i]) + api.AssertIsEqual(res[0], c.Res[i]) + } + return nil +} + +func xorHint(_ *big.Int, inputs, outputs []*big.Int) error { + outputs[0].Xor(inputs[0], inputs[1]) + return nil +} + +func TestXor(t *testing.T) { + assert := test.NewAssert(t) + bound := big.NewInt(255) + var xs, ys, ress [100]frontend.Variable + for i := range xs { + x, _ := rand.Int(rand.Reader, bound) + y, _ := rand.Int(rand.Reader, bound) + ress[i] = new(big.Int).Xor(x, y) + xs[i] = x + ys[i] = y + } + witness := &TestXORCircuit{X: xs, Y: ys, Res: ress} + assert.ProverSucceeded(&TestXORCircuit{}, witness, + test.WithBackends(backend.GROTH16), + test.WithSolverOpts(solver.WithHints(xorHint)), + test.NoFuzzing(), + test.NoSerialization(), + test.WithCurves(ecc.BN254)) +} diff --git a/std/math/bits/conversion_binary.go b/std/math/bits/conversion_binary.go index 6fb3cb8fcc..fddb60b74c 100644 --- a/std/math/bits/conversion_binary.go +++ b/std/math/bits/conversion_binary.go @@ -3,16 +3,9 @@ package bits import ( "math/big" - "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" ) -func init() { - // register hints - solver.RegisterHint(IthBit) - solver.RegisterHint(NBits) -} - // ToBinary is an alias of ToBase(api, Binary, v, opts) func ToBinary(api frontend.API, v frontend.Variable, opts ...BaseConversionOption) []frontend.Variable { return ToBase(api, Binary, v, opts...) @@ -65,7 +58,7 @@ func toBinary(api frontend.API, v frontend.Variable, opts ...BaseConversionOptio c := big.NewInt(1) - bits, err := api.Compiler().NewHint(NBits, cfg.NbDigits, v) + bits, err := api.Compiler().NewHint(nBits, cfg.NbDigits, v) if err != nil { panic(err) } @@ -85,27 +78,3 @@ func toBinary(api frontend.API, v frontend.Variable, opts ...BaseConversionOptio return bits } - -// IthBit returns the i-tb bit the input. The function expects exactly two -// integer inputs i and n, takes the little-endian bit representation of n and -// returns its i-th bit. -func IthBit(_ *big.Int, inputs []*big.Int, results []*big.Int) error { - result := results[0] - if !inputs[1].IsUint64() { - result.SetUint64(0) - return nil - } - - result.SetUint64(uint64(inputs[0].Bit(int(inputs[1].Uint64())))) - return nil -} - -// NBits returns the first bits of the input. The number of returned bits is -// defined by the length of the results slice. -func NBits(_ *big.Int, inputs []*big.Int, results []*big.Int) error { - n := inputs[0] - for i := 0; i < len(results); i++ { - results[i].SetUint64(uint64(n.Bit(i))) - } - return nil -} diff --git a/std/math/bits/conversion_ternary.go b/std/math/bits/conversion_ternary.go index 7e366eb1d9..d38095d2b2 100644 --- a/std/math/bits/conversion_ternary.go +++ b/std/math/bits/conversion_ternary.go @@ -4,18 +4,9 @@ import ( "math" "math/big" - "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" ) -// NTrits returns the first trits of the input. The number of returned trits is -// defined by the length of the results slice. -var NTrits = nTrits - -func init() { - solver.RegisterHint(NTrits) -} - // ToTernary is an alias of ToBase(api, Ternary, v, opts...) func ToTernary(api frontend.API, v frontend.Variable, opts ...BaseConversionOption) []frontend.Variable { return ToBase(api, Ternary, v, opts...) @@ -70,7 +61,7 @@ func toTernary(api frontend.API, v frontend.Variable, opts ...BaseConversionOpti c := big.NewInt(1) b := big.NewInt(3) - trits, err := api.Compiler().NewHint(NTrits, cfg.NbDigits, v) + trits, err := api.Compiler().NewHint(nTrits, cfg.NbDigits, v) if err != nil { panic(err) } @@ -105,19 +96,3 @@ func AssertIsTrit(api frontend.API, v frontend.Variable) { y := api.Mul(api.Sub(1, v), api.Sub(2, v)) api.AssertIsEqual(api.Mul(v, y), 0) } - -func nTrits(_ *big.Int, inputs []*big.Int, results []*big.Int) error { - n := inputs[0] - // TODO using big.Int Text method is likely not cheap - base3 := n.Text(3) - i := 0 - for j := len(base3) - 1; j >= 0 && i < len(results); j-- { - results[i].SetUint64(uint64(base3[j] - 48)) - i++ - } - for ; i < len(results); i++ { - results[i].SetUint64(0) - } - - return nil -} diff --git a/std/math/bits/hints.go b/std/math/bits/hints.go new file mode 100644 index 0000000000..bb3da6d13c --- /dev/null +++ b/std/math/bits/hints.go @@ -0,0 +1,114 @@ +package bits + +import ( + "errors" + "math/big" + + "github.com/consensys/gnark/constraint/solver" +) + +func GetHints() []solver.Hint { + return []solver.Hint{ + ithBit, + nBits, + nTrits, + nNaf, + } +} + +func init() { + solver.RegisterHint(GetHints()...) +} + +// IthBit returns the i-tb bit the input. The function expects exactly two +// integer inputs i and n, takes the little-endian bit representation of n and +// returns its i-th bit. +func ithBit(_ *big.Int, inputs []*big.Int, results []*big.Int) error { + result := results[0] + if !inputs[1].IsUint64() { + result.SetUint64(0) + return nil + } + + result.SetUint64(uint64(inputs[0].Bit(int(inputs[1].Uint64())))) + return nil +} + +// NBits returns the first bits of the input. The number of returned bits is +// defined by the length of the results slice. +func nBits(_ *big.Int, inputs []*big.Int, results []*big.Int) error { + n := inputs[0] + for i := 0; i < len(results); i++ { + results[i].SetUint64(uint64(n.Bit(i))) + } + return nil +} + +// nTrits returns the first trits of the input. The number of returned trits is +// defined by the length of the results slice. +func nTrits(_ *big.Int, inputs []*big.Int, results []*big.Int) error { + n := inputs[0] + // TODO using big.Int Text method is likely not cheap + base3 := n.Text(3) + i := 0 + for j := len(base3) - 1; j >= 0 && i < len(results); j-- { + results[i].SetUint64(uint64(base3[j] - 48)) + i++ + } + for ; i < len(results); i++ { + results[i].SetUint64(0) + } + + return nil +} + +// NNAF returns the NAF decomposition of the input. The number of digits is +// defined by the number of elements in the results slice. +func nNaf(_ *big.Int, inputs []*big.Int, results []*big.Int) error { + n := inputs[0] + return nafDecomposition(n, results) +} + +// nafDecomposition gets the naf decomposition of a big number +func nafDecomposition(a *big.Int, results []*big.Int) error { + if a == nil || a.Sign() == -1 { + return errors.New("invalid input to naf decomposition; negative (or nil) big.Int not supported") + } + + var zero, one, three big.Int + + one.SetUint64(1) + three.SetUint64(3) + + n := 0 + + // some buffers + var buf, aCopy big.Int + aCopy.Set(a) + + for aCopy.Cmp(&zero) != 0 && n < len(results) { + + // if aCopy % 2 == 0 + buf.And(&aCopy, &one) + + // aCopy even + if buf.Cmp(&zero) == 0 { + results[n].SetUint64(0) + } else { // aCopy odd + buf.And(&aCopy, &three) + if buf.IsUint64() && buf.Uint64() == 3 { + results[n].SetInt64(-1) + aCopy.Add(&aCopy, &one) + } else { + results[n].SetUint64(1) + } + } + aCopy.Rsh(&aCopy, 1) + n++ + } + for ; n < len(results); n++ { + results[n].SetUint64(0) + } + + return nil +} diff --git a/std/math/bits/naf.go b/std/math/bits/naf.go index cf62dc0183..56b4b9e468 100644 --- a/std/math/bits/naf.go +++ b/std/math/bits/naf.go @@ -1,21 +1,11 @@ package bits import ( - "errors" "math/big" - "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" ) -// NNAF returns the NAF decomposition of the input. The number of digits is -// defined by the number of elements in the results slice. -var NNAF = nNaf - -func init() { - solver.RegisterHint(NNAF) -} - // ToNAF returns the NAF decomposition of given input. // The non-adjacent form (NAF) of a number is a unique signed-digit representation, // in which non-zero values cannot be adjacent. For example, NAF(13) = [1, 0, -1, 0, 1]. @@ -34,7 +24,7 @@ func ToNAF(api frontend.API, v frontend.Variable, opts ...BaseConversionOption) c := big.NewInt(1) - bits, err := api.Compiler().NewHint(NNAF, cfg.NbDigits, v) + bits, err := api.Compiler().NewHint(nNaf, cfg.NbDigits, v) if err != nil { panic(err) } @@ -58,52 +48,3 @@ func ToNAF(api frontend.API, v frontend.Variable, opts ...BaseConversionOption) return bits } - -func nNaf(_ *big.Int, inputs []*big.Int, results []*big.Int) error { - n := inputs[0] - return nafDecomposition(n, results) -} - -// nafDecomposition gets the naf decomposition of a big number -func nafDecomposition(a *big.Int, results []*big.Int) error { - if a == nil || a.Sign() == -1 { - return errors.New("invalid input to naf decomposition; negative (or nil) big.Int not supported") - } - - var zero, one, three big.Int - - one.SetUint64(1) - three.SetUint64(3) - - n := 0 - - // some buffers - var buf, aCopy big.Int - aCopy.Set(a) - - for aCopy.Cmp(&zero) != 0 && n < len(results) { - - // if aCopy % 2 == 0 - buf.And(&aCopy, &one) - - // aCopy even - if buf.Cmp(&zero) == 0 { - results[n].SetUint64(0) - } else { // aCopy odd - buf.And(&aCopy, &three) - if buf.IsUint64() && buf.Uint64() == 3 { - results[n].SetInt64(-1) - aCopy.Add(&aCopy, &one) - } else { - results[n].SetUint64(1) - } - } - aCopy.Rsh(&aCopy, 1) - n++ - } - for ; n < len(results); n++ { - results[n].SetUint64(0) - } - - return nil -} diff --git a/std/math/bitslice/hints.go b/std/math/bitslice/hints.go new file mode 100644 index 0000000000..d9797c6a9a --- /dev/null +++ b/std/math/bitslice/hints.go @@ -0,0 +1,34 @@ +package bitslice + +import ( + "fmt" + "math/big" + + "github.com/consensys/gnark/constraint/solver" +) + +func init() { + solver.RegisterHint(GetHints()...) +} + +func GetHints() []solver.Hint { + return []solver.Hint{ + partitionHint, + } +} + +func partitionHint(_ *big.Int, inputs []*big.Int, outputs []*big.Int) error { + if len(inputs) != 2 { + return fmt.Errorf("expecting two inputs") + } + if len(outputs) != 2 { + return fmt.Errorf("expecting two outputs") + } + if !inputs[0].IsUint64() { + return fmt.Errorf("split location must be int") + } + split := uint(inputs[0].Uint64()) + div := new(big.Int).Lsh(big.NewInt(1), split) + outputs[0].QuoRem(inputs[1], div, outputs[1]) + return nil +} diff --git a/std/math/bitslice/opts.go b/std/math/bitslice/opts.go new file mode 100644 index 0000000000..fa333efb1a --- /dev/null +++ b/std/math/bitslice/opts.go @@ -0,0 +1,37 @@ +package bitslice + +import "fmt" + +type opt struct { + digits int + nocheck bool +} + +func parseOpts(opts ...Option) (*opt, error) { + o := new(opt) + for _, apply := range opts { + if err := apply(o); err != nil { + return nil, err + } + } + return o, nil +} + +type Option func(*opt) error + +func WithNbDigits(nbDigits int) Option { + return func(o *opt) error { + if nbDigits < 1 { + return fmt.Errorf("given number of digits %d smaller than 1", nbDigits) + } + o.digits = nbDigits + return nil + } +} + +func WithUnconstrainedOutputs() Option { + return func(o *opt) error { + o.nocheck = true + return nil + } +} diff --git a/std/math/bitslice/partition.go b/std/math/bitslice/partition.go new file mode 100644 index 0000000000..f20c6d3513 --- /dev/null +++ b/std/math/bitslice/partition.go @@ -0,0 +1,69 @@ +package bitslice + +import ( + "math/big" + + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/rangecheck" +) + +// Partition partitions v into two parts splitted at bit numbered split. The +// following holds +// +// v = lower + 2^split * upper. +// +// The method enforces that lower < 2^split and upper < 2^split', where +// split'=nbScalar-split. When giving the option [WithNbDigits], we instead use +// the bound split'=nbDigits-split. +func Partition(api frontend.API, v frontend.Variable, split uint, opts ...Option) (lower, upper frontend.Variable) { + opt, err := parseOpts(opts...) + if err != nil { + panic(err) + } + // handle constant case + if vc, ok := api.Compiler().ConstantValue(v); ok { + if opt.digits > 0 && vc.BitLen() > opt.digits { + panic("input larger than bound") + } + if split == 0 { + return 0, vc + } + div := new(big.Int).Lsh(big.NewInt(1), split) + l, u := new(big.Int), new(big.Int) + u.QuoRem(vc, div, l) + return l, u + } + rh := rangecheck.New(api) + if split == 0 { + if opt.digits > 0 { + rh.Check(v, opt.digits) + } + return 0, v + } + ret, err := api.Compiler().NewHint(partitionHint, 2, split, v) + if err != nil { + panic(err) + } + + upper = ret[0] + lower = ret[1] + + if opt.nocheck { + if opt.digits > 0 { + rh.Check(v, opt.digits) + } + return + } + upperBound := api.Compiler().FieldBitLen() + if opt.digits > 0 { + upperBound = opt.digits + } + rh.Check(upper, upperBound) + rh.Check(lower, int(split)) + + m := big.NewInt(1) + m.Lsh(m, split) + composed := api.Add(lower, api.Mul(upper, m)) + api.AssertIsEqual(composed, v) + return +} diff --git a/std/math/bitslice/partition_test.go b/std/math/bitslice/partition_test.go new file mode 100644 index 0000000000..891c01e658 --- /dev/null +++ b/std/math/bitslice/partition_test.go @@ -0,0 +1,30 @@ +package bitslice + +import ( + "testing" + + "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/test" +) + +type partitionCircuit struct { + Split uint + In, ExpLower, ExpUpper frontend.Variable +} + +func (c *partitionCircuit) Define(api frontend.API) error { + lower, upper := Partition(api, c.In, c.Split) + api.AssertIsEqual(lower, c.ExpLower) + api.AssertIsEqual(upper, c.ExpUpper) + return nil +} + +func TestPartition(t *testing.T) { + assert := test.NewAssert(t) + // TODO: for some reason next fails with PLONK+FRI + assert.ProverSucceeded(&partitionCircuit{Split: 16}, &partitionCircuit{Split: 16, ExpUpper: 0xffff, ExpLower: 0x1234, In: 0xffff1234}, test.WithBackends(backend.GROTH16, backend.PLONK)) + assert.ProverSucceeded(&partitionCircuit{Split: 0}, &partitionCircuit{Split: 0, ExpUpper: 0xffff1234, ExpLower: 0, In: 0xffff1234}, test.WithBackends(backend.GROTH16, backend.PLONK)) + assert.ProverSucceeded(&partitionCircuit{Split: 32}, &partitionCircuit{Split: 32, ExpUpper: 0, ExpLower: 0xffff1234, In: 0xffff1234}, test.WithBackends(backend.GROTH16, backend.PLONK)) + assert.ProverSucceeded(&partitionCircuit{Split: 4}, &partitionCircuit{Split: 4, ExpUpper: 0xffff123, ExpLower: 4, In: 0xffff1234}, test.WithBackends(backend.GROTH16, backend.PLONK)) +} diff --git a/std/math/uints/hints.go b/std/math/uints/hints.go new file mode 100644 index 0000000000..40dbbd9917 --- /dev/null +++ b/std/math/uints/hints.go @@ -0,0 +1,53 @@ +package uints + +import ( + "fmt" + "math/big" + + "github.com/consensys/gnark/constraint/solver" +) + +func init() { + solver.RegisterHint(GetHints()...) +} + +func GetHints() []solver.Hint { + return []solver.Hint{ + andHint, + xorHint, + toBytes, + } +} + +func xorHint(_ *big.Int, inputs, outputs []*big.Int) error { + outputs[0].Xor(inputs[0], inputs[1]) + return nil +} + +func andHint(_ *big.Int, inputs, outputs []*big.Int) error { + outputs[0].And(inputs[0], inputs[1]) + return nil +} + +func toBytes(m *big.Int, inputs []*big.Int, outputs []*big.Int) error { + if len(inputs) != 2 { + return fmt.Errorf("input must be 2 elements") + } + if !inputs[0].IsUint64() { + return fmt.Errorf("first input must be uint64") + } + nbLimbs := int(inputs[0].Uint64()) + if len(outputs) != nbLimbs { + return fmt.Errorf("output must be 8 elements") + } + if !inputs[1].IsUint64() { + return fmt.Errorf("input must be 64 bits") + } + base := new(big.Int).Lsh(big.NewInt(1), uint(8)) + tmp := new(big.Int).Set(inputs[1]) + for i := 0; i < nbLimbs; i++ { + outputs[i].Mod(tmp, base) + tmp.Rsh(tmp, 8) + } + return nil +} diff --git a/std/math/uints/uint8.go b/std/math/uints/uint8.go new file mode 100644 index 0000000000..cec591d10c --- /dev/null +++ b/std/math/uints/uint8.go @@ -0,0 +1,342 @@ +// Package uints implements optimised byte and long integer operations. +// +// Usually arithmetic in a circuit is performed in the native field, which is of +// prime order. However, for compatibility with native operations we rely on +// operating on smaller primitive types as 8-bit, 32-bit and 64-bit integer. +// Naively, these operations have to be implemented bitwise as there are no +// closed equations for boolean operations (XOR, AND, OR). +// +// However, the bitwise approach is very inefficient and leads to several +// constraints per bit. Accumulating over a long integer, it leads to very +// inefficients circuits. +// +// This package performs boolean operations using lookup tables on bytes. So, +// long integers are split into 4 or 8 bytes and we perform the operations +// bytewise. In the lookup tables, we store results for all possible 2^8×2^8 +// inputs. With this approach, every bytewise operation costs as single lookup, +// which depending on the backend is relatively cheap (one to three +// constraints). +// +// NB! The package is still work in progress. The interfaces and implementation +// details most certainly changes over time. We cannot ensure the soundness of +// the operations. +package uints + +import ( + "fmt" + + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/internal/logderivprecomp" + "github.com/consensys/gnark/std/math/bitslice" + "github.com/consensys/gnark/std/rangecheck" +) + +// TODO: if internal then enforce range check! + +// TODO: all operations can take rand linear combinations instead. Then instead +// of one check can perform multiple at the same time. + +// TODO: implement versions which take multiple inputs. Maybe can combine multiple together + +// TODO: instantiate tables only when we first query. Maybe do not need to build! + +// TODO: maybe can store everything in a single table? Later! Or if we have a +// lot of queries then makes sense to extract into separate table? + +// TODO: in ValueOf ensure consistency + +// TODO: distinguish between when we set constant in-circuit or witness +// assignment. For constant we don't have to range check but for witness +// assignment we have to. + +// TODO: add something which allows to store array in native element + +// TODO: add methods for checking if U8/Long is constant. + +// TODO: should something for byte-only ops. Implement a type and then embed it in BinaryField + +// TODO: add helper method to call hints which allows to pass in uint8s (bytes) +// and returns bytes. Then can to byte array manipluation nicely. It is useful +// for X509. For the implementation we want to pack as much bytes into a field +// element as possible. + +// TODO: methods for converting uint array into emulated element and native +// element. Most probably should add the implementation for non-native in its +// package, but for native we should add it here. + +type U8 struct { + Val frontend.Variable + internal bool +} + +// GnarkInitHook describes how to initialise the element. +func (e *U8) GnarkInitHook() { + if e.Val == nil { + e.Val = 0 + e.internal = false // we need to constrain in later. + } +} + +type U64 [8]U8 +type U32 [4]U8 + +type Long interface{ U32 | U64 } + +type BinaryField[T U32 | U64] struct { + api frontend.API + xorT, andT *logderivprecomp.Precomputed + rchecker frontend.Rangechecker + allOne U8 +} + +func New[T Long](api frontend.API) (*BinaryField[T], error) { + xorT, err := logderivprecomp.New(api, xorHint, []uint{8}) + if err != nil { + return nil, fmt.Errorf("new xor table: %w", err) + } + andT, err := logderivprecomp.New(api, andHint, []uint{8}) + if err != nil { + return nil, fmt.Errorf("new and table: %w", err) + } + rchecker := rangecheck.New(api) + bf := &BinaryField[T]{ + api: api, + xorT: xorT, + andT: andT, + rchecker: rchecker, + } + // TODO: this is const. add way to init constants + allOne := bf.ByteValueOf(0xff) + bf.allOne = allOne + return bf, nil +} + +func NewU8(v uint8) U8 { + // TODO: don't have to check constants + return U8{Val: v, internal: true} +} + +func NewU32(v uint32) U32 { + return [4]U8{ + NewU8(uint8((v >> (0 * 8)) & 0xff)), + NewU8(uint8((v >> (1 * 8)) & 0xff)), + NewU8(uint8((v >> (2 * 8)) & 0xff)), + NewU8(uint8((v >> (3 * 8)) & 0xff)), + } +} + +func NewU64(v uint64) U64 { + return [8]U8{ + NewU8(uint8((v >> (0 * 8)) & 0xff)), + NewU8(uint8((v >> (1 * 8)) & 0xff)), + NewU8(uint8((v >> (2 * 8)) & 0xff)), + NewU8(uint8((v >> (3 * 8)) & 0xff)), + NewU8(uint8((v >> (4 * 8)) & 0xff)), + NewU8(uint8((v >> (5 * 8)) & 0xff)), + NewU8(uint8((v >> (6 * 8)) & 0xff)), + NewU8(uint8((v >> (7 * 8)) & 0xff)), + } +} + +func NewU8Array(v []uint8) []U8 { + ret := make([]U8, len(v)) + for i := range v { + ret[i] = NewU8(v[i]) + } + return ret +} + +func NewU32Array(v []uint32) []U32 { + ret := make([]U32, len(v)) + for i := range v { + ret[i] = NewU32(v[i]) + } + return ret +} + +func NewU64Array(v []uint64) []U64 { + ret := make([]U64, len(v)) + for i := range v { + ret[i] = NewU64(v[i]) + } + return ret +} + +func (bf *BinaryField[T]) ByteValueOf(a frontend.Variable) U8 { + bf.rchecker.Check(a, 8) + return U8{Val: a, internal: true} +} + +func (bf *BinaryField[T]) ValueOf(a frontend.Variable) T { + var r T + bts, err := bf.api.Compiler().NewHint(toBytes, len(r), len(r), a) + if err != nil { + panic(err) + } + // TODO: add constraint which ensures that map back to + for i := range bts { + r[i] = bf.ByteValueOf(bts[i]) + } + return r +} + +func (bf *BinaryField[T]) ToValue(a T) frontend.Variable { + v := make([]frontend.Variable, len(a)) + for i := range v { + v[i] = bf.api.Mul(a[i].Val, 1<<(i*8)) + } + vv := bf.api.Add(v[0], v[1], v[2:]...) + return vv +} + +func (bf *BinaryField[T]) PackMSB(a ...U8) T { + var ret T + for i := range a { + ret[len(a)-i-1] = a[i] + } + return ret +} + +func (bf *BinaryField[T]) PackLSB(a ...U8) T { + var ret T + for i := range a { + ret[i] = a[i] + } + return ret +} + +func (bf *BinaryField[T]) UnpackMSB(a T) []U8 { + ret := make([]U8, len(a)) + for i := 0; i < len(a); i++ { + ret[len(a)-i-1] = a[i] + } + return ret +} + +func (bf *BinaryField[T]) UnpackLSB(a T) []U8 { + // cannot deduce that a can be cast to []U8 + ret := make([]U8, len(a)) + for i := 0; i < len(a); i++ { + ret[i] = a[i] + } + return ret +} + +func (bf *BinaryField[T]) twoArgFn(tbl *logderivprecomp.Precomputed, a ...U8) U8 { + ret := tbl.Query(a[0].Val, a[1].Val)[0] + for i := 2; i < len(a); i++ { + ret = tbl.Query(ret, a[i].Val)[0] + } + return U8{Val: ret} +} + +func (bf *BinaryField[T]) twoArgWideFn(tbl *logderivprecomp.Precomputed, a ...T) T { + var r T + for i, v := range reslice(a) { + r[i] = bf.twoArgFn(tbl, v...) + } + return r +} + +func (bf *BinaryField[T]) And(a ...T) T { return bf.twoArgWideFn(bf.andT, a...) } +func (bf *BinaryField[T]) Xor(a ...T) T { return bf.twoArgWideFn(bf.xorT, a...) } + +func (bf *BinaryField[T]) not(a U8) U8 { + ret := bf.xorT.Query(a.Val, bf.allOne.Val) + return U8{Val: ret[0]} +} + +func (bf *BinaryField[T]) Not(a T) T { + var r T + for i := 0; i < len(a); i++ { + r[i] = bf.not(a[i]) + } + return r +} + +func (bf *BinaryField[T]) Add(a ...T) T { + va := make([]frontend.Variable, len(a)) + for i := range a { + va[i] = bf.ToValue(a[i]) + } + vres := bf.api.Add(va[0], va[1], va[2:]...) + res := bf.ValueOf(vres) + // TODO: should also check the that carry we omitted is correct. + return res +} + +func (bf *BinaryField[T]) Lrot(a T, c int) T { + l := len(a) + if c < 0 { + c = l*8 + c + } + shiftBl := c / 8 + shiftBt := c % 8 + revShiftBt := 8 - shiftBt + if revShiftBt == 8 { + revShiftBt = 0 + } + partitioned := make([][2]frontend.Variable, l) + for i := range partitioned { + lower, upper := bitslice.Partition(bf.api, a[i].Val, uint(revShiftBt), bitslice.WithNbDigits(8)) + partitioned[i] = [2]frontend.Variable{lower, upper} + } + var ret T + for i := 0; i < l; i++ { + if shiftBt != 0 { + ret[(i+shiftBl)%l].Val = bf.api.Add(bf.api.Mul(1<<(shiftBt), partitioned[i][0]), partitioned[(i+l-1)%l][1]) + } else { + ret[(i+shiftBl)%l].Val = partitioned[i][1] + } + } + return ret +} + +func (bf *BinaryField[T]) Rshift(a T, c int) T { + shiftBl := c / 8 + shiftBt := c % 8 + partitioned := make([][2]frontend.Variable, len(a)-shiftBl) + for i := range partitioned { + lower, upper := bitslice.Partition(bf.api, a[i+shiftBl].Val, uint(shiftBt), bitslice.WithNbDigits(8)) + partitioned[i] = [2]frontend.Variable{lower, upper} + } + var ret T + for i := 0; i < len(a)-shiftBl-1; i++ { + if shiftBt != 0 { + ret[i].Val = bf.api.Add(partitioned[i][1], bf.api.Mul(1<<(8-shiftBt), partitioned[i+1][0])) + } else { + ret[i].Val = partitioned[i][1] + } + } + ret[len(a)-shiftBl-1].Val = partitioned[len(a)-shiftBl-1][1] + for i := len(a) - shiftBl; i < len(ret); i++ { + ret[i] = NewU8(0) + } + return ret +} + +func (bf *BinaryField[T]) ByteAssertEq(a, b U8) { + bf.api.AssertIsEqual(a.Val, b.Val) +} + +func (bf *BinaryField[T]) AssertEq(a, b T) { + for i := 0; i < len(a); i++ { + bf.ByteAssertEq(a[i], b[i]) + } +} + +func reslice[T U32 | U64](in []T) [][]U8 { + if len(in) == 0 { + panic("zero-length input") + } + ret := make([][]U8, len(in[0])) + for i := range ret { + ret[i] = make([]U8, len(in)) + } + for i := 0; i < len(in); i++ { + for j := 0; j < len(in[0]); j++ { + ret[j][i] = in[i][j] + } + } + return ret +} diff --git a/std/math/uints/uint8_test.go b/std/math/uints/uint8_test.go new file mode 100644 index 0000000000..bc24a8f4db --- /dev/null +++ b/std/math/uints/uint8_test.go @@ -0,0 +1,81 @@ +package uints + +import ( + "math/bits" + "testing" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/test" +) + +type lrotCirc struct { + In U32 + Out U32 + Shift int +} + +func (c *lrotCirc) Define(api frontend.API) error { + uapi, err := New[U32](api) + if err != nil { + return err + } + res := uapi.Lrot(c.In, c.Shift) + uapi.AssertEq(c.Out, res) + return nil +} + +func TestLeftRotation(t *testing.T) { + assert := test.NewAssert(t) + var err error + err = test.IsSolved(&lrotCirc{Shift: 4}, &lrotCirc{In: NewU32(0x12345678), Shift: 4, Out: NewU32(bits.RotateLeft32(0x12345678, 4))}, ecc.BN254.ScalarField()) + assert.NoError(err) + err = test.IsSolved(&lrotCirc{Shift: 14}, &lrotCirc{In: NewU32(0x12345678), Shift: 14, Out: NewU32(bits.RotateLeft32(0x12345678, 14))}, ecc.BN254.ScalarField()) + assert.NoError(err) + err = test.IsSolved(&lrotCirc{Shift: 3}, &lrotCirc{In: NewU32(0x12345678), Shift: 3, Out: NewU32(bits.RotateLeft32(0x12345678, 3))}, ecc.BN254.ScalarField()) + assert.NoError(err) + err = test.IsSolved(&lrotCirc{Shift: 11}, &lrotCirc{In: NewU32(0x12345678), Shift: 11, Out: NewU32(bits.RotateLeft32(0x12345678, 11))}, ecc.BN254.ScalarField()) + assert.NoError(err) + // full block + err = test.IsSolved(&lrotCirc{Shift: 16}, &lrotCirc{In: NewU32(0x12345678), Shift: 16, Out: NewU32(bits.RotateLeft32(0x12345678, 16))}, ecc.BN254.ScalarField()) + assert.NoError(err) + // negative rotations + err = test.IsSolved(&lrotCirc{Shift: -4}, &lrotCirc{In: NewU32(0x12345678), Shift: -4, Out: NewU32(bits.RotateLeft32(0x12345678, -4))}, ecc.BN254.ScalarField()) + assert.NoError(err) + err = test.IsSolved(&lrotCirc{Shift: -14}, &lrotCirc{In: NewU32(0x12345678), Shift: -14, Out: NewU32(bits.RotateLeft32(0x12345678, -14))}, ecc.BN254.ScalarField()) + assert.NoError(err) + err = test.IsSolved(&lrotCirc{Shift: -3}, &lrotCirc{In: NewU32(0x12345678), Shift: -3, Out: NewU32(bits.RotateLeft32(0x12345678, -3))}, ecc.BN254.ScalarField()) + assert.NoError(err) + err = test.IsSolved(&lrotCirc{Shift: -11}, &lrotCirc{In: NewU32(0x12345678), Shift: -11, Out: NewU32(bits.RotateLeft32(0x12345678, -11))}, ecc.BN254.ScalarField()) + assert.NoError(err) + err = test.IsSolved(&lrotCirc{Shift: -16}, &lrotCirc{In: NewU32(0x12345678), Shift: -16, Out: NewU32(bits.RotateLeft32(0x12345678, -16))}, ecc.BN254.ScalarField()) + assert.NoError(err) +} + +type rshiftCircuit struct { + In, Expected U32 + Shift int +} + +func (c *rshiftCircuit) Define(api frontend.API) error { + uapi, err := New[U32](api) + if err != nil { + return err + } + res := uapi.Rshift(c.In, c.Shift) + uapi.AssertEq(res, c.Expected) + return nil +} + +func TestRshift(t *testing.T) { + assert := test.NewAssert(t) + var err error + err = test.IsSolved(&rshiftCircuit{Shift: 4}, &rshiftCircuit{Shift: 4, In: NewU32(0x12345678), Expected: NewU32(0x12345678 >> 4)}, ecc.BN254.ScalarField()) + assert.NoError(err) + err = test.IsSolved(&rshiftCircuit{Shift: 12}, &rshiftCircuit{Shift: 12, In: NewU32(0x12345678), Expected: NewU32(0x12345678 >> 12)}, ecc.BN254.ScalarField()) + assert.NoError(err) + err = test.IsSolved(&rshiftCircuit{Shift: 3}, &rshiftCircuit{Shift: 3, In: NewU32(0x12345678), Expected: NewU32(0x12345678 >> 3)}, ecc.BN254.ScalarField()) + assert.NoError(err) + err = test.IsSolved(&rshiftCircuit{Shift: 11}, &rshiftCircuit{Shift: 11, In: NewU32(0x12345678), Expected: NewU32(0x12345678 >> 11)}, ecc.BN254.ScalarField()) + assert.NoError(err) +} diff --git a/std/permutation/keccakf/keccak_test.go b/std/permutation/keccakf/keccak_test.go index fe4fca829d..b7151a893c 100644 --- a/std/permutation/keccakf/keccak_test.go +++ b/std/permutation/keccakf/keccak_test.go @@ -16,7 +16,13 @@ type keccakfCircuit struct { } func (c *keccakfCircuit) Define(api frontend.API) error { - res := keccakf.Permute(api, c.In) + var res [25]frontend.Variable + for i := range res { + res[i] = c.In[i] + } + for i := 0; i < 2; i++ { + res = keccakf.Permute(api, res) + } for i := range res { api.AssertIsEqual(res[i], c.Expected[i]) } @@ -25,15 +31,22 @@ func (c *keccakfCircuit) Define(api frontend.API) error { func TestKeccakf(t *testing.T) { var nativeIn [25]uint64 + var res [25]uint64 for i := range nativeIn { nativeIn[i] = 2 + res[i] = 2 + } + for i := 0; i < 2; i++ { + res = keccakF1600(res) } - nativeOut := keccakF1600(nativeIn) witness := keccakfCircuit{} for i := range nativeIn { witness.In[i] = nativeIn[i] - witness.Expected[i] = nativeOut[i] + witness.Expected[i] = res[i] } assert := test.NewAssert(t) - assert.ProverSucceeded(&keccakfCircuit{}, &witness, test.WithCurves(ecc.BN254), test.WithBackends(backend.GROTH16, backend.PLONK)) + assert.ProverSucceeded(&keccakfCircuit{}, &witness, + test.WithCurves(ecc.BN254), + test.WithBackends(backend.GROTH16, backend.PLONK), + test.NoFuzzing()) } diff --git a/std/permutation/keccakf/keccakf.go b/std/permutation/keccakf/keccakf.go index fbaedebb72..8f5e3ae346 100644 --- a/std/permutation/keccakf/keccakf.go +++ b/std/permutation/keccakf/keccakf.go @@ -12,33 +12,34 @@ package keccakf import ( "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/math/uints" ) -var rc = [24]xuint64{ - constUint64(0x0000000000000001), - constUint64(0x0000000000008082), - constUint64(0x800000000000808A), - constUint64(0x8000000080008000), - constUint64(0x000000000000808B), - constUint64(0x0000000080000001), - constUint64(0x8000000080008081), - constUint64(0x8000000000008009), - constUint64(0x000000000000008A), - constUint64(0x0000000000000088), - constUint64(0x0000000080008009), - constUint64(0x000000008000000A), - constUint64(0x000000008000808B), - constUint64(0x800000000000008B), - constUint64(0x8000000000008089), - constUint64(0x8000000000008003), - constUint64(0x8000000000008002), - constUint64(0x8000000000000080), - constUint64(0x000000000000800A), - constUint64(0x800000008000000A), - constUint64(0x8000000080008081), - constUint64(0x8000000000008080), - constUint64(0x0000000080000001), - constUint64(0x8000000080008008), +var rc = [24]uints.U64{ + uints.NewU64(0x0000000000000001), + uints.NewU64(0x0000000000008082), + uints.NewU64(0x800000000000808A), + uints.NewU64(0x8000000080008000), + uints.NewU64(0x000000000000808B), + uints.NewU64(0x0000000080000001), + uints.NewU64(0x8000000080008081), + uints.NewU64(0x8000000000008009), + uints.NewU64(0x000000000000008A), + uints.NewU64(0x0000000000000088), + uints.NewU64(0x0000000080008009), + uints.NewU64(0x000000008000000A), + uints.NewU64(0x000000008000808B), + uints.NewU64(0x800000000000008B), + uints.NewU64(0x8000000000008089), + uints.NewU64(0x8000000000008003), + uints.NewU64(0x8000000000008002), + uints.NewU64(0x8000000000000080), + uints.NewU64(0x000000000000800A), + uints.NewU64(0x800000008000000A), + uints.NewU64(0x8000000080008081), + uints.NewU64(0x8000000000008080), + uints.NewU64(0x0000000080000001), + uints.NewU64(0x8000000080008008), } var rotc = [24]int{ 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, @@ -53,32 +54,34 @@ var piln = [24]int{ // vector. The input array must consist of 64-bit (unsigned) integers. The // returned array also contains 64-bit unsigned integers. func Permute(api frontend.API, a [25]frontend.Variable) [25]frontend.Variable { - var in [25]xuint64 - uapi := newUint64API(api) + var in [25]uints.U64 + uapi, err := uints.New[uints.U64](api) + if err != nil { + panic(err) // TODO: return error instead + } for i := range a { - in[i] = uapi.asUint64(a[i]) + in[i] = uapi.ValueOf(a[i]) } - res := permute(api, in) + res := permute(uapi, in) var out [25]frontend.Variable for i := range out { - out[i] = uapi.fromUint64(res[i]) + out[i] = uapi.ToValue(res[i]) } return out } -func permute(api frontend.API, st [25]xuint64) [25]xuint64 { - uapi := newUint64API(api) - var t xuint64 - var bc [5]xuint64 +func permute(uapi *uints.BinaryField[uints.U64], st [25]uints.U64) [25]uints.U64 { + var t uints.U64 + var bc [5]uints.U64 for r := 0; r < 24; r++ { // theta for i := 0; i < 5; i++ { - bc[i] = uapi.xor(st[i], st[i+5], st[i+10], st[i+15], st[i+20]) + bc[i] = uapi.Xor(st[i], st[i+5], st[i+10], st[i+15], st[i+20]) } for i := 0; i < 5; i++ { - t = uapi.xor(bc[(i+4)%5], uapi.lrot(bc[(i+1)%5], 1)) + t = uapi.Xor(bc[(i+4)%5], uapi.Lrot(bc[(i+1)%5], 1)) for j := 0; j < 25; j += 5 { - st[j+i] = uapi.xor(st[j+i], t) + st[j+i] = uapi.Xor(st[j+i], t) } } // rho pi @@ -86,7 +89,7 @@ func permute(api frontend.API, st [25]xuint64) [25]xuint64 { for i := 0; i < 24; i++ { j := piln[i] bc[0] = st[j] - st[j] = uapi.lrot(t, rotc[i]) + st[j] = uapi.Lrot(t, rotc[i]) t = bc[0] } @@ -96,11 +99,11 @@ func permute(api frontend.API, st [25]xuint64) [25]xuint64 { bc[i] = st[j+i] } for i := 0; i < 5; i++ { - st[j+i] = uapi.xor(st[j+i], uapi.and(uapi.not(bc[(i+1)%5]), bc[(i+2)%5])) + st[j+i] = uapi.Xor(st[j+i], uapi.And(uapi.Not(bc[(i+1)%5]), bc[(i+2)%5])) } } // iota - st[0] = uapi.xor(st[0], rc[r]) + st[0] = uapi.Xor(st[0], rc[r]) } return st } diff --git a/std/permutation/keccakf/uint64api.go b/std/permutation/keccakf/uint64api.go deleted file mode 100644 index c7c2246bb2..0000000000 --- a/std/permutation/keccakf/uint64api.go +++ /dev/null @@ -1,101 +0,0 @@ -package keccakf - -import ( - "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/math/bits" -) - -// uint64api performs binary operations on xuint64 variables. In the -// future possibly using lookup tables. -// -// TODO: we could possibly optimise using hints if working over many inputs. For -// example, if we OR many bits, then the result is 0 if the sum of the bits is -// larger than 1. And AND is 1 if the sum of bits is the number of inputs. BUt -// this probably helps only if we have a lot of similar operations in a row -// (more than 4). We could probably unroll the whole permutation and expand all -// the formulas to see. But long term tables are still better. -type uint64api struct { - api frontend.API -} - -func newUint64API(api frontend.API) *uint64api { - return &uint64api{ - api: api, - } -} - -// varUint64 represents 64-bit unsigned integer. We use this type to ensure that -// we work over constrained bits. Do not initialize directly, use [wideBinaryOpsApi.asUint64]. -type xuint64 [64]frontend.Variable - -func constUint64(a uint64) xuint64 { - var res xuint64 - for i := 0; i < 64; i++ { - res[i] = (a >> i) & 1 - } - return res -} - -func (w *uint64api) asUint64(in frontend.Variable) xuint64 { - bits := bits.ToBinary(w.api, in, bits.WithNbDigits(64)) - var res xuint64 - copy(res[:], bits) - return res -} - -func (w *uint64api) fromUint64(in xuint64) frontend.Variable { - return bits.FromBinary(w.api, in[:], bits.WithUnconstrainedInputs()) -} - -func (w *uint64api) and(in ...xuint64) xuint64 { - var res xuint64 - for i := range res { - res[i] = 1 - } - for i := range res { - for _, v := range in { - res[i] = w.api.And(res[i], v[i]) - } - } - return res -} - -func (w *uint64api) xor(in ...xuint64) xuint64 { - var res xuint64 - for i := range res { - res[i] = 0 - } - for i := range res { - for _, v := range in { - res[i] = w.api.Xor(res[i], v[i]) - } - } - return res -} - -func (w *uint64api) lrot(in xuint64, shift int) xuint64 { - var res xuint64 - for i := range res { - res[i] = in[(i-shift+64)%64] - } - return res -} - -func (w *uint64api) not(in xuint64) xuint64 { - // TODO: it would be better to have separate method for it. If we have - // native API support, then in R1CS would be free (1-X) and in PLONK 1 - // constraint (1-X). But if we do XOR, then we always have a constraint with - // R1CS (not sure if 1-2 with PLONK). If we do 1-X ourselves, then compiler - // marks as binary which is 1-2 (R1CS-PLONK). - var res xuint64 - for i := range res { - res[i] = w.api.Xor(in[i], 1) - } - return res -} - -func (w *uint64api) assertEq(a, b xuint64) { - for i := range a { - w.api.AssertIsEqual(a[i], b[i]) - } -} diff --git a/std/permutation/keccakf/uint64api_test.go b/std/permutation/keccakf/uint64api_test.go deleted file mode 100644 index 0e39794695..0000000000 --- a/std/permutation/keccakf/uint64api_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package keccakf - -import ( - "testing" - - "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/test" -) - -type lrotCirc struct { - In frontend.Variable - Shift int - Out frontend.Variable -} - -func (c *lrotCirc) Define(api frontend.API) error { - uapi := newUint64API(api) - in := uapi.asUint64(c.In) - out := uapi.asUint64(c.Out) - res := uapi.lrot(in, c.Shift) - uapi.assertEq(out, res) - return nil -} - -func TestLeftRotation(t *testing.T) { - assert := test.NewAssert(t) - // err := test.IsSolved(&lrotCirc{Shift: 2}, &lrotCirc{In: 6, Shift: 2, Out: 24}, ecc.BN254.ScalarField()) - // assert.NoError(err) - assert.ProverSucceeded(&lrotCirc{Shift: 2}, &lrotCirc{In: 6, Shift: 2, Out: 24}) -} diff --git a/std/permutation/sha2/sha2block.go b/std/permutation/sha2/sha2block.go new file mode 100644 index 0000000000..a3991230b3 --- /dev/null +++ b/std/permutation/sha2/sha2block.go @@ -0,0 +1,90 @@ +package sha2 + +import ( + "github.com/consensys/gnark/std/math/uints" +) + +var _K = uints.NewU32Array([]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 Permute(uapi *uints.BinaryField[uints.U32], currentHash [8]uints.U32, p [64]uints.U8) (newHash [8]uints.U32) { + var w [64]uints.U32 + + for i := 0; i < 16; i++ { + w[i] = uapi.PackMSB(p[4*i], p[4*i+1], p[4*i+2], p[4*i+3]) + } + + for i := 16; i < 64; i++ { + v1 := w[i-2] + t1 := uapi.Xor( + uapi.Lrot(v1, -17), + uapi.Lrot(v1, -19), + uapi.Rshift(v1, 10), + ) + v2 := w[i-15] + t2 := uapi.Xor( + uapi.Lrot(v2, -7), + uapi.Lrot(v2, -18), + uapi.Rshift(v2, 3), + ) + + w[i] = uapi.Add(t1, w[i-7], t2, w[i-16]) + } + + a, b, c, d, e, f, g, h := currentHash[0], currentHash[1], currentHash[2], currentHash[3], currentHash[4], currentHash[5], currentHash[6], currentHash[7] + + for i := 0; i < 64; i++ { + t1 := uapi.Add( + h, + uapi.Xor( + uapi.Lrot(e, -6), + uapi.Lrot(e, -11), + uapi.Lrot(e, -25)), + uapi.Xor( + uapi.And(e, f), + uapi.And( + uapi.Not(e), + g)), + _K[i], + w[i], + ) + t2 := uapi.Add( + uapi.Xor( + uapi.Lrot(a, -2), + uapi.Lrot(a, -13), + uapi.Lrot(a, -22)), + uapi.Xor( + uapi.And(a, b), + uapi.And(a, c), + uapi.And(b, c)), + ) + + h = g + g = f + f = e + e = uapi.Add(d, t1) + d = c + c = b + b = a + a = uapi.Add(t1, t2) + } + + currentHash[0] = uapi.Add(currentHash[0], a) + currentHash[1] = uapi.Add(currentHash[1], b) + currentHash[2] = uapi.Add(currentHash[2], c) + currentHash[3] = uapi.Add(currentHash[3], d) + currentHash[4] = uapi.Add(currentHash[4], e) + currentHash[5] = uapi.Add(currentHash[5], f) + currentHash[6] = uapi.Add(currentHash[6], g) + currentHash[7] = uapi.Add(currentHash[7], h) + + return currentHash +} diff --git a/std/permutation/sha2/sha2block_test.go b/std/permutation/sha2/sha2block_test.go new file mode 100644 index 0000000000..b634ab6624 --- /dev/null +++ b/std/permutation/sha2/sha2block_test.go @@ -0,0 +1,116 @@ +package sha2_test + +import ( + "math/bits" + "math/rand" + "testing" + "time" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/math/uints" + "github.com/consensys/gnark/std/permutation/sha2" + "github.com/consensys/gnark/test" +) + +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, +} + +const ( + chunk = 64 +) + +type digest struct { + h [8]uint32 +} + +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 := (bits.RotateLeft32(v1, -17)) ^ (bits.RotateLeft32(v1, -19)) ^ (v1 >> 10) + v2 := w[i-15] + t2 := (bits.RotateLeft32(v2, -7)) ^ (bits.RotateLeft32(v2, -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 + ((bits.RotateLeft32(e, -6)) ^ (bits.RotateLeft32(e, -11)) ^ (bits.RotateLeft32(e, -25))) + ((e & f) ^ (^e & g)) + _K[i] + w[i] + + t2 := ((bits.RotateLeft32(a, -2)) ^ (bits.RotateLeft32(a, -13)) ^ (bits.RotateLeft32(a, -22))) + ((a & b) ^ (a & c) ^ (b & c)) + + h, g, f, e, d, c, b, a = g, f, e, d+t1, c, b, 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 +} + +type circuitBlock struct { + CurrentDig [8]uints.U32 + In [64]uints.U8 + Expected [8]uints.U32 +} + +func (c *circuitBlock) Define(api frontend.API) error { + uapi, err := uints.New[uints.U32](api) + if err != nil { + return err + } + res := sha2.Permute(uapi, c.CurrentDig, c.In) + for i := range c.Expected { + uapi.AssertEq(c.Expected[i], res[i]) + } + return nil +} + +func TestBlockGeneric(t *testing.T) { + assert := test.NewAssert(t) + s := rand.New(rand.NewSource(time.Now().Unix())) //nolint G404, test code + witness := circuitBlock{} + dig := digest{} + var in [chunk]byte + for i := range dig.h { + dig.h[i] = s.Uint32() + witness.CurrentDig[i] = uints.NewU32(dig.h[i]) + } + for i := range in { + in[i] = byte(s.Uint32() & 0xff) + witness.In[i] = uints.NewU8(in[i]) + } + blockGeneric(&dig, in[:]) + for i := range dig.h { + witness.Expected[i] = uints.NewU32(dig.h[i]) + } + err := test.IsSolved(&circuitBlock{}, &witness, ecc.BN254.ScalarField()) + assert.NoError(err) +} diff --git a/std/signature/eddsa/eddsa.go b/std/signature/eddsa/eddsa.go index dcfcfc2870..b0841de4ad 100644 --- a/std/signature/eddsa/eddsa.go +++ b/std/signature/eddsa/eddsa.go @@ -55,7 +55,7 @@ type Signature struct { // Verify verifies an eddsa signature using MiMC hash function // cf https://en.wikipedia.org/wiki/EdDSA -func Verify(curve twistededwards.Curve, sig Signature, msg frontend.Variable, pubKey PublicKey, hash hash.Hash) error { +func Verify(curve twistededwards.Curve, sig Signature, msg frontend.Variable, pubKey PublicKey, hash hash.FieldHasher) error { // compute H(R, A, M) hash.Write(sig.R.X) diff --git a/test/engine_test.go b/test/engine_test.go index a02b81ff34..16ed830c12 100644 --- a/test/engine_test.go +++ b/test/engine_test.go @@ -18,12 +18,12 @@ type hintCircuit struct { } func (circuit *hintCircuit) Define(api frontend.API) error { - res, err := api.Compiler().NewHint(bits.IthBit, 1, circuit.A, 3) + res, err := api.Compiler().NewHint(bits.GetHints()[0], 1, circuit.A, 3) if err != nil { return fmt.Errorf("IthBit circuitA 3: %w", err) } a3b := res[0] - res, err = api.Compiler().NewHint(bits.IthBit, 1, circuit.A, 25) + res, err = api.Compiler().NewHint(bits.GetHints()[0], 1, circuit.A, 25) if err != nil { return fmt.Errorf("IthBit circuitA 25: %w", err) } From d077df7dabc2e12aa6e485273400bfa282faa80f Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Mon, 5 Jun 2023 16:31:59 -0500 Subject: [PATCH 428/464] refactor: FindInSlice use --- frontend/cs/r1cs/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index 4a864c65d5..4e6be74584 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -724,7 +724,7 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error commitments := builder.cs.GetCommitments() var alreadyCommitted bool for i := range commitments { - if alreadyCommitted, _ = utils.FindInSlice(commitments[i].Committed, t.VID); alreadyCommitted { + if _, alreadyCommitted = utils.FindInSlice(commitments[i].Committed, t.VID); alreadyCommitted { toCommit := commitments[i].CommitmentIndex vars = append(vars, expr.LinearExpression{{Coeff: constraint.Element{1}, VID: toCommit}}) // TODO Replace with mont 1 builder.heap.push(linMeta{lID: len(vars) - 1, tID: 0, val: toCommit}) From 4efbecf26fa2822728e7e16cc4ffadecd7ba280b Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Mon, 5 Jun 2023 19:00:15 -0500 Subject: [PATCH 429/464] feat: in-place-ish DivideByThresholdOrList --- backend/groth16/internal/utils.go | 29 +++---- backend/groth16/internal/utils_test.go | 105 +++++++++++++++++++++++++ 2 files changed, 120 insertions(+), 14 deletions(-) create mode 100644 backend/groth16/internal/utils_test.go diff --git a/backend/groth16/internal/utils.go b/backend/groth16/internal/utils.go index f948f699af..b61b3f5966 100644 --- a/backend/groth16/internal/utils.go +++ b/backend/groth16/internal/utils.go @@ -3,21 +3,22 @@ package internal import "math/big" // DivideByThresholdOrList divides x into two sub-lists. list must be sorted, non-repeating and contain no value less than indexThreshold -func DivideByThresholdOrList(indexThreshold int, list []int, x []*big.Int) (ltOrInList, gtAndNotInList []*big.Int) { - ltOrInList = make([]*big.Int, indexThreshold+len(list)) - gtAndNotInList = make([]*big.Int, len(x)-len(ltOrInList)) - - copy(ltOrInList, x[:indexThreshold]) - - j := 0 - for i := indexThreshold; i < len(x); i++ { - if j < len(list) && i == list[j] { - ltOrInList[indexThreshold+j] = x[i] - j++ - } else { - gtAndNotInList[i-indexThreshold-j] = x[i] +// x is modified in this process. The output lists are sub-slices of x. +func DivideByThresholdOrList(indexThreshold int, list []int, x []*big.Int) (ltOrOnList, gtAndNotOnList []*big.Int) { + ltOrOnList = x[:indexThreshold+len(list)] + gtAndNotOnList = x[len(ltOrOnList):] + onList := make([]*big.Int, len(list)) // the list is small + for i := range list { + onList[i] = x[list[i]] + } + for i := len(list) - 1; i >= 0; i-- { // overwrite the element at list[i] + sliceStart := indexThreshold + if i > 0 { + sliceStart = list[i-1] } + displacement := len(list) - i + copy(x[sliceStart+displacement:], x[sliceStart:list[i]]) } - + copy(x[indexThreshold:], onList) return } diff --git a/backend/groth16/internal/utils_test.go b/backend/groth16/internal/utils_test.go new file mode 100644 index 0000000000..87a994f581 --- /dev/null +++ b/backend/groth16/internal/utils_test.go @@ -0,0 +1,105 @@ +package internal + +import ( + "github.com/stretchr/testify/assert" + "math/big" + "math/rand" + "testing" +) + +type coinToss struct { + x uint64 + remaining byte +} + +func (r *coinToss) rand() (res bool) { + if r.remaining == 0 { + r.x = rand.Uint64() + r.remaining = 64 + } + r.remaining-- + if r.x&1 == 1 { + res = true + } + r.x /= 2 + return +} + +func createX(size int) []*big.Int { + x := make([]*big.Int, size) + for i := range x { + x[i] = big.NewInt(int64(i)) + } + return x +} + +func toInts(x []*big.Int) []int64 { + res := make([]int64, len(x)) + for i := range x { + res[i] = x[i].Int64() + } + return res +} + +func TestDivideByThresholdOrList(t *testing.T) { + x := createX(10) + list := make([]int, 0, len(x)) + var r coinToss + for threshold := range x { + // reset x + for i := range x { + x[i].SetInt64(int64(i)) + } + + // prepare list + list = list[:0] + for i := threshold; i < len(x); i++ { + if r.rand() { + list = append(list, i) + } + } + + // get result from DivideByThresholdOrList + _, _ = DivideByThresholdOrList(threshold, list, x) + for i := 0; i < threshold; i++ { + assert.Equal(t, int64(i), x[i].Int64()) + } + for i := range list { + assert.Equal(t, int64(list[i]), x[threshold+i].Int64()) + } + prev := int64(-1) + j := 0 + for i := threshold + len(list); i < len(x); i++ { + cur := x[i].Int64() + assert.Less(t, prev, cur) + + for j < len(list) && int64(list[j]) < cur { + j++ + } + if j < len(list) && int64(list[j]) == cur { + t.Error("value on list present") + } + } + } +} + +func TestDivideByThresholdOrListLen2(t *testing.T) { + x := createX(2) + _, _ = DivideByThresholdOrList(0, []int{1}, x) + xAsInts := toInts(x) + assert.Equal(t, []int64{1, 0}, xAsInts) +} + +func TestDivideByThresholdOrListLen3(t *testing.T) { + x := createX(3) + _, _ = DivideByThresholdOrList(1, []int{2}, x) + xAsInts := toInts(x) + assert.Equal(t, []int64{0, 2, 1}, xAsInts) +} + +func TestDivideByThresholdOrListLen4(t *testing.T) { + x := createX(4) + _, _ = DivideByThresholdOrList(1, []int{1, 3}, x) + xAsInts := toInts(x) + assert.Equal(t, []int64{0, 1, 3, 2}, xAsInts) +} From f48a7a21e8796e5a61a48ea06e2452ff2d782fed Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 6 Jun 2023 14:09:22 -0500 Subject: [PATCH 430/464] chore: rm deadcd, improve verifier mem, some docs --- backend/groth16/bn254/setup.go | 19 ++++--------- backend/groth16/bn254/verify.go | 27 ++++++++++-------- backend/groth16/internal/utils_test.go | 2 +- .../zkpschemes/groth16/groth16.prove.go.tmpl | 28 ++----------------- 4 files changed, 24 insertions(+), 52 deletions(-) diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index 112c07446f..606d3bd9f6 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -103,16 +103,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbPublicWires := r1cs.GetNbPublicVariables() + len(r1cs.CommitmentInfo) nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(r1cs.CommitmentInfo) - // we will need to iterate through the private-to-public wires in order - /*privToPub := make([], nbPrivateCommittedWires+len(r1cs.CommitmentInfo)) - offset := 0 - for i := range r1cs.CommitmentInfo { - copy(privToPub[offset:], r1cs.CommitmentInfo[i].PrivateCommitted()) // TODO Take out commitments - offset += r1cs.CommitmentInfo[i].NbPrivateCommitted - } - privToPub.Heapify() - */ - // Setting group for fft domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) @@ -162,11 +152,12 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Add(&t1, &C[i]). Mul(&t1, coeff) } - vI := 0 - cI := make([]int, len(r1cs.CommitmentInfo)) - nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] + vI := 0 // number of public wires seen so far + cI := make([]int, len(r1cs.CommitmentInfo)) // number of private committed wires seen so far for each commitment + nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 + // i = vI + nbPrivateCommittedSeen + nbCommitmentsSeen for i := range A { commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool @@ -176,7 +167,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbCommitmentsSeen++ } - for j := range r1cs.CommitmentInfo { + for j := range r1cs.CommitmentInfo { // does commitment j commit to i? if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j break // frontend guarantees that no private variable is committed to more than once diff --git a/backend/groth16/bn254/verify.go b/backend/groth16/bn254/verify.go index de7b3f9aac..c8ff0ad3da 100644 --- a/backend/groth16/bn254/verify.go +++ b/backend/groth16/bn254/verify.go @@ -23,9 +23,10 @@ import ( curve "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/pedersen" + "github.com/consensys/gnark-crypto/utils" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/logger" "io" - "math/big" "text/template" "time" ) @@ -62,20 +63,24 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() + maxNbPublicCommitted := 0 + for _, s := range vk.PublicCommitted { // iterate over commitments + maxNbPublicCommitted = utils.Max(maxNbPublicCommitted, len(s)) + } commitmentsSerialized := make([]byte, len(vk.PublicCommitted)*fr.Bytes) - for i := range vk.PublicCommitted { - publicCommitted := make([]*big.Int, len(vk.PublicCommitted[i])) - for j := range publicCommitted { - var b big.Int - publicWitness[vk.PublicCommitted[i][j]-1].BigInt(&b) - publicCommitted[j] = &b + commitmentPrehashSerialized := make([]byte, curve.SizeOfG1AffineUncompressed+maxNbPublicCommitted*fr.Bytes) + for i := range vk.PublicCommitted { // solveCommitmentWire + copy(commitmentPrehashSerialized, proof.Commitments[i].Marshal()) + offset := curve.SizeOfG1AffineUncompressed + for j := range vk.PublicCommitted[i] { + copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicCommitted[i][j]-1].Marshal()) + offset += fr.Bytes } - - if res, err := solveCommitmentWire(&proof.Commitments[i], publicCommitted); err != nil { + if res, err := fr.Hash(commitmentPrehashSerialized[:offset], []byte(constraint.CommitmentDst), 1); err != nil { return err } else { - publicWitness = append(publicWitness, res) - copy(commitmentsSerialized[i*fr.Bytes:], res.Marshal()) + publicWitness = append(publicWitness, res[0]) + copy(commitmentsSerialized[i*fr.Bytes:], res[0].Marshal()) } } diff --git a/backend/groth16/internal/utils_test.go b/backend/groth16/internal/utils_test.go index 87a994f581..6048ff0b1b 100644 --- a/backend/groth16/internal/utils_test.go +++ b/backend/groth16/internal/utils_test.go @@ -14,7 +14,7 @@ type coinToss struct { func (r *coinToss) rand() (res bool) { if r.remaining == 0 { - r.x = rand.Uint64() + r.x = rand.Uint64() //#nosec G404 weak rng is fine here r.remaining = 64 } r.remaining-- diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl index 6934847941..dfa234e36a 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl @@ -23,8 +23,8 @@ import ( type Proof struct { Ar, Krs curve.G1Affine Bs curve.G2Affine - CommitmentPok curve.G1Affine - Commitments []curve.G1Affine + Commitments []curve.G1Affine // Pedersen commitments a la https://eprint.iacr.org/2022/1072 + CommitmentPok curve.G1Affine // Batched proof of knowledge of the above commitments } // isValid ensures proof elements are in the correct subgroup @@ -276,30 +276,6 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return proof, nil } -// if len(indexes) == 0, returns slice, nil -// else, returns a slice with the indexes and another without -// this assumes the indexes are sorted, without repetition and that len(slice) > len(indexes) -func split(slice []*big.Int, indexes []int) (with, without []*big.Int) { - - if len(indexes) == 0 { - return slice, nil - } - with = make([]*big.Int, 0, len(slice)-len(indexes)) - without = make([]*big.Int, 0, len(indexes)) - - j := 0 - // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) - for i := 0; i < len(slice); i++ { - if j < len(indexes) && i == indexes[j] { - without = append(without, slice[i]) - j++ - continue - } - with = append(with, slice[i]) - } - return -} - // if len(toRemove) == 0, returns slice // else, returns a new slice without the indexes in toRemove // this assumes toRemove indexes are sorted and len(slice) > len(toRemove) From d80bc981a94e9885e06374d4c262fbb05516f1e0 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 6 Jun 2023 14:13:59 -0500 Subject: [PATCH 431/464] build generify --- backend/groth16/bls12-377/prove.go | 28 ++----------------- backend/groth16/bls12-377/setup.go | 19 ++++--------- backend/groth16/bls12-377/verify.go | 27 ++++++++++-------- backend/groth16/bls12-381/prove.go | 28 ++----------------- backend/groth16/bls12-381/setup.go | 19 ++++--------- backend/groth16/bls12-381/verify.go | 27 ++++++++++-------- backend/groth16/bls24-315/prove.go | 28 ++----------------- backend/groth16/bls24-315/setup.go | 19 ++++--------- backend/groth16/bls24-315/verify.go | 27 ++++++++++-------- backend/groth16/bls24-317/prove.go | 28 ++----------------- backend/groth16/bls24-317/setup.go | 19 ++++--------- backend/groth16/bls24-317/verify.go | 27 ++++++++++-------- backend/groth16/bn254/prove.go | 28 ++----------------- backend/groth16/bw6-633/prove.go | 28 ++----------------- backend/groth16/bw6-633/setup.go | 19 ++++--------- backend/groth16/bw6-633/verify.go | 27 ++++++++++-------- backend/groth16/bw6-761/prove.go | 28 ++----------------- backend/groth16/bw6-761/setup.go | 19 ++++--------- backend/groth16/bw6-761/verify.go | 27 ++++++++++-------- .../zkpschemes/groth16/groth16.setup.go.tmpl | 17 +++-------- .../zkpschemes/groth16/groth16.verify.go.tmpl | 28 +++++++++++-------- 21 files changed, 161 insertions(+), 356 deletions(-) diff --git a/backend/groth16/bls12-377/prove.go b/backend/groth16/bls12-377/prove.go index c8edd2e3f2..9c46e6c023 100644 --- a/backend/groth16/bls12-377/prove.go +++ b/backend/groth16/bls12-377/prove.go @@ -40,8 +40,8 @@ import ( type Proof struct { Ar, Krs curve.G1Affine Bs curve.G2Affine - CommitmentPok curve.G1Affine - Commitments []curve.G1Affine + Commitments []curve.G1Affine // Pedersen commitments a la https://eprint.iacr.org/2022/1072 + CommitmentPok curve.G1Affine // Batched proof of knowledge of the above commitments } // isValid ensures proof elements are in the correct subgroup @@ -293,30 +293,6 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return proof, nil } -// if len(indexes) == 0, returns slice, nil -// else, returns a slice with the indexes and another without -// this assumes the indexes are sorted, without repetition and that len(slice) > len(indexes) -func split(slice []*big.Int, indexes []int) (with, without []*big.Int) { - - if len(indexes) == 0 { - return slice, nil - } - with = make([]*big.Int, 0, len(slice)-len(indexes)) - without = make([]*big.Int, 0, len(indexes)) - - j := 0 - // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) - for i := 0; i < len(slice); i++ { - if j < len(indexes) && i == indexes[j] { - without = append(without, slice[i]) - j++ - continue - } - with = append(with, slice[i]) - } - return -} - // if len(toRemove) == 0, returns slice // else, returns a new slice without the indexes in toRemove // this assumes toRemove indexes are sorted and len(slice) > len(toRemove) diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index eb53d87d90..878657ec41 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -103,16 +103,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbPublicWires := r1cs.GetNbPublicVariables() + len(r1cs.CommitmentInfo) nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(r1cs.CommitmentInfo) - // we will need to iterate through the private-to-public wires in order - /*privToPub := make([], nbPrivateCommittedWires+len(r1cs.CommitmentInfo)) - offset := 0 - for i := range r1cs.CommitmentInfo { - copy(privToPub[offset:], r1cs.CommitmentInfo[i].PrivateCommitted()) // TODO Take out commitments - offset += r1cs.CommitmentInfo[i].NbPrivateCommitted - } - privToPub.Heapify() - */ - // Setting group for fft domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) @@ -162,11 +152,12 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Add(&t1, &C[i]). Mul(&t1, coeff) } - vI := 0 - cI := make([]int, len(r1cs.CommitmentInfo)) - nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] + vI := 0 // number of public wires seen so far + cI := make([]int, len(r1cs.CommitmentInfo)) // number of private committed wires seen so far for each commitment + nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 + // i = vI + nbPrivateCommittedSeen + nbCommitmentsSeen for i := range A { commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool @@ -176,7 +167,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbCommitmentsSeen++ } - for j := range r1cs.CommitmentInfo { + for j := range r1cs.CommitmentInfo { // does commitment j commit to i? if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j break // frontend guarantees that no private variable is committed to more than once diff --git a/backend/groth16/bls12-377/verify.go b/backend/groth16/bls12-377/verify.go index 8982fcb132..976176c048 100644 --- a/backend/groth16/bls12-377/verify.go +++ b/backend/groth16/bls12-377/verify.go @@ -23,9 +23,10 @@ import ( curve "github.com/consensys/gnark-crypto/ecc/bls12-377" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/pedersen" + "github.com/consensys/gnark-crypto/utils" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/logger" "io" - "math/big" "time" ) @@ -61,20 +62,24 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() + maxNbPublicCommitted := 0 + for _, s := range vk.PublicCommitted { // iterate over commitments + maxNbPublicCommitted = utils.Max(maxNbPublicCommitted, len(s)) + } commitmentsSerialized := make([]byte, len(vk.PublicCommitted)*fr.Bytes) - for i := range vk.PublicCommitted { - publicCommitted := make([]*big.Int, len(vk.PublicCommitted[i])) - for j := range publicCommitted { - var b big.Int - publicWitness[vk.PublicCommitted[i][j]-1].BigInt(&b) - publicCommitted[j] = &b + commitmentPrehashSerialized := make([]byte, curve.SizeOfG1AffineUncompressed+maxNbPublicCommitted*fr.Bytes) + for i := range vk.PublicCommitted { // solveCommitmentWire + copy(commitmentPrehashSerialized, proof.Commitments[i].Marshal()) + offset := curve.SizeOfG1AffineUncompressed + for j := range vk.PublicCommitted[i] { + copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicCommitted[i][j]-1].Marshal()) + offset += fr.Bytes } - - if res, err := solveCommitmentWire(&proof.Commitments[i], publicCommitted); err != nil { + if res, err := fr.Hash(commitmentPrehashSerialized[:offset], []byte(constraint.CommitmentDst), 1); err != nil { return err } else { - publicWitness = append(publicWitness, res) - copy(commitmentsSerialized[i*fr.Bytes:], res.Marshal()) + publicWitness = append(publicWitness, res[0]) + copy(commitmentsSerialized[i*fr.Bytes:], res[0].Marshal()) } } diff --git a/backend/groth16/bls12-381/prove.go b/backend/groth16/bls12-381/prove.go index 50c3711363..74344b8121 100644 --- a/backend/groth16/bls12-381/prove.go +++ b/backend/groth16/bls12-381/prove.go @@ -40,8 +40,8 @@ import ( type Proof struct { Ar, Krs curve.G1Affine Bs curve.G2Affine - CommitmentPok curve.G1Affine - Commitments []curve.G1Affine + Commitments []curve.G1Affine // Pedersen commitments a la https://eprint.iacr.org/2022/1072 + CommitmentPok curve.G1Affine // Batched proof of knowledge of the above commitments } // isValid ensures proof elements are in the correct subgroup @@ -293,30 +293,6 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return proof, nil } -// if len(indexes) == 0, returns slice, nil -// else, returns a slice with the indexes and another without -// this assumes the indexes are sorted, without repetition and that len(slice) > len(indexes) -func split(slice []*big.Int, indexes []int) (with, without []*big.Int) { - - if len(indexes) == 0 { - return slice, nil - } - with = make([]*big.Int, 0, len(slice)-len(indexes)) - without = make([]*big.Int, 0, len(indexes)) - - j := 0 - // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) - for i := 0; i < len(slice); i++ { - if j < len(indexes) && i == indexes[j] { - without = append(without, slice[i]) - j++ - continue - } - with = append(with, slice[i]) - } - return -} - // if len(toRemove) == 0, returns slice // else, returns a new slice without the indexes in toRemove // this assumes toRemove indexes are sorted and len(slice) > len(toRemove) diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index 4955be930e..a79f54e559 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -103,16 +103,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbPublicWires := r1cs.GetNbPublicVariables() + len(r1cs.CommitmentInfo) nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(r1cs.CommitmentInfo) - // we will need to iterate through the private-to-public wires in order - /*privToPub := make([], nbPrivateCommittedWires+len(r1cs.CommitmentInfo)) - offset := 0 - for i := range r1cs.CommitmentInfo { - copy(privToPub[offset:], r1cs.CommitmentInfo[i].PrivateCommitted()) // TODO Take out commitments - offset += r1cs.CommitmentInfo[i].NbPrivateCommitted - } - privToPub.Heapify() - */ - // Setting group for fft domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) @@ -162,11 +152,12 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Add(&t1, &C[i]). Mul(&t1, coeff) } - vI := 0 - cI := make([]int, len(r1cs.CommitmentInfo)) - nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] + vI := 0 // number of public wires seen so far + cI := make([]int, len(r1cs.CommitmentInfo)) // number of private committed wires seen so far for each commitment + nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 + // i = vI + nbPrivateCommittedSeen + nbCommitmentsSeen for i := range A { commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool @@ -176,7 +167,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbCommitmentsSeen++ } - for j := range r1cs.CommitmentInfo { + for j := range r1cs.CommitmentInfo { // does commitment j commit to i? if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j break // frontend guarantees that no private variable is committed to more than once diff --git a/backend/groth16/bls12-381/verify.go b/backend/groth16/bls12-381/verify.go index 893e6be13d..64673a9d72 100644 --- a/backend/groth16/bls12-381/verify.go +++ b/backend/groth16/bls12-381/verify.go @@ -23,9 +23,10 @@ import ( curve "github.com/consensys/gnark-crypto/ecc/bls12-381" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/pedersen" + "github.com/consensys/gnark-crypto/utils" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/logger" "io" - "math/big" "time" ) @@ -61,20 +62,24 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() + maxNbPublicCommitted := 0 + for _, s := range vk.PublicCommitted { // iterate over commitments + maxNbPublicCommitted = utils.Max(maxNbPublicCommitted, len(s)) + } commitmentsSerialized := make([]byte, len(vk.PublicCommitted)*fr.Bytes) - for i := range vk.PublicCommitted { - publicCommitted := make([]*big.Int, len(vk.PublicCommitted[i])) - for j := range publicCommitted { - var b big.Int - publicWitness[vk.PublicCommitted[i][j]-1].BigInt(&b) - publicCommitted[j] = &b + commitmentPrehashSerialized := make([]byte, curve.SizeOfG1AffineUncompressed+maxNbPublicCommitted*fr.Bytes) + for i := range vk.PublicCommitted { // solveCommitmentWire + copy(commitmentPrehashSerialized, proof.Commitments[i].Marshal()) + offset := curve.SizeOfG1AffineUncompressed + for j := range vk.PublicCommitted[i] { + copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicCommitted[i][j]-1].Marshal()) + offset += fr.Bytes } - - if res, err := solveCommitmentWire(&proof.Commitments[i], publicCommitted); err != nil { + if res, err := fr.Hash(commitmentPrehashSerialized[:offset], []byte(constraint.CommitmentDst), 1); err != nil { return err } else { - publicWitness = append(publicWitness, res) - copy(commitmentsSerialized[i*fr.Bytes:], res.Marshal()) + publicWitness = append(publicWitness, res[0]) + copy(commitmentsSerialized[i*fr.Bytes:], res[0].Marshal()) } } diff --git a/backend/groth16/bls24-315/prove.go b/backend/groth16/bls24-315/prove.go index 415ab11df0..6fbba81de1 100644 --- a/backend/groth16/bls24-315/prove.go +++ b/backend/groth16/bls24-315/prove.go @@ -40,8 +40,8 @@ import ( type Proof struct { Ar, Krs curve.G1Affine Bs curve.G2Affine - CommitmentPok curve.G1Affine - Commitments []curve.G1Affine + Commitments []curve.G1Affine // Pedersen commitments a la https://eprint.iacr.org/2022/1072 + CommitmentPok curve.G1Affine // Batched proof of knowledge of the above commitments } // isValid ensures proof elements are in the correct subgroup @@ -293,30 +293,6 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return proof, nil } -// if len(indexes) == 0, returns slice, nil -// else, returns a slice with the indexes and another without -// this assumes the indexes are sorted, without repetition and that len(slice) > len(indexes) -func split(slice []*big.Int, indexes []int) (with, without []*big.Int) { - - if len(indexes) == 0 { - return slice, nil - } - with = make([]*big.Int, 0, len(slice)-len(indexes)) - without = make([]*big.Int, 0, len(indexes)) - - j := 0 - // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) - for i := 0; i < len(slice); i++ { - if j < len(indexes) && i == indexes[j] { - without = append(without, slice[i]) - j++ - continue - } - with = append(with, slice[i]) - } - return -} - // if len(toRemove) == 0, returns slice // else, returns a new slice without the indexes in toRemove // this assumes toRemove indexes are sorted and len(slice) > len(toRemove) diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index 059c6db114..1698b4224a 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -103,16 +103,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbPublicWires := r1cs.GetNbPublicVariables() + len(r1cs.CommitmentInfo) nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(r1cs.CommitmentInfo) - // we will need to iterate through the private-to-public wires in order - /*privToPub := make([], nbPrivateCommittedWires+len(r1cs.CommitmentInfo)) - offset := 0 - for i := range r1cs.CommitmentInfo { - copy(privToPub[offset:], r1cs.CommitmentInfo[i].PrivateCommitted()) // TODO Take out commitments - offset += r1cs.CommitmentInfo[i].NbPrivateCommitted - } - privToPub.Heapify() - */ - // Setting group for fft domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) @@ -162,11 +152,12 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Add(&t1, &C[i]). Mul(&t1, coeff) } - vI := 0 - cI := make([]int, len(r1cs.CommitmentInfo)) - nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] + vI := 0 // number of public wires seen so far + cI := make([]int, len(r1cs.CommitmentInfo)) // number of private committed wires seen so far for each commitment + nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 + // i = vI + nbPrivateCommittedSeen + nbCommitmentsSeen for i := range A { commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool @@ -176,7 +167,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbCommitmentsSeen++ } - for j := range r1cs.CommitmentInfo { + for j := range r1cs.CommitmentInfo { // does commitment j commit to i? if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j break // frontend guarantees that no private variable is committed to more than once diff --git a/backend/groth16/bls24-315/verify.go b/backend/groth16/bls24-315/verify.go index 4c774f909b..3b3fd2f993 100644 --- a/backend/groth16/bls24-315/verify.go +++ b/backend/groth16/bls24-315/verify.go @@ -23,9 +23,10 @@ import ( curve "github.com/consensys/gnark-crypto/ecc/bls24-315" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/pedersen" + "github.com/consensys/gnark-crypto/utils" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/logger" "io" - "math/big" "time" ) @@ -61,20 +62,24 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() + maxNbPublicCommitted := 0 + for _, s := range vk.PublicCommitted { // iterate over commitments + maxNbPublicCommitted = utils.Max(maxNbPublicCommitted, len(s)) + } commitmentsSerialized := make([]byte, len(vk.PublicCommitted)*fr.Bytes) - for i := range vk.PublicCommitted { - publicCommitted := make([]*big.Int, len(vk.PublicCommitted[i])) - for j := range publicCommitted { - var b big.Int - publicWitness[vk.PublicCommitted[i][j]-1].BigInt(&b) - publicCommitted[j] = &b + commitmentPrehashSerialized := make([]byte, curve.SizeOfG1AffineUncompressed+maxNbPublicCommitted*fr.Bytes) + for i := range vk.PublicCommitted { // solveCommitmentWire + copy(commitmentPrehashSerialized, proof.Commitments[i].Marshal()) + offset := curve.SizeOfG1AffineUncompressed + for j := range vk.PublicCommitted[i] { + copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicCommitted[i][j]-1].Marshal()) + offset += fr.Bytes } - - if res, err := solveCommitmentWire(&proof.Commitments[i], publicCommitted); err != nil { + if res, err := fr.Hash(commitmentPrehashSerialized[:offset], []byte(constraint.CommitmentDst), 1); err != nil { return err } else { - publicWitness = append(publicWitness, res) - copy(commitmentsSerialized[i*fr.Bytes:], res.Marshal()) + publicWitness = append(publicWitness, res[0]) + copy(commitmentsSerialized[i*fr.Bytes:], res[0].Marshal()) } } diff --git a/backend/groth16/bls24-317/prove.go b/backend/groth16/bls24-317/prove.go index dd8ce912ba..24221fdb32 100644 --- a/backend/groth16/bls24-317/prove.go +++ b/backend/groth16/bls24-317/prove.go @@ -40,8 +40,8 @@ import ( type Proof struct { Ar, Krs curve.G1Affine Bs curve.G2Affine - CommitmentPok curve.G1Affine - Commitments []curve.G1Affine + Commitments []curve.G1Affine // Pedersen commitments a la https://eprint.iacr.org/2022/1072 + CommitmentPok curve.G1Affine // Batched proof of knowledge of the above commitments } // isValid ensures proof elements are in the correct subgroup @@ -293,30 +293,6 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return proof, nil } -// if len(indexes) == 0, returns slice, nil -// else, returns a slice with the indexes and another without -// this assumes the indexes are sorted, without repetition and that len(slice) > len(indexes) -func split(slice []*big.Int, indexes []int) (with, without []*big.Int) { - - if len(indexes) == 0 { - return slice, nil - } - with = make([]*big.Int, 0, len(slice)-len(indexes)) - without = make([]*big.Int, 0, len(indexes)) - - j := 0 - // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) - for i := 0; i < len(slice); i++ { - if j < len(indexes) && i == indexes[j] { - without = append(without, slice[i]) - j++ - continue - } - with = append(with, slice[i]) - } - return -} - // if len(toRemove) == 0, returns slice // else, returns a new slice without the indexes in toRemove // this assumes toRemove indexes are sorted and len(slice) > len(toRemove) diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index c14b6be423..f7270d9611 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -103,16 +103,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbPublicWires := r1cs.GetNbPublicVariables() + len(r1cs.CommitmentInfo) nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(r1cs.CommitmentInfo) - // we will need to iterate through the private-to-public wires in order - /*privToPub := make([], nbPrivateCommittedWires+len(r1cs.CommitmentInfo)) - offset := 0 - for i := range r1cs.CommitmentInfo { - copy(privToPub[offset:], r1cs.CommitmentInfo[i].PrivateCommitted()) // TODO Take out commitments - offset += r1cs.CommitmentInfo[i].NbPrivateCommitted - } - privToPub.Heapify() - */ - // Setting group for fft domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) @@ -162,11 +152,12 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Add(&t1, &C[i]). Mul(&t1, coeff) } - vI := 0 - cI := make([]int, len(r1cs.CommitmentInfo)) - nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] + vI := 0 // number of public wires seen so far + cI := make([]int, len(r1cs.CommitmentInfo)) // number of private committed wires seen so far for each commitment + nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 + // i = vI + nbPrivateCommittedSeen + nbCommitmentsSeen for i := range A { commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool @@ -176,7 +167,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbCommitmentsSeen++ } - for j := range r1cs.CommitmentInfo { + for j := range r1cs.CommitmentInfo { // does commitment j commit to i? if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j break // frontend guarantees that no private variable is committed to more than once diff --git a/backend/groth16/bls24-317/verify.go b/backend/groth16/bls24-317/verify.go index 8854213e89..675882e0a9 100644 --- a/backend/groth16/bls24-317/verify.go +++ b/backend/groth16/bls24-317/verify.go @@ -23,9 +23,10 @@ import ( curve "github.com/consensys/gnark-crypto/ecc/bls24-317" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/pedersen" + "github.com/consensys/gnark-crypto/utils" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/logger" "io" - "math/big" "time" ) @@ -61,20 +62,24 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() + maxNbPublicCommitted := 0 + for _, s := range vk.PublicCommitted { // iterate over commitments + maxNbPublicCommitted = utils.Max(maxNbPublicCommitted, len(s)) + } commitmentsSerialized := make([]byte, len(vk.PublicCommitted)*fr.Bytes) - for i := range vk.PublicCommitted { - publicCommitted := make([]*big.Int, len(vk.PublicCommitted[i])) - for j := range publicCommitted { - var b big.Int - publicWitness[vk.PublicCommitted[i][j]-1].BigInt(&b) - publicCommitted[j] = &b + commitmentPrehashSerialized := make([]byte, curve.SizeOfG1AffineUncompressed+maxNbPublicCommitted*fr.Bytes) + for i := range vk.PublicCommitted { // solveCommitmentWire + copy(commitmentPrehashSerialized, proof.Commitments[i].Marshal()) + offset := curve.SizeOfG1AffineUncompressed + for j := range vk.PublicCommitted[i] { + copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicCommitted[i][j]-1].Marshal()) + offset += fr.Bytes } - - if res, err := solveCommitmentWire(&proof.Commitments[i], publicCommitted); err != nil { + if res, err := fr.Hash(commitmentPrehashSerialized[:offset], []byte(constraint.CommitmentDst), 1); err != nil { return err } else { - publicWitness = append(publicWitness, res) - copy(commitmentsSerialized[i*fr.Bytes:], res.Marshal()) + publicWitness = append(publicWitness, res[0]) + copy(commitmentsSerialized[i*fr.Bytes:], res[0].Marshal()) } } diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index a3a5e1ec6d..dfb7bd81af 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -40,8 +40,8 @@ import ( type Proof struct { Ar, Krs curve.G1Affine Bs curve.G2Affine - CommitmentPok curve.G1Affine - Commitments []curve.G1Affine + Commitments []curve.G1Affine // Pedersen commitments a la https://eprint.iacr.org/2022/1072 + CommitmentPok curve.G1Affine // Batched proof of knowledge of the above commitments } // isValid ensures proof elements are in the correct subgroup @@ -293,30 +293,6 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return proof, nil } -// if len(indexes) == 0, returns slice, nil -// else, returns a slice with the indexes and another without -// this assumes the indexes are sorted, without repetition and that len(slice) > len(indexes) -func split(slice []*big.Int, indexes []int) (with, without []*big.Int) { - - if len(indexes) == 0 { - return slice, nil - } - with = make([]*big.Int, 0, len(slice)-len(indexes)) - without = make([]*big.Int, 0, len(indexes)) - - j := 0 - // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) - for i := 0; i < len(slice); i++ { - if j < len(indexes) && i == indexes[j] { - without = append(without, slice[i]) - j++ - continue - } - with = append(with, slice[i]) - } - return -} - // if len(toRemove) == 0, returns slice // else, returns a new slice without the indexes in toRemove // this assumes toRemove indexes are sorted and len(slice) > len(toRemove) diff --git a/backend/groth16/bw6-633/prove.go b/backend/groth16/bw6-633/prove.go index 719696b93b..7dbc4b2a16 100644 --- a/backend/groth16/bw6-633/prove.go +++ b/backend/groth16/bw6-633/prove.go @@ -40,8 +40,8 @@ import ( type Proof struct { Ar, Krs curve.G1Affine Bs curve.G2Affine - CommitmentPok curve.G1Affine - Commitments []curve.G1Affine + Commitments []curve.G1Affine // Pedersen commitments a la https://eprint.iacr.org/2022/1072 + CommitmentPok curve.G1Affine // Batched proof of knowledge of the above commitments } // isValid ensures proof elements are in the correct subgroup @@ -293,30 +293,6 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return proof, nil } -// if len(indexes) == 0, returns slice, nil -// else, returns a slice with the indexes and another without -// this assumes the indexes are sorted, without repetition and that len(slice) > len(indexes) -func split(slice []*big.Int, indexes []int) (with, without []*big.Int) { - - if len(indexes) == 0 { - return slice, nil - } - with = make([]*big.Int, 0, len(slice)-len(indexes)) - without = make([]*big.Int, 0, len(indexes)) - - j := 0 - // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) - for i := 0; i < len(slice); i++ { - if j < len(indexes) && i == indexes[j] { - without = append(without, slice[i]) - j++ - continue - } - with = append(with, slice[i]) - } - return -} - // if len(toRemove) == 0, returns slice // else, returns a new slice without the indexes in toRemove // this assumes toRemove indexes are sorted and len(slice) > len(toRemove) diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index e10a5240ba..3df8264131 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -103,16 +103,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbPublicWires := r1cs.GetNbPublicVariables() + len(r1cs.CommitmentInfo) nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(r1cs.CommitmentInfo) - // we will need to iterate through the private-to-public wires in order - /*privToPub := make([], nbPrivateCommittedWires+len(r1cs.CommitmentInfo)) - offset := 0 - for i := range r1cs.CommitmentInfo { - copy(privToPub[offset:], r1cs.CommitmentInfo[i].PrivateCommitted()) // TODO Take out commitments - offset += r1cs.CommitmentInfo[i].NbPrivateCommitted - } - privToPub.Heapify() - */ - // Setting group for fft domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) @@ -162,11 +152,12 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Add(&t1, &C[i]). Mul(&t1, coeff) } - vI := 0 - cI := make([]int, len(r1cs.CommitmentInfo)) - nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] + vI := 0 // number of public wires seen so far + cI := make([]int, len(r1cs.CommitmentInfo)) // number of private committed wires seen so far for each commitment + nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 + // i = vI + nbPrivateCommittedSeen + nbCommitmentsSeen for i := range A { commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool @@ -176,7 +167,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbCommitmentsSeen++ } - for j := range r1cs.CommitmentInfo { + for j := range r1cs.CommitmentInfo { // does commitment j commit to i? if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j break // frontend guarantees that no private variable is committed to more than once diff --git a/backend/groth16/bw6-633/verify.go b/backend/groth16/bw6-633/verify.go index eb81eb6f35..e5749cd44c 100644 --- a/backend/groth16/bw6-633/verify.go +++ b/backend/groth16/bw6-633/verify.go @@ -23,9 +23,10 @@ import ( curve "github.com/consensys/gnark-crypto/ecc/bw6-633" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/pedersen" + "github.com/consensys/gnark-crypto/utils" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/logger" "io" - "math/big" "time" ) @@ -61,20 +62,24 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() + maxNbPublicCommitted := 0 + for _, s := range vk.PublicCommitted { // iterate over commitments + maxNbPublicCommitted = utils.Max(maxNbPublicCommitted, len(s)) + } commitmentsSerialized := make([]byte, len(vk.PublicCommitted)*fr.Bytes) - for i := range vk.PublicCommitted { - publicCommitted := make([]*big.Int, len(vk.PublicCommitted[i])) - for j := range publicCommitted { - var b big.Int - publicWitness[vk.PublicCommitted[i][j]-1].BigInt(&b) - publicCommitted[j] = &b + commitmentPrehashSerialized := make([]byte, curve.SizeOfG1AffineUncompressed+maxNbPublicCommitted*fr.Bytes) + for i := range vk.PublicCommitted { // solveCommitmentWire + copy(commitmentPrehashSerialized, proof.Commitments[i].Marshal()) + offset := curve.SizeOfG1AffineUncompressed + for j := range vk.PublicCommitted[i] { + copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicCommitted[i][j]-1].Marshal()) + offset += fr.Bytes } - - if res, err := solveCommitmentWire(&proof.Commitments[i], publicCommitted); err != nil { + if res, err := fr.Hash(commitmentPrehashSerialized[:offset], []byte(constraint.CommitmentDst), 1); err != nil { return err } else { - publicWitness = append(publicWitness, res) - copy(commitmentsSerialized[i*fr.Bytes:], res.Marshal()) + publicWitness = append(publicWitness, res[0]) + copy(commitmentsSerialized[i*fr.Bytes:], res[0].Marshal()) } } diff --git a/backend/groth16/bw6-761/prove.go b/backend/groth16/bw6-761/prove.go index da3d48d925..3be93bb351 100644 --- a/backend/groth16/bw6-761/prove.go +++ b/backend/groth16/bw6-761/prove.go @@ -40,8 +40,8 @@ import ( type Proof struct { Ar, Krs curve.G1Affine Bs curve.G2Affine - CommitmentPok curve.G1Affine - Commitments []curve.G1Affine + Commitments []curve.G1Affine // Pedersen commitments a la https://eprint.iacr.org/2022/1072 + CommitmentPok curve.G1Affine // Batched proof of knowledge of the above commitments } // isValid ensures proof elements are in the correct subgroup @@ -293,30 +293,6 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return proof, nil } -// if len(indexes) == 0, returns slice, nil -// else, returns a slice with the indexes and another without -// this assumes the indexes are sorted, without repetition and that len(slice) > len(indexes) -func split(slice []*big.Int, indexes []int) (with, without []*big.Int) { - - if len(indexes) == 0 { - return slice, nil - } - with = make([]*big.Int, 0, len(slice)-len(indexes)) - without = make([]*big.Int, 0, len(indexes)) - - j := 0 - // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) - for i := 0; i < len(slice); i++ { - if j < len(indexes) && i == indexes[j] { - without = append(without, slice[i]) - j++ - continue - } - with = append(with, slice[i]) - } - return -} - // if len(toRemove) == 0, returns slice // else, returns a new slice without the indexes in toRemove // this assumes toRemove indexes are sorted and len(slice) > len(toRemove) diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index ca7135a535..797950717c 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -103,16 +103,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbPublicWires := r1cs.GetNbPublicVariables() + len(r1cs.CommitmentInfo) nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(r1cs.CommitmentInfo) - // we will need to iterate through the private-to-public wires in order - /*privToPub := make([], nbPrivateCommittedWires+len(r1cs.CommitmentInfo)) - offset := 0 - for i := range r1cs.CommitmentInfo { - copy(privToPub[offset:], r1cs.CommitmentInfo[i].PrivateCommitted()) // TODO Take out commitments - offset += r1cs.CommitmentInfo[i].NbPrivateCommitted - } - privToPub.Heapify() - */ - // Setting group for fft domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) @@ -162,11 +152,12 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Add(&t1, &C[i]). Mul(&t1, coeff) } - vI := 0 - cI := make([]int, len(r1cs.CommitmentInfo)) - nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] + vI := 0 // number of public wires seen so far + cI := make([]int, len(r1cs.CommitmentInfo)) // number of private committed wires seen so far for each commitment + nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 + // i = vI + nbPrivateCommittedSeen + nbCommitmentsSeen for i := range A { commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool @@ -176,7 +167,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbCommitmentsSeen++ } - for j := range r1cs.CommitmentInfo { + for j := range r1cs.CommitmentInfo { // does commitment j commit to i? if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j break // frontend guarantees that no private variable is committed to more than once diff --git a/backend/groth16/bw6-761/verify.go b/backend/groth16/bw6-761/verify.go index c610cae314..895f006f3a 100644 --- a/backend/groth16/bw6-761/verify.go +++ b/backend/groth16/bw6-761/verify.go @@ -23,9 +23,10 @@ import ( curve "github.com/consensys/gnark-crypto/ecc/bw6-761" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/pedersen" + "github.com/consensys/gnark-crypto/utils" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/logger" "io" - "math/big" "time" ) @@ -61,20 +62,24 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() + maxNbPublicCommitted := 0 + for _, s := range vk.PublicCommitted { // iterate over commitments + maxNbPublicCommitted = utils.Max(maxNbPublicCommitted, len(s)) + } commitmentsSerialized := make([]byte, len(vk.PublicCommitted)*fr.Bytes) - for i := range vk.PublicCommitted { - publicCommitted := make([]*big.Int, len(vk.PublicCommitted[i])) - for j := range publicCommitted { - var b big.Int - publicWitness[vk.PublicCommitted[i][j]-1].BigInt(&b) - publicCommitted[j] = &b + commitmentPrehashSerialized := make([]byte, curve.SizeOfG1AffineUncompressed+maxNbPublicCommitted*fr.Bytes) + for i := range vk.PublicCommitted { // solveCommitmentWire + copy(commitmentPrehashSerialized, proof.Commitments[i].Marshal()) + offset := curve.SizeOfG1AffineUncompressed + for j := range vk.PublicCommitted[i] { + copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicCommitted[i][j]-1].Marshal()) + offset += fr.Bytes } - - if res, err := solveCommitmentWire(&proof.Commitments[i], publicCommitted); err != nil { + if res, err := fr.Hash(commitmentPrehashSerialized[:offset], []byte(constraint.CommitmentDst), 1); err != nil { return err } else { - publicWitness = append(publicWitness, res) - copy(commitmentsSerialized[i*fr.Bytes:], res.Marshal()) + publicWitness = append(publicWitness, res[0]) + copy(commitmentsSerialized[i*fr.Bytes:], res[0].Marshal()) } } diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl index 406cc90d2d..490d115cd8 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl @@ -85,16 +85,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbPublicWires := r1cs.GetNbPublicVariables() + len(r1cs.CommitmentInfo) nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(r1cs.CommitmentInfo) - // we will need to iterate through the private-to-public wires in order - /*privToPub := make([], nbPrivateCommittedWires+len(r1cs.CommitmentInfo)) - offset := 0 - for i := range r1cs.CommitmentInfo { - copy(privToPub[offset:], r1cs.CommitmentInfo[i].PrivateCommitted()) // TODO Take out commitments - offset += r1cs.CommitmentInfo[i].NbPrivateCommitted - } - privToPub.Heapify() - */ - // Setting group for fft domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) @@ -144,11 +134,12 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Add(&t1, &C[i]). Mul(&t1, coeff) } - vI := 0 - cI := make([]int, len(r1cs.CommitmentInfo)) + vI := 0 // number of public wires seen so far + cI := make([]int, len(r1cs.CommitmentInfo)) // number of private committed wires seen so far for each commitment nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 + // i = vI + nbPrivateCommittedSeen + nbCommitmentsSeen for i := range A { commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool @@ -158,7 +149,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbCommitmentsSeen++ } - for j := range r1cs.CommitmentInfo { + for j := range r1cs.CommitmentInfo { // does commitment j commit to i? if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j break // frontend guarantees that no private variable is committed to more than once diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl index 566e7813e9..bae54a008d 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl @@ -6,11 +6,13 @@ import ( "errors" "time" "io" - "math/big" + {{- if eq .Curve "BN254"}} "text/template" {{- end}} {{- template "import_pedersen" .}} + "github.com/consensys/gnark-crypto/utils" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/logger" ) @@ -46,20 +48,24 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { close(chDone) }() + maxNbPublicCommitted := 0 + for _, s := range vk.PublicCommitted { // iterate over commitments + maxNbPublicCommitted = utils.Max(maxNbPublicCommitted, len(s)) + } commitmentsSerialized := make([]byte, len(vk.PublicCommitted)*fr.Bytes) - for i := range vk.PublicCommitted { - publicCommitted := make([]*big.Int, len(vk.PublicCommitted[i])) - for j := range publicCommitted { - var b big.Int - publicWitness[vk.PublicCommitted[i][j]-1].BigInt(&b) - publicCommitted[j] = &b + commitmentPrehashSerialized := make([]byte, curve.SizeOfG1AffineUncompressed+maxNbPublicCommitted*fr.Bytes) + for i := range vk.PublicCommitted { // solveCommitmentWire + copy(commitmentPrehashSerialized, proof.Commitments[i].Marshal()) + offset := curve.SizeOfG1AffineUncompressed + for j := range vk.PublicCommitted[i] { + copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicCommitted[i][j]-1].Marshal()) + offset += fr.Bytes } - - if res, err := solveCommitmentWire(&proof.Commitments[i], publicCommitted); err != nil { + if res, err := fr.Hash(commitmentPrehashSerialized[:offset], []byte(constraint.CommitmentDst), 1); err != nil { return err } else { - publicWitness = append(publicWitness, res) - copy(commitmentsSerialized[i*fr.Bytes:], res.Marshal()) + publicWitness = append(publicWitness, res[0]) + copy(commitmentsSerialized[i*fr.Bytes:], res[0].Marshal()) } } From 2246e3ea3199189ccdb123af57e548b1e6b519a2 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 7 Jun 2023 18:25:12 -0500 Subject: [PATCH 432/464] refactor: remove duplicate test utils --- backend/groth16/bn254/prove.go | 4 +- test/end_to_end.go | 101 ++++----------------------------- 2 files changed, 12 insertions(+), 93 deletions(-) diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index dfb7bd81af..021e489f57 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -67,13 +67,13 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - commitmentSubIndexes := r1cs.CommitmentInfo.CommitmentIndexesInCommittedLists() + commitmentSubIndexes := r1cs.CommitmentInfo.CommitmentIndexesInCommittedLists() // TODO @Tabaie Precompute privateCommittedValues := make([][]fr.Element, len(r1cs.CommitmentInfo)) for i := range r1cs.CommitmentInfo { solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(i int) solver.Hint { return func(_ *big.Int, in []*big.Int, out []*big.Int) error { privateCommittedValues[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-len(commitmentSubIndexes[i])) - hashed, committed := internal.DivideByThresholdOrList(r1cs.CommitmentInfo[i].NbPublicCommitted(), commitmentSubIndexes[i], in) + hashed, committed := internal.DivideByThresholdOrList(r1cs.CommitmentInfo[i].NbPublicCommitted(), commitmentSubIndexes[i], in) // TODO @Tabaie pre-order for j, inJ := range committed { privateCommittedValues[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead } diff --git a/test/end_to_end.go b/test/end_to_end.go index d5e581de57..5da06b75c9 100644 --- a/test/end_to_end.go +++ b/test/end_to_end.go @@ -3,110 +3,29 @@ package test import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/backend" - "github.com/consensys/gnark/backend/groth16" - "github.com/consensys/gnark/backend/plonk" - "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/frontend/cs/scs" - "github.com/stretchr/testify/assert" - "math/big" "reflect" "strings" "testing" ) -var fr = []ecc.ID{ - ecc.BN254, - ecc.BLS12_381, - ecc.BLS12_377, - ecc.BLS24_315, - //ecc.BLS12_378, TODO: @Tabaie Not autogenerated? - ecc.BLS24_317, - ecc.BW6_633, - //ecc.BW6_756, TODO: @Tabaie Not autogenerated? - ecc.BW6_761, -} - -func testPlonk(t *testing.T, assignment frontend.Circuit) { - circuit := hollow(assignment) - - run := func(mod *big.Int) func(t *testing.T) { - return func(t *testing.T) { - ccs, err := frontend.Compile(mod, scs.NewBuilder, circuit) - assert.NoError(t, err) - - witnessFull, err := frontend.NewWitness(assignment, mod) - assert.NoError(t, err) - witnessPublic, err := witnessFull.Public() - assert.NoError(t, err) - - srs, err := NewKZGSRS(ccs) - assert.NoError(t, err) - - pk, vk, err := plonk.Setup(ccs, srs) - assert.NoError(t, err) - - proof, err := plonk.Prove(ccs, pk, witnessFull) - assert.NoError(t, err) - - err = plonk.Verify(proof, vk, witnessPublic) - assert.NoError(t, err) - } - } - - for _, id := range fr { - t.Run(id.String(), run(id.ScalarField())) +func makeOpts(opt TestingOption, curves []ecc.ID) []TestingOption { + if len(curves) > 0 { + return []TestingOption{opt, WithCurves(curves[0], curves[1:]...)} } + return []TestingOption{opt} } -func testGroth16(t *testing.T, assignment frontend.Circuit) { - circuit := hollow(assignment) - run := func(mod *big.Int) func(*testing.T) { - return func(t *testing.T) { - cs, err := frontend.Compile(mod, r1cs.NewBuilder, circuit) - assert.NoError(t, err) - var ( - pk groth16.ProvingKey - vk groth16.VerifyingKey - w, pw witness.Witness - proof groth16.Proof - ) - pk, vk, err = groth16.Setup(cs) - assert.NoError(t, err) - - w, err = frontend.NewWitness(assignment, mod) - assert.NoError(t, err) - - proof, err = groth16.Prove(cs, pk, w) - assert.NoError(t, err) - - pw, err = w.Public() - assert.NoError(t, err) - - assert.NoError(t, groth16.Verify(proof, vk, pw)) - } - } +func testPlonk(t *testing.T, assignment frontend.Circuit, curves ...ecc.ID) { + NewAssert(t).ProverSucceeded(hollow(assignment), assignment, makeOpts(WithBackends(backend.PLONK), curves)...) +} - for _, id := range fr { - t.Run(id.String(), run(id.ScalarField())) - } +func testGroth16(t *testing.T, assignment frontend.Circuit, curves ...ecc.ID) { + NewAssert(t).ProverSucceeded(hollow(assignment), assignment, makeOpts(WithBackends(backend.GROTH16), curves)...) } func testAll(t *testing.T, assignment frontend.Circuit) { - t.Parallel() - - t.Run("fuzzer", func(t *testing.T) { - NewAssert(t).ProverSucceeded(hollow(assignment), assignment, WithBackends(backend.GROTH16, backend.PLONK)) // TODO: Support PlonkFri.Commit - }) - - t.Run("plonk-e2e", func(t *testing.T) { - testPlonk(t, assignment) - }) - - t.Run("groth16-e2e", func(t *testing.T) { - testGroth16(t, assignment) - }) + NewAssert(t).ProverSucceeded(hollow(assignment), assignment, WithBackends(backend.GROTH16, backend.PLONK)) } // hollow takes a gnark circuit and removes all the witness data. The resulting circuit can be used for compilation purposes From 6358aabcc734f15cfe9ee9ed5e172c2c1aba48d1 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 7 Jun 2023 21:01:44 -0500 Subject: [PATCH 433/464] refactor: separate groth16 commitmentInfo experiments --- backend/groth16/bls12-377/prove.go | 2 +- backend/groth16/bls12-381/prove.go | 2 +- backend/groth16/bls24-315/prove.go | 2 +- backend/groth16/bls24-317/prove.go | 2 +- backend/groth16/bn254/prove.go | 42 ++++++++++-------- backend/groth16/bn254/setup.go | 30 +++++++------ backend/groth16/bw6-633/prove.go | 2 +- backend/groth16/bw6-761/prove.go | 2 +- backend/groth16/internal/utils.go | 21 +++++++++ constraint/commitment.go | 68 ++++++++++++++++-------------- constraint/core.go | 2 +- constraint/system.go | 2 +- internal/utils/search.go | 15 +++++++ 13 files changed, 123 insertions(+), 69 deletions(-) diff --git a/backend/groth16/bls12-377/prove.go b/backend/groth16/bls12-377/prove.go index 9c46e6c023..1932c750b0 100644 --- a/backend/groth16/bls12-377/prove.go +++ b/backend/groth16/bls12-377/prove.go @@ -211,7 +211,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed - _wireValues := filterHeap(wireValues, r1cs.CommitmentInfo.CommitmentsAndPrivateCommittedIndexes()) + _wireValues := filterHeap(wireValues, r1cs.CommitmentInfo.NonPublicCommittedIndexes()) if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err diff --git a/backend/groth16/bls12-381/prove.go b/backend/groth16/bls12-381/prove.go index 74344b8121..d521df218d 100644 --- a/backend/groth16/bls12-381/prove.go +++ b/backend/groth16/bls12-381/prove.go @@ -211,7 +211,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed - _wireValues := filterHeap(wireValues, r1cs.CommitmentInfo.CommitmentsAndPrivateCommittedIndexes()) + _wireValues := filterHeap(wireValues, r1cs.CommitmentInfo.NonPublicCommittedIndexes()) if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err diff --git a/backend/groth16/bls24-315/prove.go b/backend/groth16/bls24-315/prove.go index 6fbba81de1..c5e08ce86e 100644 --- a/backend/groth16/bls24-315/prove.go +++ b/backend/groth16/bls24-315/prove.go @@ -211,7 +211,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed - _wireValues := filterHeap(wireValues, r1cs.CommitmentInfo.CommitmentsAndPrivateCommittedIndexes()) + _wireValues := filterHeap(wireValues, r1cs.CommitmentInfo.NonPublicCommittedIndexes()) if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err diff --git a/backend/groth16/bls24-317/prove.go b/backend/groth16/bls24-317/prove.go index 24221fdb32..6e92ba5a2b 100644 --- a/backend/groth16/bls24-317/prove.go +++ b/backend/groth16/bls24-317/prove.go @@ -211,7 +211,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed - _wireValues := filterHeap(wireValues, r1cs.CommitmentInfo.CommitmentsAndPrivateCommittedIndexes()) + _wireValues := filterHeap(wireValues, r1cs.CommitmentInfo.NonPublicCommittedIndexes()) if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index 021e489f57..59830d8209 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -25,6 +25,7 @@ import ( "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bn254" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" @@ -63,19 +64,21 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - proof := &Proof{Commitments: make([]curve.G1Affine, len(r1cs.CommitmentInfo))} + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + + proof := &Proof{Commitments: make([]curve.G1Affine, len(commitmentInfo))} solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - commitmentSubIndexes := r1cs.CommitmentInfo.CommitmentIndexesInCommittedLists() // TODO @Tabaie Precompute - privateCommittedValues := make([][]fr.Element, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(i int) solver.Hint { + privateCommittedValues := make([][]fr.Element, len(commitmentInfo)) + for i := range commitmentInfo { + solverOpts = append(solverOpts, solver.OverrideHint(commitmentInfo[i].HintID, func(i int) solver.Hint { return func(_ *big.Int, in []*big.Int, out []*big.Int) error { - privateCommittedValues[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-len(commitmentSubIndexes[i])) - hashed, committed := internal.DivideByThresholdOrList(r1cs.CommitmentInfo[i].NbPublicCommitted(), commitmentSubIndexes[i], in) // TODO @Tabaie pre-order + privateCommittedValues[i] = make([]fr.Element, len(commitmentInfo[i].PrivateCommitted)) + hashed := in[:len(commitmentInfo[i].PublicCommitted)+len(commitmentInfo[i].CommitmentCommitted)] + committed := in[len(hashed):] for j, inJ := range committed { - privateCommittedValues[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead + privateCommittedValues[i][j].SetBigInt(inJ) } var err error @@ -101,9 +104,9 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b start := time.Now() - commitmentsSerialized := make([]byte, fr.Bytes*len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - copy(commitmentsSerialized[fr.Bytes*i:], wireValues[r1cs.CommitmentInfo[i].CommitmentIndex].Marshal()) + commitmentsSerialized := make([]byte, fr.Bytes*len(commitmentInfo)) + for i := range commitmentInfo { + copy(commitmentsSerialized[fr.Bytes*i:], wireValues[commitmentInfo[i].CommitmentIndex].Marshal()) } if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommittedValues, commitmentsSerialized); err != nil { @@ -211,9 +214,12 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed - _wireValues := filterHeap(wireValues, r1cs.CommitmentInfo.CommitmentsAndPrivateCommittedIndexes()) + // TODO Perf @Tabaie worst memory allocation offender + toRemove := commitmentInfo.GetPrivateCommitted() + toRemove = append(toRemove, commitmentInfo.CommitmentWireIndexes()) + _wireValues := filterHeap(wireValues[r1cs.GetNbPublicVariables():], r1cs.GetNbPublicVariables(), internal.ConcatAll(toRemove...)) - if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { + if _, err := krs.MultiExp(pk.G1.K, _wireValues, ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err return } @@ -294,10 +300,10 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } // if len(toRemove) == 0, returns slice -// else, returns a new slice without the indexes in toRemove -// this assumes toRemove indexes are sorted and len(slice) > len(toRemove) +// else, returns a new slice without the indexes in toRemove. The first value in the slice is taken as indexes as sliceFirstIndex +// this assumes len(slice) > len(toRemove) // filterHeap modifies toRemove -func filterHeap(slice []fr.Element, toRemove []int) (r []fr.Element) { +func filterHeap(slice []fr.Element, sliceFirstIndex int, toRemove []int) (r []fr.Element) { if len(toRemove) == 0 { return slice @@ -310,8 +316,8 @@ func filterHeap(slice []fr.Element, toRemove []int) (r []fr.Element) { // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) for i := 0; i < len(slice); i++ { - if len(heap) > 0 && i == heap[0] { - for len(heap) > 0 && i == heap[0] { + if len(heap) > 0 && i+sliceFirstIndex == heap[0] { + for len(heap) > 0 && i+sliceFirstIndex == heap[0] { heap.Pop() } continue diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index 606d3bd9f6..84c0038ae1 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -23,6 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" "github.com/consensys/gnark-crypto/ecc/bn254/fr/pedersen" + "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bn254" "math/big" @@ -94,14 +95,19 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbPrivateCommittedWires, commitmentWires, privateCommitted, publicAndCommitmentCommitted := - r1cs.CommitmentInfo.Interleave(r1cs.GetNbPublicVariables()) + + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + commitmentWires := commitmentInfo.CommitmentWireIndexes() + privateCommitted := commitmentInfo.GetPrivateCommitted() + nbPrivateCommittedWires := internal.NbElements(privateCommitted) + //nbPrivateCommittedWires, privateCommitted, publicAndCommitmentCommitted := + // commitmentInfo.Interleave(r1cs.GetNbPublicVariables()) // a commitment is itself defined by a hint so the prover considers it private // but the verifier will need to inject the value itself so on the groth16 // level it must be considered public - nbPublicWires := r1cs.GetNbPublicVariables() + len(r1cs.CommitmentInfo) - nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(r1cs.CommitmentInfo) + nbPublicWires := r1cs.GetNbPublicVariables() + len(commitmentInfo) + nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(commitmentInfo) // Setting group for fft domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) @@ -138,8 +144,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // compute scalars for pkK, vkK and ckK pkK := make([]fr.Element, nbPrivateWires) vkK := make([]fr.Element, nbPublicWires) - ckK := make([][]fr.Element, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { + ckK := make([][]fr.Element, len(commitmentInfo)) + for i := range commitmentInfo { ckK[i] = make([]fr.Element, len(privateCommitted[i])) } @@ -152,9 +158,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Add(&t1, &C[i]). Mul(&t1, coeff) } - vI := 0 // number of public wires seen so far - cI := make([]int, len(r1cs.CommitmentInfo)) // number of private committed wires seen so far for each commitment - nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] + vI := 0 // number of public wires seen so far + cI := make([]int, len(commitmentInfo)) // number of private committed wires seen so far for each commitment + nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 // i = vI + nbPrivateCommittedSeen + nbCommitmentsSeen @@ -167,7 +173,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbCommitmentsSeen++ } - for j := range r1cs.CommitmentInfo { // does commitment j commit to i? + for j := range commitmentInfo { // does commitment j commit to i? if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j break // frontend guarantees that no private variable is committed to more than once @@ -274,7 +280,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // --------------------------------------------------------------------------------------------- // Commitment setup - commitmentBases := make([][]curve.G1Affine, len(r1cs.CommitmentInfo)) + commitmentBases := make([][]curve.G1Affine, len(commitmentInfo)) for i := range commitmentBases { size := len(ckK[i]) commitmentBases[i] = g1PointsAff[offset : offset+size] @@ -289,7 +295,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = publicAndCommitmentCommitted + vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bw6-633/prove.go b/backend/groth16/bw6-633/prove.go index 7dbc4b2a16..ea22b90b60 100644 --- a/backend/groth16/bw6-633/prove.go +++ b/backend/groth16/bw6-633/prove.go @@ -211,7 +211,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed - _wireValues := filterHeap(wireValues, r1cs.CommitmentInfo.CommitmentsAndPrivateCommittedIndexes()) + _wireValues := filterHeap(wireValues, r1cs.CommitmentInfo.NonPublicCommittedIndexes()) if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err diff --git a/backend/groth16/bw6-761/prove.go b/backend/groth16/bw6-761/prove.go index 3be93bb351..d1b89e43c7 100644 --- a/backend/groth16/bw6-761/prove.go +++ b/backend/groth16/bw6-761/prove.go @@ -211,7 +211,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed - _wireValues := filterHeap(wireValues, r1cs.CommitmentInfo.CommitmentsAndPrivateCommittedIndexes()) + _wireValues := filterHeap(wireValues, r1cs.CommitmentInfo.NonPublicCommittedIndexes()) if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err diff --git a/backend/groth16/internal/utils.go b/backend/groth16/internal/utils.go index b61b3f5966..1356deb80f 100644 --- a/backend/groth16/internal/utils.go +++ b/backend/groth16/internal/utils.go @@ -22,3 +22,24 @@ func DivideByThresholdOrList(indexThreshold int, list []int, x []*big.Int) (ltOr copy(x[indexThreshold:], onList) return } + +func ConcatAll(slices ...[]int) []int { // copyright note: written by GitHub Copilot + totalLen := 0 + for _, s := range slices { + totalLen += len(s) + } + res := make([]int, totalLen) + i := 0 + for _, s := range slices { + i += copy(res[i:], s) + } + return res +} + +func NbElements(slices [][]int) int { // copyright note: written by GitHub Copilot + totalLen := 0 + for _, s := range slices { + totalLen += len(s) + } + return totalLen +} diff --git a/constraint/commitment.go b/constraint/commitment.go index a64cc8d280..492a7c2b9b 100644 --- a/constraint/commitment.go +++ b/constraint/commitment.go @@ -1,23 +1,50 @@ package constraint import ( - "github.com/consensys/gnark/internal/utils" - "math/big" - "github.com/consensys/gnark/constraint/solver" ) const CommitmentDst = "bsb22-commitment" -type Commitment struct { - Committed []int // sorted list of id's of committed variables in groth16. in plonk, list of indexes of constraints defining committed values - NbPrivateCommitted int - HintID solver.HintID // TODO @gbotrel we probably don't need that here - CommitmentIndex int // in groth16, CommitmentIndex is the wire index. in plonk, it's the constraint defining it +type Groth16Commitment struct { + PublicAndCommitmentCommitted []int // PublicAndCommitmentCommitted sorted list of id's of public and commitment committed wires + PrivateCommitted []int // PrivateCommitted sorted list of id's of private/internal committed wires + CommitmentIndex int // CommitmentIndex the wire index of the commitment + HintID solver.HintID + NbPublicCommitted int +} + +type PlonkCommitment struct { + Committed []int // sorted list of id's of committed variables in groth16. in plonk, list of indexes of constraints defining committed values + CommitmentIndex int // CommitmentIndex index of the constraint defining the commitment + HintID solver.HintID +} + +type Commitments interface{} + +type Groth16Commitments []Groth16Commitment + +func (c Groth16Commitments) CommitmentWireIndexes() []int { + commitmentWires := make([]int, len(c)) + for i := range c { + commitmentWires[i] = c[i].CommitmentIndex + } + return commitmentWires +} + +func (c Groth16Commitments) GetPrivateCommitted() [][]int { + res := make([][]int, len(c)) + for i := range c { + res[i] = c[i].PrivateCommitted + } + return res } -type Commitments []Commitment +func (c Groth16Commitments) GetPublicAndCommitmentCommitted() [][]int { + +} +/* func (i *Commitment) NbPublicCommitted() int { return i.NbCommitted() - i.NbPrivateCommitted } @@ -67,29 +94,7 @@ func (i *Commitment) PublicCommitted() []int { return i.Committed[:i.NbPublicCommitted()] } -func (c Commitments) CommitmentWireIndexes() []int { - commitmentWires := make([]int, len(c)) - for i := range c { - commitmentWires[i] = c[i].CommitmentIndex - } - return commitmentWires -} -func (c Commitments) CommitmentsAndPrivateCommittedIndexes() []int { - nbCommitmentAndPrivCommitted := len(c) // an upper bound - for i := range c { - nbCommitmentAndPrivCommitted += c[i].NbPrivateCommitted - } - res := make([]int, nbCommitmentAndPrivCommitted) - offset := 0 - for i := range c { - copy(res[offset:], c[i].PrivateCommitted()) - offset += c[i].NbPrivateCommitted - res[offset] = c[i].CommitmentIndex - offset++ - } - return res -} // Interleave returns combined information about the commitments // nbPrivateCommittedWires doesn't double count because the frontend guarantees that no private wire is committed to more than once @@ -131,3 +136,4 @@ func (c Commitments) CommitmentIndexesInCommittedLists() [][]int { } return res } +*/ diff --git a/constraint/core.go b/constraint/core.go index c3291f6404..2a67d9c5cf 100644 --- a/constraint/core.go +++ b/constraint/core.go @@ -418,7 +418,7 @@ func (cs *System) GetSparseR1CIterator() SparseR1CIterator { return SparseR1CIterator{cs: cs} } -func (cs *System) GetCommitments() []Commitment { +func (cs *System) GetCommitments() Commitments { return cs.CommitmentInfo } diff --git a/constraint/system.go b/constraint/system.go index e733b8f12c..19f8167f32 100644 --- a/constraint/system.go +++ b/constraint/system.go @@ -51,7 +51,7 @@ type ConstraintSystem interface { AddSolverHint(f solver.Hint, id solver.HintID, input []LinearExpression, nbOutput int) (internalVariables []int, err error) AddCommitment(c Commitment) error - GetCommitments() []Commitment + GetCommitments() Commitments AddLog(l LogEntry) diff --git a/internal/utils/search.go b/internal/utils/search.go index 7a8d00e6ab..fd9bcb460b 100644 --- a/internal/utils/search.go +++ b/internal/utils/search.go @@ -9,3 +9,18 @@ func FindInSlice(x []int, target int) (int, bool) { return target - x[i] }) } + +// MultiListSeeker looks up increasing integers in a list of increasing lists of integers. +type MultiListSeeker [][]int + +// Seek returns the index of the earliest list where n is found, or -1 if not found. +func (s MultiListSeeker) Seek(n int) int { + for i, l := range s { + j, found := FindInSlice(l, n) + s[i] = l[j:] + if found { + return i + } + } + return -1 +} From 700bdcd7a55f7ff629cbf2689add214f757a5daf Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 7 Jun 2023 21:02:04 -0500 Subject: [PATCH 434/464] feat: groth16 commitmetInfo experiments --- frontend/cs/r1cs/api.go | 109 ++++++++++++++++++++++++++-------------- 1 file changed, 70 insertions(+), 39 deletions(-) diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index 4e6be74584..6c4c700a9d 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -676,25 +676,37 @@ func (builder *builder) Compiler() frontend.Compiler { return builder } +func lastIs(slice []int, n int) bool { + return len(slice) > 0 && slice[len(slice)-1] == n +} + func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error) { + commitments := builder.cs.GetCommitments() + existingCommitmentIndexes := commitments.CommitmentWireIndexes() + privateCommittedSeeker := utils.MultiListSeeker(commitments.GetPrivateCommitted()) + // we want to build a sorted slice of committed variables, without duplicates // this is the same algorithm as builder.add(...); but we expect len(v) to be quite large. vars, s := builder.toVariables(v...) + nbPublicCommittedBound := 0 // initialize the min-heap // this is the same algorithm as api.add --> we want to merge k sorted linear expression for lID, v := range vars { + if v[0].VID < builder.cs.GetNbPublicVariables() { + nbPublicCommittedBound++ + } builder.heap = append(builder.heap, linMeta{val: v[0].VID, lID: lID}) // TODO: Use int heap } builder.heap.heapify() // sort all the wires - committed := make([]int, 0, s) - - curr := -1 - nbPublicCommitted := 0 + publicCommitted := make([]int, 0, nbPublicCommittedBound) + privateCommitted := make([]int, 0, s) + commitmentsCommitted := make([]int, 0, len(existingCommitmentIndexes)) + lastInsertedWireId := -1 // process all the terms from all the inputs, in sorted order for len(builder.heap) > 0 { @@ -712,41 +724,53 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error if t.VID == 0 { continue // don't commit to ONE_WIRE } - if curr != -1 && t.VID == committed[curr] { + if lastInsertedWireId == t.VID { // it's the same variable ID, do nothing continue - } else { - if t.VID < builder.cs.GetNbPublicVariables() { - nbPublicCommitted++ - } else { - // Cannot commit to a secret variable that has already been committed to - // instead we commit to its commitment - commitments := builder.cs.GetCommitments() - var alreadyCommitted bool - for i := range commitments { - if _, alreadyCommitted = utils.FindInSlice(commitments[i].Committed, t.VID); alreadyCommitted { - toCommit := commitments[i].CommitmentIndex - vars = append(vars, expr.LinearExpression{{Coeff: constraint.Element{1}, VID: toCommit}}) // TODO Replace with mont 1 - builder.heap.push(linMeta{lID: len(vars) - 1, tID: 0, val: toCommit}) - break - } - } - if alreadyCommitted { - continue - } - } - // append, it's a new variable ID - committed = append(committed, t.VID) // if public or not already committed - curr++ } + + if t.VID < builder.cs.GetNbPublicVariables() { // public + publicCommitted = append(publicCommitted, t.VID) + lastInsertedWireId = t.VID + continue + } + + // private or commitment + for len(existingCommitmentIndexes) > 0 && existingCommitmentIndexes[0] < t.VID { + existingCommitmentIndexes = existingCommitmentIndexes[1:] + } + if len(existingCommitmentIndexes) > 0 && existingCommitmentIndexes[0] == t.VID { // commitment + commitmentsCommitted = append(commitmentsCommitted, t.VID) + existingCommitmentIndexes = existingCommitmentIndexes[1:] // technically unnecessary + lastInsertedWireId = t.VID + continue + } + + // private + // Cannot commit to a secret variable that has already been committed to + // instead we commit to its commitment + if committer := privateCommittedSeeker.Seek(t.VID); committer != -1 { + committerWireIndex := existingCommitmentIndexes[committer] // commit to this commitment instead + vars = append(vars, expr.LinearExpression{{Coeff: constraint.Element{1}, VID: committerWireIndex}}) // TODO Replace with mont 1 + builder.heap.push(linMeta{lID: len(vars) - 1, tID: 0, val: committerWireIndex}) // pushing to heap mid-op is okay because toCommit > t.VID > anything popped so far + continue + } + + // so it's a new, so-far-uncommitted private variable + privateCommitted = append(privateCommitted, t.VID) + lastInsertedWireId = t.VID } - if len(committed) == 0 { + if len(privateCommitted) == 0 { return nil, errors.New("must commit to at least one variable") } // build commitment - commitment := constraint.NewCommitment(committed, nbPublicCommitted) + commitment := constraint.Groth16Commitment{ + PublicCommitted: publicCommitted, + CommitmentCommitted: commitmentsCommitted, + PrivateCommitted: privateCommitted, + } // hint is used at solving time to compute the actual value of the commitment // it is going to be dynamically replaced at solving time. @@ -761,7 +785,11 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error return nil, err } - if hintOut, err = builder.NewHintForId(commitment.HintID, 1, builder.getCommittedVariables(&commitment)...); err != nil { + if hintOut, err = builder.NewHintForId(commitment.HintID, 1, builder.wireIDsToVars( + commitment.PublicCommitted, + commitment.CommitmentCommitted, + commitment.PrivateCommitted, + )...); err != nil { return nil, err } @@ -769,10 +797,6 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error commitment.CommitmentIndex = (cVar.(expr.LinearExpression))[0].WireID() - if commitment.CommitmentIndex <= commitment.Committed[len(commitment.Committed)-1] { - return nil, fmt.Errorf("commitment variable index smaller than some committed variable indices") - } - if err := builder.cs.AddCommitment(commitment); err != nil { return nil, err } @@ -780,10 +804,17 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error return cVar, nil } -func (builder *builder) getCommittedVariables(i *constraint.Commitment) []frontend.Variable { - res := make([]frontend.Variable, len(i.Committed)) - for j, wireIndex := range i.Committed { - res[j] = expr.NewLinearExpression(wireIndex, builder.tOne) +func (builder *builder) wireIDsToVars(wireIDs ...[]int) []frontend.Variable { + n := 0 + for i := range wireIDs { + n += len(wireIDs[i]) + } + res := make([]frontend.Variable, n) + n = 0 + for _, list := range wireIDs { + for i := range list { + res[n] = expr.NewLinearExpression(list[i], builder.tOne) + } } return res } From 13b08da842b951a032546895befc70bd8841432e Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 8 Jun 2023 12:16:45 -0500 Subject: [PATCH 435/464] refactor: bn254 groth16 commitmentinfo --- backend/groth16/bn254/prove.go | 2 +- backend/groth16/bn254/setup.go | 2 +- constraint/commitment.go | 10 ++++++++-- constraint/core.go | 9 ++++++++- frontend/cs/r1cs/api.go | 26 +++++++++++++------------- 5 files changed, 31 insertions(+), 18 deletions(-) diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index 59830d8209..eda6dcad4d 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -75,7 +75,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b solverOpts = append(solverOpts, solver.OverrideHint(commitmentInfo[i].HintID, func(i int) solver.Hint { return func(_ *big.Int, in []*big.Int, out []*big.Int) error { privateCommittedValues[i] = make([]fr.Element, len(commitmentInfo[i].PrivateCommitted)) - hashed := in[:len(commitmentInfo[i].PublicCommitted)+len(commitmentInfo[i].CommitmentCommitted)] + hashed := in[:len(commitmentInfo[i].PublicAndCommitmentCommitted)] committed := in[len(hashed):] for j, inJ := range committed { privateCommittedValues[i][j].SetBigInt(inJ) diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index 84c0038ae1..2811c4580b 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -295,7 +295,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted() + vk.PublicCommitted = commitmentInfo.GetPublicCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/constraint/commitment.go b/constraint/commitment.go index 492a7c2b9b..1284bd0adc 100644 --- a/constraint/commitment.go +++ b/constraint/commitment.go @@ -20,9 +20,11 @@ type PlonkCommitment struct { HintID solver.HintID } +type Commitment interface{} type Commitments interface{} type Groth16Commitments []Groth16Commitment +type PlonkCommitments []PlonkCommitment func (c Groth16Commitments) CommitmentWireIndexes() []int { commitmentWires := make([]int, len(c)) @@ -40,8 +42,12 @@ func (c Groth16Commitments) GetPrivateCommitted() [][]int { return res } -func (c Groth16Commitments) GetPublicAndCommitmentCommitted() [][]int { - +func (c Groth16Commitments) GetPublicCommitted() [][]int { + res := make([][]int, len(c)) + for i := range c { + res[i] = c[i].PublicAndCommitmentCommitted[:c[i].NbPublicCommitted] + } + return res } /* diff --git a/constraint/core.go b/constraint/core.go index 2a67d9c5cf..7c60579bdb 100644 --- a/constraint/core.go +++ b/constraint/core.go @@ -298,7 +298,14 @@ func (system *System) AddSolverHint(f solver.Hint, id solver.HintID, input []Lin } func (system *System) AddCommitment(c Commitment) error { - system.CommitmentInfo = append(system.CommitmentInfo, c) + switch v := c.(type) { + case Groth16Commitment: + system.CommitmentInfo = append(system.CommitmentInfo.(Groth16Commitments), v) + case PlonkCommitment: + system.CommitmentInfo = append(system.CommitmentInfo.(PlonkCommitments), v) + default: + return fmt.Errorf("unknown commitment type %T", v) + } return nil } diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index 6c4c700a9d..96dc54cd7a 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -682,7 +682,7 @@ func lastIs(slice []int, n int) bool { func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error) { - commitments := builder.cs.GetCommitments() + commitments := builder.cs.GetCommitments().(constraint.Groth16Commitments) existingCommitmentIndexes := commitments.CommitmentWireIndexes() privateCommittedSeeker := utils.MultiListSeeker(commitments.GetPrivateCommitted()) @@ -691,22 +691,22 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error vars, s := builder.toVariables(v...) - nbPublicCommittedBound := 0 + nbPublicCommitted := 0 // initialize the min-heap // this is the same algorithm as api.add --> we want to merge k sorted linear expression for lID, v := range vars { if v[0].VID < builder.cs.GetNbPublicVariables() { - nbPublicCommittedBound++ + nbPublicCommitted++ } builder.heap = append(builder.heap, linMeta{val: v[0].VID, lID: lID}) // TODO: Use int heap } builder.heap.heapify() // sort all the wires - publicCommitted := make([]int, 0, nbPublicCommittedBound) + publicAndCommitmentCommitted := make([]int, 0, nbPublicCommitted+len(existingCommitmentIndexes)) // right now nbPublicCommitted is an upper bound privateCommitted := make([]int, 0, s) - commitmentsCommitted := make([]int, 0, len(existingCommitmentIndexes)) lastInsertedWireId := -1 + nbPublicCommitted = 0 // process all the terms from all the inputs, in sorted order for len(builder.heap) > 0 { @@ -730,8 +730,9 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error } if t.VID < builder.cs.GetNbPublicVariables() { // public - publicCommitted = append(publicCommitted, t.VID) + publicAndCommitmentCommitted = append(publicAndCommitmentCommitted, t.VID) lastInsertedWireId = t.VID + nbPublicCommitted++ continue } @@ -740,7 +741,7 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error existingCommitmentIndexes = existingCommitmentIndexes[1:] } if len(existingCommitmentIndexes) > 0 && existingCommitmentIndexes[0] == t.VID { // commitment - commitmentsCommitted = append(commitmentsCommitted, t.VID) + publicAndCommitmentCommitted = append(publicAndCommitmentCommitted, t.VID) existingCommitmentIndexes = existingCommitmentIndexes[1:] // technically unnecessary lastInsertedWireId = t.VID continue @@ -767,9 +768,9 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error // build commitment commitment := constraint.Groth16Commitment{ - PublicCommitted: publicCommitted, - CommitmentCommitted: commitmentsCommitted, - PrivateCommitted: privateCommitted, + PublicAndCommitmentCommitted: publicAndCommitmentCommitted, + NbPublicCommitted: nbPublicCommitted, + PrivateCommitted: privateCommitted, } // hint is used at solving time to compute the actual value of the commitment @@ -780,14 +781,13 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error err error ) - commitment.HintID, err = cs.RegisterBsb22CommitmentComputePlaceholder(len(builder.cs.GetCommitments())) + commitment.HintID, err = cs.RegisterBsb22CommitmentComputePlaceholder(len(commitments)) if err != nil { return nil, err } if hintOut, err = builder.NewHintForId(commitment.HintID, 1, builder.wireIDsToVars( - commitment.PublicCommitted, - commitment.CommitmentCommitted, + commitment.PublicAndCommitmentCommitted, commitment.PrivateCommitted, )...); err != nil { return nil, err From c45876dc4ecfeffbc23d111a948bf210e15cdaa4 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 8 Jun 2023 12:26:07 -0500 Subject: [PATCH 436/464] build: generify bn254 changes --- backend/groth16/bls12-377/prove.go | 42 +++++++++++-------- backend/groth16/bls12-377/setup.go | 30 +++++++------ backend/groth16/bls12-381/prove.go | 42 +++++++++++-------- backend/groth16/bls12-381/setup.go | 30 +++++++------ backend/groth16/bls24-315/prove.go | 42 +++++++++++-------- backend/groth16/bls24-315/setup.go | 30 +++++++------ backend/groth16/bls24-317/prove.go | 42 +++++++++++-------- backend/groth16/bls24-317/setup.go | 30 +++++++------ backend/groth16/bw6-633/prove.go | 42 +++++++++++-------- backend/groth16/bw6-633/setup.go | 30 +++++++------ backend/groth16/bw6-761/prove.go | 42 +++++++++++-------- backend/groth16/bw6-761/setup.go | 30 +++++++------ .../zkpschemes/groth16/groth16.prove.go.tmpl | 42 +++++++++++-------- .../zkpschemes/groth16/groth16.setup.go.tmpl | 26 +++++++----- 14 files changed, 292 insertions(+), 208 deletions(-) diff --git a/backend/groth16/bls12-377/prove.go b/backend/groth16/bls12-377/prove.go index 1932c750b0..ece6c2ad87 100644 --- a/backend/groth16/bls12-377/prove.go +++ b/backend/groth16/bls12-377/prove.go @@ -25,6 +25,7 @@ import ( "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls12-377" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" @@ -63,19 +64,21 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - proof := &Proof{Commitments: make([]curve.G1Affine, len(r1cs.CommitmentInfo))} + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + + proof := &Proof{Commitments: make([]curve.G1Affine, len(commitmentInfo))} solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - commitmentSubIndexes := r1cs.CommitmentInfo.CommitmentIndexesInCommittedLists() - privateCommittedValues := make([][]fr.Element, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(i int) solver.Hint { + privateCommittedValues := make([][]fr.Element, len(commitmentInfo)) + for i := range commitmentInfo { + solverOpts = append(solverOpts, solver.OverrideHint(commitmentInfo[i].HintID, func(i int) solver.Hint { return func(_ *big.Int, in []*big.Int, out []*big.Int) error { - privateCommittedValues[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-len(commitmentSubIndexes[i])) - hashed, committed := internal.DivideByThresholdOrList(r1cs.CommitmentInfo[i].NbPublicCommitted(), commitmentSubIndexes[i], in) + privateCommittedValues[i] = make([]fr.Element, len(commitmentInfo[i].PrivateCommitted)) + hashed := in[:len(commitmentInfo[i].PublicAndCommitmentCommitted)] + committed := in[len(hashed):] for j, inJ := range committed { - privateCommittedValues[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead + privateCommittedValues[i][j].SetBigInt(inJ) } var err error @@ -101,9 +104,9 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b start := time.Now() - commitmentsSerialized := make([]byte, fr.Bytes*len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - copy(commitmentsSerialized[fr.Bytes*i:], wireValues[r1cs.CommitmentInfo[i].CommitmentIndex].Marshal()) + commitmentsSerialized := make([]byte, fr.Bytes*len(commitmentInfo)) + for i := range commitmentInfo { + copy(commitmentsSerialized[fr.Bytes*i:], wireValues[commitmentInfo[i].CommitmentIndex].Marshal()) } if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommittedValues, commitmentsSerialized); err != nil { @@ -211,9 +214,12 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed - _wireValues := filterHeap(wireValues, r1cs.CommitmentInfo.NonPublicCommittedIndexes()) + // TODO Perf @Tabaie worst memory allocation offender + toRemove := commitmentInfo.GetPrivateCommitted() + toRemove = append(toRemove, commitmentInfo.CommitmentWireIndexes()) + _wireValues := filterHeap(wireValues[r1cs.GetNbPublicVariables():], r1cs.GetNbPublicVariables(), internal.ConcatAll(toRemove...)) - if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { + if _, err := krs.MultiExp(pk.G1.K, _wireValues, ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err return } @@ -294,10 +300,10 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } // if len(toRemove) == 0, returns slice -// else, returns a new slice without the indexes in toRemove -// this assumes toRemove indexes are sorted and len(slice) > len(toRemove) +// else, returns a new slice without the indexes in toRemove. The first value in the slice is taken as indexes as sliceFirstIndex +// this assumes len(slice) > len(toRemove) // filterHeap modifies toRemove -func filterHeap(slice []fr.Element, toRemove []int) (r []fr.Element) { +func filterHeap(slice []fr.Element, sliceFirstIndex int, toRemove []int) (r []fr.Element) { if len(toRemove) == 0 { return slice @@ -310,8 +316,8 @@ func filterHeap(slice []fr.Element, toRemove []int) (r []fr.Element) { // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) for i := 0; i < len(slice); i++ { - if len(heap) > 0 && i == heap[0] { - for len(heap) > 0 && i == heap[0] { + if len(heap) > 0 && i+sliceFirstIndex == heap[0] { + for len(heap) > 0 && i+sliceFirstIndex == heap[0] { heap.Pop() } continue diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index 878657ec41..dd997f4872 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -23,6 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/pedersen" + "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls12-377" "math/big" @@ -94,14 +95,19 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbPrivateCommittedWires, commitmentWires, privateCommitted, publicAndCommitmentCommitted := - r1cs.CommitmentInfo.Interleave(r1cs.GetNbPublicVariables()) + + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + commitmentWires := commitmentInfo.CommitmentWireIndexes() + privateCommitted := commitmentInfo.GetPrivateCommitted() + nbPrivateCommittedWires := internal.NbElements(privateCommitted) + //nbPrivateCommittedWires, privateCommitted, publicAndCommitmentCommitted := + // commitmentInfo.Interleave(r1cs.GetNbPublicVariables()) // a commitment is itself defined by a hint so the prover considers it private // but the verifier will need to inject the value itself so on the groth16 // level it must be considered public - nbPublicWires := r1cs.GetNbPublicVariables() + len(r1cs.CommitmentInfo) - nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(r1cs.CommitmentInfo) + nbPublicWires := r1cs.GetNbPublicVariables() + len(commitmentInfo) + nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(commitmentInfo) // Setting group for fft domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) @@ -138,8 +144,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // compute scalars for pkK, vkK and ckK pkK := make([]fr.Element, nbPrivateWires) vkK := make([]fr.Element, nbPublicWires) - ckK := make([][]fr.Element, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { + ckK := make([][]fr.Element, len(commitmentInfo)) + for i := range commitmentInfo { ckK[i] = make([]fr.Element, len(privateCommitted[i])) } @@ -152,9 +158,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Add(&t1, &C[i]). Mul(&t1, coeff) } - vI := 0 // number of public wires seen so far - cI := make([]int, len(r1cs.CommitmentInfo)) // number of private committed wires seen so far for each commitment - nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] + vI := 0 // number of public wires seen so far + cI := make([]int, len(commitmentInfo)) // number of private committed wires seen so far for each commitment + nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 // i = vI + nbPrivateCommittedSeen + nbCommitmentsSeen @@ -167,7 +173,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbCommitmentsSeen++ } - for j := range r1cs.CommitmentInfo { // does commitment j commit to i? + for j := range commitmentInfo { // does commitment j commit to i? if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j break // frontend guarantees that no private variable is committed to more than once @@ -274,7 +280,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // --------------------------------------------------------------------------------------------- // Commitment setup - commitmentBases := make([][]curve.G1Affine, len(r1cs.CommitmentInfo)) + commitmentBases := make([][]curve.G1Affine, len(commitmentInfo)) for i := range commitmentBases { size := len(ckK[i]) commitmentBases[i] = g1PointsAff[offset : offset+size] @@ -289,7 +295,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = publicAndCommitmentCommitted + vk.PublicCommitted = commitmentInfo.GetPublicCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bls12-381/prove.go b/backend/groth16/bls12-381/prove.go index d521df218d..fb9aaa9cc9 100644 --- a/backend/groth16/bls12-381/prove.go +++ b/backend/groth16/bls12-381/prove.go @@ -25,6 +25,7 @@ import ( "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls12-381" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" @@ -63,19 +64,21 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - proof := &Proof{Commitments: make([]curve.G1Affine, len(r1cs.CommitmentInfo))} + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + + proof := &Proof{Commitments: make([]curve.G1Affine, len(commitmentInfo))} solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - commitmentSubIndexes := r1cs.CommitmentInfo.CommitmentIndexesInCommittedLists() - privateCommittedValues := make([][]fr.Element, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(i int) solver.Hint { + privateCommittedValues := make([][]fr.Element, len(commitmentInfo)) + for i := range commitmentInfo { + solverOpts = append(solverOpts, solver.OverrideHint(commitmentInfo[i].HintID, func(i int) solver.Hint { return func(_ *big.Int, in []*big.Int, out []*big.Int) error { - privateCommittedValues[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-len(commitmentSubIndexes[i])) - hashed, committed := internal.DivideByThresholdOrList(r1cs.CommitmentInfo[i].NbPublicCommitted(), commitmentSubIndexes[i], in) + privateCommittedValues[i] = make([]fr.Element, len(commitmentInfo[i].PrivateCommitted)) + hashed := in[:len(commitmentInfo[i].PublicAndCommitmentCommitted)] + committed := in[len(hashed):] for j, inJ := range committed { - privateCommittedValues[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead + privateCommittedValues[i][j].SetBigInt(inJ) } var err error @@ -101,9 +104,9 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b start := time.Now() - commitmentsSerialized := make([]byte, fr.Bytes*len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - copy(commitmentsSerialized[fr.Bytes*i:], wireValues[r1cs.CommitmentInfo[i].CommitmentIndex].Marshal()) + commitmentsSerialized := make([]byte, fr.Bytes*len(commitmentInfo)) + for i := range commitmentInfo { + copy(commitmentsSerialized[fr.Bytes*i:], wireValues[commitmentInfo[i].CommitmentIndex].Marshal()) } if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommittedValues, commitmentsSerialized); err != nil { @@ -211,9 +214,12 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed - _wireValues := filterHeap(wireValues, r1cs.CommitmentInfo.NonPublicCommittedIndexes()) + // TODO Perf @Tabaie worst memory allocation offender + toRemove := commitmentInfo.GetPrivateCommitted() + toRemove = append(toRemove, commitmentInfo.CommitmentWireIndexes()) + _wireValues := filterHeap(wireValues[r1cs.GetNbPublicVariables():], r1cs.GetNbPublicVariables(), internal.ConcatAll(toRemove...)) - if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { + if _, err := krs.MultiExp(pk.G1.K, _wireValues, ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err return } @@ -294,10 +300,10 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } // if len(toRemove) == 0, returns slice -// else, returns a new slice without the indexes in toRemove -// this assumes toRemove indexes are sorted and len(slice) > len(toRemove) +// else, returns a new slice without the indexes in toRemove. The first value in the slice is taken as indexes as sliceFirstIndex +// this assumes len(slice) > len(toRemove) // filterHeap modifies toRemove -func filterHeap(slice []fr.Element, toRemove []int) (r []fr.Element) { +func filterHeap(slice []fr.Element, sliceFirstIndex int, toRemove []int) (r []fr.Element) { if len(toRemove) == 0 { return slice @@ -310,8 +316,8 @@ func filterHeap(slice []fr.Element, toRemove []int) (r []fr.Element) { // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) for i := 0; i < len(slice); i++ { - if len(heap) > 0 && i == heap[0] { - for len(heap) > 0 && i == heap[0] { + if len(heap) > 0 && i+sliceFirstIndex == heap[0] { + for len(heap) > 0 && i+sliceFirstIndex == heap[0] { heap.Pop() } continue diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index a79f54e559..7444927202 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -23,6 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/pedersen" + "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls12-381" "math/big" @@ -94,14 +95,19 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbPrivateCommittedWires, commitmentWires, privateCommitted, publicAndCommitmentCommitted := - r1cs.CommitmentInfo.Interleave(r1cs.GetNbPublicVariables()) + + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + commitmentWires := commitmentInfo.CommitmentWireIndexes() + privateCommitted := commitmentInfo.GetPrivateCommitted() + nbPrivateCommittedWires := internal.NbElements(privateCommitted) + //nbPrivateCommittedWires, privateCommitted, publicAndCommitmentCommitted := + // commitmentInfo.Interleave(r1cs.GetNbPublicVariables()) // a commitment is itself defined by a hint so the prover considers it private // but the verifier will need to inject the value itself so on the groth16 // level it must be considered public - nbPublicWires := r1cs.GetNbPublicVariables() + len(r1cs.CommitmentInfo) - nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(r1cs.CommitmentInfo) + nbPublicWires := r1cs.GetNbPublicVariables() + len(commitmentInfo) + nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(commitmentInfo) // Setting group for fft domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) @@ -138,8 +144,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // compute scalars for pkK, vkK and ckK pkK := make([]fr.Element, nbPrivateWires) vkK := make([]fr.Element, nbPublicWires) - ckK := make([][]fr.Element, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { + ckK := make([][]fr.Element, len(commitmentInfo)) + for i := range commitmentInfo { ckK[i] = make([]fr.Element, len(privateCommitted[i])) } @@ -152,9 +158,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Add(&t1, &C[i]). Mul(&t1, coeff) } - vI := 0 // number of public wires seen so far - cI := make([]int, len(r1cs.CommitmentInfo)) // number of private committed wires seen so far for each commitment - nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] + vI := 0 // number of public wires seen so far + cI := make([]int, len(commitmentInfo)) // number of private committed wires seen so far for each commitment + nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 // i = vI + nbPrivateCommittedSeen + nbCommitmentsSeen @@ -167,7 +173,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbCommitmentsSeen++ } - for j := range r1cs.CommitmentInfo { // does commitment j commit to i? + for j := range commitmentInfo { // does commitment j commit to i? if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j break // frontend guarantees that no private variable is committed to more than once @@ -274,7 +280,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // --------------------------------------------------------------------------------------------- // Commitment setup - commitmentBases := make([][]curve.G1Affine, len(r1cs.CommitmentInfo)) + commitmentBases := make([][]curve.G1Affine, len(commitmentInfo)) for i := range commitmentBases { size := len(ckK[i]) commitmentBases[i] = g1PointsAff[offset : offset+size] @@ -289,7 +295,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = publicAndCommitmentCommitted + vk.PublicCommitted = commitmentInfo.GetPublicCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bls24-315/prove.go b/backend/groth16/bls24-315/prove.go index c5e08ce86e..ce413bbb7c 100644 --- a/backend/groth16/bls24-315/prove.go +++ b/backend/groth16/bls24-315/prove.go @@ -25,6 +25,7 @@ import ( "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls24-315" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" @@ -63,19 +64,21 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - proof := &Proof{Commitments: make([]curve.G1Affine, len(r1cs.CommitmentInfo))} + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + + proof := &Proof{Commitments: make([]curve.G1Affine, len(commitmentInfo))} solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - commitmentSubIndexes := r1cs.CommitmentInfo.CommitmentIndexesInCommittedLists() - privateCommittedValues := make([][]fr.Element, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(i int) solver.Hint { + privateCommittedValues := make([][]fr.Element, len(commitmentInfo)) + for i := range commitmentInfo { + solverOpts = append(solverOpts, solver.OverrideHint(commitmentInfo[i].HintID, func(i int) solver.Hint { return func(_ *big.Int, in []*big.Int, out []*big.Int) error { - privateCommittedValues[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-len(commitmentSubIndexes[i])) - hashed, committed := internal.DivideByThresholdOrList(r1cs.CommitmentInfo[i].NbPublicCommitted(), commitmentSubIndexes[i], in) + privateCommittedValues[i] = make([]fr.Element, len(commitmentInfo[i].PrivateCommitted)) + hashed := in[:len(commitmentInfo[i].PublicAndCommitmentCommitted)] + committed := in[len(hashed):] for j, inJ := range committed { - privateCommittedValues[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead + privateCommittedValues[i][j].SetBigInt(inJ) } var err error @@ -101,9 +104,9 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b start := time.Now() - commitmentsSerialized := make([]byte, fr.Bytes*len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - copy(commitmentsSerialized[fr.Bytes*i:], wireValues[r1cs.CommitmentInfo[i].CommitmentIndex].Marshal()) + commitmentsSerialized := make([]byte, fr.Bytes*len(commitmentInfo)) + for i := range commitmentInfo { + copy(commitmentsSerialized[fr.Bytes*i:], wireValues[commitmentInfo[i].CommitmentIndex].Marshal()) } if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommittedValues, commitmentsSerialized); err != nil { @@ -211,9 +214,12 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed - _wireValues := filterHeap(wireValues, r1cs.CommitmentInfo.NonPublicCommittedIndexes()) + // TODO Perf @Tabaie worst memory allocation offender + toRemove := commitmentInfo.GetPrivateCommitted() + toRemove = append(toRemove, commitmentInfo.CommitmentWireIndexes()) + _wireValues := filterHeap(wireValues[r1cs.GetNbPublicVariables():], r1cs.GetNbPublicVariables(), internal.ConcatAll(toRemove...)) - if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { + if _, err := krs.MultiExp(pk.G1.K, _wireValues, ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err return } @@ -294,10 +300,10 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } // if len(toRemove) == 0, returns slice -// else, returns a new slice without the indexes in toRemove -// this assumes toRemove indexes are sorted and len(slice) > len(toRemove) +// else, returns a new slice without the indexes in toRemove. The first value in the slice is taken as indexes as sliceFirstIndex +// this assumes len(slice) > len(toRemove) // filterHeap modifies toRemove -func filterHeap(slice []fr.Element, toRemove []int) (r []fr.Element) { +func filterHeap(slice []fr.Element, sliceFirstIndex int, toRemove []int) (r []fr.Element) { if len(toRemove) == 0 { return slice @@ -310,8 +316,8 @@ func filterHeap(slice []fr.Element, toRemove []int) (r []fr.Element) { // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) for i := 0; i < len(slice); i++ { - if len(heap) > 0 && i == heap[0] { - for len(heap) > 0 && i == heap[0] { + if len(heap) > 0 && i+sliceFirstIndex == heap[0] { + for len(heap) > 0 && i+sliceFirstIndex == heap[0] { heap.Pop() } continue diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index 1698b4224a..1612db16a6 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -23,6 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/pedersen" + "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls24-315" "math/big" @@ -94,14 +95,19 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbPrivateCommittedWires, commitmentWires, privateCommitted, publicAndCommitmentCommitted := - r1cs.CommitmentInfo.Interleave(r1cs.GetNbPublicVariables()) + + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + commitmentWires := commitmentInfo.CommitmentWireIndexes() + privateCommitted := commitmentInfo.GetPrivateCommitted() + nbPrivateCommittedWires := internal.NbElements(privateCommitted) + //nbPrivateCommittedWires, privateCommitted, publicAndCommitmentCommitted := + // commitmentInfo.Interleave(r1cs.GetNbPublicVariables()) // a commitment is itself defined by a hint so the prover considers it private // but the verifier will need to inject the value itself so on the groth16 // level it must be considered public - nbPublicWires := r1cs.GetNbPublicVariables() + len(r1cs.CommitmentInfo) - nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(r1cs.CommitmentInfo) + nbPublicWires := r1cs.GetNbPublicVariables() + len(commitmentInfo) + nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(commitmentInfo) // Setting group for fft domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) @@ -138,8 +144,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // compute scalars for pkK, vkK and ckK pkK := make([]fr.Element, nbPrivateWires) vkK := make([]fr.Element, nbPublicWires) - ckK := make([][]fr.Element, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { + ckK := make([][]fr.Element, len(commitmentInfo)) + for i := range commitmentInfo { ckK[i] = make([]fr.Element, len(privateCommitted[i])) } @@ -152,9 +158,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Add(&t1, &C[i]). Mul(&t1, coeff) } - vI := 0 // number of public wires seen so far - cI := make([]int, len(r1cs.CommitmentInfo)) // number of private committed wires seen so far for each commitment - nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] + vI := 0 // number of public wires seen so far + cI := make([]int, len(commitmentInfo)) // number of private committed wires seen so far for each commitment + nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 // i = vI + nbPrivateCommittedSeen + nbCommitmentsSeen @@ -167,7 +173,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbCommitmentsSeen++ } - for j := range r1cs.CommitmentInfo { // does commitment j commit to i? + for j := range commitmentInfo { // does commitment j commit to i? if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j break // frontend guarantees that no private variable is committed to more than once @@ -274,7 +280,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // --------------------------------------------------------------------------------------------- // Commitment setup - commitmentBases := make([][]curve.G1Affine, len(r1cs.CommitmentInfo)) + commitmentBases := make([][]curve.G1Affine, len(commitmentInfo)) for i := range commitmentBases { size := len(ckK[i]) commitmentBases[i] = g1PointsAff[offset : offset+size] @@ -289,7 +295,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = publicAndCommitmentCommitted + vk.PublicCommitted = commitmentInfo.GetPublicCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bls24-317/prove.go b/backend/groth16/bls24-317/prove.go index 6e92ba5a2b..5530f7f150 100644 --- a/backend/groth16/bls24-317/prove.go +++ b/backend/groth16/bls24-317/prove.go @@ -25,6 +25,7 @@ import ( "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls24-317" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" @@ -63,19 +64,21 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - proof := &Proof{Commitments: make([]curve.G1Affine, len(r1cs.CommitmentInfo))} + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + + proof := &Proof{Commitments: make([]curve.G1Affine, len(commitmentInfo))} solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - commitmentSubIndexes := r1cs.CommitmentInfo.CommitmentIndexesInCommittedLists() - privateCommittedValues := make([][]fr.Element, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(i int) solver.Hint { + privateCommittedValues := make([][]fr.Element, len(commitmentInfo)) + for i := range commitmentInfo { + solverOpts = append(solverOpts, solver.OverrideHint(commitmentInfo[i].HintID, func(i int) solver.Hint { return func(_ *big.Int, in []*big.Int, out []*big.Int) error { - privateCommittedValues[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-len(commitmentSubIndexes[i])) - hashed, committed := internal.DivideByThresholdOrList(r1cs.CommitmentInfo[i].NbPublicCommitted(), commitmentSubIndexes[i], in) + privateCommittedValues[i] = make([]fr.Element, len(commitmentInfo[i].PrivateCommitted)) + hashed := in[:len(commitmentInfo[i].PublicAndCommitmentCommitted)] + committed := in[len(hashed):] for j, inJ := range committed { - privateCommittedValues[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead + privateCommittedValues[i][j].SetBigInt(inJ) } var err error @@ -101,9 +104,9 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b start := time.Now() - commitmentsSerialized := make([]byte, fr.Bytes*len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - copy(commitmentsSerialized[fr.Bytes*i:], wireValues[r1cs.CommitmentInfo[i].CommitmentIndex].Marshal()) + commitmentsSerialized := make([]byte, fr.Bytes*len(commitmentInfo)) + for i := range commitmentInfo { + copy(commitmentsSerialized[fr.Bytes*i:], wireValues[commitmentInfo[i].CommitmentIndex].Marshal()) } if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommittedValues, commitmentsSerialized); err != nil { @@ -211,9 +214,12 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed - _wireValues := filterHeap(wireValues, r1cs.CommitmentInfo.NonPublicCommittedIndexes()) + // TODO Perf @Tabaie worst memory allocation offender + toRemove := commitmentInfo.GetPrivateCommitted() + toRemove = append(toRemove, commitmentInfo.CommitmentWireIndexes()) + _wireValues := filterHeap(wireValues[r1cs.GetNbPublicVariables():], r1cs.GetNbPublicVariables(), internal.ConcatAll(toRemove...)) - if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { + if _, err := krs.MultiExp(pk.G1.K, _wireValues, ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err return } @@ -294,10 +300,10 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } // if len(toRemove) == 0, returns slice -// else, returns a new slice without the indexes in toRemove -// this assumes toRemove indexes are sorted and len(slice) > len(toRemove) +// else, returns a new slice without the indexes in toRemove. The first value in the slice is taken as indexes as sliceFirstIndex +// this assumes len(slice) > len(toRemove) // filterHeap modifies toRemove -func filterHeap(slice []fr.Element, toRemove []int) (r []fr.Element) { +func filterHeap(slice []fr.Element, sliceFirstIndex int, toRemove []int) (r []fr.Element) { if len(toRemove) == 0 { return slice @@ -310,8 +316,8 @@ func filterHeap(slice []fr.Element, toRemove []int) (r []fr.Element) { // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) for i := 0; i < len(slice); i++ { - if len(heap) > 0 && i == heap[0] { - for len(heap) > 0 && i == heap[0] { + if len(heap) > 0 && i+sliceFirstIndex == heap[0] { + for len(heap) > 0 && i+sliceFirstIndex == heap[0] { heap.Pop() } continue diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index f7270d9611..cbeef07ad9 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -23,6 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/pedersen" + "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls24-317" "math/big" @@ -94,14 +95,19 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbPrivateCommittedWires, commitmentWires, privateCommitted, publicAndCommitmentCommitted := - r1cs.CommitmentInfo.Interleave(r1cs.GetNbPublicVariables()) + + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + commitmentWires := commitmentInfo.CommitmentWireIndexes() + privateCommitted := commitmentInfo.GetPrivateCommitted() + nbPrivateCommittedWires := internal.NbElements(privateCommitted) + //nbPrivateCommittedWires, privateCommitted, publicAndCommitmentCommitted := + // commitmentInfo.Interleave(r1cs.GetNbPublicVariables()) // a commitment is itself defined by a hint so the prover considers it private // but the verifier will need to inject the value itself so on the groth16 // level it must be considered public - nbPublicWires := r1cs.GetNbPublicVariables() + len(r1cs.CommitmentInfo) - nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(r1cs.CommitmentInfo) + nbPublicWires := r1cs.GetNbPublicVariables() + len(commitmentInfo) + nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(commitmentInfo) // Setting group for fft domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) @@ -138,8 +144,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // compute scalars for pkK, vkK and ckK pkK := make([]fr.Element, nbPrivateWires) vkK := make([]fr.Element, nbPublicWires) - ckK := make([][]fr.Element, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { + ckK := make([][]fr.Element, len(commitmentInfo)) + for i := range commitmentInfo { ckK[i] = make([]fr.Element, len(privateCommitted[i])) } @@ -152,9 +158,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Add(&t1, &C[i]). Mul(&t1, coeff) } - vI := 0 // number of public wires seen so far - cI := make([]int, len(r1cs.CommitmentInfo)) // number of private committed wires seen so far for each commitment - nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] + vI := 0 // number of public wires seen so far + cI := make([]int, len(commitmentInfo)) // number of private committed wires seen so far for each commitment + nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 // i = vI + nbPrivateCommittedSeen + nbCommitmentsSeen @@ -167,7 +173,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbCommitmentsSeen++ } - for j := range r1cs.CommitmentInfo { // does commitment j commit to i? + for j := range commitmentInfo { // does commitment j commit to i? if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j break // frontend guarantees that no private variable is committed to more than once @@ -274,7 +280,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // --------------------------------------------------------------------------------------------- // Commitment setup - commitmentBases := make([][]curve.G1Affine, len(r1cs.CommitmentInfo)) + commitmentBases := make([][]curve.G1Affine, len(commitmentInfo)) for i := range commitmentBases { size := len(ckK[i]) commitmentBases[i] = g1PointsAff[offset : offset+size] @@ -289,7 +295,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = publicAndCommitmentCommitted + vk.PublicCommitted = commitmentInfo.GetPublicCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bw6-633/prove.go b/backend/groth16/bw6-633/prove.go index ea22b90b60..75c8f233ae 100644 --- a/backend/groth16/bw6-633/prove.go +++ b/backend/groth16/bw6-633/prove.go @@ -25,6 +25,7 @@ import ( "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bw6-633" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" @@ -63,19 +64,21 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - proof := &Proof{Commitments: make([]curve.G1Affine, len(r1cs.CommitmentInfo))} + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + + proof := &Proof{Commitments: make([]curve.G1Affine, len(commitmentInfo))} solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - commitmentSubIndexes := r1cs.CommitmentInfo.CommitmentIndexesInCommittedLists() - privateCommittedValues := make([][]fr.Element, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(i int) solver.Hint { + privateCommittedValues := make([][]fr.Element, len(commitmentInfo)) + for i := range commitmentInfo { + solverOpts = append(solverOpts, solver.OverrideHint(commitmentInfo[i].HintID, func(i int) solver.Hint { return func(_ *big.Int, in []*big.Int, out []*big.Int) error { - privateCommittedValues[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-len(commitmentSubIndexes[i])) - hashed, committed := internal.DivideByThresholdOrList(r1cs.CommitmentInfo[i].NbPublicCommitted(), commitmentSubIndexes[i], in) + privateCommittedValues[i] = make([]fr.Element, len(commitmentInfo[i].PrivateCommitted)) + hashed := in[:len(commitmentInfo[i].PublicAndCommitmentCommitted)] + committed := in[len(hashed):] for j, inJ := range committed { - privateCommittedValues[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead + privateCommittedValues[i][j].SetBigInt(inJ) } var err error @@ -101,9 +104,9 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b start := time.Now() - commitmentsSerialized := make([]byte, fr.Bytes*len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - copy(commitmentsSerialized[fr.Bytes*i:], wireValues[r1cs.CommitmentInfo[i].CommitmentIndex].Marshal()) + commitmentsSerialized := make([]byte, fr.Bytes*len(commitmentInfo)) + for i := range commitmentInfo { + copy(commitmentsSerialized[fr.Bytes*i:], wireValues[commitmentInfo[i].CommitmentIndex].Marshal()) } if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommittedValues, commitmentsSerialized); err != nil { @@ -211,9 +214,12 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed - _wireValues := filterHeap(wireValues, r1cs.CommitmentInfo.NonPublicCommittedIndexes()) + // TODO Perf @Tabaie worst memory allocation offender + toRemove := commitmentInfo.GetPrivateCommitted() + toRemove = append(toRemove, commitmentInfo.CommitmentWireIndexes()) + _wireValues := filterHeap(wireValues[r1cs.GetNbPublicVariables():], r1cs.GetNbPublicVariables(), internal.ConcatAll(toRemove...)) - if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { + if _, err := krs.MultiExp(pk.G1.K, _wireValues, ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err return } @@ -294,10 +300,10 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } // if len(toRemove) == 0, returns slice -// else, returns a new slice without the indexes in toRemove -// this assumes toRemove indexes are sorted and len(slice) > len(toRemove) +// else, returns a new slice without the indexes in toRemove. The first value in the slice is taken as indexes as sliceFirstIndex +// this assumes len(slice) > len(toRemove) // filterHeap modifies toRemove -func filterHeap(slice []fr.Element, toRemove []int) (r []fr.Element) { +func filterHeap(slice []fr.Element, sliceFirstIndex int, toRemove []int) (r []fr.Element) { if len(toRemove) == 0 { return slice @@ -310,8 +316,8 @@ func filterHeap(slice []fr.Element, toRemove []int) (r []fr.Element) { // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) for i := 0; i < len(slice); i++ { - if len(heap) > 0 && i == heap[0] { - for len(heap) > 0 && i == heap[0] { + if len(heap) > 0 && i+sliceFirstIndex == heap[0] { + for len(heap) > 0 && i+sliceFirstIndex == heap[0] { heap.Pop() } continue diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index 3df8264131..b3a7c1e04e 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -23,6 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/fft" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/pedersen" + "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bw6-633" "math/big" @@ -94,14 +95,19 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbPrivateCommittedWires, commitmentWires, privateCommitted, publicAndCommitmentCommitted := - r1cs.CommitmentInfo.Interleave(r1cs.GetNbPublicVariables()) + + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + commitmentWires := commitmentInfo.CommitmentWireIndexes() + privateCommitted := commitmentInfo.GetPrivateCommitted() + nbPrivateCommittedWires := internal.NbElements(privateCommitted) + //nbPrivateCommittedWires, privateCommitted, publicAndCommitmentCommitted := + // commitmentInfo.Interleave(r1cs.GetNbPublicVariables()) // a commitment is itself defined by a hint so the prover considers it private // but the verifier will need to inject the value itself so on the groth16 // level it must be considered public - nbPublicWires := r1cs.GetNbPublicVariables() + len(r1cs.CommitmentInfo) - nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(r1cs.CommitmentInfo) + nbPublicWires := r1cs.GetNbPublicVariables() + len(commitmentInfo) + nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(commitmentInfo) // Setting group for fft domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) @@ -138,8 +144,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // compute scalars for pkK, vkK and ckK pkK := make([]fr.Element, nbPrivateWires) vkK := make([]fr.Element, nbPublicWires) - ckK := make([][]fr.Element, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { + ckK := make([][]fr.Element, len(commitmentInfo)) + for i := range commitmentInfo { ckK[i] = make([]fr.Element, len(privateCommitted[i])) } @@ -152,9 +158,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Add(&t1, &C[i]). Mul(&t1, coeff) } - vI := 0 // number of public wires seen so far - cI := make([]int, len(r1cs.CommitmentInfo)) // number of private committed wires seen so far for each commitment - nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] + vI := 0 // number of public wires seen so far + cI := make([]int, len(commitmentInfo)) // number of private committed wires seen so far for each commitment + nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 // i = vI + nbPrivateCommittedSeen + nbCommitmentsSeen @@ -167,7 +173,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbCommitmentsSeen++ } - for j := range r1cs.CommitmentInfo { // does commitment j commit to i? + for j := range commitmentInfo { // does commitment j commit to i? if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j break // frontend guarantees that no private variable is committed to more than once @@ -274,7 +280,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // --------------------------------------------------------------------------------------------- // Commitment setup - commitmentBases := make([][]curve.G1Affine, len(r1cs.CommitmentInfo)) + commitmentBases := make([][]curve.G1Affine, len(commitmentInfo)) for i := range commitmentBases { size := len(ckK[i]) commitmentBases[i] = g1PointsAff[offset : offset+size] @@ -289,7 +295,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = publicAndCommitmentCommitted + vk.PublicCommitted = commitmentInfo.GetPublicCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bw6-761/prove.go b/backend/groth16/bw6-761/prove.go index d1b89e43c7..143fa69356 100644 --- a/backend/groth16/bw6-761/prove.go +++ b/backend/groth16/bw6-761/prove.go @@ -25,6 +25,7 @@ import ( "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bw6-761" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" @@ -63,19 +64,21 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - proof := &Proof{Commitments: make([]curve.G1Affine, len(r1cs.CommitmentInfo))} + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + + proof := &Proof{Commitments: make([]curve.G1Affine, len(commitmentInfo))} solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - commitmentSubIndexes := r1cs.CommitmentInfo.CommitmentIndexesInCommittedLists() - privateCommittedValues := make([][]fr.Element, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(i int) solver.Hint { + privateCommittedValues := make([][]fr.Element, len(commitmentInfo)) + for i := range commitmentInfo { + solverOpts = append(solverOpts, solver.OverrideHint(commitmentInfo[i].HintID, func(i int) solver.Hint { return func(_ *big.Int, in []*big.Int, out []*big.Int) error { - privateCommittedValues[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-len(commitmentSubIndexes[i])) - hashed, committed := internal.DivideByThresholdOrList(r1cs.CommitmentInfo[i].NbPublicCommitted(), commitmentSubIndexes[i], in) + privateCommittedValues[i] = make([]fr.Element, len(commitmentInfo[i].PrivateCommitted)) + hashed := in[:len(commitmentInfo[i].PublicAndCommitmentCommitted)] + committed := in[len(hashed):] for j, inJ := range committed { - privateCommittedValues[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead + privateCommittedValues[i][j].SetBigInt(inJ) } var err error @@ -101,9 +104,9 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b start := time.Now() - commitmentsSerialized := make([]byte, fr.Bytes*len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - copy(commitmentsSerialized[fr.Bytes*i:], wireValues[r1cs.CommitmentInfo[i].CommitmentIndex].Marshal()) + commitmentsSerialized := make([]byte, fr.Bytes*len(commitmentInfo)) + for i := range commitmentInfo { + copy(commitmentsSerialized[fr.Bytes*i:], wireValues[commitmentInfo[i].CommitmentIndex].Marshal()) } if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommittedValues, commitmentsSerialized); err != nil { @@ -211,9 +214,12 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed - _wireValues := filterHeap(wireValues, r1cs.CommitmentInfo.NonPublicCommittedIndexes()) + // TODO Perf @Tabaie worst memory allocation offender + toRemove := commitmentInfo.GetPrivateCommitted() + toRemove = append(toRemove, commitmentInfo.CommitmentWireIndexes()) + _wireValues := filterHeap(wireValues[r1cs.GetNbPublicVariables():], r1cs.GetNbPublicVariables(), internal.ConcatAll(toRemove...)) - if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { + if _, err := krs.MultiExp(pk.G1.K, _wireValues, ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err return } @@ -294,10 +300,10 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } // if len(toRemove) == 0, returns slice -// else, returns a new slice without the indexes in toRemove -// this assumes toRemove indexes are sorted and len(slice) > len(toRemove) +// else, returns a new slice without the indexes in toRemove. The first value in the slice is taken as indexes as sliceFirstIndex +// this assumes len(slice) > len(toRemove) // filterHeap modifies toRemove -func filterHeap(slice []fr.Element, toRemove []int) (r []fr.Element) { +func filterHeap(slice []fr.Element, sliceFirstIndex int, toRemove []int) (r []fr.Element) { if len(toRemove) == 0 { return slice @@ -310,8 +316,8 @@ func filterHeap(slice []fr.Element, toRemove []int) (r []fr.Element) { // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) for i := 0; i < len(slice); i++ { - if len(heap) > 0 && i == heap[0] { - for len(heap) > 0 && i == heap[0] { + if len(heap) > 0 && i+sliceFirstIndex == heap[0] { + for len(heap) > 0 && i+sliceFirstIndex == heap[0] { heap.Pop() } continue diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index 797950717c..e27c97a88d 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -23,6 +23,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/fft" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/pedersen" + "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bw6-761" "math/big" @@ -94,14 +95,19 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbPrivateCommittedWires, commitmentWires, privateCommitted, publicAndCommitmentCommitted := - r1cs.CommitmentInfo.Interleave(r1cs.GetNbPublicVariables()) + + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + commitmentWires := commitmentInfo.CommitmentWireIndexes() + privateCommitted := commitmentInfo.GetPrivateCommitted() + nbPrivateCommittedWires := internal.NbElements(privateCommitted) + //nbPrivateCommittedWires, privateCommitted, publicAndCommitmentCommitted := + // commitmentInfo.Interleave(r1cs.GetNbPublicVariables()) // a commitment is itself defined by a hint so the prover considers it private // but the verifier will need to inject the value itself so on the groth16 // level it must be considered public - nbPublicWires := r1cs.GetNbPublicVariables() + len(r1cs.CommitmentInfo) - nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(r1cs.CommitmentInfo) + nbPublicWires := r1cs.GetNbPublicVariables() + len(commitmentInfo) + nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(commitmentInfo) // Setting group for fft domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) @@ -138,8 +144,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // compute scalars for pkK, vkK and ckK pkK := make([]fr.Element, nbPrivateWires) vkK := make([]fr.Element, nbPublicWires) - ckK := make([][]fr.Element, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { + ckK := make([][]fr.Element, len(commitmentInfo)) + for i := range commitmentInfo { ckK[i] = make([]fr.Element, len(privateCommitted[i])) } @@ -152,9 +158,9 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Add(&t1, &C[i]). Mul(&t1, coeff) } - vI := 0 // number of public wires seen so far - cI := make([]int, len(r1cs.CommitmentInfo)) // number of private committed wires seen so far for each commitment - nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] + vI := 0 // number of public wires seen so far + cI := make([]int, len(commitmentInfo)) // number of private committed wires seen so far for each commitment + nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 // i = vI + nbPrivateCommittedSeen + nbCommitmentsSeen @@ -167,7 +173,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbCommitmentsSeen++ } - for j := range r1cs.CommitmentInfo { // does commitment j commit to i? + for j := range commitmentInfo { // does commitment j commit to i? if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j break // frontend guarantees that no private variable is committed to more than once @@ -274,7 +280,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // --------------------------------------------------------------------------------------------- // Commitment setup - commitmentBases := make([][]curve.G1Affine, len(r1cs.CommitmentInfo)) + commitmentBases := make([][]curve.G1Affine, len(commitmentInfo)) for i := range commitmentBases { size := len(ckK[i]) commitmentBases[i] = g1PointsAff[offset : offset+size] @@ -289,7 +295,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = publicAndCommitmentCommitted + vk.PublicCommitted = commitmentInfo.GetPublicCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl index dfa234e36a..5078bbf3a8 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl @@ -7,6 +7,7 @@ import ( "runtime" "math/big" "time" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/backend" @@ -46,19 +47,21 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - proof := &Proof{Commitments: make([]curve.G1Affine, len(r1cs.CommitmentInfo))} + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + + proof := &Proof{Commitments: make([]curve.G1Affine, len(commitmentInfo))} solverOpts := opt.SolverOpts[:len(opt.SolverOpts):len(opt.SolverOpts)] - commitmentSubIndexes := r1cs.CommitmentInfo.CommitmentIndexesInCommittedLists() - privateCommittedValues := make([][]fr.Element, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - solverOpts = append(solverOpts, solver.OverrideHint(r1cs.CommitmentInfo[i].HintID, func(i int) solver.Hint { + privateCommittedValues := make([][]fr.Element, len(commitmentInfo)) + for i := range commitmentInfo { + solverOpts = append(solverOpts, solver.OverrideHint(commitmentInfo[i].HintID, func(i int) solver.Hint { return func(_ *big.Int, in []*big.Int, out []*big.Int) error { - privateCommittedValues[i] = make([]fr.Element, r1cs.CommitmentInfo[i].NbPrivateCommitted-len(commitmentSubIndexes[i])) - hashed, committed := internal.DivideByThresholdOrList(r1cs.CommitmentInfo[i].NbPublicCommitted(), commitmentSubIndexes[i], in) + privateCommittedValues[i] = make([]fr.Element, len(commitmentInfo[i].PrivateCommitted)) + hashed := in[:len(commitmentInfo[i].PublicAndCommitmentCommitted)] + committed := in[len(hashed):] for j, inJ := range committed { - privateCommittedValues[i][j].SetBigInt(inJ) // TODO @Tabaie Perf If this takes significant time can read values off the witness vector instead + privateCommittedValues[i][j].SetBigInt(inJ) } var err error @@ -84,9 +87,9 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b start := time.Now() - commitmentsSerialized := make([]byte, fr.Bytes*len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { - copy(commitmentsSerialized[fr.Bytes*i:], wireValues[r1cs.CommitmentInfo[i].CommitmentIndex].Marshal()) + commitmentsSerialized := make([]byte, fr.Bytes*len(commitmentInfo)) + for i := range commitmentInfo { + copy(commitmentsSerialized[fr.Bytes*i:], wireValues[commitmentInfo[i].CommitmentIndex].Marshal()) } if proof.CommitmentPok, err = pedersen.BatchProve(pk.CommitmentKeys, privateCommittedValues, commitmentsSerialized); err != nil { @@ -194,9 +197,12 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }() // filter the wire values if needed - _wireValues := filterHeap(wireValues, r1cs.CommitmentInfo.CommitmentsAndPrivateCommittedIndexes()) + // TODO Perf @Tabaie worst memory allocation offender + toRemove := commitmentInfo.GetPrivateCommitted() + toRemove = append(toRemove, commitmentInfo.CommitmentWireIndexes()) + _wireValues := filterHeap(wireValues[r1cs.GetNbPublicVariables():], r1cs.GetNbPublicVariables(), internal.ConcatAll(toRemove...)) - if _, err := krs.MultiExp(pk.G1.K, _wireValues[r1cs.GetNbPublicVariables():], ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { + if _, err := krs.MultiExp(pk.G1.K, _wireValues, ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { chKrsDone <- err return } @@ -277,10 +283,10 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } // if len(toRemove) == 0, returns slice -// else, returns a new slice without the indexes in toRemove -// this assumes toRemove indexes are sorted and len(slice) > len(toRemove) +// else, returns a new slice without the indexes in toRemove. The first value in the slice is taken as indexes as sliceFirstIndex +// this assumes len(slice) > len(toRemove) // filterHeap modifies toRemove -func filterHeap(slice []fr.Element, toRemove []int) (r []fr.Element) { +func filterHeap(slice []fr.Element, sliceFirstIndex int, toRemove []int) (r []fr.Element) { if len(toRemove) == 0 { return slice @@ -293,8 +299,8 @@ func filterHeap(slice []fr.Element, toRemove []int) (r []fr.Element) { // note: we can optimize that for the likely case where len(slice) >>> len(toRemove) for i:=0; i < len(slice);i++ { - if len(heap) > 0 && i == heap[0] { - for len(heap) > 0 && i == heap[0] { + if len(heap) > 0 && i+sliceFirstIndex == heap[0] { + for len(heap) > 0 && i+sliceFirstIndex == heap[0] { heap.Pop() } continue diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl index 490d115cd8..49c4e55a01 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl @@ -5,6 +5,7 @@ import ( {{- template "import_backend_cs" . }} {{- template "import_fft" . }} {{- template "import_pedersen" .}} + "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/constraint" "math/big" @@ -76,14 +77,19 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - nbPrivateCommittedWires, commitmentWires, privateCommitted, publicAndCommitmentCommitted := - r1cs.CommitmentInfo.Interleave(r1cs.GetNbPublicVariables()) + + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + commitmentWires := commitmentInfo.CommitmentWireIndexes() + privateCommitted := commitmentInfo.GetPrivateCommitted() + nbPrivateCommittedWires := internal.NbElements(privateCommitted) + //nbPrivateCommittedWires, privateCommitted, publicAndCommitmentCommitted := + // commitmentInfo.Interleave(r1cs.GetNbPublicVariables()) // a commitment is itself defined by a hint so the prover considers it private // but the verifier will need to inject the value itself so on the groth16 // level it must be considered public - nbPublicWires := r1cs.GetNbPublicVariables() + len(r1cs.CommitmentInfo) - nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(r1cs.CommitmentInfo) + nbPublicWires := r1cs.GetNbPublicVariables() + len(commitmentInfo) + nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - nbPrivateCommittedWires - len(commitmentInfo) // Setting group for fft domain := fft.NewDomain(uint64(r1cs.GetNbConstraints())) @@ -120,8 +126,8 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // compute scalars for pkK, vkK and ckK pkK := make([]fr.Element, nbPrivateWires) vkK := make([]fr.Element, nbPublicWires) - ckK := make([][]fr.Element, len(r1cs.CommitmentInfo)) - for i := range r1cs.CommitmentInfo { + ckK := make([][]fr.Element, len(commitmentInfo)) + for i := range commitmentInfo { ckK[i] = make([]fr.Element, len(privateCommitted[i])) } @@ -135,7 +141,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Mul(&t1, coeff) } vI := 0 // number of public wires seen so far - cI := make([]int, len(r1cs.CommitmentInfo)) // number of private committed wires seen so far for each commitment + cI := make([]int, len(commitmentInfo)) // number of private committed wires seen so far for each commitment nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 @@ -149,7 +155,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbCommitmentsSeen++ } - for j := range r1cs.CommitmentInfo { // does commitment j commit to i? + for j := range commitmentInfo { // does commitment j commit to i? if cI[j] < len(privateCommitted[j]) && privateCommitted[j][cI[j]] == i { commitment = j break // frontend guarantees that no private variable is committed to more than once @@ -256,7 +262,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // --------------------------------------------------------------------------------------------- // Commitment setup - commitmentBases := make([][]curve.G1Affine, len(r1cs.CommitmentInfo)) + commitmentBases := make([][]curve.G1Affine, len(commitmentInfo)) for i := range commitmentBases { size := len(ckK[i]) commitmentBases[i] = g1PointsAff[offset : offset+size] @@ -271,7 +277,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = publicAndCommitmentCommitted + vk.PublicCommitted = commitmentInfo.GetPublicCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars From 0948be5e2b88bd319c8afd3ab064e443966cfb85 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 8 Jun 2023 12:41:16 -0500 Subject: [PATCH 437/464] refactor: reflect changes in plonk prover --- backend/plonk/bls12-377/prove.go | 28 +++++++++--------- backend/plonk/bls12-381/prove.go | 28 +++++++++--------- backend/plonk/bls24-315/prove.go | 28 +++++++++--------- backend/plonk/bls24-317/prove.go | 28 +++++++++--------- backend/plonk/bn254/prove.go | 29 ++++++++++--------- backend/plonk/bw6-633/prove.go | 28 +++++++++--------- backend/plonk/bw6-761/prove.go | 28 +++++++++--------- frontend/cs/scs/api.go | 5 ++-- .../zkpschemes/plonk/plonk.prove.go.tmpl | 28 +++++++++--------- 9 files changed, 124 insertions(+), 106 deletions(-) diff --git a/backend/plonk/bls12-377/prove.go b/backend/plonk/bls12-377/prove.go index b2a9c29b6f..3bf15a3412 100644 --- a/backend/plonk/bls12-377/prove.go +++ b/backend/plonk/bls12-377/prove.go @@ -66,16 +66,17 @@ type Proof struct { // Computing and verifying Bsb22 multi-commits explained in https://hackmd.io/x8KsadW3RRyX7YTCFJIkHg func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, cCommitments []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { + commitmentInfo := spr.CommitmentInfo.(constraint.PlonkCommitments)[commDepth] committedValues := make([]fr.Element, pk.Domain[0].Cardinality) offset := spr.GetNbPublicVariables() for i := range ins { - committedValues[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) + committedValues[offset+commitmentInfo.Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - if _, err = committedValues[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + if _, err = committedValues[offset+commitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } if _, err = committedValues[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding @@ -116,11 +117,12 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // result proof := &Proof{} - commitmentVal := make([]fr.Element, len(spr.CommitmentInfo)) // TODO @Tabaie get rid of this - cCommitments := make([]*iop.Polynomial, len(spr.CommitmentInfo)) - proof.Bsb22Commitments = make([]kzg.Digest, len(spr.CommitmentInfo)) - for i := range spr.CommitmentInfo { - opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[i].HintID, + commitmentInfo := spr.CommitmentInfo.(constraint.PlonkCommitments) + commitmentVal := make([]fr.Element, len(commitmentInfo)) // TODO @Tabaie get rid of this + cCommitments := make([]*iop.Polynomial, len(commitmentInfo)) + proof.Bsb22Commitments = make([]kzg.Digest, len(commitmentInfo)) + for i := range commitmentInfo { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(commitmentInfo[i].HintID, bsb22ComputeCommitmentHint(spr, pk, proof, cCommitments, &commitmentVal[i], i))) } @@ -184,8 +186,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) - for i := range spr.CommitmentInfo { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[i].CommitmentIndex] = commitmentVal[i] + for i := range commitmentInfo { + qkCompletedCanonical[spr.GetNbPublicVariables()+commitmentInfo[i].CommitmentIndex] = commitmentVal[i] } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -292,8 +294,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ic.Add(&ic, &tmp) tmp.Mul(&fqo, &o) ic.Add(&ic, &tmp).Add(&ic, &fqk) - nbComms := len(spr.CommitmentInfo) - for i := range spr.CommitmentInfo { + nbComms := len(commitmentInfo) + for i := range commitmentInfo { tmp.Mul(&pi2QcPrime[i], &pi2QcPrime[i+nbComms]) ic.Add(&ic, &tmp) } @@ -405,7 +407,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // compute evaluations of (blinded version of) l, r, o, z, qCPrime at zeta var blzeta, brzeta, bozeta fr.Element - qcpzeta := make([]fr.Element, len(spr.CommitmentInfo)) + qcpzeta := make([]fr.Element, len(commitmentInfo)) var wgEvals sync.WaitGroup wgEvals.Add(3) @@ -422,7 +424,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qcpzeta[i] = pk.trace.Qcp[i].Evaluate(zeta) } } - utils.Parallelize(len(spr.CommitmentInfo), evalQcpAtZeta) + utils.Parallelize(len(commitmentInfo), evalQcpAtZeta) var zetaShifted fr.Element zetaShifted.Mul(&zeta, &pk.Vk.Generator) diff --git a/backend/plonk/bls12-381/prove.go b/backend/plonk/bls12-381/prove.go index b5972e36d3..d6c319429b 100644 --- a/backend/plonk/bls12-381/prove.go +++ b/backend/plonk/bls12-381/prove.go @@ -66,16 +66,17 @@ type Proof struct { // Computing and verifying Bsb22 multi-commits explained in https://hackmd.io/x8KsadW3RRyX7YTCFJIkHg func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, cCommitments []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { + commitmentInfo := spr.CommitmentInfo.(constraint.PlonkCommitments)[commDepth] committedValues := make([]fr.Element, pk.Domain[0].Cardinality) offset := spr.GetNbPublicVariables() for i := range ins { - committedValues[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) + committedValues[offset+commitmentInfo.Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - if _, err = committedValues[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + if _, err = committedValues[offset+commitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } if _, err = committedValues[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding @@ -116,11 +117,12 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // result proof := &Proof{} - commitmentVal := make([]fr.Element, len(spr.CommitmentInfo)) // TODO @Tabaie get rid of this - cCommitments := make([]*iop.Polynomial, len(spr.CommitmentInfo)) - proof.Bsb22Commitments = make([]kzg.Digest, len(spr.CommitmentInfo)) - for i := range spr.CommitmentInfo { - opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[i].HintID, + commitmentInfo := spr.CommitmentInfo.(constraint.PlonkCommitments) + commitmentVal := make([]fr.Element, len(commitmentInfo)) // TODO @Tabaie get rid of this + cCommitments := make([]*iop.Polynomial, len(commitmentInfo)) + proof.Bsb22Commitments = make([]kzg.Digest, len(commitmentInfo)) + for i := range commitmentInfo { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(commitmentInfo[i].HintID, bsb22ComputeCommitmentHint(spr, pk, proof, cCommitments, &commitmentVal[i], i))) } @@ -184,8 +186,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) - for i := range spr.CommitmentInfo { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[i].CommitmentIndex] = commitmentVal[i] + for i := range commitmentInfo { + qkCompletedCanonical[spr.GetNbPublicVariables()+commitmentInfo[i].CommitmentIndex] = commitmentVal[i] } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -292,8 +294,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ic.Add(&ic, &tmp) tmp.Mul(&fqo, &o) ic.Add(&ic, &tmp).Add(&ic, &fqk) - nbComms := len(spr.CommitmentInfo) - for i := range spr.CommitmentInfo { + nbComms := len(commitmentInfo) + for i := range commitmentInfo { tmp.Mul(&pi2QcPrime[i], &pi2QcPrime[i+nbComms]) ic.Add(&ic, &tmp) } @@ -405,7 +407,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // compute evaluations of (blinded version of) l, r, o, z, qCPrime at zeta var blzeta, brzeta, bozeta fr.Element - qcpzeta := make([]fr.Element, len(spr.CommitmentInfo)) + qcpzeta := make([]fr.Element, len(commitmentInfo)) var wgEvals sync.WaitGroup wgEvals.Add(3) @@ -422,7 +424,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qcpzeta[i] = pk.trace.Qcp[i].Evaluate(zeta) } } - utils.Parallelize(len(spr.CommitmentInfo), evalQcpAtZeta) + utils.Parallelize(len(commitmentInfo), evalQcpAtZeta) var zetaShifted fr.Element zetaShifted.Mul(&zeta, &pk.Vk.Generator) diff --git a/backend/plonk/bls24-315/prove.go b/backend/plonk/bls24-315/prove.go index 39e11185fa..5100785527 100644 --- a/backend/plonk/bls24-315/prove.go +++ b/backend/plonk/bls24-315/prove.go @@ -66,16 +66,17 @@ type Proof struct { // Computing and verifying Bsb22 multi-commits explained in https://hackmd.io/x8KsadW3RRyX7YTCFJIkHg func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, cCommitments []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { + commitmentInfo := spr.CommitmentInfo.(constraint.PlonkCommitments)[commDepth] committedValues := make([]fr.Element, pk.Domain[0].Cardinality) offset := spr.GetNbPublicVariables() for i := range ins { - committedValues[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) + committedValues[offset+commitmentInfo.Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - if _, err = committedValues[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + if _, err = committedValues[offset+commitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } if _, err = committedValues[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding @@ -116,11 +117,12 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // result proof := &Proof{} - commitmentVal := make([]fr.Element, len(spr.CommitmentInfo)) // TODO @Tabaie get rid of this - cCommitments := make([]*iop.Polynomial, len(spr.CommitmentInfo)) - proof.Bsb22Commitments = make([]kzg.Digest, len(spr.CommitmentInfo)) - for i := range spr.CommitmentInfo { - opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[i].HintID, + commitmentInfo := spr.CommitmentInfo.(constraint.PlonkCommitments) + commitmentVal := make([]fr.Element, len(commitmentInfo)) // TODO @Tabaie get rid of this + cCommitments := make([]*iop.Polynomial, len(commitmentInfo)) + proof.Bsb22Commitments = make([]kzg.Digest, len(commitmentInfo)) + for i := range commitmentInfo { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(commitmentInfo[i].HintID, bsb22ComputeCommitmentHint(spr, pk, proof, cCommitments, &commitmentVal[i], i))) } @@ -184,8 +186,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) - for i := range spr.CommitmentInfo { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[i].CommitmentIndex] = commitmentVal[i] + for i := range commitmentInfo { + qkCompletedCanonical[spr.GetNbPublicVariables()+commitmentInfo[i].CommitmentIndex] = commitmentVal[i] } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -292,8 +294,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ic.Add(&ic, &tmp) tmp.Mul(&fqo, &o) ic.Add(&ic, &tmp).Add(&ic, &fqk) - nbComms := len(spr.CommitmentInfo) - for i := range spr.CommitmentInfo { + nbComms := len(commitmentInfo) + for i := range commitmentInfo { tmp.Mul(&pi2QcPrime[i], &pi2QcPrime[i+nbComms]) ic.Add(&ic, &tmp) } @@ -405,7 +407,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // compute evaluations of (blinded version of) l, r, o, z, qCPrime at zeta var blzeta, brzeta, bozeta fr.Element - qcpzeta := make([]fr.Element, len(spr.CommitmentInfo)) + qcpzeta := make([]fr.Element, len(commitmentInfo)) var wgEvals sync.WaitGroup wgEvals.Add(3) @@ -422,7 +424,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qcpzeta[i] = pk.trace.Qcp[i].Evaluate(zeta) } } - utils.Parallelize(len(spr.CommitmentInfo), evalQcpAtZeta) + utils.Parallelize(len(commitmentInfo), evalQcpAtZeta) var zetaShifted fr.Element zetaShifted.Mul(&zeta, &pk.Vk.Generator) diff --git a/backend/plonk/bls24-317/prove.go b/backend/plonk/bls24-317/prove.go index 5ec3131efc..f4992a6863 100644 --- a/backend/plonk/bls24-317/prove.go +++ b/backend/plonk/bls24-317/prove.go @@ -66,16 +66,17 @@ type Proof struct { // Computing and verifying Bsb22 multi-commits explained in https://hackmd.io/x8KsadW3RRyX7YTCFJIkHg func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, cCommitments []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { + commitmentInfo := spr.CommitmentInfo.(constraint.PlonkCommitments)[commDepth] committedValues := make([]fr.Element, pk.Domain[0].Cardinality) offset := spr.GetNbPublicVariables() for i := range ins { - committedValues[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) + committedValues[offset+commitmentInfo.Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - if _, err = committedValues[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + if _, err = committedValues[offset+commitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } if _, err = committedValues[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding @@ -116,11 +117,12 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // result proof := &Proof{} - commitmentVal := make([]fr.Element, len(spr.CommitmentInfo)) // TODO @Tabaie get rid of this - cCommitments := make([]*iop.Polynomial, len(spr.CommitmentInfo)) - proof.Bsb22Commitments = make([]kzg.Digest, len(spr.CommitmentInfo)) - for i := range spr.CommitmentInfo { - opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[i].HintID, + commitmentInfo := spr.CommitmentInfo.(constraint.PlonkCommitments) + commitmentVal := make([]fr.Element, len(commitmentInfo)) // TODO @Tabaie get rid of this + cCommitments := make([]*iop.Polynomial, len(commitmentInfo)) + proof.Bsb22Commitments = make([]kzg.Digest, len(commitmentInfo)) + for i := range commitmentInfo { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(commitmentInfo[i].HintID, bsb22ComputeCommitmentHint(spr, pk, proof, cCommitments, &commitmentVal[i], i))) } @@ -184,8 +186,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) - for i := range spr.CommitmentInfo { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[i].CommitmentIndex] = commitmentVal[i] + for i := range commitmentInfo { + qkCompletedCanonical[spr.GetNbPublicVariables()+commitmentInfo[i].CommitmentIndex] = commitmentVal[i] } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -292,8 +294,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ic.Add(&ic, &tmp) tmp.Mul(&fqo, &o) ic.Add(&ic, &tmp).Add(&ic, &fqk) - nbComms := len(spr.CommitmentInfo) - for i := range spr.CommitmentInfo { + nbComms := len(commitmentInfo) + for i := range commitmentInfo { tmp.Mul(&pi2QcPrime[i], &pi2QcPrime[i+nbComms]) ic.Add(&ic, &tmp) } @@ -405,7 +407,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // compute evaluations of (blinded version of) l, r, o, z, qCPrime at zeta var blzeta, brzeta, bozeta fr.Element - qcpzeta := make([]fr.Element, len(spr.CommitmentInfo)) + qcpzeta := make([]fr.Element, len(commitmentInfo)) var wgEvals sync.WaitGroup wgEvals.Add(3) @@ -422,7 +424,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qcpzeta[i] = pk.trace.Qcp[i].Evaluate(zeta) } } - utils.Parallelize(len(spr.CommitmentInfo), evalQcpAtZeta) + utils.Parallelize(len(commitmentInfo), evalQcpAtZeta) var zetaShifted fr.Element zetaShifted.Mul(&zeta, &pk.Vk.Generator) diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index 1302571166..f0aefd8945 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -18,6 +18,7 @@ package plonk import ( "crypto/sha256" + "github.com/consensys/gnark/constraint" "math/big" "runtime" "sync" @@ -66,16 +67,17 @@ type Proof struct { // Computing and verifying Bsb22 multi-commits explained in https://hackmd.io/x8KsadW3RRyX7YTCFJIkHg func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, cCommitments []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { + commitmentInfo := spr.CommitmentInfo.(constraint.PlonkCommitments)[commDepth] committedValues := make([]fr.Element, pk.Domain[0].Cardinality) offset := spr.GetNbPublicVariables() for i := range ins { - committedValues[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) + committedValues[offset+commitmentInfo.Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - if _, err = committedValues[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + if _, err = committedValues[offset+commitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } if _, err = committedValues[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding @@ -116,11 +118,12 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // result proof := &Proof{} - commitmentVal := make([]fr.Element, len(spr.CommitmentInfo)) // TODO @Tabaie get rid of this - cCommitments := make([]*iop.Polynomial, len(spr.CommitmentInfo)) - proof.Bsb22Commitments = make([]kzg.Digest, len(spr.CommitmentInfo)) - for i := range spr.CommitmentInfo { - opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[i].HintID, + commitmentInfo := spr.CommitmentInfo.(constraint.PlonkCommitments) + commitmentVal := make([]fr.Element, len(commitmentInfo)) // TODO @Tabaie get rid of this + cCommitments := make([]*iop.Polynomial, len(commitmentInfo)) + proof.Bsb22Commitments = make([]kzg.Digest, len(commitmentInfo)) + for i := range commitmentInfo { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(commitmentInfo[i].HintID, bsb22ComputeCommitmentHint(spr, pk, proof, cCommitments, &commitmentVal[i], i))) } @@ -184,8 +187,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) - for i := range spr.CommitmentInfo { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[i].CommitmentIndex] = commitmentVal[i] + for i := range commitmentInfo { + qkCompletedCanonical[spr.GetNbPublicVariables()+commitmentInfo[i].CommitmentIndex] = commitmentVal[i] } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -292,8 +295,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ic.Add(&ic, &tmp) tmp.Mul(&fqo, &o) ic.Add(&ic, &tmp).Add(&ic, &fqk) - nbComms := len(spr.CommitmentInfo) - for i := range spr.CommitmentInfo { + nbComms := len(commitmentInfo) + for i := range commitmentInfo { tmp.Mul(&pi2QcPrime[i], &pi2QcPrime[i+nbComms]) ic.Add(&ic, &tmp) } @@ -405,7 +408,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // compute evaluations of (blinded version of) l, r, o, z, qCPrime at zeta var blzeta, brzeta, bozeta fr.Element - qcpzeta := make([]fr.Element, len(spr.CommitmentInfo)) + qcpzeta := make([]fr.Element, len(commitmentInfo)) var wgEvals sync.WaitGroup wgEvals.Add(3) @@ -422,7 +425,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qcpzeta[i] = pk.trace.Qcp[i].Evaluate(zeta) } } - utils.Parallelize(len(spr.CommitmentInfo), evalQcpAtZeta) + utils.Parallelize(len(commitmentInfo), evalQcpAtZeta) var zetaShifted fr.Element zetaShifted.Mul(&zeta, &pk.Vk.Generator) diff --git a/backend/plonk/bw6-633/prove.go b/backend/plonk/bw6-633/prove.go index ac9cf966e2..7cf5766fb7 100644 --- a/backend/plonk/bw6-633/prove.go +++ b/backend/plonk/bw6-633/prove.go @@ -66,16 +66,17 @@ type Proof struct { // Computing and verifying Bsb22 multi-commits explained in https://hackmd.io/x8KsadW3RRyX7YTCFJIkHg func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, cCommitments []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { + commitmentInfo := spr.CommitmentInfo.(constraint.PlonkCommitments)[commDepth] committedValues := make([]fr.Element, pk.Domain[0].Cardinality) offset := spr.GetNbPublicVariables() for i := range ins { - committedValues[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) + committedValues[offset+commitmentInfo.Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - if _, err = committedValues[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + if _, err = committedValues[offset+commitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } if _, err = committedValues[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding @@ -116,11 +117,12 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // result proof := &Proof{} - commitmentVal := make([]fr.Element, len(spr.CommitmentInfo)) // TODO @Tabaie get rid of this - cCommitments := make([]*iop.Polynomial, len(spr.CommitmentInfo)) - proof.Bsb22Commitments = make([]kzg.Digest, len(spr.CommitmentInfo)) - for i := range spr.CommitmentInfo { - opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[i].HintID, + commitmentInfo := spr.CommitmentInfo.(constraint.PlonkCommitments) + commitmentVal := make([]fr.Element, len(commitmentInfo)) // TODO @Tabaie get rid of this + cCommitments := make([]*iop.Polynomial, len(commitmentInfo)) + proof.Bsb22Commitments = make([]kzg.Digest, len(commitmentInfo)) + for i := range commitmentInfo { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(commitmentInfo[i].HintID, bsb22ComputeCommitmentHint(spr, pk, proof, cCommitments, &commitmentVal[i], i))) } @@ -184,8 +186,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) - for i := range spr.CommitmentInfo { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[i].CommitmentIndex] = commitmentVal[i] + for i := range commitmentInfo { + qkCompletedCanonical[spr.GetNbPublicVariables()+commitmentInfo[i].CommitmentIndex] = commitmentVal[i] } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -292,8 +294,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ic.Add(&ic, &tmp) tmp.Mul(&fqo, &o) ic.Add(&ic, &tmp).Add(&ic, &fqk) - nbComms := len(spr.CommitmentInfo) - for i := range spr.CommitmentInfo { + nbComms := len(commitmentInfo) + for i := range commitmentInfo { tmp.Mul(&pi2QcPrime[i], &pi2QcPrime[i+nbComms]) ic.Add(&ic, &tmp) } @@ -405,7 +407,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // compute evaluations of (blinded version of) l, r, o, z, qCPrime at zeta var blzeta, brzeta, bozeta fr.Element - qcpzeta := make([]fr.Element, len(spr.CommitmentInfo)) + qcpzeta := make([]fr.Element, len(commitmentInfo)) var wgEvals sync.WaitGroup wgEvals.Add(3) @@ -422,7 +424,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qcpzeta[i] = pk.trace.Qcp[i].Evaluate(zeta) } } - utils.Parallelize(len(spr.CommitmentInfo), evalQcpAtZeta) + utils.Parallelize(len(commitmentInfo), evalQcpAtZeta) var zetaShifted fr.Element zetaShifted.Mul(&zeta, &pk.Vk.Generator) diff --git a/backend/plonk/bw6-761/prove.go b/backend/plonk/bw6-761/prove.go index 340a301ea5..195a630b9a 100644 --- a/backend/plonk/bw6-761/prove.go +++ b/backend/plonk/bw6-761/prove.go @@ -66,16 +66,17 @@ type Proof struct { // Computing and verifying Bsb22 multi-commits explained in https://hackmd.io/x8KsadW3RRyX7YTCFJIkHg func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, cCommitments []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { + commitmentInfo := spr.CommitmentInfo.(constraint.PlonkCommitments)[commDepth] committedValues := make([]fr.Element, pk.Domain[0].Cardinality) offset := spr.GetNbPublicVariables() for i := range ins { - committedValues[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) + committedValues[offset+commitmentInfo.Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - if _, err = committedValues[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + if _, err = committedValues[offset+commitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } if _, err = committedValues[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding @@ -116,11 +117,12 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // result proof := &Proof{} - commitmentVal := make([]fr.Element, len(spr.CommitmentInfo)) // TODO @Tabaie get rid of this - cCommitments := make([]*iop.Polynomial, len(spr.CommitmentInfo)) - proof.Bsb22Commitments = make([]kzg.Digest, len(spr.CommitmentInfo)) - for i := range spr.CommitmentInfo { - opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[i].HintID, + commitmentInfo := spr.CommitmentInfo.(constraint.PlonkCommitments) + commitmentVal := make([]fr.Element, len(commitmentInfo)) // TODO @Tabaie get rid of this + cCommitments := make([]*iop.Polynomial, len(commitmentInfo)) + proof.Bsb22Commitments = make([]kzg.Digest, len(commitmentInfo)) + for i := range commitmentInfo { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(commitmentInfo[i].HintID, bsb22ComputeCommitmentHint(spr, pk, proof, cCommitments, &commitmentVal[i], i))) } @@ -184,8 +186,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) - for i := range spr.CommitmentInfo { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[i].CommitmentIndex] = commitmentVal[i] + for i := range commitmentInfo { + qkCompletedCanonical[spr.GetNbPublicVariables()+commitmentInfo[i].CommitmentIndex] = commitmentVal[i] } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -292,8 +294,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ic.Add(&ic, &tmp) tmp.Mul(&fqo, &o) ic.Add(&ic, &tmp).Add(&ic, &fqk) - nbComms := len(spr.CommitmentInfo) - for i := range spr.CommitmentInfo { + nbComms := len(commitmentInfo) + for i := range commitmentInfo { tmp.Mul(&pi2QcPrime[i], &pi2QcPrime[i+nbComms]) ic.Add(&ic, &tmp) } @@ -405,7 +407,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // compute evaluations of (blinded version of) l, r, o, z, qCPrime at zeta var blzeta, brzeta, bozeta fr.Element - qcpzeta := make([]fr.Element, len(spr.CommitmentInfo)) + qcpzeta := make([]fr.Element, len(commitmentInfo)) var wgEvals sync.WaitGroup wgEvals.Add(3) @@ -422,7 +424,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qcpzeta[i] = pk.trace.Qcp[i].Evaluate(zeta) } } - utils.Parallelize(len(spr.CommitmentInfo), evalQcpAtZeta) + utils.Parallelize(len(commitmentInfo), evalQcpAtZeta) var zetaShifted fr.Element zetaShifted.Mul(&zeta, &pk.Vk.Generator) diff --git a/frontend/cs/scs/api.go b/frontend/cs/scs/api.go index 20d5740c94..12eff1e730 100644 --- a/frontend/cs/scs/api.go +++ b/frontend/cs/scs/api.go @@ -571,6 +571,7 @@ func (builder *builder) Compiler() frontend.Compiler { func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error) { + commitments := builder.cs.GetCommitments().(constraint.PlonkCommitments) v = filterConstants(v) // TODO: @Tabaie Settle on a way to represent even constants; conventional hash? committed := make([]int, len(v)) @@ -583,7 +584,7 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error builder.addPlonkConstraint(sparseR1C{xa: vINeg.VID, qL: vINeg.Coeff, commitment: constraint.COMMITTED}) } - hintId, err := cs.RegisterBsb22CommitmentComputePlaceholder(len(builder.cs.GetCommitments())) + hintId, err := cs.RegisterBsb22CommitmentComputePlaceholder(len(commitments)) if err != nil { return nil, err } @@ -598,7 +599,7 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error // RHS will be provided by both prover and verifier independently, as for a public wire builder.addPlonkConstraint(sparseR1C{xa: commitmentVar.VID, qL: commitmentVar.Coeff, commitment: constraint.COMMITMENT}) // value will be injected later - return outs[0], builder.cs.AddCommitment(constraint.Commitment{ + return outs[0], builder.cs.AddCommitment(constraint.PlonkCommitment{ HintID: hintId, CommitmentIndex: commitmentConstraintIndex, Committed: committed, diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl index d2034c03ea..33bd764fb8 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl @@ -44,16 +44,17 @@ type Proof struct { // Computing and verifying Bsb22 multi-commits explained in https://hackmd.io/x8KsadW3RRyX7YTCFJIkHg func bsb22ComputeCommitmentHint(spr *cs.SparseR1CS, pk *ProvingKey, proof *Proof, cCommitments []*iop.Polynomial, res *fr.Element, commDepth int) solver.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { + commitmentInfo := spr.CommitmentInfo.(constraint.PlonkCommitments)[commDepth] committedValues := make([]fr.Element, pk.Domain[0].Cardinality) offset := spr.GetNbPublicVariables() for i := range ins { - committedValues[offset+spr.CommitmentInfo[commDepth].Committed[i]].SetBigInt(ins[i]) + committedValues[offset+commitmentInfo.Committed[i]].SetBigInt(ins[i]) } var ( err error hashRes []fr.Element ) - if _, err = committedValues[offset+spr.CommitmentInfo[commDepth].CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. + if _, err = committedValues[offset+commitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } if _, err = committedValues[offset+spr.GetNbConstraints()-1].SetRandom(); err != nil { // Last constraint has qcp = 0. Safe to use for blinding @@ -94,11 +95,12 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // result proof := &Proof{} - commitmentVal := make([]fr.Element, len(spr.CommitmentInfo)) // TODO @Tabaie get rid of this - cCommitments := make([]*iop.Polynomial, len(spr.CommitmentInfo)) - proof.Bsb22Commitments = make([]kzg.Digest, len(spr.CommitmentInfo)) - for i := range spr.CommitmentInfo { - opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(spr.CommitmentInfo[i].HintID, + commitmentInfo := spr.CommitmentInfo.(constraint.PlonkCommitments) + commitmentVal := make([]fr.Element, len(commitmentInfo)) // TODO @Tabaie get rid of this + cCommitments := make([]*iop.Polynomial, len(commitmentInfo)) + proof.Bsb22Commitments = make([]kzg.Digest, len(commitmentInfo)) + for i := range commitmentInfo { + opt.SolverOpts = append(opt.SolverOpts, solver.OverrideHint(commitmentInfo[i].HintID, bsb22ComputeCommitmentHint(spr, pk, proof, cCommitments, &commitmentVal[i], i))) } @@ -162,8 +164,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qkCompletedCanonical := make([]fr.Element, len(lqkcoef)) copy(qkCompletedCanonical, fw[:len(spr.Public)]) copy(qkCompletedCanonical[len(spr.Public):], lqkcoef[len(spr.Public):]) - for i := range spr.CommitmentInfo { - qkCompletedCanonical[spr.GetNbPublicVariables()+spr.CommitmentInfo[i].CommitmentIndex] = commitmentVal[i] + for i := range commitmentInfo { + qkCompletedCanonical[spr.GetNbPublicVariables()+commitmentInfo[i].CommitmentIndex] = commitmentVal[i] } pk.Domain[0].FFTInverse(qkCompletedCanonical, fft.DIF) fft.BitReverse(qkCompletedCanonical) @@ -270,8 +272,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ic.Add(&ic, &tmp) tmp.Mul(&fqo, &o) ic.Add(&ic, &tmp).Add(&ic, &fqk) - nbComms := len(spr.CommitmentInfo) - for i := range spr.CommitmentInfo { + nbComms := len(commitmentInfo) + for i := range commitmentInfo { tmp.Mul(&pi2QcPrime[i], &pi2QcPrime[i+nbComms]) ic.Add(&ic, &tmp) } @@ -383,7 +385,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // compute evaluations of (blinded version of) l, r, o, z, qCPrime at zeta var blzeta, brzeta, bozeta fr.Element - qcpzeta := make([]fr.Element, len(spr.CommitmentInfo)) + qcpzeta := make([]fr.Element, len(commitmentInfo)) var wgEvals sync.WaitGroup wgEvals.Add(3) @@ -400,7 +402,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts qcpzeta[i] = pk.trace.Qcp[i].Evaluate(zeta) } } - utils.Parallelize(len(spr.CommitmentInfo), evalQcpAtZeta) + utils.Parallelize(len(commitmentInfo), evalQcpAtZeta) var zetaShifted fr.Element zetaShifted.Mul(&zeta, &pk.Vk.Generator) From 9945618bc141904e48a6828271efc203b42d0dd4 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 8 Jun 2023 13:00:16 -0500 Subject: [PATCH 438/464] refactor: reflect commitmentInfo changes in plonk --- backend/groth16/bls12-377/prove.go | 2 +- backend/groth16/bls12-377/setup.go | 2 +- backend/groth16/bls12-381/prove.go | 2 +- backend/groth16/bls12-381/setup.go | 2 +- backend/groth16/bls24-315/prove.go | 2 +- backend/groth16/bls24-315/setup.go | 2 +- backend/groth16/bls24-317/prove.go | 2 +- backend/groth16/bls24-317/setup.go | 2 +- backend/groth16/bn254/prove.go | 2 +- backend/groth16/bn254/setup.go | 2 +- backend/groth16/bn254/utils_test.go | 13 +++++- backend/groth16/bw6-633/prove.go | 2 +- backend/groth16/bw6-633/setup.go | 2 +- backend/groth16/bw6-761/prove.go | 2 +- backend/groth16/bw6-761/setup.go | 2 +- backend/plonk/bls12-377/prove.go | 1 + backend/plonk/bls12-377/setup.go | 11 ++--- backend/plonk/bls12-381/prove.go | 1 + backend/plonk/bls12-381/setup.go | 11 ++--- backend/plonk/bls24-315/prove.go | 1 + backend/plonk/bls24-315/setup.go | 11 ++--- backend/plonk/bls24-317/prove.go | 1 + backend/plonk/bls24-317/setup.go | 11 ++--- backend/plonk/bn254/prove.go | 2 +- backend/plonk/bn254/setup.go | 11 ++--- backend/plonk/bw6-633/prove.go | 1 + backend/plonk/bw6-633/setup.go | 11 ++--- backend/plonk/bw6-761/prove.go | 1 + backend/plonk/bw6-761/setup.go | 11 ++--- constraint/commitment.go | 41 +++++++++++-------- frontend/cs/r1cs/api.go | 2 +- .../zkpschemes/groth16/groth16.prove.go.tmpl | 2 +- .../zkpschemes/groth16/groth16.setup.go.tmpl | 2 +- .../zkpschemes/plonk/plonk.prove.go.tmpl | 1 + .../zkpschemes/plonk/plonk.setup.go.tmpl | 11 ++--- 35 files changed, 109 insertions(+), 76 deletions(-) diff --git a/backend/groth16/bls12-377/prove.go b/backend/groth16/bls12-377/prove.go index ece6c2ad87..7f52932504 100644 --- a/backend/groth16/bls12-377/prove.go +++ b/backend/groth16/bls12-377/prove.go @@ -216,7 +216,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed // TODO Perf @Tabaie worst memory allocation offender toRemove := commitmentInfo.GetPrivateCommitted() - toRemove = append(toRemove, commitmentInfo.CommitmentWireIndexes()) + toRemove = append(toRemove, commitmentInfo.CommitmentIndexes()) _wireValues := filterHeap(wireValues[r1cs.GetNbPublicVariables():], r1cs.GetNbPublicVariables(), internal.ConcatAll(toRemove...)) if _, err := krs.MultiExp(pk.G1.K, _wireValues, ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index dd997f4872..2dc7ebd6f2 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -97,7 +97,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) - commitmentWires := commitmentInfo.CommitmentWireIndexes() + commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) //nbPrivateCommittedWires, privateCommitted, publicAndCommitmentCommitted := diff --git a/backend/groth16/bls12-381/prove.go b/backend/groth16/bls12-381/prove.go index fb9aaa9cc9..23ab3529dc 100644 --- a/backend/groth16/bls12-381/prove.go +++ b/backend/groth16/bls12-381/prove.go @@ -216,7 +216,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed // TODO Perf @Tabaie worst memory allocation offender toRemove := commitmentInfo.GetPrivateCommitted() - toRemove = append(toRemove, commitmentInfo.CommitmentWireIndexes()) + toRemove = append(toRemove, commitmentInfo.CommitmentIndexes()) _wireValues := filterHeap(wireValues[r1cs.GetNbPublicVariables():], r1cs.GetNbPublicVariables(), internal.ConcatAll(toRemove...)) if _, err := krs.MultiExp(pk.G1.K, _wireValues, ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index 7444927202..8f84a68e0f 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -97,7 +97,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) - commitmentWires := commitmentInfo.CommitmentWireIndexes() + commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) //nbPrivateCommittedWires, privateCommitted, publicAndCommitmentCommitted := diff --git a/backend/groth16/bls24-315/prove.go b/backend/groth16/bls24-315/prove.go index ce413bbb7c..0b0774af00 100644 --- a/backend/groth16/bls24-315/prove.go +++ b/backend/groth16/bls24-315/prove.go @@ -216,7 +216,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed // TODO Perf @Tabaie worst memory allocation offender toRemove := commitmentInfo.GetPrivateCommitted() - toRemove = append(toRemove, commitmentInfo.CommitmentWireIndexes()) + toRemove = append(toRemove, commitmentInfo.CommitmentIndexes()) _wireValues := filterHeap(wireValues[r1cs.GetNbPublicVariables():], r1cs.GetNbPublicVariables(), internal.ConcatAll(toRemove...)) if _, err := krs.MultiExp(pk.G1.K, _wireValues, ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index 1612db16a6..d1f06ec9f7 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -97,7 +97,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) - commitmentWires := commitmentInfo.CommitmentWireIndexes() + commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) //nbPrivateCommittedWires, privateCommitted, publicAndCommitmentCommitted := diff --git a/backend/groth16/bls24-317/prove.go b/backend/groth16/bls24-317/prove.go index 5530f7f150..72f08ac910 100644 --- a/backend/groth16/bls24-317/prove.go +++ b/backend/groth16/bls24-317/prove.go @@ -216,7 +216,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed // TODO Perf @Tabaie worst memory allocation offender toRemove := commitmentInfo.GetPrivateCommitted() - toRemove = append(toRemove, commitmentInfo.CommitmentWireIndexes()) + toRemove = append(toRemove, commitmentInfo.CommitmentIndexes()) _wireValues := filterHeap(wireValues[r1cs.GetNbPublicVariables():], r1cs.GetNbPublicVariables(), internal.ConcatAll(toRemove...)) if _, err := krs.MultiExp(pk.G1.K, _wireValues, ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index cbeef07ad9..9337073af5 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -97,7 +97,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) - commitmentWires := commitmentInfo.CommitmentWireIndexes() + commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) //nbPrivateCommittedWires, privateCommitted, publicAndCommitmentCommitted := diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index eda6dcad4d..75eb17e895 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -216,7 +216,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed // TODO Perf @Tabaie worst memory allocation offender toRemove := commitmentInfo.GetPrivateCommitted() - toRemove = append(toRemove, commitmentInfo.CommitmentWireIndexes()) + toRemove = append(toRemove, commitmentInfo.CommitmentIndexes()) _wireValues := filterHeap(wireValues[r1cs.GetNbPublicVariables():], r1cs.GetNbPublicVariables(), internal.ConcatAll(toRemove...)) if _, err := krs.MultiExp(pk.G1.K, _wireValues, ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index 2811c4580b..347898905c 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -97,7 +97,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) - commitmentWires := commitmentInfo.CommitmentWireIndexes() + commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) //nbPrivateCommittedWires, privateCommitted, publicAndCommitmentCommitted := diff --git a/backend/groth16/bn254/utils_test.go b/backend/groth16/bn254/utils_test.go index 65d22f6b2d..a5bc2a5770 100644 --- a/backend/groth16/bn254/utils_test.go +++ b/backend/groth16/bn254/utils_test.go @@ -16,14 +16,23 @@ func assertSliceEquals[T any](t *testing.T, expected []T, seen []T) { func TestFilterHeap(t *testing.T) { elems := []fr.Element{{0}, {1}, {2}, {3}} - r := filterHeap(elems, []int{1, 2}) + + r := filterHeap(elems, 0, []int{1, 2}) expected := []fr.Element{{0}, {3}} assertSliceEquals(t, expected, r) + + r = filterHeap(elems[1:], 1, []int{1, 2}) + expected = []fr.Element{{3}} + assertSliceEquals(t, expected, r) } func TestFilterRepeated(t *testing.T) { elems := []fr.Element{{0}, {1}, {2}, {3}} - r := filterHeap(elems, []int{1, 1, 2}) + r := filterHeap(elems, 0, []int{1, 1, 2}) expected := []fr.Element{{0}, {3}} assertSliceEquals(t, expected, r) + + r = filterHeap(elems[1:], 1, []int{1, 1, 2}) + expected = []fr.Element{{3}} + assertSliceEquals(t, expected, r) } diff --git a/backend/groth16/bw6-633/prove.go b/backend/groth16/bw6-633/prove.go index 75c8f233ae..41002c3f48 100644 --- a/backend/groth16/bw6-633/prove.go +++ b/backend/groth16/bw6-633/prove.go @@ -216,7 +216,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed // TODO Perf @Tabaie worst memory allocation offender toRemove := commitmentInfo.GetPrivateCommitted() - toRemove = append(toRemove, commitmentInfo.CommitmentWireIndexes()) + toRemove = append(toRemove, commitmentInfo.CommitmentIndexes()) _wireValues := filterHeap(wireValues[r1cs.GetNbPublicVariables():], r1cs.GetNbPublicVariables(), internal.ConcatAll(toRemove...)) if _, err := krs.MultiExp(pk.G1.K, _wireValues, ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index b3a7c1e04e..7804aa2d4b 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -97,7 +97,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) - commitmentWires := commitmentInfo.CommitmentWireIndexes() + commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) //nbPrivateCommittedWires, privateCommitted, publicAndCommitmentCommitted := diff --git a/backend/groth16/bw6-761/prove.go b/backend/groth16/bw6-761/prove.go index 143fa69356..7234bf7d15 100644 --- a/backend/groth16/bw6-761/prove.go +++ b/backend/groth16/bw6-761/prove.go @@ -216,7 +216,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed // TODO Perf @Tabaie worst memory allocation offender toRemove := commitmentInfo.GetPrivateCommitted() - toRemove = append(toRemove, commitmentInfo.CommitmentWireIndexes()) + toRemove = append(toRemove, commitmentInfo.CommitmentIndexes()) _wireValues := filterHeap(wireValues[r1cs.GetNbPublicVariables():], r1cs.GetNbPublicVariables(), internal.ConcatAll(toRemove...)) if _, err := krs.MultiExp(pk.G1.K, _wireValues, ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index e27c97a88d..c52a947721 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -97,7 +97,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) - commitmentWires := commitmentInfo.CommitmentWireIndexes() + commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) //nbPrivateCommittedWires, privateCommitted, publicAndCommitmentCommitted := diff --git a/backend/plonk/bls12-377/prove.go b/backend/plonk/bls12-377/prove.go index 3bf15a3412..43e999fd87 100644 --- a/backend/plonk/bls12-377/prove.go +++ b/backend/plonk/bls12-377/prove.go @@ -38,6 +38,7 @@ import ( "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" diff --git a/backend/plonk/bls12-377/setup.go b/backend/plonk/bls12-377/setup.go index 216b147d59..20d21a0d29 100644 --- a/backend/plonk/bls12-377/setup.go +++ b/backend/plonk/bls12-377/setup.go @@ -24,6 +24,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/iop" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/kzg" "github.com/consensys/gnark/backend/plonk/internal" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls12-377" ) @@ -125,8 +126,7 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - vk.CommitmentConstraintIndexes = internal.IntSliceToUint64Slice(spr.CommitmentInfo.CommitmentWireIndexes()) - // nbConstraints := len(spr.Constraints) + vk.CommitmentConstraintIndexes = internal.IntSliceToUint64Slice(spr.CommitmentInfo.CommitmentIndexes()) // step 0: set the fft domains pk.initDomains(spr) @@ -226,13 +226,14 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { nbConstraints := spr.GetNbConstraints() sizeSystem := uint64(nbConstraints + len(spr.Public)) size := ecc.NextPowerOfTwo(sizeSystem) + commitmentInfo := spr.CommitmentInfo.(constraint.PlonkCommitments) ql := make([]fr.Element, size) qr := make([]fr.Element, size) qm := make([]fr.Element, size) qo := make([]fr.Element, size) qk := make([]fr.Element, size) - qcp := make([][]fr.Element, len(spr.CommitmentInfo)) + qcp := make([][]fr.Element, len(commitmentInfo)) for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent ql[i].SetOne().Neg(&ql[i]) @@ -263,9 +264,9 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { pt.Qk = iop.NewPolynomial(&qk, lagReg) pt.Qcp = make([]*iop.Polynomial, len(qcp)) - for i := range spr.CommitmentInfo { + for i := range commitmentInfo { qcp[i] = make([]fr.Element, size) - for _, committed := range spr.CommitmentInfo[i].Committed { + for _, committed := range commitmentInfo[i].Committed { qcp[i][offset+committed].SetOne() } pt.Qcp[i] = iop.NewPolynomial(&qcp[i], lagReg) diff --git a/backend/plonk/bls12-381/prove.go b/backend/plonk/bls12-381/prove.go index d6c319429b..4397656393 100644 --- a/backend/plonk/bls12-381/prove.go +++ b/backend/plonk/bls12-381/prove.go @@ -38,6 +38,7 @@ import ( "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" diff --git a/backend/plonk/bls12-381/setup.go b/backend/plonk/bls12-381/setup.go index ed653a9aa9..b3f00a335b 100644 --- a/backend/plonk/bls12-381/setup.go +++ b/backend/plonk/bls12-381/setup.go @@ -24,6 +24,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/iop" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/kzg" "github.com/consensys/gnark/backend/plonk/internal" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls12-381" ) @@ -125,8 +126,7 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - vk.CommitmentConstraintIndexes = internal.IntSliceToUint64Slice(spr.CommitmentInfo.CommitmentWireIndexes()) - // nbConstraints := len(spr.Constraints) + vk.CommitmentConstraintIndexes = internal.IntSliceToUint64Slice(spr.CommitmentInfo.CommitmentIndexes()) // step 0: set the fft domains pk.initDomains(spr) @@ -226,13 +226,14 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { nbConstraints := spr.GetNbConstraints() sizeSystem := uint64(nbConstraints + len(spr.Public)) size := ecc.NextPowerOfTwo(sizeSystem) + commitmentInfo := spr.CommitmentInfo.(constraint.PlonkCommitments) ql := make([]fr.Element, size) qr := make([]fr.Element, size) qm := make([]fr.Element, size) qo := make([]fr.Element, size) qk := make([]fr.Element, size) - qcp := make([][]fr.Element, len(spr.CommitmentInfo)) + qcp := make([][]fr.Element, len(commitmentInfo)) for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent ql[i].SetOne().Neg(&ql[i]) @@ -263,9 +264,9 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { pt.Qk = iop.NewPolynomial(&qk, lagReg) pt.Qcp = make([]*iop.Polynomial, len(qcp)) - for i := range spr.CommitmentInfo { + for i := range commitmentInfo { qcp[i] = make([]fr.Element, size) - for _, committed := range spr.CommitmentInfo[i].Committed { + for _, committed := range commitmentInfo[i].Committed { qcp[i][offset+committed].SetOne() } pt.Qcp[i] = iop.NewPolynomial(&qcp[i], lagReg) diff --git a/backend/plonk/bls24-315/prove.go b/backend/plonk/bls24-315/prove.go index 5100785527..777bd2b8e1 100644 --- a/backend/plonk/bls24-315/prove.go +++ b/backend/plonk/bls24-315/prove.go @@ -38,6 +38,7 @@ import ( "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" diff --git a/backend/plonk/bls24-315/setup.go b/backend/plonk/bls24-315/setup.go index 90c521ac37..41fd1ee0a3 100644 --- a/backend/plonk/bls24-315/setup.go +++ b/backend/plonk/bls24-315/setup.go @@ -24,6 +24,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/iop" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/kzg" "github.com/consensys/gnark/backend/plonk/internal" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls24-315" ) @@ -125,8 +126,7 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - vk.CommitmentConstraintIndexes = internal.IntSliceToUint64Slice(spr.CommitmentInfo.CommitmentWireIndexes()) - // nbConstraints := len(spr.Constraints) + vk.CommitmentConstraintIndexes = internal.IntSliceToUint64Slice(spr.CommitmentInfo.CommitmentIndexes()) // step 0: set the fft domains pk.initDomains(spr) @@ -226,13 +226,14 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { nbConstraints := spr.GetNbConstraints() sizeSystem := uint64(nbConstraints + len(spr.Public)) size := ecc.NextPowerOfTwo(sizeSystem) + commitmentInfo := spr.CommitmentInfo.(constraint.PlonkCommitments) ql := make([]fr.Element, size) qr := make([]fr.Element, size) qm := make([]fr.Element, size) qo := make([]fr.Element, size) qk := make([]fr.Element, size) - qcp := make([][]fr.Element, len(spr.CommitmentInfo)) + qcp := make([][]fr.Element, len(commitmentInfo)) for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent ql[i].SetOne().Neg(&ql[i]) @@ -263,9 +264,9 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { pt.Qk = iop.NewPolynomial(&qk, lagReg) pt.Qcp = make([]*iop.Polynomial, len(qcp)) - for i := range spr.CommitmentInfo { + for i := range commitmentInfo { qcp[i] = make([]fr.Element, size) - for _, committed := range spr.CommitmentInfo[i].Committed { + for _, committed := range commitmentInfo[i].Committed { qcp[i][offset+committed].SetOne() } pt.Qcp[i] = iop.NewPolynomial(&qcp[i], lagReg) diff --git a/backend/plonk/bls24-317/prove.go b/backend/plonk/bls24-317/prove.go index f4992a6863..ae3d6a28dd 100644 --- a/backend/plonk/bls24-317/prove.go +++ b/backend/plonk/bls24-317/prove.go @@ -38,6 +38,7 @@ import ( "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" diff --git a/backend/plonk/bls24-317/setup.go b/backend/plonk/bls24-317/setup.go index 0f7cd1a6c0..de56d191cd 100644 --- a/backend/plonk/bls24-317/setup.go +++ b/backend/plonk/bls24-317/setup.go @@ -24,6 +24,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/iop" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/kzg" "github.com/consensys/gnark/backend/plonk/internal" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bls24-317" ) @@ -125,8 +126,7 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - vk.CommitmentConstraintIndexes = internal.IntSliceToUint64Slice(spr.CommitmentInfo.CommitmentWireIndexes()) - // nbConstraints := len(spr.Constraints) + vk.CommitmentConstraintIndexes = internal.IntSliceToUint64Slice(spr.CommitmentInfo.CommitmentIndexes()) // step 0: set the fft domains pk.initDomains(spr) @@ -226,13 +226,14 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { nbConstraints := spr.GetNbConstraints() sizeSystem := uint64(nbConstraints + len(spr.Public)) size := ecc.NextPowerOfTwo(sizeSystem) + commitmentInfo := spr.CommitmentInfo.(constraint.PlonkCommitments) ql := make([]fr.Element, size) qr := make([]fr.Element, size) qm := make([]fr.Element, size) qo := make([]fr.Element, size) qk := make([]fr.Element, size) - qcp := make([][]fr.Element, len(spr.CommitmentInfo)) + qcp := make([][]fr.Element, len(commitmentInfo)) for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent ql[i].SetOne().Neg(&ql[i]) @@ -263,9 +264,9 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { pt.Qk = iop.NewPolynomial(&qk, lagReg) pt.Qcp = make([]*iop.Polynomial, len(qcp)) - for i := range spr.CommitmentInfo { + for i := range commitmentInfo { qcp[i] = make([]fr.Element, size) - for _, committed := range spr.CommitmentInfo[i].Committed { + for _, committed := range commitmentInfo[i].Committed { qcp[i][offset+committed].SetOne() } pt.Qcp[i] = iop.NewPolynomial(&qcp[i], lagReg) diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index f0aefd8945..70baf95687 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -18,7 +18,6 @@ package plonk import ( "crypto/sha256" - "github.com/consensys/gnark/constraint" "math/big" "runtime" "sync" @@ -39,6 +38,7 @@ import ( "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" diff --git a/backend/plonk/bn254/setup.go b/backend/plonk/bn254/setup.go index e4db1924a6..a4e65bce21 100644 --- a/backend/plonk/bn254/setup.go +++ b/backend/plonk/bn254/setup.go @@ -24,6 +24,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr/iop" "github.com/consensys/gnark-crypto/ecc/bn254/fr/kzg" "github.com/consensys/gnark/backend/plonk/internal" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bn254" ) @@ -125,8 +126,7 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - vk.CommitmentConstraintIndexes = internal.IntSliceToUint64Slice(spr.CommitmentInfo.CommitmentWireIndexes()) - // nbConstraints := len(spr.Constraints) + vk.CommitmentConstraintIndexes = internal.IntSliceToUint64Slice(spr.CommitmentInfo.CommitmentIndexes()) // step 0: set the fft domains pk.initDomains(spr) @@ -226,13 +226,14 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { nbConstraints := spr.GetNbConstraints() sizeSystem := uint64(nbConstraints + len(spr.Public)) size := ecc.NextPowerOfTwo(sizeSystem) + commitmentInfo := spr.CommitmentInfo.(constraint.PlonkCommitments) ql := make([]fr.Element, size) qr := make([]fr.Element, size) qm := make([]fr.Element, size) qo := make([]fr.Element, size) qk := make([]fr.Element, size) - qcp := make([][]fr.Element, len(spr.CommitmentInfo)) + qcp := make([][]fr.Element, len(commitmentInfo)) for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent ql[i].SetOne().Neg(&ql[i]) @@ -263,9 +264,9 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { pt.Qk = iop.NewPolynomial(&qk, lagReg) pt.Qcp = make([]*iop.Polynomial, len(qcp)) - for i := range spr.CommitmentInfo { + for i := range commitmentInfo { qcp[i] = make([]fr.Element, size) - for _, committed := range spr.CommitmentInfo[i].Committed { + for _, committed := range commitmentInfo[i].Committed { qcp[i][offset+committed].SetOne() } pt.Qcp[i] = iop.NewPolynomial(&qcp[i], lagReg) diff --git a/backend/plonk/bw6-633/prove.go b/backend/plonk/bw6-633/prove.go index 7cf5766fb7..f5ffbaba57 100644 --- a/backend/plonk/bw6-633/prove.go +++ b/backend/plonk/bw6-633/prove.go @@ -38,6 +38,7 @@ import ( "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" diff --git a/backend/plonk/bw6-633/setup.go b/backend/plonk/bw6-633/setup.go index db87a4f4a0..9848de6fa7 100644 --- a/backend/plonk/bw6-633/setup.go +++ b/backend/plonk/bw6-633/setup.go @@ -24,6 +24,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/iop" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/kzg" "github.com/consensys/gnark/backend/plonk/internal" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bw6-633" ) @@ -125,8 +126,7 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - vk.CommitmentConstraintIndexes = internal.IntSliceToUint64Slice(spr.CommitmentInfo.CommitmentWireIndexes()) - // nbConstraints := len(spr.Constraints) + vk.CommitmentConstraintIndexes = internal.IntSliceToUint64Slice(spr.CommitmentInfo.CommitmentIndexes()) // step 0: set the fft domains pk.initDomains(spr) @@ -226,13 +226,14 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { nbConstraints := spr.GetNbConstraints() sizeSystem := uint64(nbConstraints + len(spr.Public)) size := ecc.NextPowerOfTwo(sizeSystem) + commitmentInfo := spr.CommitmentInfo.(constraint.PlonkCommitments) ql := make([]fr.Element, size) qr := make([]fr.Element, size) qm := make([]fr.Element, size) qo := make([]fr.Element, size) qk := make([]fr.Element, size) - qcp := make([][]fr.Element, len(spr.CommitmentInfo)) + qcp := make([][]fr.Element, len(commitmentInfo)) for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent ql[i].SetOne().Neg(&ql[i]) @@ -263,9 +264,9 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { pt.Qk = iop.NewPolynomial(&qk, lagReg) pt.Qcp = make([]*iop.Polynomial, len(qcp)) - for i := range spr.CommitmentInfo { + for i := range commitmentInfo { qcp[i] = make([]fr.Element, size) - for _, committed := range spr.CommitmentInfo[i].Committed { + for _, committed := range commitmentInfo[i].Committed { qcp[i][offset+committed].SetOne() } pt.Qcp[i] = iop.NewPolynomial(&qcp[i], lagReg) diff --git a/backend/plonk/bw6-761/prove.go b/backend/plonk/bw6-761/prove.go index 195a630b9a..54a179a33b 100644 --- a/backend/plonk/bw6-761/prove.go +++ b/backend/plonk/bw6-761/prove.go @@ -38,6 +38,7 @@ import ( "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" diff --git a/backend/plonk/bw6-761/setup.go b/backend/plonk/bw6-761/setup.go index 086e6b78db..f15643bf7b 100644 --- a/backend/plonk/bw6-761/setup.go +++ b/backend/plonk/bw6-761/setup.go @@ -24,6 +24,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/iop" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/kzg" "github.com/consensys/gnark/backend/plonk/internal" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/bw6-761" ) @@ -125,8 +126,7 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - vk.CommitmentConstraintIndexes = internal.IntSliceToUint64Slice(spr.CommitmentInfo.CommitmentWireIndexes()) - // nbConstraints := len(spr.Constraints) + vk.CommitmentConstraintIndexes = internal.IntSliceToUint64Slice(spr.CommitmentInfo.CommitmentIndexes()) // step 0: set the fft domains pk.initDomains(spr) @@ -226,13 +226,14 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { nbConstraints := spr.GetNbConstraints() sizeSystem := uint64(nbConstraints + len(spr.Public)) size := ecc.NextPowerOfTwo(sizeSystem) + commitmentInfo := spr.CommitmentInfo.(constraint.PlonkCommitments) ql := make([]fr.Element, size) qr := make([]fr.Element, size) qm := make([]fr.Element, size) qo := make([]fr.Element, size) qk := make([]fr.Element, size) - qcp := make([][]fr.Element, len(spr.CommitmentInfo)) + qcp := make([][]fr.Element, len(commitmentInfo)) for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent ql[i].SetOne().Neg(&ql[i]) @@ -263,9 +264,9 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { pt.Qk = iop.NewPolynomial(&qk, lagReg) pt.Qcp = make([]*iop.Polynomial, len(qcp)) - for i := range spr.CommitmentInfo { + for i := range commitmentInfo { qcp[i] = make([]fr.Element, size) - for _, committed := range spr.CommitmentInfo[i].Committed { + for _, committed := range commitmentInfo[i].Committed { qcp[i][offset+committed].SetOne() } pt.Qcp[i] = iop.NewPolynomial(&qcp[i], lagReg) diff --git a/constraint/commitment.go b/constraint/commitment.go index 1284bd0adc..48d4344c4a 100644 --- a/constraint/commitment.go +++ b/constraint/commitment.go @@ -2,6 +2,7 @@ package constraint import ( "github.com/consensys/gnark/constraint/solver" + "math/big" ) const CommitmentDst = "bsb22-commitment" @@ -21,12 +22,20 @@ type PlonkCommitment struct { } type Commitment interface{} -type Commitments interface{} +type Commitments interface{ CommitmentIndexes() []int } type Groth16Commitments []Groth16Commitment type PlonkCommitments []PlonkCommitment -func (c Groth16Commitments) CommitmentWireIndexes() []int { +func (c Groth16Commitments) CommitmentIndexes() []int { + commitmentWires := make([]int, len(c)) + for i := range c { + commitmentWires[i] = c[i].CommitmentIndex + } + return commitmentWires +} + +func (c PlonkCommitments) CommitmentIndexes() []int { commitmentWires := make([]int, len(c)) for i := range c { commitmentWires[i] = c[i].CommitmentIndex @@ -50,6 +59,20 @@ func (c Groth16Commitments) GetPublicCommitted() [][]int { return res } +func SerializeCommitment(privateCommitment []byte, publicCommitted []*big.Int, fieldByteLen int) []byte { + + res := make([]byte, len(privateCommitment)+len(publicCommitted)*fieldByteLen) + copy(res, privateCommitment) + + offset := len(privateCommitment) + for _, inJ := range publicCommitted { + inJ.FillBytes(res[offset : offset+fieldByteLen]) + offset += fieldByteLen + } + + return res +} + /* func (i *Commitment) NbPublicCommitted() int { return i.NbCommitted() - i.NbPrivateCommitted @@ -69,20 +92,6 @@ func NewCommitment(committed []int, nbPublicCommitted int) Commitment { } } -func SerializeCommitment(privateCommitment []byte, publicCommitted []*big.Int, fieldByteLen int) []byte { - - res := make([]byte, len(privateCommitment)+len(publicCommitted)*fieldByteLen) - copy(res, privateCommitment) - - offset := len(privateCommitment) - for _, inJ := range publicCommitted { - inJ.FillBytes(res[offset : offset+fieldByteLen]) - offset += fieldByteLen - } - - return res -} - // PrivateToPublicGroth16 returns indexes of variables which are private to the constraint system, but public to Groth16. That is, private committed variables and the commitment itself // TODO Perhaps move it elsewhere since it's specific to groth16 func (i *Commitment) PrivateToPublicGroth16() []int { diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index 96dc54cd7a..836b0b4518 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -683,7 +683,7 @@ func lastIs(slice []int, n int) bool { func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error) { commitments := builder.cs.GetCommitments().(constraint.Groth16Commitments) - existingCommitmentIndexes := commitments.CommitmentWireIndexes() + existingCommitmentIndexes := commitments.CommitmentIndexes() privateCommittedSeeker := utils.MultiListSeeker(commitments.GetPrivateCommitted()) // we want to build a sorted slice of committed variables, without duplicates diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl index 5078bbf3a8..760cf22d24 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl @@ -199,7 +199,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b // filter the wire values if needed // TODO Perf @Tabaie worst memory allocation offender toRemove := commitmentInfo.GetPrivateCommitted() - toRemove = append(toRemove, commitmentInfo.CommitmentWireIndexes()) + toRemove = append(toRemove, commitmentInfo.CommitmentIndexes()) _wireValues := filterHeap(wireValues[r1cs.GetNbPublicVariables():], r1cs.GetNbPublicVariables(), internal.ConcatAll(toRemove...)) if _, err := krs.MultiExp(pk.G1.K, _wireValues, ecc.MultiExpConfig{NbTasks: n / 2}); err != nil { diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl index 49c4e55a01..0f4a9fc291 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl @@ -79,7 +79,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) - commitmentWires := commitmentInfo.CommitmentWireIndexes() + commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) //nbPrivateCommittedWires, privateCommitted, publicAndCommitmentCommitted := diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl index 33bd764fb8..a869528cf9 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl @@ -19,6 +19,7 @@ import ( "github.com/consensys/gnark/backend" "github.com/consensys/gnark/logger" "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark/constraint" ) type Proof struct { diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl index 33e4787d3c..0bacab893c 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.setup.go.tmpl @@ -7,6 +7,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/{{toLower .Curve}}/fr/iop" "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/backend/plonk/internal" + "github.com/consensys/gnark/constraint" ) // Trace stores a plonk trace as columns @@ -107,8 +108,7 @@ func Setup(spr *cs.SparseR1CS, kzgSrs kzg.SRS) (*ProvingKey, *VerifyingKey, erro var pk ProvingKey var vk VerifyingKey pk.Vk = &vk - vk.CommitmentConstraintIndexes = internal.IntSliceToUint64Slice(spr.CommitmentInfo.CommitmentWireIndexes()) - // nbConstraints := len(spr.Constraints) + vk.CommitmentConstraintIndexes = internal.IntSliceToUint64Slice(spr.CommitmentInfo.CommitmentIndexes()) // step 0: set the fft domains pk.initDomains(spr) @@ -208,13 +208,14 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { nbConstraints := spr.GetNbConstraints() sizeSystem := uint64(nbConstraints + len(spr.Public)) size := ecc.NextPowerOfTwo(sizeSystem) + commitmentInfo := spr.CommitmentInfo.(constraint.PlonkCommitments) ql := make([]fr.Element, size) qr := make([]fr.Element, size) qm := make([]fr.Element, size) qo := make([]fr.Element, size) qk := make([]fr.Element, size) - qcp := make([][]fr.Element, len(spr.CommitmentInfo)) + qcp := make([][]fr.Element, len(commitmentInfo)) for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error is size is inconsistent ql[i].SetOne().Neg(&ql[i]) @@ -247,9 +248,9 @@ func BuildTrace(spr *cs.SparseR1CS, pt *Trace) { pt.Qk = iop.NewPolynomial(&qk, lagReg) pt.Qcp = make([]*iop.Polynomial, len(qcp)) - for i := range spr.CommitmentInfo { + for i := range commitmentInfo { qcp[i] = make([]fr.Element, size) - for _, committed := range spr.CommitmentInfo[i].Committed { + for _, committed := range commitmentInfo[i].Committed { qcp[i][offset+committed].SetOne() } pt.Qcp[i] = iop.NewPolynomial(&qcp[i], lagReg) From a0727e890bc2adb26c9c224c7ef42b86f50d7618 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 8 Jun 2023 13:18:57 -0500 Subject: [PATCH 439/464] fix: groth16 tests pass --- backend/groth16/bls12-377/prove.go | 2 +- backend/groth16/bls12-377/setup.go | 2 +- backend/groth16/bls12-381/prove.go | 2 +- backend/groth16/bls12-381/setup.go | 2 +- backend/groth16/bls24-315/prove.go | 2 +- backend/groth16/bls24-315/setup.go | 2 +- backend/groth16/bls24-317/prove.go | 2 +- backend/groth16/bls24-317/setup.go | 2 +- backend/groth16/bn254/prove.go | 2 +- backend/groth16/bn254/setup.go | 2 +- backend/groth16/bw6-633/prove.go | 2 +- backend/groth16/bw6-633/setup.go | 2 +- backend/groth16/bw6-761/prove.go | 2 +- backend/groth16/bw6-761/setup.go | 2 +- constraint/commitment.go | 82 ++----------------- constraint/core.go | 4 +- frontend/cs/r1cs/api.go | 5 +- .../zkpschemes/groth16/groth16.prove.go.tmpl | 2 +- .../zkpschemes/groth16/groth16.setup.go.tmpl | 2 +- 19 files changed, 29 insertions(+), 94 deletions(-) diff --git a/backend/groth16/bls12-377/prove.go b/backend/groth16/bls12-377/prove.go index 7f52932504..17b86a5f99 100644 --- a/backend/groth16/bls12-377/prove.go +++ b/backend/groth16/bls12-377/prove.go @@ -64,7 +64,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) proof := &Proof{Commitments: make([]curve.G1Affine, len(commitmentInfo))} diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index 2dc7ebd6f2..3d9894c052 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -96,7 +96,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) diff --git a/backend/groth16/bls12-381/prove.go b/backend/groth16/bls12-381/prove.go index 23ab3529dc..e04e832dec 100644 --- a/backend/groth16/bls12-381/prove.go +++ b/backend/groth16/bls12-381/prove.go @@ -64,7 +64,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) proof := &Proof{Commitments: make([]curve.G1Affine, len(commitmentInfo))} diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index 8f84a68e0f..58cd008224 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -96,7 +96,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) diff --git a/backend/groth16/bls24-315/prove.go b/backend/groth16/bls24-315/prove.go index 0b0774af00..55afb9e3e4 100644 --- a/backend/groth16/bls24-315/prove.go +++ b/backend/groth16/bls24-315/prove.go @@ -64,7 +64,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) proof := &Proof{Commitments: make([]curve.G1Affine, len(commitmentInfo))} diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index d1f06ec9f7..1447d72704 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -96,7 +96,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) diff --git a/backend/groth16/bls24-317/prove.go b/backend/groth16/bls24-317/prove.go index 72f08ac910..20f5626247 100644 --- a/backend/groth16/bls24-317/prove.go +++ b/backend/groth16/bls24-317/prove.go @@ -64,7 +64,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) proof := &Proof{Commitments: make([]curve.G1Affine, len(commitmentInfo))} diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index 9337073af5..c19004d5c8 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -96,7 +96,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index 75eb17e895..8a01ed186c 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -64,7 +64,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) proof := &Proof{Commitments: make([]curve.G1Affine, len(commitmentInfo))} diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index 347898905c..d9a3bead74 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -96,7 +96,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) diff --git a/backend/groth16/bw6-633/prove.go b/backend/groth16/bw6-633/prove.go index 41002c3f48..b84b91d025 100644 --- a/backend/groth16/bw6-633/prove.go +++ b/backend/groth16/bw6-633/prove.go @@ -64,7 +64,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) proof := &Proof{Commitments: make([]curve.G1Affine, len(commitmentInfo))} diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index 7804aa2d4b..b4b9beba86 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -96,7 +96,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) diff --git a/backend/groth16/bw6-761/prove.go b/backend/groth16/bw6-761/prove.go index 7234bf7d15..a4762cf7af 100644 --- a/backend/groth16/bw6-761/prove.go +++ b/backend/groth16/bw6-761/prove.go @@ -64,7 +64,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) proof := &Proof{Commitments: make([]curve.G1Affine, len(commitmentInfo))} diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index c52a947721..affc6fe0ae 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -96,7 +96,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) diff --git a/constraint/commitment.go b/constraint/commitment.go index 48d4344c4a..05c666bcea 100644 --- a/constraint/commitment.go +++ b/constraint/commitment.go @@ -73,82 +73,16 @@ func SerializeCommitment(privateCommitment []byte, publicCommitted []*big.Int, f return res } -/* -func (i *Commitment) NbPublicCommitted() int { - return i.NbCommitted() - i.NbPrivateCommitted -} - -func (i *Commitment) NbCommitted() int { - return len(i.Committed) -} - -// NewCommitment initialize a Commitment object -// - committed are the sorted wireID to commit to (without duplicate) -// - nbPublicCommitted is the number of public inputs among the committed wireIDs -func NewCommitment(committed []int, nbPublicCommitted int) Commitment { - return Commitment{ - Committed: committed, - NbPrivateCommitted: len(committed) - nbPublicCommitted, +func ToGroth16Commitments(c Commitments) Groth16Commitments { + if c == nil { + return nil } + return c.(Groth16Commitments) } -// PrivateToPublicGroth16 returns indexes of variables which are private to the constraint system, but public to Groth16. That is, private committed variables and the commitment itself -// TODO Perhaps move it elsewhere since it's specific to groth16 -func (i *Commitment) PrivateToPublicGroth16() []int { - res := make([]int, i.NbPrivateCommitted+1) - copy(res, i.PrivateCommitted()) - res[i.NbPrivateCommitted] = i.CommitmentIndex - return res -} - -func (i *Commitment) PrivateCommitted() []int { - return i.Committed[i.NbPublicCommitted():] -} - -func (i *Commitment) PublicCommitted() []int { - return i.Committed[:i.NbPublicCommitted()] -} - - - -// Interleave returns combined information about the commitments -// nbPrivateCommittedWires doesn't double count because the frontend guarantees that no private wire is committed to more than once -// publicAndCommitmentCommitted returns the index of committed wires that would be hashed, and are indexed from the verifier's point of view -func (c Commitments) Interleave(nbPublicVars int) (nbPrivateCommittedWires int, commitmentWires []int, privateCommitted [][]int, publicAndCommitmentCommitted [][]int) { - commitmentWires = c.CommitmentWireIndexes() - - privateCommitted = make([][]int, len(c)) - publicAndCommitmentCommitted = make([][]int, len(c)) - for i := range c { - nonPublicCommitted := c[i].PrivateCommitted() - privateCommitted[i] = make([]int, 0, len(nonPublicCommitted)) - publicAndCommitmentCommitted[i] = make([]int, c[i].NbPublicCommitted(), len(c[i].Committed)) - copy(publicAndCommitmentCommitted[i], c[i].PublicCommitted()) - for _, j := range nonPublicCommitted { - if k, found := utils.FindInSlice(commitmentWires, j); found { // if j is a commitment wire - publicAndCommitmentCommitted[i] = append(publicAndCommitmentCommitted[i], k+nbPublicVars) - } else { - privateCommitted[i] = append(privateCommitted[i], j) - } - } - - nbPrivateCommittedWires += len(privateCommitted[i]) - } - return -} - -// CommitmentIndexesInCommittedLists returns the indexes of the commitments in the list of committed wires -// note that these are not absolute indexes -func (c Commitments) CommitmentIndexesInCommittedLists() [][]int { - res := make([][]int, len(c)) - for i := range c { - res[i] = make([]int, 0, i) - for j := 0; j < i; j++ { - if k, found := utils.FindInSlice(c[i].PrivateCommitted(), c[j].CommitmentIndex); found { - res[i] = append(res[i], k+c[i].NbPublicCommitted()) - } - } +func ToPlonkCommitments(c Commitments) PlonkCommitments { + if c == nil { + return nil } - return res + return c.(PlonkCommitments) } -*/ diff --git a/constraint/core.go b/constraint/core.go index 7c60579bdb..7d242bd65b 100644 --- a/constraint/core.go +++ b/constraint/core.go @@ -300,9 +300,9 @@ func (system *System) AddSolverHint(f solver.Hint, id solver.HintID, input []Lin func (system *System) AddCommitment(c Commitment) error { switch v := c.(type) { case Groth16Commitment: - system.CommitmentInfo = append(system.CommitmentInfo.(Groth16Commitments), v) + system.CommitmentInfo = append(ToGroth16Commitments(system.CommitmentInfo), v) case PlonkCommitment: - system.CommitmentInfo = append(system.CommitmentInfo.(PlonkCommitments), v) + system.CommitmentInfo = append(ToPlonkCommitments(system.CommitmentInfo), v) default: return fmt.Errorf("unknown commitment type %T", v) } diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index 836b0b4518..43252ed682 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -682,7 +682,7 @@ func lastIs(slice []int, n int) bool { func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error) { - commitments := builder.cs.GetCommitments().(constraint.Groth16Commitments) + commitments := constraint.ToGroth16Commitments(builder.cs.GetCommitments()) existingCommitmentIndexes := commitments.CommitmentIndexes() privateCommittedSeeker := utils.MultiListSeeker(commitments.GetPrivateCommitted()) @@ -813,8 +813,9 @@ func (builder *builder) wireIDsToVars(wireIDs ...[]int) []frontend.Variable { n = 0 for _, list := range wireIDs { for i := range list { - res[n] = expr.NewLinearExpression(list[i], builder.tOne) + res[n+i] = expr.NewLinearExpression(list[i], builder.tOne) } + n += len(list) } return res } diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl index 760cf22d24..040797625f 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl @@ -47,7 +47,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) proof := &Proof{Commitments: make([]curve.G1Affine, len(commitmentInfo))} diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl index 0f4a9fc291..94a2122710 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl @@ -78,7 +78,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) From 7bee2c1cdb196b36461c9b88510a6f8bb1a70728 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 8 Jun 2023 15:19:22 -0500 Subject: [PATCH 440/464] fix: committed commitment folding bug --- backend/groth16/bls12-377/setup.go | 2 +- backend/groth16/bls12-381/setup.go | 2 +- backend/groth16/bls24-315/setup.go | 2 +- backend/groth16/bls24-317/setup.go | 2 +- backend/groth16/bn254/prove.go | 7 ++++++ backend/groth16/bn254/setup.go | 2 +- backend/groth16/bn254/verify.go | 4 +++ backend/groth16/bw6-633/setup.go | 2 +- backend/groth16/bw6-761/setup.go | 2 +- constraint/commitment.go | 39 ++++++++++++++++++++++++++++-- constraint/core.go | 2 ++ frontend/cs/r1cs/api.go | 2 +- go.mod | 2 ++ test/commitments_test.go | 6 ++++- 14 files changed, 65 insertions(+), 11 deletions(-) diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index 3d9894c052..885cdd6fd0 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -295,7 +295,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = commitmentInfo.GetPublicCommitted() + vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index 58cd008224..d486d711fd 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -295,7 +295,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = commitmentInfo.GetPublicCommitted() + vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index 1447d72704..86cf620c88 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -295,7 +295,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = commitmentInfo.GetPublicCommitted() + vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index c19004d5c8..078af831a0 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -295,7 +295,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = commitmentInfo.GetPublicCommitted() + vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index 8a01ed186c..31a2171838 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -17,6 +17,7 @@ package groth16 import ( + "fmt" "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr" @@ -87,8 +88,14 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var res fr.Element + fmt.Println("prover commitment", i) + fmt.Println("hashed input") + for i := range hashed { + fmt.Println(i, hashed[i].String()) + } res, err = solveCommitmentWire(&proof.Commitments[i], hashed) res.BigInt(out[0]) + fmt.Println("computed as", res.String()) return err } }(i))) diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index d9a3bead74..9c385b80e6 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -295,7 +295,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = commitmentInfo.GetPublicCommitted() + vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted(commitmentWires, r1cs.GetNbPublicVariables()) // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bn254/verify.go b/backend/groth16/bn254/verify.go index c8ff0ad3da..5096c3c390 100644 --- a/backend/groth16/bn254/verify.go +++ b/backend/groth16/bn254/verify.go @@ -70,9 +70,12 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { commitmentsSerialized := make([]byte, len(vk.PublicCommitted)*fr.Bytes) commitmentPrehashSerialized := make([]byte, curve.SizeOfG1AffineUncompressed+maxNbPublicCommitted*fr.Bytes) for i := range vk.PublicCommitted { // solveCommitmentWire + fmt.Println("verifier commitment", i) copy(commitmentPrehashSerialized, proof.Commitments[i].Marshal()) offset := curve.SizeOfG1AffineUncompressed + fmt.Println("hashed input") for j := range vk.PublicCommitted[i] { + fmt.Println(j, publicWitness[vk.PublicCommitted[i][j]-1].String()) copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicCommitted[i][j]-1].Marshal()) offset += fr.Bytes } @@ -80,6 +83,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } else { publicWitness = append(publicWitness, res[0]) + fmt.Printf("verifier computed commitment #%d = %s\n", i, res[0].String()) copy(commitmentsSerialized[i*fr.Bytes:], res[0].Marshal()) } } diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index b4b9beba86..e37e105563 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -295,7 +295,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = commitmentInfo.GetPublicCommitted() + vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index affc6fe0ae..d9bfe88b3d 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -295,7 +295,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = commitmentInfo.GetPublicCommitted() + vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted() // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/constraint/commitment.go b/constraint/commitment.go index 05c666bcea..daadd9991b 100644 --- a/constraint/commitment.go +++ b/constraint/commitment.go @@ -51,10 +51,27 @@ func (c Groth16Commitments) GetPrivateCommitted() [][]int { return res } -func (c Groth16Commitments) GetPublicCommitted() [][]int { +// GetPublicAndCommitmentCommitted returns the list of public and commitment committed wires +// if committedTranslationList is not nil, commitment indexes are translated into their relative positions on the list plus the offset +func (c Groth16Commitments) GetPublicAndCommitmentCommitted(committedTranslationList []int, offset int) [][]int { res := make([][]int, len(c)) for i := range c { - res[i] = c[i].PublicAndCommitmentCommitted[:c[i].NbPublicCommitted] + res[i] = make([]int, len(c[i].PublicAndCommitmentCommitted)) + copy(res[i], c[i].GetPublicCommitted()) + translatedCommitmentCommitted := res[i][c[i].NbPublicCommitted:] + commitmentCommitted := c[i].GetCommitmentCommitted() + // convert commitment indexes to verifier understandable ones + if committedTranslationList == nil { + copy(translatedCommitmentCommitted, commitmentCommitted) + } else { + k := 0 + for j := range translatedCommitmentCommitted { + for committedTranslationList[k] != commitmentCommitted[j] { + k++ + } // find it in the translation list + translatedCommitmentCommitted[j] = k + offset + } + } } return res } @@ -73,6 +90,16 @@ func SerializeCommitment(privateCommitment []byte, publicCommitted []*big.Int, f return res } +func NewCommitments(t SystemType) Commitments { + switch t { + case SystemR1CS: + return Groth16Commitments{} + case SystemSparseR1CS: + return PlonkCommitments{} + } + panic("unknown cs type") +} + func ToGroth16Commitments(c Commitments) Groth16Commitments { if c == nil { return nil @@ -86,3 +113,11 @@ func ToPlonkCommitments(c Commitments) PlonkCommitments { } return c.(PlonkCommitments) } + +func (c Groth16Commitment) GetPublicCommitted() []int { + return c.PublicAndCommitmentCommitted[:c.NbPublicCommitted] +} + +func (c Groth16Commitment) GetCommitmentCommitted() []int { + return c.PublicAndCommitmentCommitted[c.NbPublicCommitted:] +} diff --git a/constraint/core.go b/constraint/core.go index 7d242bd65b..3cbc636396 100644 --- a/constraint/core.go +++ b/constraint/core.go @@ -145,7 +145,9 @@ func NewSystem(scalarField *big.Int, capacity int, t SystemType) System { lbOutputs: make([]uint32, 0, 256), lbWireLevel: make([]int, 0, capacity), Levels: make([][]int, 0, capacity/2), + CommitmentInfo: NewCommitments(t), } + system.genericHint = system.AddBlueprint(&BlueprintGenericHint{}) return system } diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index 43252ed682..fe22fe7b6d 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -762,7 +762,7 @@ func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error lastInsertedWireId = t.VID } - if len(privateCommitted) == 0 { + if len(privateCommitted)+len(publicAndCommitmentCommitted) == 0 { // TODO @tabaie Necessary? return nil, errors.New("must commit to at least one variable") } diff --git a/go.mod b/go.mod index c7537d1765..5489e5b079 100644 --- a/go.mod +++ b/go.mod @@ -30,3 +30,5 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect rsc.io/tmplfunc v0.0.3 // indirect ) + +replace "github.com/consensys/gnark-crypto" => "/Users/arya/gnark-crypto" \ No newline at end of file diff --git a/test/commitments_test.go b/test/commitments_test.go index d0a1988862..e6aff094c1 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -1,6 +1,7 @@ package test import ( + "github.com/consensys/gnark/backend" "reflect" "testing" @@ -21,6 +22,7 @@ func (c *noCommitmentCircuit) Define(api frontend.API) error { } func TestNoCommitmentCircuit(t *testing.T) { + //NewAssert(t).ProverSucceeded(&noCommitmentCircuit{1}, &noCommitmentCircuit{1}, WithBackends(backend.PLONK), WithCurves(ecc.BN254)) testAll(t, &noCommitmentCircuit{1}) } @@ -144,7 +146,9 @@ func (c *twoCommitCircuit) Define(api frontend.API) error { } func TestTwoCommit(t *testing.T) { - testAll(t, &twoCommitCircuit{X: []frontend.Variable{1, 2}, Y: 3}) + assignment := &twoCommitCircuit{X: []frontend.Variable{1, 2}, Y: 3} + NewAssert(t).ProverSucceeded(hollow(assignment), assignment, WithCurves(ecc.BN254), WithBackends(backend.GROTH16)) + //testAll(t, &twoCommitCircuit{X: []frontend.Variable{1, 2}, Y: 3}) } type doubleCommitCircuit struct { From 7c958f1864d264920a61a00eb90d347253f62ef0 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 8 Jun 2023 15:24:58 -0500 Subject: [PATCH 441/464] build: generify the changes --- backend/groth16/bls12-377/setup.go | 2 +- backend/groth16/bls12-381/setup.go | 2 +- backend/groth16/bls24-315/setup.go | 2 +- backend/groth16/bls24-317/setup.go | 2 +- backend/groth16/bn254/prove.go | 7 ------- backend/groth16/bn254/verify.go | 4 ---- backend/groth16/bw6-633/setup.go | 2 +- backend/groth16/bw6-761/setup.go | 2 +- .../template/zkpschemes/groth16/groth16.setup.go.tmpl | 2 +- test/commitments_test.go | 6 +----- 10 files changed, 8 insertions(+), 23 deletions(-) diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index 885cdd6fd0..25d44728f2 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -295,7 +295,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted() + vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted(commitmentWires, r1cs.GetNbPublicVariables()) // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index d486d711fd..d17778382e 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -295,7 +295,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted() + vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted(commitmentWires, r1cs.GetNbPublicVariables()) // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index 86cf620c88..e5f1f023bb 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -295,7 +295,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted() + vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted(commitmentWires, r1cs.GetNbPublicVariables()) // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index 078af831a0..9ff0211c6a 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -295,7 +295,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted() + vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted(commitmentWires, r1cs.GetNbPublicVariables()) // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index 31a2171838..8a01ed186c 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -17,7 +17,6 @@ package groth16 import ( - "fmt" "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr" @@ -88,14 +87,8 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b } var res fr.Element - fmt.Println("prover commitment", i) - fmt.Println("hashed input") - for i := range hashed { - fmt.Println(i, hashed[i].String()) - } res, err = solveCommitmentWire(&proof.Commitments[i], hashed) res.BigInt(out[0]) - fmt.Println("computed as", res.String()) return err } }(i))) diff --git a/backend/groth16/bn254/verify.go b/backend/groth16/bn254/verify.go index 5096c3c390..c8ff0ad3da 100644 --- a/backend/groth16/bn254/verify.go +++ b/backend/groth16/bn254/verify.go @@ -70,12 +70,9 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { commitmentsSerialized := make([]byte, len(vk.PublicCommitted)*fr.Bytes) commitmentPrehashSerialized := make([]byte, curve.SizeOfG1AffineUncompressed+maxNbPublicCommitted*fr.Bytes) for i := range vk.PublicCommitted { // solveCommitmentWire - fmt.Println("verifier commitment", i) copy(commitmentPrehashSerialized, proof.Commitments[i].Marshal()) offset := curve.SizeOfG1AffineUncompressed - fmt.Println("hashed input") for j := range vk.PublicCommitted[i] { - fmt.Println(j, publicWitness[vk.PublicCommitted[i][j]-1].String()) copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicCommitted[i][j]-1].Marshal()) offset += fr.Bytes } @@ -83,7 +80,6 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { return err } else { publicWitness = append(publicWitness, res[0]) - fmt.Printf("verifier computed commitment #%d = %s\n", i, res[0].String()) copy(commitmentsSerialized[i*fr.Bytes:], res[0].Marshal()) } } diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index e37e105563..ba6b24bb36 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -295,7 +295,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted() + vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted(commitmentWires, r1cs.GetNbPublicVariables()) // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index d9bfe88b3d..fb42569e13 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -295,7 +295,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted() + vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted(commitmentWires, r1cs.GetNbPublicVariables()) // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl index 94a2122710..edfc115777 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl @@ -277,7 +277,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = commitmentInfo.GetPublicCommitted() + vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted(commitmentWires, r1cs.GetNbPublicVariables()) // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/test/commitments_test.go b/test/commitments_test.go index e6aff094c1..d0a1988862 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -1,7 +1,6 @@ package test import ( - "github.com/consensys/gnark/backend" "reflect" "testing" @@ -22,7 +21,6 @@ func (c *noCommitmentCircuit) Define(api frontend.API) error { } func TestNoCommitmentCircuit(t *testing.T) { - //NewAssert(t).ProverSucceeded(&noCommitmentCircuit{1}, &noCommitmentCircuit{1}, WithBackends(backend.PLONK), WithCurves(ecc.BN254)) testAll(t, &noCommitmentCircuit{1}) } @@ -146,9 +144,7 @@ func (c *twoCommitCircuit) Define(api frontend.API) error { } func TestTwoCommit(t *testing.T) { - assignment := &twoCommitCircuit{X: []frontend.Variable{1, 2}, Y: 3} - NewAssert(t).ProverSucceeded(hollow(assignment), assignment, WithCurves(ecc.BN254), WithBackends(backend.GROTH16)) - //testAll(t, &twoCommitCircuit{X: []frontend.Variable{1, 2}, Y: 3}) + testAll(t, &twoCommitCircuit{X: []frontend.Variable{1, 2}, Y: 3}) } type doubleCommitCircuit struct { From 2db7cf0dd5af54859513386beaa9552a0cb4cbaf Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 8 Jun 2023 15:27:49 -0500 Subject: [PATCH 442/464] remove: some unused code --- backend/groth16/internal/utils.go | 23 ------ backend/groth16/internal/utils_test.go | 105 ------------------------- internal/utils/heap.go | 21 ----- 3 files changed, 149 deletions(-) delete mode 100644 backend/groth16/internal/utils_test.go diff --git a/backend/groth16/internal/utils.go b/backend/groth16/internal/utils.go index 1356deb80f..6062ef57ce 100644 --- a/backend/groth16/internal/utils.go +++ b/backend/groth16/internal/utils.go @@ -1,28 +1,5 @@ package internal -import "math/big" - -// DivideByThresholdOrList divides x into two sub-lists. list must be sorted, non-repeating and contain no value less than indexThreshold -// x is modified in this process. The output lists are sub-slices of x. -func DivideByThresholdOrList(indexThreshold int, list []int, x []*big.Int) (ltOrOnList, gtAndNotOnList []*big.Int) { - ltOrOnList = x[:indexThreshold+len(list)] - gtAndNotOnList = x[len(ltOrOnList):] - onList := make([]*big.Int, len(list)) // the list is small - for i := range list { - onList[i] = x[list[i]] - } - for i := len(list) - 1; i >= 0; i-- { // overwrite the element at list[i] - sliceStart := indexThreshold - if i > 0 { - sliceStart = list[i-1] - } - displacement := len(list) - i - copy(x[sliceStart+displacement:], x[sliceStart:list[i]]) - } - copy(x[indexThreshold:], onList) - return -} - func ConcatAll(slices ...[]int) []int { // copyright note: written by GitHub Copilot totalLen := 0 for _, s := range slices { diff --git a/backend/groth16/internal/utils_test.go b/backend/groth16/internal/utils_test.go deleted file mode 100644 index 6048ff0b1b..0000000000 --- a/backend/groth16/internal/utils_test.go +++ /dev/null @@ -1,105 +0,0 @@ -package internal - -import ( - "github.com/stretchr/testify/assert" - "math/big" - "math/rand" - "testing" -) - -type coinToss struct { - x uint64 - remaining byte -} - -func (r *coinToss) rand() (res bool) { - if r.remaining == 0 { - r.x = rand.Uint64() //#nosec G404 weak rng is fine here - r.remaining = 64 - } - r.remaining-- - if r.x&1 == 1 { - res = true - } - r.x /= 2 - return -} - -func createX(size int) []*big.Int { - x := make([]*big.Int, size) - for i := range x { - x[i] = big.NewInt(int64(i)) - } - return x -} - -func toInts(x []*big.Int) []int64 { - res := make([]int64, len(x)) - for i := range x { - res[i] = x[i].Int64() - } - return res -} - -func TestDivideByThresholdOrList(t *testing.T) { - x := createX(10) - list := make([]int, 0, len(x)) - var r coinToss - for threshold := range x { - // reset x - for i := range x { - x[i].SetInt64(int64(i)) - } - - // prepare list - list = list[:0] - for i := threshold; i < len(x); i++ { - if r.rand() { - list = append(list, i) - } - } - - // get result from DivideByThresholdOrList - _, _ = DivideByThresholdOrList(threshold, list, x) - for i := 0; i < threshold; i++ { - assert.Equal(t, int64(i), x[i].Int64()) - } - for i := range list { - assert.Equal(t, int64(list[i]), x[threshold+i].Int64()) - } - prev := int64(-1) - j := 0 - for i := threshold + len(list); i < len(x); i++ { - cur := x[i].Int64() - assert.Less(t, prev, cur) - - for j < len(list) && int64(list[j]) < cur { - j++ - } - if j < len(list) && int64(list[j]) == cur { - t.Error("value on list present") - } - } - } -} - -func TestDivideByThresholdOrListLen2(t *testing.T) { - x := createX(2) - _, _ = DivideByThresholdOrList(0, []int{1}, x) - xAsInts := toInts(x) - assert.Equal(t, []int64{1, 0}, xAsInts) -} - -func TestDivideByThresholdOrListLen3(t *testing.T) { - x := createX(3) - _, _ = DivideByThresholdOrList(1, []int{2}, x) - xAsInts := toInts(x) - assert.Equal(t, []int64{0, 2, 1}, xAsInts) -} - -func TestDivideByThresholdOrListLen4(t *testing.T) { - x := createX(4) - _, _ = DivideByThresholdOrList(1, []int{1, 3}, x) - xAsInts := toInts(x) - assert.Equal(t, []int64{0, 1, 3, 2}, xAsInts) -} diff --git a/internal/utils/heap.go b/internal/utils/heap.go index 09bfd820dd..944bcb5e03 100644 --- a/internal/utils/heap.go +++ b/internal/utils/heap.go @@ -61,24 +61,3 @@ func (h *IntHeap) down(i0, n int) bool { } return i > i0 } - -// Copied from go codebase but not needed (yet) -/* - -// Fix re-establishes the heap ordering after the element at index i has changed its value. -// Changing the value of the element at index i and then calling fix is equivalent to, -// but less expensive than, calling Remove(h, i) followed by a Push of the new value. -// The complexity is O(log n) where n = len(*h). -func (h *IntHeap) Fix(i int) { - if !h.down(i, len(*h)) { - h.up(i) - } -} - -// Push the element x onto the heap. -// The complexity is O(log n) where n = len(*h). -func (h *IntHeap) Push(x int) { - *h = append(*h, x) - h.up(len(*h) - 1) -} -*/ From 28a2923d433b5d12711ec42172b57eb2a2b932c9 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 8 Jun 2023 15:28:42 -0500 Subject: [PATCH 443/464] remove: unused func --- frontend/cs/r1cs/api.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index fe22fe7b6d..57984c3402 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -676,10 +676,6 @@ func (builder *builder) Compiler() frontend.Compiler { return builder } -func lastIs(slice []int, n int) bool { - return len(slice) > 0 && slice[len(slice)-1] == n -} - func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error) { commitments := constraint.ToGroth16Commitments(builder.cs.GetCommitments()) From a7370406ca636f855e0cd1cfc69fe195900e2d6f Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 8 Jun 2023 15:29:37 -0500 Subject: [PATCH 444/464] dep: gnark-crypto --- go.mod | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 5489e5b079..a378d048a6 100644 --- a/go.mod +++ b/go.mod @@ -29,6 +29,4 @@ require ( gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect rsc.io/tmplfunc v0.0.3 // indirect -) - -replace "github.com/consensys/gnark-crypto" => "/Users/arya/gnark-crypto" \ No newline at end of file +) \ No newline at end of file From 62e1747dc1e6173921c67f603b1a93f9b81fc42c Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 8 Jun 2023 15:36:52 -0500 Subject: [PATCH 445/464] revert: forced conversion --- backend/groth16/bls12-377/prove.go | 2 +- backend/groth16/bls12-377/setup.go | 2 +- backend/groth16/bls12-381/prove.go | 2 +- backend/groth16/bls12-381/setup.go | 2 +- backend/groth16/bls24-315/prove.go | 2 +- backend/groth16/bls24-315/setup.go | 2 +- backend/groth16/bls24-317/prove.go | 2 +- backend/groth16/bls24-317/setup.go | 2 +- backend/groth16/bn254/prove.go | 2 +- backend/groth16/bn254/setup.go | 2 +- backend/groth16/bw6-633/prove.go | 2 +- backend/groth16/bw6-633/setup.go | 2 +- backend/groth16/bw6-761/prove.go | 2 +- backend/groth16/bw6-761/setup.go | 2 +- constraint/commitment.go | 14 -------------- constraint/core.go | 4 ++-- frontend/cs/r1cs/api.go | 2 +- .../zkpschemes/groth16/groth16.prove.go.tmpl | 2 +- .../zkpschemes/groth16/groth16.setup.go.tmpl | 2 +- 19 files changed, 19 insertions(+), 33 deletions(-) diff --git a/backend/groth16/bls12-377/prove.go b/backend/groth16/bls12-377/prove.go index 17b86a5f99..7f52932504 100644 --- a/backend/groth16/bls12-377/prove.go +++ b/backend/groth16/bls12-377/prove.go @@ -64,7 +64,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) proof := &Proof{Commitments: make([]curve.G1Affine, len(commitmentInfo))} diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index 25d44728f2..b55dba6aaf 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -96,7 +96,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) diff --git a/backend/groth16/bls12-381/prove.go b/backend/groth16/bls12-381/prove.go index e04e832dec..23ab3529dc 100644 --- a/backend/groth16/bls12-381/prove.go +++ b/backend/groth16/bls12-381/prove.go @@ -64,7 +64,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) proof := &Proof{Commitments: make([]curve.G1Affine, len(commitmentInfo))} diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index d17778382e..e0beca2530 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -96,7 +96,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) diff --git a/backend/groth16/bls24-315/prove.go b/backend/groth16/bls24-315/prove.go index 55afb9e3e4..0b0774af00 100644 --- a/backend/groth16/bls24-315/prove.go +++ b/backend/groth16/bls24-315/prove.go @@ -64,7 +64,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) proof := &Proof{Commitments: make([]curve.G1Affine, len(commitmentInfo))} diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index e5f1f023bb..26aa13d2ed 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -96,7 +96,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) diff --git a/backend/groth16/bls24-317/prove.go b/backend/groth16/bls24-317/prove.go index 20f5626247..72f08ac910 100644 --- a/backend/groth16/bls24-317/prove.go +++ b/backend/groth16/bls24-317/prove.go @@ -64,7 +64,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) proof := &Proof{Commitments: make([]curve.G1Affine, len(commitmentInfo))} diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index 9ff0211c6a..0c4a4022eb 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -96,7 +96,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index 8a01ed186c..75eb17e895 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -64,7 +64,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) proof := &Proof{Commitments: make([]curve.G1Affine, len(commitmentInfo))} diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index 9c385b80e6..332d07728c 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -96,7 +96,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) diff --git a/backend/groth16/bw6-633/prove.go b/backend/groth16/bw6-633/prove.go index b84b91d025..41002c3f48 100644 --- a/backend/groth16/bw6-633/prove.go +++ b/backend/groth16/bw6-633/prove.go @@ -64,7 +64,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) proof := &Proof{Commitments: make([]curve.G1Affine, len(commitmentInfo))} diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index ba6b24bb36..4d8575b409 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -96,7 +96,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) diff --git a/backend/groth16/bw6-761/prove.go b/backend/groth16/bw6-761/prove.go index a4762cf7af..7234bf7d15 100644 --- a/backend/groth16/bw6-761/prove.go +++ b/backend/groth16/bw6-761/prove.go @@ -64,7 +64,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) proof := &Proof{Commitments: make([]curve.G1Affine, len(commitmentInfo))} diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index fb42569e13..b9fd178500 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -96,7 +96,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) diff --git a/constraint/commitment.go b/constraint/commitment.go index daadd9991b..2e812ce906 100644 --- a/constraint/commitment.go +++ b/constraint/commitment.go @@ -100,20 +100,6 @@ func NewCommitments(t SystemType) Commitments { panic("unknown cs type") } -func ToGroth16Commitments(c Commitments) Groth16Commitments { - if c == nil { - return nil - } - return c.(Groth16Commitments) -} - -func ToPlonkCommitments(c Commitments) PlonkCommitments { - if c == nil { - return nil - } - return c.(PlonkCommitments) -} - func (c Groth16Commitment) GetPublicCommitted() []int { return c.PublicAndCommitmentCommitted[:c.NbPublicCommitted] } diff --git a/constraint/core.go b/constraint/core.go index 3cbc636396..e54fab3149 100644 --- a/constraint/core.go +++ b/constraint/core.go @@ -302,9 +302,9 @@ func (system *System) AddSolverHint(f solver.Hint, id solver.HintID, input []Lin func (system *System) AddCommitment(c Commitment) error { switch v := c.(type) { case Groth16Commitment: - system.CommitmentInfo = append(ToGroth16Commitments(system.CommitmentInfo), v) + system.CommitmentInfo = append(system.CommitmentInfo.(Groth16Commitments), v) case PlonkCommitment: - system.CommitmentInfo = append(ToPlonkCommitments(system.CommitmentInfo), v) + system.CommitmentInfo = append(system.CommitmentInfo.(PlonkCommitments), v) default: return fmt.Errorf("unknown commitment type %T", v) } diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index 57984c3402..7bb01fa76c 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -678,7 +678,7 @@ func (builder *builder) Compiler() frontend.Compiler { func (builder *builder) Commit(v ...frontend.Variable) (frontend.Variable, error) { - commitments := constraint.ToGroth16Commitments(builder.cs.GetCommitments()) + commitments := builder.cs.GetCommitments().(constraint.Groth16Commitments) existingCommitmentIndexes := commitments.CommitmentIndexes() privateCommittedSeeker := utils.MultiListSeeker(commitments.GetPrivateCommitted()) diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl index 040797625f..760cf22d24 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl @@ -47,7 +47,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() - commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) proof := &Proof{Commitments: make([]curve.G1Affine, len(commitmentInfo))} diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl index edfc115777..01bf38442b 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl @@ -78,7 +78,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() - commitmentInfo := constraint.ToGroth16Commitments(r1cs.CommitmentInfo) + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) From 50cdf3c8b594c3b39fb75c6fb3b1cb674067e9db Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Thu, 8 Jun 2023 15:47:52 -0500 Subject: [PATCH 446/464] test: add failing test for round trip pk serialization --- backend/plonk/bls12-377/marshal_test.go | 5 +++++ backend/plonk/bls12-381/marshal_test.go | 5 +++++ backend/plonk/bls24-315/marshal_test.go | 5 +++++ backend/plonk/bls24-317/marshal_test.go | 5 +++++ backend/plonk/bn254/marshal_test.go | 5 +++++ backend/plonk/bw6-633/marshal_test.go | 5 +++++ backend/plonk/bw6-761/marshal_test.go | 5 +++++ .../backend/template/zkpschemes/plonk/tests/marshal.go.tmpl | 5 +++++ 8 files changed, 40 insertions(+) diff --git a/backend/plonk/bls12-377/marshal_test.go b/backend/plonk/bls12-377/marshal_test.go index da2a447e3c..5f5b257510 100644 --- a/backend/plonk/bls12-377/marshal_test.go +++ b/backend/plonk/bls12-377/marshal_test.go @@ -114,6 +114,11 @@ func (pk *ProvingKey) randomize() { pk.Domain[0] = *fft.NewDomain(42) pk.Domain[1] = *fft.NewDomain(4 * 42) + pk.Kzg.G1 = make([]curve.G1Affine, 7) + for i := range pk.Kzg.G1 { + pk.Kzg.G1[i] = randomG1Point() + } + n := int(pk.Domain[0].Cardinality) ql := randomScalars(n) qr := randomScalars(n) diff --git a/backend/plonk/bls12-381/marshal_test.go b/backend/plonk/bls12-381/marshal_test.go index f67ebb2fe7..4feea48419 100644 --- a/backend/plonk/bls12-381/marshal_test.go +++ b/backend/plonk/bls12-381/marshal_test.go @@ -114,6 +114,11 @@ func (pk *ProvingKey) randomize() { pk.Domain[0] = *fft.NewDomain(42) pk.Domain[1] = *fft.NewDomain(4 * 42) + pk.Kzg.G1 = make([]curve.G1Affine, 7) + for i := range pk.Kzg.G1 { + pk.Kzg.G1[i] = randomG1Point() + } + n := int(pk.Domain[0].Cardinality) ql := randomScalars(n) qr := randomScalars(n) diff --git a/backend/plonk/bls24-315/marshal_test.go b/backend/plonk/bls24-315/marshal_test.go index 1881a62ace..3f069bf9f2 100644 --- a/backend/plonk/bls24-315/marshal_test.go +++ b/backend/plonk/bls24-315/marshal_test.go @@ -114,6 +114,11 @@ func (pk *ProvingKey) randomize() { pk.Domain[0] = *fft.NewDomain(42) pk.Domain[1] = *fft.NewDomain(4 * 42) + pk.Kzg.G1 = make([]curve.G1Affine, 7) + for i := range pk.Kzg.G1 { + pk.Kzg.G1[i] = randomG1Point() + } + n := int(pk.Domain[0].Cardinality) ql := randomScalars(n) qr := randomScalars(n) diff --git a/backend/plonk/bls24-317/marshal_test.go b/backend/plonk/bls24-317/marshal_test.go index 10d26631c5..004b9ff0ff 100644 --- a/backend/plonk/bls24-317/marshal_test.go +++ b/backend/plonk/bls24-317/marshal_test.go @@ -114,6 +114,11 @@ func (pk *ProvingKey) randomize() { pk.Domain[0] = *fft.NewDomain(42) pk.Domain[1] = *fft.NewDomain(4 * 42) + pk.Kzg.G1 = make([]curve.G1Affine, 7) + for i := range pk.Kzg.G1 { + pk.Kzg.G1[i] = randomG1Point() + } + n := int(pk.Domain[0].Cardinality) ql := randomScalars(n) qr := randomScalars(n) diff --git a/backend/plonk/bn254/marshal_test.go b/backend/plonk/bn254/marshal_test.go index 74254283a2..2986d77c5b 100644 --- a/backend/plonk/bn254/marshal_test.go +++ b/backend/plonk/bn254/marshal_test.go @@ -114,6 +114,11 @@ func (pk *ProvingKey) randomize() { pk.Domain[0] = *fft.NewDomain(42) pk.Domain[1] = *fft.NewDomain(4 * 42) + pk.Kzg.G1 = make([]curve.G1Affine, 7) + for i := range pk.Kzg.G1 { + pk.Kzg.G1[i] = randomG1Point() + } + n := int(pk.Domain[0].Cardinality) ql := randomScalars(n) qr := randomScalars(n) diff --git a/backend/plonk/bw6-633/marshal_test.go b/backend/plonk/bw6-633/marshal_test.go index 6e4c9d7667..d971ac2e7c 100644 --- a/backend/plonk/bw6-633/marshal_test.go +++ b/backend/plonk/bw6-633/marshal_test.go @@ -114,6 +114,11 @@ func (pk *ProvingKey) randomize() { pk.Domain[0] = *fft.NewDomain(42) pk.Domain[1] = *fft.NewDomain(4 * 42) + pk.Kzg.G1 = make([]curve.G1Affine, 7) + for i := range pk.Kzg.G1 { + pk.Kzg.G1[i] = randomG1Point() + } + n := int(pk.Domain[0].Cardinality) ql := randomScalars(n) qr := randomScalars(n) diff --git a/backend/plonk/bw6-761/marshal_test.go b/backend/plonk/bw6-761/marshal_test.go index e47c6e815b..99a8106986 100644 --- a/backend/plonk/bw6-761/marshal_test.go +++ b/backend/plonk/bw6-761/marshal_test.go @@ -114,6 +114,11 @@ func (pk *ProvingKey) randomize() { pk.Domain[0] = *fft.NewDomain(42) pk.Domain[1] = *fft.NewDomain(4 * 42) + pk.Kzg.G1 = make([]curve.G1Affine, 7) + for i := range pk.Kzg.G1 { + pk.Kzg.G1[i] = randomG1Point() + } + n := int(pk.Domain[0].Cardinality) ql := randomScalars(n) qr := randomScalars(n) diff --git a/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl index cb6acbb018..8f3946a52b 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/tests/marshal.go.tmpl @@ -94,6 +94,11 @@ func (pk *ProvingKey) randomize() { pk.Vk = &vk pk.Domain[0] = *fft.NewDomain(42) pk.Domain[1] = *fft.NewDomain(4 * 42) + + pk.Kzg.G1 = make([]curve.G1Affine, 7) + for i := range pk.Kzg.G1 { + pk.Kzg.G1[i] = randomG1Point() + } n := int(pk.Domain[0].Cardinality) ql := randomScalars(n) From 3651930179e50d416d38d4426fbdba21be639b66 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Thu, 8 Jun 2023 16:04:45 -0500 Subject: [PATCH 447/464] test: added missing integration test for round trip serialization --- test/assert.go | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/test/assert.go b/test/assert.go index 4f1581b14d..0cd30fce66 100644 --- a/test/assert.go +++ b/test/assert.go @@ -17,8 +17,10 @@ limitations under the License. package test import ( + "bytes" "errors" "fmt" + "io" "reflect" "strings" "testing" @@ -35,6 +37,7 @@ import ( "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/consensys/gnark/frontend/cs/scs" "github.com/consensys/gnark/frontend/schema" + gnarkio "github.com/consensys/gnark/io" "github.com/stretchr/testify/require" ) @@ -44,6 +47,10 @@ var ( ErrInvalidWitnessVerified = errors.New("invalid witness resulted in a valid proof") ) +// SerializationThreshold is the number of constraints above which we don't +// do a systematic round-trip serialization check for the proving and verifying keys. +const SerializationThreshold = 1000 + // Assert is a helper to test circuits type Assert struct { t *testing.T @@ -149,6 +156,16 @@ func (assert *Assert) ProverSucceeded(circuit frontend.Circuit, validAssignment case backend.GROTH16: pk, vk, err := groth16.Setup(ccs) checkError(err) + if ccs.GetNbConstraints() <= SerializationThreshold { + pkReconstructed := groth16.NewProvingKey(curve) + roundTripCheck(assert.t, pk, pkReconstructed) + pkReconstructed = groth16.NewProvingKey(curve) + roundTripCheckRaw(assert.t, pk, pkReconstructed) + vkReconstructed := groth16.NewVerifyingKey(curve) + roundTripCheck(assert.t, vk, vkReconstructed) + vkReconstructed = groth16.NewVerifyingKey(curve) + roundTripCheckRaw(assert.t, vk, vkReconstructed) + } // ensure prove / verify works well with valid witnesses @@ -164,6 +181,12 @@ func (assert *Assert) ProverSucceeded(circuit frontend.Circuit, validAssignment pk, vk, err := plonk.Setup(ccs, srs) checkError(err) + if ccs.GetNbConstraints() <= SerializationThreshold { + pkReconstructed := plonk.NewProvingKey(curve) + roundTripCheck(assert.t, pk, pkReconstructed) + vkReconstructed := plonk.NewVerifyingKey(curve) + roundTripCheck(assert.t, vk, vkReconstructed) + } correctProof, err := plonk.Prove(ccs, pk, validWitness, opt.proverOpts...) checkError(err) @@ -554,3 +577,45 @@ func (assert *Assert) marshalWitnessJSON(w witness.Witness, s *schema.Schema, cu witnessMatch := reflect.DeepEqual(w, witness) assert.True(witnessMatch, "round trip marshaling failed") } + +func roundTripCheck(t *testing.T, from io.WriterTo, reconstructed io.ReaderFrom) { + var buf bytes.Buffer + written, err := from.WriteTo(&buf) + if err != nil { + t.Fatal("couldn't serialize", err) + } + + read, err := reconstructed.ReadFrom(&buf) + if err != nil { + t.Fatal("couldn't deserialize", err) + } + + if !reflect.DeepEqual(from, reconstructed) { + t.Fatal("reconstructed object don't match original") + } + + if written != read { + t.Fatal("bytes written / read don't match") + } +} + +func roundTripCheckRaw(t *testing.T, from gnarkio.WriterRawTo, reconstructed io.ReaderFrom) { + var buf bytes.Buffer + written, err := from.WriteRawTo(&buf) + if err != nil { + t.Fatal("couldn't serialize", err) + } + + read, err := reconstructed.ReadFrom(&buf) + if err != nil { + t.Fatal("couldn't deserialize", err) + } + + if !reflect.DeepEqual(from, reconstructed) { + t.Fatal("reconstructed object don't match original") + } + + if written != read { + t.Fatal("bytes written / read don't match") + } +} From 300f49382ed6665741b651d0ce5a7464cbba26ab Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Thu, 8 Jun 2023 16:23:27 -0500 Subject: [PATCH 448/464] test: added failing test for groth16 pk serialization round trip --- backend/groth16/bls12-377/marshal.go | 14 ++++++++++++++ backend/groth16/bls12-381/marshal.go | 14 ++++++++++++++ backend/groth16/bls24-315/marshal.go | 14 ++++++++++++++ backend/groth16/bls24-317/marshal.go | 14 ++++++++++++++ backend/groth16/bn254/marshal.go | 14 ++++++++++++++ backend/groth16/bw6-633/marshal.go | 14 ++++++++++++++ backend/groth16/bw6-761/marshal.go | 14 ++++++++++++++ backend/plonk/bls12-377/marshal.go | 13 +++++++++++++ backend/plonk/bls12-381/marshal.go | 13 +++++++++++++ backend/plonk/bls24-315/marshal.go | 13 +++++++++++++ backend/plonk/bls24-317/marshal.go | 13 +++++++++++++ backend/plonk/bn254/marshal.go | 13 +++++++++++++ backend/plonk/bw6-633/marshal.go | 13 +++++++++++++ backend/plonk/bw6-761/marshal.go | 13 +++++++++++++ .../zkpschemes/groth16/groth16.marshal.go.tmpl | 14 ++++++++++++++ .../zkpschemes/plonk/plonk.marshal.go.tmpl | 13 +++++++++++++ 16 files changed, 216 insertions(+) diff --git a/backend/groth16/bls12-377/marshal.go b/backend/groth16/bls12-377/marshal.go index e4fdff1a48..c3affa0b3b 100644 --- a/backend/groth16/bls12-377/marshal.go +++ b/backend/groth16/bls12-377/marshal.go @@ -230,6 +230,14 @@ func (pk *ProvingKey) writeTo(w io.Writer, raw bool) (int64, error) { } } + // TODO pedersen commitment key only implements WriteTo + // missing WriteRawTo + n2, err := pk.CommitmentKey.WriteTo(w) + n += n2 + if err != nil { + return n, err + } + return n + enc.BytesWritten(), nil } @@ -288,5 +296,11 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) return n + dec.BytesRead(), err } + n2, err := pk.CommitmentKey.ReadFrom(r) + n += n2 + if err != nil { + return n, err + } + return n + dec.BytesRead(), nil } diff --git a/backend/groth16/bls12-381/marshal.go b/backend/groth16/bls12-381/marshal.go index bb544afd21..3ce8d52448 100644 --- a/backend/groth16/bls12-381/marshal.go +++ b/backend/groth16/bls12-381/marshal.go @@ -230,6 +230,14 @@ func (pk *ProvingKey) writeTo(w io.Writer, raw bool) (int64, error) { } } + // TODO pedersen commitment key only implements WriteTo + // missing WriteRawTo + n2, err := pk.CommitmentKey.WriteTo(w) + n += n2 + if err != nil { + return n, err + } + return n + enc.BytesWritten(), nil } @@ -288,5 +296,11 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) return n + dec.BytesRead(), err } + n2, err := pk.CommitmentKey.ReadFrom(r) + n += n2 + if err != nil { + return n, err + } + return n + dec.BytesRead(), nil } diff --git a/backend/groth16/bls24-315/marshal.go b/backend/groth16/bls24-315/marshal.go index 6a53616cd7..ad7f9c5f6f 100644 --- a/backend/groth16/bls24-315/marshal.go +++ b/backend/groth16/bls24-315/marshal.go @@ -230,6 +230,14 @@ func (pk *ProvingKey) writeTo(w io.Writer, raw bool) (int64, error) { } } + // TODO pedersen commitment key only implements WriteTo + // missing WriteRawTo + n2, err := pk.CommitmentKey.WriteTo(w) + n += n2 + if err != nil { + return n, err + } + return n + enc.BytesWritten(), nil } @@ -288,5 +296,11 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) return n + dec.BytesRead(), err } + n2, err := pk.CommitmentKey.ReadFrom(r) + n += n2 + if err != nil { + return n, err + } + return n + dec.BytesRead(), nil } diff --git a/backend/groth16/bls24-317/marshal.go b/backend/groth16/bls24-317/marshal.go index 6aeab91292..27d2af02f6 100644 --- a/backend/groth16/bls24-317/marshal.go +++ b/backend/groth16/bls24-317/marshal.go @@ -230,6 +230,14 @@ func (pk *ProvingKey) writeTo(w io.Writer, raw bool) (int64, error) { } } + // TODO pedersen commitment key only implements WriteTo + // missing WriteRawTo + n2, err := pk.CommitmentKey.WriteTo(w) + n += n2 + if err != nil { + return n, err + } + return n + enc.BytesWritten(), nil } @@ -288,5 +296,11 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) return n + dec.BytesRead(), err } + n2, err := pk.CommitmentKey.ReadFrom(r) + n += n2 + if err != nil { + return n, err + } + return n + dec.BytesRead(), nil } diff --git a/backend/groth16/bn254/marshal.go b/backend/groth16/bn254/marshal.go index f906599f75..9be068c2b9 100644 --- a/backend/groth16/bn254/marshal.go +++ b/backend/groth16/bn254/marshal.go @@ -230,6 +230,14 @@ func (pk *ProvingKey) writeTo(w io.Writer, raw bool) (int64, error) { } } + // TODO pedersen commitment key only implements WriteTo + // missing WriteRawTo + n2, err := pk.CommitmentKey.WriteTo(w) + n += n2 + if err != nil { + return n, err + } + return n + enc.BytesWritten(), nil } @@ -288,5 +296,11 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) return n + dec.BytesRead(), err } + n2, err := pk.CommitmentKey.ReadFrom(r) + n += n2 + if err != nil { + return n, err + } + return n + dec.BytesRead(), nil } diff --git a/backend/groth16/bw6-633/marshal.go b/backend/groth16/bw6-633/marshal.go index cb7e234fc5..5779064fad 100644 --- a/backend/groth16/bw6-633/marshal.go +++ b/backend/groth16/bw6-633/marshal.go @@ -230,6 +230,14 @@ func (pk *ProvingKey) writeTo(w io.Writer, raw bool) (int64, error) { } } + // TODO pedersen commitment key only implements WriteTo + // missing WriteRawTo + n2, err := pk.CommitmentKey.WriteTo(w) + n += n2 + if err != nil { + return n, err + } + return n + enc.BytesWritten(), nil } @@ -288,5 +296,11 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) return n + dec.BytesRead(), err } + n2, err := pk.CommitmentKey.ReadFrom(r) + n += n2 + if err != nil { + return n, err + } + return n + dec.BytesRead(), nil } diff --git a/backend/groth16/bw6-761/marshal.go b/backend/groth16/bw6-761/marshal.go index 662ece22be..eba8b0f732 100644 --- a/backend/groth16/bw6-761/marshal.go +++ b/backend/groth16/bw6-761/marshal.go @@ -230,6 +230,14 @@ func (pk *ProvingKey) writeTo(w io.Writer, raw bool) (int64, error) { } } + // TODO pedersen commitment key only implements WriteTo + // missing WriteRawTo + n2, err := pk.CommitmentKey.WriteTo(w) + n += n2 + if err != nil { + return n, err + } + return n + enc.BytesWritten(), nil } @@ -288,5 +296,11 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) return n + dec.BytesRead(), err } + n2, err := pk.CommitmentKey.ReadFrom(r) + n += n2 + if err != nil { + return n, err + } + return n + dec.BytesRead(), nil } diff --git a/backend/plonk/bls12-377/marshal.go b/backend/plonk/bls12-377/marshal.go index 4c74a05aa4..5066e4edd2 100644 --- a/backend/plonk/bls12-377/marshal.go +++ b/backend/plonk/bls12-377/marshal.go @@ -116,6 +116,13 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { } n += n2 + // KZG key + n2, err = pk.Kzg.WriteTo(w) + if err != nil { + return + } + n += n2 + // sanity check len(Permutation) == 3*int(pk.Domain[0].Cardinality) if len(pk.trace.S) != (3 * int(pk.Domain[0].Cardinality)) { return n, errors.New("invalid permutation size, expected 3*domain cardinality") @@ -168,6 +175,12 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { return n, err } + n2, err = pk.Kzg.ReadFrom(r) + n += n2 + if err != nil { + return n, err + } + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) dec := curve.NewDecoder(r) diff --git a/backend/plonk/bls12-381/marshal.go b/backend/plonk/bls12-381/marshal.go index 6ce9cedd20..3ab52bdfda 100644 --- a/backend/plonk/bls12-381/marshal.go +++ b/backend/plonk/bls12-381/marshal.go @@ -116,6 +116,13 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { } n += n2 + // KZG key + n2, err = pk.Kzg.WriteTo(w) + if err != nil { + return + } + n += n2 + // sanity check len(Permutation) == 3*int(pk.Domain[0].Cardinality) if len(pk.trace.S) != (3 * int(pk.Domain[0].Cardinality)) { return n, errors.New("invalid permutation size, expected 3*domain cardinality") @@ -168,6 +175,12 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { return n, err } + n2, err = pk.Kzg.ReadFrom(r) + n += n2 + if err != nil { + return n, err + } + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) dec := curve.NewDecoder(r) diff --git a/backend/plonk/bls24-315/marshal.go b/backend/plonk/bls24-315/marshal.go index 24cea7ada8..3741654311 100644 --- a/backend/plonk/bls24-315/marshal.go +++ b/backend/plonk/bls24-315/marshal.go @@ -116,6 +116,13 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { } n += n2 + // KZG key + n2, err = pk.Kzg.WriteTo(w) + if err != nil { + return + } + n += n2 + // sanity check len(Permutation) == 3*int(pk.Domain[0].Cardinality) if len(pk.trace.S) != (3 * int(pk.Domain[0].Cardinality)) { return n, errors.New("invalid permutation size, expected 3*domain cardinality") @@ -168,6 +175,12 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { return n, err } + n2, err = pk.Kzg.ReadFrom(r) + n += n2 + if err != nil { + return n, err + } + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) dec := curve.NewDecoder(r) diff --git a/backend/plonk/bls24-317/marshal.go b/backend/plonk/bls24-317/marshal.go index 5e4ba3a712..f47ee7d12a 100644 --- a/backend/plonk/bls24-317/marshal.go +++ b/backend/plonk/bls24-317/marshal.go @@ -116,6 +116,13 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { } n += n2 + // KZG key + n2, err = pk.Kzg.WriteTo(w) + if err != nil { + return + } + n += n2 + // sanity check len(Permutation) == 3*int(pk.Domain[0].Cardinality) if len(pk.trace.S) != (3 * int(pk.Domain[0].Cardinality)) { return n, errors.New("invalid permutation size, expected 3*domain cardinality") @@ -168,6 +175,12 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { return n, err } + n2, err = pk.Kzg.ReadFrom(r) + n += n2 + if err != nil { + return n, err + } + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) dec := curve.NewDecoder(r) diff --git a/backend/plonk/bn254/marshal.go b/backend/plonk/bn254/marshal.go index 1290cf2142..43dd85ef54 100644 --- a/backend/plonk/bn254/marshal.go +++ b/backend/plonk/bn254/marshal.go @@ -116,6 +116,13 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { } n += n2 + // KZG key + n2, err = pk.Kzg.WriteTo(w) + if err != nil { + return + } + n += n2 + // sanity check len(Permutation) == 3*int(pk.Domain[0].Cardinality) if len(pk.trace.S) != (3 * int(pk.Domain[0].Cardinality)) { return n, errors.New("invalid permutation size, expected 3*domain cardinality") @@ -168,6 +175,12 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { return n, err } + n2, err = pk.Kzg.ReadFrom(r) + n += n2 + if err != nil { + return n, err + } + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) dec := curve.NewDecoder(r) diff --git a/backend/plonk/bw6-633/marshal.go b/backend/plonk/bw6-633/marshal.go index b78786fbcb..02fc234629 100644 --- a/backend/plonk/bw6-633/marshal.go +++ b/backend/plonk/bw6-633/marshal.go @@ -116,6 +116,13 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { } n += n2 + // KZG key + n2, err = pk.Kzg.WriteTo(w) + if err != nil { + return + } + n += n2 + // sanity check len(Permutation) == 3*int(pk.Domain[0].Cardinality) if len(pk.trace.S) != (3 * int(pk.Domain[0].Cardinality)) { return n, errors.New("invalid permutation size, expected 3*domain cardinality") @@ -168,6 +175,12 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { return n, err } + n2, err = pk.Kzg.ReadFrom(r) + n += n2 + if err != nil { + return n, err + } + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) dec := curve.NewDecoder(r) diff --git a/backend/plonk/bw6-761/marshal.go b/backend/plonk/bw6-761/marshal.go index 5c46d00e18..28d61b7059 100644 --- a/backend/plonk/bw6-761/marshal.go +++ b/backend/plonk/bw6-761/marshal.go @@ -116,6 +116,13 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { } n += n2 + // KZG key + n2, err = pk.Kzg.WriteTo(w) + if err != nil { + return + } + n += n2 + // sanity check len(Permutation) == 3*int(pk.Domain[0].Cardinality) if len(pk.trace.S) != (3 * int(pk.Domain[0].Cardinality)) { return n, errors.New("invalid permutation size, expected 3*domain cardinality") @@ -168,6 +175,12 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { return n, err } + n2, err = pk.Kzg.ReadFrom(r) + n += n2 + if err != nil { + return n, err + } + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) dec := curve.NewDecoder(r) diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl index e29c0f451e..06d72b613b 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl @@ -217,6 +217,14 @@ func (pk *ProvingKey) writeTo(w io.Writer, raw bool) (int64, error) { } } + // TODO pedersen commitment key only implements WriteTo + // missing WriteRawTo + n2, err := pk.CommitmentKey.WriteTo(w) + n += n2 + if err != nil { + return n, err + } + return n + enc.BytesWritten(), nil } @@ -276,6 +284,12 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) return n + dec.BytesRead(), err } + n2, err := pk.CommitmentKey.ReadFrom(r) + n += n2 + if err != nil { + return n, err + } + return n + dec.BytesRead(), nil } diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl index b645b9e95f..2dfba35d65 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.marshal.go.tmpl @@ -96,6 +96,13 @@ func (pk *ProvingKey) WriteTo(w io.Writer) (n int64, err error) { } n += n2 + // KZG key + n2, err = pk.Kzg.WriteTo(w) + if err != nil { + return + } + n += n2 + // sanity check len(Permutation) == 3*int(pk.Domain[0].Cardinality) if len(pk.trace.S) != (3 * int(pk.Domain[0].Cardinality)) { return n, errors.New("invalid permutation size, expected 3*domain cardinality") @@ -148,6 +155,12 @@ func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { return n, err } + n2, err = pk.Kzg.ReadFrom(r) + n += n2 + if err != nil { + return n, err + } + pk.trace.S = make([]int64, 3*pk.Domain[0].Cardinality) dec := curve.NewDecoder(r) From e06b50b9deb8c13ed400b6f1111b23d0f0297d87 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 9 Jun 2023 09:25:03 -0500 Subject: [PATCH 449/464] fix: commitmentInfo serialization --- constraint/bls12-377/r1cs_test.go | 2 +- constraint/bls12-377/system.go | 9 +++++++++ constraint/bls12-381/r1cs_test.go | 2 +- constraint/bls12-381/system.go | 9 +++++++++ constraint/bls24-315/r1cs_test.go | 2 +- constraint/bls24-315/system.go | 9 +++++++++ constraint/bls24-317/r1cs_test.go | 2 +- constraint/bls24-317/system.go | 9 +++++++++ constraint/bn254/r1cs_test.go | 2 +- constraint/bn254/system.go | 9 +++++++++ constraint/bw6-633/r1cs_test.go | 2 +- constraint/bw6-633/system.go | 9 +++++++++ constraint/bw6-761/r1cs_test.go | 2 +- constraint/bw6-761/system.go | 9 +++++++++ constraint/tinyfield/r1cs_test.go | 2 +- constraint/tinyfield/system.go | 9 +++++++++ .../backend/template/representations/system.go.tmpl | 10 +++++++++- .../template/representations/tests/r1cs.go.tmpl | 2 +- 18 files changed, 90 insertions(+), 10 deletions(-) diff --git a/constraint/bls12-377/r1cs_test.go b/constraint/bls12-377/r1cs_test.go index f789c5f50b..b3eb222420 100644 --- a/constraint/bls12-377/r1cs_test.go +++ b/constraint/bls12-377/r1cs_test.go @@ -49,7 +49,7 @@ func TestSerialization(t *testing.T) { return } - // copmpile a second time to ensure determinism + // compile a second time to ensure determinism r1cs2, err := frontend.Compile(fr.Modulus(), r1cs.NewBuilder, tc.Circuit) if err != nil { t.Fatal(err) diff --git a/constraint/bls12-377/system.go b/constraint/bls12-377/system.go index 275a559ccc..5a35f10a00 100644 --- a/constraint/bls12-377/system.go +++ b/constraint/bls12-377/system.go @@ -179,6 +179,13 @@ func (cs *system) ReadFrom(r io.Reader) (int64, error) { return int64(decoder.NumBytesRead()), err } + switch v := cs.CommitmentInfo.(type) { + case *constraint.Groth16Commitments: + cs.CommitmentInfo = *v + case *constraint.PlonkCommitments: + cs.CommitmentInfo = *v + } + return int64(decoder.NumBytesRead()), nil } @@ -360,6 +367,8 @@ func getTagSet() cbor.TagSet { addType(reflect.TypeOf(constraint.BlueprintSparseR1CAdd{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CMul{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CBool{})) + addType(reflect.TypeOf(constraint.Groth16Commitments{})) + addType(reflect.TypeOf(constraint.PlonkCommitments{})) return ts } diff --git a/constraint/bls12-381/r1cs_test.go b/constraint/bls12-381/r1cs_test.go index 3a7e10de55..c7b0fa6156 100644 --- a/constraint/bls12-381/r1cs_test.go +++ b/constraint/bls12-381/r1cs_test.go @@ -49,7 +49,7 @@ func TestSerialization(t *testing.T) { return } - // copmpile a second time to ensure determinism + // compile a second time to ensure determinism r1cs2, err := frontend.Compile(fr.Modulus(), r1cs.NewBuilder, tc.Circuit) if err != nil { t.Fatal(err) diff --git a/constraint/bls12-381/system.go b/constraint/bls12-381/system.go index 79409d3d3c..ff3c074f67 100644 --- a/constraint/bls12-381/system.go +++ b/constraint/bls12-381/system.go @@ -179,6 +179,13 @@ func (cs *system) ReadFrom(r io.Reader) (int64, error) { return int64(decoder.NumBytesRead()), err } + switch v := cs.CommitmentInfo.(type) { + case *constraint.Groth16Commitments: + cs.CommitmentInfo = *v + case *constraint.PlonkCommitments: + cs.CommitmentInfo = *v + } + return int64(decoder.NumBytesRead()), nil } @@ -360,6 +367,8 @@ func getTagSet() cbor.TagSet { addType(reflect.TypeOf(constraint.BlueprintSparseR1CAdd{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CMul{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CBool{})) + addType(reflect.TypeOf(constraint.Groth16Commitments{})) + addType(reflect.TypeOf(constraint.PlonkCommitments{})) return ts } diff --git a/constraint/bls24-315/r1cs_test.go b/constraint/bls24-315/r1cs_test.go index bf09d377f8..3885c438b5 100644 --- a/constraint/bls24-315/r1cs_test.go +++ b/constraint/bls24-315/r1cs_test.go @@ -49,7 +49,7 @@ func TestSerialization(t *testing.T) { return } - // copmpile a second time to ensure determinism + // compile a second time to ensure determinism r1cs2, err := frontend.Compile(fr.Modulus(), r1cs.NewBuilder, tc.Circuit) if err != nil { t.Fatal(err) diff --git a/constraint/bls24-315/system.go b/constraint/bls24-315/system.go index 6b991e5afa..de1f206275 100644 --- a/constraint/bls24-315/system.go +++ b/constraint/bls24-315/system.go @@ -179,6 +179,13 @@ func (cs *system) ReadFrom(r io.Reader) (int64, error) { return int64(decoder.NumBytesRead()), err } + switch v := cs.CommitmentInfo.(type) { + case *constraint.Groth16Commitments: + cs.CommitmentInfo = *v + case *constraint.PlonkCommitments: + cs.CommitmentInfo = *v + } + return int64(decoder.NumBytesRead()), nil } @@ -360,6 +367,8 @@ func getTagSet() cbor.TagSet { addType(reflect.TypeOf(constraint.BlueprintSparseR1CAdd{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CMul{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CBool{})) + addType(reflect.TypeOf(constraint.Groth16Commitments{})) + addType(reflect.TypeOf(constraint.PlonkCommitments{})) return ts } diff --git a/constraint/bls24-317/r1cs_test.go b/constraint/bls24-317/r1cs_test.go index 124f6403f0..9ad8d2f586 100644 --- a/constraint/bls24-317/r1cs_test.go +++ b/constraint/bls24-317/r1cs_test.go @@ -49,7 +49,7 @@ func TestSerialization(t *testing.T) { return } - // copmpile a second time to ensure determinism + // compile a second time to ensure determinism r1cs2, err := frontend.Compile(fr.Modulus(), r1cs.NewBuilder, tc.Circuit) if err != nil { t.Fatal(err) diff --git a/constraint/bls24-317/system.go b/constraint/bls24-317/system.go index 65e5575b8e..f8ac490de2 100644 --- a/constraint/bls24-317/system.go +++ b/constraint/bls24-317/system.go @@ -179,6 +179,13 @@ func (cs *system) ReadFrom(r io.Reader) (int64, error) { return int64(decoder.NumBytesRead()), err } + switch v := cs.CommitmentInfo.(type) { + case *constraint.Groth16Commitments: + cs.CommitmentInfo = *v + case *constraint.PlonkCommitments: + cs.CommitmentInfo = *v + } + return int64(decoder.NumBytesRead()), nil } @@ -360,6 +367,8 @@ func getTagSet() cbor.TagSet { addType(reflect.TypeOf(constraint.BlueprintSparseR1CAdd{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CMul{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CBool{})) + addType(reflect.TypeOf(constraint.Groth16Commitments{})) + addType(reflect.TypeOf(constraint.PlonkCommitments{})) return ts } diff --git a/constraint/bn254/r1cs_test.go b/constraint/bn254/r1cs_test.go index e7ca65cfd8..8c8ba5da95 100644 --- a/constraint/bn254/r1cs_test.go +++ b/constraint/bn254/r1cs_test.go @@ -49,7 +49,7 @@ func TestSerialization(t *testing.T) { return } - // copmpile a second time to ensure determinism + // compile a second time to ensure determinism r1cs2, err := frontend.Compile(fr.Modulus(), r1cs.NewBuilder, tc.Circuit) if err != nil { t.Fatal(err) diff --git a/constraint/bn254/system.go b/constraint/bn254/system.go index 46786c663f..949e532dbe 100644 --- a/constraint/bn254/system.go +++ b/constraint/bn254/system.go @@ -179,6 +179,13 @@ func (cs *system) ReadFrom(r io.Reader) (int64, error) { return int64(decoder.NumBytesRead()), err } + switch v := cs.CommitmentInfo.(type) { + case *constraint.Groth16Commitments: + cs.CommitmentInfo = *v + case *constraint.PlonkCommitments: + cs.CommitmentInfo = *v + } + return int64(decoder.NumBytesRead()), nil } @@ -360,6 +367,8 @@ func getTagSet() cbor.TagSet { addType(reflect.TypeOf(constraint.BlueprintSparseR1CAdd{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CMul{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CBool{})) + addType(reflect.TypeOf(constraint.Groth16Commitments{})) + addType(reflect.TypeOf(constraint.PlonkCommitments{})) return ts } diff --git a/constraint/bw6-633/r1cs_test.go b/constraint/bw6-633/r1cs_test.go index e63b4d8a5e..9f9d6a0d6f 100644 --- a/constraint/bw6-633/r1cs_test.go +++ b/constraint/bw6-633/r1cs_test.go @@ -49,7 +49,7 @@ func TestSerialization(t *testing.T) { return } - // copmpile a second time to ensure determinism + // compile a second time to ensure determinism r1cs2, err := frontend.Compile(fr.Modulus(), r1cs.NewBuilder, tc.Circuit) if err != nil { t.Fatal(err) diff --git a/constraint/bw6-633/system.go b/constraint/bw6-633/system.go index 26ffb323c2..f102b47290 100644 --- a/constraint/bw6-633/system.go +++ b/constraint/bw6-633/system.go @@ -179,6 +179,13 @@ func (cs *system) ReadFrom(r io.Reader) (int64, error) { return int64(decoder.NumBytesRead()), err } + switch v := cs.CommitmentInfo.(type) { + case *constraint.Groth16Commitments: + cs.CommitmentInfo = *v + case *constraint.PlonkCommitments: + cs.CommitmentInfo = *v + } + return int64(decoder.NumBytesRead()), nil } @@ -360,6 +367,8 @@ func getTagSet() cbor.TagSet { addType(reflect.TypeOf(constraint.BlueprintSparseR1CAdd{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CMul{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CBool{})) + addType(reflect.TypeOf(constraint.Groth16Commitments{})) + addType(reflect.TypeOf(constraint.PlonkCommitments{})) return ts } diff --git a/constraint/bw6-761/r1cs_test.go b/constraint/bw6-761/r1cs_test.go index 32136c08b3..b6eae1220c 100644 --- a/constraint/bw6-761/r1cs_test.go +++ b/constraint/bw6-761/r1cs_test.go @@ -52,7 +52,7 @@ func TestSerialization(t *testing.T) { return } - // copmpile a second time to ensure determinism + // compile a second time to ensure determinism r1cs2, err := frontend.Compile(fr.Modulus(), r1cs.NewBuilder, tc.Circuit) if err != nil { t.Fatal(err) diff --git a/constraint/bw6-761/system.go b/constraint/bw6-761/system.go index 049819c3da..10e7990dfa 100644 --- a/constraint/bw6-761/system.go +++ b/constraint/bw6-761/system.go @@ -179,6 +179,13 @@ func (cs *system) ReadFrom(r io.Reader) (int64, error) { return int64(decoder.NumBytesRead()), err } + switch v := cs.CommitmentInfo.(type) { + case *constraint.Groth16Commitments: + cs.CommitmentInfo = *v + case *constraint.PlonkCommitments: + cs.CommitmentInfo = *v + } + return int64(decoder.NumBytesRead()), nil } @@ -360,6 +367,8 @@ func getTagSet() cbor.TagSet { addType(reflect.TypeOf(constraint.BlueprintSparseR1CAdd{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CMul{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CBool{})) + addType(reflect.TypeOf(constraint.Groth16Commitments{})) + addType(reflect.TypeOf(constraint.PlonkCommitments{})) return ts } diff --git a/constraint/tinyfield/r1cs_test.go b/constraint/tinyfield/r1cs_test.go index 632222a0fa..5015c06972 100644 --- a/constraint/tinyfield/r1cs_test.go +++ b/constraint/tinyfield/r1cs_test.go @@ -52,7 +52,7 @@ func TestSerialization(t *testing.T) { return } - // copmpile a second time to ensure determinism + // compile a second time to ensure determinism r1cs2, err := frontend.Compile(fr.Modulus(), r1cs.NewBuilder, tc.Circuit) if err != nil { t.Fatal(err) diff --git a/constraint/tinyfield/system.go b/constraint/tinyfield/system.go index d8f7f0e383..d75471e445 100644 --- a/constraint/tinyfield/system.go +++ b/constraint/tinyfield/system.go @@ -179,6 +179,13 @@ func (cs *system) ReadFrom(r io.Reader) (int64, error) { return int64(decoder.NumBytesRead()), err } + switch v := cs.CommitmentInfo.(type) { + case *constraint.Groth16Commitments: + cs.CommitmentInfo = *v + case *constraint.PlonkCommitments: + cs.CommitmentInfo = *v + } + return int64(decoder.NumBytesRead()), nil } @@ -360,6 +367,8 @@ func getTagSet() cbor.TagSet { addType(reflect.TypeOf(constraint.BlueprintSparseR1CAdd{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CMul{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CBool{})) + addType(reflect.TypeOf(constraint.Groth16Commitments{})) + addType(reflect.TypeOf(constraint.PlonkCommitments{})) return ts } diff --git a/internal/generator/backend/template/representations/system.go.tmpl b/internal/generator/backend/template/representations/system.go.tmpl index 2270319d9a..7288fdb546 100644 --- a/internal/generator/backend/template/representations/system.go.tmpl +++ b/internal/generator/backend/template/representations/system.go.tmpl @@ -166,6 +166,12 @@ func (cs *system) ReadFrom(r io.Reader) (int64, error) { return int64(decoder.NumBytesRead()), err } + switch v := cs.CommitmentInfo.(type) { + case *constraint.Groth16Commitments: + cs.CommitmentInfo = *v + case *constraint.PlonkCommitments: + cs.CommitmentInfo = *v + } return int64(decoder.NumBytesRead()), nil } @@ -358,6 +364,8 @@ func getTagSet() cbor.TagSet { addType(reflect.TypeOf(constraint.BlueprintSparseR1CAdd{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CMul{})) addType(reflect.TypeOf(constraint.BlueprintSparseR1CBool{})) - + addType(reflect.TypeOf(constraint.Groth16Commitments{})) + addType(reflect.TypeOf(constraint.PlonkCommitments{})) + return ts } diff --git a/internal/generator/backend/template/representations/tests/r1cs.go.tmpl b/internal/generator/backend/template/representations/tests/r1cs.go.tmpl index 3c5c9a8be4..81eebde6bc 100644 --- a/internal/generator/backend/template/representations/tests/r1cs.go.tmpl +++ b/internal/generator/backend/template/representations/tests/r1cs.go.tmpl @@ -40,7 +40,7 @@ func TestSerialization(t *testing.T) { return } - // copmpile a second time to ensure determinism + // compile a second time to ensure determinism r1cs2, err := frontend.Compile(fr.Modulus(), r1cs.NewBuilder, tc.Circuit) if err != nil { t.Fatal(err) From 61663dade9ee98be8c32a7b3b97f948b61676e20 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 9 Jun 2023 10:29:44 -0500 Subject: [PATCH 450/464] chore: more accurate field name, remove some dead code --- backend/groth16/bls12-377/marshal.go | 8 ++++---- backend/groth16/bls12-377/marshal_test.go | 8 ++++---- backend/groth16/bls12-377/setup.go | 9 +++------ backend/groth16/bls12-377/verify.go | 12 ++++++------ backend/groth16/bls12-381/marshal.go | 8 ++++---- backend/groth16/bls12-381/marshal_test.go | 8 ++++---- backend/groth16/bls12-381/setup.go | 9 +++------ backend/groth16/bls12-381/verify.go | 12 ++++++------ backend/groth16/bls24-315/marshal.go | 8 ++++---- backend/groth16/bls24-315/marshal_test.go | 8 ++++---- backend/groth16/bls24-315/setup.go | 9 +++------ backend/groth16/bls24-315/verify.go | 12 ++++++------ backend/groth16/bls24-317/marshal.go | 8 ++++---- backend/groth16/bls24-317/marshal_test.go | 8 ++++---- backend/groth16/bls24-317/setup.go | 9 +++------ backend/groth16/bls24-317/verify.go | 12 ++++++------ backend/groth16/bn254/marshal.go | 8 ++++---- backend/groth16/bn254/marshal_test.go | 8 ++++---- backend/groth16/bn254/setup.go | 9 +++------ backend/groth16/bn254/verify.go | 12 ++++++------ backend/groth16/bw6-633/marshal.go | 8 ++++---- backend/groth16/bw6-633/marshal_test.go | 8 ++++---- backend/groth16/bw6-633/setup.go | 9 +++------ backend/groth16/bw6-633/verify.go | 12 ++++++------ backend/groth16/bw6-761/marshal.go | 8 ++++---- backend/groth16/bw6-761/marshal_test.go | 8 ++++---- backend/groth16/bw6-761/setup.go | 9 +++------ backend/groth16/bw6-761/verify.go | 12 ++++++------ .../zkpschemes/groth16/groth16.marshal.go.tmpl | 8 ++++---- .../zkpschemes/groth16/groth16.setup.go.tmpl | 7 ++----- .../zkpschemes/groth16/groth16.verify.go.tmpl | 12 ++++++------ .../zkpschemes/groth16/tests/groth16.marshal.go.tmpl | 8 ++++---- 32 files changed, 135 insertions(+), 159 deletions(-) diff --git a/backend/groth16/bls12-377/marshal.go b/backend/groth16/bls12-377/marshal.go index 34c0828f09..93eb39e08c 100644 --- a/backend/groth16/bls12-377/marshal.go +++ b/backend/groth16/bls12-377/marshal.go @@ -136,10 +136,10 @@ func (vk *VerifyingKey) writeTo(w io.Writer, raw bool) (int64, error) { return enc.BytesWritten(), err } - if vk.PublicCommitted == nil { - vk.PublicCommitted = [][]int{} // only matters in tests + if vk.PublicAndCommitmentCommitted == nil { + vk.PublicAndCommitmentCommitted = [][]int{} // only matters in tests } - if err := enc.Encode(utils.IntSliceSliceToUint64SliceSlice(vk.PublicCommitted)); err != nil { + if err := enc.Encode(utils.IntSliceSliceToUint64SliceSlice(vk.PublicAndCommitmentCommitted)); err != nil { return enc.BytesWritten(), err } @@ -204,7 +204,7 @@ func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder) if err := dec.Decode(&publicCommitted); err != nil { return dec.BytesRead(), err } - vk.PublicCommitted = utils.Uint64SliceSliceToIntSliceSlice(publicCommitted) + vk.PublicAndCommitmentCommitted = utils.Uint64SliceSliceToIntSliceSlice(publicCommitted) // recompute vk.e (e(α, β)) and -[δ]2, -[γ]2 if err := vk.Precompute(); err != nil { diff --git a/backend/groth16/bls12-377/marshal_test.go b/backend/groth16/bls12-377/marshal_test.go index 5a572e147d..d4a135ee47 100644 --- a/backend/groth16/bls12-377/marshal_test.go +++ b/backend/groth16/bls12-377/marshal_test.go @@ -122,11 +122,11 @@ func TestVerifyingKeySerialization(t *testing.T) { } if withCommitment { - vk.PublicCommitted = test_utils.Random2DIntSlice(5, 10) // TODO: Use gopter randomization - bases := make([][]curve.G1Affine, len(vk.PublicCommitted)) + vk.PublicAndCommitmentCommitted = test_utils.Random2DIntSlice(5, 10) // TODO: Use gopter randomization + bases := make([][]curve.G1Affine, len(vk.PublicAndCommitmentCommitted)) elem := p1 - for i := 0; i < len(vk.PublicCommitted); i++ { - bases[i] = make([]curve.G1Affine, len(vk.PublicCommitted[i])) + for i := 0; i < len(vk.PublicAndCommitmentCommitted); i++ { + bases[i] = make([]curve.G1Affine, len(vk.PublicAndCommitmentCommitted[i])) for j := range bases[i] { bases[i][j] = elem elem.Add(&elem, &p1) diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index b55dba6aaf..e25d18113c 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -77,8 +77,8 @@ type VerifyingKey struct { // e(α, β) e curve.GT // not serialized - CommitmentKey pedersen.VerifyingKey - PublicCommitted [][]int // indexes of public committed variables + CommitmentKey pedersen.VerifyingKey + PublicAndCommitmentCommitted [][]int // indexes of public/commitment committed variables } // Setup constructs the SRS @@ -100,8 +100,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) - //nbPrivateCommittedWires, privateCommitted, publicAndCommitmentCommitted := - // commitmentInfo.Interleave(r1cs.GetNbPublicVariables()) // a commitment is itself defined by a hint so the prover considers it private // but the verifier will need to inject the value itself so on the groth16 @@ -163,7 +161,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 - // i = vI + nbPrivateCommittedSeen + nbCommitmentsSeen for i := range A { commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool @@ -295,7 +292,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted(commitmentWires, r1cs.GetNbPublicVariables()) + vk.PublicAndCommitmentCommitted = commitmentInfo.GetPublicAndCommitmentCommitted(commitmentWires, r1cs.GetNbPublicVariables()) // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bls12-377/verify.go b/backend/groth16/bls12-377/verify.go index 976176c048..3da51fcaee 100644 --- a/backend/groth16/bls12-377/verify.go +++ b/backend/groth16/bls12-377/verify.go @@ -38,7 +38,7 @@ var ( // Verify verifies a proof with given VerifyingKey and publicWitness func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { - nbPublicVars := len(vk.G1.K) - len(vk.PublicCommitted) + nbPublicVars := len(vk.G1.K) - len(vk.PublicAndCommitmentCommitted) if len(publicWitness) != nbPublicVars-1 { return fmt.Errorf("invalid witness size, got %d, expected %d (public - ONE_WIRE)", len(publicWitness), len(vk.G1.K)-1) @@ -63,16 +63,16 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { }() maxNbPublicCommitted := 0 - for _, s := range vk.PublicCommitted { // iterate over commitments + for _, s := range vk.PublicAndCommitmentCommitted { // iterate over commitments maxNbPublicCommitted = utils.Max(maxNbPublicCommitted, len(s)) } - commitmentsSerialized := make([]byte, len(vk.PublicCommitted)*fr.Bytes) + commitmentsSerialized := make([]byte, len(vk.PublicAndCommitmentCommitted)*fr.Bytes) commitmentPrehashSerialized := make([]byte, curve.SizeOfG1AffineUncompressed+maxNbPublicCommitted*fr.Bytes) - for i := range vk.PublicCommitted { // solveCommitmentWire + for i := range vk.PublicAndCommitmentCommitted { // solveCommitmentWire copy(commitmentPrehashSerialized, proof.Commitments[i].Marshal()) offset := curve.SizeOfG1AffineUncompressed - for j := range vk.PublicCommitted[i] { - copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicCommitted[i][j]-1].Marshal()) + for j := range vk.PublicAndCommitmentCommitted[i] { + copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicAndCommitmentCommitted[i][j]-1].Marshal()) offset += fr.Bytes } if res, err := fr.Hash(commitmentPrehashSerialized[:offset], []byte(constraint.CommitmentDst), 1); err != nil { diff --git a/backend/groth16/bls12-381/marshal.go b/backend/groth16/bls12-381/marshal.go index 93a77a6733..3440cc5a5c 100644 --- a/backend/groth16/bls12-381/marshal.go +++ b/backend/groth16/bls12-381/marshal.go @@ -136,10 +136,10 @@ func (vk *VerifyingKey) writeTo(w io.Writer, raw bool) (int64, error) { return enc.BytesWritten(), err } - if vk.PublicCommitted == nil { - vk.PublicCommitted = [][]int{} // only matters in tests + if vk.PublicAndCommitmentCommitted == nil { + vk.PublicAndCommitmentCommitted = [][]int{} // only matters in tests } - if err := enc.Encode(utils.IntSliceSliceToUint64SliceSlice(vk.PublicCommitted)); err != nil { + if err := enc.Encode(utils.IntSliceSliceToUint64SliceSlice(vk.PublicAndCommitmentCommitted)); err != nil { return enc.BytesWritten(), err } @@ -204,7 +204,7 @@ func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder) if err := dec.Decode(&publicCommitted); err != nil { return dec.BytesRead(), err } - vk.PublicCommitted = utils.Uint64SliceSliceToIntSliceSlice(publicCommitted) + vk.PublicAndCommitmentCommitted = utils.Uint64SliceSliceToIntSliceSlice(publicCommitted) // recompute vk.e (e(α, β)) and -[δ]2, -[γ]2 if err := vk.Precompute(); err != nil { diff --git a/backend/groth16/bls12-381/marshal_test.go b/backend/groth16/bls12-381/marshal_test.go index 157520b5cd..eb678c2242 100644 --- a/backend/groth16/bls12-381/marshal_test.go +++ b/backend/groth16/bls12-381/marshal_test.go @@ -122,11 +122,11 @@ func TestVerifyingKeySerialization(t *testing.T) { } if withCommitment { - vk.PublicCommitted = test_utils.Random2DIntSlice(5, 10) // TODO: Use gopter randomization - bases := make([][]curve.G1Affine, len(vk.PublicCommitted)) + vk.PublicAndCommitmentCommitted = test_utils.Random2DIntSlice(5, 10) // TODO: Use gopter randomization + bases := make([][]curve.G1Affine, len(vk.PublicAndCommitmentCommitted)) elem := p1 - for i := 0; i < len(vk.PublicCommitted); i++ { - bases[i] = make([]curve.G1Affine, len(vk.PublicCommitted[i])) + for i := 0; i < len(vk.PublicAndCommitmentCommitted); i++ { + bases[i] = make([]curve.G1Affine, len(vk.PublicAndCommitmentCommitted[i])) for j := range bases[i] { bases[i][j] = elem elem.Add(&elem, &p1) diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index e0beca2530..d9aec8fa02 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -77,8 +77,8 @@ type VerifyingKey struct { // e(α, β) e curve.GT // not serialized - CommitmentKey pedersen.VerifyingKey - PublicCommitted [][]int // indexes of public committed variables + CommitmentKey pedersen.VerifyingKey + PublicAndCommitmentCommitted [][]int // indexes of public/commitment committed variables } // Setup constructs the SRS @@ -100,8 +100,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) - //nbPrivateCommittedWires, privateCommitted, publicAndCommitmentCommitted := - // commitmentInfo.Interleave(r1cs.GetNbPublicVariables()) // a commitment is itself defined by a hint so the prover considers it private // but the verifier will need to inject the value itself so on the groth16 @@ -163,7 +161,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 - // i = vI + nbPrivateCommittedSeen + nbCommitmentsSeen for i := range A { commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool @@ -295,7 +292,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted(commitmentWires, r1cs.GetNbPublicVariables()) + vk.PublicAndCommitmentCommitted = commitmentInfo.GetPublicAndCommitmentCommitted(commitmentWires, r1cs.GetNbPublicVariables()) // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bls12-381/verify.go b/backend/groth16/bls12-381/verify.go index 64673a9d72..646e052f42 100644 --- a/backend/groth16/bls12-381/verify.go +++ b/backend/groth16/bls12-381/verify.go @@ -38,7 +38,7 @@ var ( // Verify verifies a proof with given VerifyingKey and publicWitness func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { - nbPublicVars := len(vk.G1.K) - len(vk.PublicCommitted) + nbPublicVars := len(vk.G1.K) - len(vk.PublicAndCommitmentCommitted) if len(publicWitness) != nbPublicVars-1 { return fmt.Errorf("invalid witness size, got %d, expected %d (public - ONE_WIRE)", len(publicWitness), len(vk.G1.K)-1) @@ -63,16 +63,16 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { }() maxNbPublicCommitted := 0 - for _, s := range vk.PublicCommitted { // iterate over commitments + for _, s := range vk.PublicAndCommitmentCommitted { // iterate over commitments maxNbPublicCommitted = utils.Max(maxNbPublicCommitted, len(s)) } - commitmentsSerialized := make([]byte, len(vk.PublicCommitted)*fr.Bytes) + commitmentsSerialized := make([]byte, len(vk.PublicAndCommitmentCommitted)*fr.Bytes) commitmentPrehashSerialized := make([]byte, curve.SizeOfG1AffineUncompressed+maxNbPublicCommitted*fr.Bytes) - for i := range vk.PublicCommitted { // solveCommitmentWire + for i := range vk.PublicAndCommitmentCommitted { // solveCommitmentWire copy(commitmentPrehashSerialized, proof.Commitments[i].Marshal()) offset := curve.SizeOfG1AffineUncompressed - for j := range vk.PublicCommitted[i] { - copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicCommitted[i][j]-1].Marshal()) + for j := range vk.PublicAndCommitmentCommitted[i] { + copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicAndCommitmentCommitted[i][j]-1].Marshal()) offset += fr.Bytes } if res, err := fr.Hash(commitmentPrehashSerialized[:offset], []byte(constraint.CommitmentDst), 1); err != nil { diff --git a/backend/groth16/bls24-315/marshal.go b/backend/groth16/bls24-315/marshal.go index b4e3c6037b..eb0a15b700 100644 --- a/backend/groth16/bls24-315/marshal.go +++ b/backend/groth16/bls24-315/marshal.go @@ -136,10 +136,10 @@ func (vk *VerifyingKey) writeTo(w io.Writer, raw bool) (int64, error) { return enc.BytesWritten(), err } - if vk.PublicCommitted == nil { - vk.PublicCommitted = [][]int{} // only matters in tests + if vk.PublicAndCommitmentCommitted == nil { + vk.PublicAndCommitmentCommitted = [][]int{} // only matters in tests } - if err := enc.Encode(utils.IntSliceSliceToUint64SliceSlice(vk.PublicCommitted)); err != nil { + if err := enc.Encode(utils.IntSliceSliceToUint64SliceSlice(vk.PublicAndCommitmentCommitted)); err != nil { return enc.BytesWritten(), err } @@ -204,7 +204,7 @@ func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder) if err := dec.Decode(&publicCommitted); err != nil { return dec.BytesRead(), err } - vk.PublicCommitted = utils.Uint64SliceSliceToIntSliceSlice(publicCommitted) + vk.PublicAndCommitmentCommitted = utils.Uint64SliceSliceToIntSliceSlice(publicCommitted) // recompute vk.e (e(α, β)) and -[δ]2, -[γ]2 if err := vk.Precompute(); err != nil { diff --git a/backend/groth16/bls24-315/marshal_test.go b/backend/groth16/bls24-315/marshal_test.go index b6bea935af..2692774253 100644 --- a/backend/groth16/bls24-315/marshal_test.go +++ b/backend/groth16/bls24-315/marshal_test.go @@ -122,11 +122,11 @@ func TestVerifyingKeySerialization(t *testing.T) { } if withCommitment { - vk.PublicCommitted = test_utils.Random2DIntSlice(5, 10) // TODO: Use gopter randomization - bases := make([][]curve.G1Affine, len(vk.PublicCommitted)) + vk.PublicAndCommitmentCommitted = test_utils.Random2DIntSlice(5, 10) // TODO: Use gopter randomization + bases := make([][]curve.G1Affine, len(vk.PublicAndCommitmentCommitted)) elem := p1 - for i := 0; i < len(vk.PublicCommitted); i++ { - bases[i] = make([]curve.G1Affine, len(vk.PublicCommitted[i])) + for i := 0; i < len(vk.PublicAndCommitmentCommitted); i++ { + bases[i] = make([]curve.G1Affine, len(vk.PublicAndCommitmentCommitted[i])) for j := range bases[i] { bases[i][j] = elem elem.Add(&elem, &p1) diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index 26aa13d2ed..caa03a0243 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -77,8 +77,8 @@ type VerifyingKey struct { // e(α, β) e curve.GT // not serialized - CommitmentKey pedersen.VerifyingKey - PublicCommitted [][]int // indexes of public committed variables + CommitmentKey pedersen.VerifyingKey + PublicAndCommitmentCommitted [][]int // indexes of public/commitment committed variables } // Setup constructs the SRS @@ -100,8 +100,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) - //nbPrivateCommittedWires, privateCommitted, publicAndCommitmentCommitted := - // commitmentInfo.Interleave(r1cs.GetNbPublicVariables()) // a commitment is itself defined by a hint so the prover considers it private // but the verifier will need to inject the value itself so on the groth16 @@ -163,7 +161,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 - // i = vI + nbPrivateCommittedSeen + nbCommitmentsSeen for i := range A { commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool @@ -295,7 +292,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted(commitmentWires, r1cs.GetNbPublicVariables()) + vk.PublicAndCommitmentCommitted = commitmentInfo.GetPublicAndCommitmentCommitted(commitmentWires, r1cs.GetNbPublicVariables()) // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bls24-315/verify.go b/backend/groth16/bls24-315/verify.go index 3b3fd2f993..6e85b70ecf 100644 --- a/backend/groth16/bls24-315/verify.go +++ b/backend/groth16/bls24-315/verify.go @@ -38,7 +38,7 @@ var ( // Verify verifies a proof with given VerifyingKey and publicWitness func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { - nbPublicVars := len(vk.G1.K) - len(vk.PublicCommitted) + nbPublicVars := len(vk.G1.K) - len(vk.PublicAndCommitmentCommitted) if len(publicWitness) != nbPublicVars-1 { return fmt.Errorf("invalid witness size, got %d, expected %d (public - ONE_WIRE)", len(publicWitness), len(vk.G1.K)-1) @@ -63,16 +63,16 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { }() maxNbPublicCommitted := 0 - for _, s := range vk.PublicCommitted { // iterate over commitments + for _, s := range vk.PublicAndCommitmentCommitted { // iterate over commitments maxNbPublicCommitted = utils.Max(maxNbPublicCommitted, len(s)) } - commitmentsSerialized := make([]byte, len(vk.PublicCommitted)*fr.Bytes) + commitmentsSerialized := make([]byte, len(vk.PublicAndCommitmentCommitted)*fr.Bytes) commitmentPrehashSerialized := make([]byte, curve.SizeOfG1AffineUncompressed+maxNbPublicCommitted*fr.Bytes) - for i := range vk.PublicCommitted { // solveCommitmentWire + for i := range vk.PublicAndCommitmentCommitted { // solveCommitmentWire copy(commitmentPrehashSerialized, proof.Commitments[i].Marshal()) offset := curve.SizeOfG1AffineUncompressed - for j := range vk.PublicCommitted[i] { - copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicCommitted[i][j]-1].Marshal()) + for j := range vk.PublicAndCommitmentCommitted[i] { + copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicAndCommitmentCommitted[i][j]-1].Marshal()) offset += fr.Bytes } if res, err := fr.Hash(commitmentPrehashSerialized[:offset], []byte(constraint.CommitmentDst), 1); err != nil { diff --git a/backend/groth16/bls24-317/marshal.go b/backend/groth16/bls24-317/marshal.go index c6f6b24261..e5f54cf26c 100644 --- a/backend/groth16/bls24-317/marshal.go +++ b/backend/groth16/bls24-317/marshal.go @@ -136,10 +136,10 @@ func (vk *VerifyingKey) writeTo(w io.Writer, raw bool) (int64, error) { return enc.BytesWritten(), err } - if vk.PublicCommitted == nil { - vk.PublicCommitted = [][]int{} // only matters in tests + if vk.PublicAndCommitmentCommitted == nil { + vk.PublicAndCommitmentCommitted = [][]int{} // only matters in tests } - if err := enc.Encode(utils.IntSliceSliceToUint64SliceSlice(vk.PublicCommitted)); err != nil { + if err := enc.Encode(utils.IntSliceSliceToUint64SliceSlice(vk.PublicAndCommitmentCommitted)); err != nil { return enc.BytesWritten(), err } @@ -204,7 +204,7 @@ func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder) if err := dec.Decode(&publicCommitted); err != nil { return dec.BytesRead(), err } - vk.PublicCommitted = utils.Uint64SliceSliceToIntSliceSlice(publicCommitted) + vk.PublicAndCommitmentCommitted = utils.Uint64SliceSliceToIntSliceSlice(publicCommitted) // recompute vk.e (e(α, β)) and -[δ]2, -[γ]2 if err := vk.Precompute(); err != nil { diff --git a/backend/groth16/bls24-317/marshal_test.go b/backend/groth16/bls24-317/marshal_test.go index 4e37fe2b88..cb58134756 100644 --- a/backend/groth16/bls24-317/marshal_test.go +++ b/backend/groth16/bls24-317/marshal_test.go @@ -122,11 +122,11 @@ func TestVerifyingKeySerialization(t *testing.T) { } if withCommitment { - vk.PublicCommitted = test_utils.Random2DIntSlice(5, 10) // TODO: Use gopter randomization - bases := make([][]curve.G1Affine, len(vk.PublicCommitted)) + vk.PublicAndCommitmentCommitted = test_utils.Random2DIntSlice(5, 10) // TODO: Use gopter randomization + bases := make([][]curve.G1Affine, len(vk.PublicAndCommitmentCommitted)) elem := p1 - for i := 0; i < len(vk.PublicCommitted); i++ { - bases[i] = make([]curve.G1Affine, len(vk.PublicCommitted[i])) + for i := 0; i < len(vk.PublicAndCommitmentCommitted); i++ { + bases[i] = make([]curve.G1Affine, len(vk.PublicAndCommitmentCommitted[i])) for j := range bases[i] { bases[i][j] = elem elem.Add(&elem, &p1) diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index 0c4a4022eb..83038d9dba 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -77,8 +77,8 @@ type VerifyingKey struct { // e(α, β) e curve.GT // not serialized - CommitmentKey pedersen.VerifyingKey - PublicCommitted [][]int // indexes of public committed variables + CommitmentKey pedersen.VerifyingKey + PublicAndCommitmentCommitted [][]int // indexes of public/commitment committed variables } // Setup constructs the SRS @@ -100,8 +100,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) - //nbPrivateCommittedWires, privateCommitted, publicAndCommitmentCommitted := - // commitmentInfo.Interleave(r1cs.GetNbPublicVariables()) // a commitment is itself defined by a hint so the prover considers it private // but the verifier will need to inject the value itself so on the groth16 @@ -163,7 +161,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 - // i = vI + nbPrivateCommittedSeen + nbCommitmentsSeen for i := range A { commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool @@ -295,7 +292,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted(commitmentWires, r1cs.GetNbPublicVariables()) + vk.PublicAndCommitmentCommitted = commitmentInfo.GetPublicAndCommitmentCommitted(commitmentWires, r1cs.GetNbPublicVariables()) // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bls24-317/verify.go b/backend/groth16/bls24-317/verify.go index 675882e0a9..3affc23113 100644 --- a/backend/groth16/bls24-317/verify.go +++ b/backend/groth16/bls24-317/verify.go @@ -38,7 +38,7 @@ var ( // Verify verifies a proof with given VerifyingKey and publicWitness func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { - nbPublicVars := len(vk.G1.K) - len(vk.PublicCommitted) + nbPublicVars := len(vk.G1.K) - len(vk.PublicAndCommitmentCommitted) if len(publicWitness) != nbPublicVars-1 { return fmt.Errorf("invalid witness size, got %d, expected %d (public - ONE_WIRE)", len(publicWitness), len(vk.G1.K)-1) @@ -63,16 +63,16 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { }() maxNbPublicCommitted := 0 - for _, s := range vk.PublicCommitted { // iterate over commitments + for _, s := range vk.PublicAndCommitmentCommitted { // iterate over commitments maxNbPublicCommitted = utils.Max(maxNbPublicCommitted, len(s)) } - commitmentsSerialized := make([]byte, len(vk.PublicCommitted)*fr.Bytes) + commitmentsSerialized := make([]byte, len(vk.PublicAndCommitmentCommitted)*fr.Bytes) commitmentPrehashSerialized := make([]byte, curve.SizeOfG1AffineUncompressed+maxNbPublicCommitted*fr.Bytes) - for i := range vk.PublicCommitted { // solveCommitmentWire + for i := range vk.PublicAndCommitmentCommitted { // solveCommitmentWire copy(commitmentPrehashSerialized, proof.Commitments[i].Marshal()) offset := curve.SizeOfG1AffineUncompressed - for j := range vk.PublicCommitted[i] { - copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicCommitted[i][j]-1].Marshal()) + for j := range vk.PublicAndCommitmentCommitted[i] { + copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicAndCommitmentCommitted[i][j]-1].Marshal()) offset += fr.Bytes } if res, err := fr.Hash(commitmentPrehashSerialized[:offset], []byte(constraint.CommitmentDst), 1); err != nil { diff --git a/backend/groth16/bn254/marshal.go b/backend/groth16/bn254/marshal.go index ea95c71a4c..44af19d184 100644 --- a/backend/groth16/bn254/marshal.go +++ b/backend/groth16/bn254/marshal.go @@ -136,10 +136,10 @@ func (vk *VerifyingKey) writeTo(w io.Writer, raw bool) (int64, error) { return enc.BytesWritten(), err } - if vk.PublicCommitted == nil { - vk.PublicCommitted = [][]int{} // only matters in tests + if vk.PublicAndCommitmentCommitted == nil { + vk.PublicAndCommitmentCommitted = [][]int{} // only matters in tests } - if err := enc.Encode(utils.IntSliceSliceToUint64SliceSlice(vk.PublicCommitted)); err != nil { + if err := enc.Encode(utils.IntSliceSliceToUint64SliceSlice(vk.PublicAndCommitmentCommitted)); err != nil { return enc.BytesWritten(), err } @@ -204,7 +204,7 @@ func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder) if err := dec.Decode(&publicCommitted); err != nil { return dec.BytesRead(), err } - vk.PublicCommitted = utils.Uint64SliceSliceToIntSliceSlice(publicCommitted) + vk.PublicAndCommitmentCommitted = utils.Uint64SliceSliceToIntSliceSlice(publicCommitted) // recompute vk.e (e(α, β)) and -[δ]2, -[γ]2 if err := vk.Precompute(); err != nil { diff --git a/backend/groth16/bn254/marshal_test.go b/backend/groth16/bn254/marshal_test.go index 5a90e4b36f..f94422c159 100644 --- a/backend/groth16/bn254/marshal_test.go +++ b/backend/groth16/bn254/marshal_test.go @@ -122,11 +122,11 @@ func TestVerifyingKeySerialization(t *testing.T) { } if withCommitment { - vk.PublicCommitted = test_utils.Random2DIntSlice(5, 10) // TODO: Use gopter randomization - bases := make([][]curve.G1Affine, len(vk.PublicCommitted)) + vk.PublicAndCommitmentCommitted = test_utils.Random2DIntSlice(5, 10) // TODO: Use gopter randomization + bases := make([][]curve.G1Affine, len(vk.PublicAndCommitmentCommitted)) elem := p1 - for i := 0; i < len(vk.PublicCommitted); i++ { - bases[i] = make([]curve.G1Affine, len(vk.PublicCommitted[i])) + for i := 0; i < len(vk.PublicAndCommitmentCommitted); i++ { + bases[i] = make([]curve.G1Affine, len(vk.PublicAndCommitmentCommitted[i])) for j := range bases[i] { bases[i][j] = elem elem.Add(&elem, &p1) diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index 332d07728c..51ddb0d1fe 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -77,8 +77,8 @@ type VerifyingKey struct { // e(α, β) e curve.GT // not serialized - CommitmentKey pedersen.VerifyingKey - PublicCommitted [][]int // indexes of public committed variables + CommitmentKey pedersen.VerifyingKey + PublicAndCommitmentCommitted [][]int // indexes of public/commitment committed variables } // Setup constructs the SRS @@ -100,8 +100,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) - //nbPrivateCommittedWires, privateCommitted, publicAndCommitmentCommitted := - // commitmentInfo.Interleave(r1cs.GetNbPublicVariables()) // a commitment is itself defined by a hint so the prover considers it private // but the verifier will need to inject the value itself so on the groth16 @@ -163,7 +161,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 - // i = vI + nbPrivateCommittedSeen + nbCommitmentsSeen for i := range A { commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool @@ -295,7 +292,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted(commitmentWires, r1cs.GetNbPublicVariables()) + vk.PublicAndCommitmentCommitted = commitmentInfo.GetPublicAndCommitmentCommitted(commitmentWires, r1cs.GetNbPublicVariables()) // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bn254/verify.go b/backend/groth16/bn254/verify.go index c8ff0ad3da..64c5073266 100644 --- a/backend/groth16/bn254/verify.go +++ b/backend/groth16/bn254/verify.go @@ -39,7 +39,7 @@ var ( // Verify verifies a proof with given VerifyingKey and publicWitness func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { - nbPublicVars := len(vk.G1.K) - len(vk.PublicCommitted) + nbPublicVars := len(vk.G1.K) - len(vk.PublicAndCommitmentCommitted) if len(publicWitness) != nbPublicVars-1 { return fmt.Errorf("invalid witness size, got %d, expected %d (public - ONE_WIRE)", len(publicWitness), len(vk.G1.K)-1) @@ -64,16 +64,16 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { }() maxNbPublicCommitted := 0 - for _, s := range vk.PublicCommitted { // iterate over commitments + for _, s := range vk.PublicAndCommitmentCommitted { // iterate over commitments maxNbPublicCommitted = utils.Max(maxNbPublicCommitted, len(s)) } - commitmentsSerialized := make([]byte, len(vk.PublicCommitted)*fr.Bytes) + commitmentsSerialized := make([]byte, len(vk.PublicAndCommitmentCommitted)*fr.Bytes) commitmentPrehashSerialized := make([]byte, curve.SizeOfG1AffineUncompressed+maxNbPublicCommitted*fr.Bytes) - for i := range vk.PublicCommitted { // solveCommitmentWire + for i := range vk.PublicAndCommitmentCommitted { // solveCommitmentWire copy(commitmentPrehashSerialized, proof.Commitments[i].Marshal()) offset := curve.SizeOfG1AffineUncompressed - for j := range vk.PublicCommitted[i] { - copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicCommitted[i][j]-1].Marshal()) + for j := range vk.PublicAndCommitmentCommitted[i] { + copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicAndCommitmentCommitted[i][j]-1].Marshal()) offset += fr.Bytes } if res, err := fr.Hash(commitmentPrehashSerialized[:offset], []byte(constraint.CommitmentDst), 1); err != nil { diff --git a/backend/groth16/bw6-633/marshal.go b/backend/groth16/bw6-633/marshal.go index c44d794d14..fe3b57de5d 100644 --- a/backend/groth16/bw6-633/marshal.go +++ b/backend/groth16/bw6-633/marshal.go @@ -136,10 +136,10 @@ func (vk *VerifyingKey) writeTo(w io.Writer, raw bool) (int64, error) { return enc.BytesWritten(), err } - if vk.PublicCommitted == nil { - vk.PublicCommitted = [][]int{} // only matters in tests + if vk.PublicAndCommitmentCommitted == nil { + vk.PublicAndCommitmentCommitted = [][]int{} // only matters in tests } - if err := enc.Encode(utils.IntSliceSliceToUint64SliceSlice(vk.PublicCommitted)); err != nil { + if err := enc.Encode(utils.IntSliceSliceToUint64SliceSlice(vk.PublicAndCommitmentCommitted)); err != nil { return enc.BytesWritten(), err } @@ -204,7 +204,7 @@ func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder) if err := dec.Decode(&publicCommitted); err != nil { return dec.BytesRead(), err } - vk.PublicCommitted = utils.Uint64SliceSliceToIntSliceSlice(publicCommitted) + vk.PublicAndCommitmentCommitted = utils.Uint64SliceSliceToIntSliceSlice(publicCommitted) // recompute vk.e (e(α, β)) and -[δ]2, -[γ]2 if err := vk.Precompute(); err != nil { diff --git a/backend/groth16/bw6-633/marshal_test.go b/backend/groth16/bw6-633/marshal_test.go index b1630b93fe..21ae4e9bd1 100644 --- a/backend/groth16/bw6-633/marshal_test.go +++ b/backend/groth16/bw6-633/marshal_test.go @@ -122,11 +122,11 @@ func TestVerifyingKeySerialization(t *testing.T) { } if withCommitment { - vk.PublicCommitted = test_utils.Random2DIntSlice(5, 10) // TODO: Use gopter randomization - bases := make([][]curve.G1Affine, len(vk.PublicCommitted)) + vk.PublicAndCommitmentCommitted = test_utils.Random2DIntSlice(5, 10) // TODO: Use gopter randomization + bases := make([][]curve.G1Affine, len(vk.PublicAndCommitmentCommitted)) elem := p1 - for i := 0; i < len(vk.PublicCommitted); i++ { - bases[i] = make([]curve.G1Affine, len(vk.PublicCommitted[i])) + for i := 0; i < len(vk.PublicAndCommitmentCommitted); i++ { + bases[i] = make([]curve.G1Affine, len(vk.PublicAndCommitmentCommitted[i])) for j := range bases[i] { bases[i][j] = elem elem.Add(&elem, &p1) diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index 4d8575b409..f24acbdd03 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -77,8 +77,8 @@ type VerifyingKey struct { // e(α, β) e curve.GT // not serialized - CommitmentKey pedersen.VerifyingKey - PublicCommitted [][]int // indexes of public committed variables + CommitmentKey pedersen.VerifyingKey + PublicAndCommitmentCommitted [][]int // indexes of public/commitment committed variables } // Setup constructs the SRS @@ -100,8 +100,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) - //nbPrivateCommittedWires, privateCommitted, publicAndCommitmentCommitted := - // commitmentInfo.Interleave(r1cs.GetNbPublicVariables()) // a commitment is itself defined by a hint so the prover considers it private // but the verifier will need to inject the value itself so on the groth16 @@ -163,7 +161,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 - // i = vI + nbPrivateCommittedSeen + nbCommitmentsSeen for i := range A { commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool @@ -295,7 +292,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted(commitmentWires, r1cs.GetNbPublicVariables()) + vk.PublicAndCommitmentCommitted = commitmentInfo.GetPublicAndCommitmentCommitted(commitmentWires, r1cs.GetNbPublicVariables()) // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bw6-633/verify.go b/backend/groth16/bw6-633/verify.go index e5749cd44c..c32a71e6a6 100644 --- a/backend/groth16/bw6-633/verify.go +++ b/backend/groth16/bw6-633/verify.go @@ -38,7 +38,7 @@ var ( // Verify verifies a proof with given VerifyingKey and publicWitness func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { - nbPublicVars := len(vk.G1.K) - len(vk.PublicCommitted) + nbPublicVars := len(vk.G1.K) - len(vk.PublicAndCommitmentCommitted) if len(publicWitness) != nbPublicVars-1 { return fmt.Errorf("invalid witness size, got %d, expected %d (public - ONE_WIRE)", len(publicWitness), len(vk.G1.K)-1) @@ -63,16 +63,16 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { }() maxNbPublicCommitted := 0 - for _, s := range vk.PublicCommitted { // iterate over commitments + for _, s := range vk.PublicAndCommitmentCommitted { // iterate over commitments maxNbPublicCommitted = utils.Max(maxNbPublicCommitted, len(s)) } - commitmentsSerialized := make([]byte, len(vk.PublicCommitted)*fr.Bytes) + commitmentsSerialized := make([]byte, len(vk.PublicAndCommitmentCommitted)*fr.Bytes) commitmentPrehashSerialized := make([]byte, curve.SizeOfG1AffineUncompressed+maxNbPublicCommitted*fr.Bytes) - for i := range vk.PublicCommitted { // solveCommitmentWire + for i := range vk.PublicAndCommitmentCommitted { // solveCommitmentWire copy(commitmentPrehashSerialized, proof.Commitments[i].Marshal()) offset := curve.SizeOfG1AffineUncompressed - for j := range vk.PublicCommitted[i] { - copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicCommitted[i][j]-1].Marshal()) + for j := range vk.PublicAndCommitmentCommitted[i] { + copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicAndCommitmentCommitted[i][j]-1].Marshal()) offset += fr.Bytes } if res, err := fr.Hash(commitmentPrehashSerialized[:offset], []byte(constraint.CommitmentDst), 1); err != nil { diff --git a/backend/groth16/bw6-761/marshal.go b/backend/groth16/bw6-761/marshal.go index 568e050a9e..8b65f44d11 100644 --- a/backend/groth16/bw6-761/marshal.go +++ b/backend/groth16/bw6-761/marshal.go @@ -136,10 +136,10 @@ func (vk *VerifyingKey) writeTo(w io.Writer, raw bool) (int64, error) { return enc.BytesWritten(), err } - if vk.PublicCommitted == nil { - vk.PublicCommitted = [][]int{} // only matters in tests + if vk.PublicAndCommitmentCommitted == nil { + vk.PublicAndCommitmentCommitted = [][]int{} // only matters in tests } - if err := enc.Encode(utils.IntSliceSliceToUint64SliceSlice(vk.PublicCommitted)); err != nil { + if err := enc.Encode(utils.IntSliceSliceToUint64SliceSlice(vk.PublicAndCommitmentCommitted)); err != nil { return enc.BytesWritten(), err } @@ -204,7 +204,7 @@ func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder) if err := dec.Decode(&publicCommitted); err != nil { return dec.BytesRead(), err } - vk.PublicCommitted = utils.Uint64SliceSliceToIntSliceSlice(publicCommitted) + vk.PublicAndCommitmentCommitted = utils.Uint64SliceSliceToIntSliceSlice(publicCommitted) // recompute vk.e (e(α, β)) and -[δ]2, -[γ]2 if err := vk.Precompute(); err != nil { diff --git a/backend/groth16/bw6-761/marshal_test.go b/backend/groth16/bw6-761/marshal_test.go index 158be28ba8..ab5617fcfc 100644 --- a/backend/groth16/bw6-761/marshal_test.go +++ b/backend/groth16/bw6-761/marshal_test.go @@ -122,11 +122,11 @@ func TestVerifyingKeySerialization(t *testing.T) { } if withCommitment { - vk.PublicCommitted = test_utils.Random2DIntSlice(5, 10) // TODO: Use gopter randomization - bases := make([][]curve.G1Affine, len(vk.PublicCommitted)) + vk.PublicAndCommitmentCommitted = test_utils.Random2DIntSlice(5, 10) // TODO: Use gopter randomization + bases := make([][]curve.G1Affine, len(vk.PublicAndCommitmentCommitted)) elem := p1 - for i := 0; i < len(vk.PublicCommitted); i++ { - bases[i] = make([]curve.G1Affine, len(vk.PublicCommitted[i])) + for i := 0; i < len(vk.PublicAndCommitmentCommitted); i++ { + bases[i] = make([]curve.G1Affine, len(vk.PublicAndCommitmentCommitted[i])) for j := range bases[i] { bases[i][j] = elem elem.Add(&elem, &p1) diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index b9fd178500..9123efa717 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -77,8 +77,8 @@ type VerifyingKey struct { // e(α, β) e curve.GT // not serialized - CommitmentKey pedersen.VerifyingKey - PublicCommitted [][]int // indexes of public committed variables + CommitmentKey pedersen.VerifyingKey + PublicAndCommitmentCommitted [][]int // indexes of public/commitment committed variables } // Setup constructs the SRS @@ -100,8 +100,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) - //nbPrivateCommittedWires, privateCommitted, publicAndCommitmentCommitted := - // commitmentInfo.Interleave(r1cs.GetNbPublicVariables()) // a commitment is itself defined by a hint so the prover considers it private // but the verifier will need to inject the value itself so on the groth16 @@ -163,7 +161,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 - // i = vI + nbPrivateCommittedSeen + nbCommitmentsSeen for i := range A { commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool @@ -295,7 +292,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted(commitmentWires, r1cs.GetNbPublicVariables()) + vk.PublicAndCommitmentCommitted = commitmentInfo.GetPublicAndCommitmentCommitted(commitmentWires, r1cs.GetNbPublicVariables()) // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/backend/groth16/bw6-761/verify.go b/backend/groth16/bw6-761/verify.go index 895f006f3a..ca49685a5e 100644 --- a/backend/groth16/bw6-761/verify.go +++ b/backend/groth16/bw6-761/verify.go @@ -38,7 +38,7 @@ var ( // Verify verifies a proof with given VerifyingKey and publicWitness func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { - nbPublicVars := len(vk.G1.K) - len(vk.PublicCommitted) + nbPublicVars := len(vk.G1.K) - len(vk.PublicAndCommitmentCommitted) if len(publicWitness) != nbPublicVars-1 { return fmt.Errorf("invalid witness size, got %d, expected %d (public - ONE_WIRE)", len(publicWitness), len(vk.G1.K)-1) @@ -63,16 +63,16 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { }() maxNbPublicCommitted := 0 - for _, s := range vk.PublicCommitted { // iterate over commitments + for _, s := range vk.PublicAndCommitmentCommitted { // iterate over commitments maxNbPublicCommitted = utils.Max(maxNbPublicCommitted, len(s)) } - commitmentsSerialized := make([]byte, len(vk.PublicCommitted)*fr.Bytes) + commitmentsSerialized := make([]byte, len(vk.PublicAndCommitmentCommitted)*fr.Bytes) commitmentPrehashSerialized := make([]byte, curve.SizeOfG1AffineUncompressed+maxNbPublicCommitted*fr.Bytes) - for i := range vk.PublicCommitted { // solveCommitmentWire + for i := range vk.PublicAndCommitmentCommitted { // solveCommitmentWire copy(commitmentPrehashSerialized, proof.Commitments[i].Marshal()) offset := curve.SizeOfG1AffineUncompressed - for j := range vk.PublicCommitted[i] { - copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicCommitted[i][j]-1].Marshal()) + for j := range vk.PublicAndCommitmentCommitted[i] { + copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicAndCommitmentCommitted[i][j]-1].Marshal()) offset += fr.Bytes } if res, err := fr.Hash(commitmentPrehashSerialized[:offset], []byte(constraint.CommitmentDst), 1); err != nil { diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl index 8f021dbf7a..a89c411594 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl @@ -120,10 +120,10 @@ func (vk *VerifyingKey) writeTo(w io.Writer, raw bool) (int64, error) { return enc.BytesWritten(), err } - if vk.PublicCommitted == nil { - vk.PublicCommitted = [][]int{} // only matters in tests + if vk.PublicAndCommitmentCommitted == nil { + vk.PublicAndCommitmentCommitted = [][]int{} // only matters in tests } - if err := enc.Encode(utils.IntSliceSliceToUint64SliceSlice(vk.PublicCommitted)); err != nil { + if err := enc.Encode(utils.IntSliceSliceToUint64SliceSlice(vk.PublicAndCommitmentCommitted)); err != nil { return enc.BytesWritten(), err } @@ -188,7 +188,7 @@ func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder) if err := dec.Decode(&publicCommitted); err != nil { return dec.BytesRead(), err } - vk.PublicCommitted = utils.Uint64SliceSliceToIntSliceSlice(publicCommitted) + vk.PublicAndCommitmentCommitted = utils.Uint64SliceSliceToIntSliceSlice(publicCommitted) // recompute vk.e (e(α, β)) and -[δ]2, -[γ]2 if err := vk.Precompute(); err != nil { diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl index 01bf38442b..1d4e6bbf8f 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl @@ -60,7 +60,7 @@ type VerifyingKey struct { e curve.GT // not serialized CommitmentKey pedersen.VerifyingKey - PublicCommitted [][]int // indexes of public committed variables + PublicAndCommitmentCommitted [][]int // indexes of public/commitment committed variables } // Setup constructs the SRS @@ -82,8 +82,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { commitmentWires := commitmentInfo.CommitmentIndexes() privateCommitted := commitmentInfo.GetPrivateCommitted() nbPrivateCommittedWires := internal.NbElements(privateCommitted) - //nbPrivateCommittedWires, privateCommitted, publicAndCommitmentCommitted := - // commitmentInfo.Interleave(r1cs.GetNbPublicVariables()) // a commitment is itself defined by a hint so the prover considers it private // but the verifier will need to inject the value itself so on the groth16 @@ -145,7 +143,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { nbPrivateCommittedSeen := 0 // = ∑ᵢ cI[i] nbCommitmentsSeen := 0 - // i = vI + nbPrivateCommittedSeen + nbCommitmentsSeen for i := range A { commitment := -1 // index of the commitment that commits to this variable as a private or commitment value var isCommitment, isPublic bool @@ -277,7 +274,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { return err } - vk.PublicCommitted = commitmentInfo.GetPublicAndCommitmentCommitted(commitmentWires, r1cs.GetNbPublicVariables()) + vk.PublicAndCommitmentCommitted = commitmentInfo.GetPublicAndCommitmentCommitted(commitmentWires, r1cs.GetNbPublicVariables()) // --------------------------------------------------------------------------------------------- // G2 scalars diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl index bae54a008d..f87b9197dd 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl @@ -24,7 +24,7 @@ var ( // Verify verifies a proof with given VerifyingKey and publicWitness func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { - nbPublicVars := len(vk.G1.K) - len(vk.PublicCommitted) + nbPublicVars := len(vk.G1.K) - len(vk.PublicAndCommitmentCommitted) if len(publicWitness) != nbPublicVars-1 { return fmt.Errorf("invalid witness size, got %d, expected %d (public - ONE_WIRE)", len(publicWitness), len(vk.G1.K) - 1) @@ -49,16 +49,16 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { }() maxNbPublicCommitted := 0 - for _, s := range vk.PublicCommitted { // iterate over commitments + for _, s := range vk.PublicAndCommitmentCommitted { // iterate over commitments maxNbPublicCommitted = utils.Max(maxNbPublicCommitted, len(s)) } - commitmentsSerialized := make([]byte, len(vk.PublicCommitted)*fr.Bytes) + commitmentsSerialized := make([]byte, len(vk.PublicAndCommitmentCommitted)*fr.Bytes) commitmentPrehashSerialized := make([]byte, curve.SizeOfG1AffineUncompressed+maxNbPublicCommitted*fr.Bytes) - for i := range vk.PublicCommitted { // solveCommitmentWire + for i := range vk.PublicAndCommitmentCommitted { // solveCommitmentWire copy(commitmentPrehashSerialized, proof.Commitments[i].Marshal()) offset := curve.SizeOfG1AffineUncompressed - for j := range vk.PublicCommitted[i] { - copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicCommitted[i][j]-1].Marshal()) + for j := range vk.PublicAndCommitmentCommitted[i] { + copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicAndCommitmentCommitted[i][j]-1].Marshal()) offset += fr.Bytes } if res, err := fr.Hash(commitmentPrehashSerialized[:offset], []byte(constraint.CommitmentDst), 1); err != nil { diff --git a/internal/generator/backend/template/zkpschemes/groth16/tests/groth16.marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/tests/groth16.marshal.go.tmpl index f84d183473..92c22f0e52 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/tests/groth16.marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/tests/groth16.marshal.go.tmpl @@ -106,11 +106,11 @@ func TestVerifyingKeySerialization(t *testing.T) { } if withCommitment { - vk.PublicCommitted = test_utils.Random2DIntSlice(5, 10) // TODO: Use gopter randomization - bases := make([][]curve.G1Affine, len(vk.PublicCommitted)) + vk.PublicAndCommitmentCommitted = test_utils.Random2DIntSlice(5, 10) // TODO: Use gopter randomization + bases := make([][]curve.G1Affine, len(vk.PublicAndCommitmentCommitted)) elem := p1 - for i := 0; i < len(vk.PublicCommitted); i++ { - bases[i] = make([]curve.G1Affine, len(vk.PublicCommitted[i])) + for i := 0; i < len(vk.PublicAndCommitmentCommitted); i++ { + bases[i] = make([]curve.G1Affine, len(vk.PublicAndCommitmentCommitted[i])) for j := range bases[i] { bases[i][j] = elem elem.Add(&elem, &p1) From 512b096274187a9dce6b80886720e1021ea9b975 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 9 Jun 2023 10:51:49 -0500 Subject: [PATCH 451/464] fix: bn254 multicommit proving keys --- backend/groth16/bn254/marshal.go | 36 +++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/backend/groth16/bn254/marshal.go b/backend/groth16/bn254/marshal.go index ccfdca7ba2..ca1540b031 100644 --- a/backend/groth16/bn254/marshal.go +++ b/backend/groth16/bn254/marshal.go @@ -18,6 +18,7 @@ package groth16 import ( curve "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/pedersen" "github.com/consensys/gnark/internal/utils" "io" ) @@ -258,6 +259,7 @@ func (pk *ProvingKey) writeTo(w io.Writer, raw bool) (int64, error) { pk.NbInfinityB, pk.InfinityA, pk.InfinityB, + uint32(len(pk.CommitmentKeys)), } for _, v := range toEncode { @@ -266,12 +268,21 @@ func (pk *ProvingKey) writeTo(w io.Writer, raw bool) (int64, error) { } } - // TODO pedersen commitment key only implements WriteTo - // missing WriteRawTo - n2, err := pk.CommitmentKey.WriteTo(w) - n += n2 - if err != nil { - return n, err + for i := range pk.CommitmentKeys { + var ( + n2 int64 + err error + ) + if raw { + n2, err = pk.CommitmentKeys[i].WriteRawTo(w) + } else { + n2, err = pk.CommitmentKeys[i].WriteTo(w) + } + + n += n2 + if err != nil { + return n, err + } } return n + enc.BytesWritten(), nil @@ -300,6 +311,7 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) dec := curve.NewDecoder(r, decOptions...) var nbWires uint64 + var nbCommitments uint32 toDecode := []interface{}{ &pk.G1.Alpha, @@ -315,6 +327,7 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) &nbWires, &pk.NbInfinityA, &pk.NbInfinityB, + &nbCommitments, } for _, v := range toDecode { @@ -332,10 +345,13 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) return n + dec.BytesRead(), err } - n2, err := pk.CommitmentKey.ReadFrom(r) - n += n2 - if err != nil { - return n, err + pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitments) + for i := range pk.CommitmentKeys { + n2, err := pk.CommitmentKeys[i].ReadFrom(r) + n += n2 + if err != nil { + return n, err + } } return n + dec.BytesRead(), nil From 3195b6373a0b3a67bd8e51dd0d75ad11138dc599 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 9 Jun 2023 11:17:24 -0500 Subject: [PATCH 452/464] fix: the previous fix --- backend/groth16/bls12-377/marshal.go | 37 ++++++++++++++----- backend/groth16/bls12-381/marshal.go | 37 ++++++++++++++----- backend/groth16/bls24-315/marshal.go | 37 ++++++++++++++----- backend/groth16/bls24-317/marshal.go | 37 ++++++++++++++----- backend/groth16/bn254/marshal.go | 6 ++- backend/groth16/bn254/marshal_test.go | 28 ++++++++++++-- backend/groth16/bw6-633/marshal.go | 37 ++++++++++++++----- backend/groth16/bw6-761/marshal.go | 37 ++++++++++++++----- .../groth16/groth16.marshal.go.tmpl | 36 +++++++++++++----- 9 files changed, 217 insertions(+), 75 deletions(-) diff --git a/backend/groth16/bls12-377/marshal.go b/backend/groth16/bls12-377/marshal.go index 9c4b875746..391ae912ce 100644 --- a/backend/groth16/bls12-377/marshal.go +++ b/backend/groth16/bls12-377/marshal.go @@ -18,6 +18,8 @@ package groth16 import ( curve "github.com/consensys/gnark-crypto/ecc/bls12-377" + + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/pedersen" "github.com/consensys/gnark/internal/utils" "io" ) @@ -258,6 +260,7 @@ func (pk *ProvingKey) writeTo(w io.Writer, raw bool) (int64, error) { pk.NbInfinityB, pk.InfinityA, pk.InfinityB, + uint32(len(pk.CommitmentKeys)), } for _, v := range toEncode { @@ -266,12 +269,21 @@ func (pk *ProvingKey) writeTo(w io.Writer, raw bool) (int64, error) { } } - // TODO pedersen commitment key only implements WriteTo - // missing WriteRawTo - n2, err := pk.CommitmentKey.WriteTo(w) - n += n2 - if err != nil { - return n, err + for i := range pk.CommitmentKeys { + var ( + n2 int64 + err error + ) + if raw { + n2, err = pk.CommitmentKeys[i].WriteRawTo(w) + } else { + n2, err = pk.CommitmentKeys[i].WriteTo(w) + } + + n += n2 + if err != nil { + return n, err + } } return n + enc.BytesWritten(), nil @@ -300,6 +312,7 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) dec := curve.NewDecoder(r, decOptions...) var nbWires uint64 + var nbCommitments uint32 toDecode := []interface{}{ &pk.G1.Alpha, @@ -315,6 +328,7 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) &nbWires, &pk.NbInfinityA, &pk.NbInfinityB, + &nbCommitments, } for _, v := range toDecode { @@ -332,10 +346,13 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) return n + dec.BytesRead(), err } - n2, err := pk.CommitmentKey.ReadFrom(r) - n += n2 - if err != nil { - return n, err + pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitments) + for i := range pk.CommitmentKeys { + n2, err := pk.CommitmentKeys[i].ReadFrom(r) + n += n2 + if err != nil { + return n, err + } } return n + dec.BytesRead(), nil diff --git a/backend/groth16/bls12-381/marshal.go b/backend/groth16/bls12-381/marshal.go index 04adcacffd..44f79fb85e 100644 --- a/backend/groth16/bls12-381/marshal.go +++ b/backend/groth16/bls12-381/marshal.go @@ -18,6 +18,8 @@ package groth16 import ( curve "github.com/consensys/gnark-crypto/ecc/bls12-381" + + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/pedersen" "github.com/consensys/gnark/internal/utils" "io" ) @@ -258,6 +260,7 @@ func (pk *ProvingKey) writeTo(w io.Writer, raw bool) (int64, error) { pk.NbInfinityB, pk.InfinityA, pk.InfinityB, + uint32(len(pk.CommitmentKeys)), } for _, v := range toEncode { @@ -266,12 +269,21 @@ func (pk *ProvingKey) writeTo(w io.Writer, raw bool) (int64, error) { } } - // TODO pedersen commitment key only implements WriteTo - // missing WriteRawTo - n2, err := pk.CommitmentKey.WriteTo(w) - n += n2 - if err != nil { - return n, err + for i := range pk.CommitmentKeys { + var ( + n2 int64 + err error + ) + if raw { + n2, err = pk.CommitmentKeys[i].WriteRawTo(w) + } else { + n2, err = pk.CommitmentKeys[i].WriteTo(w) + } + + n += n2 + if err != nil { + return n, err + } } return n + enc.BytesWritten(), nil @@ -300,6 +312,7 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) dec := curve.NewDecoder(r, decOptions...) var nbWires uint64 + var nbCommitments uint32 toDecode := []interface{}{ &pk.G1.Alpha, @@ -315,6 +328,7 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) &nbWires, &pk.NbInfinityA, &pk.NbInfinityB, + &nbCommitments, } for _, v := range toDecode { @@ -332,10 +346,13 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) return n + dec.BytesRead(), err } - n2, err := pk.CommitmentKey.ReadFrom(r) - n += n2 - if err != nil { - return n, err + pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitments) + for i := range pk.CommitmentKeys { + n2, err := pk.CommitmentKeys[i].ReadFrom(r) + n += n2 + if err != nil { + return n, err + } } return n + dec.BytesRead(), nil diff --git a/backend/groth16/bls24-315/marshal.go b/backend/groth16/bls24-315/marshal.go index 1c745134c8..51bfcf1069 100644 --- a/backend/groth16/bls24-315/marshal.go +++ b/backend/groth16/bls24-315/marshal.go @@ -18,6 +18,8 @@ package groth16 import ( curve "github.com/consensys/gnark-crypto/ecc/bls24-315" + + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/pedersen" "github.com/consensys/gnark/internal/utils" "io" ) @@ -258,6 +260,7 @@ func (pk *ProvingKey) writeTo(w io.Writer, raw bool) (int64, error) { pk.NbInfinityB, pk.InfinityA, pk.InfinityB, + uint32(len(pk.CommitmentKeys)), } for _, v := range toEncode { @@ -266,12 +269,21 @@ func (pk *ProvingKey) writeTo(w io.Writer, raw bool) (int64, error) { } } - // TODO pedersen commitment key only implements WriteTo - // missing WriteRawTo - n2, err := pk.CommitmentKey.WriteTo(w) - n += n2 - if err != nil { - return n, err + for i := range pk.CommitmentKeys { + var ( + n2 int64 + err error + ) + if raw { + n2, err = pk.CommitmentKeys[i].WriteRawTo(w) + } else { + n2, err = pk.CommitmentKeys[i].WriteTo(w) + } + + n += n2 + if err != nil { + return n, err + } } return n + enc.BytesWritten(), nil @@ -300,6 +312,7 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) dec := curve.NewDecoder(r, decOptions...) var nbWires uint64 + var nbCommitments uint32 toDecode := []interface{}{ &pk.G1.Alpha, @@ -315,6 +328,7 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) &nbWires, &pk.NbInfinityA, &pk.NbInfinityB, + &nbCommitments, } for _, v := range toDecode { @@ -332,10 +346,13 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) return n + dec.BytesRead(), err } - n2, err := pk.CommitmentKey.ReadFrom(r) - n += n2 - if err != nil { - return n, err + pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitments) + for i := range pk.CommitmentKeys { + n2, err := pk.CommitmentKeys[i].ReadFrom(r) + n += n2 + if err != nil { + return n, err + } } return n + dec.BytesRead(), nil diff --git a/backend/groth16/bls24-317/marshal.go b/backend/groth16/bls24-317/marshal.go index c4e62d286f..e795ae4598 100644 --- a/backend/groth16/bls24-317/marshal.go +++ b/backend/groth16/bls24-317/marshal.go @@ -18,6 +18,8 @@ package groth16 import ( curve "github.com/consensys/gnark-crypto/ecc/bls24-317" + + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/pedersen" "github.com/consensys/gnark/internal/utils" "io" ) @@ -258,6 +260,7 @@ func (pk *ProvingKey) writeTo(w io.Writer, raw bool) (int64, error) { pk.NbInfinityB, pk.InfinityA, pk.InfinityB, + uint32(len(pk.CommitmentKeys)), } for _, v := range toEncode { @@ -266,12 +269,21 @@ func (pk *ProvingKey) writeTo(w io.Writer, raw bool) (int64, error) { } } - // TODO pedersen commitment key only implements WriteTo - // missing WriteRawTo - n2, err := pk.CommitmentKey.WriteTo(w) - n += n2 - if err != nil { - return n, err + for i := range pk.CommitmentKeys { + var ( + n2 int64 + err error + ) + if raw { + n2, err = pk.CommitmentKeys[i].WriteRawTo(w) + } else { + n2, err = pk.CommitmentKeys[i].WriteTo(w) + } + + n += n2 + if err != nil { + return n, err + } } return n + enc.BytesWritten(), nil @@ -300,6 +312,7 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) dec := curve.NewDecoder(r, decOptions...) var nbWires uint64 + var nbCommitments uint32 toDecode := []interface{}{ &pk.G1.Alpha, @@ -315,6 +328,7 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) &nbWires, &pk.NbInfinityA, &pk.NbInfinityB, + &nbCommitments, } for _, v := range toDecode { @@ -332,10 +346,13 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) return n + dec.BytesRead(), err } - n2, err := pk.CommitmentKey.ReadFrom(r) - n += n2 - if err != nil { - return n, err + pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitments) + for i := range pk.CommitmentKeys { + n2, err := pk.CommitmentKeys[i].ReadFrom(r) + n += n2 + if err != nil { + return n, err + } } return n + dec.BytesRead(), nil diff --git a/backend/groth16/bn254/marshal.go b/backend/groth16/bn254/marshal.go index ca1540b031..37a7ea97af 100644 --- a/backend/groth16/bn254/marshal.go +++ b/backend/groth16/bn254/marshal.go @@ -19,6 +19,7 @@ package groth16 import ( curve "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr/pedersen" + "github.com/consensys/gnark/internal/utils" "io" ) @@ -327,7 +328,6 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) &nbWires, &pk.NbInfinityA, &pk.NbInfinityB, - &nbCommitments, } for _, v := range toDecode { @@ -344,7 +344,9 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) if err := dec.Decode(&pk.InfinityB); err != nil { return n + dec.BytesRead(), err } - + if err := dec.Decode(&nbCommitments); err != nil { + return n + dec.BytesRead(), err + } pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitments) for i := range pk.CommitmentKeys { n2, err := pk.CommitmentKeys[i].ReadFrom(r) diff --git a/backend/groth16/bn254/marshal_test.go b/backend/groth16/bn254/marshal_test.go index f94422c159..8d138402b5 100644 --- a/backend/groth16/bn254/marshal_test.go +++ b/backend/groth16/bn254/marshal_test.go @@ -17,13 +17,15 @@ package groth16 import ( + "fmt" curve "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" - "github.com/consensys/gnark-crypto/ecc/bn254/fr/pedersen" "github.com/consensys/gnark/backend/groth16/internal/test_utils" + "github.com/google/go-cmp/cmp" + "github.com/leanovate/gopter/gen" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "bytes" "math/big" @@ -80,6 +82,9 @@ func TestProofSerialization(t *testing.T) { return false } + fmt.Println("compressed diff", cmp.Diff(proof, pCompressed)) + fmt.Println("raw diff", cmp.Diff(proof, pRaw)) + return reflect.DeepEqual(&proof, &pCompressed) && reflect.DeepEqual(&proof, &pRaw) }, GenG1(), @@ -203,7 +208,8 @@ func TestProvingKeySerialization(t *testing.T) { properties := gopter.NewProperties(parameters) properties.Property("ProvingKey -> writer -> reader -> ProvingKey should stay constant", prop.ForAll( - func(p1 curve.G1Affine, p2 curve.G2Affine) bool { + func(p1 curve.G1Affine, p2 curve.G2Affine, nbCommitment int) bool { + fmt.Println(nbCommitment) var pk, pkCompressed, pkRaw ProvingKey // create a random pk @@ -232,6 +238,19 @@ func TestProvingKeySerialization(t *testing.T) { pk.InfinityB = make([]bool, nbWires) pk.InfinityA[2] = true + pedersenBasis := make([]curve.G1Affine, nbCommitment) + pedersenBases := make([][]curve.G1Affine, nbCommitment) + pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitment) + for i := range pedersenBasis { + pedersenBasis[i] = p1 + pedersenBases[i] = pedersenBasis[:i+1] + } + { + var err error + pk.CommitmentKeys, _, err = pedersen.Setup(pedersenBases...) + require.NoError(t, err) + } + var bufCompressed bytes.Buffer written, err := pk.WriteTo(&bufCompressed) if err != nil { @@ -268,10 +287,13 @@ func TestProvingKeySerialization(t *testing.T) { return false } + //fmt.Println("raw diff", cmp.Diff(pk, pkRaw)) + return reflect.DeepEqual(&pk, &pkCompressed) && reflect.DeepEqual(&pk, &pkRaw) }, GenG1(), GenG2(), + gen.IntRange(0, 2), )) properties.TestingRun(t, gopter.ConsoleReporter(false)) diff --git a/backend/groth16/bw6-633/marshal.go b/backend/groth16/bw6-633/marshal.go index 5e3d920a1b..467055c05b 100644 --- a/backend/groth16/bw6-633/marshal.go +++ b/backend/groth16/bw6-633/marshal.go @@ -18,6 +18,8 @@ package groth16 import ( curve "github.com/consensys/gnark-crypto/ecc/bw6-633" + + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/pedersen" "github.com/consensys/gnark/internal/utils" "io" ) @@ -258,6 +260,7 @@ func (pk *ProvingKey) writeTo(w io.Writer, raw bool) (int64, error) { pk.NbInfinityB, pk.InfinityA, pk.InfinityB, + uint32(len(pk.CommitmentKeys)), } for _, v := range toEncode { @@ -266,12 +269,21 @@ func (pk *ProvingKey) writeTo(w io.Writer, raw bool) (int64, error) { } } - // TODO pedersen commitment key only implements WriteTo - // missing WriteRawTo - n2, err := pk.CommitmentKey.WriteTo(w) - n += n2 - if err != nil { - return n, err + for i := range pk.CommitmentKeys { + var ( + n2 int64 + err error + ) + if raw { + n2, err = pk.CommitmentKeys[i].WriteRawTo(w) + } else { + n2, err = pk.CommitmentKeys[i].WriteTo(w) + } + + n += n2 + if err != nil { + return n, err + } } return n + enc.BytesWritten(), nil @@ -300,6 +312,7 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) dec := curve.NewDecoder(r, decOptions...) var nbWires uint64 + var nbCommitments uint32 toDecode := []interface{}{ &pk.G1.Alpha, @@ -315,6 +328,7 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) &nbWires, &pk.NbInfinityA, &pk.NbInfinityB, + &nbCommitments, } for _, v := range toDecode { @@ -332,10 +346,13 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) return n + dec.BytesRead(), err } - n2, err := pk.CommitmentKey.ReadFrom(r) - n += n2 - if err != nil { - return n, err + pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitments) + for i := range pk.CommitmentKeys { + n2, err := pk.CommitmentKeys[i].ReadFrom(r) + n += n2 + if err != nil { + return n, err + } } return n + dec.BytesRead(), nil diff --git a/backend/groth16/bw6-761/marshal.go b/backend/groth16/bw6-761/marshal.go index 78d4225b5a..229173563b 100644 --- a/backend/groth16/bw6-761/marshal.go +++ b/backend/groth16/bw6-761/marshal.go @@ -18,6 +18,8 @@ package groth16 import ( curve "github.com/consensys/gnark-crypto/ecc/bw6-761" + + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/pedersen" "github.com/consensys/gnark/internal/utils" "io" ) @@ -258,6 +260,7 @@ func (pk *ProvingKey) writeTo(w io.Writer, raw bool) (int64, error) { pk.NbInfinityB, pk.InfinityA, pk.InfinityB, + uint32(len(pk.CommitmentKeys)), } for _, v := range toEncode { @@ -266,12 +269,21 @@ func (pk *ProvingKey) writeTo(w io.Writer, raw bool) (int64, error) { } } - // TODO pedersen commitment key only implements WriteTo - // missing WriteRawTo - n2, err := pk.CommitmentKey.WriteTo(w) - n += n2 - if err != nil { - return n, err + for i := range pk.CommitmentKeys { + var ( + n2 int64 + err error + ) + if raw { + n2, err = pk.CommitmentKeys[i].WriteRawTo(w) + } else { + n2, err = pk.CommitmentKeys[i].WriteTo(w) + } + + n += n2 + if err != nil { + return n, err + } } return n + enc.BytesWritten(), nil @@ -300,6 +312,7 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) dec := curve.NewDecoder(r, decOptions...) var nbWires uint64 + var nbCommitments uint32 toDecode := []interface{}{ &pk.G1.Alpha, @@ -315,6 +328,7 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) &nbWires, &pk.NbInfinityA, &pk.NbInfinityB, + &nbCommitments, } for _, v := range toDecode { @@ -332,10 +346,13 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) return n + dec.BytesRead(), err } - n2, err := pk.CommitmentKey.ReadFrom(r) - n += n2 - if err != nil { - return n, err + pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitments) + for i := range pk.CommitmentKeys { + n2, err := pk.CommitmentKeys[i].ReadFrom(r) + n += n2 + if err != nil { + return n, err + } } return n + dec.BytesRead(), nil diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl index 98933e2922..84bb33db42 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl @@ -1,5 +1,6 @@ import ( {{ template "import_curve" . }} + {{ template "import_pedersen" . }} "github.com/consensys/gnark/internal/utils" "io" ) @@ -245,6 +246,7 @@ func (pk *ProvingKey) writeTo(w io.Writer, raw bool) (int64, error) { pk.NbInfinityB, pk.InfinityA, pk.InfinityB, + uint32(len(pk.CommitmentKeys)), } for _, v := range toEncode { @@ -253,12 +255,21 @@ func (pk *ProvingKey) writeTo(w io.Writer, raw bool) (int64, error) { } } - // TODO pedersen commitment key only implements WriteTo - // missing WriteRawTo - n2, err := pk.CommitmentKey.WriteTo(w) - n += n2 - if err != nil { - return n, err + for i := range pk.CommitmentKeys { + var ( + n2 int64 + err error + ) + if raw { + n2, err = pk.CommitmentKeys[i].WriteRawTo(w) + } else { + n2, err = pk.CommitmentKeys[i].WriteTo(w) + } + + n += n2 + if err != nil { + return n, err + } } return n + enc.BytesWritten(), nil @@ -288,6 +299,7 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) dec := curve.NewDecoder(r, decOptions...) var nbWires uint64 + var nbCommitments uint32 toDecode := []interface{}{ &pk.G1.Alpha, @@ -303,6 +315,7 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) &nbWires, &pk.NbInfinityA, &pk.NbInfinityB, + &nbCommitments, } for _, v := range toDecode { @@ -320,10 +333,13 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) return n + dec.BytesRead(), err } - n2, err := pk.CommitmentKey.ReadFrom(r) - n += n2 - if err != nil { - return n, err + pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitments) + for i := range pk.CommitmentKeys { + n2, err := pk.CommitmentKeys[i].ReadFrom(r) + n += n2 + if err != nil { + return n, err + } } return n + dec.BytesRead(), nil From 3de391c28cdc24b71fbd16275f90ca7f70de8015 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 9 Jun 2023 11:21:44 -0500 Subject: [PATCH 453/464] build generify changes --- backend/groth16/bls12-377/marshal.go | 4 +++- backend/groth16/bls12-377/marshal_test.go | 18 ++++++++++++++++- backend/groth16/bls12-381/marshal.go | 4 +++- backend/groth16/bls12-381/marshal_test.go | 18 ++++++++++++++++- backend/groth16/bls24-315/marshal.go | 4 +++- backend/groth16/bls24-315/marshal_test.go | 18 ++++++++++++++++- backend/groth16/bls24-317/marshal.go | 4 +++- backend/groth16/bls24-317/marshal_test.go | 18 ++++++++++++++++- backend/groth16/bn254/marshal.go | 3 ++- backend/groth16/bn254/marshal_test.go | 12 +++-------- backend/groth16/bw6-633/marshal.go | 4 +++- backend/groth16/bw6-633/marshal_test.go | 18 ++++++++++++++++- backend/groth16/bw6-761/marshal.go | 4 +++- backend/groth16/bw6-761/marshal_test.go | 18 ++++++++++++++++- .../groth16/groth16.marshal.go.tmpl | 4 +++- .../groth16/tests/groth16.marshal.go.tmpl | 20 +++++++++++++++++-- 16 files changed, 146 insertions(+), 25 deletions(-) diff --git a/backend/groth16/bls12-377/marshal.go b/backend/groth16/bls12-377/marshal.go index 391ae912ce..bec919254c 100644 --- a/backend/groth16/bls12-377/marshal.go +++ b/backend/groth16/bls12-377/marshal.go @@ -328,7 +328,6 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) &nbWires, &pk.NbInfinityA, &pk.NbInfinityB, - &nbCommitments, } for _, v := range toDecode { @@ -345,6 +344,9 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) if err := dec.Decode(&pk.InfinityB); err != nil { return n + dec.BytesRead(), err } + if err := dec.Decode(&nbCommitments); err != nil { + return n + dec.BytesRead(), err + } pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitments) for i := range pk.CommitmentKeys { diff --git a/backend/groth16/bls12-377/marshal_test.go b/backend/groth16/bls12-377/marshal_test.go index d4a135ee47..b5fe628704 100644 --- a/backend/groth16/bls12-377/marshal_test.go +++ b/backend/groth16/bls12-377/marshal_test.go @@ -24,12 +24,14 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/pedersen" "github.com/consensys/gnark/backend/groth16/internal/test_utils" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "bytes" "math/big" "reflect" "github.com/leanovate/gopter" + "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" "testing" @@ -203,7 +205,7 @@ func TestProvingKeySerialization(t *testing.T) { properties := gopter.NewProperties(parameters) properties.Property("ProvingKey -> writer -> reader -> ProvingKey should stay constant", prop.ForAll( - func(p1 curve.G1Affine, p2 curve.G2Affine) bool { + func(p1 curve.G1Affine, p2 curve.G2Affine, nbCommitment int) bool { var pk, pkCompressed, pkRaw ProvingKey // create a random pk @@ -232,6 +234,19 @@ func TestProvingKeySerialization(t *testing.T) { pk.InfinityB = make([]bool, nbWires) pk.InfinityA[2] = true + pedersenBasis := make([]curve.G1Affine, nbCommitment) + pedersenBases := make([][]curve.G1Affine, nbCommitment) + pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitment) + for i := range pedersenBasis { + pedersenBasis[i] = p1 + pedersenBases[i] = pedersenBasis[:i+1] + } + { + var err error + pk.CommitmentKeys, _, err = pedersen.Setup(pedersenBases...) + require.NoError(t, err) + } + var bufCompressed bytes.Buffer written, err := pk.WriteTo(&bufCompressed) if err != nil { @@ -272,6 +287,7 @@ func TestProvingKeySerialization(t *testing.T) { }, GenG1(), GenG2(), + gen.IntRange(0, 2), )) properties.TestingRun(t, gopter.ConsoleReporter(false)) diff --git a/backend/groth16/bls12-381/marshal.go b/backend/groth16/bls12-381/marshal.go index 44f79fb85e..5a51575c78 100644 --- a/backend/groth16/bls12-381/marshal.go +++ b/backend/groth16/bls12-381/marshal.go @@ -328,7 +328,6 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) &nbWires, &pk.NbInfinityA, &pk.NbInfinityB, - &nbCommitments, } for _, v := range toDecode { @@ -345,6 +344,9 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) if err := dec.Decode(&pk.InfinityB); err != nil { return n + dec.BytesRead(), err } + if err := dec.Decode(&nbCommitments); err != nil { + return n + dec.BytesRead(), err + } pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitments) for i := range pk.CommitmentKeys { diff --git a/backend/groth16/bls12-381/marshal_test.go b/backend/groth16/bls12-381/marshal_test.go index eb678c2242..55d8c0856f 100644 --- a/backend/groth16/bls12-381/marshal_test.go +++ b/backend/groth16/bls12-381/marshal_test.go @@ -24,12 +24,14 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/pedersen" "github.com/consensys/gnark/backend/groth16/internal/test_utils" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "bytes" "math/big" "reflect" "github.com/leanovate/gopter" + "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" "testing" @@ -203,7 +205,7 @@ func TestProvingKeySerialization(t *testing.T) { properties := gopter.NewProperties(parameters) properties.Property("ProvingKey -> writer -> reader -> ProvingKey should stay constant", prop.ForAll( - func(p1 curve.G1Affine, p2 curve.G2Affine) bool { + func(p1 curve.G1Affine, p2 curve.G2Affine, nbCommitment int) bool { var pk, pkCompressed, pkRaw ProvingKey // create a random pk @@ -232,6 +234,19 @@ func TestProvingKeySerialization(t *testing.T) { pk.InfinityB = make([]bool, nbWires) pk.InfinityA[2] = true + pedersenBasis := make([]curve.G1Affine, nbCommitment) + pedersenBases := make([][]curve.G1Affine, nbCommitment) + pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitment) + for i := range pedersenBasis { + pedersenBasis[i] = p1 + pedersenBases[i] = pedersenBasis[:i+1] + } + { + var err error + pk.CommitmentKeys, _, err = pedersen.Setup(pedersenBases...) + require.NoError(t, err) + } + var bufCompressed bytes.Buffer written, err := pk.WriteTo(&bufCompressed) if err != nil { @@ -272,6 +287,7 @@ func TestProvingKeySerialization(t *testing.T) { }, GenG1(), GenG2(), + gen.IntRange(0, 2), )) properties.TestingRun(t, gopter.ConsoleReporter(false)) diff --git a/backend/groth16/bls24-315/marshal.go b/backend/groth16/bls24-315/marshal.go index 51bfcf1069..3da8e55772 100644 --- a/backend/groth16/bls24-315/marshal.go +++ b/backend/groth16/bls24-315/marshal.go @@ -328,7 +328,6 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) &nbWires, &pk.NbInfinityA, &pk.NbInfinityB, - &nbCommitments, } for _, v := range toDecode { @@ -345,6 +344,9 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) if err := dec.Decode(&pk.InfinityB); err != nil { return n + dec.BytesRead(), err } + if err := dec.Decode(&nbCommitments); err != nil { + return n + dec.BytesRead(), err + } pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitments) for i := range pk.CommitmentKeys { diff --git a/backend/groth16/bls24-315/marshal_test.go b/backend/groth16/bls24-315/marshal_test.go index 2692774253..ecdd8b4ea1 100644 --- a/backend/groth16/bls24-315/marshal_test.go +++ b/backend/groth16/bls24-315/marshal_test.go @@ -24,12 +24,14 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/pedersen" "github.com/consensys/gnark/backend/groth16/internal/test_utils" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "bytes" "math/big" "reflect" "github.com/leanovate/gopter" + "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" "testing" @@ -203,7 +205,7 @@ func TestProvingKeySerialization(t *testing.T) { properties := gopter.NewProperties(parameters) properties.Property("ProvingKey -> writer -> reader -> ProvingKey should stay constant", prop.ForAll( - func(p1 curve.G1Affine, p2 curve.G2Affine) bool { + func(p1 curve.G1Affine, p2 curve.G2Affine, nbCommitment int) bool { var pk, pkCompressed, pkRaw ProvingKey // create a random pk @@ -232,6 +234,19 @@ func TestProvingKeySerialization(t *testing.T) { pk.InfinityB = make([]bool, nbWires) pk.InfinityA[2] = true + pedersenBasis := make([]curve.G1Affine, nbCommitment) + pedersenBases := make([][]curve.G1Affine, nbCommitment) + pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitment) + for i := range pedersenBasis { + pedersenBasis[i] = p1 + pedersenBases[i] = pedersenBasis[:i+1] + } + { + var err error + pk.CommitmentKeys, _, err = pedersen.Setup(pedersenBases...) + require.NoError(t, err) + } + var bufCompressed bytes.Buffer written, err := pk.WriteTo(&bufCompressed) if err != nil { @@ -272,6 +287,7 @@ func TestProvingKeySerialization(t *testing.T) { }, GenG1(), GenG2(), + gen.IntRange(0, 2), )) properties.TestingRun(t, gopter.ConsoleReporter(false)) diff --git a/backend/groth16/bls24-317/marshal.go b/backend/groth16/bls24-317/marshal.go index e795ae4598..75deea5847 100644 --- a/backend/groth16/bls24-317/marshal.go +++ b/backend/groth16/bls24-317/marshal.go @@ -328,7 +328,6 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) &nbWires, &pk.NbInfinityA, &pk.NbInfinityB, - &nbCommitments, } for _, v := range toDecode { @@ -345,6 +344,9 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) if err := dec.Decode(&pk.InfinityB); err != nil { return n + dec.BytesRead(), err } + if err := dec.Decode(&nbCommitments); err != nil { + return n + dec.BytesRead(), err + } pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitments) for i := range pk.CommitmentKeys { diff --git a/backend/groth16/bls24-317/marshal_test.go b/backend/groth16/bls24-317/marshal_test.go index cb58134756..860e08725c 100644 --- a/backend/groth16/bls24-317/marshal_test.go +++ b/backend/groth16/bls24-317/marshal_test.go @@ -24,12 +24,14 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/pedersen" "github.com/consensys/gnark/backend/groth16/internal/test_utils" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "bytes" "math/big" "reflect" "github.com/leanovate/gopter" + "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" "testing" @@ -203,7 +205,7 @@ func TestProvingKeySerialization(t *testing.T) { properties := gopter.NewProperties(parameters) properties.Property("ProvingKey -> writer -> reader -> ProvingKey should stay constant", prop.ForAll( - func(p1 curve.G1Affine, p2 curve.G2Affine) bool { + func(p1 curve.G1Affine, p2 curve.G2Affine, nbCommitment int) bool { var pk, pkCompressed, pkRaw ProvingKey // create a random pk @@ -232,6 +234,19 @@ func TestProvingKeySerialization(t *testing.T) { pk.InfinityB = make([]bool, nbWires) pk.InfinityA[2] = true + pedersenBasis := make([]curve.G1Affine, nbCommitment) + pedersenBases := make([][]curve.G1Affine, nbCommitment) + pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitment) + for i := range pedersenBasis { + pedersenBasis[i] = p1 + pedersenBases[i] = pedersenBasis[:i+1] + } + { + var err error + pk.CommitmentKeys, _, err = pedersen.Setup(pedersenBases...) + require.NoError(t, err) + } + var bufCompressed bytes.Buffer written, err := pk.WriteTo(&bufCompressed) if err != nil { @@ -272,6 +287,7 @@ func TestProvingKeySerialization(t *testing.T) { }, GenG1(), GenG2(), + gen.IntRange(0, 2), )) properties.TestingRun(t, gopter.ConsoleReporter(false)) diff --git a/backend/groth16/bn254/marshal.go b/backend/groth16/bn254/marshal.go index 37a7ea97af..0a310d6d15 100644 --- a/backend/groth16/bn254/marshal.go +++ b/backend/groth16/bn254/marshal.go @@ -18,8 +18,8 @@ package groth16 import ( curve "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark-crypto/ecc/bn254/fr/pedersen" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/pedersen" "github.com/consensys/gnark/internal/utils" "io" ) @@ -347,6 +347,7 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) if err := dec.Decode(&nbCommitments); err != nil { return n + dec.BytesRead(), err } + pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitments) for i := range pk.CommitmentKeys { n2, err := pk.CommitmentKeys[i].ReadFrom(r) diff --git a/backend/groth16/bn254/marshal_test.go b/backend/groth16/bn254/marshal_test.go index 8d138402b5..ff9d807805 100644 --- a/backend/groth16/bn254/marshal_test.go +++ b/backend/groth16/bn254/marshal_test.go @@ -17,13 +17,12 @@ package groth16 import ( - "fmt" curve "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/pedersen" "github.com/consensys/gnark/backend/groth16/internal/test_utils" - "github.com/google/go-cmp/cmp" - "github.com/leanovate/gopter/gen" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -32,6 +31,7 @@ import ( "reflect" "github.com/leanovate/gopter" + "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" "testing" @@ -82,9 +82,6 @@ func TestProofSerialization(t *testing.T) { return false } - fmt.Println("compressed diff", cmp.Diff(proof, pCompressed)) - fmt.Println("raw diff", cmp.Diff(proof, pRaw)) - return reflect.DeepEqual(&proof, &pCompressed) && reflect.DeepEqual(&proof, &pRaw) }, GenG1(), @@ -209,7 +206,6 @@ func TestProvingKeySerialization(t *testing.T) { properties.Property("ProvingKey -> writer -> reader -> ProvingKey should stay constant", prop.ForAll( func(p1 curve.G1Affine, p2 curve.G2Affine, nbCommitment int) bool { - fmt.Println(nbCommitment) var pk, pkCompressed, pkRaw ProvingKey // create a random pk @@ -287,8 +283,6 @@ func TestProvingKeySerialization(t *testing.T) { return false } - //fmt.Println("raw diff", cmp.Diff(pk, pkRaw)) - return reflect.DeepEqual(&pk, &pkCompressed) && reflect.DeepEqual(&pk, &pkRaw) }, GenG1(), diff --git a/backend/groth16/bw6-633/marshal.go b/backend/groth16/bw6-633/marshal.go index 467055c05b..edca7ba642 100644 --- a/backend/groth16/bw6-633/marshal.go +++ b/backend/groth16/bw6-633/marshal.go @@ -328,7 +328,6 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) &nbWires, &pk.NbInfinityA, &pk.NbInfinityB, - &nbCommitments, } for _, v := range toDecode { @@ -345,6 +344,9 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) if err := dec.Decode(&pk.InfinityB); err != nil { return n + dec.BytesRead(), err } + if err := dec.Decode(&nbCommitments); err != nil { + return n + dec.BytesRead(), err + } pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitments) for i := range pk.CommitmentKeys { diff --git a/backend/groth16/bw6-633/marshal_test.go b/backend/groth16/bw6-633/marshal_test.go index 21ae4e9bd1..9e1c0f0728 100644 --- a/backend/groth16/bw6-633/marshal_test.go +++ b/backend/groth16/bw6-633/marshal_test.go @@ -24,12 +24,14 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/pedersen" "github.com/consensys/gnark/backend/groth16/internal/test_utils" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "bytes" "math/big" "reflect" "github.com/leanovate/gopter" + "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" "testing" @@ -203,7 +205,7 @@ func TestProvingKeySerialization(t *testing.T) { properties := gopter.NewProperties(parameters) properties.Property("ProvingKey -> writer -> reader -> ProvingKey should stay constant", prop.ForAll( - func(p1 curve.G1Affine, p2 curve.G2Affine) bool { + func(p1 curve.G1Affine, p2 curve.G2Affine, nbCommitment int) bool { var pk, pkCompressed, pkRaw ProvingKey // create a random pk @@ -232,6 +234,19 @@ func TestProvingKeySerialization(t *testing.T) { pk.InfinityB = make([]bool, nbWires) pk.InfinityA[2] = true + pedersenBasis := make([]curve.G1Affine, nbCommitment) + pedersenBases := make([][]curve.G1Affine, nbCommitment) + pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitment) + for i := range pedersenBasis { + pedersenBasis[i] = p1 + pedersenBases[i] = pedersenBasis[:i+1] + } + { + var err error + pk.CommitmentKeys, _, err = pedersen.Setup(pedersenBases...) + require.NoError(t, err) + } + var bufCompressed bytes.Buffer written, err := pk.WriteTo(&bufCompressed) if err != nil { @@ -272,6 +287,7 @@ func TestProvingKeySerialization(t *testing.T) { }, GenG1(), GenG2(), + gen.IntRange(0, 2), )) properties.TestingRun(t, gopter.ConsoleReporter(false)) diff --git a/backend/groth16/bw6-761/marshal.go b/backend/groth16/bw6-761/marshal.go index 229173563b..6f072bc90e 100644 --- a/backend/groth16/bw6-761/marshal.go +++ b/backend/groth16/bw6-761/marshal.go @@ -328,7 +328,6 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) &nbWires, &pk.NbInfinityA, &pk.NbInfinityB, - &nbCommitments, } for _, v := range toDecode { @@ -345,6 +344,9 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) if err := dec.Decode(&pk.InfinityB); err != nil { return n + dec.BytesRead(), err } + if err := dec.Decode(&nbCommitments); err != nil { + return n + dec.BytesRead(), err + } pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitments) for i := range pk.CommitmentKeys { diff --git a/backend/groth16/bw6-761/marshal_test.go b/backend/groth16/bw6-761/marshal_test.go index ab5617fcfc..36e5f692a4 100644 --- a/backend/groth16/bw6-761/marshal_test.go +++ b/backend/groth16/bw6-761/marshal_test.go @@ -24,12 +24,14 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/pedersen" "github.com/consensys/gnark/backend/groth16/internal/test_utils" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "bytes" "math/big" "reflect" "github.com/leanovate/gopter" + "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" "testing" @@ -203,7 +205,7 @@ func TestProvingKeySerialization(t *testing.T) { properties := gopter.NewProperties(parameters) properties.Property("ProvingKey -> writer -> reader -> ProvingKey should stay constant", prop.ForAll( - func(p1 curve.G1Affine, p2 curve.G2Affine) bool { + func(p1 curve.G1Affine, p2 curve.G2Affine, nbCommitment int) bool { var pk, pkCompressed, pkRaw ProvingKey // create a random pk @@ -232,6 +234,19 @@ func TestProvingKeySerialization(t *testing.T) { pk.InfinityB = make([]bool, nbWires) pk.InfinityA[2] = true + pedersenBasis := make([]curve.G1Affine, nbCommitment) + pedersenBases := make([][]curve.G1Affine, nbCommitment) + pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitment) + for i := range pedersenBasis { + pedersenBasis[i] = p1 + pedersenBases[i] = pedersenBasis[:i+1] + } + { + var err error + pk.CommitmentKeys, _, err = pedersen.Setup(pedersenBases...) + require.NoError(t, err) + } + var bufCompressed bytes.Buffer written, err := pk.WriteTo(&bufCompressed) if err != nil { @@ -272,6 +287,7 @@ func TestProvingKeySerialization(t *testing.T) { }, GenG1(), GenG2(), + gen.IntRange(0, 2), )) properties.TestingRun(t, gopter.ConsoleReporter(false)) diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl index 84bb33db42..eaa9835d95 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl @@ -315,7 +315,6 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) &nbWires, &pk.NbInfinityA, &pk.NbInfinityB, - &nbCommitments, } for _, v := range toDecode { @@ -332,6 +331,9 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) if err := dec.Decode(&pk.InfinityB); err != nil { return n + dec.BytesRead(), err } + if err := dec.Decode(&nbCommitments); err != nil { + return n + dec.BytesRead(), err + } pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitments) for i := range pk.CommitmentKeys { diff --git a/internal/generator/backend/template/zkpschemes/groth16/tests/groth16.marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/tests/groth16.marshal.go.tmpl index 92c22f0e52..1366e7ac92 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/tests/groth16.marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/tests/groth16.marshal.go.tmpl @@ -5,6 +5,7 @@ import ( {{ template "import_pedersen" . }} "github.com/consensys/gnark/backend/groth16/internal/test_utils" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "bytes" "math/big" @@ -12,6 +13,7 @@ import ( "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" + "github.com/leanovate/gopter/gen" "testing" ) @@ -189,7 +191,7 @@ func TestProvingKeySerialization(t *testing.T) { properties := gopter.NewProperties(parameters) properties.Property("ProvingKey -> writer -> reader -> ProvingKey should stay constant", prop.ForAll( - func(p1 curve.G1Affine, p2 curve.G2Affine) bool { + func(p1 curve.G1Affine, p2 curve.G2Affine, nbCommitment int) bool { var pk, pkCompressed, pkRaw ProvingKey // create a random pk @@ -216,7 +218,20 @@ func TestProvingKeySerialization(t *testing.T) { pk.NbInfinityA = 1 pk.InfinityA = make([]bool, nbWires) pk.InfinityB = make([]bool, nbWires) - pk.InfinityA[2] = true + pk.InfinityA[2] = true + + pedersenBasis := make([]curve.G1Affine, nbCommitment) + pedersenBases := make([][]curve.G1Affine, nbCommitment) + pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitment) + for i := range pedersenBasis { + pedersenBasis[i] = p1 + pedersenBases[i] = pedersenBasis[:i+1] + } + { + var err error + pk.CommitmentKeys, _, err = pedersen.Setup(pedersenBases...) + require.NoError(t, err) + } var bufCompressed bytes.Buffer written, err := pk.WriteTo(&bufCompressed) @@ -258,6 +273,7 @@ func TestProvingKeySerialization(t *testing.T) { }, GenG1(), GenG2(), + gen.IntRange(0, 2), )) properties.TestingRun(t, gopter.ConsoleReporter(false)) From 05ea5267c2613a276db7c0644dd97e6f54fefae0 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 9 Jun 2023 12:20:21 -0500 Subject: [PATCH 454/464] fix: nil -> empty slice --- backend/groth16/bls12-377/marshal.go | 4 ++++ backend/groth16/bls12-381/marshal.go | 4 ++++ backend/groth16/bls24-315/marshal.go | 4 ++++ backend/groth16/bls24-317/marshal.go | 4 ++++ backend/groth16/bn254/marshal.go | 4 ++++ backend/groth16/bw6-633/marshal.go | 4 ++++ backend/groth16/bw6-761/marshal.go | 4 ++++ .../template/zkpschemes/groth16/groth16.marshal.go.tmpl | 4 ++++ 8 files changed, 32 insertions(+) diff --git a/backend/groth16/bls12-377/marshal.go b/backend/groth16/bls12-377/marshal.go index bec919254c..5e219769ee 100644 --- a/backend/groth16/bls12-377/marshal.go +++ b/backend/groth16/bls12-377/marshal.go @@ -357,5 +357,9 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) } } + if pk.G1.K == nil { + pk.G1.K = []curve.G1Affine{} + } + return n + dec.BytesRead(), nil } diff --git a/backend/groth16/bls12-381/marshal.go b/backend/groth16/bls12-381/marshal.go index 5a51575c78..84f7c7e44e 100644 --- a/backend/groth16/bls12-381/marshal.go +++ b/backend/groth16/bls12-381/marshal.go @@ -357,5 +357,9 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) } } + if pk.G1.K == nil { + pk.G1.K = []curve.G1Affine{} + } + return n + dec.BytesRead(), nil } diff --git a/backend/groth16/bls24-315/marshal.go b/backend/groth16/bls24-315/marshal.go index 3da8e55772..8732ac5d63 100644 --- a/backend/groth16/bls24-315/marshal.go +++ b/backend/groth16/bls24-315/marshal.go @@ -357,5 +357,9 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) } } + if pk.G1.K == nil { + pk.G1.K = []curve.G1Affine{} + } + return n + dec.BytesRead(), nil } diff --git a/backend/groth16/bls24-317/marshal.go b/backend/groth16/bls24-317/marshal.go index 75deea5847..9a72e2ae5a 100644 --- a/backend/groth16/bls24-317/marshal.go +++ b/backend/groth16/bls24-317/marshal.go @@ -357,5 +357,9 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) } } + if pk.G1.K == nil { + pk.G1.K = []curve.G1Affine{} + } + return n + dec.BytesRead(), nil } diff --git a/backend/groth16/bn254/marshal.go b/backend/groth16/bn254/marshal.go index 0a310d6d15..fe7e46a723 100644 --- a/backend/groth16/bn254/marshal.go +++ b/backend/groth16/bn254/marshal.go @@ -357,5 +357,9 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) } } + if pk.G1.Z == nil { + pk.G1.Z = []curve.G1Affine{} + } + return n + dec.BytesRead(), nil } diff --git a/backend/groth16/bw6-633/marshal.go b/backend/groth16/bw6-633/marshal.go index edca7ba642..991d834924 100644 --- a/backend/groth16/bw6-633/marshal.go +++ b/backend/groth16/bw6-633/marshal.go @@ -357,5 +357,9 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) } } + if pk.G1.K == nil { + pk.G1.K = []curve.G1Affine{} + } + return n + dec.BytesRead(), nil } diff --git a/backend/groth16/bw6-761/marshal.go b/backend/groth16/bw6-761/marshal.go index 6f072bc90e..cfb7b8b4d0 100644 --- a/backend/groth16/bw6-761/marshal.go +++ b/backend/groth16/bw6-761/marshal.go @@ -357,5 +357,9 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) } } + if pk.G1.K == nil { + pk.G1.K = []curve.G1Affine{} + } + return n + dec.BytesRead(), nil } diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl index eaa9835d95..49ab5dca4b 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl @@ -344,6 +344,10 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) } } + if pk.G1.K == nil { + pk.G1.K = []curve.G1Affine{} + } + return n + dec.BytesRead(), nil } From fddaf7191721c2716931274a61189b3f04668968 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 9 Jun 2023 12:22:46 -0500 Subject: [PATCH 455/464] build: go gen --- backend/groth16/bn254/marshal.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/groth16/bn254/marshal.go b/backend/groth16/bn254/marshal.go index fe7e46a723..3a4acd654d 100644 --- a/backend/groth16/bn254/marshal.go +++ b/backend/groth16/bn254/marshal.go @@ -357,8 +357,8 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) } } - if pk.G1.Z == nil { - pk.G1.Z = []curve.G1Affine{} + if pk.G1.K == nil { + pk.G1.K = []curve.G1Affine{} } return n + dec.BytesRead(), nil From 92ec8a8c27412cde1d06762ba017ec0b206d8c14 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 9 Jun 2023 12:29:06 -0500 Subject: [PATCH 456/464] fix: K -> Z --- backend/groth16/bls12-377/marshal.go | 4 ++-- backend/groth16/bls12-381/marshal.go | 4 ++-- backend/groth16/bls24-315/marshal.go | 4 ++-- backend/groth16/bls24-317/marshal.go | 4 ++-- backend/groth16/bn254/marshal.go | 4 ++-- backend/groth16/bw6-633/marshal.go | 4 ++-- backend/groth16/bw6-761/marshal.go | 4 ++-- .../template/zkpschemes/groth16/groth16.marshal.go.tmpl | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/backend/groth16/bls12-377/marshal.go b/backend/groth16/bls12-377/marshal.go index 5e219769ee..f9fd56549c 100644 --- a/backend/groth16/bls12-377/marshal.go +++ b/backend/groth16/bls12-377/marshal.go @@ -357,8 +357,8 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) } } - if pk.G1.K == nil { - pk.G1.K = []curve.G1Affine{} + if pk.G1.Z == nil { + pk.G1.Z = []curve.G1Affine{} } return n + dec.BytesRead(), nil diff --git a/backend/groth16/bls12-381/marshal.go b/backend/groth16/bls12-381/marshal.go index 84f7c7e44e..f3af4c619c 100644 --- a/backend/groth16/bls12-381/marshal.go +++ b/backend/groth16/bls12-381/marshal.go @@ -357,8 +357,8 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) } } - if pk.G1.K == nil { - pk.G1.K = []curve.G1Affine{} + if pk.G1.Z == nil { + pk.G1.Z = []curve.G1Affine{} } return n + dec.BytesRead(), nil diff --git a/backend/groth16/bls24-315/marshal.go b/backend/groth16/bls24-315/marshal.go index 8732ac5d63..48380b0511 100644 --- a/backend/groth16/bls24-315/marshal.go +++ b/backend/groth16/bls24-315/marshal.go @@ -357,8 +357,8 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) } } - if pk.G1.K == nil { - pk.G1.K = []curve.G1Affine{} + if pk.G1.Z == nil { + pk.G1.Z = []curve.G1Affine{} } return n + dec.BytesRead(), nil diff --git a/backend/groth16/bls24-317/marshal.go b/backend/groth16/bls24-317/marshal.go index 9a72e2ae5a..e9cb65eab2 100644 --- a/backend/groth16/bls24-317/marshal.go +++ b/backend/groth16/bls24-317/marshal.go @@ -357,8 +357,8 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) } } - if pk.G1.K == nil { - pk.G1.K = []curve.G1Affine{} + if pk.G1.Z == nil { + pk.G1.Z = []curve.G1Affine{} } return n + dec.BytesRead(), nil diff --git a/backend/groth16/bn254/marshal.go b/backend/groth16/bn254/marshal.go index 3a4acd654d..fe7e46a723 100644 --- a/backend/groth16/bn254/marshal.go +++ b/backend/groth16/bn254/marshal.go @@ -357,8 +357,8 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) } } - if pk.G1.K == nil { - pk.G1.K = []curve.G1Affine{} + if pk.G1.Z == nil { + pk.G1.Z = []curve.G1Affine{} } return n + dec.BytesRead(), nil diff --git a/backend/groth16/bw6-633/marshal.go b/backend/groth16/bw6-633/marshal.go index 991d834924..4834ec3900 100644 --- a/backend/groth16/bw6-633/marshal.go +++ b/backend/groth16/bw6-633/marshal.go @@ -357,8 +357,8 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) } } - if pk.G1.K == nil { - pk.G1.K = []curve.G1Affine{} + if pk.G1.Z == nil { + pk.G1.Z = []curve.G1Affine{} } return n + dec.BytesRead(), nil diff --git a/backend/groth16/bw6-761/marshal.go b/backend/groth16/bw6-761/marshal.go index cfb7b8b4d0..9caf604bdc 100644 --- a/backend/groth16/bw6-761/marshal.go +++ b/backend/groth16/bw6-761/marshal.go @@ -357,8 +357,8 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) } } - if pk.G1.K == nil { - pk.G1.K = []curve.G1Affine{} + if pk.G1.Z == nil { + pk.G1.Z = []curve.G1Affine{} } return n + dec.BytesRead(), nil diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl index 49ab5dca4b..02a38f311b 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl @@ -344,8 +344,8 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) } } - if pk.G1.K == nil { - pk.G1.K = []curve.G1Affine{} + if pk.G1.Z == nil { + pk.G1.Z = []curve.G1Affine{} } return n + dec.BytesRead(), nil From 679d38ddf1fa71dd272a9b4a6a46c33103ae9d36 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 9 Jun 2023 12:58:26 -0500 Subject: [PATCH 457/464] dep: newer gnark-crypto --- go.mod | 4 ++-- go.sum | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index a378d048a6..db277cb80b 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/bits-and-blooms/bitset v1.5.0 github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 - github.com/consensys/gnark-crypto v0.11.1-0.20230602185655-ff9bcec080c7 + github.com/consensys/gnark-crypto v0.11.1-0.20230609175512-0ee617fa6d43 github.com/fxamacker/cbor/v2 v2.4.0 github.com/google/go-cmp v0.5.9 github.com/google/pprof v0.0.0-20230309165930-d61513b1440d @@ -29,4 +29,4 @@ require ( gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect rsc.io/tmplfunc v0.0.3 // indirect -) \ No newline at end of file +) diff --git a/go.sum b/go.sum index 298ce09a43..557bb991cb 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/Yj github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= github.com/consensys/gnark-crypto v0.11.1-0.20230602185655-ff9bcec080c7 h1:Pi5ONVS8L+U35O7f00faO0h56EZNztHLvHwnGkACIYU= github.com/consensys/gnark-crypto v0.11.1-0.20230602185655-ff9bcec080c7/go.mod h1:6C2ytC8zmP8uH2GKVfPOjf0Vw3KwMAaUxlCPK5WQqmw= +github.com/consensys/gnark-crypto v0.11.1-0.20230609175512-0ee617fa6d43 h1:6VCNdjn2RmxgG2ZklMmSGov9BtCNfVF4VjqAngysiPU= +github.com/consensys/gnark-crypto v0.11.1-0.20230609175512-0ee617fa6d43/go.mod h1:6C2ytC8zmP8uH2GKVfPOjf0Vw3KwMAaUxlCPK5WQqmw= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= From ede869d0ff77aa8d1bfdc9444ab7b67bd9d19204 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 9 Jun 2023 12:59:40 -0500 Subject: [PATCH 458/464] revert: special case for empty slice --- backend/groth16/bls12-377/marshal.go | 4 ---- backend/groth16/bls12-381/marshal.go | 4 ---- backend/groth16/bls24-315/marshal.go | 4 ---- backend/groth16/bls24-317/marshal.go | 4 ---- backend/groth16/bn254/marshal.go | 4 ---- backend/groth16/bw6-633/marshal.go | 4 ---- backend/groth16/bw6-761/marshal.go | 4 ---- .../template/zkpschemes/groth16/groth16.marshal.go.tmpl | 4 ---- 8 files changed, 32 deletions(-) diff --git a/backend/groth16/bls12-377/marshal.go b/backend/groth16/bls12-377/marshal.go index f9fd56549c..bec919254c 100644 --- a/backend/groth16/bls12-377/marshal.go +++ b/backend/groth16/bls12-377/marshal.go @@ -357,9 +357,5 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) } } - if pk.G1.Z == nil { - pk.G1.Z = []curve.G1Affine{} - } - return n + dec.BytesRead(), nil } diff --git a/backend/groth16/bls12-381/marshal.go b/backend/groth16/bls12-381/marshal.go index f3af4c619c..5a51575c78 100644 --- a/backend/groth16/bls12-381/marshal.go +++ b/backend/groth16/bls12-381/marshal.go @@ -357,9 +357,5 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) } } - if pk.G1.Z == nil { - pk.G1.Z = []curve.G1Affine{} - } - return n + dec.BytesRead(), nil } diff --git a/backend/groth16/bls24-315/marshal.go b/backend/groth16/bls24-315/marshal.go index 48380b0511..3da8e55772 100644 --- a/backend/groth16/bls24-315/marshal.go +++ b/backend/groth16/bls24-315/marshal.go @@ -357,9 +357,5 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) } } - if pk.G1.Z == nil { - pk.G1.Z = []curve.G1Affine{} - } - return n + dec.BytesRead(), nil } diff --git a/backend/groth16/bls24-317/marshal.go b/backend/groth16/bls24-317/marshal.go index e9cb65eab2..75deea5847 100644 --- a/backend/groth16/bls24-317/marshal.go +++ b/backend/groth16/bls24-317/marshal.go @@ -357,9 +357,5 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) } } - if pk.G1.Z == nil { - pk.G1.Z = []curve.G1Affine{} - } - return n + dec.BytesRead(), nil } diff --git a/backend/groth16/bn254/marshal.go b/backend/groth16/bn254/marshal.go index fe7e46a723..0a310d6d15 100644 --- a/backend/groth16/bn254/marshal.go +++ b/backend/groth16/bn254/marshal.go @@ -357,9 +357,5 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) } } - if pk.G1.Z == nil { - pk.G1.Z = []curve.G1Affine{} - } - return n + dec.BytesRead(), nil } diff --git a/backend/groth16/bw6-633/marshal.go b/backend/groth16/bw6-633/marshal.go index 4834ec3900..edca7ba642 100644 --- a/backend/groth16/bw6-633/marshal.go +++ b/backend/groth16/bw6-633/marshal.go @@ -357,9 +357,5 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) } } - if pk.G1.Z == nil { - pk.G1.Z = []curve.G1Affine{} - } - return n + dec.BytesRead(), nil } diff --git a/backend/groth16/bw6-761/marshal.go b/backend/groth16/bw6-761/marshal.go index 9caf604bdc..6f072bc90e 100644 --- a/backend/groth16/bw6-761/marshal.go +++ b/backend/groth16/bw6-761/marshal.go @@ -357,9 +357,5 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) } } - if pk.G1.Z == nil { - pk.G1.Z = []curve.G1Affine{} - } - return n + dec.BytesRead(), nil } diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl index 02a38f311b..eaa9835d95 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl @@ -344,10 +344,6 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) } } - if pk.G1.Z == nil { - pk.G1.Z = []curve.G1Affine{} - } - return n + dec.BytesRead(), nil } From d5a7678bb74aaf2c32a7a09da284841ec5a60e7d Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 20 Jun 2023 16:14:33 -0500 Subject: [PATCH 459/464] refactor: compactify commitment tests (#728) --- backend/groth16/bls12-377/setup.go | 2 +- backend/groth16/bls12-381/setup.go | 2 +- backend/groth16/bls24-315/setup.go | 2 +- backend/groth16/bls24-317/setup.go | 2 +- backend/groth16/bn254/setup.go | 2 +- backend/groth16/bw6-633/setup.go | 2 +- backend/groth16/bw6-761/setup.go | 2 +- .../zkpschemes/groth16/groth16.setup.go.tmpl | 2 +- test/commitments_test.go | 74 +++++++------------ 9 files changed, 33 insertions(+), 57 deletions(-) diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index e25d18113c..2b6add4ba9 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -655,7 +655,7 @@ func (pk *ProvingKey) NbG2() int { return 2 + len(pk.G2.B) } -// bitRerverse permutation as in fft.BitReverse , but with []curve.G1Affine +// bitReverse permutation as in fft.BitReverse , but with []curve.G1Affine func bitReverse(a []curve.G1Affine) { n := uint(len(a)) nn := uint(bits.UintSize - bits.TrailingZeros(n)) diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index d9aec8fa02..eae8f007e3 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -655,7 +655,7 @@ func (pk *ProvingKey) NbG2() int { return 2 + len(pk.G2.B) } -// bitRerverse permutation as in fft.BitReverse , but with []curve.G1Affine +// bitReverse permutation as in fft.BitReverse , but with []curve.G1Affine func bitReverse(a []curve.G1Affine) { n := uint(len(a)) nn := uint(bits.UintSize - bits.TrailingZeros(n)) diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index caa03a0243..0780e815a9 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -655,7 +655,7 @@ func (pk *ProvingKey) NbG2() int { return 2 + len(pk.G2.B) } -// bitRerverse permutation as in fft.BitReverse , but with []curve.G1Affine +// bitReverse permutation as in fft.BitReverse , but with []curve.G1Affine func bitReverse(a []curve.G1Affine) { n := uint(len(a)) nn := uint(bits.UintSize - bits.TrailingZeros(n)) diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index 83038d9dba..8005edb029 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -655,7 +655,7 @@ func (pk *ProvingKey) NbG2() int { return 2 + len(pk.G2.B) } -// bitRerverse permutation as in fft.BitReverse , but with []curve.G1Affine +// bitReverse permutation as in fft.BitReverse , but with []curve.G1Affine func bitReverse(a []curve.G1Affine) { n := uint(len(a)) nn := uint(bits.UintSize - bits.TrailingZeros(n)) diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index 51ddb0d1fe..7c85a63e7b 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -655,7 +655,7 @@ func (pk *ProvingKey) NbG2() int { return 2 + len(pk.G2.B) } -// bitRerverse permutation as in fft.BitReverse , but with []curve.G1Affine +// bitReverse permutation as in fft.BitReverse , but with []curve.G1Affine func bitReverse(a []curve.G1Affine) { n := uint(len(a)) nn := uint(bits.UintSize - bits.TrailingZeros(n)) diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index f24acbdd03..5f4a3299f9 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -655,7 +655,7 @@ func (pk *ProvingKey) NbG2() int { return 2 + len(pk.G2.B) } -// bitRerverse permutation as in fft.BitReverse , but with []curve.G1Affine +// bitReverse permutation as in fft.BitReverse , but with []curve.G1Affine func bitReverse(a []curve.G1Affine) { n := uint(len(a)) nn := uint(bits.UintSize - bits.TrailingZeros(n)) diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index 9123efa717..e83fa0d489 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -655,7 +655,7 @@ func (pk *ProvingKey) NbG2() int { return 2 + len(pk.G2.B) } -// bitRerverse permutation as in fft.BitReverse , but with []curve.G1Affine +// bitReverse permutation as in fft.BitReverse , but with []curve.G1Affine func bitReverse(a []curve.G1Affine) { n := uint(len(a)) nn := uint(bits.UintSize - bits.TrailingZeros(n)) diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl index 1d4e6bbf8f..8214b173a2 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl @@ -638,7 +638,7 @@ func (pk *ProvingKey) NbG2() int { return 2 + len(pk.G2.B) } -// bitRerverse permutation as in fft.BitReverse , but with []curve.G1Affine +// bitReverse permutation as in fft.BitReverse , but with []curve.G1Affine func bitReverse(a []curve.G1Affine) { n := uint(len(a)) nn := uint(bits.UintSize - bits.TrailingZeros(n)) diff --git a/test/commitments_test.go b/test/commitments_test.go index d0a1988862..ec3c3f17ac 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -1,6 +1,7 @@ package test import ( + "github.com/consensys/gnark/backend" "reflect" "testing" @@ -20,10 +21,6 @@ func (c *noCommitmentCircuit) Define(api frontend.API) error { return nil } -func TestNoCommitmentCircuit(t *testing.T) { - testAll(t, &noCommitmentCircuit{1}) -} - type commitmentCircuit struct { Public []frontend.Variable `gnark:",public"` X []frontend.Variable @@ -46,31 +43,6 @@ func (c *commitmentCircuit) Define(api frontend.API) error { return nil } -func TestSingleCommitment(t *testing.T) { - assignment := &commitmentCircuit{X: []frontend.Variable{1}, Public: []frontend.Variable{}} - testAll(t, assignment) -} - -func TestTwoCommitments(t *testing.T) { - assignment := &commitmentCircuit{X: []frontend.Variable{1, 2}, Public: []frontend.Variable{}} - testAll(t, assignment) -} - -func TestFiveCommitments(t *testing.T) { - assignment := &commitmentCircuit{X: []frontend.Variable{1, 2, 3, 4, 5}, Public: []frontend.Variable{}} - testAll(t, assignment) -} - -func TestSingleCommitmentSinglePublic(t *testing.T) { - assignment := &commitmentCircuit{X: []frontend.Variable{0}, Public: []frontend.Variable{1}} - testAll(t, assignment) -} - -func TestFiveCommitmentsFivePublic(t *testing.T) { - assignment := &commitmentCircuit{X: []frontend.Variable{0, 1, 2, 3, 4}, Public: []frontend.Variable{1, 2, 3, 4, 5}} - testAll(t, assignment) -} - type committedConstantCircuit struct { X frontend.Variable } @@ -84,10 +56,6 @@ func (c *committedConstantCircuit) Define(api frontend.API) error { return nil } -func TestCommittedConstant(t *testing.T) { - testAll(t, &committedConstantCircuit{1}) -} - type committedPublicCircuit struct { X frontend.Variable `gnark:",public"` } @@ -101,10 +69,6 @@ func (c *committedPublicCircuit) Define(api frontend.API) error { return nil } -func TestCommittedPublic(t *testing.T) { - testAll(t, &committedPublicCircuit{1}) -} - type independentCommitsCircuit struct { X []frontend.Variable } @@ -121,10 +85,6 @@ func (c *independentCommitsCircuit) Define(api frontend.API) error { return nil } -func TestTwoIndependentCommits(t *testing.T) { - testAll(t, &independentCommitsCircuit{X: []frontend.Variable{1, 1}}) -} - type twoCommitCircuit struct { X []frontend.Variable Y frontend.Variable @@ -143,10 +103,6 @@ func (c *twoCommitCircuit) Define(api frontend.API) error { return nil } -func TestTwoCommit(t *testing.T) { - testAll(t, &twoCommitCircuit{X: []frontend.Variable{1, 2}, Y: 3}) -} - type doubleCommitCircuit struct { X, Y frontend.Variable } @@ -164,10 +120,6 @@ func (c *doubleCommitCircuit) Define(api frontend.API) error { return nil } -func TestDoubleCommit(t *testing.T) { - testAll(t, &doubleCommitCircuit{X: 1, Y: 2}) -} - func TestHollow(t *testing.T) { run := func(c, expected frontend.Circuit) func(t *testing.T) { @@ -222,3 +174,27 @@ func TestCommitUniquenessZerosScs(t *testing.T) { // TODO @Tabaie Randomize Grot _, err = ccs.Solve(w) assert.NoError(t, err) } + +var commitmentTestCircuits []frontend.Circuit + +func init() { + commitmentTestCircuits = []frontend.Circuit{ + &noCommitmentCircuit{1}, + &commitmentCircuit{X: []frontend.Variable{1}, Public: []frontend.Variable{}}, // single commitment + &commitmentCircuit{X: []frontend.Variable{1, 2}, Public: []frontend.Variable{}}, // two commitments + &commitmentCircuit{X: []frontend.Variable{1, 2, 3, 4, 5}, Public: []frontend.Variable{}}, // five commitments + &commitmentCircuit{X: []frontend.Variable{0}, Public: []frontend.Variable{1}}, // single commitment single public + &commitmentCircuit{X: []frontend.Variable{0, 1, 2, 3, 4}, Public: []frontend.Variable{1, 2, 3, 4, 5}}, // five commitments five public + &committedConstantCircuit{1}, // single committed constant + &committedPublicCircuit{1}, // single committed public + &independentCommitsCircuit{X: []frontend.Variable{1, 1}}, // two independent commitments + &twoCommitCircuit{X: []frontend.Variable{1, 2}, Y: 3}, // two commitments, second depending on first + &doubleCommitCircuit{X: 1, Y: 2}, // double committing to the same variable + } +} + +func TestCommitment(t *testing.T) { + for _, assignment := range commitmentTestCircuits { + NewAssert(t).ProverSucceeded(hollow(assignment), assignment, WithBackends(backend.GROTH16, backend.PLONK)) + } +} From ffc3d122695f3a7bf9ddfdda15ae6cff8e21aedb Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Wed, 21 Jun 2023 14:36:06 -0500 Subject: [PATCH 460/464] feat: added dummy setup part for g16 multi commit (#725) * feat: added dummy setup part for g16 multi commit * refactor: compactify commitment tests * test: found errors * fix: bn254 * build go generate * fix: empty branch --------- Co-authored-by: Arya Tabaie --- backend/groth16/bls12-377/setup.go | 23 ++++++- backend/groth16/bls12-381/setup.go | 23 ++++++- backend/groth16/bls24-315/setup.go | 23 ++++++- backend/groth16/bls24-317/setup.go | 23 ++++++- backend/groth16/bn254/setup.go | 23 ++++++- backend/groth16/bw6-633/setup.go | 23 ++++++- backend/groth16/bw6-761/setup.go | 23 ++++++- go.sum | 2 - .../zkpschemes/groth16/groth16.setup.go.tmpl | 23 ++++++- test/commitments_test.go | 60 +++++++++++++++++++ 10 files changed, 228 insertions(+), 18 deletions(-) diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index 2b6add4ba9..1cd302a9a9 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -483,6 +483,9 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbConstraints := r1cs.GetNbConstraints() + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + privateCommitted := commitmentInfo.GetPrivateCommitted() + nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - internal.NbElements(privateCommitted) - len(commitmentInfo) // Setting group for fft domain := fft.NewDomain(uint64(nbConstraints)) @@ -494,8 +497,8 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { // initialize proving key pk.G1.A = make([]curve.G1Affine, nbWires-nbZeroesA) pk.G1.B = make([]curve.G1Affine, nbWires-nbZeroesB) - pk.G1.K = make([]curve.G1Affine, nbWires-r1cs.GetNbPublicVariables()) - pk.G1.Z = make([]curve.G1Affine, domain.Cardinality) + pk.G1.K = make([]curve.G1Affine, nbPrivateWires) + pk.G1.Z = make([]curve.G1Affine, domain.Cardinality-1) pk.G2.B = make([]curve.G2Affine, nbWires-nbZeroesB) // set infinity markers @@ -549,6 +552,22 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { pk.Domain = *domain + // --------------------------------------------------------------------------------------------- + // Commitment setup + commitmentBases := make([][]curve.G1Affine, len(commitmentInfo)) + for i := range commitmentBases { + size := len(privateCommitted[i]) + commitmentBases[i] = make([]curve.G1Affine, size) + for j := range commitmentBases[i] { + commitmentBases[i][j] = r1Aff + } + } + + pk.CommitmentKeys, _, err = pedersen.Setup(commitmentBases...) + if err != nil { + return err + } + return nil } diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index eae8f007e3..d1ca2e9b2d 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -483,6 +483,9 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbConstraints := r1cs.GetNbConstraints() + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + privateCommitted := commitmentInfo.GetPrivateCommitted() + nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - internal.NbElements(privateCommitted) - len(commitmentInfo) // Setting group for fft domain := fft.NewDomain(uint64(nbConstraints)) @@ -494,8 +497,8 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { // initialize proving key pk.G1.A = make([]curve.G1Affine, nbWires-nbZeroesA) pk.G1.B = make([]curve.G1Affine, nbWires-nbZeroesB) - pk.G1.K = make([]curve.G1Affine, nbWires-r1cs.GetNbPublicVariables()) - pk.G1.Z = make([]curve.G1Affine, domain.Cardinality) + pk.G1.K = make([]curve.G1Affine, nbPrivateWires) + pk.G1.Z = make([]curve.G1Affine, domain.Cardinality-1) pk.G2.B = make([]curve.G2Affine, nbWires-nbZeroesB) // set infinity markers @@ -549,6 +552,22 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { pk.Domain = *domain + // --------------------------------------------------------------------------------------------- + // Commitment setup + commitmentBases := make([][]curve.G1Affine, len(commitmentInfo)) + for i := range commitmentBases { + size := len(privateCommitted[i]) + commitmentBases[i] = make([]curve.G1Affine, size) + for j := range commitmentBases[i] { + commitmentBases[i][j] = r1Aff + } + } + + pk.CommitmentKeys, _, err = pedersen.Setup(commitmentBases...) + if err != nil { + return err + } + return nil } diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index 0780e815a9..a37ce828cd 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -483,6 +483,9 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbConstraints := r1cs.GetNbConstraints() + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + privateCommitted := commitmentInfo.GetPrivateCommitted() + nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - internal.NbElements(privateCommitted) - len(commitmentInfo) // Setting group for fft domain := fft.NewDomain(uint64(nbConstraints)) @@ -494,8 +497,8 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { // initialize proving key pk.G1.A = make([]curve.G1Affine, nbWires-nbZeroesA) pk.G1.B = make([]curve.G1Affine, nbWires-nbZeroesB) - pk.G1.K = make([]curve.G1Affine, nbWires-r1cs.GetNbPublicVariables()) - pk.G1.Z = make([]curve.G1Affine, domain.Cardinality) + pk.G1.K = make([]curve.G1Affine, nbPrivateWires) + pk.G1.Z = make([]curve.G1Affine, domain.Cardinality-1) pk.G2.B = make([]curve.G2Affine, nbWires-nbZeroesB) // set infinity markers @@ -549,6 +552,22 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { pk.Domain = *domain + // --------------------------------------------------------------------------------------------- + // Commitment setup + commitmentBases := make([][]curve.G1Affine, len(commitmentInfo)) + for i := range commitmentBases { + size := len(privateCommitted[i]) + commitmentBases[i] = make([]curve.G1Affine, size) + for j := range commitmentBases[i] { + commitmentBases[i][j] = r1Aff + } + } + + pk.CommitmentKeys, _, err = pedersen.Setup(commitmentBases...) + if err != nil { + return err + } + return nil } diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index 8005edb029..04156ae8bd 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -483,6 +483,9 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbConstraints := r1cs.GetNbConstraints() + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + privateCommitted := commitmentInfo.GetPrivateCommitted() + nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - internal.NbElements(privateCommitted) - len(commitmentInfo) // Setting group for fft domain := fft.NewDomain(uint64(nbConstraints)) @@ -494,8 +497,8 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { // initialize proving key pk.G1.A = make([]curve.G1Affine, nbWires-nbZeroesA) pk.G1.B = make([]curve.G1Affine, nbWires-nbZeroesB) - pk.G1.K = make([]curve.G1Affine, nbWires-r1cs.GetNbPublicVariables()) - pk.G1.Z = make([]curve.G1Affine, domain.Cardinality) + pk.G1.K = make([]curve.G1Affine, nbPrivateWires) + pk.G1.Z = make([]curve.G1Affine, domain.Cardinality-1) pk.G2.B = make([]curve.G2Affine, nbWires-nbZeroesB) // set infinity markers @@ -549,6 +552,22 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { pk.Domain = *domain + // --------------------------------------------------------------------------------------------- + // Commitment setup + commitmentBases := make([][]curve.G1Affine, len(commitmentInfo)) + for i := range commitmentBases { + size := len(privateCommitted[i]) + commitmentBases[i] = make([]curve.G1Affine, size) + for j := range commitmentBases[i] { + commitmentBases[i][j] = r1Aff + } + } + + pk.CommitmentKeys, _, err = pedersen.Setup(commitmentBases...) + if err != nil { + return err + } + return nil } diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index 7c85a63e7b..d6eaf37793 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -483,6 +483,9 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbConstraints := r1cs.GetNbConstraints() + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + privateCommitted := commitmentInfo.GetPrivateCommitted() + nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - internal.NbElements(privateCommitted) - len(commitmentInfo) // Setting group for fft domain := fft.NewDomain(uint64(nbConstraints)) @@ -494,8 +497,8 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { // initialize proving key pk.G1.A = make([]curve.G1Affine, nbWires-nbZeroesA) pk.G1.B = make([]curve.G1Affine, nbWires-nbZeroesB) - pk.G1.K = make([]curve.G1Affine, nbWires-r1cs.GetNbPublicVariables()) - pk.G1.Z = make([]curve.G1Affine, domain.Cardinality) + pk.G1.K = make([]curve.G1Affine, nbPrivateWires) + pk.G1.Z = make([]curve.G1Affine, domain.Cardinality-1) pk.G2.B = make([]curve.G2Affine, nbWires-nbZeroesB) // set infinity markers @@ -549,6 +552,22 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { pk.Domain = *domain + // --------------------------------------------------------------------------------------------- + // Commitment setup + commitmentBases := make([][]curve.G1Affine, len(commitmentInfo)) + for i := range commitmentBases { + size := len(privateCommitted[i]) + commitmentBases[i] = make([]curve.G1Affine, size) + for j := range commitmentBases[i] { + commitmentBases[i][j] = r1Aff + } + } + + pk.CommitmentKeys, _, err = pedersen.Setup(commitmentBases...) + if err != nil { + return err + } + return nil } diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index 5f4a3299f9..92c73871b7 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -483,6 +483,9 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbConstraints := r1cs.GetNbConstraints() + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + privateCommitted := commitmentInfo.GetPrivateCommitted() + nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - internal.NbElements(privateCommitted) - len(commitmentInfo) // Setting group for fft domain := fft.NewDomain(uint64(nbConstraints)) @@ -494,8 +497,8 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { // initialize proving key pk.G1.A = make([]curve.G1Affine, nbWires-nbZeroesA) pk.G1.B = make([]curve.G1Affine, nbWires-nbZeroesB) - pk.G1.K = make([]curve.G1Affine, nbWires-r1cs.GetNbPublicVariables()) - pk.G1.Z = make([]curve.G1Affine, domain.Cardinality) + pk.G1.K = make([]curve.G1Affine, nbPrivateWires) + pk.G1.Z = make([]curve.G1Affine, domain.Cardinality-1) pk.G2.B = make([]curve.G2Affine, nbWires-nbZeroesB) // set infinity markers @@ -549,6 +552,22 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { pk.Domain = *domain + // --------------------------------------------------------------------------------------------- + // Commitment setup + commitmentBases := make([][]curve.G1Affine, len(commitmentInfo)) + for i := range commitmentBases { + size := len(privateCommitted[i]) + commitmentBases[i] = make([]curve.G1Affine, size) + for j := range commitmentBases[i] { + commitmentBases[i][j] = r1Aff + } + } + + pk.CommitmentKeys, _, err = pedersen.Setup(commitmentBases...) + if err != nil { + return err + } + return nil } diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index e83fa0d489..5a69e9799a 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -483,6 +483,9 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbConstraints := r1cs.GetNbConstraints() + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + privateCommitted := commitmentInfo.GetPrivateCommitted() + nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - internal.NbElements(privateCommitted) - len(commitmentInfo) // Setting group for fft domain := fft.NewDomain(uint64(nbConstraints)) @@ -494,8 +497,8 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { // initialize proving key pk.G1.A = make([]curve.G1Affine, nbWires-nbZeroesA) pk.G1.B = make([]curve.G1Affine, nbWires-nbZeroesB) - pk.G1.K = make([]curve.G1Affine, nbWires-r1cs.GetNbPublicVariables()) - pk.G1.Z = make([]curve.G1Affine, domain.Cardinality) + pk.G1.K = make([]curve.G1Affine, nbPrivateWires) + pk.G1.Z = make([]curve.G1Affine, domain.Cardinality-1) pk.G2.B = make([]curve.G2Affine, nbWires-nbZeroesB) // set infinity markers @@ -549,6 +552,22 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { pk.Domain = *domain + // --------------------------------------------------------------------------------------------- + // Commitment setup + commitmentBases := make([][]curve.G1Affine, len(commitmentInfo)) + for i := range commitmentBases { + size := len(privateCommitted[i]) + commitmentBases[i] = make([]curve.G1Affine, size) + for j := range commitmentBases[i] { + commitmentBases[i][j] = r1Aff + } + } + + pk.CommitmentKeys, _, err = pedersen.Setup(commitmentBases...) + if err != nil { + return err + } + return nil } diff --git a/go.sum b/go.sum index 557bb991cb..3819139c37 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,6 @@ github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.11.1-0.20230602185655-ff9bcec080c7 h1:Pi5ONVS8L+U35O7f00faO0h56EZNztHLvHwnGkACIYU= -github.com/consensys/gnark-crypto v0.11.1-0.20230602185655-ff9bcec080c7/go.mod h1:6C2ytC8zmP8uH2GKVfPOjf0Vw3KwMAaUxlCPK5WQqmw= github.com/consensys/gnark-crypto v0.11.1-0.20230609175512-0ee617fa6d43 h1:6VCNdjn2RmxgG2ZklMmSGov9BtCNfVF4VjqAngysiPU= github.com/consensys/gnark-crypto v0.11.1-0.20230609175512-0ee617fa6d43/go.mod h1:6C2ytC8zmP8uH2GKVfPOjf0Vw3KwMAaUxlCPK5WQqmw= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl index 8214b173a2..1795c3987d 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl @@ -465,6 +465,9 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { // get R1CS nb constraints, wires and public/private inputs nbWires := r1cs.NbInternalVariables + r1cs.GetNbPublicVariables() + r1cs.GetNbSecretVariables() nbConstraints := r1cs.GetNbConstraints() + commitmentInfo := r1cs.CommitmentInfo.(constraint.Groth16Commitments) + privateCommitted := commitmentInfo.GetPrivateCommitted() + nbPrivateWires := r1cs.GetNbSecretVariables() + r1cs.NbInternalVariables - internal.NbElements(privateCommitted) - len(commitmentInfo) // Setting group for fft domain := fft.NewDomain(uint64(nbConstraints)) @@ -476,8 +479,8 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { // initialize proving key pk.G1.A = make([]curve.G1Affine, nbWires-nbZeroesA) pk.G1.B = make([]curve.G1Affine, nbWires-nbZeroesB) - pk.G1.K = make([]curve.G1Affine, nbWires-r1cs.GetNbPublicVariables()) - pk.G1.Z = make([]curve.G1Affine, domain.Cardinality) + pk.G1.K = make([]curve.G1Affine, nbPrivateWires) + pk.G1.Z = make([]curve.G1Affine, domain.Cardinality-1) pk.G2.B = make([]curve.G2Affine, nbWires-nbZeroesB) // set infinity markers @@ -531,6 +534,22 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { pk.Domain = *domain + // --------------------------------------------------------------------------------------------- + // Commitment setup + commitmentBases := make([][]curve.G1Affine, len(commitmentInfo)) + for i := range commitmentBases { + size := len(privateCommitted[i]) + commitmentBases[i] = make([]curve.G1Affine, size) + for j := range commitmentBases[i] { + commitmentBases[i][j] = r1Aff + } + } + + pk.CommitmentKeys,_, err = pedersen.Setup(commitmentBases...) + if err != nil { + return err + } + return nil } diff --git a/test/commitments_test.go b/test/commitments_test.go index ec3c3f17ac..2b62bb8f09 100644 --- a/test/commitments_test.go +++ b/test/commitments_test.go @@ -1,7 +1,13 @@ package test import ( + "fmt" "github.com/consensys/gnark/backend" + groth16 "github.com/consensys/gnark/backend/groth16/bn254" + "github.com/consensys/gnark/backend/witness" + cs "github.com/consensys/gnark/constraint/bn254" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/stretchr/testify/require" "reflect" "testing" @@ -194,7 +200,61 @@ func init() { } func TestCommitment(t *testing.T) { + t.Parallel() + for _, assignment := range commitmentTestCircuits { NewAssert(t).ProverSucceeded(hollow(assignment), assignment, WithBackends(backend.GROTH16, backend.PLONK)) } } + +func TestCommitmentDummySetup(t *testing.T) { + t.Parallel() + + run := func(assignment frontend.Circuit) func(t *testing.T) { + return func(t *testing.T) { + // just test the prover + _cs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, hollow(assignment)) + require.NoError(t, err) + _r1cs := _cs.(*cs.R1CS) + var ( + dPk, pk groth16.ProvingKey + vk groth16.VerifyingKey + w witness.Witness + ) + require.NoError(t, groth16.Setup(_r1cs, &pk, &vk)) + require.NoError(t, groth16.DummySetup(_r1cs, &dPk)) + + comparePkSizes(t, dPk, pk) + + w, err = frontend.NewWitness(assignment, ecc.BN254.ScalarField()) + require.NoError(t, err) + _, err = groth16.Prove(_r1cs, &pk, w) + require.NoError(t, err) + } + } + + for _, assignment := range commitmentTestCircuits { + name := removePackageName(reflect.TypeOf(assignment).String()) + if c, ok := assignment.(*commitmentCircuit); ok { + name += fmt.Sprintf(":%dprivate %dpublic", len(c.X), len(c.Public)) + } + t.Run(name, run(assignment)) + } +} + +func comparePkSizes(t *testing.T, pk1, pk2 groth16.ProvingKey) { + // skipping the domain + require.Equal(t, len(pk1.G1.A), len(pk2.G1.A)) + require.Equal(t, len(pk1.G1.B), len(pk2.G1.B)) + require.Equal(t, len(pk1.G1.Z), len(pk2.G1.Z)) + require.Equal(t, len(pk1.G1.K), len(pk2.G1.K)) + + require.Equal(t, len(pk1.G2.B), len(pk2.G2.B)) + + require.Equal(t, len(pk1.InfinityA), len(pk2.InfinityA)) + require.Equal(t, len(pk1.InfinityB), len(pk2.InfinityB)) + require.Equal(t, pk1.NbInfinityA, pk2.NbInfinityA) + require.Equal(t, pk1.NbInfinityB, pk2.NbInfinityB) + + require.Equal(t, len(pk1.CommitmentKeys), len(pk2.CommitmentKeys)) // TODO @Tabaie Compare the commitment keys +} From 0fdc46edc2c455389dadf10aeb14ef9b8387ccf8 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 22 Jun 2023 13:26:53 +0200 Subject: [PATCH 461/464] fix: emulated ToBits (#731) * test: implement failing test case * fix: unify emulated ToBits between constant and var --- std/math/emulated/element_test.go | 44 +++++++++++++++++++++++++++++++ std/math/emulated/field_binary.go | 1 - 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/std/math/emulated/element_test.go b/std/math/emulated/element_test.go index 86ab97b605..4f4e3eb4bb 100644 --- a/std/math/emulated/element_test.go +++ b/std/math/emulated/element_test.go @@ -87,6 +87,50 @@ func testAssertIsLessEqualThan[T FieldParams](t *testing.T) { }, testName[T]()) } +type AssertIsLessEqualThanConstantCiruit[T FieldParams] struct { + L Element[T] + R *big.Int +} + +func (c *AssertIsLessEqualThanConstantCiruit[T]) Define(api frontend.API) error { + f, err := NewField[T](api) + if err != nil { + return err + } + R := f.NewElement(c.R) + f.AssertIsLessOrEqual(&c.L, R) + return nil +} + +func testAssertIsLessEqualThanConstant[T FieldParams](t *testing.T) { + var fp T + assert := test.NewAssert(t) + assert.Run(func(assert *test.Assert) { + var circuit, witness AssertIsLessEqualThanConstantCiruit[T] + R, _ := rand.Int(rand.Reader, fp.Modulus()) + L, _ := rand.Int(rand.Reader, R) + circuit.R = R + witness.R = R + witness.L = ValueOf[T](L) + assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) + }, testName[T]()) + assert.Run(func(assert *test.Assert) { + var circuit, witness AssertIsLessEqualThanConstantCiruit[T] + R := new(big.Int).Set(fp.Modulus()) + L, _ := rand.Int(rand.Reader, R) + circuit.R = R + witness.R = R + witness.L = ValueOf[T](L) + assert.ProverSucceeded(&circuit, &witness, test.WithCurves(testCurve), test.NoSerialization(), test.WithBackends(backend.GROTH16, backend.PLONK)) + }, fmt.Sprintf("overflow/%s", testName[T]())) +} + +func TestAssertIsLessEqualThanConstant(t *testing.T) { + testAssertIsLessEqualThanConstant[Goldilocks](t) + testAssertIsLessEqualThanConstant[Secp256k1Fp](t) + testAssertIsLessEqualThanConstant[BN254Fp](t) +} + type AddCircuit[T FieldParams] struct { A, B, C Element[T] } diff --git a/std/math/emulated/field_binary.go b/std/math/emulated/field_binary.go index 3088bd0be0..8c949af2e4 100644 --- a/std/math/emulated/field_binary.go +++ b/std/math/emulated/field_binary.go @@ -14,7 +14,6 @@ func (f *Field[T]) ToBits(a *Element[T]) []frontend.Variable { f.enforceWidthConditional(a) ba, aConst := f.constantValue(a) if aConst { - ba.Mod(ba, f.fParams.Modulus()) res := make([]frontend.Variable, f.fParams.BitsPerLimb()*f.fParams.NbLimbs()) for i := range res { res[i] = ba.Bit(i) From 9fe3b8c54bdff9574b91820bd55b6ab07e551f1b Mon Sep 17 00:00:00 2001 From: Behrouz Date: Thu, 22 Jun 2023 18:49:36 +0330 Subject: [PATCH 462/464] perf: add a generalized version of binary selection (#636) * perf: add a generalized version of binary selection This commit adds `BinaryMux` which is a generalization of `api.Select` and `api.Lookup2` for inputs of arbitrary length. This generalization generates fewer constraints for cases when the length of the input is not a power of 2, in the expense of having undefined output when the selector is outside. Signed-off-by: aybehrouz * fix: simplify the implementation * test: add more tests * docs: improve readability * feat: check the input len is a power of 2 * feat: add decoder functions * style: wrap comment lines on 80 * fix: remove the option for constraining inputs * refactor: revert AssertBits in math/bits * refactor: rename and change the signature of `generateIndicators` Signed-off-by: aybehrouz * refactor: use `OnesCount` instead of `Log2` * refactor: use `panic` instead of `log.Panicf` --------- Signed-off-by: aybehrouz Co-authored-by: Ivo Kubjas --- std/math/bits/conversion_binary.go | 7 ++ std/selector/multiplexer.go | 126 ++++++++++++++++++----------- std/selector/multiplexer_test.go | 12 +++ std/selector/mux.go | 45 +++++++++++ std/selector/mux_test.go | 96 ++++++++++++++++++++++ 5 files changed, 239 insertions(+), 47 deletions(-) create mode 100644 std/selector/mux.go create mode 100644 std/selector/mux_test.go diff --git a/std/math/bits/conversion_binary.go b/std/math/bits/conversion_binary.go index fddb60b74c..693f477b3f 100644 --- a/std/math/bits/conversion_binary.go +++ b/std/math/bits/conversion_binary.go @@ -56,6 +56,13 @@ func toBinary(api frontend.API, v frontend.Variable, opts ...BaseConversionOptio } } + // when cfg.NbDigits == 1, v itself has to be a binary digit. This if clause + // saves one constraint. + if cfg.NbDigits == 1 { + api.AssertIsBoolean(v) + return []frontend.Variable{v} + } + c := big.NewInt(1) bits, err := api.Compiler().NewHint(nBits, cfg.NbDigits, v) diff --git a/std/selector/multiplexer.go b/std/selector/multiplexer.go index b8f0ca878e..5f9b0d7114 100644 --- a/std/selector/multiplexer.go +++ b/std/selector/multiplexer.go @@ -1,4 +1,4 @@ -// Package selector provides a lookup table and map based on linear scan. +// Package selector provides a lookup table and map, based on linear scan. // // The native [frontend.API] provides 1- and 2-bit lookups through the interface // methods Select and Lookup2. This package extends the lookups to @@ -6,19 +6,16 @@ // elements (function [Mux]) or using a key, for which the user needs to provide // the slice of keys (function [Map]). // -// The implementation uses linear scan over all inputs, so the constraint count -// for every invocation of the function is C*len(values)+1, where: -// - for R1CS, C = 3 -// - for PLONK, C = 5 +// The implementation uses linear scan over all inputs. package selector import ( "fmt" - "github.com/consensys/gnark/std/math/bits" - "math/big" - "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/math/bits" + "math/big" + binary "math/bits" ) func init() { @@ -32,51 +29,80 @@ func GetHints() []solver.Hint { return []solver.Hint{stepOutput, muxIndicators, mapIndicators} } -// Map is a key value associative array: the output will be values[i] such that keys[i] == queryKey. If keys does not -// contain queryKey, no proofs can be generated. If keys has more than one key that equals to queryKey, the output will -// be undefined, and the output could be a linear combination of all the corresponding values with that queryKey. +// Map is a key value associative array: the output will be values[i] such that +// keys[i] == queryKey. If keys does not contain queryKey, no proofs can be +// generated. If keys has more than one key that equals to queryKey, the output +// will be undefined, and the output could be any linear combination of all the +// corresponding values with that queryKey. // -// In case keys and values do not have the same length, this function will panic. +// In case keys and values do not have the same length, this function will +// panic. func Map(api frontend.API, queryKey frontend.Variable, keys []frontend.Variable, values []frontend.Variable) frontend.Variable { - // we don't need this check, but we added it to produce more informative errors and disallow - // len(keys) < len(values) which is supported by generateSelector. + // we don't need this check, but we added it to produce more informative errors + // and disallow len(keys) < len(values) which is supported by generateSelector. if len(keys) != len(values) { - panic("The number of keys and values must be equal") + panic(fmt.Sprintf("The number of keys and values must be equal (%d != %d)", len(keys), len(values))) } - return generateSelector(api, false, queryKey, keys, values) + return dotProduct(api, values, KeyDecoder(api, queryKey, keys)) } -// Mux is an n to 1 multiplexer: out = inputs[sel]. In other words, it selects exactly one of its -// inputs based on sel. The index of inputs starts from zero. +// Mux is an n to 1 multiplexer: out = inputs[sel]. In other words, it selects +// exactly one of its inputs based on sel. The index of inputs starts from zero. // -// sel needs to be between 0 and n - 1 (inclusive), where n is the number of inputs, otherwise the proof will fail. +// sel needs to be between 0 and n - 1 (inclusive), where n is the number of +// inputs, otherwise the proof will fail. func Mux(api frontend.API, sel frontend.Variable, inputs ...frontend.Variable) frontend.Variable { - return generateSelector(api, true, sel, nil, inputs) + // we use BinaryMux when len(inputs) is a power of 2. + if binary.OnesCount(uint(len(inputs))) == 1 { + selBits := bits.ToBinary(api, sel, bits.WithNbDigits(binary.Len(uint(len(inputs)))-1)) + return BinaryMux(api, selBits, inputs) + } + return dotProduct(api, inputs, Decoder(api, len(inputs), sel)) } -// generateSelector generates a circuit for a multiplexer or an associative array (map). If wantMux is true, a -// multiplexer is generated and keys are ignored. If wantMux is false, a map is generated, and we must have -// len(keys) <= len(values), or it panics. -func generateSelector(api frontend.API, wantMux bool, sel frontend.Variable, - keys []frontend.Variable, values []frontend.Variable) (out frontend.Variable) { - - var indicators []frontend.Variable - var err error - if wantMux { - if len(values) == 2 { - return api.Select(sel, values[1], values[0]) - } +// KeyDecoder is a decoder that associates keys to its output wires. It outputs +// 1 on the wire that is associated to a key that equals to queryKey. In other +// words: +// +// if keys[i] == queryKey +// out[i] = 1 +// else +// out[i] = 0 +// +// If keys has more than one key that equals to queryKey, the output is +// undefined. However, the output is guaranteed to be zero for the wires that +// are associated with a key which is not equal to queryKey. +func KeyDecoder(api frontend.API, queryKey frontend.Variable, keys []frontend.Variable) []frontend.Variable { + return generateDecoder(api, false, 0, queryKey, keys) +} - if len(values) == 4 { - // api.Lookup2 adds constraints for the boolean assertion, so we use - // bits.WithUnconstrainedOutputs() - selBits := bits.ToBinary(api, sel, bits.WithNbDigits(2), bits.WithUnconstrainedOutputs()) - return api.Lookup2(selBits[0], selBits[1], values[0], values[1], values[2], values[3]) - } +// Decoder is a decoder with n outputs. It outputs 1 on the wire with index sel, +// and 0 otherwise. Indices start from zero. In other words: +// +// if i == sel +// out[i] = 1 +// else +// out[i] = 0 +// +// sel needs to be between 0 and n - 1 (inclusive) otherwise no proof can be +// generated. +func Decoder(api frontend.API, n int, sel frontend.Variable) []frontend.Variable { + return generateDecoder(api, true, n, sel, nil) +} - indicators, err = api.Compiler().NewHint(muxIndicators, len(values), sel) +// generateDecoder generates a circuit for a decoder which indicates the +// selected index. If sequential is true, an ordinary decoder of size n is +// generated, and keys are ignored. If sequential is false, a key based decoder +// is generated, and len(keys) is used to determine the size of the output. n +// will be ignored in this case. +func generateDecoder(api frontend.API, sequential bool, n int, sel frontend.Variable, + keys []frontend.Variable) []frontend.Variable { + var indicators []frontend.Variable + var err error + if sequential { + indicators, err = api.Compiler().NewHint(muxIndicators, n, sel) } else { indicators, err = api.Compiler().NewHint(mapIndicators, len(keys), append(keys, sel)...) } @@ -84,11 +110,10 @@ func generateSelector(api frontend.API, wantMux bool, sel frontend.Variable, panic(fmt.Sprintf("error in calling Mux/Map hint: %v", err)) } - out = 0 indicatorsSum := frontend.Variable(0) for i := 0; i < len(indicators); i++ { // Check that all indicators for inputs that are not selected, are zero. - if wantMux { + if sequential { // indicators[i] * (sel - i) == 0 api.AssertIsEqual(api.Mul(indicators[i], api.Sub(sel, i)), 0) } else { @@ -96,12 +121,19 @@ func generateSelector(api frontend.API, wantMux bool, sel frontend.Variable, api.AssertIsEqual(api.Mul(indicators[i], api.Sub(sel, keys[i])), 0) } indicatorsSum = api.Add(indicatorsSum, indicators[i]) - // out += indicators[i] * values[i] - out = api.MulAcc(out, indicators[i], values[i]) } - // We need to check that the indicator of the selected input is exactly 1. We used a sum constraint, because usually - // it is cheap. + // We need to check that the indicator of the selected input is exactly 1. We + // use a sum constraint, because usually it is cheap. api.AssertIsEqual(indicatorsSum, 1) + return indicators +} + +func dotProduct(api frontend.API, a, b []frontend.Variable) frontend.Variable { + out := frontend.Variable(0) + for i := 0; i < len(a); i++ { + // out += indicators[i] * values[i] + out = api.MulAcc(out, a[i], b[i]) + } return out } @@ -110,8 +142,8 @@ func generateSelector(api frontend.API, wantMux bool, sel frontend.Variable, func muxIndicators(_ *big.Int, inputs []*big.Int, results []*big.Int) error { sel := inputs[0] for i := 0; i < len(results); i++ { - // i is an int which can be int32 or int64. We convert i to int64 then to bigInt, which is safe. We should - // not convert sel to int64. + // i is an int which can be int32 or int64. We convert i to int64 then to + // bigInt, which is safe. We should not convert sel to int64. if sel.Cmp(big.NewInt(int64(i))) == 0 { results[i].SetUint64(1) } else { diff --git a/std/selector/multiplexer_test.go b/std/selector/multiplexer_test.go index 03b6ddf093..2c01f08a01 100644 --- a/std/selector/multiplexer_test.go +++ b/std/selector/multiplexer_test.go @@ -1,6 +1,8 @@ package selector_test import ( + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/frontend/cs/r1cs" "testing" "github.com/consensys/gnark/frontend" @@ -105,11 +107,21 @@ func TestMux(t *testing.T) { OUT: 22, }) + assert.ProverSucceeded(&mux4to1Circuit{}, &mux4to1Circuit{ + SEL: 0, + In: [4]frontend.Variable{11, 22, 33, 44}, + OUT: 11, + }) + assert.ProverFailed(&mux4to1Circuit{}, &mux4to1Circuit{ SEL: 4, In: [4]frontend.Variable{11, 22, 33, 44}, OUT: 44, }) + + cs, _ := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &mux4to1Circuit{}) + // (4 - 1) + (2 + 1) + 1 == 7 + assert.Equal(7, cs.GetNbConstraints()) } // Map tests: diff --git a/std/selector/mux.go b/std/selector/mux.go new file mode 100644 index 0000000000..d437430353 --- /dev/null +++ b/std/selector/mux.go @@ -0,0 +1,45 @@ +package selector + +import ( + "fmt" + "github.com/consensys/gnark/frontend" +) + +// BinaryMux is a 2^k to 1 multiplexer which uses a binary selector. selBits are +// the selector bits, and the input at the index equal to the binary number +// represented by the selector bits will be selected. More precisely the output +// will be: +// +// inputs[selBits[0]+selBits[1]*(1<<1)+selBits[2]*(1<<2)+...] +// +// len(inputs) must be 2^len(selBits). +func BinaryMux(api frontend.API, selBits, inputs []frontend.Variable) frontend.Variable { + if len(inputs) != 1<= len(inputs) { + return binaryMuxRecursive(api, nextSelBits, inputs) + } + + left := binaryMuxRecursive(api, nextSelBits, inputs[:pivot]) + right := binaryMuxRecursive(api, nextSelBits, inputs[pivot:]) + return api.Add(left, api.Mul(msb, api.Sub(right, left))) +} diff --git a/std/selector/mux_test.go b/std/selector/mux_test.go new file mode 100644 index 0000000000..f590c23f02 --- /dev/null +++ b/std/selector/mux_test.go @@ -0,0 +1,96 @@ +package selector + +import ( + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/test" + "testing" +) + +type binaryMuxCircuit struct { + Sel [4]frontend.Variable + In [10]frontend.Variable + Out frontend.Variable +} + +func (c *binaryMuxCircuit) Define(api frontend.API) error { + + out := binaryMuxRecursive(api, c.Sel[:], c.In[:]) + + api.AssertIsEqual(out, c.Out) + + return nil +} + +type binary7to1MuxCircuit struct { + Sel [3]frontend.Variable + In [7]frontend.Variable + Out frontend.Variable +} + +func (c *binary7to1MuxCircuit) Define(api frontend.API) error { + + out := binaryMuxRecursive(api, c.Sel[:], c.In[:]) + + api.AssertIsEqual(out, c.Out) + + return nil +} + +func Test_binaryMuxRecursive(t *testing.T) { + assert := test.NewAssert(t) + + assert.ProverSucceeded(&binaryMuxCircuit{}, &binaryMuxCircuit{ + Sel: [4]frontend.Variable{0, 0, 1, 0}, + In: [10]frontend.Variable{100, 111, 122, 133, 144, 155, 166, 177, 188, 199}, + Out: 144, + }) + + assert.ProverSucceeded(&binaryMuxCircuit{}, &binaryMuxCircuit{ + Sel: [4]frontend.Variable{0, 0, 0, 0}, + In: [10]frontend.Variable{100, 111, 122, 133, 144, 155, 166, 177, 188, 199}, + Out: 100, + }) + + assert.ProverSucceeded(&binaryMuxCircuit{}, &binaryMuxCircuit{ + Sel: [4]frontend.Variable{1, 0, 0, 1}, + In: [10]frontend.Variable{100, 111, 122, 133, 144, 155, 166, 177, 188, 199}, + Out: 199, + }) + + assert.ProverSucceeded(&binaryMuxCircuit{}, &binaryMuxCircuit{ + Sel: [4]frontend.Variable{0, 1, 0, 0}, + In: [10]frontend.Variable{100, 111, 122, 133, 144, 155, 166, 177, 188, 199}, + Out: 122, + }) + + assert.ProverSucceeded(&binaryMuxCircuit{}, &binaryMuxCircuit{ + Sel: [4]frontend.Variable{0, 0, 0, 1}, + In: [10]frontend.Variable{100, 111, 122, 133, 144, 155, 166, 177, 188, 199}, + Out: 188, + }) + + // 7 to 1 + assert.ProverSucceeded(&binary7to1MuxCircuit{}, &binary7to1MuxCircuit{ + Sel: [3]frontend.Variable{0, 0, 1}, + In: [7]frontend.Variable{5, 3, 10, 6, 0, 9, 1}, + Out: 0, + }) + + assert.ProverSucceeded(&binary7to1MuxCircuit{}, &binary7to1MuxCircuit{ + Sel: [3]frontend.Variable{0, 1, 1}, + In: [7]frontend.Variable{5, 3, 10, 6, 0, 9, 1}, + Out: 1, + }) + + assert.ProverSucceeded(&binary7to1MuxCircuit{}, &binary7to1MuxCircuit{ + Sel: [3]frontend.Variable{0, 0, 0}, + In: [7]frontend.Variable{5, 3, 10, 6, 0, 9, 1}, + Out: 5, + }) + + assert.ProverSucceeded(&binary7to1MuxCircuit{}, &binary7to1MuxCircuit{ + Sel: [3]frontend.Variable{1, 0, 1}, + In: [7]frontend.Variable{5, 3, 10, 6, 0, 9, 1}, + Out: 9, + }) +} From a75adf0c99181a012d8b280b00a246893905f9cc Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Thu, 22 Jun 2023 21:54:05 -0500 Subject: [PATCH 463/464] feat: update plonk solidity template (#729) * feat: plonk + sol rebased on latest develop branch * feat: kept only verifier template * refactor: plonk solidity generate match expected gnark interface * tmp: change Library to Contract and add MarshalSolidity on proof * feat: plonk sodliity change visibility of some funcs * feat: add SPDIX apache 2 identifier * fix: move new solidity code into tmpl generation --------- Co-authored-by: Thomas Piellard --- backend/plonk/bn254/solidity.go | 1737 +++++++++-------- backend/plonk/bn254/verify.go | 22 +- go.mod | 10 +- go.sum | 19 +- .../zkpschemes/plonk/plonk.verify.go.tmpl | 25 +- 5 files changed, 998 insertions(+), 815 deletions(-) diff --git a/backend/plonk/bn254/solidity.go b/backend/plonk/bn254/solidity.go index 7fddbd204f..13593a479c 100644 --- a/backend/plonk/bn254/solidity.go +++ b/backend/plonk/bn254/solidity.go @@ -1,907 +1,1050 @@ package plonk -const solidityTemplate = ` -// Warning this code was contributed into gnark here: -// https://github.com/ConsenSys/gnark/pull/358 -// -// It has not been audited and is provided as-is, we make no guarantees or warranties to its safety and reliability. -// -// According to https://eprint.iacr.org/archive/2019/953/1585767119.pdf -pragma solidity ^0.8.0; -pragma experimental ABIEncoderV2; - -library PairingsBn254 { - uint256 constant q_mod = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - uint256 constant r_mod = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - uint256 constant bn254_b_coeff = 3; - - struct G1Point { - uint256 X; - uint256 Y; - } - - struct Fr { - uint256 value; - } - - function new_fr(uint256 fr) internal pure returns (Fr memory) { - require(fr < r_mod); - return Fr({value: fr}); - } +const tmplSolidityVerifier = `// SPDX-License-Identifier: Apache-2.0 + +// Copyright 2023 Consensys Software Inc. +// +// 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. + +// Code generated by gnark DO NOT EDIT - function copy(Fr memory self) internal pure returns (Fr memory n) { - n.value = self.value; - } - - function assign(Fr memory self, Fr memory other) internal pure { - self.value = other.value; - } +pragma solidity ^0.8.0; - function inverse(Fr memory fr) internal view returns (Fr memory) { - require(fr.value != 0); - return pow(fr, r_mod-2); - } +pragma experimental ABIEncoderV2; - function add_assign(Fr memory self, Fr memory other) internal pure { - self.value = addmod(self.value, other.value, r_mod); - } - function sub_assign(Fr memory self, Fr memory other) internal pure { - self.value = addmod(self.value, r_mod - other.value, r_mod); - } +library Utils { - function mul_assign(Fr memory self, Fr memory other) internal pure { - self.value = mulmod(self.value, other.value, r_mod); - } + uint256 constant r_mod = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - function pow(Fr memory self, uint256 power) internal view returns (Fr memory) { - uint256[6] memory input = [32, 32, 32, self.value, power, r_mod]; - uint256[1] memory result; - bool success; - assembly { - success := staticcall(gas(), 0x05, input, 0xc0, result, 0x20) + /** + * @dev ExpandMsgXmd expands msg to a slice of lenInBytes bytes. + * https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-5 + * https://tools.ietf.org/html/rfc8017#section-4.1 (I2OSP/O2ISP) + */ + function expand_msg(uint256 x, uint256 y) public pure returns(uint8[48] memory res){ + + string memory dst = "BSB22-Plonk"; + + //uint8[64] memory pad; // 64 is sha256 block size. + // sha256(pad || msg || (0 || 48 || 0) || dst || 11) + bytes memory tmp; + uint8 zero = 0; + uint8 lenInBytes = 48; + uint8 sizeDomain = 11; // size of dst + + for (uint i=0; i<64; i++){ + tmp = abi.encodePacked(tmp, zero); } - require(success); - return Fr({value: result[0]}); - } + tmp = abi.encodePacked(tmp, x, y, zero, lenInBytes, zero, dst, sizeDomain); + bytes32 b0 = sha256(tmp); - // Encoding of field elements is: X[0] * z + X[1] - struct G2Point { - uint[2] X; - uint[2] Y; - } - - function P1() internal pure returns (G1Point memory) { - return G1Point(1, 2); - } - - function new_g1(uint256 x, uint256 y) internal pure returns (G1Point memory) { - return G1Point(x, y); - } - - function new_g1_checked(uint256 x, uint256 y) internal pure returns (G1Point memory) { - if (x == 0 && y == 0) { - // point of infinity is (0,0) - return G1Point(x, y); + tmp = abi.encodePacked(b0, uint8(1), dst, sizeDomain); + bytes32 b1 = sha256(tmp); + for (uint i=0; i<32; i++){ + res[i] = uint8(b1[i]); } - // check encoding - require(x < q_mod); - require(y < q_mod); - // check on curve - uint256 lhs = mulmod(y, y, q_mod); // y^2 - uint256 rhs = mulmod(x, x, q_mod); // x^2 - rhs = mulmod(rhs, x, q_mod); // x^3 - rhs = addmod(rhs, bn254_b_coeff, q_mod); // x^3 + b - require(lhs == rhs); - - return G1Point(x, y); - } - - function new_g2(uint256[2] memory x, uint256[2] memory y) internal pure returns (G2Point memory) { - return G2Point(x, y); - } - - function copy_g1(G1Point memory self) internal pure returns (G1Point memory result) { - result.X = self.X; - result.Y = self.Y; - } - - function P2() internal pure returns (G2Point memory) { - // for some reason ethereum expects to have c1*v + c0 form - - return G2Point( - [0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2, - 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed], - [0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b, - 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa] - ); - } - - function negate(G1Point memory self) internal pure { - // The prime q in the base field F_q for G1 - if (self.Y == 0) { - require(self.X == 0); - return; + tmp = abi.encodePacked(uint8(b0[0]) ^ uint8(b1[0])); + for (uint i=1; i<32; i++){ + tmp = abi.encodePacked(tmp, uint8(b0[i]) ^ uint8(b1[i])); } - self.Y = q_mod - self.Y; - } - - function point_add(G1Point memory p1, G1Point memory p2) - internal view returns (G1Point memory r) - { - point_add_into_dest(p1, p2, r); - return r; - } - - function point_add_assign(G1Point memory p1, G1Point memory p2) - internal view - { - point_add_into_dest(p1, p2, p1); - } + tmp = abi.encodePacked(tmp, uint8(2), dst, sizeDomain); + b1 = sha256(tmp); - function point_add_into_dest(G1Point memory p1, G1Point memory p2, G1Point memory dest) - internal view - { - if (p2.X == 0 && p2.Y == 0) { - // we add zero, nothing happens - dest.X = p1.X; - dest.Y = p1.Y; - return; - } else if (p1.X == 0 && p1.Y == 0) { - // we add into zero, and we add non-zero point - dest.X = p2.X; - dest.Y = p2.Y; - return; - } else { - uint256[4] memory input; - - input[0] = p1.X; - input[1] = p1.Y; - input[2] = p2.X; - input[3] = p2.Y; - - bool success = false; - assembly { - success := staticcall(gas(), 6, input, 0x80, dest, 0x40) - } - require(success); + // TODO handle the size of the dst (check gnark-crypto) + for (uint i=0; i<16; i++){ + res[i+32] = uint8(b1[i]); } - } - function point_sub_assign(G1Point memory p1, G1Point memory p2) - internal view - { - point_sub_into_dest(p1, p2, p1); + return res; } - function point_sub_into_dest(G1Point memory p1, G1Point memory p2, G1Point memory dest) - internal view - { - if (p2.X == 0 && p2.Y == 0) { - // we subtracted zero, nothing happens - dest.X = p1.X; - dest.Y = p1.Y; - return; - } else if (p1.X == 0 && p1.Y == 0) { - // we subtract from zero, and we subtract non-zero point - dest.X = p2.X; - dest.Y = q_mod - p2.Y; - return; - } else { - uint256[4] memory input; - - input[0] = p1.X; - input[1] = p1.Y; - input[2] = p2.X; - input[3] = q_mod - p2.Y; - - bool success = false; - assembly { - success := staticcall(gas(), 6, input, 0x80, dest, 0x40) - } - require(success); - } - } + /** + * @dev cf https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-5.2 + * corresponds to https://github.com/ConsenSys/gnark-crypto/blob/develop/ecc/bn254/fr/element.go + */ + function hash_fr(uint256 x, uint256 y) internal pure returns(uint256 res) { - function point_mul(G1Point memory p, Fr memory s) - internal view returns (G1Point memory r) - { - point_mul_into_dest(p, s, r); - return r; - } + // interpret a as a bigEndian integer and reduce it mod r + uint8[48] memory xmsg = expand_msg(x, y); + // uint8[48] memory xmsg = [0x44, 0x74, 0xb5, 0x29, 0xd7, 0xfb, 0x29, 0x88, 0x3a, 0x7a, 0xc1, 0x65, 0xfd, 0x72, 0xce, 0xd0, 0xd4, 0xd1, 0x3f, 0x9e, 0x85, 0x8a, 0x3, 0x86, 0x1c, 0x90, 0x83, 0x1e, 0x94, 0xdc, 0xfc, 0x1d, 0x70, 0x82, 0xf5, 0xbf, 0x30, 0x3, 0x39, 0x87, 0x21, 0x38, 0x15, 0xed, 0x12, 0x75, 0x44, 0x6a]; - function point_mul_assign(G1Point memory p, Fr memory s) - internal view - { - point_mul_into_dest(p, s, p); - } - - function point_mul_into_dest(G1Point memory p, Fr memory s, G1Point memory dest) - internal view - { - uint[3] memory input; - input[0] = p.X; - input[1] = p.Y; - input[2] = s.value; - bool success; - assembly { - success := staticcall(gas(), 7, input, 0x60, dest, 0x40) + // reduce xmsg mod r, where xmsg is intrepreted in big endian + // (as SetBytes does for golang's Big.Int library). + for (uint i=0; i<32; i++){ + res += uint256(xmsg[47-i])<<(8*i); } - require(success); - } - - function pairing(G1Point[] memory p1, G2Point[] memory p2) - internal view returns (bool) - { - require(p1.length == p2.length); - uint elements = p1.length; - uint inputSize = elements * 6; - uint[] memory input = new uint[](inputSize); - for (uint i = 0; i < elements; i++) - { - input[i * 6 + 0] = p1[i].X; - input[i * 6 + 1] = p1[i].Y; - input[i * 6 + 2] = p2[i].X[0]; - input[i * 6 + 3] = p2[i].X[1]; - input[i * 6 + 4] = p2[i].Y[0]; - input[i * 6 + 5] = p2[i].Y[1]; + res = res % r_mod; + uint256 tmp; + for (uint i=0; i<16; i++){ + tmp += uint256(xmsg[15-i])<<(8*i); } - uint[1] memory out; - bool success; + + // 2**256%r + uint256 b = 6350874878119819312338956282401532410528162663560392320966563075034087161851; assembly { - success := staticcall(gas(), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20) + tmp := mulmod(tmp, b, r_mod) + res := addmod(res, tmp, r_mod) } - require(success); - return out[0] != 0; - } - - /// Convenience method for a pairing check for two pairs. - function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) - internal view returns (bool) - { - G1Point[] memory p1 = new G1Point[](2); - G2Point[] memory p2 = new G2Point[](2); - p1[0] = a1; - p1[1] = b1; - p2[0] = a2; - p2[1] = b2; - return pairing(p1, p2); - } -} - -library TranscriptLibrary { - uint32 constant DST_0 = 0; - uint32 constant DST_1 = 1; - uint32 constant DST_CHALLENGE = 2; - - struct Transcript { - bytes32 previous_randomness; - bytes bindings; - string name; - uint32 challenge_counter; - } - function new_transcript() internal pure returns (Transcript memory t) { - t.challenge_counter = 0; + return res; } - function set_challenge_name(Transcript memory self, string memory name) internal pure { - self.name = name; - } - - function update_with_u256(Transcript memory self, uint256 value) internal pure { - self.bindings = abi.encodePacked(self.bindings, value); - } - - function update_with_fr(Transcript memory self, PairingsBn254.Fr memory value) internal pure { - self.bindings = abi.encodePacked(self.bindings, value.value); - } - - function update_with_g1(Transcript memory self, PairingsBn254.G1Point memory p) internal pure { - self.bindings = abi.encodePacked(self.bindings, p.X, p.Y); - } - - function get_encode(Transcript memory self) internal pure returns(bytes memory query) { - if (self.challenge_counter != 0) { - query = abi.encodePacked(self.name, self.previous_randomness, self.bindings); - } else { - query = abi.encodePacked(self.name, self.bindings); - } - return query; - } - function get_challenge(Transcript memory self) internal pure returns(PairingsBn254.Fr memory challenge) { - bytes32 query; - if (self.challenge_counter != 0) { - query = sha256(abi.encodePacked(self.name, self.previous_randomness, self.bindings)); - } else { - query = sha256(abi.encodePacked(self.name, self.bindings)); - } - self.challenge_counter += 1; - self.previous_randomness = query; - challenge = PairingsBn254.Fr({value: uint256(query) % PairingsBn254.r_mod}); - self.bindings = ""; - } } contract PlonkVerifier { - using PairingsBn254 for PairingsBn254.G1Point; - using PairingsBn254 for PairingsBn254.G2Point; - using PairingsBn254 for PairingsBn254.Fr; - - using TranscriptLibrary for TranscriptLibrary.Transcript; - - uint256 constant STATE_WIDTH = 3; - - struct VerificationKey { - uint256 domain_size; - uint256 num_inputs; - PairingsBn254.Fr omega; // w - PairingsBn254.G1Point[STATE_WIDTH+2] selector_commitments; // STATE_WIDTH for witness + multiplication + constant - PairingsBn254.G1Point[STATE_WIDTH] permutation_commitments; // [Sσ1(x)],[Sσ2(x)],[Sσ3(x)] - PairingsBn254.Fr[STATE_WIDTH-1] permutation_non_residues; // k1, k2 - PairingsBn254.G2Point g2_x; - } - struct Proof { - uint256[] input_values; - PairingsBn254.G1Point[STATE_WIDTH] wire_commitments; // [a(x)]/[b(x)]/[c(x)] - PairingsBn254.G1Point grand_product_commitment; // [z(x)] - PairingsBn254.G1Point[STATE_WIDTH] quotient_poly_commitments; // [t_lo]/[t_mid]/[t_hi] - PairingsBn254.Fr[STATE_WIDTH] wire_values_at_zeta; // a(zeta)/b(zeta)/c(zeta) - PairingsBn254.Fr grand_product_at_zeta_omega; // z(w*zeta) - PairingsBn254.Fr quotient_polynomial_at_zeta; // t(zeta) - PairingsBn254.Fr linearization_polynomial_at_zeta; // r(zeta) - PairingsBn254.Fr[STATE_WIDTH-1] permutation_polynomials_at_zeta; // Sσ1(zeta),Sσ2(zeta) - - PairingsBn254.G1Point opening_at_zeta_proof; // [Wzeta] - PairingsBn254.G1Point opening_at_zeta_omega_proof; // [Wzeta*omega] + using Utils for *; + uint256 constant r_mod = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + uint256 constant p_mod = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + {{ range $index, $element := .Kzg.G2 }} + uint256 constant g2_srs_{{ $index }}_x_0 = {{ (fpptr $element.X.A1).String }}; + uint256 constant g2_srs_{{ $index }}_x_1 = {{ (fpptr $element.X.A0).String }}; + uint256 constant g2_srs_{{ $index }}_y_0 = {{ (fpptr $element.Y.A1).String }}; + uint256 constant g2_srs_{{ $index }}_y_1 = {{ (fpptr $element.Y.A0).String }}; + {{ end }} + // ----------------------- vk --------------------- + uint256 constant vk_domain_size = {{ .Size }}; + uint256 constant vk_inv_domain_size = {{ (frptr .SizeInv).String }}; + uint256 constant vk_omega = {{ (frptr .Generator).String }}; + uint256 constant vk_ql_com_x = {{ (fpptr .Ql.X).String }}; + uint256 constant vk_ql_com_y = {{ (fpptr .Ql.Y).String }}; + uint256 constant vk_qr_com_x = {{ (fpptr .Qr.X).String }}; + uint256 constant vk_qr_com_y = {{ (fpptr .Qr.Y).String }}; + uint256 constant vk_qm_com_x = {{ (fpptr .Qm.X).String }}; + uint256 constant vk_qm_com_y = {{ (fpptr .Qm.Y).String }}; + uint256 constant vk_qo_com_x = {{ (fpptr .Qo.X).String }}; + uint256 constant vk_qo_com_y = {{ (fpptr .Qo.Y).String }}; + uint256 constant vk_qk_com_x = {{ (fpptr .Qk.X).String }}; + uint256 constant vk_qk_com_y = {{ (fpptr .Qk.Y).String }}; + {{ range $index, $element := .S }} + uint256 constant vk_s{{ inc $index }}_com_x = {{ (fpptr $element.X).String }}; + uint256 constant vk_s{{ inc $index }}_com_y = {{ (fpptr $element.Y).String }}; + {{ end }} + uint256 constant vk_coset_shift = 5; + + {{ range $index, $element := .Qcp}} + uint256 constant vk_selector_commitments_commit_api_{{ $index }}_x = {{ (fpptr $element.X).String }}; + uint256 constant vk_selector_commitments_commit_api_{{ $index }}_y = {{ (fpptr $element.Y).String }}; + {{ end }} + + {{ if (gt (len .CommitmentConstraintIndexes) 0 )}} + function load_vk_commitments_indices_commit_api(uint256[] memory v) + internal view { + assembly { + let _v := add(v, 0x20) + {{ range .CommitmentConstraintIndexes }} + mstore(_v, {{ . }}) + _v := add(_v, 0x20) + {{ end }} } + } + {{ end }} + uint256 constant vk_nb_commitments_commit_api = {{ len .CommitmentConstraintIndexes }}; - struct PartialVerifierState { - PairingsBn254.Fr alpha; - PairingsBn254.Fr beta; - PairingsBn254.Fr gamma; - PairingsBn254.Fr v; - PairingsBn254.Fr u; - PairingsBn254.Fr zeta; - PairingsBn254.Fr[] cached_lagrange_evals; + // ------------------------------------------------ - PairingsBn254.G1Point cached_fold_quotient_ploy_commitments; - } + // offset proof + uint256 constant proof_l_com_x = 0x20; + uint256 constant proof_l_com_y = 0x40; + uint256 constant proof_r_com_x = 0x60; + uint256 constant proof_r_com_y = 0x80; + uint256 constant proof_o_com_x = 0xa0; + uint256 constant proof_o_com_y = 0xc0; - function verify_initial( - PartialVerifierState memory state, - Proof memory proof, - VerificationKey memory vk) internal view returns (bool) { + // h = h_0 + x^{n+2}h_1 + x^{2(n+2)}h_2 + uint256 constant proof_h_0_x = 0xe0; + uint256 constant proof_h_0_y = 0x100; + uint256 constant proof_h_1_x = 0x120; + uint256 constant proof_h_1_y = 0x140; + uint256 constant proof_h_2_x = 0x160; + uint256 constant proof_h_2_y = 0x180; - require(proof.input_values.length == vk.num_inputs, "not match"); - require(vk.num_inputs >= 1, "inv input"); - - TranscriptLibrary.Transcript memory t = TranscriptLibrary.new_transcript(); - t.set_challenge_name("gamma"); - for (uint256 i = 0; i < vk.permutation_commitments.length; i++) { - t.update_with_g1(vk.permutation_commitments[i]); - } - // this is gnark order: Ql, Qr, Qm, Qo, Qk - // - t.update_with_g1(vk.selector_commitments[0]); - t.update_with_g1(vk.selector_commitments[1]); - t.update_with_g1(vk.selector_commitments[3]); - t.update_with_g1(vk.selector_commitments[2]); - t.update_with_g1(vk.selector_commitments[4]); - - for (uint256 i = 0; i < proof.input_values.length; i++) { - t.update_with_u256(proof.input_values[i]); - } - state.gamma = t.get_challenge(); + // wire values at zeta + uint256 constant proof_l_at_zeta = 0x1a0; + uint256 constant proof_r_at_zeta = 0x1c0; + uint256 constant proof_o_at_zeta = 0x1e0; - t.set_challenge_name("beta"); - state.beta = t.get_challenge(); + //uint256[STATE_WIDTH-1] permutation_polynomials_at_zeta; // Sσ1(zeta),Sσ2(zeta) + uint256 constant proof_s1_at_zeta = 0x200; // Sσ1(zeta) + uint256 constant proof_s2_at_zeta = 0x220; // Sσ2(zeta) - t.set_challenge_name("alpha"); - t.update_with_g1(proof.grand_product_commitment); - state.alpha = t.get_challenge(); + //Bn254.G1Point grand_product_commitment; // [z(x)] + uint256 constant proof_grand_product_commitment_x = 0x240; + uint256 constant proof_grand_product_commitment_y = 0x260; - t.set_challenge_name("zeta"); - for (uint256 i = 0; i < proof.quotient_poly_commitments.length; i++) { - t.update_with_g1(proof.quotient_poly_commitments[i]); - } - state.zeta = t.get_challenge(); + uint256 constant proof_grand_product_at_zeta_omega = 0x280; // z(w*zeta) + uint256 constant proof_quotient_polynomial_at_zeta = 0x2a0; // t(zeta) + uint256 constant proof_linearised_polynomial_at_zeta = 0x2c0; // r(zeta) - uint256[] memory lagrange_poly_numbers = new uint256[](vk.num_inputs); - for (uint256 i = 0; i < lagrange_poly_numbers.length; i++) { - lagrange_poly_numbers[i] = i; - } - state.cached_lagrange_evals = batch_evaluate_lagrange_poly_out_of_domain( - lagrange_poly_numbers, - vk.domain_size, - vk.omega, state.zeta - ); - - bool valid = verify_quotient_poly_eval_at_zeta(state, proof, vk); - return valid; - } + // Folded proof for the opening of H, linearised poly, l, r, o, s_1, s_2, qcp + uint256 constant proof_batch_opening_at_zeta_x = 0x2e0; // [Wzeta] + uint256 constant proof_batch_opening_at_zeta_y = 0x300; - function verify_commitments( - PartialVerifierState memory state, - Proof memory proof, - VerificationKey memory vk - ) internal view returns (bool) { - PairingsBn254.G1Point memory d = reconstruct_d(state, proof, vk); + //Bn254.G1Point opening_at_zeta_omega_proof; // [Wzeta*omega] + uint256 constant proof_opening_at_zeta_omega_x = 0x320; + uint256 constant proof_opening_at_zeta_omega_y = 0x340; + + uint256 constant proof_openings_selector_commit_api_at_zeta = 0x360; + // -> next part of proof is + // [ openings_selector_commits || commitments_wires_commit_api] - PairingsBn254.G1Point memory tmp_g1 = PairingsBn254.P1(); + // -------- offset state - PairingsBn254.Fr memory aggregation_challenge = PairingsBn254.new_fr(1); + // challenges to check the claimed quotient + uint256 constant state_alpha = 0x00; + uint256 constant state_beta = 0x20; + uint256 constant state_gamma = 0x40; + uint256 constant state_zeta = 0x60; - PairingsBn254.G1Point memory commitment_aggregation = PairingsBn254.copy_g1(state.cached_fold_quotient_ploy_commitments); - PairingsBn254.Fr memory tmp_fr = PairingsBn254.new_fr(1); + // challenges related to KZG + uint256 constant state_sv = 0x80; + uint256 constant state_su = 0xa0; - aggregation_challenge.mul_assign(state.v); - commitment_aggregation.point_add_assign(d); + // reusable value + uint256 constant state_alpha_square_lagrange = 0xc0; - for (uint i = 0; i < proof.wire_commitments.length; i++) { - aggregation_challenge.mul_assign(state.v); - tmp_g1 = proof.wire_commitments[i].point_mul(aggregation_challenge); - commitment_aggregation.point_add_assign(tmp_g1); - } + // commitment to H + // Bn254.G1Point folded_h; + uint256 constant state_folded_h_x = 0xe0; + uint256 constant state_folded_h_y = 0x100; - for (uint i = 0; i < vk.permutation_commitments.length - 1; i++) { - aggregation_challenge.mul_assign(state.v); - tmp_g1 = vk.permutation_commitments[i].point_mul(aggregation_challenge); - commitment_aggregation.point_add_assign(tmp_g1); - } + // commitment to the linearised polynomial + uint256 constant state_linearised_polynomial_x = 0x120; + uint256 constant state_linearised_polynomial_y = 0x140; - // collect opening values - aggregation_challenge = PairingsBn254.new_fr(1); + // Folded proof for the opening of H, linearised poly, l, r, o, s_1, s_2, qcp + // Kzg.OpeningProof folded_proof; + uint256 constant state_folded_claimed_values = 0x160; - PairingsBn254.Fr memory aggregated_value = PairingsBn254.copy(proof.quotient_polynomial_at_zeta); + // folded digests of H, linearised poly, l, r, o, s_1, s_2, qcp + // Bn254.G1Point folded_digests; + uint256 constant state_folded_digests_x = 0x180; + uint256 constant state_folded_digests_y = 0x1a0; - aggregation_challenge.mul_assign(state.v); + uint256 constant state_pi = 0x1c0; - tmp_fr.assign(proof.linearization_polynomial_at_zeta); - tmp_fr.mul_assign(aggregation_challenge); - aggregated_value.add_assign(tmp_fr); + uint256 constant state_zeta_power_n_minus_one = 0x1e0; + uint256 constant state_alpha_square_lagrange_one = 0x200; - for (uint i = 0; i < proof.wire_values_at_zeta.length; i++) { - aggregation_challenge.mul_assign(state.v); + uint256 constant state_gamma_kzg = 0x220; - tmp_fr.assign(proof.wire_values_at_zeta[i]); - tmp_fr.mul_assign(aggregation_challenge); - aggregated_value.add_assign(tmp_fr); - } + uint256 constant state_success = 0x240; + uint256 constant state_check_var = 0x260; // /!\ this slot is used for debugging only - for (uint i = 0; i < proof.permutation_polynomials_at_zeta.length; i++) { - aggregation_challenge.mul_assign(state.v); - tmp_fr.assign(proof.permutation_polynomials_at_zeta[i]); - tmp_fr.mul_assign(aggregation_challenge); - aggregated_value.add_assign(tmp_fr); - } - tmp_fr.assign(proof.grand_product_at_zeta_omega); - tmp_fr.mul_assign(state.u); - aggregated_value.add_assign(tmp_fr); + uint256 constant state_last_mem = 0x280; - commitment_aggregation.point_sub_assign(PairingsBn254.P1().point_mul(aggregated_value)); + event PrintUint256(uint256 a); - PairingsBn254.G1Point memory pair_with_generator = commitment_aggregation; - pair_with_generator.point_add_assign(proof.opening_at_zeta_proof.point_mul(state.zeta)); + function derive_gamma_beta_alpha_zeta(bytes memory proof, uint256[] memory public_inputs) + internal view returns(uint256, uint256, uint256, uint256) { - tmp_fr.assign(state.zeta); - tmp_fr.mul_assign(vk.omega); - tmp_fr.mul_assign(state.u); - pair_with_generator.point_add_assign(proof.opening_at_zeta_omega_proof.point_mul(tmp_fr)); + uint256 gamma; + uint256 beta; + uint256 alpha; + uint256 zeta; - PairingsBn254.G1Point memory pair_with_x = proof.opening_at_zeta_omega_proof.point_mul(state.u); - pair_with_x.point_add_assign(proof.opening_at_zeta_proof); - pair_with_x.negate(); + assembly { - return PairingsBn254.pairingProd2(pair_with_generator, PairingsBn254.P2(), pair_with_x, vk.g2_x); - } - - function reconstruct_d( - PartialVerifierState memory state, - Proof memory proof, - VerificationKey memory vk - ) internal view returns (PairingsBn254.G1Point memory res) { - res = PairingsBn254.copy_g1(vk.selector_commitments[STATE_WIDTH + 1]); - - PairingsBn254.G1Point memory tmp_g1 = PairingsBn254.P1(); - PairingsBn254.Fr memory tmp_fr = PairingsBn254.new_fr(0); - - // addition gates - for (uint256 i = 0; i < STATE_WIDTH; i++) { - tmp_g1 = vk.selector_commitments[i].point_mul(proof.wire_values_at_zeta[i]); - res.point_add_assign(tmp_g1); - } - - // multiplication gate - tmp_fr.assign(proof.wire_values_at_zeta[0]); - tmp_fr.mul_assign(proof.wire_values_at_zeta[1]); - tmp_g1 = vk.selector_commitments[STATE_WIDTH].point_mul(tmp_fr); - res.point_add_assign(tmp_g1); - - // z * non_res * beta + gamma + a - PairingsBn254.Fr memory grand_product_part_at_z = PairingsBn254.copy(state.zeta); - grand_product_part_at_z.mul_assign(state.beta); - grand_product_part_at_z.add_assign(proof.wire_values_at_zeta[0]); - grand_product_part_at_z.add_assign(state.gamma); - for (uint256 i = 0; i < vk.permutation_non_residues.length; i++) { - tmp_fr.assign(state.zeta); - tmp_fr.mul_assign(vk.permutation_non_residues[i]); - tmp_fr.mul_assign(state.beta); - tmp_fr.add_assign(state.gamma); - tmp_fr.add_assign(proof.wire_values_at_zeta[i+1]); - - grand_product_part_at_z.mul_assign(tmp_fr); - } - - grand_product_part_at_z.mul_assign(state.alpha); - - tmp_fr.assign(state.cached_lagrange_evals[0]); - tmp_fr.mul_assign(state.alpha); - tmp_fr.mul_assign(state.alpha); - // NOTICE - grand_product_part_at_z.sub_assign(tmp_fr); - PairingsBn254.Fr memory last_permutation_part_at_z = PairingsBn254.new_fr(1); - for (uint256 i = 0; i < proof.permutation_polynomials_at_zeta.length; i++) { - tmp_fr.assign(state.beta); - tmp_fr.mul_assign(proof.permutation_polynomials_at_zeta[i]); - tmp_fr.add_assign(state.gamma); - tmp_fr.add_assign(proof.wire_values_at_zeta[i]); - - last_permutation_part_at_z.mul_assign(tmp_fr); - } + let mem := mload(0x40) - last_permutation_part_at_z.mul_assign(state.beta); - last_permutation_part_at_z.mul_assign(proof.grand_product_at_zeta_omega); - last_permutation_part_at_z.mul_assign(state.alpha); + derive_gamma(proof, public_inputs) + gamma := mload(mem) - // gnark implementation: add third part and sub second second part - // plonk paper implementation: add second part and sub third part - /* - tmp_g1 = proof.grand_product_commitment.point_mul(grand_product_part_at_z); - tmp_g1.point_sub_assign(vk.permutation_commitments[STATE_WIDTH - 1].point_mul(last_permutation_part_at_z)); - */ - // add to the linearization + derive_beta(proof, gamma) + beta := mload(mem) - tmp_g1 = vk.permutation_commitments[STATE_WIDTH - 1].point_mul(last_permutation_part_at_z); - tmp_g1.point_sub_assign(proof.grand_product_commitment.point_mul(grand_product_part_at_z)); - res.point_add_assign(tmp_g1); + derive_alpha(proof, beta) + alpha := mload(mem) - generate_uv_challenge(state, proof, vk, res); + derive_zeta(proof, alpha) + zeta := mload(mem) - res.point_mul_assign(state.v); - res.point_add_assign(proof.grand_product_commitment.point_mul(state.u)); - } + gamma := mod(gamma, r_mod) + beta := mod(beta, r_mod) + alpha := mod(alpha, r_mod) + zeta := mod(zeta, r_mod) - // gnark v generation process: - // sha256(zeta, proof.quotient_poly_commitments, linearizedPolynomialDigest, proof.wire_commitments, vk.permutation_commitments[0..1], ) - // NOTICE: gnark use "gamma" name for v, it's not reasonable - // NOTICE: gnark use zeta^(n+2) which is a bit different with plonk paper - // generate_v_challenge(); - function generate_uv_challenge( - PartialVerifierState memory state, - Proof memory proof, - VerificationKey memory vk, - PairingsBn254.G1Point memory linearization_point) view internal { - TranscriptLibrary.Transcript memory transcript = TranscriptLibrary.new_transcript(); - transcript.set_challenge_name("gamma"); - transcript.update_with_fr(state.zeta); - PairingsBn254.Fr memory zeta_plus_two = PairingsBn254.copy(state.zeta); - PairingsBn254.Fr memory n_plus_two = PairingsBn254.new_fr(vk.domain_size); - n_plus_two.add_assign(PairingsBn254.new_fr(2)); - zeta_plus_two = zeta_plus_two.pow(n_plus_two.value); - state.cached_fold_quotient_ploy_commitments = PairingsBn254.copy_g1(proof.quotient_poly_commitments[STATE_WIDTH-1]); - for (uint256 i = 0; i < STATE_WIDTH - 1; i++) { - state.cached_fold_quotient_ploy_commitments.point_mul_assign(zeta_plus_two); - state.cached_fold_quotient_ploy_commitments.point_add_assign(proof.quotient_poly_commitments[STATE_WIDTH - 2 - i]); + function derive_gamma(aproof, pub_inputs) { + + let mPtr := mload(0x40) + + // gamma + mstore(mPtr, 0x67616d6d61) // "gamma" + + mstore(add(mPtr, 0x20), vk_s1_com_x) + mstore(add(mPtr, 0x40), vk_s1_com_y) + mstore(add(mPtr, 0x60), vk_s2_com_x) + mstore(add(mPtr, 0x80), vk_s2_com_y) + mstore(add(mPtr, 0xa0), vk_s3_com_x) + mstore(add(mPtr, 0xc0), vk_s3_com_y) + mstore(add(mPtr, 0xe0), vk_ql_com_x) + mstore(add(mPtr, 0x100), vk_ql_com_y) + mstore(add(mPtr, 0x120), vk_qr_com_x) + mstore(add(mPtr, 0x140), vk_qr_com_y) + mstore(add(mPtr, 0x160), vk_qm_com_x) + mstore(add(mPtr, 0x180), vk_qm_com_y) + mstore(add(mPtr, 0x1a0), vk_qo_com_x) + mstore(add(mPtr, 0x1c0), vk_qo_com_y) + mstore(add(mPtr, 0x1e0), vk_qk_com_x) + mstore(add(mPtr, 0x200), vk_qk_com_y) + + let pi := add(pub_inputs, 0x20) + let _mPtr := add(mPtr, 0x220) + for {let i:=0} lt(i, mload(pub_inputs)) {i:=add(i,1)} + { + mstore(_mPtr, mload(pi)) + pi := add(pi, 0x20) + _mPtr := add(_mPtr, 0x20) } - transcript.update_with_g1(state.cached_fold_quotient_ploy_commitments); - transcript.update_with_g1(linearization_point); - for (uint256 i = 0; i < proof.wire_commitments.length; i++) { - transcript.update_with_g1(proof.wire_commitments[i]); - } - for (uint256 i = 0; i < vk.permutation_commitments.length - 1; i++) { - transcript.update_with_g1(vk.permutation_commitments[i]); + let _proof := add(aproof, proof_openings_selector_commit_api_at_zeta) + _proof := add(_proof, mul(vk_nb_commitments_commit_api, 0x20)) + for {let i:=0} lt(i, vk_nb_commitments_commit_api) {i:=add(i,1)} + { + mstore(_mPtr, mload(_proof)) + mstore(add(_mPtr, 0x20), mload(add(_proof, 0x20))) + _mPtr := add(_mPtr, 0x40) + _proof := add(_proof, 0x40) } - state.v = transcript.get_challenge(); - // gnark use local randomness to generate u - // we use opening_at_zeta_proof and opening_at_zeta_omega_proof - transcript.set_challenge_name("u"); - transcript.update_with_g1(proof.opening_at_zeta_proof); - transcript.update_with_g1(proof.opening_at_zeta_omega_proof); - state.u = transcript.get_challenge(); + // pop(staticcall(sub(gas(), 2000), 0x2, add(mPtr, 0x1b), 0x2a5, mPtr, 0x20)) //0x1b -> 000.."gamma" + + mstore(_mPtr, mload(add(aproof, proof_l_com_x))) + mstore(add(_mPtr, 0x20), mload(add(aproof, proof_l_com_y))) + mstore(add(_mPtr, 0x40), mload(add(aproof, proof_r_com_x))) + mstore(add(_mPtr, 0x60), mload(add(aproof, proof_r_com_y))) + mstore(add(_mPtr, 0x80), mload(add(aproof, proof_o_com_x))) + mstore(add(_mPtr, 0xa0), mload(add(aproof, proof_o_com_y))) + // pop(staticcall(sub(gas(), 2000), 0x2, add(mPtr, 0x1b), 0x365, mPtr, 0x20)) //0x1b -> 000.."gamma" + + let size := add(0x2c5, mul(mload(pub_inputs), 0x20)) // 0x2c5 = 22*32+5 + size := add(size, mul(vk_nb_commitments_commit_api, 0x40)) + pop(staticcall(sub(gas(), 2000), 0x2, add(mPtr, 0x1b), size, mPtr, 0x20)) //0x1b -> 000.."gamma" + } + + function derive_beta(aproof, prev_challenge){ + let mPtr := mload(0x40) + // beta + mstore(mPtr, 0x62657461) // "beta" + mstore(add(mPtr, 0x20), prev_challenge) + pop(staticcall(sub(gas(), 2000), 0x2, add(mPtr, 0x1c), 0x24, mPtr, 0x20)) //0x1b -> 000.."gamma" + } + + function derive_alpha(aproof, prev_challenge){ + let mPtr := mload(0x40) + // alpha + mstore(mPtr, 0x616C706861) // "alpha" + mstore(add(mPtr, 0x20), prev_challenge) + mstore(add(mPtr, 0x40), mload(add(aproof, proof_grand_product_commitment_x))) + mstore(add(mPtr, 0x60), mload(add(aproof, proof_grand_product_commitment_y))) + pop(staticcall(sub(gas(), 2000), 0x2, add(mPtr, 0x1b), 0x65, mPtr, 0x20)) //0x1b -> 000.."gamma" + } + + function derive_zeta(aproof, prev_challenge) { + let mPtr := mload(0x40) + // zeta + mstore(mPtr, 0x7a657461) // "zeta" + mstore(add(mPtr, 0x20), prev_challenge) + mstore(add(mPtr, 0x40), mload(add(aproof, proof_h_0_x))) + mstore(add(mPtr, 0x60), mload(add(aproof, proof_h_0_y))) + mstore(add(mPtr, 0x80), mload(add(aproof, proof_h_1_x))) + mstore(add(mPtr, 0xa0), mload(add(aproof, proof_h_1_y))) + mstore(add(mPtr, 0xc0), mload(add(aproof, proof_h_2_x))) + mstore(add(mPtr, 0xe0), mload(add(aproof, proof_h_2_y))) + pop(staticcall(sub(gas(), 2000), 0x2, add(mPtr, 0x1c), 0xe4, mPtr, 0x20)) + } } - function batch_evaluate_lagrange_poly_out_of_domain( - uint256[] memory poly_nums, - uint256 domain_size, - PairingsBn254.Fr memory omega, - PairingsBn254.Fr memory at - ) internal view returns (PairingsBn254.Fr[] memory res) { - PairingsBn254.Fr memory one = PairingsBn254.new_fr(1); - PairingsBn254.Fr memory tmp_1 = PairingsBn254.new_fr(0); - PairingsBn254.Fr memory tmp_2 = PairingsBn254.new_fr(domain_size); - PairingsBn254.Fr memory vanishing_at_zeta = at.pow(domain_size); - vanishing_at_zeta.sub_assign(one); - // we can not have random point z be in domain - require(vanishing_at_zeta.value != 0); - PairingsBn254.Fr[] memory nums = new PairingsBn254.Fr[](poly_nums.length); - PairingsBn254.Fr[] memory dens = new PairingsBn254.Fr[](poly_nums.length); - // numerators in a form omega^i * (z^n - 1) - // denoms in a form (z - omega^i) * N - for (uint i = 0; i < poly_nums.length; i++) { - tmp_1 = omega.pow(poly_nums[i]); // power of omega - nums[i].assign(vanishing_at_zeta); - nums[i].mul_assign(tmp_1); - - dens[i].assign(at); // (X - omega^i) * N - dens[i].sub_assign(tmp_1); - dens[i].mul_assign(tmp_2); // mul by domain size - } + return (gamma, beta, alpha, zeta); + } + + function load_wire_commitments_commit_api(uint256[] memory wire_commitments, bytes memory proof) + pure internal { + assembly { + let w := add(wire_commitments, 0x20) + let p := add(proof, proof_openings_selector_commit_api_at_zeta) + p := add(p, mul(vk_nb_commitments_commit_api, 0x20)) + for {let i:=0} lt(i, mul(vk_nb_commitments_commit_api,2)) {i:=add(i,1)} + { + mstore(w, mload(p)) + w := add(w,0x20) + p := add(p,0x20) + mstore(w, mload(p)) + w := add(w,0x20) + p := add(p,0x20) + } + } + } + + function compute_ith_lagrange_at_z(uint256 zeta, uint256 i) + internal view returns (uint256) { + + uint256 res; + assembly { + + // _n^_i [r] + function pow_local(x, e)->result { + let mPtr := mload(0x40) + mstore(mPtr, 0x20) + mstore(add(mPtr, 0x20), 0x20) + mstore(add(mPtr, 0x40), 0x20) + mstore(add(mPtr, 0x60), x) + mstore(add(mPtr, 0x80), e) + mstore(add(mPtr, 0xa0), r_mod) + pop(staticcall(sub(gas(), 2000),0x05,mPtr,0xc0,0x00,0x20)) + result := mload(0x00) + } + + let w := pow_local(vk_omega,i) // w**i + i := addmod(zeta, sub(r_mod, w), r_mod) // z-w**i + zeta := pow_local(zeta, vk_domain_size) // z**n + zeta := addmod(zeta, sub(r_mod, 1), r_mod) // z**n-1 + w := mulmod(w, vk_inv_domain_size, r_mod) // w**i/n + i := pow_local(i, sub(r_mod,2)) // (z-w**i)**-1 + w := mulmod(w, i, r_mod) // w**i/n*(z-w)**-1 + res := mulmod(w, zeta, r_mod) + } + + return res; + } - PairingsBn254.Fr[] memory partial_products = new PairingsBn254.Fr[](poly_nums.length); - partial_products[0].assign(PairingsBn254.new_fr(1)); - for (uint i = 1; i < dens.length; i++) { - partial_products[i].assign(dens[i-1]); - partial_products[i].mul_assign(partial_products[i-1]); - } + function compute_pi( + bytes memory proof, + uint256[] memory public_inputs, + uint256 zeta + ) internal view returns (uint256) { - tmp_2.assign(partial_products[partial_products.length - 1]); - tmp_2.mul_assign(dens[dens.length - 1]); - tmp_2 = tmp_2.inverse(); // tmp_2 contains a^-1 * b^-1 (with! the last one) + // evaluation of Z=Xⁿ⁻¹ at ζ + // uint256 zeta_power_n_minus_one = Fr.pow(zeta, vk_domain_size); + // zeta_power_n_minus_one = Fr.sub(zeta_power_n_minus_one, 1); + uint256 zeta_power_n_minus_one; - for (uint i = dens.length; i > 0; i--) { - tmp_1.assign(tmp_2); // all inversed - tmp_1.mul_assign(partial_products[i-1]); // clear lowest terms - tmp_2.mul_assign(dens[i-1]); - dens[i-1].assign(tmp_1); - } + uint256 pi; - for (uint i = 0; i < nums.length; i++) { - nums[i].mul_assign(dens[i]); + assembly { + + sum_pi_wo_api_commit(add(public_inputs,0x20), mload(public_inputs), zeta) + pi := mload(mload(0x40)) + + function sum_pi_wo_api_commit(ins, n, z) { + let li := mload(0x40) + batch_compute_lagranges_at_z(z, n, li) + let res := 0 + let tmp := 0 + for {let i:=0} lt(i,n) {i:=add(i,1)} + { + tmp := mulmod(mload(li), mload(ins), r_mod) + res := addmod(res, tmp, r_mod) + li := add(li, 0x20) + ins := add(ins, 0x20) + } + mstore(mload(0x40), res) } - return nums; - } - - // plonk paper verify process step8: Compute quotient polynomial evaluation - function verify_quotient_poly_eval_at_zeta( - PartialVerifierState memory state, - Proof memory proof, - VerificationKey memory vk - ) internal view returns (bool) { - PairingsBn254.Fr memory lhs = evaluate_vanishing(vk.domain_size, state.zeta); - require(lhs.value != 0); // we can not check a polynomial relationship if point z is in the domain - lhs.mul_assign(proof.quotient_polynomial_at_zeta); - - PairingsBn254.Fr memory quotient_challenge = PairingsBn254.new_fr(1); - PairingsBn254.Fr memory rhs = PairingsBn254.copy(proof.linearization_polynomial_at_zeta); - - // public inputs - PairingsBn254.Fr memory tmp = PairingsBn254.new_fr(0); - for (uint256 i = 0; i < proof.input_values.length; i++) { - tmp.assign(state.cached_lagrange_evals[i]); - tmp.mul_assign(PairingsBn254.new_fr(proof.input_values[i])); - rhs.add_assign(tmp); + // mPtr <- [L_0(z), .., L_{n-1}(z)] + function batch_compute_lagranges_at_z(z, n, mPtr) { + let zn := addmod(pow(z, vk_domain_size, mPtr), sub(r_mod, 1), r_mod) + zn := mulmod(zn, vk_inv_domain_size, r_mod) + let _w := 1 + let _mPtr := mPtr + for {let i:=0} lt(i,n) {i:=add(i,1)} + { + mstore(_mPtr, addmod(z,sub(r_mod, _w), r_mod)) + _w := mulmod(_w, vk_omega, r_mod) + _mPtr := add(_mPtr, 0x20) + } + batch_invert(mPtr, n, _mPtr) + _mPtr := mPtr + _w := 1 + for {let i:=0} lt(i,n) {i:=add(i,1)} + { + mstore(_mPtr, mulmod(mulmod(mload(_mPtr), zn , r_mod), _w, r_mod)) + _mPtr := add(_mPtr, 0x20) + _w := mulmod(_w, vk_omega, r_mod) + } + } + + function batch_invert(ins, nb_ins, mPtr) { + mstore(mPtr, 1) + let offset := 0 + for {let i:=0} lt(i, nb_ins) {i:=add(i,1)} + { + let prev := mload(add(mPtr, offset)) + let cur := mload(add(ins, offset)) + cur := mulmod(prev, cur, r_mod) + offset := add(offset, 0x20) + mstore(add(mPtr, offset), cur) + } + ins := add(ins, sub(offset, 0x20)) + mPtr := add(mPtr, offset) + let inv := pow(mload(mPtr), sub(r_mod,2), add(mPtr, 0x20)) + for {let i:=0} lt(i, nb_ins) {i:=add(i,1)} + { + mPtr := sub(mPtr, 0x20) + let tmp := mload(ins) + let cur := mulmod(inv, mload(mPtr), r_mod) + mstore(ins, cur) + inv := mulmod(inv, tmp, r_mod) + ins := sub(ins, 0x20) + } } - quotient_challenge.mul_assign(state.alpha); - - PairingsBn254.Fr memory z_part = PairingsBn254.copy(proof.grand_product_at_zeta_omega); - for (uint256 i = 0; i < proof.permutation_polynomials_at_zeta.length; i++) { - tmp.assign(proof.permutation_polynomials_at_zeta[i]); - tmp.mul_assign(state.beta); - tmp.add_assign(state.gamma); - tmp.add_assign(proof.wire_values_at_zeta[i]); - - z_part.mul_assign(tmp); + // res <- x^e mod r + function pow(x, e, mPtr)->res { + mstore(mPtr, 0x20) + mstore(add(mPtr, 0x20), 0x20) + mstore(add(mPtr, 0x40), 0x20) + mstore(add(mPtr, 0x60), x) + mstore(add(mPtr, 0x80), e) + mstore(add(mPtr, 0xa0), r_mod) + pop(staticcall(sub(gas(), 2000),0x05,mPtr,0xc0,mPtr,0x20)) + res := mload(mPtr) } - tmp.assign(state.gamma); - // we need a wire value of the last polynomial in enumeration - tmp.add_assign(proof.wire_values_at_zeta[STATE_WIDTH - 1]); - - z_part.mul_assign(tmp); - z_part.mul_assign(quotient_challenge); - - // NOTICE: this is different with plonk paper - // plonk paper should be: rhs.sub_assign(z_part); - rhs.add_assign(z_part); + zeta_power_n_minus_one := pow(zeta, vk_domain_size, mload(0x40)) + zeta_power_n_minus_one := addmod(zeta_power_n_minus_one, sub(r_mod, 1), r_mod) + } + + {{ if (gt (len .CommitmentConstraintIndexes) 0 )}} + uint256[] memory commitment_indices = new uint256[](vk_nb_commitments_commit_api); + load_vk_commitments_indices_commit_api(commitment_indices); + + uint256[] memory wire_committed_commitments; + wire_committed_commitments = new uint256[](2*vk_nb_commitments_commit_api); + + load_wire_commitments_commit_api(wire_committed_commitments, proof); + + for (uint256 i=0; ires { + mstore(mPtr, 0x20) + mstore(add(mPtr, 0x20), 0x20) + mstore(add(mPtr, 0x40), 0x20) + mstore(add(mPtr, 0x60), x) + mstore(add(mPtr, 0x80), e) + mstore(add(mPtr, 0xa0), r_mod) + pop(staticcall(sub(gas(), 2000),0x05,mPtr,0xc0,mPtr,0x20)) + res := mload(mPtr) + } + } - proof.opening_at_zeta_proof = PairingsBn254.new_g1_checked( - serialized_proof[j], - serialized_proof[j+1] - ); - j += 2; + return success; - proof.opening_at_zeta_omega_proof = PairingsBn254.new_g1_checked( - serialized_proof[j], - serialized_proof[j+1] - ); - } + } - function verify_serialized_proof( - uint256[] memory public_inputs, - uint256[] memory serialized_proof - ) public view returns (bool) { - VerificationKey memory vk = get_verification_key(); - require(vk.num_inputs == public_inputs.length); - Proof memory proof = deserialize_proof(public_inputs, serialized_proof); - bool valid = verify(proof, vk); - return valid; - } } ` + +// MarshalSolidity converts a proof to a byte array that can be used in a +// Solidity contract. +func (proof *Proof) MarshalSolidity() []byte { + + res := make([]byte, 0, 1024) + + // uint256 l_com_x; + // uint256 l_com_y; + // uint256 r_com_x; + // uint256 r_com_y; + // uint256 o_com_x; + // uint256 o_com_y; + var tmp64 [64]byte + for i := 0; i < 3; i++ { + tmp64 = proof.LRO[i].RawBytes() + res = append(res, tmp64[:]...) + } + + // uint256 h_0_x; + // uint256 h_0_y; + // uint256 h_1_x; + // uint256 h_1_y; + // uint256 h_2_x; + // uint256 h_2_y; + for i := 0; i < 3; i++ { + tmp64 = proof.H[i].RawBytes() + res = append(res, tmp64[:]...) + } + var tmp32 [32]byte + + // uint256 l_at_zeta; + // uint256 r_at_zeta; + // uint256 o_at_zeta; + // uint256 s1_at_zeta; + // uint256 s2_at_zeta; + for i := 2; i < 7; i++ { + tmp32 = proof.BatchedProof.ClaimedValues[i].Bytes() + res = append(res, tmp32[:]...) + } + + // uint256 grand_product_commitment_x; + // uint256 grand_product_commitment_y; + tmp64 = proof.Z.RawBytes() + res = append(res, tmp64[:]...) + + // uint256 grand_product_at_zeta_omega; + tmp32 = proof.ZShiftedOpening.ClaimedValue.Bytes() + res = append(res, tmp32[:]...) + + // uint256 quotient_polynomial_at_zeta; + // uint256 linearization_polynomial_at_zeta; + tmp32 = proof.BatchedProof.ClaimedValues[0].Bytes() + res = append(res, tmp32[:]...) + tmp32 = proof.BatchedProof.ClaimedValues[1].Bytes() + res = append(res, tmp32[:]...) + + // uint256 opening_at_zeta_proof_x; + // uint256 opening_at_zeta_proof_y; + tmp64 = proof.BatchedProof.H.RawBytes() + res = append(res, tmp64[:]...) + + // uint256 opening_at_zeta_omega_proof_x; + // uint256 opening_at_zeta_omega_proof_y; + tmp64 = proof.ZShiftedOpening.H.RawBytes() + res = append(res, tmp64[:]...) + + // uint256[] selector_commit_api_at_zeta; + // uint256[] wire_committed_commitments; + if len(proof.Bsb22Commitments) > 0 { + tmp32 = proof.BatchedProof.ClaimedValues[7].Bytes() + res = append(res, tmp32[:]...) + + for _, bc := range proof.Bsb22Commitments { + tmp64 = bc.RawBytes() + res = append(res, tmp64[:]...) + } + } + + return res +} diff --git a/backend/plonk/bn254/verify.go b/backend/plonk/bn254/verify.go index 4820560fe5..a809b04fa7 100644 --- a/backend/plonk/bn254/verify.go +++ b/backend/plonk/bn254/verify.go @@ -25,6 +25,8 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark-crypto/ecc/bn254/fp" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/kzg" curve "github.com/consensys/gnark-crypto/ecc/bn254" @@ -346,9 +348,25 @@ func deriveRandomness(fs *fiatshamir.Transcript, challenge string, points ...*cu // // Code has not been audited and is provided as-is, we make no guarantees or warranties to its safety and reliability. func (vk *VerifyingKey) ExportSolidity(w io.Writer) error { - tmpl, err := template.New("").Parse(solidityTemplate) + funcMap := template.FuncMap{ + // The name "inc" is what the function will be called in the template text. + "inc": func(i int) int { + return i + 1 + }, + "frptr": func(x fr.Element) *fr.Element { + return &x + }, + "fpptr": func(x fp.Element) *fp.Element { + return &x + }, + "add": func(i, j int) int { + return i + j + }, + } + + t, err := template.New("t").Funcs(funcMap).Parse(tmplSolidityVerifier) if err != nil { return err } - return tmpl.Execute(w, vk) + return t.Execute(w, vk) } diff --git a/go.mod b/go.mod index db277cb80b..afac14d9ee 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/consensys/gnark go 1.19 require ( - github.com/bits-and-blooms/bitset v1.5.0 + github.com/bits-and-blooms/bitset v1.7.0 github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 github.com/consensys/gnark-crypto v0.11.1-0.20230609175512-0ee617fa6d43 @@ -13,19 +13,19 @@ require ( github.com/leanovate/gopter v0.2.9 github.com/rs/zerolog v1.29.0 github.com/stretchr/testify v1.8.2 - golang.org/x/crypto v0.6.0 + golang.org/x/crypto v0.10.0 golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/kr/pretty v0.3.1 // indirect - github.com/mattn/go-colorable v0.1.12 // indirect - github.com/mattn/go-isatty v0.0.14 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.16 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/x448/float16 v0.8.4 // indirect - golang.org/x/sys v0.5.0 // indirect + golang.org/x/sys v0.9.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect rsc.io/tmplfunc v0.0.3 // indirect diff --git a/go.sum b/go.sum index 3819139c37..cfb27fb3eb 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/bits-and-blooms/bitset v1.5.0 h1:NpE8frKRLGHIcEzkR+gZhiioW1+WbYV6fKwD6ZIpQT8= -github.com/bits-and-blooms/bitset v1.5.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bits-and-blooms/bitset v1.7.0 h1:YjAGVd3XmtK9ktAbX8Zg2g2PwLIMjGREZJHlV4j7NEo= +github.com/bits-and-blooms/bitset v1.7.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= @@ -28,10 +28,12 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= -github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= @@ -53,14 +55,15 @@ github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= -golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= -golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= +golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb h1:PaBZQdo+iSDyHT053FjUCgZQ/9uqVwPOcl7KSWhKn6w= golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl index 3ab826cedd..fb94969418 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl @@ -5,6 +5,9 @@ import ( "time" "io" {{ template "import_fr" . }} + {{if eq .Curve "BN254"}} + "github.com/consensys/gnark-crypto/ecc/bn254/fp" + {{end}} {{ template "import_kzg" . }} {{ template "import_curve" . }} {{if eq .Curve "BN254"}} @@ -325,13 +328,29 @@ func deriveRandomness(fs *fiatshamir.Transcript, challenge string, points ...*cu // // See https://github.com/ConsenSys/gnark-tests for example usage. // -// Code has not been audited and is provided as-is, we make no guarantees or warranties to its safety and reliability. +// Code has not been audited and is provided as-is, we make no guarantees or warranties to its safety and reliability. func (vk *VerifyingKey) ExportSolidity(w io.Writer) error { - tmpl, err := template.New("").Parse(solidityTemplate) + funcMap := template.FuncMap{ + // The name "inc" is what the function will be called in the template text. + "inc": func(i int) int { + return i + 1 + }, + "frptr": func(x fr.Element) *fr.Element { + return &x + }, + "fpptr": func(x fp.Element) *fp.Element { + return &x + }, + "add": func(i, j int) int { + return i + j + }, + } + + t, err := template.New("t").Funcs(funcMap).Parse(tmplSolidityVerifier) if err != nil { return err } - return tmpl.Execute(w, vk) + return t.Execute(w, vk) } {{else}} From e1332fa2dd28009d8eb2be6b472116e4fb71d6c2 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Fri, 23 Jun 2023 15:52:52 -0500 Subject: [PATCH 464/464] feat/ci: make CI run solidity verification with integartion test. Added test.WithSolidity option. (#732) * feat: plonk + sol rebased on latest develop branch * feat: kept only verifier template * refactor: plonk solidity generate match expected gnark interface * tmp: change Library to Contract and add MarshalSolidity on proof * feat: plonk sodliity change visibility of some funcs * feat: add SPDIX apache 2 identifier * fix: move new solidity code into tmpl generation * fix: use big int string in solidity generation for plonk to avoid negative numbers * feat: add WithSolidity option in assert helper * ci: attempt to make gnark-solidity-checker run on CI * fix: address PR comments --------- Co-authored-by: Thomas Piellard --- .github/workflows/pr.yml | 10 +- backend/plonk/bn254/solidity.go | 40 ++++---- backend/plonk/bn254/verify.go | 14 ++- integration_test.go | 3 +- .../zkpschemes/plonk/plonk.verify.go.tmpl | 14 ++- test/assert.go | 14 ++- test/assert_solidity.go | 95 +++++++++++++++++++ test/options.go | 14 +++ test/solccheck_with.go | 5 + test/solccheck_without.go | 5 + 10 files changed, 181 insertions(+), 33 deletions(-) create mode 100644 test/assert_solidity.go create mode 100644 test/solccheck_with.go create mode 100644 test/solccheck_without.go diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 4ebfba8c25..c0e2c60046 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -70,10 +70,16 @@ jobs: restore-keys: | ${{ runner.os }}-go- - name: install deps - run: go install golang.org/x/tools/cmd/goimports@latest && go install github.com/klauspost/asmfmt/cmd/asmfmt@latest + run: | + go install golang.org/x/tools/cmd/goimports@latest && go install github.com/klauspost/asmfmt/cmd/asmfmt@latest + go install github.com/ethereum/go-ethereum/cmd/abigen@v1.12.0 + go install github.com/consensys/gnark-solidity-checker@latest + sudo add-apt-repository ppa:ethereum/ethereum + sudo apt-get update + sudo apt-get install solc - name: Test run: | - go test -v -short -timeout=30m ./... + go test -v -short -tags=solccheck -timeout=30m ./... - name: Test race run: | go test -v -short -race -timeout=30m diff --git a/backend/plonk/bn254/solidity.go b/backend/plonk/bn254/solidity.go index 13593a479c..f3aeeb2a79 100644 --- a/backend/plonk/bn254/solidity.go +++ b/backend/plonk/bn254/solidity.go @@ -110,34 +110,34 @@ contract PlonkVerifier { uint256 constant r_mod = 21888242871839275222246405745257275088548364400416034343698204186575808495617; uint256 constant p_mod = 21888242871839275222246405745257275088696311157297823662689037894645226208583; {{ range $index, $element := .Kzg.G2 }} - uint256 constant g2_srs_{{ $index }}_x_0 = {{ (fpptr $element.X.A1).String }}; - uint256 constant g2_srs_{{ $index }}_x_1 = {{ (fpptr $element.X.A0).String }}; - uint256 constant g2_srs_{{ $index }}_y_0 = {{ (fpptr $element.Y.A1).String }}; - uint256 constant g2_srs_{{ $index }}_y_1 = {{ (fpptr $element.Y.A0).String }}; + uint256 constant g2_srs_{{ $index }}_x_0 = {{ (fpstr $element.X.A1) }}; + uint256 constant g2_srs_{{ $index }}_x_1 = {{ (fpstr $element.X.A0) }}; + uint256 constant g2_srs_{{ $index }}_y_0 = {{ (fpstr $element.Y.A1) }}; + uint256 constant g2_srs_{{ $index }}_y_1 = {{ (fpstr $element.Y.A0) }}; {{ end }} // ----------------------- vk --------------------- uint256 constant vk_domain_size = {{ .Size }}; - uint256 constant vk_inv_domain_size = {{ (frptr .SizeInv).String }}; - uint256 constant vk_omega = {{ (frptr .Generator).String }}; - uint256 constant vk_ql_com_x = {{ (fpptr .Ql.X).String }}; - uint256 constant vk_ql_com_y = {{ (fpptr .Ql.Y).String }}; - uint256 constant vk_qr_com_x = {{ (fpptr .Qr.X).String }}; - uint256 constant vk_qr_com_y = {{ (fpptr .Qr.Y).String }}; - uint256 constant vk_qm_com_x = {{ (fpptr .Qm.X).String }}; - uint256 constant vk_qm_com_y = {{ (fpptr .Qm.Y).String }}; - uint256 constant vk_qo_com_x = {{ (fpptr .Qo.X).String }}; - uint256 constant vk_qo_com_y = {{ (fpptr .Qo.Y).String }}; - uint256 constant vk_qk_com_x = {{ (fpptr .Qk.X).String }}; - uint256 constant vk_qk_com_y = {{ (fpptr .Qk.Y).String }}; + uint256 constant vk_inv_domain_size = {{ (frstr .SizeInv) }}; + uint256 constant vk_omega = {{ (frstr .Generator) }}; + uint256 constant vk_ql_com_x = {{ (fpstr .Ql.X) }}; + uint256 constant vk_ql_com_y = {{ (fpstr .Ql.Y) }}; + uint256 constant vk_qr_com_x = {{ (fpstr .Qr.X) }}; + uint256 constant vk_qr_com_y = {{ (fpstr .Qr.Y) }}; + uint256 constant vk_qm_com_x = {{ (fpstr .Qm.X) }}; + uint256 constant vk_qm_com_y = {{ (fpstr .Qm.Y) }}; + uint256 constant vk_qo_com_x = {{ (fpstr .Qo.X) }}; + uint256 constant vk_qo_com_y = {{ (fpstr .Qo.Y) }}; + uint256 constant vk_qk_com_x = {{ (fpstr .Qk.X) }}; + uint256 constant vk_qk_com_y = {{ (fpstr .Qk.Y) }}; {{ range $index, $element := .S }} - uint256 constant vk_s{{ inc $index }}_com_x = {{ (fpptr $element.X).String }}; - uint256 constant vk_s{{ inc $index }}_com_y = {{ (fpptr $element.Y).String }}; + uint256 constant vk_s{{ inc $index }}_com_x = {{ (fpstr $element.X) }}; + uint256 constant vk_s{{ inc $index }}_com_y = {{ (fpstr $element.Y) }}; {{ end }} uint256 constant vk_coset_shift = 5; {{ range $index, $element := .Qcp}} - uint256 constant vk_selector_commitments_commit_api_{{ $index }}_x = {{ (fpptr $element.X).String }}; - uint256 constant vk_selector_commitments_commit_api_{{ $index }}_y = {{ (fpptr $element.Y).String }}; + uint256 constant vk_selector_commitments_commit_api_{{ $index }}_x = {{ (fpstr $element.X) }}; + uint256 constant vk_selector_commitments_commit_api_{{ $index }}_y = {{ (fpstr $element.Y) }}; {{ end }} {{ if (gt (len .CommitmentConstraintIndexes) 0 )}} diff --git a/backend/plonk/bn254/verify.go b/backend/plonk/bn254/verify.go index a809b04fa7..88bd903f5e 100644 --- a/backend/plonk/bn254/verify.go +++ b/backend/plonk/bn254/verify.go @@ -353,11 +353,17 @@ func (vk *VerifyingKey) ExportSolidity(w io.Writer) error { "inc": func(i int) int { return i + 1 }, - "frptr": func(x fr.Element) *fr.Element { - return &x + "frstr": func(x fr.Element) string { + // we use big.Int to always get a positive string. + // not the most efficient hack, but it works better for .sol generation. + bv := new(big.Int) + x.BigInt(bv) + return bv.String() }, - "fpptr": func(x fp.Element) *fp.Element { - return &x + "fpstr": func(x fp.Element) string { + bv := new(big.Int) + x.BigInt(bv) + return bv.String() }, "add": func(i, j int) int { return i + j diff --git a/integration_test.go b/integration_test.go index 99955e092f..598d9f9165 100644 --- a/integration_test.go +++ b/integration_test.go @@ -58,7 +58,8 @@ func TestIntegrationAPI(t *testing.T) { tData.Circuit, tData.ValidAssignments[i], test.WithSolverOpts(solver.WithHints(tData.HintFunctions...)), test.WithCurves(tData.Curves[0], tData.Curves[1:]...), - test.WithBackends(backends[0], backends[1:]...)) + test.WithBackends(backends[0], backends[1:]...), + test.WithSolidity()) }, fmt.Sprintf("valid-%d", i)) } diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl index fb94969418..43e5bd3c6f 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl @@ -335,11 +335,17 @@ func (vk *VerifyingKey) ExportSolidity(w io.Writer) error { "inc": func(i int) int { return i + 1 }, - "frptr": func(x fr.Element) *fr.Element { - return &x + "frstr": func(x fr.Element) string { + // we use big.Int to always get a positive string. + // not the most efficient hack, but it works better for .sol generation. + bv := new(big.Int) + x.BigInt(bv) + return bv.String() }, - "fpptr": func(x fp.Element) *fp.Element { - return &x + "fpstr": func(x fp.Element) string { + bv := new(big.Int) + x.BigInt(bv) + return bv.String() }, "add": func(i, j int) int { return i + j diff --git a/test/assert.go b/test/assert.go index 0cd30fce66..10d1ebf977 100644 --- a/test/assert.go +++ b/test/assert.go @@ -175,6 +175,11 @@ func (assert *Assert) ProverSucceeded(circuit frontend.Circuit, validAssignment err = groth16.Verify(proof, vk, validPublicWitness) checkError(err) + if opt.solidity && curve == ecc.BN254 && vk.NbPublicWitness() > 0 { + // check that the proof can be verified by gnark-solidity-checker + assert.solidityVerification(b, vk, proof, validPublicWitness) + } + case backend.PLONK: srs, err := NewKZGSRS(ccs) checkError(err) @@ -188,12 +193,17 @@ func (assert *Assert) ProverSucceeded(circuit frontend.Circuit, validAssignment roundTripCheck(assert.t, vk, vkReconstructed) } - correctProof, err := plonk.Prove(ccs, pk, validWitness, opt.proverOpts...) + proof, err := plonk.Prove(ccs, pk, validWitness, opt.proverOpts...) checkError(err) - err = plonk.Verify(correctProof, vk, validPublicWitness) + err = plonk.Verify(proof, vk, validPublicWitness) checkError(err) + if opt.solidity && curve == ecc.BN254 { + // check that the proof can be verified by gnark-solidity-checker + assert.solidityVerification(b, vk, proof, validPublicWitness) + } + case backend.PLONKFRI: pk, vk, err := plonkfri.Setup(ccs) checkError(err) diff --git a/test/assert_solidity.go b/test/assert_solidity.go new file mode 100644 index 0000000000..1f027ac2b7 --- /dev/null +++ b/test/assert_solidity.go @@ -0,0 +1,95 @@ +package test + +import ( + "bytes" + "encoding/hex" + "io" + "os" + "os/exec" + "path/filepath" + "strconv" + + "github.com/consensys/gnark/backend" + groth16_bn254 "github.com/consensys/gnark/backend/groth16/bn254" + plonk_bn254 "github.com/consensys/gnark/backend/plonk/bn254" + "github.com/consensys/gnark/backend/witness" +) + +// solidityVerification checks that the exported solidity contract can verify the proof +// and that the proof is valid. +// It uses gnark-solidity-checker see test.WithSolidity option. +func (assert *Assert) solidityVerification(b backend.ID, vk interface { + NbPublicWitness() int + ExportSolidity(io.Writer) error +}, + proof any, + validPublicWitness witness.Witness) { + if !solcCheck { + return // nothing to check, will make solc fail. + } + assert.t.Helper() + + // make temp dir + tmpDir, err := os.MkdirTemp("", "gnark-solidity-check*") + assert.NoError(err) + defer os.RemoveAll(tmpDir) + + // export solidity contract + fSolidity, err := os.Create(filepath.Join(tmpDir, "gnark_verifier.sol")) + assert.NoError(err) + + err = vk.ExportSolidity(fSolidity) + assert.NoError(err) + + err = fSolidity.Close() + assert.NoError(err) + + // generate assets + // gnark-solidity-checker generate --dir tmpdir --solidity contract_g16.sol + cmd := exec.Command("gnark-solidity-checker", "generate", "--dir", tmpDir, "--solidity", "gnark_verifier.sol") + assert.t.Log("running ", cmd.String()) + out, err := cmd.CombinedOutput() + assert.NoError(err, string(out)) + + // proof to hex + var proofStr string + var optBackend string + + if b == backend.GROTH16 { + optBackend = "--groth16" + var buf bytes.Buffer + _proof := proof.(*groth16_bn254.Proof) + _, err = _proof.WriteRawTo(&buf) + assert.NoError(err) + proofStr = hex.EncodeToString(buf.Bytes()) + } else if b == backend.PLONK { + optBackend = "--plonk" + _proof := proof.(*plonk_bn254.Proof) + // TODO @gbotrel make a single Marshal function for PlonK proof. + proofStr = hex.EncodeToString(_proof.MarshalSolidity()) + } else { + panic("not implemented") + } + + // public witness to hex + bPublicWitness, err := validPublicWitness.MarshalBinary() + assert.NoError(err) + // that's quite dirty... + // first 4 bytes -> nbPublic + // next 4 bytes -> nbSecret + // next 4 bytes -> nb elements in the vector (== nbPublic + nbSecret) + bPublicWitness = bPublicWitness[12:] + publicWitnessStr := hex.EncodeToString(bPublicWitness) + + // verify proof + // gnark-solidity-checker verify --dir tmdir --groth16 --nb-public-inputs 1 --proof 1234 --public-inputs dead + cmd = exec.Command("gnark-solidity-checker", "verify", + "--dir", tmpDir, + optBackend, + "--nb-public-inputs", strconv.Itoa(vk.NbPublicWitness()), + "--proof", proofStr, + "--public-inputs", publicWitnessStr) + assert.t.Log("running ", cmd.String()) + out, err = cmd.CombinedOutput() + assert.NoError(err, string(out)) +} diff --git a/test/options.go b/test/options.go index 00ca2924a2..65aa8a00c2 100644 --- a/test/options.go +++ b/test/options.go @@ -36,6 +36,7 @@ type testingConfig struct { proverOpts []backend.ProverOption compileOpts []frontend.CompileOption fuzzing bool + solidity bool } // WithBackends is testing option which restricts the backends the assertions are @@ -103,3 +104,16 @@ func WithCompileOpts(compileOpts ...frontend.CompileOption) TestingOption { return nil } } + +// WithSolidity is a testing option which enables solidity tests in assertions. +// If the build tag "solccheck" is not set, this option is ignored. +// When the tag is set; this requires gnark-solidity-checker to be installed, which in turns +// requires solc and abigen to be reachable in the PATH. +// +// See https://github.com/ConsenSys/gnark-solidity-checker for more details. +func WithSolidity() TestingOption { + return func(opt *testingConfig) error { + opt.solidity = true && solcCheck + return nil + } +} diff --git a/test/solccheck_with.go b/test/solccheck_with.go new file mode 100644 index 0000000000..9bf23579e1 --- /dev/null +++ b/test/solccheck_with.go @@ -0,0 +1,5 @@ +//go:build solccheck + +package test + +const solcCheck = true diff --git a/test/solccheck_without.go b/test/solccheck_without.go new file mode 100644 index 0000000000..a6414c27de --- /dev/null +++ b/test/solccheck_without.go @@ -0,0 +1,5 @@ +//go:build !solccheck + +package test + +const solcCheck = false